diff --git a/README.md b/README.md
index 2a9b46825..df6fdfec4 100644
--- a/README.md
+++ b/README.md
@@ -15,12 +15,12 @@ There are two modules in the oracle:
### Accounting module
Accounting module updates the protocol TVL, distributes node-operator rewards, updates information about the number of exited and stuck validators and processes user withdrawal requests.
-Also Accounting module makes decision to turn on/off the bunker.
+Also Accounting module makes decision to turn on/off the bunker.
**Flow**
The oracle work is delineated by time periods called frames. Oracles finalize a report in each frame.
-The default Accounting Oracle frame length on mainnet is 225 epochs, which is 24 hours (it could be changed by DAO).
+The default Accounting Oracle frame length on mainnet is 225 epochs, which is 24 hours (it could be changed by DAO).
The frame includes these stages:
- **Waiting** - oracle starts as daemon and wakes up every 12 seconds (by default) in order to find the last finalized slot (ref slot).
@@ -67,10 +67,10 @@ Oracle needs two weeks of archived data.
| Client | Tested | Notes |
|-------------------------------------------------|--------|---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|
-| [Geth](https://geth.ethereum.org/) | | `--gcmode=archive`
`--syncmode=snap`
OR
`--gcmode=archive`
`--syncmode=full` |
+| [Geth](https://geth.ethereum.org/) | ✅ | `--gcmode=archive`
`--syncmode=snap`
OR
`--gcmode=archive`
`--syncmode=full` |
| [Nethermind](https://nethermind.io/) | | Not tested yet |
-| [Besu](https://besu.hyperledger.org/en/stable/) | | Use
`--rpc-max-logs-range=100000`
`--sync-mode=FULL`
`--data-storage-format="FOREST"`
`--pruning-enabled`
`--pruning-blocks-retained=100000`
params |
-| [Erigon](https://github.com/ledgerwatch/erigon) | | Use
`--prune=htc`
`--prune.h.before=100000`
`--prune.t.before=100000`
`--prune.c.before=100000`
params |
+| [Besu](https://besu.hyperledger.org/en/stable/) | ✅ | Use
`--rpc-max-logs-range=100000`
`--sync-mode=FULL`
`--data-storage-format="FOREST"`
`--pruning-enabled`
`--pruning-blocks-retained=100000`
params |
+| [Erigon](https://github.com/ledgerwatch/erigon) | ✅ | Use
`--prune=htc`
`--prune.h.before=100000`
`--prune.t.before=100000`
`--prune.c.before=100000`
params |
### Consensus Client Node
@@ -78,11 +78,11 @@ Also, to calculate some metrics for bunker mode Oracle needs [archive](https://e
| Client | Tested | Notes |
|---------------------------------------------------|--------|-------------------------------------------------------------------------------------------------------------------------------------------------|
-| [Lighthouse](https://lighthouse.sigmaprime.io/) | | Use `--reconstruct-historic-states` param |
-| [Lodestar](https://nethermind.io/) | | Not tested yet |
-| [Nimbus](https://besu.hyperledger.org/en/stable/) | | Not tested yet |
-| [Prysm](https://github.com/ledgerwatch/erigon) | | Use
`--grpc-max-msg-size=104857600`
`--enable-historical-state-representation=true`
`--slots-per-archive-point=1024`
params |
-| [Teku](https://docs.teku.consensys.net) | | Use
`--data-storage-mode=archive`
`--data-storage-archive-frequency=1024`
`--reconstruct-historic-states=true`
params |
+| [Lighthouse](https://lighthouse.sigmaprime.io/) | ✅ | Use `--reconstruct-historic-states` param |
+| [Lodestar](https://lodestar.chainsafe.io) | | Not tested yet |
+| [Nimbus](https://nimbus.team) | | Not tested yet |
+| [Prysm](https://github.com/prysmaticlabs/prysm) | ✅ | Use
`--grpc-max-msg-size=104857600`
`--enable-historical-state-representation=true`
`--slots-per-archive-point=1024`
params |
+| [Teku](https://docs.teku.consensys.net) | ✅ | Use
`--data-storage-mode=archive`
`--data-storage-archive-frequency=1024`
`--reconstruct-historic-states=true`
params |
### Keys API Service
@@ -150,13 +150,13 @@ Full variables list could be found [here](https://github.com/lidofinance/lido-or
Oracle could be executed once in "manual" mode. To do this setup `DAEMON` variable to 'False'.
-**Note**: Use `-it` option to run manual mode in Docker container in interactive mode.
+**Note**: Use `-it` option to run manual mode in Docker container in interactive mode.
Example `docker run -ti --env-file .env --rm lidofinance/oracle:{tag} {type}`
In this mode Oracle will build report as usual (if contracts are reportable) and before submitting transactions
Oracle will ask for manual input to send transaction.
-In manual mode all sleeps are disabled and `ALLOW_REPORTING_IN_BUNKER_MODE` is True.
+In manual mode all sleeps are disabled and `ALLOW_REPORTING_IN_BUNKER_MODE` is True.
## Env variables
@@ -166,6 +166,8 @@ In manual mode all sleeps are disabled and `ALLOW_REPORTING_IN_BUNKER_MODE` is T
| `CONSENSUS_CLIENT_URI` | URI of the Consensus Layer client | True | `http://localhost:5052` |
| `KEYS_API_URI` | URI of the Keys API | True | `http://localhost:8080` |
| `LIDO_LOCATOR_ADDRESS` | Address of the Lido contract | True | `0x1...` |
+| `CSM_ORACLE_ADDRESS` | Address of the CSFeeOracle contract | ? | `0x1...` |
+| `CSM_MODULE_ADDRESS` | Address of the CSModule contract | ? | `0x1...` |
| `MEMBER_PRIV_KEY` | Private key of the Oracle member account | False | `0x1...` |
| `MEMBER_PRIV_KEY_FILE` | A path to the file contained the private key of the Oracle member account. It takes precedence over `MEMBER_PRIV_KEY` | False | `/app/private_key` |
| `FINALIZATION_BATCH_MAX_REQUEST_COUNT` | The size of the batch to be finalized per request (The larger the batch size, the more memory of the contract is used but the fewer requests are needed) | False | `1000` |
@@ -173,6 +175,7 @@ In manual mode all sleeps are disabled and `ALLOW_REPORTING_IN_BUNKER_MODE` is T
| `DAEMON` | If False Oracle runs one cycle and ask for manual input to send report. | False | `True` |
| `TX_GAS_ADDITION` | Used to modify gas parameter that used in transaction. (gas = estimated_gas + TX_GAS_ADDITION) | False | `100000` |
| `CYCLE_SLEEP_IN_SECONDS` | The time between cycles of the oracle's activity | False | `12` |
+| `MAX_CYCLE_LIFETIME_IN_SECONDS` | The maximum time for a cycle to continue (0 = infinity) | False | `3000` |
| `SUBMIT_DATA_DELAY_IN_SLOTS` | The difference in slots between submit data transactions from Oracles. It is used to prevent simultaneous sending of transactions and, as a result, transactions revert. | False | `6` |
| `HTTP_REQUEST_TIMEOUT_EXECUTION` | Timeout for HTTP execution layer requests | False | `120` |
| `HTTP_REQUEST_TIMEOUT_CONSENSUS` | Timeout for HTTP consensus layer requests | False | `300` |
@@ -181,16 +184,17 @@ In manual mode all sleeps are disabled and `ALLOW_REPORTING_IN_BUNKER_MODE` is T
| `HTTP_REQUEST_TIMEOUT_KEYS_API` | Timeout for HTTP keys api requests | False | `120` |
| `HTTP_REQUEST_RETRY_COUNT_KEYS_API` | Total number of retries to fetch data from endpoint for keys api requests | False | `300` |
| `HTTP_REQUEST_SLEEP_BEFORE_RETRY_IN_SECONDS_KEYS_API` | The delay http provider sleeps if API is stuck for keys api | False | `300` |
+| `EVENTS_SEARCH_STEP` | Maximum length of a range for eth_getLogs method calls | False | `10000` |
| `PRIORITY_FEE_PERCENTILE` | Priority fee percentile from prev block that would be used to send tx | False | `3` |
| `MIN_PRIORITY_FEE` | Min priority fee that would be used to send tx | False | `50000000` |
| `MAX_PRIORITY_FEE` | Max priority fee that would be used to send tx | False | `100000000000` |
### Mainnet variables
-> LIDO_LOCATOR_ADDRESS=0xC1d0b3DE6792Bf6b4b37EccdcC24e45978Cfd2Eb
+> LIDO_LOCATOR_ADDRESS=0xC1d0b3DE6792Bf6b4b37EccdcC24e45978Cfd2Eb
> ALLOW_REPORTING_IN_BUNKER_MODE=False
### Goerli variables
-> LIDO_LOCATOR_ADDRESS=0x1eDf09b5023DC86737b59dE68a8130De878984f5
+> LIDO_LOCATOR_ADDRESS=0x1eDf09b5023DC86737b59dE68a8130De878984f5
> ALLOW_REPORTING_IN_BUNKER_MODE=True
### Alerts
@@ -225,26 +229,26 @@ groups:
The oracle exposes the following basic metrics:
-| Metric name | Description | Labels |
-|-----------------------------|-----------------------------------------------------------------|----------------------------------------------------------------------------------------------------|
-| build_info | Build info | version, branch, commit |
-| env_variables_info | Env variables for the app | ACCOUNT, LIDO_LOCATOR_ADDRESS, FINALIZATION_BATCH_MAX_REQUEST_COUNT, MAX_CYCLE_LIFETIME_IN_SECONDS |
-| genesis_time | Fetched genesis time from node | |
-| account_balance | Fetched account balance from EL | address |
-| slot_number | Last fetched slot number from CL | state (`head` or `finalized`) |
-| block_number | Last fetched block number from CL | state (`head` or `finalized`) |
-| functions_duration | Histogram metric with duration of each main function in the app | name, status |
-| el_requests_duration | Histogram metric with duration of each EL request | endpoint, call_method, call_to, code, domain |
-| cl_requests_duration | Histogram metric with duration of each CL request | endpoint, code, domain |
-| keys_api_requests_duration | Histogram metric with duration of each KeysAPI request | endpoint, code, domain |
-| keys_api_latest_blocknumber | Latest block number from KeysAPI metadata | |
-| transaction_count | Total count of transactions. Success or failure | status |
-| member_info | Oracle member info | is_report_member, is_submit_member, is_fast_lane |
-| member_last_report_ref_slot | Member last report ref slot | |
-| frame_current_ref_slot | Current frame ref slot | |
-| frame_deadline_slot | Current frame deadline slot | |
-| frame_prev_report_ref_slot | Previous report ref slot | |
-| contract_on_pause | Contract on pause | |
+| Metric name | Description | Labels |
+|-----------------------------|-----------------------------------------------------------------|--------------------------------------------------------------------------------------------------------------------------------------------|
+| build_info | Build info | version, branch, commit |
+| env_variables_info | Env variables for the app | ACCOUNT, LIDO_LOCATOR_ADDRESS, CSM_ORACLE_ADDRESS, CSM_MODULE_ADDRESS, FINALIZATION_BATCH_MAX_REQUEST_COUNT, MAX_CYCLE_LIFETIME_IN_SECONDS |
+| genesis_time | Fetched genesis time from node | |
+| account_balance | Fetched account balance from EL | address |
+| slot_number | Last fetched slot number from CL | state (`head` or `finalized`) |
+| block_number | Last fetched block number from CL | state (`head` or `finalized`) |
+| functions_duration | Histogram metric with duration of each main function in the app | name, status |
+| el_requests_duration | Histogram metric with duration of each EL request | endpoint, call_method, call_to, code, domain |
+| cl_requests_duration | Histogram metric with duration of each CL request | endpoint, code, domain |
+| keys_api_requests_duration | Histogram metric with duration of each KeysAPI request | endpoint, code, domain |
+| keys_api_latest_blocknumber | Latest block number from KeysAPI metadata | |
+| transaction_count | Total count of transactions. Success or failure | status |
+| member_info | Oracle member info | is_report_member, is_submit_member, is_fast_lane |
+| member_last_report_ref_slot | Member last report ref slot | |
+| frame_current_ref_slot | Current frame ref slot | |
+| frame_deadline_slot | Current frame deadline slot | |
+| frame_prev_report_ref_slot | Previous report ref slot | |
+| contract_on_pause | Contract on pause | |
Special metrics for accounting oracle:
@@ -266,6 +270,12 @@ Special metrics for ejector oracle:
| ejector_max_withdrawal_epoch | Max exit epoch between all validators in CL | |
| ejector_validators_count_to_eject | Validators count to eject | |
+Special metrics for CSM oracle:
+
+| Metric name | Description | Labels |
+|-----------------------------------|---------------------------------------------|--------|
+| TBD | TBD | |
+
# Development
Python version: 3.11
@@ -281,13 +291,25 @@ poetry install
## Startup
-Required variables
+Required variables for accounting and ejector modules
+
+```bash
+export EXECUTION_CLIENT_URI=...
+export CONSENSUS_CLIENT_URI=...
+export KEYS_API_URI=...
+export LIDO_LOCATOR_ADDRESS=...
+```
+
+Required variables for CSM module
```bash
export EXECUTION_CLIENT_URI=...
export CONSENSUS_CLIENT_URI=...
export KEYS_API_URI=...
export LIDO_LOCATOR_ADDRESS=...
+export CSM_ORACLE_ADDRESS=...
+export CSM_MODULE_ADDRESS=...
+export MAX_CYCLE_LIFETIME_IN_SECONDS=0
```
Run oracle module
@@ -300,6 +322,7 @@ Where `{module}` is one of:
- `accounting`
- `ejector`
+- `csm`
- `check`
## Tests
diff --git a/src/main.py b/src/main.py
index 284148095..934096b69 100644
--- a/src/main.py
+++ b/src/main.py
@@ -41,12 +41,17 @@ def main(module_name: OracleModule):
'module': module_name,
'ACCOUNT': variables.ACCOUNT.address if variables.ACCOUNT else 'Dry',
'LIDO_LOCATOR_ADDRESS': variables.LIDO_LOCATOR_ADDRESS,
+ 'CSM_ORACLE_ADDRESS': variables.CSM_ORACLE_ADDRESS,
+ 'CSM_MODULE_ADDRESS': variables.CSM_MODULE_ADDRESS,
+ 'FINALIZATION_BATCH_MAX_REQUEST_COUNT': variables.FINALIZATION_BATCH_MAX_REQUEST_COUNT,
'MAX_CYCLE_LIFETIME_IN_SECONDS': variables.MAX_CYCLE_LIFETIME_IN_SECONDS,
},
})
ENV_VARIABLES_INFO.info({
"ACCOUNT": str(variables.ACCOUNT.address) if variables.ACCOUNT else 'Dry',
"LIDO_LOCATOR_ADDRESS": str(variables.LIDO_LOCATOR_ADDRESS),
+ "CSM_ORACLE_ADDRESS": str(variables.CSM_ORACLE_ADDRESS),
+ "CSM_MODULE_ADDRESS": str(variables.CSM_MODULE_ADDRESS),
"FINALIZATION_BATCH_MAX_REQUEST_COUNT": str(variables.FINALIZATION_BATCH_MAX_REQUEST_COUNT),
"MAX_CYCLE_LIFETIME_IN_SECONDS": str(variables.MAX_CYCLE_LIFETIME_IN_SECONDS),
})
diff --git a/src/modules/submodules/oracle_module.py b/src/modules/submodules/oracle_module.py
index 674ede2c2..546202ef2 100644
--- a/src/modules/submodules/oracle_module.py
+++ b/src/modules/submodules/oracle_module.py
@@ -54,7 +54,6 @@ def run_as_daemon(self):
logger.info({'msg': 'Startup new cycle.'})
self.cycle_handler()
- # TODO: We need a configurable timeout for CSM, just use a variable?
@timeout(variables.MAX_CYCLE_LIFETIME_IN_SECONDS)
def cycle_handler(self):
blockstamp = self._receive_last_finalized_slot()
diff --git a/src/variables.py b/src/variables.py
index 4b5662153..c2185d7ab 100644
--- a/src/variables.py
+++ b/src/variables.py
@@ -76,7 +76,7 @@
HEALTHCHECK_SERVER_PORT = int(os.getenv('HEALTHCHECK_SERVER_PORT', 9010))
-MAX_CYCLE_LIFETIME_IN_SECONDS = int(os.getenv("MAX_CYCLE_LIFETIME_IN_SECONDS", 3000))
+MAX_CYCLE_LIFETIME_IN_SECONDS = int(os.getenv("MAX_CYCLE_LIFETIME_IN_SECONDS", 3000)) or None
def check_all_required_variables():