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

Batch provision node #55

Open
wants to merge 36 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
36 commits
Select commit Hold shift + click to select a range
f6aa636
feat: boilerplate code after brainstorming
ksatyarth2 Aug 23, 2024
52c3742
2 step POC
bxmmm1 Aug 23, 2024
6c2364d
Delete mainnet-contracts/src/PufferWithdrawalManager.sol
bxmmm1 Aug 23, 2024
d896595
feat: optimize & add fuzz tests
ksatyarth2 Aug 23, 2024
c7b6d36
use uin256 constant instead of uint8
bxmmm1 Aug 26, 2024
c1c7e26
forge fmt
bxmmm1 Aug 26, 2024
2ddbe06
Rename WIthdrawalManager.sol to WithdrawalManager.sol
bxmmm1 Aug 26, 2024
e83e13c
Create puffer.json
bxmmm1 Aug 27, 2024
36fd710
add back the file to fix the tests
bxmmm1 Aug 27, 2024
184f476
Add ACL, interfaces, upgradability (#42)
ksatyarth2 Sep 3, 2024
9808266
Merge branch 'master' of github.com:PufferFinance/puffer-contracts in…
bxmmm1 Sep 3, 2024
dc8c352
Merge branch '2step-poc' of github.com:PufferFinance/puffer-contracts…
bxmmm1 Sep 3, 2024
44f72bd
update .cursorignore and .gitignore
bxmmm1 Sep 3, 2024
ce4eb27
update wording, tests
bxmmm1 Sep 3, 2024
ef0b6fa
Merge branch 'master' of github.com:PufferFinance/puffer-contracts in…
bxmmm1 Sep 5, 2024
1e35f1d
tests cleanup, add deployment script and accessmanager script
bxmmm1 Sep 5, 2024
c2f8b7b
add mainnet fork happy case test
bxmmm1 Sep 5, 2024
74c343b
comment out the calldata
bxmmm1 Sep 5, 2024
ab21b22
add more tests
bxmmm1 Sep 5, 2024
2e70a5b
update test
bxmmm1 Sep 5, 2024
87426a9
cosmetic updates
bxmmm1 Sep 6, 2024
03561c5
add happy and sad case in the mainnet fork test
bxmmm1 Sep 6, 2024
710b047
update access manager setup
bxmmm1 Sep 6, 2024
5ea929f
update the deployment script
bxmmm1 Sep 6, 2024
b32d5fa
update action version
bxmmm1 Sep 7, 2024
03d7fc1
solc update
bxmmm1 Sep 7, 2024
8834c90
custom error require statements
bxmmm1 Sep 7, 2024
4e26073
Print selectors to job summary
bxmmm1 Sep 7, 2024
2bad84c
ci fix
bxmmm1 Sep 7, 2024
93e64c4
codespell gha
bxmmm1 Sep 7, 2024
b1eefe5
spelling fix
bxmmm1 Sep 7, 2024
3e58f2b
update l2 toml
bxmmm1 Sep 7, 2024
ae7bfb9
add solhint rules
bxmmm1 Sep 8, 2024
4382356
batch provision node
bxmmm1 Sep 8, 2024
6bc9515
update gitignore
bxmmm1 Sep 9, 2024
2bfac6b
Merge branch 'master' of github.com:PufferFinance/puffer-contracts in…
bxmmm1 Nov 26, 2024
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
44 changes: 44 additions & 0 deletions mainnet-contracts/src/PufferProtocol.sol
Original file line number Diff line number Diff line change
Expand Up @@ -247,6 +247,50 @@
});
}

