Skip to content

Commit

Permalink
feat!: staking library
Browse files Browse the repository at this point in the history
  • Loading branch information
LHerskind committed Jan 29, 2025
1 parent f4e5f8d commit 745526f
Show file tree
Hide file tree
Showing 21 changed files with 395 additions and 269 deletions.
146 changes: 110 additions & 36 deletions l1-contracts/src/core/ValidatorSelection.sol
Original file line number Diff line number Diff line change
Expand Up @@ -7,16 +7,17 @@ import {
EpochData,
ValidatorSelectionStorage
} from "@aztec/core/interfaces/IValidatorSelection.sol";
import {IStaking, ValidatorInfo, Exit, OperatorInfo} from "@aztec/core/interfaces/IStaking.sol";
import {Signature} from "@aztec/core/libraries/crypto/SignatureLib.sol";
import {DataStructures} from "@aztec/core/libraries/DataStructures.sol";
import {Errors} from "@aztec/core/libraries/Errors.sol";
import {ValidatorSelectionLib} from
"@aztec/core/libraries/ValidatorSelectionLib/ValidatorSelectionLib.sol";
import {StakingLib} from "@aztec/core/libraries/staking/StakingLib.sol";
import {
Timestamp, Slot, Epoch, SlotLib, EpochLib, TimeLib
} from "@aztec/core/libraries/TimeLib.sol";
import {ValidatorSelectionLib} from
"@aztec/core/libraries/ValidatorSelectionLib/ValidatorSelectionLib.sol";
import {Staking} from "@aztec/core/staking/Staking.sol";

import {Slasher} from "@aztec/core/staking/Slasher.sol";
import {IERC20} from "@oz/token/ERC20/IERC20.sol";
import {EnumerableSet} from "@oz/utils/structs/EnumerableSet.sol";

