Skip to content

Commit

Permalink
Add update commitment function
Browse files Browse the repository at this point in the history
  • Loading branch information
m30m committed Aug 9, 2024
1 parent c41df03 commit d25c74a
Show file tree
Hide file tree
Showing 4 changed files with 155 additions and 1 deletion.
43 changes: 43 additions & 0 deletions target_chains/ethereum/contracts/contracts/entropy/Entropy.sol
Original file line number Diff line number Diff line change
Expand Up @@ -355,6 +355,49 @@ abstract contract Entropy is IEntropy, EntropyState {
}
}

// Update the provider commitment and increase the sequence number.
// This is used to reduce the `numHashes` required for future requests which leads to reduced gas usage.
function updateProviderCommitment(
address provider,
uint32 updatedSequenceNumber,
bytes32 providerRevelation
) public override {
EntropyStructs.ProviderInfo storage providerInfo = _state.providers[
provider
];
if (
updatedSequenceNumber <=
providerInfo.currentCommitmentSequenceNumber
) revert EntropyErrors.UpdateTooOld();
if (updatedSequenceNumber >= providerInfo.endSequenceNumber)
revert EntropyErrors.AssertionFailure();

uint32 numHashes = SafeCast.toUint32(
updatedSequenceNumber - providerInfo.currentCommitmentSequenceNumber
);
bytes32 providerCommitment = constructProviderCommitment(
numHashes,
providerRevelation
);

if (providerCommitment != providerInfo.currentCommitment)
revert EntropyErrors.IncorrectRevelation();

providerInfo.currentCommitmentSequenceNumber = updatedSequenceNumber;
providerInfo.currentCommitment = providerRevelation;
if (
providerInfo.currentCommitmentSequenceNumber >=
providerInfo.sequenceNumber
) {
// This means the provider called the function with a sequence number that was not yet requested.
// Assuming this is landed on-chain it's better to bump the sequence number and never use that range
// for future requests. Otherwise, someone can use the leaked revelation to derive favorable random numbers.
providerInfo.sequenceNumber =
providerInfo.currentCommitmentSequenceNumber +
1;
}
}

// Fulfill a request for a random number. This method validates the provided userRandomness and provider's proof
// against the corresponding commitments in the in-flight request. If both values are validated, this function returns
// the corresponding random number.
Expand Down
103 changes: 102 additions & 1 deletion target_chains/ethereum/contracts/forge-test/Entropy.t.sol
Original file line number Diff line number Diff line change
Expand Up @@ -958,7 +958,6 @@ contract EntropyTest is Test, EntropyTestUtils, EntropyEvents {
}

function testLastRevealedTooOld() public {
vm.roll(17);
uint64 sequenceNumber = request(user2, provider1, 42, false);
assertRevealSucceeds(
user2,
Expand All @@ -980,6 +979,108 @@ contract EntropyTest is Test, EntropyTestUtils, EntropyEvents {
);
}

function testUpdateProviderCommitment(
uint32 requestCount,
uint32 updateSeqNumber
) public {
vm.assume(requestCount < 500);
vm.assume(requestCount < provider1ChainLength);
vm.assume(updateSeqNumber < requestCount);
vm.assume(0 < updateSeqNumber);

for (uint256 i = 0; i < requestCount; i++) {
request(user1, provider1, 42, false);
}
assertInvariants();
EntropyStructs.ProviderInfo memory info1 = random.getProviderInfo(
provider1
);
assertEq(info1.currentCommitmentSequenceNumber, 0);
assertEq(info1.sequenceNumber, requestCount + 1);
random.updateProviderCommitment(
provider1,
updateSeqNumber,
provider1Proofs[updateSeqNumber]
);
info1 = random.getProviderInfo(provider1);
assertEq(info1.currentCommitmentSequenceNumber, updateSeqNumber);
assertEq(info1.currentCommitment, provider1Proofs[updateSeqNumber]);
assertEq(info1.sequenceNumber, requestCount + 1);
assertInvariants();
}

function testUpdateProviderCommitmentTooOld(
uint32 requestCount,
uint32 updateSeqNumber
) public {
vm.assume(requestCount < 500);
vm.assume(requestCount < provider1ChainLength);
vm.assume(updateSeqNumber < requestCount);
vm.assume(0 < updateSeqNumber);

for (uint256 i = 0; i < requestCount; i++) {
request(user1, provider1, 42, false);
}
assertRevealSucceeds(
user1,
provider1,
requestCount,
42,
provider1Proofs[requestCount],
ALL_ZEROS
);
vm.expectRevert(EntropyErrors.UpdateTooOld.selector);
random.updateProviderCommitment(
provider1,
updateSeqNumber,
provider1Proofs[updateSeqNumber]
);
}

function testUpdateProviderCommitmentIncorrectRevelation(
uint32 seqNumber,
uint32 mismatchedProofNumber
) public {
vm.assume(seqNumber < provider1ChainLength);
vm.assume(mismatchedProofNumber < provider1ChainLength);
vm.assume(seqNumber != mismatchedProofNumber);
vm.assume(seqNumber > 0);
vm.expectRevert(EntropyErrors.IncorrectRevelation.selector);
random.updateProviderCommitment(
provider1,
seqNumber,
provider1Proofs[mismatchedProofNumber]
);
}

function testUpdateProviderCommitmentUpdatesSequenceNumber(
uint32 seqNumber
) public {
vm.assume(seqNumber < provider1ChainLength);
vm.assume(seqNumber > 0);
random.updateProviderCommitment(
provider1,
seqNumber,
provider1Proofs[seqNumber]
);
EntropyStructs.ProviderInfo memory info1 = random.getProviderInfo(
provider1
);
assertEq(info1.sequenceNumber, seqNumber + 1);
}

function testUpdateProviderCommitmentHigherThanChainLength(
uint32 seqNumber
) public {
vm.assume(seqNumber >= provider1ChainLength);
vm.expectRevert(EntropyErrors.AssertionFailure.selector);
random.updateProviderCommitment(
provider1,
seqNumber,
provider1Proofs[0]
);
}

function testFeeManager() public {
address manager = address(12);

Expand Down
2 changes: 2 additions & 0 deletions target_chains/ethereum/entropy_sdk/solidity/EntropyErrors.sol
Original file line number Diff line number Diff line change
Expand Up @@ -41,4 +41,6 @@ library EntropyErrors {
// The last random number revealed from the provider is too old. Therefore, too many hashes
// are required for any new reveal. Please update the currentCommitment before making more requests.
error LastRevealedTooOld();
// A more recent commitment is already revealed on-chain
error UpdateTooOld();
}
8 changes: 8 additions & 0 deletions target_chains/ethereum/entropy_sdk/solidity/IEntropy.sol
Original file line number Diff line number Diff line change
Expand Up @@ -120,6 +120,14 @@ interface IEntropy is EntropyEvents {
// will override the previous value. Call this function with the all-zero address to disable the fee manager role.
function setFeeManager(address manager) external;

// Update the provider commitment and increase the sequence number.
// This is used to reduce the `numHashes` required for future requests which leads to reduced gas usage.
function updateProviderCommitment(
address provider,
uint32 updatedSequenceNumber,
bytes32 providerRevelation
) external;

function constructUserCommitment(
bytes32 userRandomness
) external pure returns (bytes32 userCommitment);
Expand Down

0 comments on commit d25c74a

Please sign in to comment.