/**
* @dev Restricted to Puffer Paymaster
*/
function batchProvisionNode(
bytes[][] calldata guardianEnclaveSignatures,
bytes[] calldata validatorSignatures,
bytes32 depositRootHash
) external {
if (depositRootHash != BEACON_DEPOSIT_CONTRACT.get_deposit_root()) {
revert InvalidDepositRootHash();

Check warning on line 259 in mainnet-contracts/src/PufferProtocol.sol

View check run for this annotation

Codecov / codecov/patch

mainnet-contracts/src/PufferProtocol.sol#L259

Added line #L259 was not covered by tests
}

ProtocolStorage storage $ = _getPufferProtocolStorage();

uint256 numValidators = validatorSignatures.length;

for (uint256 i = 0; i < numValidators; ++i) {
(bytes32 moduleName, uint256 index) = getNextValidatorToProvision();

// Increment next validator to be provisioned index, panics if there is no validator for provisioning
$.nextToBeProvisioned[moduleName] = index + 1;
unchecked {
// Increment module selection index
++$.moduleSelectIndex;
}

_validateSignaturesAndProvisionValidator({
$: $,
moduleName: moduleName,
index: index,
guardianEnclaveSignatures: guardianEnclaveSignatures[i],
validatorSignature: validatorSignatures[i]
});

// Update Node Operator info
address node = $.validators[moduleName][index].node;
--$.nodeOperatorInfo[node].pendingValidatorCount;
++$.nodeOperatorInfo[node].activeValidatorCount;

// Mark the validator as active
$.validators[moduleName][index].status = Status.ACTIVE;
}
}

