commit
2afd32391a
@ -0,0 +1 @@ |
||||
target |
@ -0,0 +1,960 @@ |
||||
# This file is automatically @generated by Cargo. |
||||
# It is not intended for manual editing. |
||||
[[package]] |
||||
name = "anyhow" |
||||
version = "1.0.38" |
||||
source = "registry+https://github.com/rust-lang/crates.io-index" |
||||
checksum = "afddf7f520a80dbf76e6f50a35bca42a2331ef227a28b3b6dc5c2e2338d114b1" |
||||
|
||||
[[package]] |
||||
name = "arrayvec" |
||||
version = "0.5.2" |
||||
source = "registry+https://github.com/rust-lang/crates.io-index" |
||||
checksum = "23b62fc65de8e4e7f52534fb52b0f3ed04746ae267519eef2a83941e8085068b" |
||||
|
||||
[[package]] |
||||
name = "async-trait" |
||||
version = "0.1.42" |
||||
source = "registry+https://github.com/rust-lang/crates.io-index" |
||||
checksum = "8d3a45e77e34375a7923b1e8febb049bb011f064714a8e17a1a616fef01da13d" |
||||
dependencies = [ |
||||
"proc-macro2", |
||||
"quote", |
||||
"syn", |
||||
] |
||||
|
||||
[[package]] |
||||
name = "bitvec" |
||||
version = "0.17.4" |
||||
source = "registry+https://github.com/rust-lang/crates.io-index" |
||||
checksum = "41262f11d771fd4a61aa3ce019fca363b4b6c282fca9da2a31186d3965a47a5c" |
||||
dependencies = [ |
||||
"either", |
||||
"radium 0.3.0", |
||||
] |
||||
|
||||
[[package]] |
||||
name = "bitvec" |
||||
version = "0.18.4" |
||||
source = "registry+https://github.com/rust-lang/crates.io-index" |
||||
checksum = "1d2838fdd79e8776dbe07a106c784b0f8dda571a21b2750a092cc4cbaa653c8e" |
||||
dependencies = [ |
||||
"funty", |
||||
"radium 0.4.1", |
||||
"wyz", |
||||
] |
||||
|
||||
[[package]] |
||||
name = "block-buffer" |
||||
version = "0.9.0" |
||||
source = "registry+https://github.com/rust-lang/crates.io-index" |
||||
checksum = "4152116fd6e9dadb291ae18fc1ec3575ed6d84c29642d97890f4b4a3417297e4" |
||||
dependencies = [ |
||||
"block-padding", |
||||
"generic-array", |
||||
] |
||||
|
||||
[[package]] |
||||
name = "block-padding" |
||||
version = "0.2.1" |
||||
source = "registry+https://github.com/rust-lang/crates.io-index" |
||||
checksum = "8d696c370c750c948ada61c69a0ee2cbbb9c50b1019ddb86d9317157a99c2cae" |
||||
|
||||
[[package]] |
||||
name = "byte-slice-cast" |
||||
version = "0.3.5" |
||||
source = "registry+https://github.com/rust-lang/crates.io-index" |
||||
checksum = "b0a5e3906bcbf133e33c1d4d95afc664ad37fbdb9f6568d8043e7ea8c27d93d3" |
||||
|
||||
[[package]] |
||||
name = "byteorder" |
||||
version = "1.4.2" |
||||
source = "registry+https://github.com/rust-lang/crates.io-index" |
||||
checksum = "ae44d1a3d5a19df61dd0c8beb138458ac2a53a7ac09eba97d55592540004306b" |
||||
|
||||
[[package]] |
||||
name = "bytes" |
||||
version = "1.0.1" |
||||
source = "registry+https://github.com/rust-lang/crates.io-index" |
||||
checksum = "b700ce4376041dcd0a327fd0097c41095743c4c8af8887265942faf1100bd040" |
||||
dependencies = [ |
||||
"serde", |
||||
] |
||||
|
||||
[[package]] |
||||
name = "cfg-if" |
||||
version = "1.0.0" |
||||
source = "registry+https://github.com/rust-lang/crates.io-index" |
||||
checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd" |
||||
|
||||
[[package]] |
||||
name = "cpuid-bool" |
||||
version = "0.1.2" |
||||
source = "registry+https://github.com/rust-lang/crates.io-index" |
||||
checksum = "8aebca1129a03dc6dc2b127edd729435bbc4a37e1d5f4d7513165089ceb02634" |
||||
|
||||
[[package]] |
||||
name = "crunchy" |
||||
version = "0.2.2" |
||||
source = "registry+https://github.com/rust-lang/crates.io-index" |
||||
checksum = "7a81dae078cea95a014a339291cec439d2f232ebe854a9d672b796c6afafa9b7" |
||||
|
||||
[[package]] |
||||
name = "crypto-mac" |
||||
version = "0.10.0" |
||||
source = "registry+https://github.com/rust-lang/crates.io-index" |
||||
checksum = "4857fd85a0c34b3c3297875b747c1e02e06b6a0ea32dd892d8192b9ce0813ea6" |
||||
dependencies = [ |
||||
"generic-array", |
||||
"subtle", |
||||
] |
||||
|
||||
[[package]] |
||||
name = "digest" |
||||
version = "0.9.0" |
||||
source = "registry+https://github.com/rust-lang/crates.io-index" |
||||
checksum = "d3dd60d1080a57a05ab032377049e0591415d2b31afd7028356dbf3cc6dcb066" |
||||
dependencies = [ |
||||
"generic-array", |
||||
] |
||||
|
||||
[[package]] |
||||
name = "ecdsa" |
||||
version = "0.10.2" |
||||
source = "registry+https://github.com/rust-lang/crates.io-index" |
||||
checksum = "41fbdb4ff710acb4db8ca29f93b897529ea6d6a45626d5183b47e012aa6ae7e4" |
||||
dependencies = [ |
||||
"elliptic-curve", |
||||
"hmac", |
||||
"signature", |
||||
] |
||||
|
||||
[[package]] |
||||
name = "either" |
||||
version = "1.6.1" |
||||
source = "registry+https://github.com/rust-lang/crates.io-index" |
||||
checksum = "e78d4f1cc4ae33bbfc157ed5d5a5ef3bc29227303d595861deb238fcec4e9457" |
||||
|
||||
[[package]] |
||||
name = "elliptic-curve" |
||||
version = "0.8.4" |
||||
source = "registry+https://github.com/rust-lang/crates.io-index" |
||||
checksum = "592b1c857559479c056b73a3053c717108a70e4dce320ad28c79c63f5c2e62ba" |
||||
dependencies = [ |
||||
"bitvec 0.18.4", |
||||
"digest", |
||||
"ff", |
||||
"generic-array", |
||||
"group", |
||||
"rand_core 0.5.1", |
||||
"subtle", |
||||
"zeroize", |
||||
] |
||||
|
||||
[[package]] |
||||
name = "eth-keystore" |
||||
version = "0.1.0" |
||||
source = "git+https://github.com/roynalnaruto/eth-keystore-rs#6e99e64d341a345f4fed24c97fa356eec6941843" |
||||
dependencies = [ |
||||
"hex", |
||||
"rand 0.7.3", |
||||
"rust-crypto", |
||||
"serde", |
||||
"serde_json", |
||||
"thiserror", |
||||
"uuid", |
||||
] |
||||
|
||||
[[package]] |
||||
name = "ethabi-next" |
||||
version = "13.0.0" |
||||
source = "registry+https://github.com/rust-lang/crates.io-index" |
||||
checksum = "f4bb43ca3464de349cd4f94bb37113eb4938dfb7df1a28320049bbbe3e9ffc6a" |
||||
dependencies = [ |
||||
"anyhow", |
||||
"ethereum-types", |
||||
"hex", |
||||
"serde", |
||||
"serde_json", |
||||
"sha3", |
||||
"thiserror", |
||||
"uint", |
||||
] |
||||
|
||||
[[package]] |
||||
name = "ethbloom" |
||||
version = "0.10.0" |
||||
source = "registry+https://github.com/rust-lang/crates.io-index" |
||||
checksum = "22a621dcebea74f2a6f2002d0a885c81ccf6cbdf86760183316a7722b5707ca4" |
||||
dependencies = [ |
||||
"crunchy", |
||||
"fixed-hash", |
||||
"impl-rlp", |
||||
"impl-serde", |
||||
"tiny-keccak", |
||||
] |
||||
|
||||
[[package]] |
||||
name = "ethereum-types" |
||||
version = "0.10.0" |
||||
source = "registry+https://github.com/rust-lang/crates.io-index" |
||||
checksum = "05dc5f0df4915fa6dff7f975a8366ecfaaa8959c74235469495153e7bb1b280e" |
||||
dependencies = [ |
||||
"ethbloom", |
||||
"fixed-hash", |
||||
"impl-rlp", |
||||
"impl-serde", |
||||
"primitive-types", |
||||
"uint", |
||||
] |
||||
|
||||
[[package]] |
||||
name = "ethers-core" |
||||
version = "0.1.3" |
||||
source = "git+https://github.com/gakonst/ethers-rs#177f0c3eb90dc634276536dc928c956b2a939400" |
||||
dependencies = [ |
||||
"arrayvec", |
||||
"bytes", |
||||
"ecdsa", |
||||
"elliptic-curve", |
||||
"ethabi-next", |
||||
"ethereum-types", |
||||
"generic-array", |
||||
"glob", |
||||
"hex", |
||||
"k256", |
||||
"rand 0.7.3", |
||||
"rlp", |
||||
"serde", |
||||
"serde_json", |
||||
"thiserror", |
||||
"tiny-keccak", |
||||
] |
||||
|
||||
[[package]] |
||||
name = "ethers-signers" |
||||
version = "0.1.3" |
||||
source = "git+https://github.com/gakonst/ethers-rs#177f0c3eb90dc634276536dc928c956b2a939400" |
||||
dependencies = [ |
||||
"async-trait", |
||||
"elliptic-curve", |
||||
"eth-keystore", |
||||
"ethers-core", |
||||
"futures-executor", |
||||
"futures-util", |
||||
"hex", |
||||
"rand 0.7.3", |
||||
"serde", |
||||
"sha2", |
||||
"thiserror", |
||||
] |
||||
|
||||
[[package]] |
||||
name = "ff" |
||||
version = "0.8.0" |
||||
source = "registry+https://github.com/rust-lang/crates.io-index" |
||||
checksum = "01646e077d4ebda82b73f1bca002ea1e91561a77df2431a9e79729bcc31950ef" |
||||
dependencies = [ |
||||
"bitvec 0.18.4", |
||||
"rand_core 0.5.1", |
||||
"subtle", |
||||
] |
||||
|
||||
[[package]] |
||||
name = "fixed-hash" |
||||
version = "0.7.0" |
||||
source = "registry+https://github.com/rust-lang/crates.io-index" |
||||
checksum = "cfcf0ed7fe52a17a03854ec54a9f76d6d84508d1c0e66bc1793301c73fc8493c" |
||||
dependencies = [ |
||||
"byteorder", |
||||
"rand 0.8.1", |
||||
"rustc-hex", |
||||
"static_assertions", |
||||
] |
||||
|
||||
[[package]] |
||||
name = "fuchsia-cprng" |
||||
version = "0.1.1" |
||||
source = "registry+https://github.com/rust-lang/crates.io-index" |
||||
checksum = "a06f77d526c1a601b7c4cdd98f54b5eaabffc14d5f2f0296febdc7f357c6d3ba" |
||||
|
||||
[[package]] |
||||
name = "funty" |
||||
version = "1.1.0" |
||||
source = "registry+https://github.com/rust-lang/crates.io-index" |
||||
checksum = "fed34cd105917e91daa4da6b3728c47b068749d6a62c59811f06ed2ac71d9da7" |
||||
|
||||
[[package]] |
||||
name = "futures-core" |
||||
version = "0.3.9" |
||||
source = "registry+https://github.com/rust-lang/crates.io-index" |
||||
checksum = "db8d3b0917ff63a2a96173133c02818fac4a746b0a57569d3baca9ec0e945e08" |
||||
|
||||
[[package]] |
||||
name = "futures-executor" |
||||
version = "0.3.9" |
||||
source = "registry+https://github.com/rust-lang/crates.io-index" |
||||
checksum = "9ee9ca2f7eb4475772cf39dd1cd06208dce2670ad38f4d9c7262b3e15f127068" |
||||
dependencies = [ |
||||
"futures-core", |
||||
"futures-task", |
||||
"futures-util", |
||||
] |
||||
|
||||
[[package]] |
||||
name = "futures-macro" |
||||
version = "0.3.9" |
||||
source = "registry+https://github.com/rust-lang/crates.io-index" |
||||
checksum = "0f8719ca0e1f3c5e34f3efe4570ef2c0610ca6da85ae7990d472e9cbfba13664" |
||||
dependencies = [ |
||||
"proc-macro-hack", |
||||
"proc-macro2", |
||||
"quote", |
||||
"syn", |
||||
] |
||||
|
||||
[[package]] |
||||
name = "futures-task" |
||||
version = "0.3.9" |
||||
source = "registry+https://github.com/rust-lang/crates.io-index" |
||||
checksum = "a92a0843a2ff66823a8f7c77bffe9a09be2b64e533562c412d63075643ec0038" |
||||
dependencies = [ |
||||
"once_cell", |
||||
] |
||||
|
||||
[[package]] |
||||
name = "futures-util" |
||||
version = "0.3.9" |
||||
source = "registry+https://github.com/rust-lang/crates.io-index" |
||||
checksum = "036a2107cdeb57f6d7322f1b6c363dad67cd63ca3b7d1b925bdf75bd5d96cda9" |
||||
dependencies = [ |
||||
"futures-core", |
||||
"futures-macro", |
||||
"futures-task", |
||||
"pin-project-lite", |
||||
"pin-utils", |
||||
"proc-macro-hack", |
||||
"proc-macro-nested", |
||||
"slab", |
||||
] |
||||
|
||||
[[package]] |
||||
name = "gcc" |
||||
version = "0.3.55" |
||||
source = "registry+https://github.com/rust-lang/crates.io-index" |
||||
checksum = "8f5f3913fa0bfe7ee1fd8248b6b9f42a5af4b9d65ec2dd2c3c26132b950ecfc2" |
||||
|
||||
[[package]] |
||||
name = "generic-array" |
||||
version = "0.14.4" |
||||
source = "registry+https://github.com/rust-lang/crates.io-index" |
||||
checksum = "501466ecc8a30d1d3b7fc9229b122b2ce8ed6e9d9223f1138d4babb253e51817" |
||||
dependencies = [ |
||||
"typenum", |
||||
"version_check", |
||||
] |
||||
|
||||
[[package]] |
||||
name = "getrandom" |
||||
version = "0.1.16" |
||||
source = "registry+https://github.com/rust-lang/crates.io-index" |
||||
checksum = "8fc3cb4d91f53b50155bdcfd23f6a4c39ae1969c2ae85982b135750cccaf5fce" |
||||
dependencies = [ |
||||
"cfg-if", |
||||
"libc", |
||||
"wasi 0.9.0+wasi-snapshot-preview1", |
||||
] |
||||
|
||||
[[package]] |
||||
name = "getrandom" |
||||
version = "0.2.1" |
||||
source = "registry+https://github.com/rust-lang/crates.io-index" |
||||
checksum = "4060f4657be78b8e766215b02b18a2e862d83745545de804638e2b545e81aee6" |
||||
dependencies = [ |
||||
"cfg-if", |
||||
"libc", |
||||
"wasi 0.10.1+wasi-snapshot-preview1", |
||||
] |
||||
|
||||
[[package]] |
||||
name = "glob" |
||||
version = "0.3.0" |
||||
source = "registry+https://github.com/rust-lang/crates.io-index" |
||||
checksum = "9b919933a397b79c37e33b77bb2aa3dc8eb6e165ad809e58ff75bc7db2e34574" |
||||
|
||||
[[package]] |
||||
name = "group" |
||||
version = "0.8.0" |
||||
source = "registry+https://github.com/rust-lang/crates.io-index" |
||||
checksum = "cc11f9f5fbf1943b48ae7c2bf6846e7d827a512d1be4f23af708f5ca5d01dde1" |
||||
dependencies = [ |
||||
"ff", |
||||
"rand_core 0.5.1", |
||||
"subtle", |
||||
] |
||||
|
||||
[[package]] |
||||
name = "hex" |
||||
version = "0.4.2" |
||||
source = "registry+https://github.com/rust-lang/crates.io-index" |
||||
checksum = "644f9158b2f133fd50f5fb3242878846d9eb792e445c893805ff0e3824006e35" |
||||
|
||||
[[package]] |
||||
name = "hmac" |
||||
version = "0.10.1" |
||||
source = "registry+https://github.com/rust-lang/crates.io-index" |
||||
checksum = "c1441c6b1e930e2817404b5046f1f989899143a12bf92de603b69f4e0aee1e15" |
||||
dependencies = [ |
||||
"crypto-mac", |
||||
"digest", |
||||
] |
||||
|
||||
[[package]] |
||||
name = "impl-codec" |
||||
version = "0.4.2" |
||||
source = "registry+https://github.com/rust-lang/crates.io-index" |
||||
checksum = "1be51a921b067b0eaca2fad532d9400041561aa922221cc65f95a85641c6bf53" |
||||
dependencies = [ |
||||
"parity-scale-codec", |
||||
] |
||||
|
||||
[[package]] |
||||
name = "impl-rlp" |
||||
version = "0.3.0" |
||||
source = "registry+https://github.com/rust-lang/crates.io-index" |
||||
checksum = "f28220f89297a075ddc7245cd538076ee98b01f2a9c23a53a4f1105d5a322808" |
||||
dependencies = [ |
||||
"rlp", |
||||
] |
||||
|
||||
[[package]] |
||||
name = "impl-serde" |
||||
version = "0.3.1" |
||||
source = "registry+https://github.com/rust-lang/crates.io-index" |
||||
checksum = "b47ca4d2b6931707a55fce5cf66aff80e2178c8b63bbb4ecb5695cbc870ddf6f" |
||||
dependencies = [ |
||||
"serde", |
||||
] |
||||
|
||||
[[package]] |
||||
name = "itoa" |
||||
version = "0.4.7" |
||||
source = "registry+https://github.com/rust-lang/crates.io-index" |
||||
checksum = "dd25036021b0de88a0aff6b850051563c6516d0bf53f8638938edbb9de732736" |
||||
|
||||
[[package]] |
||||
name = "k256" |
||||
version = "0.7.1" |
||||
source = "registry+https://github.com/rust-lang/crates.io-index" |
||||
checksum = "e443f962f64bcd3753b09e9d6c3733986a81e49b2a36c3c2faaedbe2c3a8e7dd" |
||||
dependencies = [ |
||||
"cfg-if", |
||||
"ecdsa", |
||||
"elliptic-curve", |
||||
"sha3", |
||||
] |
||||
|
||||
[[package]] |
||||
name = "keccak" |
||||
version = "0.1.0" |
||||
source = "registry+https://github.com/rust-lang/crates.io-index" |
||||
checksum = "67c21572b4949434e4fc1e1978b99c5f77064153c59d998bf13ecd96fb5ecba7" |
||||
|
||||
[[package]] |
||||
name = "lazy_static" |
||||
version = "1.4.0" |
||||
source = "registry+https://github.com/rust-lang/crates.io-index" |
||||
checksum = "e2abad23fbc42b3700f2f279844dc832adb2b2eb069b2df918f455c4e18cc646" |
||||
|
||||
[[package]] |
||||
name = "libc" |
||||
version = "0.2.82" |
||||
source = "registry+https://github.com/rust-lang/crates.io-index" |
||||
checksum = "89203f3fba0a3795506acaad8ebce3c80c0af93f994d5a1d7a0b1eeb23271929" |
||||
|
||||
[[package]] |
||||
name = "once_cell" |
||||
version = "1.5.2" |
||||
source = "registry+https://github.com/rust-lang/crates.io-index" |
||||
checksum = "13bd41f508810a131401606d54ac32a467c97172d74ba7662562ebba5ad07fa0" |
||||
|
||||
[[package]] |
||||
name = "opaque-debug" |
||||
version = "0.3.0" |
||||
source = "registry+https://github.com/rust-lang/crates.io-index" |
||||
checksum = "624a8340c38c1b80fd549087862da4ba43e08858af025b236e509b6649fc13d5" |
||||
|
||||
[[package]] |
||||
name = "optics-core" |
||||
version = "0.1.0" |
||||
dependencies = [ |
||||
"ethers-core", |
||||
"ethers-signers", |
||||
"lazy_static", |
||||
"sha3", |
||||
"thiserror", |
||||
] |
||||
|
||||
[[package]] |
||||
name = "parity-scale-codec" |
||||
version = "1.3.6" |
||||
source = "registry+https://github.com/rust-lang/crates.io-index" |
||||
checksum = "79602888a81ace83e3d1d4b2873286c1f5f906c84db667594e8db8da3506c383" |
||||
dependencies = [ |
||||
"arrayvec", |
||||
"bitvec 0.17.4", |
||||
"byte-slice-cast", |
||||
"serde", |
||||
] |
||||
|
||||
[[package]] |
||||
name = "pin-project-lite" |
||||
version = "0.2.4" |
||||
source = "registry+https://github.com/rust-lang/crates.io-index" |
||||
checksum = "439697af366c49a6d0a010c56a0d97685bc140ce0d377b13a2ea2aa42d64a827" |
||||
|
||||
[[package]] |
||||
name = "pin-utils" |
||||
version = "0.1.0" |
||||
source = "registry+https://github.com/rust-lang/crates.io-index" |
||||
checksum = "8b870d8c151b6f2fb93e84a13146138f05d02ed11c7e7c54f8826aaaf7c9f184" |
||||
|
||||
[[package]] |
||||
name = "ppv-lite86" |
||||
version = "0.2.10" |
||||
source = "registry+https://github.com/rust-lang/crates.io-index" |
||||
checksum = "ac74c624d6b2d21f425f752262f42188365d7b8ff1aff74c82e45136510a4857" |
||||
|
||||
[[package]] |
||||
name = "primitive-types" |
||||
version = "0.8.0" |
||||
source = "registry+https://github.com/rust-lang/crates.io-index" |
||||
checksum = "b3824ae2c5e27160113b9e029a10ec9e3f0237bad8029f69c7724393c9fdefd8" |
||||
dependencies = [ |
||||
"fixed-hash", |
||||
"impl-codec", |
||||
"impl-rlp", |
||||
"impl-serde", |
||||
"uint", |
||||
] |
||||
|
||||
[[package]] |
||||
name = "proc-macro-hack" |
||||
version = "0.5.19" |
||||
source = "registry+https://github.com/rust-lang/crates.io-index" |
||||
checksum = "dbf0c48bc1d91375ae5c3cd81e3722dff1abcf81a30960240640d223f59fe0e5" |
||||
|
||||
[[package]] |
||||
name = "proc-macro-nested" |
||||
version = "0.1.6" |
||||
source = "registry+https://github.com/rust-lang/crates.io-index" |
||||
checksum = "eba180dafb9038b050a4c280019bbedf9f2467b61e5d892dcad585bb57aadc5a" |
||||
|
||||
[[package]] |
||||
name = "proc-macro2" |
||||
version = "1.0.24" |
||||
source = "registry+https://github.com/rust-lang/crates.io-index" |
||||
checksum = "1e0704ee1a7e00d7bb417d0770ea303c1bccbabf0ef1667dae92b5967f5f8a71" |
||||
dependencies = [ |
||||
"unicode-xid", |
||||
] |
||||
|
||||
[[package]] |
||||
name = "quote" |
||||
version = "1.0.8" |
||||
source = "registry+https://github.com/rust-lang/crates.io-index" |
||||
checksum = "991431c3519a3f36861882da93630ce66b52918dcf1b8e2fd66b397fc96f28df" |
||||
dependencies = [ |
||||
"proc-macro2", |
||||
] |
||||
|
||||
[[package]] |
||||
name = "radium" |
||||
version = "0.3.0" |
||||
source = "registry+https://github.com/rust-lang/crates.io-index" |
||||
checksum = "def50a86306165861203e7f84ecffbbdfdea79f0e51039b33de1e952358c47ac" |
||||
|
||||
[[package]] |
||||
name = "radium" |
||||
version = "0.4.1" |
||||
source = "registry+https://github.com/rust-lang/crates.io-index" |
||||
checksum = "64de9a0c5361e034f1aefc9f71a86871ec870e766fe31a009734a989b329286a" |
||||
|
||||
[[package]] |
||||
name = "rand" |
||||
version = "0.3.23" |
||||
source = "registry+https://github.com/rust-lang/crates.io-index" |
||||
checksum = "64ac302d8f83c0c1974bf758f6b041c6c8ada916fbb44a609158ca8b064cc76c" |
||||
dependencies = [ |
||||
"libc", |
||||
"rand 0.4.6", |
||||
] |
||||
|
||||
[[package]] |
||||
name = "rand" |
||||
version = "0.4.6" |
||||
source = "registry+https://github.com/rust-lang/crates.io-index" |
||||
checksum = "552840b97013b1a26992c11eac34bdd778e464601a4c2054b5f0bff7c6761293" |
||||
dependencies = [ |
||||
"fuchsia-cprng", |
||||
"libc", |
||||
"rand_core 0.3.1", |
||||
"rdrand", |
||||
"winapi", |
||||
] |
||||
|
||||
[[package]] |
||||
name = "rand" |
||||
version = "0.7.3" |
||||
source = "registry+https://github.com/rust-lang/crates.io-index" |
||||
checksum = "6a6b1679d49b24bbfe0c803429aa1874472f50d9b363131f0e89fc356b544d03" |
||||
dependencies = [ |
||||
"getrandom 0.1.16", |
||||
"libc", |
||||
"rand_chacha 0.2.2", |
||||
"rand_core 0.5.1", |
||||
"rand_hc", |
||||
] |
||||
|
||||
[[package]] |
||||
name = "rand" |
||||
version = "0.8.1" |
||||
source = "registry+https://github.com/rust-lang/crates.io-index" |
||||
checksum = "c24fcd450d3fa2b592732565aa4f17a27a61c65ece4726353e000939b0edee34" |
||||
dependencies = [ |
||||
"libc", |
||||
"rand_chacha 0.3.0", |
||||
"rand_core 0.6.1", |
||||
] |
||||
|
||||
[[package]] |
||||
name = "rand_chacha" |
||||
version = "0.2.2" |
||||
source = "registry+https://github.com/rust-lang/crates.io-index" |
||||
checksum = "f4c8ed856279c9737206bf725bf36935d8666ead7aa69b52be55af369d193402" |
||||
dependencies = [ |
||||
"ppv-lite86", |
||||
"rand_core 0.5.1", |
||||
] |
||||
|
||||
[[package]] |
||||
name = "rand_chacha" |
||||
version = "0.3.0" |
||||
source = "registry+https://github.com/rust-lang/crates.io-index" |
||||
checksum = "e12735cf05c9e10bf21534da50a147b924d555dc7a547c42e6bb2d5b6017ae0d" |
||||
dependencies = [ |
||||
"ppv-lite86", |
||||
"rand_core 0.6.1", |
||||
] |
||||
|
||||
[[package]] |
||||
name = "rand_core" |
||||
version = "0.3.1" |
||||
source = "registry+https://github.com/rust-lang/crates.io-index" |
||||
checksum = "7a6fdeb83b075e8266dcc8762c22776f6877a63111121f5f8c7411e5be7eed4b" |
||||
dependencies = [ |
||||
"rand_core 0.4.2", |
||||
] |
||||
|
||||
[[package]] |
||||
name = "rand_core" |
||||
version = "0.4.2" |
||||
source = "registry+https://github.com/rust-lang/crates.io-index" |
||||
checksum = "9c33a3c44ca05fa6f1807d8e6743f3824e8509beca625669633be0acbdf509dc" |
||||
|
||||
[[package]] |
||||
name = "rand_core" |
||||
version = "0.5.1" |
||||
source = "registry+https://github.com/rust-lang/crates.io-index" |
||||
checksum = "90bde5296fc891b0cef12a6d03ddccc162ce7b2aff54160af9338f8d40df6d19" |
||||
dependencies = [ |
||||
"getrandom 0.1.16", |
||||
] |
||||
|
||||
[[package]] |
||||
name = "rand_core" |
||||
version = "0.6.1" |
||||
source = "registry+https://github.com/rust-lang/crates.io-index" |
||||
checksum = "c026d7df8b298d90ccbbc5190bd04d85e159eaf5576caeacf8741da93ccbd2e5" |
||||
dependencies = [ |
||||
"getrandom 0.2.1", |
||||
] |
||||
|
||||
[[package]] |
||||
name = "rand_hc" |
||||
version = "0.2.0" |
||||
source = "registry+https://github.com/rust-lang/crates.io-index" |
||||
checksum = "ca3129af7b92a17112d59ad498c6f81eaf463253766b90396d39ea7a39d6613c" |
||||
dependencies = [ |
||||
"rand_core 0.5.1", |
||||
] |
||||
|
||||
[[package]] |
||||
name = "rdrand" |
||||
version = "0.4.0" |
||||
source = "registry+https://github.com/rust-lang/crates.io-index" |
||||
checksum = "678054eb77286b51581ba43620cc911abf02758c91f93f479767aed0f90458b2" |
||||
dependencies = [ |
||||
"rand_core 0.3.1", |
||||
] |
||||
|
||||
[[package]] |
||||
name = "rlp" |
||||
version = "0.5.0" |
||||
source = "registry+https://github.com/rust-lang/crates.io-index" |
||||
checksum = "e54369147e3e7796c9b885c7304db87ca3d09a0a98f72843d532868675bbfba8" |
||||
dependencies = [ |
||||
"bytes", |
||||
"rustc-hex", |
||||
] |
||||
|
||||
[[package]] |
||||
name = "rust-crypto" |
||||
version = "0.2.36" |
||||
source = "registry+https://github.com/rust-lang/crates.io-index" |
||||
checksum = "f76d05d3993fd5f4af9434e8e436db163a12a9d40e1a58a726f27a01dfd12a2a" |
||||
dependencies = [ |
||||
"gcc", |
||||
"libc", |
||||
"rand 0.3.23", |
||||
"rustc-serialize", |
||||
"time", |
||||
] |
||||
|
||||
[[package]] |
||||
name = "rustc-hex" |
||||
version = "2.1.0" |
||||
source = "registry+https://github.com/rust-lang/crates.io-index" |
||||
checksum = "3e75f6a532d0fd9f7f13144f392b6ad56a32696bfcd9c78f797f16bbb6f072d6" |
||||
|
||||
[[package]] |
||||
name = "rustc-serialize" |
||||
version = "0.3.24" |
||||
source = "registry+https://github.com/rust-lang/crates.io-index" |
||||
checksum = "dcf128d1287d2ea9d80910b5f1120d0b8eede3fbf1abe91c40d39ea7d51e6fda" |
||||
|
||||
[[package]] |
||||
name = "ryu" |
||||
version = "1.0.5" |
||||
source = "registry+https://github.com/rust-lang/crates.io-index" |
||||
checksum = "71d301d4193d031abdd79ff7e3dd721168a9572ef3fe51a1517aba235bd8f86e" |
||||
|
||||
[[package]] |
||||
name = "serde" |
||||
version = "1.0.119" |
||||
source = "registry+https://github.com/rust-lang/crates.io-index" |
||||
checksum = "9bdd36f49e35b61d49efd8aa7fc068fd295961fd2286d0b2ee9a4c7a14e99cc3" |
||||
dependencies = [ |
||||
"serde_derive", |
||||
] |
||||
|
||||
[[package]] |
||||
name = "serde_derive" |
||||
version = "1.0.119" |
||||
source = "registry+https://github.com/rust-lang/crates.io-index" |
||||
checksum = "552954ce79a059ddd5fd68c271592374bd15cab2274970380c000118aeffe1cd" |
||||
dependencies = [ |
||||
"proc-macro2", |
||||
"quote", |
||||
"syn", |
||||
] |
||||
|
||||
[[package]] |
||||
name = "serde_json" |
||||
version = "1.0.61" |
||||
source = "registry+https://github.com/rust-lang/crates.io-index" |
||||
checksum = "4fceb2595057b6891a4ee808f70054bd2d12f0e97f1cbb78689b59f676df325a" |
||||
dependencies = [ |
||||
"itoa", |
||||
"ryu", |
||||
"serde", |
||||
] |
||||
|
||||
[[package]] |
||||
name = "sha2" |
||||
version = "0.9.2" |
||||
source = "registry+https://github.com/rust-lang/crates.io-index" |
||||
checksum = "6e7aab86fe2149bad8c507606bdb3f4ef5e7b2380eb92350f56122cca72a42a8" |
||||
dependencies = [ |
||||
"block-buffer", |
||||
"cfg-if", |
||||
"cpuid-bool", |
||||
"digest", |
||||
"opaque-debug", |
||||
] |
||||
|
||||
[[package]] |
||||
name = "sha3" |
||||
version = "0.9.1" |
||||
source = "registry+https://github.com/rust-lang/crates.io-index" |
||||
checksum = "f81199417d4e5de3f04b1e871023acea7389672c4135918f05aa9cbf2f2fa809" |
||||
dependencies = [ |
||||
"block-buffer", |
||||
"digest", |
||||
"keccak", |
||||
"opaque-debug", |
||||
] |
||||
|
||||
[[package]] |
||||
name = "signature" |
||||
version = "1.2.2" |
||||
source = "registry+https://github.com/rust-lang/crates.io-index" |
||||
checksum = "29f060a7d147e33490ec10da418795238fd7545bba241504d6b31a409f2e6210" |
||||
dependencies = [ |
||||
"digest", |
||||
"rand_core 0.5.1", |
||||
] |
||||
|
||||
[[package]] |
||||
name = "slab" |
||||
version = "0.4.2" |
||||
source = "registry+https://github.com/rust-lang/crates.io-index" |
||||
checksum = "c111b5bd5695e56cffe5129854aa230b39c93a305372fdbb2668ca2394eea9f8" |
||||
|
||||
[[package]] |
||||
name = "static_assertions" |
||||
version = "1.1.0" |
||||
source = "registry+https://github.com/rust-lang/crates.io-index" |
||||
checksum = "a2eb9349b6444b326872e140eb1cf5e7c522154d69e7a0ffb0fb81c06b37543f" |
||||
|
||||
[[package]] |
||||
name = "subtle" |
||||
version = "2.4.0" |
||||
source = "registry+https://github.com/rust-lang/crates.io-index" |
||||
checksum = "1e81da0851ada1f3e9d4312c704aa4f8806f0f9d69faaf8df2f3464b4a9437c2" |
||||
|
||||
[[package]] |
||||
name = "syn" |
||||
version = "1.0.58" |
||||
source = "registry+https://github.com/rust-lang/crates.io-index" |
||||
checksum = "cc60a3d73ea6594cd712d830cc1f0390fd71542d8c8cd24e70cc54cdfd5e05d5" |
||||
dependencies = [ |
||||
"proc-macro2", |
||||
"quote", |
||||
"unicode-xid", |
||||
] |
||||
|
||||
[[package]] |
||||
name = "thiserror" |
||||
version = "1.0.23" |
||||
source = "registry+https://github.com/rust-lang/crates.io-index" |
||||
checksum = "76cc616c6abf8c8928e2fdcc0dbfab37175edd8fb49a4641066ad1364fdab146" |
||||
dependencies = [ |
||||
"thiserror-impl", |
||||
] |
||||
|
||||
[[package]] |
||||
name = "thiserror-impl" |
||||
version = "1.0.23" |
||||
source = "registry+https://github.com/rust-lang/crates.io-index" |
||||
checksum = "9be73a2caec27583d0046ef3796c3794f868a5bc813db689eed00c7631275cd1" |
||||
dependencies = [ |
||||
"proc-macro2", |
||||
"quote", |
||||
"syn", |
||||
] |
||||
|
||||
[[package]] |
||||
name = "time" |
||||
version = "0.1.43" |
||||
source = "registry+https://github.com/rust-lang/crates.io-index" |
||||
checksum = "ca8a50ef2360fbd1eeb0ecd46795a87a19024eb4b53c5dc916ca1fd95fe62438" |
||||
dependencies = [ |
||||
"libc", |
||||
"winapi", |
||||
] |
||||
|
||||
[[package]] |
||||
name = "tiny-keccak" |
||||
version = "2.0.2" |
||||
source = "registry+https://github.com/rust-lang/crates.io-index" |
||||
checksum = "2c9d3793400a45f954c52e73d068316d76b6f4e36977e3fcebb13a2721e80237" |
||||
dependencies = [ |
||||
"crunchy", |
||||
] |
||||
|
||||
[[package]] |
||||
name = "typenum" |
||||
version = "1.12.0" |
||||
source = "registry+https://github.com/rust-lang/crates.io-index" |
||||
checksum = "373c8a200f9e67a0c95e62a4f52fbf80c23b4381c05a17845531982fa99e6b33" |
||||
|
||||
[[package]] |
||||
name = "uint" |
||||
version = "0.9.0" |
||||
source = "registry+https://github.com/rust-lang/crates.io-index" |
||||
checksum = "e11fe9a9348741cf134085ad57c249508345fe16411b3d7fb4ff2da2f1d6382e" |
||||
dependencies = [ |
||||
"byteorder", |
||||
"crunchy", |
||||
"hex", |
||||
"static_assertions", |
||||
] |
||||
|
||||
[[package]] |
||||
name = "unicode-xid" |
||||
version = "0.2.1" |
||||
source = "registry+https://github.com/rust-lang/crates.io-index" |
||||
checksum = "f7fe0bb3479651439c9112f72b6c505038574c9fbb575ed1bf3b797fa39dd564" |
||||
|
||||
[[package]] |
||||
name = "uuid" |
||||
version = "0.8.2" |
||||
source = "registry+https://github.com/rust-lang/crates.io-index" |
||||
checksum = "bc5cf98d8186244414c848017f0e2676b3fcb46807f6668a97dfe67359a3c4b7" |
||||
dependencies = [ |
||||
"getrandom 0.2.1", |
||||
"serde", |
||||
] |
||||
|
||||
[[package]] |
||||
name = "version_check" |
||||
version = "0.9.2" |
||||
source = "registry+https://github.com/rust-lang/crates.io-index" |
||||
checksum = "b5a972e5669d67ba988ce3dc826706fb0a8b01471c088cb0b6110b805cc36aed" |
||||
|
||||
[[package]] |
||||
name = "wasi" |
||||
version = "0.9.0+wasi-snapshot-preview1" |
||||
source = "registry+https://github.com/rust-lang/crates.io-index" |
||||
checksum = "cccddf32554fecc6acb585f82a32a72e28b48f8c4c1883ddfeeeaa96f7d8e519" |
||||
|
||||
[[package]] |
||||
name = "wasi" |
||||
version = "0.10.1+wasi-snapshot-preview1" |
||||
source = "registry+https://github.com/rust-lang/crates.io-index" |
||||
checksum = "93c6c3420963c5c64bca373b25e77acb562081b9bb4dd5bb864187742186cea9" |
||||
|
||||
[[package]] |
||||
name = "winapi" |
||||
version = "0.3.9" |
||||
source = "registry+https://github.com/rust-lang/crates.io-index" |
||||
checksum = "5c839a674fcd7a98952e593242ea400abe93992746761e38641405d28b00f419" |
||||
dependencies = [ |
||||
"winapi-i686-pc-windows-gnu", |
||||
"winapi-x86_64-pc-windows-gnu", |
||||
] |
||||
|
||||
[[package]] |
||||
name = "winapi-i686-pc-windows-gnu" |
||||
version = "0.4.0" |
||||
source = "registry+https://github.com/rust-lang/crates.io-index" |
||||
checksum = "ac3b87c63620426dd9b991e5ce0329eff545bccbbb34f3be09ff6fb6ab51b7b6" |
||||
|
||||
[[package]] |
||||
name = "winapi-x86_64-pc-windows-gnu" |
||||
version = "0.4.0" |
||||
source = "registry+https://github.com/rust-lang/crates.io-index" |
||||
checksum = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f" |
||||
|
||||
[[package]] |
||||
name = "wyz" |
||||
version = "0.2.0" |
||||
source = "registry+https://github.com/rust-lang/crates.io-index" |
||||
checksum = "85e60b0d1b5f99db2556934e21937020776a5d31520bf169e851ac44e6420214" |
||||
|
||||
[[package]] |
||||
name = "zeroize" |
||||
version = "1.2.0" |
||||
source = "registry+https://github.com/rust-lang/crates.io-index" |
||||
checksum = "81a974bcdd357f0dca4d41677db03436324d45a4c9ed2d0b873a5a360ce41c36" |
@ -0,0 +1,14 @@ |
||||
[package] |
||||
name = "optics-core" |
||||
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] |
||||
ethers-core = { git = "https://github.com/gakonst/ethers-rs" } |
||||
ethers-signers = { git = "https://github.com/gakonst/ethers-rs" } |
||||
sha3 = "0.9.1" |
||||
lazy_static = "*" |
||||
thiserror = "*" |
@ -0,0 +1,159 @@ |
||||
use crate::{ |
||||
merkle::{verify_merkle_proof, MerkleTree, ZERO_HASHES}, |
||||
*, |
||||
}; |
||||
use ethers_core::types::H256; |
||||
use sha3::Keccak256; |
||||
|
||||
pub const TREE_DEPTH: usize = 32; |
||||
pub const MAX_MESSAGES: u32 = u32::MAX; |
||||
|
||||
#[derive(Debug, Clone, Copy)] |
||||
pub struct Proof { |
||||
leaf: H256, |
||||
index: usize, |
||||
path: [H256; TREE_DEPTH], |
||||
} |
||||
|
||||
#[derive(Debug, Clone, Copy)] |
||||
pub struct IncrementalMerkle { |
||||
branch: [H256; TREE_DEPTH], |
||||
count: u32, |
||||
} |
||||
|
||||
fn hash_concat(left: impl AsRef<[u8]>, right: impl AsRef<[u8]>) -> H256 { |
||||
let mut k = Keccak256::new(); |
||||
k.update(left.as_ref()); |
||||
k.update(right.as_ref()); |
||||
let digest = k.finalize(); |
||||
H256::from_slice(digest.as_slice()) |
||||
} |
||||
|
||||
impl Default for IncrementalMerkle { |
||||
fn default() -> Self { |
||||
let mut branch: [H256; TREE_DEPTH] = Default::default(); |
||||
branch |
||||
.iter_mut() |
||||
.enumerate() |
||||
.for_each(|(i, elem)| *elem = ZERO_HASHES[i]); |
||||
Self { branch, count: 0 } |
||||
} |
||||
} |
||||
|
||||
impl IncrementalMerkle { |
||||
pub fn ingest(&mut self, element: H256) { |
||||
let mut node = element; |
||||
self.count += 1; |
||||
let mut size = self.count; |
||||
for i in 0..TREE_DEPTH { |
||||
if (size & 1) == 1 { |
||||
self.branch[i] = node; |
||||
return; |
||||
} |
||||
node = hash_concat(self.branch[i], node); |
||||
size /= 2; |
||||
} |
||||
unreachable!() |
||||
} |
||||
|
||||
pub fn root(&self) -> H256 { |
||||
let mut node: H256 = Default::default(); |
||||
let mut size = self.count; |
||||
|
||||
self.branch.iter().enumerate().for_each(|(i, elem)| { |
||||
node = if (size & 1) == 1 { |
||||
hash_concat(elem, node) |
||||
} else { |
||||
hash_concat(node, ZERO_HASHES[i]) |
||||
}; |
||||
size /= 2; |
||||
}); |
||||
|
||||
node |
||||
} |
||||
|
||||
pub fn count(&self) -> u32 { |
||||
self.count |
||||
} |
||||
|
||||
pub fn branch(&self) -> &[H256; TREE_DEPTH] { |
||||
&self.branch |
||||
} |
||||
} |
||||
|
||||
#[derive(Debug)] |
||||
pub struct IncrementalMerkleProver { |
||||
light: IncrementalMerkle, |
||||
full: MerkleTree, |
||||
} |
||||
|
||||
impl Default for IncrementalMerkleProver { |
||||
fn default() -> Self { |
||||
let light = IncrementalMerkle::default(); |
||||
let full = MerkleTree::create(&[], TREE_DEPTH); |
||||
Self { light, full } |
||||
} |
||||
} |
||||
|
||||
impl IncrementalMerkleProver { |
||||
pub fn ingest(&mut self, element: H256) -> H256 { |
||||
self.light.ingest(element); |
||||
self.full.push_leaf(element, TREE_DEPTH).unwrap(); |
||||
debug_assert_eq!(self.light.root(), self.full.hash()); |
||||
self.full.hash() |
||||
} |
||||
|
||||
pub fn root(&self) -> H256 { |
||||
self.full.hash() |
||||
} |
||||
|
||||
pub fn count(&self) -> u32 { |
||||
self.light.count() |
||||
} |
||||
|
||||
pub fn prove(&self, index: usize) -> Result<Proof, ()> { |
||||
if index > u32::MAX as usize { |
||||
return Err(()); |
||||
} |
||||
let (leaf, hashes) = self.full.generate_proof(index, TREE_DEPTH); |
||||
let mut path = [H256::zero(); 32]; |
||||
path.copy_from_slice(&hashes[..32]); |
||||
Ok(Proof { leaf, index, path }) |
||||
} |
||||
|
||||
pub fn verify(&self, proof: &Proof) -> Result<(), ()> { |
||||
if verify_merkle_proof( |
||||
proof.leaf, |
||||
proof.path.as_ref(), |
||||
TREE_DEPTH, |
||||
proof.index, |
||||
self.root(), |
||||
) { |
||||
Ok(()) |
||||
} else { |
||||
Err(()) |
||||
} |
||||
} |
||||
} |
||||
|
||||
#[cfg(test)] |
||||
mod test { |
||||
use super::*; |
||||
|
||||
#[test] |
||||
fn it_test() { |
||||
let mut tree = IncrementalMerkleProver::default(); |
||||
|
||||
let elements: Vec<_> = (1..32).map(|i| H256::repeat_byte(i as u8)).collect(); |
||||
tree.ingest(elements[0]); |
||||
tree.ingest(elements[1]); |
||||
tree.ingest(elements[2]); |
||||
|
||||
assert_eq!(tree.count(), 3); |
||||
|
||||
let idx = 1; |
||||
let proof = tree.prove(idx).unwrap(); |
||||
dbg!(&proof); |
||||
tree.verify(&proof).unwrap(); |
||||
} |
||||
} |
@ -0,0 +1,157 @@ |
||||
use ethers_core::types::H256; |
||||
use std::{collections::VecDeque, io::Write}; |
||||
|
||||
use crate::{accumulator::*, *}; |
||||
|
||||
#[derive(Default, Debug, Clone)] |
||||
pub struct Waiting { |
||||
queue: VecDeque<H256>, |
||||
accumulator: IncrementalMerkle, |
||||
} |
||||
|
||||
#[derive(Debug, Clone)] |
||||
pub struct Failed { |
||||
queue: VecDeque<H256>, |
||||
accumulator: IncrementalMerkle, |
||||
} |
||||
|
||||
impl Waiting { |
||||
pub fn queue(&self) -> &VecDeque<H256> { |
||||
&self.queue |
||||
} |
||||
|
||||
pub fn accumulator(&self) -> &IncrementalMerkle { |
||||
&self.accumulator |
||||
} |
||||
} |
||||
|
||||
impl Failed { |
||||
pub fn queue(&self) -> &VecDeque<H256> { |
||||
&self.queue |
||||
} |
||||
|
||||
pub fn accumulator(&self) -> &IncrementalMerkle { |
||||
&self.accumulator |
||||
} |
||||
} |
||||
|
||||
fn format_message( |
||||
origin: u32, |
||||
sender: H256, |
||||
destination: u32, |
||||
recipient: H256, |
||||
body: &[u8], |
||||
) -> Vec<u8> { |
||||
let mut buf = vec![]; |
||||
buf.write_all(&origin.to_be_bytes()).unwrap(); |
||||
buf.write_all(sender.as_ref()).unwrap(); |
||||
buf.write_all(&destination.to_be_bytes()).unwrap(); |
||||
buf.write_all(recipient.as_ref()).unwrap(); |
||||
buf.write_all(&body).unwrap(); |
||||
buf |
||||
} |
||||
|
||||
#[derive(Debug, Clone)] |
||||
pub struct Home<S> { |
||||
origin: u32, |
||||
updater: Address, |
||||
current_root: H256, |
||||
state: S, |
||||
} |
||||
|
||||
impl<S> Home<S> { |
||||
pub fn origin(&self) -> u32 { |
||||
self.origin |
||||
} |
||||
|
||||
pub fn updater(&self) -> Address { |
||||
self.updater |
||||
} |
||||
|
||||
pub fn state(&self) -> &S { |
||||
&self.state |
||||
} |
||||
|
||||
fn check_sig(&self, update: &SignedUpdate) -> Result<(), ()> { |
||||
let signer = update.recover()?; |
||||
if signer == self.updater { |
||||
Ok(()) |
||||
} else { |
||||
Err(()) |
||||
} |
||||
} |
||||
} |
||||
|
||||
impl From<Home<Waiting>> for Home<Failed> { |
||||
fn from(h: Home<Waiting>) -> Self { |
||||
Self { |
||||
origin: h.origin, |
||||
updater: h.updater, |
||||
current_root: h.current_root, |
||||
state: Failed { |
||||
accumulator: h.state.accumulator, |
||||
queue: h.state.queue, |
||||
}, |
||||
} |
||||
} |
||||
} |
||||
|
||||
impl Home<Waiting> { |
||||
pub fn init(origin: u32, updater: Address) -> Home<Waiting> { |
||||
Self { |
||||
origin, |
||||
updater, |
||||
current_root: Default::default(), |
||||
state: Waiting::default(), |
||||
} |
||||
} |
||||
|
||||
pub fn enqueue(&mut self, sender: H256, destination: u32, recipient: H256, body: &[u8]) { |
||||
let message = format_message(self.origin, sender, destination, recipient, body); |
||||
let message_hash = keccak256(message); |
||||
self.state.accumulator.ingest(message_hash); |
||||
self.state.queue.push_back(self.state.accumulator.root()); |
||||
} |
||||
|
||||
fn _update(&mut self, update: &Update) -> Result<(), ()> { |
||||
if update.previous_root != self.current_root { |
||||
return Err(()); |
||||
} |
||||
|
||||
if self.state.queue.contains(&update.new_root) { |
||||
loop { |
||||
let item = self.state.queue.pop_front().unwrap(); |
||||
if item == update.new_root { |
||||
return Ok(()); |
||||
} |
||||
} |
||||
} |
||||
|
||||
Err(()) |
||||
} |
||||
|
||||
pub fn update(&mut self, update: &SignedUpdate) -> Result<(), ()> { |
||||
self.check_sig(update)?; |
||||
self._update(&update.update) |
||||
} |
||||
|
||||
pub fn double_update( |
||||
self, |
||||
first: &SignedUpdate, |
||||
second: &SignedUpdate, |
||||
) -> Result<Home<Failed>, Home<Waiting>> { |
||||
if first == second || self.check_sig(first).is_err() || self.check_sig(second).is_err() { |
||||
Err(self) |
||||
} else { |
||||
Ok(self.into()) |
||||
} |
||||
} |
||||
|
||||
pub fn improper_update(self, update: &SignedUpdate) -> Result<Home<Failed>, Home<Waiting>> { |
||||
if self.check_sig(update).is_err() || self.state.queue.contains(&update.update.new_root) { |
||||
Err(self) |
||||
} else { |
||||
Ok(self.into()) |
||||
} |
||||
} |
||||
} |
@ -0,0 +1,135 @@ |
||||
pub mod accumulator; |
||||
pub mod home; |
||||
mod merkle; |
||||
pub mod replica; |
||||
|
||||
use ethers_core::types::{Address, Signature, H256}; |
||||
use ethers_signers::Signer; |
||||
use sha3::{Digest, Keccak256}; |
||||
|
||||
pub trait Encode { |
||||
fn write_to<W>(&self, writer: &mut W) -> std::io::Result<usize> |
||||
where |
||||
W: std::io::Write; |
||||
} |
||||
|
||||
impl Encode for Signature { |
||||
fn write_to<W>(&self, writer: &mut W) -> std::io::Result<usize> |
||||
where |
||||
W: std::io::Write, |
||||
{ |
||||
writer.write_all(&self.to_vec())?; |
||||
Ok(64) |
||||
} |
||||
} |
||||
|
||||
fn keccak256(buf: impl AsRef<[u8]>) -> H256 { |
||||
H256::from_slice(Keccak256::digest(buf.as_ref()).as_slice()) |
||||
} |
||||
|
||||
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() |
||||
) |
||||
} |
||||
|
||||
#[derive(Debug, Clone)] |
||||
pub struct Message { |
||||
origin: u32, // 4 SLIP-44 ID
|
||||
sender: H256, // 32 Address in origin convention
|
||||
destination: u32, // 4 SLIP-44 ID
|
||||
recipient: H256, // 32 Address in destination convention
|
||||
sequence: u32, // 4 Count of all previous messages to destination
|
||||
body: Vec<u8>, // 0+ Message contents
|
||||
} |
||||
|
||||
impl Encode for Message { |
||||
fn write_to<W>(&self, writer: &mut W) -> std::io::Result<usize> |
||||
where |
||||
W: std::io::Write, |
||||
{ |
||||
writer.write_all(&self.origin.to_be_bytes())?; |
||||
writer.write_all(self.sender.as_ref())?; |
||||
writer.write_all(&self.destination.to_be_bytes())?; |
||||
writer.write_all(self.recipient.as_ref())?; |
||||
writer.write_all(&self.sequence.to_be_bytes())?; |
||||
Ok(36 + 36 + 4 + self.body.len()) |
||||
} |
||||
} |
||||
|
||||
#[derive(Copy, Clone, Debug, Eq, PartialEq)] |
||||
pub struct Update { |
||||
origin_chain: u32, |
||||
previous_root: H256, |
||||
new_root: H256, |
||||
} |
||||
|
||||
impl Encode for Update { |
||||
fn write_to<W>(&self, writer: &mut W) -> std::io::Result<usize> |
||||
where |
||||
W: std::io::Write, |
||||
{ |
||||
writer.write_all(&self.origin_chain.to_be_bytes())?; |
||||
writer.write_all(self.previous_root.as_ref())?; |
||||
writer.write_all(self.new_root.as_ref())?; |
||||
Ok(4 + 32 + 32) |
||||
} |
||||
} |
||||
|
||||
impl Update { |
||||
fn signing_hash(&self) -> H256 { |
||||
// sign:
|
||||
// domain(origin) || previous_root || new_root
|
||||
H256::from_slice( |
||||
Keccak256::new() |
||||
.chain(domain_hash(self.origin_chain)) |
||||
.chain(self.previous_root) |
||||
.chain(self.new_root) |
||||
.finalize() |
||||
.as_slice(), |
||||
) |
||||
} |
||||
|
||||
pub async fn sign_update<S>(self, signer: S) -> Result<SignedUpdate, S::Error> |
||||
where |
||||
S: Signer, |
||||
{ |
||||
let signature = signer.sign_message(self.signing_hash()).await?; |
||||
Ok(SignedUpdate { |
||||
update: self, |
||||
signature, |
||||
}) |
||||
} |
||||
} |
||||
|
||||
// 129 bytes.
|
||||
// serialized as tightly-packed, sig in RSV format
|
||||
#[derive(Clone, Debug, Eq, PartialEq)] |
||||
pub struct SignedUpdate { |
||||
update: Update, |
||||
signature: Signature, |
||||
} |
||||
|
||||
impl Encode for SignedUpdate { |
||||
fn write_to<W>(&self, writer: &mut W) -> std::io::Result<usize> |
||||
where |
||||
W: std::io::Write, |
||||
{ |
||||
let mut written = 0; |
||||
written += self.update.write_to(writer)?; |
||||
written += self.signature.write_to(writer)?; |
||||
Ok(written) |
||||
} |
||||
} |
||||
|
||||
impl SignedUpdate { |
||||
pub fn recover(&self) -> Result<Address, ()> { |
||||
self.signature |
||||
.recover(self.update.signing_hash()) |
||||
.map_err(|_| ()) |
||||
} |
||||
} |
@ -0,0 +1,634 @@ |
||||
use ethers_core::types::H256; |
||||
use lazy_static::lazy_static; |
||||
use sha3::{Digest, Keccak256}; |
||||
use thiserror::Error; |
||||
|
||||
// Some code has been derived from
|
||||
// https://github.com/sigp/lighthouse/blob/c6baa0eed131c5e8ecc5860778ffc7d4a4c18d2d/consensus/merkle_proof/src/lib.rs#L25
|
||||
// It has been modified as follows:
|
||||
// - improve legibility
|
||||
// - remove eth2-specific features.
|
||||
// - use keccak256
|
||||
// - remove ring dependency
|
||||
// In accordance with its license terms, the apache2 license is reproduced below
|
||||
|
||||
const MAX_TREE_DEPTH: usize = 32; |
||||
const EMPTY_SLICE: &[H256] = &[]; |
||||
|
||||
fn hash_concat(left: impl AsRef<[u8]>, right: impl AsRef<[u8]>) -> H256 { |
||||
H256::from_slice( |
||||
Keccak256::new() |
||||
.chain(left.as_ref()) |
||||
.chain(right.as_ref()) |
||||
.finalize() |
||||
.as_slice(), |
||||
) |
||||
} |
||||
|
||||
lazy_static! { |
||||
/// Zero nodes to act as "synthetic" left and right subtrees of other zero nodes.
|
||||
pub static ref ZERO_NODES: Vec<MerkleTree> = { |
||||
(0..=MAX_TREE_DEPTH).map(MerkleTree::Zero).collect() |
||||
}; |
||||
|
||||
pub static ref ZERO_HASHES: [H256; MAX_TREE_DEPTH + 1] = { |
||||
let mut hashes = [H256::zero(); MAX_TREE_DEPTH + 1]; |
||||
for i in 0..MAX_TREE_DEPTH { |
||||
hashes[i + 1] = hash_concat(hashes[i], hashes[i]); |
||||
} |
||||
hashes |
||||
}; |
||||
} |
||||
|
||||
/// Right-sparse Merkle tree.
|
||||
///
|
||||
/// Efficiently represents a Merkle tree of fixed depth where only the first N
|
||||
/// indices are populated by non-zero leaves (perfect for the deposit contract tree).
|
||||
#[derive(Debug, PartialEq)] |
||||
pub enum MerkleTree { |
||||
/// Leaf node with the hash of its content.
|
||||
Leaf(H256), |
||||
/// Internal node with hash, left subtree and right subtree.
|
||||
Node(H256, Box<Self>, Box<Self>), |
||||
/// Zero subtree of a given depth.
|
||||
///
|
||||
/// It represents a Merkle tree of 2^depth zero leaves.
|
||||
Zero(usize), |
||||
} |
||||
|
||||
#[derive(Debug, PartialEq, Clone, Error)] |
||||
pub enum MerkleTreeError { |
||||
// Trying to push in a leaf
|
||||
#[error("Trying to push in a leaf")] |
||||
LeafReached, |
||||
// No more space in the MerkleTree
|
||||
#[error("No more space in the MerkleTree")] |
||||
MerkleTreeFull, |
||||
// MerkleTree is invalid
|
||||
#[error("MerkleTree is invalid")] |
||||
Invalid, |
||||
// Incorrect Depth provided
|
||||
#[error("Incorrect Depth provided")] |
||||
DepthTooSmall, |
||||
} |
||||
|
||||
impl MerkleTree { |
||||
/// Retrieve the root hash of this Merkle tree.
|
||||
pub fn hash(&self) -> H256 { |
||||
match *self { |
||||
MerkleTree::Leaf(h) => h, |
||||
MerkleTree::Node(h, _, _) => h, |
||||
MerkleTree::Zero(depth) => ZERO_HASHES[depth], |
||||
} |
||||
} |
||||
|
||||
/// Create a new Merkle tree from a list of leaves and a fixed depth.
|
||||
pub fn create(leaves: &[H256], depth: usize) -> Self { |
||||
use MerkleTree::*; |
||||
|
||||
if leaves.is_empty() { |
||||
return Zero(depth); |
||||
} |
||||
|
||||
match depth { |
||||
0 => { |
||||
debug_assert_eq!(leaves.len(), 1); |
||||
Leaf(leaves[0]) |
||||
} |
||||
_ => { |
||||
// Split leaves into left and right subtrees
|
||||
let subtree_capacity = 2usize.pow(depth as u32 - 1); |
||||
let (left_leaves, right_leaves) = if leaves.len() <= subtree_capacity { |
||||
(leaves, EMPTY_SLICE) |
||||
} else { |
||||
leaves.split_at(subtree_capacity) |
||||
}; |
||||
|
||||
let left_subtree = MerkleTree::create(left_leaves, depth - 1); |
||||
let right_subtree = MerkleTree::create(right_leaves, depth - 1); |
||||
let hash = hash_concat(left_subtree.hash(), right_subtree.hash()); |
||||
|
||||
Node(hash, Box::new(left_subtree), Box::new(right_subtree)) |
||||
} |
||||
} |
||||
} |
||||
|
||||
/// Push an element in the MerkleTree.
|
||||
/// MerkleTree and depth must be correct, as the algorithm expects valid data.
|
||||
pub fn push_leaf(&mut self, elem: H256, depth: usize) -> Result<(), MerkleTreeError> { |
||||
use MerkleTree::*; |
||||
|
||||
if depth == 0 { |
||||
return Err(MerkleTreeError::DepthTooSmall); |
||||
} |
||||
|
||||
match self { |
||||
Leaf(_) => return Err(MerkleTreeError::LeafReached), |
||||
Zero(_) => { |
||||
*self = MerkleTree::create(&[elem], depth); |
||||
} |
||||
Node(ref mut hash, ref mut left, ref mut right) => { |
||||
let left: &mut MerkleTree = &mut *left; |
||||
let right: &mut MerkleTree = &mut *right; |
||||
match (&*left, &*right) { |
||||
// Tree is full
|
||||
(Leaf(_), Leaf(_)) => return Err(MerkleTreeError::MerkleTreeFull), |
||||
// There is a right node so insert in right node
|
||||
(Node(_, _, _), Node(_, _, _)) => { |
||||
if let Err(e) = right.push_leaf(elem, depth - 1) { |
||||
return Err(e); |
||||
} |
||||
} |
||||
// Both branches are zero, insert in left one
|
||||
(Zero(_), Zero(_)) => { |
||||
*left = MerkleTree::create(&[elem], depth - 1); |
||||
} |
||||
// Leaf on left branch and zero on right branch, insert on right side
|
||||
(Leaf(_), Zero(_)) => { |
||||
*right = MerkleTree::create(&[elem], depth - 1); |
||||
} |
||||
// Try inserting on the left node -> if it fails because it is full, insert in right side.
|
||||
(Node(_, _, _), Zero(_)) => { |
||||
match left.push_leaf(elem, depth - 1) { |
||||
Ok(_) => (), |
||||
// Left node is full, insert in right node
|
||||
Err(MerkleTreeError::MerkleTreeFull) => { |
||||
*right = MerkleTree::create(&[elem], depth - 1); |
||||
} |
||||
Err(e) => return Err(e), |
||||
}; |
||||
} |
||||
// All other possibilities are invalid MerkleTrees
|
||||
(_, _) => return Err(MerkleTreeError::Invalid), |
||||
}; |
||||
hash.assign_from_slice(hash_concat(left.hash(), right.hash()).as_ref()); |
||||
} |
||||
} |
||||
|
||||
Ok(()) |
||||
} |
||||
/// Get a reference to the left and right subtrees if they exist.
|
||||
pub fn left_and_right_branches(&self) -> Option<(&Self, &Self)> { |
||||
match *self { |
||||
MerkleTree::Leaf(_) | MerkleTree::Zero(0) => None, |
||||
MerkleTree::Node(_, ref l, ref r) => Some((l, r)), |
||||
MerkleTree::Zero(depth) => Some((&ZERO_NODES[depth - 1], &ZERO_NODES[depth - 1])), |
||||
} |
||||
} |
||||
|
||||
/// Is this Merkle tree a leaf?
|
||||
pub fn is_leaf(&self) -> bool { |
||||
matches!(self, MerkleTree::Leaf(_)) |
||||
} |
||||
|
||||
/// Return the leaf at `index` and a Merkle proof of its inclusion.
|
||||
///
|
||||
/// The Merkle proof is in "bottom-up" order, starting with a leaf node
|
||||
/// and moving up the tree. Its length will be exactly equal to `depth`.
|
||||
pub fn generate_proof(&self, index: usize, depth: usize) -> (H256, Vec<H256>) { |
||||
let mut proof = vec![]; |
||||
let mut current_node = self; |
||||
let mut current_depth = depth; |
||||
while current_depth > 0 { |
||||
let ith_bit = (index >> (current_depth - 1)) & 0x01; |
||||
// Note: unwrap is safe because leaves are only ever constructed at depth == 0.
|
||||
let (left, right) = current_node.left_and_right_branches().unwrap(); |
||||
|
||||
// Go right, include the left branch in the proof.
|
||||
if ith_bit == 1 { |
||||
proof.push(left.hash()); |
||||
current_node = right; |
||||
} else { |
||||
proof.push(right.hash()); |
||||
current_node = left; |
||||
} |
||||
current_depth -= 1; |
||||
} |
||||
|
||||
debug_assert_eq!(proof.len(), depth); |
||||
debug_assert!(current_node.is_leaf()); |
||||
|
||||
// Put proof in bottom-up order.
|
||||
proof.reverse(); |
||||
|
||||
(current_node.hash(), proof) |
||||
} |
||||
} |
||||
|
||||
/// Verify a proof that `leaf` exists at `index` in a Merkle tree rooted at `root`.
|
||||
///
|
||||
/// The `branch` argument is the main component of the proof: it should be a list of internal
|
||||
/// node hashes such that the root can be reconstructed (in bottom-up order).
|
||||
pub fn verify_merkle_proof( |
||||
leaf: H256, |
||||
branch: &[H256], |
||||
depth: usize, |
||||
index: usize, |
||||
root: H256, |
||||
) -> bool { |
||||
if branch.len() == depth { |
||||
merkle_root_from_branch(leaf, branch, depth, index) == root |
||||
} else { |
||||
false |
||||
} |
||||
} |
||||
|
||||
/// Compute a root hash from a leaf and a Merkle proof.
|
||||
fn merkle_root_from_branch(leaf: H256, branch: &[H256], depth: usize, index: usize) -> H256 { |
||||
assert_eq!(branch.len(), depth, "proof length should equal depth"); |
||||
|
||||
let mut merkle_root = leaf; |
||||
|
||||
for (i, leaf) in branch.iter().enumerate().take(depth) { |
||||
let ith_bit = (index >> i) & 0x01; |
||||
if ith_bit == 1 { |
||||
merkle_root = hash_concat(leaf, merkle_root); |
||||
} else { |
||||
merkle_root = hash_concat(merkle_root, leaf); |
||||
} |
||||
} |
||||
|
||||
merkle_root |
||||
} |
||||
|
||||
#[cfg(test)] |
||||
mod tests { |
||||
use super::*; |
||||
|
||||
#[test] |
||||
fn sparse_zero_correct() { |
||||
let depth = 2; |
||||
let zero = H256::from([0x00; 32]); |
||||
let dense_tree = MerkleTree::create(&[zero, zero, zero, zero], depth); |
||||
let sparse_tree = MerkleTree::create(&[], depth); |
||||
assert_eq!(dense_tree.hash(), sparse_tree.hash()); |
||||
} |
||||
|
||||
#[test] |
||||
fn create_small_example() { |
||||
// Construct a small merkle tree manually and check that it's consistent with
|
||||
// the MerkleTree type.
|
||||
let leaf_b00 = H256::from([0xAA; 32]); |
||||
let leaf_b01 = H256::from([0xBB; 32]); |
||||
let leaf_b10 = H256::from([0xCC; 32]); |
||||
let leaf_b11 = H256::from([0xDD; 32]); |
||||
|
||||
let node_b0x = hash_concat(leaf_b00, leaf_b01); |
||||
let node_b1x = hash_concat(leaf_b10, leaf_b11); |
||||
|
||||
let root = hash_concat(node_b0x, node_b1x); |
||||
|
||||
let tree = MerkleTree::create(&[leaf_b00, leaf_b01, leaf_b10, leaf_b11], 2); |
||||
assert_eq!(tree.hash(), root); |
||||
} |
||||
|
||||
#[test] |
||||
fn verify_small_example() { |
||||
// Construct a small merkle tree manually
|
||||
let leaf_b00 = H256::from([0xAA; 32]); |
||||
let leaf_b01 = H256::from([0xBB; 32]); |
||||
let leaf_b10 = H256::from([0xCC; 32]); |
||||
let leaf_b11 = H256::from([0xDD; 32]); |
||||
|
||||
let node_b0x = hash_concat(leaf_b00, leaf_b01); |
||||
let node_b1x = hash_concat(leaf_b10, leaf_b11); |
||||
|
||||
let root = hash_concat(node_b0x, node_b1x); |
||||
|
||||
// Run some proofs
|
||||
assert!(verify_merkle_proof( |
||||
leaf_b00, |
||||
&[leaf_b01, node_b1x], |
||||
2, |
||||
0b00, |
||||
root |
||||
)); |
||||
assert!(verify_merkle_proof( |
||||
leaf_b01, |
||||
&[leaf_b00, node_b1x], |
||||
2, |
||||
0b01, |
||||
root |
||||
)); |
||||
assert!(verify_merkle_proof( |
||||
leaf_b10, |
||||
&[leaf_b11, node_b0x], |
||||
2, |
||||
0b10, |
||||
root |
||||
)); |
||||
assert!(verify_merkle_proof( |
||||
leaf_b11, |
||||
&[leaf_b10, node_b0x], |
||||
2, |
||||
0b11, |
||||
root |
||||
)); |
||||
assert!(verify_merkle_proof( |
||||
leaf_b11, |
||||
&[leaf_b10], |
||||
1, |
||||
0b11, |
||||
node_b1x |
||||
)); |
||||
|
||||
// Ensure that incorrect proofs fail
|
||||
// Zero-length proof
|
||||
assert!(!verify_merkle_proof(leaf_b01, &[], 2, 0b01, root)); |
||||
// Proof in reverse order
|
||||
assert!(!verify_merkle_proof( |
||||
leaf_b01, |
||||
&[node_b1x, leaf_b00], |
||||
2, |
||||
0b01, |
||||
root |
||||
)); |
||||
// Proof too short
|
||||
assert!(!verify_merkle_proof(leaf_b01, &[leaf_b00], 2, 0b01, root)); |
||||
// Wrong index
|
||||
assert!(!verify_merkle_proof( |
||||
leaf_b01, |
||||
&[leaf_b00, node_b1x], |
||||
2, |
||||
0b10, |
||||
root |
||||
)); |
||||
// Wrong root
|
||||
assert!(!verify_merkle_proof( |
||||
leaf_b01, |
||||
&[leaf_b00, node_b1x], |
||||
2, |
||||
0b01, |
||||
node_b1x |
||||
)); |
||||
} |
||||
|
||||
#[test] |
||||
fn verify_zero_depth() { |
||||
let leaf = H256::from([0xD6; 32]); |
||||
let junk = H256::from([0xD7; 32]); |
||||
assert!(verify_merkle_proof(leaf, &[], 0, 0, leaf)); |
||||
assert!(!verify_merkle_proof(leaf, &[], 0, 7, junk)); |
||||
} |
||||
|
||||
#[test] |
||||
fn push_complete_example() { |
||||
let depth = 2; |
||||
let mut tree = MerkleTree::create(&[], depth); |
||||
|
||||
let leaf_b00 = H256::from([0xAA; 32]); |
||||
|
||||
let res = tree.push_leaf(leaf_b00, 0); |
||||
assert_eq!(res, Err(MerkleTreeError::DepthTooSmall)); |
||||
let expected_tree = MerkleTree::create(&[], depth); |
||||
assert_eq!(tree.hash(), expected_tree.hash()); |
||||
|
||||
tree.push_leaf(leaf_b00, depth) |
||||
.expect("Pushing in empty tree failed"); |
||||
let expected_tree = MerkleTree::create(&[leaf_b00], depth); |
||||
assert_eq!(tree.hash(), expected_tree.hash()); |
||||
|
||||
let leaf_b01 = H256::from([0xBB; 32]); |
||||
tree.push_leaf(leaf_b01, depth) |
||||
.expect("Pushing in left then right node failed"); |
||||
let expected_tree = MerkleTree::create(&[leaf_b00, leaf_b01], depth); |
||||
assert_eq!(tree.hash(), expected_tree.hash()); |
||||
|
||||
let leaf_b10 = H256::from([0xCC; 32]); |
||||
tree.push_leaf(leaf_b10, depth) |
||||
.expect("Pushing in right then left node failed"); |
||||
let expected_tree = MerkleTree::create(&[leaf_b00, leaf_b01, leaf_b10], depth); |
||||
assert_eq!(tree.hash(), expected_tree.hash()); |
||||
|
||||
let leaf_b11 = H256::from([0xDD; 32]); |
||||
tree.push_leaf(leaf_b11, depth) |
||||
.expect("Pushing in outtermost leaf failed"); |
||||
let expected_tree = MerkleTree::create(&[leaf_b00, leaf_b01, leaf_b10, leaf_b11], depth); |
||||
assert_eq!(tree.hash(), expected_tree.hash()); |
||||
|
||||
let leaf_b12 = H256::from([0xEE; 32]); |
||||
let res = tree.push_leaf(leaf_b12, depth); |
||||
assert_eq!(res, Err(MerkleTreeError::MerkleTreeFull)); |
||||
assert_eq!(tree.hash(), expected_tree.hash()); |
||||
} |
||||
|
||||
#[test] |
||||
fn big_test() { |
||||
let leaves: Vec<_> = (0..64).map(|i| H256::from_low_u64_be(i)).collect(); |
||||
|
||||
let mut tree = MerkleTree::create(&[], 32); |
||||
leaves.iter().for_each(|leaf| { |
||||
tree.push_leaf(*leaf, 32).unwrap(); |
||||
}); |
||||
|
||||
leaves.iter().enumerate().for_each(|(i, leaf)| { |
||||
let (l, proof) = tree.generate_proof(i, 32); |
||||
assert_eq!(l, *leaf); |
||||
assert!(verify_merkle_proof(*leaf, &proof, 32, i, tree.hash())); |
||||
}); |
||||
} |
||||
} |
||||
|
||||
/* |
||||
Apache License |
||||
Version 2.0, January 2004 |
||||
http://www.apache.org/licenses/
|
||||
|
||||
TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION |
||||
|
||||
1. Definitions. |
||||
|
||||
"License" shall mean the terms and conditions for use, reproduction, |
||||
and distribution as defined by Sections 1 through 9 of this document. |
||||
|
||||
"Licensor" shall mean the copyright owner or entity authorized by |
||||
the copyright owner that is granting the License. |
||||
|
||||
"Legal Entity" shall mean the union of the acting entity and all |
||||
other entities that control, are controlled by, or are under common |
||||
control with that entity. For the purposes of this definition, |
||||
"control" means (i) the power, direct or indirect, to cause the |
||||
direction or management of such entity, whether by contract or |
||||
otherwise, or (ii) ownership of fifty percent (50%) or more of the |
||||
outstanding shares, or (iii) beneficial ownership of such entity. |
||||
|
||||
"You" (or "Your") shall mean an individual or Legal Entity |
||||
exercising permissions granted by this License. |
||||
|
||||
"Source" form shall mean the preferred form for making modifications, |
||||
including but not limited to software source code, documentation |
||||
source, and configuration files. |
||||
|
||||
"Object" form shall mean any form resulting from mechanical |
||||
transformation or translation of a Source form, including but |
||||
not limited to compiled object code, generated documentation, |
||||
and conversions to other media types. |
||||
|
||||
"Work" shall mean the work of authorship, whether in Source or |
||||
Object form, made available under the License, as indicated by a |
||||
copyright notice that is included in or attached to the work |
||||
(an example is provided in the Appendix below). |
||||
|
||||
"Derivative Works" shall mean any work, whether in Source or Object |
||||
form, that is based on (or derived from) the Work and for which the |
||||
editorial revisions, annotations, elaborations, or other modifications |
||||
represent, as a whole, an original work of authorship. For the purposes |
||||
of this License, Derivative Works shall not include works that remain |
||||
separable from, or merely link (or bind by name) to the interfaces of, |
||||
the Work and Derivative Works thereof. |
||||
|
||||
"Contribution" shall mean any work of authorship, including |
||||
the original version of the Work and any modifications or additions |
||||
to that Work or Derivative Works thereof, that is intentionally |
||||
submitted to Licensor for inclusion in the Work by the copyright owner |
||||
or by an individual or Legal Entity authorized to submit on behalf of |
||||
the copyright owner. For the purposes of this definition, "submitted" |
||||
means any form of electronic, verbal, or written communication sent |
||||
to the Licensor or its representatives, including but not limited to |
||||
communication on electronic mailing lists, source code control systems, |
||||
and issue tracking systems that are managed by, or on behalf of, the |
||||
Licensor for the purpose of discussing and improving the Work, but |
||||
excluding communication that is conspicuously marked or otherwise |
||||
designated in writing by the copyright owner as "Not a Contribution." |
||||
|
||||
"Contributor" shall mean Licensor and any individual or Legal Entity |
||||
on behalf of whom a Contribution has been received by Licensor and |
||||
subsequently incorporated within the Work. |
||||
|
||||
2. Grant of Copyright License. Subject to the terms and conditions of |
||||
this License, each Contributor hereby grants to You a perpetual, |
||||
worldwide, non-exclusive, no-charge, royalty-free, irrevocable |
||||
copyright license to reproduce, prepare Derivative Works of, |
||||
publicly display, publicly perform, sublicense, and distribute the |
||||
Work and such Derivative Works in Source or Object form. |
||||
|
||||
3. Grant of Patent License. Subject to the terms and conditions of |
||||
this License, each Contributor hereby grants to You a perpetual, |
||||
worldwide, non-exclusive, no-charge, royalty-free, irrevocable |
||||
(except as stated in this section) patent license to make, have made, |
||||
use, offer to sell, sell, import, and otherwise transfer the Work, |
||||
where such license applies only to those patent claims licensable |
||||
by such Contributor that are necessarily infringed by their |
||||
Contribution(s) alone or by combination of their Contribution(s) |
||||
with the Work to which such Contribution(s) was submitted. If You |
||||
institute patent litigation against any entity (including a |
||||
cross-claim or counterclaim in a lawsuit) alleging that the Work |
||||
or a Contribution incorporated within the Work constitutes direct |
||||
or contributory patent infringement, then any patent licenses |
||||
granted to You under this License for that Work shall terminate |
||||
as of the date such litigation is filed. |
||||
|
||||
4. Redistribution. You may reproduce and distribute copies of the |
||||
Work or Derivative Works thereof in any medium, with or without |
||||
modifications, and in Source or Object form, provided that You |
||||
meet the following conditions: |
||||
|
||||
(a) You must give any other recipients of the Work or |
||||
Derivative Works a copy of this License; and |
||||
|
||||
(b) You must cause any modified files to carry prominent notices |
||||
stating that You changed the files; and |
||||
|
||||
(c) You must retain, in the Source form of any Derivative Works |
||||
that You distribute, all copyright, patent, trademark, and |
||||
attribution notices from the Source form of the Work, |
||||
excluding those notices that do not pertain to any part of |
||||
the Derivative Works; and |
||||
|
||||
(d) If the Work includes a "NOTICE" text file as part of its |
||||
distribution, then any Derivative Works that You distribute must |
||||
include a readable copy of the attribution notices contained |
||||
within such NOTICE file, excluding those notices that do not |
||||
pertain to any part of the Derivative Works, in at least one |
||||
of the following places: within a NOTICE text file distributed |
||||
as part of the Derivative Works; within the Source form or |
||||
documentation, if provided along with the Derivative Works; or, |
||||
within a display generated by the Derivative Works, if and |
||||
wherever such third-party notices normally appear. The contents |
||||
of the NOTICE file are for informational purposes only and |
||||
do not modify the License. You may add Your own attribution |
||||
notices within Derivative Works that You distribute, alongside |
||||
or as an addendum to the NOTICE text from the Work, provided |
||||
that such additional attribution notices cannot be construed |
||||
as modifying the License. |
||||
|
||||
You may add Your own copyright statement to Your modifications and |
||||
may provide additional or different license terms and conditions |
||||
for use, reproduction, or distribution of Your modifications, or |
||||
for any such Derivative Works as a whole, provided Your use, |
||||
reproduction, and distribution of the Work otherwise complies with |
||||
the conditions stated in this License. |
||||
|
||||
5. Submission of Contributions. Unless You explicitly state otherwise, |
||||
any Contribution intentionally submitted for inclusion in the Work |
||||
by You to the Licensor shall be under the terms and conditions of |
||||
this License, without any additional terms or conditions. |
||||
Notwithstanding the above, nothing herein shall supersede or modify |
||||
the terms of any separate license agreement you may have executed |
||||
with Licensor regarding such Contributions. |
||||
|
||||
6. Trademarks. This License does not grant permission to use the trade |
||||
names, trademarks, service marks, or product names of the Licensor, |
||||
except as required for reasonable and customary use in describing the |
||||
origin of the Work and reproducing the content of the NOTICE file. |
||||
|
||||
7. Disclaimer of Warranty. Unless required by applicable law or |
||||
agreed to in writing, Licensor provides the Work (and each |
||||
Contributor provides its Contributions) on an "AS IS" BASIS, |
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or |
||||
implied, including, without limitation, any warranties or conditions |
||||
of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A |
||||
PARTICULAR PURPOSE. You are solely responsible for determining the |
||||
appropriateness of using or redistributing the Work and assume any |
||||
risks associated with Your exercise of permissions under this License. |
||||
|
||||
8. Limitation of Liability. In no event and under no legal theory, |
||||
whether in tort (including negligence), contract, or otherwise, |
||||
unless required by applicable law (such as deliberate and grossly |
||||
negligent acts) or agreed to in writing, shall any Contributor be |
||||
liable to You for damages, including any direct, indirect, special, |
||||
incidental, or consequential damages of any character arising as a |
||||
result of this License or out of the use or inability to use the |
||||
Work (including but not limited to damages for loss of goodwill, |
||||
work stoppage, computer failure or malfunction, or any and all |
||||
other commercial damages or losses), even if such Contributor |
||||
has been advised of the possibility of such damages. |
||||
|
||||
9. Accepting Warranty or Additional Liability. While redistributing |
||||
the Work or Derivative Works thereof, You may choose to offer, |
||||
and charge a fee for, acceptance of support, warranty, indemnity, |
||||
or other liability obligations and/or rights consistent with this |
||||
License. However, in accepting such obligations, You may act only |
||||
on Your own behalf and on Your sole responsibility, not on behalf |
||||
of any other Contributor, and only if You agree to indemnify, |
||||
defend, and hold each Contributor harmless for any liability |
||||
incurred by, or claims asserted against, such Contributor by reason |
||||
of your accepting any such warranty or additional liability. |
||||
|
||||
END OF TERMS AND CONDITIONS |
||||
|
||||
APPENDIX: How to apply the Apache License to your work. |
||||
|
||||
To apply the Apache License to your work, attach the following |
||||
boilerplate notice, with the fields enclosed by brackets "[]" |
||||
replaced with your own identifying information. (Don't include |
||||
the brackets!) The text should be enclosed in the appropriate |
||||
comment syntax for the file format. We also recommend that a |
||||
file or class name and description of purpose be included on the |
||||
same "printed page" as the copyright notice for easier |
||||
identification within third-party archives. |
||||
|
||||
Copyright 2018 Sigma Prime Pty Ltd |
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License"); |
||||
you may not use this file except in compliance with the License. |
||||
You may obtain a copy of the License at |
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software |
||||
distributed under the License is distributed on an "AS IS" BASIS, |
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
||||
See the License for the specific language governing permissions and |
||||
limitations under the License. |
||||
*/ |
@ -0,0 +1,127 @@ |
||||
use crate::SignedUpdate; |
||||
use ethers_core::types::{Address, H256, U256}; |
||||
|
||||
#[derive(Debug, Clone, Copy, Default)] |
||||
pub struct Waiting { |
||||
root: H256, |
||||
} |
||||
|
||||
#[derive(Debug, Clone, Copy)] |
||||
pub struct Pending { |
||||
root: H256, |
||||
new_root: H256, |
||||
timeout: U256, |
||||
} |
||||
|
||||
#[derive(Debug, Clone, Copy)] |
||||
pub struct Failed {} |
||||
|
||||
#[derive(Debug, Clone, Copy, Default)] |
||||
pub struct Replica<S> { |
||||
origin: u32, |
||||
local: u32, |
||||
updater: Address, |
||||
optimistic_wait: U256, |
||||
state: S, |
||||
} |
||||
|
||||
impl<S> Replica<S> { |
||||
pub fn origin(&self) -> u32 { |
||||
self.origin |
||||
} |
||||
|
||||
pub fn local(&self) -> u32 { |
||||
self.local |
||||
} |
||||
|
||||
pub fn updater(&self) -> Address { |
||||
self.updater |
||||
} |
||||
|
||||
pub fn wait(&self) -> U256 { |
||||
self.optimistic_wait |
||||
} |
||||
|
||||
pub fn state(&self) -> &S { |
||||
&self.state |
||||
} |
||||
|
||||
fn check_sig(&self, update: &SignedUpdate) -> Result<(), ()> { |
||||
let signer = update.recover()?; |
||||
if signer == self.updater { |
||||
Ok(()) |
||||
} else { |
||||
Err(()) |
||||
} |
||||
} |
||||
|
||||
pub fn double_update( |
||||
self, |
||||
first: &SignedUpdate, |
||||
second: &SignedUpdate, |
||||
) -> Result<Replica<Failed>, Self> { |
||||
if first == second || self.check_sig(first).is_err() || self.check_sig(second).is_err() { |
||||
Err(self) |
||||
} else { |
||||
Ok(Replica { |
||||
origin: self.origin, |
||||
local: self.local, |
||||
updater: self.updater, |
||||
optimistic_wait: self.optimistic_wait, |
||||
state: Failed {}, |
||||
}) |
||||
} |
||||
} |
||||
} |
||||
|
||||
impl Replica<Waiting> { |
||||
pub fn init(origin: u32, local: u32, updater: Address, optimistic_wait: U256) -> Self { |
||||
Self { |
||||
origin, |
||||
local, |
||||
updater, |
||||
optimistic_wait, |
||||
state: Waiting::default(), |
||||
} |
||||
} |
||||
|
||||
pub fn update( |
||||
self, |
||||
update: &SignedUpdate, |
||||
now: impl FnOnce() -> U256, |
||||
) -> Result<Replica<Pending>, Replica<Waiting>> { |
||||
if self.check_sig(update).is_err() { |
||||
return Err(self); |
||||
} |
||||
|
||||
Ok(Replica { |
||||
origin: self.origin, |
||||
local: self.local, |
||||
updater: self.updater, |
||||
optimistic_wait: self.optimistic_wait, |
||||
state: Pending { |
||||
root: self.state.root, |
||||
new_root: update.update.new_root, |
||||
timeout: now() + self.optimistic_wait, |
||||
}, |
||||
}) |
||||
} |
||||
} |
||||
|
||||
impl Replica<Pending> { |
||||
pub fn confirm_update(self, now: impl FnOnce() -> U256) -> Result<Replica<Waiting>, Self> { |
||||
if self.state.timeout < now() { |
||||
return Err(self); |
||||
} |
||||
|
||||
Ok(Replica { |
||||
origin: self.origin, |
||||
local: self.local, |
||||
updater: self.updater, |
||||
optimistic_wait: self.optimistic_wait, |
||||
state: Waiting { |
||||
root: self.state.new_root, |
||||
}, |
||||
}) |
||||
} |
||||
} |
@ -0,0 +1,3 @@ |
||||
node_modules/ |
||||
cache/ |
||||
artifacts/ |
@ -0,0 +1,15 @@ |
||||
{ |
||||
"overrides": [ |
||||
{ |
||||
"files": "*.sol", |
||||
"options": { |
||||
"printWidth": 80, |
||||
"tabWidth": 4, |
||||
"useTabs": false, |
||||
"singleQuote": false, |
||||
"bracketSpacing": false, |
||||
"explicitTypes": "always" |
||||
} |
||||
} |
||||
] |
||||
} |
@ -0,0 +1,115 @@ |
||||
// SPDX-License-Identifier: MIT OR Apache-2.0 |
||||
pragma solidity >=0.6.11; |
||||
|
||||
import "@openzeppelin/contracts/cryptography/ECDSA.sol"; |
||||
|
||||
import "./Merkle.sol"; |
||||
import "./Queue.sol"; |
||||
|
||||
contract Home is MerkleTreeManager, QueueManager { |
||||
using QueueLib for QueueLib.Queue; |
||||
using MerkleLib for MerkleLib.Tree; |
||||
|
||||
enum States {WAITING, FAILED} |
||||
|
||||
States public state; |
||||
uint32 public immutable originSLIP44; |
||||
bytes32 public immutable DOMAIN_HASH; |
||||
address public updater; |
||||
event DoubleUpdate(); |
||||
event ImproperUpdate(); |
||||
|
||||
modifier notFailed() { |
||||
require(state == States.WAITING); |
||||
_; |
||||
} |
||||
|
||||
constructor(uint32 _originSLIP44, address _updater) |
||||
MerkleTreeManager() |
||||
QueueManager() |
||||
{ |
||||
DOMAIN_HASH = keccak256(abi.encodePacked(_originSLIP44, "OPTICS")); |
||||
updater = _updater; |
||||
originSLIP44 = _originSLIP44; |
||||
state = States.WAITING; |
||||
} |
||||
|
||||
// TODO |
||||
function fail() internal { |
||||
state = States.FAILED; |
||||
require(false, "not implemented: slashing"); |
||||
} |
||||
|
||||
function checkSig( |
||||
bytes32 _newRoot, |
||||
bytes32 _oldRoot, |
||||
bytes memory _signature |
||||
) internal view returns (bool) { |
||||
bytes32 _digest = |
||||
keccak256(abi.encodePacked(DOMAIN_HASH, _oldRoot, _newRoot)); |
||||
_digest = ECDSA.toEthSignedMessageHash(_digest); |
||||
return ECDSA.recover(_digest, _signature) == updater; |
||||
} |
||||
|
||||
function enqueue( |
||||
uint32 destination, |
||||
bytes32 recipient, |
||||
bytes memory body |
||||
) external notFailed { |
||||
bytes32 _digest = |
||||
keccak256( |
||||
abi.encodePacked( |
||||
originSLIP44, |
||||
bytes32(uint256(uint160(msg.sender))), |
||||
destination, |
||||
recipient, |
||||
body |
||||
) |
||||
); |
||||
|
||||
tree.insert(_digest); |
||||
queue.enqueue(root()); |
||||
} |
||||
|
||||
function update( |
||||
bytes32 _newRoot, |
||||
bytes32 _oldRoot, |
||||
bytes memory _signature |
||||
) external notFailed { |
||||
if (improperUpdate(_newRoot, _oldRoot, _signature)) return; |
||||
while (true) { |
||||
bytes32 next = queue.dequeue(); |
||||
if (next == _newRoot) break; |
||||
} |
||||
} |
||||
|
||||
function doubleUpdate( |
||||
bytes32[2] calldata _newRoot, |
||||
bytes32[2] calldata _oldRoot, |
||||
bytes calldata _signature, |
||||
bytes calldata _signature2 |
||||
) external notFailed { |
||||
if ( |
||||
checkSig(_newRoot[0], _oldRoot[0], _signature) && |
||||
checkSig(_newRoot[1], _oldRoot[1], _signature2) && |
||||
(_newRoot[0] != _newRoot[1] || _oldRoot[0] != _oldRoot[1]) |
||||
) { |
||||
fail(); |
||||
emit DoubleUpdate(); |
||||
} |
||||
} |
||||
|
||||
function improperUpdate( |
||||
bytes32 _newRoot, |
||||
bytes32 _oldRoot, |
||||
bytes memory _signature |
||||
) public notFailed returns (bool) { |
||||
require(checkSig(_newRoot, _oldRoot, _signature), "bad sig"); |
||||
if (!queue.contains(_newRoot)) { |
||||
fail(); |
||||
emit ImproperUpdate(); |
||||
return true; |
||||
} |
||||
return false; |
||||
} |
||||
} |
@ -0,0 +1,67 @@ |
||||
// SPDX-License-Identifier: MIT OR Apache-2.0 |
||||
|
||||
// work based on eth2 deposit contract, which is used under CC0-1.0 |
||||
|
||||
pragma solidity >=0.6.11; |
||||
|
||||
library MerkleLib { |
||||
uint256 constant TREE_DEPTH = 32; |
||||
uint256 constant MAX_LEAVES = 2**TREE_DEPTH - 1; |
||||
|
||||
struct Tree { |
||||
bytes32[TREE_DEPTH] branch; |
||||
uint256 count; |
||||
} |
||||
|
||||
function root(Tree storage _tree, bytes32[TREE_DEPTH] storage zero_hashes) |
||||
internal |
||||
view |
||||
returns (bytes32 node) |
||||
{ |
||||
uint256 size = _tree.count; |
||||
for (uint256 i = 0; i < TREE_DEPTH; i++) { |
||||
if ((size & 1) == 1) |
||||
node = sha256(abi.encodePacked(_tree.branch[i], node)); |
||||
else node = sha256(abi.encodePacked(node, zero_hashes[i])); |
||||
size /= 2; |
||||
} |
||||
} |
||||
|
||||
function insert(Tree storage _tree, bytes32 node) internal { |
||||
require(_tree.count < MAX_LEAVES, "merkle tree full"); |
||||
|
||||
_tree.count += 1; |
||||
uint256 size = _tree.count; |
||||
for (uint256 i = 0; i < TREE_DEPTH; i++) { |
||||
if ((size & 1) == 1) { |
||||
_tree.branch[i] = node; |
||||
return; |
||||
} |
||||
node = sha256(abi.encodePacked(_tree.branch[i], node)); |
||||
size /= 2; |
||||
} |
||||
// As the loop should always end prematurely with the `return` statement, |
||||
// this code should be unreachable. We assert `false` just to be safe. |
||||
assert(false); |
||||
} |
||||
} |
||||
|
||||
contract MerkleTreeManager { |
||||
using MerkleLib for MerkleLib.Tree; |
||||
uint256 constant TREE_DEPTH = 32; |
||||
|
||||
bytes32[TREE_DEPTH] internal zero_hashes; |
||||
MerkleLib.Tree public tree; |
||||
|
||||
constructor() { |
||||
// Compute hashes in empty sparse Merkle tree |
||||
for (uint256 i = 0; i < MerkleLib.TREE_DEPTH - 1; i++) |
||||
zero_hashes[i + 1] = sha256( |
||||
abi.encodePacked(zero_hashes[i], zero_hashes[i]) |
||||
); |
||||
} |
||||
|
||||
function root() public view returns (bytes32) { |
||||
return tree.root(zero_hashes); |
||||
} |
||||
} |
@ -0,0 +1,57 @@ |
||||
// SPDX-License-Identifier: MIT OR Apache-2.0 |
||||
pragma solidity >=0.6.11; |
||||
|
||||
library QueueLib { |
||||
struct Queue { |
||||
uint256 first; |
||||
uint256 last; |
||||
mapping(uint256 => bytes32) queue; |
||||
} |
||||
|
||||
function init(Queue storage _q) internal { |
||||
if (_q.first == 0) { |
||||
_q.first = 1; |
||||
} |
||||
} |
||||
|
||||
function contains(Queue storage _q, bytes32 _item) |
||||
internal |
||||
view |
||||
returns (bool) |
||||
{ |
||||
for (uint256 i = _q.first; i < _q.last; i++) { |
||||
if (_q.queue[i] == _item) { |
||||
return true; |
||||
} |
||||
} |
||||
return false; |
||||
} |
||||
|
||||
function enqueue(Queue storage _q, bytes32 _item) internal { |
||||
uint256 _last = _q.last + 1; |
||||
_q.last = _last; |
||||
_q.queue[_last] = _item; |
||||
} |
||||
|
||||
function dequeue(Queue storage _q) internal returns (bytes32 item) { |
||||
uint256 _first = _q.first; |
||||
require(_q.last >= _first, "Empty"); |
||||
item = _q.queue[_first]; |
||||
delete _q.queue[_first]; |
||||
_q.first = _first + 1; |
||||
} |
||||
|
||||
function length(Queue storage _q) internal view returns (uint256) { |
||||
// Cannot underflow unless state is corrupted |
||||
return _q.first - _q.last - 1; |
||||
} |
||||
} |
||||
|
||||
contract QueueManager { |
||||
using QueueLib for QueueLib.Queue; |
||||
QueueLib.Queue internal queue; |
||||
|
||||
constructor() { |
||||
queue.init(); |
||||
} |
||||
} |
@ -0,0 +1,94 @@ |
||||
// SPDX-License-Identifier: MIT OR Apache-2.0 |
||||
pragma solidity >=0.6.11; |
||||
|
||||
import "@openzeppelin/contracts/cryptography/ECDSA.sol"; |
||||
|
||||
contract Replica { |
||||
enum States {WAITING, FAILED} |
||||
|
||||
States public state; |
||||
|
||||
uint32 public immutable originSLIP44; |
||||
uint32 public immutable ownSLIP44; |
||||
bytes32 public immutable DOMAIN_HASH; |
||||
address public updater; |
||||
uint256 public optimisticSeconds; |
||||
|
||||
bytes32 current; |
||||
bytes32 pending; |
||||
uint256 confirmAt; |
||||
|
||||
event DoubleUpdate(); |
||||
|
||||
modifier notFailed() { |
||||
require(state == States.WAITING); |
||||
_; |
||||
} |
||||
|
||||
constructor( |
||||
uint32 _originSLIP44, |
||||
uint32 _ownSLIP44, |
||||
address _updater, |
||||
uint256 _optimisticSeconds, |
||||
bytes32 _start |
||||
) { |
||||
DOMAIN_HASH = keccak256(abi.encodePacked(_originSLIP44, "OPTICS")); |
||||
updater = _updater; |
||||
originSLIP44 = _originSLIP44; |
||||
ownSLIP44 = _ownSLIP44; |
||||
state = States.WAITING; |
||||
optimisticSeconds = _optimisticSeconds; |
||||
current = _start; |
||||
} |
||||
|
||||
function fail() internal { |
||||
state = States.FAILED; |
||||
} |
||||
|
||||
function checkSig( |
||||
bytes32 _newRoot, |
||||
bytes32 _oldRoot, |
||||
bytes memory _signature |
||||
) internal view returns (bool) { |
||||
bytes32 _digest = |
||||
keccak256(abi.encodePacked(DOMAIN_HASH, _oldRoot, _newRoot)); |
||||
_digest = ECDSA.toEthSignedMessageHash(_digest); |
||||
return ECDSA.recover(_digest, _signature) == updater; |
||||
} |
||||
|
||||
function update( |
||||
bytes32 _newRoot, |
||||
bytes32 _oldRoot, |
||||
bytes memory _signature |
||||
) external notFailed { |
||||
require(current == _oldRoot, "Not current update"); |
||||
require(checkSig(_newRoot, _oldRoot, _signature), "Bad sig"); |
||||
|
||||
confirmAt = block.timestamp + optimisticSeconds; |
||||
pending = _newRoot; |
||||
} |
||||
|
||||
function confirm() external notFailed { |
||||
require(confirmAt != 0, "No pending"); |
||||
require(block.timestamp >= confirmAt, "Not yet"); |
||||
current = pending; |
||||
delete pending; |
||||
delete confirmAt; |
||||
} |
||||
|
||||
function doubleUpdate( |
||||
bytes32[2] calldata _newRoot, |
||||
bytes32[2] calldata _oldRoot, |
||||
bytes calldata _signature, |
||||
bytes calldata _signature2 |
||||
) external notFailed { |
||||
if ( |
||||
checkSig(_newRoot[0], _oldRoot[0], _signature) && |
||||
checkSig(_newRoot[1], _oldRoot[1], _signature2) && |
||||
(_newRoot[0] != _newRoot[1] || _oldRoot[0] != _oldRoot[1]) |
||||
) { |
||||
fail(); |
||||
emit DoubleUpdate(); |
||||
} |
||||
} |
||||
} |
@ -0,0 +1,8 @@ |
||||
require("@nomiclabs/hardhat-waffle"); |
||||
require("@nomiclabs/hardhat-ethers"); |
||||
/** |
||||
* @type import('hardhat/config').HardhatUserConfig |
||||
*/ |
||||
module.exports = { |
||||
solidity: "0.7.6", |
||||
}; |
File diff suppressed because it is too large
Load Diff
@ -0,0 +1,26 @@ |
||||
{ |
||||
"name": "@celo-org/optics-sol", |
||||
"devDependencies": { |
||||
"@nomiclabs/hardhat-ethers": "^2.0.1", |
||||
"@nomiclabs/hardhat-waffle": "^2.0.1", |
||||
"@openzeppelin/contracts": "^3.3.0", |
||||
"ethereum-waffle": "^3.2.1", |
||||
"ethers": "^5.0.25", |
||||
"hardhat": "^2.0.7", |
||||
"prettier": "2.2.1", |
||||
"prettier-plugin-solidity": "^1.0.0-beta.3" |
||||
}, |
||||
"version": "0.0.0", |
||||
"description": "Optimistic Interchain Communications", |
||||
"main": " ", |
||||
"directories": { |
||||
"test": "test" |
||||
}, |
||||
"dependencies": {}, |
||||
"scripts": { |
||||
"compile": "hardhat compile", |
||||
"test": "hardhat test" |
||||
}, |
||||
"author": "James Prestwich", |
||||
"license": "MIT OR Apache-2.0" |
||||
} |
Loading…
Reference in new issue