Problem: no functionality exists to dynamically fetch gas-prices
Currently, gas-prices are set upon bridge startup via the Users's config TOML file; this value remains constant for the life of the Bridge. Solution: create a mechanism that asynchronously queries gas-prices from an "Oracle" service on a timed interval. This mechanism should be a stream of gas-prices that can be polled from the Bridge.
This commit is contained in:
parent
cc4147c9cc
commit
aaa5bee49e
|
@ -157,6 +157,8 @@ dependencies = [
|
||||||
"ethcore-transaction 0.1.0 (git+http://github.com/paritytech/parity?rev=991f0ca)",
|
"ethcore-transaction 0.1.0 (git+http://github.com/paritytech/parity?rev=991f0ca)",
|
||||||
"ethereum-types 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)",
|
"ethereum-types 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
"futures 0.1.21 (registry+https://github.com/rust-lang/crates.io-index)",
|
"futures 0.1.21 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
|
"hyper 0.11.27 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
|
"hyper-tls 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
"itertools 0.7.8 (registry+https://github.com/rust-lang/crates.io-index)",
|
"itertools 0.7.8 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
"jsonrpc-core 8.0.1 (registry+https://github.com/rust-lang/crates.io-index)",
|
"jsonrpc-core 8.0.1 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
"keccak-hash 0.1.0 (git+http://github.com/paritytech/parity?rev=991f0ca)",
|
"keccak-hash 0.1.0 (git+http://github.com/paritytech/parity?rev=991f0ca)",
|
||||||
|
@ -792,7 +794,7 @@ source = "git+http://github.com/paritytech/parity?rev=991f0ca#991f0cac6ebb75b270
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"futures 0.1.21 (registry+https://github.com/rust-lang/crates.io-index)",
|
"futures 0.1.21 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
"futures-timer 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)",
|
"futures-timer 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
"hyper 0.11.25 (registry+https://github.com/rust-lang/crates.io-index)",
|
"hyper 0.11.27 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
"hyper-rustls 0.11.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
"hyper-rustls 0.11.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
"log 0.4.1 (registry+https://github.com/rust-lang/crates.io-index)",
|
"log 0.4.1 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
"tokio-core 0.1.17 (registry+https://github.com/rust-lang/crates.io-index)",
|
"tokio-core 0.1.17 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
|
@ -997,7 +999,7 @@ dependencies = [
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "hyper"
|
name = "hyper"
|
||||||
version = "0.11.25"
|
version = "0.11.27"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"base64 0.9.1 (registry+https://github.com/rust-lang/crates.io-index)",
|
"base64 0.9.1 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
|
@ -1009,6 +1011,7 @@ dependencies = [
|
||||||
"language-tags 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)",
|
"language-tags 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
"log 0.4.1 (registry+https://github.com/rust-lang/crates.io-index)",
|
"log 0.4.1 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
"mime 0.3.5 (registry+https://github.com/rust-lang/crates.io-index)",
|
"mime 0.3.5 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
|
"net2 0.2.32 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
"percent-encoding 1.0.1 (registry+https://github.com/rust-lang/crates.io-index)",
|
"percent-encoding 1.0.1 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
"relay 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)",
|
"relay 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
"time 0.1.39 (registry+https://github.com/rust-lang/crates.io-index)",
|
"time 0.1.39 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
|
@ -1017,6 +1020,7 @@ dependencies = [
|
||||||
"tokio-proto 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)",
|
"tokio-proto 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
"tokio-service 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
"tokio-service 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
"unicase 2.1.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
"unicase 2.1.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
|
"want 0.0.4 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
|
@ -1026,7 +1030,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"ct-logs 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
"ct-logs 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
"futures 0.1.21 (registry+https://github.com/rust-lang/crates.io-index)",
|
"futures 0.1.21 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
"hyper 0.11.25 (registry+https://github.com/rust-lang/crates.io-index)",
|
"hyper 0.11.27 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
"rustls 0.11.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
"rustls 0.11.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
"tokio-core 0.1.17 (registry+https://github.com/rust-lang/crates.io-index)",
|
"tokio-core 0.1.17 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
"tokio-io 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)",
|
"tokio-io 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
|
@ -1042,7 +1046,7 @@ version = "0.1.3"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"futures 0.1.21 (registry+https://github.com/rust-lang/crates.io-index)",
|
"futures 0.1.21 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
"hyper 0.11.25 (registry+https://github.com/rust-lang/crates.io-index)",
|
"hyper 0.11.27 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
"native-tls 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)",
|
"native-tls 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
"tokio-core 0.1.17 (registry+https://github.com/rust-lang/crates.io-index)",
|
"tokio-core 0.1.17 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
"tokio-io 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)",
|
"tokio-io 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
|
@ -2332,6 +2336,7 @@ version = "0.1.0"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"bridge 0.2.0",
|
"bridge 0.2.0",
|
||||||
"ethabi 5.1.1 (registry+https://github.com/rust-lang/crates.io-index)",
|
"ethabi 5.1.1 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
|
"ethcore 1.11.0 (git+http://github.com/paritytech/parity?rev=991f0ca)",
|
||||||
"ethereum-types 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)",
|
"ethereum-types 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
"futures 0.1.21 (registry+https://github.com/rust-lang/crates.io-index)",
|
"futures 0.1.21 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
"jsonrpc-core 8.0.1 (registry+https://github.com/rust-lang/crates.io-index)",
|
"jsonrpc-core 8.0.1 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
|
@ -2606,6 +2611,11 @@ dependencies = [
|
||||||
"rlp 0.2.1 (git+http://github.com/paritytech/parity?rev=991f0ca)",
|
"rlp 0.2.1 (git+http://github.com/paritytech/parity?rev=991f0ca)",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "try-lock"
|
||||||
|
version = "0.1.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "typeable"
|
name = "typeable"
|
||||||
version = "0.1.2"
|
version = "0.1.2"
|
||||||
|
@ -2766,6 +2776,16 @@ name = "void"
|
||||||
version = "1.0.2"
|
version = "1.0.2"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "want"
|
||||||
|
version = "0.0.4"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
dependencies = [
|
||||||
|
"futures 0.1.21 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
|
"log 0.4.1 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
|
"try-lock 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "wasm"
|
name = "wasm"
|
||||||
version = "0.1.0"
|
version = "0.1.0"
|
||||||
|
@ -2802,7 +2822,7 @@ dependencies = [
|
||||||
"ethabi 5.1.1 (registry+https://github.com/rust-lang/crates.io-index)",
|
"ethabi 5.1.1 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
"ethereum-types 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)",
|
"ethereum-types 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
"futures 0.1.21 (registry+https://github.com/rust-lang/crates.io-index)",
|
"futures 0.1.21 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
"hyper 0.11.25 (registry+https://github.com/rust-lang/crates.io-index)",
|
"hyper 0.11.27 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
"hyper-tls 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)",
|
"hyper-tls 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
"jsonrpc-core 8.0.1 (registry+https://github.com/rust-lang/crates.io-index)",
|
"jsonrpc-core 8.0.1 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
"log 0.4.1 (registry+https://github.com/rust-lang/crates.io-index)",
|
"log 0.4.1 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
|
@ -3003,7 +3023,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
"checksum humantime 1.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "0484fda3e7007f2a4a0d9c3a703ca38c71c54c55602ce4660c419fd32e188c9e"
|
"checksum humantime 1.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "0484fda3e7007f2a4a0d9c3a703ca38c71c54c55602ce4660c419fd32e188c9e"
|
||||||
"checksum hyper 0.10.0-a.0 (git+https://github.com/paritytech/hyper)" = "<none>"
|
"checksum hyper 0.10.0-a.0 (git+https://github.com/paritytech/hyper)" = "<none>"
|
||||||
"checksum hyper 0.10.13 (registry+https://github.com/rust-lang/crates.io-index)" = "368cb56b2740ebf4230520e2b90ebb0461e69034d85d1945febd9b3971426db2"
|
"checksum hyper 0.10.13 (registry+https://github.com/rust-lang/crates.io-index)" = "368cb56b2740ebf4230520e2b90ebb0461e69034d85d1945febd9b3971426db2"
|
||||||
"checksum hyper 0.11.25 (registry+https://github.com/rust-lang/crates.io-index)" = "549dbb86397490ce69d908425b9beebc85bbaad25157d67479d4995bb56fdf9a"
|
"checksum hyper 0.11.27 (registry+https://github.com/rust-lang/crates.io-index)" = "34a590ca09d341e94cddf8e5af0bbccde205d5fbc2fa3c09dd67c7f85cea59d7"
|
||||||
"checksum hyper-rustls 0.11.0 (registry+https://github.com/rust-lang/crates.io-index)" = "1d6cdc1751771a14b8175764394f025e309a28c825ed9eaf97fa62bb831dc8c5"
|
"checksum hyper-rustls 0.11.0 (registry+https://github.com/rust-lang/crates.io-index)" = "1d6cdc1751771a14b8175764394f025e309a28c825ed9eaf97fa62bb831dc8c5"
|
||||||
"checksum hyper-tls 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)" = "a5aa51f6ae9842239b0fac14af5f22123b8432b4cc774a44ff059fcba0f675ca"
|
"checksum hyper-tls 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)" = "a5aa51f6ae9842239b0fac14af5f22123b8432b4cc774a44ff059fcba0f675ca"
|
||||||
"checksum idna 0.1.4 (registry+https://github.com/rust-lang/crates.io-index)" = "014b298351066f1512874135335d62a789ffe78a9974f94b43ed5621951eaf7d"
|
"checksum idna 0.1.4 (registry+https://github.com/rust-lang/crates.io-index)" = "014b298351066f1512874135335d62a789ffe78a9974f94b43ed5621951eaf7d"
|
||||||
|
@ -3179,6 +3199,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
"checksum transient-hashmap 0.4.1 (registry+https://github.com/rust-lang/crates.io-index)" = "aeb4b191d033a35edfce392a38cdcf9790b6cebcb30fa690c312c29da4dc433e"
|
"checksum transient-hashmap 0.4.1 (registry+https://github.com/rust-lang/crates.io-index)" = "aeb4b191d033a35edfce392a38cdcf9790b6cebcb30fa690c312c29da4dc433e"
|
||||||
"checksum trezor-sys 1.0.0 (git+https://github.com/paritytech/trezor-sys)" = "<none>"
|
"checksum trezor-sys 1.0.0 (git+https://github.com/paritytech/trezor-sys)" = "<none>"
|
||||||
"checksum triehash 0.1.0 (git+http://github.com/paritytech/parity?rev=991f0ca)" = "<none>"
|
"checksum triehash 0.1.0 (git+http://github.com/paritytech/parity?rev=991f0ca)" = "<none>"
|
||||||
|
"checksum try-lock 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "ee2aa4715743892880f70885373966c83d73ef1b0838a664ef0c76fffd35e7c2"
|
||||||
"checksum typeable 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)" = "1410f6f91f21d1612654e7cc69193b0334f909dcf2c790c4826254fbb86f8887"
|
"checksum typeable 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)" = "1410f6f91f21d1612654e7cc69193b0334f909dcf2c790c4826254fbb86f8887"
|
||||||
"checksum ucd-util 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "fd2be2d6639d0f8fe6cdda291ad456e23629558d466e2789d2c3e9892bda285d"
|
"checksum ucd-util 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "fd2be2d6639d0f8fe6cdda291ad456e23629558d466e2789d2c3e9892bda285d"
|
||||||
"checksum uint 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "6477b2716357758c176c36719023e1f9726974d762150e4fc0a9c8c75488c343"
|
"checksum uint 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "6477b2716357758c176c36719023e1f9726974d762150e4fc0a9c8c75488c343"
|
||||||
|
@ -3202,6 +3223,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
"checksum version_check 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)" = "6b772017e347561807c1aa192438c5fd74242a670a6cffacc40f2defd1dc069d"
|
"checksum version_check 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)" = "6b772017e347561807c1aa192438c5fd74242a670a6cffacc40f2defd1dc069d"
|
||||||
"checksum vm 0.1.0 (git+http://github.com/paritytech/parity?rev=991f0ca)" = "<none>"
|
"checksum vm 0.1.0 (git+http://github.com/paritytech/parity?rev=991f0ca)" = "<none>"
|
||||||
"checksum void 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)" = "6a02e4885ed3bc0f2de90ea6dd45ebcbb66dacffe03547fadbb0eeae2770887d"
|
"checksum void 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)" = "6a02e4885ed3bc0f2de90ea6dd45ebcbb66dacffe03547fadbb0eeae2770887d"
|
||||||
|
"checksum want 0.0.4 (registry+https://github.com/rust-lang/crates.io-index)" = "a05d9d966753fa4b5c8db73fcab5eed4549cfe0e1e4e66911e5564a0085c35d1"
|
||||||
"checksum wasm 0.1.0 (git+http://github.com/paritytech/parity?rev=991f0ca)" = "<none>"
|
"checksum wasm 0.1.0 (git+http://github.com/paritytech/parity?rev=991f0ca)" = "<none>"
|
||||||
"checksum wasmi 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)" = "d19da510b59247935ad5f598357b3cc739912666d75d3d28318026478d95bbdb"
|
"checksum wasmi 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)" = "d19da510b59247935ad5f598357b3cc739912666d75d3d28318026478d95bbdb"
|
||||||
"checksum web3 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)" = "a806fc4a6fe10166a083806e3c06b21c7aa5e6f2cf8094416835f1070844e13a"
|
"checksum web3 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)" = "a806fc4a6fe10166a083806e3c06b21c7aa5e6f2cf8094416835f1070844e13a"
|
||||||
|
|
|
@ -117,6 +117,10 @@ withdraw_confirm = { gas = 3000000, gas_price = 1000000000 }
|
||||||
- `home/foreign.poll_interval` - specify how often home node should be polled for changes (in seconds, default: **1**)
|
- `home/foreign.poll_interval` - specify how often home node should be polled for changes (in seconds, default: **1**)
|
||||||
- `home/foreign.request_timeout` - specify request timeout (in seconds, default: **3600**)
|
- `home/foreign.request_timeout` - specify request timeout (in seconds, default: **3600**)
|
||||||
- `home/foreign.password` - path to the file containing a password for the validator's account (to decrypt the key from the keystore)
|
- `home/foreign.password` - path to the file containing a password for the validator's account (to decrypt the key from the keystore)
|
||||||
|
- `home/foreign.gas_price_oracle_url` - the URL used to query the current gas-price for the home and foreign nodes, this service is known as the gas-price Oracle. This config option defaults to `None` if not supplied in the User's config TOML file. If this config value is `None`, no Oracle gas-price querying will occur, resulting in the config value for `home/foreign.default_gas_price` being used for all gas-prices.
|
||||||
|
- `home/foreign.gas_price_timeout` - the number of seconds to wait for an HTTP response from the gas price oracle before using the default gas price. Defaults to `10 seconds`.
|
||||||
|
- `home/foreign.gas_price_speed_type` - retrieve the gas-price corresponding to this speed when querying from an Oracle. Defaults to `fast`. The available values are: "instant", "fast", "standard", and "slow".
|
||||||
|
- `home/foreign.default_gas_price` - the default gas price (in WEI) used in transactions with the home or foreign nodes. The `default_gas_price` is used when the Oracle cannot be reached. The default value is `15_000_000_000` WEI (ie. 15 GWEI).
|
||||||
|
|
||||||
#### authorities options
|
#### authorities options
|
||||||
|
|
||||||
|
|
|
@ -25,6 +25,8 @@ keccak-hash = { git = "http://github.com/paritytech/parity", rev = "991f0ca" }
|
||||||
ethcore-transaction = { git = "http://github.com/paritytech/parity", rev = "991f0ca" }
|
ethcore-transaction = { git = "http://github.com/paritytech/parity", rev = "991f0ca" }
|
||||||
itertools = "0.7"
|
itertools = "0.7"
|
||||||
jsonrpc-core = "8.0"
|
jsonrpc-core = "8.0"
|
||||||
|
hyper = "0.11.27"
|
||||||
|
hyper-tls = "0.1.3"
|
||||||
|
|
||||||
[dev-dependencies]
|
[dev-dependencies]
|
||||||
tempdir = "0.3"
|
tempdir = "0.3"
|
||||||
|
|
|
@ -42,7 +42,7 @@ enum DepositRelayState<T: Transport> {
|
||||||
Yield(Option<u64>),
|
Yield(Option<u64>),
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn create_deposit_relay<T: Transport + Clone>(app: Arc<App<T>>, init: &Database, foreign_balance: Arc<RwLock<Option<U256>>>, foreign_chain_id: u64) -> DepositRelay<T> {
|
pub fn create_deposit_relay<T: Transport + Clone>(app: Arc<App<T>>, init: &Database, foreign_balance: Arc<RwLock<Option<U256>>>, foreign_chain_id: u64, foreign_gas_price: Arc<RwLock<u64>>) -> DepositRelay<T> {
|
||||||
let logs_init = api::LogStreamInit {
|
let logs_init = api::LogStreamInit {
|
||||||
after: init.checked_deposit_relay,
|
after: init.checked_deposit_relay,
|
||||||
request_timeout: app.config.home.request_timeout,
|
request_timeout: app.config.home.request_timeout,
|
||||||
|
@ -57,6 +57,7 @@ pub fn create_deposit_relay<T: Transport + Clone>(app: Arc<App<T>>, init: &Datab
|
||||||
app,
|
app,
|
||||||
foreign_balance,
|
foreign_balance,
|
||||||
foreign_chain_id,
|
foreign_chain_id,
|
||||||
|
foreign_gas_price,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -67,6 +68,7 @@ pub struct DepositRelay<T: Transport> {
|
||||||
foreign_contract: Address,
|
foreign_contract: Address,
|
||||||
foreign_balance: Arc<RwLock<Option<U256>>>,
|
foreign_balance: Arc<RwLock<Option<U256>>>,
|
||||||
foreign_chain_id: u64,
|
foreign_chain_id: u64,
|
||||||
|
foreign_gas_price: Arc<RwLock<u64>>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<T: Transport> Stream for DepositRelay<T> {
|
impl<T: Transport> Stream for DepositRelay<T> {
|
||||||
|
@ -85,7 +87,11 @@ impl<T: Transport> Stream for DepositRelay<T> {
|
||||||
let item = try_stream!(self.logs.poll().map_err(|e| ErrorKind::ContextualizedError(Box::new(e), "polling home for deposits")));
|
let item = try_stream!(self.logs.poll().map_err(|e| ErrorKind::ContextualizedError(Box::new(e), "polling home for deposits")));
|
||||||
let len = item.logs.len();
|
let len = item.logs.len();
|
||||||
info!("got {} new deposits to relay", len);
|
info!("got {} new deposits to relay", len);
|
||||||
let balance_required = U256::from(self.app.config.txs.deposit_relay.gas) * U256::from(self.app.config.txs.deposit_relay.gas_price) * U256::from(item.logs.len());
|
|
||||||
|
let gas = U256::from(self.app.config.txs.deposit_relay.gas);
|
||||||
|
let gas_price = U256::from(*self.foreign_gas_price.read().unwrap());
|
||||||
|
let balance_required = gas * gas_price * U256::from(item.logs.len());
|
||||||
|
|
||||||
if balance_required > *foreign_balance.as_ref().unwrap() {
|
if balance_required > *foreign_balance.as_ref().unwrap() {
|
||||||
return Err(ErrorKind::InsufficientFunds.into())
|
return Err(ErrorKind::InsufficientFunds.into())
|
||||||
}
|
}
|
||||||
|
@ -96,8 +102,8 @@ impl<T: Transport> Stream for DepositRelay<T> {
|
||||||
.into_iter()
|
.into_iter()
|
||||||
.map(|payload| {
|
.map(|payload| {
|
||||||
let tx = Transaction {
|
let tx = Transaction {
|
||||||
gas: self.app.config.txs.deposit_relay.gas.into(),
|
gas,
|
||||||
gas_price: self.app.config.txs.deposit_relay.gas_price.into(),
|
gas_price,
|
||||||
value: U256::zero(),
|
value: U256::zero(),
|
||||||
data: payload.0,
|
data: payload.0,
|
||||||
nonce: U256::zero(),
|
nonce: U256::zero(),
|
||||||
|
|
|
@ -0,0 +1,98 @@
|
||||||
|
use std::collections::HashMap;
|
||||||
|
use std::time::{Duration, Instant};
|
||||||
|
|
||||||
|
use futures::{Async, Future, Poll, Stream};
|
||||||
|
use hyper::{Chunk, client::HttpConnector, Client, Uri};
|
||||||
|
use hyper_tls::HttpsConnector;
|
||||||
|
use serde_json as json;
|
||||||
|
use tokio_core::reactor::Handle;
|
||||||
|
use tokio_timer::{Interval, Timer, Timeout};
|
||||||
|
|
||||||
|
use config::{GasPriceSpeed, Node};
|
||||||
|
use error::Error;
|
||||||
|
|
||||||
|
const CACHE_TIMEOUT_DURATION: Duration = Duration::from_secs(5 * 60);
|
||||||
|
const REQUEST_TIMEOUT_DURATION: Duration = Duration::from_secs(30);
|
||||||
|
|
||||||
|
enum State {
|
||||||
|
Initial,
|
||||||
|
WaitingForResponse(Timeout<Box<Future<Item = Chunk, Error = Error>>>),
|
||||||
|
Yield(Option<u64>),
|
||||||
|
}
|
||||||
|
|
||||||
|
pub struct GasPriceStream {
|
||||||
|
state: State,
|
||||||
|
client: Client<HttpsConnector<HttpConnector>>,
|
||||||
|
uri: Uri,
|
||||||
|
speed: GasPriceSpeed,
|
||||||
|
request_timer: Timer,
|
||||||
|
interval: Interval,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl GasPriceStream {
|
||||||
|
pub fn new(node: &Node, handle: &Handle, timer: &Timer) -> Self {
|
||||||
|
let client = Client::configure()
|
||||||
|
.connector(HttpsConnector::new(4, handle).unwrap())
|
||||||
|
.build(handle);
|
||||||
|
|
||||||
|
let uri: Uri = node.gas_price_oracle_url.clone().unwrap().parse().unwrap();
|
||||||
|
|
||||||
|
GasPriceStream {
|
||||||
|
state: State::Initial,
|
||||||
|
client,
|
||||||
|
uri,
|
||||||
|
speed: node.gas_price_speed,
|
||||||
|
request_timer: timer.clone(),
|
||||||
|
interval: timer.interval_at(Instant::now(), CACHE_TIMEOUT_DURATION),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Stream for GasPriceStream {
|
||||||
|
type Item = u64;
|
||||||
|
type Error = Error;
|
||||||
|
|
||||||
|
fn poll(&mut self) -> Poll<Option<Self::Item>, Self::Error> {
|
||||||
|
loop {
|
||||||
|
let next_state = match self.state {
|
||||||
|
State::Initial => {
|
||||||
|
let _ = try_stream!(self.interval.poll());
|
||||||
|
|
||||||
|
let request: Box<Future<Item = Chunk, Error = Error>> =
|
||||||
|
Box::new(
|
||||||
|
self.client.get(self.uri.clone())
|
||||||
|
.and_then(|resp| resp.body().concat2())
|
||||||
|
.map_err(|e| e.into())
|
||||||
|
);
|
||||||
|
|
||||||
|
let request_future = self.request_timer
|
||||||
|
.timeout(request, REQUEST_TIMEOUT_DURATION);
|
||||||
|
|
||||||
|
State::WaitingForResponse(request_future)
|
||||||
|
},
|
||||||
|
State::WaitingForResponse(ref mut request_future) => {
|
||||||
|
match request_future.poll() {
|
||||||
|
Ok(Async::NotReady) => return Ok(Async::NotReady),
|
||||||
|
Ok(Async::Ready(chunk)) => {
|
||||||
|
let json_obj: HashMap<String, json::Value> = json::from_slice(&chunk)?;
|
||||||
|
|
||||||
|
let gas_price = match json_obj.get(self.speed.as_str()) {
|
||||||
|
Some(json::Value::Number(price)) => (price.as_f64().unwrap() * 1_000_000_000.0).trunc() as u64,
|
||||||
|
_ => unreachable!(),
|
||||||
|
};
|
||||||
|
|
||||||
|
State::Yield(Some(gas_price))
|
||||||
|
},
|
||||||
|
Err(e) => panic!(e),
|
||||||
|
}
|
||||||
|
},
|
||||||
|
State::Yield(ref mut opt) => match opt.take() {
|
||||||
|
None => State::Initial,
|
||||||
|
price => return Ok(Async::Ready(price)),
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
self.state = next_state;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -5,6 +5,7 @@ pub mod nonce;
|
||||||
mod deposit_relay;
|
mod deposit_relay;
|
||||||
mod withdraw_confirm;
|
mod withdraw_confirm;
|
||||||
mod withdraw_relay;
|
mod withdraw_relay;
|
||||||
|
mod gas_price;
|
||||||
|
|
||||||
use std::fs;
|
use std::fs;
|
||||||
use std::sync::{Arc, RwLock};
|
use std::sync::{Arc, RwLock};
|
||||||
|
@ -15,6 +16,7 @@ use web3::types::U256;
|
||||||
use app::App;
|
use app::App;
|
||||||
use database::Database;
|
use database::Database;
|
||||||
use error::{Error, ErrorKind, Result};
|
use error::{Error, ErrorKind, Result};
|
||||||
|
use tokio_core::reactor::Handle;
|
||||||
|
|
||||||
pub use self::deploy::{Deploy, Deployed, create_deploy};
|
pub use self::deploy::{Deploy, Deployed, create_deploy};
|
||||||
pub use self::balance::{BalanceCheck, create_balance_check};
|
pub use self::balance::{BalanceCheck, create_balance_check};
|
||||||
|
@ -22,6 +24,7 @@ pub use self::chain_id::{ChainIdRetrieval, create_chain_id_retrieval};
|
||||||
pub use self::deposit_relay::{DepositRelay, create_deposit_relay};
|
pub use self::deposit_relay::{DepositRelay, create_deposit_relay};
|
||||||
pub use self::withdraw_relay::{WithdrawRelay, create_withdraw_relay};
|
pub use self::withdraw_relay::{WithdrawRelay, create_withdraw_relay};
|
||||||
pub use self::withdraw_confirm::{WithdrawConfirm, create_withdraw_confirm};
|
pub use self::withdraw_confirm::{WithdrawConfirm, create_withdraw_confirm};
|
||||||
|
pub use self::gas_price::GasPriceStream;
|
||||||
|
|
||||||
/// Last block checked by the bridge components.
|
/// Last block checked by the bridge components.
|
||||||
#[derive(Clone, Copy)]
|
#[derive(Clone, Copy)]
|
||||||
|
@ -71,30 +74,52 @@ enum BridgeStatus {
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Creates new bridge.
|
/// Creates new bridge.
|
||||||
pub fn create_bridge<T: Transport + Clone>(app: Arc<App<T>>, init: &Database, home_chain_id: u64, foreign_chain_id: u64) -> Bridge<T, FileBackend> {
|
pub fn create_bridge<T: Transport + Clone>(app: Arc<App<T>>, init: &Database, handle: &Handle, home_chain_id: u64, foreign_chain_id: u64) -> Bridge<T, FileBackend> {
|
||||||
let backend = FileBackend {
|
let backend = FileBackend {
|
||||||
path: app.database_path.clone(),
|
path: app.database_path.clone(),
|
||||||
database: init.clone(),
|
database: init.clone(),
|
||||||
};
|
};
|
||||||
|
|
||||||
create_bridge_backed_by(app, init, backend, home_chain_id, foreign_chain_id)
|
create_bridge_backed_by(app, init, backend, handle, home_chain_id, foreign_chain_id)
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Creates new bridge writing to custom backend.
|
/// Creates new bridge writing to custom backend.
|
||||||
pub fn create_bridge_backed_by<T: Transport + Clone, F: BridgeBackend>(app: Arc<App<T>>, init: &Database, backend: F, home_chain_id: u64, foreign_chain_id: u64) -> Bridge<T, F> {
|
pub fn create_bridge_backed_by<T: Transport + Clone, F: BridgeBackend>(app: Arc<App<T>>, init: &Database, backend: F, handle: &Handle, home_chain_id: u64, foreign_chain_id: u64) -> Bridge<T, F> {
|
||||||
let home_balance = Arc::new(RwLock::new(None));
|
let home_balance = Arc::new(RwLock::new(None));
|
||||||
let foreign_balance = Arc::new(RwLock::new(None));
|
let foreign_balance = Arc::new(RwLock::new(None));
|
||||||
|
|
||||||
|
let home_gas_stream = if app.config.home.gas_price_oracle_url.is_some() {
|
||||||
|
let stream = GasPriceStream::new(&app.config.home, handle, &app.timer);
|
||||||
|
Some(stream)
|
||||||
|
} else {
|
||||||
|
None
|
||||||
|
};
|
||||||
|
|
||||||
|
let foreign_gas_stream = if app.config.foreign.gas_price_oracle_url.is_some() {
|
||||||
|
let stream = GasPriceStream::new(&app.config.foreign, handle, &app.timer);
|
||||||
|
Some(stream)
|
||||||
|
} else {
|
||||||
|
None
|
||||||
|
};
|
||||||
|
|
||||||
|
let home_gas_price = Arc::new(RwLock::new(app.config.home.default_gas_price));
|
||||||
|
let foreign_gas_price = Arc::new(RwLock::new(app.config.foreign.default_gas_price));
|
||||||
|
|
||||||
Bridge {
|
Bridge {
|
||||||
foreign_balance_check: create_balance_check(app.clone(), app.connections.foreign.clone(), app.config.foreign.clone()),
|
foreign_balance_check: create_balance_check(app.clone(), app.connections.foreign.clone(), app.config.foreign.clone()),
|
||||||
home_balance_check: create_balance_check(app.clone(), app.connections.home.clone(), app.config.home.clone()),
|
home_balance_check: create_balance_check(app.clone(), app.connections.home.clone(), app.config.home.clone()),
|
||||||
foreign_balance: foreign_balance.clone(),
|
foreign_balance: foreign_balance.clone(),
|
||||||
home_balance: home_balance.clone(),
|
home_balance: home_balance.clone(),
|
||||||
deposit_relay: create_deposit_relay(app.clone(), init, foreign_balance.clone(), foreign_chain_id),
|
deposit_relay: create_deposit_relay(app.clone(), init, foreign_balance.clone(), foreign_chain_id, foreign_gas_price.clone()),
|
||||||
withdraw_relay: create_withdraw_relay(app.clone(), init, home_balance.clone(), home_chain_id),
|
withdraw_relay: create_withdraw_relay(app.clone(), init, home_balance.clone(), home_chain_id, home_gas_price.clone()),
|
||||||
withdraw_confirm: create_withdraw_confirm(app.clone(), init, foreign_balance.clone(), foreign_chain_id),
|
withdraw_confirm: create_withdraw_confirm(app.clone(), init, foreign_balance.clone(), foreign_chain_id, foreign_gas_price.clone()),
|
||||||
state: BridgeStatus::Wait,
|
state: BridgeStatus::Wait,
|
||||||
backend,
|
backend,
|
||||||
running: app.running.clone(),
|
running: app.running.clone(),
|
||||||
|
home_gas_stream,
|
||||||
|
foreign_gas_stream,
|
||||||
|
home_gas_price,
|
||||||
|
foreign_gas_price,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -109,6 +134,10 @@ pub struct Bridge<T: Transport, F> {
|
||||||
state: BridgeStatus,
|
state: BridgeStatus,
|
||||||
backend: F,
|
backend: F,
|
||||||
running: Arc<AtomicBool>,
|
running: Arc<AtomicBool>,
|
||||||
|
home_gas_stream: Option<GasPriceStream>,
|
||||||
|
foreign_gas_stream: Option<GasPriceStream>,
|
||||||
|
home_gas_price: Arc<RwLock<u64>>,
|
||||||
|
foreign_gas_price: Arc<RwLock<u64>>,
|
||||||
}
|
}
|
||||||
|
|
||||||
use std::sync::atomic::{AtomicBool, Ordering};
|
use std::sync::atomic::{AtomicBool, Ordering};
|
||||||
|
@ -134,6 +163,19 @@ impl<T: Transport, F: BridgeBackend> Bridge<T, F> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn get_gas_prices(&mut self) -> Poll<Option<()>, Error> {
|
||||||
|
if let Some(ref mut home_gas_stream) = self.home_gas_stream {
|
||||||
|
let mut home_price = self.home_gas_price.write().unwrap();
|
||||||
|
*home_price = try_bridge!(home_gas_stream.poll()).unwrap_or(*home_price);
|
||||||
|
}
|
||||||
|
|
||||||
|
if let Some(ref mut foreign_gas_stream) = self.foreign_gas_stream {
|
||||||
|
let mut foreign_price = self.foreign_gas_price.write().unwrap();
|
||||||
|
*foreign_price = try_bridge!(foreign_gas_stream.poll()).unwrap_or(*foreign_price);
|
||||||
|
}
|
||||||
|
|
||||||
|
Ok(Async::Ready(None))
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<T: Transport, F: BridgeBackend> Stream for Bridge<T, F> {
|
impl<T: Transport, F: BridgeBackend> Stream for Bridge<T, F> {
|
||||||
|
@ -161,6 +203,8 @@ impl<T: Transport, F: BridgeBackend> Stream for Bridge<T, F> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
let _ = self.get_gas_prices();
|
||||||
|
|
||||||
let d_relay = try_bridge!(self.deposit_relay.poll().map_err(|e| ErrorKind::ContextualizedError(Box::new(e), "deposit_relay")))
|
let d_relay = try_bridge!(self.deposit_relay.poll().map_err(|e| ErrorKind::ContextualizedError(Box::new(e), "deposit_relay")))
|
||||||
.map(BridgeChecked::DepositRelay);
|
.map(BridgeChecked::DepositRelay);
|
||||||
|
|
||||||
|
|
|
@ -37,7 +37,7 @@ enum WithdrawConfirmState<T: Transport> {
|
||||||
Yield(Option<u64>),
|
Yield(Option<u64>),
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn create_withdraw_confirm<T: Transport + Clone>(app: Arc<App<T>>, init: &Database, foreign_balance: Arc<RwLock<Option<U256>>>, foreign_chain_id: u64) -> WithdrawConfirm<T> {
|
pub fn create_withdraw_confirm<T: Transport + Clone>(app: Arc<App<T>>, init: &Database, foreign_balance: Arc<RwLock<Option<U256>>>, foreign_chain_id: u64, foreign_gas_price: Arc<RwLock<u64>>) -> WithdrawConfirm<T> {
|
||||||
let logs_init = api::LogStreamInit {
|
let logs_init = api::LogStreamInit {
|
||||||
after: init.checked_withdraw_confirm,
|
after: init.checked_withdraw_confirm,
|
||||||
request_timeout: app.config.foreign.request_timeout,
|
request_timeout: app.config.foreign.request_timeout,
|
||||||
|
@ -53,6 +53,7 @@ pub fn create_withdraw_confirm<T: Transport + Clone>(app: Arc<App<T>>, init: &Da
|
||||||
app,
|
app,
|
||||||
foreign_balance,
|
foreign_balance,
|
||||||
foreign_chain_id,
|
foreign_chain_id,
|
||||||
|
foreign_gas_price,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -63,6 +64,7 @@ pub struct WithdrawConfirm<T: Transport> {
|
||||||
foreign_contract: Address,
|
foreign_contract: Address,
|
||||||
foreign_balance: Arc<RwLock<Option<U256>>>,
|
foreign_balance: Arc<RwLock<Option<U256>>>,
|
||||||
foreign_chain_id: u64,
|
foreign_chain_id: u64,
|
||||||
|
foreign_gas_price: Arc<RwLock<u64>>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<T: Transport> Stream for WithdrawConfirm<T> {
|
impl<T: Transport> Stream for WithdrawConfirm<T> {
|
||||||
|
@ -73,7 +75,7 @@ impl<T: Transport> Stream for WithdrawConfirm<T> {
|
||||||
// borrow checker...
|
// borrow checker...
|
||||||
let app = &self.app;
|
let app = &self.app;
|
||||||
let gas = self.app.config.txs.withdraw_confirm.gas.into();
|
let gas = self.app.config.txs.withdraw_confirm.gas.into();
|
||||||
let gas_price = self.app.config.txs.withdraw_confirm.gas_price.into();
|
let gas_price = U256::from(*self.foreign_gas_price.read().unwrap());
|
||||||
let contract = self.foreign_contract.clone();
|
let contract = self.foreign_contract.clone();
|
||||||
loop {
|
loop {
|
||||||
let next_state = match self.state {
|
let next_state = match self.state {
|
||||||
|
@ -110,7 +112,7 @@ impl<T: Transport> Stream for WithdrawConfirm<T> {
|
||||||
|
|
||||||
let block = item.to;
|
let block = item.to;
|
||||||
|
|
||||||
let balance_required = U256::from(self.app.config.txs.withdraw_confirm.gas) * U256::from(self.app.config.txs.withdraw_confirm.gas_price) * U256::from(signatures.len());
|
let balance_required = gas * gas_price * U256::from(signatures.len());
|
||||||
if balance_required > *foreign_balance.as_ref().unwrap() {
|
if balance_required > *foreign_balance.as_ref().unwrap() {
|
||||||
return Err(ErrorKind::InsufficientFunds.into())
|
return Err(ErrorKind::InsufficientFunds.into())
|
||||||
}
|
}
|
||||||
|
@ -124,7 +126,8 @@ impl<T: Transport> Stream for WithdrawConfirm<T> {
|
||||||
})
|
})
|
||||||
.map(|payload| {
|
.map(|payload| {
|
||||||
let tx = Transaction {
|
let tx = Transaction {
|
||||||
gas, gas_price,
|
gas,
|
||||||
|
gas_price,
|
||||||
value: U256::zero(),
|
value: U256::zero(),
|
||||||
data: payload.0,
|
data: payload.0,
|
||||||
nonce: U256::zero(),
|
nonce: U256::zero(),
|
||||||
|
|
|
@ -76,7 +76,7 @@ pub enum WithdrawRelayState<T: Transport> {
|
||||||
Yield(Option<u64>),
|
Yield(Option<u64>),
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn create_withdraw_relay<T: Transport + Clone>(app: Arc<App<T>>, init: &Database, home_balance: Arc<RwLock<Option<U256>>>, home_chain_id: u64) -> WithdrawRelay<T> {
|
pub fn create_withdraw_relay<T: Transport + Clone>(app: Arc<App<T>>, init: &Database, home_balance: Arc<RwLock<Option<U256>>>, home_chain_id: u64, home_gas_price: Arc<RwLock<u64>>) -> WithdrawRelay<T> {
|
||||||
let logs_init = api::LogStreamInit {
|
let logs_init = api::LogStreamInit {
|
||||||
after: init.checked_withdraw_relay,
|
after: init.checked_withdraw_relay,
|
||||||
request_timeout: app.config.foreign.request_timeout,
|
request_timeout: app.config.foreign.request_timeout,
|
||||||
|
@ -93,6 +93,7 @@ pub fn create_withdraw_relay<T: Transport + Clone>(app: Arc<App<T>>, init: &Data
|
||||||
app,
|
app,
|
||||||
home_balance,
|
home_balance,
|
||||||
home_chain_id,
|
home_chain_id,
|
||||||
|
home_gas_price,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -104,6 +105,7 @@ pub struct WithdrawRelay<T: Transport> {
|
||||||
home_contract: Address,
|
home_contract: Address,
|
||||||
home_balance: Arc<RwLock<Option<U256>>>,
|
home_balance: Arc<RwLock<Option<U256>>>,
|
||||||
home_chain_id: u64,
|
home_chain_id: u64,
|
||||||
|
home_gas_price: Arc<RwLock<u64>>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<T: Transport> Stream for WithdrawRelay<T> {
|
impl<T: Transport> Stream for WithdrawRelay<T> {
|
||||||
|
@ -113,6 +115,7 @@ impl<T: Transport> Stream for WithdrawRelay<T> {
|
||||||
fn poll(&mut self) -> Poll<Option<Self::Item>, Self::Error> {
|
fn poll(&mut self) -> Poll<Option<Self::Item>, Self::Error> {
|
||||||
let app = &self.app;
|
let app = &self.app;
|
||||||
let gas = self.app.config.txs.withdraw_relay.gas.into();
|
let gas = self.app.config.txs.withdraw_relay.gas.into();
|
||||||
|
let gas_price = U256::from(*self.home_gas_price.read().unwrap());
|
||||||
let contract = self.home_contract.clone();
|
let contract = self.home_contract.clone();
|
||||||
let home = &self.app.config.home;
|
let home = &self.app.config.home;
|
||||||
let t = &self.app.connections.home;
|
let t = &self.app.connections.home;
|
||||||
|
@ -178,7 +181,7 @@ impl<T: Transport> Stream for WithdrawRelay<T> {
|
||||||
info!("fetching messages and signatures complete");
|
info!("fetching messages and signatures complete");
|
||||||
assert_eq!(messages_raw.len(), signatures_raw.len());
|
assert_eq!(messages_raw.len(), signatures_raw.len());
|
||||||
|
|
||||||
let balance_required = U256::from(self.app.config.txs.withdraw_relay.gas) * U256::from(self.app.config.txs.withdraw_relay.gas_price) * U256::from(messages_raw.len());
|
let balance_required = gas * gas_price * U256::from(messages_raw.len());
|
||||||
if balance_required > *home_balance.as_ref().unwrap() {
|
if balance_required > *home_balance.as_ref().unwrap() {
|
||||||
return Err(ErrorKind::InsufficientFunds.into())
|
return Err(ErrorKind::InsufficientFunds.into())
|
||||||
}
|
}
|
||||||
|
@ -221,7 +224,8 @@ impl<T: Transport> Stream for WithdrawRelay<T> {
|
||||||
message.clone().0).into();
|
message.clone().0).into();
|
||||||
let gas_price = MessageToMainnet::from_bytes(message.0.as_slice()).mainnet_gas_price;
|
let gas_price = MessageToMainnet::from_bytes(message.0.as_slice()).mainnet_gas_price;
|
||||||
let tx = Transaction {
|
let tx = Transaction {
|
||||||
gas, gas_price,
|
gas,
|
||||||
|
gas_price,
|
||||||
value: U256::zero(),
|
value: U256::zero(),
|
||||||
data: payload.0,
|
data: payload.0,
|
||||||
nonce: U256::zero(),
|
nonce: U256::zero(),
|
||||||
|
|
|
@ -1,6 +1,7 @@
|
||||||
use std::path::{Path, PathBuf};
|
use std::path::{Path, PathBuf};
|
||||||
use std::fs;
|
use std::fs;
|
||||||
use std::io::Read;
|
use std::io::Read;
|
||||||
|
use std::str::FromStr;
|
||||||
use std::time::Duration;
|
use std::time::Duration;
|
||||||
#[cfg(feature = "deploy")]
|
#[cfg(feature = "deploy")]
|
||||||
use rustc_hex::FromHex;
|
use rustc_hex::FromHex;
|
||||||
|
@ -15,6 +16,9 @@ const DEFAULT_CONFIRMATIONS: usize = 12;
|
||||||
const DEFAULT_TIMEOUT: u64 = 3600;
|
const DEFAULT_TIMEOUT: u64 = 3600;
|
||||||
const DEFAULT_RPC_PORT: u16 = 8545;
|
const DEFAULT_RPC_PORT: u16 = 8545;
|
||||||
const DEFAULT_CONCURRENCY: usize = 100;
|
const DEFAULT_CONCURRENCY: usize = 100;
|
||||||
|
const DEFAULT_GAS_PRICE_SPEED: GasPriceSpeed = GasPriceSpeed::Fast;
|
||||||
|
const DEFAULT_GAS_PRICE_TIMEOUT_SECS: u64 = 10;
|
||||||
|
const DEFAULT_GAS_PRICE_WEI: u64 = 15_000_000_000;
|
||||||
|
|
||||||
/// Application config.
|
/// Application config.
|
||||||
#[derive(Debug, PartialEq, Clone)]
|
#[derive(Debug, PartialEq, Clone)]
|
||||||
|
@ -71,6 +75,10 @@ pub struct Node {
|
||||||
pub rpc_port: u16,
|
pub rpc_port: u16,
|
||||||
pub password: PathBuf,
|
pub password: PathBuf,
|
||||||
pub info: NodeInfo,
|
pub info: NodeInfo,
|
||||||
|
pub gas_price_oracle_url: Option<String>,
|
||||||
|
pub gas_price_speed: GasPriceSpeed,
|
||||||
|
pub gas_price_timeout: Duration,
|
||||||
|
pub default_gas_price: u64,
|
||||||
}
|
}
|
||||||
|
|
||||||
use std::sync::{Arc, RwLock};
|
use std::sync::{Arc, RwLock};
|
||||||
|
@ -97,6 +105,20 @@ impl PartialEq for NodeInfo {
|
||||||
|
|
||||||
impl Node {
|
impl Node {
|
||||||
fn from_load_struct(node: load::Node) -> Result<Node, Error> {
|
fn from_load_struct(node: load::Node) -> Result<Node, Error> {
|
||||||
|
let gas_price_oracle_url = node.gas_price_oracle_url.clone();
|
||||||
|
|
||||||
|
let gas_price_speed = match node.gas_price_speed {
|
||||||
|
Some(ref s) => GasPriceSpeed::from_str(s).unwrap(),
|
||||||
|
None => DEFAULT_GAS_PRICE_SPEED
|
||||||
|
};
|
||||||
|
|
||||||
|
let gas_price_timeout = {
|
||||||
|
let n_secs = node.gas_price_timeout.unwrap_or(DEFAULT_GAS_PRICE_TIMEOUT_SECS);
|
||||||
|
Duration::from_secs(n_secs)
|
||||||
|
};
|
||||||
|
|
||||||
|
let default_gas_price = node.default_gas_price.unwrap_or(DEFAULT_GAS_PRICE_WEI);
|
||||||
|
|
||||||
let result = Node {
|
let result = Node {
|
||||||
account: node.account,
|
account: node.account,
|
||||||
#[cfg(feature = "deploy")]
|
#[cfg(feature = "deploy")]
|
||||||
|
@ -115,6 +137,10 @@ impl Node {
|
||||||
rpc_port: node.rpc_port.unwrap_or(DEFAULT_RPC_PORT),
|
rpc_port: node.rpc_port.unwrap_or(DEFAULT_RPC_PORT),
|
||||||
password: node.password,
|
password: node.password,
|
||||||
info: Default::default(),
|
info: Default::default(),
|
||||||
|
gas_price_oracle_url,
|
||||||
|
gas_price_speed,
|
||||||
|
gas_price_timeout,
|
||||||
|
default_gas_price,
|
||||||
};
|
};
|
||||||
|
|
||||||
Ok(result)
|
Ok(result)
|
||||||
|
@ -184,6 +210,40 @@ pub struct Authorities {
|
||||||
pub required_signatures: u32,
|
pub required_signatures: u32,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[derive(Clone, Copy, Debug, PartialEq)]
|
||||||
|
pub enum GasPriceSpeed {
|
||||||
|
Instant,
|
||||||
|
Fast,
|
||||||
|
Standard,
|
||||||
|
Slow,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl FromStr for GasPriceSpeed {
|
||||||
|
type Err = ();
|
||||||
|
|
||||||
|
fn from_str(s: &str) -> Result<Self, Self::Err> {
|
||||||
|
let speed = match s {
|
||||||
|
"instant" => GasPriceSpeed::Instant,
|
||||||
|
"fast" => GasPriceSpeed::Fast,
|
||||||
|
"standard" => GasPriceSpeed::Standard,
|
||||||
|
"slow" => GasPriceSpeed::Slow,
|
||||||
|
_ => return Err(()),
|
||||||
|
};
|
||||||
|
Ok(speed)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl GasPriceSpeed {
|
||||||
|
pub fn as_str(&self) -> &str {
|
||||||
|
match *self {
|
||||||
|
GasPriceSpeed::Instant => "instant",
|
||||||
|
GasPriceSpeed::Fast => "fast",
|
||||||
|
GasPriceSpeed::Standard => "standard",
|
||||||
|
GasPriceSpeed::Slow => "slow",
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/// Some config values may not be defined in `toml` file, but they should be specified at runtime.
|
/// Some config values may not be defined in `toml` file, but they should be specified at runtime.
|
||||||
/// `load` module separates `Config` representation in file with optional from the one used
|
/// `load` module separates `Config` representation in file with optional from the one used
|
||||||
/// in application.
|
/// in application.
|
||||||
|
@ -213,6 +273,10 @@ mod load {
|
||||||
pub rpc_host: Option<String>,
|
pub rpc_host: Option<String>,
|
||||||
pub rpc_port: Option<u16>,
|
pub rpc_port: Option<u16>,
|
||||||
pub password: PathBuf,
|
pub password: PathBuf,
|
||||||
|
pub gas_price_oracle_url: Option<String>,
|
||||||
|
pub gas_price_speed: Option<String>,
|
||||||
|
pub gas_price_timeout: Option<u64>,
|
||||||
|
pub default_gas_price: Option<u64>,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Deserialize)]
|
#[derive(Deserialize)]
|
||||||
|
@ -258,7 +322,7 @@ mod tests {
|
||||||
use super::ContractConfig;
|
use super::ContractConfig;
|
||||||
#[cfg(feature = "deploy")]
|
#[cfg(feature = "deploy")]
|
||||||
use super::TransactionConfig;
|
use super::TransactionConfig;
|
||||||
use super::DEFAULT_TIMEOUT;
|
use super::{DEFAULT_TIMEOUT, DEFAULT_CONCURRENCY, DEFAULT_GAS_PRICE_SPEED, DEFAULT_GAS_PRICE_TIMEOUT_SECS, DEFAULT_GAS_PRICE_WEI};
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn load_full_setup_from_str() {
|
fn load_full_setup_from_str() {
|
||||||
|
@ -314,6 +378,10 @@ home_deploy = { gas = 20 }
|
||||||
rpc_port: 8545,
|
rpc_port: 8545,
|
||||||
password: "password".into(),
|
password: "password".into(),
|
||||||
info: Default::default(),
|
info: Default::default(),
|
||||||
|
gas_price_oracle_url: None,
|
||||||
|
gas_price_speed: DEFAULT_GAS_PRICE_SPEED,
|
||||||
|
gas_price_timeout: Duration::from_secs(DEFAULT_GAS_PRICE_TIMEOUT_SECS),
|
||||||
|
default_gas_price: DEFAULT_GAS_PRICE_WEI,
|
||||||
},
|
},
|
||||||
foreign: Node {
|
foreign: Node {
|
||||||
account: "0000000000000000000000000000000000000001".into(),
|
account: "0000000000000000000000000000000000000001".into(),
|
||||||
|
@ -328,6 +396,10 @@ home_deploy = { gas = 20 }
|
||||||
rpc_port: 8545,
|
rpc_port: 8545,
|
||||||
password: "password".into(),
|
password: "password".into(),
|
||||||
info: Default::default(),
|
info: Default::default(),
|
||||||
|
gas_price_oracle_url: None,
|
||||||
|
gas_price_speed: DEFAULT_GAS_PRICE_SPEED,
|
||||||
|
gas_price_timeout: Duration::from_secs(DEFAULT_GAS_PRICE_TIMEOUT_SECS),
|
||||||
|
default_gas_price: DEFAULT_GAS_PRICE_WEI,
|
||||||
},
|
},
|
||||||
authorities: Authorities {
|
authorities: Authorities {
|
||||||
accounts: vec![
|
accounts: vec![
|
||||||
|
@ -346,6 +418,7 @@ home_deploy = { gas = 20 }
|
||||||
expected.txs.home_deploy = TransactionConfig {
|
expected.txs.home_deploy = TransactionConfig {
|
||||||
gas: 20,
|
gas: 20,
|
||||||
gas_price: 0,
|
gas_price: 0,
|
||||||
|
concurrency: DEFAULT_CONCURRENCY,
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -398,6 +471,10 @@ required_signatures = 2
|
||||||
rpc_port: 8545,
|
rpc_port: 8545,
|
||||||
password: "password".into(),
|
password: "password".into(),
|
||||||
info: Default::default(),
|
info: Default::default(),
|
||||||
|
gas_price_oracle_url: None,
|
||||||
|
gas_price_speed: DEFAULT_GAS_PRICE_SPEED,
|
||||||
|
gas_price_timeout: Duration::from_secs(DEFAULT_GAS_PRICE_TIMEOUT_SECS),
|
||||||
|
default_gas_price: DEFAULT_GAS_PRICE_WEI,
|
||||||
},
|
},
|
||||||
foreign: Node {
|
foreign: Node {
|
||||||
account: "0000000000000000000000000000000000000001".into(),
|
account: "0000000000000000000000000000000000000001".into(),
|
||||||
|
@ -412,6 +489,10 @@ required_signatures = 2
|
||||||
rpc_port: 8545,
|
rpc_port: 8545,
|
||||||
password: "password".into(),
|
password: "password".into(),
|
||||||
info: Default::default(),
|
info: Default::default(),
|
||||||
|
gas_price_oracle_url: None,
|
||||||
|
gas_price_speed: DEFAULT_GAS_PRICE_SPEED,
|
||||||
|
gas_price_timeout: Duration::from_secs(DEFAULT_GAS_PRICE_TIMEOUT_SECS),
|
||||||
|
default_gas_price: DEFAULT_GAS_PRICE_WEI,
|
||||||
},
|
},
|
||||||
authorities: Authorities {
|
authorities: Authorities {
|
||||||
accounts: vec![
|
accounts: vec![
|
||||||
|
|
|
@ -5,6 +5,8 @@ use tokio_timer::{TimerError, TimeoutError};
|
||||||
use {web3, toml, ethabi, rustc_hex};
|
use {web3, toml, ethabi, rustc_hex};
|
||||||
use ethcore::ethstore;
|
use ethcore::ethstore;
|
||||||
use ethcore::account_provider::{SignError, Error as AccountError};
|
use ethcore::account_provider::{SignError, Error as AccountError};
|
||||||
|
use serde_json;
|
||||||
|
use hyper;
|
||||||
|
|
||||||
error_chain! {
|
error_chain! {
|
||||||
types {
|
types {
|
||||||
|
@ -17,6 +19,8 @@ error_chain! {
|
||||||
Ethabi(ethabi::Error);
|
Ethabi(ethabi::Error);
|
||||||
Timer(TimerError);
|
Timer(TimerError);
|
||||||
Hex(rustc_hex::FromHexError);
|
Hex(rustc_hex::FromHexError);
|
||||||
|
Json(serde_json::Error);
|
||||||
|
Hyper(hyper::Error);
|
||||||
}
|
}
|
||||||
|
|
||||||
errors {
|
errors {
|
||||||
|
|
|
@ -30,6 +30,8 @@ extern crate keccak_hash;
|
||||||
extern crate jsonrpc_core as rpc;
|
extern crate jsonrpc_core as rpc;
|
||||||
|
|
||||||
extern crate itertools;
|
extern crate itertools;
|
||||||
|
extern crate hyper;
|
||||||
|
extern crate hyper_tls;
|
||||||
|
|
||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
#[macro_use]
|
#[macro_use]
|
||||||
|
|
|
@ -123,6 +123,7 @@ fn execute<S, I>(command: I, running: Arc<AtomicBool>) -> Result<String, UserFac
|
||||||
|
|
||||||
info!(target: "bridge", "Starting event loop");
|
info!(target: "bridge", "Starting event loop");
|
||||||
let mut event_loop = Core::new().unwrap();
|
let mut event_loop = Core::new().unwrap();
|
||||||
|
let handle = event_loop.handle();
|
||||||
|
|
||||||
info!(target: "bridge", "Home rpc host {}", config.clone().home.rpc_host);
|
info!(target: "bridge", "Home rpc host {}", config.clone().home.rpc_host);
|
||||||
info!(target: "bridge", "Foreign rpc host {}", config.clone().foreign.rpc_host);
|
info!(target: "bridge", "Foreign rpc host {}", config.clone().foreign.rpc_host);
|
||||||
|
@ -130,7 +131,7 @@ fn execute<S, I>(command: I, running: Arc<AtomicBool>) -> Result<String, UserFac
|
||||||
info!(target: "bridge", "Establishing connection:");
|
info!(target: "bridge", "Establishing connection:");
|
||||||
|
|
||||||
info!(target:"bridge", " using RPC connection");
|
info!(target:"bridge", " using RPC connection");
|
||||||
let app = match App::new_http(config.clone(), &args.arg_database, &event_loop.handle(), running.clone()) {
|
let app = match App::new_http(config.clone(), &args.arg_database, &handle, running.clone()) {
|
||||||
Ok(app) => app,
|
Ok(app) => app,
|
||||||
Err(e) => {
|
Err(e) => {
|
||||||
warn!("Can't establish an RPC connection: {:?}", e);
|
warn!("Can't establish an RPC connection: {:?}", e);
|
||||||
|
@ -176,7 +177,7 @@ fn execute<S, I>(command: I, running: Arc<AtomicBool>) -> Result<String, UserFac
|
||||||
};
|
};
|
||||||
|
|
||||||
info!(target: "bridge", "Starting listening to events");
|
info!(target: "bridge", "Starting listening to events");
|
||||||
let bridge = create_bridge(app.clone(), &database, home_chain_id, foreign_chain_id).and_then(|_| future::ok(true)).collect();
|
let bridge = create_bridge(app.clone(), &database, &handle, home_chain_id, foreign_chain_id).and_then(|_| future::ok(true)).collect();
|
||||||
let mut result = event_loop.run(bridge);
|
let mut result = event_loop.run(bridge);
|
||||||
loop {
|
loop {
|
||||||
match result {
|
match result {
|
||||||
|
|
|
@ -7,6 +7,7 @@ required_confirmations = 0
|
||||||
rpc_host = "http://127.0.0.1"
|
rpc_host = "http://127.0.0.1"
|
||||||
rpc_port = 8550
|
rpc_port = 8550
|
||||||
password = "password.txt"
|
password = "password.txt"
|
||||||
|
default_gas_price = 0
|
||||||
|
|
||||||
[home.contract]
|
[home.contract]
|
||||||
bin = "../compiled_contracts/HomeBridge.bin"
|
bin = "../compiled_contracts/HomeBridge.bin"
|
||||||
|
@ -17,6 +18,7 @@ required_confirmations = 0
|
||||||
rpc_host = "http://127.0.0.1"
|
rpc_host = "http://127.0.0.1"
|
||||||
rpc_port = 8551
|
rpc_port = 8551
|
||||||
password = "password.txt"
|
password = "password.txt"
|
||||||
|
default_gas_price = 0
|
||||||
|
|
||||||
[foreign.contract]
|
[foreign.contract]
|
||||||
bin = "../compiled_contracts/ForeignBridge.bin"
|
bin = "../compiled_contracts/ForeignBridge.bin"
|
||||||
|
|
|
@ -11,5 +11,6 @@ web3 = "0.3"
|
||||||
serde_json = "1.0"
|
serde_json = "1.0"
|
||||||
pretty_assertions = "0.2.1"
|
pretty_assertions = "0.2.1"
|
||||||
ethabi = "5.0"
|
ethabi = "5.0"
|
||||||
|
ethcore = { git = "http://github.com/paritytech/parity", rev = "991f0ca" }
|
||||||
ethereum-types = "0.3"
|
ethereum-types = "0.3"
|
||||||
rustc-hex = "1.0"
|
rustc-hex = "1.0"
|
||||||
|
|
|
@ -5,6 +5,7 @@ extern crate web3;
|
||||||
extern crate bridge;
|
extern crate bridge;
|
||||||
#[macro_use]
|
#[macro_use]
|
||||||
extern crate pretty_assertions;
|
extern crate pretty_assertions;
|
||||||
|
extern crate ethcore;
|
||||||
|
|
||||||
use std::cell::Cell;
|
use std::cell::Cell;
|
||||||
use web3::Transport;
|
use web3::Transport;
|
||||||
|
@ -35,9 +36,47 @@ impl Transport for MockedTransport {
|
||||||
type Out = web3::Result<rpc::Value>;
|
type Out = web3::Result<rpc::Value>;
|
||||||
|
|
||||||
fn prepare(&self, method: &str, params: Vec<rpc::Value>) -> (usize, rpc::Call) {
|
fn prepare(&self, method: &str, params: Vec<rpc::Value>) -> (usize, rpc::Call) {
|
||||||
let n = self.requests.get();
|
let n = self.requests.get();
|
||||||
assert_eq!(&self.expected_requests[n].method as &str, method, "invalid method called");
|
assert_eq!(&self.expected_requests[n].method as &str, method, "invalid method called");
|
||||||
assert_eq!(self.expected_requests[n].params, params, "invalid method params");
|
|
||||||
|
for (expected_params, params) in self.expected_requests[n].params.iter().zip(params.iter()) {
|
||||||
|
assert_eq!(expected_params.get("address"), params.get("address"), "invalid method params, addresses do not match");
|
||||||
|
assert_eq!(expected_params.get("fromBlock"), params.get("fromBlock"), "invalid method params, from-blocks do not match");
|
||||||
|
assert_eq!(expected_params.get("limit"), params.get("limit"), "invalid method params, limits do not match");
|
||||||
|
assert_eq!(expected_params.get("toBlock"), params.get("toBlock"), "invalid method params, to-blocks do not match");
|
||||||
|
|
||||||
|
let expected_topics: Vec<rpc::Value> = if let Some(ref topics) = expected_params.get("topics") {
|
||||||
|
topics.as_array().unwrap().clone()
|
||||||
|
.iter()
|
||||||
|
.filter_map(|topic|
|
||||||
|
if topic != &rpc::Value::Null {
|
||||||
|
Some(topic.clone())
|
||||||
|
} else {
|
||||||
|
None
|
||||||
|
}
|
||||||
|
)
|
||||||
|
.collect()
|
||||||
|
} else {
|
||||||
|
vec![]
|
||||||
|
};
|
||||||
|
|
||||||
|
let topics: Vec<rpc::Value> = if let Some(ref topics) = params.get("topics") {
|
||||||
|
topics.as_array().unwrap().clone()
|
||||||
|
.iter()
|
||||||
|
.filter_map(|topic|
|
||||||
|
if topic != &rpc::Value::Null {
|
||||||
|
Some(topic.clone())
|
||||||
|
} else {
|
||||||
|
None
|
||||||
|
}
|
||||||
|
)
|
||||||
|
.collect()
|
||||||
|
} else {
|
||||||
|
vec![]
|
||||||
|
};
|
||||||
|
|
||||||
|
assert_eq!(expected_topics, topics, "invalid method params, topics do not match");
|
||||||
|
}
|
||||||
self.requests.set(n + 1);
|
self.requests.set(n + 1);
|
||||||
|
|
||||||
let request = web3::helpers::build_request(1, method, params);
|
let request = web3::helpers::build_request(1, method, params);
|
||||||
|
@ -98,15 +137,16 @@ macro_rules! test_app_stream {
|
||||||
use self::futures::{Future, Stream};
|
use self::futures::{Future, Stream};
|
||||||
use self::bridge::app::{App, Connections};
|
use self::bridge::app::{App, Connections};
|
||||||
use self::bridge::contracts::{foreign, home};
|
use self::bridge::contracts::{foreign, home};
|
||||||
use self::bridge::config::{Config, Authorities, Node, ContractConfig, Transactions, TransactionConfig};
|
use self::bridge::config::{Config, Authorities, Node, NodeInfo, ContractConfig, Transactions, TransactionConfig, GasPriceSpeed};
|
||||||
use self::bridge::database::Database;
|
use self::bridge::database::Database;
|
||||||
|
use ethcore::account_provider::AccountProvider;
|
||||||
|
|
||||||
let home = $crate::MockedTransport {
|
let home = $crate::MockedTransport {
|
||||||
requests: Default::default(),
|
requests: Default::default(),
|
||||||
expected_requests: vec![$($home_method),*].into_iter().zip(vec![$($home_req),*].into_iter()).map(Into::into).collect(),
|
expected_requests: vec![$($home_method),*].into_iter().zip(vec![$($home_req),*].into_iter()).map(Into::into).collect(),
|
||||||
mocked_responses: vec![$($home_res),*],
|
mocked_responses: vec![$($home_res),*],
|
||||||
};
|
};
|
||||||
|
|
||||||
let foreign = $crate::MockedTransport {
|
let foreign = $crate::MockedTransport {
|
||||||
requests: Default::default(),
|
requests: Default::default(),
|
||||||
expected_requests: vec![$($foreign_method),*].into_iter().zip(vec![$($foreign_req),*].into_iter()).map(Into::into).collect(),
|
expected_requests: vec![$($foreign_method),*].into_iter().zip(vec![$($foreign_req),*].into_iter()).map(Into::into).collect(),
|
||||||
|
@ -125,6 +165,12 @@ macro_rules! test_app_stream {
|
||||||
required_confirmations: $home_conf,
|
required_confirmations: $home_conf,
|
||||||
rpc_host: "".into(),
|
rpc_host: "".into(),
|
||||||
rpc_port: 8545,
|
rpc_port: 8545,
|
||||||
|
password: "password.txt".into(),
|
||||||
|
info: NodeInfo::default(),
|
||||||
|
gas_price_oracle_url: None,
|
||||||
|
gas_price_speed: GasPriceSpeed::Fast,
|
||||||
|
gas_price_timeout: Duration::from_secs(5),
|
||||||
|
default_gas_price: 0,
|
||||||
},
|
},
|
||||||
foreign: Node {
|
foreign: Node {
|
||||||
account: $foreign_acc.parse().unwrap(),
|
account: $foreign_acc.parse().unwrap(),
|
||||||
|
@ -136,6 +182,12 @@ macro_rules! test_app_stream {
|
||||||
required_confirmations: $foreign_conf,
|
required_confirmations: $foreign_conf,
|
||||||
rpc_host: "".into(),
|
rpc_host: "".into(),
|
||||||
rpc_port: 8545,
|
rpc_port: 8545,
|
||||||
|
password: "password.txt".into(),
|
||||||
|
info: NodeInfo::default(),
|
||||||
|
gas_price_oracle_url: None,
|
||||||
|
gas_price_speed: GasPriceSpeed::Fast,
|
||||||
|
gas_price_timeout: Duration::from_secs(5),
|
||||||
|
default_gas_price: 0,
|
||||||
},
|
},
|
||||||
authorities: Authorities {
|
authorities: Authorities {
|
||||||
accounts: $authorities_accs.iter().map(|a: &&str| a.parse().unwrap()).collect(),
|
accounts: $authorities_accs.iter().map(|a: &&str| a.parse().unwrap()).collect(),
|
||||||
|
@ -156,9 +208,10 @@ macro_rules! test_app_stream {
|
||||||
foreign_bridge: foreign::ForeignBridge::default(),
|
foreign_bridge: foreign::ForeignBridge::default(),
|
||||||
timer: Default::default(),
|
timer: Default::default(),
|
||||||
running: Arc::new(AtomicBool::new(true)),
|
running: Arc::new(AtomicBool::new(true)),
|
||||||
|
keystore: AccountProvider::transient_provider(),
|
||||||
};
|
};
|
||||||
|
|
||||||
let app = Arc::new(app);
|
let app = Arc::new(app);
|
||||||
let stream = $init_stream(app, &$db);
|
let stream = $init_stream(app, &$db);
|
||||||
let res = stream.collect().wait();
|
let res = stream.collect().wait();
|
||||||
|
|
||||||
|
|
|
@ -4,6 +4,7 @@ extern crate serde_json;
|
||||||
extern crate bridge;
|
extern crate bridge;
|
||||||
#[macro_use]
|
#[macro_use]
|
||||||
extern crate tests;
|
extern crate tests;
|
||||||
|
extern crate ethcore;
|
||||||
|
|
||||||
use bridge::bridge::create_deposit_relay;
|
use bridge::bridge::create_deposit_relay;
|
||||||
|
|
||||||
|
@ -27,7 +28,7 @@ test_app_stream! {
|
||||||
],
|
],
|
||||||
signatures => 1;
|
signatures => 1;
|
||||||
txs => Transactions::default(),
|
txs => Transactions::default(),
|
||||||
init => |app, db| create_deposit_relay(app, db, Arc::new(RwLock::new(Some(99999999999u64.into())))).take(2),
|
init => |app, db| create_deposit_relay(app, db, Arc::new(RwLock::new(Some(99999999999u64.into()))), 17, Arc::new(RwLock::new(1))).take(2),
|
||||||
expected => vec![0x1005, 0x1006],
|
expected => vec![0x1005, 0x1006],
|
||||||
home_transport => [
|
home_transport => [
|
||||||
"eth_blockNumber" =>
|
"eth_blockNumber" =>
|
||||||
|
@ -77,7 +78,7 @@ test_app_stream! {
|
||||||
],
|
],
|
||||||
signatures => 1;
|
signatures => 1;
|
||||||
txs => Transactions::default(),
|
txs => Transactions::default(),
|
||||||
init => |app, db| create_deposit_relay(app, db, Arc::new(RwLock::new(Some(99999999999u64.into())))).take(2),
|
init => |app, db| create_deposit_relay(app, db, Arc::new(RwLock::new(Some(99999999999u64.into()))), 17, Arc::new(RwLock::new(1))).take(2),
|
||||||
expected => vec![0x1005, 0x1006],
|
expected => vec![0x1005, 0x1006],
|
||||||
home_transport => [
|
home_transport => [
|
||||||
"eth_blockNumber" =>
|
"eth_blockNumber" =>
|
||||||
|
@ -146,10 +147,11 @@ test_app_stream! {
|
||||||
deposit_relay: TransactionConfig {
|
deposit_relay: TransactionConfig {
|
||||||
gas: 0xfd,
|
gas: 0xfd,
|
||||||
gas_price: 0xa0,
|
gas_price: 0xa0,
|
||||||
|
concurrency: 100,
|
||||||
},
|
},
|
||||||
..Default::default()
|
..Default::default()
|
||||||
},
|
},
|
||||||
init => |app, db| create_deposit_relay(app, db, Arc::new(RwLock::new(Some(99999999999u64.into())))).take(1),
|
init => |app, db| create_deposit_relay(app, db, Arc::new(RwLock::new(Some(99999999999u64.into()))), 17, Arc::new(RwLock::new(1))).take(1),
|
||||||
expected => vec![0x1005],
|
expected => vec![0x1005],
|
||||||
home_transport => [
|
home_transport => [
|
||||||
"eth_blockNumber" =>
|
"eth_blockNumber" =>
|
||||||
|
@ -202,7 +204,7 @@ test_app_stream! {
|
||||||
],
|
],
|
||||||
signatures => 1;
|
signatures => 1;
|
||||||
txs => Transactions::default(),
|
txs => Transactions::default(),
|
||||||
init => |app, db| create_deposit_relay(app, db, Arc::new(RwLock::new(Some(99999999999u64.into())))).take(1),
|
init => |app, db| create_deposit_relay(app, db, Arc::new(RwLock::new(Some(99999999999u64.into()))), 17, Arc::new(RwLock::new(1))).take(1),
|
||||||
expected => vec![0x1005],
|
expected => vec![0x1005],
|
||||||
home_transport => [
|
home_transport => [
|
||||||
"eth_blockNumber" =>
|
"eth_blockNumber" =>
|
||||||
|
@ -257,7 +259,7 @@ test_app_stream! {
|
||||||
],
|
],
|
||||||
signatures => 1;
|
signatures => 1;
|
||||||
txs => Transactions::default(),
|
txs => Transactions::default(),
|
||||||
init => |app, db| create_deposit_relay(app, db, Arc::new(RwLock::new(Some(99999999999u64.into())))).take(1),
|
init => |app, db| create_deposit_relay(app, db, Arc::new(RwLock::new(Some(99999999999u64.into()))), 17, Arc::new(RwLock::new(1))).take(1),
|
||||||
expected => vec![0x1005],
|
expected => vec![0x1005],
|
||||||
home_transport => [
|
home_transport => [
|
||||||
"eth_blockNumber" =>
|
"eth_blockNumber" =>
|
||||||
|
@ -308,7 +310,7 @@ test_app_stream! {
|
||||||
],
|
],
|
||||||
signatures => 1;
|
signatures => 1;
|
||||||
txs => Transactions::default(),
|
txs => Transactions::default(),
|
||||||
init => |app, db| create_deposit_relay(app, db, Arc::new(RwLock::new(Some(99999999999u64.into())))).take(1),
|
init => |app, db| create_deposit_relay(app, db, Arc::new(RwLock::new(Some(99999999999u64.into()))), 17, Arc::new(RwLock::new(1))).take(1),
|
||||||
expected => vec![0x1005],
|
expected => vec![0x1005],
|
||||||
home_transport => [
|
home_transport => [
|
||||||
"eth_blockNumber" =>
|
"eth_blockNumber" =>
|
||||||
|
|
|
@ -5,6 +5,7 @@ extern crate web3;
|
||||||
extern crate bridge;
|
extern crate bridge;
|
||||||
#[macro_use]
|
#[macro_use]
|
||||||
extern crate tests;
|
extern crate tests;
|
||||||
|
extern crate ethcore;
|
||||||
|
|
||||||
use std::time::Duration;
|
use std::time::Duration;
|
||||||
use web3::types::{FilterBuilder, H160, H256, Log};
|
use web3::types::{FilterBuilder, H160, H256, Log};
|
||||||
|
@ -336,8 +337,14 @@ test_transport_stream! {
|
||||||
address: "0000000000000000000000000000000000000001".into(),
|
address: "0000000000000000000000000000000000000001".into(),
|
||||||
topics: vec![],
|
topics: vec![],
|
||||||
data: vec![0x10].into(),
|
data: vec![0x10].into(),
|
||||||
log_type: "".into(),
|
block_hash: None,
|
||||||
..Default::default()
|
block_number: None,
|
||||||
|
transaction_hash: None,
|
||||||
|
transaction_index: None,
|
||||||
|
log_index: None,
|
||||||
|
transaction_log_index: None,
|
||||||
|
log_type: None,
|
||||||
|
removed: None,
|
||||||
}],
|
}],
|
||||||
}],
|
}],
|
||||||
"eth_blockNumber" =>
|
"eth_blockNumber" =>
|
||||||
|
@ -379,8 +386,14 @@ test_transport_stream! {
|
||||||
address: "0000000000000000000000000000000000000001".into(),
|
address: "0000000000000000000000000000000000000001".into(),
|
||||||
topics: vec![],
|
topics: vec![],
|
||||||
data: vec![0x10].into(),
|
data: vec![0x10].into(),
|
||||||
log_type: "".into(),
|
block_hash: None,
|
||||||
..Default::default()
|
block_number: None,
|
||||||
|
transaction_hash: None,
|
||||||
|
transaction_index: None,
|
||||||
|
log_index: None,
|
||||||
|
transaction_log_index: None,
|
||||||
|
log_type: None,
|
||||||
|
removed: None,
|
||||||
}],
|
}],
|
||||||
}, LogStreamItem {
|
}, LogStreamItem {
|
||||||
from: 0x1007,
|
from: 0x1007,
|
||||||
|
@ -393,14 +406,26 @@ test_transport_stream! {
|
||||||
address: "0000000000000000000000000000000000000002".into(),
|
address: "0000000000000000000000000000000000000002".into(),
|
||||||
topics: vec![],
|
topics: vec![],
|
||||||
data: vec![0x20].into(),
|
data: vec![0x20].into(),
|
||||||
log_type: "".into(),
|
block_hash: None,
|
||||||
..Default::default()
|
block_number: None,
|
||||||
|
transaction_hash: None,
|
||||||
|
transaction_index: None,
|
||||||
|
log_index: None,
|
||||||
|
transaction_log_index: None,
|
||||||
|
log_type: None,
|
||||||
|
removed: None,
|
||||||
}, Log {
|
}, Log {
|
||||||
address: "0000000000000000000000000000000000000002".into(),
|
address: "0000000000000000000000000000000000000002".into(),
|
||||||
topics: vec![],
|
topics: vec![],
|
||||||
data: vec![0x30].into(),
|
data: vec![0x30].into(),
|
||||||
log_type: "".into(),
|
block_hash: None,
|
||||||
..Default::default()
|
block_number: None,
|
||||||
|
transaction_hash: None,
|
||||||
|
transaction_index: None,
|
||||||
|
log_index: None,
|
||||||
|
transaction_log_index: None,
|
||||||
|
log_type: None,
|
||||||
|
removed: None,
|
||||||
}],
|
}],
|
||||||
}],
|
}],
|
||||||
"eth_blockNumber" =>
|
"eth_blockNumber" =>
|
||||||
|
|
|
@ -9,6 +9,7 @@ extern crate tests;
|
||||||
extern crate ethabi;
|
extern crate ethabi;
|
||||||
extern crate rustc_hex;
|
extern crate rustc_hex;
|
||||||
extern crate ethereum_types;
|
extern crate ethereum_types;
|
||||||
|
extern crate ethcore;
|
||||||
|
|
||||||
use rustc_hex::{ToHex, FromHex};
|
use rustc_hex::{ToHex, FromHex};
|
||||||
use bridge::bridge::create_withdraw_confirm;
|
use bridge::bridge::create_withdraw_confirm;
|
||||||
|
@ -36,7 +37,7 @@ test_app_stream! {
|
||||||
],
|
],
|
||||||
signatures => 1;
|
signatures => 1;
|
||||||
txs => Transactions::default(),
|
txs => Transactions::default(),
|
||||||
init => |app, db| create_withdraw_confirm(app, db, Arc::new(RwLock::new(Some(99999999999u64.into())))).take(2),
|
init => |app, db| create_withdraw_confirm(app, db, Arc::new(RwLock::new(Some(99999999999u64.into()))), 17, Arc::new(RwLock::new(1))).take(2),
|
||||||
expected => vec![0x1005, 0x1006],
|
expected => vec![0x1005, 0x1006],
|
||||||
home_transport => [],
|
home_transport => [],
|
||||||
foreign_transport => [
|
foreign_transport => [
|
||||||
|
@ -86,7 +87,7 @@ test_app_stream! {
|
||||||
],
|
],
|
||||||
signatures => 1;
|
signatures => 1;
|
||||||
txs => Transactions::default(),
|
txs => Transactions::default(),
|
||||||
init => |app, db| create_withdraw_confirm(app, db, Arc::new(RwLock::new(Some(99999999999u64.into())))).take(2),
|
init => |app, db| create_withdraw_confirm(app, db, Arc::new(RwLock::new(Some(99999999999u64.into()))), 17, Arc::new(RwLock::new(1))).take(2),
|
||||||
expected => vec![0x1005, 0x1006],
|
expected => vec![0x1005, 0x1006],
|
||||||
home_transport => [],
|
home_transport => [],
|
||||||
foreign_transport => [
|
foreign_transport => [
|
||||||
|
@ -140,7 +141,7 @@ test_app_stream! {
|
||||||
],
|
],
|
||||||
signatures => 1;
|
signatures => 1;
|
||||||
txs => Transactions::default(),
|
txs => Transactions::default(),
|
||||||
init => |app, db| create_withdraw_confirm(app, db, Arc::new(RwLock::new(Some(99999999999u64.into())))).take(2),
|
init => |app, db| create_withdraw_confirm(app, db, Arc::new(RwLock::new(Some(99999999999u64.into()))), 17, Arc::new(RwLock::new(1))).take(2),
|
||||||
expected => vec![0x1005, 0x1006],
|
expected => vec![0x1005, 0x1006],
|
||||||
home_transport => [],
|
home_transport => [],
|
||||||
foreign_transport => [
|
foreign_transport => [
|
||||||
|
@ -198,10 +199,11 @@ test_app_stream! {
|
||||||
withdraw_confirm: TransactionConfig {
|
withdraw_confirm: TransactionConfig {
|
||||||
gas: 0xfe,
|
gas: 0xfe,
|
||||||
gas_price: 0xa1,
|
gas_price: 0xa1,
|
||||||
|
concurrency: 100,
|
||||||
},
|
},
|
||||||
..Default::default()
|
..Default::default()
|
||||||
},
|
},
|
||||||
init => |app, db| create_withdraw_confirm(app, db, Arc::new(RwLock::new(Some(99999999999u64.into())))).take(2),
|
init => |app, db| create_withdraw_confirm(app, db, Arc::new(RwLock::new(Some(99999999999u64.into()))), 17, Arc::new(RwLock::new(1))).take(2),
|
||||||
expected => vec![0x1005, 0x1006],
|
expected => vec![0x1005, 0x1006],
|
||||||
home_transport => [],
|
home_transport => [],
|
||||||
foreign_transport => [
|
foreign_transport => [
|
||||||
|
@ -303,10 +305,11 @@ test_app_stream! {
|
||||||
withdraw_confirm: TransactionConfig {
|
withdraw_confirm: TransactionConfig {
|
||||||
gas: 0xff,
|
gas: 0xff,
|
||||||
gas_price: 0xaa,
|
gas_price: 0xaa,
|
||||||
|
concurrency: 100,
|
||||||
},
|
},
|
||||||
..Default::default()
|
..Default::default()
|
||||||
},
|
},
|
||||||
init => |app, db| create_withdraw_confirm(app, db, Arc::new(RwLock::new(Some(99999999999u64.into())))).take(2),
|
init => |app, db| create_withdraw_confirm(app, db, Arc::new(RwLock::new(Some(99999999999u64.into()))), 17, Arc::new(RwLock::new(1))).take(2),
|
||||||
expected => vec![0x2, 0x1006],
|
expected => vec![0x2, 0x1006],
|
||||||
home_transport => [],
|
home_transport => [],
|
||||||
foreign_transport => [
|
foreign_transport => [
|
||||||
|
|
|
@ -9,6 +9,7 @@ extern crate tests;
|
||||||
extern crate ethabi;
|
extern crate ethabi;
|
||||||
extern crate ethereum_types;
|
extern crate ethereum_types;
|
||||||
extern crate rustc_hex;
|
extern crate rustc_hex;
|
||||||
|
extern crate ethcore;
|
||||||
|
|
||||||
use ethereum_types::{U256, H256};
|
use ethereum_types::{U256, H256};
|
||||||
use rustc_hex::ToHex;
|
use rustc_hex::ToHex;
|
||||||
|
@ -41,7 +42,7 @@ test_app_stream! {
|
||||||
],
|
],
|
||||||
signatures => 1;
|
signatures => 1;
|
||||||
txs => Transactions::default(),
|
txs => Transactions::default(),
|
||||||
init => |app, db| create_withdraw_relay(app, db, Arc::new(RwLock::new(Some(99999999999u64.into())))).take(2),
|
init => |app, db| create_withdraw_relay(app, db, Arc::new(RwLock::new(Some(99999999999u64.into()))), 17, Arc::new(RwLock::new(1))).take(2),
|
||||||
expected => vec![0x1005, 0x1006],
|
expected => vec![0x1005, 0x1006],
|
||||||
home_transport => [],
|
home_transport => [],
|
||||||
foreign_transport => [
|
foreign_transport => [
|
||||||
|
@ -92,7 +93,7 @@ test_app_stream! {
|
||||||
],
|
],
|
||||||
signatures => 1;
|
signatures => 1;
|
||||||
txs => Transactions::default(),
|
txs => Transactions::default(),
|
||||||
init => |app, db| create_withdraw_relay(app, db, Arc::new(RwLock::new(Some(99999999999u64.into())))).take(1),
|
init => |app, db| create_withdraw_relay(app, db, Arc::new(RwLock::new(Some(99999999999u64.into()))), 17, Arc::new(RwLock::new(1))).take(1),
|
||||||
expected => vec![0x1005],
|
expected => vec![0x1005],
|
||||||
home_transport => [],
|
home_transport => [],
|
||||||
foreign_transport => [
|
foreign_transport => [
|
||||||
|
@ -140,7 +141,7 @@ test_app_stream! {
|
||||||
],
|
],
|
||||||
signatures => 2;
|
signatures => 2;
|
||||||
txs => Transactions::default(),
|
txs => Transactions::default(),
|
||||||
init => |app, db| create_withdraw_relay(app, db, Arc::new(RwLock::new(Some(99999999999u64.into())))).take(1),
|
init => |app, db| create_withdraw_relay(app, db, Arc::new(RwLock::new(Some(99999999999u64.into()))), 17, Arc::new(RwLock::new(1))).take(1),
|
||||||
expected => vec![0x1005],
|
expected => vec![0x1005],
|
||||||
home_transport => [
|
home_transport => [
|
||||||
// `HomeBridge.withdraw`
|
// `HomeBridge.withdraw`
|
||||||
|
|
Loading…
Reference in New Issue