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

feat(contracts): parse validator indexes as arrays from solidity #120

Merged
merged 2 commits into from
Jul 11, 2024
Merged
Changes from 1 commit
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
Next Next commit
feat: parse validator indexes as arrays from solidity
merklefruit committed Jul 5, 2024

Verified

This commit was signed with the committer’s verified signature.
myii Imran Iqbal
commit d9c722ab776e0b83446b74f3282ec4680dca0bb4
74 changes: 69 additions & 5 deletions bolt-contracts/script/RegisterValidators.s.sol
Original file line number Diff line number Diff line change
@@ -10,12 +10,19 @@ contract RegisterValidators is Script {
uint64[] public validatorIndexes;
address public registryAddress = 0xdF11D829eeC4C192774F3Ec171D822f6Cb4C14d9;

using StringToUintArrayLib for string;

function run() public {
signerKey = vm.envUint("PRIVATE_KEY");
string[] memory indexStrings = vm.envString("VALIDATOR_INDEXES", ",");
string memory rpc = vm.envString("RPC_ADDR");
vm.startBroadcast(signerKey);

string memory validatorIndexesEnv = vm.envString("VALIDATOR_INDEXES");
uint256[] memory indexes = StringToUintArrayLib.fromStr(validatorIndexesEnv);
for (uint256 i = 0; i < indexes.length; i++) {
validatorIndexes.push(uint64(indexes[i]));
}
merklefruit marked this conversation as resolved.
Show resolved Hide resolved

console.log("Bolt registry address:", registryAddress);
BoltRegistry registry = BoltRegistry(registryAddress);

@@ -33,10 +40,6 @@ contract RegisterValidators is Script {
revert("Insufficient balance");
}

for (uint256 i = 0; i < indexStrings.length; i++) {
validatorIndexes.push(uint64(vm.parseUint(indexStrings[i])));
}

// Register with minimal collateral
registry.register{value: registry.MINIMUM_COLLATERAL()}(
validatorIndexes,
@@ -47,3 +50,64 @@ contract RegisterValidators is Script {
vm.stopBroadcast();
}
}

library StringToUintArrayLib {
// Maximum number of validators parsed in a single function call
uint256 constant MAX_VALIDATORS = 256;

function fromStr(string memory s) internal pure returns (uint256[] memory) {
bytes memory strBytes = bytes(s);
uint256[] memory vec = new uint256[](MAX_VALIDATORS); // Initial allocation, will resize later
uint256 vecIndex = 0;
uint256 tempNum;
bool parsingRange = false;
uint256 rangeStart;

for (uint256 i = 0; i < strBytes.length; i++) {
if (strBytes[i] == ',') {
if (parsingRange) {
// Handle end of range
for (uint256 j = rangeStart; j <= tempNum; j++) {
vec[vecIndex] = j;
vecIndex++;
}
parsingRange = false;
} else {
// Handle single number
vec[vecIndex] = tempNum;
vecIndex++;
}
tempNum = 0;
} else if (strBytes[i] == '.') {
if (i + 1 < strBytes.length && strBytes[i + 1] == '.') {
// Handle start of range
parsingRange = true;
rangeStart = tempNum;
tempNum = 0;
i++; // Skip next dot
}
} else if (strBytes[i] >= '0' && strBytes[i] <= '9') {
tempNum = tempNum * 10 + (uint8(strBytes[i]) - 48); // Convert ASCII to integer
}
}

// Handle the last part after the final comma (or single number/range end)
if (parsingRange) {
for (uint256 j = rangeStart; j <= tempNum; j++) {
vec[vecIndex] = j;
vecIndex++;
}
} else {
vec[vecIndex] = tempNum;
vecIndex++;
}

// Resize array to actual size
uint256[] memory result = new uint256[](vecIndex);
for (uint256 i = 0; i < vecIndex; i++) {
result[i] = vec[i];
}

return result;
}
merklefruit marked this conversation as resolved.
Show resolved Hide resolved
}
82 changes: 82 additions & 0 deletions bolt-contracts/test/StringToUintArrayLib.t.sol
Original file line number Diff line number Diff line change
@@ -0,0 +1,82 @@
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;

import "forge-std/Test.sol";
import "../script/RegisterValidators.s.sol";

contract StringToUintArrayTest is Test {

function setUp() public {}

function testParseValidatorIndexes1() public pure {
uint256[] memory indexes = StringToUintArrayLib.fromStr("1,2,3,4");
uint256[4] memory expected;
expected[0] = 1;
expected[1] = 2;
expected[2] = 3;
expected[3] = 4;

assertEq(indexes.length, expected.length);
for (uint256 i = 0; i < indexes.length; i++) {
assertEq(indexes[i], expected[i]);
}
}

function testParseValidatorIndexes2() public pure {
uint256[] memory indexes = StringToUintArrayLib.fromStr("1..4");
uint256[4] memory expected;
expected[0] = 1;
expected[1] = 2;
expected[2] = 3;
expected[3] = 4;

assertEq(indexes.length, expected.length);
for (uint256 i = 0; i < indexes.length; i++) {
assertEq(indexes[i], expected[i]);
}
}

function testParseValidatorIndexes3() public pure {
uint256[] memory indexes = StringToUintArrayLib.fromStr("1..4,6..8");
uint256[7] memory expected;
expected[0] = 1;
expected[1] = 2;
expected[2] = 3;
expected[3] = 4;
expected[4] = 6;
expected[5] = 7;
expected[6] = 8;

assertEq(indexes.length, expected.length);
for (uint256 i = 0; i < indexes.length; i++) {
assertEq(indexes[i], expected[i]);
}
}

function testParseValidatorIndexes4() public pure {
uint256[] memory indexes = StringToUintArrayLib.fromStr("1,2..4,6..8");
uint256[7] memory expected;
expected[0] = 1;
expected[1] = 2;
expected[2] = 3;
expected[3] = 4;
expected[4] = 6;
expected[5] = 7;
expected[6] = 8;

assertEq(indexes.length, expected.length);
for (uint256 i = 0; i < indexes.length; i++) {
assertEq(indexes[i], expected[i]);
}
}

function testParse100Indexes() public pure {
string memory input = "1..100";

uint256[] memory indexes = StringToUintArrayLib.fromStr(input);
assertEq(indexes.length, 100);
for (uint256 i = 0; i < indexes.length; i++) {
assertEq(indexes[i], i + 1);
}
}
}