Deployment and Configuration
⚠️ Before you continue: Please read the Disclaimer.
By using this site, software, or contracts, you acknowledge that you have read and accepted it.
Run Model
IMPORTANT: The event listener may perform a hard System.exit(1) (e.g. upon lost web socket connection).
In that case, the container should schedule a restart (Docker: restart: unless-stopped).
This is by design: It is much harder to recover a lost ws connection than to schedule a clean restart.
The oracle is implemented in a way, that it will pick-up the unprocessed events.
Setup
If you like to set up a key decryption oracle from scratch:
Once (Initial Setup)
-
Owner EOA: You need an off-chain private key and address that functions as the owner of the on-chain contract and can deploy the on-chain oracle contract.
-
Oracle EOA: You need an off-chain private key and address that functions as the signer of the fulfillments performed by the off-chain oracle.
-
Deploy the on-chain oracle procy contract (
src/main/solidity/KeyDecryptionOracle.sol) using the off-chain oracle address (signer of the fulfillments) in the constructor. Note the address of the on-chain oracle contract. -
Generate a private-public-key pair for the “key decryption” using the script
scripts/generate-keys.shin the parent project. This will create a directorysecretsand the following filessecrets/oracle.crt.pem secrets/oracle.p12 secrets/oracle.pw secrets/oracle-public-key.der secrets/oracle-public-key.pemNote: This is the private-public-key that is used for encryption and decryption of the key provided by the decryption oracle. You reference these files in the application.properties. Put them in a safe place and make them available to the off-chain oracle. See
docker-compose.ymlandapplication.properties. -
Adapt the
application.properties(see below)- Add private key of the off-chain oracle EOA (needed to sign the
fulfill*). Setethereum.sender.privateKey - Add the address of the off-chain oracle EOA (needed to sign the
fulfill*). Setethereum.sender.address - Add the address of the on-chain oracle contract (needed to for the event listening to the
request*). Setethereum.keydecryptionoracle.contract - If the
secretsfolder is mounted in thedocker-compose.ymlyou do not adjust the setting oforacle.keystore.*.
- Add private key of the off-chain oracle EOA (needed to sign the
-
Adapt the
docker-compose.yml(see below)- Adjust
PATH-TO-CONFIGin/PATH-TO-CONFIG/secrets:/app/secrets:roto the location of the generatedsecrets(needs to be secure). - Adjust
PATH-TO-CONFIGin/PATH-TO-CONFIG/state:/app/state:rwto the location where the off-chain oracle can persist state. - Adjust
PATH-TO-CONFIGin/PATH-TO-CONFIG/config:/app/config:roto the location where theapplication.propiertiesresides (needs to be secure, because it contains the private key for EOA).
- Adjust
Start and Stop
For the folder containing the docker-compose.yml (see below):
- Use
docker-compose up -dto start the off-chain oracle. - Use
docker-compose downto stop the off-chain oracle. - Use
docker-compose log -fto view the logs in the console.
Configuration: Application Properties
Configure the off-chain oracle via command-line or application.properties:
Important: if you use listenerMode to be stream then the rpcUrl must use wss:///.
# RPC URL (use either ws or http - example: wss://eth-mainnet.g.alchemy.com/v2/... or https://eth-mainnet.g.alchemy.com/v2/...). If streaming, use ws.
ethereum.rpcUrl = <url>
# Numeric chain id (ethereum mainnet: 1, ethereum testnet: 11155111, polygon mainnet: 137, polygon testnet: 80002, local (besu/anvil): 1337)
ethereum.chainId = <id>
# Poll interval if the listener is http (not used in ws-mode)
ethereum.listener.pollIntervalMs = 5000
# Poll chunk size (maximum number of blocks that are requested in a single call to the RPC)
ethereum.listener.pollingChunkSizeBlocks = 500
# ReST Service port
server.port=8080
# Chain Event Listener (required)
ethereum.listener.enabled=true
ethereum.tx.enabled=true
# Sender of the fulfill-ment of request-s
ethereum.sender.privateKey = <private key hex 0x...>
# Address of sender (this needs to be passed to the on-chain oracles constructor)
ethereum.sender.address = <address hex of the sender 0x..>
#
# Listener Configuration
#
# Listener mode: may be poll (polling of ethGetLogs), steam-http (ehtLogFlowable on http (will poll)), stream-ws (ethLogFlowable on ws), stream (sames as stream-ws). Note: stream: cheap with low latency on small number of events; poll: usually cheaper with high number of events.
ethereum.calldecryptionoracle.listenerMode = stream
# Address of the on chain CallDecryptionOracle (to listen to)
ethereum.calldecryptionoracle.contract = <address hex of the on-chain oracle 0x..>
# Block to start listening, given that no state file is found
ethereum.calldecryptionoracle.fromBlock = latest
# finalityBlocks: block to wait (and to check finality thereafter). default 0 = process immediately; >0 waits N confirmations
ethereum.calldecryptionoracle.finalityBlocks = 3
# replayBlocks: block to replay upon restart. default 0 = no replay; if 0, uses finalityBlocks
ethereum.calldecryptionoracle.replayBlocks = 0
# finalityPollIntervalMs: head polling interval; only calls eth_blockNumber while pending queue is non-empty
ethereum.calldecryptionoracle.finalityPollIntervalMs = 5000
# reconciliationIntervalMs: if > 0 and streaming is used, an optional reconciliation polling is done periodically
ethereum.calldecryptionoracle.reconciliationIntervalMs = 90000
# reconciliationChunkSizeBlocks: Poll chunk size (maximum number of blocks that are requested in a single call to the RPC)
ethereum.calldecryptionoracle.reconciliationChunkSizeBlocks = 2000
#
# EIP-1559 fee policy (values in wei)
#
# Tip high enough to get picked quickly under load.
# Suggestion: ethereum 20000000 (0.02 gwei), polygon 40000000000 (40 gwei)
ethereum.gas.min-priority-fee-wei=40000000000
# Cap high so base-fee spikes don't stall you. We pay (base + priority) and not this cap
# Suggestions:
# tight..: ethereum 1000000000 (1 gwei), polygon 500000000000 (500 gwei)
# relaxed: ethereum 5000000000 (5 gwei), polygon 1000000000000 (1000 gwei)
ethereum.gas.max-fee-wei=1000000000000
# Gas limits (units) - do NOT affect speed, just OOG safety
# Suggestion: 1000000
ethereum.gas.limit-default=1000000
#
# keystore for the decryption oracle
#
oracle.keystore.type=PKCS12
oracle.keystore.path=secrets/oracle.p12
oracle.keystore.password-file=secrets/oracle.pw
oracle.key.alias=oracle-rsa
# optional if different from keystore password:
# oracle.key.password-file=/run/secrets/oracle.pw
Remarks
Gas
Ensure that off-chain oracle is funded and that the ethereum.gas.* parameters are set appropriately.
Fees
The off-chain oracle (ethereum.sender.privateKey) needs to be funded to pay the gas for a fulfillment.
The on-chain oracle receives the fee at (ethereum.keydecryptionoracle.contract).
The oracle implementation should allow to withdraw the fees. The reference implementation provides a method that transfers the accumulated on-chain fees to the off-chain oracle sender.
Private Key for the Decryption Oracle
The decryption oracle needs a public/private key for the generation/decryption of the encrypted key. You can generate the required files using the script generate-keys.sh.
Docker image
A docker image is available at
docker.io/finmath/finmath-decryption-oracle-encrypted-hashed-execution:2.5.5
Configuration: Docker Compose
Example docker-compose.yml
Given that the secrets are in /PATH-TO-CONFIG/secrets and the application.properties is in /PATH-TO-CONFIG/config
a sample docker compose yml may look as follows:
name: decryption-oracle
services:
key_decryption_oracle:
image: docker.io/finmath/finmath-decryption-oracle-encrypted-hashed-execution:2.5.5
container_name: key-decryption-oracle
restart: unless-stopped
ports:
- "8080:8080"
environment:
SPRING_CONFIG_LOCATION: "file:/app/config/application.properties"
volumes:
- /PATH-TO-CONFIG/secrets:/app/secrets:ro
- /PATH-TO-CONFIG/state:/app/state:rw
- /PATH-TO-CONFIG/config:/app/config:ro
