Skip to content

Commit 8679ebb

Browse files
committed
feat: add hardcoded fork timestamp; tests pass for deneb container
1 parent b03e6fe commit 8679ebb

File tree

5 files changed

+40
-11
lines changed

5 files changed

+40
-11
lines changed

src/contracts/libraries/BeaconChainProofs.sol

Lines changed: 27 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -28,7 +28,8 @@ library BeaconChainProofs {
2828
/// | HEIGHT: VALIDATOR_TREE_HEIGHT
2929
/// individual validators
3030
uint256 internal constant BEACON_BLOCK_HEADER_TREE_HEIGHT = 3;
31-
uint256 internal constant BEACON_STATE_TREE_HEIGHT = 6;
31+
uint256 internal constant DENEB_BEACON_STATE_TREE_HEIGHT = 5;
32+
uint256 internal constant PECTRA_BEACON_STATE_TREE_HEIGHT = 6;
3233
uint256 internal constant BALANCE_TREE_HEIGHT = 38;
3334
uint256 internal constant VALIDATOR_TREE_HEIGHT = 40;
3435

@@ -134,17 +135,20 @@ library BeaconChainProofs {
134135
/// @param validatorFieldsProof a merkle proof of inclusion of `validatorFields` under `beaconStateRoot`
135136
/// @param validatorIndex the validator's unique index
136137
function verifyValidatorFields(
138+
uint64 proofTimestamp,
137139
bytes32 beaconStateRoot,
138140
bytes32[] calldata validatorFields,
139141
bytes calldata validatorFieldsProof,
140142
uint40 validatorIndex
141143
) internal view {
142144
require(validatorFields.length == VALIDATOR_FIELDS_LENGTH, InvalidValidatorFieldsLength());
143145

146+
uint256 beaconStateTreeHeight = getBeaconStateTreeHeight(proofTimestamp);
147+
144148
/// Note: the reason we use `VALIDATOR_TREE_HEIGHT + 1` here is because the merklization process for
145149
/// this container includes hashing the root of the validator tree with the length of the validator list
146150
require(
147-
validatorFieldsProof.length == 32 * ((VALIDATOR_TREE_HEIGHT + 1) + BEACON_STATE_TREE_HEIGHT),
151+
validatorFieldsProof.length == 32 * ((VALIDATOR_TREE_HEIGHT + 1) + beaconStateTreeHeight),
148152
InvalidProofLength()
149153
);
150154

@@ -185,10 +189,15 @@ library BeaconChainProofs {
185189
/// against the same balance container root.
186190
/// @param beaconBlockRoot merkle root of the beacon block
187191
/// @param proof a beacon balance container root and merkle proof of its inclusion under `beaconBlockRoot`
188-
function verifyBalanceContainer(bytes32 beaconBlockRoot, BalanceContainerProof calldata proof) internal view {
192+
function verifyBalanceContainer(
193+
uint64 proofTimestamp,
194+
bytes32 beaconBlockRoot,
195+
BalanceContainerProof calldata proof
196+
) internal view {
197+
uint256 beaconStateTreeHeight = getBeaconStateTreeHeight(proofTimestamp);
198+
189199
require(
190-
proof.proof.length == 32 * (BEACON_BLOCK_HEADER_TREE_HEIGHT + BEACON_STATE_TREE_HEIGHT),
191-
InvalidProofLength()
200+
proof.proof.length == 32 * (BEACON_BLOCK_HEADER_TREE_HEIGHT + beaconStateTreeHeight), InvalidProofLength()
192201
);
193202

194203
/// This proof combines two proofs, so its index accounts for the relative position of leaves in two trees:
@@ -197,7 +206,7 @@ library BeaconChainProofs {
197206
/// -- beaconStateRoot
198207
/// | HEIGHT: BEACON_STATE_TREE_HEIGHT
199208
/// ---- balancesContainerRoot
200-
uint256 index = (STATE_ROOT_INDEX << (BEACON_STATE_TREE_HEIGHT)) | BALANCE_CONTAINER_INDEX;
209+
uint256 index = (STATE_ROOT_INDEX << (beaconStateTreeHeight)) | BALANCE_CONTAINER_INDEX;
201210

202211
require(
203212
Merkle.verifyInclusionSha256({
@@ -312,4 +321,16 @@ library BeaconChainProofs {
312321
) internal pure returns (uint64) {
313322
return Endian.fromLittleEndianUint64(validatorFields[VALIDATOR_EXIT_EPOCH_INDEX]);
314323
}
324+
325+
/// @notice The timestamp of the Pectra hard fork - this is updated on a per-network basis
326+
uint64 public constant PECTRA_FORK_TIMESTAMP = 1_739_352_768;
327+
328+
/// @dev We check if the proofTimestamp is <= pectraForkTimestamp because a `proofTimestamp` at the `pectraForkTimestamp`
329+
/// is considered to be Pre-Pectra given the EIP-4788 oracle returns the parent block.
330+
function getBeaconStateTreeHeight(
331+
uint64 proofTimestamp
332+
) internal pure returns (uint256) {
333+
return
334+
proofTimestamp <= PECTRA_FORK_TIMESTAMP ? DENEB_BEACON_STATE_TREE_HEIGHT : PECTRA_BEACON_STATE_TREE_HEIGHT;
335+
}
315336
}

src/contracts/pods/EigenPod.sol

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -159,6 +159,7 @@ contract EigenPod is Initializable, ReentrancyGuardUpgradeable, EigenPodPausingC
159159

160160
// Verify `balanceContainerProof` against `beaconBlockRoot`
161161
BeaconChainProofs.verifyBalanceContainer({
162+
proofTimestamp: checkpointTimestamp,
162163
beaconBlockRoot: checkpoint.beaconBlockRoot,
163164
proof: balanceContainerProof
164165
});
@@ -254,6 +255,7 @@ contract EigenPod is Initializable, ReentrancyGuardUpgradeable, EigenPodPausingC
254255
for (uint256 i = 0; i < validatorIndices.length; i++) {
255256
// forgefmt: disable-next-item
256257
totalAmountToBeRestakedWei += _verifyWithdrawalCredentials(
258+
beaconTimestamp,
257259
stateRootProof.beaconStateRoot,
258260
validatorIndices[i],
259261
validatorFieldsProofs[i],
@@ -341,6 +343,7 @@ contract EigenPod is Initializable, ReentrancyGuardUpgradeable, EigenPodPausingC
341343

342344
// Verify Validator container proof against `beaconStateRoot`
343345
BeaconChainProofs.verifyValidatorFields({
346+
proofTimestamp: beaconTimestamp,
344347
beaconStateRoot: stateRootProof.beaconStateRoot,
345348
validatorFields: proof.validatorFields,
346349
validatorFieldsProof: proof.proof,
@@ -419,6 +422,7 @@ contract EigenPod is Initializable, ReentrancyGuardUpgradeable, EigenPodPausingC
419422
* @param validatorFields are the fields of the "Validator Container", refer to consensus specs
420423
*/
421424
function _verifyWithdrawalCredentials(
425+
uint64 beaconTimestamp,
422426
bytes32 beaconStateRoot,
423427
uint40 validatorIndex,
424428
bytes calldata validatorFieldsProof,
@@ -484,6 +488,7 @@ contract EigenPod is Initializable, ReentrancyGuardUpgradeable, EigenPodPausingC
484488

485489
// Verify passed-in validatorFields against verified beaconStateRoot:
486490
BeaconChainProofs.verifyValidatorFields({
491+
proofTimestamp: beaconTimestamp,
487492
beaconStateRoot: beaconStateRoot,
488493
validatorFields: validatorFields,
489494
validatorFieldsProof: validatorFieldsProof,

src/test/harnesses/EigenPodHarness.sol

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -25,12 +25,14 @@ contract EigenPodHarness is EigenPod {
2525
}
2626

2727
function verifyWithdrawalCredentials(
28+
uint64 beaconTimestamp,
2829
bytes32 beaconStateRoot,
2930
uint40 validatorIndex,
3031
bytes calldata validatorFieldsProof,
3132
bytes32[] calldata validatorFields
3233
) public returns (uint256) {
3334
return _verifyWithdrawalCredentials(
35+
beaconTimestamp,
3436
beaconStateRoot,
3537
validatorIndex,
3638
validatorFieldsProof,

src/test/integration/mocks/BeaconChainMock.t.sol

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -68,10 +68,10 @@ contract BeaconChainMock is Logger {
6868

6969
uint immutable BLOCKROOT_PROOF_LEN = 32 * BeaconChainProofs.BEACON_BLOCK_HEADER_TREE_HEIGHT;
7070
uint immutable VAL_FIELDS_PROOF_LEN = 32 * (
71-
(BeaconChainProofs.VALIDATOR_TREE_HEIGHT + 1) + BeaconChainProofs.BEACON_STATE_TREE_HEIGHT
71+
(BeaconChainProofs.VALIDATOR_TREE_HEIGHT + 1) + BeaconChainProofs.DENEB_BEACON_STATE_TREE_HEIGHT
7272
);
7373
uint immutable BALANCE_CONTAINER_PROOF_LEN = 32 * (
74-
BeaconChainProofs.BEACON_BLOCK_HEADER_TREE_HEIGHT + BeaconChainProofs.BEACON_STATE_TREE_HEIGHT
74+
BeaconChainProofs.BEACON_BLOCK_HEADER_TREE_HEIGHT + BeaconChainProofs.DENEB_BEACON_STATE_TREE_HEIGHT
7575
);
7676
uint immutable BALANCE_PROOF_LEN = 32 * (BeaconChainProofs.BALANCE_TREE_HEIGHT + 1);
7777

@@ -406,7 +406,7 @@ contract BeaconChainMock is Logger {
406406
// Build merkle tree for BeaconState
407407
bytes32 beaconStateRoot = _buildMerkleTree({
408408
leaves: _getBeaconStateLeaves(validatorsRoot, balanceContainerRoot),
409-
treeHeight: BeaconChainProofs.BEACON_STATE_TREE_HEIGHT,
409+
treeHeight: BeaconChainProofs.DENEB_BEACON_STATE_TREE_HEIGHT,
410410
tree: trees[curTimestamp].stateTree
411411
});
412412
// console.log("-- beacon state root", beaconStateRoot);
@@ -592,7 +592,7 @@ contract BeaconChainMock is Logger {
592592

593593
uint totalHeight = BALANCE_CONTAINER_PROOF_LEN / 32;
594594
uint depth = 0;
595-
for (uint i = 0; i < BeaconChainProofs.BEACON_STATE_TREE_HEIGHT; i++) {
595+
for (uint i = 0; i < BeaconChainProofs.DENEB_BEACON_STATE_TREE_HEIGHT; i++) {
596596
bytes32 sibling = trees[curTimestamp].stateTree.siblings[curNode];
597597

598598
// proof[j] = sibling;
@@ -658,7 +658,7 @@ contract BeaconChainMock is Logger {
658658
// Validator container root -> beacon state root
659659
for (
660660
uint j = depth;
661-
j < 1 + BeaconChainProofs.VALIDATOR_TREE_HEIGHT + BeaconChainProofs.BEACON_STATE_TREE_HEIGHT;
661+
j < 1 + BeaconChainProofs.VALIDATOR_TREE_HEIGHT + BeaconChainProofs.DENEB_BEACON_STATE_TREE_HEIGHT;
662662
j++
663663
) {
664664
bytes32 sibling = trees[curTimestamp].stateTree.siblings[curNode];

src/test/unit/EigenPodUnit.t.sol

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1783,6 +1783,7 @@ contract EigenPodUnitTests_proofParsingTests is EigenPodHarnessSetup, ProofParsi
17831783
oracleTimestamp = uint64(block.timestamp);
17841784

17851785
eigenPodHarness.verifyWithdrawalCredentials(
1786+
oracleTimestamp,
17861787
beaconStateRoot,
17871788
validatorIndex,
17881789
validatorFieldsProof,

0 commit comments

Comments
 (0)