diff --git a/.github/workflows/yarn-lint.yml b/.github/workflows/yarn.yml similarity index 79% rename from .github/workflows/yarn-lint.yml rename to .github/workflows/yarn.yml index 7d481a4480..50949480b4 100644 --- a/.github/workflows/yarn-lint.yml +++ b/.github/workflows/yarn.yml @@ -1,6 +1,6 @@ on: [push, pull_request] -name: yarn-lint +name: yarn jobs: lint: @@ -14,3 +14,5 @@ jobs: run: yarn - working-directory: ./test run: yarn lint + - working-directory: ./test + run: yarn test-mock diff --git a/Cargo.lock b/Cargo.lock index b156e752fc..8e640e8f69 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -6,6 +6,38 @@ version = "1.0.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "7e522997b529f05601e05166c07ed17789691f562762c7f3b987263d2dedee5c" +[[package]] +name = "aes" +version = "0.3.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "54eb1d8fe354e5fc611daf4f2ea97dd45a765f4f1e4512306ec183ae2e8f20c9" +dependencies = [ + "aes-soft", + "aesni", + "block-cipher-trait", +] + +[[package]] +name = "aes-soft" +version = "0.3.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cfd7e7ae3f9a1fb5c03b389fc6bb9a51400d0c13053f0dca698c832bfd893a0d" +dependencies = [ + "block-cipher-trait", + "byteorder", + "opaque-debug", +] + +[[package]] +name = "aesni" +version = "0.6.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2f70a6b5f971e473091ab7cfb5ffac6cde81666c4556751d8d5620ead8abf100" +dependencies = [ + "block-cipher-trait", + "opaque-debug", +] + [[package]] name = "aho-corasick" version = "0.6.4" @@ -30,7 +62,7 @@ version = "0.11.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ee49baf6cb617b853aa8d93bf420db2383fab46d314482ca2803b40d5fde979b" dependencies = [ - "winapi 0.3.6", + "winapi 0.3.9", ] [[package]] @@ -62,7 +94,7 @@ checksum = "2fc4a1aa4c24c0718a250f0681885c1af91419d242f29eb8f2ab28502d80dbd1" dependencies = [ "libc", "termion", - "winapi 0.3.6", + "winapi 0.3.9", ] [[package]] @@ -81,7 +113,7 @@ dependencies = [ "cfg-if", "libc", "rustc-demangle", - "winapi 0.3.6", + "winapi 0.3.9", ] [[package]] @@ -112,9 +144,9 @@ checksum = "1955ebdd52d5c5f1fb4f94e97aa241c2ce5729d200b3c34fc71ac6ff7a7cc556" [[package]] name = "bitflags" -version = "1.0.3" +version = "1.2.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d0c54bb8f454c567f21197eefcdbf5679d0bd99f2ddbe52e84c77061952e6789" +checksum = "cf1de2fe8c75bc145a2f577add951f8134889b4795d47466a54a5c846d691693" [[package]] name = "bitstring" @@ -122,6 +154,18 @@ version = "0.1.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "3e54f7b7a46d7b183eb41e2d82965261fa8a1597c68b50aced268ee1fc70272d" +[[package]] +name = "blake2" +version = "0.8.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "94cb07b0da6a73955f8fb85d24c466778e70cda767a568229b104f0264089330" +dependencies = [ + "byte-tools", + "crypto-mac", + "digest", + "opaque-debug", +] + [[package]] name = "block-buffer" version = "0.7.3" @@ -134,6 +178,25 @@ dependencies = [ "generic-array", ] +[[package]] +name = "block-cipher-trait" +version = "0.6.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1c924d49bd09e7c06003acda26cd9742e796e34282ec6c1189404dee0c1f4774" +dependencies = [ + "generic-array", +] + +[[package]] +name = "block-modes" +version = "0.3.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "31aa8410095e39fdb732909fb5730a48d5bd7c2e3cd76bd1b07b3dbea130c529" +dependencies = [ + "block-cipher-trait", + "block-padding", +] + [[package]] name = "block-padding" version = "0.1.4" @@ -239,6 +302,15 @@ dependencies = [ "bitflags", ] +[[package]] +name = "cloudabi" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4344512281c643ae7638bbabc3af17a11307803ec8f0fcad9fae512a8bf36467" +dependencies = [ + "bitflags", +] + [[package]] name = "cmake" version = "0.1.35" @@ -279,8 +351,9 @@ dependencies = [ "log 0.4.6", "never-type", "panic_hook", - "parking_lot 0.6.4", + "parking_lot 0.11.0", "primitives", + "rlp", "rpassword", "rustc-serialize", "serde", @@ -319,7 +392,7 @@ dependencies = [ "lru-cache", "merkle-trie", "num-rational", - "parking_lot 0.6.4", + "parking_lot 0.11.0", "primitives", "rand 0.6.1", "rand_xorshift", @@ -332,19 +405,29 @@ dependencies = [ [[package]] name = "codechain-crypto" -version = "0.1.0" -source = "git+https://github.com/CodeChain-io/rust-codechain-crypto.git#2857470de2f5480b7d61ff57fb652f9d9fc5585b" +version = "0.2.0" +source = "git+https://github.com/CodeChain-io/rust-codechain-crypto.git#565c1eebf3abc909ed297bee584dddb84784d838" dependencies = [ + "aes", + "blake2", + "block-modes", + "ctr", + "digest", + "hex", "primitives", "quick-error", "ring", - "rust-crypto", + "ripemd160", + "scrypt", + "sha-1", + "sha2", + "sha3", ] [[package]] name = "codechain-db" -version = "0.1.0" -source = "git+https://github.com/CodeChain-io/rust-codechain-db.git#9948464d24f3432f70fcb12df97c81ec8eab7bfa" +version = "0.2.0" +source = "git+https://github.com/CodeChain-io/rust-codechain-db.git#08bd8ceeb360a1e17e011b4dcb084333ddda5cab" dependencies = [ "codechain-crypto", "kvdb", @@ -365,7 +448,7 @@ dependencies = [ "lazy_static 1.2.0", "log 0.4.6", "never-type", - "parking_lot 0.6.4", + "parking_lot 0.11.0", "primitives", "rand 0.6.1", "rlp", @@ -380,7 +463,7 @@ dependencies = [ "crossbeam", "log 0.4.6", "mio", - "parking_lot 0.6.4", + "parking_lot 0.11.0", ] [[package]] @@ -403,7 +486,7 @@ dependencies = [ "codechain-crypto", "lazy_static 1.2.0", "never-type", - "parking_lot 0.6.4", + "parking_lot 0.11.0", "primitives", "rand 0.6.1", "rand_xorshift", @@ -427,7 +510,7 @@ dependencies = [ "libc", "log 0.4.6", "matches", - "parking_lot 0.6.4", + "parking_lot 0.11.0", "primitives", "rand 0.6.1", "rustc-hex 1.0.0", @@ -448,7 +531,7 @@ dependencies = [ "env_logger 0.6.0", "lazy_static 1.2.0", "log 0.4.6", - "parking_lot 0.6.4", + "parking_lot 0.11.0", "sendgrid", "serde", "serde_derive", @@ -473,7 +556,7 @@ dependencies = [ "log 0.4.6", "mio", "never-type", - "parking_lot 0.6.4", + "parking_lot 0.11.0", "primitives", "rand 0.6.1", "rlp", @@ -508,7 +591,7 @@ dependencies = [ "kvdb-rocksdb", "lazy_static 1.2.0", "log 0.4.6", - "parking_lot 0.6.4", + "parking_lot 0.11.0", "primitives", "rand 0.6.1", "rlp", @@ -536,7 +619,7 @@ dependencies = [ "log 0.4.6", "lru-cache", "merkle-trie", - "parking_lot 0.6.4", + "parking_lot 0.11.0", "primitives", "rlp", "rlp_derive", @@ -555,7 +638,7 @@ dependencies = [ "jsonrpc-derive", "jsonrpc-tcp-server", "log 0.4.6", - "parking_lot 0.6.4", + "parking_lot 0.11.0", "primitives", "tokio-core", "tokio-io", @@ -566,6 +649,7 @@ name = "codechain-sync" version = "0.1.0" dependencies = [ "codechain-core", + "codechain-crypto", "codechain-db", "codechain-key", "codechain-logger", @@ -578,13 +662,11 @@ dependencies = [ "log 0.4.6", "merkle-trie", "never-type", - "parking_lot 0.6.4", "primitives", "rand 0.6.1", "rlp", "snap", "tempfile", - "time", "token-generator", "trie-standardmap", ] @@ -595,7 +677,7 @@ version = "0.1.0" dependencies = [ "codechain-logger", "log 0.4.6", - "parking_lot 0.6.4", + "parking_lot 0.11.0", ] [[package]] @@ -741,6 +823,26 @@ version = "0.2.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "7a81dae078cea95a014a339291cec439d2f232ebe854a9d672b796c6afafa9b7" +[[package]] +name = "crypto-mac" +version = "0.7.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4434400df11d95d556bac068ddfedd482915eb18fe8bea89bc80b6e4b1c179e5" +dependencies = [ + "generic-array", + "subtle", +] + +[[package]] +name = "ctr" +version = "0.3.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "022cd691704491df67d25d006fe8eca083098253c4d43516c2206479c58c6736" +dependencies = [ + "block-cipher-trait", + "stream-cipher", +] + [[package]] name = "ctrlc" version = "1.1.1" @@ -788,7 +890,7 @@ dependencies = [ "openssl-sys", "pkg-config", "vcpkg", - "winapi 0.3.6", + "winapi 0.3.9", ] [[package]] @@ -856,15 +958,6 @@ dependencies = [ "termcolor 1.0.4", ] -[[package]] -name = "error-chain" -version = "0.12.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "07e791d3be96241c77c43846b665ef1384606da2cd2a48730abe606a12906e02" -dependencies = [ - "backtrace", -] - [[package]] name = "ethbloom" version = "0.5.0" @@ -986,7 +1079,7 @@ dependencies = [ "lazy_static 1.2.0", "libc", "libloading", - "winapi 0.3.6", + "winapi 0.3.9", ] [[package]] @@ -1075,17 +1168,6 @@ dependencies = [ "wasi", ] -[[package]] -name = "getset" -version = "0.0.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "54c7f36a235738bb25904d6a2b3dbb28f6f5736cd3918c4bf80d6bb236200782" -dependencies = [ - "proc-macro2 0.3.8", - "quote 0.5.2", - "syn 0.13.11", -] - [[package]] name = "globset" version = "0.4.1" @@ -1123,7 +1205,7 @@ version = "0.4.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "1679e6ea370dee694f91f1dc469bf94cf8f52051d147aec3e1f9497c6fc22461" dependencies = [ - "winapi 0.3.6", + "winapi 0.3.9", ] [[package]] @@ -1135,6 +1217,22 @@ dependencies = [ "libc", ] +[[package]] +name = "hex" +version = "0.4.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "644f9158b2f133fd50f5fb3242878846d9eb792e445c893805ff0e3824006e35" + +[[package]] +name = "hmac" +version = "0.7.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5dcb5e64cda4c23119ab41ba960d1e170a774c8e4b9d9e6a9bc18aabf5e59695" +dependencies = [ + "crypto-mac", + "digest", +] + [[package]] name = "http" version = "0.1.17" @@ -1248,6 +1346,12 @@ version = "1.0.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "7e81a7c05f79578dbc15793d8b619db9ba32b4577003ef3af1a91c416798c58d" +[[package]] +name = "instant" +version = "0.1.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5b141fdc7836c525d4d594027d318c84161ca17aaf8113ab1f81ab93ae897485" + [[package]] name = "interleaved-ordered" version = "0.1.1" @@ -1360,6 +1464,12 @@ dependencies = [ "ws", ] +[[package]] +name = "keccak" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "67c21572b4949434e4fc1e1978b99c5f77064153c59d998bf13ecd96fb5ecba7" + [[package]] name = "kernel32-sys" version = "0.2.2" @@ -1433,9 +1543,9 @@ checksum = "ddba4c30a78328befecec92fc94970e53b3ae385827d28620f0f5bb2493081e0" [[package]] name = "libc" -version = "0.2.62" +version = "0.2.74" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "34fcd2c08d2f832f376f4173a231990fa5aef4e99fb569867318a227ef4c06ba" +checksum = "a2f02823cf78b754822df5f7f268fb59822e7296276d3e069d8e8cb26a14bd10" [[package]] name = "libflate" @@ -1455,7 +1565,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "f2b111a074963af1d37a139918ac6d49ad1d0d5e47f72fd55388619691a7d753" dependencies = [ "cc", - "winapi 0.3.6", + "winapi 0.3.9", ] [[package]] @@ -1512,7 +1622,16 @@ version = "0.3.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "f8912e782533a93a167888781b836336a6ca5da6175c05944c86cf28c31104dc" dependencies = [ - "scopeguard 1.0.0", + "scopeguard 1.1.0", +] + +[[package]] +name = "lock_api" +version = "0.4.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "28247cc5a5be2f05fbcd76dd0cf2c7d3b5400cb978a28042abcd4fa0b3f8261c" +dependencies = [ + "scopeguard 1.1.0", ] [[package]] @@ -1562,11 +1681,12 @@ checksum = "0f9dc261e2b62d7a622bf416ea3c5245cdd5d9a7fcc428c0d06804dfce1775b3" [[package]] name = "merkle-trie" -version = "0.1.0" -source = "git+https://github.com/CodeChain-io/rust-merkle-trie.git#a6e067fe71c232d9024952ee63905ab4f5c4407d" +version = "0.4.0" +source = "git+https://github.com/CodeChain-io/rust-merkle-trie.git#c2a84172e9c212bee1a29ae2e056d3ea988115ce" dependencies = [ "codechain-crypto", "codechain-db", + "lru-cache", "primitives", "rand 0.6.1", "rlp", @@ -1644,7 +1764,7 @@ dependencies = [ "log 0.4.6", "mio", "miow 0.3.3", - "winapi 0.3.6", + "winapi 0.3.9", ] [[package]] @@ -1677,7 +1797,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "396aa0f2003d7df8395cb93e09871561ccc3e785f0acb369170e8cc74ddf9226" dependencies = [ "socket2", - "winapi 0.3.6", + "winapi 0.3.9", ] [[package]] @@ -1715,7 +1835,7 @@ checksum = "9044faf1413a1057267be51b5afba8eb1090bd2231c693664aa1db716fe1eae0" dependencies = [ "cfg-if", "libc", - "winapi 0.3.6", + "winapi 0.3.9", ] [[package]] @@ -1898,7 +2018,7 @@ dependencies = [ "tokio", "tokio-named-pipes", "tokio-uds", - "winapi 0.3.6", + "winapi 0.3.9", ] [[package]] @@ -1922,6 +2042,17 @@ dependencies = [ "rustc_version", ] +[[package]] +name = "parking_lot" +version = "0.11.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a4893845fa2ca272e647da5d0e46660a314ead9c2fdd9a883aabc32e481a8733" +dependencies = [ + "instant", + "lock_api 0.4.1", + "parking_lot_core 0.8.0", +] + [[package]] name = "parking_lot_core" version = "0.3.1" @@ -1932,7 +2063,7 @@ dependencies = [ "rand 0.5.5", "rustc_version", "smallvec 0.6.4", - "winapi 0.3.6", + "winapi 0.3.9", ] [[package]] @@ -1942,12 +2073,37 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "b876b1b9e7ac6e1a74a6da34d25c42e17e8862aa409cbbbdcfc8d86c6f3bc62b" dependencies = [ "cfg-if", - "cloudabi", + "cloudabi 0.0.3", "libc", "redox_syscall", "rustc_version", "smallvec 0.6.4", - "winapi 0.3.6", + "winapi 0.3.9", +] + +[[package]] +name = "parking_lot_core" +version = "0.8.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c361aa727dd08437f2f1447be8b59a33b0edd15e0fcee698f935613d9efbca9b" +dependencies = [ + "cfg-if", + "cloudabi 0.1.0", + "instant", + "libc", + "redox_syscall", + "smallvec 1.4.1", + "winapi 0.3.9", +] + +[[package]] +name = "pbkdf2" +version = "0.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "006c038a43a45995a9670da19e67600114740e8511d4333bf97a56e66a7542d9" +dependencies = [ + "byteorder", + "crypto-mac", ] [[package]] @@ -2025,7 +2181,7 @@ checksum = "e3cbf9f658cdb5000fcf6f362b8ea2ba154b9f146a61c7a20d647034c6b6561b" [[package]] name = "primitives" version = "0.4.0" -source = "git+https://github.com/CodeChain-io/rust-codechain-primitives.git#9dbda1bcc2b8f68c00e6426754800fb806e8117a" +source = "git+https://github.com/CodeChain-io/rust-codechain-primitives.git#eb8da500a77fa84e53750e8661a8603a78a2a7b3" dependencies = [ "ethereum-types", ] @@ -2127,7 +2283,7 @@ checksum = "8356f47b32624fef5b3301c1be97e5944ecdd595409cc5da11d05f211db6cfbd" dependencies = [ "fuchsia-zircon", "libc", - "winapi 0.3.6", + "winapi 0.3.9", ] [[package]] @@ -2136,11 +2292,11 @@ version = "0.5.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e464cd887e869cddcae8792a4ee31d23c7edd516700695608f5b98c67ee0131c" dependencies = [ - "cloudabi", + "cloudabi 0.0.3", "fuchsia-zircon", "libc", "rand_core 0.2.2", - "winapi 0.3.6", + "winapi 0.3.9", ] [[package]] @@ -2149,7 +2305,7 @@ version = "0.6.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ae9d223d52ae411a33cf7e54ec6034ec165df296ccd23533d671a28252b6f66a" dependencies = [ - "cloudabi", + "cloudabi 0.0.3", "fuchsia-zircon", "libc", "rand_chacha 0.1.0", @@ -2159,7 +2315,7 @@ dependencies = [ "rand_pcg", "rand_xorshift", "rustc_version", - "winapi 0.3.6", + "winapi 0.3.9", ] [[package]] @@ -2267,9 +2423,9 @@ dependencies = [ [[package]] name = "redox_syscall" -version = "0.1.40" +version = "0.1.57" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c214e91d3ecf43e9a4e41e578973adeb14b474f2bee858742d127af75a0112b1" +checksum = "41cc0f7e4d5d4544e8861606a285bb08d3e70712ccc7d2b84d7c0ccfaf4b05ce" [[package]] name = "redox_termios" @@ -2304,7 +2460,7 @@ version = "0.5.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "3488ba1b9a2084d38645c4c08276a1752dcbf2c7130d74f1569681ad5d2799c5" dependencies = [ - "winapi 0.3.6", + "winapi 0.3.9", ] [[package]] @@ -2345,13 +2501,24 @@ dependencies = [ "libc", "spin", "untrusted", - "winapi 0.3.6", + "winapi 0.3.9", +] + +[[package]] +name = "ripemd160" +version = "0.8.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ad5112e0dbbb87577bfbc56c42450235e3012ce336e29c5befd7807bd626da4a" +dependencies = [ + "block-buffer", + "digest", + "opaque-debug", ] [[package]] name = "rlp" version = "0.4.0" -source = "git+https://github.com/CodeChain-io/rlp.git#339cc6aa02d91635199178e7c7be07b347054697" +source = "git+https://github.com/CodeChain-io/rlp.git#64fdbc5758e05483f62fae99521520f566eaca9d" dependencies = [ "primitives", "rustc-hex 1.0.0", @@ -2369,7 +2536,7 @@ dependencies = [ [[package]] name = "rlp_derive" version = "0.2.0" -source = "git+https://github.com/CodeChain-io/rlp.git#339cc6aa02d91635199178e7c7be07b347054697" +source = "git+https://github.com/CodeChain-io/rlp.git#64fdbc5758e05483f62fae99521520f566eaca9d" dependencies = [ "proc-macro2 0.4.30", "quote 0.6.12", @@ -2458,7 +2625,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "f2f6abf258d99c3c1c5c2131d99d064e94b7b3dd5f416483057f308fea253339" dependencies = [ "lazy_static 1.2.0", - "winapi 0.3.6", + "winapi 0.3.9", ] [[package]] @@ -2475,9 +2642,22 @@ checksum = "94258f53601af11e6a49f722422f6e3425c52b06245a5cf9bc09908b174f5e27" [[package]] name = "scopeguard" -version = "1.0.0" +version = "1.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d29ab0c6d3fc0ee92fe66e2d99f700eab17a8d57d1c1d3b748380fb20baa78cd" + +[[package]] +name = "scrypt" +version = "0.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b42e15e59b18a828bbf5c58ea01debb36b9b096346de35d941dcb89009f24a0d" +checksum = "656c79d0e90d0ab28ac86bf3c3d10bfbbac91450d3f190113b4e76d9fec3cfdd" +dependencies = [ + "byte-tools", + "byteorder", + "hmac", + "pbkdf2", + "sha2", +] [[package]] name = "secp256k1" @@ -2584,9 +2764,9 @@ dependencies = [ [[package]] name = "sha-1" -version = "0.8.1" +version = "0.8.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "23962131a91661d643c98940b20fcaffe62d776a823247be80a48fcb8b6fce68" +checksum = "f7d94d0bede923b3cea61f3f1ff57ff8cdfd77b400fb8f9998949e0cf04163df" dependencies = [ "block-buffer", "digest", @@ -2594,6 +2774,31 @@ dependencies = [ "opaque-debug", ] +[[package]] +name = "sha2" +version = "0.8.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a256f46ea78a0c0d9ff00077504903ac881a1dafdc20da66545699e7776b3e69" +dependencies = [ + "block-buffer", + "digest", + "fake-simd", + "opaque-debug", +] + +[[package]] +name = "sha3" +version = "0.8.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "dd26bc0e7a2e3a7c959bc494caf58b72ee0c71d67704e9520f736ca7e4853ecf" +dependencies = [ + "block-buffer", + "byte-tools", + "digest", + "keccak", + "opaque-debug", +] + [[package]] name = "shell32-sys" version = "0.1.2" @@ -2647,6 +2852,12 @@ dependencies = [ "unreachable", ] +[[package]] +name = "smallvec" +version = "1.4.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3757cb9d89161a2f24e1cf78efa0c1fcff485d18e3f55e0aa3480824ddaa0f3f" + [[package]] name = "snap" version = "0.2.4" @@ -2666,7 +2877,7 @@ dependencies = [ "cfg-if", "libc", "redox_syscall", - "winapi 0.3.6", + "winapi 0.3.9", ] [[package]] @@ -2687,6 +2898,15 @@ version = "1.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "15132e0e364248108c5e2c02e3ab539be8d6f5d52a01ca9bbf27ed657316f02b" +[[package]] +name = "stream-cipher" +version = "0.3.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8131256a5896cabcf5eb04f4d6dacbe1aefda854b0d9896e09cb58829ec5638c" +dependencies = [ + "generic-array", +] + [[package]] name = "string" version = "0.1.3" @@ -2699,6 +2919,12 @@ version = "0.7.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "bb4f380125926a99e52bc279241539c018323fab05ad6368b56f93d9369ff550" +[[package]] +name = "subtle" +version = "1.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2d67a5a62ba6e01cb2192ff309324cb4875d0c451d55fe2319433abe7a05a8ee" + [[package]] name = "syn" version = "0.13.11" @@ -2769,7 +2995,7 @@ dependencies = [ "rand 0.7.2", "redox_syscall", "remove_dir_all", - "winapi 0.3.6", + "winapi 0.3.9", ] [[package]] @@ -2827,7 +3053,7 @@ checksum = "d825be0eb33fda1a7e68012d51e9c7f451dc1a69391e7fdc197060bb8c56667b" dependencies = [ "libc", "redox_syscall", - "winapi 0.3.6", + "winapi 0.3.9", ] [[package]] @@ -3094,8 +3320,8 @@ dependencies = [ [[package]] name = "trie-standardmap" -version = "0.2.0" -source = "git+https://github.com/CodeChain-io/trie-standardmap.git#f2cdd24acb7f00e44566d86af6102c5d16b02921" +version = "0.3.0" +source = "git+https://github.com/CodeChain-io/trie-standardmap.git#190b7a3b43adc063e0d7c5043afc1ff9d981c870" dependencies = [ "codechain-crypto", "primitives", @@ -3247,14 +3473,12 @@ dependencies = [ [[package]] name = "vergen" -version = "2.0.0" +version = "3.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9a16834fc61e1492c07dae49b6c14b55f8b1d43a5f5f9e9a2ecc063f47b9f93c" +checksum = "4ce50d8996df1f85af15f2cd8d33daae6e479575123ef4314a51a70a230739cb" dependencies = [ "bitflags", "chrono", - "error-chain", - "getset", ] [[package]] @@ -3294,9 +3518,9 @@ checksum = "167dc9d6949a9b857f3451275e911c3f44255842c1f7a76f33c55103a909087a" [[package]] name = "winapi" -version = "0.3.6" +version = "0.3.9" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "92c1eb33641e276cfa214a0522acad57be5c56b10cb348b3c5117db75f3ac4b0" +checksum = "5c839a674fcd7a98952e593242ea400abe93992746761e38641405d28b00f419" dependencies = [ "winapi-i686-pc-windows-gnu", "winapi-x86_64-pc-windows-gnu", @@ -3320,7 +3544,7 @@ version = "0.1.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "afc5508759c5bf4285e61feb862b6083c8480aec864fa17a81fdec6f69b461ab" dependencies = [ - "winapi 0.3.6", + "winapi 0.3.9", ] [[package]] @@ -3335,7 +3559,7 @@ version = "0.1.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "eeb06499a3a4d44302791052df005d5232b927ed1a9658146d842165c4de7767" dependencies = [ - "winapi 0.3.6", + "winapi 0.3.9", ] [[package]] @@ -3344,7 +3568,7 @@ version = "1.0.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "561ed901ae465d6185fa7864d63fbd5720d0ef718366c9a4dc83cf6170d7e9ba" dependencies = [ - "winapi 0.3.6", + "winapi 0.3.9", "winapi-util", ] diff --git a/Cargo.toml b/Cargo.toml index 753c49c770..36f1b480af 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -18,7 +18,7 @@ edition = "2018" app_dirs = "^1.2.1" clap = { version = "2", features = ["yaml"] } codechain-core = { path = "core" } -codechain-crypto = { git = "https://github.com/CodeChain-io/rust-codechain-crypto.git", version = "0.1" } +codechain-crypto = { git = "https://github.com/CodeChain-io/rust-codechain-crypto.git", version = "0.2" } codechain-discovery = { path = "discovery" } codechain-logger = { path = "util/logger" } codechain-key = { path = "key" } @@ -41,8 +41,9 @@ log = "0.4.6" env_logger = "0.5.3" never-type = "0.1.0" panic_hook = { path = "util/panic_hook" } -parking_lot = "0.6.0" +parking_lot = "0.11.0" primitives = { git = "https://github.com/CodeChain-io/rust-codechain-primitives.git", version = "0.4" } +rlp = { git = "https://github.com/CodeChain-io/rlp.git", version = "0.4" } rpassword = "2.0.0" rustc-serialize = "0.3" serde = "1.0" @@ -53,7 +54,7 @@ toml = "0.4" cidr = "0.0.4" [build-dependencies] -vergen = "2" +vergen = "3" [[bin]] path = "codechain/main.rs" diff --git a/build.rs b/build.rs index deadea443d..7848e973d0 100644 --- a/build.rs +++ b/build.rs @@ -14,20 +14,8 @@ // You should have received a copy of the GNU Affero General Public License // along with this program. If not, see . -extern crate vergen; - -use vergen::{ConstantsFlags, Result, Vergen}; +use vergen::{generate_cargo_keys, ConstantsFlags}; fn main() { - gen_constants().expect("Unable to generate vergen constants!"); -} - -fn gen_constants() -> Result<()> { - let vergen = Vergen::new(ConstantsFlags::all())?; - - for (k, v) in vergen.build_info() { - println!("cargo:rustc-env={}={}", k.name(), v); - } - - Ok(()) + generate_cargo_keys(ConstantsFlags::all()).expect("Unable to generate vergen constants!"); } diff --git a/codechain/auto_self_nominate.rs b/codechain/auto_self_nominate.rs new file mode 100644 index 0000000000..70c616706a --- /dev/null +++ b/codechain/auto_self_nominate.rs @@ -0,0 +1,203 @@ +// Copyright 2020 Kodebox, Inc. +// This file is part of CodeChain. +// +// This program is free software: you can redistribute it and/or modify +// it under the terms of the GNU Affero General Public License as +// published by the Free Software Foundation, either version 3 of the +// License, or (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU Affero General Public License for more details. +// +// You should have received a copy of the GNU Affero General Public License +// along with this program. If not, see . + +use crate::config::load_config; +use ccore::stake::Action::SelfNominate; +use ccore::stake::{Banned, Candidates, Jail, CUSTOM_ACTION_HANDLER_ID}; +use ccore::{ + AccountProvider, AccountProviderError, BlockId, ConsensusClient, SignedTransaction, UnverifiedTransaction, +}; +use ckey::PlatformAddress; +use ckey::{Address, Public, Signature}; +use ckeystore::DecryptedAccount; +use clap::ArgMatches; +use codechain_types::transaction::{Action, Transaction}; +use primitives::{Bytes, H256}; +use rlp::Encodable; +use std::sync::Arc; +use std::thread; +use std::time::Duration; + +const NEED_NOMINATION_UNDER_TERM_LEFT: u64 = 3; +#[derive(Clone)] +struct SelfSigner { + account_provider: Arc, + signer: Option<(Address, Public)>, + decrypted_account: Option, +} +impl SelfSigner { + pub fn new(ap: Arc, address: Address) -> Self { + let public = { + let account = ap.get_unlocked_account(&address).expect("The address must be registered in AccountProvider"); + account.public().expect("Cannot get public from account") + }; + Self { + account_provider: ap, + signer: Some((address, public)), + decrypted_account: None, + } + } + + pub fn sign_ecdsa(&self, hash: H256) -> Result { + let address = self.signer.map(|(address, _public)| address).unwrap_or_else(Default::default); + let result = match &self.decrypted_account { + Some(account) => account.sign(&hash)?, + None => { + let account = self.account_provider.get_unlocked_account(&address)?; + account.sign(&hash)? + } + }; + Ok(result) + } + + pub fn address(&self) -> Option<&Address> { + self.signer.as_ref().map(|(address, _)| address) + } +} + +pub struct AutoSelfNomination { + client: Arc, + signer: SelfSigner, +} + +impl AutoSelfNomination { + pub fn new(client: Arc, ap: Arc, address: Address) -> Arc { + Arc::new(Self { + client, + signer: SelfSigner::new(ap, address), + }) + } + + pub fn send_self_nominate_transaction(&self, matches: &ArgMatches) { + let config = load_config(matches).unwrap(); + let account_address = config.mining.engine_signer.unwrap(); + let default_metadata = config.mining.self_nomination_metadata.unwrap(); + let target_deposit = config.mining.self_target_deposit.unwrap(); + let interval = config.mining.self_nomination_interval.unwrap(); + let self_client = self.client.clone(); + let self_signer = self.signer.clone(); + thread::Builder::new() + .name("Auto Self Nomination".to_string()) + .spawn(move || loop { + AutoSelfNomination::send( + &self_client, + &self_signer, + &account_address, + &default_metadata, + target_deposit, + ); + thread::sleep(Duration::from_millis(interval)); + }) + .unwrap(); + } + + fn send( + client: &Arc, + signer: &SelfSigner, + account_address: &PlatformAddress, + metadata: &str, + targetdep: u64, + ) { + let metabytes = metadata.rlp_bytes(); + let mut dep = targetdep; + let address = account_address.address(); + let block_id = BlockId::Latest; + let state = client.state_at(block_id).unwrap(); + let current_term = client.current_term_id(block_id).unwrap(); + let banned = Banned::load_from_state(&state).unwrap(); + if banned.is_banned(address) { + cwarn!(ENGINE, "Account is banned"); + return + } + let jailed = Jail::load_from_state(&state).unwrap(); + if jailed.get_prisoner(&address).is_some() { + let prisoner = jailed.get_prisoner(&address).unwrap(); + + if prisoner.custody_until <= (current_term) { + cwarn!(ENGINE, "Account is still in custody"); + return + } + } + let candidate = Candidates::load_from_state(&state).unwrap(); + if candidate.get_candidate(&address).is_some() { + let candidate_need_nomination = candidate.get_candidate(&address).unwrap(); + if candidate_need_nomination.nomination_ends_at + NEED_NOMINATION_UNDER_TERM_LEFT <= current_term { + cdebug!( + ENGINE, + "No need self nominate. nomination_ends_at: {}, current_term: {}", + candidate_need_nomination.nomination_ends_at, + current_term + ); + return + } + if candidate_need_nomination.deposit.lt(&targetdep) { + dep = targetdep.min(targetdep); + } else { + dep = 0 as u64; + } + } + + AutoSelfNomination::self_nomination_transaction(&client, &signer, dep, metabytes); + } + + fn self_nomination_transaction( + client: &Arc, + signer: &SelfSigner, + deposit: u64, + metadata: Bytes, + ) { + let network_id = client.network_id(); + let seq = match signer.address() { + Some(address) => client.latest_seq(address), + None => { + cwarn!(ENGINE, "Signer was not assigned"); + return + } + }; + let selfnominate = SelfNominate { + deposit, + metadata, + }; + let tx = Transaction { + seq, + fee: 0, + network_id, + action: Action::Custom { + handler_id: CUSTOM_ACTION_HANDLER_ID, + bytes: selfnominate.rlp_bytes(), + }, + }; + + let signature = match signer.sign_ecdsa(*tx.hash()) { + Ok(signature) => signature, + Err(e) => { + cerror!(ENGINE, "Could not sign the message:{}", e); + return + } + }; + let unverified = UnverifiedTransaction::new(tx, signature); + let signed = SignedTransaction::try_new(unverified).expect("secret is valid so it's recoverable"); + + match client.queue_own_transaction(signed) { + Ok(_) => { + cinfo!(ENGINE, "Send self nominate transaction"); + } + Err(e) => { + cerror!(ENGINE, "Failed to queue self nominate transaction: {}", e); + } + } + } +} diff --git a/codechain/codechain.yml b/codechain/codechain.yml index 0558880d58..00a88b0a71 100644 --- a/codechain/codechain.yml +++ b/codechain/codechain.yml @@ -160,6 +160,21 @@ args: long: engine-signer help: Specify the address which should be used to sign consensus messages and issue blocks. takes_value: true + - self-nomination-metadata: + long: self-nomination-metadata + help: Specify metadata which should be used to do self nomination. + takes_value: true + - self-nomination-target-deposit: + long: self-nomination-target-deposit + help: Specify the amount of deposit need to provide deposite for candidatory in the process of self nomination. + takes_value: true + - self-nomination-interval: + long: self-nomination-interval + help: Specify the time(ms) interval for self nomination process. + takes_value: true + - enable-auto-self-nomination: + long: enable-auto-self-nomination + help: Run auto self nomination thread. - password-path: long: password-path help: Specify the password file path. diff --git a/codechain/config/mod.rs b/codechain/config/mod.rs index d126f37692..c6f0a09d0a 100644 --- a/codechain/config/mod.rs +++ b/codechain/config/mod.rs @@ -1,4 +1,4 @@ -// Copyright 2018-2019 Kodebox, Inc. +// Copyright 2018-2020 Kodebox, Inc. // This file is part of CodeChain. // // This program is free software: you can redistribute it and/or modify @@ -16,7 +16,7 @@ mod chain_type; -use ccore::{MemPoolFees, MinerOptions, StratumConfig, TimeGapParams}; +use ccore::{MemPoolMinFees, MinerOptions, StratumConfig, TimeGapParams}; use cidr::IpCidr; use ckey::PlatformAddress; use clap; @@ -74,7 +74,7 @@ impl Config { None => unreachable!(), }; - let mem_pool_fees = MemPoolFees::create_from_options( + let mem_pool_min_fees = MemPoolMinFees::create_from_options( self.mining.min_pay_transaction_cost, self.mining.min_set_regular_key_transaction_cost, self.mining.min_create_shard_transaction_cost, @@ -107,7 +107,7 @@ impl Config { reseal_max_period: Duration::from_millis(self.mining.reseal_max_period.unwrap()), no_reseal_timer: self.mining.no_reseal_timer.unwrap(), work_queue_size: self.mining.work_queue_size.unwrap(), - mem_pool_fees, + mem_pool_min_fees, }) } @@ -236,6 +236,10 @@ pub struct Mining { pub engine_signer: Option, pub mem_pool_size: Option, pub mem_pool_mem_limit: Option, + pub self_nomination_metadata: Option, + pub self_target_deposit: Option, + pub self_nomination_enable: bool, + pub self_nomination_interval: Option, pub mem_pool_fee_bump_shift: Option, pub allow_create_shard: Option, pub notify_work: Option>, @@ -411,6 +415,15 @@ impl Mining { if other.engine_signer.is_some() { self.engine_signer = other.engine_signer; } + if other.self_nomination_metadata.is_some() { + self.self_nomination_metadata = other.self_nomination_metadata.clone(); + } + if other.self_target_deposit.is_some() { + self.self_target_deposit = other.self_target_deposit; + } + if other.self_nomination_interval.is_some() { + self.self_nomination_interval = other.self_nomination_interval; + } if other.mem_pool_size.is_some() { self.mem_pool_size = other.mem_pool_size; } @@ -492,6 +505,22 @@ impl Mining { if let Some(engine_signer) = matches.value_of("engine-signer") { self.engine_signer = Some(engine_signer.parse().map_err(|_| "Invalid address format")?); } + if let Some(self_nomination_metadata) = matches.value_of("self-nomination-metadata") { + self.self_nomination_metadata = + Some(self_nomination_metadata.parse().map_err(|_| "Invalid self nomination metadata format")?); + } + if let Some(self_nomination_target_deposit) = matches.value_of("self-nomination-target-deposit") { + self.self_target_deposit = Some( + self_nomination_target_deposit.parse().map_err(|_| "Invalid self nomination target deposit format")?, + ); + } + if let Some(self_nomination_interval) = matches.value_of("self-nomination-interval") { + self.self_nomination_interval = + Some(self_nomination_interval.parse().map_err(|_| "Invalid self nomination interval format")?); + } + if matches.is_present("enable-auto-self-nomination") { + self.self_nomination_enable = true; + } if matches.is_present("no-miner") { self.author = None; self.engine_signer = None; diff --git a/codechain/config/presets/config.dev.toml b/codechain/config/presets/config.dev.toml index 2b8890b4f7..1d700136d8 100644 --- a/codechain/config/presets/config.dev.toml +++ b/codechain/config/presets/config.dev.toml @@ -15,6 +15,7 @@ reseal_min_period = 0 reseal_max_period = 120000 no_reseal_timer = false work_queue_size = 20 +self_nomination_enable = false allowed_past_gap = 30000 allowed_future_gap = 5000 diff --git a/codechain/config/presets/config.prod.toml b/codechain/config/presets/config.prod.toml index b67e2746bb..dcd415ea82 100644 --- a/codechain/config/presets/config.prod.toml +++ b/codechain/config/presets/config.prod.toml @@ -6,6 +6,7 @@ chain = "mainnet" [mining] mem_pool_mem_limit = 512 # MB mem_pool_size = 524288 +self_nomination_enable = false mem_pool_fee_bump_shift = 3 # 12.5% allow_create_shard = false notify_work = [] diff --git a/codechain/main.rs b/codechain/main.rs index 4c7f6691f8..e372f5027f 100644 --- a/codechain/main.rs +++ b/codechain/main.rs @@ -54,6 +54,7 @@ extern crate primitives; extern crate rpassword; extern crate toml; +mod auto_self_nominate; mod config; mod constants; mod dummy_network_service; diff --git a/codechain/run_node.rs b/codechain/run_node.rs index c6f0e4e4b8..e0c49b1b8d 100644 --- a/codechain/run_node.rs +++ b/codechain/run_node.rs @@ -14,6 +14,7 @@ // You should have received a copy of the GNU Affero General Public License // along with this program. If not, see . +use crate::auto_self_nominate::AutoSelfNomination; use crate::config::{self, load_config}; use crate::constants::{DEFAULT_DB_PATH, DEFAULT_KEYS_PATH}; use crate::dummy_network_service::DummyNetworkService; @@ -21,8 +22,9 @@ use crate::json::PasswordFile; use crate::rpc::{rpc_http_start, rpc_ipc_start, rpc_ws_start}; use crate::rpc_apis::ApiDependencies; use ccore::{ - AccountProvider, AccountProviderError, BlockId, ChainNotify, Client, ClientConfig, ClientService, EngineClient, - EngineInfo, EngineType, Miner, MinerService, PeerDb, Scheme, Stratum, StratumConfig, StratumError, NUM_COLUMNS, + AccountProvider, AccountProviderError, BlockId, ChainNotify, Client, ClientConfig, ClientService, ConsensusClient, + EngineClient, EngineInfo, EngineType, Miner, MinerService, PeerDb, Scheme, Stratum, StratumConfig, StratumError, + NUM_COLUMNS, }; use cdiscovery::{Config, Discovery}; use ckey::{Address, NetworkId, PlatformAddress}; @@ -69,6 +71,11 @@ fn network_start( Ok(service) } +fn self_nominate_start(c: Arc, matches: &ArgMatches, ap: Arc, address: Address) { + let auto_self_nominate = AutoSelfNomination::new(c, ap, address); + auto_self_nominate.send_self_nominate_transaction(matches); +} + fn discovery_start( service: &NetworkService, cfg: &config::Network, @@ -124,7 +131,7 @@ fn new_miner( ap: Arc, db: Arc, ) -> Result, String> { - let miner = Miner::new(config.miner_options()?, scheme, Some(ap), db); + let miner = Miner::new(config.miner_options()?, scheme, ap, db); match miner.engine_type() { EngineType::PoW => match &config.mining.author { @@ -138,8 +145,7 @@ fn new_miner( Some(ref engine_signer) => match miner.set_author((*engine_signer).into_address()) { Err(AccountProviderError::NotUnlocked) => { return Err( - "The account is not unlocked. Specify the password path using --password-path option." - .to_string(), + format!("The account {} is not unlocked. The key file should exist in the keys_path directory, and the account's password should exist in the password_path file.", engine_signer) ) } Err(e) => return Err(format!("{}", e)), @@ -316,6 +322,12 @@ pub fn run_node(matches: &ArgMatches) -> Result<(), String> { Arc::new(DummyNetworkService::new()) } }; + if config.mining.self_nomination_enable { + let c = client.client(); + let address = miner.get_author_address(); + let accountp = ap.clone(); + self_nominate_start(c, matches, accountp, address); + } let rpc_apis_deps = ApiDependencies { client: client.client(), diff --git a/codechain/test_lock.rs b/codechain/test_lock.rs deleted file mode 100644 index e69de29bb2..0000000000 diff --git a/core/Cargo.toml b/core/Cargo.toml index ee8ec36be0..cf78db5961 100644 --- a/core/Cargo.toml +++ b/core/Cargo.toml @@ -5,8 +5,8 @@ authors = ["CodeChain Team "] edition = "2018" [dependencies] -codechain-crypto = { git = "https://github.com/CodeChain-io/rust-codechain-crypto.git", version = "0.1" } -codechain-db = { git = "https://github.com/CodeChain-io/rust-codechain-db.git", version = "0.1" } +codechain-crypto = { git = "https://github.com/CodeChain-io/rust-codechain-crypto.git", version = "0.2" } +codechain-db = { git = "https://github.com/CodeChain-io/rust-codechain-db.git", version = "0.2" } codechain-io = { path = "../util/io" } codechain-json = { path = "../json" } codechain-key = { path = "../key" } @@ -27,9 +27,9 @@ kvdb-memorydb = "0.1" linked-hash-map = "0.5" log = "0.4.6" lru-cache = "0.1.2" -merkle-trie = { git = "https://github.com/CodeChain-io/rust-merkle-trie.git", version = "0.1" } +merkle-trie = { git = "https://github.com/CodeChain-io/rust-merkle-trie.git", version = "0.4" } num-rational = "0.2.1" -parking_lot = "0.6.0" +parking_lot = "0.11.0" primitives = { git = "https://github.com/CodeChain-io/rust-codechain-primitives.git", version = "0.4" } rand = "0.6.1" rlp = { git = "https://github.com/CodeChain-io/rlp.git", version = "0.4" } diff --git a/core/src/block.rs b/core/src/block.rs index ebd3484fcf..421c840883 100644 --- a/core/src/block.rs +++ b/core/src/block.rs @@ -34,7 +34,7 @@ use rlp::{Decodable, DecoderError, Encodable, Rlp, RlpStream}; use std::collections::HashSet; /// A block, encoded as it is on the block chain. -#[derive(Debug, Clone, PartialEq)] +#[derive(Debug, Clone)] pub struct Block { /// The header of this block pub header: Header, @@ -152,7 +152,6 @@ impl<'x> OpenBlock<'x> { pub fn push_transaction( &mut self, tx: SignedTransaction, - h: Option, client: &C, parent_block_number: BlockNumber, parent_block_timestamp: u64, @@ -173,7 +172,7 @@ impl<'x> OpenBlock<'x> { self.block.header.timestamp(), ) { Ok(()) => { - self.block.transactions_set.insert(h.unwrap_or(hash)); + self.block.transactions_set.insert(hash); self.block.transactions.push(tx); None } @@ -200,7 +199,7 @@ impl<'x> OpenBlock<'x> { parent_block_timestamp: u64, ) -> Result<(), Error> { for tx in transactions { - self.push_transaction(tx.clone(), None, client, parent_block_number, parent_block_timestamp)?; + self.push_transaction(tx.clone(), client, parent_block_number, parent_block_timestamp)?; } Ok(()) } diff --git a/core/src/blockchain/body_db.rs b/core/src/blockchain/body_db.rs index 38978b1227..7b50e40663 100644 --- a/core/src/blockchain/body_db.rs +++ b/core/src/blockchain/body_db.rs @@ -346,9 +346,9 @@ fn tx_hash_and_address_entries( fn tracker_and_addresses_entries( block_hash: BlockHash, - tx_hashes: impl IntoIterator, + transactions: impl IntoIterator, ) -> impl Iterator { - tx_hashes.into_iter().enumerate().filter_map(move |(index, tx)| { + transactions.into_iter().enumerate().filter_map(move |(index, tx)| { tx.tracker().map(|tracker| { ( tracker, diff --git a/core/src/client/chain_notify.rs b/core/src/client/chain_notify.rs index a4868a7571..cd964773a5 100644 --- a/core/src/client/chain_notify.rs +++ b/core/src/client/chain_notify.rs @@ -14,8 +14,7 @@ // You should have received a copy of the GNU Affero General Public License // along with this program. If not, see . -use cnetwork::NodeId; -use ctypes::{BlockHash, TxHash}; +use ctypes::BlockHash; /// Represents what has to be handled by actor listening to chain events pub trait ChainNotify: Send + Sync { @@ -43,9 +42,4 @@ pub trait ChainNotify: Send + Sync { ) { // does nothing by default } - - /// fires when new transactions are received from a peer - fn transactions_received(&self, _hashes: Vec, _peer_id: NodeId) { - // does nothing by default - } } diff --git a/core/src/client/client.rs b/core/src/client/client.rs index c9e6feb6ee..4a6965184b 100644 --- a/core/src/client/client.rs +++ b/core/src/client/client.rs @@ -31,16 +31,16 @@ use crate::scheme::Scheme; use crate::service::ClientIoMessage; use crate::transaction::{LocalizedTransaction, PendingSignedTransactions, SignedTransaction, UnverifiedTransaction}; use crate::types::{BlockId, BlockStatus, TransactionId, VerificationQueueInfo as BlockQueueInfo}; +use crate::MemPoolMinFees; use cdb::{new_journaldb, Algorithm, AsHashDB, DatabaseError}; use cio::IoChannel; use ckey::{Address, NetworkId, PlatformAddress, Public}; -use cnetwork::NodeId; use cstate::{ ActionHandler, AssetScheme, FindActionHandler, OwnedAsset, StateDB, StateResult, Text, TopLevelState, TopStateView, }; use ctimer::{TimeoutHandler, TimerApi, TimerScheduleError, TimerToken}; use ctypes::transaction::{AssetTransferInput, PartialHashing, ShardTransaction}; -use ctypes::{BlockHash, BlockNumber, CommonParams, ShardId, Tracker, TxHash}; +use ctypes::{BlockHash, BlockNumber, CommonParams, Header, ShardId, Tracker, TxHash}; use cvm::{decode, execute, ChainTimeInfo, ScriptResult, VMConfig}; use kvdb::{DBTransaction, KeyValueDB}; use merkle_trie::Result as TrieResult; @@ -75,6 +75,9 @@ pub struct Client { importer: Importer, + /// Handles block sealing + miner: Arc, + /// Timer for reseal_min_period/reseal_max_period on miner client reseal_timer: TimerApi, } @@ -103,11 +106,10 @@ impl Client { let gb = scheme.genesis_block(); let chain = BlockChain::new(&gb, db.clone()); - scheme.check_genesis_common_params(&chain)?; let engine = scheme.engine.clone(); - let importer = Importer::try_new(config, engine.clone(), message_channel.clone(), miner)?; + let importer = Importer::try_new(config, engine.clone(), message_channel.clone(), Arc::clone(&miner))?; let genesis_accounts = scheme.genesis_accounts(); let client = Arc::new(Client { @@ -120,6 +122,7 @@ impl Client { queue_transactions: AtomicUsize::new(0), genesis_accounts, importer, + miner, reseal_timer, }); @@ -138,12 +141,6 @@ impl Client { self.notify.write().push(target); } - pub fn transactions_received(&self, hashes: &[TxHash], peer_id: NodeId) { - self.notify(|notify| { - notify.transactions_received(hashes.to_vec(), peer_id); - }); - } - pub fn new_blocks( &self, imported: &[BlockHash], @@ -196,7 +193,7 @@ impl Client { /// This is triggered by a message coming from a header queue when the header is ready for insertion pub fn import_verified_headers(&self) -> usize { - self.importer.import_verified_headers(self) + self.importer.import_verified_headers_from_queue(self) } /// This is triggered by a message coming from a block queue when the block is ready for insertion @@ -206,7 +203,7 @@ impl Client { /// This is triggered by a message coming from a engine when a new block should be created pub fn update_sealing(&self, parent_block: BlockId, allow_empty_block: bool) { - self.importer.miner.update_sealing(self, parent_block, allow_empty_block); + self.miner.update_sealing(self, parent_block, allow_empty_block); } fn block_hash(chain: &BlockChain, id: &BlockId) -> Option { @@ -236,14 +233,12 @@ impl Client { } /// Import transactions from the IO queue - pub fn import_queued_transactions(&self, transactions: &[Bytes], peer_id: NodeId) -> usize { + pub fn import_queued_transactions(&self, transactions: &[Bytes]) -> usize { ctrace!(EXTERNAL_TX, "Importing queued"); self.queue_transactions.fetch_sub(transactions.len(), AtomicOrdering::SeqCst); let transactions: Vec = transactions.iter().filter_map(|bytes| Rlp::new(bytes).as_val().ok()).collect(); - let hashes: Vec<_> = transactions.iter().map(UnverifiedTransaction::hash).collect(); - self.transactions_received(&hashes, peer_id); - let results = self.importer.miner.import_external_transactions(self, transactions); + let results = self.miner.import_external_transactions(self, transactions); results.len() } @@ -273,7 +268,7 @@ impl Client { } let (enacted, retracted) = self.importer.calculate_enacted_retracted(&[route]); - self.importer.miner.chain_new_blocks(self, &[], &[], &enacted, &retracted); + self.miner.chain_new_blocks(self, &[], &[], &enacted, &retracted); self.new_blocks(&[], &[], &enacted, &retracted, &[]); } @@ -324,7 +319,7 @@ impl TimeoutHandler for Client { match token { RESEAL_MAX_TIMER_TOKEN => { // Working in PoW only - if self.engine().seals_internally().is_none() && !self.importer.miner.prepare_work_sealing(self) { + if self.engine().seals_internally().is_none() && !self.miner.prepare_work_sealing(self) { self.update_sealing(BlockId::Latest, true); } } @@ -556,7 +551,7 @@ impl EngineClient for Client { /// Submit a seal for a block in the mining queue. fn submit_seal(&self, block_hash: BlockHash, seal: Vec) { - if self.importer.miner.submit_seal(self, block_hash, seal).is_err() { + if self.miner.submit_seal(self, block_hash, seal).is_err() { cwarn!(CLIENT, "Wrong internal seal submission!") } } @@ -645,17 +640,14 @@ impl ImportBlock for Client { Ok(self.importer.block_queue.import(unverified)?) } - fn import_header(&self, bytes: Bytes) -> Result { - let unverified = encoded::Header::new(bytes).decode(); - { - if self.block_chain().is_known_header(&unverified.hash()) { - return Err(BlockImportError::Import(ImportError::AlreadyInChain)) - } + fn import_header(&self, unverified: Header) -> Result { + if self.block_chain().is_known_header(&unverified.hash()) { + return Err(BlockImportError::Import(ImportError::AlreadyInChain)) } Ok(self.importer.header_queue.import(unverified)?) } - fn import_sealed_block(&self, block: &SealedBlock) -> ImportResult { + fn import_generated_block(&self, block: &SealedBlock) -> ImportResult { let h = block.header().hash(); let route = { // scope for self.import_lock @@ -665,14 +657,14 @@ impl ImportBlock for Client { let block_data = block.rlp_bytes(); let header = block.header(); - self.importer.import_headers(vec![header], self, &import_lock); + self.importer.import_verified_headers(vec![header], self, &import_lock); let route = self.importer.commit_block(block, header, &block_data, self); cinfo!(CLIENT, "Imported sealed block #{} ({})", number, h); route }; let (enacted, retracted) = self.importer.calculate_enacted_retracted(&[route]); - self.importer.miner.chain_new_blocks(self, &[h], &[], &enacted, &retracted); + self.miner.chain_new_blocks(self, &[h], &[], &enacted, &retracted); self.new_blocks(&[h], &[], &enacted, &retracted, &[h]); self.db().flush().expect("DB flush failed."); Ok(h) @@ -680,10 +672,7 @@ impl ImportBlock for Client { fn set_min_timer(&self) { self.reseal_timer.cancel(RESEAL_MIN_TIMER_TOKEN).expect("Reseal min timer clear succeeds"); - match self - .reseal_timer - .schedule_once(self.importer.miner.get_options().reseal_min_period, RESEAL_MIN_TIMER_TOKEN) - { + match self.reseal_timer.schedule_once(self.miner.get_options().reseal_min_period, RESEAL_MIN_TIMER_TOKEN) { Ok(_) => {} Err(TimerScheduleError::TokenAlreadyScheduled) => { // Since set_min_timer could be called in multi thread, ignore the TokenAlreadyScheduled error @@ -694,10 +683,7 @@ impl ImportBlock for Client { fn set_max_timer(&self) { self.reseal_timer.cancel(RESEAL_MAX_TIMER_TOKEN).expect("Reseal max timer clear succeeds"); - match self - .reseal_timer - .schedule_once(self.importer.miner.get_options().reseal_max_period, RESEAL_MAX_TIMER_TOKEN) - { + match self.reseal_timer.schedule_once(self.miner.get_options().reseal_max_period, RESEAL_MAX_TIMER_TOKEN) { Ok(_) => {} Err(TimerScheduleError::TokenAlreadyScheduled) => { // Since set_max_timer could be called in multi thread, ignore the TokenAlreadyScheduled error @@ -715,18 +701,18 @@ impl BlockChainClient for Client { /// Import own transaction fn queue_own_transaction(&self, transaction: SignedTransaction) -> Result<(), Error> { - self.importer.miner.import_own_transaction(self, transaction)?; + self.miner.import_own_transaction(self, transaction)?; Ok(()) } - fn queue_transactions(&self, transactions: Vec, peer_id: NodeId) { + fn queue_transactions(&self, transactions: Vec) { let queue_size = self.queue_transactions.load(AtomicOrdering::Relaxed); ctrace!(EXTERNAL_TX, "Queue size: {}", queue_size); if queue_size > MAX_MEM_POOL_SIZE { cwarn!(EXTERNAL_TX, "Ignoring {} transactions: queue is full", transactions.len()); } else { let len = transactions.len(); - match self.io_channel.lock().send(ClientIoMessage::NewTransactions(transactions, peer_id)) { + match self.io_channel.lock().send(ClientIoMessage::NewTransactions(transactions)) { Ok(_) => { self.queue_transactions.fetch_add(len, AtomicOrdering::SeqCst); } @@ -738,26 +724,26 @@ impl BlockChainClient for Client { } fn delete_all_pending_transactions(&self) { - self.importer.miner.delete_all_pending_transactions(); + self.miner.delete_all_pending_transactions(); } fn ready_transactions(&self, range: Range) -> PendingSignedTransactions { - self.importer.miner.ready_transactions(range) + self.miner.ready_transactions(range) } fn count_pending_transactions(&self, range: Range) -> usize { - self.importer.miner.count_pending_transactions(range) + self.miner.count_pending_transactions(range) } fn future_included_count_pending_transactions(&self, range: Range) -> usize { - self.importer.miner.future_included_count_pending_transactions(range) + self.miner.future_included_count_pending_transactions(range) } fn future_ready_transactions(&self, range: Range) -> PendingSignedTransactions { - self.importer.miner.future_ready_transactions(range) + self.miner.future_ready_transactions(range) } fn is_pending_queue_empty(&self) -> bool { - self.importer.miner.status().transactions_in_pending_queue == 0 + self.miner.status().transactions_in_pending_queue == 0 } fn block_number(&self, id: &BlockId) -> Option { @@ -907,23 +893,27 @@ impl BlockProducer for Client { impl MiningBlockChainClient for Client { fn get_malicious_users(&self) -> Vec
{ - self.importer.miner.get_malicious_users() + self.miner.get_malicious_users() } fn release_malicious_users(&self, prisoner_vec: Vec
) { - self.importer.miner.release_malicious_users(prisoner_vec) + self.miner.release_malicious_users(prisoner_vec) } fn imprison_malicious_users(&self, prisoner_vec: Vec
) { - self.importer.miner.imprison_malicious_users(prisoner_vec) + self.miner.imprison_malicious_users(prisoner_vec) } fn get_immune_users(&self) -> Vec
{ - self.importer.miner.get_immune_users() + self.miner.get_immune_users() } fn register_immune_users(&self, immune_user_vec: Vec
) { - self.importer.miner.register_immune_users(immune_user_vec) + self.miner.register_immune_users(immune_user_vec) + } + + fn mem_pool_min_fees(&self) -> MemPoolMinFees { + self.miner.get_options().mem_pool_min_fees } } diff --git a/core/src/client/config.rs b/core/src/client/config.rs index f64b679609..e1afbb6097 100644 --- a/core/src/client/config.rs +++ b/core/src/client/config.rs @@ -14,7 +14,7 @@ // You should have received a copy of the GNU Affero General Public License // along with this program. If not, see . -use crate::verification::{QueueConfig, VerifierType}; +use crate::verification::QueueConfig; use kvdb_rocksdb::CompactionProfile; use std::path::Path; use std::str::FromStr; @@ -71,8 +71,6 @@ pub struct ClientConfig { pub db_compaction: DatabaseCompactionProfile, /// State db cache-size. pub state_cache_size: usize, - /// Type of block verifier used by client. - pub verifier_type: VerifierType, } impl Default for ClientConfig { @@ -84,7 +82,6 @@ impl Default for ClientConfig { db_cache_size: Default::default(), db_compaction: Default::default(), state_cache_size: DEFAULT_STATE_CACHE_SIZE as usize * mb, - verifier_type: Default::default(), } } } diff --git a/core/src/client/importer.rs b/core/src/client/importer.rs index 28a080ff6b..da46a1734a 100644 --- a/core/src/client/importer.rs +++ b/core/src/client/importer.rs @@ -41,7 +41,7 @@ pub struct Importer { pub import_lock: Mutex<()>, // FIXME Maybe wrap the whole `Importer` instead? /// Used to verify blocks - pub verifier: Box>, + pub verifier: Verifier, /// Queue containing pending blocks pub block_queue: BlockQueue, @@ -50,7 +50,7 @@ pub struct Importer { pub header_queue: HeaderQueue, /// Handles block sealing - pub miner: Arc, + miner: Arc, /// CodeChain engine to be used during import pub engine: Arc, @@ -63,19 +63,13 @@ impl Importer { message_channel: IoChannel, miner: Arc, ) -> Result { - let block_queue = BlockQueue::new( - &config.queue, - engine.clone(), - message_channel.clone(), - config.verifier_type.verifying_seal(), - ); + let block_queue = BlockQueue::new(&config.queue, engine.clone(), message_channel.clone(), true); - let header_queue = - HeaderQueue::new(&config.queue, engine.clone(), message_channel, config.verifier_type.verifying_seal()); + let header_queue = HeaderQueue::new(&config.queue, engine.clone(), message_channel, true); Ok(Importer { import_lock: Mutex::new(()), - verifier: verification::new(config.verifier_type), + verifier: Verifier::new(), block_queue, header_queue, miner, @@ -99,7 +93,7 @@ impl Importer { { let headers: Vec<&Header> = blocks.iter().map(|block| &block.header).collect(); - self.import_headers(headers, client, &import_lock); + self.import_verified_headers(headers, client, &import_lock); } for block in blocks { @@ -293,14 +287,14 @@ impl Importer { } /// This is triggered by a message coming from a header queue when the header is ready for insertion - pub fn import_verified_headers(&self, client: &Client) -> usize { + pub fn import_verified_headers_from_queue(&self, client: &Client) -> usize { const MAX_HEADERS_TO_IMPORT: usize = 1_000; let lock = self.import_lock.lock(); let headers = self.header_queue.drain(MAX_HEADERS_TO_IMPORT); - self.import_headers(&headers, client, &lock) + self.import_verified_headers(&headers, client, &lock) } - pub fn import_headers<'a>( + pub fn import_verified_headers<'a>( &'a self, headers: impl IntoIterator, client: &Client, diff --git a/core/src/client/mod.rs b/core/src/client/mod.rs index 32aea185c4..aa4766ecd1 100644 --- a/core/src/client/mod.rs +++ b/core/src/client/mod.rs @@ -32,14 +32,14 @@ use crate::blockchain_info::BlockChainInfo; use crate::consensus::EngineError; use crate::encoded; use crate::error::{BlockImportError, Error as GenericError}; +use crate::miner::MemPoolMinFees; use crate::transaction::{LocalizedTransaction, PendingSignedTransactions, SignedTransaction}; use crate::types::{BlockId, BlockStatus, TransactionId, VerificationQueueInfo as BlockQueueInfo}; use cdb::DatabaseError; use ckey::{Address, NetworkId, PlatformAddress, Public}; -use cnetwork::NodeId; use cstate::{AssetScheme, FindActionHandler, OwnedAsset, StateResult, Text, TopLevelState, TopStateView}; use ctypes::transaction::{AssetTransferInput, PartialHashing, ShardTransaction}; -use ctypes::{BlockHash, BlockNumber, CommonParams, ShardId, Tracker, TxHash}; +use ctypes::{BlockHash, BlockNumber, CommonParams, Header, ShardId, Tracker, TxHash}; use cvm::ChainTimeInfo; use kvdb::KeyValueDB; use merkle_trie::Result as TrieResult; @@ -197,10 +197,10 @@ pub trait ImportBlock { fn import_block(&self, bytes: Bytes) -> Result; /// Import a header into the blockchain - fn import_header(&self, bytes: Bytes) -> Result; + fn import_header(&self, header: Header) -> Result; /// Import sealed block. Skips all verifications. - fn import_sealed_block(&self, block: &SealedBlock) -> ImportResult; + fn import_generated_block(&self, block: &SealedBlock) -> ImportResult; /// Set reseal min timer as reseal_min_period, for creating blocks with transactions which are pending because of reseal_min_period fn set_min_timer(&self); @@ -217,7 +217,7 @@ pub trait BlockChainClient: Sync + Send + AccountData + BlockChainTrait + Import fn queue_own_transaction(&self, transaction: SignedTransaction) -> Result<(), GenericError>; /// Queue transactions for importing. - fn queue_transactions(&self, transactions: Vec, peer_id: NodeId); + fn queue_transactions(&self, transactions: Vec); /// Delete all pending transactions. fn delete_all_pending_transactions(&self); @@ -294,6 +294,8 @@ pub trait MiningBlockChainClient: BlockChainClient + BlockProducer + FindActionH /// Append designated users to the immune user list. fn register_immune_users(&self, immune_user_vec: Vec
); + + fn mem_pool_min_fees(&self) -> MemPoolMinFees; } /// Provides methods to access database. diff --git a/core/src/client/test_client.rs b/core/src/client/test_client.rs index e30e84d069..43e164b636 100644 --- a/core/src/client/test_client.rs +++ b/core/src/client/test_client.rs @@ -41,13 +41,12 @@ use crate::consensus::EngineError; use crate::db::{COL_STATE, NUM_COLUMNS}; use crate::encoded; use crate::error::{BlockImportError, Error as GenericError}; -use crate::miner::{Miner, MinerService, TransactionImportResult}; +use crate::miner::{MemPoolMinFees, Miner, MinerService, TransactionImportResult}; use crate::scheme::Scheme; use crate::transaction::{LocalizedTransaction, PendingSignedTransactions, SignedTransaction}; use crate::types::{BlockId, TransactionId, VerificationQueueInfo as QueueInfo}; use cdb; use ckey::{public_to_address, Address, Generator, KeyPair, NetworkId, PlatformAddress, Private, Public, Random}; -use cnetwork::NodeId; use cstate::tests::helpers::empty_top_state; use cstate::{FindActionHandler, StateDB, TopLevelState}; use ctimer::{TimeoutHandler, TimerToken}; @@ -151,7 +150,7 @@ impl TestBlockChainClient { seqs: RwLock::new(HashMap::new()), storage: RwLock::new(HashMap::new()), queue_size: AtomicUsize::new(0), - miner: Arc::new(Miner::with_scheme(&scheme, db)), + miner: Arc::new(Miner::with_scheme_for_test(&scheme, db)), scheme, latest_block_timestamp: RwLock::new(10_000_000), history: RwLock::new(None), @@ -378,6 +377,10 @@ impl MiningBlockChainClient for TestBlockChainClient { fn register_immune_users(&self, immune_user_vec: Vec
) { self.miner.register_immune_users(immune_user_vec) } + + fn mem_pool_min_fees(&self) -> MemPoolMinFees { + self.miner.get_options().mem_pool_min_fees + } } impl AccountData for TestBlockChainClient { @@ -505,11 +508,11 @@ impl ImportBlock for TestBlockChainClient { Ok(h) } - fn import_header(&self, _bytes: Bytes) -> Result { + fn import_header(&self, _bytes: BlockHeader) -> Result { unimplemented!() } - fn import_sealed_block(&self, _block: &SealedBlock) -> ImportResult { + fn import_generated_block(&self, _block: &SealedBlock) -> ImportResult { Ok(H256::default().into()) } @@ -536,7 +539,7 @@ impl BlockChainClient for TestBlockChainClient { Ok(()) } - fn queue_transactions(&self, transactions: Vec, _peer_id: NodeId) { + fn queue_transactions(&self, transactions: Vec) { // import right here let transactions = transactions.into_iter().filter_map(|bytes| Rlp::new(&bytes).as_val().ok()).collect(); self.miner.import_external_transactions(self, transactions); diff --git a/core/src/consensus/blake_pow/mod.rs b/core/src/consensus/blake_pow/mod.rs index 386dfa36bf..8df5d2c58e 100644 --- a/core/src/consensus/blake_pow/mod.rs +++ b/core/src/consensus/blake_pow/mod.rs @@ -83,10 +83,6 @@ impl BlakePoW { } impl ConsensusEngine for BlakePoW { - fn name(&self) -> &str { - "BlakePoW" - } - fn machine(&self) -> &CodeChainMachine { &self.machine } diff --git a/core/src/consensus/cuckoo/mod.rs b/core/src/consensus/cuckoo/mod.rs index 6aefe7c5e6..5e3dd243ee 100644 --- a/core/src/consensus/cuckoo/mod.rs +++ b/core/src/consensus/cuckoo/mod.rs @@ -89,10 +89,6 @@ impl Cuckoo { } impl ConsensusEngine for Cuckoo { - fn name(&self) -> &str { - "Cuckoo" - } - fn machine(&self) -> &CodeChainMachine { &self.machine } @@ -210,7 +206,6 @@ mod tests { fn has_valid_metadata() { let engine = Scheme::new_test_cuckoo().engine; - assert_eq!(engine.name(), "Cuckoo"); assert_eq!(engine.engine_type(), EngineType::PoW); } diff --git a/core/src/consensus/mod.rs b/core/src/consensus/mod.rs index 7adf4d6328..ed55ba6818 100644 --- a/core/src/consensus/mod.rs +++ b/core/src/consensus/mod.rs @@ -18,7 +18,7 @@ mod bit_set; mod blake_pow; mod cuckoo; mod null_engine; -mod signer; +pub(crate) mod signer; mod simple_poa; mod solo; pub mod stake; @@ -138,9 +138,6 @@ impl EngineType { /// A consensus mechanism for the chain. pub trait ConsensusEngine: Sync + Send { - /// The name of this engine. - fn name(&self) -> &str; - /// Get access to the underlying state machine. fn machine(&self) -> &CodeChainMachine; diff --git a/core/src/consensus/null_engine/mod.rs b/core/src/consensus/null_engine/mod.rs index cbd1a07bc7..9fba363cdf 100644 --- a/core/src/consensus/null_engine/mod.rs +++ b/core/src/consensus/null_engine/mod.rs @@ -42,10 +42,6 @@ impl NullEngine { } impl ConsensusEngine for NullEngine { - fn name(&self) -> &str { - "NullEngine" - } - fn machine(&self) -> &CodeChainMachine { &self.machine } diff --git a/core/src/consensus/simple_poa/mod.rs b/core/src/consensus/simple_poa/mod.rs index 4db084d9cf..75d08f543c 100644 --- a/core/src/consensus/simple_poa/mod.rs +++ b/core/src/consensus/simple_poa/mod.rs @@ -73,10 +73,6 @@ fn verify_external(header: &Header, validators: &dyn ValidatorSet) -> Result<(), } impl ConsensusEngine for SimplePoA { - fn name(&self) -> &str { - "SimplePoA" - } - fn machine(&self) -> &CodeChainMachine { &self.machine } @@ -159,12 +155,6 @@ mod tests { use super::*; - #[test] - fn has_valid_metadata() { - let engine = Scheme::new_test_simple_poa().engine; - assert!(!engine.name().is_empty()); - } - #[test] fn fail_to_verify_signature_when_seal_is_invalid() { let engine = Scheme::new_test_simple_poa().engine; diff --git a/core/src/consensus/solo/mod.rs b/core/src/consensus/solo/mod.rs index 69cead2f84..5faa74e6e1 100644 --- a/core/src/consensus/solo/mod.rs +++ b/core/src/consensus/solo/mod.rs @@ -61,10 +61,6 @@ impl Solo { } impl ConsensusEngine for Solo { - fn name(&self) -> &str { - "Solo" - } - fn machine(&self) -> &CodeChainMachine { &self.machine } diff --git a/core/src/consensus/stake/action_data.rs b/core/src/consensus/stake/action_data.rs index 170774b541..d798f0fe49 100644 --- a/core/src/consensus/stake/action_data.rs +++ b/core/src/consensus/stake/action_data.rs @@ -510,6 +510,9 @@ impl Candidates { pub fn len(&self) -> usize { self.0.len() } + pub fn is_empty(&self) -> bool { + self.0.len() == 0 + } #[cfg(test)] pub fn get_index(&self, account: &Address) -> Option { @@ -628,6 +631,9 @@ impl Jail { pub fn len(&self) -> usize { self.0.len() } + pub fn is_empty(&self) -> bool { + self.0.len() == 0 + } pub fn add(&mut self, candidate: Candidate, custody_until: u64, released_at: u64) { assert!(custody_until <= released_at); diff --git a/core/src/consensus/stake/distribute.rs b/core/src/consensus/stake/distribute.rs index 1c5dd55ea0..d76d13bac6 100644 --- a/core/src/consensus/stake/distribute.rs +++ b/core/src/consensus/stake/distribute.rs @@ -19,7 +19,10 @@ use std::collections::hash_map; use std::collections::HashMap; use std::convert::TryFrom; -pub fn fee_distribute(total_min_fee: u64, stakes: &HashMap) -> FeeDistributeIter { +pub fn fee_distribute( + total_min_fee: u64, + stakes: &HashMap, +) -> FeeDistributeIter { FeeDistributeIter { total_stakes: stakes.values().sum(), total_min_fee, diff --git a/core/src/consensus/stake/mod.rs b/core/src/consensus/stake/mod.rs index ee7601b4ee..4c7a636f06 100644 --- a/core/src/consensus/stake/mod.rs +++ b/core/src/consensus/stake/mod.rs @@ -32,8 +32,8 @@ use std::collections::btree_map::BTreeMap; use std::collections::HashMap; use std::sync::{Arc, Weak}; -pub use self::action_data::{Banned, Validator, Validators}; -use self::action_data::{Candidates, Delegation, IntermediateRewards, Jail, ReleaseResult, StakeAccount, Stakeholders}; +pub use self::action_data::{Banned, Candidates, Jail, Validator, Validators}; +use self::action_data::{Delegation, IntermediateRewards, ReleaseResult, StakeAccount, Stakeholders}; pub use self::actions::Action; pub use self::distribute::fee_distribute; use super::ValidatorSet; diff --git a/core/src/consensus/tendermint/engine.rs b/core/src/consensus/tendermint/engine.rs index 6e15d3b5b9..b0b14505c6 100644 --- a/core/src/consensus/tendermint/engine.rs +++ b/core/src/consensus/tendermint/engine.rs @@ -53,10 +53,6 @@ struct WorkInfo { } impl ConsensusEngine for Tendermint { - fn name(&self) -> &str { - "Tendermint" - } - fn machine(&self) -> &CodeChainMachine { &self.machine.as_ref() } @@ -137,7 +133,6 @@ impl ConsensusEngine for Tendermint { self.inner.send(worker::Event::OnTimeout(token)).unwrap(); } - fn stop(&self) {} fn on_close_block( &self, diff --git a/core/src/consensus/tendermint/mod.rs b/core/src/consensus/tendermint/mod.rs index 87c6d37b11..4523840ef6 100644 --- a/core/src/consensus/tendermint/mod.rs +++ b/core/src/consensus/tendermint/mod.rs @@ -29,7 +29,7 @@ use self::chain_notify::TendermintChainNotify; pub use self::message::{ConsensusMessage, VoteOn, VoteStep}; pub use self::params::{TendermintParams, TimeGapParams, TimeoutParams}; pub use self::types::{Height, Step, View}; -use super::{stake, ValidatorSet}; +pub use super::{stake, ValidatorSet}; use crate::client::ConsensusClient; use crate::codechain_machine::CodeChainMachine; use crate::ChainNotify; @@ -124,16 +124,17 @@ const SEAL_FIELDS: usize = 4; #[cfg(test)] mod tests { use ccrypto::blake256; - use ckey::Address; + use ckey::{public_to_address, sign_schnorr, Address, KeyPair, Private}; use ctypes::{CommonParams, Header}; use primitives::Bytes; + use std::str::FromStr; use super::super::BitSet; use super::message::VoteStep; use crate::account_provider::AccountProvider; use crate::block::{ClosedBlock, OpenBlock}; use crate::client::TestBlockChainClient; - use crate::consensus::{CodeChainEngine, EngineError, Seal}; + use crate::consensus::{CodeChainEngine, Seal}; use crate::error::BlockError; use crate::error::Error; use crate::scheme::Scheme; @@ -177,15 +178,44 @@ mod tests { } #[test] - fn has_valid_metadata() { - use std::time::Duration; - let engine = Scheme::new_test_tendermint().engine; - let time_gap_params = TimeGapParams { - allowed_past_gap: Duration::from_millis(30000), - allowed_future_gap: Duration::from_millis(5000), + fn serialize_deserialize_test() { + let key_pair = { + let serialized_priv_key = "ede1d4ccb4ec9a8bbbae9a13db3f4a7b56ea04189be86ac3a6a439d9a0a1addd"; + let private_key = Private::from_str(&serialized_priv_key).unwrap(); + KeyPair::from_private(private_key).unwrap() + }; + + let mut header = Header::default(); + header.set_number(4); + header.set_author(public_to_address(key_pair.public())); + + let precommit_bitset = { + let mut bitset = BitSet::new(); + bitset.set(2); + bitset }; - engine.register_time_gap_config_to_worker(time_gap_params); - assert!(!engine.name().is_empty()); + let signature = { + let height = 3; + let view = 0; + let step = Step::Precommit; + let vote_on = VoteOn { + step: VoteStep::new(height, view, step), + block_hash: Some(*header.parent_hash()), + }; + sign_schnorr(key_pair.private(), &vote_on.hash()).unwrap() + }; + let seal = Seal::Tendermint { + prev_view: 0, + cur_view: 0, + precommits: vec![signature], + precommit_bitset, + }; + header.set_seal(seal.seal_fields().unwrap()); + + let encoded = rlp::encode(&header); + let decoded: Header = rlp::decode(&encoded).unwrap(); + + assert_eq!(header.hash(), decoded.hash()); } #[test] @@ -249,83 +279,4 @@ mod tests { println!("....."); assert!(engine.verify_block_external(&header).is_err()); } - - #[test] - #[ignore] // FIXME - fn seal_signatures_checking() { - let (spec, tap, c) = setup(); - let engine = spec.engine; - - let validator0 = insert_and_unlock(&tap, "0"); - let validator1 = insert_and_unlock(&tap, "1"); - let validator2 = insert_and_unlock(&tap, "2"); - let validator3 = insert_and_unlock(&tap, "3"); - - let block1_hash = c.add_block_with_author(Some(validator1), 1, 1); - - let mut header = Header::default(); - header.set_number(2); - let proposer = validator2; - header.set_author(proposer); - header.set_parent_hash(block1_hash); - - let vote_info = VoteOn { - step: VoteStep::new(1, 0, Step::Precommit), - block_hash: Some(*header.parent_hash()), - }; - let signature2 = tap.get_account(&proposer, None).unwrap().sign_schnorr(&vote_info.hash()).unwrap(); - - let seal = Seal::Tendermint { - prev_view: 0, - cur_view: 0, - precommits: vec![signature2], - precommit_bitset: BitSet::new_with_indices(&[2]), - } - .seal_fields() - .unwrap(); - header.set_seal(seal); - - // One good signature is not enough. - match engine.verify_block_external(&header) { - Err(Error::Engine(EngineError::BadSealFieldSize(_))) => {} - _ => panic!(), - } - - let voter = validator3; - let signature3 = tap.get_account(&voter, None).unwrap().sign_schnorr(&vote_info.hash()).unwrap(); - let voter = validator0; - let signature0 = tap.get_account(&voter, None).unwrap().sign_schnorr(&vote_info.hash()).unwrap(); - - let seal = Seal::Tendermint { - prev_view: 0, - cur_view: 0, - precommits: vec![signature0, signature2, signature3], - precommit_bitset: BitSet::new_with_indices(&[0, 2, 3]), - } - .seal_fields() - .unwrap(); - header.set_seal(seal); - - assert!(engine.verify_block_external(&header).is_ok()); - - let bad_voter = insert_and_unlock(&tap, "101"); - let bad_signature = tap.get_account(&bad_voter, None).unwrap().sign_schnorr(&vote_info.hash()).unwrap(); - - let seal = Seal::Tendermint { - prev_view: 0, - cur_view: 0, - precommits: vec![signature0, signature2, bad_signature], - precommit_bitset: BitSet::new_with_indices(&[0, 2, 3]), - } - .seal_fields() - .unwrap(); - header.set_seal(seal); - - // Two good and one bad signature. - match engine.verify_block_external(&header) { - Err(Error::Engine(EngineError::BlockNotAuthorized(_))) => {} - _ => panic!(), - }; - engine.stop(); - } } diff --git a/core/src/consensus/tendermint/worker.rs b/core/src/consensus/tendermint/worker.rs index 763250873e..fb399d075e 100644 --- a/core/src/consensus/tendermint/worker.rs +++ b/core/src/consensus/tendermint/worker.rs @@ -956,6 +956,7 @@ impl Worker { if !self.votes.is_old_or_known(&message) { if let Err(double_vote) = self.votes.collect(message) { cerror!(ENGINE, "Double vote found on_commit_message: {:?}", double_vote); + self.report_double_vote(&double_vote); } } } @@ -1432,9 +1433,9 @@ impl Worker { self.votes_received.set(vote_index); } - if let Err(double) = self.votes.collect(message.clone()) { - cerror!(ENGINE, "Double vote found {:?}", double); - self.report_double_vote(&double); + if let Err(double_vote) = self.votes.collect(message.clone()) { + cerror!(ENGINE, "Double vote found {:?}", double_vote); + self.report_double_vote(&double_vote); return Err(EngineError::DoubleVote(sender)) } ctrace!(ENGINE, "Handling a valid {:?} from {}.", message, sender); @@ -1821,9 +1822,9 @@ impl Worker { ); } - if let Err(double) = self.votes.collect(message) { - cerror!(ENGINE, "Double Vote found {:?}", double); - self.report_double_vote(&double); + if let Err(double_vote) = self.votes.collect(message) { + cerror!(ENGINE, "Double Vote found {:?}", double_vote); + self.report_double_vote(&double_vote); return None } } @@ -2162,6 +2163,7 @@ impl Worker { if !self.votes.is_old_or_known(&vote) { if let Err(double_vote) = self.votes.collect(vote) { cerror!(ENGINE, "Double vote found on_commit_message: {:?}", double_vote); + self.report_double_vote(&double_vote); } } } diff --git a/core/src/lib.rs b/core/src/lib.rs index 9e378dca47..f748b5d7df 100644 --- a/core/src/lib.rs +++ b/core/src/lib.rs @@ -82,14 +82,15 @@ mod tests; pub use crate::account_provider::{AccountProvider, Error as AccountProviderError}; pub use crate::block::Block; pub use crate::client::{ - AccountData, AssetClient, BlockChainClient, BlockChainTrait, ChainNotify, Client, ClientConfig, DatabaseClient, - EngineClient, EngineInfo, ExecuteClient, ImportBlock, MiningBlockChainClient, Shard, StateInfo, TermInfo, - TestBlockChainClient, TextClient, + AccountData, AssetClient, BlockChainClient, BlockChainTrait, ChainNotify, Client, ClientConfig, ConsensusClient, + DatabaseClient, EngineClient, EngineInfo, ExecuteClient, ImportBlock, MiningBlockChainClient, Shard, StateInfo, + TermInfo, TestBlockChainClient, TextClient, }; +pub use crate::consensus::stake; pub use crate::consensus::{EngineType, TimeGapParams}; pub use crate::db::{COL_STATE, NUM_COLUMNS}; pub use crate::error::{BlockImportError, Error, ImportError}; -pub use crate::miner::{MemPoolFees, Miner, MinerOptions, MinerService, Stratum, StratumConfig, StratumError}; +pub use crate::miner::{MemPoolMinFees, Miner, MinerOptions, MinerService, Stratum, StratumConfig, StratumError}; pub use crate::peer_db::PeerDb; pub use crate::scheme::Scheme; pub use crate::service::ClientService; diff --git a/core/src/miner/mem_pool.rs b/core/src/miner/mem_pool.rs index c7aca0cb99..bf2a4f0d1e 100644 --- a/core/src/miner/mem_pool.rs +++ b/core/src/miner/mem_pool.rs @@ -16,8 +16,8 @@ use super::backup; use super::mem_pool_types::{ - AccountDetails, CurrentQueue, FutureQueue, MemPoolFees, MemPoolInput, MemPoolItem, MemPoolStatus, PoolingInstant, - QueueTag, TransactionOrder, TransactionOrderWithTag, TxOrigin, TxTimelock, + AccountDetails, CurrentQueue, FutureQueue, MemPoolInput, MemPoolItem, MemPoolMinFees, MemPoolStatus, + PoolingInstant, QueueTag, TransactionOrder, TransactionOrderWithTag, TxOrigin, TxTimelock, }; use super::TransactionImportResult; use crate::client::{AccountData, BlockChainTrait}; @@ -74,7 +74,7 @@ impl From for Error { pub struct MemPool { /// Fee threshold for transactions that can be imported to this pool - minimum_fees: MemPoolFees, + minimum_fees: MemPoolMinFees, /// A value which is used to check whether a new transaciton can replace a transaction in the memory pool with the same signer and seq. /// If the fee of the new transaction is `new_fee` and the fee of the transaction in the memory pool is `old_fee`, /// then `new_fee > old_fee + old_fee >> mem_pool_fee_bump_shift` should be satisfied to replace. @@ -119,7 +119,7 @@ impl MemPool { memory_limit: usize, fee_bump_shift: usize, db: Arc, - minimum_fees: MemPoolFees, + minimum_fees: MemPoolMinFees, ) -> Self { MemPool { minimum_fees, @@ -868,17 +868,6 @@ impl MemPool { Ok(()) } - /// Removes all elements (in any state) from the pool - #[allow(dead_code)] - pub fn clear(&mut self) { - self.current.clear(); - self.future.clear(); - self.by_signer_public.clear(); - self.by_hash.clear(); - self.first_seqs.clear(); - self.next_seqs.clear(); - } - /// Returns top transactions whose timestamp are in the given range from the pool ordered by priority. // FIXME: current_timestamp should be `u64`, not `Option`. // FIXME: if range_contains becomes stable, use range.contains instead of inequality. @@ -1669,7 +1658,7 @@ pub mod test { let test_client = TestBlockChainClient::new(); // Set the pay transaction minimum fee - let fees = MemPoolFees::create_from_options( + let fees = MemPoolMinFees::create_from_options( Some(150), None, None, @@ -1724,7 +1713,7 @@ pub mod test { fn external_transactions_whose_fees_are_under_the_mem_pool_min_fee_are_rejected() { let test_client = TestBlockChainClient::new(); // Set the pay transaction minimum fee - let fees = MemPoolFees::create_from_options( + let fees = MemPoolMinFees::create_from_options( Some(150), None, None, diff --git a/core/src/miner/mem_pool_types.rs b/core/src/miner/mem_pool_types.rs index bc1eb7094f..26a85eb4f6 100644 --- a/core/src/miner/mem_pool_types.rs +++ b/core/src/miner/mem_pool_types.rs @@ -440,24 +440,24 @@ pub struct AccountDetails { #[derive(Default, Clone, Copy, Debug, PartialEq)] /// Minimum fee thresholds defined not by network but by Mempool -pub struct MemPoolFees { - min_pay_transaction_cost: u64, - min_set_regular_key_transaction_cost: u64, - min_create_shard_transaction_cost: u64, - min_set_shard_owners_transaction_cost: u64, - min_set_shard_users_transaction_cost: u64, - min_wrap_ccc_transaction_cost: u64, - min_custom_transaction_cost: u64, - min_store_transaction_cost: u64, - min_remove_transaction_cost: u64, - min_asset_mint_cost: u64, - min_asset_transfer_cost: u64, - min_asset_scheme_change_cost: u64, - min_asset_supply_increase_cost: u64, - min_asset_unwrap_ccc_cost: u64, +pub struct MemPoolMinFees { + pub min_pay_transaction_cost: u64, + pub min_set_regular_key_transaction_cost: u64, + pub min_create_shard_transaction_cost: u64, + pub min_set_shard_owners_transaction_cost: u64, + pub min_set_shard_users_transaction_cost: u64, + pub min_wrap_ccc_transaction_cost: u64, + pub min_custom_transaction_cost: u64, + pub min_store_transaction_cost: u64, + pub min_remove_transaction_cost: u64, + pub min_asset_mint_cost: u64, + pub min_asset_transfer_cost: u64, + pub min_asset_scheme_change_cost: u64, + pub min_asset_supply_increase_cost: u64, + pub min_asset_unwrap_ccc_cost: u64, } -impl MemPoolFees { +impl MemPoolMinFees { #[allow(clippy::too_many_arguments)] pub fn create_from_options( min_pay_cost_option: Option, @@ -475,7 +475,7 @@ impl MemPoolFees { min_asset_supply_increase_cost_option: Option, min_asset_unwrap_ccc_cost_option: Option, ) -> Self { - MemPoolFees { + MemPoolMinFees { min_pay_transaction_cost: min_pay_cost_option.unwrap_or_default(), min_set_regular_key_transaction_cost: min_set_regular_key_cost_option.unwrap_or_default(), min_create_shard_transaction_cost: min_create_shard_cost_option.unwrap_or_default(), diff --git a/core/src/miner/miner.rs b/core/src/miner/miner.rs index cc865d20b8..51a5ff5e70 100644 --- a/core/src/miner/miner.rs +++ b/core/src/miner/miner.rs @@ -15,7 +15,7 @@ // along with this program. If not, see . use super::mem_pool::{Error as MemPoolError, MemPool}; -pub use super::mem_pool_types::MemPoolFees; +pub use super::mem_pool_types::MemPoolMinFees; use super::mem_pool_types::{MemPoolInput, TxOrigin, TxTimelock}; use super::sealing_queue::SealingQueue; use super::work_notify::{NotifyWork, WorkPoster}; @@ -46,7 +46,7 @@ use std::iter::once; use std::ops::Range; use std::sync::atomic::{AtomicBool, Ordering}; use std::sync::Arc; -use std::time::{Duration, Instant}; +use std::time::{Duration, Instant, SystemTime, UNIX_EPOCH}; /// Configures the behaviour of the miner. #[derive(Debug, PartialEq)] @@ -78,7 +78,7 @@ pub struct MinerOptions { /// How many historical work packages can we store before running out? pub work_queue_size: usize, /// Minimum fees configured by the machine. - pub mem_pool_fees: MemPoolFees, + pub mem_pool_min_fees: MemPoolMinFees, } impl Default for MinerOptions { @@ -96,7 +96,7 @@ impl Default for MinerOptions { mem_pool_fee_bump_shift: 3, allow_create_shard: false, work_queue_size: 20, - mem_pool_fees: Default::default(), + mem_pool_min_fees: Default::default(), } } } @@ -124,7 +124,7 @@ pub struct Miner { sealing_enabled: AtomicBool, - accounts: Option>, + accounts: Arc, notifiers: Notifiers, malicious_users: Users, immune_users: Users, @@ -266,20 +266,20 @@ impl Miner { pub fn new( options: MinerOptions, scheme: &Scheme, - accounts: Option>, + accounts: Arc, db: Arc, ) -> Arc { Arc::new(Self::new_raw(options, scheme, accounts, db)) } - pub fn with_scheme(scheme: &Scheme, db: Arc) -> Self { - Self::new_raw(Default::default(), scheme, None, db) + pub fn with_scheme_for_test(scheme: &Scheme, db: Arc) -> Self { + Self::new_raw(Default::default(), scheme, AccountProvider::transient_provider(), db) } fn new_raw( options: MinerOptions, scheme: &Scheme, - accounts: Option>, + accounts: Arc, db: Arc, ) -> Self { let mem_limit = options.mem_pool_memory_limit.unwrap_or_else(usize::max_value); @@ -288,7 +288,7 @@ impl Miner { mem_limit, options.mem_pool_fee_bump_shift, db, - options.mem_pool_fees, + options.mem_pool_min_fees, ))); let notifiers: Vec> = if options.new_work_notify.is_empty() { @@ -401,15 +401,11 @@ impl Miner { self.immune_users.insert(signer_address); } - let origin = self - .accounts - .as_ref() - .and_then(|accounts| match accounts.has_public(&signer_public) { - Ok(true) => Some(TxOrigin::Local), - Ok(false) => None, - Err(_) => None, - }) - .unwrap_or(default_origin); + let origin = if self.accounts.has_public(&signer_public).unwrap_or_default() { + TxOrigin::Local + } else { + default_origin + }; if self.malicious_users.contains(&signer_address) { // FIXME: just to skip, think about another way. @@ -437,7 +433,7 @@ impl Miner { } _ => {} } - cdebug!(MINER, "Rejected transaction {:?} with invalid signature: {:?}", hash, e); + cdebug!(MINER, "Rejected transaction {:?} with error {:?}", hash, e); e })?; @@ -661,7 +657,7 @@ impl Miner { // Check whether transaction type is allowed for sender let result = self.engine.machine().verify_transaction(&tx, open_block.header(), chain, true).and_then(|_| { - open_block.push_transaction(tx, None, chain, parent_header.number(), parent_header.timestamp()) + open_block.push_transaction(tx, chain, parent_header.number(), parent_header.timestamp()) }); match result { @@ -777,7 +773,7 @@ impl Miner { self.engine.proposal_generated(&sealed); } - chain.import_sealed_block(&sealed).is_ok() + chain.import_generated_block(&sealed).is_ok() } /// Are we allowed to do a non-mandatory reseal? @@ -834,24 +830,21 @@ impl MinerService for Miner { self.params.apply(|params| params.author = address); if self.engine_type().need_signer_key() && self.engine.seals_internally().is_some() { - if let Some(ref ap) = self.accounts { - ctrace!(MINER, "Set author to {:?}", address); - // Sign test message - ap.get_unlocked_account(&address)?.sign(&Default::default())?; - // Limit the scope of the locks. - { - let mut sealing_work = self.sealing_work.lock(); - sealing_work.enabled = true; - } - self.engine.set_signer(ap.clone(), address); - Ok(()) - } else { - cwarn!(MINER, "No account provider"); - Err(AccountProviderError::NotFound) + ctrace!(MINER, "Set author to {:?}", address); + // Sign test message + self.accounts.get_unlocked_account(&address)?.sign(&Default::default())?; + // Limit the scope of the locks. + { + let mut sealing_work = self.sealing_work.lock(); + sealing_work.enabled = true; } - } else { - Ok(()) + self.engine.set_signer(Arc::clone(&self.accounts), address); } + Ok(()) + } + + fn get_author_address(&self) -> Address { + self.params.get().author } fn set_extra_data(&self, extra_data: Bytes) { @@ -998,6 +991,14 @@ impl MinerService for Miner { } }; + if std::env::var("RUN_ON_TEST").is_ok() { + let now = SystemTime::now().duration_since(UNIX_EPOCH).expect("There is no time machine.").as_secs(); + if block.header().timestamp() > now { + let delta = block.header().timestamp() - now; + std::thread::sleep(std::time::Duration::from_secs(delta)); + } + } + match self.engine.seals_internally() { Some(true) => { ctrace!(MINER, "update_sealing: engine indicates internal sealing"); @@ -1049,7 +1050,7 @@ impl MinerService for Miner { result.and_then(|sealed| { let n = sealed.header().number(); let h = sealed.header().hash(); - chain.import_sealed_block(&sealed)?; + chain.import_generated_block(&sealed)?; cinfo!(MINER, "Submitted block imported OK. #{}: {}", n, h); Ok(()) }) @@ -1276,7 +1277,7 @@ pub mod test { fn check_add_transactions_result_idx() { let db = Arc::new(kvdb_memorydb::create(NUM_COLUMNS.unwrap())); let scheme = Scheme::new_test(); - let miner = Arc::new(Miner::with_scheme(&scheme, db.clone())); + let miner = Arc::new(Miner::with_scheme_for_test(&scheme, db.clone())); let mut mem_pool = MemPool::with_limits(8192, usize::max_value(), 3, db.clone(), Default::default()); let client = generate_test_client(db, Arc::clone(&miner), &scheme).unwrap(); diff --git a/core/src/miner/mod.rs b/core/src/miner/mod.rs index 10d37fa3eb..64e69c9210 100644 --- a/core/src/miner/mod.rs +++ b/core/src/miner/mod.rs @@ -24,7 +24,7 @@ mod stratum; mod work_notify; use self::mem_pool_types::AccountDetails; -pub use self::mem_pool_types::MemPoolFees; +pub use self::mem_pool_types::MemPoolMinFees; pub use self::miner::{AuthoringParams, Miner, MinerOptions}; pub use self::stratum::{Config as StratumConfig, Error as StratumError, Stratum}; use crate::account_provider::{AccountProvider, Error as AccountProviderError}; @@ -58,6 +58,9 @@ pub trait MinerService: Send + Sync { /// Set the author that we will seal blocks as. fn set_author(&self, author: Address) -> Result<(), AccountProviderError>; + ///Get the address that sealed the block. + fn get_author_address(&self) -> Address; + /// Set the extra_data that we will seal blocks with. fn set_extra_data(&self, extra_data: Bytes); @@ -120,7 +123,7 @@ pub trait MinerService: Send + Sync { ) -> Vec>; /// Imports own (node owner) transaction to mem pool. - fn import_own_transaction( + fn import_own_transaction( &self, chain: &C, tx: SignedTransaction, diff --git a/core/src/scheme/scheme.rs b/core/src/scheme/scheme.rs index e35ec00fb5..7d2f7f4b88 100644 --- a/core/src/scheme/scheme.rs +++ b/core/src/scheme/scheme.rs @@ -17,11 +17,10 @@ use super::pod_state::{PodAccounts, PodShards}; use super::seal::Generic as GenericSeal; use super::Genesis; -use crate::blockchain::HeaderProvider; use crate::codechain_machine::CodeChainMachine; use crate::consensus::{BlakePoW, CodeChainEngine, Cuckoo, NullEngine, SimplePoA, Solo, Tendermint}; use crate::error::{Error, SchemeError}; -use ccrypto::{blake256, BLAKE_NULL_RLP}; +use ccrypto::BLAKE_NULL_RLP; use cdb::{AsHashDB, HashDB}; use cjson; use ckey::Address; @@ -199,19 +198,6 @@ impl Scheme { Ok(self.initialize_state(db)?) } - pub fn check_genesis_common_params(&self, chain: &HP) -> Result<(), Error> { - let genesis_header = self.genesis_header(); - let genesis_header_hash = genesis_header.hash(); - let header = - chain.block_header(&genesis_header_hash).ok_or_else(|| Error::Scheme(SchemeError::InvalidCommonParams))?; - let extra_data = header.extra_data(); - let common_params_hash = blake256(&self.genesis_params().rlp_bytes()).to_vec(); - if extra_data != &common_params_hash { - return Err(Error::Scheme(SchemeError::InvalidCommonParams)) - } - Ok(()) - } - /// Return the state root for the genesis state, memoising accordingly. pub fn state_root(&self) -> H256 { *self.state_root_memo.read() @@ -291,7 +277,7 @@ impl Scheme { header.set_number(0); header.set_author(self.author); header.set_transactions_root(self.transactions_root); - header.set_extra_data(blake256(&self.genesis_params().rlp_bytes()).to_vec()); + header.set_extra_data(self.extra_data.clone()); header.set_state_root(self.state_root()); header.set_score(self.score); header.set_seal({ @@ -354,21 +340,3 @@ fn load_from(s: cjson::scheme::Scheme) -> Result { Ok(s) } - -#[cfg(test)] -mod tests { - use ccrypto::Blake; - - use super::*; - - #[test] - fn extra_data_of_genesis_header_is_hash_of_common_params() { - let scheme = Scheme::new_test(); - let common_params = scheme.genesis_params(); - let hash_of_common_params = H256::blake(&common_params.rlp_bytes()).to_vec(); - - let genesis_header = scheme.genesis_header(); - let result = genesis_header.extra_data(); - assert_eq!(&hash_of_common_params, result); - } -} diff --git a/core/src/service.rs b/core/src/service.rs index cb75c7d7f5..59347bcb66 100644 --- a/core/src/service.rs +++ b/core/src/service.rs @@ -20,7 +20,6 @@ use crate::miner::Miner; use crate::scheme::Scheme; use crate::BlockId; use cio::{IoContext, IoHandler, IoHandlerResult, IoService}; -use cnetwork::NodeId; use ctimer::TimerApi; use ctypes::BlockHash; use kvdb::KeyValueDB; @@ -71,7 +70,7 @@ pub enum ClientIoMessage { /// A header is ready HeaderVerified, /// New transaction RLPs are ready to be imported - NewTransactions(Vec, NodeId), + NewTransactions(Vec), /// Block generation is required NewBlockRequired { parent_block: BlockId, @@ -96,8 +95,8 @@ impl IoHandler for ClientIoHandler { ClientIoMessage::HeaderVerified => { self.client.import_verified_headers(); } - ClientIoMessage::NewTransactions(transactions, peer_id) => { - self.client.import_queued_transactions(&transactions, peer_id); + ClientIoMessage::NewTransactions(transactions) => { + self.client.import_queued_transactions(&transactions); } ClientIoMessage::NewBlockRequired { parent_block, diff --git a/core/src/tests/helpers.rs b/core/src/tests/helpers.rs index 348f547bca..57015d63bc 100644 --- a/core/src/tests/helpers.rs +++ b/core/src/tests/helpers.rs @@ -15,7 +15,6 @@ // along with this program. If not, see . use crate::scheme::Scheme; -use crate::transaction::SignedTransaction; use cstate::StateDB; use ctypes::{BlockHash, Header}; use primitives::{Bytes, U256}; @@ -28,18 +27,6 @@ pub fn create_test_block(header: &Header) -> Bytes { rlp.out() } -#[allow(dead_code)] -pub fn create_test_block_with_data(header: &Header, txs: &[SignedTransaction], uncles: &[Header]) -> Bytes { - let mut rlp = RlpStream::new_list(3); - rlp.append(header); - rlp.begin_list(txs.len()); - for t in txs { - rlp.append_raw(&rlp::encode(t), 1); - } - rlp.append_list(&uncles); - rlp.out() -} - pub fn get_good_dummy_block() -> Bytes { let (_, bytes) = get_good_dummy_block_hash(); bytes diff --git a/core/src/verification/canon_verifier.rs b/core/src/verification/canon_verifier.rs deleted file mode 100644 index 86adff0411..0000000000 --- a/core/src/verification/canon_verifier.rs +++ /dev/null @@ -1,47 +0,0 @@ -// Copyright 2018-2019 Kodebox, Inc. -// This file is part of CodeChain. -// -// This program is free software: you can redistribute it and/or modify -// it under the terms of the GNU Affero General Public License as -// published by the Free Software Foundation, either version 3 of the -// License, or (at your option) any later version. -// -// This program is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU Affero General Public License for more details. -// -// You should have received a copy of the GNU Affero General Public License -// along with this program. If not, see . - -use super::verification; -use super::Verifier; -use crate::client::BlockChainTrait; -use crate::consensus::CodeChainEngine; -use crate::error::Error; -use ctypes::{CommonParams, Header}; - -/// A canonial verifier -- this does full verification. -pub struct CanonVerifier; - -impl Verifier for CanonVerifier { - fn verify_block_family( - &self, - block: &[u8], - header: &Header, - parent: &Header, - engine: &dyn CodeChainEngine, - do_full: Option>, - common_params: &CommonParams, - ) -> Result<(), Error> { - verification::verify_block_family(block, header, parent, engine, do_full, common_params) - } - - fn verify_block_final(&self, expected: &Header, got: &Header) -> Result<(), Error> { - verification::verify_block_final(expected, got) - } - - fn verify_block_external(&self, header: &Header, engine: &dyn CodeChainEngine) -> Result<(), Error> { - engine.verify_block_external(header) - } -} diff --git a/core/src/verification/mod.rs b/core/src/verification/mod.rs index a13cb4a00e..dce8ca2e85 100644 --- a/core/src/verification/mod.rs +++ b/core/src/verification/mod.rs @@ -14,53 +14,11 @@ // You should have received a copy of the GNU Affero General Public License // along with this program. If not, see . -mod canon_verifier; -mod noop_verifier; pub mod queue; #[cfg_attr(feature = "cargo-clippy", allow(clippy::module_inception))] mod verification; mod verifier; -pub use self::canon_verifier::CanonVerifier; -pub use self::noop_verifier::NoopVerifier; pub use self::queue::{BlockQueue, Config as QueueConfig}; pub use self::verification::*; pub use self::verifier::Verifier; - -use crate::client::BlockChainTrait; - -/// Verifier type. -#[derive(Debug, PartialEq, Clone, Copy)] -pub enum VerifierType { - /// Verifies block normally. - Canon, - /// Verifies block normally, but skips seal verification. - CanonNoSeal, - /// Does not verify block at all. - /// Used in tests. - Noop, -} - -impl VerifierType { - /// Check if seal verification is enabled for this verifier type. - pub fn verifying_seal(self) -> bool { - match self { - VerifierType::Canon => true, - VerifierType::Noop | VerifierType::CanonNoSeal => false, - } - } -} - -impl Default for VerifierType { - fn default() -> Self { - VerifierType::Canon - } -} - -/// Create a new verifier based on type. -pub fn new(v: VerifierType) -> Box> { - match v { - VerifierType::Canon | VerifierType::CanonNoSeal => Box::new(CanonVerifier), - VerifierType::Noop => Box::new(NoopVerifier), - } -} diff --git a/core/src/verification/noop_verifier.rs b/core/src/verification/noop_verifier.rs deleted file mode 100644 index 9321de701b..0000000000 --- a/core/src/verification/noop_verifier.rs +++ /dev/null @@ -1,46 +0,0 @@ -// Copyright 2018-2019 Kodebox, Inc. -// This file is part of CodeChain. -// -// This program is free software: you can redistribute it and/or modify -// it under the terms of the GNU Affero General Public License as -// published by the Free Software Foundation, either version 3 of the -// License, or (at your option) any later version. -// -// This program is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU Affero General Public License for more details. -// -// You should have received a copy of the GNU Affero General Public License -// along with this program. If not, see . - -use super::{verification, Verifier}; -use crate::client::BlockChainTrait; -use crate::consensus::CodeChainEngine; -use crate::error::Error; -use ctypes::{CommonParams, Header}; - -/// A no-op verifier -- this will verify everything it's given immediately. -pub struct NoopVerifier; - -impl Verifier for NoopVerifier { - fn verify_block_family( - &self, - _block: &[u8], - _: &Header, - _t: &Header, - _: &dyn CodeChainEngine, - _: Option>, - _common_params: &CommonParams, - ) -> Result<(), Error> { - Ok(()) - } - - fn verify_block_final(&self, _expected: &Header, _got: &Header) -> Result<(), Error> { - Ok(()) - } - - fn verify_block_external(&self, _header: &Header, _engine: &dyn CodeChainEngine) -> Result<(), Error> { - Ok(()) - } -} diff --git a/core/src/verification/queue/mod.rs b/core/src/verification/queue/mod.rs index 7f060a4b8a..0b060e0872 100644 --- a/core/src/verification/queue/mod.rs +++ b/core/src/verification/queue/mod.rs @@ -68,8 +68,6 @@ pub struct VerificationQueue { deleting: Arc, ready_signal: Arc, total_score: RwLock, - #[allow(dead_code)] - empty: Arc, more_to_verify: Arc, verifier_handles: Vec>, max_queue_size: usize, @@ -135,7 +133,6 @@ impl VerificationQueue { verified: AtomicUsize::new(0), }, check_seal, - empty_mutex: SMutex::new(()), more_to_verify_mutex: SMutex::new(()), }); let deleting = Arc::new(AtomicBool::new(false)); @@ -182,7 +179,6 @@ impl VerificationQueue { deleting, ready_signal, total_score: RwLock::new(0.into()), - empty, more_to_verify, verifier_handles, max_queue_size: cmp::max(config.max_queue_size, MIN_QUEUE_LIMIT), @@ -511,8 +507,6 @@ struct Verification { bad: Mutex>, sizes: Sizes, check_seal: bool, - #[allow(dead_code)] - empty_mutex: SMutex<()>, more_to_verify_mutex: SMutex<()>, } diff --git a/core/src/verification/verifier.rs b/core/src/verification/verifier.rs index 7b032da593..4fcb058bbe 100644 --- a/core/src/verification/verifier.rs +++ b/core/src/verification/verifier.rs @@ -19,13 +19,26 @@ use crate::client::BlockChainTrait; use crate::consensus::CodeChainEngine; use crate::error::Error; use ctypes::{CommonParams, Header}; +use std::marker::PhantomData; /// Should be used to verify blocks. -pub trait Verifier: Send + Sync +pub struct Verifier where C: BlockChainTrait, { + phantom: PhantomData, +} + +impl Verifier { + pub fn new() -> Self { + Self { + phantom: Default::default(), + } + } +} + +impl Verifier { /// Verify a block relative to its parent and uncles. - fn verify_block_family( + pub fn verify_block_family( &self, block: &[u8], header: &Header, @@ -33,10 +46,17 @@ where engine: &dyn CodeChainEngine, do_full: Option>, common_params: &CommonParams, - ) -> Result<(), Error>; + ) -> Result<(), Error> { + verification::verify_block_family(block, header, parent, engine, do_full, common_params) + } /// Do a final verification check for an enacted header vs its expected counterpart. - fn verify_block_final(&self, expected: &Header, got: &Header) -> Result<(), Error>; + pub fn verify_block_final(&self, expected: &Header, got: &Header) -> Result<(), Error> { + verification::verify_block_final(expected, got) + } + /// Verify a block, inspecting external state. - fn verify_block_external(&self, header: &Header, engine: &dyn CodeChainEngine) -> Result<(), Error>; + pub fn verify_block_external(&self, header: &Header, engine: &dyn CodeChainEngine) -> Result<(), Error> { + engine.verify_block_external(header) + } } diff --git a/discovery/Cargo.toml b/discovery/Cargo.toml index f04144ecce..d5f30532f2 100644 --- a/discovery/Cargo.toml +++ b/discovery/Cargo.toml @@ -5,14 +5,14 @@ authors = ["CodeChain Team "] edition = "2018" [dependencies] -codechain-crypto = { git = "https://github.com/CodeChain-io/rust-codechain-crypto.git", version = "0.1" } +codechain-crypto = { git = "https://github.com/CodeChain-io/rust-codechain-crypto.git", version = "0.2" } codechain-key = { path = "../key" } codechain-logger = { path = "../util/logger" } codechain-network = { path = "../network" } codechain-timer = { path = "../util/timer" } log = "0.4.6" never-type = "0.1.0" -parking_lot = "0.6.0" +parking_lot = "0.11.0" primitives = { git = "https://github.com/CodeChain-io/rust-codechain-primitives.git", version = "0.4" } rand = "0.6.1" rlp = { git = "https://github.com/CodeChain-io/rlp.git", version = "0.4" } diff --git a/key/Cargo.toml b/key/Cargo.toml index 8a3b6cadad..5c59bc36c1 100644 --- a/key/Cargo.toml +++ b/key/Cargo.toml @@ -10,9 +10,9 @@ rustc-hex = "1.0" rustc-serialize = "0.3" lazy_static = "1.2" bech32 = "0.2.2" -codechain-crypto = { git = "https://github.com/CodeChain-io/rust-codechain-crypto.git", version = "0.1" } +codechain-crypto = { git = "https://github.com/CodeChain-io/rust-codechain-crypto.git", version = "0.2" } never-type = "0.1.0" -parking_lot = "0.6.0" +parking_lot = "0.11.0" primitives = { git = "https://github.com/CodeChain-io/rust-codechain-primitives.git", version = "0.4" } rand_xorshift = "0.1.0" rlp = { git = "https://github.com/CodeChain-io/rlp.git", version = "0.4" } diff --git a/keystore/Cargo.toml b/keystore/Cargo.toml index 8c091d432a..aeb8e45751 100644 --- a/keystore/Cargo.toml +++ b/keystore/Cargo.toml @@ -16,8 +16,8 @@ serde_json = "1.0" serde_derive = "1.0" rustc-hex = "1.0" time = "0.1.34" -parking_lot = "0.6.0" -codechain-crypto = { git = "https://github.com/CodeChain-io/rust-codechain-crypto.git", version = "0.1" } +parking_lot = "0.11.0" +codechain-crypto = { git = "https://github.com/CodeChain-io/rust-codechain-crypto.git", version = "0.2" } smallvec = "0.4" tempdir = "0.3" diff --git a/keystore/src/account/decrypted_account.rs b/keystore/src/account/decrypted_account.rs index d9b4ce08ec..6169da3bd4 100644 --- a/keystore/src/account/decrypted_account.rs +++ b/keystore/src/account/decrypted_account.rs @@ -19,6 +19,7 @@ use ckey::{ }; /// An opaque wrapper for secret. +#[derive(Clone)] pub struct DecryptedAccount { secret: Secret, } diff --git a/network/Cargo.toml b/network/Cargo.toml index c3c89e7502..a11a8d966a 100644 --- a/network/Cargo.toml +++ b/network/Cargo.toml @@ -5,7 +5,7 @@ authors = ["CodeChain Team "] edition = "2018" [dependencies] -codechain-crypto = { git = "https://github.com/CodeChain-io/rust-codechain-crypto.git", version = "0.1" } +codechain-crypto = { git = "https://github.com/CodeChain-io/rust-codechain-crypto.git", version = "0.2" } codechain-io = { path = "../util/io" } codechain-key = { path = "../key" } codechain-logger = { path = "../util/logger" } @@ -18,7 +18,7 @@ log = "0.4.6" kvdb = "0.1" mio = "0.6.16" never-type = "0.1.0" -parking_lot = "0.6.0" +parking_lot = "0.11.0" rand = "0.6.1" rlp = { git = "https://github.com/CodeChain-io/rlp.git", version = "0.4" } rlp_derive = { git = "https://github.com/CodeChain-io/rlp.git", version = "0.2" } diff --git a/network/src/p2p/connection/mod.rs b/network/src/p2p/connection/mod.rs index edacbc470f..4be1cc72e5 100644 --- a/network/src/p2p/connection/mod.rs +++ b/network/src/p2p/connection/mod.rs @@ -1,4 +1,4 @@ -// Copyright 2019 Kodebox, Inc. +// Copyright 2019-2020 Kodebox, Inc. // This file is part of CodeChain. // // This program is free software: you can redistribute it and/or modify @@ -19,7 +19,7 @@ mod incoming; mod message; mod outgoing; -use ccrypto::aes::SymmetricCipherError; +use ccrypto::error::SymmError; use rlp::DecoderError; use std::fmt; use std::io; @@ -36,7 +36,7 @@ use super::stream::Error as P2pStreamError; #[derive(Debug)] pub enum Error { - SymmetricCipher(SymmetricCipherError), + SymmetricCipher(SymmError), IoError(io::Error), Decoder(DecoderError), InvalidSign, @@ -78,8 +78,8 @@ impl From for Error { } } -impl From for Error { - fn from(err: SymmetricCipherError) -> Self { +impl From for Error { + fn from(err: SymmError) -> Self { Error::SymmetricCipher(err) } } diff --git a/network/src/p2p/handler.rs b/network/src/p2p/handler.rs index 4a1498ff16..1f12b11749 100644 --- a/network/src/p2p/handler.rs +++ b/network/src/p2p/handler.rs @@ -1,4 +1,4 @@ -// Copyright 2018-2019 Kodebox, Inc. +// Copyright 2018-2020 Kodebox, Inc. // This file is part of CodeChain. // // This program is free software: you can redistribute it and/or modify @@ -20,10 +20,11 @@ use super::connection::{ use super::listener::Listener; use super::{NegotiationMessage, NetworkMessage}; use crate::client::Client; +use crate::p2p::connection::Error as P2PConnectionError; use crate::session::Session; use crate::stream::Stream; use crate::{FiltersControl, NodeId, RoutingTable, SocketAddr}; -use ccrypto::aes::SymmetricCipherError; +use ccrypto::error::SymmError; use cio::{IoChannel, IoContext, IoHandler, IoHandlerResult, IoManager, StreamToken, TimerToken}; use ckey::NetworkId; use finally_block::finally; @@ -242,7 +243,7 @@ impl Handler { let mut result = HashMap::with_capacity(network_usage_in_10_seconds.len()); let now = Instant::now(); for (name, times) in &mut *network_usage_in_10_seconds { - remove_outdated_network_usage(times, &now); + remove_outdated_network_usage(times, now); let total = times.iter().map(|(_, usage)| usage).sum(); if total != 0 { result.insert(name.clone(), total); @@ -662,7 +663,13 @@ impl IoHandler for Handler { io.update_registration(stream_token); } }); - match con.receive()? { + let received = con.receive(); + if let Err(P2PConnectionError::IoError(ioerr)) = &received { + if ioerr.kind() == std::io::ErrorKind::ConnectionAborted { + io.deregister_stream(stream_token); + } + }; + match received? { Some(NetworkMessage::Extension(msg)) => { let remote_node_id = *self.remote_node_ids.read().get(&stream_token).unwrap_or_else(|| { unreachable!("Node id for {}:{} must exist", stream_token, con.peer_addr()) @@ -731,7 +738,13 @@ impl IoHandler for Handler { io.update_registration(stream_token); } }); - match con.receive()? { + let received = con.receive(); + if let Err(P2PConnectionError::IoError(ioerr)) = &received { + if ioerr.kind() == std::io::ErrorKind::ConnectionAborted { + io.deregister_stream(stream_token); + } + }; + match received? { Some(NetworkMessage::Extension(msg)) => { let remote_node_id = *self.remote_node_ids.read().get(&stream_token).unwrap_or_else(|| { unreachable!("Node id for {}:{} must exist", stream_token, con.peer_addr()) @@ -776,7 +789,13 @@ impl IoHandler for Handler { io.update_registration(stream_token); } }); - match con.receive()? { + let received = con.receive(); + if let Err(P2PConnectionError::IoError(ioerr)) = &received { + if ioerr.kind() == std::io::ErrorKind::ConnectionAborted { + io.deregister_stream(stream_token); + } + }; + match received? { Some(OutgoingMessage::Sync1 { initiator_pub_key, network_id, @@ -871,7 +890,13 @@ impl IoHandler for Handler { } }); let from = *con.peer_addr(); - match con.receive()? { + let received = con.receive(); + if let Err(P2PConnectionError::IoError(ioerr)) = &received { + if ioerr.kind() == std::io::ErrorKind::ConnectionAborted { + io.deregister_stream(stream_token); + } + }; + match received? { Some(IncomingMessage::Ack { recipient_pub_key, encrypted_nonce, @@ -908,32 +933,56 @@ impl IoHandler for Handler { Ok(()) } - fn stream_writable(&self, _io: &IoContext, stream: StreamToken) -> IoHandlerResult<()> { + fn stream_writable(&self, io: &IoContext, stream: StreamToken) -> IoHandlerResult<()> { match stream { FIRST_INBOUND..=LAST_INBOUND => { if let Some(con) = self.inbound_connections.write().get_mut(&stream) { - con.flush()?; + let flush_result = con.flush(); + if let Err(P2PConnectionError::IoError(io_error)) = &flush_result { + if io_error.kind() == std::io::ErrorKind::BrokenPipe { + io.deregister_stream(stream); + } + } + flush_result?; } else { cdebug!(NETWORK, "Invalid inbound token({}) on write", stream); } } FIRST_OUTBOUND..=LAST_OUTBOUND => { if let Some(con) = self.outbound_connections.write().get_mut(&stream) { - con.flush()?; + let flush_result = con.flush(); + if let Err(P2PConnectionError::IoError(io_error)) = &flush_result { + if io_error.kind() == std::io::ErrorKind::BrokenPipe { + io.deregister_stream(stream); + } + } + flush_result?; } else { cdebug!(NETWORK, "Invalid outbound token({}) on write", stream); } } FIRST_INCOMING..=LAST_INCOMING => { if let Some(con) = self.incoming_connections.write().get_mut(&stream) { - con.flush()?; + let flush_result = con.flush(); + if let Err(P2PConnectionError::IoError(io_error)) = &flush_result { + if io_error.kind() == std::io::ErrorKind::BrokenPipe { + io.deregister_stream(stream); + } + } + flush_result?; } else { cdebug!(NETWORK, "Invalid incoming token({}) on write", stream); } } FIRST_OUTGOING..=LAST_OUTGOING => { if let Some(con) = self.outgoing_connections.write().get_mut(&stream) { - con.flush()?; + let flush_result = con.flush(); + if let Err(P2PConnectionError::IoError(io_error)) = &flush_result { + if io_error.kind() == std::io::ErrorKind::BrokenPipe { + io.deregister_stream(stream); + } + } + flush_result?; } else { cdebug!(NETWORK, "Invalid outgoing token({}) on write", stream); } @@ -1155,8 +1204,8 @@ impl IoHandler for Handler { } } -impl From for Error { - fn from(err: SymmetricCipherError) -> Self { +impl From for Error { + fn from(err: SymmError) -> Self { Error::SymmetricCipher(err) } } @@ -1186,7 +1235,7 @@ pub enum Message { #[derive(Debug)] enum Error { InvalidNode(NodeId), - SymmetricCipher(SymmetricCipherError), + SymmetricCipher(SymmError), } impl ::std::fmt::Display for Error { @@ -1198,9 +1247,9 @@ impl ::std::fmt::Display for Error { } } -fn remove_outdated_network_usage(usage_per_extension: &mut VecDeque<(Instant, usize)>, now: &Instant) { +fn remove_outdated_network_usage(usage_per_extension: &mut VecDeque<(Instant, usize)>, now: Instant) { while let Some((time, size)) = usage_per_extension.pop_front() { - if *now < time { + if now < time { usage_per_extension.push_front((time, size)); break } @@ -1209,6 +1258,6 @@ fn remove_outdated_network_usage(usage_per_extension: &mut VecDeque<(Instant, us fn insert_network_usage(usage_per_extension: &mut VecDeque<(Instant, usize)>, network_message_size: usize) { let now = Instant::now(); - remove_outdated_network_usage(usage_per_extension, &now); + remove_outdated_network_usage(usage_per_extension, now); usage_per_extension.push_back((now + Duration::from_secs(10), network_message_size)); } diff --git a/network/src/p2p/message/extension.rs b/network/src/p2p/message/extension.rs index bb74bc98ce..5d3d7e0fce 100644 --- a/network/src/p2p/message/extension.rs +++ b/network/src/p2p/message/extension.rs @@ -1,4 +1,4 @@ -// Copyright 2018-2019 Kodebox, Inc. +// Copyright 2018-2020 Kodebox, Inc. // This file is part of CodeChain. // // This program is free software: you can redistribute it and/or modify @@ -17,7 +17,8 @@ use super::ENCRYPTED_ID; use super::UNENCRYPTED_ID; use crate::session::Session; -use ccrypto::aes::{self, SymmetricCipherError}; +use ccrypto::aes; +use ccrypto::error::SymmError; use primitives::Bytes; use rlp::{Decodable, DecoderError, Encodable, Rlp, RlpStream}; use std::sync::Arc; @@ -47,7 +48,7 @@ impl Message { extension_name: String, unencrypted_data: &[u8], session: &Session, - ) -> Result { + ) -> Result { let encrypted = aes::encrypt(unencrypted_data, session.secret(), &session.nonce())?; Ok(Self::encrypted(extension_name, encrypted)) } @@ -73,7 +74,7 @@ impl Message { } } - pub fn unencrypted_data(&self, session: &Session) -> Result, SymmetricCipherError> { + pub fn unencrypted_data(&self, session: &Session) -> Result, SymmError> { match self { Message::Encrypted { encrypted, @@ -124,7 +125,7 @@ impl Decodable for Message { let item_count = rlp.item_count()?; if item_count != 3 { return Err(DecoderError::RlpInvalidLength { - expected: 5, + expected: 3, got: item_count, }) } diff --git a/network/src/routing_table.rs b/network/src/routing_table.rs index dd8ed4d1b1..cb33539f57 100644 --- a/network/src/routing_table.rs +++ b/network/src/routing_table.rs @@ -1,4 +1,4 @@ -// Copyright 2018-2019 Kodebox, Inc. +// Copyright 2018-2020 Kodebox, Inc. // This file is part of CodeChain. // // This program is free software: you can redistribute it and/or modify @@ -16,7 +16,8 @@ use crate::session::{Nonce, Session}; use crate::SocketAddr; -use ccrypto::aes::{self, SymmetricCipherError}; +use ccrypto::aes; +use ccrypto::error::SymmError; use ckey::{exchange, Generator, KeyPair, Public, Random, Secret}; use parking_lot::{Mutex, RwLock}; use primitives::Bytes; @@ -506,8 +507,7 @@ impl RoutingTable { State::Establishing1(local_key_pair) => { let shared_secret = exchange(&remote_public, local_key_pair.private()) .map_err(|e| format!("Cannot exchange key: {:?}", e))?; - let nonce = decrypt_nonce(encrypted_nonce, &shared_secret) - .map_err(|e| format!("Cannot decrypt nonce: {:?}", e))?; + let nonce = decrypt_nonce(encrypted_nonce, &shared_secret)?; State::Established { local_key_pair: *local_key_pair, remote_public, @@ -529,8 +529,7 @@ impl RoutingTable { )) } debug_assert_eq!(*shared_secret, exchange(&remote_public, local_key_pair.private()).unwrap()); - let nonce = decrypt_nonce(encrypted_nonce, &shared_secret) - .map_err(|e| format!("Cannot decrypt nonce: {:?}", e))?; + let nonce = decrypt_nonce(encrypted_nonce, &shared_secret)?; State::Established { local_key_pair: *local_key_pair, remote_public, @@ -618,19 +617,23 @@ impl RoutingTable { } } -fn decrypt_nonce(encrypted_bytes: &[u8], shared_secret: &Secret) -> Result { +fn decrypt_nonce(encrypted_bytes: &[u8], shared_secret: &Secret) -> Result { let iv = 0; // FIXME: Use proper iv - let unecrypted = aes::decrypt(encrypted_bytes, shared_secret, &iv)?; + let unecrypted = + aes::decrypt(encrypted_bytes, shared_secret, &iv).map_err(|e| format!("Cannot decrypt nonce: {:?}", e))?; debug_assert_eq!(std::mem::size_of::(), 16); if unecrypted.len() != 16 { - return Err(SymmetricCipherError::InvalidLength) // FIXME + return Err(format!( + "Cannot decrpyt nonce: 16 length bytes expected but, {} length bytes received", + unecrypted.len() + )) // FIXME } let mut nonce_bytes = [0u8; 16]; nonce_bytes.copy_from_slice(&unecrypted); Ok(Nonce::from_be_bytes(nonce_bytes)) } -fn encrypt_nonce(nonce: Nonce, shared_secret: &Secret) -> Result { +fn encrypt_nonce(nonce: Nonce, shared_secret: &Secret) -> Result { let iv = 0; // FIXME: Use proper iv Ok(aes::encrypt(&nonce.to_be_bytes(), shared_secret, &iv)?) } diff --git a/network/src/session/session.rs b/network/src/session/session.rs index 21b4993a3e..1f3967dc06 100644 --- a/network/src/session/session.rs +++ b/network/src/session/session.rs @@ -1,4 +1,4 @@ -// Copyright 2018-2019 Kodebox, Inc. +// Copyright 2018-2020 Kodebox, Inc. // This file is part of CodeChain. // // This program is free software: you can redistribute it and/or modify @@ -15,7 +15,8 @@ // along with this program. If not, see . use super::Nonce; -use ccrypto::aes::{self, SymmetricCipherError}; +use ccrypto::aes; +use ccrypto::error::SymmError; use ccrypto::Blake; use ckey::Secret; use primitives::H256; @@ -26,8 +27,6 @@ pub struct Session { nonce: Nonce, } -type Error = SymmetricCipherError; - impl Session { pub fn new_with_zero_nonce(secret: Secret) -> Self { Self::new(secret, 0) @@ -52,11 +51,11 @@ impl Session { self.nonce } - pub fn encrypt(&self, data: &[u8]) -> Result, Error> { + pub fn encrypt(&self, data: &[u8]) -> Result, SymmError> { Ok(aes::encrypt(&data, &self.secret, &self.nonce())?) } - pub fn decrypt(&self, data: &[u8]) -> Result, Error> { + pub fn decrypt(&self, data: &[u8]) -> Result, SymmError> { Ok(aes::decrypt(&data, &self.secret, &self.nonce())?) } diff --git a/network/src/stream.rs b/network/src/stream.rs index 6651def14a..ffe1f30edb 100644 --- a/network/src/stream.rs +++ b/network/src/stream.rs @@ -109,6 +109,9 @@ impl TryStream { assert!(read_size < len_of_len, "{} should be less than {}", read_size, len_of_len); if let Some(new_read_size) = self.stream.try_read(&mut bytes[(1 + read_size)..=len_of_len])? { + if new_read_size == 0 { + return Err(io::Error::new(io::ErrorKind::ConnectionAborted, "EOF")) + } read_size += new_read_size; }; if len_of_len == read_size { @@ -128,7 +131,7 @@ impl TryStream { if let Some(read_size) = self.stream.try_read(&mut bytes)? { if read_size == 0 { - return Ok(None) + return Err(io::Error::new(io::ErrorKind::ConnectionAborted, "EOF").into()) } debug_assert_eq!(1, read_size); if 0xf8 <= bytes[0] { @@ -184,6 +187,9 @@ impl TryStream { while remain_length != 0 { let to_be_read = ::std::cmp::min(remain_length, 1024); if let Some(read_size) = self.stream.try_read(&mut bytes[0..to_be_read])? { + if read_size == 0 { + return Err(io::Error::new(io::ErrorKind::ConnectionAborted, "EOF").into()) + } result.extend_from_slice(&bytes[..read_size]); debug_assert!(remain_length >= read_size); remain_length -= read_size; diff --git a/rpc/Cargo.toml b/rpc/Cargo.toml index aea4fc5467..5b97f9465d 100644 --- a/rpc/Cargo.toml +++ b/rpc/Cargo.toml @@ -9,7 +9,7 @@ edition = "2018" [dependencies] cidr = "0.0.4" codechain-core = { path = "../core" } -codechain-crypto = { git = "https://github.com/CodeChain-io/rust-codechain-crypto.git", version = "0.1" } +codechain-crypto = { git = "https://github.com/CodeChain-io/rust-codechain-crypto.git", version = "0.2" } codechain-json = { path = "../json" } codechain-key = { path = "../key" } codechain-keystore = { path = "../keystore" } @@ -23,7 +23,7 @@ kvdb = "0.1" kvdb-rocksdb = "0.1" lazy_static = "1.2" log = "0.4.6" -parking_lot = "0.6.0" +parking_lot = "0.11.0" primitives = { git = "https://github.com/CodeChain-io/rust-codechain-primitives.git", version = "0.4" } rlp = { git = "https://github.com/CodeChain-io/rlp.git", version = "0.4" } serde = "1.0" diff --git a/rpc/src/v1/impls/devel.rs b/rpc/src/v1/impls/devel.rs index fb39ecf846..8231b5cd63 100644 --- a/rpc/src/v1/impls/devel.rs +++ b/rpc/src/v1/impls/devel.rs @@ -1,4 +1,4 @@ -// Copyright 2018-2019 Kodebox, Inc. +// Copyright 2018-2020 Kodebox, Inc. // This file is part of CodeChain. // // This program is free software: you can redistribute it and/or modify @@ -29,7 +29,7 @@ use csync::BlockSyncEvent; use ctypes::transaction::{ Action, AssetMintOutput, AssetOutPoint, AssetTransferInput, AssetTransferOutput, Transaction, }; -use ctypes::{Tracker, TxHash}; +use ctypes::{BlockHash, Tracker, TxHash}; use jsonrpc_core::Result; use kvdb::KeyValueDB; use primitives::{H160, H256}; @@ -106,6 +106,26 @@ where } } + fn get_peer_best_block_hashes(&self) -> Result> { + if let Some(block_sync) = self.block_sync.as_ref() { + let (sender, receiver) = unbounded_event_callback(); + block_sync.send(BlockSyncEvent::GetPeerBestBlockHashes(sender)).unwrap(); + Ok(receiver.iter().collect()) + } else { + Ok(Vec::new()) + } + } + + fn get_target_block_hashes(&self) -> Result> { + if let Some(block_sync) = self.block_sync.as_ref() { + let (sender, receiver) = unbounded_event_callback(); + block_sync.send(BlockSyncEvent::GetTargetBlockHashes(sender)).unwrap(); + Ok(receiver.iter().collect()) + } else { + Ok(Vec::new()) + } + } + fn test_tps(&self, setting: TPSTestSetting) -> Result { let common_params = self.client.common_params(BlockId::Latest).unwrap(); let mint_fee = common_params.min_asset_mint_cost(); diff --git a/rpc/src/v1/impls/mempool.rs b/rpc/src/v1/impls/mempool.rs index c5cb2c2db9..9a386a5eac 100644 --- a/rpc/src/v1/impls/mempool.rs +++ b/rpc/src/v1/impls/mempool.rs @@ -16,7 +16,7 @@ use super::super::errors; use super::super::traits::Mempool; -use super::super::types::PendingTransactions; +use super::super::types::{MemPoolMinFees, PendingTransactions}; use ccore::{BlockChainClient, EngineInfo, MiningBlockChainClient, SignedTransaction}; use cjson::bytes::Bytes; use ckey::{Address, PlatformAddress}; @@ -132,4 +132,8 @@ where self.client.register_immune_users(immune_user_vec); Ok(()) } + + fn get_machine_minimum_fees(&self) -> Result { + Ok(MemPoolMinFees::from(self.client.mem_pool_min_fees())) + } } diff --git a/rpc/src/v1/traits/devel.rs b/rpc/src/v1/traits/devel.rs index 351c1ab096..8ea0f735f0 100644 --- a/rpc/src/v1/traits/devel.rs +++ b/rpc/src/v1/traits/devel.rs @@ -1,4 +1,4 @@ -// Copyright 2018 Kodebox, Inc. +// Copyright 2018-2020 Kodebox, Inc. // This file is part of CodeChain. // // This program is free software: you can redistribute it and/or modify @@ -16,6 +16,7 @@ use super::super::types::TPSTestSetting; use cjson::bytes::Bytes; +use ctypes::BlockHash; use jsonrpc_core::Result; use primitives::H256; use std::net::SocketAddr; @@ -37,6 +38,12 @@ pub trait Devel { #[rpc(name = "devel_getBlockSyncPeers")] fn get_block_sync_peers(&self) -> Result>; + #[rpc(name = "devel_getPeerBestBlockHashes")] + fn get_peer_best_block_hashes(&self) -> Result>; + + #[rpc(name = "devel_getTargetBlockHashes")] + fn get_target_block_hashes(&self) -> Result>; + #[rpc(name = "devel_testTPS")] fn test_tps(&self, setting: TPSTestSetting) -> Result; } diff --git a/rpc/src/v1/traits/mempool.rs b/rpc/src/v1/traits/mempool.rs index 8ea69d4e25..392cd06a3a 100644 --- a/rpc/src/v1/traits/mempool.rs +++ b/rpc/src/v1/traits/mempool.rs @@ -14,7 +14,7 @@ // You should have received a copy of the GNU Affero General Public License // along with this program. If not, see . -use super::super::types::PendingTransactions; +use super::super::types::{MemPoolMinFees, PendingTransactions}; use cjson::bytes::Bytes; use ckey::PlatformAddress; use ctypes::{Tracker, TxHash}; @@ -70,4 +70,7 @@ pub trait Mempool { #[rpc(name = "mempool_registerImmuneAccounts")] fn register_immune_accounts(&self, immune_user_list: Vec) -> Result<()>; + + #[rpc(name = "mempool_getMachineMinimumFees")] + fn get_machine_minimum_fees(&self) -> Result; } diff --git a/rpc/src/v1/types/mem_pool.rs b/rpc/src/v1/types/mem_pool.rs new file mode 100644 index 0000000000..6ba73aa20d --- /dev/null +++ b/rpc/src/v1/types/mem_pool.rs @@ -0,0 +1,55 @@ +// Copyright 2020 Kodebox, Inc. +// This file is part of CodeChain. +// +// This program is free software: you can redistribute it and/or modify +// it under the terms of the GNU Affero General Public License as +// published by the Free Software Foundation, either version 3 of the +// License, or (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU Affero General Public License for more details. +// +// You should have received a copy of the GNU Affero General Public License +// along with this program. If not, see . + +#[derive(Debug, Serialize)] +#[serde(rename_all = "camelCase")] +pub struct MemPoolMinFees { + min_pay_transaction_cost: u64, + min_set_regular_key_transaction_cost: u64, + min_create_shard_transaction_cost: u64, + min_set_shard_owners_transaction_cost: u64, + min_set_shard_users_transaction_cost: u64, + min_wrap_ccc_transaction_cost: u64, + min_custom_transaction_cost: u64, + min_store_transaction_cost: u64, + min_remove_transaction_cost: u64, + min_asset_mint_cost: u64, + min_asset_transfer_cost: u64, + min_asset_scheme_change_cost: u64, + min_asset_supply_increase_cost: u64, + min_asset_unwrap_ccc_cost: u64, +} + +impl From for MemPoolMinFees { + fn from(fees: ccore::MemPoolMinFees) -> Self { + Self { + min_pay_transaction_cost: fees.min_pay_transaction_cost, + min_set_regular_key_transaction_cost: fees.min_set_regular_key_transaction_cost, + min_create_shard_transaction_cost: fees.min_create_shard_transaction_cost, + min_set_shard_owners_transaction_cost: fees.min_set_shard_owners_transaction_cost, + min_set_shard_users_transaction_cost: fees.min_set_shard_users_transaction_cost, + min_wrap_ccc_transaction_cost: fees.min_wrap_ccc_transaction_cost, + min_custom_transaction_cost: fees.min_custom_transaction_cost, + min_store_transaction_cost: fees.min_store_transaction_cost, + min_remove_transaction_cost: fees.min_remove_transaction_cost, + min_asset_mint_cost: fees.min_asset_mint_cost, + min_asset_transfer_cost: fees.min_asset_transfer_cost, + min_asset_scheme_change_cost: fees.min_asset_scheme_change_cost, + min_asset_supply_increase_cost: fees.min_asset_supply_increase_cost, + min_asset_unwrap_ccc_cost: fees.min_asset_unwrap_ccc_cost, + } + } +} diff --git a/rpc/src/v1/types/mod.rs b/rpc/src/v1/types/mod.rs index 66d9b30ba5..8f73c25e24 100644 --- a/rpc/src/v1/types/mod.rs +++ b/rpc/src/v1/types/mod.rs @@ -1,4 +1,4 @@ -// Copyright 2018-2019 Kodebox, Inc. +// Copyright 2018-2020 Kodebox, Inc. // This file is part of CodeChain. // // This program is free software: you can redistribute it and/or modify @@ -20,6 +20,7 @@ mod asset_input; mod asset_output; mod asset_scheme; mod block; +mod mem_pool; mod text; mod transaction; mod unsigned_transaction; @@ -34,6 +35,7 @@ pub use self::asset::OwnedAsset; pub use self::asset_scheme::AssetScheme; pub use self::block::Block; pub use self::block::BlockNumberAndHash; +pub use self::mem_pool::MemPoolMinFees; pub use self::text::Text; pub use self::transaction::{PendingTransactions, Transaction}; pub use self::unsigned_transaction::UnsignedTransaction; diff --git a/spec/JSON-RPC.md b/spec/JSON-RPC.md index 486a0cdb0b..8e9f3f5d73 100644 --- a/spec/JSON-RPC.md +++ b/spec/JSON-RPC.md @@ -328,6 +328,7 @@ When `Transaction` is included in any response, there will be an additional fiel * [mempool_banAccounts](#mempool_banaccounts) * [mempool_registerImmuneAccounts](#mempool_registerimmuneaccounts) * [mempool_getRegisteredImmuneAccounts](#mempool_getregisteredimmuneaccounts) + * [mempool_getMachineMinimumFees](#mempool_getmachineminimumfees) *** * [engine_getCoinbase](#engine_getcoinbase) * [engine_getBlockReward](#engine_getblockreward) @@ -370,7 +371,8 @@ When `Transaction` is included in any response, there will be an additional fiel * [devel_startSealing](#devel_startsealing) * [devel_stopSealing](#devel_stopsealing) * [devel_getBlockSyncPeers](#devel_getblocksyncpeers) - + * [devel_getPeerBestBlockHashes](#devel_getpeerbestblockhases) + * [devel_getTargetBlockHashes](#devel_gettargetblockhashes) # Specification @@ -1987,6 +1989,65 @@ curl \ [Back to **List of methods**](#list-of-methods) +## mempool_getMachineMinimumFees +Get minimum fees configured by the machine. + +### Params +No parameters + +### Returns +{ + "minAssetMintCost": `number`, + "minAssetSchemeChangeCost":`number`, + "minAssetSupplyIncreaseCost": `number`, + "minAssetTransferCost":`number`, + "minAssetUnwrapCccCost":`number`, + "minCreateShardTransactionCost":`number`, + "minCustomTransactionCost":`number`, + "minStoreTransactionCost": `number`, + "minRemoveTransactionCost": `number`, + "minPayTransactionCost":`number`, + "minSetRegularKeyTransactionCost":`number`, + "minSetShardOwnersTransactionCost":`number`, + "minSetShardUsersTransactionCost":`number`, + "minWrapCccTransactionCost":`number` +} + +### Request Example +``` +curl \ + -H 'Content-Type: application/json' \ + -d '{"jsonrpc": "2.0", "method": "mempool_getMachineMinimumFees", "params": [], "id": null}' \ + localhost:8080 +``` + +### Response Example +``` +{ + "jsonrpc":"2.0", + "result":{ + "minAssetMintCost":0, + "minAssetSchemeChangeCost":0, + "minAssetSupplyIncreaseCost":0, + "minAssetTransferCost":0, + "minAssetUnwrapCccCost":0, + "minCreateShardTransactionCost":0, + "minCustomTransactionCost":0, + "minStoreTransactionCost": 0, + "minRemoveTransactionCost": 0, + "minPayTransactionCost":0, + "minSetRegularKeyTransactionCost":0, + "minSetShardOwnersTransactionCost":0, + "minSetShardUsersTransactionCost":0, + "minWrapCccTransactionCost":0 + }, + "id":null +} + +``` + +[Back to **List of methods**](#list-of-methods) + ## engine_getCoinbase Gets coinbase's account id. @@ -3093,6 +3154,76 @@ No parameters [Back to **List of methods**](#list-of-methods) +## devel_getPeerBestBlockHashes + +Get IP address and best block hash of each peer. + +### Params + +No parameters + +### Returns + +[ 'string', 'H256' ][] + +### Request Example + +``` + curl \ + -H 'Content-Type: application/json' \ + -d '{"jsonrpc": "2.0", "method": "devel_getPeerBestBlockHashes", "params": [], "id": 3}' \ + localhost:8080 +``` + +### Response Example +``` +{ + "jsonrpc":"2.0", + "result": [ + ["1.2.3.4:3485", "0x56642f04d519ae3262c7ba6facf1c5b11450ebaeb7955337cfbc45420d573077"], + ["1.2.3.5:3485", "0x7f7104b580f9418d444560009e5a92a4573d42d2c51cd0c6045afdc761826249"] + ], + "id":3 +} +``` + +[Back to **List of methods**](#list-of-methods) + +## devel_getTargetBlockHashes + +Get hashes of target blocks + +### Params + +No parameters + +### Returns + +'`H256[]` + +### Request Example + +``` + curl \ + -H 'Content-Type: application/json' \ + -d '{"jsonrpc": "2.0", "method": "devel_getTargetBlockHashes", "params": [], "id": 3}' \ + localhost:8080 +``` + +### Response Example +``` +{ + "jsonrpc":"2.0", + "result": [ + "0x56642f04d519ae3262c7ba6facf1c5b11450ebaeb7955337cfbc45420d573077", + "0x7f7104b580f9418d444560009e5a92a4573d42d2c51cd0c6045afdc761826249" + ], + "id":3 +} +``` + +[Back to **List of methods**](#list-of-methods) + ## devel_testTPS Test TPS as the parameters. diff --git a/state/Cargo.toml b/state/Cargo.toml index 6124dd69d5..b1e6d7c23b 100644 --- a/state/Cargo.toml +++ b/state/Cargo.toml @@ -5,8 +5,8 @@ authors = ["CodeChain Team "] edition = "2018" [dependencies] -codechain-crypto = { git = "https://github.com/CodeChain-io/rust-codechain-crypto.git", version = "0.1" } -codechain-db = { git = "https://github.com/CodeChain-io/rust-codechain-db.git", version = "0.1" } +codechain-crypto = { git = "https://github.com/CodeChain-io/rust-codechain-crypto.git", version = "0.2" } +codechain-db = { git = "https://github.com/CodeChain-io/rust-codechain-db.git", version = "0.2" } codechain-logger = { path = "../util/logger" } codechain-key = { path = "../key" } codechain-types = { path = "../types" } @@ -15,8 +15,8 @@ kvdb = "0.1" kvdb-memorydb = "0.1" log = "0.4.6" lru-cache = "0.1.1" -merkle-trie = { git = "https://github.com/CodeChain-io/rust-merkle-trie.git", version = "0.1" } -parking_lot = "0.6.0" +merkle-trie = { git = "https://github.com/CodeChain-io/rust-merkle-trie.git", version = "0.4" } +parking_lot = "0.11.0" primitives = { git = "https://github.com/CodeChain-io/rust-codechain-primitives.git", version = "0.4" } rlp = { git = "https://github.com/CodeChain-io/rlp.git", version = "0.4" } rlp_derive = { git = "https://github.com/CodeChain-io/rlp.git", version = "0.2" } diff --git a/state/src/cache/top_cache.rs b/state/src/cache/top_cache.rs index d8efc422ad..e1b81d2b2f 100644 --- a/state/src/cache/top_cache.rs +++ b/state/src/cache/top_cache.rs @@ -128,10 +128,6 @@ impl TopCache { self.shard.get_mut(a, db) } - #[allow(dead_code)] - pub fn remove_shard(&self, address: &ShardAddress) { - self.shard.remove(address) - } pub fn text(&self, a: &H256, db: &dyn Trie) -> TrieResult> { self.text.get(a, db) diff --git a/state/src/item/account.rs b/state/src/item/account.rs index 9907d2b18d..a89d94ab78 100644 --- a/state/src/item/account.rs +++ b/state/src/item/account.rs @@ -123,7 +123,7 @@ impl CacheableItem for Account { } } -const PREFIX: u8 = super::ADDRESS_PREFIX; +const PREFIX: u8 = super::Prefix::Account as u8; impl Encodable for Account { fn rlp_append(&self, s: &mut RlpStream) { diff --git a/state/src/item/asset.rs b/state/src/item/asset.rs index 0647798150..1cd292d057 100644 --- a/state/src/item/asset.rs +++ b/state/src/item/asset.rs @@ -99,7 +99,7 @@ impl CacheableItem for OwnedAsset { } } -const PREFIX: u8 = super::OWNED_ASSET_PREFIX; +const PREFIX: u8 = super::Prefix::OwnedAsset as u8; impl Encodable for OwnedAsset { fn rlp_append(&self, s: &mut RlpStream) { diff --git a/state/src/item/asset_scheme.rs b/state/src/item/asset_scheme.rs index a8be675e7f..3dd5ed1bed 100644 --- a/state/src/item/asset_scheme.rs +++ b/state/src/item/asset_scheme.rs @@ -148,7 +148,7 @@ impl AssetScheme { } } -const PREFIX: u8 = super::ASSET_SCHEME_PREFIX; +const PREFIX: u8 = super::Prefix::AssetScheme as u8; impl Default for AssetScheme { fn default() -> Self { diff --git a/state/src/item/metadata.rs b/state/src/item/metadata.rs index dc65cde376..69340f7f74 100644 --- a/state/src/item/metadata.rs +++ b/state/src/item/metadata.rs @@ -121,7 +121,7 @@ impl CacheableItem for Metadata { } } -const PREFIX: u8 = super::METADATA_PREFIX; +const PREFIX: u8 = super::Prefix::Metadata as u8; impl Encodable for Metadata { fn rlp_append(&self, s: &mut RlpStream) { diff --git a/state/src/item/mod.rs b/state/src/item/mod.rs index 6eb88c9a7b..79f8f221a4 100644 --- a/state/src/item/mod.rs +++ b/state/src/item/mod.rs @@ -26,10 +26,14 @@ pub mod regular_account; pub mod shard; pub mod text; -const OWNED_ASSET_PREFIX: u8 = b'A'; -const ADDRESS_PREFIX: u8 = b'C'; -const SHARD_PREFIX: u8 = b'H'; -const METADATA_PREFIX: u8 = b'M'; -const REGULAR_ACCOUNT_PREFIX: u8 = b'R'; -const ASSET_SCHEME_PREFIX: u8 = b'S'; -const TEXT_PREFIX: u8 = b'T'; +#[derive(Clone, Copy)] +#[repr(u8)] +enum Prefix { + OwnedAsset = b'A', + Account = b'C', + Shard = b'H', + Metadata = b'M', + RegularAccount = b'R', + AssetScheme = b'S', + Text = b'T', +} diff --git a/state/src/item/regular_account.rs b/state/src/item/regular_account.rs index c185aa5781..18ae925506 100644 --- a/state/src/item/regular_account.rs +++ b/state/src/item/regular_account.rs @@ -54,7 +54,7 @@ impl CacheableItem for RegularAccount { } } -const PREFIX: u8 = super::REGULAR_ACCOUNT_PREFIX; +const PREFIX: u8 = super::Prefix::RegularAccount as u8; impl Encodable for RegularAccount { fn rlp_append(&self, s: &mut RlpStream) { diff --git a/state/src/item/shard.rs b/state/src/item/shard.rs index 694d3838bb..64ad1bcd7e 100644 --- a/state/src/item/shard.rs +++ b/state/src/item/shard.rs @@ -78,7 +78,7 @@ impl CacheableItem for Shard { } } -const PREFIX: u8 = super::SHARD_PREFIX; +const PREFIX: u8 = super::Prefix::Shard as u8; impl Encodable for Shard { fn rlp_append(&self, s: &mut RlpStream) { diff --git a/state/src/item/text.rs b/state/src/item/text.rs index cda8f3c4fb..6bc2e588a0 100644 --- a/state/src/item/text.rs +++ b/state/src/item/text.rs @@ -62,7 +62,7 @@ impl CacheableItem for Text { } } -const PREFIX: u8 = super::TEXT_PREFIX; +const PREFIX: u8 = super::Prefix::Text as u8; impl Encodable for Text { fn rlp_append(&self, s: &mut RlpStream) { diff --git a/stratum/Cargo.toml b/stratum/Cargo.toml index 5b8ff7136c..d0da998314 100644 --- a/stratum/Cargo.toml +++ b/stratum/Cargo.toml @@ -7,14 +7,14 @@ authors = ["Parity Technologies ", "CodeChain Team , + }, + Drained, +} + +impl Default for State { + fn default() -> Self { + State::Queued + } +} #[derive(Clone)] struct Target { @@ -28,8 +46,7 @@ struct Target { #[derive(Default)] pub struct BodyDownloader { targets: Vec, - downloading: HashSet, - downloaded: HashMap>, + states: HashMap, } impl BodyDownloader { @@ -37,9 +54,12 @@ impl BodyDownloader { const MAX_BODY_REQEUST_LENGTH: usize = 128; let mut hashes = Vec::new(); for t in &self.targets { - if !self.downloading.contains(&t.hash) && !self.downloaded.contains_key(&t.hash) { - hashes.push(t.hash); + let state = self.states.entry(t.hash).or_default(); + if *state != State::Queued { + continue } + *state = State::Downloading; + hashes.push(t.hash); if hashes.len() >= MAX_BODY_REQEUST_LENGTH { break } @@ -47,97 +67,100 @@ impl BodyDownloader { if hashes.is_empty() { None } else { - self.downloading.extend(&hashes); Some(RequestMessage::Bodies(hashes)) } } pub fn import_bodies(&mut self, hashes: Vec, bodies: Vec>) { - for (hash, body) in hashes.into_iter().zip(bodies) { - if self.downloading.remove(&hash) { - let target = self.targets.iter().find(|t| t.hash == hash).expect("Downloading target must exist"); - if body.is_empty() { - if !target.is_empty { - cwarn!(SYNC, "Invalid body of {}. It should be not empty.", hash); - continue - } - } else if target.is_empty { - cwarn!(SYNC, "Invalid body of {}. It should be empty.", hash); + assert_eq!(hashes.len(), bodies.len()); + for (hash, transactions) in hashes.into_iter().zip(bodies) { + if let Some(state) = self.states.get_mut(&hash) { + if state != &State::Downloading { continue } - self.downloaded.insert(hash, body); + *state = State::Downloaded { + transactions, + } } } - self.downloading.shrink_to_fit(); + } + + pub fn get_target_hashes(&self) -> Vec { + self.targets.iter().map(|t| t.hash).collect() } pub fn add_target(&mut self, header: &Header, is_empty: bool) { cdebug!(SYNC, "Add download target: {}", header.hash()); + self.states.insert(header.hash(), State::Queued); self.targets.push(Target { hash: header.hash(), is_empty, }); } - pub fn remove_target(&mut self, targets: &[BlockHash]) { + pub fn remove_targets(&mut self, targets: &[BlockHash]) { if targets.is_empty() { return } cdebug!(SYNC, "Remove download targets: {:?}", targets); - for hash in targets { - if let Some(index) = self.targets.iter().position(|t| t.hash == *hash) { - self.targets.remove(index); - } - self.downloading.remove(hash); - self.downloaded.remove(hash); - } + // XXX: It can be slow. + self.states.retain(|hash, _| !targets.contains(hash)); + self.targets.retain(|target| !targets.contains(&target.hash)); + self.states.shrink_to_fit(); self.targets.shrink_to_fit(); - self.downloading.shrink_to_fit(); - self.downloaded.shrink_to_fit(); } pub fn reset_downloading(&mut self, hashes: &[BlockHash]) { cdebug!(SYNC, "Remove downloading by timeout {:?}", hashes); for hash in hashes { - self.downloading.remove(&hash); + if let Some(state) = self.states.get_mut(hash) { + if *state == State::Downloading { + *state = State::Queued; + } + } } - self.downloading.shrink_to_fit(); } pub fn drain(&mut self) -> Vec<(BlockHash, Vec)> { let mut result = Vec::new(); for t in &self.targets { - if let Some(body) = self.downloaded.remove(&t.hash) { - result.push((t.hash, body)); - } else { - break + let entry = self.states.entry(t.hash); + let state = match entry { + Entry::Vacant(_) => unreachable!(), + Entry::Occupied(mut entry) => match entry.get_mut() { + state @ State::Downloaded { + .. + } => replace(state, State::Drained), + _ => break, + }, + }; + match state { + State::Downloaded { + transactions, + } => { + result.push((t.hash, transactions)); + } + _ => unreachable!(), } } - self.downloaded.shrink_to_fit(); - self.targets.drain(0..result.len()); - self.targets.shrink_to_fit(); result } - pub fn re_request( - &mut self, - hash: BlockHash, - is_empty: bool, - remains: Vec<(BlockHash, Vec)>, - ) { - let mut new_targets = vec![Target { - hash, - is_empty, - }]; - new_targets.extend(remains.into_iter().map(|(hash, transactions)| { - let is_empty = transactions.is_empty(); - self.downloaded.insert(hash, transactions); - Target { - hash, - is_empty, - } - })); - new_targets.append(&mut self.targets); - self.targets = new_targets; + pub fn re_request(&mut self, hash: BlockHash, remains: Vec<(BlockHash, Vec)>) { + #[inline] + fn insert(states: &mut HashMap, hash: BlockHash, state: State) { + let old = states.insert(hash, state); + debug_assert_ne!(None, old); + } + // The implementation of extend method allocates an additional memory for new items. + // However, our implementation guarantees that new items are already in the map and it just + // update the states. So iterating over new items and calling the insert method is faster + // than using the extend method and uses less memory. + for (hash, transactions) in remains { + insert(&mut self.states, hash, State::Downloaded { + transactions, + }); + } + insert(&mut self.states, hash, State::Queued); } } diff --git a/sync/src/block/downloader/header.rs b/sync/src/block/downloader/header.rs index fff1bfe56e..1dbc9f9cbc 100644 --- a/sync/src/block/downloader/header.rs +++ b/sync/src/block/downloader/header.rs @@ -1,4 +1,4 @@ -// Copyright 2018 Kodebox, Inc. +// Copyright 2018-2020 Kodebox, Inc. // This file is part of CodeChain. // // This program is free software: you can redistribute it and/or modify @@ -15,9 +15,8 @@ // along with this program. If not, see . use super::super::message::RequestMessage; -use ccore::encoded::Header; use ccore::{BlockChainClient, BlockId}; -use ctypes::BlockHash; +use ctypes::{BlockHash, Header}; use primitives::U256; use std::cmp::Ordering; use std::collections::HashMap; @@ -43,9 +42,11 @@ pub struct HeaderDownloader { total_score: U256, best_hash: BlockHash, + /// The last header we downloaded from this peer. pivot: Pivot, request_time: Option, downloaded: HashMap, + /// Headers that are importing now. queued: HashMap, trial: usize, } @@ -110,7 +111,7 @@ impl HeaderDownloader { Some(header) => header.clone(), None => match self.downloaded.get(&self.pivot.hash) { Some(header) => header.clone(), - None => self.client.block_header(&BlockId::Hash(self.pivot.hash)).unwrap(), + None => self.client.block_header(&BlockId::Hash(self.pivot.hash)).unwrap().decode(), }, } } @@ -119,6 +120,10 @@ impl HeaderDownloader { self.pivot.total_score } + pub fn best_hash(&self) -> BlockHash { + self.best_hash + } + pub fn is_idle(&self) -> bool { let can_request = self.request_time.is_none() && self.total_score > self.pivot.total_score; @@ -173,7 +178,7 @@ impl HeaderDownloader { } else if first_header_number == pivot_header.number() { if pivot_header.number() != 0 { self.pivot = Pivot { - hash: pivot_header.parent_hash(), + hash: *pivot_header.parent_hash(), total_score: self.pivot.total_score - pivot_header.score(), } } diff --git a/sync/src/block/extension.rs b/sync/src/block/extension.rs index 751e992d60..f533d18ddb 100644 --- a/sync/src/block/extension.rs +++ b/sync/src/block/extension.rs @@ -21,7 +21,7 @@ use ccore::{ Block, BlockChainClient, BlockChainTrait, BlockId, BlockImportError, ChainNotify, Client, ImportBlock, ImportError, UnverifiedTransaction, }; -use cnetwork::{Api, EventSender, NetworkExtension, NodeId}; +use cnetwork::{Api, EventSender, IntoSocketAddr, NetworkExtension, NodeId}; use cstate::FindActionHandler; use ctimer::TimerToken; use ctypes::header::{Header, Seal}; @@ -34,6 +34,7 @@ use rand::thread_rng; use rlp::{Encodable, Rlp}; use std::collections::hash_map::Entry; use std::collections::{HashMap, HashSet}; +use std::net::SocketAddr; use std::sync::Arc; use std::time::Duration; use token_generator::TokenGenerator; @@ -353,6 +354,16 @@ impl NetworkExtension for Extension { channel.send(*peer).unwrap(); } } + Event::GetPeerBestBlockHashes(channel) => { + for (node_id, header_downloader) in self.header_downloaders.iter() { + channel.send((SocketAddr::from(node_id.into_addr()), header_downloader.best_hash())).unwrap(); + } + } + Event::GetTargetBlockHashes(channel) => { + for target in self.body_downloader.get_target_hashes() { + channel.send(target).unwrap(); + } + } Event::NewHeaders { imported, enacted, @@ -372,6 +383,8 @@ impl NetworkExtension for Extension { pub enum Event { GetPeers(EventSender), + GetPeerBestBlockHashes(EventSender<(SocketAddr, BlockHash)>), + GetTargetBlockHashes(EventSender), NewHeaders { imported: Vec, enacted: Vec, @@ -391,19 +404,19 @@ impl Extension { peer.mark_as_imported(imported.clone()); } } + let mut headers_to_download: Vec<_> = enacted .into_iter() .map(|hash| self.client.block_header(&BlockId::Hash(hash)).expect("Enacted header must exist")) .collect(); headers_to_download.sort_unstable_by_key(EncodedHeader::number); - #[allow(clippy::redundant_closure)] - // False alarm. https://github.com/rust-lang/rust-clippy/issues/1439 headers_to_download.dedup_by_key(|h| h.hash()); let headers: Vec<_> = headers_to_download .into_iter() .filter(|header| self.client.block_body(&BlockId::Hash(header.hash())).is_none()) .collect(); // FIXME: No need to collect here if self is not borrowed. + for header in headers { let parent = self .client @@ -412,12 +425,12 @@ impl Extension { let is_empty = header.transactions_root() == parent.transactions_root(); self.body_downloader.add_target(&header.decode(), is_empty); } - self.body_downloader.remove_target(&retracted); + self.body_downloader.remove_targets(&retracted); } fn new_blocks(&mut self, imported: Vec, invalid: Vec) { - self.body_downloader.remove_target(&imported); - self.body_downloader.remove_target(&invalid); + self.body_downloader.remove_targets(&imported); + self.body_downloader.remove_targets(&invalid); let chain_info = self.client.chain_info(); @@ -574,7 +587,7 @@ impl Extension { match response { ResponseMessage::Headers(headers) => { self.dismiss_request(from, id); - self.on_header_response(from, &headers) + self.on_header_response(from, headers) } ResponseMessage::Bodies(bodies) => { self.check_sync_variable(); @@ -665,30 +678,28 @@ impl Extension { } } - fn on_header_response(&mut self, from: &NodeId, headers: &[Header]) { + fn on_header_response(&mut self, from: &NodeId, headers: Vec
) { ctrace!(SYNC, "Received header response from({}) with length({})", from, headers.len()); let (mut completed, pivot_score_changed) = if let Some(peer) = self.header_downloaders.get_mut(from) { let before_pivot_score = peer.pivot_score(); - let encoded: Vec<_> = headers.iter().map(|h| EncodedHeader::new(h.rlp_bytes().to_vec())).collect(); - peer.import_headers(&encoded); + peer.import_headers(&headers); let after_pivot_score = peer.pivot_score(); (peer.downloaded(), before_pivot_score != after_pivot_score) } else { (Vec::new(), false) }; - completed.sort_unstable_by_key(EncodedHeader::number); - + completed.sort_unstable_by_key(Header::number); let mut exists = Vec::new(); let mut queued = Vec::new(); for header in completed { let hash = header.hash(); - match self.client.import_header(header.clone().into_inner()) { + match self.client.import_header(header) { Err(BlockImportError::Import(ImportError::AlreadyInChain)) => exists.push(hash), Err(BlockImportError::Import(ImportError::AlreadyQueued)) => queued.push(hash), // FIXME: handle import errors Err(err) => { - cwarn!(SYNC, "Cannot import header({}): {:?}", header.hash(), err); + cwarn!(SYNC, "Cannot import header({}): {:?}", hash, err); break } _ => {} @@ -708,6 +719,7 @@ impl Extension { } fn import_blocks(&mut self, blocks: Vec<(BlockHash, Vec)>) { + let mut imported = Vec::new(); let mut remains = Vec::new(); let mut error_target = None; for (hash, transactions) in blocks { @@ -727,7 +739,7 @@ impl Extension { skewed_merkle_root(parent_transactions_root, transactions.iter().map(Encodable::rlp_bytes)); if *header.transactions_root() != calculated_transactions_root { cwarn!(SYNC, "Received corrupted body for ${}({}", header.number(), hash); - error_target = Some((hash, transactions.is_empty())); + error_target = Some(hash); continue } @@ -748,12 +760,15 @@ impl Extension { cwarn!(SYNC, "Cannot import block({}): {:?}", hash, err); break } - Ok(_) => {} + Ok(_) => { + imported.push(hash); + } } } - if let Some((hash, is_empty)) = error_target { - self.body_downloader.re_request(hash, is_empty, remains); + if let Some(hash) = error_target { + self.body_downloader.re_request(hash, remains); } + self.body_downloader.remove_targets(&imported); } fn on_body_response(&mut self, hashes: Vec, bodies: Vec>) { diff --git a/sync/src/block/message/mod.rs b/sync/src/block/message/mod.rs index 3ecdf124cf..8ca850df56 100644 --- a/sync/src/block/message/mod.rs +++ b/sync/src/block/message/mod.rs @@ -62,7 +62,7 @@ impl Decodable for MessageID { } } -#[derive(Debug, PartialEq)] +#[derive(Debug)] pub enum Message { Status { total_score: U256, @@ -162,29 +162,44 @@ impl Decodable for Message { #[cfg(test)] mod tests { + use super::*; use primitives::H256; - use rlp::rlp_encode_and_decode_test; - use super::*; + /// For a type that does not have PartialEq, uses Debug instead. + fn assert_eq_by_debug(a: &T, b: &T) { + assert_eq!(format!("{:?}", a), format!("{:?}", b)); + } #[test] fn status_message_rlp() { - rlp_encode_and_decode_test!(Message::Status { + let status_message = Message::Status { total_score: U256::default(), best_hash: H256::default().into(), genesis_hash: H256::default().into(), - }); + }; + let encoded = rlp::encode(&status_message); + let decoded: Message = rlp::decode(&encoded).unwrap(); + + assert_eq_by_debug(&status_message, &decoded) } #[test] fn request_bodies_message_rlp() { let request_id = 10; - rlp_encode_and_decode_test!(Message::Request(request_id, RequestMessage::Bodies(vec![]))); + let message = Message::Request(request_id, RequestMessage::Bodies(vec![])); + let encoded = rlp::encode(&message); + let decoded: Message = rlp::decode(&encoded).unwrap(); + + assert_eq_by_debug(&message, &decoded) } #[test] fn request_state_head_rlp() { let request_id = 10; - rlp_encode_and_decode_test!(Message::Request(request_id, RequestMessage::StateHead(H256::random().into()))); + let message = Message::Request(request_id, RequestMessage::StateHead(H256::random().into())); + let encoded = rlp::encode(&message); + let decoded: Message = rlp::decode(&encoded).unwrap(); + + assert_eq_by_debug(&message, &decoded) } } diff --git a/sync/src/block/message/response.rs b/sync/src/block/message/response.rs index 76ec905467..8217fe1f67 100644 --- a/sync/src/block/message/response.rs +++ b/sync/src/block/message/response.rs @@ -20,7 +20,7 @@ use ctypes::Header; use rlp::{DecoderError, Encodable, Rlp, RlpStream}; use snap; -#[derive(Debug, PartialEq)] +#[derive(Debug)] pub enum ResponseMessage { Headers(Vec
), Bodies(Vec>), @@ -152,6 +152,11 @@ mod tests { ResponseMessage::decode(id, &rlp).unwrap() } + /// For a type that does not have PartialEq, uses Debug instead. + fn assert_eq_by_debug(a: &T, b: &T) { + assert_eq!(format!("{:?}", a), format!("{:?}", b)); + } + #[test] fn headers_message_rlp() { let headers = vec![Header::default()]; @@ -160,13 +165,13 @@ mod tests { }); let message = ResponseMessage::Headers(headers); - assert_eq!(message, decode_bytes(message.message_id(), message.rlp_bytes().as_ref())); + assert_eq_by_debug(&message, &decode_bytes(message.message_id(), message.rlp_bytes().as_ref())) } #[test] fn bodies_message_rlp() { let message = ResponseMessage::Bodies(vec![vec![]]); - assert_eq!(message, decode_bytes(message.message_id(), message.rlp_bytes().as_ref())); + assert_eq_by_debug(&message, &decode_bytes(message.message_id(), message.rlp_bytes().as_ref())); let tx = UnverifiedTransaction::new( Transaction { @@ -181,18 +186,18 @@ mod tests { ); let message = ResponseMessage::Bodies(vec![vec![tx]]); - assert_eq!(message, decode_bytes(message.message_id(), message.rlp_bytes().as_ref())); + assert_eq_by_debug(&message, &decode_bytes(message.message_id(), message.rlp_bytes().as_ref())); } #[test] fn state_head_message_rlp() { let message = ResponseMessage::StateHead(vec![]); - assert_eq!(message, decode_bytes(message.message_id(), message.rlp_bytes().as_ref())); + assert_eq_by_debug(&message, &decode_bytes(message.message_id(), message.rlp_bytes().as_ref())); } #[test] fn state_chunk_message_rlp() { let message = ResponseMessage::StateChunk(vec![]); - assert_eq!(message, decode_bytes(message.message_id(), message.rlp_bytes().as_ref())); + assert_eq_by_debug(&message, &decode_bytes(message.message_id(), message.rlp_bytes().as_ref())); } } diff --git a/sync/src/lib.rs b/sync/src/lib.rs index 8792691242..c3f52ea2ed 100644 --- a/sync/src/lib.rs +++ b/sync/src/lib.rs @@ -14,8 +14,6 @@ // You should have received a copy of the GNU Affero General Public License // along with this program. If not, see . -extern crate parking_lot; - extern crate codechain_core as ccore; extern crate codechain_db as cdb; #[macro_use] @@ -37,7 +35,6 @@ extern crate rlp; extern crate snap; #[cfg(test)] extern crate tempfile; -extern crate time; extern crate token_generator; #[cfg(test)] extern crate trie_standardmap; diff --git a/sync/src/transaction/extension.rs b/sync/src/transaction/extension.rs index e412a9e17e..76f8369286 100644 --- a/sync/src/transaction/extension.rs +++ b/sync/src/transaction/extension.rs @@ -111,7 +111,6 @@ impl NetworkExtension for Extension { self.client.queue_transactions( transactions.iter().map(|unverified| unverified.rlp_bytes().to_vec()).collect(), - *token, ); if let Some(peer) = self.peers.get_mut(token) { let transactions: Vec<_> = transactions diff --git a/sync/src/transaction/message.rs b/sync/src/transaction/message.rs index c16a1b614f..5cf45da61e 100644 --- a/sync/src/transaction/message.rs +++ b/sync/src/transaction/message.rs @@ -63,17 +63,23 @@ impl Decodable for Message { #[cfg(test)] mod tests { - use rlp::rlp_encode_and_decode_test; - use ccore::UnverifiedTransaction; use ckey::{Address, Signature}; use ctypes::transaction::{Action, Transaction}; use super::Message; + /// For a type that does not have PartialEq, uses Debug instead. + fn assert_eq_by_debug(a: &T, b: &T) { + assert_eq!(format!("{:?}", a), format!("{:?}", b)); + } + #[test] fn transactions_message_rlp() { - rlp_encode_and_decode_test!(Message::Transactions(Vec::new())); + let message = Message::Transactions(Vec::new()); + let encoded = rlp::encode(&message); + let decoded: Message = rlp::decode(&encoded).unwrap(); + assert_eq_by_debug(&message, &decoded); } #[test] @@ -90,6 +96,9 @@ mod tests { Signature::default(), ); - rlp_encode_and_decode_test!(Message::Transactions(vec![tx])); + let message = Message::Transactions(vec![tx]); + let encoded = rlp::encode(&message); + let decoded: Message = rlp::decode(&encoded).unwrap(); + assert_eq_by_debug(&message, &decoded); } } diff --git a/test/package.json b/test/package.json index 6f23b156b3..2d43bd56da 100644 --- a/test/package.json +++ b/test/package.json @@ -19,9 +19,10 @@ "start-short-release": "cargo build --release && NODE_ENV=production mocha -r ts-node/register --timeout 5000 src/e2e/*.test.ts", "start-long-release": "cargo build --release && NODE_ENV=production mocha -r ts-node/register --timeout 10000 src/e2e.long/*.test.ts", "start-dyn-val-release": "cargo build --release && NODE_ENV=production mocha -r ts-node/register --timeout 10000 src/e2e.dynval/*.test.ts", + "test-mock": "mocha -r ts-node/register --timeout 5000 \"src/helper/mock/**/*.test.ts\"", "tendermint-test-local": "cargo build --release && NODE_ENV=production ts-node src/tendermint.test/local.ts", "tendermint-test-remote": "NODE_ENV=production ts-node src/tendermint.test/remote.ts", - "lint": "tslint -p . && prettier 'src/**/*.{ts, json}' -l", + "lint": "tsc -p . --noEmit && tslint -p . && prettier 'src/**/*.{ts, json}' -l", "fmt": "tslint -p . --fix && prettier 'src/**/*.{ts, json}' --write" }, "devDependencies": { @@ -50,6 +51,7 @@ "codechain-sdk": "https://github.com/MSNTCS/codechain-sdk-js#getPendingTransactions", "codechain-stakeholder-sdk": "^2.0.0", "elliptic": "^6.5.3", + "get-port": "^5.1.1", "lodash": "^4.17.19", "mkdirp": "^0.5.1", "ncp": "^2.0.0", diff --git a/test/src/config/mem-pool-min-fee1.toml b/test/src/config/mem-pool-min-fee1.toml index 7211ead60e..8b567b86d7 100644 --- a/test/src/config/mem-pool-min-fee1.toml +++ b/test/src/config/mem-pool-min-fee1.toml @@ -2,6 +2,7 @@ [mining] min_pay_transaction_cost = 150 +self_nomination_enable = false [network] diff --git a/test/src/config/mem-pool-min-fee2.toml b/test/src/config/mem-pool-min-fee2.toml index f7dab7f1f3..21abdf674d 100644 --- a/test/src/config/mem-pool-min-fee2.toml +++ b/test/src/config/mem-pool-min-fee2.toml @@ -2,6 +2,7 @@ [mining] min_pay_transaction_cost = 200 +self_nomination_enable = false [network] diff --git a/test/src/e2e.dynval/2/autoselfnomination.test.ts b/test/src/e2e.dynval/2/autoselfnomination.test.ts new file mode 100644 index 0000000000..7b3af2f0d7 --- /dev/null +++ b/test/src/e2e.dynval/2/autoselfnomination.test.ts @@ -0,0 +1,122 @@ +// Copyright 2020 Kodebox, Inc. +// This file is part of CodeChain. +// +// This program is free software: you can redistribute it and/or modify +// it under the terms of the GNU Affero General Public License as +// published by the Free Software Foundation, either version 3 of the +// License, or (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU Affero General Public License for more details. +// +// You should have received a copy of the GNU Affero General Public License +// along with this program. If not, see . + +import { expect } from "chai"; +import { H512 } from "codechain-primitives/lib"; +import * as stake from "codechain-stakeholder-sdk"; +import "mocha"; + +import { validators } from "../../../tendermint.dynval/constants"; +import { PromiseExpect } from "../../helper/promise"; +import { + findNode, + selfNominate, + setTermTestTimeout, + withNodes +} from "../setup"; + +describe("Auto Self Nomination", function() { + const promiseExpect = new PromiseExpect(); + const NOMINATION_EXPIRATION = 2; + const TERM_SECOND = 30; + + describe("Alice doesn't self nominate in NOMINATION_EXPIRATION, Bob sends auto self nomination", async function() { + const initialValidators = validators.slice(0, 3); + const alice = validators[3]; + const bob = validators[4]; + const { nodes } = withNodes(this, { + promiseExpect, + overrideParams: { + termSeconds: TERM_SECOND, + nominationExpiration: NOMINATION_EXPIRATION + }, + validators: [ + ...initialValidators.map((validator, index) => ({ + signer: validator, + delegation: 5000 - index, + deposit: 100000 + })), + { signer: alice, autoSelfNominate: false }, + { signer: bob, autoSelfNominate: true } + ] + }); + it("Alice be eligible after 2 terms and Bob did auto self nomination", async function() { + const termWaiter = setTermTestTimeout(this, { + terms: 3, + params: { + termSeconds: TERM_SECOND + } + }); + + const aliceNode = findNode(nodes, alice); + const selfNominationHash = await selfNominate( + aliceNode.sdk, + alice, + 10 + ); + await aliceNode.waitForTx(selfNominationHash); + // bob will send self-nomination transaction automatically. + const beforeCandidates = await stake.getCandidates(nodes[0].sdk); + + expect( + beforeCandidates.map(candidate => candidate.pubkey.toString()) + ).to.includes(H512.ensure(alice.publicKey).toString()); + expect( + beforeCandidates.map(candidate => candidate.pubkey.toString()) + ).to.includes(H512.ensure(bob.publicKey).toString()); + + await termWaiter.waitNodeUntilTerm(nodes[0], { + target: 4, + termPeriods: 3 + }); + + const [ + currentValidators, + banned, + candidates, + jailed + ] = await Promise.all([ + stake.getValidators(nodes[0].sdk), + stake.getBanned(nodes[0].sdk), + stake.getCandidates(nodes[0].sdk), + stake.getJailed(nodes[0].sdk) + ]); + + expect( + currentValidators.map(validator => validator.pubkey.toString()) + ).not.to.includes(alice.publicKey); + expect( + banned.map(ban => ban.getAccountId().toString()) + ).not.to.includes(alice.accountId); + expect( + candidates.map(candidate => candidate.pubkey.toString()) + ).not.to.includes(alice.publicKey); + expect(jailed.map(jail => jail.address)).not.to.includes( + alice.platformAddress.toString() + ); + expect( + currentValidators.map(validator => validator.pubkey.toString()) + ).not.to.includes(bob.publicKey); + expect( + candidates.map(candidate => candidate.pubkey.toString()) + ).to.includes(bob.publicKey); + }); + }); + + afterEach(function() { + promiseExpect.checkFulfilled(); + }); +}); diff --git a/test/src/e2e.dynval/setup.ts b/test/src/e2e.dynval/setup.ts index 493f6ef602..58217433c6 100644 --- a/test/src/e2e.dynval/setup.ts +++ b/test/src/e2e.dynval/setup.ts @@ -37,6 +37,7 @@ interface ValidatorConfig { signer: Signer; deposit?: U64Value; delegation?: U64Value; + autoSelfNominate?: boolean; } export function withNodes( @@ -127,15 +128,29 @@ async function createNodes(options: { const nodes: CodeChain[] = []; for (let i = 0; i < validators.length; i++) { const { signer: validator } = validators[i]; + const argv = [ + "--engine-signer", + validator.platformAddress.value, + "--password-path", + `test/tendermint.dynval/${validator.platformAddress.value}/password.json`, + "--force-sealing" + ]; + + if (validators[i].autoSelfNominate) { + argv.push( + "--enable-auto-self-nomination", + "--self-nomination-metadata", + "", + "--self-nomination-target-deposit", + "10", + "--self-nomination-interval", + "1000" + ); + } + nodes[i] = new CodeChain({ chain, - argv: [ - "--engine-signer", - validator.platformAddress.value, - "--password-path", - `test/tendermint.dynval/${validator.platformAddress.value}/password.json`, - "--force-sealing" - ], + argv, additionalKeysPath: `tendermint.dynval/${validator.platformAddress.value}/keys` }); nodes[i].signer = validator; diff --git a/test/src/e2e/unwrap.test.ts b/test/src/e2e/unwrap.test.ts index e5a1db6127..65d3b33276 100644 --- a/test/src/e2e/unwrap.test.ts +++ b/test/src/e2e/unwrap.test.ts @@ -25,7 +25,7 @@ import { import "mocha"; import { aliceAddress, - faucetAccointId, + faucetAccountId, faucetAddress, faucetSecret } from "../helper/constants"; @@ -50,7 +50,7 @@ describe("Unwrap CCC", function() { shardId: 0, recipient, quantity, - payer: PlatformAddress.fromAccountId(faucetAccointId, { + payer: PlatformAddress.fromAccountId(faucetAccountId, { networkId: "tc" }) }) @@ -107,7 +107,7 @@ describe("Unwrap CCC", function() { shardId: 0, recipient, quantity, - payer: PlatformAddress.fromAccountId(faucetAccointId, { + payer: PlatformAddress.fromAccountId(faucetAccountId, { networkId: "tc" }) }) diff --git a/test/src/e2e/verification.test.ts b/test/src/e2e/verification.test.ts index 8e78b9a00a..85f51c5039 100644 --- a/test/src/e2e/verification.test.ts +++ b/test/src/e2e/verification.test.ts @@ -24,7 +24,7 @@ import { import "mocha"; import { aliceAddress, - faucetAccointId, + faucetAccountId, faucetAddress, faucetSecret } from "../helper/constants"; @@ -680,7 +680,7 @@ describe("solo - 1 node", function() { shardId: 0, recipient, quantity: 10, - payer: PlatformAddress.fromAccountId(faucetAccointId, { + payer: PlatformAddress.fromAccountId(faucetAccountId, { networkId: "tc" }) }) diff --git a/test/src/e2e/wrap.test.ts b/test/src/e2e/wrap.test.ts index a8530c582e..de94f02fce 100644 --- a/test/src/e2e/wrap.test.ts +++ b/test/src/e2e/wrap.test.ts @@ -20,7 +20,7 @@ chai.use(chaiAsPromised); import { H160, PlatformAddress } from "codechain-primitives"; import "mocha"; import { - faucetAccointId, + faucetAccountId, faucetAddress, faucetSecret } from "../helper/constants"; @@ -44,7 +44,7 @@ describe("WrapCCC", function() { shardId: 0, recipient, quantity: amount, - payer: PlatformAddress.fromAccountId(faucetAccointId, { + payer: PlatformAddress.fromAccountId(faucetAccountId, { networkId: "tc" }) }) @@ -71,7 +71,7 @@ describe("WrapCCC", function() { shardId: 0, recipient, quantity: 0, - payer: PlatformAddress.fromAccountId(faucetAccointId, { + payer: PlatformAddress.fromAccountId(faucetAccountId, { networkId: "tc" }) }) @@ -95,7 +95,7 @@ describe("WrapCCC", function() { shardId, recipient: await node.createP2PKHBurnAddress(), quantity: 30, - payer: PlatformAddress.fromAccountId(faucetAccointId, { + payer: PlatformAddress.fromAccountId(faucetAccountId, { networkId: "tc" }) }); @@ -159,7 +159,7 @@ describe("WrapCCC", function() { shardId: 0, recipient: await node.createP2PKHBurnAddress(), quantity: 30, - payer: PlatformAddress.fromAccountId(faucetAccointId, { + payer: PlatformAddress.fromAccountId(faucetAccountId, { networkId: "tc" }) }); @@ -203,7 +203,7 @@ describe("WrapCCC", function() { shardId: 0, recipient: await node.createP2PKHBurnAddress(), quantity: 30, - payer: PlatformAddress.fromAccountId(faucetAccointId, { + payer: PlatformAddress.fromAccountId(faucetAccountId, { networkId: "tc" }) }); diff --git a/test/src/helper/constants.ts b/test/src/helper/constants.ts index 8f896b97f0..80af6a2476 100644 --- a/test/src/helper/constants.ts +++ b/test/src/helper/constants.ts @@ -18,9 +18,9 @@ import { SDK } from "codechain-sdk"; export const faucetSecret = "ede1d4ccb4ec9a8bbbae9a13db3f4a7b56ea04189be86ac3a6a439d9a0a1addd"; -export const faucetAccointId = SDK.util.getAccountIdFromPrivate(faucetSecret); // 6fe64ffa3a46c074226457c90ccb32dc06ccced1 +export const faucetAccountId = SDK.util.getAccountIdFromPrivate(faucetSecret); // 6fe64ffa3a46c074226457c90ccb32dc06ccced1 export const faucetAddress = SDK.Core.classes.PlatformAddress.fromAccountId( - faucetAccointId, + faucetAccountId, { networkId: "tc" } ); // tccq9h7vnl68frvqapzv3tujrxtxtwqdnxw6yamrrgd diff --git a/test/src/helper/mock/cHeader.ts b/test/src/helper/mock/cHeader.ts index a8f73a771f..277a56ace8 100644 --- a/test/src/helper/mock/cHeader.ts +++ b/test/src/helper/mock/cHeader.ts @@ -51,6 +51,25 @@ export class Header { return header; } + + public static default(): Header { + return new Header( + new H256( + "0000000000000000000000000000000000000000000000000000000000000000" + ), + new U256(0), + new U256(0), + new H160("0000000000000000000000000000000000000000"), + Buffer.alloc(0), + BLAKE_NULL_RLP, + BLAKE_NULL_RLP, + new U256( + "0000000000000000000000000000000000000000000000000000000000000000" + ), + [] + ); + } + private parentHash: H256; private timestamp: U256; private number: U256; @@ -59,7 +78,7 @@ export class Header { private transactionsRoot: H256; private stateRoot: H256; private score: U256; - private seal: number[][]; + private seal: any[]; private hash: null | H256; private bareHash: null | H256; @@ -72,7 +91,7 @@ export class Header { transactionsRoot: H256, stateRoot: H256, score: U256, - seal: number[][], + seal: any[], hash?: H256, bareHash?: H256 ) { @@ -121,10 +140,14 @@ export class Header { this.score = score; } - public setSeal(seal: number[][]) { + public setSeal(seal: any[]) { this.seal = seal; } + public getParentHash(): H256 | null { + return this.parentHash; + } + public getHash(): H256 | null { return this.hash; } @@ -137,24 +160,6 @@ export class Header { return this.score; } - public default(): Header { - return new Header( - new H256( - "0000000000000000000000000000000000000000000000000000000000000000" - ), - new U256(0), - new U256(0), - new H160("0000000000000000000000000000000000000000"), - Buffer.alloc(0), - BLAKE_NULL_RLP, - BLAKE_NULL_RLP, - new U256( - "0000000000000000000000000000000000000000000000000000000000000000" - ), - [] - ); - } - public toEncodeObject(): Array { return [ this.parentHash.toEncodeObject(), @@ -165,7 +170,7 @@ export class Header { this.number.toEncodeObject(), this.timestamp.toEncodeObject(), this.extraData - ].concat(this.seal.map(seal => Buffer.of(...seal))); + ].concat(this.seal); } public rlpBytes(): Buffer { diff --git a/test/src/helper/mock/test/blockSyncMessage.test.ts b/test/src/helper/mock/test/blockSyncMessage.test.ts index 6c1a2a70a4..593b8d2310 100644 --- a/test/src/helper/mock/test/blockSyncMessage.test.ts +++ b/test/src/helper/mock/test/blockSyncMessage.test.ts @@ -14,7 +14,7 @@ describe("Check BlockSyncMessage RLP encoding", function() { id: new U256(10), message }); - expect([...msg.rlpBytes()]).deep.equal([195, 4, 10, 192]); + expect(msg.rlpBytes().toString("hex")).deep.equal("c3040ac0"); }); it("ResponseBodyMessage RLP encoding test", function() { @@ -27,6 +27,6 @@ describe("Check BlockSyncMessage RLP encoding", function() { id: new U256(10), message }); - expect([...msg.rlpBytes()]).deep.equal([196, 5, 10, 193, 192]); + expect(msg.rlpBytes().toString("hex")).deep.equal("c8050ac5840204c1c0"); }); }); diff --git a/test/src/helper/mock/test/header.test.ts b/test/src/helper/mock/test/header.test.ts new file mode 100644 index 0000000000..3de02e23d1 --- /dev/null +++ b/test/src/helper/mock/test/header.test.ts @@ -0,0 +1,69 @@ +import { Buffer } from "buffer"; +import { expect } from "chai"; +import "mocha"; +import * as RLP from "rlp"; +import { + getPublicFromPrivate, + H256, + U256, + H160, + blake256, + blake160, + signEcdsa, + signSchnorr, + getAccountIdFromPublic +} from "codechain-primitives"; +import { Header } from "../cHeader"; + +describe("Check Header RLP encoding", function() { + it("empty Header RLP encoding test", function() { + const header = Header.default(); + // Find the empty header's rlp encoded data in the unit test in header.rs file + expect(header.rlpBytes().toString("hex")).deep.equal( + "f87ca00000000000000000000000000000000000000000000000000000000000000000940000000000000000000000000000000000000000a045b0cfc220ceec5b7c1c62c4d4193d38e4eba48e8815729ce75f9c0ab0e4c1c0a045b0cfc220ceec5b7c1c62c4d4193d38e4eba48e8815729ce75f9c0ab0e4c1c080808080" + ); + }); + + it("Header RLP encoding test", function() { + const privateKey = + "ede1d4ccb4ec9a8bbbae9a13db3f4a7b56ea04189be86ac3a6a439d9a0a1addd"; + const publicKey = getPublicFromPrivate(privateKey); + const header = Header.default(); + header.setNumber(new U256(4)); + header.setAuthor(new H160(getAccountIdFromPublic(publicKey))); + const bitset = Buffer.alloc(100, 0); + bitset[0] = 4; + const signature = createPrecommit({ + height: 3, + view: 0, + step: 2, + parentHash: header.getParentHash()!, + privateKey + }); + header.setSeal([0, 0, [Buffer.from(signature, "hex")], bitset]); + // Find the header's rlp encoded data in the unit test in the tendermint/mod.rs file + expect(header.rlpBytes().toString("hex")).deep.equal( + "f90128a00000000000000000000000000000000000000000000000000000000000000000946fe64ffa3a46c074226457c90ccb32dc06ccced1a045b0cfc220ceec5b7c1c62c4d4193d38e4eba48e8815729ce75f9c0ab0e4c1c0a045b0cfc220ceec5b7c1c62c4d4193d38e4eba48e8815729ce75f9c0ab0e4c1c0800480808080f842b8405aa028f952416218d440568ddf58b42a02515d53dbe40aec6d8fbc3a0b9de171bd1fa833c2bf9e7b950414ca4bbc261c662d50372340c0f7b41ab0a12d11a789b86404000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000" + ); + }); + + function createPrecommit({ + height, + view, + step, + parentHash, + privateKey + }: { + height: number; + view: number; + step: number; + parentHash: H256; + privateKey: string; + }): string { + const voteOn = [[height, view, step], [parentHash.toEncodeObject()]]; + const serializedVoteOn = RLP.encode(voteOn); + const message = blake256(serializedVoteOn); + const { r, s } = signSchnorr(message, privateKey); + return r + s; + } +}); diff --git a/test/src/helper/mock/test/txSyncMessage.test.ts b/test/src/helper/mock/test/txSyncMessage.test.ts index 2b281be507..c90929b2d2 100644 --- a/test/src/helper/mock/test/txSyncMessage.test.ts +++ b/test/src/helper/mock/test/txSyncMessage.test.ts @@ -8,6 +8,6 @@ describe("Check TransactionSyncMessage RLP encoding", function() { type: "transactions", data: [] }); - expect([...msg.rlpBytes()]).deep.equal([192]); + expect(msg.rlpBytes().toString("hex")).deep.equal("830100c0"); }); }); diff --git a/test/src/helper/spawn.ts b/test/src/helper/spawn.ts index 4b2eb4bc95..0c7bc87a7b 100644 --- a/test/src/helper/spawn.ts +++ b/test/src/helper/spawn.ts @@ -40,6 +40,8 @@ import { createInterface as createReadline, ReadLine } from "readline"; import { faucetAddress, faucetSecret } from "./constants"; import { wait } from "./promise"; +const getPort = require("get-port"); + const projectRoot = `${__dirname}/../../..`; export type SchemeFilepath = string; @@ -77,7 +79,6 @@ export interface Signer { export default class CodeChain { private static idCounter = 0; private readonly _id: number; - private readonly _sdk: SDK; private readonly _localKeyStorePath: string; private readonly _dbPath: string; private readonly _ipcPath: string; @@ -85,9 +86,11 @@ export default class CodeChain { private readonly _logFile: string; private readonly _logPath: string; private readonly _chain: ChainType; - private readonly _rpcPort: number; private readonly argv: string[]; private readonly env: { [key: string]: string }; + private _sdk?: SDK; + private _port?: number; + private _rpcPort?: number; private process: ProcessState; private restarts: number; private _keepLogs: boolean; @@ -99,7 +102,7 @@ export default class CodeChain { } public get sdk(): SDK { if (this.process.state === "running") { - return this._sdk; + return this._sdk!; } else { throw new ProcessStateError(this.id, this.process); } @@ -123,10 +126,10 @@ export default class CodeChain { return this._logPath; } public get rpcPort(): number { - return this._rpcPort; + return this._rpcPort!; } public get port(): number { - return 3486 + this.id; + return this._port!; } public get secretKey(): number { return 1 + this.id; @@ -160,9 +163,6 @@ export default class CodeChain { const { chain, argv, additionalKeysPath, env } = options; this._id = CodeChain.idCounter++; - const { rpcPort = 8081 + this.id } = options; - this._rpcPort = rpcPort; - mkdirp.sync(`${projectRoot}/db/`); mkdirp.sync(`${projectRoot}/keys/`); mkdirp.sync(`${projectRoot}/test/log/`); @@ -188,7 +188,6 @@ export default class CodeChain { this.id }.log`; this._logPath = `${projectRoot}/test/log/${this._logFile}`; - this._sdk = new SDK({ server: `http://localhost:${this.rpcPort}` }); this._chain = chain || "solo"; this.argv = argv || []; this.env = env || {}; @@ -207,6 +206,10 @@ export default class CodeChain { throw new ProcessStateError(this.id, this.process); } + await this.initialize_port(); + + this._sdk = new SDK({ server: `http://localhost:${this.rpcPort}` }); + const { argv = [], logLevel = "trace,mio=warn,tokio=warn,hyper=warn,timer=warn", @@ -252,6 +255,7 @@ export default class CodeChain { { cwd: projectRoot, env: { + RUN_ON_TEST: "1", ...process.env, ...this.env } @@ -871,4 +875,9 @@ export default class CodeChain { } } } + + private async initialize_port() { + this._port = await getPort({ port: this.id + 3486 }); + this._rpcPort = await getPort({ port: this.id + 8081 }); + } } diff --git a/test/yarn.lock b/test/yarn.lock index 6c35a4396c..cc9f3cd613 100644 --- a/test/yarn.lock +++ b/test/yarn.lock @@ -778,6 +778,11 @@ get-func-name@^2.0.0: resolved "https://registry.yarnpkg.com/get-func-name/-/get-func-name-2.0.0.tgz#ead774abee72e20409433a066366023dd6887a41" integrity sha1-6td0q+5y4gQJQzoGY2YCPdaIekE= +get-port@^5.1.1: + version "5.1.1" + resolved "https://registry.yarnpkg.com/get-port/-/get-port-5.1.1.tgz#0469ed07563479de6efb986baf053dcd7d4e3193" + integrity sha512-g/Q1aTSDOxFpchXC4i8ZWvxA1lnPqx/JHqcpIw0/LX9T8x/GBbi6YnlN5nhaKIFkT8oFsscUKgDJYxfwfS6QsQ== + getpass@^0.1.1: version "0.1.7" resolved "https://registry.yarnpkg.com/getpass/-/getpass-0.1.7.tgz#5eff8e3e684d569ae4cb2b1282604e8ba62149fa" diff --git a/types/Cargo.toml b/types/Cargo.toml index e80af0950c..9f04601561 100644 --- a/types/Cargo.toml +++ b/types/Cargo.toml @@ -5,7 +5,7 @@ authors = ["CodeChain Team "] edition = "2018" [dependencies] -codechain-crypto = { git = "https://github.com/CodeChain-io/rust-codechain-crypto.git", version = "0.1" } +codechain-crypto = { git = "https://github.com/CodeChain-io/rust-codechain-crypto.git", version = "0.2" } codechain-json = { path = "../json" } codechain-key = { path = "../key" } primitives = { git = "https://github.com/CodeChain-io/rust-codechain-primitives.git", version = "0.4" } diff --git a/types/src/header.rs b/types/src/header.rs index c9027e8e2f..e88bb60f61 100644 --- a/types/src/header.rs +++ b/types/src/header.rs @@ -32,7 +32,7 @@ pub enum Seal { } /// A block header. -#[derive(Debug, Clone, PartialEq)] +#[derive(Debug, Clone)] pub struct Header { /// Parent hash. parent_hash: BlockHash, @@ -305,3 +305,16 @@ impl Encodable for Header { self.stream_rlp(s, &Seal::With); } } + +#[cfg(test)] +mod tests { + use super::*; + + #[test] + fn serialize_deserialize_test() { + let empty = Header::default(); + let encoded = rlp::encode(&empty); + let decoded: Header = rlp::decode(&encoded).unwrap(); + assert_eq!(empty.hash(), decoded.hash()); + } +} diff --git a/types/src/transaction/action.rs b/types/src/transaction/action.rs index 3d46389a69..973680c39f 100644 --- a/types/src/transaction/action.rs +++ b/types/src/transaction/action.rs @@ -23,25 +23,57 @@ use primitives::{Bytes, H160, H256}; use rlp::{Decodable, DecoderError, Encodable, Rlp, RlpStream}; use std::collections::{HashMap, HashSet}; -const PAY: u8 = 0x02; -const SET_REGULAR_KEY: u8 = 0x03; -const CREATE_SHARD: u8 = 0x04; -const SET_SHARD_OWNERS: u8 = 0x05; -const SET_SHARD_USERS: u8 = 0x06; -const WRAP_CCC: u8 = 0x07; -const STORE: u8 = 0x08; -const REMOVE: u8 = 0x09; -const UNWRAP_CCC: u8 = 0x11; -const MINT_ASSET: u8 = 0x13; -const TRANSFER_ASSET: u8 = 0x14; -const CHANGE_ASSET_SCHEME: u8 = 0x15; -// Derepcated -//const COMPOSE_ASSET: u8 = 0x16; -// Derepcated -//const DECOMPOSE_ASSET: u8 = 0x17; -const INCREASE_ASSET_SUPPLY: u8 = 0x18; +#[derive(Clone, Copy)] +#[repr(u8)] +enum ActionTag { + Pay = 0x02, + SetRegularKey = 0x03, + CreateShard = 0x04, + SetShardOwners = 0x05, + SetShardUsers = 0x06, + WrapCcc = 0x07, + Store = 0x08, + Remove = 0x09, + UnwrapCcc = 0x11, + MintAsset = 0x13, + TransferAsset = 0x14, + ChangeAssetScheme = 0x15, + // Derepcated + // ComposeAsset = 0x16, + // Derepcated + // DecomposeAsset = 0x17, + IncreaseAssetSupply = 0x18, + Custom = 0xFF, +} -const CUSTOM: u8 = 0xFF; +impl Encodable for ActionTag { + fn rlp_append(&self, s: &mut RlpStream) { + (*self as u8).rlp_append(s) + } +} + +impl Decodable for ActionTag { + fn decode(rlp: &Rlp) -> Result { + let tag = rlp.as_val()?; + match tag { + 0x02u8 => Ok(Self::Pay), + 0x03u8 => Ok(Self::SetRegularKey), + 0x04u8 => Ok(Self::CreateShard), + 0x05u8 => Ok(Self::SetShardOwners), + 0x06u8 => Ok(Self::SetShardUsers), + 0x07u8 => Ok(Self::WrapCcc), + 0x08u8 => Ok(Self::Store), + 0x09u8 => Ok(Self::Remove), + 0x11u8 => Ok(Self::UnwrapCcc), + 0x13u8 => Ok(Self::MintAsset), + 0x14u8 => Ok(Self::TransferAsset), + 0x15u8 => Ok(Self::ChangeAssetScheme), + 0x18u8 => Ok(Self::IncreaseAssetSupply), + 0xFFu8 => Ok(Self::Custom), + _ => Err(DecoderError::Custom("Unexpected action prefix")), + } + } +} #[derive(Debug, Clone, PartialEq, Eq)] pub enum Action { @@ -464,7 +496,7 @@ impl Encodable for Action { approvals, } => { s.begin_list(11) - .append(&MINT_ASSET) + .append(&ActionTag::MintAsset) .append(network_id) .append(shard_id) .append(metadata) @@ -487,7 +519,7 @@ impl Encodable for Action { } => { let empty: Vec = vec![]; s.begin_list(9) - .append(&TRANSFER_ASSET) + .append(&ActionTag::TransferAsset) .append(network_id) .append_list(burns) .append_list(inputs) @@ -510,7 +542,7 @@ impl Encodable for Action { approvals, } => { s.begin_list(10) - .append(&CHANGE_ASSET_SCHEME) + .append(&ActionTag::ChangeAssetScheme) .append(network_id) .append(shard_id) .append(asset_type) @@ -530,7 +562,7 @@ impl Encodable for Action { approvals, } => { s.begin_list(9) - .append(&INCREASE_ASSET_SUPPLY) + .append(&ActionTag::IncreaseAssetSupply) .append(network_id) .append(shard_id) .append(asset_type) @@ -545,14 +577,14 @@ impl Encodable for Action { burn, receiver, } => { - s.begin_list(4).append(&UNWRAP_CCC).append(network_id).append(burn).append(receiver); + s.begin_list(4).append(&ActionTag::UnwrapCcc).append(network_id).append(burn).append(receiver); } Action::Pay { receiver, quantity, } => { s.begin_list(3); - s.append(&PAY); + s.append(&ActionTag::Pay); s.append(receiver); s.append(quantity); } @@ -560,14 +592,14 @@ impl Encodable for Action { key, } => { s.begin_list(2); - s.append(&SET_REGULAR_KEY); + s.append(&ActionTag::SetRegularKey); s.append(key); } Action::CreateShard { users, } => { s.begin_list(2); - s.append(&CREATE_SHARD); + s.append(&ActionTag::CreateShard); s.append_list(users); } Action::SetShardOwners { @@ -575,7 +607,7 @@ impl Encodable for Action { owners, } => { s.begin_list(3); - s.append(&SET_SHARD_OWNERS); + s.append(&ActionTag::SetShardOwners); s.append(shard_id); s.append_list(owners); } @@ -584,7 +616,7 @@ impl Encodable for Action { users, } => { s.begin_list(3); - s.append(&SET_SHARD_USERS); + s.append(&ActionTag::SetShardUsers); s.append(shard_id); s.append_list(users); } @@ -596,7 +628,7 @@ impl Encodable for Action { payer, } => { s.begin_list(6); - s.append(&WRAP_CCC); + s.append(&ActionTag::WrapCcc); s.append(shard_id); s.append(lock_script_hash); s.append(parameters); @@ -609,7 +641,7 @@ impl Encodable for Action { signature, } => { s.begin_list(4); - s.append(&STORE); + s.append(&ActionTag::Store); s.append(content); s.append(certifier); s.append(signature); @@ -619,7 +651,7 @@ impl Encodable for Action { signature, } => { s.begin_list(3); - s.append(&REMOVE); + s.append(&ActionTag::Remove); s.append(hash); s.append(signature); } @@ -628,7 +660,7 @@ impl Encodable for Action { bytes, } => { s.begin_list(3); - s.append(&CUSTOM); + s.append(&ActionTag::Custom); s.append(handler_id); s.append(bytes); } @@ -639,7 +671,7 @@ impl Encodable for Action { impl Decodable for Action { fn decode(rlp: &Rlp) -> Result { match rlp.val_at(0)? { - MINT_ASSET => { + ActionTag::MintAsset => { let item_count = rlp.item_count()?; if item_count != 11 { return Err(DecoderError::RlpIncorrectListLen { @@ -662,7 +694,7 @@ impl Decodable for Action { approvals: rlp.list_at(10)?, }) } - TRANSFER_ASSET => { + ActionTag::TransferAsset => { let item_count = rlp.item_count()?; if item_count != 9 { return Err(DecoderError::RlpIncorrectListLen { @@ -680,7 +712,7 @@ impl Decodable for Action { expiration: rlp.val_at(8)?, }) } - CHANGE_ASSET_SCHEME => { + ActionTag::ChangeAssetScheme => { let item_count = rlp.item_count()?; if item_count != 10 { return Err(DecoderError::RlpIncorrectListLen { @@ -700,7 +732,7 @@ impl Decodable for Action { approvals: rlp.list_at(9)?, }) } - INCREASE_ASSET_SUPPLY => { + ActionTag::IncreaseAssetSupply => { let item_count = rlp.item_count()?; if item_count != 9 { return Err(DecoderError::RlpIncorrectListLen { @@ -721,7 +753,7 @@ impl Decodable for Action { approvals: rlp.list_at(8)?, }) } - UNWRAP_CCC => { + ActionTag::UnwrapCcc => { let item_count = rlp.item_count()?; if item_count != 4 { return Err(DecoderError::RlpIncorrectListLen { @@ -735,7 +767,7 @@ impl Decodable for Action { receiver: rlp.val_at(3)?, }) } - PAY => { + ActionTag::Pay => { let item_count = rlp.item_count()?; if item_count != 3 { return Err(DecoderError::RlpIncorrectListLen { @@ -748,7 +780,7 @@ impl Decodable for Action { quantity: rlp.val_at(2)?, }) } - SET_REGULAR_KEY => { + ActionTag::SetRegularKey => { let item_count = rlp.item_count()?; if item_count != 2 { return Err(DecoderError::RlpIncorrectListLen { @@ -760,7 +792,7 @@ impl Decodable for Action { key: rlp.val_at(1)?, }) } - CREATE_SHARD => { + ActionTag::CreateShard => { let item_count = rlp.item_count()?; if item_count != 2 { return Err(DecoderError::RlpIncorrectListLen { @@ -772,7 +804,7 @@ impl Decodable for Action { users: rlp.list_at(1)?, }) } - SET_SHARD_OWNERS => { + ActionTag::SetShardOwners => { let item_count = rlp.item_count()?; if item_count != 3 { return Err(DecoderError::RlpIncorrectListLen { @@ -785,7 +817,7 @@ impl Decodable for Action { owners: rlp.list_at(2)?, }) } - SET_SHARD_USERS => { + ActionTag::SetShardUsers => { let item_count = rlp.item_count()?; if item_count != 3 { return Err(DecoderError::RlpIncorrectListLen { @@ -798,7 +830,7 @@ impl Decodable for Action { users: rlp.list_at(2)?, }) } - WRAP_CCC => { + ActionTag::WrapCcc => { let item_count = rlp.item_count()?; if item_count != 6 { return Err(DecoderError::RlpIncorrectListLen { @@ -814,7 +846,7 @@ impl Decodable for Action { payer: rlp.val_at(5)?, }) } - STORE => { + ActionTag::Store => { let item_count = rlp.item_count()?; if item_count != 4 { return Err(DecoderError::RlpIncorrectListLen { @@ -828,7 +860,7 @@ impl Decodable for Action { signature: rlp.val_at(3)?, }) } - REMOVE => { + ActionTag::Remove => { let item_count = rlp.item_count()?; if item_count != 3 { return Err(DecoderError::RlpIncorrectListLen { @@ -841,7 +873,7 @@ impl Decodable for Action { signature: rlp.val_at(2)?, }) } - CUSTOM => { + ActionTag::Custom => { let item_count = rlp.item_count()?; if item_count != 3 { return Err(DecoderError::RlpIncorrectListLen { @@ -854,7 +886,6 @@ impl Decodable for Action { bytes: rlp.val_at(2)?, }) } - _ => Err(DecoderError::Custom("Unexpected action prefix")), } } } diff --git a/util/io/Cargo.toml b/util/io/Cargo.toml index f0849917d0..32a3140c45 100644 --- a/util/io/Cargo.toml +++ b/util/io/Cargo.toml @@ -11,5 +11,5 @@ edition = "2018" codechain-logger = { path = "../logger" } mio = "0.6.16" crossbeam = "0.5.0" -parking_lot = "0.6.0" +parking_lot = "0.11.0" log = "0.4.6" diff --git a/util/logger/Cargo.toml b/util/logger/Cargo.toml index 5808f502fe..489bdc6dcc 100644 --- a/util/logger/Cargo.toml +++ b/util/logger/Cargo.toml @@ -10,7 +10,7 @@ colored = "1.6" env_logger = "0.6.0" lazy_static = "1.2" log = "0.4.6" -parking_lot = "0.6.0" +parking_lot = "0.11.0" sendgrid = "0.8.1" serde = "1.0" serde_derive = "1.0" diff --git a/util/timer/Cargo.toml b/util/timer/Cargo.toml index 322427a4ce..f7e977363d 100644 --- a/util/timer/Cargo.toml +++ b/util/timer/Cargo.toml @@ -7,6 +7,6 @@ edition = "2018" [lib] [dependencies] -parking_lot = "0.6.0" +parking_lot = "0.11.0" log = "0.4.6" codechain-logger = { path = "../logger" } diff --git a/vm/Cargo.toml b/vm/Cargo.toml index c3ee936994..71514e49ab 100644 --- a/vm/Cargo.toml +++ b/vm/Cargo.toml @@ -7,7 +7,7 @@ edition = "2018" [lib] [dependencies] -codechain-crypto = { git = "https://github.com/CodeChain-io/rust-codechain-crypto.git", version = "0.1" } +codechain-crypto = { git = "https://github.com/CodeChain-io/rust-codechain-crypto.git", version = "0.2" } codechain-key = { path = "../key" } codechain-types = { path = "../types" } primitives = { git = "https://github.com/CodeChain-io/rust-codechain-primitives.git", version = "0.4" }