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: worker for selfregistersqrttaskmiddleware #11

Merged
merged 5 commits into from
Dec 21, 2024
Merged
Show file tree
Hide file tree
Changes from 2 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
35 changes: 35 additions & 0 deletions src/examples/sqrt-task-network/worker/Dockerfile
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
FROM python:3.11-slim

WORKDIR /app

# Install system dependencies
RUN apt-get update && \
apt-get install -y gcc python3-dev && \
rm -rf /var/lib/apt/lists/*

# Copy requirements first to leverage Docker cache
COPY requirements.txt .
RUN pip install --no-cache-dir -r requirements.txt

# Copy worker code and ABI
COPY worker.py .
COPY abi.json .

# Environment variables will be provided at runtime
ENV WEB3_URL=https://ethereum-holesky-rpc.publicnode.com
ENV VALIDATOR_PRIVATE_KEY=""

# Add restart script
RUN echo '#!/bin/sh\n' \
'while true; do\n' \
' python worker.py start \\\n' \
' --validator-private-key "$VALIDATOR_PRIVATE_KEY" \\\n' \
' --web3-url "$WEB3_URL"\n' \
' status=$?\n' \
' echo "Process exited with status $status, restarting in 5 seconds..."\n' \
' sleep 5\n' \
'done\n' > /app/start.sh

RUN chmod +x /app/start.sh

CMD ["/app/start.sh"]
71 changes: 71 additions & 0 deletions src/examples/sqrt-task-network/worker/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,71 @@
# Sqrt Task Network Worker

This is a worker implementation for the Sqrt Task Network example. The worker listens for new tasks, computes square roots, and submits the results back to the blockchain.

## Prerequisites

- Docker
- Python 3.11+
- Access to an Holesky Ethereum node
alrxy marked this conversation as resolved.
Show resolved Hide resolved
- Private keys for validator and operator accounts
1kresh marked this conversation as resolved.
Show resolved Hide resolved
- Some Holesky ETH in the operator and validator account for gas fees
1kresh marked this conversation as resolved.
Show resolved Hide resolved
alrxy marked this conversation as resolved.
Show resolved Hide resolved
- Registration in `OperatorRegistry` and opt-in in `NetworkOptInService` to the network (middleware address: 0x18586B8cb86b59EF3F44BC915Ef92C83B6BAfd75)
1kresh marked this conversation as resolved.
Show resolved Hide resolved
alrxy marked this conversation as resolved.
Show resolved Hide resolved

## Usage

### Registering as an Operator

1. Install dependencies:

```
pip install -r requirements.txt
```

2. Register as an operator (one-time setup):
```bash
python worker.py register \
--validator-private-key YOUR_VALIDATOR_PRIVATE_KEY \
--operator-private-key YOUR_OPERATOR_PRIVATE_KEY \
--vault-address YOUR_VAULT_ADDRESS
```

3. (Optional) Submit an incorrect answer for a specific task:
```bash
python worker.py submit-incorrect-answer \
--validator-private-key YOUR_VALIDATOR_PRIVATE_KEY \
--task-id TASK_ID
```

### Running the Worker

1. Build the Docker image:
```bash
docker build -t sqrt-worker .
```

2. Run the container:
```bash
docker run -e VALIDATOR_PRIVATE_KEY=your_private_key -e WEB3_URL=your_web3_url sqrt-worker
```

## Configuration Options

- `--validator-private-key`: Private key for signing task results
- `--operator-private-key`: Private key for transaction submission (only needed for registration)
- `--web3-url`: RPC endpoint URL (default: Holesky public node)
- `--vault-address`: Operator-specific vault address (default: 0x0)

## How It Works

1. The worker monitors the blockchain for new sqrt calculation tasks
2. When a task is found, it computes the square root using Python's math.isqrt
3. The result is signed using EIP-712 and submitted back to the contract
4. The worker maintains a block cache to resume from the last processed block

## Error Handling

The worker includes automatic retry logic and will:
- Reconnect on network issues
- Skip already completed tasks
- Log all operations for debugging
- Restart automatically when run in Docker
1 change: 1 addition & 0 deletions src/examples/sqrt-task-network/worker/abi.json
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
[{"type":"constructor","inputs":[{"name":"networkRegistry","type":"address","internalType":"address"},{"name":"slashingWindow","type":"uint48","internalType":"uint48"},{"name":"operatorRegistry","type":"address","internalType":"address"},{"name":"vaultRegistry","type":"address","internalType":"address"},{"name":"operatorNetOptin","type":"address","internalType":"address"},{"name":"reader","type":"address","internalType":"address"},{"name":"owner","type":"address","internalType":"address"}],"stateMutability":"nonpayable"},{"type":"fallback","stateMutability":"nonpayable"},{"type":"function","name":"BaseMiddleware_VERSION","inputs":[],"outputs":[{"name":"","type":"uint64","internalType":"uint64"}],"stateMutability":"view"},{"type":"function","name":"ECDSASig_VERSION","inputs":[],"outputs":[{"name":"","type":"uint64","internalType":"uint64"}],"stateMutability":"view"},{"type":"function","name":"KeyManager256_VERSION","inputs":[],"outputs":[{"name":"","type":"uint64","internalType":"uint64"}],"stateMutability":"view"},{"type":"function","name":"MAX_OPERATORS","inputs":[],"outputs":[{"name":"","type":"uint256","internalType":"uint256"}],"stateMutability":"view"},{"type":"function","name":"MAX_OPERATOR_VAULTS","inputs":[],"outputs":[{"name":"","type":"uint256","internalType":"uint256"}],"stateMutability":"view"},{"type":"function","name":"MAX_SHARED_VAULTS","inputs":[],"outputs":[{"name":"","type":"uint256","internalType":"uint256"}],"stateMutability":"view"},{"type":"function","name":"OwnableAccessManager_VERSION","inputs":[],"outputs":[{"name":"","type":"uint64","internalType":"uint64"}],"stateMutability":"view"},{"type":"function","name":"SelfRegisterOperators_VERSION","inputs":[],"outputs":[{"name":"","type":"uint64","internalType":"uint64"}],"stateMutability":"view"},{"type":"function","name":"SharedVaults_VERSION","inputs":[],"outputs":[{"name":"","type":"uint64","internalType":"uint64"}],"stateMutability":"view"},{"type":"function","name":"TimestampCapture_VERSION","inputs":[],"outputs":[{"name":"","type":"uint64","internalType":"uint64"}],"stateMutability":"view"},{"type":"function","name":"completeTask","inputs":[{"name":"taskIndex","type":"uint256","internalType":"uint256"},{"name":"answer","type":"uint256","internalType":"uint256"},{"name":"signature","type":"bytes","internalType":"bytes"},{"name":"stakeHints","type":"bytes[]","internalType":"bytes[]"},{"name":"slashHints","type":"bytes[]","internalType":"bytes[]"}],"outputs":[{"name":"isValidAnswer","type":"bool","internalType":"bool"}],"stateMutability":"nonpayable"},{"type":"function","name":"createTask","inputs":[{"name":"value","type":"uint256","internalType":"uint256"},{"name":"operator","type":"address","internalType":"address"}],"outputs":[{"name":"taskIndex","type":"uint256","internalType":"uint256"}],"stateMutability":"nonpayable"},{"type":"function","name":"eip712Domain","inputs":[],"outputs":[{"name":"fields","type":"bytes1","internalType":"bytes1"},{"name":"name","type":"string","internalType":"string"},{"name":"version","type":"string","internalType":"string"},{"name":"chainId","type":"uint256","internalType":"uint256"},{"name":"verifyingContract","type":"address","internalType":"address"},{"name":"salt","type":"bytes32","internalType":"bytes32"},{"name":"extensions","type":"uint256[]","internalType":"uint256[]"}],"stateMutability":"view"},{"type":"function","name":"executeSlash","inputs":[{"name":"epochStart","type":"uint48","internalType":"uint48"},{"name":"vault","type":"address","internalType":"address"},{"name":"subnetwork","type":"bytes32","internalType":"bytes32"},{"name":"operator","type":"address","internalType":"address"},{"name":"amount","type":"uint256","internalType":"uint256"},{"name":"hints","type":"bytes","internalType":"bytes"}],"outputs":[],"stateMutability":"nonpayable"},{"type":"function","name":"getCaptureTimestamp","inputs":[],"outputs":[{"name":"timestamp","type":"uint48","internalType":"uint48"}],"stateMutability":"view"},{"type":"function","name":"keyWasActiveAt","inputs":[{"name":"timestamp","type":"uint48","internalType":"uint48"},{"name":"key_","type":"bytes","internalType":"bytes"}],"outputs":[{"name":"","type":"bool","internalType":"bool"}],"stateMutability":"view"},{"type":"function","name":"nonces","inputs":[{"name":"operator","type":"address","internalType":"address"}],"outputs":[{"name":"","type":"uint256","internalType":"uint256"}],"stateMutability":"view"},{"type":"function","name":"operatorByKey","inputs":[{"name":"key","type":"bytes","internalType":"bytes"}],"outputs":[{"name":"","type":"address","internalType":"address"}],"stateMutability":"view"},{"type":"function","name":"operatorKey","inputs":[{"name":"operator","type":"address","internalType":"address"}],"outputs":[{"name":"","type":"bytes","internalType":"bytes"}],"stateMutability":"view"},{"type":"function","name":"owner","inputs":[],"outputs":[{"name":"","type":"address","internalType":"address"}],"stateMutability":"view"},{"type":"function","name":"pauseOperator","inputs":[],"outputs":[],"stateMutability":"nonpayable"},{"type":"function","name":"pauseOperator","inputs":[{"name":"operator","type":"address","internalType":"address"},{"name":"signature","type":"bytes","internalType":"bytes"}],"outputs":[],"stateMutability":"nonpayable"},{"type":"function","name":"pauseOperatorVault","inputs":[{"name":"vault","type":"address","internalType":"address"}],"outputs":[],"stateMutability":"nonpayable"},{"type":"function","name":"pauseOperatorVault","inputs":[{"name":"operator","type":"address","internalType":"address"},{"name":"vault","type":"address","internalType":"address"},{"name":"signature","type":"bytes","internalType":"bytes"}],"outputs":[],"stateMutability":"nonpayable"},{"type":"function","name":"pauseSharedVault","inputs":[{"name":"sharedVault","type":"address","internalType":"address"}],"outputs":[],"stateMutability":"nonpayable"},{"type":"function","name":"recover","inputs":[{"name":"hash","type":"bytes32","internalType":"bytes32"},{"name":"signature","type":"bytes","internalType":"bytes"}],"outputs":[{"name":"","type":"address","internalType":"address"}],"stateMutability":"pure"},{"type":"function","name":"registerOperator","inputs":[{"name":"operator","type":"address","internalType":"address"},{"name":"key","type":"bytes","internalType":"bytes"},{"name":"vault","type":"address","internalType":"address"},{"name":"signature","type":"bytes","internalType":"bytes"},{"name":"keySignature","type":"bytes","internalType":"bytes"}],"outputs":[],"stateMutability":"nonpayable"},{"type":"function","name":"registerOperator","inputs":[{"name":"key","type":"bytes","internalType":"bytes"},{"name":"vault","type":"address","internalType":"address"},{"name":"signature","type":"bytes","internalType":"bytes"}],"outputs":[],"stateMutability":"nonpayable"},{"type":"function","name":"registerOperatorVault","inputs":[{"name":"vault","type":"address","internalType":"address"}],"outputs":[],"stateMutability":"nonpayable"},{"type":"function","name":"registerOperatorVault","inputs":[{"name":"operator","type":"address","internalType":"address"},{"name":"vault","type":"address","internalType":"address"},{"name":"signature","type":"bytes","internalType":"bytes"}],"outputs":[],"stateMutability":"nonpayable"},{"type":"function","name":"registerSharedVault","inputs":[{"name":"sharedVault","type":"address","internalType":"address"}],"outputs":[],"stateMutability":"nonpayable"},{"type":"function","name":"renounceOwnership","inputs":[],"outputs":[],"stateMutability":"nonpayable"},{"type":"function","name":"setOwner","inputs":[{"name":"owner_","type":"address","internalType":"address"}],"outputs":[],"stateMutability":"nonpayable"},{"type":"function","name":"stakeToPower","inputs":[{"name":"vault","type":"address","internalType":"address"},{"name":"stake","type":"uint256","internalType":"uint256"}],"outputs":[{"name":"power","type":"uint256","internalType":"uint256"}],"stateMutability":"pure"},{"type":"function","name":"tasks","inputs":[{"name":"","type":"uint256","internalType":"uint256"}],"outputs":[{"name":"captureTimestamp","type":"uint48","internalType":"uint48"},{"name":"value","type":"uint256","internalType":"uint256"},{"name":"operator","type":"address","internalType":"address"},{"name":"completed","type":"bool","internalType":"bool"}],"stateMutability":"view"},{"type":"function","name":"unpauseOperator","inputs":[],"outputs":[],"stateMutability":"nonpayable"},{"type":"function","name":"unpauseOperator","inputs":[{"name":"operator","type":"address","internalType":"address"},{"name":"signature","type":"bytes","internalType":"bytes"}],"outputs":[],"stateMutability":"nonpayable"},{"type":"function","name":"unpauseOperatorVault","inputs":[{"name":"vault","type":"address","internalType":"address"}],"outputs":[],"stateMutability":"nonpayable"},{"type":"function","name":"unpauseOperatorVault","inputs":[{"name":"operator","type":"address","internalType":"address"},{"name":"vault","type":"address","internalType":"address"},{"name":"signature","type":"bytes","internalType":"bytes"}],"outputs":[],"stateMutability":"nonpayable"},{"type":"function","name":"unpauseSharedVault","inputs":[{"name":"sharedVault","type":"address","internalType":"address"}],"outputs":[],"stateMutability":"nonpayable"},{"type":"function","name":"unregisterOperator","inputs":[],"outputs":[],"stateMutability":"nonpayable"},{"type":"function","name":"unregisterOperator","inputs":[{"name":"operator","type":"address","internalType":"address"},{"name":"signature","type":"bytes","internalType":"bytes"}],"outputs":[],"stateMutability":"nonpayable"},{"type":"function","name":"unregisterOperatorVault","inputs":[{"name":"operator","type":"address","internalType":"address"},{"name":"vault","type":"address","internalType":"address"},{"name":"signature","type":"bytes","internalType":"bytes"}],"outputs":[],"stateMutability":"nonpayable"},{"type":"function","name":"unregisterOperatorVault","inputs":[{"name":"vault","type":"address","internalType":"address"}],"outputs":[],"stateMutability":"nonpayable"},{"type":"function","name":"unregisterSharedVault","inputs":[{"name":"sharedVault","type":"address","internalType":"address"}],"outputs":[],"stateMutability":"nonpayable"},{"type":"function","name":"updateOperatorKey","inputs":[{"name":"operator","type":"address","internalType":"address"},{"name":"key","type":"bytes","internalType":"bytes"},{"name":"signature","type":"bytes","internalType":"bytes"},{"name":"keySignature","type":"bytes","internalType":"bytes"}],"outputs":[],"stateMutability":"nonpayable"},{"type":"function","name":"updateOperatorKey","inputs":[{"name":"key","type":"bytes","internalType":"bytes"},{"name":"signature","type":"bytes","internalType":"bytes"}],"outputs":[],"stateMutability":"nonpayable"},{"type":"event","name":"CompleteTask","inputs":[{"name":"taskIndex","type":"uint256","indexed":true,"internalType":"uint256"},{"name":"isValidAnswer","type":"bool","indexed":false,"internalType":"bool"}],"anonymous":false},{"type":"event","name":"CreateTask","inputs":[{"name":"taskIndex","type":"uint256","indexed":true,"internalType":"uint256"},{"name":"operator","type":"address","indexed":true,"internalType":"address"}],"anonymous":false},{"type":"event","name":"EIP712DomainChanged","inputs":[],"anonymous":false},{"type":"event","name":"Initialized","inputs":[{"name":"version","type":"uint64","indexed":false,"internalType":"uint64"}],"anonymous":false},{"type":"event","name":"InstantSlash","inputs":[{"name":"vault","type":"address","indexed":false,"internalType":"address"},{"name":"subnetwork","type":"bytes32","indexed":false,"internalType":"bytes32"},{"name":"amount","type":"uint256","indexed":false,"internalType":"uint256"}],"anonymous":false},{"type":"event","name":"VetoSlash","inputs":[{"name":"vault","type":"address","indexed":false,"internalType":"address"},{"name":"subnetwork","type":"bytes32","indexed":false,"internalType":"bytes32"},{"name":"index","type":"uint256","indexed":false,"internalType":"uint256"}],"anonymous":false},{"type":"error","name":"AlreadyEnabled","inputs":[]},{"type":"error","name":"AlreadyRegistered","inputs":[]},{"type":"error","name":"DuplicateKey","inputs":[]},{"type":"error","name":"ECDSAInvalidSignature","inputs":[]},{"type":"error","name":"ECDSAInvalidSignatureLength","inputs":[{"name":"length","type":"uint256","internalType":"uint256"}]},{"type":"error","name":"ECDSAInvalidSignatureS","inputs":[{"name":"s","type":"bytes32","internalType":"bytes32"}]},{"type":"error","name":"Enabled","inputs":[]},{"type":"error","name":"ImmutablePeriodNotPassed","inputs":[]},{"type":"error","name":"InactiveVaultSlash","inputs":[]},{"type":"error","name":"InvalidHints","inputs":[]},{"type":"error","name":"InvalidInitialization","inputs":[]},{"type":"error","name":"InvalidOwner","inputs":[{"name":"owner","type":"address","internalType":"address"}]},{"type":"error","name":"InvalidSignature","inputs":[]},{"type":"error","name":"MaxDisabledKeysReached","inputs":[]},{"type":"error","name":"NoSlasher","inputs":[]},{"type":"error","name":"NonVetoSlasher","inputs":[]},{"type":"error","name":"NotEnabled","inputs":[]},{"type":"error","name":"NotInitializing","inputs":[]},{"type":"error","name":"NotOperator","inputs":[]},{"type":"error","name":"NotOperatorSpecificVault","inputs":[]},{"type":"error","name":"NotOperatorVault","inputs":[]},{"type":"error","name":"NotRegistered","inputs":[]},{"type":"error","name":"NotVault","inputs":[]},{"type":"error","name":"OnlyOwnerCanCall","inputs":[{"name":"sender","type":"address","internalType":"address"}]},{"type":"error","name":"OperatorNotOptedIn","inputs":[]},{"type":"error","name":"OperatorNotRegistered","inputs":[]},{"type":"error","name":"SafeCastOverflowedUintDowncast","inputs":[{"name":"bits","type":"uint8","internalType":"uint8"},{"name":"value","type":"uint256","internalType":"uint256"}]},{"type":"error","name":"TaskCompleted","inputs":[]},{"type":"error","name":"TooManyOperatorVaults","inputs":[]},{"type":"error","name":"TooManyOperators","inputs":[]},{"type":"error","name":"TooManySharedVaults","inputs":[]},{"type":"error","name":"TooOldTimestampSlash","inputs":[]},{"type":"error","name":"UnknownSlasherType","inputs":[]},{"type":"error","name":"VaultAlreadyRegistered","inputs":[]},{"type":"error","name":"VaultEpochTooShort","inputs":[]},{"type":"error","name":"VaultNotInitialized","inputs":[]}]
3 changes: 3 additions & 0 deletions src/examples/sqrt-task-network/worker/requirements.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
web3==7.6.0
eth-account==0.13.4
click==8.1.7
Loading
Loading