Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: Populate epoch 0 from initial validator set #8286

Merged
merged 1 commit into from
Aug 30, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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();
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

nice

}

/**
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
Loading