Skip to content
Open
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
37 changes: 31 additions & 6 deletions script/AddKeyperSet.gnosh.s.sol
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,10 @@ import {KeyBroadcastContract} from "../src/common/KeyBroadcastContract.sol";
import {EonKeyPublish} from "../src/common/EonKeyPublish.sol";

error ActivationDeltaTooLow();
error EmptyKeyperSet();
error ThresholdTooLow();
error ThresholdExceedsKeyperSetSize(uint256 threshold, uint256 keyperSetSize);
error DuplicateKeyper(address keyper);
error UnexpectedKeyperSet(
uint256 index,
address expectedKeyperSet,
Expand All @@ -20,13 +23,16 @@ contract AddKeyperSet is Script {
uint256 deployerPrivateKey = vm.envUint("PRIVATE_KEY");
address deployerAddress = vm.addr(deployerPrivateKey);
console.log("deployer:", deployerAddress);
vm.startBroadcast(deployerPrivateKey);

uint256 activationDelta = vm.envOr("ACTIVATION_DELTA", uint256(1));
if (activationDelta < 1) {
revert ActivationDeltaTooLow();
}

address[] memory keypers = vm.envAddress("KEYPER_ADDRESSES", ",");
uint256 threshold = vm.envUint("THRESHOLD");
_validateKeyperConfig(keypers, threshold);

address keyperSetManagerAddress = vm.envAddress(
"KEYPERSETMANAGER_ADDRESS"
);
Expand All @@ -41,11 +47,7 @@ contract AddKeyperSet is Script {
keyBroadcastContractAddress
);

address[] memory keypers = vm.envAddress("KEYPER_ADDRESSES", ",");
uint256 threshold = vm.envUint("THRESHOLD");
if (threshold > keypers.length) {
revert ThresholdExceedsKeyperSetSize(threshold, keypers.length);
}
vm.startBroadcast(deployerPrivateKey);

uint64 keyperSetIndex = keyperSetManager.getNumKeyperSets();
KeyperSet keyperSet = new KeyperSet();
Expand Down Expand Up @@ -79,4 +81,27 @@ contract AddKeyperSet is Script {

vm.stopBroadcast();
}

function _validateKeyperConfig(
address[] memory keypers,
uint256 threshold
) internal pure {
if (keypers.length == 0) {
revert EmptyKeyperSet();
}
if (threshold == 0) {
revert ThresholdTooLow();
}
if (threshold > keypers.length) {
revert ThresholdExceedsKeyperSetSize(threshold, keypers.length);
}

for (uint256 i = 0; i < keypers.length; i++) {
for (uint256 j = i + 1; j < keypers.length; j++) {
if (keypers[i] == keypers[j]) {
revert DuplicateKeyper(keypers[i]);
}
}
}
}
}
37 changes: 31 additions & 6 deletions script/AddKeyperSet.s.sol
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,10 @@ import {KeyBroadcastContract} from "../src/common/KeyBroadcastContract.sol";
import {EonKeyPublish} from "../src/common/EonKeyPublish.sol";

error ActivationDeltaTooLow();
error EmptyKeyperSet();
error ThresholdTooLow();
error ThresholdExceedsKeyperSetSize(uint256 threshold, uint256 keyperSetSize);
error DuplicateKeyper(address keyper);
error UnexpectedKeyperSet(
uint256 index,
address expectedKeyperSet,
Expand All @@ -20,13 +23,16 @@ contract AddKeyperSet is Script {
uint256 deployerPrivateKey = vm.envUint("PRIVATE_KEY");
address deployerAddress = vm.addr(deployerPrivateKey);
console.log("deployer:", deployerAddress);
vm.startBroadcast(deployerPrivateKey);

uint256 activationDelta = vm.envOr("ACTIVATION_DELTA", uint256(1));
if (activationDelta < 1) {
revert ActivationDeltaTooLow();
}

address[] memory keypers = vm.envAddress("KEYPER_ADDRESSES", ",");
uint256 threshold = vm.envUint("THRESHOLD");
_validateKeyperConfig(keypers, threshold);

address keyperSetManagerAddress = vm.envAddress(
"KEYPERSETMANAGER_ADDRESS"
);
Expand All @@ -41,11 +47,7 @@ contract AddKeyperSet is Script {
keyBroadcastContractAddress
);

address[] memory keypers = vm.envAddress("KEYPER_ADDRESSES", ",");
uint256 threshold = vm.envUint("THRESHOLD");
if (threshold > keypers.length) {
revert ThresholdExceedsKeyperSetSize(threshold, keypers.length);
}
vm.startBroadcast(deployerPrivateKey);

uint64 keyperSetIndex = keyperSetManager.getNumKeyperSets();
KeyperSet keyperSet = new KeyperSet();
Expand Down Expand Up @@ -79,4 +81,27 @@ contract AddKeyperSet is Script {

vm.stopBroadcast();
}

function _validateKeyperConfig(
address[] memory keypers,
uint256 threshold
) internal pure {
if (keypers.length == 0) {
revert EmptyKeyperSet();
}
if (threshold == 0) {
revert ThresholdTooLow();
}
if (threshold > keypers.length) {
revert ThresholdExceedsKeyperSetSize(threshold, keypers.length);
}

for (uint256 i = 0; i < keypers.length; i++) {
for (uint256 j = i + 1; j < keypers.length; j++) {
if (keypers[i] == keypers[j]) {
revert DuplicateKeyper(keypers[i]);
}
}
}
}
}
122 changes: 122 additions & 0 deletions test/AddKeyperSet.t.sol
Original file line number Diff line number Diff line change
@@ -0,0 +1,122 @@
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.22;

import "forge-std/Test.sol";
import {
ActivationDeltaTooLow,
AddKeyperSet,
DuplicateKeyper,
EmptyKeyperSet,
ThresholdExceedsKeyperSetSize,
ThresholdTooLow
} from "../script/AddKeyperSet.s.sol";

contract AddKeyperSetHarness is AddKeyperSet {
function validateKeyperConfig(
address[] memory keypers,
uint256 threshold
) external pure {
_validateKeyperConfig(keypers, threshold);
}
}

contract AddKeyperSetTest is Test {
AddKeyperSetHarness internal addKeyperSet;

function setUp() public {
addKeyperSet = new AddKeyperSetHarness();
}

function testRejectsEmptyKeyperSet() public {
address[] memory keypers = new address[](0);

vm.expectRevert(EmptyKeyperSet.selector);
addKeyperSet.validateKeyperConfig(keypers, 1);
}

function testRejectsZeroThreshold() public {
address[] memory keypers = _keypers(1);

vm.expectRevert(ThresholdTooLow.selector);
addKeyperSet.validateKeyperConfig(keypers, 0);
}

function testRejectsThresholdAboveKeyperSetSize() public {
address[] memory keypers = _keypers(2);

vm.expectRevert(
abi.encodeWithSelector(
ThresholdExceedsKeyperSetSize.selector,
3,
keypers.length
)
);
addKeyperSet.validateKeyperConfig(keypers, 3);
}

function testRejectsDuplicateKeyper() public {
address[] memory keypers = _keypers(3);
keypers[2] = keypers[0];

vm.expectRevert(
abi.encodeWithSelector(DuplicateKeyper.selector, keypers[0])
);
addKeyperSet.validateKeyperConfig(keypers, 2);
}

function testAcceptsSingleKeyperWithThresholdOne() public view {
address[] memory keypers = _keypers(1);

addKeyperSet.validateKeyperConfig(keypers, 1);
}

function testAcceptsThresholdEqualToKeyperSetSize() public view {
address[] memory keypers = _keypers(3);

addKeyperSet.validateKeyperConfig(keypers, keypers.length);
}

function testAcceptsThresholdBelowSimpleMajority() public view {
address[] memory keypers = _keypers(3);

addKeyperSet.validateKeyperConfig(keypers, 1);
}

function testRunRejectsInvalidActivationDeltaBeforeBroadcastSetup() public {

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

this test is failing

vm.setEnv("PRIVATE_KEY", "1");
vm.setEnv("ACTIVATION_DELTA", "0");
vm.setEnv("KEYPER_ADDRESSES", "not-an-address");

vm.expectRevert(ActivationDeltaTooLow.selector);
addKeyperSet.run();
}

function testRunRejectsInvalidKeyperConfigBeforeBroadcastSetup() public {
vm.setEnv("PRIVATE_KEY", "1");
vm.setEnv("ACTIVATION_DELTA", "1");
vm.setEnv("KEYPERSETMANAGER_ADDRESS", "not-an-address");
vm.setEnv(
"KEYPER_ADDRESSES",
"0x0000000000000000000000000000000000000001"
);
vm.setEnv("THRESHOLD", "2");

vm.expectRevert(
abi.encodeWithSelector(
ThresholdExceedsKeyperSetSize.selector,
2,
1
)
);
addKeyperSet.run();
}

function _keypers(
uint256 count
) internal pure returns (address[] memory keypers) {
keypers = new address[](count);
for (uint256 i = 0; i < count; i++) {
keypers[i] = address(uint160(i + 1));
}
}
}