/**
* @inheritdoc IPufferProtocol
* @dev Restricted to Puffer Paymaster
Expand Down
106 changes: 106 additions & 0 deletions mainnet-contracts/test/unit/PufferProtocol.t.sol
Original file line number Diff line number Diff line change
Expand Up @@ -1442,6 +1442,70 @@ contract PufferProtocolTest is UnitTestHelper {
assertEq(bobBalanceBefore, pufferVault.balanceOf(bob), "bob balance");
}

function test_batchProvisionNode() public {
// Register multiple validators
_registerValidatorKey(bytes32("alice"), PUFFER_MODULE_0);
_registerValidatorKey(bytes32("bob"), PUFFER_MODULE_0);
_registerValidatorKey(bytes32("charlie"), PUFFER_MODULE_0);
_registerValidatorKey(bytes32("david"), PUFFER_MODULE_0);
_registerValidatorKey(bytes32("emma"), PUFFER_MODULE_0);

// Get validator signatures
bytes[] memory validatorSignatures = new bytes[](5);
validatorSignatures[0] = _validatorSignature();
validatorSignatures[1] = _validatorSignature();
validatorSignatures[2] = _validatorSignature();
validatorSignatures[3] = _validatorSignature();
validatorSignatures[4] = _validatorSignature();

// Get guardian enclave signatures
bytes[][] memory guardianEnclaveSignatures = new bytes[][](5);
guardianEnclaveSignatures[0] =
_getGuardianSignaturesForValidator(_getPubKey(bytes32("alice")), PUFFER_MODULE_0, 0);
guardianEnclaveSignatures[1] =
_getGuardianSignaturesForValidator(_getPubKey(bytes32("bob")), PUFFER_MODULE_0, 1);
guardianEnclaveSignatures[2] =
_getGuardianSignaturesForValidator(_getPubKey(bytes32("charlie")), PUFFER_MODULE_0, 2);
guardianEnclaveSignatures[3] =
_getGuardianSignaturesForValidator(_getPubKey(bytes32("david")), PUFFER_MODULE_0, 3);
guardianEnclaveSignatures[4] =
_getGuardianSignaturesForValidator(_getPubKey(bytes32("emma")), PUFFER_MODULE_0, 4);

// Batch provision the validators
vm.expectEmit(true, true, true, true);
emit SuccessfullyProvisioned(_getPubKey(bytes32("alice")), 0, PUFFER_MODULE_0);
vm.expectEmit(true, true, true, true);
emit SuccessfullyProvisioned(_getPubKey(bytes32("bob")), 1, PUFFER_MODULE_0);
vm.expectEmit(true, true, true, true);
emit SuccessfullyProvisioned(_getPubKey(bytes32("charlie")), 2, PUFFER_MODULE_0);
vm.expectEmit(true, true, true, true);
emit SuccessfullyProvisioned(_getPubKey(bytes32("david")), 3, PUFFER_MODULE_0);
vm.expectEmit(true, true, true, true);
emit SuccessfullyProvisioned(_getPubKey(bytes32("emma")), 4, PUFFER_MODULE_0);
pufferProtocol.batchProvisionNode(guardianEnclaveSignatures, validatorSignatures, DEFAULT_DEPOSIT_ROOT);

// Check that the validators are marked as active
Validator memory aliceValidator = pufferProtocol.getValidatorInfo(PUFFER_MODULE_0, 0);
Validator memory bobValidator = pufferProtocol.getValidatorInfo(PUFFER_MODULE_0, 1);
Validator memory charlieValidator = pufferProtocol.getValidatorInfo(PUFFER_MODULE_0, 2);
Validator memory davidValidator = pufferProtocol.getValidatorInfo(PUFFER_MODULE_0, 3);
Validator memory emmaValidator = pufferProtocol.getValidatorInfo(PUFFER_MODULE_0, 4);

assertTrue(aliceValidator.status == Status.ACTIVE, "Alice's validator should be active");
assertTrue(bobValidator.status == Status.ACTIVE, "Bob's validator should be active");
assertTrue(charlieValidator.status == Status.ACTIVE, "Charlie's validator should be active");
assertTrue(davidValidator.status == Status.ACTIVE, "David's validator should be active");
assertTrue(emmaValidator.status == Status.ACTIVE, "Emma's validator should be active");

// Check that the node operator info is updated correctly
assertEq(
pufferProtocol.getNodeInfo(address(this)).activeValidatorCount, 5, "Active validator count should be 5"
);
assertEq(
pufferProtocol.getNodeInfo(address(this)).pendingValidatorCount, 0, "Pending validator count should be 0"
);
}

function _executeFullWithdrawal(StoppedValidatorInfo memory validatorInfo) internal {
StoppedValidatorInfo[] memory stopInfos = new StoppedValidatorInfo[](1);
stopInfos[0] = validatorInfo;
Expand Down Expand Up @@ -1857,6 +1921,48 @@ contract PufferProtocolTest is UnitTestHelper {
assertEq(validatorTicket.balanceOf(bob), 50 ether, "bob got the VT");
}

function _getGuardianSignaturesForValidator(bytes memory pubKey, bytes32 moduleName, uint256 pendingIdx)
internal
view
returns (bytes[] memory)
{
Validator memory validator = pufferProtocol.getValidatorInfo(moduleName, pendingIdx);
// If there is no module return empty byte array
if (validator.module == address(0)) {
return new bytes[](0);
}
bytes memory withdrawalCredentials = pufferProtocol.getWithdrawalCredentials(validator.module);

bytes32 digest = LibGuardianMessages._getBeaconDepositMessageToBeSigned(
pendingIdx,
pubKey,
_validatorSignature(),
withdrawalCredentials,
pufferProtocol.getDepositDataRoot({
pubKey: pubKey,
signature: _validatorSignature(),
withdrawalCredentials: withdrawalCredentials
})
);

(uint8 v, bytes32 r, bytes32 s) = vm.sign(guardian1SKEnclave, digest);
bytes memory signature1 = abi.encodePacked(r, s, v); // note the order here is different from line above.

(v, r, s) = vm.sign(guardian2SKEnclave, digest);
(v, r, s) = vm.sign(guardian3SKEnclave, digest);
bytes memory signature2 = abi.encodePacked(r, s, v); // note the order here is different from line above.

(v, r, s) = vm.sign(guardian3SKEnclave, digest);
bytes memory signature3 = abi.encodePacked(r, s, v); // note the order here is different from line above.

bytes[] memory guardianSignatures = new bytes[](3);
guardianSignatures[0] = signature1;
guardianSignatures[1] = signature2;
guardianSignatures[2] = signature3;

return guardianSignatures;
}

function _getGuardianSignatures(bytes memory pubKey) internal view returns (bytes[] memory) {
(bytes32 moduleName, uint256 pendingIdx) = pufferProtocol.getNextValidatorToProvision();
Validator memory validator = pufferProtocol.getValidatorInfo(moduleName, pendingIdx);
Expand Down
Loading