Expand All @@ -27,7 +28,7 @@ import {EnumerableSet} from "@oz/utils/structs/EnumerableSet.sol";
* It is a reference implementation, it is not optimized for gas.
*
*/
contract ValidatorSelection is Staking, IValidatorSelection {
contract ValidatorSelection is IValidatorSelection, IStaking {
using EnumerableSet for EnumerableSet.AddressSet;

using SlotLib for Slot;
Expand All @@ -50,10 +51,45 @@ contract ValidatorSelection is Staking, IValidatorSelection {
uint256 _slotDuration,
uint256 _epochDuration,
uint256 _targetCommitteeSize
) Staking(_stakingAsset, _minimumStake, _slashingQuorum, _roundSize) {
) {
TARGET_COMMITTEE_SIZE = _targetCommitteeSize;

TimeLib.initialize(block.timestamp, _slotDuration, _epochDuration);

Timestamp exitDelay = Timestamp.wrap(60 * 60 * 24);
Slasher slasher = new Slasher(_slashingQuorum, _roundSize);
StakingLib.initialize(_stakingAsset, _minimumStake, exitDelay, address(slasher));
}

function deposit(address _attester, address _proposer, address _withdrawer, uint256 _amount)
external
override(IStaking)
{
setupEpoch();
require(
_attester != address(0) && _proposer != address(0),
Errors.ValidatorSelection__InvalidDeposit(_attester, _proposer)
);
StakingLib.deposit(_attester, _proposer, _withdrawer, _amount);
}

function initiateWithdraw(address _attester, address _recipient)
external
override(IStaking)
returns (bool)
{
// @note The attester might be chosen for the epoch, so the delay must be long enough
// to allow for that.
setupEpoch();
return StakingLib.initiateWithdraw(_attester, _recipient);
}

function finaliseWithdraw(address _attester) external override(IStaking) {
StakingLib.finaliseWithdraw(_attester);
}

function slash(address _attester, uint256 _amount) external override(IStaking) {
StakingLib.slash(_attester, _amount);
}

function getGenesisTime() external view override(IValidatorSelection) returns (Timestamp) {
Expand All @@ -68,6 +104,67 @@ contract ValidatorSelection is Staking, IValidatorSelection {
return TimeLib.getStorage().epochDuration;
}

function getSlasher() external view override(IStaking) returns (address) {
return StakingLib.getStorage().slasher;
}

function getStakingAsset() external view override(IStaking) returns (IERC20) {
return StakingLib.getStorage().stakingAsset;
}

function getMinimumStake() external view override(IStaking) returns (uint256) {
return StakingLib.getStorage().minimumStake;
}

function getExitDelay() external view override(IStaking) returns (Timestamp) {
return StakingLib.getStorage().exitDelay;
}

function getActiveAttesterCount() external view override(IStaking) returns (uint256) {
return StakingLib.getStorage().attesters.length();
}

function getProposerForAttester(address _attester)
external
view
override(IStaking)
returns (address)
{
return StakingLib.getStorage().info[_attester].proposer;
}

function getAttesterAtIndex(uint256 _index) external view override(IStaking) returns (address) {
return StakingLib.getStorage().attesters.at(_index);
}

function getProposerAtIndex(uint256 _index) external view override(IStaking) returns (address) {
return StakingLib.getStorage().info[StakingLib.getStorage().attesters.at(_index)].proposer;
}

function getInfo(address _attester)
external
view
override(IStaking)
returns (ValidatorInfo memory)
{
return StakingLib.getStorage().info[_attester];
}

function getExit(address _attester) external view override(IStaking) returns (Exit memory) {
return StakingLib.getStorage().exits[_attester];
}

function getOperatorAtIndex(uint256 _index)
external
view
override(IStaking)
returns (OperatorInfo memory)
{
address attester = StakingLib.getStorage().attesters.at(_index);
return
OperatorInfo({proposer: StakingLib.getStorage().info[attester].proposer, attester: attester});
}

/**
* @notice Get the validator set for a given epoch
*
Expand Down Expand Up @@ -97,7 +194,7 @@ contract ValidatorSelection is Staking, IValidatorSelection {
returns (address[] memory)
{
return ValidatorSelectionLib.getCommitteeAt(
validatorSelectionStore, stakingStore, getCurrentEpoch(), TARGET_COMMITTEE_SIZE
validatorSelectionStore, StakingLib.getStorage(), getCurrentEpoch(), TARGET_COMMITTEE_SIZE
);
}

Expand All @@ -115,7 +212,7 @@ contract ValidatorSelection is Staking, IValidatorSelection {
returns (address[] memory)
{
return ValidatorSelectionLib.getCommitteeAt(
validatorSelectionStore, stakingStore, getEpochAt(_ts), TARGET_COMMITTEE_SIZE
validatorSelectionStore, StakingLib.getStorage(), getEpochAt(_ts), TARGET_COMMITTEE_SIZE
);
}

Expand Down Expand Up @@ -144,29 +241,6 @@ contract ValidatorSelection is Staking, IValidatorSelection {
return ValidatorSelectionLib.getSampleSeed(validatorSelectionStore, getCurrentEpoch());
}

function initiateWithdraw(address _attester, address _recipient)
public
override(Staking)
returns (bool)
{
// @note The attester might be chosen for the epoch, so the delay must be long enough
// to allow for that.
setupEpoch();
return super.initiateWithdraw(_attester, _recipient);
}

function deposit(address _attester, address _proposer, address _withdrawer, uint256 _amount)
public
override(Staking)
{
setupEpoch();
require(
_attester != address(0) && _proposer != address(0),
Errors.ValidatorSelection__InvalidDeposit(_attester, _proposer)
);
super.deposit(_attester, _proposer, _withdrawer, _amount);
}

/**
* @notice Performs a setup of an epoch if needed. The setup will
* - Sample the validator set for the epoch
Expand All @@ -185,7 +259,7 @@ contract ValidatorSelection is Staking, IValidatorSelection {
epoch.sampleSeed = ValidatorSelectionLib.getSampleSeed(validatorSelectionStore, epochNumber);
epoch.nextSeed = validatorSelectionStore.lastSeed = _computeNextSeed(epochNumber);
epoch.committee = ValidatorSelectionLib.sampleValidators(
stakingStore, epoch.sampleSeed, TARGET_COMMITTEE_SIZE
StakingLib.getStorage(), epoch.sampleSeed, TARGET_COMMITTEE_SIZE
);
}
}
Expand All @@ -198,7 +272,7 @@ contract ValidatorSelection is Staking, IValidatorSelection {
* @return The validator set
*/
function getAttesters() public view override(IValidatorSelection) returns (address[] memory) {
return stakingStore.attesters.values();
return StakingLib.getStorage().attesters.values();
}

/**
Expand Down Expand Up @@ -271,7 +345,7 @@ contract ValidatorSelection is Staking, IValidatorSelection {
Slot slot = getSlotAt(_ts);
Epoch epochNumber = getEpochAtSlot(slot);
return ValidatorSelectionLib.getProposerAt(
validatorSelectionStore, stakingStore, slot, epochNumber, TARGET_COMMITTEE_SIZE
validatorSelectionStore, StakingLib.getStorage(), slot, epochNumber, TARGET_COMMITTEE_SIZE
);
}

Expand Down Expand Up @@ -325,7 +399,7 @@ contract ValidatorSelection is Staking, IValidatorSelection {
Errors.ValidatorSelection__InvalidDeposit(_attester, _proposer)
);

super.deposit(_attester, _proposer, _withdrawer, _amount);
StakingLib.deposit(_attester, _proposer, _withdrawer, _amount);
}

/**
Expand Down Expand Up @@ -353,7 +427,7 @@ contract ValidatorSelection is Staking, IValidatorSelection {
Epoch epochNumber = getEpochAtSlot(_slot);
ValidatorSelectionLib.validateValidatorSelection(
validatorSelectionStore,
stakingStore,
StakingLib.getStorage(),
_slot,
epochNumber,
_signatures,
Expand Down
11 changes: 10 additions & 1 deletion l1-contracts/src/core/interfaces/IStaking.sol
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,8 @@
// Copyright 2024 Aztec Labs.
pragma solidity >=0.8.27;

import {Timestamp} from "@aztec/core/libraries/TimeLib.sol";
import {Timestamp} from "@aztec/core/libraries/TimeMath.sol";
import {IERC20} from "@oz/token/ERC20/IERC20.sol";
import {EnumerableSet} from "@oz/utils/structs/EnumerableSet.sol";

// None -> Does not exist in our setup
Expand Down Expand Up @@ -35,6 +36,10 @@ struct Exit {
}

struct StakingStorage {
IERC20 stakingAsset;
address slasher;
uint256 minimumStake;
Timestamp exitDelay;
EnumerableSet.AddressSet attesters;
mapping(address attester => ValidatorInfo) info;
mapping(address attester => Exit) exits;
Expand All @@ -61,4 +66,8 @@ interface IStaking {
function getProposerAtIndex(uint256 _index) external view returns (address);
function getProposerForAttester(address _attester) external view returns (address);
function getOperatorAtIndex(uint256 _index) external view returns (OperatorInfo memory);
function getSlasher() external view returns (address);
function getStakingAsset() external view returns (IERC20);
function getMinimumStake() external view returns (uint256);
function getExitDelay() external view returns (Timestamp);
}
Loading

0 comments on commit 745526f

Please sign in to comment.