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
84 changes: 62 additions & 22 deletions contracts/script/e2e/CheckSignature.s.sol
Original file line number Diff line number Diff line change
Expand Up @@ -33,17 +33,13 @@ contract CheckSignature is Script {
}

struct OperatorData {
Operator operator1;
Operator operator2;
Operator operator3;
Operator[] operators;
address[] operatorAddresses;
}

struct SignatureData {
bytes32 messageHash;
BN254.G1Point s1;
BN254.G1Point s2;
BN254.G1Point s3;
BN254.G1Point[] signatures;
BN254.G1Point sigma;
}

Expand All @@ -52,7 +48,6 @@ contract CheckSignature is Script {
uint32 blockNumber;
}

// TODO: does not support dynamic operator counts
function run() external {
ContractAddresses memory contracts = ContractAddresses({
registryCoordinator: vm.envAddress("REGISTRY_COORDINATOR_ADDRESS"),
Expand All @@ -65,29 +60,32 @@ contract CheckSignature is Script {
blockNumber: 0 // Will be set later
});

// Read operator keys from files
OperatorData memory operatorData;
operatorData.operator1 = _readOperatorFromFile("testacc1", config.operatorKeysDir);
operatorData.operator2 = _readOperatorFromFile("testacc2", config.operatorKeysDir);
operatorData.operator3 = _readOperatorFromFile("testacc3", config.operatorKeysDir);
// Read operator keys from files dynamically
OperatorData memory operatorData = _readOperators(config.operatorKeysDir);

// Create a message to sign
SignatureData memory sigData;
sigData.messageHash = bytes32(uint256(0x1234));

// Sign the message with BLS
sigData.s1 = _signBLSMessage(operatorData.operator1, sigData.messageHash);
sigData.s2 = _signBLSMessage(operatorData.operator2, sigData.messageHash);
sigData.s3 = _signBLSMessage(operatorData.operator3, sigData.messageHash);

sigData.sigma = sigData.s1.plus(sigData.s2).plus(sigData.s3);
// Sign the message with BLS for all operators
sigData.signatures = new BN254.G1Point[](operatorData.operators.length);
sigData.sigma = BN254.G1Point(0, 0);

for (uint256 i = 0; i < operatorData.operators.length; i++) {
sigData.signatures[i] = _signBLSMessage(operatorData.operators[i], sigData.messageHash);
if (i == 0) {
sigData.sigma = sigData.signatures[i];
} else {
sigData.sigma = sigData.sigma.plus(sigData.signatures[i]);
}
}

vm.createSelectFork(vm.envString("L1_RPC_URL"));

operatorData.operatorAddresses = new address[](3);
operatorData.operatorAddresses[0] = operatorData.operator1.operator;
operatorData.operatorAddresses[1] = operatorData.operator2.operator;
operatorData.operatorAddresses[2] = operatorData.operator3.operator;
operatorData.operatorAddresses = new address[](operatorData.operators.length);
for (uint256 i = 0; i < operatorData.operators.length; i++) {
operatorData.operatorAddresses[i] = operatorData.operators[i].operator;
}

config.blockNumber = uint32(block.number - 1);

Expand Down Expand Up @@ -133,6 +131,48 @@ contract CheckSignature is Script {
console.log("Total stake for quorum 0:", quorumStakeTotals.totalStakeForQuorum[0]);
}

function _readOperators(string memory operatorKeysDir) internal view returns (OperatorData memory) {
// Get the list of operator names from environment variable or config
string memory operatorNames = vm.envOr("OPERATOR_NAMES", string("testacc1,testacc2,testacc3"));

// Count operators by counting commas + 1
uint256 operatorCount = 1;
bytes memory namesBytes = bytes(operatorNames);
for (uint256 i = 0; i < namesBytes.length; i++) {
if (namesBytes[i] == bytes1(uint8(44))) {
// comma
operatorCount++;
}
}

OperatorData memory operatorData;
operatorData.operators = new Operator[](operatorCount);

// Parse operator names and read their data
uint256 currentIndex = 0;
uint256 startIndex = 0;

for (uint256 i = 0; i <= namesBytes.length; i++) {
if (i == namesBytes.length || namesBytes[i] == bytes1(uint8(44))) {
// Extract operator name
uint256 nameLength = i - startIndex;
bytes memory nameBytes = new bytes(nameLength);
for (uint256 j = 0; j < nameLength; j++) {
nameBytes[j] = namesBytes[startIndex + j];
}
string memory operatorName = string(nameBytes);

// Read operator data
operatorData.operators[currentIndex] = _readOperatorFromFile(operatorName, operatorKeysDir);

currentIndex++;
startIndex = i + 1;
}
}

return operatorData;
}

function _readOperatorFromFile(string memory operatorName, string memory operatorKeysDir)
internal
view
Expand Down
55 changes: 55 additions & 0 deletions e2e/DYNAMIC_OPERATORS.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,55 @@
# Dynamic Operator Support for E2E Tests

This document describes how to use the dynamic operator support in the e2e tests.

## Overview

The e2e test suite now supports running with a configurable number of operators instead of the previously hardcoded 3 operators.

## Usage

### Using Default Operators (3 operators)

By default, the tests will run with 3 operators (testacc1, testacc2, testacc3):

```bash
cd e2e/docker
./scripts/run-check-signatures.sh
```

### Using Custom Number of Operators

To run with a different set of operators, set the `OPERATOR_NAMES` environment variable:

```bash
# Run with 2 operators
export OPERATOR_NAMES="testacc1,testacc2"
./scripts/run-check-signatures.sh

# Run with 5 operators (assuming testacc4 and testacc5 are configured)
export OPERATOR_NAMES="testacc1,testacc2,testacc3,testacc4,testacc5"
./scripts/run-check-signatures.sh
```

## Configuration Requirements

For each operator name specified in `OPERATOR_NAMES`, the following files must exist in the operator keys directory:

1. `{operatorName}.private.bls.key.json` - Private BLS key
2. `{operatorName}.bls.key.json` - Public BLS key
3. `{operatorName}.ecdsa.key.json` - ECDSA key with operator address

Additionally, each operator should be registered in the AVS system before running the signature check.

## Implementation Details

The dynamic operator support is implemented in:
- `contracts/script/e2e/CheckSignature.s.sol` - Main script that reads operator configuration
- `e2e/docker/scripts/run-check-signatures.sh` - Shell script that exports the OPERATOR_NAMES variable

The script automatically:
1. Reads the comma-separated list of operator names from the environment
2. Loads the corresponding keys for each operator
3. Generates BLS signatures for all operators
4. Aggregates the signatures
5. Verifies the aggregated signature on L2
3 changes: 3 additions & 0 deletions e2e/docker/scripts/run-check-signatures.sh
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,9 @@ export L2_RPC_URL
export PRIVATE_KEY=$DEPLOYER_KEY
export OPERATOR_KEYS_DIR="$NODES_DIR/operator_keys/"

# Support dynamic operator names - can be overridden via environment
export OPERATOR_NAMES="${OPERATOR_NAMES:-testacc1,testacc2,testacc3}"

# Run the Forge script with required environment variables
cd "$FOUNDRY_ROOT_DIR"
echo "Running check signatures..."
Expand Down