Skip to content

Commit

Permalink
feat: instant lock selectSignatoryQuorum for rotated quorum types (#276)
Browse files Browse the repository at this point in the history
* feat: instant lock selectSignatoryQuorum for rotated quorum types

* feat: instant lock selectSignatoryQuorum for rotated quorum types

* fix: selectSignatoryQuorum method

* fix: remove console.log

* test: unit tests for selectSignatoryQuorum

* test: unit tests for selectSignatoryQuorum

* fix: LLMQ_25_67 params

* fix: LLMQ_25_67 params

* test: instant lock
  • Loading branch information
Konstantin Shuplenkov authored Apr 16, 2023
1 parent 231550c commit c111ad6
Show file tree
Hide file tree
Showing 5 changed files with 800 additions and 2 deletions.
16 changes: 14 additions & 2 deletions lib/deterministicmnlist/SimplifiedMNList.js
Original file line number Diff line number Diff line change
Expand Up @@ -384,6 +384,7 @@ SimplifiedMNList.prototype.getLLMQTypes = function getLLMQTypes() {
constants.LLMQ_TYPES.LLMQ_TYPE_400_60,
constants.LLMQ_TYPES.LLMQ_TYPE_400_85,
constants.LLMQ_TYPES.LLMQ_TYPE_TEST_V17,
constants.LLMQ_TYPES.LLMQ_TYPE_25_67,
];
return llmqTypes;
}
Expand Down Expand Up @@ -513,10 +514,10 @@ SimplifiedMNList.prototype.getInstantSendLLMQType =

switch (this.network.name) {
case Networks.livenet.name:
return constants.LLMQ_TYPES.LLMQ_TYPE_60_75;
return constants.LLMQ_TYPES.LLMQ_TYPE_25_67;
case Networks.testnet.name:
if (this.mnList.length > 100) {
return constants.LLMQ_TYPES.LLMQ_TYPE_60_75;
return constants.LLMQ_TYPES.LLMQ_TYPE_25_67;
}
// regtest
if (Networks.testnet.regtestEnabled === true) {
Expand All @@ -529,6 +530,17 @@ SimplifiedMNList.prototype.getInstantSendLLMQType =
}
};

/**
*
* @param {constants.LLMQ_TYPES} llmq
*/
SimplifiedMNList.prototype.isLLMQTypeRotated =
function isLLMQTypeRotated(llmq) {
return llmq === constants.LLMQ_TYPES.LLMQ_DEVNET_DIP0024 ||
llmq === constants.LLMQ_TYPES.LLMQ_TYPE_TEST_DIP0024 ||
llmq === constants.LLMQ_TYPES.LLMQ_TYPE_25_67;
};

/**
* Converts simplified MN list to simplified MN list diff that can be used to serialize data
* to json, buffer, or a hex string
Expand Down
45 changes: 45 additions & 0 deletions lib/instantlock/instantlock.js
Original file line number Diff line number Diff line change
Expand Up @@ -307,6 +307,7 @@ class InstantLock {
/**
* Selects the correct quorum that signed this InstantLock
* msgHash
* @private
* @param {SimplifiedMNListStore} smlStore - used to reconstruct quorum lists
* @param {Buffer} requestId
* @param {number} offset
Expand All @@ -317,6 +318,25 @@ class InstantLock {
smlStore.getTipHeight() - offset + 1
);

const llmq = instantlockSML.getInstantSendLLMQType();

return instantlockSML.isLLMQTypeRotated(llmq) ?
this.selectSignatoryRotatedQuorum(smlStore, requestId, offset) :
this.selectSignatoryNonRotatedQuorum(smlStore, requestId, offset);
}

/**
* @private
* @param {SimplifiedMNListStore} smlStore - used to reconstruct quorum lists
* @param {Buffer} requestId
* @param {number} offset
* @returns {QuorumEntry|null} - signatoryQuorum
*/
selectSignatoryNonRotatedQuorum(smlStore, requestId, offset) {
const instantlockSML = smlStore.getSMLbyHeight(
smlStore.getTipHeight() - offset + 1
);

const scoredQuorums = instantlockSML.calculateSignatoryQuorumScores(
instantlockSML.getInstantSendLLMQType(),
requestId
Expand All @@ -331,6 +351,31 @@ class InstantLock {
return scoredQuorums[0].quorum;
}

/**
* @private
* @param {SimplifiedMNListStore} smlStore - used to reconstruct quorum lists
* @param {Buffer} requestId
* @param {number} offset
* @returns {QuorumEntry|null} - signatoryQuorum
*/
selectSignatoryRotatedQuorum(smlStore, requestId, offset) {
const instantlockSML = smlStore.getSMLbyHeight(
smlStore.getTipHeight() - offset + 1
);

// Take the last n bits of the requestId with n = log2(quorum count)
// The value of these n bits will be the quorum index i.
const quorums = instantlockSML.getQuorumsOfType(instantlockSML.getInstantSendLLMQType());
const quorumCount = quorums.length;

const n = Math.log2(quorumCount);

const i = BufferUtil.readLastNBits(requestId, n);

// // The LLMQ at index i should be used to perform signing.
return quorums[i];
}

/**
* Computes signature id for a quorum entry
* @param {QuorumEntry} quorumEntry
Expand Down
26 changes: 26 additions & 0 deletions lib/util/buffer.js
Original file line number Diff line number Diff line change
Expand Up @@ -173,6 +173,32 @@ module.exports = {
assert(js.isHexa(string));
return Buffer.from(string, 'hex');
},

/**
*
* @param {Buffer} buffer
* @param {number} n
* @returns {number}
*/
readLastNBits: function readLastNBits(buffer, n) {
const numBytes = Math.ceil(n / 8);

const lastNBytes = Buffer.alloc(numBytes);

// Calculate the starting position for the bytes we need to read
const startByte = Math.floor((buffer.length * 8 - n) / 8);

buffer.copy(lastNBytes, 0, startByte);

// Calculate the number of bits we need to shift the final byte to get the last `n` bits
const shift = (numBytes * 8) - n;

// Shift the final byte and return the result as an integer
const lastByte = lastNBytes.readUIntBE(numBytes - 1, 1);

// eslint-disable-next-line no-bitwise
return lastByte >>> shift;
},
};

module.exports.NULL_HASH = module.exports.fill(Buffer.alloc(32), 0);
Expand Down
Loading

0 comments on commit c111ad6

Please sign in to comment.