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

Deneb Mainnet Patch #395

Merged
merged 22 commits into from
Feb 1, 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
16 changes: 16 additions & 0 deletions src/contracts/interfaces/IEigenPodManager.sol
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,8 @@ interface IEigenPodManager is IPausable {
bytes32 withdrawalRoot
);

event DenebForkTimestampUpdated(uint64 newValue);

/**
* @notice Creates an EigenPod for the sender.
* @dev Function will revert if the `msg.sender` already has an EigenPod.
Expand Down Expand Up @@ -146,4 +148,18 @@ interface IEigenPodManager is IPausable {
* @dev Reverts if `shares` is not a whole Gwei amount
*/
function withdrawSharesAsTokens(address podOwner, address destination, uint256 shares) external;

/**
* @notice the deneb hard fork timestamp used to determine which proof path to use for proving a withdrawal
*/
function denebForkTimestamp() external view returns (uint64);

/**
* setting the deneb hard fork timestamp by the eigenPodManager owner
* @dev this function is designed to be called twice. Once, it is set to type(uint64).max
* prior to the actual deneb fork timestamp being set, and then the second time it is set
* to the actual deneb fork timestamp.
*/
function setDenebForkTimestamp(uint64 newDenebForkTimestamp) external;

}
13 changes: 9 additions & 4 deletions src/contracts/libraries/BeaconChainProofs.sol
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,9 @@ library BeaconChainProofs {
uint256 internal constant VALIDATOR_FIELD_TREE_HEIGHT = 3;

uint256 internal constant NUM_EXECUTION_PAYLOAD_HEADER_FIELDS = 15;
Sidu28 marked this conversation as resolved.
Show resolved Hide resolved
uint256 internal constant EXECUTION_PAYLOAD_HEADER_FIELD_TREE_HEIGHT = 4;
//Note: changed in the deneb hard fork from 4->5
uint256 internal constant EXECUTION_PAYLOAD_HEADER_FIELD_TREE_HEIGHT_DENEB = 5;
uint256 internal constant EXECUTION_PAYLOAD_HEADER_FIELD_TREE_HEIGHT_CAPELLA = 4;

uint256 internal constant NUM_EXECUTION_PAYLOAD_FIELDS = 15;
uint256 internal constant EXECUTION_PAYLOAD_FIELD_TREE_HEIGHT = 4;
Expand Down Expand Up @@ -211,7 +213,8 @@ library BeaconChainProofs {
function verifyWithdrawal(
bytes32 beaconStateRoot,
bytes32[] calldata withdrawalFields,
WithdrawalProof calldata withdrawalProof
WithdrawalProof calldata withdrawalProof,
uint64 denebForkTimestamp
) internal view {
require(
withdrawalFields.length == 2 ** WITHDRAWAL_FIELD_TREE_HEIGHT,
Expand All @@ -232,9 +235,11 @@ library BeaconChainProofs {
"BeaconChainProofs.verifyWithdrawal: historicalSummaryIndex is too large"
);

//Note: post deneb hard fork, the exection payload header fields increased, adding an extra level to the tree height
uint256 executionPayloadHeaderFieldTreeHeight = (getWithdrawalTimestamp(withdrawalProof) < denebForkTimestamp) ? EXECUTION_PAYLOAD_HEADER_FIELD_TREE_HEIGHT_CAPELLA : EXECUTION_PAYLOAD_HEADER_FIELD_TREE_HEIGHT_DENEB;
require(
withdrawalProof.withdrawalProof.length ==
32 * (EXECUTION_PAYLOAD_HEADER_FIELD_TREE_HEIGHT + WITHDRAWALS_TREE_HEIGHT + 1),
32 * (executionPayloadHeaderFieldTreeHeight + WITHDRAWALS_TREE_HEIGHT + 1),
"BeaconChainProofs.verifyWithdrawal: withdrawalProof has incorrect length"
);
require(
Expand All @@ -247,7 +252,7 @@ library BeaconChainProofs {
"BeaconChainProofs.verifyWithdrawal: slotProof has incorrect length"
);
require(
withdrawalProof.timestampProof.length == 32 * (EXECUTION_PAYLOAD_HEADER_FIELD_TREE_HEIGHT),
withdrawalProof.timestampProof.length == 32 * (executionPayloadHeaderFieldTreeHeight),
"BeaconChainProofs.verifyWithdrawal: timestampProof has incorrect length"
);

Expand Down
3 changes: 2 additions & 1 deletion src/contracts/pods/EigenPod.sol
Original file line number Diff line number Diff line change
Expand Up @@ -607,7 +607,8 @@ contract EigenPod is IEigenPod, Initializable, ReentrancyGuardUpgradeable, Eigen
BeaconChainProofs.verifyWithdrawal({
beaconStateRoot: beaconStateRoot,
withdrawalFields: withdrawalFields,
withdrawalProof: withdrawalProof
withdrawalProof: withdrawalProof,
denebForkTimestamp: eigenPodManager.denebForkTimestamp()
});

uint40 validatorIndex = withdrawalFields.getValidatorIndex();
Expand Down
22 changes: 22 additions & 0 deletions src/contracts/pods/EigenPodManager.sol
Original file line number Diff line number Diff line change
Expand Up @@ -241,6 +241,28 @@ contract EigenPodManager is
_updateBeaconChainOracle(newBeaconChainOracle);
}

/**
* @notice Sets the timestamp of the Deneb fork.
* @param newDenebForkTimestamp is the new timestamp of the Deneb fork
*/
function setDenebForkTimestamp(uint64 newDenebForkTimestamp) external onlyOwner {

/**
* @notice Modifier to ensure that the deneb fork timestamp is not set
* @dev Note that this function is only ever meant to be called twice. First, it will be called to set the timestamp
* to type(uint64).max, and then it will be called to set the timestamp to the actual timestamp
*/
require(newDenebForkTimestamp != 0, "EigenPodManager.denebForkEnabled: cannot set newDenebForkTimestamp to 0");
if(newDenebForkTimestamp == type(uint64).max){
require(denebForkTimestamp == 0, "EigenPodManager.denebForkEnabled: denebForkTimestamp must not be set yet");
} else {
require(denebForkTimestamp ==type(uint64).max, "EigenPodManager.denebForkEnabled: Deneb fork timestamp cannot be set");
}

denebForkTimestamp = newDenebForkTimestamp;
emit DenebForkTimestampUpdated(denebForkTimestamp);
}

// INTERNAL FUNCTIONS

function _deployPod() internal returns (IEigenPod) {
Expand Down
4 changes: 3 additions & 1 deletion src/contracts/pods/EigenPodManagerStorage.sol
Original file line number Diff line number Diff line change
Expand Up @@ -64,6 +64,8 @@ abstract contract EigenPodManagerStorage is IEigenPodManager {
*/
mapping(address => int256) public podOwnerShares;

uint64 public denebForkTimestamp;

constructor(
IETHPOSDeposit _ethPOS,
IBeacon _eigenPodBeacon,
Expand All @@ -83,5 +85,5 @@ abstract contract EigenPodManagerStorage is IEigenPodManager {
* variables without shifting down storage in the inheritance chain.
* See https://docs.openzeppelin.com/contracts/4.x/upgradeable#storage_gaps
*/
uint256[45] private __gap;
uint256[44] private __gap;
}
53 changes: 47 additions & 6 deletions src/test/EigenPod.t.sol
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,8 @@ contract EigenPodTests is ProofParsing, EigenPodPausingConstants {


uint256 internal constant GWEI_TO_WEI = 1e9;
uint64 public constant DENEB_FORK_TIMESTAMP_GOERLI = 1705473120;


bytes pubkey =
hex"88347ed1c492eedc97fc8c506a35d44d81f27a0c7a1c661b35913cfd15256c0cccbd34a83341f505c7de2983292f2cab";
Expand All @@ -24,6 +26,8 @@ contract EigenPodTests is ProofParsing, EigenPodPausingConstants {

address podOwner = address(42000094993494);

bool public IS_DENEB;

Vm cheats = Vm(HEVM_ADDRESS);
DelegationManager public delegation;
IStrategyManager public strategyManager;
Expand Down Expand Up @@ -255,6 +259,8 @@ contract EigenPodTests is ProofParsing, EigenPodPausingConstants {
)
);

eigenPodManager.setDenebForkTimestamp(type(uint64).max);

cheats.deal(address(podOwner), 5 * stakeAmount);

fuzzedAddressMapping[address(0)] = true;
Expand Down Expand Up @@ -502,6 +508,37 @@ contract EigenPodTests is ProofParsing, EigenPodPausingConstants {
}

/// @notice This test is to ensure the full withdrawal flow works
function testFullWithdrawalFlowDeneb() public returns (IEigenPod) {
eigenPodManager.setDenebForkTimestamp(DENEB_FORK_TIMESTAMP_GOERLI);
IS_DENEB = true;
//this call is to ensure that validator 302913 has proven their withdrawalcreds
// ./solidityProofGen -newBalance=32000115173 "ValidatorFieldsProof" 302913 true "data/withdrawal_proof_goerli/goerli_block_header_6399998.json" "data/withdrawal_proof_goerli/goerli_slot_6399998.json" "withdrawal_credential_proof_302913.json"
setJSON("./src/test/test-data/withdrawal_credential_proof_302913.json");
_testDeployAndVerifyNewEigenPod(podOwner, signature, depositDataRoot);
IEigenPod newPod = eigenPodManager.getPod(podOwner);

//Deneb: ./solidityProofGen/solidityProofGen "WithdrawalFieldsProof" 302913 271 8191 true false "data/deneb_goerli_block_header_7431952.json" "data/deneb_goerli_slot_7431952.json" "data/deneb_goerli_slot_7421952.json" "data/deneb_goerli_block_header_7421951.json" "data/deneb_goerli_block_7421951.json" "fullWithdrawalProof_Latest.json" false false
// To get block header: curl -H "Accept: application/json" 'https://eigenlayer.spiceai.io/goerli/beacon/eth/v1/beacon/headers/6399000?api_key\="343035|f6ebfef661524745abb4f1fd908a76e8"' > block_header_6399000.json
// To get block: curl -H "Accept: application/json" 'https://eigenlayer.spiceai.io/goerli/beacon/eth/v2/beacon/blocks/6399000?api_key\="343035|f6ebfef661524745abb4f1fd908a76e8"' > block_6399000.json
setJSON("./src/test/test-data/fullWithdrawalDeneb.json");
return _proveWithdrawalForPod(newPod);
}

function testFullWithdrawalFlowCapellaWithdrawalAgainstDenebRoot() public returns (IEigenPod) {
IS_DENEB = false;
//this call is to ensure that validator 302913 has proven their withdrawalcreds
// ./solidityProofGen/solidityProofGen "WithdrawalFieldsProof" 302913 146 8092 true false "data/deneb_goerli_block_header_7431952.json" "data/deneb_goerli_slot_7431952.json" "data/goerli_slot_6397952.json" "data/goerli_block_header_6397852.json" "data/goerli_block_6397852.json" "fullWithdrawalProof_CapellaAgainstDeneb.json" false true
setJSON("./src/test/test-data/withdrawal_credential_proof_302913.json");
_testDeployAndVerifyNewEigenPod(podOwner, signature, depositDataRoot);
IEigenPod newPod = eigenPodManager.getPod(podOwner);

//Deneb: ./solidityProofGen/solidityProofGen "WithdrawalFieldsProof" 302913 271 8191 true false "data/deneb_goerli_block_header_7431952.json" "data/deneb_goerli_slot_7431952.json" "data/deneb_goerli_slot_7421952.json" "data/deneb_goerli_block_header_7421951.json" "data/deneb_goerli_block_7421951.json" "fullWithdrawalProof_Latest.json" false
// To get block header: curl -H "Accept: application/json" 'https://eigenlayer.spiceai.io/goerli/beacon/eth/v1/beacon/headers/6399000?api_key\="343035|f6ebfef661524745abb4f1fd908a76e8"' > block_header_6399000.json
// To get block: curl -H "Accept: application/json" 'https://eigenlayer.spiceai.io/goerli/beacon/eth/v2/beacon/blocks/6399000?api_key\="343035|f6ebfef661524745abb4f1fd908a76e8"' > block_6399000.json
setJSON("./src/test/test-data/fullWithdrawalCapellaAgainstDenebRoot.json");
return _proveWithdrawalForPod(newPod);
}

function testFullWithdrawalFlow() public returns (IEigenPod) {
//this call is to ensure that validator 302913 has proven their withdrawalcreds
// ./solidityProofGen -newBalance=32000115173 "ValidatorFieldsProof" 302913 true "data/withdrawal_proof_goerli/goerli_block_header_6399998.json" "data/withdrawal_proof_goerli/goerli_slot_6399998.json" "withdrawal_credential_proof_302913.json"
Expand Down Expand Up @@ -835,7 +872,6 @@ contract EigenPodTests is ProofParsing, EigenPodPausingConstants {
emit log("hello");

IEigenPod newPod = _testDeployAndVerifyNewEigenPod(podOwner, signature, depositDataRoot);
emit log("hello");
//./solidityProofGen "WithdrawalFieldsProof" 302913 146 8092 true false "data/withdrawal_proof_goerli/goerli_block_header_6399998.json" "data/withdrawal_proof_goerli/goerli_slot_6399998.json" "data/withdrawal_proof_goerli/goerli_slot_6397852.json" "data/withdrawal_proof_goerli/goerli_block_header_6397852.json" "data/withdrawal_proof_goerli/goerli_block_6397852.json" "fullWithdrawalProof_Latest.json" false
// To get block header: curl -H "Accept: application/json" 'https://eigenlayer.spiceai.io/goerli/beacon/eth/v1/beacon/headers/6399000?api_key\="343035|f6ebfef661524745abb4f1fd908a76e8"' > block_header_6399000.json
// To get block: curl -H "Accept: application/json" 'https://eigenlayer.spiceai.io/goerli/beacon/eth/v2/beacon/blocks/6399000?api_key\="343035|f6ebfef661524745abb4f1fd908a76e8"' > block_6399000.json
Expand Down Expand Up @@ -1475,7 +1511,7 @@ contract EigenPodTests is ProofParsing, EigenPodPausingConstants {
uint64 withdrawalAmountGwei = Endian.fromLittleEndianUint64(
withdrawalFields[BeaconChainProofs.WITHDRAWAL_VALIDATOR_AMOUNT_INDEX]
);

emit log_named_uint("withdrawalAmountGwei", withdrawalAmountGwei);
uint64 leftOverBalanceWEI = uint64(withdrawalAmountGwei - newPod.MAX_RESTAKED_BALANCE_GWEI_PER_VALIDATOR()) *
uint64(GWEI_TO_WEI);
cheats.deal(address(newPod), leftOverBalanceWEI);
Expand Down Expand Up @@ -1727,18 +1763,22 @@ contract EigenPodTests is ProofParsing, EigenPodPausingConstants {
eigenPodManager.stake{value: stakeAmount}(pubkey, signature, depositDataRoot);
cheats.stopPrank();

if(!IS_DENEB){
emit log("NOT DENEB");
}
bytes memory withdrawalProof = IS_DENEB ? abi.encodePacked(getWithdrawalProofDeneb()) : abi.encodePacked(getWithdrawalProofCapella());
bytes memory timestampProof = IS_DENEB ? abi.encodePacked(getTimestampProofDeneb()) : abi.encodePacked(getTimestampProofCapella());
{
bytes32 blockRoot = getBlockRoot();
bytes32 slotRoot = getSlotRoot();
bytes32 timestampRoot = getTimestampRoot();
bytes32 executionPayloadRoot = getExecutionPayloadRoot();

return
BeaconChainProofs.WithdrawalProof(
abi.encodePacked(getWithdrawalProof()),
abi.encodePacked(withdrawalProof),
abi.encodePacked(getSlotProof()),
abi.encodePacked(getExecutionPayloadProof()),
abi.encodePacked(getTimestampProof()),
abi.encodePacked(timestampProof),
abi.encodePacked(getHistoricalSummaryProof()),
uint64(getBlockRootIndex()),
uint64(getHistoricalSummaryIndex()),
Expand All @@ -1750,6 +1790,7 @@ contract EigenPodTests is ProofParsing, EigenPodPausingConstants {
);
}
}


function _setOracleBlockRoot() internal {
bytes32 latestBlockRoot = getLatestBlockRoot();
Expand Down Expand Up @@ -1778,7 +1819,7 @@ contract Relayer is Test {
bytes32[] calldata withdrawalFields,
BeaconChainProofs.WithdrawalProof calldata proofs
) public view {
BeaconChainProofs.verifyWithdrawal(beaconStateRoot, withdrawalFields, proofs);
BeaconChainProofs.verifyWithdrawal(beaconStateRoot, withdrawalFields, proofs, type(uint64).max);
}
}

Expand Down
4 changes: 4 additions & 0 deletions src/test/events/IEigenPodManagerEvents.sol
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,10 @@ interface IEigenPodManagerEvents {
/// @notice Emitted to notify the update of the beaconChainOracle address
event BeaconOracleUpdated(address indexed newOracleAddress);

/// @notice Emitted to notify that the denebForkTimestamp has been set
event DenebForkTimestampUpdated(uint64 denebForkTimestamp);


/// @notice Emitted to notify the deployment of an EigenPod
event PodDeployed(address indexed eigenPod, address indexed podOwner);

Expand Down
5 changes: 5 additions & 0 deletions src/test/integration/IntegrationDeployer.t.sol
Original file line number Diff line number Diff line change
Expand Up @@ -272,6 +272,11 @@ abstract contract IntegrationDeployer is Test, IUserDeployer {

// Create mock beacon chain / proof gen interface
beaconChain = new BeaconChainMock(timeMachine, beaconChainOracle);



//set deneb fork timestamp
eigenPodManager.setDenebForkTimestamp(type(uint64).max);
}

/// @dev Deploy a strategy and its underlying token, push to global lists of tokens/strategies, and whitelist
Expand Down
21 changes: 15 additions & 6 deletions src/test/integration/mocks/BeaconChainMock.t.sol
Original file line number Diff line number Diff line change
Expand Up @@ -694,19 +694,28 @@ contract BeaconChainMock is Test {
(BeaconChainProofs.VALIDATOR_TREE_HEIGHT + 1) + BeaconChainProofs.BEACON_STATE_FIELD_TREE_HEIGHT
);

uint immutable WITHDRAWAL_PROOF_LEN = 32 * (
BeaconChainProofs.EXECUTION_PAYLOAD_HEADER_FIELD_TREE_HEIGHT +
uint immutable WITHDRAWAL_PROOF_LEN_CAPELLA = 32 * (
BeaconChainProofs.EXECUTION_PAYLOAD_HEADER_FIELD_TREE_HEIGHT_CAPELLA +
BeaconChainProofs.WITHDRAWALS_TREE_HEIGHT + 1
);

uint immutable WITHDRAWAL_PROOF_LEN_DENEB= 32 * (
BeaconChainProofs.EXECUTION_PAYLOAD_HEADER_FIELD_TREE_HEIGHT_DENEB +
BeaconChainProofs.WITHDRAWALS_TREE_HEIGHT + 1
);

uint immutable EXECPAYLOAD_PROOF_LEN = 32 * (
BeaconChainProofs.BEACON_BLOCK_HEADER_FIELD_TREE_HEIGHT +
BeaconChainProofs.BEACON_BLOCK_BODY_FIELD_TREE_HEIGHT
);
uint immutable SLOT_PROOF_LEN = 32 * (
BeaconChainProofs.BEACON_BLOCK_HEADER_FIELD_TREE_HEIGHT
);
uint immutable TIMESTAMP_PROOF_LEN = 32 * (
BeaconChainProofs.EXECUTION_PAYLOAD_HEADER_FIELD_TREE_HEIGHT
uint immutable TIMESTAMP_PROOF_LEN_CAPELLA = 32 * (
BeaconChainProofs.EXECUTION_PAYLOAD_HEADER_FIELD_TREE_HEIGHT_CAPELLA
);
uint immutable TIMESTAMP_PROOF_LEN_DENEB = 32 * (
BeaconChainProofs.EXECUTION_PAYLOAD_HEADER_FIELD_TREE_HEIGHT_DENEB
);
uint immutable HISTSUMMARY_PROOF_LEN = 32 * (
BeaconChainProofs.BEACON_STATE_FIELD_TREE_HEIGHT +
Expand All @@ -725,10 +734,10 @@ contract BeaconChainMock is Test {
uint64 oracleTimestamp
) internal view returns (BeaconChainProofs.WithdrawalProof memory) {
return BeaconChainProofs.WithdrawalProof({
withdrawalProof: new bytes(WITHDRAWAL_PROOF_LEN),
withdrawalProof: new bytes(WITHDRAWAL_PROOF_LEN_CAPELLA),
slotProof: new bytes(SLOT_PROOF_LEN),
executionPayloadProof: new bytes(EXECPAYLOAD_PROOF_LEN),
timestampProof: new bytes(TIMESTAMP_PROOF_LEN),
timestampProof: new bytes(TIMESTAMP_PROOF_LEN_CAPELLA),
historicalSummaryBlockRootProof: new bytes(HISTSUMMARY_PROOF_LEN),
blockRootIndex: 0,
historicalSummaryIndex: 0,
Expand Down
7 changes: 7 additions & 0 deletions src/test/mocks/EigenPodManagerMock.sol
Original file line number Diff line number Diff line change
Expand Up @@ -85,4 +85,11 @@ contract EigenPodManagerMock is IEigenPodManager, Test {
function numPods() external view returns (uint256) {}

function maxPods() external view returns (uint256) {}


function denebForkTimestamp() external view returns (uint64){
return type(uint64).max;
}

function setDenebForkTimestamp(uint64 timestamp) external{}
}
Loading
Loading