Skip to content

Commit

Permalink
test: update eigen pod unit tests with new balance update functionality
Browse files Browse the repository at this point in the history
  • Loading branch information
ypatil12 committed Nov 30, 2023
1 parent 4379e38 commit 547e50a
Show file tree
Hide file tree
Showing 3 changed files with 45 additions and 56 deletions.
4 changes: 2 additions & 2 deletions src/contracts/pods/EigenPod.sol
Original file line number Diff line number Diff line change
Expand Up @@ -541,7 +541,7 @@ contract EigenPod is IEigenPod, Initializable, ReentrancyGuardUpgradeable, Eigen

uint64 currentRestakedBalanceGwei = validatorInfo.restakedBalanceGwei;
uint64 newRestakedBalanceGwei;
if (validatorBalance > MAX_RESTAKED_BALANCE_GWEI_PER_VALIDATOR) {
if (validatorEffectiveBalanceGwei > MAX_RESTAKED_BALANCE_GWEI_PER_VALIDATOR) {
newRestakedBalanceGwei = MAX_RESTAKED_BALANCE_GWEI_PER_VALIDATOR;
} else {
newRestakedBalanceGwei = validatorEffectiveBalanceGwei;
Expand Down Expand Up @@ -748,7 +748,7 @@ contract EigenPod is IEigenPod, Initializable, ReentrancyGuardUpgradeable, Eigen
}

///@notice Calculates the pubkey hash of a validator's pubkey as per SSZ spec
function _calculateValidatorPubkeyHash(bytes memory validatorPubkey) internal view returns(bytes32){
function _calculateValidatorPubkeyHash(bytes memory validatorPubkey) internal pure returns (bytes32){
require(validatorPubkey.length == 48, "EigenPod._calculateValidatorPubkeyHash must be a 48-byte BLS public key");
return sha256(abi.encodePacked(validatorPubkey, bytes16(0)));
}
Expand Down
52 changes: 25 additions & 27 deletions src/test/unit/EigenPod-PodManagerUnit.t.sol
Original file line number Diff line number Diff line change
Expand Up @@ -142,21 +142,19 @@ contract EigenPod_PodManager_UnitTests_EigenPodPausing is EigenPod_PodManager_Un
uint8 internal constant PAUSED_EIGENPODS_VERIFY_WITHDRAWAL = 4;

function test_verifyBalanceUpdates_revert_pausedEigenVerifyBalanceUpdate() public {
bytes32[][] memory validatorFieldsArray = new bytes32[][](1);
BeaconChainProofs.StateRootProof memory stateRootProofStruct;

bytes32[][] memory validatorFieldsArray = new bytes32[][](1);
bytes[] memory proofsArray = new bytes[](1);
uint40[] memory validatorIndices = new uint40[](1);

BeaconChainProofs.BalanceUpdateProof[] memory proofs = new BeaconChainProofs.BalanceUpdateProof[](1);

BeaconChainProofs.StateRootProof memory stateRootProofStruct;

// pause the contract
cheats.prank(address(pauser));
eigenPodManager.pause(2 ** PAUSED_EIGENPODS_VERIFY_BALANCE_UPDATE);

cheats.prank(address(podOwner));
cheats.expectRevert(bytes("EigenPod.onlyWhenNotPaused: index is paused in EigenPodManager"));
eigenPod.verifyBalanceUpdates(0, validatorIndices, stateRootProofStruct, proofs, validatorFieldsArray);
eigenPod.verifyBalanceUpdates(0, validatorIndices, stateRootProofStruct, proofsArray, validatorFieldsArray);
}

function test_verifyAndProcessWithdrawals_revert_pausedEigenVerifyWithdrawal() public {
Expand Down Expand Up @@ -268,7 +266,7 @@ contract EigenPod_PodManager_UnitTests_EigenPodManager is EigenPod_PodManager_Un
uint40[] validatorIndices;
bytes[] validatorFieldsProofs;
bytes32[][] validatorFields;
BeaconChainProofs.BalanceUpdateProof[] balanceUpdateProof;
// BeaconChainProofs.BalanceUpdateProof[] balanceUpdateProof;
BeaconChainProofs.WithdrawalProof[] withdrawalProofs;
bytes32[][] withdrawalFields;

Expand Down Expand Up @@ -318,14 +316,14 @@ contract EigenPod_PodManager_UnitTests_EigenPodManager is EigenPod_PodManager_Un

// Save state for checks
int256 initialShares = eigenPodManager.podOwnerShares(podOwner);
uint64 newValidatorBalance = balanceUpdateProof[0].balanceRoot.getBalanceAtIndex(validatorIndices[0]);
uint64 newValidatorBalance = validatorFields[0].getEffectiveBalanceGwei();

// Verify balance update
eigenPod.verifyBalanceUpdates(
oracleTimestamp,
validatorIndices,
stateRootProofStruct,
balanceUpdateProof,
validatorFieldsProofs,
validatorFields
);

Expand All @@ -344,7 +342,7 @@ contract EigenPod_PodManager_UnitTests_EigenPodManager is EigenPod_PodManager_Un
_verifyWithdrawalCredentials();

// Set JSON
setJSON("src/test/test-data/balanceUpdateProof_overCommitted_302913.json");
setJSON("src/test/test-data/balanceUpdateProof_notOverCommitted_302913.json");
bytes32 validatorPubkeyHash = validatorFields[0].getPubkeyHash();

// Set proof params, oracle block root, and warp time
Expand All @@ -355,14 +353,14 @@ contract EigenPod_PodManager_UnitTests_EigenPodManager is EigenPod_PodManager_Un

// Save state for checks
int256 initialShares = eigenPodManager.podOwnerShares(podOwner);
uint64 newValidatorBalance = balanceUpdateProof[0].balanceRoot.getBalanceAtIndex(validatorIndices[0]);
uint64 newValidatorBalance = validatorFields[0].getEffectiveBalanceGwei();

// Verify balance update
eigenPod.verifyBalanceUpdates(
oracleTimestamp,
validatorIndices,
stateRootProofStruct,
balanceUpdateProof,
validatorFieldsProofs,
validatorFields
);

Expand Down Expand Up @@ -575,20 +573,20 @@ contract EigenPod_PodManager_UnitTests_EigenPodManager is EigenPod_PodManager_Un
// Reset arrays
delete validatorIndices;
delete validatorFields;
delete balanceUpdateProof;
delete validatorFieldsProofs;

// Set state proof struct
stateRootProofStruct = _getStateRootProof();
// Set validator index, beacon state root, balance update proof, and validator fields

// Set validator indices
uint40 validatorIndex = uint40(getValidatorIndex());
validatorIndices.push(validatorIndex);

// Set validatorFields array
// Set validatorFieldsArray
validatorFields.push(getValidatorFields());

// Set balance update proof
balanceUpdateProof.push(_getBalanceUpdateProof());
// Set validator fields proof
validatorFieldsProofs.push(abi.encodePacked(getBalanceUpdateProof())); // Validator fields are proven here
}

function _setWithdrawalProofParams() internal {
Expand All @@ -614,15 +612,15 @@ contract EigenPod_PodManager_UnitTests_EigenPodManager is EigenPod_PodManager_Un
withdrawalProofs.push(_getWithdrawalProof());
}

function _getBalanceUpdateProof() internal returns (BeaconChainProofs.BalanceUpdateProof memory) {
bytes32 balanceRoot = getBalanceRoot();
BeaconChainProofs.BalanceUpdateProof memory proofs = BeaconChainProofs.BalanceUpdateProof(
abi.encodePacked(getValidatorBalanceProof()),
abi.encodePacked(getWithdrawalCredentialProof()), //technically this is to verify validator pubkey in the validator fields, but the WC proof is effectively the same so we use it here again.
balanceRoot
);
return proofs;
}
// function _getBalanceUpdateProof() internal returns (BeaconChainProofs.BalanceUpdateProof memory) {
// bytes32 balanceRoot = getBalanceRoot();
// BeaconChainProofs.BalanceUpdateProof memory proofs = BeaconChainProofs.BalanceUpdateProof(
// abi.encodePacked(getValidatorBalanceProof()),
// abi.encodePacked(getWithdrawalCredentialProof()), //technically this is to verify validator pubkey in the validator fields, but the WC proof is effectively the same so we use it here again.
// balanceRoot
// );
// return proofs;
// }

/// @notice this function just generates a valid proof so that we can test other functionalities of the withdrawal flow
function _getWithdrawalProof() internal returns (BeaconChainProofs.WithdrawalProof memory) {
Expand Down
45 changes: 18 additions & 27 deletions src/test/unit/EigenPodUnit.t.sol
Original file line number Diff line number Diff line change
Expand Up @@ -521,7 +521,7 @@ contract EigenPodUnitTests_VerifyBalanceUpdateTests is EigenPodHarnessSetup, Pro
uint64 oracleTimestamp;
uint40 validatorIndex;
bytes32 beaconStateRoot;
BeaconChainProofs.BalanceUpdateProof balanceUpdateProof;
bytes validatorFieldsProof;
bytes32[] validatorFields;

function testFuzz_revert_oracleTimestampStale(uint64 oracleFuzzTimestamp, uint64 mostRecentBalanceUpdateTimestamp) public {
Expand All @@ -531,7 +531,7 @@ contract EigenPodUnitTests_VerifyBalanceUpdateTests is EigenPodHarnessSetup, Pro

// Get validator fields and balance update root
validatorFields = getValidatorFields();
BeaconChainProofs.BalanceUpdateProof memory proof = _getBalanceUpdateProof();
validatorFieldsProof = abi.encodePacked(getBalanceUpdateProof());

// Balance update reversion
cheats.expectRevert(
Expand All @@ -541,7 +541,7 @@ contract EigenPodUnitTests_VerifyBalanceUpdateTests is EigenPodHarnessSetup, Pro
oracleFuzzTimestamp,
0,
bytes32(0),
balanceUpdateProof,
validatorFieldsProof,
validatorFields,
mostRecentBalanceUpdateTimestamp
);
Expand All @@ -565,7 +565,7 @@ contract EigenPodUnitTests_VerifyBalanceUpdateTests is EigenPodHarnessSetup, Pro
oracleTimestamp,
validatorIndex,
beaconStateRoot,
balanceUpdateProof,
validatorFieldsProof,
validatorFields,
0 // Most recent balance update timestamp set to 0
);
Expand All @@ -578,38 +578,39 @@ contract EigenPodUnitTests_VerifyBalanceUpdateTests is EigenPodHarnessSetup, Pro
*/
function test_revert_balanceUpdateAfterWithdrawableEpoch() external {
// Set Json proof
setJSON("src/test/test-data/balanceUpdateProof_overCommitted_302913.json");
setJSON("src/test/test-data/balanceUpdateProof_notOverCommitted_302913.json");

// Set proof params
_setBalanceUpdateParams();

// Set balance root and withdrawable epoch
balanceUpdateProof.balanceRoot = bytes32(uint256(0));
// Set effective balance and withdrawable epoch
validatorFields[2] = bytes32(uint256(0)); // per consensus spec, slot 2 is effective balance
validatorFields[7] = bytes32(uint256(0)); // per consensus spec, slot 7 is withdrawable epoch == 0

console.log("withdrawable epoch: ", validatorFields.getWithdrawableEpoch());
// Expect revert on balance update
cheats.expectRevert(bytes("EigenPod.verifyBalanceUpdate: validator is withdrawable but has not withdrawn"));
eigenPodHarness.verifyBalanceUpdate(oracleTimestamp, validatorIndex, beaconStateRoot, balanceUpdateProof, validatorFields, 0);
eigenPodHarness.verifyBalanceUpdate(oracleTimestamp, validatorIndex, beaconStateRoot, validatorFieldsProof, validatorFields, 0);
}

/// @notice Rest of tests assume beacon chain proofs are correct; Now we update the validator's balance

///@notice Balance of validator is > 32e9
///@notice Balance of validator is >= 32e9
function test_positiveSharesDelta() public {
// Set JSON
setJSON("src/test/test-data/balanceUpdateProof_overCommitted_302913.json");
setJSON("src/test/test-data/balanceUpdateProof_notOverCommitted_302913.json");

// Set proof params
_setBalanceUpdateParams();

// Verify balance update
vm.expectEmit(true, true, true, true);
emit ValidatorBalanceUpdated(validatorIndex, oracleTimestamp, MAX_RESTAKED_BALANCE_GWEI_PER_VALIDATOR);
int256 sharesDeltaGwei = eigenPodHarness.verifyBalanceUpdate(
oracleTimestamp,
validatorIndex,
beaconStateRoot,
balanceUpdateProof,
validatorFieldsProof,
validatorFields,
0 // Most recent balance update timestamp set to 0
);
Expand All @@ -627,7 +628,7 @@ contract EigenPodUnitTests_VerifyBalanceUpdateTests is EigenPodHarnessSetup, Pro

// Set proof params
_setBalanceUpdateParams();
uint64 newValidatorBalance = balanceUpdateProof.balanceRoot.getBalanceAtIndex(validatorIndex);
uint64 newValidatorBalance = validatorFields.getEffectiveBalanceGwei();

// Set balance of validator to max ETH
eigenPodHarness.setValidatorRestakedBalance(validatorFields[0], MAX_RESTAKED_BALANCE_GWEI_PER_VALIDATOR);
Expand All @@ -637,7 +638,7 @@ contract EigenPodUnitTests_VerifyBalanceUpdateTests is EigenPodHarnessSetup, Pro
oracleTimestamp,
validatorIndex,
beaconStateRoot,
balanceUpdateProof,
validatorFieldsProof,
validatorFields,
0 // Most recent balance update timestamp set to 0
);
Expand All @@ -652,7 +653,7 @@ contract EigenPodUnitTests_VerifyBalanceUpdateTests is EigenPodHarnessSetup, Pro

function test_zeroSharesDelta() public {
// Set JSON
setJSON("src/test/test-data/balanceUpdateProof_overCommitted_302913.json");
setJSON("src/test/test-data/balanceUpdateProof_notOverCommitted_302913.json");

// Set proof params
_setBalanceUpdateParams();
Expand All @@ -665,7 +666,7 @@ contract EigenPodUnitTests_VerifyBalanceUpdateTests is EigenPodHarnessSetup, Pro
oracleTimestamp,
validatorIndex,
beaconStateRoot,
balanceUpdateProof,
validatorFieldsProof,
validatorFields,
0 // Most recent balance update timestamp set to 0
);
Expand All @@ -678,7 +679,7 @@ contract EigenPodUnitTests_VerifyBalanceUpdateTests is EigenPodHarnessSetup, Pro
// Set validator index, beacon state root, balance update proof, and validator fields
validatorIndex = uint40(getValidatorIndex());
beaconStateRoot = getBeaconStateRoot();
balanceUpdateProof = _getBalanceUpdateProof();
validatorFieldsProof = abi.encodePacked(getBalanceUpdateProof());
validatorFields = getValidatorFields();

// Get an oracle timestamp
Expand All @@ -688,16 +689,6 @@ contract EigenPodUnitTests_VerifyBalanceUpdateTests is EigenPodHarnessSetup, Pro
// Set validator status to active
eigenPodHarness.setValidatorStatus(validatorFields[0], IEigenPod.VALIDATOR_STATUS.ACTIVE);
}

function _getBalanceUpdateProof() internal returns (BeaconChainProofs.BalanceUpdateProof memory) {
bytes32 balanceRoot = getBalanceRoot();
BeaconChainProofs.BalanceUpdateProof memory proofs = BeaconChainProofs.BalanceUpdateProof(
abi.encodePacked(getValidatorBalanceProof()),
abi.encodePacked(getWithdrawalCredentialProof()), //technically this is to verify validator pubkey in the validator fields, but the WC proof is effectively the same so we use it here again.
balanceRoot
);
return proofs;
}
}

contract EigenPodUnitTests_WithdrawalTests is EigenPodHarnessSetup, ProofParsing, IEigenPodEvents {
Expand Down

0 comments on commit 547e50a

Please sign in to comment.