Skip to content

Commit

Permalink
feat: Populate epoch 0 from initial validator set (#8286)
Browse files Browse the repository at this point in the history
  • Loading branch information
LHerskind authored Aug 30, 2024
1 parent d85ece1 commit cbdec54
Show file tree
Hide file tree
Showing 3 changed files with 38 additions and 35 deletions.
1 change: 1 addition & 0 deletions l1-contracts/src/core/Rollup.sol
Original file line number Diff line number Diff line change
Expand Up @@ -104,6 +104,7 @@ contract Rollup is Leonidas, IRollup, ITestRollup {
for (uint256 i = 0; i < _validators.length; i++) {
_addValidator(_validators[i]);
}
setupEpoch();
}

/**
Expand Down
35 changes: 7 additions & 28 deletions l1-contracts/src/core/sequencer_selection/Leonidas.sol
Original file line number Diff line number Diff line change
Expand Up @@ -78,11 +78,6 @@ contract Leonidas is Ownable, ILeonidas {

constructor(address _ares) Ownable(_ares) {
GENESIS_TIME = block.timestamp;

// We will setup the initial epoch value
uint256 seed = _computeNextSeed(0);
epochs[0] = Epoch({committee: new address[](0), sampleSeed: type(uint256).max, nextSeed: seed});
lastSeed = seed;
}

/**
Expand Down Expand Up @@ -135,10 +130,6 @@ contract Leonidas is Ownable, ILeonidas {

function getCommitteeAt(uint256 _ts) internal view returns (address[] memory) {
uint256 epochNumber = getEpochAt(_ts);
if (epochNumber == 0) {
return new address[](0);
}

Epoch storage epoch = epochs[epochNumber];

if (epoch.sampleSeed != 0) {
Expand All @@ -156,7 +147,7 @@ contract Leonidas is Ownable, ILeonidas {

// Emulate a sampling of the validators
uint256 sampleSeed = _getSampleSeed(epochNumber);
return _sampleValidators(epochNumber, sampleSeed);
return _sampleValidators(sampleSeed);
}

/**
Expand Down Expand Up @@ -224,12 +215,11 @@ contract Leonidas is Ownable, ILeonidas {
uint256 epochNumber = getCurrentEpoch();
Epoch storage epoch = epochs[epochNumber];

// For epoch 0 the sampleSeed == type(uint256).max, so we will never enter this
if (epoch.sampleSeed == 0) {
epoch.sampleSeed = _getSampleSeed(epochNumber);
epoch.nextSeed = lastSeed = _computeNextSeed(epochNumber);

epoch.committee = _sampleValidators(epochNumber, epoch.sampleSeed);
epoch.committee = _sampleValidators(epoch.sampleSeed);
}
}

Expand Down Expand Up @@ -326,7 +316,7 @@ contract Leonidas is Ownable, ILeonidas {

// Emulate a sampling of the validators
uint256 sampleSeed = _getSampleSeed(epochNumber);
address[] memory committee = _sampleValidators(epochNumber, sampleSeed);
address[] memory committee = _sampleValidators(sampleSeed);
return committee[_computeProposerIndex(epochNumber, slot, sampleSeed, committee.length)];
}

Expand Down Expand Up @@ -415,23 +405,9 @@ contract Leonidas is Ownable, ILeonidas {
* @dev Only used internally, should never be called for anything but the "next" epoch
* Allowing us to always use `lastSeed`.
*
* @dev The first epoch will always return an empty list
* If the validator set is empty, we return an empty list
* If the validator set is smaller than the target committee size, we return the full set
* If the validator set is larger than the target committee size, we sample the validators
* by using the seed of the previous epoch to compute an offset for the validator set and then
* we take the next `TARGET_COMMITTEE_SIZE` validators from that offset (wrapping around).
*
* @param _epoch - The epoch to sample the validators for
*
* @return The validators for the given epoch
*/
function _sampleValidators(uint256 _epoch, uint256 _seed) private view returns (address[] memory) {
// If we are in the first epoch, we just return an empty list
if (_epoch == 0) {
return new address[](0);
}

function _sampleValidators(uint256 _seed) private view returns (address[] memory) {
uint256 validatorSetSize = validatorSet.length();
if (validatorSetSize == 0) {
return new address[](0);
Expand Down Expand Up @@ -467,6 +443,9 @@ contract Leonidas is Ownable, ILeonidas {
* @return The sample seed for the epoch
*/
function _getSampleSeed(uint256 _epoch) private view returns (uint256) {
if (_epoch == 0) {
return type(uint256).max;
}
uint256 sampleSeed = epochs[_epoch].sampleSeed;
if (sampleSeed != 0) {
return sampleSeed;
Expand Down
37 changes: 30 additions & 7 deletions l1-contracts/test/sparta/Sparta.t.sol
Original file line number Diff line number Diff line change
Expand Up @@ -59,6 +59,14 @@ contract SpartaTest is DecoderBase {
vm.warp(initialTime);
}

address[] memory initialValidators = new address[](_validatorCount);
for (uint256 i = 1; i < _validatorCount + 1; i++) {
uint256 privateKey = uint256(keccak256(abi.encode("validator", i)));
address validator = vm.addr(privateKey);
privateKeys[validator] = privateKey;
initialValidators[i - 1] = validator;
}

registry = new Registry(address(this));
availabilityOracle = new AvailabilityOracle();
portalERC20 = new PortalERC20();
Expand All @@ -68,7 +76,7 @@ contract SpartaTest is DecoderBase {
IFeeJuicePortal(address(0)),
bytes32(0),
address(this),
new address[](0)
initialValidators
);
inbox = Inbox(address(rollup.INBOX()));
outbox = Outbox(address(rollup.OUTBOX()));
Expand All @@ -78,15 +86,30 @@ contract SpartaTest is DecoderBase {
merkleTestUtil = new MerkleTestUtil();
txsHelper = new TxsDecoderHelper();

for (uint256 i = 1; i < _validatorCount + 1; i++) {
uint256 privateKey = uint256(keccak256(abi.encode("validator", i)));
address validator = vm.addr(privateKey);
privateKeys[validator] = privateKey;
rollup.addValidator(validator);
}
_;
}

mapping(address => bool) internal _seenValidators;
mapping(address => bool) internal _seenCommittee;

function testInitialCommitteMatch() public setup(4) {
address[] memory validators = rollup.getValidators();
address[] memory committee = rollup.getCurrentEpochCommittee();
assertEq(rollup.getCurrentEpoch(), 0);
assertEq(validators.length, 4, "Invalid validator set size");
assertEq(committee.length, 4, "invalid committee set size");

for (uint256 i = 0; i < validators.length; i++) {
_seenValidators[validators[i]] = true;
}

for (uint256 i = 0; i < committee.length; i++) {
assertTrue(_seenValidators[committee[i]]);
assertFalse(_seenCommittee[committee[i]]);
_seenCommittee[committee[i]] = true;
}
}

function testProposerForNonSetupEpoch(uint8 _epochsToJump) public setup(4) {
if (Constants.IS_DEV_NET == 1) {
return;
Expand Down

0 comments on commit cbdec54

Please sign in to comment.