@@ -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}
0 commit comments