diff --git a/CHANGELOG.md b/CHANGELOG.md index 3a6eab0..d39ac66 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,20 +1,4 @@ -# 0.3.x - -1. Fix issue with coordinator not storing empty responses -2. Report script improvements -3. Height checks in service not clientchain -4. Challenge asset key import -5. Docker secrets -6. Docker secrets -7. Bitcoin library updates -8. Docker secrets -9. Enhancements - -# 0.3.0 - -* RPC API - # 0.2.0 * Finished core interfaces and testing diff --git a/Cargo.lock b/Cargo.lock index 37b59c7..863d691 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -21,6 +21,14 @@ name = "arrayref" version = "0.3.5" source = "registry+https://github.com/rust-lang/crates.io-index" +[[package]] +name = "arrayvec" +version = "0.4.12" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "nodrop 0.1.14 (registry+https://github.com/rust-lang/crates.io-index)", +] + [[package]] name = "atty" version = "0.2.13" @@ -54,29 +62,75 @@ dependencies = [ [[package]] name = "bech32" -version = "0.7.1" +version = "0.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" + +[[package]] +name = "bech32" +version = "0.6.0" source = "registry+https://github.com/rust-lang/crates.io-index" [[package]] name = "bitcoin" -version = "0.20.0" +version = "0.17.1" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "bech32 0.7.1 (registry+https://github.com/rust-lang/crates.io-index)", - "bitcoin_hashes 0.7.1 (registry+https://github.com/rust-lang/crates.io-index)", + "bitcoin-bech32 0.8.1 (registry+https://github.com/rust-lang/crates.io-index)", + "bitcoin_hashes 0.3.2 (registry+https://github.com/rust-lang/crates.io-index)", "byteorder 1.3.2 (registry+https://github.com/rust-lang/crates.io-index)", "hex 0.3.2 (registry+https://github.com/rust-lang/crates.io-index)", - "secp256k1 0.15.5 (registry+https://github.com/rust-lang/crates.io-index)", - "serde 1.0.102 (registry+https://github.com/rust-lang/crates.io-index)", + "rand 0.3.23 (registry+https://github.com/rust-lang/crates.io-index)", + "secp256k1 0.12.2 (registry+https://github.com/rust-lang/crates.io-index)", + "serde 1.0.101 (registry+https://github.com/rust-lang/crates.io-index)", + "strason 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "bitcoin" +version = "0.18.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "bitcoin-bech32 0.9.0 (registry+https://github.com/rust-lang/crates.io-index)", + "bitcoin_hashes 0.3.2 (registry+https://github.com/rust-lang/crates.io-index)", + "byteorder 1.3.2 (registry+https://github.com/rust-lang/crates.io-index)", + "hex 0.3.2 (registry+https://github.com/rust-lang/crates.io-index)", + "rand 0.3.23 (registry+https://github.com/rust-lang/crates.io-index)", + "secp256k1 0.12.2 (registry+https://github.com/rust-lang/crates.io-index)", + "serde 1.0.101 (registry+https://github.com/rust-lang/crates.io-index)", + "serde_test 1.0.101 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "bitcoin-amount" +version = "0.1.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "serde 1.0.101 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "bitcoin-bech32" +version = "0.8.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "bech32 0.5.0 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "bitcoin-bech32" +version = "0.9.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "bech32 0.6.0 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] name = "bitcoin_hashes" -version = "0.7.1" +version = "0.3.2" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "byteorder 1.3.2 (registry+https://github.com/rust-lang/crates.io-index)", - "serde 1.0.102 (registry+https://github.com/rust-lang/crates.io-index)", + "serde 1.0.101 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -106,7 +160,7 @@ dependencies = [ "linked-hash-map 0.5.2 (registry+https://github.com/rust-lang/crates.io-index)", "md5 0.3.8 (registry+https://github.com/rust-lang/crates.io-index)", "rand 0.5.6 (registry+https://github.com/rust-lang/crates.io-index)", - "serde 1.0.102 (registry+https://github.com/rust-lang/crates.io-index)", + "serde 1.0.101 (registry+https://github.com/rust-lang/crates.io-index)", "serde_json 1.0.41 (registry+https://github.com/rust-lang/crates.io-index)", "time 0.1.42 (registry+https://github.com/rust-lang/crates.io-index)", "try_from 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)", @@ -147,7 +201,7 @@ dependencies = [ [[package]] name = "cc" -version = "1.0.41" +version = "1.0.26" source = "registry+https://github.com/rust-lang/crates.io-index" [[package]] @@ -162,7 +216,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "libc 0.2.65 (registry+https://github.com/rust-lang/crates.io-index)", "num-integer 0.1.41 (registry+https://github.com/rust-lang/crates.io-index)", - "num-traits 0.2.9 (registry+https://github.com/rust-lang/crates.io-index)", + "num-traits 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)", "time 0.1.42 (registry+https://github.com/rust-lang/crates.io-index)", ] @@ -182,7 +236,7 @@ dependencies = [ "lazy_static 1.4.0 (registry+https://github.com/rust-lang/crates.io-index)", "nom 4.2.3 (registry+https://github.com/rust-lang/crates.io-index)", "rust-ini 0.13.0 (registry+https://github.com/rust-lang/crates.io-index)", - "serde 1.0.102 (registry+https://github.com/rust-lang/crates.io-index)", + "serde 1.0.101 (registry+https://github.com/rust-lang/crates.io-index)", "serde-hjson 0.8.2 (registry+https://github.com/rust-lang/crates.io-index)", "serde_json 1.0.41 (registry+https://github.com/rust-lang/crates.io-index)", "toml 0.4.10 (registry+https://github.com/rust-lang/crates.io-index)", @@ -196,10 +250,11 @@ source = "registry+https://github.com/rust-lang/crates.io-index" [[package]] name = "coordinator" -version = "0.3.9" +version = "0.1.0" dependencies = [ "base64 0.10.1 (registry+https://github.com/rust-lang/crates.io-index)", - "bitcoin 0.20.0 (registry+https://github.com/rust-lang/crates.io-index)", + "bitcoin 0.17.1 (registry+https://github.com/rust-lang/crates.io-index)", + "bitcoin_hashes 0.3.2 (registry+https://github.com/rust-lang/crates.io-index)", "config 0.9.3 (registry+https://github.com/rust-lang/crates.io-index)", "env_logger 0.6.2 (registry+https://github.com/rust-lang/crates.io-index)", "futures 0.1.29 (registry+https://github.com/rust-lang/crates.io-index)", @@ -207,31 +262,32 @@ dependencies = [ "jsonrpc-http-server 11.0.0 (registry+https://github.com/rust-lang/crates.io-index)", "log 0.4.8 (registry+https://github.com/rust-lang/crates.io-index)", "mongodb 0.3.12 (registry+https://github.com/rust-lang/crates.io-index)", - "ocean-rpc 0.8.0 (git+https://github.com/commerceblock/rust-ocean-rpc)", - "rust-ocean 0.10.0 (git+https://github.com/commerceblock/rust-ocean)", - "serde 1.0.102 (registry+https://github.com/rust-lang/crates.io-index)", + "ocean-rpc 0.3.0 (git+https://github.com/commerceblock/rust-ocean-rpc)", + "rust-ocean 0.6.0 (git+https://github.com/commerceblock/rust-ocean)", + "secp256k1 0.12.2 (registry+https://github.com/rust-lang/crates.io-index)", + "serde 1.0.101 (registry+https://github.com/rust-lang/crates.io-index)", "serde_json 1.0.41 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] name = "crossbeam-deque" -version = "0.7.2" +version = "0.7.1" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "crossbeam-epoch 0.8.0 (registry+https://github.com/rust-lang/crates.io-index)", - "crossbeam-utils 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)", + "crossbeam-epoch 0.7.2 (registry+https://github.com/rust-lang/crates.io-index)", + "crossbeam-utils 0.6.6 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] name = "crossbeam-epoch" -version = "0.8.0" +version = "0.7.2" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "autocfg 0.1.7 (registry+https://github.com/rust-lang/crates.io-index)", + "arrayvec 0.4.12 (registry+https://github.com/rust-lang/crates.io-index)", "cfg-if 0.1.10 (registry+https://github.com/rust-lang/crates.io-index)", - "crossbeam-utils 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)", + "crossbeam-utils 0.6.6 (registry+https://github.com/rust-lang/crates.io-index)", "lazy_static 1.4.0 (registry+https://github.com/rust-lang/crates.io-index)", - "memoffset 0.5.3 (registry+https://github.com/rust-lang/crates.io-index)", + "memoffset 0.5.1 (registry+https://github.com/rust-lang/crates.io-index)", "scopeguard 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)", ] @@ -252,16 +308,6 @@ dependencies = [ "lazy_static 1.4.0 (registry+https://github.com/rust-lang/crates.io-index)", ] -[[package]] -name = "crossbeam-utils" -version = "0.7.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "autocfg 0.1.7 (registry+https://github.com/rust-lang/crates.io-index)", - "cfg-if 0.1.10 (registry+https://github.com/rust-lang/crates.io-index)", - "lazy_static 1.4.0 (registry+https://github.com/rust-lang/crates.io-index)", -] - [[package]] name = "crypto-mac" version = "0.6.2" @@ -341,7 +387,7 @@ version = "0.1.8" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "futures 0.1.29 (registry+https://github.com/rust-lang/crates.io-index)", - "num_cpus 1.11.1 (registry+https://github.com/rust-lang/crates.io-index)", + "num_cpus 1.10.1 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -381,14 +427,6 @@ dependencies = [ "tokio-io 0.1.12 (registry+https://github.com/rust-lang/crates.io-index)", ] -[[package]] -name = "hermit-abi" -version = "0.1.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "libc 0.2.65 (registry+https://github.com/rust-lang/crates.io-index)", -] - [[package]] name = "hex" version = "0.3.2" @@ -456,7 +494,7 @@ dependencies = [ "language-tags 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)", "log 0.3.9 (registry+https://github.com/rust-lang/crates.io-index)", "mime 0.2.6 (registry+https://github.com/rust-lang/crates.io-index)", - "num_cpus 1.11.1 (registry+https://github.com/rust-lang/crates.io-index)", + "num_cpus 1.10.1 (registry+https://github.com/rust-lang/crates.io-index)", "time 0.1.42 (registry+https://github.com/rust-lang/crates.io-index)", "traitobject 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)", "typeable 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)", @@ -500,7 +538,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "matches 0.1.8 (registry+https://github.com/rust-lang/crates.io-index)", "unicode-bidi 0.3.4 (registry+https://github.com/rust-lang/crates.io-index)", - "unicode-normalization 0.1.9 (registry+https://github.com/rust-lang/crates.io-index)", + "unicode-normalization 0.1.8 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -530,8 +568,8 @@ version = "0.11.0" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "hyper 0.10.16 (registry+https://github.com/rust-lang/crates.io-index)", - "serde 1.0.102 (registry+https://github.com/rust-lang/crates.io-index)", - "serde_derive 1.0.102 (registry+https://github.com/rust-lang/crates.io-index)", + "serde 1.0.101 (registry+https://github.com/rust-lang/crates.io-index)", + "serde_derive 1.0.101 (registry+https://github.com/rust-lang/crates.io-index)", "serde_json 1.0.41 (registry+https://github.com/rust-lang/crates.io-index)", ] @@ -542,8 +580,8 @@ source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "futures 0.1.29 (registry+https://github.com/rust-lang/crates.io-index)", "log 0.4.8 (registry+https://github.com/rust-lang/crates.io-index)", - "serde 1.0.102 (registry+https://github.com/rust-lang/crates.io-index)", - "serde_derive 1.0.102 (registry+https://github.com/rust-lang/crates.io-index)", + "serde 1.0.101 (registry+https://github.com/rust-lang/crates.io-index)", + "serde_derive 1.0.101 (registry+https://github.com/rust-lang/crates.io-index)", "serde_json 1.0.41 (registry+https://github.com/rust-lang/crates.io-index)", ] @@ -557,7 +595,7 @@ dependencies = [ "jsonrpc-server-utils 11.0.0 (registry+https://github.com/rust-lang/crates.io-index)", "log 0.4.8 (registry+https://github.com/rust-lang/crates.io-index)", "net2 0.2.33 (registry+https://github.com/rust-lang/crates.io-index)", - "unicase 2.6.0 (registry+https://github.com/rust-lang/crates.io-index)", + "unicase 2.5.1 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -570,10 +608,10 @@ dependencies = [ "jsonrpc-core 11.0.0 (registry+https://github.com/rust-lang/crates.io-index)", "lazy_static 1.4.0 (registry+https://github.com/rust-lang/crates.io-index)", "log 0.4.8 (registry+https://github.com/rust-lang/crates.io-index)", - "num_cpus 1.11.1 (registry+https://github.com/rust-lang/crates.io-index)", + "num_cpus 1.10.1 (registry+https://github.com/rust-lang/crates.io-index)", "tokio 0.1.22 (registry+https://github.com/rust-lang/crates.io-index)", "tokio-codec 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)", - "unicase 2.6.0 (registry+https://github.com/rust-lang/crates.io-index)", + "unicase 2.5.1 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -648,11 +686,6 @@ name = "matches" version = "0.1.8" source = "registry+https://github.com/rust-lang/crates.io-index" -[[package]] -name = "maybe-uninit" -version = "2.0.0" -source = "registry+https://github.com/rust-lang/crates.io-index" - [[package]] name = "md-5" version = "0.7.0" @@ -675,7 +708,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" [[package]] name = "memoffset" -version = "0.5.3" +version = "0.5.1" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "rustc_version 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)", @@ -761,6 +794,11 @@ dependencies = [ "winapi 0.3.8 (registry+https://github.com/rust-lang/crates.io-index)", ] +[[package]] +name = "nodrop" +version = "0.1.14" +source = "registry+https://github.com/rust-lang/crates.io-index" + [[package]] name = "nom" version = "4.2.3" @@ -777,8 +815,8 @@ source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "autocfg 0.1.7 (registry+https://github.com/rust-lang/crates.io-index)", "num-integer 0.1.41 (registry+https://github.com/rust-lang/crates.io-index)", - "num-traits 0.2.9 (registry+https://github.com/rust-lang/crates.io-index)", - "serde 1.0.102 (registry+https://github.com/rust-lang/crates.io-index)", + "num-traits 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)", + "serde 1.0.101 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -787,7 +825,7 @@ version = "0.1.41" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "autocfg 0.1.7 (registry+https://github.com/rust-lang/crates.io-index)", - "num-traits 0.2.9 (registry+https://github.com/rust-lang/crates.io-index)", + "num-traits 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -795,12 +833,12 @@ name = "num-traits" version = "0.1.43" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "num-traits 0.2.9 (registry+https://github.com/rust-lang/crates.io-index)", + "num-traits 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] name = "num-traits" -version = "0.2.9" +version = "0.2.8" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "autocfg 0.1.7 (registry+https://github.com/rust-lang/crates.io-index)", @@ -808,39 +846,44 @@ dependencies = [ [[package]] name = "num_cpus" -version = "1.11.1" +version = "1.10.1" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "hermit-abi 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)", "libc 0.2.65 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] name = "ocean-rpc" -version = "0.8.0" -source = "git+https://github.com/commerceblock/rust-ocean-rpc#1215da59f5bca1f2f86727d1212b7367acff3290" +version = "0.3.0" +source = "git+https://github.com/commerceblock/rust-ocean-rpc#a8ffb9e94751a608eeb8c5d8a4e082266658184f" dependencies = [ - "bitcoin 0.20.0 (registry+https://github.com/rust-lang/crates.io-index)", + "bitcoin 0.18.2 (registry+https://github.com/rust-lang/crates.io-index)", + "bitcoin-amount 0.1.4 (registry+https://github.com/rust-lang/crates.io-index)", + "bitcoin_hashes 0.3.2 (registry+https://github.com/rust-lang/crates.io-index)", "hex 0.3.2 (registry+https://github.com/rust-lang/crates.io-index)", "jsonrpc 0.11.0 (registry+https://github.com/rust-lang/crates.io-index)", "log 0.4.8 (registry+https://github.com/rust-lang/crates.io-index)", "num-bigint 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)", - "ocean-rpc-json 0.8.0 (git+https://github.com/commerceblock/rust-ocean-rpc)", - "rust-ocean 0.10.0 (git+https://github.com/commerceblock/rust-ocean)", - "serde 1.0.102 (registry+https://github.com/rust-lang/crates.io-index)", + "ocean-rpc-json 0.3.0 (git+https://github.com/commerceblock/rust-ocean-rpc)", + "rust-ocean 0.6.0 (git+https://github.com/commerceblock/rust-ocean)", + "secp256k1 0.12.2 (registry+https://github.com/rust-lang/crates.io-index)", + "serde 1.0.101 (registry+https://github.com/rust-lang/crates.io-index)", "serde_json 1.0.41 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] name = "ocean-rpc-json" -version = "0.8.0" -source = "git+https://github.com/commerceblock/rust-ocean-rpc#1215da59f5bca1f2f86727d1212b7367acff3290" +version = "0.3.0" +source = "git+https://github.com/commerceblock/rust-ocean-rpc#a8ffb9e94751a608eeb8c5d8a4e082266658184f" dependencies = [ - "bitcoin 0.20.0 (registry+https://github.com/rust-lang/crates.io-index)", + "bitcoin 0.18.2 (registry+https://github.com/rust-lang/crates.io-index)", + "bitcoin-amount 0.1.4 (registry+https://github.com/rust-lang/crates.io-index)", + "bitcoin_hashes 0.3.2 (registry+https://github.com/rust-lang/crates.io-index)", "hex 0.3.2 (registry+https://github.com/rust-lang/crates.io-index)", "num-bigint 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)", - "rust-ocean 0.10.0 (git+https://github.com/commerceblock/rust-ocean)", - "serde 1.0.102 (registry+https://github.com/rust-lang/crates.io-index)", + "secp256k1 0.12.2 (registry+https://github.com/rust-lang/crates.io-index)", + "serde 1.0.101 (registry+https://github.com/rust-lang/crates.io-index)", + "serde_derive 1.0.101 (registry+https://github.com/rust-lang/crates.io-index)", "serde_json 1.0.41 (registry+https://github.com/rust-lang/crates.io-index)", ] @@ -864,7 +907,7 @@ dependencies = [ "libc 0.2.65 (registry+https://github.com/rust-lang/crates.io-index)", "redox_syscall 0.1.56 (registry+https://github.com/rust-lang/crates.io-index)", "rustc_version 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)", - "smallvec 0.6.13 (registry+https://github.com/rust-lang/crates.io-index)", + "smallvec 0.6.10 (registry+https://github.com/rust-lang/crates.io-index)", "winapi 0.3.8 (registry+https://github.com/rust-lang/crates.io-index)", ] @@ -1094,11 +1137,13 @@ source = "registry+https://github.com/rust-lang/crates.io-index" [[package]] name = "rust-ocean" -version = "0.10.0" -source = "git+https://github.com/commerceblock/rust-ocean#56a64d11f6f073caebfb37c2fc92b97a288be8ec" +version = "0.6.0" +source = "git+https://github.com/commerceblock/rust-ocean#b3728b67611c52f1bd408e588cf396562ffb4c7a" dependencies = [ - "bitcoin 0.20.0 (registry+https://github.com/rust-lang/crates.io-index)", - "serde 1.0.102 (registry+https://github.com/rust-lang/crates.io-index)", + "bech32 0.6.0 (registry+https://github.com/rust-lang/crates.io-index)", + "bitcoin 0.18.2 (registry+https://github.com/rust-lang/crates.io-index)", + "bitcoin_hashes 0.3.2 (registry+https://github.com/rust-lang/crates.io-index)", + "secp256k1 0.12.2 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -1134,11 +1179,12 @@ source = "registry+https://github.com/rust-lang/crates.io-index" [[package]] name = "secp256k1" -version = "0.15.5" +version = "0.12.2" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "cc 1.0.41 (registry+https://github.com/rust-lang/crates.io-index)", - "rand 0.6.5 (registry+https://github.com/rust-lang/crates.io-index)", + "cc 1.0.26 (registry+https://github.com/rust-lang/crates.io-index)", + "rand 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)", + "serde 1.0.101 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -1174,10 +1220,10 @@ source = "registry+https://github.com/rust-lang/crates.io-index" [[package]] name = "serde" -version = "1.0.102" +version = "1.0.101" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "serde_derive 1.0.102 (registry+https://github.com/rust-lang/crates.io-index)", + "serde_derive 1.0.101 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -1194,12 +1240,12 @@ dependencies = [ [[package]] name = "serde_derive" -version = "1.0.102" +version = "1.0.101" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "proc-macro2 1.0.6 (registry+https://github.com/rust-lang/crates.io-index)", "quote 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)", - "syn 1.0.8 (registry+https://github.com/rust-lang/crates.io-index)", + "syn 1.0.5 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -1210,7 +1256,7 @@ dependencies = [ "indexmap 1.3.0 (registry+https://github.com/rust-lang/crates.io-index)", "itoa 0.4.4 (registry+https://github.com/rust-lang/crates.io-index)", "ryu 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)", - "serde 1.0.102 (registry+https://github.com/rust-lang/crates.io-index)", + "serde 1.0.101 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -1221,6 +1267,14 @@ dependencies = [ "serde 0.8.23 (registry+https://github.com/rust-lang/crates.io-index)", ] +[[package]] +name = "serde_test" +version = "1.0.101" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "serde 1.0.101 (registry+https://github.com/rust-lang/crates.io-index)", +] + [[package]] name = "sha-1" version = "0.7.0" @@ -1250,10 +1304,15 @@ source = "registry+https://github.com/rust-lang/crates.io-index" [[package]] name = "smallvec" -version = "0.6.13" +version = "0.6.10" +source = "registry+https://github.com/rust-lang/crates.io-index" + +[[package]] +name = "strason" +version = "0.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "maybe-uninit 2.0.0 (registry+https://github.com/rust-lang/crates.io-index)", + "serde 1.0.101 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -1266,7 +1325,7 @@ dependencies = [ [[package]] name = "syn" -version = "1.0.8" +version = "1.0.5" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "proc-macro2 1.0.6 (registry+https://github.com/rust-lang/crates.io-index)", @@ -1291,8 +1350,8 @@ dependencies = [ "byteorder 1.3.2 (registry+https://github.com/rust-lang/crates.io-index)", "chrono 0.4.9 (registry+https://github.com/rust-lang/crates.io-index)", "rand 0.6.5 (registry+https://github.com/rust-lang/crates.io-index)", - "serde 1.0.102 (registry+https://github.com/rust-lang/crates.io-index)", - "serde_derive 1.0.102 (registry+https://github.com/rust-lang/crates.io-index)", + "serde 1.0.101 (registry+https://github.com/rust-lang/crates.io-index)", + "serde_derive 1.0.101 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -1321,7 +1380,7 @@ dependencies = [ "bytes 0.4.12 (registry+https://github.com/rust-lang/crates.io-index)", "futures 0.1.29 (registry+https://github.com/rust-lang/crates.io-index)", "mio 0.6.19 (registry+https://github.com/rust-lang/crates.io-index)", - "num_cpus 1.11.1 (registry+https://github.com/rust-lang/crates.io-index)", + "num_cpus 1.10.1 (registry+https://github.com/rust-lang/crates.io-index)", "tokio-codec 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)", "tokio-current-thread 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)", "tokio-executor 0.1.8 (registry+https://github.com/rust-lang/crates.io-index)", @@ -1404,7 +1463,7 @@ dependencies = [ "lazy_static 1.4.0 (registry+https://github.com/rust-lang/crates.io-index)", "log 0.4.8 (registry+https://github.com/rust-lang/crates.io-index)", "mio 0.6.19 (registry+https://github.com/rust-lang/crates.io-index)", - "num_cpus 1.11.1 (registry+https://github.com/rust-lang/crates.io-index)", + "num_cpus 1.10.1 (registry+https://github.com/rust-lang/crates.io-index)", "parking_lot 0.9.0 (registry+https://github.com/rust-lang/crates.io-index)", "slab 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)", "tokio-executor 0.1.8 (registry+https://github.com/rust-lang/crates.io-index)", @@ -1439,13 +1498,13 @@ name = "tokio-threadpool" version = "0.1.16" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "crossbeam-deque 0.7.2 (registry+https://github.com/rust-lang/crates.io-index)", + "crossbeam-deque 0.7.1 (registry+https://github.com/rust-lang/crates.io-index)", "crossbeam-queue 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)", "crossbeam-utils 0.6.6 (registry+https://github.com/rust-lang/crates.io-index)", "futures 0.1.29 (registry+https://github.com/rust-lang/crates.io-index)", "lazy_static 1.4.0 (registry+https://github.com/rust-lang/crates.io-index)", "log 0.4.8 (registry+https://github.com/rust-lang/crates.io-index)", - "num_cpus 1.11.1 (registry+https://github.com/rust-lang/crates.io-index)", + "num_cpus 1.10.1 (registry+https://github.com/rust-lang/crates.io-index)", "slab 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)", "tokio-executor 0.1.8 (registry+https://github.com/rust-lang/crates.io-index)", ] @@ -1497,7 +1556,7 @@ name = "toml" version = "0.4.10" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "serde 1.0.102 (registry+https://github.com/rust-lang/crates.io-index)", + "serde 1.0.101 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -1540,10 +1599,10 @@ dependencies = [ [[package]] name = "unicase" -version = "2.6.0" +version = "2.5.1" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "version_check 0.9.1 (registry+https://github.com/rust-lang/crates.io-index)", + "version_check 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -1556,10 +1615,10 @@ dependencies = [ [[package]] name = "unicode-normalization" -version = "0.1.9" +version = "0.1.8" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "smallvec 0.6.13 (registry+https://github.com/rust-lang/crates.io-index)", + "smallvec 0.6.10 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -1587,11 +1646,6 @@ name = "version_check" version = "0.1.5" source = "registry+https://github.com/rust-lang/crates.io-index" -[[package]] -name = "version_check" -version = "0.9.1" -source = "registry+https://github.com/rust-lang/crates.io-index" - [[package]] name = "want" version = "0.2.0" @@ -1677,13 +1731,19 @@ dependencies = [ "checksum aho-corasick 0.6.10 (registry+https://github.com/rust-lang/crates.io-index)" = "81ce3d38065e618af2d7b77e10c5ad9a069859b4be3c2250f674af3840d9c8a5" "checksum aho-corasick 0.7.6 (registry+https://github.com/rust-lang/crates.io-index)" = "58fb5e95d83b38284460a5fda7d6470aa0b8844d283a0b614b8535e880800d2d" "checksum arrayref 0.3.5 (registry+https://github.com/rust-lang/crates.io-index)" = "0d382e583f07208808f6b1249e60848879ba3543f57c32277bf52d69c2f0f0ee" +"checksum arrayvec 0.4.12 (registry+https://github.com/rust-lang/crates.io-index)" = "cd9fd44efafa8690358b7408d253adf110036b88f55672a933f01d616ad9b1b9" "checksum atty 0.2.13 (registry+https://github.com/rust-lang/crates.io-index)" = "1803c647a3ec87095e7ae7acfca019e98de5ec9a7d01343f611cf3152ed71a90" "checksum autocfg 0.1.7 (registry+https://github.com/rust-lang/crates.io-index)" = "1d49d90015b3c36167a20fe2810c5cd875ad504b39cff3d4eae7977e6b7c1cb2" "checksum base64 0.10.1 (registry+https://github.com/rust-lang/crates.io-index)" = "0b25d992356d2eb0ed82172f5248873db5560c4721f564b13cb5193bda5e668e" "checksum base64 0.9.3 (registry+https://github.com/rust-lang/crates.io-index)" = "489d6c0ed21b11d038c31b6ceccca973e65d73ba3bd8ecb9a2babf5546164643" -"checksum bech32 0.7.1 (registry+https://github.com/rust-lang/crates.io-index)" = "9e0089c35ab7c6f2bc55ab23f769913f0ac65b1023e7e74638a1f43128dd5df2" -"checksum bitcoin 0.20.0 (registry+https://github.com/rust-lang/crates.io-index)" = "01337c65290ce0c948738d821aa9f87488ca6c2b0f02d672ef778f9ae54f22c8" -"checksum bitcoin_hashes 0.7.1 (registry+https://github.com/rust-lang/crates.io-index)" = "db6b697833d852acea530c9e815e6adc724267856b6506bc500362a068a39c7b" +"checksum bech32 0.5.0 (registry+https://github.com/rust-lang/crates.io-index)" = "ad20b907fd16610c3960c7fe9dae13dd243343409bab80299774c9a8b5d7bed8" +"checksum bech32 0.6.0 (registry+https://github.com/rust-lang/crates.io-index)" = "58946044516aa9dc922182e0d6e9d124a31aafe6b421614654eb27cf90cec09c" +"checksum bitcoin 0.17.1 (registry+https://github.com/rust-lang/crates.io-index)" = "0105a5a9c83f4ac366ca45f99ba502805a097fdf426ade4af0a822853cdd0886" +"checksum bitcoin 0.18.2 (registry+https://github.com/rust-lang/crates.io-index)" = "cd5e7935f613ba170459072926f01dc5ddb8aa22382dc4badf44bbb55e2d243d" +"checksum bitcoin-amount 0.1.4 (registry+https://github.com/rust-lang/crates.io-index)" = "0bd5ae6712113fac4edfa917b1d865801f476b021a108e6749ce20d3057abb9e" +"checksum bitcoin-bech32 0.8.1 (registry+https://github.com/rust-lang/crates.io-index)" = "f0a5cfe5abcb5040b36d4ea8acba95288fefebd7959b59475f2c4ec705974b4c" +"checksum bitcoin-bech32 0.9.0 (registry+https://github.com/rust-lang/crates.io-index)" = "4e67e8ccfc663811145e6cabdb9a2a6978877f72b048516e83eb95622e9b2554" +"checksum bitcoin_hashes 0.3.2 (registry+https://github.com/rust-lang/crates.io-index)" = "2b7a2e9773ee7ae7f2560f0426c938f57902dcb9e39321b0cbd608f47ed579a4" "checksum bitflags 1.2.1 (registry+https://github.com/rust-lang/crates.io-index)" = "cf1de2fe8c75bc145a2f577add951f8134889b4795d47466a54a5c846d691693" "checksum block-buffer 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)" = "a076c298b9ecdb530ed9d967e74a6027d6a7478924520acddcddc24c1c8ab3ab" "checksum bson 0.13.0 (registry+https://github.com/rust-lang/crates.io-index)" = "8984b7b33b1f8ac97468df3cefa76c7035abb0786473aa2a437dea0c72855702" @@ -1692,17 +1752,16 @@ dependencies = [ "checksum byte-tools 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "560c32574a12a89ecd91f5e742165893f86e3ab98d21f8ea548658eb9eef5f40" "checksum byteorder 1.3.2 (registry+https://github.com/rust-lang/crates.io-index)" = "a7c3dd8985a7111efc5c80b44e23ecdd8c007de8ade3b96595387e812b957cf5" "checksum bytes 0.4.12 (registry+https://github.com/rust-lang/crates.io-index)" = "206fdffcfa2df7cbe15601ef46c813fce0965eb3286db6b56c583b814b51c81c" -"checksum cc 1.0.41 (registry+https://github.com/rust-lang/crates.io-index)" = "8dae9c4b8fedcae85592ba623c4fd08cfdab3e3b72d6df780c6ead964a69bfff" +"checksum cc 1.0.26 (registry+https://github.com/rust-lang/crates.io-index)" = "389803e36973d242e7fecb092b2de44a3d35ac62524b3b9339e51d577d668e02" "checksum cfg-if 0.1.10 (registry+https://github.com/rust-lang/crates.io-index)" = "4785bdd1c96b2a846b2bd7cc02e86b6b3dbf14e7e53446c4f54c92a361040822" "checksum chrono 0.4.9 (registry+https://github.com/rust-lang/crates.io-index)" = "e8493056968583b0193c1bb04d6f7684586f3726992d6c573261941a895dbd68" "checksum cloudabi 0.0.3 (registry+https://github.com/rust-lang/crates.io-index)" = "ddfc5b9aa5d4507acaf872de71051dfd0e309860e88966e1051e462a077aac4f" "checksum config 0.9.3 (registry+https://github.com/rust-lang/crates.io-index)" = "f9107d78ed62b3fa5a86e7d18e647abed48cfd8f8fab6c72f4cdb982d196f7e6" "checksum constant_time_eq 0.1.4 (registry+https://github.com/rust-lang/crates.io-index)" = "995a44c877f9212528ccc74b21a232f66ad69001e40ede5bcee2ac9ef2657120" -"checksum crossbeam-deque 0.7.2 (registry+https://github.com/rust-lang/crates.io-index)" = "c3aa945d63861bfe624b55d153a39684da1e8c0bc8fba932f7ee3a3c16cea3ca" -"checksum crossbeam-epoch 0.8.0 (registry+https://github.com/rust-lang/crates.io-index)" = "5064ebdbf05ce3cb95e45c8b086f72263f4166b29b97f6baff7ef7fe047b55ac" +"checksum crossbeam-deque 0.7.1 (registry+https://github.com/rust-lang/crates.io-index)" = "b18cd2e169ad86297e6bc0ad9aa679aee9daa4f19e8163860faf7c164e4f5a71" +"checksum crossbeam-epoch 0.7.2 (registry+https://github.com/rust-lang/crates.io-index)" = "fedcd6772e37f3da2a9af9bf12ebe046c0dfe657992377b4df982a2b54cd37a9" "checksum crossbeam-queue 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)" = "7c979cd6cfe72335896575c6b5688da489e420d36a27a0b9eb0c73db574b4a4b" "checksum crossbeam-utils 0.6.6 (registry+https://github.com/rust-lang/crates.io-index)" = "04973fa96e96579258a5091af6003abde64af786b860f18622b82e026cca60e6" -"checksum crossbeam-utils 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)" = "ce446db02cdc3165b94ae73111e570793400d0794e46125cc4056c81cbb039f4" "checksum crypto-mac 0.6.2 (registry+https://github.com/rust-lang/crates.io-index)" = "7afa06d05a046c7a47c3a849907ec303504608c927f4e85f7bfff22b7180d971" "checksum data-encoding 2.1.2 (registry+https://github.com/rust-lang/crates.io-index)" = "f4f47ca1860a761136924ddd2422ba77b2ea54fe8cc75b9040804a0d9d32ad97" "checksum digest 0.7.6 (registry+https://github.com/rust-lang/crates.io-index)" = "03b072242a8cbaf9c145665af9d250c59af3b958f83ed6824e13533cf76d5b90" @@ -1718,7 +1777,6 @@ dependencies = [ "checksum generic-array 0.9.0 (registry+https://github.com/rust-lang/crates.io-index)" = "ef25c5683767570c2bbd7deba372926a55eaae9982d7726ee2a1050239d45b9d" "checksum globset 0.4.4 (registry+https://github.com/rust-lang/crates.io-index)" = "925aa2cac82d8834e2b2a4415b6f6879757fb5c0928fc445ae76461a12eed8f2" "checksum h2 0.1.26 (registry+https://github.com/rust-lang/crates.io-index)" = "a5b34c246847f938a410a03c5458c7fee2274436675e76d8b903c08efc29c462" -"checksum hermit-abi 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)" = "307c3c9f937f38e3534b1d6447ecf090cafcc9744e4a6360e8b037b2cf5af120" "checksum hex 0.3.2 (registry+https://github.com/rust-lang/crates.io-index)" = "805026a5d0141ffc30abb3be3173848ad46a1b1664fe632428479619a3644d77" "checksum hmac 0.6.3 (registry+https://github.com/rust-lang/crates.io-index)" = "733e1b3ac906631ca01ebb577e9bb0f5e37a454032b9036b5eaea4013ed6f99a" "checksum hostname 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)" = "21ceb46a83a85e824ef93669c8b390009623863b5c195d1ba747292c0c72f94e" @@ -1747,25 +1805,25 @@ dependencies = [ "checksum log 0.3.9 (registry+https://github.com/rust-lang/crates.io-index)" = "e19e8d5c34a3e0e2223db8e060f9e8264aeeb5c5fc64a4ee9965c062211c024b" "checksum log 0.4.8 (registry+https://github.com/rust-lang/crates.io-index)" = "14b6052be84e6b71ab17edffc2eeabf5c2c3ae1fdb464aae35ac50c67a44e1f7" "checksum matches 0.1.8 (registry+https://github.com/rust-lang/crates.io-index)" = "7ffc5c5338469d4d3ea17d269fa8ea3512ad247247c30bd2df69e68309ed0a08" -"checksum maybe-uninit 2.0.0 (registry+https://github.com/rust-lang/crates.io-index)" = "60302e4db3a61da70c0cb7991976248362f30319e88850c487b9b95bbf059e00" "checksum md-5 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)" = "9402eaae33a9e144ce18ef488a0e4ca19869673c7bcdbbfe2030fdc3f84211cd" "checksum md5 0.3.8 (registry+https://github.com/rust-lang/crates.io-index)" = "79c56d6a0b07f9e19282511c83fc5b086364cbae4ba8c7d5f190c3d9b0425a48" "checksum memchr 2.2.1 (registry+https://github.com/rust-lang/crates.io-index)" = "88579771288728879b57485cc7d6b07d648c9f0141eb955f8ab7f9d45394468e" -"checksum memoffset 0.5.3 (registry+https://github.com/rust-lang/crates.io-index)" = "75189eb85871ea5c2e2c15abbdd541185f63b408415e5051f5cac122d8c774b9" +"checksum memoffset 0.5.1 (registry+https://github.com/rust-lang/crates.io-index)" = "ce6075db033bbbb7ee5a0bbd3a3186bbae616f57fb001c485c7ff77955f8177f" "checksum mime 0.2.6 (registry+https://github.com/rust-lang/crates.io-index)" = "ba626b8a6de5da682e1caa06bdb42a335aee5a84db8e5046a3e8ab17ba0a3ae0" "checksum mio 0.6.19 (registry+https://github.com/rust-lang/crates.io-index)" = "83f51996a3ed004ef184e16818edc51fadffe8e7ca68be67f9dee67d84d0ff23" "checksum mio-uds 0.6.7 (registry+https://github.com/rust-lang/crates.io-index)" = "966257a94e196b11bb43aca423754d87429960a768de9414f3691d6957abf125" "checksum miow 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)" = "8c1f2f3b1cf331de6896aabf6e9d55dca90356cc9960cca7eaaf408a355ae919" "checksum mongodb 0.3.12 (registry+https://github.com/rust-lang/crates.io-index)" = "d558c8c1ee6140954f82b53558135bb9ecb7b258e10dbd7206d985d134d388e0" "checksum net2 0.2.33 (registry+https://github.com/rust-lang/crates.io-index)" = "42550d9fb7b6684a6d404d9fa7250c2eb2646df731d1c06afc06dcee9e1bcf88" +"checksum nodrop 0.1.14 (registry+https://github.com/rust-lang/crates.io-index)" = "72ef4a56884ca558e5ddb05a1d1e7e1bfd9a68d9ed024c21704cc98872dae1bb" "checksum nom 4.2.3 (registry+https://github.com/rust-lang/crates.io-index)" = "2ad2a91a8e869eeb30b9cb3119ae87773a8f4ae617f41b1eb9c154b2905f7bd6" "checksum num-bigint 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)" = "f9c3f34cdd24f334cb265d9bf8bfa8a241920d026916785747a92f0e55541a1a" "checksum num-integer 0.1.41 (registry+https://github.com/rust-lang/crates.io-index)" = "b85e541ef8255f6cf42bbfe4ef361305c6c135d10919ecc26126c4e5ae94bc09" "checksum num-traits 0.1.43 (registry+https://github.com/rust-lang/crates.io-index)" = "92e5113e9fd4cc14ded8e499429f396a20f98c772a47cc8622a736e1ec843c31" -"checksum num-traits 0.2.9 (registry+https://github.com/rust-lang/crates.io-index)" = "443c53b3c3531dfcbfa499d8893944db78474ad7a1d87fa2d94d1a2231693ac6" -"checksum num_cpus 1.11.1 (registry+https://github.com/rust-lang/crates.io-index)" = "76dac5ed2a876980778b8b85f75a71b6cbf0db0b1232ee12f826bccb00d09d72" -"checksum ocean-rpc 0.8.0 (git+https://github.com/commerceblock/rust-ocean-rpc)" = "" -"checksum ocean-rpc-json 0.8.0 (git+https://github.com/commerceblock/rust-ocean-rpc)" = "" +"checksum num-traits 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)" = "6ba9a427cfca2be13aa6f6403b0b7e7368fe982bfa16fccc450ce74c46cd9b32" +"checksum num_cpus 1.10.1 (registry+https://github.com/rust-lang/crates.io-index)" = "bcef43580c035376c0705c42792c294b66974abbfd2789b511784023f71f3273" +"checksum ocean-rpc 0.3.0 (git+https://github.com/commerceblock/rust-ocean-rpc)" = "" +"checksum ocean-rpc-json 0.3.0 (git+https://github.com/commerceblock/rust-ocean-rpc)" = "" "checksum parking_lot 0.9.0 (registry+https://github.com/rust-lang/crates.io-index)" = "f842b1982eb6c2fe34036a4fbfb06dd185a3f5c8edfaacdf7d1ea10b07de6252" "checksum parking_lot_core 0.6.2 (registry+https://github.com/rust-lang/crates.io-index)" = "b876b1b9e7ac6e1a74a6da34d25c42e17e8862aa409cbbbdcfc8d86c6f3bc62b" "checksum pbkdf2 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)" = "0c09cddfbfc98de7f76931acf44460972edb4023eb14d0c6d4018800e552d8e0" @@ -1793,29 +1851,31 @@ dependencies = [ "checksum regex-syntax 0.5.6 (registry+https://github.com/rust-lang/crates.io-index)" = "7d707a4fa2637f2dca2ef9fd02225ec7661fe01a53623c1e6515b6916511f7a7" "checksum regex-syntax 0.6.12 (registry+https://github.com/rust-lang/crates.io-index)" = "11a7e20d1cce64ef2fed88b66d347f88bd9babb82845b2b858f3edbf59a4f716" "checksum rust-ini 0.13.0 (registry+https://github.com/rust-lang/crates.io-index)" = "3e52c148ef37f8c375d49d5a73aa70713125b7f19095948a923f80afdeb22ec2" -"checksum rust-ocean 0.10.0 (git+https://github.com/commerceblock/rust-ocean)" = "" +"checksum rust-ocean 0.6.0 (git+https://github.com/commerceblock/rust-ocean)" = "" "checksum rustc_version 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)" = "138e3e0acb6c9fb258b19b67cb8abd63c00679d2851805ea151465464fe9030a" "checksum ryu 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)" = "bfa8506c1de11c9c4e4c38863ccbe02a305c8188e85a05a784c9e11e1c3910c8" "checksum safemem 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)" = "ef703b7cb59335eae2eb93ceb664c0eb7ea6bf567079d843e09420219668e072" "checksum scan_fmt 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)" = "8b87497427f9fbe539ee6b9626f5a5e899331fdf1c1d62f14c637a462969db30" "checksum scopeguard 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)" = "b42e15e59b18a828bbf5c58ea01debb36b9b096346de35d941dcb89009f24a0d" -"checksum secp256k1 0.15.5 (registry+https://github.com/rust-lang/crates.io-index)" = "4d311229f403d64002e9eed9964dfa5a0a0c1ac443344f7546bf48e916c6053a" +"checksum secp256k1 0.12.2 (registry+https://github.com/rust-lang/crates.io-index)" = "bfaccd3a23619349e0878d9a241f34b1982343cdf67367058cd7d078d326b63e" "checksum semver 0.8.0 (registry+https://github.com/rust-lang/crates.io-index)" = "bee2bc909ab2d8d60dab26e8cad85b25d795b14603a0dcb627b78b9d30b6454b" "checksum semver 0.9.0 (registry+https://github.com/rust-lang/crates.io-index)" = "1d7eb9ef2c18661902cc47e535f9bc51b78acd254da71d375c2f6720d9a40403" "checksum semver-parser 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)" = "388a1df253eca08550bef6c72392cfe7c30914bf41df5269b68cbd6ff8f570a3" "checksum separator 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)" = "7acc4d818f952ed02e7911df5da8098c8b00a3c5ba2832e035a750b56e8fc32b" "checksum serde 0.8.23 (registry+https://github.com/rust-lang/crates.io-index)" = "9dad3f759919b92c3068c696c15c3d17238234498bbdcc80f2c469606f948ac8" -"checksum serde 1.0.102 (registry+https://github.com/rust-lang/crates.io-index)" = "0c4b39bd9b0b087684013a792c59e3e07a46a01d2322518d8a1104641a0b1be0" +"checksum serde 1.0.101 (registry+https://github.com/rust-lang/crates.io-index)" = "9796c9b7ba2ffe7a9ce53c2287dfc48080f4b2b362fcc245a259b3a7201119dd" "checksum serde-hjson 0.8.2 (registry+https://github.com/rust-lang/crates.io-index)" = "0b833c5ad67d52ced5f5938b2980f32a9c1c5ef047f0b4fb3127e7a423c76153" -"checksum serde_derive 1.0.102 (registry+https://github.com/rust-lang/crates.io-index)" = "ca13fc1a832f793322228923fbb3aba9f3f44444898f835d31ad1b74fa0a2bf8" +"checksum serde_derive 1.0.101 (registry+https://github.com/rust-lang/crates.io-index)" = "4b133a43a1ecd55d4086bd5b4dc6c1751c68b1bfbeba7a5040442022c7e7c02e" "checksum serde_json 1.0.41 (registry+https://github.com/rust-lang/crates.io-index)" = "2f72eb2a68a7dc3f9a691bfda9305a1c017a6215e5a4545c258500d2099a37c2" "checksum serde_test 0.8.23 (registry+https://github.com/rust-lang/crates.io-index)" = "110b3dbdf8607ec493c22d5d947753282f3bae73c0f56d322af1e8c78e4c23d5" +"checksum serde_test 1.0.101 (registry+https://github.com/rust-lang/crates.io-index)" = "4aaf891d32257c9f65259b841af6e0b35d2ee22e41f1becbead01f0217f3e000" "checksum sha-1 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)" = "51b9d1f3b5de8a167ab06834a7c883bd197f2191e1dda1a22d9ccfeedbf9aded" "checksum sha2 0.7.1 (registry+https://github.com/rust-lang/crates.io-index)" = "9eb6be24e4c23a84d7184280d2722f7f2731fcdd4a9d886efbfe4413e4847ea0" "checksum slab 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)" = "c111b5bd5695e56cffe5129854aa230b39c93a305372fdbb2668ca2394eea9f8" -"checksum smallvec 0.6.13 (registry+https://github.com/rust-lang/crates.io-index)" = "f7b0758c52e15a8b5e3691eae6cc559f08eee9406e548a4477ba4e67770a82b6" +"checksum smallvec 0.6.10 (registry+https://github.com/rust-lang/crates.io-index)" = "ab606a9c5e214920bb66c458cd7be8ef094f813f20fe77a54cc7dbfff220d4b7" +"checksum strason 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "dcd1098ae32c583b8d538072380c340a01e46fbca379d6248ff77721373e2cef" "checksum string 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)" = "d24114bfcceb867ca7f71a0d3fe45d45619ec47a6fbfa98cb14e14250bfa5d6d" -"checksum syn 1.0.8 (registry+https://github.com/rust-lang/crates.io-index)" = "661641ea2aa15845cddeb97dad000d22070bb5c1fb456b96c1cba883ec691e92" +"checksum syn 1.0.5 (registry+https://github.com/rust-lang/crates.io-index)" = "66850e97125af79138385e9b88339cbcd037e3f28ceab8c5ad98e64f0f1f80bf" "checksum termcolor 1.0.5 (registry+https://github.com/rust-lang/crates.io-index)" = "96d6098003bde162e4277c70665bd87c326f5a0c3f3fbfb285787fa482d54e6e" "checksum textnonce 0.6.5 (registry+https://github.com/rust-lang/crates.io-index)" = "dafb35214e317d6c0a72b16d1aa667bbc0fea57e302798e7bc520e0f39988006" "checksum thread_local 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)" = "c6b53e329000edc2b34dbe8545fd20e55a333362d0a321909685a19bd28c3f1b" @@ -1842,14 +1902,13 @@ dependencies = [ "checksum typenum 1.11.2 (registry+https://github.com/rust-lang/crates.io-index)" = "6d2783fe2d6b8c1101136184eb41be8b1ad379e4657050b8aaff0c79ee7575f9" "checksum ucd-util 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)" = "fa9b3b49edd3468c0e6565d85783f51af95212b6fa3986a5500954f00b460874" "checksum unicase 1.4.2 (registry+https://github.com/rust-lang/crates.io-index)" = "7f4765f83163b74f957c797ad9253caf97f103fb064d3999aea9568d09fc8a33" -"checksum unicase 2.6.0 (registry+https://github.com/rust-lang/crates.io-index)" = "50f37be617794602aabbeee0be4f259dc1778fabe05e2d67ee8f79326d5cb4f6" +"checksum unicase 2.5.1 (registry+https://github.com/rust-lang/crates.io-index)" = "2e2e6bd1e59e56598518beb94fd6db628ded570326f0a98c679a304bd9f00150" "checksum unicode-bidi 0.3.4 (registry+https://github.com/rust-lang/crates.io-index)" = "49f2bd0c6468a8230e1db229cff8029217cf623c767ea5d60bfbd42729ea54d5" -"checksum unicode-normalization 0.1.9 (registry+https://github.com/rust-lang/crates.io-index)" = "09c8070a9942f5e7cfccd93f490fdebd230ee3c3c9f107cb25bad5351ef671cf" +"checksum unicode-normalization 0.1.8 (registry+https://github.com/rust-lang/crates.io-index)" = "141339a08b982d942be2ca06ff8b076563cbe223d1befd5450716790d44e2426" "checksum unicode-xid 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "826e7639553986605ec5979c7dd957c7895e93eabed50ab2ffa7f6128a75097c" "checksum url 1.7.2 (registry+https://github.com/rust-lang/crates.io-index)" = "dd4e7c0d531266369519a4aa4f399d748bd37043b00bde1e4ff1f60a120b355a" "checksum utf8-ranges 1.0.4 (registry+https://github.com/rust-lang/crates.io-index)" = "b4ae116fef2b7fea257ed6440d3cfcff7f190865f170cdad00bb6465bf18ecba" "checksum version_check 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)" = "914b1a6776c4c929a602fafd8bc742e06365d4bcbe48c30f9cca5824f70dc9dd" -"checksum version_check 0.9.1 (registry+https://github.com/rust-lang/crates.io-index)" = "078775d0255232fb988e6fccf26ddc9d1ac274299aaedcedce21c6f72cc533ce" "checksum want 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "b6395efa4784b027708f7451087e647ec73cc74f5d9bc2e418404248d679a230" "checksum winapi 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)" = "167dc9d6949a9b857f3451275e911c3f44255842c1f7a76f33c55103a909087a" "checksum winapi 0.3.8 (registry+https://github.com/rust-lang/crates.io-index)" = "8093091eeb260906a183e6ae1abdba2ef5ef2257a21801128899c3fc699229c6" diff --git a/Cargo.toml b/Cargo.toml index 0bc9fe6..558c720 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "coordinator" -version = "0.3.9" +version = "0.1.0" authors = ["nkostoulas "] description = "Guardnode Coordinator implementation for the Commerceblock Covalence system" homepage = "https://github.com/commerceblock" @@ -19,4 +19,6 @@ mongodb = "0.3.11" jsonrpc-http-server = "11.0" rust-ocean = { git = "https://github.com/commerceblock/rust-ocean"} ocean-rpc = { git = "https://github.com/commerceblock/rust-ocean-rpc"} -bitcoin = { version = "0.20", features = [ "use-serde" ] } +bitcoin = { version = "0.17", features = [ "serde-decimal" ] } +bitcoin_hashes = "0.3" +secp256k1 = "0.12.2" diff --git a/config/default.toml b/config/default.toml index cff639f..719d1b1 100644 --- a/config/default.toml +++ b/config/default.toml @@ -1,14 +1,14 @@ # Log level option used to set RUST_LOG for the rust env logger -# log_level = "coordinator,demo" +log_level = "coordinator,demo" # Duration that we wait for challenge responses from guardnodes, in seconds -# challenge_duration = 60 +challenge_duration = 60 # Frequency of creating new challenges, in number of blocks -# challenge_frequency = 2 +challenge_frequency = 2 -# Block find time of service chain, in seconds -# block_time = 60 +# Duration that we attempt to verify a challenge transaction before skipping, in seconds +verify_duration = 150 # Host address that the listener binds to and receives guardnode requests listener_host = "127.0.0.1:9999" @@ -28,12 +28,11 @@ host = "127.0.0.1:5555" user = "user1" pass = "password1" genesis_hash = "ff8950160a77988cdc485913568d06c2d69a8c952ef0f179b4b097e3de63d7cc" -block_time = 60 asset = "CHALLENGE" asset_key = "cScSHCQp9AEwzZoucRpX9bMRkLCJ4LoQWBNFTZuD6tPX9qwNMWfQ" -chain = "ocean_test" -payment_asset = "CBT" [storage] host = "localhost:27017" name = "coordinator" +user = "user" +pass = "pass" diff --git a/docker-compose.yml b/docker-compose.yml index 9fa705c..8a0886c 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -46,8 +46,6 @@ services: CO_CLIENTCHAIN_PASS: password1 CO_CLIENTCHAIN_GENESIS_HASH: d1fbd07bd9a7a80a85445b8e28246f0b644c01ac7412e81ce3ffc0815386ad77 CO_CLIENTCHAIN_ASSET_KEY: cScSHCQp9AEwzZoucRpX9bMRkLCJ4LoQWBNFTZuD6tPX9qwNMWfQ - CO_CLIENTCHAIN_CHAIN: ocean_test - CO_CLIENTCHAIN_PAYMENT_ASSET: CBT # cb service chain node connectivity CO_SERVICE_HOST: service_chain:5555 diff --git a/examples/demo.rs b/examples/demo.rs index fca821f..e941f2b 100644 --- a/examples/demo.rs +++ b/examples/demo.rs @@ -1,33 +1,30 @@ //! Simple demo of coordinator with mock guard node -//! -//! Demo Coordinator connects to demo client chain (can be built by running -//! ./scripts/demo.sh) and sends challenges to mock guardnodes that made bids. -//! When guardnode responses are received by coordinator they are verified and -//! can be stored ready for fee payments to be made. #[macro_use] extern crate log; extern crate bitcoin; +extern crate bitcoin_hashes; extern crate coordinator; extern crate env_logger; extern crate hyper; extern crate ocean_rpc; +extern crate secp256k1; use std::sync::Arc; use std::{env, thread, time}; use bitcoin::consensus::encode::serialize; -use bitcoin::hashes::{hex::FromHex, hex::ToHex, sha256d}; -use bitcoin::secp256k1::{Message, Secp256k1, SecretKey}; +use bitcoin_hashes::{hex::FromHex, hex::ToHex, sha256d}; use hyper::{ rt::{self, Future, Stream}, Body, Client, Method, Request, }; use ocean_rpc::RpcApi; +use secp256k1::{Message, Secp256k1, SecretKey}; +use coordinator::clientchain::get_first_unspent; use coordinator::coordinator as coordinator_main; -use coordinator::interfaces::clientchain::get_first_unspent; -use coordinator::util::ocean::OceanClient; +use coordinator::ocean::OceanClient; /// Demo coordinator with listener and challenge service running /// mock implementation for service chain interface and ocean @@ -36,11 +33,9 @@ use coordinator::util::ocean::OceanClient; fn main() { let mut config = coordinator::config::Config::new().unwrap(); config.challenge_duration = 5; - config.challenge_frequency = 2; - config.block_time = 10; - config.clientchain.block_time = 10; + config.verify_duration = 30; - env::set_var("RUST_LOG", "coordinator,demo"); + env::set_var("RUST_LOG", &config.log_level); env::set_var("RUST_BACKTRACE", "1"); env_logger::init(); @@ -56,7 +51,7 @@ fn main() { // auto client chain block generation let client_rpc_clone = client_rpc.clone(); thread::spawn(move || loop { - thread::sleep(time::Duration::from_secs(10)); + thread::sleep(time::Duration::from_secs(5)); if let Err(e) = client_rpc_clone.clone().client.generate(1) { error!("{}", e); } @@ -73,6 +68,7 @@ fn main() { for bid in client_rpc.get_request_bids(&request_txid).unwrap().unwrap().bids { if bid.fee_pub_key.to_string() == guardnode_pubkey { guardnode_txid = bid.txid; + println!("guardnode bid txid: {}", guardnode_txid); break; } } diff --git a/examples/hyperclient.rs b/examples/hyperclient.rs index 48e6340..ff1cf02 100644 --- a/examples/hyperclient.rs +++ b/examples/hyperclient.rs @@ -1,17 +1,19 @@ //! Mock Example of client sending a POST request to server extern crate bitcoin; +extern crate bitcoin_hashes; extern crate hyper; +extern crate secp256k1; use bitcoin::consensus::encode::serialize; -use bitcoin::hashes::hex::{FromHex, ToHex}; -use bitcoin::hashes::sha256d; -use bitcoin::secp256k1::{Message, Secp256k1, SecretKey}; +use bitcoin_hashes::hex::{FromHex, ToHex}; +use bitcoin_hashes::sha256d; use hyper::{ header::HeaderValue, rt::{self, Future, Stream}, Body, Client, Method, Request, }; +use secp256k1::{Message, Secp256k1, SecretKey}; fn main() { let client = Client::new(); diff --git a/examples/rpc.rs b/examples/rpc.rs index 5a689aa..1720d70 100644 --- a/examples/rpc.rs +++ b/examples/rpc.rs @@ -3,7 +3,7 @@ extern crate ocean_rpc; extern crate rust_ocean; -use ocean_rpc::{Auth, Client, Error, RpcApi}; +use ocean_rpc::{Client, Error, RpcApi}; fn main_result() -> Result<(), Error> { let mut args = std::env::args(); @@ -14,7 +14,7 @@ fn main_result() -> Result<(), Error> { let user = args.next(); let pass = args.next(); - let rpc = Client::new(url, Auth::UserPass(user.unwrap(), pass.unwrap())).unwrap(); + let rpc = Client::new(url, user, pass); let blockchain_info = rpc.get_blockchain_info()?; println!("info\n{:?}", blockchain_info); diff --git a/scripts/create_request.sh b/scripts/create_request.sh index 6fca816..72000b5 100755 --- a/scripts/create_request.sh +++ b/scripts/create_request.sh @@ -1,12 +1,3 @@ -# Script builds, signs and sends a request transaction on service chain whose -# connectivity information is specified in $RPC_USER, RPC_PASS, RPC_CONNECT, -# and RPC_PORT env variables from the local ocean wallet. -# -# Several checks are made for validity of given arguments. If all is well then an -# unspent permission asset output is found (or provided in argument 9 and 10) and -# used as input to a raw request tx. The request is broadcast and its spending script -# address imported to the wallet to allow for automatic renewal of the request. - #!/bin/bash shopt -s expand_aliases alias ocl="$HOME/jsonrpc-cli/jsonrpc-cli --user=$RPC_USER --pass=$RPC_PASS --format=jsonpretty --resultonly=on --highlight=off http://$RPC_CONNECT:$RPC_PORT/" diff --git a/scripts/demo.sh b/scripts/demo.sh index bb56203..525b3e7 100755 --- a/scripts/demo.sh +++ b/scripts/demo.sh @@ -1,8 +1,3 @@ -# Script spins up new chain with datadir=~/co-client-dir/ and creates a new -# demo request transaction along with 2 bids. This can be used to initialise -# exmples/demo.rs to perform coordinator functionality on a mock client and service -# chain. - #!/bin/bash shopt -s expand_aliases diff --git a/scripts/report.py b/scripts/report.py index b6e9afc..b4dc02b 100755 --- a/scripts/report.py +++ b/scripts/report.py @@ -1,11 +1,3 @@ -# Script to generate report of responses from guardnodes using -# coordinator RPC API interface. -# -# First connection to a local Ocean node is made, the request data for a -# txid is found via getrequest RPC and fee size is calculated. -# Then getrequestresponse RPC is called to get challenge responses which can be -# used to determine rewards for guardnodes. - #!/usr/bin/env python3 import requests import json @@ -82,9 +74,9 @@ def calculate_fees(rpc, start_height, end_height): return fee addr_prefix = 235 -txid = "6e993034df3203c0867c98f420f85b5ffecd7cb8580e2b6f2d33764e1cbfb074" -url = 'http://userApi:passwordApi@localhost:3333' -rpc = connect("user1", "password1", "localhost", "5555") +txid = "78f954d07de5badbc1526a60fe0ea639216f17f490a3bf41e48840453eca243f" +url = 'https://userApi:passwordApi@coordinator-api.testnet.commerceblock.com:10006' +rpc = connect("ocean", "oceanpass", "localhost", "7043") payload = '{{"jsonrpc": "2.0", "method": "getrequest", "params": {{"txid": "{}"}}, "id": 1}}'.format(txid) headers = {'content-type': 'application/json', 'Accept-Charset': 'UTF-8'} @@ -98,8 +90,11 @@ def calculate_fees(rpc, start_height, end_height): print("") print("Calculating total fees...") -fee_start_height = request['start_blockheight_clientchain'] -fee_end_height = request['end_blockheight_clientchain'] +# For requests that are serving the service chain the fee start/end heights +# can be picked up from the request information. For requests in client chains +# these heights need to be found manually and inserted below to calculate fees +fee_start_height = request['start_blockheight'] +fee_end_height = request['end_blockheight'] fee = calculate_fees(rpc, fee_start_height, fee_end_height) fee_percentage = request['fee_percentage'] fee_out = fee*fee_percentage/100 @@ -117,17 +112,21 @@ def calculate_fees(rpc, start_height, end_height): fee_per_guard = float(fee_out/len(bids)) print("") -payload = '{{"jsonrpc": "2.0", "method": "getrequestresponse", "params": {{"txid": "{}"}}, "id": 1}}'.format(txid) +payload = '{{"jsonrpc": "2.0", "method": "getrequestresponses", "params": {{"txid": "{}"}}, "id": 1}}'.format(txid) headers = {'content-type': 'application/json', 'Accept-Charset': 'UTF-8'} r = requests.post(url, data=payload, headers=headers) result = json.loads(json.loads(r.content)['result']) -challenge_resps = result["response"] -num_of_challenges = challenge_resps["num_challenges"] +challenge_resps = result["responses"] +num_of_challenges = len(challenge_resps) print("Number of challenges: {}".format(num_of_challenges)) resps = {} -for (bid, resp_num) in challenge_resps["bid_responses"].items(): - resps[bid] = resp_num / num_of_challenges +for challenge_resp in challenge_resps: + for bid_resp in challenge_resp: + if bid_resp in resps: + resps[bid_resp] += (1/num_of_challenges) + else: + resps[bid_resp] = (1/num_of_challenges) print("Results") for bid, key in bids.items(): @@ -136,4 +135,4 @@ def calculate_fees(rpc, start_height, end_height): performance = resps[bid] print("Bid {0}\npubkey: {1}\naddress: {2}\nperformance: {3:.2f}%\nreward: {4}\n".\ format(bid, key, key_to_p2pkh(key, addr_prefix), 100*performance, fee_per_guard*performance)) -print("End") +print("End") \ No newline at end of file diff --git a/src/api.rs b/src/api.rs index bf58f07..1b7581e 100644 --- a/src/api.rs +++ b/src/api.rs @@ -8,16 +8,16 @@ use std::sync::Arc; use std::thread; use base64::decode; -use bitcoin::hashes::sha256d; +use bitcoin_hashes::sha256d; use hyper::{Body, Request, StatusCode}; use jsonrpc_http_server::jsonrpc_core::{Error, ErrorCode, IoHandler, Params, Value}; use jsonrpc_http_server::{hyper::header, AccessControlAllowOrigin, DomainsValidation, Response, ServerBuilder}; use serde::{Deserialize, Serialize}; +use crate::challenger::ChallengeResponseIds; use crate::config::ApiConfig; -use crate::interfaces::response::Response as ChallengeResponse; -use crate::interfaces::storage::Storage; -use crate::interfaces::{bid::BidSet, request::Request as ServiceRequest}; +use crate::request::{BidSet, Request as ServiceRequest}; +use crate::storage::Storage; #[derive(Deserialize, Debug)] struct GetRequestParams { @@ -59,7 +59,7 @@ struct GetRequestsResponse { /// Get requests RPC call returning all stored requests fn get_requests(storage: Arc) -> futures::Finished { - let requests = storage.get_requests(None).unwrap(); + let requests = storage.get_requests().unwrap(); let mut response = GetRequestsResponse { requests: vec![] }; for request in requests { let bids = storage.get_bids(request.txid).unwrap(); @@ -74,27 +74,19 @@ struct GetRequestResponsesParams { } #[derive(Serialize, Debug)] -struct GetRequestResponseResponse { - response: ChallengeResponse, +struct GetRequestResponsesResponse { + responses: Vec, } /// Get requests responses RPC call returning all responses for a specific /// request transaction id hash -fn get_request_response(params: Params, storage: Arc) -> futures::Finished { +fn get_request_responses(params: Params, storage: Arc) -> futures::Finished { let try_parse = params.parse::(); match try_parse { Ok(parse) => { - let response_get = storage.get_response(parse.txid).unwrap(); - if let Some(response) = response_get { - let res_serialized = serde_json::to_string(&GetRequestResponseResponse { response }).unwrap(); - return futures::finished(Value::String(res_serialized)); - } else { - return futures::failed(Error { - code: ErrorCode::InvalidParams, - message: "Invalid params: `txid` does not exist.".to_string(), - data: None, - }); - } + let responses = storage.get_responses(parse.txid).unwrap(); + let res_serialized = serde_json::to_string(&GetRequestResponsesResponse { responses }).unwrap(); + return futures::finished(Value::String(res_serialized)); } Err(e) => return futures::failed(e), } @@ -127,8 +119,8 @@ pub fn run_api_server( ) -> thread::JoinHandle<()> { let mut io = IoHandler::default(); let storage_ref = storage.clone(); - io.add_method("getrequestresponse", move |params: Params| { - get_request_response(params, storage_ref.clone()) + io.add_method("getrequestresponses", move |params: Params| { + get_request_responses(params, storage_ref.clone()) }); let storage_ref = storage.clone(); io.add_method("getrequest", move |params: Params| { @@ -169,7 +161,6 @@ mod tests { use futures::Future; - use crate::challenger::ChallengeResponseIds; use crate::util::testing::{gen_challenge_state, gen_dummy_hash, MockStorage}; #[test] @@ -194,7 +185,7 @@ mod tests { let resp = get_request(params, storage.clone()); assert_eq!( format!( - r#"{{"request":{{"txid":"{}","start_blockheight":2,"end_blockheight":5,"genesis_blockhash":"0000000000000000000000000000000000000000000000000000000000000000","fee_percentage":5,"num_tickets":10,"start_blockheight_clientchain":0,"end_blockheight_clientchain":0,"is_payment_complete":false}},"bids":[{{"txid":"1234567890000000000000000000000000000000000000000000000000000000","pubkey":"026a04ab98d9e4774ad806e302dddeb63bea16b5cb5f223ee77478e861bb583eb3","payment":null}}]}}"#, + r#"{{"request":{{"txid":"{}","start_blockheight":2,"end_blockheight":5,"genesis_blockhash":"0000000000000000000000000000000000000000000000000000000000000000","fee_percentage":5,"num_tickets":10}},"bids":[{{"txid":"1234567890000000000000000000000000000000000000000000000000000000","pubkey":"026a04ab98d9e4774ad806e302dddeb63bea16b5cb5f223ee77478e861bb583eb3"}}]}}"#, dummy_hash.to_string() ), resp.wait().unwrap() @@ -216,7 +207,7 @@ mod tests { let resp = get_requests(storage.clone()); assert_eq!( format!( - r#"{{"requests":[{{"request":{{"txid":"{}","start_blockheight":2,"end_blockheight":5,"genesis_blockhash":"0000000000000000000000000000000000000000000000000000000000000000","fee_percentage":5,"num_tickets":10,"start_blockheight_clientchain":0,"end_blockheight_clientchain":0,"is_payment_complete":false}},"bids":[{{"txid":"1234567890000000000000000000000000000000000000000000000000000000","pubkey":"026a04ab98d9e4774ad806e302dddeb63bea16b5cb5f223ee77478e861bb583eb3","payment":null}}]}}]}}"#, + r#"{{"requests":[{{"request":{{"txid":"{}","start_blockheight":2,"end_blockheight":5,"genesis_blockhash":"0000000000000000000000000000000000000000000000000000000000000000","fee_percentage":5,"num_tickets":10}},"bids":[{{"txid":"1234567890000000000000000000000000000000000000000000000000000000","pubkey":"026a04ab98d9e4774ad806e302dddeb63bea16b5cb5f223ee77478e861bb583eb3"}}]}}]}}"#, dummy_hash.to_string() ), resp.wait().unwrap() @@ -228,7 +219,7 @@ mod tests { let resp = get_requests(storage.clone()); assert_eq!( format!( - r#"{{"requests":[{{"request":{{"txid":"{}","start_blockheight":2,"end_blockheight":5,"genesis_blockhash":"0000000000000000000000000000000000000000000000000000000000000000","fee_percentage":5,"num_tickets":10,"start_blockheight_clientchain":0,"end_blockheight_clientchain":0,"is_payment_complete":false}},"bids":[{{"txid":"1234567890000000000000000000000000000000000000000000000000000000","pubkey":"026a04ab98d9e4774ad806e302dddeb63bea16b5cb5f223ee77478e861bb583eb3","payment":null}}]}},{{"request":{{"txid":"{}","start_blockheight":2,"end_blockheight":5,"genesis_blockhash":"0000000000000000000000000000000000000000000000000000000000000000","fee_percentage":5,"num_tickets":10,"start_blockheight_clientchain":0,"end_blockheight_clientchain":0,"is_payment_complete":false}},"bids":[{{"txid":"1234567890000000000000000000000000000000000000000000000000000000","pubkey":"026a04ab98d9e4774ad806e302dddeb63bea16b5cb5f223ee77478e861bb583eb3","payment":null}}]}}]}}"#, + r#"{{"requests":[{{"request":{{"txid":"{}","start_blockheight":2,"end_blockheight":5,"genesis_blockhash":"0000000000000000000000000000000000000000000000000000000000000000","fee_percentage":5,"num_tickets":10}},"bids":[{{"txid":"1234567890000000000000000000000000000000000000000000000000000000","pubkey":"026a04ab98d9e4774ad806e302dddeb63bea16b5cb5f223ee77478e861bb583eb3"}}]}},{{"request":{{"txid":"{}","start_blockheight":2,"end_blockheight":5,"genesis_blockhash":"0000000000000000000000000000000000000000000000000000000000000000","fee_percentage":5,"num_tickets":10}},"bids":[{{"txid":"1234567890000000000000000000000000000000000000000000000000000000","pubkey":"026a04ab98d9e4774ad806e302dddeb63bea16b5cb5f223ee77478e861bb583eb3"}}]}}]}}"#, dummy_hash.to_string(), dummy_hash2.to_string() ), @@ -237,20 +228,10 @@ mod tests { } #[test] - fn get_request_response_test() { + fn get_request_responses_test() { let storage = Arc::new(MockStorage::new()); let dummy_hash = gen_dummy_hash(1); let dummy_hash_bid = gen_dummy_hash(2); - - // no such request - let s = format!(r#"{{"txid": "{}"}}"#, dummy_hash.to_string()); - let params: Params = serde_json::from_str(&s).unwrap(); - let resp = get_request_response(params, storage.clone()); - assert_eq!( - "Invalid params: `txid` does not exist.", - resp.wait().unwrap_err().message - ); - let mut dummy_response_set = ChallengeResponseIds::new(); let _ = dummy_response_set.insert(dummy_hash_bid); let _ = storage.save_response(dummy_hash, &dummy_response_set); @@ -258,7 +239,7 @@ mod tests { // invalid key let s = format!(r#"{{"hash": "{}"}}"#, dummy_hash.to_string()); let params: Params = serde_json::from_str(&s).unwrap(); - let resp = get_request_response(params, storage.clone()); + let resp = get_request_responses(params, storage.clone()); assert_eq!( "Invalid params: missing field `txid`.", resp.wait().unwrap_err().message @@ -267,21 +248,18 @@ mod tests { // invalid value let s = format!(r#"{{"txid": "{}a"}}"#, dummy_hash.to_string()); let params: Params = serde_json::from_str(&s).unwrap(); - let resp = get_request_response(params, storage.clone()); + let resp = get_request_responses(params, storage.clone()); assert_eq!( - "Invalid params: odd hex string length 65.", + "Invalid params: bad hex string length 65 (expected 64).", resp.wait().unwrap_err().message ); // valid key and value let s = format!(r#"{{"txid": "{}"}}"#, dummy_hash.to_string()); let params: Params = serde_json::from_str(&s).unwrap(); - let resp = get_request_response(params, storage.clone()); + let resp = get_request_responses(params, storage.clone()); assert_eq!( - format!( - r#"{{"response":{{"num_challenges":1,"bid_responses":{{"{}":1}}}}}}"#, - dummy_hash_bid.to_string() - ), + format!("{{\"responses\":[[\"{}\"]]}}", dummy_hash_bid.to_string()), resp.wait().unwrap() ); } diff --git a/src/bin/main.rs b/src/bin/main.rs deleted file mode 100644 index f760e7d..0000000 --- a/src/bin/main.rs +++ /dev/null @@ -1,35 +0,0 @@ -//! # Main -//! -//! Main daemon entry - -#[macro_use] -extern crate log; -extern crate coordinator; -extern crate env_logger; - -use std::env; -use std::process; - -fn main() { - // Fetch config which is set from default values in config - // and any values overriden by the corresponding env variable - match coordinator::config::Config::new() { - Ok(config) => { - // To see results set RUST_LOG to one of the following: - // info, warning, debug, error, coordinator(for all) - env::set_var("RUST_LOG", &config.log_level); - env::set_var("RUST_BACKTRACE", "1"); - // Init env logger with value set from config - env_logger::init(); - if let Err(e) = coordinator::coordinator::run(config) { - error!("daemon failure: {}", e); - } - } - Err(e) => { - env::set_var("RUST_LOG", "error"); - env_logger::init(); - error!("config failure: {}", e); - } - } - process::exit(1); -} diff --git a/src/challenger.rs b/src/challenger.rs index 5d56a50..5deab01 100644 --- a/src/challenger.rs +++ b/src/challenger.rs @@ -1,52 +1,46 @@ //! Challenger //! -//! Methods and models for fetching, structuring, storing and running challenge -//! requests +//! Methods and models for fetching, structuring and running challenge requests use std::collections::HashSet; use std::sync::mpsc::{Receiver, RecvTimeoutError}; use std::sync::{Arc, Mutex}; use std::{thread, time}; -use bitcoin::hashes::sha256d; +use bitcoin_hashes::sha256d; +use crate::clientchain::ClientChain; use crate::error::{CError, Error, Result}; -use crate::interfaces::clientchain::ClientChain; -use crate::interfaces::service::Service; -use crate::interfaces::storage::Storage; -use crate::interfaces::{ - bid::{Bid, BidSet}, - request::Request, -}; +use crate::request::{Bid, BidSet, Request}; +use crate::service::Service; +use crate::storage::Storage; -/// Verify attempt interval to client in ms -pub const CHALLENGER_VERIFY_INTERVAL: u64 = 100; +/// Number of verify attempts for challenge transaction +pub const CHALLENGER_VERIFY_ATTEMPTS: u32 = 5; /// Attempts to verify that a challenge has been included in the client chain -/// This makes attempts every CHALLENGER_VERIFY_INTERVAL ms and for the verify -/// duration specified, which is variable in order to allow easy configuration +/// Method tries a fixed number of attempts CHALLENGER_VERIFY_ATTEMPTS for a +/// variable delay time to allow easy configuration fn verify_challenge( hash: &sha256d::Hash, clientchain: &K, - verify_duration: time::Duration, -) -> Result<()> { + attempt_delay: time::Duration, +) -> Result { info! {"verifying challenge hash: {}", hash} - let start_time = time::Instant::now(); - loop { - let now = time::Instant::now(); - if start_time + verify_duration > now { - if clientchain.verify_challenge(&hash)? { - info! {"challenge verified"} - return Ok(()); - } - } else { + for i in 0..CHALLENGER_VERIFY_ATTEMPTS { + // fixed number of attempts? + if clientchain.verify_challenge(&hash)? { + info! {"challenge verified"} + return Ok(true); + } + warn! {"attempt {} failed", i+1} + if i + 1 == CHALLENGER_VERIFY_ATTEMPTS { break; } - // This will potentially be replaced by subscribing to the ocean node - // for transaction updates but this is good enough for now - thread::sleep(std::time::Duration::from_millis(CHALLENGER_VERIFY_INTERVAL)) + info! {"sleeping for {:?}...", attempt_delay/CHALLENGER_VERIFY_ATTEMPTS} + thread::sleep(attempt_delay / CHALLENGER_VERIFY_ATTEMPTS) } - Err(Error::from(CError::UnverifiedChallenge)) + Ok(false) } /// Get responses to the challenge by reading data from the channel receiver @@ -102,7 +96,7 @@ pub fn run_challenge_request( refresh_delay: time::Duration, ) -> Result<()> { let request = challenge_state.lock().unwrap().request.clone(); // clone as const and drop mutex - info! {"Running challenge request: {:?}", request.txid}; + info! {"Running challenge request: {:?}", request}; let mut prev_challenge_height: u64 = 0; loop { let challenge_height = service.get_blockheight()?; @@ -119,9 +113,9 @@ pub fn run_challenge_request( let challenge_hash = clientchain.send_challenge()?; challenge_state.lock().unwrap().latest_challenge = Some(challenge_hash); - if let Err(e) = verify_challenge(&challenge_hash, clientchain, verify_duration) { + if !verify_challenge(&challenge_hash, clientchain, verify_duration)? { challenge_state.lock().unwrap().latest_challenge = None; // stop receiving responses - return Err(e); + continue; } info! {"fetching responses..."} @@ -136,35 +130,6 @@ pub fn run_challenge_request( Ok(()) } -/// Update challenge state request with client chain start and end block -/// heights and store challenge state -/// If request already stored set challenge state request to request in -/// storage (catcher for coordinator failure after storing request but -/// before request service period over) -pub fn update_challenge_request_state( - clientchain: &K, - storage: Arc, - challenge: &mut ChallengeState, - block_time_servicechain: u64, - block_time_clientchain: u64, -) -> Result<()> { - match storage.get_request(challenge.request.txid)? { - Some(req) => challenge.request = req, - None => { - // Set request's start_blockheight_clientchain - challenge.request.start_blockheight_clientchain = clientchain.get_blockheight()?; - let service_period_time_s = (challenge.request.end_blockheight - challenge.request.start_blockheight) - * block_time_servicechain as u32; - // Calculate and set request's end_blockheight_clientchain - challenge.request.end_blockheight_clientchain = challenge.request.start_blockheight_clientchain - + (service_period_time_s as f32 / block_time_clientchain as f32).floor() as u32; - storage.save_challenge_state(&challenge)?; // Store Challenge - // Request - } - } - Ok(()) -} - /// Tuple struct to store a verified challenge response /// for a winning bid on a specific challenge hash #[derive(Debug, Hash, Clone)] @@ -244,29 +209,22 @@ mod tests { use std::sync::mpsc::{channel, Receiver, Sender}; use crate::error::Error; - use crate::interfaces::response::Response; - use crate::util::testing::{gen_challenge_state, gen_dummy_hash, MockClientChain, MockService, MockStorage}; + use crate::util::testing::{gen_dummy_hash, MockClientChain, MockService, MockStorage}; #[test] fn verify_challenge_test() { let mut clientchain = MockClientChain::new(); let dummy_hash = gen_dummy_hash(5); - // duration doesn't matter here - assert!(verify_challenge(&dummy_hash, &clientchain, time::Duration::from_millis(10)).unwrap() == ()); + assert!(verify_challenge(&dummy_hash, &clientchain, time::Duration::from_nanos(1)).unwrap() == true); clientchain.return_false = true; - let res = verify_challenge(&dummy_hash, &clientchain, time::Duration::from_millis(10)); - match res { - Ok(_) => assert!(false, "should not return Ok"), - Err(Error::Coordinator(e)) => assert_eq!(CError::UnverifiedChallenge.to_string(), e.to_string()), - Err(_) => assert!(false, "should not return any error"), - } + assert!(verify_challenge(&dummy_hash, &clientchain, time::Duration::from_nanos(1)).unwrap() == false); clientchain.return_false = false; clientchain.return_err = true; assert!( - verify_challenge(&dummy_hash, &clientchain, time::Duration::from_millis(10)).is_err(), + verify_challenge(&dummy_hash, &clientchain, time::Duration::from_nanos(1)).is_err(), "verify_challenge failed" ) } @@ -313,64 +271,6 @@ mod tests { } } - #[test] - fn update_challenge_request_state_test() { - let clientchain = MockClientChain::new(); - let storage = Arc::new(MockStorage::new()); - - let dummy_hash = gen_dummy_hash(11); - let mut challenge = gen_challenge_state(&dummy_hash); - let num_service_chain_blocks = challenge.request.end_blockheight - challenge.request.start_blockheight; - - // Test challenge state request set and stored correctly - let _ = clientchain.height.replace(1); - let mut comparison_challenge_request = challenge.request.clone(); // Clone request for comparison - let _ = update_challenge_request_state(&clientchain, storage.clone(), &mut challenge, 1, 1); - // All fields stay the same but start and end blockheight_clientchain - comparison_challenge_request.start_blockheight_clientchain = *clientchain.height.borrow(); - comparison_challenge_request.end_blockheight_clientchain = - challenge.request.start_blockheight_clientchain + num_service_chain_blocks; // start_height + number of servcie chain blocks - assert_eq!(challenge.request, comparison_challenge_request); - assert_eq!( - storage.get_request(challenge.request.txid).unwrap().unwrap(), - comparison_challenge_request - ); - - // Test challenge state set and storage performed correctly - // for client chain block time half of service chain block time - let storage = Arc::new(MockStorage::new()); //reset storage - let _ = clientchain.height.replace(1); - let mut comparison_challenge_request = challenge.request.clone(); // Clone request for comparison - let _ = update_challenge_request_state(&clientchain, storage.clone(), &mut challenge, 2, 1); - // All fields stay the same but start and end blockheight_clientchain - comparison_challenge_request.start_blockheight_clientchain = *clientchain.height.borrow(); - comparison_challenge_request.end_blockheight_clientchain = - challenge.request.start_blockheight_clientchain + 2 * num_service_chain_blocks; // start_height + (2 times client chain blocks as service chain blocks in same - // time period * number of service chain block) - assert_eq!(challenge.request, comparison_challenge_request); - assert_eq!( - storage.get_request(challenge.request.txid).unwrap().unwrap(), - comparison_challenge_request - ); - - // Test stored version unchanged if attempt is made to store request a second - // time - let old_challenge = challenge.clone(); // save old challenge state - challenge.request.fee_percentage = 25; // alter random field - let new_challenge = challenge.clone(); // save new challenge state - let _ = update_challenge_request_state(&clientchain, storage.clone(), &mut challenge, 2, 1); - assert_eq!(challenge.request, old_challenge.request); - assert_eq!( - storage.get_request(challenge.request.txid).unwrap().unwrap(), - old_challenge.request - ); - assert_ne!(challenge.request, new_challenge.request); - assert_ne!( - storage.get_request(challenge.request.txid).unwrap().unwrap(), - new_challenge.request - ); - } - #[test] fn check_request_test() { let service = MockService::new(); @@ -465,13 +365,12 @@ mod tests { // test normal operation of run_challenge_request by adding some responses for // the first challenge let _ = service.height.replace(dummy_request.start_blockheight as u64); // set height for fetch_next to succeed - let challenge_state = fetch_next(&service, &dummy_hash).unwrap().unwrap(); storage.save_challenge_state(&challenge_state).unwrap(); let (vtx, vrx): (Sender, Receiver) = channel(); - let _ = clientchain.height.replace((dummy_request.start_blockheight) + 1); // set height +1 for challenge hash response + let _ = clientchain.height.replace((dummy_request.start_blockheight as u64) + 1); // set height +1 for challenge hash response let dummy_challenge_hash = clientchain.send_challenge().unwrap(); let dummy_bid = challenge_state.bids.iter().next().unwrap().clone(); vtx.send(ChallengeResponse(dummy_challenge_hash, dummy_bid.clone())) @@ -488,17 +387,16 @@ mod tests { storage.clone(), time::Duration::from_millis(10), time::Duration::from_millis(10), - 50, + 3, time::Duration::from_millis(10), ); - match res { Ok(_) => { - let resps = storage.get_response(dummy_request.txid).unwrap(); - assert_eq!(resps, None); + let resps = storage.get_responses(dummy_request.txid).unwrap(); + assert_eq!(1, resps.len()); let bids = storage.get_bids(dummy_request.txid).unwrap(); assert_eq!(challenge_state.bids, bids); - let requests = storage.get_requests(None).unwrap(); + let requests = storage.get_requests().unwrap(); assert_eq!(1, requests.len()); assert_eq!(&challenge_state.request, &requests[0]); assert_eq!( @@ -525,21 +423,16 @@ mod tests { 1, time::Duration::from_millis(10), ); - match res { Ok(_) => { - let resps = storage.get_response(dummy_request.txid).unwrap(); - assert_eq!( - resps.unwrap(), - Response { - num_challenges: 4, - bid_responses: [(dummy_bid.txid, 1)].iter().cloned().collect() - } - ); - assert_eq!(1, storage.challenge_responses.borrow().len()); + let resps = storage.get_responses(dummy_request.txid).unwrap(); + assert_eq!(5, resps.len()); + assert_eq!(1, resps[1].len()); + assert_eq!(dummy_bid.txid, *resps[1].iter().next().unwrap()); + assert_eq!(5, storage.challenge_responses.borrow().len()); let bids = storage.get_bids(dummy_request.txid).unwrap(); assert_eq!(challenge_state.bids, bids); - let requests = storage.get_requests(None).unwrap(); + let requests = storage.get_requests().unwrap(); assert_eq!(1, requests.len()); assert_eq!(&challenge_state.request, &requests[0]); assert_eq!( @@ -629,12 +522,10 @@ mod tests { time::Duration::from_millis(10), ); match res { - Ok(_) => assert!(false, "should not return Ok"), - Err(Error::Coordinator(e)) => { + Ok(_) => { assert_eq!(0, storage.challenge_responses.borrow().len()); - assert_eq!(CError::UnverifiedChallenge.to_string(), e.to_string()); } - Err(_) => assert!(false, "should not return any error"), + Err(_) => assert!(false, "should not return error"), } clientchain.return_false = false; diff --git a/src/interfaces/clientchain.rs b/src/clientchain.rs similarity index 83% rename from src/interfaces/clientchain.rs rename to src/clientchain.rs index 9bfb93a..912ae5a 100644 --- a/src/interfaces/clientchain.rs +++ b/src/clientchain.rs @@ -4,16 +4,16 @@ use std::collections::HashMap; -use bitcoin::hashes::{hex::FromHex, sha256d}; +use bitcoin_hashes::{hex::FromHex, sha256d}; use ocean_rpc::{json, RpcApi}; use crate::config::ClientChainConfig; use crate::error::{CError, Error, Result}; -use crate::util::ocean::OceanClient; +use crate::ocean::OceanClient; /// Method that returns the first unspent output for given asset /// or an error if the client wallet does not have any unspent/funds -pub fn get_first_unspent(client: &OceanClient, asset: &str) -> Result { +pub fn get_first_unspent(client: &OceanClient, asset: &str) -> Result { // Check asset is held by the wallet and return unspent tx let unspent = client.list_unspent(None, None, None, None, Some(asset))?; if unspent.is_empty() { @@ -33,8 +33,6 @@ pub trait ClientChain { fn send_challenge(&self) -> Result; /// Verify challenge transaction has been included in the chain fn verify_challenge(&self, txid: &sha256d::Hash) -> Result; - /// Get height of client chain - fn get_blockheight(&self) -> Result; } /// Rpc implementation of Service using an underlying ocean rpc connection @@ -87,21 +85,26 @@ impl<'a> ClientChain for RpcClientChain<'a> { }]; let mut outs = HashMap::new(); - let _ = outs.insert(unspent.address.to_string(), unspent.amount); + let _ = outs.insert( + unspent.address.clone(), + (unspent.amount.into_inner() / 100000000) as f64, + ); let mut outs_assets = HashMap::new(); - let _ = outs_assets.insert(unspent.address.to_string(), unspent.asset); + let _ = outs_assets.insert(unspent.address.clone(), unspent.asset.to_string()); let tx_hex = self .client - .create_raw_transaction_hex(&utxos, &outs, Some(&outs_assets), None)?; + .create_raw_transaction_hex(&utxos, Some(&outs), Some(&outs_assets), None)?; // sign the transaction and send via the client rpc - let tx_signed = self - .client - .sign_raw_transaction(&Vec::::from_hex(&tx_hex)? as &[u8], None, None, None)?; + let tx_signed = + self.client + .sign_raw_transaction((&Vec::::from_hex(&tx_hex)? as &[u8]).into(), None, None, None)?; - Ok(self.client.send_raw_transaction(&tx_signed.hex)?) + Ok(sha256d::Hash::from_hex( + &self.client.send_raw_transaction(&tx_signed.hex)?, + )?) } /// Verify challenge transaction has been included in the chain @@ -121,9 +124,4 @@ impl<'a> ClientChain for RpcClientChain<'a> { } Ok(false) } - - /// Return block count of chain - fn get_blockheight(&self) -> Result { - Ok(self.client.get_block_count()? as u32) - } } diff --git a/src/config.rs b/src/config.rs index cb4ecd6..f4312a8 100644 --- a/src/config.rs +++ b/src/config.rs @@ -2,16 +2,13 @@ //! //! Config module handling config options from file/env -use std::env; -use std::str::FromStr; - use config_rs::{Config as ConfigRs, Environment, File}; -use ocean::Address; +use error::InputErrorType::{GenHash, PrivKey}; use serde::{Deserialize, Serialize}; +use std::env; +use util::checks::{check_hash_string, check_privkey_string}; -use crate::error::InputErrorType::{GenHash, MissingArgument, PrivKey}; use crate::error::{CError, Error, Result}; -use crate::util::checks::{check_hash_string, check_privkey_string}; #[derive(Debug, Serialize, Deserialize)] /// Api specific config @@ -55,7 +52,7 @@ impl Default for ServiceConfig { } } -#[derive(Debug, Serialize, Deserialize, Clone)] +#[derive(Debug, Serialize, Deserialize)] /// Clientchain specific config pub struct ClientChainConfig { /// Client rpc host @@ -66,20 +63,10 @@ pub struct ClientChainConfig { pub pass: String, /// Client genesis hash pub genesis_hash: String, - /// Block time in seconds - pub block_time: u64, /// Client asset label pub asset: String, /// Client asset key pub asset_key: String, - /// Client chain name - pub chain: String, - /// Payment asset label or asset id or ANY asset to be used for payments - pub payment_asset: String, - /// Payment key; optional as the coordinator might not be doing payments - pub payment_key: Option, - /// Payment address corresponding to payment key - pub payment_addr: Option, } impl Default for ClientChainConfig { @@ -89,13 +76,8 @@ impl Default for ClientChainConfig { user: String::new(), pass: String::new(), genesis_hash: String::new(), - block_time: CONFIG_BLOCK_TIME_DEFAULT, asset: String::from("CHALLENGE"), asset_key: String::new(), - chain: String::new(), - payment_asset: String::new(), - payment_key: None, - payment_addr: None, } } } @@ -133,8 +115,8 @@ pub struct Config { pub challenge_duration: u64, /// Challenge frequency in number of blocks pub challenge_frequency: u64, - /// Block time of service chain in seconds - pub block_time: u64, + /// Verify duration in seconds + pub verify_duration: u64, /// Listener host address pub listener_host: String, /// Api configuration @@ -147,18 +129,13 @@ pub struct Config { pub storage: StorageConfig, } -/// Config default variable definitons -const CONFIG_CHALLENGE_DURATION_DEFAULT: u64 = 60; -const CONFIG_CHALLENGE_FREQUENCY_DEFAULT: u64 = 1; -const CONFIG_BLOCK_TIME_DEFAULT: u64 = 60; - impl Default for Config { fn default() -> Config { Config { log_level: String::from("coordinator"), - challenge_duration: CONFIG_CHALLENGE_DURATION_DEFAULT, - challenge_frequency: CONFIG_CHALLENGE_FREQUENCY_DEFAULT, - block_time: CONFIG_BLOCK_TIME_DEFAULT, + challenge_duration: 60, + challenge_frequency: 1, + verify_duration: 150, listener_host: String::from("localhost:80"), api: ApiConfig::default(), service: ServiceConfig::default(), @@ -233,21 +210,6 @@ impl Config { if let Ok(v) = env::var("CO_CLIENTCHAIN_GENESIS_HASH") { let _ = conf_rs.set("clientchain.genesis_hash", v)?; } - if let Ok(v) = env::var("CO_CLIENTCHAIN_BLOCK_TIME") { - let _ = conf_rs.set("clientchain.block_time", v)?; - } - if let Ok(v) = env::var("CO_CLIENTCHAIN_CHAIN") { - let _ = conf_rs.set("clientchain.chain", v)?; - } - if let Ok(v) = env::var("CO_CLIENTCHAIN_PAYMENT_ASSET") { - let _ = conf_rs.set("clientchain.payment_asset", v)?; - } - if let Ok(v) = env::var("CO_CLIENTCHAIN_PAYMENT_KEY") { - let _ = conf_rs.set("clientchain.payment_key", v)?; - } - if let Ok(v) = env::var("CO_CLIENTCHAIN_PAYMENT_ADDR") { - let _ = conf_rs.set("clientchain.payment_addr", v)?; - } if let Ok(v) = env::var("CO_STORAGE_HOST") { let _ = conf_rs.set("storage.host", v)?; @@ -263,34 +225,18 @@ impl Config { } // Perform type checks - let key = conf_rs.get_str("clientchain.asset_key")?; - if !check_privkey_string(&key) { - return Err(Error::from(CError::InputError(PrivKey, key))); - } - let payment_key = conf_rs.get::>("clientchain.payment_key")?; - if !payment_key.is_none() && !check_privkey_string(&payment_key.clone().unwrap()) { - return Err(Error::from(CError::InputError(PrivKey, payment_key.unwrap()))); - } - if let Some(payment_addr) = conf_rs.get::>("clientchain.payment_addr")? { - let _ = Address::from_str(&payment_addr)?; + if let Ok(key) = conf_rs.get_str("clientchain.asset_key") { + if !check_privkey_string(&key) { + println!("{}", CError::InputError(PrivKey, key.clone())); + return Err(Error::from(CError::InputError(PrivKey, key))); + } + } + if let Ok(hash) = conf_rs.get_str("clientchain.genesis_hash") { + if !check_hash_string(&hash) { + println!("{}", CError::InputError(GenHash, hash.clone())); + return Err(Error::from(CError::InputError(GenHash, hash))); + } } - let hash = conf_rs.get_str("clientchain.genesis_hash")?; - if !check_hash_string(&hash) { - return Err(Error::from(CError::InputError(GenHash, hash))); - } - if conf_rs.get_str("clientchain.chain")?.len() == 0 { - return Err(Error::from(CError::InputError( - MissingArgument, - "clientchain.chain".into(), - ))); - } - if conf_rs.get_str("clientchain.payment_asset")?.len() == 0 { - return Err(Error::from(CError::InputError( - MissingArgument, - "clientchain.payment_asset".into(), - ))); - } - Ok(conf_rs.try_into()?) } } diff --git a/src/coordinator.rs b/src/coordinator.rs index 3e583e2..f494506 100644 --- a/src/coordinator.rs +++ b/src/coordinator.rs @@ -6,15 +6,15 @@ use std::sync::mpsc::{channel, Receiver, Sender}; use std::sync::{Arc, Mutex}; use std::{thread, time}; -use bitcoin::hashes::{hex::FromHex, sha256d}; +use bitcoin_hashes::{hex::FromHex, sha256d}; use futures::sync::oneshot; use crate::challenger::ChallengeResponse; +use crate::clientchain::{ClientChain, RpcClientChain}; use crate::config::Config; use crate::error::Result; -use crate::interfaces::clientchain::{ClientChain, RpcClientChain}; -use crate::interfaces::service::{RpcService, Service}; -use crate::interfaces::storage::{MongoStorage, Storage}; +use crate::service::{RpcService, Service}; +use crate::storage::{MongoStorage, Storage}; /// Run coordinator main method pub fn run(config: Config) -> Result<()> { @@ -26,21 +26,18 @@ pub fn run(config: Config) -> Result<()> { let genesis_hash = sha256d::Hash::from_hex(&config.clientchain.genesis_hash)?; let _ = ::api::run_api_server(&config.api, storage.clone()); - let (req_send, req_recv): (Sender, Receiver) = channel(); - let _ = ::payments::run_payments(config.clientchain.clone(), storage.clone(), req_recv)?; // This loop runs continuously fetching and running challenge requests, // generating challenge responses and fails on any errors that occur loop { if let Some(request_id) = run_request(&config, &service, &clientchain, storage.clone(), genesis_hash)? { // if challenge request succeeds print responses - req_send.send(request_id).unwrap(); - info! {"***** Response *****"} - let resp = storage.get_response(request_id)?.unwrap(); - info! {"{}", serde_json::to_string_pretty(&resp).unwrap()}; + println! {"***** Responses *****"} + let resp = storage.get_responses(request_id).unwrap(); + println! {"{}", serde_json::to_string_pretty(&resp).unwrap()}; } - info! {"Sleeping for {} sec...", config.block_time} - thread::sleep(time::Duration::from_secs(config.block_time)) + info! {"Sleeping for 10 sec..."} + thread::sleep(time::Duration::from_secs(10)) } } @@ -55,17 +52,10 @@ pub fn run_request( genesis_hash: sha256d::Hash, ) -> Result> { match ::challenger::fetch_next(service, &genesis_hash)? { - Some(mut challenge) => { - // First attempt to store the challenge state information - // on requests and winning bids and exit if it fails. - // If already set update challenge state with correct version from storage - ::challenger::update_challenge_request_state( - clientchain, - storage.clone(), - &mut challenge, - config.block_time, - config.clientchain.block_time, - )?; + Some(challenge) => { + // first attempt to store the challenge state information + // on requests and winning bids and exit if that fails + storage.save_challenge_state(&challenge)?; // create a challenge state mutex to share between challenger and listener let shared_challenge = Arc::new(Mutex::new(challenge)); @@ -84,10 +74,10 @@ pub fn run_request( shared_challenge.clone(), &verify_rx, storage.clone(), - time::Duration::from_secs(5 * config.block_time), + time::Duration::from_secs(config.verify_duration), time::Duration::from_secs(config.challenge_duration), config.challenge_frequency, - time::Duration::from_secs(config.block_time / 2), + time::Duration::from_secs(10), )?; // stop listener service diff --git a/src/error.rs b/src/error.rs index b62ebe4..ba7b19a 100644 --- a/src/error.rs +++ b/src/error.rs @@ -6,13 +6,11 @@ use std::error; use std::fmt; use std::result; -use bitcoin::hashes::hex::Error as HashesHexError; -use bitcoin::hashes::Error as HashesError; -use bitcoin::secp256k1::Error as Secp256k1Error; +use bitcoin_hashes::Error as HashesError; use config_rs::ConfigError; use mongodb::Error as MongoDbError; -use ocean::AddressError; use ocean_rpc::Error as OceanRpcError; +use secp256k1::Error as Secp256k1Error; /// Crate specific Result for crate specific Errors pub type Result = result::Result; @@ -22,8 +20,6 @@ pub type Result = result::Result; pub enum CError { /// Missing bids for a specific request error MissingBids, - /// Challenge was not successfully verified - UnverifiedChallenge, /// Listener receiver disconnected error ReceiverDisconnected, /// Missing unspent for challenge asset. Takes parameters asset label and @@ -48,16 +44,15 @@ pub enum InputErrorType { PrivKey, /// Invalid genesis hash string GenHash, - /// Missing input argument - MissingArgument, } impl InputErrorType { fn as_str(&self) -> &'static str { match *self { - InputErrorType::PrivKey => "Private key input - must be base58check string of length 52", - InputErrorType::GenHash => "Chain genesis hash input must be hexadecimal string of length 64", - InputErrorType::MissingArgument => "Argument missing", + InputErrorType::PrivKey => "Invalid private key input - must be base58check string of length 52.", + InputErrorType::GenHash => { + "Invalid client chain genesis hash input - must be hexadecimal string of length 64." + } } } } @@ -66,7 +61,9 @@ impl fmt::Display for CError { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { match *self { CError::Generic(ref e) => write!(f, "generic Error: {}", e), - CError::InputError(ref error, ref value) => write!(f, "Input Error: {} (value: {})", error.as_str(), value), + CError::InputError(ref error, ref value) => { + write!(f, "Input Error: {} \nProblem value: {}", error.as_str(), value) + } CError::MissingUnspent(ref asset, ref chain) => { write!(f, "No unspent found for {} asset on {} chain", asset, chain) } @@ -80,7 +77,6 @@ impl error::Error for CError { match *self { CError::Generic(_) => "Generic error", CError::MissingBids => "No bids found", - CError::UnverifiedChallenge => "Challenge not successfully verified", CError::ReceiverDisconnected => "Challenge response receiver disconnected", CError::MissingUnspent(_, _) => "No unspent found for asset", CError::InputError(_, _) => "Input parameter error", @@ -100,10 +96,6 @@ pub enum Error { OceanRpc(OceanRpcError), /// Bitcoin hashes error BitcoinHashes(HashesError), - /// Bitcoin hex hashes error - BitcoinHashesHex(HashesHexError), - /// Ocean address error - OceanAddress(AddressError), /// Secp256k1 error Secp256k1(Secp256k1Error), /// Mongodb error @@ -132,24 +124,12 @@ impl From for Error { } } -impl From for Error { - fn from(e: HashesHexError) -> Error { - Error::BitcoinHashesHex(e) - } -} - impl From for Error { fn from(e: Secp256k1Error) -> Error { Error::Secp256k1(e) } } -impl From for Error { - fn from(e: AddressError) -> Error { - Error::OceanAddress(e) - } -} - impl From for Error { fn from(e: MongoDbError) -> Error { Error::MongoDb(e) @@ -167,9 +147,7 @@ impl fmt::Display for Error { match *self { Error::OceanRpc(ref e) => write!(f, "ocean rpc error: {}", e), Error::BitcoinHashes(ref e) => write!(f, "bitcoin hashes error: {}", e), - Error::BitcoinHashesHex(ref e) => write!(f, "bitcoin hashes hex error: {}", e), Error::Secp256k1(ref e) => write!(f, "secp256k1 error: {}", e), - Error::OceanAddress(ref e) => write!(f, "ocean address error: {}", e), Error::MongoDb(ref e) => write!(f, "mongodb error: {}", e), Error::Config(ref e) => write!(f, "config error: {}", e), Error::Coordinator(ref e) => write!(f, "coordinator error: {}", e), @@ -182,9 +160,7 @@ impl error::Error for Error { match *self { Error::OceanRpc(ref e) => Some(e), Error::BitcoinHashes(ref e) => Some(e), - Error::BitcoinHashesHex(ref e) => Some(e), Error::Secp256k1(ref e) => Some(e), - Error::OceanAddress(ref e) => Some(e), Error::MongoDb(ref e) => Some(e), Error::Config(ref e) => Some(e), Error::Coordinator(_) => None, diff --git a/src/interfaces/mod.rs b/src/interfaces/mod.rs deleted file mode 100644 index a75dcf4..0000000 --- a/src/interfaces/mod.rs +++ /dev/null @@ -1,10 +0,0 @@ -//! # Interfaces -//! -//! Interfaces used by the coordinator library - -pub mod bid; -pub mod clientchain; -pub mod request; -pub mod response; -pub mod service; -pub mod storage; diff --git a/src/interfaces/request.rs b/src/interfaces/request.rs deleted file mode 100644 index 76b959f..0000000 --- a/src/interfaces/request.rs +++ /dev/null @@ -1,49 +0,0 @@ -//! # Request -//! -//! Service request models for client requests - -use bitcoin::hashes::sha256d; - -use ocean_rpc::json::GetRequestsResult; -use serde::Serialize; - -/// Request struct storing info on client request and modelling data that need -/// to be stored -#[derive(Debug, PartialEq, Clone, Serialize)] -pub struct Request { - /// Ocean transaction ID of the request transaction - pub txid: sha256d::Hash, - /// Request start block height - pub start_blockheight: u32, - /// Request end block height - pub end_blockheight: u32, - /// Genesis blockhash of client issuing request - pub genesis_blockhash: sha256d::Hash, - /// Fee percentage for Guardnodes set by client - pub fee_percentage: u32, - /// Num of Guardnode tickets set by client - pub num_tickets: u32, - /// Request client chain start block height - pub start_blockheight_clientchain: u32, - /// Request client chain end block height - pub end_blockheight_clientchain: u32, - /// Payment complete flag for request - pub is_payment_complete: bool, -} - -impl Request { - /// Return an instance of Request from an ocean json rpc GetRequestsResult - pub fn from_json(res: &GetRequestsResult) -> Self { - Request { - txid: res.txid, - start_blockheight: res.start_block_height, - end_blockheight: res.end_block_height, - genesis_blockhash: res.genesis_block, - fee_percentage: res.fee_percentage, - num_tickets: res.num_tickets, - start_blockheight_clientchain: 0, - end_blockheight_clientchain: 0, - is_payment_complete: false, - } - } -} diff --git a/src/interfaces/response.rs b/src/interfaces/response.rs deleted file mode 100644 index f031694..0000000 --- a/src/interfaces/response.rs +++ /dev/null @@ -1,39 +0,0 @@ -//! # Response -//! -//! Response model for service challenge responses - -use std::collections::HashMap; - -use crate::challenger::ChallengeResponseIds; -use bitcoin::hashes::sha256d; -use serde::Serialize; - -/// Response struct that models responses to service challenges -/// by keeping track of the total number of challengers and the -/// number of challenges that each bid owner responded to -#[derive(Debug, Serialize, PartialEq)] -pub struct Response { - /// Total number of challenges - pub num_challenges: u32, - /// Number of responses per bid txid - pub bid_responses: HashMap, -} - -impl Response { - /// Create new Response instance - pub fn new() -> Response { - Response { - num_challenges: 0, - bid_responses: HashMap::new(), - } - } - - /// Update Response struct from challenge response ids - pub fn update(&mut self, responses: &ChallengeResponseIds) { - self.num_challenges += 1; - for txid in responses.iter() { - let bid_entry = self.bid_responses.entry(*txid).or_insert(0); - *bid_entry += 1; - } - } -} diff --git a/src/interfaces/storage.rs b/src/interfaces/storage.rs deleted file mode 100644 index 7602b2e..0000000 --- a/src/interfaces/storage.rs +++ /dev/null @@ -1,318 +0,0 @@ -//! Storage -//! -//! Storage interface and implementations - -use std::mem::drop; -use std::sync::{Mutex, MutexGuard}; - -use bitcoin::hashes::sha256d; -use mongodb::db::{Database, ThreadedDatabase}; -use mongodb::{coll::options::FindOptions, Client, ThreadedClient}; -use util::doc_format::*; - -use crate::challenger::{ChallengeResponseIds, ChallengeState}; -use crate::config::StorageConfig; -use crate::error::{Error::MongoDb, Result}; -use crate::interfaces::response::Response; -use crate::interfaces::{ - bid::{Bid, BidSet}, - request::Request, -}; - -/// Storage trait defining required functionality for objects that store request -/// and challenge information -pub trait Storage { - /// Store the state of a challenge request - fn save_challenge_state(&self, challenge: &ChallengeState) -> Result<()>; - /// Update request in storage - fn update_request(&self, request: &Request) -> Result<()>; - /// Update bid in storage - fn update_bid(&self, request_hash: sha256d::Hash, bid: &Bid) -> Result<()>; - /// Store response for a specific challenge request - fn save_response(&self, request_hash: sha256d::Hash, ids: &ChallengeResponseIds) -> Result<()>; - /// Get challenge response for a specific request - fn get_response(&self, request_hash: sha256d::Hash) -> Result>; - /// Get all bids for a specific request - fn get_bids(&self, request_hash: sha256d::Hash) -> Result; - /// Get all the requests, with an optional flag to return payment complete - /// only - fn get_requests(&self, complete: Option) -> Result>; - /// Get request for a specific request txid - fn get_request(&self, request_hash: sha256d::Hash) -> Result>; -} - -/// Database implementation of Storage trait -pub struct MongoStorage { - db: Mutex, - config: StorageConfig, -} - -impl MongoStorage { - /// Create DbStorage instance - pub fn new(storage_config: StorageConfig) -> Result { - let uri = &format!("mongodb://{}/{}", storage_config.host, storage_config.name); - let client = Client::with_uri(&uri)?; - - let db = client.db("coordinator"); - if let Some(ref user) = storage_config.user { - if let Some(ref pass) = storage_config.pass { - db.auth(user, pass)?; - } - } - - // Specify collections Indexes - if let Err(e) = db.collection("Request").create_index(doc! ("txid":1), None) { - return Err(MongoDb(e)); - } - if let Err(e) = db.collection("Bid").create_index(doc! ("request_id":1), None) { - return Err(MongoDb(e)); - } - if let Err(e) = db.collection("Response").create_index(doc! ("request_id":1), None) { - return Err(MongoDb(e)); - } - - Ok(MongoStorage { - db: Mutex::new(db), - config: storage_config, - }) - } - - /// Do db authentication using user/pass from config - fn auth(&self, db_locked: &MutexGuard) -> Result<()> { - match db_locked.list_collections(None) { - // only do authentication if connectivity check fails - Err(_) => { - if let Some(ref user) = self.config.user { - if let Some(ref pass) = self.config.pass { - db_locked.auth(user, pass)?; - } - } - } - _ => (), - } - Ok(()) - } -} - -impl Storage for MongoStorage { - /// Store the state of a challenge request - fn save_challenge_state(&self, challenge: &ChallengeState) -> Result<()> { - let db_locked = self.db.lock().unwrap(); - self.auth(&db_locked)?; - - let request_id; - let coll = db_locked.collection("Request"); - let filter = doc! {"txid"=>challenge.request.txid.to_string()}; - match coll.find_one(Some(filter), None)? { - Some(res) => { - request_id = res.get("_id").unwrap().clone(); - } - None => { - request_id = coll - .insert_one(request_to_doc(&challenge.request), None)? - .inserted_id - .unwrap(); - } - } - - let coll = db_locked.collection("Bid"); - for bid in challenge.bids.iter() { - let doc = bid_to_doc(&request_id, bid); - match coll.find_one(Some(doc.clone()), None)? { - Some(_) => (), - None => { - let _ = coll.insert_one(doc, None)?; - } - } - } - Ok(()) - } - - /// Update entry in Request collection with given Request object - fn update_request(&self, request: &Request) -> Result<()> { - let db_locked = self.db.lock().unwrap(); - self.auth(&db_locked)?; - let coll = db_locked.collection("Request"); - let filter = doc! {"txid"=>&request.txid.clone().to_string()}; - let update = doc! {"$set" => request_to_doc(&request)}; - let _ = coll.update_one(filter, update, None)?; - Ok(()) - } - - /// Update entry in Bid collection with given Bid object - fn update_bid(&self, request_hash: sha256d::Hash, bid: &Bid) -> Result<()> { - let db_locked = self.db.lock().unwrap(); - self.auth(&db_locked)?; - - let request_id = db_locked - .collection("Request") - .find_one( - Some(doc! { - "txid": request_hash.to_string(), - }), - None, - )? - .unwrap() - .get("_id") - .unwrap() - .clone(); - - let coll = db_locked.collection("Bid"); - let filter = doc! {"request_id": request_id.clone()}; - let update = doc! {"$set" => bid_to_doc(&request_id, &bid)}; - let _ = coll.update_one(filter, update, None)?; - Ok(()) - } - - /// Store response for a specific challenge request - fn save_response(&self, request_hash: sha256d::Hash, ids: &ChallengeResponseIds) -> Result<()> { - let db_locked = self.db.lock().unwrap(); - self.auth(&db_locked)?; - - let request_id = db_locked - .collection("Request") - .find_one( - Some(doc! { - "txid": request_hash.to_string(), - }), - None, - )? - .unwrap() - .get("_id") - .unwrap() - .clone(); - - let coll = db_locked.collection("Response"); - let filter = doc! {"request_id": request_id.clone()}; - match coll.find_one(Some(filter.clone()), None)? { - Some(res) => { - let mut resp = doc_to_response(&res); - resp.update(ids); - let update = doc! {"$set" => response_to_doc(&request_id, &resp)}; - let _ = coll.update_one(filter, update, None)?; - } - None => { - let mut resp = Response::new(); - resp.update(ids); - let _ = coll.insert_one(response_to_doc(&request_id, &resp), None)?; - } - } - Ok(()) - } - - /// Get challenge response for a specific request - fn get_response(&self, request_hash: sha256d::Hash) -> Result> { - let db_locked = self.db.lock().unwrap(); - self.auth(&db_locked)?; - - let mut resp_aggr = db_locked.collection("Request").aggregate( - [ - doc! { - "$lookup": { - "from": "Response", - "localField": "_id", - "foreignField": "request_id", - "as": "response" - } - }, - doc! { - "$match": { - "txid": request_hash.to_string() - }, - }, - doc! { - "$unwind": { - "path": "$response" - } - }, - ] - .to_vec(), - None, - )?; - drop(db_locked); // drop immediately on get requests - - if let Some(resp) = resp_aggr.next() { - return Ok(Some(doc_to_response(&resp?.get_document("response").unwrap()))); - } - Ok(None) - } - - /// Get all bids for a specific request - fn get_bids(&self, request_hash: sha256d::Hash) -> Result { - let db_locked = self.db.lock().unwrap(); - self.auth(&db_locked)?; - - let mut resp_aggr = db_locked.collection("Request").aggregate( - [ - doc! { - "$lookup": { - "from": "Bid", - "localField": "_id", - "foreignField": "request_id", - "as": "bids" - } - }, - doc! { - "$match": { - "txid": request_hash.to_string() - }, - }, - ] - .to_vec(), - None, - )?; - drop(db_locked); // drop immediately on get requests - - let mut all_bids = BidSet::new(); - if let Some(resp) = resp_aggr.next() { - for bid in resp?.get_array("bids").unwrap().iter() { - let _ = all_bids.insert(doc_to_bid(bid.as_document().unwrap())); - } - } - Ok(all_bids) - } - - /// Get all the requests, with an optional flag to return payment complete - /// only - fn get_requests(&self, complete: Option) -> Result> { - let db_locked = self.db.lock().unwrap(); - self.auth(&db_locked)?; - - let mut options = FindOptions::new(); - options.sort = Some(doc! { "_id" : 1 }); // sort ascending, latest request is last - let filter = if let Some(is_complete) = complete { - Some(doc! { "is_payment_complete": is_complete }) - } else { - None - }; - let resps = db_locked.collection("Request").find(filter, Some(options))?; - drop(db_locked); // drop immediately on get requests - - let mut requests = vec![]; - for resp in resps { - if let Ok(req) = resp { - requests.push(doc_to_request(&req)) - } - } - Ok(requests) - } - - /// Get request for a specific request txid - fn get_request(&self, request_hash: sha256d::Hash) -> Result> { - let db_locked = self.db.lock().unwrap(); - self.auth(&db_locked)?; - - let request = db_locked.collection("Request").find_one( - Some(doc! { - "txid": request_hash.to_string(), - }), - None, - )?; - drop(db_locked); // drop immediately on get requests - - match request { - Some(doc) => Ok(Some(doc_to_request(&doc))), - None => Ok(None), - } - } -} diff --git a/src/lib.rs b/src/lib.rs index 34c7106..d6812fa 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -1,6 +1,6 @@ //! # Coordinator Library //! -//! Core functionality of the coordinator library +//! Basic functionality required by Coordinator daemon // Coding conventions #![deny(non_upper_case_globals)] @@ -20,11 +20,13 @@ extern crate log; extern crate base64; extern crate bitcoin; +extern crate bitcoin_hashes; extern crate config as config_rs; extern crate futures; extern crate hyper; extern crate ocean_rpc; -extern crate rust_ocean as ocean; +extern crate rust_ocean as _ocean; +extern crate secp256k1; extern crate serde as serde; extern crate serde_json; #[macro_use] @@ -33,11 +35,17 @@ extern crate jsonrpc_http_server; pub mod api; pub mod challenger; +pub mod clientchain; pub mod config; pub mod coordinator; pub mod error; pub mod listener; -pub mod payments; - -pub mod interfaces; -pub mod util; +pub mod ocean; +pub mod request; +pub mod service; +pub mod storage; +/// utilities +pub mod util { + pub mod checks; + pub mod testing; +} diff --git a/src/listener.rs b/src/listener.rs index 6352e59..0cc59c1 100644 --- a/src/listener.rs +++ b/src/listener.rs @@ -9,18 +9,18 @@ use std::sync::{Arc, Mutex}; use std::thread; use bitcoin::consensus::serialize; -use bitcoin::hashes::{hex::FromHex, sha256d}; -use bitcoin::secp256k1::{Message, PublicKey, Secp256k1, Signature}; +use bitcoin_hashes::{hex::FromHex, sha256d}; use futures::future; use futures::sync::oneshot; use hyper::rt::{self, Future, Stream}; use hyper::service::service_fn; use hyper::{Body, Method, Request, Response, Server, StatusCode}; +use secp256k1::{Message, PublicKey, Secp256k1, Signature}; use serde_json::{self, Value}; use crate::challenger::{ChallengeResponse, ChallengeState}; use crate::error::Result; -use crate::interfaces::bid::Bid; +use crate::request::Bid; /// Messsage type for challenge proofs sent by guardnodes #[derive(Debug)] @@ -43,11 +43,7 @@ impl ChallengeProof { Ok(ChallengeProof { hash, sig, - bid: Bid { - txid, - pubkey, - payment: None, - }, + bid: Bid { txid, pubkey }, }) } @@ -181,8 +177,8 @@ mod tests { use std::sync::mpsc::{channel, Receiver, TryRecvError}; - use bitcoin::hashes::hex::ToHex; - use bitcoin::secp256k1::SecretKey; + use bitcoin_hashes::hex::ToHex; + use secp256k1::SecretKey; use crate::util::testing::{gen_challenge_state_with_challenge, gen_dummy_hash}; @@ -208,7 +204,7 @@ mod tests { "sig": "304402201742daea5ec3b7306b9164be862fc1659cc830032180b8b17beffe02645860d602201039eba402d22e630308e6af05da8dd4f05b51b7d672ca5fc9e3b0a57776365c" }"#; let proof = ChallengeProof::from_json(serde_json::from_str::(data).unwrap()); - assert!(proof.err().unwrap().to_string().contains("bitcoin hashes hex error")); + assert!(proof.err().unwrap().to_string().contains("bitcoin hashes error")); // bad pubkey let data = r#" @@ -230,7 +226,7 @@ mod tests { "sig": "304402201742daea5ec3b7306b9164be862fc1659cc830032180b8b17beffe02645860d602201039eba402d22e630308e6af05da8dd4f05b51b7d672ca5fc9e3b0a57776365c" }"#; let proof = ChallengeProof::from_json(serde_json::from_str::(data).unwrap()); - assert!(proof.err().unwrap().to_string().contains("bitcoin hashes hex error")); + assert!(proof.err().unwrap().to_string().contains("bitcoin hashes error")); // bad sig let data = r#" @@ -262,7 +258,6 @@ mod tests { bid: Bid { txid: bid_txid, pubkey: bid_pubkey, - payment: None, }, }; @@ -279,7 +274,6 @@ mod tests { bid: Bid { txid: bid_txid, pubkey: bid_pubkey, - payment: None, }, }; @@ -420,7 +414,6 @@ mod tests { Bid { txid: bid_txid, pubkey: bid_pubkey, - payment: None }, )) ); // check receiver not empty @@ -669,7 +662,6 @@ mod tests { Bid { txid: bid_txid, pubkey: bid_pubkey, - payment: None }, )) ); // check receiver not empty diff --git a/src/main.rs b/src/main.rs new file mode 100644 index 0000000..3bc2708 --- /dev/null +++ b/src/main.rs @@ -0,0 +1,29 @@ +//! # Main +//! +//! Main daemon entry + +#[macro_use] +extern crate log; +extern crate coordinator; +extern crate env_logger; + +use std::env; +use std::process; + +fn main() { + // Fetch config which is set from default values in config + // and any values overriden by the corresponding env variable + let config = coordinator::config::Config::new().unwrap(); + + // To see results set RUST_LOG to one of the following: + // info, warning, debug, error, coordinator(for all) + env::set_var("RUST_LOG", &config.log_level); + env::set_var("RUST_BACKTRACE", "1"); + // Init env logger with value set from config + env_logger::init(); + + if let Err(e) = coordinator::coordinator::run(config) { + error!("daemon failure: {}", e); + process::exit(1); + } +} diff --git a/src/util/ocean.rs b/src/ocean.rs similarity index 69% rename from src/util/ocean.rs rename to src/ocean.rs index c9d38aa..fad8aae 100644 --- a/src/util/ocean.rs +++ b/src/ocean.rs @@ -2,7 +2,7 @@ //! //! Ocean node communication implementations -use ocean_rpc::{Auth, Client, RpcApi}; +use ocean_rpc::{Client, RpcApi}; use crate::error::Result; @@ -15,23 +15,17 @@ pub struct OceanClient { impl OceanClient { /// Create an OceanClient with underlying rpc client connectivity pub fn new(url: String, user: Option, pass: Option) -> Result { - let mut auth = Auth::None; - if let Some(ref _user) = user { - if let Some(ref _pass) = pass { - auth = Auth::UserPass(_user.clone(), _pass.clone()); - } - } Ok(OceanClient { - client: Client::new(format!("http://{}", url), auth)?, + client: Client::new(format!("http://{}", url), user, pass), }) } } /// Interval between retry attempts of rpc client -pub const OCEAN_CLIENT_RETRY_INTERVAL: u64 = 10; +pub const CLIENT_INTERVAL: u64 = 10; /// Number of retry attemps for rpc client calls -pub const OCEAN_CLIENT_RETRY_ATTEMPTS: u8 = 5; +pub const CLIENT_RETRY_ATTEMPTS: u8 = 5; impl RpcApi for OceanClient { fn call serde::de::Deserialize<'b>>( @@ -39,12 +33,12 @@ impl RpcApi for OceanClient { cmd: &str, args: &[serde_json::Value], ) -> ocean_rpc::Result { - for _ in 0..OCEAN_CLIENT_RETRY_ATTEMPTS { + for _ in 0..CLIENT_RETRY_ATTEMPTS { match self.client.call(cmd, args) { Ok(ret) => return Ok(ret), Err(ocean_rpc::Error::JsonRpc(e)) => { warn!("rpc error: {}, retrying...", e); - ::std::thread::sleep(::std::time::Duration::from_millis(OCEAN_CLIENT_RETRY_INTERVAL)); + ::std::thread::sleep(::std::time::Duration::from_millis(CLIENT_INTERVAL)); continue; } Err(e) => return Err(e), diff --git a/src/payments.rs b/src/payments.rs deleted file mode 100644 index 7d9ba3e..0000000 --- a/src/payments.rs +++ /dev/null @@ -1,278 +0,0 @@ -//! Payments -//! -//! TODO: Add description - -use std::str::FromStr; -use std::sync::mpsc::{Receiver, RecvError}; -use std::sync::Arc; -use std::thread; - -use bitcoin::hashes::sha256d; -use bitcoin::Amount; -use bitcoin::PublicKey; -use ocean::{Address, AddressParams}; -use ocean_rpc::RpcApi; - -use crate::config::ClientChainConfig; -use crate::error::{CError, Error, Result}; -use crate::interfaces::{ - bid::{Bid, BidPayment}, - request::Request, - response::Response, - storage::Storage, -}; -use crate::util::ocean::OceanClient; - -/// Get addr params from chain name -pub fn get_chain_addr_params(chain: &String) -> &'static AddressParams { - match chain.to_lowercase().as_ref() { - "ocean_main" => return &AddressParams::OCEAN, - "gold_main" => return &AddressParams::GOLD, - _ => &AddressParams::ELEMENTS, - } -} - -/// Function that calculates all the fees accumulated in the duration of a -/// service request in the clientchain -fn calculate_fees(request: &Request, client: &OceanClient) -> Result { - let mut fee_sum = Amount::ZERO; - for i in request.start_blockheight_clientchain..request.end_blockheight_clientchain { - let block = client.get_block_info(&client.get_block_hash(i.into())?)?; - let tx = client.get_raw_transaction_verbose(&block.tx[0], None)?; // coinbase tx - assert!(tx.is_coinbase() == true); - for txout in tx.vout { - match txout.assetlabel { - Some(label) => { - // any other label is a policy asset - if label == "CBT" { - fee_sum += txout.value; - } - } - None => fee_sum += txout.value, - } - } - } - Ok(fee_sum) -} - -/// Function that calculates the fee amount to be received per bid given total -/// fees, fee percentage and bid number -fn calculate_bid_payment(fees_amount: &Amount, fee_percentage: u64, num_bids: u64) -> Result { - let total_amount = *fees_amount * fee_percentage / 100; - Ok(total_amount / num_bids) // amount per bid -} - -/// Payment Struct holding data and logic required to pay bids at the end of the -/// service request -pub struct Payments { - /// Thread safe storage instance - pub storage: Arc, - /// Client config required for fee payments - pub config: ClientChainConfig, - /// Ocean rpc connectivity to client chain - pub client: OceanClient, - /// Clientchain address params required for fee payments - pub addr_params: &'static AddressParams, -} - -impl Payments { - /// TODO: implement payments - fn complete_bid_payments(&self, _bids: &mut Vec) -> Result<()> { - // pay - // set bid txid - Ok(()) - } - - /// Process bid payments method handles calculating the payment to be - /// received per bid and on which address, and updates the corresponding - /// payment info in Storage - fn process_bid_payments(&self, bids: &mut Vec, bid_payment: &Amount, response: &Response) -> Result<()> { - for bid in bids { - if let Some(bid_resp) = response.bid_responses.get(&bid.txid) { - // correct bid payment by calculating the performance - // base on successful responses / total responses - let bid_payment_corrected = *bid_payment * (*bid_resp).into() / response.num_challenges.into(); - let bid_pay_to_addr = Address::p2pkh( - &PublicKey { - key: bid.pubkey, - compressed: true, - }, - None, - self.addr_params, - ); - - bid.payment = Some(BidPayment { - amount: bid_payment_corrected, - address: bid_pay_to_addr, - txid: None, - }); - } - } - Ok(()) - } - - /// Method that handles payments for a single request, fetching bid - /// information, calculating fees, updating payment information and doing - /// payments - fn do_request_payment(&self, request: &mut Request) -> Result<()> { - // skip requests that have not finished - if request.end_blockheight_clientchain == 0 - || (self.client.get_block_count()? as u32) < request.end_blockheight_clientchain - { - warn! {"Skipping unfinished request: {}", request.txid}; - } - - // fetch bids and responses - let bids_set = self.storage.get_bids(request.txid)?; - if bids_set.len() > 0 { - let mut bids: Vec = bids_set.iter().map(|val| val.clone()).collect(); - if let Some(resp) = self.storage.get_response(request.txid)? { - let fees_amount = calculate_fees(request, &self.client)?; - info! {"Total fees: {}", fees_amount}; - let bid_payment_amount = - calculate_bid_payment(&fees_amount, request.fee_percentage.into(), bids.len() as u64)?; - self.process_bid_payments(&mut bids, &bid_payment_amount, &resp)?; - self.complete_bid_payments(&mut bids)?; - } - - // update bids with payment information - for bid in bids { - self.storage.update_bid(request.txid, &bid)?; - } - } - - // update request with payment complete - request.is_payment_complete = true; - self.storage.update_request(request)?; - Ok(()) - } - - /// Main Request payments method; first checks for any incomplete requests - /// and then listens for new requests on the receiver channel - fn do_request_payments(&self, req_recv: Receiver) -> Result<()> { - // Look for incomplete requests - let incomplete_requests = self.storage.get_requests(Some(false))?; - for mut req in incomplete_requests { - info! {"Found incomplete request: {} ", req.txid}; - let _ = self.do_request_payment(&mut req)?; - } - - // Wait for new requests - loop { - match req_recv.recv() { - Ok(resp) => { - let mut req = self.storage.get_request(resp)?.unwrap(); - info! {"New request: {}", req.txid}; - let _ = self.do_request_payment(&mut req)?; - } - Err(RecvError) => { - return Err(Error::from(CError::ReceiverDisconnected)); - } - } - } - } - - /// Return new Payments instance that requires clientchain config for - /// various payment info and rpc calls to calculate payment fees and do the - /// payments as well as a thread-safe reference to a Storage instance for - /// getting request information and updating payment details - pub fn new(clientchain_config: ClientChainConfig, storage: Arc) -> Result { - let client = OceanClient::new( - clientchain_config.host.clone(), - Some(clientchain_config.user.clone()), - Some(clientchain_config.pass.clone()), - )?; - - // Check if payment addr/key are set and import the key for payment funds - let addr_params = get_chain_addr_params(&clientchain_config.chain); - if let Some(addr) = &clientchain_config.payment_addr { - let ocean_addr = Address::from_str(&addr)?; - if *ocean_addr.params != *addr_params { - warn!("payment addr and chain config addr param mismatch"); - } else if let Some(key) = &clientchain_config.payment_key { - let addr_unspent = client.list_unspent(None, None, Some(&[ocean_addr]), None, None)?; - if addr_unspent.len() == 0 { - client.import_priv_key(key, None, Some(true))?; - } - } else { - warn!("payment key missing"); - } - } else { - warn!("payment addr missing"); - } - - Ok(Payments { - storage: storage, - config: clientchain_config, - client: client, - addr_params: addr_params, - }) - } -} - -/// Run payments daemon in a separate thread with a Payments instance receiving -/// information on finished requests via a Receiver channel -pub fn run_payments( - clientchain_config: ClientChainConfig, - storage: Arc, - req_recv: Receiver, -) -> Result> { - let payments = Payments::new(clientchain_config, storage)?; - Ok(thread::spawn(move || { - if let Err(err) = payments.do_request_payments(req_recv) { - error! {"payments error: {}", err}; - } - })) -} - -#[cfg(test)] -mod tests { - use super::*; - - #[test] - fn calculate_bid_payment_test() { - assert_eq!( - 1.125, - calculate_bid_payment(&Amount::from_btc(6.0).unwrap(), 75, 4) - .unwrap() - .as_btc() - ); - assert_eq!( - 0.24, - calculate_bid_payment(&Amount::from_btc(4.0).unwrap(), 30, 5) - .unwrap() - .as_btc() - ); - assert_eq!( - 1.0, - calculate_bid_payment(&Amount::from_btc(100.0).unwrap(), 1, 1) - .unwrap() - .as_btc() - ); - assert_eq!( - 0.0, - calculate_bid_payment(&Amount::from_btc(0.0).unwrap(), 1, 1) - .unwrap() - .as_btc() - ); - assert_eq!( - 0.0, - calculate_bid_payment(&Amount::from_btc(4.0).unwrap(), 0, 5) - .unwrap() - .as_btc() - ); - } - - #[test] - fn get_chain_addr_params_test() { - assert_eq!( - &AddressParams::OCEAN, - get_chain_addr_params(&String::from("ocean_main")) - ); - assert_eq!(&AddressParams::GOLD, get_chain_addr_params(&String::from("gold_main"))); - assert_eq!( - &AddressParams::ELEMENTS, - get_chain_addr_params(&String::from("supersilverhazechain")) - ); - } -} diff --git a/src/interfaces/bid.rs b/src/request.rs similarity index 52% rename from src/interfaces/bid.rs rename to src/request.rs index 0af7328..316900a 100644 --- a/src/interfaces/bid.rs +++ b/src/request.rs @@ -1,14 +1,46 @@ -//! # Bid +//! # Request //! -//! Service request models for bids and bid payments +//! Service request models for client requests and bids use std::collections::HashSet; -use bitcoin::{hashes::sha256d, secp256k1::PublicKey, Amount}; -use ocean::Address; -use ocean_rpc::json::GetRequestBidsResultBid; +use bitcoin_hashes::sha256d; +use ocean_rpc::json::{GetRequestBidsResultBid, GetRequestsResult}; +use secp256k1::key::PublicKey; use serde::{Serialize, Serializer}; +/// Request struct storing info on client request and modelling data that need +/// to be stored +#[derive(Debug, PartialEq, Clone, Serialize)] +pub struct Request { + /// Ocean transaction ID of the request transaction + pub txid: sha256d::Hash, + /// Request start block height + pub start_blockheight: u32, + /// Request end block height + pub end_blockheight: u32, + /// Genesis blockhash of client issuing request + pub genesis_blockhash: sha256d::Hash, + /// Fee percentage for Guardnodes set by client + pub fee_percentage: u32, + /// Num of Guardnode tickets set by client + pub num_tickets: u32, +} + +impl Request { + /// Return an instance of Request from an ocean json rpc GetRequestsResult + pub fn from_json(res: &GetRequestsResult) -> Self { + Request { + txid: res.txid, + start_blockheight: res.start_block_height, + end_blockheight: res.end_block_height, + genesis_blockhash: res.genesis_block, + fee_percentage: res.fee_percentage, + num_tickets: res.num_tickets, + } + } +} + /// Bid struct storing successful bids and modelling data that need to be stored #[derive(Clone, Debug, PartialEq, Hash, Eq, Serialize)] pub struct Bid { @@ -17,8 +49,6 @@ pub struct Bid { /// Bid owner verification public key #[serde(serialize_with = "serialize_pubkey")] pub pubkey: PublicKey, - /// Bid payment optional - pub payment: Option, } impl Bid { @@ -26,25 +56,11 @@ impl Bid { pub fn from_json(res: &GetRequestBidsResultBid) -> Self { Bid { txid: res.txid, - pubkey: res.fee_pub_key.key, - payment: None, + pubkey: res.fee_pub_key, } } } -/// Bid payment struct holding information for fee payments received by bid -/// owners -#[derive(Clone, Debug, PartialEq, Hash, Eq, Serialize)] -pub struct BidPayment { - /// Bid payment transaction id; optional as might not be set yet - pub txid: Option, - /// Bid pay to address - pub address: Address, - /// Bid amount expected - #[serde(with = "bitcoin::util::amount::serde::as_btc")] - pub amount: Amount, -} - /// Type defining a set of Bids pub type BidSet = HashSet; @@ -63,7 +79,7 @@ mod tests { use std::str::FromStr; - use bitcoin::hashes::hex::FromHex; + use bitcoin_hashes::hex::FromHex; #[test] fn serialize_pubkey_test() { @@ -72,12 +88,11 @@ mod tests { let bid = Bid { txid: sha256d::Hash::from_hex(txid_hex).unwrap(), pubkey: PublicKey::from_str(pubkey_hex).unwrap(), - payment: None, }; let serialized = serde_json::to_string(&bid); assert_eq!( - format!(r#"{{"txid":"{}","pubkey":"{}","payment":null}}"#, txid_hex, pubkey_hex), + format!(r#"{{"txid":"{}","pubkey":"{}"}}"#, txid_hex, pubkey_hex), serialized.unwrap() ); } diff --git a/src/interfaces/service.rs b/src/service.rs similarity index 95% rename from src/interfaces/service.rs rename to src/service.rs index 6cffe87..bb31319 100644 --- a/src/interfaces/service.rs +++ b/src/service.rs @@ -2,16 +2,13 @@ //! //! Service chain interface and implementations -use bitcoin::hashes::sha256d; +use bitcoin_hashes::sha256d; use ocean_rpc::RpcApi; use crate::config::ServiceConfig; use crate::error::Result; -use crate::interfaces::{ - bid::{Bid, BidSet}, - request::Request, -}; -use crate::util::ocean::OceanClient; +use crate::ocean::OceanClient; +use crate::request::{Bid, BidSet, Request}; /// Service trait defining functionality for interfacing with service chain pub trait Service { diff --git a/src/storage.rs b/src/storage.rs new file mode 100644 index 0000000..88fe94e --- /dev/null +++ b/src/storage.rs @@ -0,0 +1,395 @@ +//! Storage +//! +//! Storage interface and implementations + +use std::mem::drop; +use std::str::FromStr; +use std::sync::{Mutex, MutexGuard}; + +use bitcoin_hashes::{hex::FromHex, sha256d}; +use mongodb::db::{Database, ThreadedDatabase}; +use mongodb::ordered::OrderedDocument; +use mongodb::{coll::options::FindOptions, Bson, Client, ThreadedClient}; +use secp256k1::key::PublicKey; + +use crate::challenger::{ChallengeResponseIds, ChallengeState}; +use crate::config::StorageConfig; +use crate::error::Result; +use crate::request::{Bid, BidSet, Request}; + +/// Storage trait defining required functionality for objects that store request +/// and challenge information +pub trait Storage { + /// Store the state of a challenge request + fn save_challenge_state(&self, challenge: &ChallengeState) -> Result<()>; + /// Store responses for a specific challenge request + fn save_response(&self, request_hash: sha256d::Hash, ids: &ChallengeResponseIds) -> Result<()>; + /// Get all challenge responses for a specific request + fn get_responses(&self, request_hash: sha256d::Hash) -> Result>; + /// Get all bids for a specific request + fn get_bids(&self, request_hash: sha256d::Hash) -> Result; + /// Get all the requests + fn get_requests(&self) -> Result>; + /// Get request for a specific request txid + fn get_request(&self, request_hash: sha256d::Hash) -> Result>; +} + +/// Database implementation of Storage trait +pub struct MongoStorage { + db: Mutex, + config: StorageConfig, +} + +impl MongoStorage { + /// Create DbStorage instance + pub fn new(storage_config: StorageConfig) -> Result { + let uri = &format!("mongodb://{}/{}", storage_config.host, storage_config.name); + let client = Client::with_uri(&uri)?; + + let db = client.db("coordinator"); + if let Some(ref user) = storage_config.user { + if let Some(ref pass) = storage_config.pass { + db.auth(user, pass)?; + } + } + + Ok(MongoStorage { + db: Mutex::new(db), + config: storage_config, + }) + } + + /// Do db authentication using user/pass from config + fn auth(&self, db_locked: &MutexGuard) -> Result<()> { + match db_locked.list_collections(None) { + // only do authentication if connectivity check fails + Err(_) => { + if let Some(ref user) = self.config.user { + if let Some(ref pass) = self.config.pass { + db_locked.auth(user, pass)?; + } + } + } + _ => (), + } + Ok(()) + } +} + +impl Storage for MongoStorage { + /// Store the state of a challenge request + fn save_challenge_state(&self, challenge: &ChallengeState) -> Result<()> { + let db_locked = self.db.lock().unwrap(); + self.auth(&db_locked)?; + + let request_id; + let coll = db_locked.collection("Request"); + let doc = request_to_doc(&challenge.request); + match coll.find_one(Some(doc.clone()), None)? { + Some(res) => request_id = res.get("_id").unwrap().clone(), + None => { + request_id = coll.insert_one(doc, None)?.inserted_id.unwrap(); + } + } + + let coll = db_locked.collection("Bid"); + for bid in challenge.bids.iter() { + let doc = bid_to_doc(&request_id, bid); + match coll.find_one(Some(doc.clone()), None)? { + Some(_) => (), + None => { + let _ = coll.insert_one(doc, None)?; + } + } + } + Ok(()) + } + + /// Store responses for a specific challenge request + fn save_response(&self, request_hash: sha256d::Hash, ids: &ChallengeResponseIds) -> Result<()> { + let db_locked = self.db.lock().unwrap(); + self.auth(&db_locked)?; + + let request = db_locked + .collection("Request") + .find_one( + Some(doc! { + "txid": request_hash.to_string(), + }), + None, + )? + .unwrap(); + + let _ = db_locked + .collection("Response") + .insert_one(challenge_responses_to_doc(request.get("_id").unwrap(), ids), None)?; + Ok(()) + } + + /// Get all challenge responses for a specific request + fn get_responses(&self, request_hash: sha256d::Hash) -> Result> { + let db_locked = self.db.lock().unwrap(); + self.auth(&db_locked)?; + + let mut resp_aggr = db_locked.collection("Request").aggregate( + [ + doc! { + "$lookup": { + "from": "Response", + "localField": "_id", + "foreignField": "request_id", + "as": "challenges" + } + }, + doc! { + "$match": { + "txid": request_hash.to_string() + }, + }, + ] + .to_vec(), + None, + )?; + drop(db_locked); // drop immediately on get requests + + let mut all_resps: Vec = Vec::new(); + if let Some(resp) = resp_aggr.next() { + for challenge in resp?.get_array("challenges").unwrap().iter() { + all_resps.push(doc_to_challenge_responses(challenge.as_document().unwrap())) + } + } + Ok(all_resps) + } + + /// Get all bids for a specific request + fn get_bids(&self, request_hash: sha256d::Hash) -> Result { + let db_locked = self.db.lock().unwrap(); + self.auth(&db_locked)?; + + let mut resp_aggr = db_locked.collection("Request").aggregate( + [ + doc! { + "$lookup": { + "from": "Bid", + "localField": "_id", + "foreignField": "request_id", + "as": "bids" + } + }, + doc! { + "$match": { + "txid": request_hash.to_string() + }, + }, + ] + .to_vec(), + None, + )?; + drop(db_locked); // drop immediately on get requests + + let mut all_bids = BidSet::new(); + if let Some(resp) = resp_aggr.next() { + for bid in resp?.get_array("bids").unwrap().iter() { + let _ = all_bids.insert(doc_to_bid(bid.as_document().unwrap())); + } + } + Ok(all_bids) + } + + /// Get all the requests + fn get_requests(&self) -> Result> { + let db_locked = self.db.lock().unwrap(); + self.auth(&db_locked)?; + + let mut options = FindOptions::new(); + options.sort = Some(doc! { "_id" : 1 }); // sort ascending, latest request is last + let resps = db_locked.collection("Request").find(None, Some(options))?; + drop(db_locked); // drop immediately on get requests + + let mut requests = vec![]; + for resp in resps { + if let Ok(req) = resp { + requests.push(doc_to_request(&req)) + } + } + Ok(requests) + } + + /// Get request for a specific request txid + fn get_request(&self, request_hash: sha256d::Hash) -> Result> { + let db_locked = self.db.lock().unwrap(); + self.auth(&db_locked)?; + + let request = db_locked.collection("Request").find_one( + Some(doc! { + "txid": request_hash.to_string(), + }), + None, + )?; + drop(db_locked); // drop immediately on get requests + + match request { + Some(doc) => Ok(Some(doc_to_request(&doc))), + None => Ok(None), + } + } +} + +/// Util method that generates a Request document from a request +pub fn request_to_doc(request: &Request) -> OrderedDocument { + doc! { + "txid": request.txid.to_string(), + "start_blockheight": request.start_blockheight, + "end_blockheight": request.end_blockheight, + "genesis_blockhash": request.genesis_blockhash.to_string(), + "fee_percentage": request.fee_percentage, + "num_tickets": request.num_tickets + } +} + +/// Util method that generates a request from a Request document +pub fn doc_to_request(doc: &OrderedDocument) -> Request { + Request { + txid: sha256d::Hash::from_hex(doc.get("txid").unwrap().as_str().unwrap()).unwrap(), + start_blockheight: doc.get("start_blockheight").unwrap().as_i32().unwrap() as u32, + end_blockheight: doc.get("end_blockheight").unwrap().as_i32().unwrap() as u32, + genesis_blockhash: sha256d::Hash::from_hex(doc.get("genesis_blockhash").unwrap().as_str().unwrap()).unwrap(), + fee_percentage: doc.get("fee_percentage").unwrap().as_i32().unwrap() as u32, + num_tickets: doc.get("num_tickets").unwrap().as_i32().unwrap() as u32, + } +} + +/// Util method that generates a Bid document from a request bid +pub fn bid_to_doc(request_id: &Bson, bid: &Bid) -> OrderedDocument { + doc! { + "request_id": request_id.clone(), + "txid": bid.txid.to_string(), + "pubkey": bid.pubkey.to_string() + } +} + +/// Util method that generates a request bid from a Bid document +pub fn doc_to_bid(doc: &OrderedDocument) -> Bid { + Bid { + txid: sha256d::Hash::from_hex(doc.get("txid").unwrap().as_str().unwrap()).unwrap(), + pubkey: PublicKey::from_str(doc.get("pubkey").unwrap().as_str().unwrap()).unwrap(), + } +} + +/// Util method that generates a Response document from challenge responses +pub fn challenge_responses_to_doc(request_id: &Bson, responses: &ChallengeResponseIds) -> OrderedDocument { + let bids = responses + .iter() + .map(|x| Bson::String(x.to_string())) + .collect::>(); + doc! { + "request_id": request_id.clone(), + "bid_txids": bids + } +} + +/// Util method that generates challenge responses from a Response document +pub fn doc_to_challenge_responses(doc: &OrderedDocument) -> ChallengeResponseIds { + doc.get_array("bid_txids") + .unwrap() + .iter() + .map(|x| sha256d::Hash::from_hex(x.as_str().unwrap()).unwrap()) + .collect() +} + +#[cfg(test)] +mod tests { + use super::*; + + use mongodb::oid::ObjectId; + + use crate::util::testing::gen_dummy_hash; + + #[test] + fn request_doc_test() { + let request_hash = gen_dummy_hash(9); + let genesis_hash = "1100000000000000000000000000000000000000000000000000000000000022"; + let request = Request { + txid: request_hash, + start_blockheight: 2, + end_blockheight: 5, + genesis_blockhash: sha256d::Hash::from_hex(genesis_hash).unwrap(), + fee_percentage: 5, + num_tickets: 10, + }; + + let doc = request_to_doc(&request); + assert_eq!( + doc! { + "txid": request_hash.to_string(), + "start_blockheight": 2, + "end_blockheight": 5, + "genesis_blockhash": genesis_hash, + "fee_percentage": 5, + "num_tickets": 10 + }, + doc + ); + assert_eq!(request, doc_to_request(&doc)); + } + + #[test] + fn bid_doc_test() { + let id = ObjectId::new().unwrap(); + let pubkey_hex = "026a04ab98d9e4774ad806e302dddeb63bea16b5cb5f223ee77478e861bb583eb3"; + let hash = gen_dummy_hash(1); + let bid = Bid { + txid: hash, + pubkey: PublicKey::from_str(pubkey_hex).unwrap(), + }; + + let doc = bid_to_doc(&Bson::ObjectId(id.clone()), &bid); + assert_eq!( + doc! { + "request_id": id.clone(), + "txid": hash.to_string(), + "pubkey": pubkey_hex + }, + doc + ); + assert_eq!(bid, doc_to_bid(&doc)); + } + + #[test] + fn challenge_responses_doc_test() { + let id = ObjectId::new().unwrap(); + let mut ids = ChallengeResponseIds::new(); + + let doc = challenge_responses_to_doc(&Bson::ObjectId(id.clone()), &ids); + assert_eq!( + doc! { + "request_id": id.clone(), + "bid_txids": [] + }, + doc + ); + assert_eq!(ids, doc_to_challenge_responses(&doc)); + + let _ = ids.insert(gen_dummy_hash(0)); + let doc = challenge_responses_to_doc(&Bson::ObjectId(id.clone()), &ids); + assert_eq!( + doc! { + "request_id": id.clone(), + "bid_txids": [gen_dummy_hash(0).to_string()] + }, + doc + ); + assert_eq!(ids, doc_to_challenge_responses(&doc)); + + let _ = ids.insert(gen_dummy_hash(1)); + let _ = ids.insert(gen_dummy_hash(2)); + let _ = ids.insert(gen_dummy_hash(3)); + let doc = challenge_responses_to_doc(&Bson::ObjectId(id.clone()), &ids); + assert_eq!(&id, doc.get("request_id").unwrap().as_object_id().unwrap()); + for id in doc.get_array("bid_txids").unwrap().iter() { + assert!(ids.contains(&sha256d::Hash::from_hex(id.as_str().unwrap()).unwrap())); + } + assert_eq!(4, doc.get_array("bid_txids").unwrap().len()); + assert_eq!(ids, doc_to_challenge_responses(&doc)); + } +} diff --git a/src/util/checks.rs b/src/util/checks.rs index 56edeb0..8dfd270 100644 --- a/src/util/checks.rs +++ b/src/util/checks.rs @@ -9,7 +9,6 @@ fn is_base58_char(char: &char) -> bool { _ => false, } } - /// Check for correct priv key input string format pub fn check_privkey_string(str: &String) -> bool { if str.len() == 52 && str.chars().all(|x| is_base58_char(&x)) { @@ -17,7 +16,6 @@ pub fn check_privkey_string(str: &String) -> bool { } return false; } - /// Check for correct hash input string format pub fn check_hash_string(str: &String) -> bool { if str.len() == 64 && str.chars().all(|x| x.is_ascii_hexdigit()) { diff --git a/src/util/doc_format.rs b/src/util/doc_format.rs deleted file mode 100644 index f346934..0000000 --- a/src/util/doc_format.rs +++ /dev/null @@ -1,285 +0,0 @@ -//! doc_format -//! -//! doc format is used to store items in the db. -//! File contains methods to convert to/from document format. - -use std::collections::HashMap; -use std::str::FromStr; - -use bitcoin::hashes::{hex::FromHex, sha256d}; -use bitcoin::secp256k1::PublicKey; -use bitcoin::Amount; -use mongodb::{ordered::OrderedDocument, Bson}; -use ocean::Address; - -use crate::interfaces::response::Response; -use crate::interfaces::{ - bid::{Bid, BidPayment}, - request::Request, -}; - -/// Util method that generates a Request document from a request -pub fn request_to_doc(request: &Request) -> OrderedDocument { - doc! { - "txid": request.txid.to_string(), - "start_blockheight": request.start_blockheight, - "end_blockheight": request.end_blockheight, - "genesis_blockhash": request.genesis_blockhash.to_string(), - "fee_percentage": request.fee_percentage, - "num_tickets": request.num_tickets, - "start_blockheight_clientchain": request.start_blockheight_clientchain, - "end_blockheight_clientchain": request.end_blockheight_clientchain, - "is_payment_complete": request.is_payment_complete, - } -} - -/// Util method that generates a request from a Request document -pub fn doc_to_request(doc: &OrderedDocument) -> Request { - Request { - txid: sha256d::Hash::from_hex(doc.get("txid").unwrap().as_str().unwrap()).unwrap(), - start_blockheight: doc.get("start_blockheight").unwrap().as_i32().unwrap() as u32, - end_blockheight: doc.get("end_blockheight").unwrap().as_i32().unwrap() as u32, - genesis_blockhash: sha256d::Hash::from_hex(doc.get("genesis_blockhash").unwrap().as_str().unwrap()).unwrap(), - fee_percentage: doc.get("fee_percentage").unwrap().as_i32().unwrap() as u32, - num_tickets: doc.get("num_tickets").unwrap().as_i32().unwrap() as u32, - start_blockheight_clientchain: doc.get("start_blockheight_clientchain").unwrap().as_i32().unwrap() as u32, - end_blockheight_clientchain: doc.get("end_blockheight_clientchain").unwrap().as_i32().unwrap() as u32, - is_payment_complete: doc.get("is_payment_complete").unwrap().as_bool().unwrap(), - } -} - -/// Util method that generates a Bid document from a request bid -pub fn bid_to_doc(request_id: &Bson, bid: &Bid) -> OrderedDocument { - let mut bid_doc = doc! { - "request_id": request_id.clone(), - "txid": bid.txid.to_string(), - "pubkey": bid.pubkey.to_string(), - }; - if let Some(payment) = &bid.payment { - let mut bid_payment_doc = doc! { - "address": payment.address.to_string(), - "amount": payment.amount.as_btc(), - }; - if let Some(txid) = payment.txid { - let _ = bid_payment_doc.insert("txid", txid.to_string()); - } - let _ = bid_doc.insert("payment", bid_payment_doc); - } - bid_doc -} - -/// Util method that generates a request bid from a Bid document -pub fn doc_to_bid(doc: &OrderedDocument) -> Bid { - let mut payment: Option = None; - if let Some(doc_payment) = doc.get("payment") { - let doc_doc_payment = doc_payment.as_document().unwrap(); - let mut payment_txid: Option = None; - if let Some(doc_payment_txid) = doc_doc_payment.get("txid") { - payment_txid = Some(sha256d::Hash::from_hex(doc_payment_txid.as_str().unwrap()).unwrap()) - } - payment = Some(BidPayment { - txid: payment_txid, - address: Address::from_str(doc_doc_payment.get("address").unwrap().as_str().unwrap()).unwrap(), - amount: Amount::from_btc(doc_doc_payment.get("amount").unwrap().as_f64().unwrap()).unwrap(), - }); - } - Bid { - txid: sha256d::Hash::from_hex(doc.get("txid").unwrap().as_str().unwrap()).unwrap(), - pubkey: PublicKey::from_str(doc.get("pubkey").unwrap().as_str().unwrap()).unwrap(), - payment: payment, - } -} - -/// Util method that generates a Response document from request response -pub fn response_to_doc(request_id: &Bson, response: &Response) -> OrderedDocument { - let bid_resps_doc: OrderedDocument = response - .bid_responses - .iter() - .map(|(key, val)| (key.to_string(), Bson::I32(*val as i32))) - .collect(); - doc! { - "request_id": request_id.clone(), - "num_challenges": response.num_challenges, - "bid_responses": bid_resps_doc - } -} - -/// Util method that generates request response from a Response document -pub fn doc_to_response(doc: &OrderedDocument) -> Response { - let bid_resps: HashMap = doc - .get("bid_responses") - .unwrap() - .as_document() - .unwrap() - .iter() - .map(|(key, val)| { - ( - sha256d::Hash::from_hex(key.as_str()).unwrap(), - val.as_i32().unwrap() as u32, - ) - }) - .collect(); - Response { - num_challenges: doc.get("num_challenges").unwrap().as_i32().unwrap() as u32, - bid_responses: bid_resps, - } -} - -#[cfg(test)] -mod tests { - use super::*; - - use mongodb::oid::ObjectId; - - use crate::challenger::ChallengeResponseIds; - use crate::util::testing::gen_dummy_hash; - - #[test] - fn request_doc_test() { - let request_hash = gen_dummy_hash(9); - let genesis_hash = "1100000000000000000000000000000000000000000000000000000000000022"; - let request = Request { - txid: request_hash, - start_blockheight: 2, - end_blockheight: 5, - genesis_blockhash: sha256d::Hash::from_hex(genesis_hash).unwrap(), - fee_percentage: 5, - num_tickets: 10, - start_blockheight_clientchain: 0, - end_blockheight_clientchain: 0, - is_payment_complete: false, - }; - - let doc = request_to_doc(&request); - assert_eq!( - doc! { - "txid": request_hash.to_string(), - "start_blockheight": 2, - "end_blockheight": 5, - "genesis_blockhash": genesis_hash, - "fee_percentage": 5, - "num_tickets": 10, - "start_blockheight_clientchain":0, - "end_blockheight_clientchain":0, - "is_payment_complete": false, - }, - doc - ); - assert_eq!(request, doc_to_request(&doc)); - } - - #[test] - fn bid_doc_test() { - let id = ObjectId::new().unwrap(); - let pubkey_hex = "026a04ab98d9e4774ad806e302dddeb63bea16b5cb5f223ee77478e861bb583eb3"; - let hash = gen_dummy_hash(1); - let mut bid = Bid { - txid: hash, - pubkey: PublicKey::from_str(pubkey_hex).unwrap(), - payment: None, - }; - - let doc = bid_to_doc(&Bson::ObjectId(id.clone()), &bid); - assert_eq!( - doc! { - "request_id": id.clone(), - "txid": hash.to_string(), - "pubkey": pubkey_hex - }, - doc - ); - assert_eq!(bid, doc_to_bid(&doc)); - - let addr = "1HXfr2qBwT4qGZYn8FczNy68rw5dwG8trc"; - let amount = 56.123; - let mut bid_payment = BidPayment { - txid: None, - address: Address::from_str(addr).unwrap(), - amount: Amount::from_btc(amount).unwrap(), - }; - bid.payment = Some(bid_payment.clone()); - let doc = bid_to_doc(&Bson::ObjectId(id.clone()), &bid); - assert_eq!( - doc! { - "request_id": id.clone(), - "txid": hash.to_string(), - "pubkey": pubkey_hex, - "payment": doc!{ - "address": addr, - "amount": amount - } - }, - doc - ); - assert_eq!(bid, doc_to_bid(&doc)); - - let payment_txid = gen_dummy_hash(123); - bid_payment.txid = Some(payment_txid); - bid.payment = Some(bid_payment.clone()); - let doc = bid_to_doc(&Bson::ObjectId(id.clone()), &bid); - assert_eq!( - doc! { - "request_id": id.clone(), - "txid": hash.to_string(), - "pubkey": pubkey_hex, - "payment": doc!{ - "address": addr, - "amount": amount, - "txid": payment_txid.to_string() - } - }, - doc - ); - assert_eq!(bid, doc_to_bid(&doc)); - } - - #[test] - fn response_doc_test() { - let id = ObjectId::new().unwrap(); - let mut ids = ChallengeResponseIds::new(); - let mut resp = Response::new(); - - let doc = response_to_doc(&Bson::ObjectId(id.clone()), &resp); - assert_eq!( - doc! { - "request_id": id.clone(), - "num_challenges": 0, - "bid_responses": doc! {} - }, - doc - ); - assert_eq!(resp, doc_to_response(&doc)); - - let hash0 = gen_dummy_hash(0); - let _ = ids.insert(hash0); - resp.update(&ids); - let doc = response_to_doc(&Bson::ObjectId(id.clone()), &resp); - assert_eq!( - doc! { - "request_id": id.clone(), - "num_challenges": 1, - "bid_responses": doc! { gen_dummy_hash(0).to_string(): 1 } - }, - doc - ); - assert_eq!(resp, doc_to_response(&doc)); - - let _ = ids.insert(gen_dummy_hash(1)); - let _ = ids.insert(gen_dummy_hash(2)); - let _ = ids.insert(gen_dummy_hash(3)); - resp.update(&ids); - let doc = response_to_doc(&Bson::ObjectId(id.clone()), &resp); - assert_eq!(&id, doc.get("request_id").unwrap().as_object_id().unwrap()); - assert_eq!(2, doc.get("num_challenges").unwrap().as_i32().unwrap()); - for (key, val) in doc.get_document("bid_responses").unwrap().iter() { - if sha256d::Hash::from_hex(key.as_str()).unwrap() == hash0 { - assert_eq!(2, val.as_i32().unwrap()); - } else { - assert_eq!(1, val.as_i32().unwrap()); - } - assert!(ids.contains(&sha256d::Hash::from_hex(key.as_str()).unwrap())); - } - assert_eq!(4, doc.get_document("bid_responses").unwrap().len()); - assert_eq!(resp, doc_to_response(&doc)); - } -} diff --git a/src/util/mod.rs b/src/util/mod.rs deleted file mode 100644 index 0d18852..0000000 --- a/src/util/mod.rs +++ /dev/null @@ -1,8 +0,0 @@ -//! # Util -//! -//! Util functionality required by the coordinator library - -pub mod checks; -pub mod doc_format; -pub mod ocean; -pub mod testing; diff --git a/src/util/testing.rs b/src/util/testing.rs index 77c059c..9597a80 100644 --- a/src/util/testing.rs +++ b/src/util/testing.rs @@ -2,23 +2,18 @@ //! //! Colleciton of helper functions used in tests module -use bitcoin::hashes::{hex::FromHex, sha256d, Hash}; -use bitcoin::secp256k1::PublicKey; +use bitcoin_hashes::{hex::FromHex, sha256d, Hash}; use mongodb::ordered::OrderedDocument; use mongodb::Bson; +use secp256k1::PublicKey; use std::cell::RefCell; use std::str::FromStr; -use util::doc_format::*; use crate::challenger::{ChallengeResponseIds, ChallengeState}; -use crate::interfaces::clientchain::ClientChain; -use crate::interfaces::response::Response; -use crate::interfaces::service::Service; -use crate::interfaces::storage::*; -use crate::interfaces::{ - bid::{Bid, BidSet}, - request::Request as ServiceRequest, -}; +use crate::clientchain::ClientChain; +use crate::request::{Bid, BidSet, Request as ServiceRequest}; +use crate::service::Service; +use crate::storage::*; use crate::error::*; @@ -36,15 +31,11 @@ pub fn gen_challenge_state(request_hash: &sha256d::Hash) -> ChallengeState { genesis_blockhash: gen_dummy_hash(0), fee_percentage: 5, num_tickets: 10, - start_blockheight_clientchain: 0, - end_blockheight_clientchain: 0, - is_payment_complete: false, }; let mut bids = BidSet::new(); let _ = bids.insert(Bid { txid: sha256d::Hash::from_hex("1234567890000000000000000000000000000000000000000000000000000000").unwrap(), pubkey: PublicKey::from_str("026a04ab98d9e4774ad806e302dddeb63bea16b5cb5f223ee77478e861bb583eb3").unwrap(), - payment: None, }); ChallengeState { request, @@ -65,16 +56,12 @@ pub fn gen_challenge_state_with_challenge( genesis_blockhash: *request_hash, fee_percentage: 5, num_tickets: 10, - start_blockheight_clientchain: 0, - end_blockheight_clientchain: 0, - is_payment_complete: false, }; let mut bids = BidSet::new(); let _ = bids.insert(Bid { txid: sha256d::Hash::from_hex("1234567890000000000000000000000000000000000000000000000000000000").unwrap(), // pubkey corresponding to SecretKey::from_slice(&[0xaa; 32]) pubkey: PublicKey::from_str("026a04ab98d9e4774ad806e302dddeb63bea16b5cb5f223ee77478e861bb583eb3").unwrap(), - payment: None, }); ChallengeState { request, @@ -92,7 +79,7 @@ pub struct MockClientChain { /// bool pub return_false: bool, /// Mock client chain blockheight - pub height: RefCell, + pub height: RefCell, } impl MockClientChain { @@ -126,11 +113,6 @@ impl ClientChain for MockClientChain { } Ok(true) } - - /// Get block count dummy - fn get_blockheight(&self) -> Result { - Ok(self.height.clone().into_inner()) - } } /// Mock implementation of Service using some mock logic for testing @@ -142,7 +124,7 @@ pub struct MockService { /// Option pub return_none: bool, /// Current active request - pub request: RefCell, + pub request: ServiceRequest, /// Mock service chain blockheight - incremented by default on /// get_blockheight pub height: RefCell, @@ -161,15 +143,12 @@ impl MockService { .unwrap(), fee_percentage: 5, num_tickets: 10, - start_blockheight_clientchain: 0, - end_blockheight_clientchain: 0, - is_payment_complete: false, }; MockService { return_err: false, return_none: false, - request: RefCell::new(request), + request, height: RefCell::new(0), } } @@ -190,9 +169,9 @@ impl Service for MockService { return Err(Error::from(CError::Generic("get_request failed".to_owned()))); } - let mut dummy_req = self.request.borrow_mut(); + let mut dummy_req = self.request.clone(); dummy_req.genesis_blockhash = *hash; - Ok(Some(dummy_req.clone())) + Ok(Some(dummy_req)) } /// Try get active request bids, by transaction hash, from service chain @@ -208,19 +187,16 @@ impl Service for MockService { txid: sha256d::Hash::from_hex("1234567890000000000000000000000000000000000000000000000000000000").unwrap(), // pubkey corresponding to SecretKey::from_slice(&[0xaa; 32]) pubkey: PublicKey::from_str("026a04ab98d9e4774ad806e302dddeb63bea16b5cb5f223ee77478e861bb583eb3").unwrap(), - payment: None, }); let _ = bid_set.insert(Bid { txid: sha256d::Hash::from_hex("0000000001234567890000000000000000000000000000000000000000000000").unwrap(), // pubkey corresponding to SecretKey::from_slice(&[0xbb; 32]) pubkey: PublicKey::from_str("0268680737c76dabb801cb2204f57dbe4e4579e4f710cd67dc1b4227592c81e9b5").unwrap(), - payment: None, }); let _ = bid_set.insert(Bid { txid: sha256d::Hash::from_hex("0000000000000000001234567890000000000000000000000000000000000000").unwrap(), // pubkey corresponding to SecretKey::from_slice(&[0xcc; 32]) pubkey: PublicKey::from_str("02b95c249d84f417e3e395a127425428b540671cc15881eb828c17b722a53fc599").unwrap(), - payment: None, }); Ok(Some(bid_set)) } @@ -269,15 +245,7 @@ impl Storage for MockStorage { if self.return_err { return Err(Error::from(CError::Generic("save_challenge_state failed".to_owned()))); } - // do not add request if already exists - if !self - .requests - .borrow_mut() - .iter() - .any(|request| request.get("txid").unwrap().as_str().unwrap() == &challenge.request.txid.to_string()) - { - self.requests.borrow_mut().push(request_to_doc(&challenge.request)); - } + self.requests.borrow_mut().push(request_to_doc(&challenge.request)); for bid in challenge.bids.iter() { self.bids .borrow_mut() @@ -286,52 +254,26 @@ impl Storage for MockStorage { Ok(()) } - /// update request in mock storage - fn update_request(&self, request_update: &ServiceRequest) -> Result<()> { - for request in self.requests.borrow_mut().iter_mut() { - if request.get("txid").unwrap().as_str().unwrap() == &request_update.txid.to_string() { - *request = request_to_doc(&request_update); - } - } - Ok(()) - } - - /// update bid in mock storage - fn update_bid(&self, _request_hash: sha256d::Hash, _bid: &Bid) -> Result<()> { - Ok(()) - } - - /// Store response for a specific challenge request + /// Store responses for a specific challenge request fn save_response(&self, request_hash: sha256d::Hash, ids: &ChallengeResponseIds) -> Result<()> { if self.return_err { return Err(Error::from(CError::Generic("save_response failed".to_owned()))); } - - for resp_doc in self.challenge_responses.borrow_mut().iter_mut() { - if resp_doc.get("request_id").unwrap().as_str().unwrap() == &request_hash.to_string() { - let mut resp = doc_to_response(resp_doc); - resp.update(&ids); - *resp_doc = response_to_doc(&Bson::String(request_hash.to_string()), &resp); - return Ok(()); - } - } - - let mut resp = Response::new(); - resp.update(&ids); self.challenge_responses .borrow_mut() - .push(response_to_doc(&Bson::String(request_hash.to_string()), &resp)); + .push(challenge_responses_to_doc(&Bson::String(request_hash.to_string()), ids)); Ok(()) } - /// Get challenge response for a specific request - fn get_response(&self, request_hash: sha256d::Hash) -> Result> { + /// Get all challenge responses for a specific request + fn get_responses(&self, request_hash: sha256d::Hash) -> Result> { + let mut challenge_responses = vec![]; for doc in self.challenge_responses.borrow().to_vec().iter() { if doc.get("request_id").unwrap().as_str().unwrap() == request_hash.to_string() { - return Ok(Some(doc_to_response(doc))); + challenge_responses.push(doc_to_challenge_responses(doc)); } } - Ok(None) + Ok(challenge_responses) } /// Get all bids for a specific request @@ -345,9 +287,8 @@ impl Storage for MockStorage { Ok(bids) } - /// Get all the requests, with an optional flag to return payment complete - /// only - fn get_requests(&self, _complete: Option) -> Result> { + /// Get all the requests + fn get_requests(&self) -> Result> { let mut requests = vec![]; for doc in self.requests.borrow().to_vec().iter() { requests.push(doc_to_request(doc))