parent
f831e4a660
commit
8fb2db9269
File diff suppressed because it is too large
Load Diff
@ -0,0 +1,23 @@ |
|||||||
|
[package] |
||||||
|
name = "optics-base" |
||||||
|
version = "0.1.0" |
||||||
|
authors = ["James Prestwich <prestwich@clabs.co>"] |
||||||
|
edition = "2018" |
||||||
|
|
||||||
|
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html |
||||||
|
|
||||||
|
[dependencies] |
||||||
|
tokio = { version = "1.0.1", features = ["rt"] } |
||||||
|
optics-core = { path = "../optics-core" } |
||||||
|
config = "0.10" |
||||||
|
serde = "1.0.120" |
||||||
|
serde_json = { version = "1.0.61", default-features = false } |
||||||
|
|
||||||
|
ethers = { git = "https://github.com/gakonst/ethers-rs" } |
||||||
|
ethers-core = { git = "https://github.com/gakonst/ethers-rs" } |
||||||
|
ethers-providers = { git = "https://github.com/gakonst/ethers-rs" } |
||||||
|
ethers-contract = { git = "https://github.com/gakonst/ethers-rs", features = ["abigen"] } |
||||||
|
|
||||||
|
thiserror = { version = "1.0.22", default-features = false } |
||||||
|
async-trait = { version = "0.1.42", default-features = false } |
||||||
|
url = { version = "2.2.0", default-features = false } |
@ -0,0 +1,10 @@ |
|||||||
|
[home] |
||||||
|
chain = "Ethereum" |
||||||
|
http = "http://localhost:8545" |
||||||
|
address = "0x0000000000000000000000000000000000000000" |
||||||
|
|
||||||
|
[replicas] |
||||||
|
[replicas.Celo] |
||||||
|
chain = "Ethereum" |
||||||
|
address = "0x0000000000000000000000000000000000000000" |
||||||
|
ws = "wss://" |
@ -0,0 +1,347 @@ |
|||||||
|
[ |
||||||
|
{ |
||||||
|
"inputs": [ |
||||||
|
{ |
||||||
|
"internalType": "uint32", |
||||||
|
"name": "_originSLIP44", |
||||||
|
"type": "uint32" |
||||||
|
}, |
||||||
|
{ |
||||||
|
"internalType": "address", |
||||||
|
"name": "_updater", |
||||||
|
"type": "address" |
||||||
|
}, |
||||||
|
{ |
||||||
|
"internalType": "bytes32", |
||||||
|
"name": "_current", |
||||||
|
"type": "bytes32" |
||||||
|
} |
||||||
|
], |
||||||
|
"stateMutability": "payable", |
||||||
|
"type": "constructor" |
||||||
|
}, |
||||||
|
{ |
||||||
|
"anonymous": false, |
||||||
|
"inputs": [ |
||||||
|
{ |
||||||
|
"indexed": true, |
||||||
|
"internalType": "uint32", |
||||||
|
"name": "destination", |
||||||
|
"type": "uint32" |
||||||
|
}, |
||||||
|
{ |
||||||
|
"indexed": true, |
||||||
|
"internalType": "uint32", |
||||||
|
"name": "sequence", |
||||||
|
"type": "uint32" |
||||||
|
}, |
||||||
|
{ |
||||||
|
"indexed": true, |
||||||
|
"internalType": "bytes32", |
||||||
|
"name": "current", |
||||||
|
"type": "bytes32" |
||||||
|
}, |
||||||
|
{ |
||||||
|
"indexed": false, |
||||||
|
"internalType": "bytes", |
||||||
|
"name": "message", |
||||||
|
"type": "bytes" |
||||||
|
} |
||||||
|
], |
||||||
|
"name": "Dispatch", |
||||||
|
"type": "event" |
||||||
|
}, |
||||||
|
{ |
||||||
|
"anonymous": false, |
||||||
|
"inputs": [ |
||||||
|
{ |
||||||
|
"indexed": false, |
||||||
|
"internalType": "bytes32[2]", |
||||||
|
"name": "_oldRoot", |
||||||
|
"type": "bytes32[2]" |
||||||
|
}, |
||||||
|
{ |
||||||
|
"indexed": false, |
||||||
|
"internalType": "bytes32[2]", |
||||||
|
"name": "_newRoot", |
||||||
|
"type": "bytes32[2]" |
||||||
|
}, |
||||||
|
{ |
||||||
|
"indexed": false, |
||||||
|
"internalType": "bytes", |
||||||
|
"name": "_signature", |
||||||
|
"type": "bytes" |
||||||
|
}, |
||||||
|
{ |
||||||
|
"indexed": false, |
||||||
|
"internalType": "bytes", |
||||||
|
"name": "_signature2", |
||||||
|
"type": "bytes" |
||||||
|
} |
||||||
|
], |
||||||
|
"name": "DoubleUpdate", |
||||||
|
"type": "event" |
||||||
|
}, |
||||||
|
{ |
||||||
|
"anonymous": false, |
||||||
|
"inputs": [], |
||||||
|
"name": "ImproperUpdate", |
||||||
|
"type": "event" |
||||||
|
}, |
||||||
|
{ |
||||||
|
"anonymous": false, |
||||||
|
"inputs": [ |
||||||
|
{ |
||||||
|
"indexed": true, |
||||||
|
"internalType": "bytes32", |
||||||
|
"name": "_oldRoot", |
||||||
|
"type": "bytes32" |
||||||
|
}, |
||||||
|
{ |
||||||
|
"indexed": true, |
||||||
|
"internalType": "bytes32", |
||||||
|
"name": "_newRoot", |
||||||
|
"type": "bytes32" |
||||||
|
}, |
||||||
|
{ |
||||||
|
"indexed": false, |
||||||
|
"internalType": "bytes", |
||||||
|
"name": "signature", |
||||||
|
"type": "bytes" |
||||||
|
} |
||||||
|
], |
||||||
|
"name": "Update", |
||||||
|
"type": "event" |
||||||
|
}, |
||||||
|
{ |
||||||
|
"inputs": [], |
||||||
|
"name": "DOMAIN_HASH", |
||||||
|
"outputs": [ |
||||||
|
{ |
||||||
|
"internalType": "bytes32", |
||||||
|
"name": "", |
||||||
|
"type": "bytes32" |
||||||
|
} |
||||||
|
], |
||||||
|
"stateMutability": "view", |
||||||
|
"type": "function" |
||||||
|
}, |
||||||
|
{ |
||||||
|
"inputs": [], |
||||||
|
"name": "current", |
||||||
|
"outputs": [ |
||||||
|
{ |
||||||
|
"internalType": "bytes32", |
||||||
|
"name": "", |
||||||
|
"type": "bytes32" |
||||||
|
} |
||||||
|
], |
||||||
|
"stateMutability": "view", |
||||||
|
"type": "function" |
||||||
|
}, |
||||||
|
{ |
||||||
|
"inputs": [ |
||||||
|
{ |
||||||
|
"internalType": "bytes32[2]", |
||||||
|
"name": "_oldRoot", |
||||||
|
"type": "bytes32[2]" |
||||||
|
}, |
||||||
|
{ |
||||||
|
"internalType": "bytes32[2]", |
||||||
|
"name": "_newRoot", |
||||||
|
"type": "bytes32[2]" |
||||||
|
}, |
||||||
|
{ |
||||||
|
"internalType": "bytes", |
||||||
|
"name": "_signature", |
||||||
|
"type": "bytes" |
||||||
|
}, |
||||||
|
{ |
||||||
|
"internalType": "bytes", |
||||||
|
"name": "_signature2", |
||||||
|
"type": "bytes" |
||||||
|
} |
||||||
|
], |
||||||
|
"name": "doubleUpdate", |
||||||
|
"outputs": [], |
||||||
|
"stateMutability": "nonpayable", |
||||||
|
"type": "function" |
||||||
|
}, |
||||||
|
{ |
||||||
|
"inputs": [ |
||||||
|
{ |
||||||
|
"internalType": "uint32", |
||||||
|
"name": "destination", |
||||||
|
"type": "uint32" |
||||||
|
}, |
||||||
|
{ |
||||||
|
"internalType": "bytes32", |
||||||
|
"name": "recipient", |
||||||
|
"type": "bytes32" |
||||||
|
}, |
||||||
|
{ |
||||||
|
"internalType": "bytes", |
||||||
|
"name": "body", |
||||||
|
"type": "bytes" |
||||||
|
} |
||||||
|
], |
||||||
|
"name": "enqueue", |
||||||
|
"outputs": [], |
||||||
|
"stateMutability": "nonpayable", |
||||||
|
"type": "function" |
||||||
|
}, |
||||||
|
{ |
||||||
|
"inputs": [ |
||||||
|
{ |
||||||
|
"internalType": "bytes32", |
||||||
|
"name": "_oldRoot", |
||||||
|
"type": "bytes32" |
||||||
|
}, |
||||||
|
{ |
||||||
|
"internalType": "bytes32", |
||||||
|
"name": "_newRoot", |
||||||
|
"type": "bytes32" |
||||||
|
}, |
||||||
|
{ |
||||||
|
"internalType": "bytes", |
||||||
|
"name": "_signature", |
||||||
|
"type": "bytes" |
||||||
|
} |
||||||
|
], |
||||||
|
"name": "improperUpdate", |
||||||
|
"outputs": [ |
||||||
|
{ |
||||||
|
"internalType": "bool", |
||||||
|
"name": "", |
||||||
|
"type": "bool" |
||||||
|
} |
||||||
|
], |
||||||
|
"stateMutability": "nonpayable", |
||||||
|
"type": "function" |
||||||
|
}, |
||||||
|
{ |
||||||
|
"inputs": [], |
||||||
|
"name": "originSLIP44", |
||||||
|
"outputs": [ |
||||||
|
{ |
||||||
|
"internalType": "uint32", |
||||||
|
"name": "", |
||||||
|
"type": "uint32" |
||||||
|
} |
||||||
|
], |
||||||
|
"stateMutability": "view", |
||||||
|
"type": "function" |
||||||
|
}, |
||||||
|
{ |
||||||
|
"inputs": [], |
||||||
|
"name": "root", |
||||||
|
"outputs": [ |
||||||
|
{ |
||||||
|
"internalType": "bytes32", |
||||||
|
"name": "", |
||||||
|
"type": "bytes32" |
||||||
|
} |
||||||
|
], |
||||||
|
"stateMutability": "view", |
||||||
|
"type": "function" |
||||||
|
}, |
||||||
|
{ |
||||||
|
"inputs": [ |
||||||
|
{ |
||||||
|
"internalType": "uint32", |
||||||
|
"name": "", |
||||||
|
"type": "uint32" |
||||||
|
} |
||||||
|
], |
||||||
|
"name": "sequences", |
||||||
|
"outputs": [ |
||||||
|
{ |
||||||
|
"internalType": "uint32", |
||||||
|
"name": "", |
||||||
|
"type": "uint32" |
||||||
|
} |
||||||
|
], |
||||||
|
"stateMutability": "view", |
||||||
|
"type": "function" |
||||||
|
}, |
||||||
|
{ |
||||||
|
"inputs": [], |
||||||
|
"name": "state", |
||||||
|
"outputs": [ |
||||||
|
{ |
||||||
|
"internalType": "enum Common.States", |
||||||
|
"name": "", |
||||||
|
"type": "uint8" |
||||||
|
} |
||||||
|
], |
||||||
|
"stateMutability": "view", |
||||||
|
"type": "function" |
||||||
|
}, |
||||||
|
{ |
||||||
|
"inputs": [], |
||||||
|
"name": "suggestUpdate", |
||||||
|
"outputs": [ |
||||||
|
{ |
||||||
|
"internalType": "bytes32", |
||||||
|
"name": "", |
||||||
|
"type": "bytes32" |
||||||
|
}, |
||||||
|
{ |
||||||
|
"internalType": "bytes32", |
||||||
|
"name": "", |
||||||
|
"type": "bytes32" |
||||||
|
} |
||||||
|
], |
||||||
|
"stateMutability": "view", |
||||||
|
"type": "function" |
||||||
|
}, |
||||||
|
{ |
||||||
|
"inputs": [], |
||||||
|
"name": "tree", |
||||||
|
"outputs": [ |
||||||
|
{ |
||||||
|
"internalType": "uint256", |
||||||
|
"name": "count", |
||||||
|
"type": "uint256" |
||||||
|
} |
||||||
|
], |
||||||
|
"stateMutability": "view", |
||||||
|
"type": "function" |
||||||
|
}, |
||||||
|
{ |
||||||
|
"inputs": [ |
||||||
|
{ |
||||||
|
"internalType": "bytes32", |
||||||
|
"name": "_oldRoot", |
||||||
|
"type": "bytes32" |
||||||
|
}, |
||||||
|
{ |
||||||
|
"internalType": "bytes32", |
||||||
|
"name": "_newRoot", |
||||||
|
"type": "bytes32" |
||||||
|
}, |
||||||
|
{ |
||||||
|
"internalType": "bytes", |
||||||
|
"name": "_signature", |
||||||
|
"type": "bytes" |
||||||
|
} |
||||||
|
], |
||||||
|
"name": "update", |
||||||
|
"outputs": [], |
||||||
|
"stateMutability": "nonpayable", |
||||||
|
"type": "function" |
||||||
|
}, |
||||||
|
{ |
||||||
|
"inputs": [], |
||||||
|
"name": "updater", |
||||||
|
"outputs": [ |
||||||
|
{ |
||||||
|
"internalType": "address", |
||||||
|
"name": "", |
||||||
|
"type": "address" |
||||||
|
} |
||||||
|
], |
||||||
|
"stateMutability": "view", |
||||||
|
"type": "function" |
||||||
|
} |
||||||
|
] |
@ -0,0 +1,369 @@ |
|||||||
|
[ |
||||||
|
{ |
||||||
|
"inputs": [ |
||||||
|
{ |
||||||
|
"internalType": "uint32", |
||||||
|
"name": "_originSLIP44", |
||||||
|
"type": "uint32" |
||||||
|
}, |
||||||
|
{ |
||||||
|
"internalType": "uint32", |
||||||
|
"name": "_ownSLIP44", |
||||||
|
"type": "uint32" |
||||||
|
}, |
||||||
|
{ |
||||||
|
"internalType": "address", |
||||||
|
"name": "_updater", |
||||||
|
"type": "address" |
||||||
|
}, |
||||||
|
{ |
||||||
|
"internalType": "uint256", |
||||||
|
"name": "_optimisticSeconds", |
||||||
|
"type": "uint256" |
||||||
|
}, |
||||||
|
{ |
||||||
|
"internalType": "bytes32", |
||||||
|
"name": "_start", |
||||||
|
"type": "bytes32" |
||||||
|
}, |
||||||
|
{ |
||||||
|
"internalType": "uint256", |
||||||
|
"name": "_lastProcessed", |
||||||
|
"type": "uint256" |
||||||
|
} |
||||||
|
], |
||||||
|
"stateMutability": "nonpayable", |
||||||
|
"type": "constructor" |
||||||
|
}, |
||||||
|
{ |
||||||
|
"anonymous": false, |
||||||
|
"inputs": [ |
||||||
|
{ |
||||||
|
"indexed": false, |
||||||
|
"internalType": "bytes32[2]", |
||||||
|
"name": "_oldRoot", |
||||||
|
"type": "bytes32[2]" |
||||||
|
}, |
||||||
|
{ |
||||||
|
"indexed": false, |
||||||
|
"internalType": "bytes32[2]", |
||||||
|
"name": "_newRoot", |
||||||
|
"type": "bytes32[2]" |
||||||
|
}, |
||||||
|
{ |
||||||
|
"indexed": false, |
||||||
|
"internalType": "bytes", |
||||||
|
"name": "_signature", |
||||||
|
"type": "bytes" |
||||||
|
}, |
||||||
|
{ |
||||||
|
"indexed": false, |
||||||
|
"internalType": "bytes", |
||||||
|
"name": "_signature2", |
||||||
|
"type": "bytes" |
||||||
|
} |
||||||
|
], |
||||||
|
"name": "DoubleUpdate", |
||||||
|
"type": "event" |
||||||
|
}, |
||||||
|
{ |
||||||
|
"anonymous": false, |
||||||
|
"inputs": [ |
||||||
|
{ |
||||||
|
"indexed": true, |
||||||
|
"internalType": "bytes32", |
||||||
|
"name": "_oldRoot", |
||||||
|
"type": "bytes32" |
||||||
|
}, |
||||||
|
{ |
||||||
|
"indexed": true, |
||||||
|
"internalType": "bytes32", |
||||||
|
"name": "_newRoot", |
||||||
|
"type": "bytes32" |
||||||
|
}, |
||||||
|
{ |
||||||
|
"indexed": false, |
||||||
|
"internalType": "bytes", |
||||||
|
"name": "signature", |
||||||
|
"type": "bytes" |
||||||
|
} |
||||||
|
], |
||||||
|
"name": "Update", |
||||||
|
"type": "event" |
||||||
|
}, |
||||||
|
{ |
||||||
|
"inputs": [], |
||||||
|
"name": "DOMAIN_HASH", |
||||||
|
"outputs": [ |
||||||
|
{ |
||||||
|
"internalType": "bytes32", |
||||||
|
"name": "", |
||||||
|
"type": "bytes32" |
||||||
|
} |
||||||
|
], |
||||||
|
"stateMutability": "view", |
||||||
|
"type": "function" |
||||||
|
}, |
||||||
|
{ |
||||||
|
"inputs": [], |
||||||
|
"name": "PROCESS_GAS", |
||||||
|
"outputs": [ |
||||||
|
{ |
||||||
|
"internalType": "uint256", |
||||||
|
"name": "", |
||||||
|
"type": "uint256" |
||||||
|
} |
||||||
|
], |
||||||
|
"stateMutability": "view", |
||||||
|
"type": "function" |
||||||
|
}, |
||||||
|
{ |
||||||
|
"inputs": [], |
||||||
|
"name": "RESERVE_GAS", |
||||||
|
"outputs": [ |
||||||
|
{ |
||||||
|
"internalType": "uint256", |
||||||
|
"name": "", |
||||||
|
"type": "uint256" |
||||||
|
} |
||||||
|
], |
||||||
|
"stateMutability": "view", |
||||||
|
"type": "function" |
||||||
|
}, |
||||||
|
{ |
||||||
|
"inputs": [], |
||||||
|
"name": "confirm", |
||||||
|
"outputs": [], |
||||||
|
"stateMutability": "nonpayable", |
||||||
|
"type": "function" |
||||||
|
}, |
||||||
|
{ |
||||||
|
"inputs": [], |
||||||
|
"name": "current", |
||||||
|
"outputs": [ |
||||||
|
{ |
||||||
|
"internalType": "bytes32", |
||||||
|
"name": "", |
||||||
|
"type": "bytes32" |
||||||
|
} |
||||||
|
], |
||||||
|
"stateMutability": "view", |
||||||
|
"type": "function" |
||||||
|
}, |
||||||
|
{ |
||||||
|
"inputs": [ |
||||||
|
{ |
||||||
|
"internalType": "bytes32[2]", |
||||||
|
"name": "_oldRoot", |
||||||
|
"type": "bytes32[2]" |
||||||
|
}, |
||||||
|
{ |
||||||
|
"internalType": "bytes32[2]", |
||||||
|
"name": "_newRoot", |
||||||
|
"type": "bytes32[2]" |
||||||
|
}, |
||||||
|
{ |
||||||
|
"internalType": "bytes", |
||||||
|
"name": "_signature", |
||||||
|
"type": "bytes" |
||||||
|
}, |
||||||
|
{ |
||||||
|
"internalType": "bytes", |
||||||
|
"name": "_signature2", |
||||||
|
"type": "bytes" |
||||||
|
} |
||||||
|
], |
||||||
|
"name": "doubleUpdate", |
||||||
|
"outputs": [], |
||||||
|
"stateMutability": "nonpayable", |
||||||
|
"type": "function" |
||||||
|
}, |
||||||
|
{ |
||||||
|
"inputs": [ |
||||||
|
{ |
||||||
|
"internalType": "bytes32", |
||||||
|
"name": "", |
||||||
|
"type": "bytes32" |
||||||
|
} |
||||||
|
], |
||||||
|
"name": "messages", |
||||||
|
"outputs": [ |
||||||
|
{ |
||||||
|
"internalType": "enum ProcessingReplica.MessageStatus", |
||||||
|
"name": "", |
||||||
|
"type": "uint8" |
||||||
|
} |
||||||
|
], |
||||||
|
"stateMutability": "view", |
||||||
|
"type": "function" |
||||||
|
}, |
||||||
|
{ |
||||||
|
"inputs": [], |
||||||
|
"name": "optimisticSeconds", |
||||||
|
"outputs": [ |
||||||
|
{ |
||||||
|
"internalType": "uint256", |
||||||
|
"name": "", |
||||||
|
"type": "uint256" |
||||||
|
} |
||||||
|
], |
||||||
|
"stateMutability": "view", |
||||||
|
"type": "function" |
||||||
|
}, |
||||||
|
{ |
||||||
|
"inputs": [], |
||||||
|
"name": "originSLIP44", |
||||||
|
"outputs": [ |
||||||
|
{ |
||||||
|
"internalType": "uint32", |
||||||
|
"name": "", |
||||||
|
"type": "uint32" |
||||||
|
} |
||||||
|
], |
||||||
|
"stateMutability": "view", |
||||||
|
"type": "function" |
||||||
|
}, |
||||||
|
{ |
||||||
|
"inputs": [], |
||||||
|
"name": "ownSLIP44", |
||||||
|
"outputs": [ |
||||||
|
{ |
||||||
|
"internalType": "uint32", |
||||||
|
"name": "", |
||||||
|
"type": "uint32" |
||||||
|
} |
||||||
|
], |
||||||
|
"stateMutability": "view", |
||||||
|
"type": "function" |
||||||
|
}, |
||||||
|
{ |
||||||
|
"inputs": [ |
||||||
|
{ |
||||||
|
"internalType": "bytes", |
||||||
|
"name": "_message", |
||||||
|
"type": "bytes" |
||||||
|
} |
||||||
|
], |
||||||
|
"name": "process", |
||||||
|
"outputs": [ |
||||||
|
{ |
||||||
|
"internalType": "bool", |
||||||
|
"name": "", |
||||||
|
"type": "bool" |
||||||
|
}, |
||||||
|
{ |
||||||
|
"internalType": "bytes", |
||||||
|
"name": "", |
||||||
|
"type": "bytes" |
||||||
|
} |
||||||
|
], |
||||||
|
"stateMutability": "nonpayable", |
||||||
|
"type": "function" |
||||||
|
}, |
||||||
|
{ |
||||||
|
"inputs": [ |
||||||
|
{ |
||||||
|
"internalType": "bytes32", |
||||||
|
"name": "leaf", |
||||||
|
"type": "bytes32" |
||||||
|
}, |
||||||
|
{ |
||||||
|
"internalType": "bytes32[32]", |
||||||
|
"name": "proof", |
||||||
|
"type": "bytes32[32]" |
||||||
|
}, |
||||||
|
{ |
||||||
|
"internalType": "uint256", |
||||||
|
"name": "index", |
||||||
|
"type": "uint256" |
||||||
|
} |
||||||
|
], |
||||||
|
"name": "prove", |
||||||
|
"outputs": [ |
||||||
|
{ |
||||||
|
"internalType": "bool", |
||||||
|
"name": "", |
||||||
|
"type": "bool" |
||||||
|
} |
||||||
|
], |
||||||
|
"stateMutability": "nonpayable", |
||||||
|
"type": "function" |
||||||
|
}, |
||||||
|
{ |
||||||
|
"inputs": [ |
||||||
|
{ |
||||||
|
"internalType": "bytes32", |
||||||
|
"name": "leaf", |
||||||
|
"type": "bytes32" |
||||||
|
}, |
||||||
|
{ |
||||||
|
"internalType": "bytes32[32]", |
||||||
|
"name": "proof", |
||||||
|
"type": "bytes32[32]" |
||||||
|
}, |
||||||
|
{ |
||||||
|
"internalType": "uint256", |
||||||
|
"name": "index", |
||||||
|
"type": "uint256" |
||||||
|
}, |
||||||
|
{ |
||||||
|
"internalType": "bytes", |
||||||
|
"name": "message", |
||||||
|
"type": "bytes" |
||||||
|
} |
||||||
|
], |
||||||
|
"name": "proveAndProcess", |
||||||
|
"outputs": [], |
||||||
|
"stateMutability": "nonpayable", |
||||||
|
"type": "function" |
||||||
|
}, |
||||||
|
{ |
||||||
|
"inputs": [], |
||||||
|
"name": "state", |
||||||
|
"outputs": [ |
||||||
|
{ |
||||||
|
"internalType": "enum Common.States", |
||||||
|
"name": "", |
||||||
|
"type": "uint8" |
||||||
|
} |
||||||
|
], |
||||||
|
"stateMutability": "view", |
||||||
|
"type": "function" |
||||||
|
}, |
||||||
|
{ |
||||||
|
"inputs": [ |
||||||
|
{ |
||||||
|
"internalType": "bytes32", |
||||||
|
"name": "_oldRoot", |
||||||
|
"type": "bytes32" |
||||||
|
}, |
||||||
|
{ |
||||||
|
"internalType": "bytes32", |
||||||
|
"name": "_newRoot", |
||||||
|
"type": "bytes32" |
||||||
|
}, |
||||||
|
{ |
||||||
|
"internalType": "bytes", |
||||||
|
"name": "_signature", |
||||||
|
"type": "bytes" |
||||||
|
} |
||||||
|
], |
||||||
|
"name": "update", |
||||||
|
"outputs": [], |
||||||
|
"stateMutability": "nonpayable", |
||||||
|
"type": "function" |
||||||
|
}, |
||||||
|
{ |
||||||
|
"inputs": [], |
||||||
|
"name": "updater", |
||||||
|
"outputs": [ |
||||||
|
{ |
||||||
|
"internalType": "address", |
||||||
|
"name": "", |
||||||
|
"type": "address" |
||||||
|
} |
||||||
|
], |
||||||
|
"stateMutability": "view", |
||||||
|
"type": "function" |
||||||
|
} |
||||||
|
] |
@ -0,0 +1,180 @@ |
|||||||
|
use async_trait::async_trait; |
||||||
|
use ethers_contract::abigen; |
||||||
|
use ethers_core::types::{Address, H256, U256}; |
||||||
|
use std::sync::Arc; |
||||||
|
|
||||||
|
use optics_core::{ |
||||||
|
traits::{ChainCommunicationError, Common, Home, State, TxOutcome}, |
||||||
|
Message, SignedUpdate, Update, |
||||||
|
}; |
||||||
|
|
||||||
|
abigen!( |
||||||
|
ReplicaContractInternal, |
||||||
|
"src/abis/ProcessingReplica.abi.json" |
||||||
|
); |
||||||
|
|
||||||
|
abigen!(HomeContractInternal, "src/abis/Home.abi.json"); |
||||||
|
|
||||||
|
#[derive(Debug)] |
||||||
|
pub struct HomeContract<M> |
||||||
|
where |
||||||
|
M: ethers_providers::Middleware, |
||||||
|
{ |
||||||
|
contract: HomeContractInternal<M>, |
||||||
|
slip44: u32, |
||||||
|
} |
||||||
|
|
||||||
|
impl<M> HomeContract<M> |
||||||
|
where |
||||||
|
M: ethers_providers::Middleware, |
||||||
|
{ |
||||||
|
pub fn at(slip44: u32, address: Address, provider: Arc<M>) -> Self { |
||||||
|
Self { |
||||||
|
contract: HomeContractInternal::new(address, provider), |
||||||
|
slip44, |
||||||
|
} |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
#[async_trait] |
||||||
|
impl<M> Common for HomeContract<M> |
||||||
|
where |
||||||
|
M: ethers_providers::Middleware + 'static, |
||||||
|
{ |
||||||
|
async fn status(&self, txid: H256) -> Result<Option<TxOutcome>, ChainCommunicationError> { |
||||||
|
let receipt_opt = self |
||||||
|
.contract |
||||||
|
.client() |
||||||
|
.get_transaction_receipt(txid) |
||||||
|
.await |
||||||
|
.map_err(|e| ChainCommunicationError::CustomError(Box::new(e)))?; |
||||||
|
|
||||||
|
Ok(receipt_opt.map(Into::into)) |
||||||
|
} |
||||||
|
|
||||||
|
fn origin_slip44(&self) -> u32 { |
||||||
|
self.slip44 |
||||||
|
} |
||||||
|
|
||||||
|
async fn updater(&self) -> Result<H256, ChainCommunicationError> { |
||||||
|
Ok(self.contract.updater().call().await?.into()) |
||||||
|
} |
||||||
|
|
||||||
|
async fn state(&self) -> Result<State, ChainCommunicationError> { |
||||||
|
let state = self.contract.state().call().await?; |
||||||
|
match state { |
||||||
|
0 => Ok(State::Waiting), |
||||||
|
1 => Ok(State::Failed), |
||||||
|
_ => unreachable!(), |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
async fn current_root(&self) -> Result<H256, ChainCommunicationError> { |
||||||
|
Ok(self.contract.current().call().await?.into()) |
||||||
|
} |
||||||
|
|
||||||
|
async fn update(&self, update: &SignedUpdate) -> Result<TxOutcome, ChainCommunicationError> { |
||||||
|
Ok(self |
||||||
|
.contract |
||||||
|
.update( |
||||||
|
update.update.previous_root.to_fixed_bytes(), |
||||||
|
update.update.new_root.to_fixed_bytes(), |
||||||
|
update.signature.to_vec(), |
||||||
|
) |
||||||
|
.send() |
||||||
|
.await? |
||||||
|
.await? |
||||||
|
.into()) |
||||||
|
} |
||||||
|
|
||||||
|
async fn double_update( |
||||||
|
&self, |
||||||
|
left: &SignedUpdate, |
||||||
|
right: &SignedUpdate, |
||||||
|
) -> Result<TxOutcome, ChainCommunicationError> { |
||||||
|
Ok(self |
||||||
|
.contract |
||||||
|
.double_update( |
||||||
|
[ |
||||||
|
left.update.previous_root.to_fixed_bytes(), |
||||||
|
right.update.previous_root.to_fixed_bytes(), |
||||||
|
], |
||||||
|
[ |
||||||
|
left.update.new_root.to_fixed_bytes(), |
||||||
|
right.update.new_root.to_fixed_bytes(), |
||||||
|
], |
||||||
|
left.signature.to_vec(), |
||||||
|
right.signature.to_vec(), |
||||||
|
) |
||||||
|
.send() |
||||||
|
.await? |
||||||
|
.await? |
||||||
|
.into()) |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
#[async_trait] |
||||||
|
impl<M> Home for HomeContract<M> |
||||||
|
where |
||||||
|
M: ethers_providers::Middleware + 'static, |
||||||
|
{ |
||||||
|
async fn lookup_message( |
||||||
|
&self, |
||||||
|
destination: u32, |
||||||
|
sequence: u32, |
||||||
|
) -> Result<Option<Vec<u8>>, ChainCommunicationError> { |
||||||
|
let filters = self |
||||||
|
.contract |
||||||
|
.dispatch_filter() |
||||||
|
.topic1(U256::from(destination)) |
||||||
|
.topic2(U256::from(sequence)) |
||||||
|
.query() |
||||||
|
.await?; |
||||||
|
|
||||||
|
Ok(filters.into_iter().next().map(|f| f.message.clone())) |
||||||
|
} |
||||||
|
|
||||||
|
async fn sequences(&self, destination: u32) -> Result<u32, ChainCommunicationError> { |
||||||
|
Ok(self.contract.sequences(destination).call().await?) |
||||||
|
} |
||||||
|
|
||||||
|
async fn enqueue(&self, message: &Message) -> Result<TxOutcome, ChainCommunicationError> { |
||||||
|
Ok(self |
||||||
|
.contract |
||||||
|
.enqueue( |
||||||
|
message.destination, |
||||||
|
message.recipient.to_fixed_bytes(), |
||||||
|
message.body.clone(), |
||||||
|
) |
||||||
|
.send() |
||||||
|
.await? |
||||||
|
.await? |
||||||
|
.into()) |
||||||
|
} |
||||||
|
|
||||||
|
async fn improper_update( |
||||||
|
&self, |
||||||
|
update: &SignedUpdate, |
||||||
|
) -> Result<TxOutcome, ChainCommunicationError> { |
||||||
|
Ok(self |
||||||
|
.contract |
||||||
|
.improper_update( |
||||||
|
update.update.previous_root.to_fixed_bytes(), |
||||||
|
update.update.new_root.to_fixed_bytes(), |
||||||
|
update.signature.to_vec(), |
||||||
|
) |
||||||
|
.send() |
||||||
|
.await? |
||||||
|
.await? |
||||||
|
.into()) |
||||||
|
} |
||||||
|
|
||||||
|
async fn produce_update(&self) -> Result<Update, ChainCommunicationError> { |
||||||
|
let (a, b) = self.contract.suggest_update().call().await?; |
||||||
|
Ok(Update { |
||||||
|
origin_chain: self.origin_slip44(), |
||||||
|
previous_root: a.into(), |
||||||
|
new_root: b.into(), |
||||||
|
}) |
||||||
|
} |
||||||
|
} |
@ -0,0 +1,43 @@ |
|||||||
|
mod abis; |
||||||
|
mod settings; |
||||||
|
|
||||||
|
use ethers_providers::{Http, Provider}; |
||||||
|
// use std::collections::HashMap;
|
||||||
|
use std::{convert::TryFrom, sync::Arc}; |
||||||
|
|
||||||
|
use optics_core::traits::{Home, Replica}; |
||||||
|
|
||||||
|
#[derive(Debug)] |
||||||
|
struct App { |
||||||
|
home: Box<dyn Home>, |
||||||
|
replicas: Vec<Box<dyn Replica>>, |
||||||
|
} |
||||||
|
|
||||||
|
async fn _main(settings: settings::Settings) { |
||||||
|
println!("{:?}", &settings); |
||||||
|
|
||||||
|
let home = { |
||||||
|
let provider = Arc::new(Provider::<Http>::try_from(settings.home().url()).expect("!url")); |
||||||
|
Box::new(abis::HomeContract::at( |
||||||
|
0, |
||||||
|
settings.home().address().into(), |
||||||
|
provider, |
||||||
|
)) |
||||||
|
}; |
||||||
|
|
||||||
|
let app = App { |
||||||
|
home, |
||||||
|
replicas: vec![], |
||||||
|
}; |
||||||
|
println!("{:?}", &app); |
||||||
|
} |
||||||
|
|
||||||
|
fn main() { |
||||||
|
let settings = settings::Settings::new().expect("!config"); |
||||||
|
|
||||||
|
tokio::runtime::Builder::new_current_thread() |
||||||
|
.enable_all() |
||||||
|
.build() |
||||||
|
.unwrap() |
||||||
|
.block_on(_main(settings)) |
||||||
|
} |
@ -0,0 +1,86 @@ |
|||||||
|
use config::{Config, ConfigError, Environment, File}; |
||||||
|
use std::{collections::HashMap, env}; |
||||||
|
|
||||||
|
use ethers_core::types::{Address, H256}; |
||||||
|
|
||||||
|
#[derive(Debug, serde::Deserialize)] |
||||||
|
#[serde(untagged)] |
||||||
|
pub(crate) enum Ethereum { |
||||||
|
Http { address: Address, http: String }, |
||||||
|
Ws { address: Address, ws: String }, |
||||||
|
} |
||||||
|
|
||||||
|
impl Ethereum { |
||||||
|
pub fn url(&self) -> &str { |
||||||
|
match self { |
||||||
|
Self::Http { address: _, http } => &http, |
||||||
|
Self::Ws { address: _, ws } => &ws, |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
pub fn address(&self) -> Address { |
||||||
|
match self { |
||||||
|
Self::Http { address, http: _ } => *address, |
||||||
|
Self::Ws { address, ws: _ } => *address, |
||||||
|
} |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
#[derive(Debug, serde::Deserialize)] |
||||||
|
#[serde(tag = "chain")] |
||||||
|
pub(crate) enum Home { |
||||||
|
Ethereum(Ethereum), |
||||||
|
} |
||||||
|
|
||||||
|
impl Home { |
||||||
|
pub fn url(&self) -> &str { |
||||||
|
match self { |
||||||
|
Self::Ethereum(e) => e.url(), |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
pub fn address(&self) -> H256 { |
||||||
|
match self { |
||||||
|
Self::Ethereum(e) => e.address().into(), |
||||||
|
} |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
#[derive(Debug, serde::Deserialize)] |
||||||
|
#[serde(tag = "chain")] |
||||||
|
pub(crate) enum Replica { |
||||||
|
Ethereum(Ethereum), |
||||||
|
} |
||||||
|
|
||||||
|
#[derive(Debug, serde::Deserialize)] |
||||||
|
pub(crate) struct Settings { |
||||||
|
home: Home, |
||||||
|
replicas: HashMap<String, Replica>, |
||||||
|
} |
||||||
|
|
||||||
|
impl Settings { |
||||||
|
pub fn new() -> Result<Self, ConfigError> { |
||||||
|
let mut s = Config::new(); |
||||||
|
|
||||||
|
s.merge(File::with_name("config/default"))?; |
||||||
|
|
||||||
|
let env = env::var("RUN_MODE").unwrap_or_else(|_| "development".into()); |
||||||
|
s.merge(File::with_name(&format!("config/{}", env)).required(false))?; |
||||||
|
|
||||||
|
// Add in settings from the environment (with a prefix of OPTRELAY)
|
||||||
|
// Eg.. `OPTRELAY_DEBUG=1 would set the `debug` key
|
||||||
|
s.merge(Environment::with_prefix("OPTRELAY"))?; |
||||||
|
|
||||||
|
s.try_into() |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
impl Settings { |
||||||
|
pub fn home(&self) -> &Home { |
||||||
|
&self.home |
||||||
|
} |
||||||
|
|
||||||
|
pub fn replicas(&self) -> &HashMap<String, Replica> { |
||||||
|
&self.replicas |
||||||
|
} |
||||||
|
} |
@ -0,0 +1,7 @@ |
|||||||
|
#!/bin/zsh |
||||||
|
|
||||||
|
cd ../../solidity && \ |
||||||
|
npm i && \ |
||||||
|
npm run compile && \ |
||||||
|
cat artifacts/contracts/Replica.sol/ProcessingReplica.json| jq .abi > ../rust/optics-base/src/abis/ProcessingReplica.abi.json && \ |
||||||
|
cat artifacts/contracts/Home.sol/Home.json| jq .abi > ../rust/optics-base/src/abis/Home.abi.json |
File diff suppressed because it is too large
Load Diff
@ -0,0 +1,37 @@ |
|||||||
|
use async_trait::async_trait; |
||||||
|
|
||||||
|
use crate::{ |
||||||
|
traits::{ChainCommunicationError, Common, TxOutcome}, |
||||||
|
Message, SignedUpdate, Update, |
||||||
|
}; |
||||||
|
|
||||||
|
/// Interface for the Home chain contract. Allows abstraction over different
|
||||||
|
/// chains
|
||||||
|
#[async_trait] |
||||||
|
pub trait Home: Common { |
||||||
|
/// Fetch the message to destination at the sequence number (or error).
|
||||||
|
/// This should fetch events from the chain API
|
||||||
|
async fn lookup_message( |
||||||
|
&self, |
||||||
|
destination: u32, |
||||||
|
sequence: u32, |
||||||
|
) -> Result<Option<Vec<u8>>, ChainCommunicationError>; |
||||||
|
|
||||||
|
/// Fetch the sequence
|
||||||
|
async fn sequences(&self, destination: u32) -> Result<u32, ChainCommunicationError>; |
||||||
|
|
||||||
|
/// Queue a message.
|
||||||
|
async fn enqueue(&self, message: &Message) -> Result<TxOutcome, ChainCommunicationError>; |
||||||
|
|
||||||
|
/// Submit an improper update for slashing
|
||||||
|
async fn improper_update( |
||||||
|
&self, |
||||||
|
update: &SignedUpdate, |
||||||
|
) -> Result<TxOutcome, ChainCommunicationError>; |
||||||
|
|
||||||
|
/// Create a valid update based on the chain's current state.
|
||||||
|
/// This merely suggests an update. It does NOT ensure that no other valid
|
||||||
|
/// update has been produced. The updater MUST take measures to prevent
|
||||||
|
/// double-updating.
|
||||||
|
async fn produce_update(&self) -> Result<Update, ChainCommunicationError>; |
||||||
|
} |
@ -0,0 +1,107 @@ |
|||||||
|
/// Interface for home chain contract
|
||||||
|
pub mod home; |
||||||
|
|
||||||
|
/// Interface for replica chain contract
|
||||||
|
pub mod replica; |
||||||
|
|
||||||
|
use async_trait::async_trait; |
||||||
|
use ethers_core::types::{TransactionReceipt, H256}; |
||||||
|
use thiserror::Error; |
||||||
|
|
||||||
|
use crate::{utils::domain_hash, SignedUpdate}; |
||||||
|
|
||||||
|
pub use home::*; |
||||||
|
pub use replica::*; |
||||||
|
|
||||||
|
/// Contract states
|
||||||
|
#[derive(Debug)] |
||||||
|
pub enum State { |
||||||
|
/// Contract is active
|
||||||
|
Waiting, |
||||||
|
/// Contract has failed
|
||||||
|
Failed, |
||||||
|
} |
||||||
|
|
||||||
|
/// The result of a transaction
|
||||||
|
#[derive(Debug)] |
||||||
|
pub struct TxOutcome { |
||||||
|
/// The txid
|
||||||
|
pub txid: H256, |
||||||
|
/// True if executed, false otherwise
|
||||||
|
pub executed: bool, |
||||||
|
} |
||||||
|
|
||||||
|
impl From<TransactionReceipt> for TxOutcome { |
||||||
|
fn from(t: TransactionReceipt) -> Self { |
||||||
|
Self { |
||||||
|
txid: t.transaction_hash, |
||||||
|
executed: t.status.unwrap().low_u32() == 1, |
||||||
|
} |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
#[derive(Debug, Error)] |
||||||
|
/// Error type for chain communication
|
||||||
|
pub enum ChainCommunicationError { |
||||||
|
/// Provider Error
|
||||||
|
#[error(transparent)] |
||||||
|
ProviderError(#[from] ethers_providers::ProviderError), |
||||||
|
/// Contract Error
|
||||||
|
#[error(transparent)] |
||||||
|
ContractError(Box<dyn std::error::Error>), |
||||||
|
/// Custom error or contract error
|
||||||
|
#[error(transparent)] |
||||||
|
CustomError(#[from] Box<dyn std::error::Error>), |
||||||
|
} |
||||||
|
|
||||||
|
impl<M> From<ethers_contract::ContractError<M>> for ChainCommunicationError |
||||||
|
where |
||||||
|
M: ethers_providers::Middleware + 'static, |
||||||
|
{ |
||||||
|
fn from(e: ethers_contract::ContractError<M>) -> Self { |
||||||
|
Self::ContractError(Box::new(e)) |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
// impl<M> From<ethers_contract::ContractError<M>> for ChainCommunicationError
|
||||||
|
// where
|
||||||
|
// M: ethers_providers::Middleware + 'static,
|
||||||
|
// {
|
||||||
|
// fn from(e: ethers_contract::ContractError<M>) -> Self {
|
||||||
|
// Self::ContractError(Box::new(e))
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
|
||||||
|
/// Interface for attributes shared by Home and Replica
|
||||||
|
#[async_trait] |
||||||
|
pub trait Common: Sync + Send + std::fmt::Debug { |
||||||
|
/// Get the status of a transaction
|
||||||
|
async fn status(&self, txid: H256) -> Result<Option<TxOutcome>, ChainCommunicationError>; |
||||||
|
|
||||||
|
/// Return the slip44 ID
|
||||||
|
fn origin_slip44(&self) -> u32; |
||||||
|
|
||||||
|
/// Return the domain hash
|
||||||
|
fn domain_hash(&self) -> H256 { |
||||||
|
domain_hash(self.origin_slip44()) |
||||||
|
} |
||||||
|
|
||||||
|
/// Fetch the current updater value
|
||||||
|
async fn updater(&self) -> Result<H256, ChainCommunicationError>; |
||||||
|
|
||||||
|
/// Fetch the current state.
|
||||||
|
async fn state(&self) -> Result<State, ChainCommunicationError>; |
||||||
|
|
||||||
|
/// Fetch the current root
|
||||||
|
async fn current_root(&self) -> Result<H256, ChainCommunicationError>; |
||||||
|
|
||||||
|
/// Submit a signed update for inclusion
|
||||||
|
async fn update(&self, update: &SignedUpdate) -> Result<TxOutcome, ChainCommunicationError>; |
||||||
|
|
||||||
|
/// Submit a double update for slashing
|
||||||
|
async fn double_update( |
||||||
|
&self, |
||||||
|
left: &SignedUpdate, |
||||||
|
right: &SignedUpdate, |
||||||
|
) -> Result<TxOutcome, ChainCommunicationError>; |
||||||
|
} |
@ -0,0 +1,31 @@ |
|||||||
|
use async_trait::async_trait; |
||||||
|
use ethers_core::types::{H256, U256}; |
||||||
|
|
||||||
|
use crate::{ |
||||||
|
traits::{ChainCommunicationError, Common, TxOutcome}, |
||||||
|
Message, |
||||||
|
}; |
||||||
|
|
||||||
|
/// Interface for on-chain replicas
|
||||||
|
#[async_trait] |
||||||
|
pub trait Replica: Common { |
||||||
|
/// Return the pending root and time, if any
|
||||||
|
async fn pending(&self) -> Result<Option<(H256, U256)>, ChainCommunicationError>; |
||||||
|
|
||||||
|
/// Confirm the next pending root (after its timer has elapsed);
|
||||||
|
async fn confirm(&self) -> Result<TxOutcome, ChainCommunicationError>; |
||||||
|
|
||||||
|
/// Fetch the previous root.
|
||||||
|
async fn previous_root(&self) -> Result<H256, ChainCommunicationError>; |
||||||
|
|
||||||
|
/// Prove inclusion of some leaf in the replica
|
||||||
|
async fn prove( |
||||||
|
&self, |
||||||
|
leaf: H256, |
||||||
|
index: u32, |
||||||
|
proof: [H256; 32], |
||||||
|
) -> Result<TxOutcome, ChainCommunicationError>; |
||||||
|
|
||||||
|
/// Trigger processing of a message
|
||||||
|
async fn process(&self, message: &Message) -> Result<TxOutcome, ChainCommunicationError>; |
||||||
|
} |
@ -0,0 +1,12 @@ |
|||||||
|
use ethers_core::types::H256; |
||||||
|
use sha3::{Digest, Keccak256}; |
||||||
|
|
||||||
|
pub(crate) fn domain_hash(origin_slip44_id: u32) -> H256 { |
||||||
|
H256::from_slice( |
||||||
|
Keccak256::new() |
||||||
|
.chain(origin_slip44_id.to_be_bytes()) |
||||||
|
.chain("OPTICS".as_bytes()) |
||||||
|
.finalize() |
||||||
|
.as_slice(), |
||||||
|
) |
||||||
|
} |
Loading…
Reference in new issue