diff --git a/.circleci/config.yml b/.circleci/config.yml index 1a43b851d..434ae46b0 100644 --- a/.circleci/config.yml +++ b/.circleci/config.yml @@ -238,7 +238,22 @@ jobs: name: Basic Tls Test command: ./tests/integrate_test/cita_basic.sh --enable_tls - "JSON-RPC Mock Test in Charge Mode": + # "JSON-RPC Mock Test in Charge Mode": + # <<: *job-default + # steps: + # - restore_cache: *restore-source-codes-cache + # - restore_cache: *restore-release-cache + # - run: *after-restore-release-cache + # - run: + # name: JSON-RPC Mock Test in Quota Mode + # command: ./tests/integrate_test/cita_jsonrpc_schema_mock.sh quota + # - run: + # name: (Skip & TODO) JSON-RPC Mock Test in Charge Mode + # command: | + # echo "We should add it back later." + # ./tests/integrate_test/cita_jsonrpc_schema_mock.sh charge + + "JSON-RPC Mock Test in Quota Mode": <<: *job-default steps: - restore_cache: *restore-source-codes-cache @@ -247,31 +262,26 @@ jobs: - run: name: JSON-RPC Mock Test in Quota Mode command: ./tests/integrate_test/cita_jsonrpc_schema_mock.sh quota - - run: - name: (Skip & TODO) JSON-RPC Mock Test in Charge Mode - command: | - echo "We should add it back later." - # ./tests/integrate_test/cita_jsonrpc_schema_mock.sh charge - "JSON-RPC Mock Test in Quota Mode": + "Test Transfer Value in Charge Mode": <<: *job-default steps: - restore_cache: *restore-source-codes-cache - restore_cache: *restore-release-cache - run: *after-restore-release-cache - run: - name: JSON-RPC Mock Test in Quota Mode - command: ./tests/integrate_test/cita_jsonrpc_schema_mock.sh quota + name: Test Transfer Value in Charge Mode + command: ./tests/integrate_test/cita_charge_mode.sh - "Test Transfer Value in Charge Mode": + "Test System Features": <<: *job-default steps: - restore_cache: *restore-source-codes-cache - restore_cache: *restore-release-cache - run: *after-restore-release-cache - run: - name: Test Transfer Value in Charge Mode - command: ./tests/integrate_test/cita_charge_mode.sh + name: Test System Features + command: ./tests/integrate_test/cita_features_test.sh "Test Executor Process SignProposal/BlockWithProof": <<: *job-default @@ -405,7 +415,7 @@ workflows: - "Check Basic" - - "Check Contracts" + # - "Check Contracts" # - "Test Coverage": # requires: @@ -418,10 +428,6 @@ workflows: requires: - "Check Basic" - - "Unit Test (sha3 & secp256k1)": - requires: - - "Release" - - "Basic Test": requires: - "Release" @@ -429,18 +435,21 @@ workflows: requires: - "Release" - - "JSON-RPC Mock Test in Charge Mode": - requires: - - "Release" + # - "JSON-RPC Mock Test in Charge Mode": + # requires: + # - "Release" - "JSON-RPC Mock Test in Quota Mode": requires: - "Release" - "Test Transfer Value in Charge Mode": requires: - "Release" - - "Test Snapshot Taking And Restoring": + - "Test System Features": requires: - "Release" + # - "Test Snapshot Taking And Restoring": + # requires: + # - "Release" - "Test Amend": requires: - "Release" @@ -457,9 +466,9 @@ workflows: - "Byzantine Test in Charge Mode": requires: - "Release" - - "Crosschain Test": - requires: - - "Release" + # - "Crosschain Test": + # requires: + # - "Release" - "Robustness Test": requires: - "Release" @@ -467,6 +476,9 @@ workflows: requires: - "Release" + - "Unit Test (sha3 & secp256k1)": + requires: + - "Release" - "Unit Test (blake2b & ed25519)": requires: - "Unit Test (sha3 & secp256k1)" @@ -476,19 +488,23 @@ workflows: - "Passed": requires: - - "Basic Test" - - "Basic Tls Test" - - "JSON-RPC Mock Test in Charge Mode" - - "JSON-RPC Mock Test in Quota Mode" - - "Test Transfer Value in Charge Mode" - - "Test Snapshot Taking And Restoring" - - "Test Amend" - - "Test Executor Process Invalid Proof" - - "Discovery Test for network" - - "Byzantine Test in Quota Mode" - - "Byzantine Test in Charge Mode" - - "Crosschain Test" - - "Robustness Test" - - "Genesis Test" - - "Unit Test (blake2b & ed25519)" - - "Unit Test (sm3 & sm2)" + - "Check Basic" + - "Check Clippy" + - "Release" + - "Basic Test" + - "Basic Tls Test" + - "JSON-RPC Mock Test in Quota Mode" + - "Test Transfer Value in Charge Mode" + - "Test System Features" + - "Test Amend" + - "Test Executor Process Invalid Proof" + - "Discovery Test for network" + - "Byzantine Test in Quota Mode" + - "Byzantine Test in Charge Mode" + - "Robustness Test" + - "Genesis Test" + - "Unit Test (blake2b & ed25519)" + - "Unit Test (sm3 & sm2)" + # - "Crosschain Test" + # - "Test Snapshot Taking And Restoring" + # - "JSON-RPC Mock Test in Charge Mode" diff --git a/.github/ISSUE_TEMPLATE/bug_report.md b/.github/ISSUE_TEMPLATE/bug_report.md index 6035b5ca6..77267880b 100644 --- a/.github/ISSUE_TEMPLATE/bug_report.md +++ b/.github/ISSUE_TEMPLATE/bug_report.md @@ -3,7 +3,7 @@ name: Bug report about: Create a report to help us improve title: '' labels: bug -assignees: kaikai1024 +assignees: jerry-yu --- diff --git a/.gitignore b/.gitignore index 83d59196d..d55196fe7 100644 --- a/.gitignore +++ b/.gitignore @@ -60,3 +60,6 @@ docs/site # localtime for macos users localtime + +# test data +**/test-rocksdb diff --git a/Cargo.lock b/Cargo.lock index 26dc596ca..1535cc2c0 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -135,7 +135,7 @@ dependencies = [ [[package]] name = "authority_manage" version = "0.1.0" -source = "git+https://github.com/cryptape/cita-common.git?branch=develop#b948764c71c656943506317505868bbde95bc3f3" +source = "git+https://github.com/cryptape/cita-common.git?branch=develop#788444602d6181741281c06c2684d3d60374a350" dependencies = [ "bincode 0.8.0 (registry+https://github.com/rust-lang/crates.io-index)", "cita-types 0.1.0 (git+https://github.com/cryptape/cita-common.git?branch=develop)", @@ -216,20 +216,23 @@ dependencies = [ [[package]] name = "bindgen" -version = "0.37.4" +version = "0.49.2" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "cexpr 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)", + "bitflags 1.0.4 (registry+https://github.com/rust-lang/crates.io-index)", + "cexpr 0.3.5 (registry+https://github.com/rust-lang/crates.io-index)", "cfg-if 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)", - "clang-sys 0.23.0 (registry+https://github.com/rust-lang/crates.io-index)", + "clang-sys 0.28.0 (registry+https://github.com/rust-lang/crates.io-index)", "clap 2.33.0 (registry+https://github.com/rust-lang/crates.io-index)", - "env_logger 0.5.13 (registry+https://github.com/rust-lang/crates.io-index)", + "env_logger 0.6.1 (registry+https://github.com/rust-lang/crates.io-index)", + "fxhash 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)", "lazy_static 1.3.0 (registry+https://github.com/rust-lang/crates.io-index)", "log 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)", "peeking_take_while 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)", - "proc-macro2 0.3.5 (registry+https://github.com/rust-lang/crates.io-index)", - "quote 0.5.2 (registry+https://github.com/rust-lang/crates.io-index)", + "proc-macro2 0.4.20 (registry+https://github.com/rust-lang/crates.io-index)", + "quote 0.6.8 (registry+https://github.com/rust-lang/crates.io-index)", "regex 1.0.5 (registry+https://github.com/rust-lang/crates.io-index)", + "shlex 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)", "which 1.0.5 (registry+https://github.com/rust-lang/crates.io-index)", ] @@ -270,7 +273,7 @@ dependencies = [ [[package]] name = "blake2b" version = "0.1.0" -source = "git+https://github.com/cryptape/cita-common.git?branch=develop#b948764c71c656943506317505868bbde95bc3f3" +source = "git+https://github.com/cryptape/cita-common.git?branch=develop#788444602d6181741281c06c2684d3d60374a350" dependencies = [ "cc 1.0.26 (registry+https://github.com/rust-lang/crates.io-index)", ] @@ -325,7 +328,7 @@ version = "0.1.0" dependencies = [ "bincode 0.8.0 (registry+https://github.com/rust-lang/crates.io-index)", "cita-crypto 0.1.0 (git+https://github.com/cryptape/cita-common.git?branch=develop)", - "cita-logger 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)", + "cita-logger 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)", "cita-types 0.1.0 (git+https://github.com/cryptape/cita-common.git?branch=develop)", "clap 2.33.0 (registry+https://github.com/rust-lang/crates.io-index)", "dotenv 0.13.0 (registry+https://github.com/rust-lang/crates.io-index)", @@ -383,13 +386,16 @@ dependencies = [ name = "cc" version = "1.0.26" source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "rayon 1.2.0 (registry+https://github.com/rust-lang/crates.io-index)", +] [[package]] name = "cexpr" -version = "0.2.3" +version = "0.3.5" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "nom 3.2.1 (registry+https://github.com/rust-lang/crates.io-index)", + "nom 4.2.3 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -403,7 +409,7 @@ version = "0.1.0" dependencies = [ "bincode 0.8.0 (registry+https://github.com/rust-lang/crates.io-index)", "cita-crypto 0.1.0 (git+https://github.com/cryptape/cita-common.git?branch=develop)", - "cita-logger 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)", + "cita-logger 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)", "cita-types 0.1.0 (git+https://github.com/cryptape/cita-common.git?branch=develop)", "clap 2.33.0 (registry+https://github.com/rust-lang/crates.io-index)", "dotenv 0.13.0 (registry+https://github.com/rust-lang/crates.io-index)", @@ -424,7 +430,7 @@ version = "0.1.0" dependencies = [ "bincode 0.8.0 (registry+https://github.com/rust-lang/crates.io-index)", "cita-crypto 0.1.0 (git+https://github.com/cryptape/cita-common.git?branch=develop)", - "cita-logger 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)", + "cita-logger 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)", "cita-types 0.1.0 (git+https://github.com/cryptape/cita-common.git?branch=develop)", "clap 2.33.0 (registry+https://github.com/rust-lang/crates.io-index)", "common-types 0.1.0", @@ -454,13 +460,12 @@ name = "cita-auth" version = "0.1.0" dependencies = [ "cita-crypto 0.1.0 (git+https://github.com/cryptape/cita-common.git?branch=develop)", + "cita-database 0.1.0 (git+https://github.com/cryptape/cita-database.git?branch=develop)", "cita-directories 0.1.0 (git+https://github.com/cryptape/cita-common.git?branch=develop)", - "cita-logger 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)", + "cita-logger 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)", "cita-types 0.1.0 (git+https://github.com/cryptape/cita-common.git?branch=develop)", "clap 2.33.0 (registry+https://github.com/rust-lang/crates.io-index)", - "core 0.1.0", "cpuprofiler 0.0.3 (registry+https://github.com/rust-lang/crates.io-index)", - "db 0.1.0 (git+https://github.com/cryptape/cita-common.git?branch=develop)", "dotenv 0.13.0 (registry+https://github.com/rust-lang/crates.io-index)", "error 0.1.0 (git+https://github.com/cryptape/cita-common.git?branch=develop)", "hashable 0.1.0 (git+https://github.com/cryptape/cita-common.git?branch=develop)", @@ -469,7 +474,7 @@ dependencies = [ "lru 0.1.8 (registry+https://github.com/rust-lang/crates.io-index)", "pubsub 0.6.0 (git+https://github.com/cryptape/cita-common.git?branch=develop)", "quickcheck 0.7.2 (registry+https://github.com/rust-lang/crates.io-index)", - "rayon 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)", + "rayon 1.2.0 (registry+https://github.com/rust-lang/crates.io-index)", "serde 1.0.89 (registry+https://github.com/rust-lang/crates.io-index)", "serde_derive 1.0.89 (registry+https://github.com/rust-lang/crates.io-index)", "serde_json 1.0.39 (registry+https://github.com/rust-lang/crates.io-index)", @@ -488,7 +493,7 @@ dependencies = [ "bincode 0.8.0 (registry+https://github.com/rust-lang/crates.io-index)", "cita-crypto 0.1.0 (git+https://github.com/cryptape/cita-common.git?branch=develop)", "cita-directories 0.1.0 (git+https://github.com/cryptape/cita-common.git?branch=develop)", - "cita-logger 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)", + "cita-logger 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)", "cita-types 0.1.0 (git+https://github.com/cryptape/cita-common.git?branch=develop)", "clap 2.33.0 (registry+https://github.com/rust-lang/crates.io-index)", "cpuprofiler 0.0.3 (registry+https://github.com/rust-lang/crates.io-index)", @@ -498,7 +503,6 @@ dependencies = [ "libproto 0.6.0 (git+https://github.com/cryptape/cita-common.git?branch=develop)", "lru-cache 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)", "min-max-heap 1.2.2 (registry+https://github.com/rust-lang/crates.io-index)", - "ntp 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)", "proof 0.6.0 (git+https://github.com/cryptape/cita-common.git?branch=develop)", "pubsub 0.6.0 (git+https://github.com/cryptape/cita-common.git?branch=develop)", "rustc-hex 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)", @@ -512,14 +516,13 @@ dependencies = [ name = "cita-chain" version = "0.6.0" dependencies = [ - "byteorder 1.3.1 (registry+https://github.com/rust-lang/crates.io-index)", + "cita-database 0.1.0 (git+https://github.com/cryptape/cita-database.git?branch=develop)", "cita-directories 0.1.0 (git+https://github.com/cryptape/cita-common.git?branch=develop)", - "cita-logger 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)", + "cita-logger 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)", "cita-types 0.1.0 (git+https://github.com/cryptape/cita-common.git?branch=develop)", "clap 2.33.0 (registry+https://github.com/rust-lang/crates.io-index)", "common-types 0.1.0", "core 0.1.0", - "db 0.1.0 (git+https://github.com/cryptape/cita-common.git?branch=develop)", "dotenv 0.13.0 (registry+https://github.com/rust-lang/crates.io-index)", "error 0.1.0 (git+https://github.com/cryptape/cita-common.git?branch=develop)", "jsonrpc-types 0.1.0 (git+https://github.com/cryptape/cita-common.git?branch=develop)", @@ -533,7 +536,7 @@ dependencies = [ [[package]] name = "cita-crypto" version = "0.1.0" -source = "git+https://github.com/cryptape/cita-common.git?branch=develop#b948764c71c656943506317505868bbde95bc3f3" +source = "git+https://github.com/cryptape/cita-common.git?branch=develop#788444602d6181741281c06c2684d3d60374a350" dependencies = [ "cita-crypto-trait 0.1.0 (git+https://github.com/cryptape/cita-common.git?branch=develop)", "cita-ed25519 0.6.0 (git+https://github.com/cryptape/cita-common.git?branch=develop)", @@ -544,15 +547,24 @@ dependencies = [ [[package]] name = "cita-crypto-trait" version = "0.1.0" -source = "git+https://github.com/cryptape/cita-common.git?branch=develop#b948764c71c656943506317505868bbde95bc3f3" +source = "git+https://github.com/cryptape/cita-common.git?branch=develop#788444602d6181741281c06c2684d3d60374a350" dependencies = [ "cita-types 0.1.0 (git+https://github.com/cryptape/cita-common.git?branch=develop)", ] +[[package]] +name = "cita-database" +version = "0.1.0" +source = "git+https://github.com/cryptape/cita-database.git?branch=develop#87b515b813ad484bf98e3ae82f4f2177844011e0" +dependencies = [ + "cita-logger 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)", + "rocksdb 0.12.3 (registry+https://github.com/rust-lang/crates.io-index)", +] + [[package]] name = "cita-directories" version = "0.1.0" -source = "git+https://github.com/cryptape/cita-common.git?branch=develop#b948764c71c656943506317505868bbde95bc3f3" +source = "git+https://github.com/cryptape/cita-common.git?branch=develop#788444602d6181741281c06c2684d3d60374a350" dependencies = [ "uuid 0.7.1 (registry+https://github.com/rust-lang/crates.io-index)", ] @@ -560,7 +572,7 @@ dependencies = [ [[package]] name = "cita-ed25519" version = "0.6.0" -source = "git+https://github.com/cryptape/cita-common.git?branch=develop#b948764c71c656943506317505868bbde95bc3f3" +source = "git+https://github.com/cryptape/cita-common.git?branch=develop#788444602d6181741281c06c2684d3d60374a350" dependencies = [ "bincode 0.8.0 (registry+https://github.com/rust-lang/crates.io-index)", "cita-crypto-trait 0.1.0 (git+https://github.com/cryptape/cita-common.git?branch=develop)", @@ -569,7 +581,7 @@ dependencies = [ "rlp 0.2.0 (git+https://github.com/cryptape/cita-common.git?branch=develop)", "rustc-serialize 0.3.24 (registry+https://github.com/rust-lang/crates.io-index)", "serde 1.0.89 (registry+https://github.com/rust-lang/crates.io-index)", - "sodiumoxide 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)", + "sodiumoxide 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -578,20 +590,20 @@ version = "0.1.0" dependencies = [ "bincode 0.8.0 (registry+https://github.com/rust-lang/crates.io-index)", "cita-crypto 0.1.0 (git+https://github.com/cryptape/cita-common.git?branch=develop)", + "cita-database 0.1.0 (git+https://github.com/cryptape/cita-database.git?branch=develop)", "cita-directories 0.1.0 (git+https://github.com/cryptape/cita-common.git?branch=develop)", "cita-ed25519 0.6.0 (git+https://github.com/cryptape/cita-common.git?branch=develop)", - "cita-logger 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)", + "cita-logger 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)", "cita-types 0.1.0 (git+https://github.com/cryptape/cita-common.git?branch=develop)", + "cita-vm 0.2.1 (git+https://github.com/cryptape/cita-vm.git?branch=cita)", "clap 2.33.0 (registry+https://github.com/rust-lang/crates.io-index)", "common-types 0.1.0", "core-executor 0.1.0", - "crossbeam-channel 0.2.6 (registry+https://github.com/rust-lang/crates.io-index)", - "db 0.1.0 (git+https://github.com/cryptape/cita-common.git?branch=develop)", + "crossbeam-channel 0.3.9 (registry+https://github.com/rust-lang/crates.io-index)", "dotenv 0.13.0 (registry+https://github.com/rust-lang/crates.io-index)", "error 0.1.0 (git+https://github.com/cryptape/cita-common.git?branch=develop)", - "evm 0.1.0", - "grpc 0.5.0 (registry+https://github.com/rust-lang/crates.io-index)", "hashable 0.1.0 (git+https://github.com/cryptape/cita-common.git?branch=develop)", + "itertools 0.5.10 (registry+https://github.com/rust-lang/crates.io-index)", "jsonrpc-types 0.1.0 (git+https://github.com/cryptape/cita-common.git?branch=develop)", "libproto 0.6.0 (git+https://github.com/cryptape/cita-common.git?branch=develop)", "proof 0.6.0 (git+https://github.com/cryptape/cita-common.git?branch=develop)", @@ -607,9 +619,9 @@ dependencies = [ name = "cita-forever" version = "0.1.0" dependencies = [ - "cita-logger 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)", + "cita-logger 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)", "clap 2.33.0 (registry+https://github.com/rust-lang/crates.io-index)", - "crossbeam-channel 0.3.8 (registry+https://github.com/rust-lang/crates.io-index)", + "crossbeam-channel 0.3.9 (registry+https://github.com/rust-lang/crates.io-index)", "serde 1.0.89 (registry+https://github.com/rust-lang/crates.io-index)", "serde_derive 1.0.89 (registry+https://github.com/rust-lang/crates.io-index)", "util 0.6.0 (git+https://github.com/cryptape/cita-common.git?branch=develop)", @@ -620,7 +632,7 @@ name = "cita-jsonrpc" version = "0.1.0" dependencies = [ "bytes 0.4.12 (registry+https://github.com/rust-lang/crates.io-index)", - "cita-logger 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)", + "cita-logger 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)", "clap 2.33.0 (registry+https://github.com/rust-lang/crates.io-index)", "cpuprofiler 0.0.3 (registry+https://github.com/rust-lang/crates.io-index)", "dotenv 0.13.0 (registry+https://github.com/rust-lang/crates.io-index)", @@ -654,11 +666,11 @@ dependencies = [ [[package]] name = "cita-logger" -version = "0.1.0" +version = "0.1.1" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "chrono 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)", - "crossbeam-channel 0.2.6 (registry+https://github.com/rust-lang/crates.io-index)", + "crossbeam-channel 0.3.9 (registry+https://github.com/rust-lang/crates.io-index)", "libc 0.2.46 (registry+https://github.com/rust-lang/crates.io-index)", "log 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)", "log4rs 0.8.1 (registry+https://github.com/rust-lang/crates.io-index)", @@ -668,12 +680,11 @@ dependencies = [ [[package]] name = "cita-merklehash" version = "0.1.0" -source = "git+https://github.com/cryptape/cita-common.git?branch=develop#b948764c71c656943506317505868bbde95bc3f3" +source = "git+https://github.com/cryptape/cita-common.git?branch=develop#788444602d6181741281c06c2684d3d60374a350" dependencies = [ "cita-types 0.1.0 (git+https://github.com/cryptape/cita-common.git?branch=develop)", "hashable 0.1.0 (git+https://github.com/cryptape/cita-common.git?branch=develop)", "rlp 0.2.0 (git+https://github.com/cryptape/cita-common.git?branch=develop)", - "rlp_derive 0.1.0 (git+https://github.com/cryptape/cita-common.git?branch=develop)", "static_merkle_tree 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)", ] @@ -683,7 +694,7 @@ version = "0.6.0" dependencies = [ "byteorder 1.3.1 (registry+https://github.com/rust-lang/crates.io-index)", "bytes 0.4.12 (registry+https://github.com/rust-lang/crates.io-index)", - "cita-logger 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)", + "cita-logger 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)", "cita-types 0.1.0 (git+https://github.com/cryptape/cita-common.git?branch=develop)", "clap 2.33.0 (registry+https://github.com/rust-lang/crates.io-index)", "dotenv 0.13.0 (registry+https://github.com/rust-lang/crates.io-index)", @@ -698,8 +709,8 @@ dependencies = [ "serde_derive 1.0.89 (registry+https://github.com/rust-lang/crates.io-index)", "serde_json 1.0.39 (registry+https://github.com/rust-lang/crates.io-index)", "tempfile 3.0.7 (registry+https://github.com/rust-lang/crates.io-index)", - "tentacle 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)", - "tentacle-discovery 0.2.4 (registry+https://github.com/rust-lang/crates.io-index)", + "tentacle 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)", + "tentacle-discovery 0.2.5 (registry+https://github.com/rust-lang/crates.io-index)", "tokio 0.1.16 (registry+https://github.com/rust-lang/crates.io-index)", "util 0.6.0 (git+https://github.com/cryptape/cita-common.git?branch=develop)", ] @@ -709,7 +720,7 @@ name = "cita-relayer-parser" version = "0.1.0" dependencies = [ "cita-crypto 0.1.0 (git+https://github.com/cryptape/cita-common.git?branch=develop)", - "cita-logger 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)", + "cita-logger 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)", "cita-types 0.1.0 (git+https://github.com/cryptape/cita-common.git?branch=develop)", "clap 2.33.0 (registry+https://github.com/rust-lang/crates.io-index)", "core 0.1.0", @@ -728,7 +739,7 @@ dependencies = [ [[package]] name = "cita-secp256k1" version = "0.6.0" -source = "git+https://github.com/cryptape/cita-common.git?branch=develop#b948764c71c656943506317505868bbde95bc3f3" +source = "git+https://github.com/cryptape/cita-common.git?branch=develop#788444602d6181741281c06c2684d3d60374a350" dependencies = [ "bincode 0.8.0 (registry+https://github.com/rust-lang/crates.io-index)", "cita-crypto-trait 0.1.0 (git+https://github.com/cryptape/cita-common.git?branch=develop)", @@ -745,12 +756,12 @@ dependencies = [ [[package]] name = "cita-sm2" version = "0.1.0" -source = "git+https://github.com/cryptape/cita-common.git?branch=develop#b948764c71c656943506317505868bbde95bc3f3" +source = "git+https://github.com/cryptape/cita-common.git?branch=develop#788444602d6181741281c06c2684d3d60374a350" dependencies = [ "cita-crypto-trait 0.1.0 (git+https://github.com/cryptape/cita-common.git?branch=develop)", "cita-types 0.1.0 (git+https://github.com/cryptape/cita-common.git?branch=develop)", "hashable 0.1.0 (git+https://github.com/cryptape/cita-common.git?branch=develop)", - "libsm 0.3.0 (git+https://github.com/cryptape/libsm?rev=ac323abd3512a9fdb8bfd6cd349a6fc46deb688f)", + "libsm 0.3.0 (git+https://github.com/cryptape/libsm?rev=4d0e6199fca0934c58131de1d0036e9aa4da26c1)", "rlp 0.2.0 (git+https://github.com/cryptape/cita-common.git?branch=develop)", "rustc-serialize 0.3.24 (registry+https://github.com/rust-lang/crates.io-index)", "serde 1.0.89 (registry+https://github.com/rust-lang/crates.io-index)", @@ -759,15 +770,50 @@ dependencies = [ [[package]] name = "cita-types" version = "0.1.0" -source = "git+https://github.com/cryptape/cita-common.git?branch=develop#b948764c71c656943506317505868bbde95bc3f3" +source = "git+https://github.com/cryptape/cita-common.git?branch=develop#788444602d6181741281c06c2684d3d60374a350" dependencies = [ - "ethereum-types 0.3.2 (registry+https://github.com/rust-lang/crates.io-index)", + "ethereum-types 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)", "plain_hasher 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)", ] +[[package]] +name = "cita-vm" +version = "0.2.1" +source = "git+https://github.com/cryptape/cita-vm.git?branch=cita#535c36d3a945236982e12b0add124d4cd078c4a2" +dependencies = [ + "byteorder 1.3.1 (registry+https://github.com/rust-lang/crates.io-index)", + "cita_trie 2.0.0 (registry+https://github.com/rust-lang/crates.io-index)", + "env_logger 0.6.1 (registry+https://github.com/rust-lang/crates.io-index)", + "ethereum-types 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)", + "hashbrown 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)", + "hasher 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)", + "hex 0.3.2 (registry+https://github.com/rust-lang/crates.io-index)", + "libsecp256k1 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)", + "log 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)", + "rayon 1.2.0 (registry+https://github.com/rust-lang/crates.io-index)", + "ripemd160 0.8.0 (registry+https://github.com/rust-lang/crates.io-index)", + "rlp 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)", + "serde 1.0.89 (registry+https://github.com/rust-lang/crates.io-index)", + "serde_derive 1.0.89 (registry+https://github.com/rust-lang/crates.io-index)", + "serde_json 1.0.39 (registry+https://github.com/rust-lang/crates.io-index)", + "sha2 0.8.0 (registry+https://github.com/rust-lang/crates.io-index)", + "sha3 0.8.2 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "cita_trie" +version = "2.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "hashbrown 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)", + "hasher 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)", + "parking_lot 0.8.0 (registry+https://github.com/rust-lang/crates.io-index)", + "rlp 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)", +] + [[package]] name = "clang-sys" -version = "0.23.0" +version = "0.28.0" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "glob 0.2.11 (registry+https://github.com/rust-lang/crates.io-index)", @@ -797,32 +843,28 @@ dependencies = [ "bitflags 1.0.4 (registry+https://github.com/rust-lang/crates.io-index)", ] -[[package]] -name = "cmake" -version = "0.1.35" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "cc 1.0.26 (registry+https://github.com/rust-lang/crates.io-index)", -] - [[package]] name = "common-types" version = "0.1.0" dependencies = [ "bloomchain 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)", "cita-crypto 0.1.0 (git+https://github.com/cryptape/cita-common.git?branch=develop)", - "cita-logger 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)", + "cita-database 0.1.0 (git+https://github.com/cryptape/cita-database.git?branch=develop)", + "cita-ed25519 0.6.0 (git+https://github.com/cryptape/cita-common.git?branch=develop)", + "cita-logger 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)", "cita-types 0.1.0 (git+https://github.com/cryptape/cita-common.git?branch=develop)", - "db 0.1.0 (git+https://github.com/cryptape/cita-common.git?branch=develop)", + "cita-vm 0.2.1 (git+https://github.com/cryptape/cita-vm.git?branch=cita)", + "cita_trie 2.0.0 (registry+https://github.com/rust-lang/crates.io-index)", "hashable 0.1.0 (git+https://github.com/cryptape/cita-common.git?branch=develop)", "jsonrpc-types 0.1.0 (git+https://github.com/cryptape/cita-common.git?branch=develop)", "lazy_static 0.2.11 (registry+https://github.com/rust-lang/crates.io-index)", "libproto 0.6.0 (git+https://github.com/cryptape/cita-common.git?branch=develop)", "proof 0.6.0 (git+https://github.com/cryptape/cita-common.git?branch=develop)", "rlp 0.2.0 (git+https://github.com/cryptape/cita-common.git?branch=develop)", - "rlp_derive 0.1.0 (git+https://github.com/cryptape/cita-common.git?branch=develop)", + "rustc-hex 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)", "serde 1.0.89 (registry+https://github.com/rust-lang/crates.io-index)", "serde_derive 1.0.89 (registry+https://github.com/rust-lang/crates.io-index)", + "snappy 0.1.0 (git+https://github.com/cryptape/cita-common.git?branch=develop)", "time 0.1.40 (registry+https://github.com/rust-lang/crates.io-index)", "util 0.6.0 (git+https://github.com/cryptape/cita-common.git?branch=develop)", ] @@ -834,7 +876,7 @@ dependencies = [ "bincode 0.8.0 (registry+https://github.com/rust-lang/crates.io-index)", "chrono 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)", "cita-crypto 0.1.0 (git+https://github.com/cryptape/cita-common.git?branch=develop)", - "cita-logger 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)", + "cita-logger 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)", "cita-types 0.1.0 (git+https://github.com/cryptape/cita-common.git?branch=develop)", "clap 2.33.0 (registry+https://github.com/rust-lang/crates.io-index)", "hashable 0.1.0 (git+https://github.com/cryptape/cita-common.git?branch=develop)", @@ -850,48 +892,34 @@ name = "constant_time_eq" version = "0.1.3" source = "registry+https://github.com/rust-lang/crates.io-index" -[[package]] -name = "conv" -version = "0.3.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "custom_derive 0.1.7 (registry+https://github.com/rust-lang/crates.io-index)", -] - [[package]] name = "core" version = "0.1.0" dependencies = [ "bincode 0.8.0 (registry+https://github.com/rust-lang/crates.io-index)", - "bit-set 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)", - "byteorder 1.3.1 (registry+https://github.com/rust-lang/crates.io-index)", "cita-crypto 0.1.0 (git+https://github.com/cryptape/cita-common.git?branch=develop)", + "cita-database 0.1.0 (git+https://github.com/cryptape/cita-database.git?branch=develop)", "cita-ed25519 0.6.0 (git+https://github.com/cryptape/cita-common.git?branch=develop)", - "cita-logger 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)", + "cita-logger 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)", "cita-merklehash 0.1.0 (git+https://github.com/cryptape/cita-common.git?branch=develop)", "cita-secp256k1 0.6.0 (git+https://github.com/cryptape/cita-common.git?branch=develop)", "cita-types 0.1.0 (git+https://github.com/cryptape/cita-common.git?branch=develop)", "common-types 0.1.0", "cpuprofiler 0.0.3 (registry+https://github.com/rust-lang/crates.io-index)", "crossbeam 0.2.12 (registry+https://github.com/rust-lang/crates.io-index)", - "db 0.1.0 (git+https://github.com/cryptape/cita-common.git?branch=develop)", "hashable 0.1.0 (git+https://github.com/cryptape/cita-common.git?branch=develop)", "jsonrpc-types 0.1.0 (git+https://github.com/cryptape/cita-common.git?branch=develop)", "lazy_static 0.2.11 (registry+https://github.com/rust-lang/crates.io-index)", "libproto 0.6.0 (git+https://github.com/cryptape/cita-common.git?branch=develop)", - "lru-cache 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)", "proof 0.6.0 (git+https://github.com/cryptape/cita-common.git?branch=develop)", "pubsub 0.6.0 (git+https://github.com/cryptape/cita-common.git?branch=develop)", "rand 0.3.22 (registry+https://github.com/rust-lang/crates.io-index)", "rlp 0.2.0 (git+https://github.com/cryptape/cita-common.git?branch=develop)", - "rlp_derive 0.1.0 (git+https://github.com/cryptape/cita-common.git?branch=develop)", "rustc-hex 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)", "serde 1.0.89 (registry+https://github.com/rust-lang/crates.io-index)", "serde_derive 1.0.89 (registry+https://github.com/rust-lang/crates.io-index)", - "snappy 0.1.0 (git+https://github.com/cryptape/cita-common.git?branch=develop)", "tempdir 0.3.7 (registry+https://github.com/rust-lang/crates.io-index)", "time 0.1.40 (registry+https://github.com/rust-lang/crates.io-index)", - "transient-hashmap 0.4.1 (registry+https://github.com/rust-lang/crates.io-index)", "util 0.6.0 (git+https://github.com/cryptape/cita-common.git?branch=develop)", ] @@ -904,22 +932,21 @@ dependencies = [ "byteorder 1.3.1 (registry+https://github.com/rust-lang/crates.io-index)", "cita-crypto 0.1.0 (git+https://github.com/cryptape/cita-common.git?branch=develop)", "cita-crypto-trait 0.1.0 (git+https://github.com/cryptape/cita-common.git?branch=develop)", + "cita-database 0.1.0 (git+https://github.com/cryptape/cita-database.git?branch=develop)", "cita-ed25519 0.6.0 (git+https://github.com/cryptape/cita-common.git?branch=develop)", - "cita-logger 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)", + "cita-logger 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)", "cita-merklehash 0.1.0 (git+https://github.com/cryptape/cita-common.git?branch=develop)", "cita-secp256k1 0.6.0 (git+https://github.com/cryptape/cita-common.git?branch=develop)", "cita-types 0.1.0 (git+https://github.com/cryptape/cita-common.git?branch=develop)", + "cita-vm 0.2.1 (git+https://github.com/cryptape/cita-vm.git?branch=cita)", + "cita_trie 2.0.0 (registry+https://github.com/rust-lang/crates.io-index)", "common-types 0.1.0", "core 0.1.0", "cpuprofiler 0.0.3 (registry+https://github.com/rust-lang/crates.io-index)", - "crossbeam 0.2.12 (registry+https://github.com/rust-lang/crates.io-index)", - "crossbeam-channel 0.2.6 (registry+https://github.com/rust-lang/crates.io-index)", - "db 0.1.0 (git+https://github.com/cryptape/cita-common.git?branch=develop)", + "crossbeam-channel 0.3.9 (registry+https://github.com/rust-lang/crates.io-index)", "enum_primitive 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)", "ethabi 4.2.0 (registry+https://github.com/rust-lang/crates.io-index)", - "ethcore-bloom-journal 0.1.0 (git+https://github.com/cryptape/cita-common.git?branch=develop)", - "evm 0.1.0", - "grpc 0.5.0 (registry+https://github.com/rust-lang/crates.io-index)", + "ethbloom 0.6.4 (registry+https://github.com/rust-lang/crates.io-index)", "hashable 0.1.0 (git+https://github.com/cryptape/cita-common.git?branch=develop)", "hex 0.3.2 (registry+https://github.com/rust-lang/crates.io-index)", "jsonrpc-types 0.1.0 (git+https://github.com/cryptape/cita-common.git?branch=develop)", @@ -928,19 +955,21 @@ dependencies = [ "libproto 0.6.0 (git+https://github.com/cryptape/cita-common.git?branch=develop)", "lru-cache 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)", "num 0.1.42 (registry+https://github.com/rust-lang/crates.io-index)", + "parking_lot 0.8.0 (registry+https://github.com/rust-lang/crates.io-index)", "proof 0.6.0 (git+https://github.com/cryptape/cita-common.git?branch=develop)", "rand 0.3.22 (registry+https://github.com/rust-lang/crates.io-index)", "rlp 0.2.0 (git+https://github.com/cryptape/cita-common.git?branch=develop)", - "rlp_derive 0.1.0 (git+https://github.com/cryptape/cita-common.git?branch=develop)", "rust-crypto 0.2.36 (registry+https://github.com/rust-lang/crates.io-index)", "rustc-hex 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)", "rustc-serialize 0.3.24 (registry+https://github.com/rust-lang/crates.io-index)", "serde 1.0.89 (registry+https://github.com/rust-lang/crates.io-index)", "serde_derive 1.0.89 (registry+https://github.com/rust-lang/crates.io-index)", "serde_json 1.0.39 (registry+https://github.com/rust-lang/crates.io-index)", + "sha3 0.8.2 (registry+https://github.com/rust-lang/crates.io-index)", "snappy 0.1.0 (git+https://github.com/cryptape/cita-common.git?branch=develop)", "tempdir 0.3.7 (registry+https://github.com/rust-lang/crates.io-index)", "time 0.1.40 (registry+https://github.com/rust-lang/crates.io-index)", + "tiny-keccak 1.4.2 (registry+https://github.com/rust-lang/crates.io-index)", "transient-hashmap 0.4.1 (registry+https://github.com/rust-lang/crates.io-index)", "util 0.6.0 (git+https://github.com/cryptape/cita-common.git?branch=develop)", "zktx 0.0.1 (git+https://github.com/cryptape/zktx.git)", @@ -963,15 +992,24 @@ dependencies = [ "build_const 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)", ] +[[package]] +name = "crc32fast" +version = "1.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "cfg-if 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)", +] + [[package]] name = "create-genesis" version = "0.1.0" dependencies = [ + "cita-types 0.1.0 (git+https://github.com/cryptape/cita-common.git?branch=develop)", + "cita-vm 0.2.1 (git+https://github.com/cryptape/cita-vm.git?branch=cita)", + "cita_trie 2.0.0 (registry+https://github.com/rust-lang/crates.io-index)", "clap 2.33.0 (registry+https://github.com/rust-lang/crates.io-index)", - "core-executor 0.1.0", - "ethabi 7.0.0 (registry+https://github.com/rust-lang/crates.io-index)", - "ethereum-types 0.5.2 (registry+https://github.com/rust-lang/crates.io-index)", - "evm 0.1.0", + "ethabi 6.1.0 (registry+https://github.com/rust-lang/crates.io-index)", + "ethereum-types 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)", "hex 0.3.2 (registry+https://github.com/rust-lang/crates.io-index)", "json 0.11.14 (registry+https://github.com/rust-lang/crates.io-index)", "libproto 0.6.0 (git+https://github.com/cryptape/cita-common.git?branch=develop)", @@ -1002,89 +1040,40 @@ source = "registry+https://github.com/rust-lang/crates.io-index" [[package]] name = "crossbeam-channel" -version = "0.2.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "crossbeam-epoch 0.6.0 (registry+https://github.com/rust-lang/crates.io-index)", - "crossbeam-utils 0.5.0 (registry+https://github.com/rust-lang/crates.io-index)", - "parking_lot 0.6.4 (registry+https://github.com/rust-lang/crates.io-index)", - "rand 0.5.5 (registry+https://github.com/rust-lang/crates.io-index)", - "smallvec 0.6.5 (registry+https://github.com/rust-lang/crates.io-index)", -] - -[[package]] -name = "crossbeam-channel" -version = "0.3.8" +version = "0.3.9" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "crossbeam-utils 0.6.5 (registry+https://github.com/rust-lang/crates.io-index)", - "smallvec 0.6.5 (registry+https://github.com/rust-lang/crates.io-index)", -] - -[[package]] -name = "crossbeam-deque" -version = "0.2.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "crossbeam-epoch 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)", - "crossbeam-utils 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] name = "crossbeam-deque" -version = "0.6.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "crossbeam-epoch 0.5.2 (registry+https://github.com/rust-lang/crates.io-index)", - "crossbeam-utils 0.5.0 (registry+https://github.com/rust-lang/crates.io-index)", -] - -[[package]] -name = "crossbeam-epoch" -version = "0.3.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "arrayvec 0.4.7 (registry+https://github.com/rust-lang/crates.io-index)", - "cfg-if 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)", - "crossbeam-utils 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)", - "lazy_static 1.3.0 (registry+https://github.com/rust-lang/crates.io-index)", - "memoffset 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)", - "nodrop 0.1.12 (registry+https://github.com/rust-lang/crates.io-index)", - "scopeguard 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)", -] - -[[package]] -name = "crossbeam-epoch" -version = "0.5.2" +version = "0.7.1" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "arrayvec 0.4.7 (registry+https://github.com/rust-lang/crates.io-index)", - "cfg-if 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)", - "crossbeam-utils 0.5.0 (registry+https://github.com/rust-lang/crates.io-index)", - "lazy_static 1.3.0 (registry+https://github.com/rust-lang/crates.io-index)", - "memoffset 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)", - "scopeguard 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)", + "crossbeam-epoch 0.7.2 (registry+https://github.com/rust-lang/crates.io-index)", + "crossbeam-utils 0.6.5 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] name = "crossbeam-epoch" -version = "0.6.0" +version = "0.7.2" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "arrayvec 0.4.7 (registry+https://github.com/rust-lang/crates.io-index)", "cfg-if 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)", - "crossbeam-utils 0.5.0 (registry+https://github.com/rust-lang/crates.io-index)", + "crossbeam-utils 0.6.5 (registry+https://github.com/rust-lang/crates.io-index)", "lazy_static 1.3.0 (registry+https://github.com/rust-lang/crates.io-index)", - "memoffset 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)", - "scopeguard 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)", + "memoffset 0.5.1 (registry+https://github.com/rust-lang/crates.io-index)", + "scopeguard 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] -name = "crossbeam-utils" -version = "0.2.2" +name = "crossbeam-queue" +version = "0.1.2" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "cfg-if 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)", + "crossbeam-utils 0.6.5 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -1152,33 +1141,11 @@ dependencies = [ "winapi 0.3.7 (registry+https://github.com/rust-lang/crates.io-index)", ] -[[package]] -name = "custom_derive" -version = "0.1.7" -source = "registry+https://github.com/rust-lang/crates.io-index" - [[package]] name = "data-encoding" version = "2.1.2" source = "registry+https://github.com/rust-lang/crates.io-index" -[[package]] -name = "db" -version = "0.1.0" -source = "git+https://github.com/cryptape/cita-common.git?branch=develop#b948764c71c656943506317505868bbde95bc3f3" -dependencies = [ - "cita-logger 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)", - "cita-types 0.1.0 (git+https://github.com/cryptape/cita-common.git?branch=develop)", - "elastic-array 0.9.0 (registry+https://github.com/rust-lang/crates.io-index)", - "hashable 0.1.0 (git+https://github.com/cryptape/cita-common.git?branch=develop)", - "heapsize 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)", - "itertools 0.5.10 (registry+https://github.com/rust-lang/crates.io-index)", - "parity-rocksdb 0.5.0 (registry+https://github.com/rust-lang/crates.io-index)", - "regex 1.0.5 (registry+https://github.com/rust-lang/crates.io-index)", - "rlp 0.2.0 (git+https://github.com/cryptape/cita-common.git?branch=develop)", - "util 0.6.0 (git+https://github.com/cryptape/cita-common.git?branch=develop)", -] - [[package]] name = "dbghelp-sys" version = "0.2.0" @@ -1235,11 +1202,11 @@ dependencies = [ [[package]] name = "engine" version = "0.6.0" -source = "git+https://github.com/cryptape/cita-common.git?branch=develop#b948764c71c656943506317505868bbde95bc3f3" +source = "git+https://github.com/cryptape/cita-common.git?branch=develop#788444602d6181741281c06c2684d3d60374a350" dependencies = [ "cita-crypto 0.1.0 (git+https://github.com/cryptape/cita-common.git?branch=develop)", "cita-types 0.1.0 (git+https://github.com/cryptape/cita-common.git?branch=develop)", - "crossbeam-channel 0.3.8 (registry+https://github.com/rust-lang/crates.io-index)", + "crossbeam-channel 0.3.9 (registry+https://github.com/rust-lang/crates.io-index)", "libproto 0.6.0 (git+https://github.com/cryptape/cita-common.git?branch=develop)", "util 0.6.0 (git+https://github.com/cryptape/cita-common.git?branch=develop)", ] @@ -1298,7 +1265,7 @@ dependencies = [ [[package]] name = "error" version = "0.1.0" -source = "git+https://github.com/cryptape/cita-common.git?branch=develop#b948764c71c656943506317505868bbde95bc3f3" +source = "git+https://github.com/cryptape/cita-common.git?branch=develop#788444602d6181741281c06c2684d3d60374a350" [[package]] name = "error-chain" @@ -1344,11 +1311,11 @@ dependencies = [ [[package]] name = "ethabi" -version = "7.0.0" +version = "6.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "error-chain 0.12.1 (registry+https://github.com/rust-lang/crates.io-index)", - "ethereum-types 0.5.2 (registry+https://github.com/rust-lang/crates.io-index)", + "ethereum-types 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)", "rustc-hex 2.0.1 (registry+https://github.com/rust-lang/crates.io-index)", "serde 1.0.89 (registry+https://github.com/rust-lang/crates.io-index)", "serde_derive 1.0.89 (registry+https://github.com/rust-lang/crates.io-index)", @@ -1390,28 +1357,6 @@ dependencies = [ "tiny-keccak 1.4.2 (registry+https://github.com/rust-lang/crates.io-index)", ] -[[package]] -name = "ethcore-bloom-journal" -version = "0.1.0" -source = "git+https://github.com/cryptape/cita-common.git?branch=develop#b948764c71c656943506317505868bbde95bc3f3" -dependencies = [ - "siphasher 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)", -] - -[[package]] -name = "ethereum-types" -version = "0.3.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "crunchy 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)", - "ethbloom 0.5.0 (registry+https://github.com/rust-lang/crates.io-index)", - "ethereum-types-serialize 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)", - "fixed-hash 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)", - "rustc_version 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)", - "serde 1.0.89 (registry+https://github.com/rust-lang/crates.io-index)", - "uint 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)", -] - [[package]] name = "ethereum-types" version = "0.4.2" @@ -1425,19 +1370,6 @@ dependencies = [ "uint 0.4.1 (registry+https://github.com/rust-lang/crates.io-index)", ] -[[package]] -name = "ethereum-types" -version = "0.5.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "crunchy 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)", - "ethbloom 0.6.4 (registry+https://github.com/rust-lang/crates.io-index)", - "ethereum-types-serialize 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)", - "fixed-hash 0.3.2 (registry+https://github.com/rust-lang/crates.io-index)", - "serde 1.0.89 (registry+https://github.com/rust-lang/crates.io-index)", - "uint 0.5.0 (registry+https://github.com/rust-lang/crates.io-index)", -] - [[package]] name = "ethereum-types-serialize" version = "0.2.2" @@ -1446,22 +1378,6 @@ dependencies = [ "serde 1.0.89 (registry+https://github.com/rust-lang/crates.io-index)", ] -[[package]] -name = "evm" -version = "0.1.0" -dependencies = [ - "bit-set 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)", - "cita-logger 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)", - "cita-types 0.1.0 (git+https://github.com/cryptape/cita-common.git?branch=develop)", - "common-types 0.1.0", - "db 0.1.0 (git+https://github.com/cryptape/cita-common.git?branch=develop)", - "hashable 0.1.0 (git+https://github.com/cryptape/cita-common.git?branch=develop)", - "lazy_static 0.2.11 (registry+https://github.com/rust-lang/crates.io-index)", - "rlp 0.2.0 (git+https://github.com/cryptape/cita-common.git?branch=develop)", - "rustc-hex 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)", - "util 0.6.0 (git+https://github.com/cryptape/cita-common.git?branch=develop)", -] - [[package]] name = "failure" version = "0.1.5" @@ -1515,6 +1431,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "byteorder 1.3.1 (registry+https://github.com/rust-lang/crates.io-index)", "heapsize 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)", + "libc 0.2.46 (registry+https://github.com/rust-lang/crates.io-index)", "rand 0.5.5 (registry+https://github.com/rust-lang/crates.io-index)", "rustc-hex 2.0.1 (registry+https://github.com/rust-lang/crates.io-index)", "static_assertions 0.2.5 (registry+https://github.com/rust-lang/crates.io-index)", @@ -1525,7 +1442,7 @@ name = "flatbuffers" version = "0.6.0" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "smallvec 0.6.5 (registry+https://github.com/rust-lang/crates.io-index)", + "smallvec 0.6.10 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -1611,6 +1528,14 @@ dependencies = [ "num_cpus 1.8.0 (registry+https://github.com/rust-lang/crates.io-index)", ] +[[package]] +name = "fxhash" +version = "0.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "byteorder 1.3.1 (registry+https://github.com/rust-lang/crates.io-index)", +] + [[package]] name = "gcc" version = "0.3.55" @@ -1633,14 +1558,6 @@ dependencies = [ "typenum 1.10.0 (registry+https://github.com/rust-lang/crates.io-index)", ] -[[package]] -name = "getopts" -version = "0.2.18" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "unicode-width 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)", -] - [[package]] name = "git2" version = "0.7.5" @@ -1661,23 +1578,9 @@ version = "0.2.11" source = "registry+https://github.com/rust-lang/crates.io-index" [[package]] -name = "grpc" -version = "0.5.0" +name = "glob" +version = "0.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "base64 0.9.3 (registry+https://github.com/rust-lang/crates.io-index)", - "bytes 0.4.12 (registry+https://github.com/rust-lang/crates.io-index)", - "futures 0.1.25 (registry+https://github.com/rust-lang/crates.io-index)", - "futures-cpupool 0.1.8 (registry+https://github.com/rust-lang/crates.io-index)", - "httpbis 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)", - "log 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)", - "protobuf 2.6.2 (registry+https://github.com/rust-lang/crates.io-index)", - "tls-api 0.1.20 (registry+https://github.com/rust-lang/crates.io-index)", - "tls-api-stub 0.1.20 (registry+https://github.com/rust-lang/crates.io-index)", - "tokio-core 0.1.17 (registry+https://github.com/rust-lang/crates.io-index)", - "tokio-io 0.1.10 (registry+https://github.com/rust-lang/crates.io-index)", - "tokio-tls-api 0.1.20 (registry+https://github.com/rust-lang/crates.io-index)", -] [[package]] name = "h2" @@ -1699,11 +1602,27 @@ dependencies = [ [[package]] name = "hashable" version = "0.1.0" -source = "git+https://github.com/cryptape/cita-common.git?branch=develop#b948764c71c656943506317505868bbde95bc3f3" +source = "git+https://github.com/cryptape/cita-common.git?branch=develop#788444602d6181741281c06c2684d3d60374a350" dependencies = [ "blake2b 0.1.0 (git+https://github.com/cryptape/cita-common.git?branch=develop)", "cita-types 0.1.0 (git+https://github.com/cryptape/cita-common.git?branch=develop)", - "libsm 0.3.0 (git+https://github.com/cryptape/libsm?rev=ac323abd3512a9fdb8bfd6cd349a6fc46deb688f)", + "libsm 0.3.0 (git+https://github.com/cryptape/libsm?rev=4d0e6199fca0934c58131de1d0036e9aa4da26c1)", + "tiny-keccak 1.4.2 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "hashbrown" +version = "0.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "rayon 1.2.0 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "hasher" +version = "0.1.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ "tiny-keccak 1.4.2 (registry+https://github.com/rust-lang/crates.io-index)", ] @@ -1764,27 +1683,6 @@ name = "httparse" version = "1.3.3" source = "registry+https://github.com/rust-lang/crates.io-index" -[[package]] -name = "httpbis" -version = "0.7.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "bytes 0.4.12 (registry+https://github.com/rust-lang/crates.io-index)", - "futures 0.1.25 (registry+https://github.com/rust-lang/crates.io-index)", - "futures-cpupool 0.1.8 (registry+https://github.com/rust-lang/crates.io-index)", - "log 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)", - "net2 0.2.33 (registry+https://github.com/rust-lang/crates.io-index)", - "tls-api 0.1.20 (registry+https://github.com/rust-lang/crates.io-index)", - "tls-api-stub 0.1.20 (registry+https://github.com/rust-lang/crates.io-index)", - "tokio-core 0.1.17 (registry+https://github.com/rust-lang/crates.io-index)", - "tokio-io 0.1.10 (registry+https://github.com/rust-lang/crates.io-index)", - "tokio-timer 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)", - "tokio-tls-api 0.1.20 (registry+https://github.com/rust-lang/crates.io-index)", - "tokio-uds 0.1.7 (registry+https://github.com/rust-lang/crates.io-index)", - "unix_socket 0.5.0 (registry+https://github.com/rust-lang/crates.io-index)", - "void 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)", -] - [[package]] name = "humantime" version = "1.1.1" @@ -1838,7 +1736,7 @@ dependencies = [ "tokio-io 0.1.10 (registry+https://github.com/rust-lang/crates.io-index)", "tokio-reactor 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)", "tokio-tcp 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)", - "tokio-threadpool 0.1.8 (registry+https://github.com/rust-lang/crates.io-index)", + "tokio-threadpool 0.1.12 (registry+https://github.com/rust-lang/crates.io-index)", "tokio-timer 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)", "want 0.0.6 (registry+https://github.com/rust-lang/crates.io-index)", ] @@ -1936,10 +1834,10 @@ source = "registry+https://github.com/rust-lang/crates.io-index" [[package]] name = "jsonrpc-proto" version = "0.1.0" -source = "git+https://github.com/cryptape/cita-common.git?branch=develop#b948764c71c656943506317505868bbde95bc3f3" +source = "git+https://github.com/cryptape/cita-common.git?branch=develop#788444602d6181741281c06c2684d3d60374a350" dependencies = [ "bincode 0.8.0 (registry+https://github.com/rust-lang/crates.io-index)", - "cita-logger 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)", + "cita-logger 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)", "cita-types 0.1.0 (git+https://github.com/cryptape/cita-common.git?branch=develop)", "jsonrpc-types 0.1.0 (git+https://github.com/cryptape/cita-common.git?branch=develop)", "libproto 0.6.0 (git+https://github.com/cryptape/cita-common.git?branch=develop)", @@ -1953,7 +1851,7 @@ dependencies = [ [[package]] name = "jsonrpc-types" version = "0.1.0" -source = "git+https://github.com/cryptape/cita-common.git?branch=develop#b948764c71c656943506317505868bbde95bc3f3" +source = "git+https://github.com/cryptape/cita-common.git?branch=develop#788444602d6181741281c06c2684d3d60374a350" dependencies = [ "bincode 0.8.0 (registry+https://github.com/rust-lang/crates.io-index)", "cita-types 0.1.0 (git+https://github.com/cryptape/cita-common.git?branch=develop)", @@ -1967,7 +1865,7 @@ dependencies = [ [[package]] name = "jsonrpc-types-internals" version = "0.1.0" -source = "git+https://github.com/cryptape/cita-common.git?branch=develop#b948764c71c656943506317505868bbde95bc3f3" +source = "git+https://github.com/cryptape/cita-common.git?branch=develop#788444602d6181741281c06c2684d3d60374a350" dependencies = [ "proc-macro2 0.4.20 (registry+https://github.com/rust-lang/crates.io-index)", "quote 0.6.8 (registry+https://github.com/rust-lang/crates.io-index)", @@ -1984,6 +1882,11 @@ dependencies = [ "rand 0.3.22 (registry+https://github.com/rust-lang/crates.io-index)", ] +[[package]] +name = "keccak" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" + [[package]] name = "kernel32-sys" version = "0.2.2" @@ -2023,6 +1926,17 @@ name = "libc" version = "0.2.46" source = "registry+https://github.com/rust-lang/crates.io-index" +[[package]] +name = "libflate" +version = "0.1.26" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "adler32 1.0.3 (registry+https://github.com/rust-lang/crates.io-index)", + "crc32fast 1.2.0 (registry+https://github.com/rust-lang/crates.io-index)", + "rle-decode-fast 1.0.1 (registry+https://github.com/rust-lang/crates.io-index)", + "take_mut 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)", +] + [[package]] name = "libgit2-sys" version = "0.7.10" @@ -2049,13 +1963,12 @@ dependencies = [ [[package]] name = "libproto" version = "0.6.0" -source = "git+https://github.com/cryptape/cita-common.git?branch=develop#b948764c71c656943506317505868bbde95bc3f3" +source = "git+https://github.com/cryptape/cita-common.git?branch=develop#788444602d6181741281c06c2684d3d60374a350" dependencies = [ "cita-crypto 0.1.0 (git+https://github.com/cryptape/cita-common.git?branch=develop)", - "cita-logger 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)", + "cita-logger 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)", "cita-merklehash 0.1.0 (git+https://github.com/cryptape/cita-common.git?branch=develop)", "cita-types 0.1.0 (git+https://github.com/cryptape/cita-common.git?branch=develop)", - "grpc 0.5.0 (registry+https://github.com/rust-lang/crates.io-index)", "hashable 0.1.0 (git+https://github.com/cryptape/cita-common.git?branch=develop)", "protobuf 2.6.2 (registry+https://github.com/rust-lang/crates.io-index)", "rlp 0.2.0 (git+https://github.com/cryptape/cita-common.git?branch=develop)", @@ -2066,6 +1979,17 @@ dependencies = [ "tls-api 0.1.20 (registry+https://github.com/rust-lang/crates.io-index)", ] +[[package]] +name = "librocksdb-sys" +version = "6.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "bindgen 0.49.2 (registry+https://github.com/rust-lang/crates.io-index)", + "cc 1.0.26 (registry+https://github.com/rust-lang/crates.io-index)", + "glob 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)", + "libc 0.2.46 (registry+https://github.com/rust-lang/crates.io-index)", +] + [[package]] name = "libsecp256k1" version = "0.2.2" @@ -2082,7 +2006,7 @@ dependencies = [ [[package]] name = "libsm" version = "0.3.0" -source = "git+https://github.com/cryptape/libsm?rev=ac323abd3512a9fdb8bfd6cd349a6fc46deb688f#ac323abd3512a9fdb8bfd6cd349a6fc46deb688f" +source = "git+https://github.com/cryptape/libsm?rev=4d0e6199fca0934c58131de1d0036e9aa4da26c1#4d0e6199fca0934c58131de1d0036e9aa4da26c1" dependencies = [ "byteorder 1.3.1 (registry+https://github.com/rust-lang/crates.io-index)", "lazy_static 1.3.0 (registry+https://github.com/rust-lang/crates.io-index)", @@ -2095,12 +2019,15 @@ dependencies = [ [[package]] name = "libsodium-sys" -version = "0.1.0" +version = "0.2.2" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "bindgen 0.37.4 (registry+https://github.com/rust-lang/crates.io-index)", + "cc 1.0.26 (registry+https://github.com/rust-lang/crates.io-index)", "libc 0.2.46 (registry+https://github.com/rust-lang/crates.io-index)", + "libflate 0.1.26 (registry+https://github.com/rust-lang/crates.io-index)", "pkg-config 0.3.14 (registry+https://github.com/rust-lang/crates.io-index)", + "tar 0.4.25 (registry+https://github.com/rust-lang/crates.io-index)", + "vcpkg 0.2.6 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -2138,22 +2065,20 @@ version = "0.5.1" source = "registry+https://github.com/rust-lang/crates.io-index" [[package]] -name = "local-encoding" -version = "0.2.0" +name = "lock_api" +version = "0.1.4" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "kernel32-sys 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)", - "skeptic 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)", - "winapi 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)", + "owning_ref 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)", + "scopeguard 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] name = "lock_api" -version = "0.1.4" +version = "0.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "owning_ref 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)", - "scopeguard 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)", + "scopeguard 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -2237,14 +2162,6 @@ dependencies = [ "libc 0.2.46 (registry+https://github.com/rust-lang/crates.io-index)", ] -[[package]] -name = "memchr" -version = "1.0.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "libc 0.2.46 (registry+https://github.com/rust-lang/crates.io-index)", -] - [[package]] name = "memchr" version = "2.1.0" @@ -2257,8 +2174,11 @@ dependencies = [ [[package]] name = "memoffset" -version = "0.2.1" +version = "0.5.1" source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "rustc_version 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)", +] [[package]] name = "metadeps" @@ -2378,10 +2298,11 @@ source = "registry+https://github.com/rust-lang/crates.io-index" [[package]] name = "nom" -version = "3.2.1" +version = "4.2.3" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "memchr 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)", + "memchr 2.1.0 (registry+https://github.com/rust-lang/crates.io-index)", + "version_check 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -2394,25 +2315,12 @@ dependencies = [ "fsevent 0.2.17 (registry+https://github.com/rust-lang/crates.io-index)", "fsevent-sys 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)", "inotify 0.6.1 (registry+https://github.com/rust-lang/crates.io-index)", - "kernel32-sys 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)", - "libc 0.2.46 (registry+https://github.com/rust-lang/crates.io-index)", - "mio 0.6.16 (registry+https://github.com/rust-lang/crates.io-index)", - "mio-extras 2.0.5 (registry+https://github.com/rust-lang/crates.io-index)", - "walkdir 2.2.7 (registry+https://github.com/rust-lang/crates.io-index)", - "winapi 0.3.7 (registry+https://github.com/rust-lang/crates.io-index)", -] - -[[package]] -name = "ntp" -version = "0.4.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "byteorder 1.3.1 (registry+https://github.com/rust-lang/crates.io-index)", - "conv 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)", - "custom_derive 0.1.7 (registry+https://github.com/rust-lang/crates.io-index)", - "error-chain 0.11.0 (registry+https://github.com/rust-lang/crates.io-index)", - "log 0.3.9 (registry+https://github.com/rust-lang/crates.io-index)", - "time 0.1.40 (registry+https://github.com/rust-lang/crates.io-index)", + "kernel32-sys 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)", + "libc 0.2.46 (registry+https://github.com/rust-lang/crates.io-index)", + "mio 0.6.16 (registry+https://github.com/rust-lang/crates.io-index)", + "mio-extras 2.0.5 (registry+https://github.com/rust-lang/crates.io-index)", + "walkdir 2.2.7 (registry+https://github.com/rust-lang/crates.io-index)", + "winapi 0.3.7 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -2435,7 +2343,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "num-integer 0.1.39 (registry+https://github.com/rust-lang/crates.io-index)", "num-traits 0.2.6 (registry+https://github.com/rust-lang/crates.io-index)", - "rand 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)", + "rand 0.3.22 (registry+https://github.com/rust-lang/crates.io-index)", "rustc-serialize 0.3.24 (registry+https://github.com/rust-lang/crates.io-index)", ] @@ -2555,10 +2463,10 @@ dependencies = [ [[package]] name = "panic_hook" version = "0.0.1" -source = "git+https://github.com/cryptape/cita-common.git?branch=develop#b948764c71c656943506317505868bbde95bc3f3" +source = "git+https://github.com/cryptape/cita-common.git?branch=develop#788444602d6181741281c06c2684d3d60374a350" dependencies = [ "backtrace 0.3.9 (registry+https://github.com/rust-lang/crates.io-index)", - "cita-logger 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)", + "cita-logger 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -2590,53 +2498,48 @@ dependencies = [ ] [[package]] -name = "parity-rocksdb" -version = "0.5.0" +name = "parking_lot" +version = "0.6.4" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "libc 0.2.46 (registry+https://github.com/rust-lang/crates.io-index)", - "local-encoding 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)", - "parity-rocksdb-sys 0.5.3 (registry+https://github.com/rust-lang/crates.io-index)", + "lock_api 0.1.4 (registry+https://github.com/rust-lang/crates.io-index)", + "parking_lot_core 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] -name = "parity-rocksdb-sys" -version = "0.5.3" +name = "parking_lot" +version = "0.8.0" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "cmake 0.1.35 (registry+https://github.com/rust-lang/crates.io-index)", - "libc 0.2.46 (registry+https://github.com/rust-lang/crates.io-index)", - "local-encoding 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)", - "parity-snappy-sys 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)", + "lock_api 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)", + "parking_lot_core 0.5.0 (registry+https://github.com/rust-lang/crates.io-index)", + "rustc_version 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] -name = "parity-snappy-sys" -version = "0.1.1" +name = "parking_lot_core" +version = "0.3.1" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "cmake 0.1.35 (registry+https://github.com/rust-lang/crates.io-index)", "libc 0.2.46 (registry+https://github.com/rust-lang/crates.io-index)", -] - -[[package]] -name = "parking_lot" -version = "0.6.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "lock_api 0.1.4 (registry+https://github.com/rust-lang/crates.io-index)", - "parking_lot_core 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)", + "rand 0.5.5 (registry+https://github.com/rust-lang/crates.io-index)", + "rustc_version 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)", + "smallvec 0.6.10 (registry+https://github.com/rust-lang/crates.io-index)", + "winapi 0.3.7 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] name = "parking_lot_core" -version = "0.3.1" +version = "0.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ + "cfg-if 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)", + "cloudabi 0.0.3 (registry+https://github.com/rust-lang/crates.io-index)", "libc 0.2.46 (registry+https://github.com/rust-lang/crates.io-index)", - "rand 0.5.5 (registry+https://github.com/rust-lang/crates.io-index)", + "rand 0.6.5 (registry+https://github.com/rust-lang/crates.io-index)", + "redox_syscall 0.1.40 (registry+https://github.com/rust-lang/crates.io-index)", "rustc_version 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)", - "smallvec 0.6.5 (registry+https://github.com/rust-lang/crates.io-index)", + "smallvec 0.6.10 (registry+https://github.com/rust-lang/crates.io-index)", "winapi 0.3.7 (registry+https://github.com/rust-lang/crates.io-index)", ] @@ -2663,14 +2566,6 @@ dependencies = [ "crunchy 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)", ] -[[package]] -name = "proc-macro2" -version = "0.3.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "unicode-xid 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)", -] - [[package]] name = "proc-macro2" version = "0.4.20" @@ -2682,7 +2577,7 @@ dependencies = [ [[package]] name = "proof" version = "0.6.0" -source = "git+https://github.com/cryptape/cita-common.git?branch=develop#b948764c71c656943506317505868bbde95bc3f3" +source = "git+https://github.com/cryptape/cita-common.git?branch=develop#788444602d6181741281c06c2684d3d60374a350" dependencies = [ "bincode 0.8.0 (registry+https://github.com/rust-lang/crates.io-index)", "cita-crypto 0.1.0 (git+https://github.com/cryptape/cita-common.git?branch=develop)", @@ -2705,7 +2600,7 @@ dependencies = [ [[package]] name = "pubsub" version = "0.6.0" -source = "git+https://github.com/cryptape/cita-common.git?branch=develop#b948764c71c656943506317505868bbde95bc3f3" +source = "git+https://github.com/cryptape/cita-common.git?branch=develop#788444602d6181741281c06c2684d3d60374a350" dependencies = [ "dotenv 0.13.0 (registry+https://github.com/rust-lang/crates.io-index)", "pubsub_kafka 0.1.0 (git+https://github.com/cryptape/cita-common.git?branch=develop)", @@ -2716,10 +2611,10 @@ dependencies = [ [[package]] name = "pubsub_kafka" version = "0.1.0" -source = "git+https://github.com/cryptape/cita-common.git?branch=develop#b948764c71c656943506317505868bbde95bc3f3" +source = "git+https://github.com/cryptape/cita-common.git?branch=develop#788444602d6181741281c06c2684d3d60374a350" dependencies = [ - "cita-logger 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)", - "crossbeam-channel 0.3.8 (registry+https://github.com/rust-lang/crates.io-index)", + "cita-logger 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)", + "crossbeam-channel 0.3.9 (registry+https://github.com/rust-lang/crates.io-index)", "futures 0.1.25 (registry+https://github.com/rust-lang/crates.io-index)", "futures-cpupool 0.1.8 (registry+https://github.com/rust-lang/crates.io-index)", "rdkafka 0.12.0 (git+https://github.com/fede1024/rust-rdkafka.git?rev=84d4062)", @@ -2728,30 +2623,22 @@ dependencies = [ [[package]] name = "pubsub_rabbitmq" version = "0.1.0" -source = "git+https://github.com/cryptape/cita-common.git?branch=develop#b948764c71c656943506317505868bbde95bc3f3" +source = "git+https://github.com/cryptape/cita-common.git?branch=develop#788444602d6181741281c06c2684d3d60374a350" dependencies = [ "amqp 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)", - "crossbeam-channel 0.3.8 (registry+https://github.com/rust-lang/crates.io-index)", + "crossbeam-channel 0.3.9 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] name = "pubsub_zeromq" version = "0.1.0" -source = "git+https://github.com/cryptape/cita-common.git?branch=develop#b948764c71c656943506317505868bbde95bc3f3" +source = "git+https://github.com/cryptape/cita-common.git?branch=develop#788444602d6181741281c06c2684d3d60374a350" dependencies = [ - "cita-logger 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)", - "crossbeam-channel 0.3.8 (registry+https://github.com/rust-lang/crates.io-index)", + "cita-logger 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)", + "crossbeam-channel 0.3.9 (registry+https://github.com/rust-lang/crates.io-index)", "zmq 0.8.2 (registry+https://github.com/rust-lang/crates.io-index)", ] -[[package]] -name = "pulldown-cmark" -version = "0.0.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "getopts 0.2.18 (registry+https://github.com/rust-lang/crates.io-index)", -] - [[package]] name = "quick-error" version = "1.2.2" @@ -2768,19 +2655,6 @@ dependencies = [ "rand_core 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)", ] -[[package]] -name = "quote" -version = "0.3.15" -source = "registry+https://github.com/rust-lang/crates.io-index" - -[[package]] -name = "quote" -version = "0.5.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "proc-macro2 0.3.5 (registry+https://github.com/rust-lang/crates.io-index)", -] - [[package]] name = "quote" version = "0.6.8" @@ -2847,7 +2721,7 @@ version = "0.1.1" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "autocfg 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)", - "rand_core 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)", + "rand_core 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -2876,7 +2750,7 @@ name = "rand_hc" version = "0.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "rand_core 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)", + "rand_core 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -2924,27 +2798,28 @@ name = "rand_xorshift" version = "0.1.1" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "rand_core 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)", + "rand_core 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] name = "rayon" -version = "1.0.2" +version = "1.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "crossbeam-deque 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)", + "crossbeam-deque 0.7.1 (registry+https://github.com/rust-lang/crates.io-index)", "either 1.5.0 (registry+https://github.com/rust-lang/crates.io-index)", - "rayon-core 1.4.1 (registry+https://github.com/rust-lang/crates.io-index)", + "rayon-core 1.6.0 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] name = "rayon-core" -version = "1.4.1" +version = "1.6.0" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "crossbeam-deque 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)", + "crossbeam-deque 0.7.1 (registry+https://github.com/rust-lang/crates.io-index)", + "crossbeam-queue 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)", + "crossbeam-utils 0.6.5 (registry+https://github.com/rust-lang/crates.io-index)", "lazy_static 1.3.0 (registry+https://github.com/rust-lang/crates.io-index)", - "libc 0.2.46 (registry+https://github.com/rust-lang/crates.io-index)", "num_cpus 1.8.0 (registry+https://github.com/rust-lang/crates.io-index)", ] @@ -3056,14 +2931,29 @@ dependencies = [ "cc 1.0.26 (registry+https://github.com/rust-lang/crates.io-index)", "lazy_static 1.3.0 (registry+https://github.com/rust-lang/crates.io-index)", "libc 0.2.46 (registry+https://github.com/rust-lang/crates.io-index)", - "spin 0.5.0 (registry+https://github.com/rust-lang/crates.io-index)", + "spin 0.5.2 (registry+https://github.com/rust-lang/crates.io-index)", "untrusted 0.6.2 (registry+https://github.com/rust-lang/crates.io-index)", ] +[[package]] +name = "ripemd160" +version = "0.8.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "block-buffer 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)", + "digest 0.8.0 (registry+https://github.com/rust-lang/crates.io-index)", + "opaque-debug 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "rle-decode-fast" +version = "1.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" + [[package]] name = "rlp" version = "0.2.0" -source = "git+https://github.com/cryptape/cita-common.git?branch=develop#b948764c71c656943506317505868bbde95bc3f3" +source = "git+https://github.com/cryptape/cita-common.git?branch=develop#788444602d6181741281c06c2684d3d60374a350" dependencies = [ "byteorder 1.3.1 (registry+https://github.com/rust-lang/crates.io-index)", "cita-types 0.1.0 (git+https://github.com/cryptape/cita-common.git?branch=develop)", @@ -3072,6 +2962,16 @@ dependencies = [ "rustc-hex 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)", ] +[[package]] +name = "rlp" +version = "0.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "byteorder 1.3.1 (registry+https://github.com/rust-lang/crates.io-index)", + "ethereum-types 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)", + "rustc-hex 2.0.1 (registry+https://github.com/rust-lang/crates.io-index)", +] + [[package]] name = "rlp" version = "0.4.0" @@ -3082,12 +2982,12 @@ dependencies = [ ] [[package]] -name = "rlp_derive" -version = "0.1.0" -source = "git+https://github.com/cryptape/cita-common.git?branch=develop#b948764c71c656943506317505868bbde95bc3f3" +name = "rocksdb" +version = "0.12.3" +source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "quote 0.3.15 (registry+https://github.com/rust-lang/crates.io-index)", - "syn 0.11.11 (registry+https://github.com/rust-lang/crates.io-index)", + "libc 0.2.46 (registry+https://github.com/rust-lang/crates.io-index)", + "librocksdb-sys 6.1.2 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -3158,6 +3058,11 @@ name = "scopeguard" version = "0.3.3" source = "registry+https://github.com/rust-lang/crates.io-index" +[[package]] +name = "scopeguard" +version = "1.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" + [[package]] name = "secp256k1" version = "0.12.2" @@ -3257,33 +3162,31 @@ dependencies = [ ] [[package]] -name = "signal-hook" -version = "0.1.5" +name = "sha3" +version = "0.8.2" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "arc-swap 0.3.4 (registry+https://github.com/rust-lang/crates.io-index)", - "libc 0.2.46 (registry+https://github.com/rust-lang/crates.io-index)", + "block-buffer 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)", + "byte-tools 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)", + "digest 0.8.0 (registry+https://github.com/rust-lang/crates.io-index)", + "keccak 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)", + "opaque-debug 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] -name = "siphasher" -version = "0.1.3" +name = "shlex" +version = "0.1.1" source = "registry+https://github.com/rust-lang/crates.io-index" [[package]] -name = "skeptic" -version = "0.4.0" +name = "signal-hook" +version = "0.1.5" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "pulldown-cmark 0.0.3 (registry+https://github.com/rust-lang/crates.io-index)", - "tempdir 0.3.7 (registry+https://github.com/rust-lang/crates.io-index)", + "arc-swap 0.3.4 (registry+https://github.com/rust-lang/crates.io-index)", + "libc 0.2.46 (registry+https://github.com/rust-lang/crates.io-index)", ] -[[package]] -name = "slab" -version = "0.3.0" -source = "registry+https://github.com/rust-lang/crates.io-index" - [[package]] name = "slab" version = "0.4.1" @@ -3291,16 +3194,13 @@ source = "registry+https://github.com/rust-lang/crates.io-index" [[package]] name = "smallvec" -version = "0.6.5" +version = "0.6.10" source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "unreachable 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)", -] [[package]] name = "snappy" version = "0.1.0" -source = "git+https://github.com/cryptape/cita-common.git?branch=develop#b948764c71c656943506317505868bbde95bc3f3" +source = "git+https://github.com/cryptape/cita-common.git?branch=develop#788444602d6181741281c06c2684d3d60374a350" dependencies = [ "libc 0.2.46 (registry+https://github.com/rust-lang/crates.io-index)", ] @@ -3309,7 +3209,7 @@ dependencies = [ name = "snapshot-tool" version = "0.2.0" dependencies = [ - "cita-logger 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)", + "cita-logger 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)", "clap 2.33.0 (registry+https://github.com/rust-lang/crates.io-index)", "dotenv 0.13.0 (registry+https://github.com/rust-lang/crates.io-index)", "error 0.1.0 (git+https://github.com/cryptape/cita-common.git?branch=develop)", @@ -3321,17 +3221,17 @@ dependencies = [ [[package]] name = "sodiumoxide" -version = "0.1.0" +version = "0.2.2" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "libc 0.2.46 (registry+https://github.com/rust-lang/crates.io-index)", - "libsodium-sys 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)", + "libsodium-sys 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)", "serde 1.0.89 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] name = "spin" -version = "0.5.0" +version = "0.5.2" source = "registry+https://github.com/rust-lang/crates.io-index" [[package]] @@ -3343,10 +3243,13 @@ source = "registry+https://github.com/rust-lang/crates.io-index" name = "state-test" version = "0.1.0" dependencies = [ + "cita-crypto 0.1.0 (git+https://github.com/cryptape/cita-common.git?branch=develop)", + "cita-types 0.1.0 (git+https://github.com/cryptape/cita-common.git?branch=develop)", + "cita-vm 0.2.1 (git+https://github.com/cryptape/cita-vm.git?branch=cita)", + "cita_trie 2.0.0 (registry+https://github.com/rust-lang/crates.io-index)", "core-executor 0.1.0", "env_logger 0.6.1 (registry+https://github.com/rust-lang/crates.io-index)", "ethereum-types 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)", - "evm 0.1.0", "hex 0.3.2 (registry+https://github.com/rust-lang/crates.io-index)", "libproto 0.6.0 (git+https://github.com/cryptape/cita-common.git?branch=develop)", "libsecp256k1 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)", @@ -3390,16 +3293,6 @@ name = "subtle" version = "1.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" -[[package]] -name = "syn" -version = "0.11.11" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "quote 0.3.15 (registry+https://github.com/rust-lang/crates.io-index)", - "synom 0.11.3 (registry+https://github.com/rust-lang/crates.io-index)", - "unicode-xid 0.0.4 (registry+https://github.com/rust-lang/crates.io-index)", -] - [[package]] name = "syn" version = "0.14.9" @@ -3420,14 +3313,6 @@ dependencies = [ "unicode-xid 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)", ] -[[package]] -name = "synom" -version = "0.11.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "unicode-xid 0.0.4 (registry+https://github.com/rust-lang/crates.io-index)", -] - [[package]] name = "synstructure" version = "0.10.0" @@ -3439,6 +3324,22 @@ dependencies = [ "unicode-xid 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)", ] +[[package]] +name = "take_mut" +version = "0.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" + +[[package]] +name = "tar" +version = "0.4.25" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "filetime 0.2.5 (registry+https://github.com/rust-lang/crates.io-index)", + "libc 0.2.46 (registry+https://github.com/rust-lang/crates.io-index)", + "redox_syscall 0.1.40 (registry+https://github.com/rust-lang/crates.io-index)", + "xattr 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)", +] + [[package]] name = "tempdir" version = "0.3.7" @@ -3475,7 +3376,7 @@ dependencies = [ [[package]] name = "tentacle" -version = "0.2.1" +version = "0.2.3" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "bytes 0.4.12 (registry+https://github.com/rust-lang/crates.io-index)", @@ -3488,14 +3389,14 @@ dependencies = [ "parity-multiaddr 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)", "tentacle-secio 0.1.7 (registry+https://github.com/rust-lang/crates.io-index)", "tokio 0.1.16 (registry+https://github.com/rust-lang/crates.io-index)", - "tokio-threadpool 0.1.8 (registry+https://github.com/rust-lang/crates.io-index)", + "tokio-threadpool 0.1.12 (registry+https://github.com/rust-lang/crates.io-index)", "tokio-yamux 0.1.12 (registry+https://github.com/rust-lang/crates.io-index)", "winapi 0.3.7 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] name = "tentacle-discovery" -version = "0.2.4" +version = "0.2.5" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "byteorder 1.3.1 (registry+https://github.com/rust-lang/crates.io-index)", @@ -3506,7 +3407,7 @@ dependencies = [ "futures 0.1.25 (registry+https://github.com/rust-lang/crates.io-index)", "log 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)", "rand 0.6.5 (registry+https://github.com/rust-lang/crates.io-index)", - "tentacle 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)", + "tentacle 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)", "tokio 0.1.16 (registry+https://github.com/rust-lang/crates.io-index)", ] @@ -3629,15 +3530,6 @@ dependencies = [ "log 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)", ] -[[package]] -name = "tls-api-stub" -version = "0.1.20" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "tls-api 0.1.20 (registry+https://github.com/rust-lang/crates.io-index)", - "void 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)", -] - [[package]] name = "tokio" version = "0.1.16" @@ -3655,7 +3547,7 @@ dependencies = [ "tokio-reactor 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)", "tokio-sync 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)", "tokio-tcp 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)", - "tokio-threadpool 0.1.8 (registry+https://github.com/rust-lang/crates.io-index)", + "tokio-threadpool 0.1.12 (registry+https://github.com/rust-lang/crates.io-index)", "tokio-timer 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)", "tokio-udp 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)", "tokio-uds 0.2.5 (registry+https://github.com/rust-lang/crates.io-index)", @@ -3713,7 +3605,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "futures 0.1.25 (registry+https://github.com/rust-lang/crates.io-index)", "tokio-io 0.1.10 (registry+https://github.com/rust-lang/crates.io-index)", - "tokio-threadpool 0.1.8 (registry+https://github.com/rust-lang/crates.io-index)", + "tokio-threadpool 0.1.12 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -3734,7 +3626,7 @@ dependencies = [ "futures 0.1.25 (registry+https://github.com/rust-lang/crates.io-index)", "log 0.3.9 (registry+https://github.com/rust-lang/crates.io-index)", "net2 0.2.33 (registry+https://github.com/rust-lang/crates.io-index)", - "smallvec 0.6.5 (registry+https://github.com/rust-lang/crates.io-index)", + "smallvec 0.6.10 (registry+https://github.com/rust-lang/crates.io-index)", "tokio-core 0.1.17 (registry+https://github.com/rust-lang/crates.io-index)", "tokio-io 0.1.10 (registry+https://github.com/rust-lang/crates.io-index)", "tokio-service 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)", @@ -3789,27 +3681,20 @@ dependencies = [ [[package]] name = "tokio-threadpool" -version = "0.1.8" +version = "0.1.12" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "crossbeam-deque 0.6.1 (registry+https://github.com/rust-lang/crates.io-index)", - "crossbeam-utils 0.5.0 (registry+https://github.com/rust-lang/crates.io-index)", + "crossbeam-deque 0.7.1 (registry+https://github.com/rust-lang/crates.io-index)", + "crossbeam-queue 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)", + "crossbeam-utils 0.6.5 (registry+https://github.com/rust-lang/crates.io-index)", "futures 0.1.25 (registry+https://github.com/rust-lang/crates.io-index)", "log 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)", "num_cpus 1.8.0 (registry+https://github.com/rust-lang/crates.io-index)", - "rand 0.5.5 (registry+https://github.com/rust-lang/crates.io-index)", + "rand 0.6.5 (registry+https://github.com/rust-lang/crates.io-index)", + "slab 0.4.1 (registry+https://github.com/rust-lang/crates.io-index)", "tokio-executor 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)", ] -[[package]] -name = "tokio-timer" -version = "0.1.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "futures 0.1.25 (registry+https://github.com/rust-lang/crates.io-index)", - "slab 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)", -] - [[package]] name = "tokio-timer" version = "0.2.8" @@ -3821,17 +3706,6 @@ dependencies = [ "tokio-executor 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)", ] -[[package]] -name = "tokio-tls-api" -version = "0.1.20" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "futures 0.1.25 (registry+https://github.com/rust-lang/crates.io-index)", - "tls-api 0.1.20 (registry+https://github.com/rust-lang/crates.io-index)", - "tokio-core 0.1.17 (registry+https://github.com/rust-lang/crates.io-index)", - "tokio-io 0.1.10 (registry+https://github.com/rust-lang/crates.io-index)", -] - [[package]] name = "tokio-udp" version = "0.1.2" @@ -3846,22 +3720,6 @@ dependencies = [ "tokio-reactor 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)", ] -[[package]] -name = "tokio-uds" -version = "0.1.7" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "bytes 0.4.12 (registry+https://github.com/rust-lang/crates.io-index)", - "futures 0.1.25 (registry+https://github.com/rust-lang/crates.io-index)", - "iovec 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)", - "libc 0.2.46 (registry+https://github.com/rust-lang/crates.io-index)", - "log 0.3.9 (registry+https://github.com/rust-lang/crates.io-index)", - "mio 0.6.16 (registry+https://github.com/rust-lang/crates.io-index)", - "mio-uds 0.6.7 (registry+https://github.com/rust-lang/crates.io-index)", - "tokio-core 0.1.17 (registry+https://github.com/rust-lang/crates.io-index)", - "tokio-io 0.1.10 (registry+https://github.com/rust-lang/crates.io-index)", -] - [[package]] name = "tokio-uds" version = "0.2.5" @@ -3933,7 +3791,7 @@ dependencies = [ [[package]] name = "tx_pool" version = "0.6.0" -source = "git+https://github.com/cryptape/cita-common.git?branch=develop#b948764c71c656943506317505868bbde95bc3f3" +source = "git+https://github.com/cryptape/cita-common.git?branch=develop#788444602d6181741281c06c2684d3d60374a350" dependencies = [ "cita-crypto 0.1.0 (git+https://github.com/cryptape/cita-common.git?branch=develop)", "cita-types 0.1.0 (git+https://github.com/cryptape/cita-common.git?branch=develop)", @@ -3959,17 +3817,6 @@ name = "ucd-util" version = "0.1.1" source = "registry+https://github.com/rust-lang/crates.io-index" -[[package]] -name = "uint" -version = "0.2.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "byteorder 1.3.1 (registry+https://github.com/rust-lang/crates.io-index)", - "heapsize 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)", - "rustc-hex 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)", - "rustc_version 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)", -] - [[package]] name = "uint" version = "0.4.1" @@ -3981,17 +3828,6 @@ dependencies = [ "rustc-hex 2.0.1 (registry+https://github.com/rust-lang/crates.io-index)", ] -[[package]] -name = "uint" -version = "0.5.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "byteorder 1.3.1 (registry+https://github.com/rust-lang/crates.io-index)", - "crunchy 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)", - "heapsize 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)", - "rustc-hex 2.0.1 (registry+https://github.com/rust-lang/crates.io-index)", -] - [[package]] name = "unicase" version = "2.2.0" @@ -4018,25 +3854,11 @@ name = "unicode-width" version = "0.1.5" source = "registry+https://github.com/rust-lang/crates.io-index" -[[package]] -name = "unicode-xid" -version = "0.0.4" -source = "registry+https://github.com/rust-lang/crates.io-index" - [[package]] name = "unicode-xid" version = "0.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" -[[package]] -name = "unix_socket" -version = "0.5.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "cfg-if 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)", - "libc 0.2.46 (registry+https://github.com/rust-lang/crates.io-index)", -] - [[package]] name = "unreachable" version = "1.0.0" @@ -4086,7 +3908,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" [[package]] name = "util" version = "0.6.0" -source = "git+https://github.com/cryptape/cita-common.git?branch=develop#b948764c71c656943506317505868bbde95bc3f3" +source = "git+https://github.com/cryptape/cita-common.git?branch=develop#788444602d6181741281c06c2684d3d60374a350" dependencies = [ "ansi_term 0.9.0 (registry+https://github.com/rust-lang/crates.io-index)", "cita-types 0.1.0 (git+https://github.com/cryptape/cita-common.git?branch=develop)", @@ -4233,6 +4055,14 @@ dependencies = [ "winapi-build 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)", ] +[[package]] +name = "xattr" +version = "0.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "libc 0.2.46 (registry+https://github.com/rust-lang/crates.io-index)", +] + [[package]] name = "xml-rs" version = "0.7.0" @@ -4323,7 +4153,7 @@ dependencies = [ "checksum base64 0.9.3 (registry+https://github.com/rust-lang/crates.io-index)" = "489d6c0ed21b11d038c31b6ceccca973e65d73ba3bd8ecb9a2babf5546164643" "checksum bellman 0.0.4 (git+https://github.com/cryptape/bellman.git?branch=0.0.4_modified)" = "" "checksum bincode 0.8.0 (registry+https://github.com/rust-lang/crates.io-index)" = "e103c8b299b28a9c6990458b7013dc4a8356a9b854c51b9883241f5866fac36e" -"checksum bindgen 0.37.4 (registry+https://github.com/rust-lang/crates.io-index)" = "1b25ab82877ea8fe6ce1ce1f8ac54361f0218bad900af9eb11803994bf67c221" +"checksum bindgen 0.49.2 (registry+https://github.com/rust-lang/crates.io-index)" = "846a1fba6535362a01487ef6b10f0275faa12e5c5d835c5c1c627aabc46ccbd6" "checksum bit-set 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "d9bf6104718e80d7b26a68fdbacff3481cfc05df670821affc7e9cbc1884400c" "checksum bit-vec 0.4.4 (registry+https://github.com/rust-lang/crates.io-index)" = "02b4ff8b16e6076c3e14220b39fbc1fabb6737522281a388998046859400895f" "checksum bitflags 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)" = "aad18937a628ec6abcd26d1489012cc0e18c21798210f491af69ded9b881106d" @@ -4343,36 +4173,34 @@ dependencies = [ "checksum byteorder 1.3.1 (registry+https://github.com/rust-lang/crates.io-index)" = "a019b10a2a7cdeb292db131fc8113e57ea2a908f6e7894b0c3c671893b65dbeb" "checksum bytes 0.4.12 (registry+https://github.com/rust-lang/crates.io-index)" = "206fdffcfa2df7cbe15601ef46c813fce0965eb3286db6b56c583b814b51c81c" "checksum cc 1.0.26 (registry+https://github.com/rust-lang/crates.io-index)" = "389803e36973d242e7fecb092b2de44a3d35ac62524b3b9339e51d577d668e02" -"checksum cexpr 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)" = "42aac45e9567d97474a834efdee3081b3c942b2205be932092f53354ce503d6c" +"checksum cexpr 0.3.5 (registry+https://github.com/rust-lang/crates.io-index)" = "a7fa24eb00d5ffab90eaeaf1092ac85c04c64aaf358ea6f84505b8116d24c6af" "checksum cfg-if 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)" = "082bb9b28e00d3c9d39cc03e64ce4cea0f1bb9b3fde493f0cbc008472d22bdf4" "checksum chrono 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)" = "45912881121cb26fad7c38c17ba7daa18764771836b34fab7d3fbd93ed633878" "checksum cita-crypto 0.1.0 (git+https://github.com/cryptape/cita-common.git?branch=develop)" = "" "checksum cita-crypto-trait 0.1.0 (git+https://github.com/cryptape/cita-common.git?branch=develop)" = "" +"checksum cita-database 0.1.0 (git+https://github.com/cryptape/cita-database.git?branch=develop)" = "" "checksum cita-directories 0.1.0 (git+https://github.com/cryptape/cita-common.git?branch=develop)" = "" "checksum cita-ed25519 0.6.0 (git+https://github.com/cryptape/cita-common.git?branch=develop)" = "" -"checksum cita-logger 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "5c0fccf6b33be6ab71808f2b5bb36206acef2eee9f5d0d29f87b81327242b521" +"checksum cita-logger 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "3f28d41799c3ceeaa16c6aef432fbffb96722a270fe877696c09656cfead4e2b" "checksum cita-merklehash 0.1.0 (git+https://github.com/cryptape/cita-common.git?branch=develop)" = "" "checksum cita-secp256k1 0.6.0 (git+https://github.com/cryptape/cita-common.git?branch=develop)" = "" "checksum cita-sm2 0.1.0 (git+https://github.com/cryptape/cita-common.git?branch=develop)" = "" "checksum cita-types 0.1.0 (git+https://github.com/cryptape/cita-common.git?branch=develop)" = "" -"checksum clang-sys 0.23.0 (registry+https://github.com/rust-lang/crates.io-index)" = "d7f7c04e52c35222fffcc3a115b5daf5f7e2bfb71c13c4e2321afe1fc71859c2" +"checksum cita-vm 0.2.1 (git+https://github.com/cryptape/cita-vm.git?branch=cita)" = "" +"checksum cita_trie 2.0.0 (registry+https://github.com/rust-lang/crates.io-index)" = "b90456b297d4aa962afb8712ed5a581abdde0f7835653e5f2142c5ed06d1eeed" +"checksum clang-sys 0.28.0 (registry+https://github.com/rust-lang/crates.io-index)" = "4227269cec09f5f83ff160be12a1e9b0262dd1aa305302d5ba296c2ebd291055" "checksum clap 2.33.0 (registry+https://github.com/rust-lang/crates.io-index)" = "5067f5bb2d80ef5d68b4c87db81601f0b75bca627bc2ef76b141d7b846a3c6d9" "checksum cloudabi 0.0.3 (registry+https://github.com/rust-lang/crates.io-index)" = "ddfc5b9aa5d4507acaf872de71051dfd0e309860e88966e1051e462a077aac4f" -"checksum cmake 0.1.35 (registry+https://github.com/rust-lang/crates.io-index)" = "6ec65ee4f9c9d16f335091d23693457ed4928657ba4982289d7fafee03bc614a" "checksum constant_time_eq 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)" = "8ff012e225ce166d4422e0e78419d901719760f62ae2b7969ca6b564d1b54a9e" -"checksum conv 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)" = "78ff10625fd0ac447827aa30ea8b861fead473bb60aeb73af6c1c58caf0d1299" "checksum cpuprofiler 0.0.3 (registry+https://github.com/rust-lang/crates.io-index)" = "33f07976bb6821459632d7a18d97ccca005cb5c552f251f822c7c1781c1d7035" "checksum crc 1.8.1 (registry+https://github.com/rust-lang/crates.io-index)" = "d663548de7f5cca343f1e0a48d14dcfb0e9eb4e079ec58883b7251539fa10aeb" +"checksum crc32fast 1.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "ba125de2af0df55319f41944744ad91c71113bf74a4646efff39afe1f6842db1" "checksum crossbeam 0.2.12 (registry+https://github.com/rust-lang/crates.io-index)" = "bd66663db5a988098a89599d4857919b3acf7f61402e61365acfd3919857b9be" "checksum crossbeam 0.3.2 (registry+https://github.com/rust-lang/crates.io-index)" = "24ce9782d4d5c53674646a6a4c1863a21a8fc0cb649b3c94dfc16e45071dea19" -"checksum crossbeam-channel 0.2.6 (registry+https://github.com/rust-lang/crates.io-index)" = "7b85741761b7f160bc5e7e0c14986ef685b7f8bf9b7ad081c60c604bb4649827" -"checksum crossbeam-channel 0.3.8 (registry+https://github.com/rust-lang/crates.io-index)" = "0f0ed1a4de2235cabda8558ff5840bffb97fcb64c97827f354a451307df5f72b" -"checksum crossbeam-deque 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "f739f8c5363aca78cfb059edf753d8f0d36908c348f3d8d1503f03d8b75d9cf3" -"checksum crossbeam-deque 0.6.1 (registry+https://github.com/rust-lang/crates.io-index)" = "3486aefc4c0487b9cb52372c97df0a48b8c249514af1ee99703bf70d2f2ceda1" -"checksum crossbeam-epoch 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)" = "927121f5407de9956180ff5e936fe3cf4324279280001cd56b669d28ee7e9150" -"checksum crossbeam-epoch 0.5.2 (registry+https://github.com/rust-lang/crates.io-index)" = "30fecfcac6abfef8771151f8be4abc9e4edc112c2bcb233314cafde2680536e9" -"checksum crossbeam-epoch 0.6.0 (registry+https://github.com/rust-lang/crates.io-index)" = "9c90f1474584f38e270b5b613e898c8c328aa4f3dea85e0a27ac2e642f009416" -"checksum crossbeam-utils 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)" = "2760899e32a1d58d5abb31129f8fae5de75220bc2176e77ff7c627ae45c918d9" +"checksum crossbeam-channel 0.3.9 (registry+https://github.com/rust-lang/crates.io-index)" = "c8ec7fcd21571dc78f96cc96243cab8d8f035247c3efd16c687be154c3fa9efa" +"checksum crossbeam-deque 0.7.1 (registry+https://github.com/rust-lang/crates.io-index)" = "b18cd2e169ad86297e6bc0ad9aa679aee9daa4f19e8163860faf7c164e4f5a71" +"checksum crossbeam-epoch 0.7.2 (registry+https://github.com/rust-lang/crates.io-index)" = "fedcd6772e37f3da2a9af9bf12ebe046c0dfe657992377b4df982a2b54cd37a9" +"checksum crossbeam-queue 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)" = "7c979cd6cfe72335896575c6b5688da489e420d36a27a0b9eb0c73db574b4a4b" "checksum crossbeam-utils 0.5.0 (registry+https://github.com/rust-lang/crates.io-index)" = "677d453a17e8bd2b913fa38e8b9cf04bcdbb5be790aa294f2389661d72036015" "checksum crossbeam-utils 0.6.5 (registry+https://github.com/rust-lang/crates.io-index)" = "f8306fcef4a7b563b76b7dd949ca48f52bc1141aa067d2ea09565f3e2652aa5c" "checksum crunchy 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)" = "a2f4a431c5c9f662e1200b7c7f02c34e91361150e382089a8f2dec3ba680cbda" @@ -4381,9 +4209,7 @@ dependencies = [ "checksum crypto-mac 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)" = "4434400df11d95d556bac068ddfedd482915eb18fe8bea89bc80b6e4b1c179e5" "checksum ctr 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)" = "044f882973b245404e90c90e7e42e8ee8d7a64edfd7adf83d684fb97e8e2c1b6" "checksum curl-sys 0.4.13 (registry+https://github.com/rust-lang/crates.io-index)" = "08459503c415173da1ce6b41036a37b8bfdd86af46d45abb9964d4c61fe670ef" -"checksum custom_derive 0.1.7 (registry+https://github.com/rust-lang/crates.io-index)" = "ef8ae57c4978a2acd8b869ce6b9ca1dfe817bff704c220209fdef2c0b75a01b9" "checksum data-encoding 2.1.2 (registry+https://github.com/rust-lang/crates.io-index)" = "f4f47ca1860a761136924ddd2422ba77b2ea54fe8cc75b9040804a0d9d32ad97" -"checksum db 0.1.0 (git+https://github.com/cryptape/cita-common.git?branch=develop)" = "" "checksum dbghelp-sys 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "97590ba53bcb8ac28279161ca943a924d1fd4a8fb3fa63302591647c4fc5b850" "checksum digest 0.6.2 (registry+https://github.com/rust-lang/crates.io-index)" = "e5b29bf156f3f4b3c4f610a25ff69370616ae6e0657d416de22645483e72af0a" "checksum digest 0.8.0 (registry+https://github.com/rust-lang/crates.io-index)" = "05f47366984d3ad862010e22c7ce81a7dbcaebbdfb37241a620f8b6596ee135c" @@ -4403,14 +4229,11 @@ dependencies = [ "checksum error-chain 0.12.1 (registry+https://github.com/rust-lang/crates.io-index)" = "3ab49e9dcb602294bc42f9a7dfc9bc6e936fca4418ea300dbfb84fe16de0b7d9" "checksum error-chain 0.5.0 (registry+https://github.com/rust-lang/crates.io-index)" = "bd5c82c815138e278b8dcdeffc49f27ea6ffb528403e9dea4194f2e3dd40b143" "checksum ethabi 4.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "0c49de42ee3e3e4734bd847d015e7c55b7855ab978800795c4f032772573d077" -"checksum ethabi 7.0.0 (registry+https://github.com/rust-lang/crates.io-index)" = "be9a03ff8f3d495d9b73d59fd166acc91d0fd81779911b0b8b4c87b6024a670a" +"checksum ethabi 6.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "8eb362fde43ed0b50b258bb0c72b72b3dccfd29f8de9506295eaf9251c49ca31" "checksum ethbloom 0.2.5 (registry+https://github.com/rust-lang/crates.io-index)" = "3d1d93b56bf23b8d38c71e4a5360607fc8e91d402ec20a7e90f4e896cfd21d2b" "checksum ethbloom 0.5.0 (registry+https://github.com/rust-lang/crates.io-index)" = "1a93a43ce2e9f09071449da36bfa7a1b20b950ee344b6904ff23de493b03b386" "checksum ethbloom 0.6.4 (registry+https://github.com/rust-lang/crates.io-index)" = "3932e82d64d347a045208924002930dc105a138995ccdc1479d0f05f0359f17c" -"checksum ethcore-bloom-journal 0.1.0 (git+https://github.com/cryptape/cita-common.git?branch=develop)" = "" -"checksum ethereum-types 0.3.2 (registry+https://github.com/rust-lang/crates.io-index)" = "9c48729b8aea8aedb12cf4cb2e5cef439fdfe2dda4a89e47eeebd15778ef53b6" "checksum ethereum-types 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)" = "6e742184dc63a01c8ea0637369f8faa27c40f537949908a237f95c05e68d2c96" -"checksum ethereum-types 0.5.2 (registry+https://github.com/rust-lang/crates.io-index)" = "b054df51e53f253837ea422681215b42823c02824bde982699d0dceecf6165a1" "checksum ethereum-types-serialize 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)" = "1873d77b32bc1891a79dad925f2acbc318ee942b38b9110f9dbc5fbeffcea350" "checksum failure 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)" = "795bd83d3abeb9220f257e597aa0080a508b27533824adf336529648f6abf7e2" "checksum failure_derive 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)" = "ea1063915fd7ef4309e222a5a07cf9c319fb9c7836b1f89b85458672dbb127e1" @@ -4430,15 +4253,17 @@ dependencies = [ "checksum fuchsia-zircon-sys 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)" = "3dcaa9ae7725d12cdb85b3ad99a434db70b468c09ded17e012d86b5c1010f7a7" "checksum futures 0.1.25 (registry+https://github.com/rust-lang/crates.io-index)" = "49e7653e374fe0d0c12de4250f0bdb60680b8c80eed558c5c7538eec9c89e21b" "checksum futures-cpupool 0.1.8 (registry+https://github.com/rust-lang/crates.io-index)" = "ab90cde24b3319636588d0c35fe03b1333857621051837ed769faefb4c2162e4" +"checksum fxhash 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)" = "c31b6d751ae2c7f11320402d34e41349dd1016f8d5d45e48c4312bc8625af50c" "checksum gcc 0.3.55 (registry+https://github.com/rust-lang/crates.io-index)" = "8f5f3913fa0bfe7ee1fd8248b6b9f42a5af4b9d65ec2dd2c3c26132b950ecfc2" "checksum generic-array 0.12.0 (registry+https://github.com/rust-lang/crates.io-index)" = "3c0f28c2f5bfb5960175af447a2da7c18900693738343dc896ffbcabd9839592" "checksum generic-array 0.8.3 (registry+https://github.com/rust-lang/crates.io-index)" = "fceb69994e330afed50c93524be68c42fa898c2d9fd4ee8da03bd7363acd26f2" -"checksum getopts 0.2.18 (registry+https://github.com/rust-lang/crates.io-index)" = "0a7292d30132fb5424b354f5dc02512a86e4c516fe544bb7a25e7f266951b797" "checksum git2 0.7.5 (registry+https://github.com/rust-lang/crates.io-index)" = "591f8be1674b421644b6c030969520bc3fa12114d2eb467471982ed3e9584e71" "checksum glob 0.2.11 (registry+https://github.com/rust-lang/crates.io-index)" = "8be18de09a56b60ed0edf84bc9df007e30040691af7acd1c41874faac5895bfb" -"checksum grpc 0.5.0 (registry+https://github.com/rust-lang/crates.io-index)" = "553ad8ca834fe01bc8a8261b41e73d7abdb20b420d793ee41718f4e5eb77efc1" +"checksum glob 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)" = "9b919933a397b79c37e33b77bb2aa3dc8eb6e165ad809e58ff75bc7db2e34574" "checksum h2 0.1.14 (registry+https://github.com/rust-lang/crates.io-index)" = "1ac030ae20dee464c5d0f36544d8b914a6bc606da44a57e052d2b0f5dae129e0" "checksum hashable 0.1.0 (git+https://github.com/cryptape/cita-common.git?branch=develop)" = "" +"checksum hashbrown 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)" = "29fba9abe4742d586dfd0c06ae4f7e73a1c2d86b856933509b269d82cdf06e18" +"checksum hasher 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)" = "10e8846de73a692b8012bcb5b52e76c33087da83da9b36edded3b1af60efd71a" "checksum heapsize 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)" = "1679e6ea370dee694f91f1dc469bf94cf8f52051d147aec3e1f9497c6fc22461" "checksum hex 0.3.2 (registry+https://github.com/rust-lang/crates.io-index)" = "805026a5d0141ffc30abb3be3173848ad46a1b1664fe632428479619a3644d77" "checksum hmac 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)" = "7a13f4163aa0c5ca1be584aace0e2212b2e41be5478218d4f657f5f778b2ae2a" @@ -4446,7 +4271,6 @@ dependencies = [ "checksum hmac-drbg 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)" = "4fe727d41d2eec0a6574d887914347e5ff96a3b87177817e2a9820c5c87fecc2" "checksum http 0.1.17 (registry+https://github.com/rust-lang/crates.io-index)" = "eed324f0f0daf6ec10c474f150505af2c143f251722bf9dbd1261bd1f2ee2c1a" "checksum httparse 1.3.3 (registry+https://github.com/rust-lang/crates.io-index)" = "e8734b0cfd3bc3e101ec59100e101c2eecd19282202e87808b3037b442777a83" -"checksum httpbis 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)" = "7689cfa896b2a71da4f16206af167542b75d242b6906313e53857972a92d5614" "checksum humantime 1.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "0484fda3e7007f2a4a0d9c3a703ca38c71c54c55602ce4660c419fd32e188c9e" "checksum hyper 0.11.22 (git+https://github.com/cryptape/hyper.git?branch=reuse_port)" = "" "checksum hyper 0.12.16 (registry+https://github.com/rust-lang/crates.io-index)" = "0aeedb8ca5f0f96be00f84073c6d0d5f962ecad020ef543dff99a7c12717a60e" @@ -4465,6 +4289,7 @@ dependencies = [ "checksum jsonrpc-types 0.1.0 (git+https://github.com/cryptape/cita-common.git?branch=develop)" = "" "checksum jsonrpc-types-internals 0.1.0 (git+https://github.com/cryptape/cita-common.git?branch=develop)" = "" "checksum jubjub 0.0.1 (git+https://github.com/cryptape/jubjub-prototype.git?branch=modified)" = "" +"checksum keccak 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "67c21572b4949434e4fc1e1978b99c5f77064153c59d998bf13ecd96fb5ecba7" "checksum kernel32-sys 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)" = "7507624b29483431c0ba2d82aece8ca6cdba9382bff4ddd0f7490560c056098d" "checksum language-tags 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)" = "a91d884b6667cd606bb5a69aa0c99ba811a115fc68915e7056ec08a46e93199a" "checksum largest-remainder-method 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "d8c981a891c1d14a3fd9dfc2cd0455949e9958279fd433463386ae2337cf2c57" @@ -4472,18 +4297,20 @@ dependencies = [ "checksum lazy_static 1.3.0 (registry+https://github.com/rust-lang/crates.io-index)" = "bc5729f27f159ddd61f4df6228e827e86643d4d3e7c32183cb30a1c08f604a14" "checksum lazycell 1.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "ddba4c30a78328befecec92fc94970e53b3ae385827d28620f0f5bb2493081e0" "checksum libc 0.2.46 (registry+https://github.com/rust-lang/crates.io-index)" = "023a4cd09b2ff695f9734c1934145a315594b7986398496841c7031a5a1bbdbd" +"checksum libflate 0.1.26 (registry+https://github.com/rust-lang/crates.io-index)" = "45c97cf62125b79dcac52d506acdc4799f21a198597806947fd5f40dc7b93412" "checksum libgit2-sys 0.7.10 (registry+https://github.com/rust-lang/crates.io-index)" = "4916b5addc78ec36cc309acfcdf0b9f9d97ab7b84083118b248709c5b7029356" "checksum libloading 0.5.0 (registry+https://github.com/rust-lang/crates.io-index)" = "9c3ad660d7cb8c5822cd83d10897b0f1f1526792737a179e73896152f85b88c2" "checksum libproto 0.6.0 (git+https://github.com/cryptape/cita-common.git?branch=develop)" = "" +"checksum librocksdb-sys 6.1.2 (registry+https://github.com/rust-lang/crates.io-index)" = "a6af56e6599bce586321e8ba8acf8a0a5e97431fd9ab49f9b69f92d93fe642c6" "checksum libsecp256k1 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)" = "688e8d65e495567c2c35ea0001b26b9debf0b4ea11f8cccc954233b75fc3428a" -"checksum libsm 0.3.0 (git+https://github.com/cryptape/libsm?rev=ac323abd3512a9fdb8bfd6cd349a6fc46deb688f)" = "" -"checksum libsodium-sys 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "01839d6a151535905648d69dbbbf9c3f8f104b7890469508d504f4cd48d64643" +"checksum libsm 0.3.0 (git+https://github.com/cryptape/libsm?rev=4d0e6199fca0934c58131de1d0036e9aa4da26c1)" = "" +"checksum libsodium-sys 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)" = "de29595a79ddae2612ad0f27793a0b86cdf05a12f94ad5b87674540cc568171e" "checksum libssh2-sys 0.2.11 (registry+https://github.com/rust-lang/crates.io-index)" = "126a1f4078368b163bfdee65fbab072af08a1b374a5551b21e87ade27b1fbf9d" "checksum libz-sys 1.0.25 (registry+https://github.com/rust-lang/crates.io-index)" = "2eb5e43362e38e2bca2fd5f5134c4d4564a23a5c28e9b95411652021a8675ebe" "checksum linked-hash-map 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)" = "7860ec297f7008ff7a1e3382d7f7e1dcd69efc94751a2284bafc3d013c2aa939" "checksum linked-hash-map 0.5.1 (registry+https://github.com/rust-lang/crates.io-index)" = "70fb39025bc7cdd76305867c4eccf2f2dcf6e9a57f5b21a93e1c2d86cd03ec9e" -"checksum local-encoding 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "e1ceb20f39ff7ae42f3ff9795f3986b1daad821caaa1e1732a0944103a5a1a66" "checksum lock_api 0.1.4 (registry+https://github.com/rust-lang/crates.io-index)" = "775751a3e69bde4df9b38dd00a1b5d6ac13791e4223d4a0506577f0dd27cfb7a" +"checksum lock_api 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "ed946d4529956a20f2d63ebe1b69996d5a2137c91913fe3ebbeff957f5bca7ff" "checksum log 0.3.9 (registry+https://github.com/rust-lang/crates.io-index)" = "e19e8d5c34a3e0e2223db8e060f9e8264aeeb5c5fc64a4ee9965c062211c024b" "checksum log 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)" = "c84ec4b527950aa83a329754b01dbe3f58361d1c5efacd1f6d68c494d08a17c6" "checksum log-mdc 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "a94d21414c1f4a51209ad204c1776a3d0765002c76c6abcb602a6f09f1e881c7" @@ -4493,9 +4320,8 @@ dependencies = [ "checksum lz4-sys 1.8.2 (registry+https://github.com/rust-lang/crates.io-index)" = "a41fe7bc4964530eb26cf243b6ca0348a5d67949957840fe6489d5322a3ce937" "checksum matches 0.1.8 (registry+https://github.com/rust-lang/crates.io-index)" = "7ffc5c5338469d4d3ea17d269fa8ea3512ad247247c30bd2df69e68309ed0a08" "checksum memchr 0.1.11 (registry+https://github.com/rust-lang/crates.io-index)" = "d8b629fb514376c675b98c1421e80b151d3817ac42d7c667717d282761418d20" -"checksum memchr 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)" = "148fab2e51b4f1cfc66da2a7c32981d1d3c083a803978268bb11fe4b86925e7a" "checksum memchr 2.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "4b3629fe9fdbff6daa6c33b90f7c08355c1aca05a3d01fa8063b822fcf185f3b" -"checksum memoffset 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)" = "0f9dc261e2b62d7a622bf416ea3c5245cdd5d9a7fcc428c0d06804dfce1775b3" +"checksum memoffset 0.5.1 (registry+https://github.com/rust-lang/crates.io-index)" = "ce6075db033bbbb7ee5a0bbd3a3186bbae616f57fb001c485c7ff77955f8177f" "checksum metadeps 1.1.2 (registry+https://github.com/rust-lang/crates.io-index)" = "73b122901b3a675fac8cecf68dcb2f0d3036193bc861d1ac0e1c337f7d5254c2" "checksum mime 0.3.12 (registry+https://github.com/rust-lang/crates.io-index)" = "0a907b83e7b9e987032439a387e187119cddafc92d5c2aaeb1d92580a793f630" "checksum min-max-heap 1.2.2 (registry+https://github.com/rust-lang/crates.io-index)" = "f4c4c98e56ed3027c65dd9a7d10bd0b7d8fbdf2f5769c2dd4ac91a79b896ed65" @@ -4508,9 +4334,8 @@ dependencies = [ "checksum miow 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)" = "8c1f2f3b1cf331de6896aabf6e9d55dca90356cc9960cca7eaaf408a355ae919" "checksum net2 0.2.33 (registry+https://github.com/rust-lang/crates.io-index)" = "42550d9fb7b6684a6d404d9fa7250c2eb2646df731d1c06afc06dcee9e1bcf88" "checksum nodrop 0.1.12 (registry+https://github.com/rust-lang/crates.io-index)" = "9a2228dca57108069a5262f2ed8bd2e82496d2e074a06d1ccc7ce1687b6ae0a2" -"checksum nom 3.2.1 (registry+https://github.com/rust-lang/crates.io-index)" = "05aec50c70fd288702bcd93284a8444607f3292dbdf2a30de5ea5dcdbe72287b" +"checksum nom 4.2.3 (registry+https://github.com/rust-lang/crates.io-index)" = "2ad2a91a8e869eeb30b9cb3119ae87773a8f4ae617f41b1eb9c154b2905f7bd6" "checksum notify 4.0.10 (registry+https://github.com/rust-lang/crates.io-index)" = "abb1581693e44d8a0ec347ef12289625063f52a1dddc3f3c9befd5fc59e88943" -"checksum ntp 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "5a6db8a93b2f1ae56aa64c5bfa0a4a5a07d59ec92da3ec090d5a6b8e1cfe3965" "checksum num 0.1.42 (registry+https://github.com/rust-lang/crates.io-index)" = "4703ad64153382334aa8db57c637364c322d3372e097840c72000dabdcf6156e" "checksum num-bigint 0.1.44 (registry+https://github.com/rust-lang/crates.io-index)" = "e63899ad0da84ce718c14936262a41cee2c79c981fc0a0e7c7beb47d5a07e8c1" "checksum num-complex 0.1.43 (registry+https://github.com/rust-lang/crates.io-index)" = "b288631d7878aaf59442cffd36910ea604ecd7745c36054328595114001c9656" @@ -4530,16 +4355,14 @@ dependencies = [ "checksum panic_hook 0.0.1 (git+https://github.com/cryptape/cita-common.git?branch=develop)" = "" "checksum parity-multiaddr 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "18a130a727008cfcd1068a28439fe939897ccad28664422aeca65b384d6de6d0" "checksum parity-multihash 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "3e8eab0287ccde7821e337a124dc5a4f1d6e4c25d10cc91e3f9361615dd95076" -"checksum parity-rocksdb 0.5.0 (registry+https://github.com/rust-lang/crates.io-index)" = "cd55d2d6d6000ec99f021cf52c9acc7d2a402e14f95ced4c5de230696fabe00b" -"checksum parity-rocksdb-sys 0.5.3 (registry+https://github.com/rust-lang/crates.io-index)" = "0e59eda423021494a6cf1be74f6989add403f53157409993f794e17b123cab51" -"checksum parity-snappy-sys 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "c2086caac40c79289cb70d7e1c64f5888e1c53f5d38399d3e95101493739f423" "checksum parking_lot 0.6.4 (registry+https://github.com/rust-lang/crates.io-index)" = "f0802bff09003b291ba756dc7e79313e51cc31667e94afbe847def490424cde5" +"checksum parking_lot 0.8.0 (registry+https://github.com/rust-lang/crates.io-index)" = "fa7767817701cce701d5585b9c4db3cdd02086398322c1d7e8bf5094a96a2ce7" "checksum parking_lot_core 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)" = "ad7f7e6ebdc79edff6fdcb87a55b620174f7a989e3eb31b65231f4af57f00b8c" +"checksum parking_lot_core 0.5.0 (registry+https://github.com/rust-lang/crates.io-index)" = "cb88cb1cb3790baa6776844f968fea3be44956cf184fa1be5a03341f5491278c" "checksum peeking_take_while 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)" = "19b17cddbe7ec3f8bc800887bab5e717348c95ea2ca0b1bf0837fb964dc67099" "checksum percent-encoding 1.0.1 (registry+https://github.com/rust-lang/crates.io-index)" = "31010dd2e1ac33d5b46a5b413495239882813e0369f8ed8a5e266f173602f831" "checksum pkg-config 0.3.14 (registry+https://github.com/rust-lang/crates.io-index)" = "676e8eb2b1b4c9043511a9b7bea0915320d7e502b0a079fb03f9635a5252b18c" "checksum plain_hasher 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "83ae80873992f511142c07d0ec6c44de5636628fdb7e204abd655932ea79d995" -"checksum proc-macro2 0.3.5 (registry+https://github.com/rust-lang/crates.io-index)" = "77997c53ae6edd6d187fec07ec41b207063b5ee6f33680e9fa86d405cdd313d4" "checksum proc-macro2 0.4.20 (registry+https://github.com/rust-lang/crates.io-index)" = "3d7b7eaaa90b4a90a932a9ea6666c95a389e424eff347f0f793979289429feee" "checksum proof 0.6.0 (git+https://github.com/cryptape/cita-common.git?branch=develop)" = "" "checksum protobuf 2.6.2 (registry+https://github.com/rust-lang/crates.io-index)" = "7e9076cae823584ab4d8fab3a111658d1232faf106611dc8378161b7d062b628" @@ -4547,11 +4370,8 @@ dependencies = [ "checksum pubsub_kafka 0.1.0 (git+https://github.com/cryptape/cita-common.git?branch=develop)" = "" "checksum pubsub_rabbitmq 0.1.0 (git+https://github.com/cryptape/cita-common.git?branch=develop)" = "" "checksum pubsub_zeromq 0.1.0 (git+https://github.com/cryptape/cita-common.git?branch=develop)" = "" -"checksum pulldown-cmark 0.0.3 (registry+https://github.com/rust-lang/crates.io-index)" = "8361e81576d2e02643b04950e487ec172b687180da65c731c03cf336784e6c07" "checksum quick-error 1.2.2 (registry+https://github.com/rust-lang/crates.io-index)" = "9274b940887ce9addde99c4eee6b5c44cc494b182b97e73dc8ffdcb3397fd3f0" "checksum quickcheck 0.7.2 (registry+https://github.com/rust-lang/crates.io-index)" = "d4537d3e4edf73a15dd059b75bed1c292d17d3ea7517f583cebe716794fcf816" -"checksum quote 0.3.15 (registry+https://github.com/rust-lang/crates.io-index)" = "7a6e920b65c65f10b2ae65c831a81a073a89edd28c7cce89475bff467ab4167a" -"checksum quote 0.5.2 (registry+https://github.com/rust-lang/crates.io-index)" = "9949cfe66888ffe1d53e6ec9d9f3b70714083854be20fd5e271b232a017401e8" "checksum quote 0.6.8 (registry+https://github.com/rust-lang/crates.io-index)" = "dd636425967c33af890042c483632d33fa7a18f19ad1d7ea72e8998c6ef8dea5" "checksum rand 0.3.22 (registry+https://github.com/rust-lang/crates.io-index)" = "15a732abf9d20f0ad8eeb6f909bf6868722d9a06e1e50802b6a70351f40b4eb1" "checksum rand 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)" = "552840b97013b1a26992c11eac34bdd778e464601a4c2054b5f0bff7c6761293" @@ -4567,8 +4387,8 @@ dependencies = [ "checksum rand_os 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)" = "b7c690732391ae0abafced5015ffb53656abfaec61b342290e5eb56b286a679d" "checksum rand_pcg 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)" = "abf9b09b01790cfe0364f52bf32995ea3c39f4d2dd011eac241d2914146d0b44" "checksum rand_xorshift 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "cbf7e9e623549b0e21f6e97cf8ecf247c1a8fd2e8a992ae265314300b2455d5c" -"checksum rayon 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)" = "df7a791f788cb4c516f0e091301a29c2b71ef680db5e644a7d68835c8ae6dbfa" -"checksum rayon-core 1.4.1 (registry+https://github.com/rust-lang/crates.io-index)" = "b055d1e92aba6877574d8fe604a63c8b5df60f60e5982bf7ccbb1338ea527356" +"checksum rayon 1.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "83a27732a533a1be0a0035a111fe76db89ad312f6f0347004c220c57f209a123" +"checksum rayon-core 1.6.0 (registry+https://github.com/rust-lang/crates.io-index)" = "98dcf634205083b17d0861252431eb2acbfb698ab7478a2d20de07954f47ec7b" "checksum rdkafka 0.12.0 (git+https://github.com/fede1024/rust-rdkafka.git?rev=84d4062)" = "" "checksum rdkafka-sys 0.11.0-1 (git+https://github.com/fede1024/rust-rdkafka.git?rev=84d4062)" = "" "checksum rdrand 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "678054eb77286b51581ba43620cc911abf02758c91f93f479767aed0f90458b2" @@ -4581,9 +4401,12 @@ dependencies = [ "checksum relay 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "1576e382688d7e9deecea24417e350d3062d97e32e45d70b1cde65994ff1489a" "checksum remove_dir_all 0.5.1 (registry+https://github.com/rust-lang/crates.io-index)" = "3488ba1b9a2084d38645c4c08276a1752dcbf2c7130d74f1569681ad5d2799c5" "checksum ring 0.14.5 (registry+https://github.com/rust-lang/crates.io-index)" = "148fc853f6d85f53f5f315d46701eaacc565cdfb3cb1959730c96e81e7e49999" +"checksum ripemd160 0.8.0 (registry+https://github.com/rust-lang/crates.io-index)" = "ad5112e0dbbb87577bfbc56c42450235e3012ce336e29c5befd7807bd626da4a" +"checksum rle-decode-fast 1.0.1 (registry+https://github.com/rust-lang/crates.io-index)" = "cabe4fa914dec5870285fa7f71f602645da47c486e68486d2b4ceb4a343e90ac" "checksum rlp 0.2.0 (git+https://github.com/cryptape/cita-common.git?branch=develop)" = "" +"checksum rlp 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)" = "16d1effe9845d54f90e7be8420ee49e5c94623140b97ee4bc6fb5bfddb745720" "checksum rlp 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "3b0d56c1450bfbef1181fdeb78b902dc1d23178de77c23d705317508e03d1b7c" -"checksum rlp_derive 0.1.0 (git+https://github.com/cryptape/cita-common.git?branch=develop)" = "" +"checksum rocksdb 0.12.3 (registry+https://github.com/rust-lang/crates.io-index)" = "2e7523c32e26bf2ebc4540645961dafcbd086c652e8ecb563a507f432eb7636d" "checksum rust-crypto 0.2.36 (registry+https://github.com/rust-lang/crates.io-index)" = "f76d05d3993fd5f4af9434e8e436db163a12a9d40e1a58a726f27a01dfd12a2a" "checksum rustc-demangle 0.1.9 (registry+https://github.com/rust-lang/crates.io-index)" = "bcfe5b13211b4d78e5c2cadfebd7769197d95c639c35a50057eb4c05de811395" "checksum rustc-hex 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)" = "0ceb8ce7a5e520de349e1fa172baeba4a9e8d5ef06c47471863530bc4972ee1e" @@ -4595,6 +4418,7 @@ dependencies = [ "checksum same-file 1.0.4 (registry+https://github.com/rust-lang/crates.io-index)" = "8f20c4be53a8a1ff4c1f1b2bd14570d2f634628709752f0702ecdd2b3f9a5267" "checksum scoped-tls 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)" = "332ffa32bf586782a3efaeb58f127980944bbc8c4d6913a86107ac2a5ab24b28" "checksum scopeguard 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)" = "94258f53601af11e6a49f722422f6e3425c52b06245a5cf9bc09908b174f5e27" +"checksum scopeguard 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)" = "b42e15e59b18a828bbf5c58ea01debb36b9b096346de35d941dcb89009f24a0d" "checksum secp256k1 0.12.2 (registry+https://github.com/rust-lang/crates.io-index)" = "bfaccd3a23619349e0878d9a241f34b1982343cdf67367058cd7d078d326b63e" "checksum semver 0.9.0 (registry+https://github.com/rust-lang/crates.io-index)" = "1d7eb9ef2c18661902cc47e535f9bc51b78acd254da71d375c2f6720d9a40403" "checksum semver-parser 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)" = "388a1df253eca08550bef6c72392cfe7c30914bf41df5269b68cbd6ff8f570a3" @@ -4606,15 +4430,14 @@ dependencies = [ "checksum sha1 0.6.0 (registry+https://github.com/rust-lang/crates.io-index)" = "2579985fda508104f7587689507983eadd6a6e84dd35d6d115361f530916fa0d" "checksum sha2 0.6.0 (registry+https://github.com/rust-lang/crates.io-index)" = "7d963c78ce367df26d7ea8b8cc655c651b42e8a1e584e869c1e17dae3ccb116a" "checksum sha2 0.8.0 (registry+https://github.com/rust-lang/crates.io-index)" = "7b4d8bfd0e469f417657573d8451fb33d16cfe0989359b93baf3a1ffc639543d" +"checksum sha3 0.8.2 (registry+https://github.com/rust-lang/crates.io-index)" = "dd26bc0e7a2e3a7c959bc494caf58b72ee0c71d67704e9520f736ca7e4853ecf" +"checksum shlex 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "7fdf1b9db47230893d76faad238fd6097fd6d6a9245cd7a4d90dbd639536bbd2" "checksum signal-hook 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)" = "f7ca1f1c0ed6c8beaab713ad902c041e4f09d06e1b4bb74c5fc553c078ed0110" -"checksum siphasher 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)" = "833011ca526bd88f16778d32c699d325a9ad302fa06381cd66f7be63351d3f6d" -"checksum skeptic 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "24ebf8a06f5f8bae61ae5bbc7af7aac4ef6907ae975130faba1199e5fe82256a" -"checksum slab 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)" = "17b4fcaed89ab08ef143da37bc52adbcc04d4a69014f4c1208d6b51f0c47bc23" "checksum slab 0.4.1 (registry+https://github.com/rust-lang/crates.io-index)" = "5f9776d6b986f77b35c6cf846c11ad986ff128fe0b2b63a3628e3755e8d3102d" -"checksum smallvec 0.6.5 (registry+https://github.com/rust-lang/crates.io-index)" = "153ffa32fd170e9944f7e0838edf824a754ec4c1fc64746fcc9fe1f8fa602e5d" +"checksum smallvec 0.6.10 (registry+https://github.com/rust-lang/crates.io-index)" = "ab606a9c5e214920bb66c458cd7be8ef094f813f20fe77a54cc7dbfff220d4b7" "checksum snappy 0.1.0 (git+https://github.com/cryptape/cita-common.git?branch=develop)" = "" -"checksum sodiumoxide 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "71c0682b4406fa25d621b19d2e70b5f6c8627e39b4b7ce0e24b2ef05d0fbe1ca" -"checksum spin 0.5.0 (registry+https://github.com/rust-lang/crates.io-index)" = "44363f6f51401c34e7be73db0db371c04705d35efbe9f7d6082e03a921a32c55" +"checksum sodiumoxide 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)" = "31532969f87f66ea5667b203fdee70aec8ddbe25aac69d243daff58c01688152" +"checksum spin 0.5.2 (registry+https://github.com/rust-lang/crates.io-index)" = "6e63cff320ae2c57904679ba7cb63280a3dc4613885beafb148ee7bf9aa9042d" "checksum stable_deref_trait 1.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "dba1a27d3efae4351c8051072d619e3ade2820635c3958d826bfea39d59b54c8" "checksum static_assertions 0.2.5 (registry+https://github.com/rust-lang/crates.io-index)" = "c19be23126415861cb3a23e501d34a708f7f9b2183c5252d690941c2e69199d5" "checksum static_merkle_tree 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "f8c6d128ce6eff23dd4a2df63c61a96f729455cf776911917eed1a4c92155f9f" @@ -4622,16 +4445,16 @@ dependencies = [ "checksum string 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)" = "98998cced76115b1da46f63388b909d118a37ae0be0f82ad35773d4a4bc9d18d" "checksum strsim 0.8.0 (registry+https://github.com/rust-lang/crates.io-index)" = "8ea5119cdb4c55b55d432abb513a0429384878c15dde60cc77b1c99de1a95a6a" "checksum subtle 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)" = "2d67a5a62ba6e01cb2192ff309324cb4875d0c451d55fe2319433abe7a05a8ee" -"checksum syn 0.11.11 (registry+https://github.com/rust-lang/crates.io-index)" = "d3b891b9015c88c576343b9b3e41c2c11a51c219ef067b264bd9c8aa9b441dad" "checksum syn 0.14.9 (registry+https://github.com/rust-lang/crates.io-index)" = "261ae9ecaa397c42b960649561949d69311f08eeaea86a65696e6e46517cf741" "checksum syn 0.15.27 (registry+https://github.com/rust-lang/crates.io-index)" = "525bd55255f03c816e5d7f615587bd13030c7103354fadb104993dcee6a788ec" -"checksum synom 0.11.3 (registry+https://github.com/rust-lang/crates.io-index)" = "a393066ed9010ebaed60b9eafa373d4b1baac186dd7e008555b0f702b51945b6" "checksum synstructure 0.10.0 (registry+https://github.com/rust-lang/crates.io-index)" = "ec37f4fab4bafaf6b5621c1d54e6aa5d4d059a8f84929e87abfdd7f9f04c6db2" +"checksum take_mut 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)" = "f764005d11ee5f36500a149ace24e00e3da98b0158b3e2d53a7495660d3f4d60" +"checksum tar 0.4.25 (registry+https://github.com/rust-lang/crates.io-index)" = "7201214ded95b34e3bc00c9557b6dcec34fd1af428d343143f5db67c661762f0" "checksum tempdir 0.3.7 (registry+https://github.com/rust-lang/crates.io-index)" = "15f2b5fb00ccdf689e0149d1b1b3c03fead81c2b37735d812fa8bddbbf41b6d8" "checksum tempfile 2.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "11ce2fe9db64b842314052e2421ac61a73ce41b898dc8e3750398b219c5fc1e0" "checksum tempfile 3.0.7 (registry+https://github.com/rust-lang/crates.io-index)" = "b86c784c88d98c801132806dadd3819ed29d8600836c4088e855cdf3e178ed8a" -"checksum tentacle 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)" = "8dcddd2761682b538db6c0d20723a031d6beeac74d73656e5e9b54ff6cd25bed" -"checksum tentacle-discovery 0.2.4 (registry+https://github.com/rust-lang/crates.io-index)" = "48f049945da9545ef3208a10a28a33ca64e9672dab762ad28cfc861262f9a770" +"checksum tentacle 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)" = "ea86eecc50e36fdcdc6988df3eda74f4c8db0e8c3662967727f22b9dc9f04828" +"checksum tentacle-discovery 0.2.5 (registry+https://github.com/rust-lang/crates.io-index)" = "66079c177dba4f89cc882d74a16b037774059cf5be4fe9179b12937d7b4ffe40" "checksum tentacle-secio 0.1.7 (registry+https://github.com/rust-lang/crates.io-index)" = "1f7e6cfc62a132bec2b68c0827dcbfbe7b54744783aeaf15219acaeb8e07e8cd" "checksum termcolor 1.0.4 (registry+https://github.com/rust-lang/crates.io-index)" = "4096add70612622289f2fdcdbd5086dc81c1e2675e6ae58d6c4f62a16c6d7f2f" "checksum termion 1.5.1 (registry+https://github.com/rust-lang/crates.io-index)" = "689a3bdfaab439fd92bc87df5c4c78417d3cbe537487274e9b0b2dce76e92096" @@ -4644,7 +4467,6 @@ dependencies = [ "checksum time 0.1.40 (registry+https://github.com/rust-lang/crates.io-index)" = "d825be0eb33fda1a7e68012d51e9c7f451dc1a69391e7fdc197060bb8c56667b" "checksum tiny-keccak 1.4.2 (registry+https://github.com/rust-lang/crates.io-index)" = "e9175261fbdb60781fcd388a4d6cc7e14764a2b629a7ad94abb439aed223a44f" "checksum tls-api 0.1.20 (registry+https://github.com/rust-lang/crates.io-index)" = "e452fe2fdf40a10715adb3a5f244c7411cdf2ecc887b07160310939785db9182" -"checksum tls-api-stub 0.1.20 (registry+https://github.com/rust-lang/crates.io-index)" = "25a2dcddd0fd52bdbedf9b4f0fd1cb884abfa0984e6a54121d4cefdf3d234e4c" "checksum tokio 0.1.16 (registry+https://github.com/rust-lang/crates.io-index)" = "fcaabb3cec70485d0df6e9454fe514393ad1c4070dee8915f11041e95630b230" "checksum tokio-codec 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "5c501eceaf96f0e1793cf26beb63da3d11c738c4a943fdf3746d81d64684c39f" "checksum tokio-core 0.1.17 (registry+https://github.com/rust-lang/crates.io-index)" = "aeeffbbb94209023feaef3c196a41cbcdafa06b4a6f893f68779bb5e53796f71" @@ -4657,12 +4479,9 @@ dependencies = [ "checksum tokio-service 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "24da22d077e0f15f55162bdbdc661228c1581892f52074fb242678d015b45162" "checksum tokio-sync 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)" = "1bf2b9dac2a0509b5cfd1df5aa25eafacb616a42a491a13604d6bbeab4486363" "checksum tokio-tcp 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)" = "1d14b10654be682ac43efee27401d792507e30fd8d26389e1da3b185de2e4119" -"checksum tokio-threadpool 0.1.8 (registry+https://github.com/rust-lang/crates.io-index)" = "3929aee321c9220ed838ed6c3928be7f9b69986b0e3c22c972a66dbf8a298c68" -"checksum tokio-timer 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)" = "6131e780037787ff1b3f8aad9da83bca02438b72277850dd6ad0d455e0e20efc" +"checksum tokio-threadpool 0.1.12 (registry+https://github.com/rust-lang/crates.io-index)" = "742e511f6ce2298aeb86fc9ea0d8df81c2388c6ebae3dc8a7316e8c9df0df801" "checksum tokio-timer 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)" = "4f37f0111d76cc5da132fe9bc0590b9b9cfd079bc7e75ac3846278430a299ff8" -"checksum tokio-tls-api 0.1.20 (registry+https://github.com/rust-lang/crates.io-index)" = "c7ac6ebb2f40e7e068cb43e1f3b09b40d7869bcc7e49e7f50610d4e0e75a18d7" "checksum tokio-udp 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)" = "da941144b816d0dcda4db3a1ba87596e4df5e860a72b70783fe435891f80601c" -"checksum tokio-uds 0.1.7 (registry+https://github.com/rust-lang/crates.io-index)" = "65ae5d255ce739e8537221ed2942e0445f4b3b813daebac1c0050ddaaa3587f9" "checksum tokio-uds 0.2.5 (registry+https://github.com/rust-lang/crates.io-index)" = "037ffc3ba0e12a0ab4aca92e5234e0dedeb48fddf6ccd260f1f150a36a9f2445" "checksum tokio-yamux 0.1.12 (registry+https://github.com/rust-lang/crates.io-index)" = "2e8787adfb7b3a984b1093478895b304d7094d4de4e919655c6b0378e921f3df" "checksum toml 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)" = "736b60249cb25337bc196faa43ee12c705e426f3d55c214d73a4e7be06f92cb4" @@ -4675,16 +4494,12 @@ dependencies = [ "checksum typemap 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)" = "653be63c80a3296da5551e1bfd2cca35227e13cdd08c6668903ae2f4f77aa1f6" "checksum typenum 1.10.0 (registry+https://github.com/rust-lang/crates.io-index)" = "612d636f949607bdf9b123b4a6f6d966dedf3ff669f7f045890d3a4a73948169" "checksum ucd-util 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "fd2be2d6639d0f8fe6cdda291ad456e23629558d466e2789d2c3e9892bda285d" -"checksum uint 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)" = "38051a96565903d81c9a9210ce11076b2218f3b352926baa1f5f6abbdfce8273" "checksum uint 0.4.1 (registry+https://github.com/rust-lang/crates.io-index)" = "754ba11732b9161b94c41798e5197e5e75388d012f760c42adb5000353e98646" -"checksum uint 0.5.0 (registry+https://github.com/rust-lang/crates.io-index)" = "082df6964410f6aa929a61ddfafc997e4f32c62c22490e439ac351cec827f436" "checksum unicase 2.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "9d3218ea14b4edcaccfa0df0a64a3792a2c32cc706f1b336e48867f9d3147f90" "checksum unicode-bidi 0.3.4 (registry+https://github.com/rust-lang/crates.io-index)" = "49f2bd0c6468a8230e1db229cff8029217cf623c767ea5d60bfbd42729ea54d5" "checksum unicode-normalization 0.1.7 (registry+https://github.com/rust-lang/crates.io-index)" = "6a0180bc61fc5a987082bfa111f4cc95c4caff7f9799f3e46df09163a937aa25" "checksum unicode-width 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)" = "882386231c45df4700b275c7ff55b6f3698780a650026380e72dabe76fa46526" -"checksum unicode-xid 0.0.4 (registry+https://github.com/rust-lang/crates.io-index)" = "8c1f860d7d29cf02cb2f3f359fd35991af3d30bac52c57d265a3c461074cb4dc" "checksum unicode-xid 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "fc72304796d0818e357ead4e000d19c9c174ab23dc11093ac919054d20a6a7fc" -"checksum unix_socket 0.5.0 (registry+https://github.com/rust-lang/crates.io-index)" = "6aa2700417c405c38f5e6902d699345241c28c0b7ade4abaad71e35a87eb1564" "checksum unreachable 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)" = "382810877fe448991dfc7f0dd6e3ae5d58088fd0ea5e35189655f84e6814fa56" "checksum unsafe-any 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)" = "f30360d7979f5e9c6e6cea48af192ea8fab4afb3cf72597154b8f08935bc9c7f" "checksum unsigned-varint 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)" = "2c64cdf40b4a9645534a943668681bcb219faf51874d4b65d2e0abda1b10a2ab" @@ -4710,6 +4525,7 @@ dependencies = [ "checksum wincolor 1.0.1 (registry+https://github.com/rust-lang/crates.io-index)" = "561ed901ae465d6185fa7864d63fbd5720d0ef718366c9a4dc83cf6170d7e9ba" "checksum ws 0.7.9 (registry+https://github.com/rust-lang/crates.io-index)" = "329d3e6dd450a9c5c73024e1047f0be7e24121a68484eb0b5368977bee3cf8c3" "checksum ws2_32-sys 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)" = "d59cefebd0c892fa2dd6de581e937301d8552cb44489cdff035c6187cb63fa5e" +"checksum xattr 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)" = "244c3741f4240ef46274860397c7c74e50eb23624996930e484c16679633a54c" "checksum xml-rs 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)" = "3c1cb601d29fe2c2ac60a2b2e5e293994d87a1f6fa9687a31a15270f909be9c2" "checksum xmltree 0.8.0 (registry+https://github.com/rust-lang/crates.io-index)" = "ff8eaee9d17062850f1e6163b509947969242990ee59a35801af437abe041e70" "checksum yaml-rust 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)" = "95acf0db5515d07da9965ec0e0ba6cc2d825e2caeb7303b66ca441729801254e" diff --git a/LICENSE b/LICENSE index 733c07236..132f937a9 100644 --- a/LICENSE +++ b/LICENSE @@ -1,675 +1,201 @@ - GNU GENERAL PUBLIC LICENSE - Version 3, 29 June 2007 - - Copyright (C) 2007 Free Software Foundation, Inc. - Everyone is permitted to copy and distribute verbatim copies - of this license document, but changing it is not allowed. - - Preamble - - The GNU General Public License is a free, copyleft license for -software and other kinds of works. - - The licenses for most software and other practical works are designed -to take away your freedom to share and change the works. By contrast, -the GNU General Public License is intended to guarantee your freedom to -share and change all versions of a program--to make sure it remains free -software for all its users. We, the Free Software Foundation, use the -GNU General Public License for most of our software; it applies also to -any other work released this way by its authors. You can apply it to -your programs, too. - - When we speak of free software, we are referring to freedom, not -price. Our General Public Licenses are designed to make sure that you -have the freedom to distribute copies of free software (and charge for -them if you wish), that you receive source code or can get it if you -want it, that you can change the software or use pieces of it in new -free programs, and that you know you can do these things. - - To protect your rights, we need to prevent others from denying you -these rights or asking you to surrender the rights. Therefore, you have -certain responsibilities if you distribute copies of the software, or if -you modify it: responsibilities to respect the freedom of others. - - For example, if you distribute copies of such a program, whether -gratis or for a fee, you must pass on to the recipients the same -freedoms that you received. You must make sure that they, too, receive -or can get the source code. And you must show them these terms so they -know their rights. - - Developers that use the GNU GPL protect your rights with two steps: -(1) assert copyright on the software, and (2) offer you this License -giving you legal permission to copy, distribute and/or modify it. - - For the developers' and authors' protection, the GPL clearly explains -that there is no warranty for this free software. For both users' and -authors' sake, the GPL requires that modified versions be marked as -changed, so that their problems will not be attributed erroneously to -authors of previous versions. - - Some devices are designed to deny users access to install or run -modified versions of the software inside them, although the manufacturer -can do so. This is fundamentally incompatible with the aim of -protecting users' freedom to change the software. The systematic -pattern of such abuse occurs in the area of products for individuals to -use, which is precisely where it is most unacceptable. Therefore, we -have designed this version of the GPL to prohibit the practice for those -products. If such problems arise substantially in other domains, we -stand ready to extend this provision to those domains in future versions -of the GPL, as needed to protect the freedom of users. - - Finally, every program is threatened constantly by software patents. -States should not allow patents to restrict development and use of -software on general-purpose computers, but in those that do, we wish to -avoid the special danger that patents applied to a free program could -make it effectively proprietary. To prevent this, the GPL assures that -patents cannot be used to render the program non-free. - - The precise terms and conditions for copying, distribution and -modification follow. - - TERMS AND CONDITIONS - - 0. Definitions. - - "This License" refers to version 3 of the GNU General Public License. - - "Copyright" also means copyright-like laws that apply to other kinds of -works, such as semiconductor masks. - - "The Program" refers to any copyrightable work licensed under this -License. Each licensee is addressed as "you". "Licensees" and -"recipients" may be individuals or organizations. - - To "modify" a work means to copy from or adapt all or part of the work -in a fashion requiring copyright permission, other than the making of an -exact copy. The resulting work is called a "modified version" of the -earlier work or a work "based on" the earlier work. - - A "covered work" means either the unmodified Program or a work based -on the Program. - - To "propagate" a work means to do anything with it that, without -permission, would make you directly or secondarily liable for -infringement under applicable copyright law, except executing it on a -computer or modifying a private copy. Propagation includes copying, -distribution (with or without modification), making available to the -public, and in some countries other activities as well. - - To "convey" a work means any kind of propagation that enables other -parties to make or receive copies. Mere interaction with a user through -a computer network, with no transfer of a copy, is not conveying. - - An interactive user interface displays "Appropriate Legal Notices" -to the extent that it includes a convenient and prominently visible -feature that (1) displays an appropriate copyright notice, and (2) -tells the user that there is no warranty for the work (except to the -extent that warranties are provided), that licensees may convey the -work under this License, and how to view a copy of this License. If -the interface presents a list of user commands or options, such as a -menu, a prominent item in the list meets this criterion. - - 1. Source Code. - - The "source code" for a work means the preferred form of the work -for making modifications to it. "Object code" means any non-source -form of a work. - - A "Standard Interface" means an interface that either is an official -standard defined by a recognized standards body, or, in the case of -interfaces specified for a particular programming language, one that -is widely used among developers working in that language. - - The "System Libraries" of an executable work include anything, other -than the work as a whole, that (a) is included in the normal form of -packaging a Major Component, but which is not part of that Major -Component, and (b) serves only to enable use of the work with that -Major Component, or to implement a Standard Interface for which an -implementation is available to the public in source code form. A -"Major Component", in this context, means a major essential component -(kernel, window system, and so on) of the specific operating system -(if any) on which the executable work runs, or a compiler used to -produce the work, or an object code interpreter used to run it. - - The "Corresponding Source" for a work in object code form means all -the source code needed to generate, install, and (for an executable -work) run the object code and to modify the work, including scripts to -control those activities. However, it does not include the work's -System Libraries, or general-purpose tools or generally available free -programs which are used unmodified in performing those activities but -which are not part of the work. For example, Corresponding Source -includes interface definition files associated with source files for -the work, and the source code for shared libraries and dynamically -linked subprograms that the work is specifically designed to require, -such as by intimate data communication or control flow between those -subprograms and other parts of the work. - - The Corresponding Source need not include anything that users -can regenerate automatically from other parts of the Corresponding -Source. - - The Corresponding Source for a work in source code form is that -same work. - - 2. Basic Permissions. - - All rights granted under this License are granted for the term of -copyright on the Program, and are irrevocable provided the stated -conditions are met. This License explicitly affirms your unlimited -permission to run the unmodified Program. The output from running a -covered work is covered by this License only if the output, given its -content, constitutes a covered work. This License acknowledges your -rights of fair use or other equivalent, as provided by copyright law. - - You may make, run and propagate covered works that you do not -convey, without conditions so long as your license otherwise remains -in force. You may convey covered works to others for the sole purpose -of having them make modifications exclusively for you, or provide you -with facilities for running those works, provided that you comply with -the terms of this License in conveying all material for which you do -not control copyright. Those thus making or running the covered works -for you must do so exclusively on your behalf, under your direction -and control, on terms that prohibit them from making any copies of -your copyrighted material outside their relationship with you. - - Conveying under any other circumstances is permitted solely under -the conditions stated below. Sublicensing is not allowed; section 10 -makes it unnecessary. - - 3. Protecting Users' Legal Rights From Anti-Circumvention Law. - - No covered work shall be deemed part of an effective technological -measure under any applicable law fulfilling obligations under article -11 of the WIPO copyright treaty adopted on 20 December 1996, or -similar laws prohibiting or restricting circumvention of such -measures. - - When you convey a covered work, you waive any legal power to forbid -circumvention of technological measures to the extent such circumvention -is effected by exercising rights under this License with respect to -the covered work, and you disclaim any intention to limit operation or -modification of the work as a means of enforcing, against the work's -users, your or third parties' legal rights to forbid circumvention of -technological measures. - - 4. Conveying Verbatim Copies. - - You may convey verbatim copies of the Program's source code as you -receive it, in any medium, provided that you conspicuously and -appropriately publish on each copy an appropriate copyright notice; -keep intact all notices stating that this License and any -non-permissive terms added in accord with section 7 apply to the code; -keep intact all notices of the absence of any warranty; and give all -recipients a copy of this License along with the Program. - - You may charge any price or no price for each copy that you convey, -and you may offer support or warranty protection for a fee. - - 5. Conveying Modified Source Versions. - - You may convey a work based on the Program, or the modifications to -produce it from the Program, in the form of source code under the -terms of section 4, provided that you also meet all of these conditions: - - a) The work must carry prominent notices stating that you modified - it, and giving a relevant date. - - b) The work must carry prominent notices stating that it is - released under this License and any conditions added under section - 7. This requirement modifies the requirement in section 4 to - "keep intact all notices". - - c) You must license the entire work, as a whole, under this - License to anyone who comes into possession of a copy. This - License will therefore apply, along with any applicable section 7 - additional terms, to the whole of the work, and all its parts, - regardless of how they are packaged. This License gives no - permission to license the work in any other way, but it does not - invalidate such permission if you have separately received it. - - d) If the work has interactive user interfaces, each must display - Appropriate Legal Notices; however, if the Program has interactive - interfaces that do not display Appropriate Legal Notices, your - work need not make them do so. - - A compilation of a covered work with other separate and independent -works, which are not by their nature extensions of the covered work, -and which are not combined with it such as to form a larger program, -in or on a volume of a storage or distribution medium, is called an -"aggregate" if the compilation and its resulting copyright are not -used to limit the access or legal rights of the compilation's users -beyond what the individual works permit. Inclusion of a covered work -in an aggregate does not cause this License to apply to the other -parts of the aggregate. - - 6. Conveying Non-Source Forms. - - You may convey a covered work in object code form under the terms -of sections 4 and 5, provided that you also convey the -machine-readable Corresponding Source under the terms of this License, -in one of these ways: - - a) Convey the object code in, or embodied in, a physical product - (including a physical distribution medium), accompanied by the - Corresponding Source fixed on a durable physical medium - customarily used for software interchange. - - b) Convey the object code in, or embodied in, a physical product - (including a physical distribution medium), accompanied by a - written offer, valid for at least three years and valid for as - long as you offer spare parts or customer support for that product - model, to give anyone who possesses the object code either (1) a - copy of the Corresponding Source for all the software in the - product that is covered by this License, on a durable physical - medium customarily used for software interchange, for a price no - more than your reasonable cost of physically performing this - conveying of source, or (2) access to copy the - Corresponding Source from a network server at no charge. - - c) Convey individual copies of the object code with a copy of the - written offer to provide the Corresponding Source. This - alternative is allowed only occasionally and noncommercially, and - only if you received the object code with such an offer, in accord - with subsection 6b. - - d) Convey the object code by offering access from a designated - place (gratis or for a charge), and offer equivalent access to the - Corresponding Source in the same way through the same place at no - further charge. You need not require recipients to copy the - Corresponding Source along with the object code. If the place to - copy the object code is a network server, the Corresponding Source - may be on a different server (operated by you or a third party) - that supports equivalent copying facilities, provided you maintain - clear directions next to the object code saying where to find the - Corresponding Source. Regardless of what server hosts the - Corresponding Source, you remain obligated to ensure that it is - available for as long as needed to satisfy these requirements. - - e) Convey the object code using peer-to-peer transmission, provided - you inform other peers where the object code and Corresponding - Source of the work are being offered to the general public at no - charge under subsection 6d. - - A separable portion of the object code, whose source code is excluded -from the Corresponding Source as a System Library, need not be -included in conveying the object code work. - - A "User Product" is either (1) a "consumer product", which means any -tangible personal property which is normally used for personal, family, -or household purposes, or (2) anything designed or sold for incorporation -into a dwelling. In determining whether a product is a consumer product, -doubtful cases shall be resolved in favor of coverage. For a particular -product received by a particular user, "normally used" refers to a -typical or common use of that class of product, regardless of the status -of the particular user or of the way in which the particular user -actually uses, or expects or is expected to use, the product. A product -is a consumer product regardless of whether the product has substantial -commercial, industrial or non-consumer uses, unless such uses represent -the only significant mode of use of the product. - - "Installation Information" for a User Product means any methods, -procedures, authorization keys, or other information required to install -and execute modified versions of a covered work in that User Product from -a modified version of its Corresponding Source. The information must -suffice to ensure that the continued functioning of the modified object -code is in no case prevented or interfered with solely because -modification has been made. - - If you convey an object code work under this section in, or with, or -specifically for use in, a User Product, and the conveying occurs as -part of a transaction in which the right of possession and use of the -User Product is transferred to the recipient in perpetuity or for a -fixed term (regardless of how the transaction is characterized), the -Corresponding Source conveyed under this section must be accompanied -by the Installation Information. But this requirement does not apply -if neither you nor any third party retains the ability to install -modified object code on the User Product (for example, the work has -been installed in ROM). - - The requirement to provide Installation Information does not include a -requirement to continue to provide support service, warranty, or updates -for a work that has been modified or installed by the recipient, or for -the User Product in which it has been modified or installed. Access to a -network may be denied when the modification itself materially and -adversely affects the operation of the network or violates the rules and -protocols for communication across the network. - - Corresponding Source conveyed, and Installation Information provided, -in accord with this section must be in a format that is publicly -documented (and with an implementation available to the public in -source code form), and must require no special password or key for -unpacking, reading or copying. - - 7. Additional Terms. - - "Additional permissions" are terms that supplement the terms of this -License by making exceptions from one or more of its conditions. -Additional permissions that are applicable to the entire Program shall -be treated as though they were included in this License, to the extent -that they are valid under applicable law. If additional permissions -apply only to part of the Program, that part may be used separately -under those permissions, but the entire Program remains governed by -this License without regard to the additional permissions. - - When you convey a copy of a covered work, you may at your option -remove any additional permissions from that copy, or from any part of -it. (Additional permissions may be written to require their own -removal in certain cases when you modify the work.) You may place -additional permissions on material, added by you to a covered work, -for which you have or can give appropriate copyright permission. - - Notwithstanding any other provision of this License, for material you -add to a covered work, you may (if authorized by the copyright holders of -that material) supplement the terms of this License with terms: - - a) Disclaiming warranty or limiting liability differently from the - terms of sections 15 and 16 of this License; or - - b) Requiring preservation of specified reasonable legal notices or - author attributions in that material or in the Appropriate Legal - Notices displayed by works containing it; or - - c) Prohibiting misrepresentation of the origin of that material, or - requiring that modified versions of such material be marked in - reasonable ways as different from the original version; or - - d) Limiting the use for publicity purposes of names of licensors or - authors of the material; or - - e) Declining to grant rights under trademark law for use of some - trade names, trademarks, or service marks; or - - f) Requiring indemnification of licensors and authors of that - material by anyone who conveys the material (or modified versions of - it) with contractual assumptions of liability to the recipient, for - any liability that these contractual assumptions directly impose on - those licensors and authors. - - All other non-permissive additional terms are considered "further -restrictions" within the meaning of section 10. If the Program as you -received it, or any part of it, contains a notice stating that it is -governed by this License along with a term that is a further -restriction, you may remove that term. If a license document contains -a further restriction but permits relicensing or conveying under this -License, you may add to a covered work material governed by the terms -of that license document, provided that the further restriction does -not survive such relicensing or conveying. - - If you add terms to a covered work in accord with this section, you -must place, in the relevant source files, a statement of the -additional terms that apply to those files, or a notice indicating -where to find the applicable terms. - - Additional terms, permissive or non-permissive, may be stated in the -form of a separately written license, or stated as exceptions; -the above requirements apply either way. - - 8. Termination. - - You may not propagate or modify a covered work except as expressly -provided under this License. Any attempt otherwise to propagate or -modify it is void, and will automatically terminate your rights under -this License (including any patent licenses granted under the third -paragraph of section 11). - - However, if you cease all violation of this License, then your -license from a particular copyright holder is reinstated (a) -provisionally, unless and until the copyright holder explicitly and -finally terminates your license, and (b) permanently, if the copyright -holder fails to notify you of the violation by some reasonable means -prior to 60 days after the cessation. - - Moreover, your license from a particular copyright holder is -reinstated permanently if the copyright holder notifies you of the -violation by some reasonable means, this is the first time you have -received notice of violation of this License (for any work) from that -copyright holder, and you cure the violation prior to 30 days after -your receipt of the notice. - - Termination of your rights under this section does not terminate the -licenses of parties who have received copies or rights from you under -this License. If your rights have been terminated and not permanently -reinstated, you do not qualify to receive new licenses for the same -material under section 10. - - 9. Acceptance Not Required for Having Copies. - - You are not required to accept this License in order to receive or -run a copy of the Program. Ancillary propagation of a covered work -occurring solely as a consequence of using peer-to-peer transmission -to receive a copy likewise does not require acceptance. However, -nothing other than this License grants you permission to propagate or -modify any covered work. These actions infringe copyright if you do -not accept this License. Therefore, by modifying or propagating a -covered work, you indicate your acceptance of this License to do so. - - 10. Automatic Licensing of Downstream Recipients. - - Each time you convey a covered work, the recipient automatically -receives a license from the original licensors, to run, modify and -propagate that work, subject to this License. You are not responsible -for enforcing compliance by third parties with this License. - - An "entity transaction" is a transaction transferring control of an -organization, or substantially all assets of one, or subdividing an -organization, or merging organizations. If propagation of a covered -work results from an entity transaction, each party to that -transaction who receives a copy of the work also receives whatever -licenses to the work the party's predecessor in interest had or could -give under the previous paragraph, plus a right to possession of the -Corresponding Source of the work from the predecessor in interest, if -the predecessor has it or can get it with reasonable efforts. - - You may not impose any further restrictions on the exercise of the -rights granted or affirmed under this License. For example, you may -not impose a license fee, royalty, or other charge for exercise of -rights granted under this License, and you may not initiate litigation -(including a cross-claim or counterclaim in a lawsuit) alleging that -any patent claim is infringed by making, using, selling, offering for -sale, or importing the Program or any portion of it. - - 11. Patents. - - A "contributor" is a copyright holder who authorizes use under this -License of the Program or a work on which the Program is based. The -work thus licensed is called the contributor's "contributor version". - - A contributor's "essential patent claims" are all patent claims -owned or controlled by the contributor, whether already acquired or -hereafter acquired, that would be infringed by some manner, permitted -by this License, of making, using, or selling its contributor version, -but do not include claims that would be infringed only as a -consequence of further modification of the contributor version. For -purposes of this definition, "control" includes the right to grant -patent sublicenses in a manner consistent with the requirements of -this License. - - Each contributor grants you a non-exclusive, worldwide, royalty-free -patent license under the contributor's essential patent claims, to -make, use, sell, offer for sale, import and otherwise run, modify and -propagate the contents of its contributor version. - - In the following three paragraphs, a "patent license" is any express -agreement or commitment, however denominated, not to enforce a patent -(such as an express permission to practice a patent or covenant not to -sue for patent infringement). To "grant" such a patent license to a -party means to make such an agreement or commitment not to enforce a -patent against the party. - - If you convey a covered work, knowingly relying on a patent license, -and the Corresponding Source of the work is not available for anyone -to copy, free of charge and under the terms of this License, through a -publicly available network server or other readily accessible means, -then you must either (1) cause the Corresponding Source to be so -available, or (2) arrange to deprive yourself of the benefit of the -patent license for this particular work, or (3) arrange, in a manner -consistent with the requirements of this License, to extend the patent -license to downstream recipients. "Knowingly relying" means you have -actual knowledge that, but for the patent license, your conveying the -covered work in a country, or your recipient's use of the covered work -in a country, would infringe one or more identifiable patents in that -country that you have reason to believe are valid. - - If, pursuant to or in connection with a single transaction or -arrangement, you convey, or propagate by procuring conveyance of, a -covered work, and grant a patent license to some of the parties -receiving the covered work authorizing them to use, propagate, modify -or convey a specific copy of the covered work, then the patent license -you grant is automatically extended to all recipients of the covered -work and works based on it. - - A patent license is "discriminatory" if it does not include within -the scope of its coverage, prohibits the exercise of, or is -conditioned on the non-exercise of one or more of the rights that are -specifically granted under this License. You may not convey a covered -work if you are a party to an arrangement with a third party that is -in the business of distributing software, under which you make payment -to the third party based on the extent of your activity of conveying -the work, and under which the third party grants, to any of the -parties who would receive the covered work from you, a discriminatory -patent license (a) in connection with copies of the covered work -conveyed by you (or copies made from those copies), or (b) primarily -for and in connection with specific products or compilations that -contain the covered work, unless you entered into that arrangement, -or that patent license was granted, prior to 28 March 2007. - - Nothing in this License shall be construed as excluding or limiting -any implied license or other defenses to infringement that may -otherwise be available to you under applicable patent law. - - 12. No Surrender of Others' Freedom. - - If conditions are imposed on you (whether by court order, agreement or -otherwise) that contradict the conditions of this License, they do not -excuse you from the conditions of this License. If you cannot convey a -covered work so as to satisfy simultaneously your obligations under this -License and any other pertinent obligations, then as a consequence you may -not convey it at all. For example, if you agree to terms that obligate you -to collect a royalty for further conveying from those to whom you convey -the Program, the only way you could satisfy both those terms and this -License would be to refrain entirely from conveying the Program. - - 13. Use with the GNU Affero General Public License. - - Notwithstanding any other provision of this License, you have -permission to link or combine any covered work with a work licensed -under version 3 of the GNU Affero General Public License into a single -combined work, and to convey the resulting work. The terms of this -License will continue to apply to the part which is the covered work, -but the special requirements of the GNU Affero General Public License, -section 13, concerning interaction through a network will apply to the -combination as such. - - 14. Revised Versions of this License. - - The Free Software Foundation may publish revised and/or new versions of -the GNU General Public License from time to time. Such new versions will -be similar in spirit to the present version, but may differ in detail to -address new problems or concerns. - - Each version is given a distinguishing version number. If the -Program specifies that a certain numbered version of the GNU General -Public License "or any later version" applies to it, you have the -option of following the terms and conditions either of that numbered -version or of any later version published by the Free Software -Foundation. If the Program does not specify a version number of the -GNU General Public License, you may choose any version ever published -by the Free Software Foundation. - - If the Program specifies that a proxy can decide which future -versions of the GNU General Public License can be used, that proxy's -public statement of acceptance of a version permanently authorizes you -to choose that version for the Program. - - Later license versions may give you additional or different -permissions. However, no additional obligations are imposed on any -author or copyright holder as a result of your choosing to follow a -later version. - - 15. Disclaimer of Warranty. - - THERE IS NO WARRANTY FOR THE PROGRAM, TO THE EXTENT PERMITTED BY -APPLICABLE LAW. EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT -HOLDERS AND/OR OTHER PARTIES PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY -OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, -THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR -PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE PROGRAM -IS WITH YOU. SHOULD THE PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF -ALL NECESSARY SERVICING, REPAIR OR CORRECTION. - - 16. Limitation of Liability. - - IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING -WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MODIFIES AND/OR CONVEYS -THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY -GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE -USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED TO LOSS OF -DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD -PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS), -EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF -SUCH DAMAGES. - - 17. Interpretation of Sections 15 and 16. - - If the disclaimer of warranty and limitation of liability provided -above cannot be given local legal effect according to their terms, -reviewing courts shall apply local law that most closely approximates -an absolute waiver of all civil liability in connection with the -Program, unless a warranty or assumption of liability accompanies a -copy of the Program in return for a fee. - - END OF TERMS AND CONDITIONS - - How to Apply These Terms to Your New Programs - - If you develop a new program, and you want it to be of the greatest -possible use to the public, the best way to achieve this is to make it -free software which everyone can redistribute and change under these terms. - - To do so, attach the following notices to the program. It is safest -to attach them to the start of each source file to most effectively -state the exclusion of warranty; and each file should have at least -the "copyright" line and a pointer to where the full notice is found. - - {one line to give the program's name and a brief idea of what it does.} - Copyright (C) {year} {name of author} - - This program is free software: you can redistribute it and/or modify - it under the terms of the GNU 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 General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program. If not, see . - -Also add information on how to contact you by electronic and paper mail. - - If the program does terminal interaction, make it output a short -notice like this when it starts in an interactive mode: - - {project} Copyright (C) {year} {fullname} - This program comes with ABSOLUTELY NO WARRANTY; for details type `show w'. - This is free software, and you are welcome to redistribute it - under certain conditions; type `show c' for details. - -The hypothetical commands `show w' and `show c' should show the appropriate -parts of the General Public License. Of course, your program's commands -might be different; for a GUI interface, you would use an "about box". - - You should also get your employer (if you work as a programmer) or school, -if any, to sign a "copyright disclaimer" for the program, if necessary. -For more information on this, and how to apply and follow the GNU GPL, see -. - - The GNU General Public License does not permit incorporating your program -into proprietary programs. If your program is a subroutine library, you -may consider it more useful to permit linking proprietary applications with -the library. If this is what you want to do, use the GNU Lesser General -Public License instead of this License. But first, please read -. - + Apache License + Version 2.0, January 2004 + http://www.apache.org/licenses/ + + TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + + 1. Definitions. + + "License" shall mean the terms and conditions for use, reproduction, + and distribution as defined by Sections 1 through 9 of this document. + + "Licensor" shall mean the copyright owner or entity authorized by + the copyright owner that is granting the License. + + "Legal Entity" shall mean the union of the acting entity and all + other entities that control, are controlled by, or are under common + control with that entity. For the purposes of this definition, + "control" means (i) the power, direct or indirect, to cause the + direction or management of such entity, whether by contract or + otherwise, or (ii) ownership of fifty percent (50%) or more of the + outstanding shares, or (iii) beneficial ownership of such entity. + + "You" (or "Your") shall mean an individual or Legal Entity + exercising permissions granted by this License. + + "Source" form shall mean the preferred form for making modifications, + including but not limited to software source code, documentation + source, and configuration files. + + "Object" form shall mean any form resulting from mechanical + transformation or translation of a Source form, including but + not limited to compiled object code, generated documentation, + and conversions to other media types. + + "Work" shall mean the work of authorship, whether in Source or + Object form, made available under the License, as indicated by a + copyright notice that is included in or attached to the work + (an example is provided in the Appendix below). + + "Derivative Works" shall mean any work, whether in Source or Object + form, that is based on (or derived from) the Work and for which the + editorial revisions, annotations, elaborations, or other modifications + represent, as a whole, an original work of authorship. For the purposes + of this License, Derivative Works shall not include works that remain + separable from, or merely link (or bind by name) to the interfaces of, + the Work and Derivative Works thereof. + + "Contribution" shall mean any work of authorship, including + the original version of the Work and any modifications or additions + to that Work or Derivative Works thereof, that is intentionally + submitted to Licensor for inclusion in the Work by the copyright owner + or by an individual or Legal Entity authorized to submit on behalf of + the copyright owner. For the purposes of this definition, "submitted" + means any form of electronic, verbal, or written communication sent + to the Licensor or its representatives, including but not limited to + communication on electronic mailing lists, source code control systems, + and issue tracking systems that are managed by, or on behalf of, the + Licensor for the purpose of discussing and improving the Work, but + excluding communication that is conspicuously marked or otherwise + designated in writing by the copyright owner as "Not a Contribution." + + "Contributor" shall mean Licensor and any individual or Legal Entity + on behalf of whom a Contribution has been received by Licensor and + subsequently incorporated within the Work. + + 2. Grant of Copyright License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + copyright license to reproduce, prepare Derivative Works of, + publicly display, publicly perform, sublicense, and distribute the + Work and such Derivative Works in Source or Object form. + + 3. Grant of Patent License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + (except as stated in this section) patent license to make, have made, + use, offer to sell, sell, import, and otherwise transfer the Work, + where such license applies only to those patent claims licensable + by such Contributor that are necessarily infringed by their + Contribution(s) alone or by combination of their Contribution(s) + with the Work to which such Contribution(s) was submitted. If You + institute patent litigation against any entity (including a + cross-claim or counterclaim in a lawsuit) alleging that the Work + or a Contribution incorporated within the Work constitutes direct + or contributory patent infringement, then any patent licenses + granted to You under this License for that Work shall terminate + as of the date such litigation is filed. + + 4. Redistribution. You may reproduce and distribute copies of the + Work or Derivative Works thereof in any medium, with or without + modifications, and in Source or Object form, provided that You + meet the following conditions: + + (a) You must give any other recipients of the Work or + Derivative Works a copy of this License; and + + (b) You must cause any modified files to carry prominent notices + stating that You changed the files; and + + (c) You must retain, in the Source form of any Derivative Works + that You distribute, all copyright, patent, trademark, and + attribution notices from the Source form of the Work, + excluding those notices that do not pertain to any part of + the Derivative Works; and + + (d) If the Work includes a "NOTICE" text file as part of its + distribution, then any Derivative Works that You distribute must + include a readable copy of the attribution notices contained + within such NOTICE file, excluding those notices that do not + pertain to any part of the Derivative Works, in at least one + of the following places: within a NOTICE text file distributed + as part of the Derivative Works; within the Source form or + documentation, if provided along with the Derivative Works; or, + within a display generated by the Derivative Works, if and + wherever such third-party notices normally appear. The contents + of the NOTICE file are for informational purposes only and + do not modify the License. You may add Your own attribution + notices within Derivative Works that You distribute, alongside + or as an addendum to the NOTICE text from the Work, provided + that such additional attribution notices cannot be construed + as modifying the License. + + You may add Your own copyright statement to Your modifications and + may provide additional or different license terms and conditions + for use, reproduction, or distribution of Your modifications, or + for any such Derivative Works as a whole, provided Your use, + reproduction, and distribution of the Work otherwise complies with + the conditions stated in this License. + + 5. Submission of Contributions. Unless You explicitly state otherwise, + any Contribution intentionally submitted for inclusion in the Work + by You to the Licensor shall be under the terms and conditions of + this License, without any additional terms or conditions. + Notwithstanding the above, nothing herein shall supersede or modify + the terms of any separate license agreement you may have executed + with Licensor regarding such Contributions. + + 6. Trademarks. This License does not grant permission to use the trade + names, trademarks, service marks, or product names of the Licensor, + except as required for reasonable and customary use in describing the + origin of the Work and reproducing the content of the NOTICE file. + + 7. Disclaimer of Warranty. Unless required by applicable law or + agreed to in writing, Licensor provides the Work (and each + Contributor provides its Contributions) on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + implied, including, without limitation, any warranties or conditions + of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A + PARTICULAR PURPOSE. You are solely responsible for determining the + appropriateness of using or redistributing the Work and assume any + risks associated with Your exercise of permissions under this License. + + 8. Limitation of Liability. In no event and under no legal theory, + whether in tort (including negligence), contract, or otherwise, + unless required by applicable law (such as deliberate and grossly + negligent acts) or agreed to in writing, shall any Contributor be + liable to You for damages, including any direct, indirect, special, + incidental, or consequential damages of any character arising as a + result of this License or out of the use or inability to use the + Work (including but not limited to damages for loss of goodwill, + work stoppage, computer failure or malfunction, or any and all + other commercial damages or losses), even if such Contributor + has been advised of the possibility of such damages. + + 9. Accepting Warranty or Additional Liability. While redistributing + the Work or Derivative Works thereof, You may choose to offer, + and charge a fee for, acceptance of support, warranty, indemnity, + or other liability obligations and/or rights consistent with this + License. However, in accepting such obligations, You may act only + on Your own behalf and on Your sole responsibility, not on behalf + of any other Contributor, and only if You agree to indemnify, + defend, and hold each Contributor harmless for any liability + incurred by, or claims asserted against, such Contributor by reason + of your accepting any such warranty or additional liability. + + END OF TERMS AND CONDITIONS + + APPENDIX: How to apply the Apache License to your work. + + To apply the Apache License to your work, attach the following + boilerplate notice, with the fields enclosed by brackets "[]" + replaced with your own identifying information. (Don't include + the brackets!) The text should be enclosed in the appropriate + comment syntax for the file format. We also recommend that a + file or class name and description of purpose be included on the + same "printed page" as the copyright notice for easier + identification within third-party archives. + + Copyright Cryptape Technologies LLC. + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. diff --git a/README-CN.md b/README-CN.md index 22c27816c..dcc7ea2c4 100644 --- a/README-CN.md +++ b/README-CN.md @@ -82,9 +82,9 @@ CITA 目前仍在紧张的开发中,欢迎大家为 CITA 贡献自己的一份 [Weibo](http://weibo.com/u/6307204864) -## 开源协议 +## 开源协议 [![FOSSA Status](https://app.fossa.com/api/projects/git%2Bgithub.com%2Fcryptape%2Fcita.svg?type=shield)](https://app.fossa.com/projects/git%2Bgithub.com%2Fcryptape%2Fcita?ref=badge_shield) -GPLv3 license +Apache 2.0 license ## 权益归属 diff --git a/README.md b/README.md index 5f6c31c67..5f0785a07 100644 --- a/README.md +++ b/README.md @@ -62,11 +62,9 @@ Please check [CONTRIBUTING](.github/CONTRIBUTING.md) for more details. [Weibo](http://weibo.com/u/6307204864) -## License +## License [![FOSSA Status](https://app.fossa.com/api/projects/git%2Bgithub.com%2Fcryptape%2Fcita.svg?type=shield)](https://app.fossa.com/projects/git%2Bgithub.com%2Fcryptape%2Fcita?ref=badge_shield) -CITA is currently under the GPLv3 license. See the LICENSE file for details. - -**CITA will move to Apache 2.0 license soon.** +CITA is currently under Apache 2.0 license. See the LICENSE file for details. ## Credits diff --git a/cita-auth/Cargo.toml b/cita-auth/Cargo.toml index 47abcd2fb..d29aeee24 100644 --- a/cita-auth/Cargo.toml +++ b/cita-auth/Cargo.toml @@ -2,6 +2,7 @@ name = "cita-auth" version = "0.1.0" authors = ["Cryptape Technologies "] +license = "Apache-2.0" edition = "2018" [dependencies] @@ -11,7 +12,7 @@ cpuprofiler = "0.0.3" serde = "1.0" serde_derive = "1.0" serde_json = "1.0" -cita-logger = "0.1.0" +cita-logger = "0.1.1" cita-types = { git = "https://github.com/cryptape/cita-common.git", branch = "develop" } cita-directories = { git = "https://github.com/cryptape/cita-common.git", branch = "develop" } util = { git = "https://github.com/cryptape/cita-common.git", branch = "develop" } @@ -21,12 +22,11 @@ libproto = { git = "https://github.com/cryptape/cita-common.git", branch = "deve cita-crypto = { git = "https://github.com/cryptape/cita-common.git", branch = "develop" } tx_pool = { git = "https://github.com/cryptape/cita-common.git", branch = "develop" } jsonrpc-types = { git = "https://github.com/cryptape/cita-common.git", branch = "develop" } -core = { path = "../cita-chain/core" } uuid = { version = "0.7", features = ["v4"] } lru = "0.1" -rayon = "1.0" +rayon = "1.2" hashable = { git = "https://github.com/cryptape/cita-common.git", branch = "develop" } -db = { git = "https://github.com/cryptape/cita-common.git", branch = "develop" } +cita-database = { git = "https://github.com/cryptape/cita-database.git", branch = "develop" } [dev-dependencies] tempfile = "2" @@ -41,9 +41,9 @@ default = ["secp256k1", "sha3hash", "rabbitmq"] secp256k1 = ["cita-crypto/secp256k1", "libproto/secp256k1", "tx_pool/secp256k1"] ed25519 = ["cita-crypto/ed25519", "libproto/ed25519", "tx_pool/ed25519"] sm2 = ["cita-crypto/sm2", "libproto/sm2", "tx_pool/sm2"] -sha3hash = ["libproto/sha3hash", "db/sha3hash", "tx_pool/sha3hash"] -blake2bhash = ["libproto/blake2bhash", "db/blake2bhash", "tx_pool/blake2bhash"] -sm3hash = ["libproto/sm3hash", "db/sm3hash", "tx_pool/sm3hash"] +sha3hash = ["libproto/sha3hash", "tx_pool/sha3hash"] +blake2bhash = ["libproto/blake2bhash", "tx_pool/blake2bhash"] +sm3hash = ["libproto/sm3hash", "tx_pool/sm3hash"] rabbitmq = ["pubsub/rabbitmq"] zeromq = ["pubsub/zeromq"] kafka = ["pubsub/kafka"] diff --git a/cita-auth/build.rs b/cita-auth/build.rs index 0b73a9c9c..0c9a51c99 100644 --- a/cita-auth/build.rs +++ b/cita-auth/build.rs @@ -1,19 +1,16 @@ -// CITA -// Copyright 2016-2019 Cryptape Technologies LLC. - -// This program is free software: you can redistribute it -// and/or modify it under the terms of the GNU 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 General Public License for more details. - -// You should have received a copy of the GNU General Public License -// along with this program. If not, see . +// Copyright Cryptape Technologies LLC. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. extern crate util; diff --git a/cita-auth/src/batch_forward.rs b/cita-auth/src/batch_forward.rs index 890c7f7fe..44ad9d096 100644 --- a/cita-auth/src/batch_forward.rs +++ b/cita-auth/src/batch_forward.rs @@ -1,19 +1,16 @@ -// CITA -// Copyright 2016-2019 Cryptape Technologies LLC. - -// This program is free software: you can redistribute it -// and/or modify it under the terms of the GNU 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 General Public License for more details. - -// You should have received a copy of the GNU General Public License -// along with this program. If not, see . +// Copyright Cryptape Technologies LLC. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. use libproto::router::{MsgType, RoutingKey, SubModules}; use libproto::TryInto; diff --git a/cita-auth/src/block_txn.rs b/cita-auth/src/block_txn.rs index 81185f7b0..0578915fd 100644 --- a/cita-auth/src/block_txn.rs +++ b/cita-auth/src/block_txn.rs @@ -1,19 +1,16 @@ -// CITA -// Copyright 2016-2019 Cryptape Technologies LLC. - -// This program is free software: you can redistribute it -// and/or modify it under the terms of the GNU 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 General Public License for more details. - -// You should have received a copy of the GNU General Public License -// along with this program. If not, see . +// Copyright Cryptape Technologies LLC. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. use crate::handler::verify_tx_sig; use crate::hashable::Hashable; diff --git a/cita-auth/src/block_verify.rs b/cita-auth/src/block_verify.rs index 0a6d1c46a..cc7810a75 100644 --- a/cita-auth/src/block_verify.rs +++ b/cita-auth/src/block_verify.rs @@ -1,20 +1,18 @@ -// CITA -// Copyright 2016-2019 Cryptape Technologies LLC. - -// This program is free software: you can redistribute it -// and/or modify it under the terms of the GNU 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 General Public License for more details. - -// You should have received a copy of the GNU General Public License -// along with this program. If not, see . - +// Copyright Cryptape Technologies LLC. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +use crate::handler::verify_base_quota_required; use cita_types::traits::LowerHex; use cita_types::Address; use crypto::{pubkey_to_address, PubKey}; @@ -52,6 +50,10 @@ impl<'a> BlockVerify<'a> { return false; } + if !verify_base_quota_required(tx.get_transaction_with_sig().get_transaction()) { + return false; + } + if check_quota { let value = account_gas_used.entry(signer).or_insert_with(|| { if let Some(value) = specific_quota_limit.remove(&signer.lower_hex()) { diff --git a/cita-auth/src/config.rs b/cita-auth/src/config.rs index f017e771e..b9c2f4cac 100644 --- a/cita-auth/src/config.rs +++ b/cita-auth/src/config.rs @@ -1,19 +1,16 @@ -// CITA -// Copyright 2016-2019 Cryptape Technologies LLC. - -// This program is free software: you can redistribute it -// and/or modify it under the terms of the GNU 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 General Public License for more details. - -// You should have received a copy of the GNU General Public License -// along with this program. If not, see . +// Copyright Cryptape Technologies LLC. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. #[derive(Debug, PartialEq, Deserialize)] pub struct Config { diff --git a/cita-auth/src/dispatcher.rs b/cita-auth/src/dispatcher.rs index ee22acfe9..fa1de9484 100644 --- a/cita-auth/src/dispatcher.rs +++ b/cita-auth/src/dispatcher.rs @@ -1,19 +1,16 @@ -// CITA -// Copyright 2016-2019 Cryptape Technologies LLC. - -// This program is free software: you can redistribute it -// and/or modify it under the terms of the GNU 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 General Public License for more details. - -// You should have received a copy of the GNU General Public License -// along with this program. If not, see . +// Copyright Cryptape Technologies LLC. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. use crate::handler::SysConfigInfo; use crate::txwal::TxWal; diff --git a/cita-auth/src/handler.rs b/cita-auth/src/handler.rs index 31fbdd398..974e54fd5 100644 --- a/cita-auth/src/handler.rs +++ b/cita-auth/src/handler.rs @@ -1,19 +1,16 @@ -// CITA -// Copyright 2016-2019 Cryptape Technologies LLC. - -// This program is free software: you can redistribute it -// and/or modify it under the terms of the GNU 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 General Public License for more details. - -// You should have received a copy of the GNU General Public License -// along with this program. If not, see . +// Copyright Cryptape Technologies LLC. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. use crate::block_txn::{BlockTxnMessage, BlockTxnReq}; use crate::block_verify::BlockVerify; @@ -26,7 +23,7 @@ use crypto::{pubkey_to_address, PubKey, Sign, Signature, SIGNATURE_BYTES_LEN}; use error::ErrorCode; use jsonrpc_types::rpc_types::TxResponse; use libproto::auth::{Miscellaneous, MiscellaneousReq}; -use libproto::blockchain::{AccountGasLimit, SignedTransaction}; +use libproto::blockchain::{AccountGasLimit, SignedTransaction, Transaction}; use libproto::router::{MsgType, RoutingKey, SubModules}; use libproto::snapshot::{Cmd, Resp, SnapshotReq, SnapshotResp}; use libproto::{ @@ -46,6 +43,12 @@ use std::time::Duration; use util::BLOCKLIMIT; const TX_OK: &str = "OK"; +// Paid for every non-zero byte of data or code for a transaction +const G_TX_DATA_NON_ZERO: usize = 68; +// Paid for every transaction +const G_TRANSACTION: usize = 21000; +// Paid for contract create +const G_CREATE: usize = 32000; // verify signature pub fn verify_tx_sig(crypto: Crypto, hash: &H256, sig_bytes: &[u8]) -> Result, ()> { @@ -183,12 +186,17 @@ impl MsgHandler { true } - // verify to and version + // verify to and version and min quota fn verify_request(&self, req: &Request) -> Result<(), Error> { let un_tx = req.get_un_tx(); let tx = un_tx.get_transaction(); let tx_version = tx.get_version(); if tx_version != self.config_info.version.unwrap() { + info!( + "invalid version: tx_verion-{:?}, chain_version-{:?}", + tx_version, + self.config_info.version.unwrap() + ); return Err(Error::InvalidVersion); } if tx_version == 0 { @@ -215,6 +223,10 @@ impl MsgHandler { return Err(Error::InvalidValue); } + if !verify_base_quota_required(tx) { + return Err(Error::QuotaNotEnough); + } + Ok(()) } @@ -1090,3 +1102,19 @@ fn snapshot_response(sender: &Sender<(String, Vec)>, ack: Resp, flag: bool) )) .unwrap(); } + +// only verify if tx.version > 2 +pub fn verify_base_quota_required(tx: &Transaction) -> bool { + match tx.get_version() { + 0...2 => true, + _ => { + let to = tx.get_to_v1(); + if to.is_empty() || Address::from(to) == Address::zero() { + tx.get_quota() as usize + >= tx.data.len() * G_TX_DATA_NON_ZERO + G_TRANSACTION + G_CREATE + } else { + tx.get_quota() as usize >= tx.data.len() * G_TX_DATA_NON_ZERO + G_TRANSACTION + } + } + } +} diff --git a/cita-auth/src/history.rs b/cita-auth/src/history.rs index 331370d3f..e7bcb9f7d 100644 --- a/cita-auth/src/history.rs +++ b/cita-auth/src/history.rs @@ -1,19 +1,16 @@ -// CITA -// Copyright 2016-2019 Cryptape Technologies LLC. - -// This program is free software: you can redistribute it -// and/or modify it under the terms of the GNU 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 General Public License for more details. - -// You should have received a copy of the GNU General Public License -// along with this program. If not, see . +// Copyright Cryptape Technologies LLC. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. use std::collections::HashSet; use util::instrument::{unix_now, AsMillis}; diff --git a/cita-auth/src/main.rs b/cita-auth/src/main.rs index 5de961cd1..660a9a4d7 100644 --- a/cita-auth/src/main.rs +++ b/cita-auth/src/main.rs @@ -1,19 +1,16 @@ -// CITA -// Copyright 2016-2019 Cryptape Technologies LLC. - -// This program is free software: you can redistribute it -// and/or modify it under the terms of the GNU 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 General Public License for more details. - -// You should have received a copy of the GNU General Public License -// along with this program. If not, see . +// Copyright Cryptape Technologies LLC. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. //! # Summary //! @@ -69,7 +66,6 @@ //! extern crate cita_crypto as crypto; -extern crate core as chain_core; #[macro_use] extern crate libproto; #[macro_use] @@ -83,7 +79,6 @@ extern crate serde_derive; extern crate tempfile; #[macro_use] extern crate util; -extern crate db as cita_db; extern crate hashable; use batch_forward::BatchForward; diff --git a/cita-auth/src/transaction_verify.rs b/cita-auth/src/transaction_verify.rs index 8912c4f1c..6487a3d0b 100644 --- a/cita-auth/src/transaction_verify.rs +++ b/cita-auth/src/transaction_verify.rs @@ -1,19 +1,17 @@ -// CITA -// Copyright 2016-2019 Cryptape Technologies LLC. +// Copyright Cryptape Technologies LLC. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. -// This program is free software: you can redistribute it -// and/or modify it under the terms of the GNU 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 General Public License for more details. - -// You should have received a copy of the GNU General Public License -// along with this program. If not, see . use std::fmt; #[derive(Debug, PartialEq)] diff --git a/cita-auth/src/txwal.rs b/cita-auth/src/txwal.rs index 53248539e..4704a1480 100644 --- a/cita-auth/src/txwal.rs +++ b/cita-auth/src/txwal.rs @@ -1,22 +1,18 @@ -// CITA -// Copyright 2016-2019 Cryptape Technologies LLC. - -// This program is free software: you can redistribute it -// and/or modify it under the terms of the GNU 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 General Public License for more details. - -// You should have received a copy of the GNU General Public License -// along with this program. If not, see . - -use chain_core::db; -use cita_db::kvdb::{Database, DatabaseConfig, KeyValueDB}; +// Copyright Cryptape Technologies LLC. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +use cita_database::{Config, Database, RocksDB, NUM_COLUMNS}; use cita_directories::DataPath; use cita_types::H256; use libproto::blockchain::SignedTransaction; @@ -27,63 +23,71 @@ use std::sync::Arc; /// used to persist transaction pools message #[derive(Clone)] pub struct TxWal { - db: Arc, + db: Arc, } impl TxWal { pub fn new(path: &str) -> Self { let nosql_path = DataPath::root_node_path() + path; - // TODO: Can remove db::NUM_COLUMNS - let config = DatabaseConfig::with_columns(db::NUM_COLUMNS); - let db = Database::open(&config, &nosql_path).unwrap(); + // TODO: Can remove NUM_COLUMNS(useless) + let config = Config::with_category_num(NUM_COLUMNS); + let db = RocksDB::open(&nosql_path, &config).unwrap(); TxWal { db: Arc::new(db) } } pub fn regenerate(&mut self, path: &str) { let nosql_path = DataPath::root_node_path() + path; - let _ = self.db.restore(&nosql_path); + let _ = Arc::get_mut(&mut self.db).unwrap().restore(&nosql_path); } pub fn write(&self, tx: &SignedTransaction) { - let mut batch = self.db.transaction(); + // TODO Fix the block_binary. tx_binary? let block_binary: Vec = tx.try_into().unwrap(); - batch.put_vec(None, tx.get_tx_hash(), block_binary); - self.db.write(batch).expect("insert tx"); + self.db + .insert(None, tx.get_tx_hash().to_vec(), block_binary) + .expect("insert tx"); } pub fn write_batch(&self, txs: &[SignedTransaction]) { - let mut batch = self.db.transaction(); + let mut values: Vec> = Vec::new(); + let mut keys: Vec> = Vec::new(); for tx in txs { let block_binary: Vec = tx.try_into().unwrap(); - batch.put_vec(None, tx.get_tx_hash(), block_binary); + values.push(block_binary); + keys.push(tx.get_tx_hash().to_vec()); } - self.db.write(batch).expect("insert batch txs"); + self.db + .insert_batch(None, keys, values) + .expect("insert batch txs"); } pub fn delete_with_hash(&mut self, tx_hash: &H256) { - let mut batch = self.db.transaction(); - batch.delete(None, tx_hash); - self.db.write(batch).expect("delete with hash"); + self.db.remove(None, tx_hash).expect("delete with hash"); } pub fn delete_with_hashes(&mut self, tx_hashes: &[H256]) { - let mut batch = self.db.transaction(); + let mut keys: Vec> = Vec::new(); for tx_hash in tx_hashes { - batch.delete(None, tx_hash); + keys.push(tx_hash.to_vec()); } - self.db.write(batch).expect("delete with hashes"); + self.db + .remove_batch(None, &keys) + .expect("delete with hashes"); } pub fn read_all(&self) -> Vec { - let items = self.db.iter(None); + // TODO fix the unwrap + let items = self.db.iterator(None).unwrap(); + items .map(|item| SignedTransaction::try_from(item.1.as_ref()).unwrap()) .collect() } pub fn get(&self, tx_hash: &[u8]) -> Option { + // TODO fix the unwrap let result = self.db.get(None, tx_hash).unwrap(); - result.map(|item| SignedTransaction::try_from(item.as_ref()).unwrap()) + result.map(|item| SignedTransaction::try_from(&item).unwrap()) } } @@ -97,8 +101,8 @@ mod tests { fn tx_wal() -> TxWal { let tempdir = TempDir::new("").unwrap().into_path(); - let config = DatabaseConfig::with_columns(None); - let db = Database::open(&config, &tempdir.to_str().unwrap()).unwrap(); + let config = Config::with_category_num(None); + let db = RocksDB::open(&tempdir.to_str().unwrap(), &config).unwrap(); TxWal { db: Arc::new(db) } } diff --git a/cita-bft b/cita-bft index 72cf820cc..0445d8d38 160000 --- a/cita-bft +++ b/cita-bft @@ -1 +1 @@ -Subproject commit 72cf820cc057bf5b3860cdf5e41a1cd6b9030989 +Subproject commit 0445d8d3820d0f9471e3b8b9fe7578e346c63a70 diff --git a/cita-chain/Cargo.toml b/cita-chain/Cargo.toml index 0b1c92a10..f018742c9 100644 --- a/cita-chain/Cargo.toml +++ b/cita-chain/Cargo.toml @@ -3,14 +3,14 @@ description = "CITA node." name = "cita-chain" version = "0.6.0" authors = ["Cryptape Technologies "] +license = "Apache-2.0" edition = "2018" [dependencies] dotenv = "0.13.0" clap = "2" -byteorder = { version = "1", default-features = false } serde_json = "1.0" -cita-logger = "0.1.0" +cita-logger = "0.1.1" cita-types = { git = "https://github.com/cryptape/cita-common.git", branch = "develop" } libproto = { git = "https://github.com/cryptape/cita-common.git", branch = "develop" } pubsub = { git = "https://github.com/cryptape/cita-common.git", branch = "develop" } @@ -21,7 +21,7 @@ jsonrpc-types = { git = "https://github.com/cryptape/cita-common.git", branch = core = { path = "./core" } common-types = { path = "./types" } proof = { git = "https://github.com/cryptape/cita-common.git", branch = "develop" } -db = { git = "https://github.com/cryptape/cita-common.git", branch = "develop" } +cita_db = { git = "https://github.com/cryptape/cita-database.git", branch = "develop", package = "cita-database" } [build-dependencies] util = { git = "https://github.com/cryptape/cita-common.git", branch = "develop" } @@ -31,9 +31,9 @@ default = ["secp256k1", "sha3hash", "rabbitmq"] secp256k1 = ["libproto/secp256k1", "proof/secp256k1"] ed25519 = ["libproto/ed25519", "proof/ed25519"] sm2 = ["libproto/sm2", "proof/sm2"] -sha3hash = ["libproto/sha3hash", "db/sha3hash", "proof/sha3hash"] -blake2bhash = ["libproto/blake2bhash", "db/blake2bhash", "proof/blake2bhash"] -sm3hash = ["libproto/sm3hash", "db/sm3hash", "proof/sm3hash"] +sha3hash = ["libproto/sha3hash", "proof/sha3hash"] +blake2bhash = ["libproto/blake2bhash", "proof/blake2bhash"] +sm3hash = ["libproto/sm3hash", "proof/sm3hash"] rabbitmq = ["pubsub/rabbitmq"] zeromq = ["pubsub/zeromq"] kafka = ["pubsub/kafka"] diff --git a/cita-chain/build.rs b/cita-chain/build.rs index d3ee509ce..03dcbd59d 100644 --- a/cita-chain/build.rs +++ b/cita-chain/build.rs @@ -1,3 +1,17 @@ +// Copyright Cryptape Technologies LLC. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + use std::env; use util::build_info::gen_build_info; diff --git a/cita-chain/core/Cargo.toml b/cita-chain/core/Cargo.toml index ea0f94ef7..970b6fb3a 100644 --- a/cita-chain/core/Cargo.toml +++ b/cita-chain/core/Cargo.toml @@ -1,51 +1,45 @@ [package] name = "core" version = "0.1.0" -authors = ["Cryptape Technologies ", "Parity Technologies "] +authors = ["Cryptape Technologies "] +license = "Apache-2.0" edition = "2018" [dependencies] -byteorder = { version = "1", default-features = false } bincode = "0.8.0" serde = "1.0" serde_derive = "1.0" rustc-hex = "1.0" -lru-cache = "0.1.1" lazy_static = "0.2" -bit-set = "0.4" time = "0.1" crossbeam = "0.2" -transient-hashmap = "0.4.0" -cita-logger = "0.1.0" +cita-logger = "0.1.1" +common-types = { path = "../types" } + libproto = { git = "https://github.com/cryptape/cita-common.git", branch = "develop" } cita-ed25519 = { git = "https://github.com/cryptape/cita-common.git", branch = "develop" } cita-secp256k1 = { git = "https://github.com/cryptape/cita-common.git", branch = "develop" } cita-types = { git = "https://github.com/cryptape/cita-common.git", branch = "develop" } cita-crypto = { git = "https://github.com/cryptape/cita-common.git", branch = "develop" } cita-merklehash = { git = "https://github.com/cryptape/cita-common.git", branch = "develop" } -snappy = { git = "https://github.com/cryptape/cita-common.git", branch = "develop" } hashable = { git = "https://github.com/cryptape/cita-common.git", branch = "develop" } proof = { git = "https://github.com/cryptape/cita-common.git", branch = "develop" } jsonrpc-types = { git = "https://github.com/cryptape/cita-common.git", branch = "develop" } rlp = { git = "https://github.com/cryptape/cita-common.git", branch = "develop" } -rlp_derive = { git = "https://github.com/cryptape/cita-common.git", branch = "develop" } util = { git = "https://github.com/cryptape/cita-common.git", branch = "develop" } -common-types = { path = "../types" } -db = { git = "https://github.com/cryptape/cita-common.git", branch = "develop" } +cita-database = { git = "https://github.com/cryptape/cita-database.git", branch = "develop" } pubsub = { git = "https://github.com/cryptape/cita-common.git", branch = "develop" } [dev-dependencies] rand = "0.3" cpuprofiler = "0.0.3" tempdir = "0.3.7" -cita-logger = "0.1.0" [features] default = ["secp256k1", "sha3hash"] secp256k1 = ["cita-crypto/secp256k1", "libproto/secp256k1", "proof/secp256k1"] ed25519 = ["cita-crypto/ed25519", "libproto/ed25519", "proof/ed25519"] sm2 = ["cita-crypto/sm2", "libproto/sm2", "proof/sm2"] -sha3hash = ["hashable/sha3hash", "db/sha3hash", "libproto/sha3hash", "proof/sha3hash"] -blake2bhash = ["hashable/blake2bhash", "db/blake2bhash", "libproto/blake2bhash", "proof/blake2bhash"] -sm3hash = ["hashable/sm3hash", "db/sm3hash", "libproto/sm3hash", "proof/sm3hash"] -evm-debug= [] +sha3hash = ["hashable/sha3hash", "libproto/sha3hash", "proof/sha3hash"] +blake2bhash = ["hashable/blake2bhash", "libproto/blake2bhash", "proof/blake2bhash"] +sm3hash = ["hashable/sm3hash", "libproto/sm3hash", "proof/sm3hash"] diff --git a/cita-chain/core/README.md b/cita-chain/core/README.md deleted file mode 100644 index db89dfee2..000000000 --- a/cita-chain/core/README.md +++ /dev/null @@ -1,25 +0,0 @@ -# Chain microservice core for CITA - -Files below are extracted from [Parity](https://github.com/paritytech/parity): - -- ./src/cache_manager.rs -- ./src/env_info.rs -- ./src/snapshot/mod.rs -- ./src/snapshot/io.rs -- ./src/snapshot/error.rs -- ./src/snapshot/service.rs -- ./src/db.rs -- ./src/basic_types.rs -- ./src/state/mod.rs -- ./src/state/backend.rs -- ./src/libchain/cache.rs -- ./src/filters/mod.rs -- ./src/filters/poll_manager.rs -- ./src/filters/poll_filter.rs -- ./src/filters/eth_filter.rs -- ./src/state_db.rs - -with following modifications: - -- ./src/error.rs -- ./src/libchain/extras.rs diff --git a/cita-chain/core/src/env_info.rs b/cita-chain/core/src/env_info.rs deleted file mode 100644 index f19178efb..000000000 --- a/cita-chain/core/src/env_info.rs +++ /dev/null @@ -1,71 +0,0 @@ -// Copyright 2015-2017 Parity Technologies (UK) Ltd. -// This file is part of Parity. - -// This software is free software: you can redistribute it and/or modify -// it under the terms of the GNU General Public License as published by -// the Free Software Foundation, either version 3 of the License, or -// (at your option) any later version. - -// This software 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 General Public License for more details. - -// You should have received a copy of the GNU General Public License -// along with Parity. If not, see . - -use crate::header::BlockNumber; -use cita_types::{Address, H256, U256}; -use std::sync::Arc; - -/// Simple vector of hashes, should be at most 256 items large, can be smaller if being used -/// for a block whose number is less than 257. -pub type LastHashes = Vec; - -/// Information concerning the execution environment for a message-call/contract-creation. -#[derive(Debug)] -pub struct EnvInfo { - /// The block number. - pub number: BlockNumber, - /// The block author. - pub author: Address, - /// The block timestamp. - pub timestamp: u64, - /// The block difficulty. - pub difficulty: U256, - /// The block gas limit. - pub quota_limit: U256, - /// The last 256 block hashes. - pub last_hashes: Arc, - /// The quota used. - pub quota_used: U256, - /// The account quota limit - pub account_quota_limit: U256, -} - -impl Default for EnvInfo { - fn default() -> Self { - EnvInfo { - number: 0, - author: Address::default(), - timestamp: 0, - difficulty: 0.into(), - quota_limit: U256::from(u64::max_value()), - last_hashes: Arc::new(vec![]), - quota_used: 0.into(), - account_quota_limit: 0.into(), - } - } -} - -#[cfg(test)] -mod tests { - use super::*; - - #[test] - fn it_can_be_created_as_default() { - let default_env_info = EnvInfo::default(); - - assert_eq!(default_env_info.difficulty, 0.into()); - } -} diff --git a/cita-chain/core/src/error.rs b/cita-chain/core/src/error.rs deleted file mode 100644 index 541889999..000000000 --- a/cita-chain/core/src/error.rs +++ /dev/null @@ -1,439 +0,0 @@ -// Copyright 2015-2017 Parity Technologies (UK) Ltd. -// This file is part of Parity. - -// This software is free software: you can redistribute it and/or modify -// it under the terms of the GNU General Public License as published by -// the Free Software Foundation, either version 3 of the License, or -// (at your option) any later version. - -// This software 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 General Public License for more details. - -// You should have received a copy of the GNU General Public License -// along with Parity. If not, see . - -//! General error types for use in ethcore. - -use crate::basic_types::LogBloom; -use cita_ed25519::Error as EthkeyError; - -use crate::cita_db::TrieError; -use crate::header::BlockNumber; -use crate::snapshot::error::Error as SnapshotError; -use cita_types::{H256, U256, U512}; -use snappy; -use std::fmt; -use util::*; - -#[derive(Debug, PartialEq, Clone, Copy)] -/// Errors concerning transaction processing. -pub enum TransactionError { - /// Transaction is already imported to the queue - AlreadyImported, - /// Transaction is not valid anymore (state already has higher nonce) - Old, - /// Transaction has too low fee - /// (there is already a transaction with the same sender-nonce but higher gas price) - TooCheapToReplace, - /// Transaction was not imported to the queue because limit has been reached. - LimitReached, - /// Transaction's gas price is below threshold. - InsufficientGasPrice { - /// Minimal expected gas price - minimal: U256, - /// Transaction gas price - got: U256, - }, - /// Transaction's gas is below currently set minimal gas requirement. - InsufficientGas { - /// Minimal expected gas - minimal: U256, - /// Transaction gas - got: U256, - }, - /// Sender doesn't have enough funds to pay for this transaction - InsufficientBalance { - /// Senders balance - balance: U256, - /// Transaction cost - cost: U256, - }, - /// Transactions gas is higher then current gas limit - GasLimitExceeded { - /// Current gas limit - limit: U256, - /// Declared transaction gas - got: U256, - }, - /// Transaction's gas limit (aka gas) is invalid. - InvalidGasLimit(OutOfBounds), - /// Transaction sender is banned. - SenderBanned, - /// Transaction receipient is banned. - RecipientBanned, - /// Contract creation code is banned. - CodeBanned, - /// Invalid network ID given. - InvalidNetworkId, -} - -impl fmt::Display for TransactionError { - fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { - use self::TransactionError::*; - let msg = match *self { - AlreadyImported => "Already imported".into(), - Old => "No longer valid".into(), - TooCheapToReplace => "Gas price too low to replace".into(), - LimitReached => "Transaction limit reached".into(), - InsufficientGasPrice { minimal, got } => { - format!("Insufficient gas price. Min={}, Given={}", minimal, got) - } - InsufficientGas { minimal, got } => { - format!("Insufficient gas. Min={}, Given={}", minimal, got) - } - InsufficientBalance { balance, cost } => format!( - "Insufficient balance for transaction. Balance={}, Cost={}", - balance, cost - ), - GasLimitExceeded { limit, got } => { - format!("Gas limit exceeded. Limit={}, Given={}", limit, got) - } - InvalidGasLimit(ref err) => format!("Invalid gas limit. {}", err), - SenderBanned => "Sender is temporarily banned.".into(), - RecipientBanned => "Recipient is temporarily banned.".into(), - CodeBanned => "Contract code is temporarily banned.".into(), - InvalidNetworkId => { - "Transaction of this network ID is not allowed on this chain.".into() - } - }; - - f.write_fmt(format_args!("Transaction error ({})", msg)) - } -} - -#[allow(unknown_lints, clippy::large_enum_variant)] // TODO clippy -#[derive(Debug, PartialEq, Clone, Copy, Eq)] -/// Errors concerning block processing. -pub enum BlockError { - /// Extra data is of an invalid length. - ExtraDataOutOfBounds(OutOfBounds), - /// Seal is incorrect format. - InvalidSealArity(Mismatch), - /// Block has too much gas used. - TooMuchGasUsed(OutOfBounds), - /// State root header field is invalid. - InvalidStateRoot(Mismatch), - /// Gas used header field is invalid. - InvalidGasUsed(Mismatch), - /// Transactions root header field is invalid. - InvalidTransactionsRoot(Mismatch), - /// Difficulty is out of range; this can be used as an looser error prior to getting a definitive - /// value for difficulty. This error needs only provide bounds of which it is out. - DifficultyOutOfBounds(OutOfBounds), - /// Difficulty header field is invalid; this is a strong error used after getting a definitive - /// value for difficulty (which is provided). - InvalidDifficulty(Mismatch), - /// Seal element of type H256 (max_hash for Ethash, but could be something else for - /// other seal engines) is out of bounds. - MismatchedH256SealElement(Mismatch), - /// Proof-of-work aspect of seal, which we assume is a 256-bit value, is invalid. - InvalidProofOfWork(OutOfBounds), - /// Some low-level aspect of the seal is incorrect. - InvalidSeal, - /// Gas limit header field is invalid. - InvalidGasLimit(OutOfBounds), - /// Receipts trie root header field is invalid. - InvalidReceiptsRoot(Mismatch), - /// Timestamp header field is invalid. - InvalidTimestamp(OutOfBounds), - /// Log bloom header field is invalid. - InvalidLogBloom(Mismatch), - /// Parent hash field of header is invalid; this is an invalid error indicating a logic flaw in the codebase. - /// TODO: remove and favour an assert!/panic!. - InvalidParentHash(Mismatch), - /// Number field of header is invalid. - InvalidNumber(Mismatch), - /// Block number isn't sensible. - RidiculousNumber(OutOfBounds), - /// Parent given is unknown. - UnknownParent(H256), -} - -impl fmt::Display for BlockError { - fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { - use self::BlockError::*; - - let msg = match *self { - ExtraDataOutOfBounds(ref oob) => format!("Extra block data too long. {}", oob), - InvalidSealArity(ref mis) => format!("Block seal in incorrect format: {}", mis), - TooMuchGasUsed(ref oob) => format!("Block has too much gas used. {}", oob), - InvalidStateRoot(ref mis) => format!("Invalid state root in header: {}", mis), - InvalidGasUsed(ref mis) => format!("Invalid gas used in header: {}", mis), - InvalidTransactionsRoot(ref mis) => { - format!("Invalid transactions root in header: {}", mis) - } - DifficultyOutOfBounds(ref oob) => format!("Invalid block difficulty: {}", oob), - InvalidDifficulty(ref mis) => format!("Invalid block difficulty: {}", mis), - MismatchedH256SealElement(ref mis) => format!("Seal element out of bounds: {}", mis), - InvalidProofOfWork(ref oob) => format!("Block has invalid PoW: {}", oob), - InvalidSeal => "Block has invalid seal.".into(), - InvalidGasLimit(ref oob) => format!("Invalid gas limit: {}", oob), - InvalidReceiptsRoot(ref mis) => { - format!("Invalid receipts trie root in header: {}", mis) - } - InvalidTimestamp(ref oob) => format!("Invalid timestamp in header: {}", oob), - InvalidLogBloom(ref oob) => format!("Invalid log bloom in header: {}", oob), - InvalidParentHash(ref mis) => format!("Invalid parent hash: {}", mis), - InvalidNumber(ref mis) => format!("Invalid number in header: {}", mis), - RidiculousNumber(ref oob) => format!("Implausible block number. {}", oob), - UnknownParent(ref hash) => format!("Unknown parent: {}", hash), - }; - - f.write_fmt(format_args!("Block error ({})", msg)) - } -} - -#[derive(Debug, Clone, Copy, PartialEq)] -/// Import to the block queue result -pub enum ImportError { - /// Already in the block chain. - AlreadyInChain, - /// Already in the block queue. - AlreadyQueued, - /// Already marked as bad from a previous import (could mean parent is bad). - KnownBad, -} - -impl fmt::Display for ImportError { - fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { - let msg = match *self { - ImportError::AlreadyInChain => "block already in chain", - ImportError::AlreadyQueued => "block already in the block queue", - ImportError::KnownBad => "block known to be bad", - }; - - f.write_fmt(format_args!("Block import error ({})", msg)) - } -} - -/// Result of executing the transaction. -#[derive(PartialEq, Debug, Clone)] -#[cfg_attr(feature = "ipc", binary)] -pub enum ExecutionError { - /// Returned when there gas paid for transaction execution is - /// lower than base gas required. - NotEnoughBaseGas { - /// Absolute minimum gas required. - required: U256, - /// Gas provided. - got: U256, - }, - /// Returned when block (quota_used + gas) > quota_limit. - /// - /// If gas =< quota_limit, upstream may try to execute the transaction - /// in next block. - BlockGasLimitReached { - /// Gas limit of block for transaction. - quota_limit: U256, - /// Gas used in block prior to transaction. - quota_used: U256, - /// Amount of gas in block. - gas: U256, - }, - AccountGasLimitReached { - /// Account Gas limit left - quota_limit: U256, - /// Amount of gas in transaction - gas: U256, - }, - /// Returned when transaction nonce does not match state nonce. - InvalidNonce { - /// Nonce expected. - expected: U256, - /// Nonce found. - got: U256, - }, - /// Returned when cost of transaction (value + gas_price * gas) exceeds - /// current sender balance. - NotEnoughCash { - /// Minimum required balance. - required: U512, - /// Actual balance. - got: U512, - }, - NoTransactionPermission, - NoContractPermission, - NoCallPermission, - /// Returned when internal evm error occurs. - ExecutionInternal(String), - /// Returned when generic transaction occurs - TransactionMalformed(String), -} - -impl fmt::Display for ExecutionError { - fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { - use self::ExecutionError::*; - - let msg = match *self { - NotEnoughBaseGas { ref required, ref got } => format!("Not enough base quota. {} is required, but only {} paid", required, got), - BlockGasLimitReached { - ref quota_limit, - ref quota_used, - ref gas, - } => format!("Block gas limit reached. The limit is {}, {} has already been used, and {} more is required", quota_limit, quota_used, gas), - AccountGasLimitReached { ref quota_limit, ref gas } => format!("Account gas limit reached. The limit is {}, {} more is required", quota_limit, gas), - InvalidNonce { ref expected, ref got } => format!("Invalid transaction nonce: expected {}, found {}", expected, got), - NotEnoughCash { ref required, ref got } => format!("Cost of transaction exceeds sender balance. {} is required but the sender only has {}", required, got), - ExecutionInternal(ref msg) => msg.clone(), - TransactionMalformed(ref err) => format!("Malformed transaction: {}", err), - NoTransactionPermission => "No transaction permission".to_owned(), - NoContractPermission => "No contract permission".to_owned(), - NoCallPermission => "No call contract permission".to_owned(), - }; - - f.write_fmt(format_args!("Transaction execution error ({}).", msg)) - } -} - -#[allow(unknown_lints, clippy::large_enum_variant)] // TODO clippy -#[derive(Debug)] -/// General error type which should be capable of representing all errors in ethcore. -pub enum Error { - /// Error concerning a utility. - Util(UtilError), - /// Error concerning block processing. - Block(BlockError), - /// Unknown engine given. - UnknownEngineName(String), - /// Error concerning EVM code execution. - Execution(ExecutionError), - /// Error concerning transaction processing. - Transaction(TransactionError), - /// Error concerning block import. - Import(ImportError), - /// PoW hash is invalid or out of date. - PowHashInvalid, - /// The value of the nonce or mishash is invalid. - PowInvalid, - /// Error concerning TrieDBs - Trie(TrieError), - /// Standard io error. - StdIo(::std::io::Error), - /// Snappy error. - Snappy(snappy::SnappyError), - /// Ethkey error. - Ethkey(EthkeyError), - /// Snapshot error - Snapshot(SnapshotError), -} - -impl fmt::Display for Error { - fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { - match *self { - Error::Util(ref err) => err.fmt(f), - Error::Block(ref err) => err.fmt(f), - Error::Execution(ref err) => err.fmt(f), - Error::Transaction(ref err) => err.fmt(f), - Error::Import(ref err) => err.fmt(f), - Error::UnknownEngineName(ref name) => { - f.write_fmt(format_args!("Unknown engine name ({})", name)) - } - Error::PowHashInvalid => f.write_str("Invalid or out of date PoW hash."), - Error::PowInvalid => f.write_str("Invalid nonce or mishash"), - Error::Trie(ref err) => err.fmt(f), - Error::StdIo(ref err) => err.fmt(f), - Error::Snappy(ref err) => err.fmt(f), - Error::Ethkey(ref err) => err.fmt(f), - Error::Snapshot(ref err) => err.fmt(f), - } - } -} - -/// Result of import block operation. -pub type ImportResult = Result; - -impl From for Error { - fn from(err: TransactionError) -> Error { - Error::Transaction(err) - } -} - -impl From for Error { - fn from(err: ImportError) -> Error { - Error::Import(err) - } -} - -impl From for Error { - fn from(err: BlockError) -> Error { - Error::Block(err) - } -} - -impl From for Error { - fn from(err: ExecutionError) -> Error { - Error::Execution(err) - } -} - -impl From<::rlp::DecoderError> for Error { - fn from(err: ::rlp::DecoderError) -> Error { - Error::Util(UtilError::Decoder(err)) - } -} - -impl From for Error { - fn from(err: UtilError) -> Error { - Error::Util(err) - } -} - -impl From for Error { - fn from(err: TrieError) -> Error { - Error::Trie(err) - } -} - -impl From<::std::io::Error> for Error { - fn from(err: ::std::io::Error) -> Error { - Error::StdIo(err) - } -} - -impl From for Error { - fn from(err: snappy::SnappyError) -> Error { - Error::Snappy(err) - } -} - -impl From for Error { - fn from(err: EthkeyError) -> Error { - Error::Ethkey(err) - } -} - -impl From for Error { - fn from(err: SnapshotError) -> Error { - match err { - SnapshotError::Trie(err) => err.into(), - SnapshotError::Decoder(err) => err.into(), - other => Error::Snapshot(other), - } - } -} - -// TODO: uncomment below once https://github.com/rust-lang/rust/issues/27336 sorted. -/*#![feature(concat_idents)] -macro_rules! assimilate { - ($name:ident) => ( - impl From for Error { - fn from(err: concat_idents!($name, Error)) -> Error { - Error:: $name (err) - } - } - ) -} -assimilate!(FromHex); -assimilate!(BaseData);*/ diff --git a/cita-chain/core/src/filters/eth_filter.rs b/cita-chain/core/src/filters/eth_filter.rs deleted file mode 100644 index 68bdc04b1..000000000 --- a/cita-chain/core/src/filters/eth_filter.rs +++ /dev/null @@ -1,121 +0,0 @@ -// Copyright 2015-2017 Parity Technologies (UK) Ltd. -// This file is part of Parity. - -// This software is free software: you can redistribute it and/or modify -// it under the terms of the GNU General Public License as published by -// the Free Software Foundation, either version 3 of the License, or -// (at your option) any later version. - -// This software 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 General Public License for more details. - -// You should have received a copy of the GNU General Public License -// along with Parity. If not, see . - -use super::{limit_logs, PollFilter, PollId}; -use crate::libchain::chain::Chain; -use crate::types::filter::Filter as EthcoreFilter; -use crate::types::ids::BlockId; -use cita_types::H256; -use jsonrpc_types::rpc_types::{Filter, FilterChanges, Log}; - -pub trait EthFilter { - fn new_filter(&self, filter: Filter) -> PollId; - fn new_block_filter(&self) -> PollId; - fn filter_changes(&self, index: usize) -> Option; - fn filter_logs(&self, index: usize) -> Option>; - fn uninstall_filter(&self, index: usize) -> bool; -} - -impl EthFilter for Chain { - fn new_filter(&self, filter: Filter) -> PollId { - let polls = self.poll_filter(); - let block_number = self.get_current_height(); - let id = - polls - .lock() - .create_poll(PollFilter::Logs(block_number, Default::default(), filter)); - drop(polls); - id - } - - fn new_block_filter(&self) -> PollId { - let polls = self.poll_filter(); - let id = polls - .lock() - .create_poll(PollFilter::Block(self.get_current_height())); - drop(polls); - id - } - - fn filter_changes(&self, index: usize) -> Option { - let polls = self.poll_filter(); - let log = match polls.lock().poll_mut(index) { - None => Some(FilterChanges::Empty), - Some(filter) => match *filter { - PollFilter::Block(ref mut block_number) => { - // + 1, cause we want to return hashes including current block hash. - let current_number = self.get_current_height() + 1; - // + 1, cause we want to return hashes from next block after a block filter was created. - let hashes = ((*block_number + 1)..current_number) - .filter_map(|_id| self.block_hash_by_height(_id)) - .collect::>(); - - *block_number = current_number; - Some(FilterChanges::Hashes( - hashes.into_iter().map(Into::into).collect(), - )) - } - PollFilter::Logs(ref mut block_number, ref mut _previous_logs, ref filter) => { - // retrive the current block number - let current_number = self.get_current_height(); - // build appropriate filter - let mut filter: EthcoreFilter = filter.clone().into(); - filter.from_block = BlockId::Number(*block_number); - filter.to_block = BlockId::Latest; - // save the number of the next block as a first block from which - // we want to get logs - *block_number = current_number + 1; - // retrieve logs in range from_block..min(BlockId::Latest..to_block) - let limit = filter.limit; - Some(FilterChanges::Logs(limit_logs( - self.get_logs(&filter).into_iter().map(Into::into).collect(), - limit, - ))) - } - }, - }; - drop(polls); - log - } - - fn filter_logs(&self, index: usize) -> Option> { - let polls = self.poll_filter(); - let log = match polls.lock().poll(index) { - Some(&PollFilter::Logs(ref _block_number, ref _previous_log, ref filter)) => { - let filter: EthcoreFilter = filter.clone().into(); - Some(self.get_logs(&filter).into_iter().map(Into::into).collect()) - } - // just empty array - _ => None, - }; - drop(polls); - log - } - - fn uninstall_filter(&self, index: usize) -> bool { - let polls = self.poll_filter(); - let mut polls = polls.lock(); - let is_uninstall = match polls.poll(index) { - Some(_) => { - polls.remove_poll(index); - true - } - None => false, - }; - drop(polls); - is_uninstall - } -} diff --git a/cita-chain/core/src/filters/filterdb.rs b/cita-chain/core/src/filters/filterdb.rs new file mode 100644 index 000000000..3a22d1f14 --- /dev/null +++ b/cita-chain/core/src/filters/filterdb.rs @@ -0,0 +1,263 @@ +// CopyrightTechnologies LLC. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +use jsonrpc_types::rpc_types::Filter; +use std::collections::HashMap; +use std::time::SystemTime; + +// TODO Refactor: +// * use generic data type +// * use one hashmap: use tuple type +// +// ```rust +// struct FilterData { +// data: HashMap, +// } +// ``` +#[derive(Default)] +pub struct BlockFilter { + /// To save the filter for filter_blocks + data: HashMap, +} + +impl BlockFilter { + fn is_filter(&self, id: usize) -> bool { + self.data.contains_key(&id) + } + + fn insert(&mut self, id: usize, filter: u64) { + self.data.insert(id, filter); + } + + fn remove(&mut self, id: usize) { + self.data.remove(&id); + } + + fn get(&self, id: usize) -> Option<&u64> { + self.data.get(&id) + } +} + +#[derive(Default)] +pub struct LogsFilter { + /// To save the filter for filter_logs + data: HashMap, +} + +impl LogsFilter { + fn is_filter(&self, id: usize) -> bool { + self.data.contains_key(&id) + } + + fn insert(&mut self, id: usize, filter: Filter) { + self.data.insert(id, filter); + } + + fn remove(&mut self, id: usize) { + self.data.remove(&id); + } + + fn get(&self, id: usize) -> Option<&Filter> { + self.data.get(&id) + } +} + +#[derive(Default)] +pub struct FilterDB { + /// Self-increase ID. + next_available_id: usize, + /// To save the last update timestamp + last_update: HashMap, + /// Refactor: Note: logs filter includes block filter. + block_filter: BlockFilter, + logs_filter: LogsFilter, + /// lifetime of fileter id + lifetime: u32, +} + +impl FilterDB { + pub fn new() -> Self { + FilterDB { + // Set the lifetime: 60s + lifetime: 60, + ..Default::default() + } + } + + #[cfg(test)] + pub fn set_lifetime(&mut self, lifetime: u32) { + self.lifetime = lifetime; + } + + /// Generate a new fresh id + /// Prune the hashmap first. + pub fn gen_id(&mut self) -> usize { + self.prune(); + let id = self.next_available_id; + self.next_available_id = self.next_available_id.wrapping_add(1); + id + } + + /// Generate a new normal filter + pub fn gen_logs_filter(&mut self, id: usize, filter: Filter) { + let now = now(); + self.last_update.insert(id, now); + self.logs_filter.insert(id, filter); + } + + /// Generate a new filter for block + pub fn gen_block_filter(&mut self, id: usize, filter: u64) { + let now = now(); + self.last_update.insert(id, now); + self.block_filter.insert(id, filter); + } + + /// Uninstall the filter id + pub fn uninstall(&mut self, id: usize) -> bool { + self.prune(); + // Logs filter includes the block filter. + // Remove block filter if is filter. + if self.is_filter(id) { + self.block_filter.remove(id); + if self.is_logs_filter(id) { + self.logs_filter.remove(id); + } + + true + } else { + false + } + } + + /// Prune the overdue id manually + /// Remove all the ids that: (now-lastupdate) > self.lifetime + pub fn prune(&mut self) { + let now = now(); + for (id, time) in self.last_update.clone().iter() { + if (now - *time) >= self.lifetime.into() { + trace!("Prune filter, time: {:?}", (now - *time)); + self.block_filter.remove(*id); + self.logs_filter.remove(*id); + } + } + } + + /// Get the filter for logs. + /// Prune the hashmap first. + pub fn get_logs_filter(&mut self, id: usize) -> Option<&Filter> { + let now = now(); + trace!("Get logs filter: {:?}", self.logs_filter.get(id)); + self.prune(); + self.last_update.insert(id, now); + self.logs_filter.get(id) + } + + /// Get the filter for block + /// Prune the hashmap first. + pub fn get_block_filter(&mut self, id: usize) -> Option<&u64> { + let now = now(); + trace!("Get block filter: {:?}", self.block_filter.get(id)); + self.prune(); + self.last_update.insert(id, now); + self.block_filter.get(id) + } + + /// Check the id is for block filter: + /// Check the log, too. cause the logs filter also insert block filter. + pub fn is_block_filter(&self, id: usize) -> bool { + self.block_filter.is_filter(id) && !self.logs_filter.is_filter(id) + } + + /// Check the id is for logs + pub fn is_logs_filter(&self, id: usize) -> bool { + self.logs_filter.is_filter(id) + } + + /// Check the id is block filter or logs filter + pub fn is_filter(&self, id: usize) -> bool { + self.logs_filter.is_filter(id) || self.block_filter.is_filter(id) + } +} + +/// Generate the now time +fn now() -> u64 { + SystemTime::now() + .duration_since(SystemTime::UNIX_EPOCH) + .unwrap() + .as_secs() +} + +#[cfg(test)] +mod tests { + use super::FilterDB; + use jsonrpc_types::rpc_types::BlockNumber; + use jsonrpc_types::rpc_types::Filter; + + #[test] + fn test_gen_id() { + let mut filterdb = FilterDB::new(); + let id = filterdb.next_available_id; + filterdb.gen_id(); + assert_eq!(filterdb.next_available_id, id + 1); + } + + #[test] + fn test_gen_logs_filter_and_uninstall() { + let mut filterdb = FilterDB::new(); + let id = filterdb.gen_id(); + let filter = Filter::new(BlockNumber::earliest(), BlockNumber::earliest(), None, None); + assert_eq!(filterdb.is_logs_filter(id), false); + assert_eq!(filterdb.get_logs_filter(id), None); + // Gen logs filter + filterdb.gen_logs_filter(id, filter.clone()); + assert_eq!(filterdb.is_logs_filter(id), true); + assert_eq!(*filterdb.get_logs_filter(id).unwrap(), filter); + // Uninstall + filterdb.uninstall(id); + assert_eq!(filterdb.is_block_filter(id), false); + assert_eq!(filterdb.get_block_filter(id), None); + } + + #[test] + fn test_gen_block_filter_and_uninstall() { + let mut filterdb = FilterDB::new(); + let id = filterdb.gen_id(); + let filter = 0; + assert_eq!(filterdb.is_block_filter(id), false); + assert_eq!(filterdb.get_block_filter(id), None); + // Gen block filter + filterdb.gen_block_filter(id, filter.clone()); + assert_eq!(filterdb.is_block_filter(id), true); + assert_eq!(*filterdb.get_block_filter(id).unwrap(), filter); + // Uninstall + filterdb.uninstall(id); + assert_eq!(filterdb.is_block_filter(id), false); + assert_eq!(filterdb.get_block_filter(id), None); + } + + #[test] + fn test_prune() { + let mut filterdb = FilterDB::new(); + let id = filterdb.gen_id(); + let filter = 0; + filterdb.gen_block_filter(id, filter.clone()); + assert_eq!(filterdb.is_filter(id), true); + assert_eq!(*filterdb.get_block_filter(id).unwrap(), filter); + filterdb.set_lifetime(0); + assert_eq!(filterdb.lifetime, 0); + filterdb.prune(); + assert_eq!(filterdb.get_block_filter(id), None); + assert_eq!(filterdb.is_filter(id), false); + } +} diff --git a/cita-chain/core/src/filters/mod.rs b/cita-chain/core/src/filters/mod.rs index 01ac9516a..bfeac217b 100644 --- a/cita-chain/core/src/filters/mod.rs +++ b/cita-chain/core/src/filters/mod.rs @@ -1,22 +1,16 @@ -// Copyright 2015-2017 Parity Technologies (UK) Ltd. -// This file is part of Parity. +// Copyright Cryptape Technologies LLC. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. -// This software is free software: you can redistribute it and/or modify -// it under the terms of the GNU General Public License as published by -// the Free Software Foundation, either version 3 of the License, or -// (at your option) any later version. - -// This software 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 General Public License for more details. - -// You should have received a copy of the GNU General Public License -// along with Parity. If not, see . - -pub mod eth_filter; -pub mod poll_filter; -pub mod poll_manager; - -pub use self::poll_filter::{limit_logs, PollFilter}; -pub use self::poll_manager::{PollId, PollManager}; +pub mod filterdb; +pub mod rpc_filter; diff --git a/cita-chain/core/src/filters/poll_filter.rs b/cita-chain/core/src/filters/poll_filter.rs deleted file mode 100644 index be8e0d3bd..000000000 --- a/cita-chain/core/src/filters/poll_filter.rs +++ /dev/null @@ -1,39 +0,0 @@ -// Copyright 2015-2017 Parity Technologies (UK) Ltd. -// This file is part of Parity. - -// This software is free software: you can redistribute it and/or modify -// it under the terms of the GNU General Public License as published by -// the Free Software Foundation, either version 3 of the License, or -// (at your option) any later version. - -// This software 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 General Public License for more details. - -// You should have received a copy of the GNU General Public License -// along with Parity. If not, see . - -//! Helper type with all filter state data. - -use jsonrpc_types::rpc_types::{Filter, Log}; -use std::collections::HashSet; -pub type BlockNumber = u64; - -/// Filter state. -#[derive(Clone)] -pub enum PollFilter { - /// Number of last block which client was notified about. - Block(BlockNumber), - /// Number of From block number, pending logs and log filter itself. - Logs(BlockNumber, HashSet, Filter), -} - -/// Returns only last `n` logs -pub fn limit_logs(mut logs: Vec, limit: Option) -> Vec { - let len = logs.len(); - match limit { - Some(limit) if len >= limit => logs.split_off(len - limit), - _ => logs, - } -} diff --git a/cita-chain/core/src/filters/poll_manager.rs b/cita-chain/core/src/filters/poll_manager.rs deleted file mode 100644 index 95e25fa33..000000000 --- a/cita-chain/core/src/filters/poll_manager.rs +++ /dev/null @@ -1,129 +0,0 @@ -// Copyright 2015-2017 Parity Technologies (UK) Ltd. -// This file is part of Parity. - -// This software is free software: you can redistribute it and/or modify -// it under the terms of the GNU General Public License as published by -// the Free Software Foundation, either version 3 of the License, or -// (at your option) any later version. - -// This software 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 General Public License for more details. - -// You should have received a copy of the GNU General Public License -// along with Parity. If not, see . - -//! Indexes all rpc poll requests. - -use transient_hashmap::{StandardTimer, Timer, TransientHashMap}; - -/// Lifetime of poll (in seconds). -const POLL_LIFETIME: u32 = 60; - -pub type PollId = usize; - -/// Indexes all poll requests. -/// -/// Lazily garbage collects unused polls info. -pub struct PollManager -where - T: Timer, -{ - polls: TransientHashMap, - next_available_id: PollId, -} - -impl PollManager { - /// Creates new instance of indexer. - pub fn default() -> Self { - PollManager::new_with_timer(Default::default()) - } -} - -impl PollManager -where - T: Timer, -{ - pub fn new_with_timer(timer: T) -> Self { - PollManager { - polls: TransientHashMap::new_with_timer(POLL_LIFETIME, timer), - next_available_id: 0, - } - } - - /// Returns id which can be used for new poll. - /// - /// Stores information when last poll happend. - pub fn create_poll(&mut self, filter: F) -> PollId { - self.polls.prune(); - - let id = self.next_available_id; - self.polls.insert(id, filter); - - self.next_available_id += 1; - id - } - - // Implementation is always using `poll_mut` - /// Get a reference to stored poll filter - pub fn poll(&mut self, id: PollId) -> Option<&F> { - self.polls.prune(); - self.polls.get(&id) - } - - /// Get a mutable reference to stored poll filter - pub fn poll_mut(&mut self, id: PollId) -> Option<&mut F> { - self.polls.prune(); - self.polls.get_mut(&id) - } - - /// Removes poll info. - pub fn remove_poll(&mut self, id: PollId) { - self.polls.remove(&id); - } -} - -#[cfg(test)] -mod tests { - use super::*; - use std::cell::Cell; - use transient_hashmap::Timer; - - struct TestTimer<'a> { - time: &'a Cell, - } - - impl<'a> Timer for TestTimer<'a> { - fn get_time(&self) -> i64 { - self.time.get() - } - } - - #[test] - fn test_poll_indexer() { - let time = Cell::new(0); - let timer = TestTimer { time: &time }; - - let mut indexer = PollManager::new_with_timer(timer); - assert_eq!(indexer.create_poll(20), 0); - assert_eq!(indexer.create_poll(20), 1); - - time.set(10); - *indexer.poll_mut(0).unwrap() = 21; - assert_eq!(*indexer.poll(0).unwrap(), 21); - assert_eq!(*indexer.poll(1).unwrap(), 20); - - time.set(30); - *indexer.poll_mut(1).unwrap() = 23; - assert_eq!(*indexer.poll(1).unwrap(), 23); - - time.set(75); - assert!(indexer.poll(0).is_none()); - assert_eq!(*indexer.poll(1).unwrap(), 23); - - indexer.remove_poll(1); - assert!(indexer.poll(1).is_none()); - } - -} diff --git a/cita-chain/core/src/filters/rpc_filter.rs b/cita-chain/core/src/filters/rpc_filter.rs new file mode 100644 index 000000000..98284ff4b --- /dev/null +++ b/cita-chain/core/src/filters/rpc_filter.rs @@ -0,0 +1,172 @@ +// Copyrighttape Technologies LLC. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +use crate::libchain::chain::Chain; +use crate::types::block_number::{BlockNumber, BlockTag, Tag}; +use crate::types::filter::Filter as FilterType; +use cita_types::H256; +use jsonrpc_types::rpc_types::{Filter, FilterChanges, Log}; + +/// The RPC interfaces about filter. +/// * newFilter +/// * newBlockFilter +/// * getFilterChanges +/// * getFilterLogs +/// * uninstallFilter +/// *Not include `getLogs`*. +pub trait RpcFilter { + // Create a new filter and return the filter id + // https://docs.citahub.com/zh-CN/cita/rpc-guide/rpc#newfilter + fn new_filter(&self, filter: Filter) -> usize; + // Create a new filter that can listen the new block. + // https://docs.citahub.com/zh-CN/cita/rpc-guide/rpc#newblockfilter + fn new_block_filter(&self) -> usize; + // Get the logs for the filter with the given id since last time it was called. + // https://docs.citahub.com/zh-CN/cita/rpc-guide/rpc#getfilterchanges + fn get_filter_changes(&self, id: usize) -> Option; + // Get the logs for the filter with the given id. + // https://docs.citahub.com/zh-CN/cita/rpc-guide/rpc#getfilterlogs + fn get_filter_logs(&self, id: usize) -> Option>; + // Remove the filter with the given id. + // https://docs.citahub.com/zh-CN/cita/rpc-guide/rpc#uninstallfilter + fn uninstall_filter(&self, id: usize) -> bool; +} + +/// Helper for RpcFilter +trait FilterHelper { + // Get the block filter with the given id + fn get_block_filter(&self, id: usize) -> BlockNumber; + // Get logs with given filter + fn get_logs_with_filter(&self, filter: Filter, block_filter: BlockNumber) -> Vec; +} + +impl FilterHelper for Chain { + fn get_block_filter(&self, id: usize) -> BlockNumber { + let filterdb = self.filter_db(); + let mut block_filter = BlockNumber::min_value(); + + if let Some(block_number) = filterdb.try_lock().unwrap().get_block_filter(id) { + block_filter = *block_number; + } + + drop(filterdb); + block_filter + } + + fn get_logs_with_filter(&self, filter: Filter, block_filter: BlockNumber) -> Vec { + let mut filter: FilterType = filter.into(); + filter.from_block = BlockTag::Height(block_filter); + filter.to_block = BlockTag::Tag(Tag::Latest); + let limit = filter.limit; + split_logs( + self.get_logs(&filter).into_iter().map(Into::into).collect(), + limit, + ) + } +} + +impl RpcFilter for Chain { + fn new_filter(&self, filter: Filter) -> usize { + let filterdb = self.filter_db(); + let id = filterdb.try_lock().unwrap().gen_id(); + let block_number = self.get_current_height(); + filterdb.try_lock().unwrap().gen_logs_filter(id, filter); + filterdb + .try_lock() + .unwrap() + .gen_block_filter(id, block_number); + drop(filterdb); + id + } + + fn new_block_filter(&self) -> usize { + let filterdb = self.filter_db(); + let block_number = self.get_current_height(); + let id = filterdb.try_lock().unwrap().gen_id(); + filterdb + .try_lock() + .unwrap() + .gen_block_filter(id, block_number); + drop(filterdb); + id + } + + fn get_filter_changes(&self, id: usize) -> Option { + let filterdb = self.filter_db(); + let mut changes = Some(FilterChanges::Empty); + let current_number = self.get_current_height(); + let block_filter = self.get_block_filter(id); + + if !filterdb.try_lock().unwrap().is_filter(id) { + drop(filterdb); + return changes; + } + + // Check the logs + if let Some(filter) = filterdb.try_lock().unwrap().get_logs_filter(id) { + trace!("Into filter changes: logs"); + changes = Some(FilterChanges::Logs( + self.get_logs_with_filter(filter.clone(), block_filter), + )); + }; + + // Check the block + if filterdb.try_lock().unwrap().is_block_filter(id) { + trace!("Into filter changes: block"); + // Return hashes from next block after the filter was created to the current block. + let hashes = ((block_filter + 1)..=current_number) + .filter_map(|_id| self.block_hash_by_height(_id)) + .collect::>(); + trace!("Block filter changes: {:?}", hashes); + changes = Some(FilterChanges::Hashes( + hashes.into_iter().map(Into::into).collect(), + )); + }; + + // Update the block filter: use the current number + filterdb + .try_lock() + .unwrap() + .gen_block_filter(id, current_number + 1); + drop(filterdb); + changes + } + + fn get_filter_logs(&self, id: usize) -> Option> { + let filterdb = self.filter_db(); + let block_filter = self.get_block_filter(id); + let logs = match filterdb.try_lock().unwrap().get_logs_filter(id) { + Some(filter) => Some(self.get_logs_with_filter(filter.clone(), block_filter)), + _ => None, + }; + drop(filterdb); + logs + } + + fn uninstall_filter(&self, id: usize) -> bool { + let filterdb = self.filter_db(); + let uninstall_ok = filterdb.try_lock().unwrap().uninstall(id); + drop(filterdb); + uninstall_ok + } +} + +/// Split the logs with the limit filter. +fn split_logs(mut logs: Vec, limit: Option) -> Vec { + let len = logs.len(); + match limit { + Some(limit) if len >= limit => logs.split_off(len - limit), + _ => logs, + } +} diff --git a/cita-chain/core/src/lib.rs b/cita-chain/core/src/lib.rs index 54be60040..72a885e66 100644 --- a/cita-chain/core/src/lib.rs +++ b/cita-chain/core/src/lib.rs @@ -1,62 +1,31 @@ -// CITA -// Copyright 2016-2019 Cryptape Technologies LLC. +// Copyright Cryptape Technologies LLC. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. -// This program is free software: you can redistribute it -// and/or modify it under the terms of the GNU 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 General Public License for more details. - -// You should have received a copy of the GNU General Public License -// along with this program. If not, see . - -extern crate byteorder; #[macro_use] extern crate libproto; #[macro_use] extern crate cita_logger as logger; -extern crate cita_merklehash; -extern crate hashable; -extern crate lru_cache; -extern crate proof; -extern crate rlp; -extern crate snappy; #[macro_use] extern crate serde_derive; #[macro_use] extern crate util; -extern crate db as cita_db; - -#[macro_use] -extern crate rlp_derive; -extern crate rustc_hex; - -extern crate bincode; -extern crate bit_set; -extern crate cita_ed25519; -extern crate cita_secp256k1; -extern crate cita_types; -extern crate common_types as types; -extern crate crossbeam; -extern crate jsonrpc_types; -extern crate pubsub; -extern crate time; -extern crate transient_hashmap; - #[cfg(test)] extern crate cita_crypto; -pub mod env_info; +extern crate cita_database as cita_db; +extern crate common_types as types; -#[macro_use] -pub mod error; pub mod filters; pub mod libchain; -pub mod snapshot; -pub use crate::cita_db::journaldb; pub use crate::types::*; diff --git a/cita-chain/core/src/libchain/cache.rs b/cita-chain/core/src/libchain/cache.rs deleted file mode 100644 index 16bf8245f..000000000 --- a/cita-chain/core/src/libchain/cache.rs +++ /dev/null @@ -1,35 +0,0 @@ -// Copyright 2015-2017 Parity Technologies (UK) Ltd. -// This file is part of Parity. - -// This software is free software: you can redistribute it and/or modify -// it under the terms of the GNU General Public License as published by -// the Free Software Foundation, either version 3 of the License, or -// (at your option) any later version. - -// This software 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 General Public License for more details. - -// You should have received a copy of the GNU General Public License -// along with Parity. If not, see . - -/// Represents blockchain's in-memory cache size in bytes. -#[derive(Debug)] -pub struct CacheSize { - /// Blocks cache size. - pub blocks: usize, - /// Transaction addresses cache size. - pub transaction_addresses: usize, - /// Blooms cache size. - pub blocks_blooms: usize, - /// Block receipts size. - pub block_receipts: usize, -} - -impl CacheSize { - /// Total amount used by the cache. - pub fn total(&self) -> usize { - self.blocks + self.transaction_addresses + self.blocks_blooms + self.block_receipts - } -} diff --git a/cita-chain/core/src/libchain/chain.rs b/cita-chain/core/src/libchain/chain.rs index 7908664ac..6191c6b28 100644 --- a/cita-chain/core/src/libchain/chain.rs +++ b/cita-chain/core/src/libchain/chain.rs @@ -1,66 +1,65 @@ -// CITA -// Copyright 2016-2019 Cryptape Technologies LLC. +// Copyright Cryptape Technologies LLC. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. -// This program is free software: you can redistribute it -// and/or modify it under the terms of the GNU 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 General Public License for more details. - -// You should have received a copy of the GNU General Public License -// along with this program. If not, see . - -use crate::basic_types::{LogBloom, LogBloomGroup}; use crate::bloomchain::group::{ BloomGroup, BloomGroupChain, BloomGroupDatabase, GroupPosition as BloomGroupPosition, }; use crate::bloomchain::{Bloom, Config as BloomChainConfig, Number as BloomChainNumber}; -use crate::db; -use crate::db::*; -pub use byteorder::{BigEndian, ByteOrder}; - -use crate::filters::{PollFilter, PollManager}; -use crate::header::*; -use crate::libchain::cache::CacheSize; +use crate::header::{BlockNumber, Header}; use crate::libchain::status::Status; -pub use crate::types::block::*; -use crate::types::extras::*; +use crate::log_blooms::LogBloomGroup; +use crate::receipt::{Receipt, RichReceipt}; +use cita_merklehash; +use hashable::Hashable; + use libproto::blockchain::{ AccountGasLimit as ProtoAccountGasLimit, Proof as ProtoProof, ProofType, RichStatus as ProtoRichStatus, StateSignal, }; -use crate::cita_db::kvdb::*; -use crate::header::Header; -use crate::receipt::{LocalizedReceipt, Receipt}; -use crate::types::cache_manager::CacheManager; -use crate::types::filter::Filter; -use crate::types::ids::{BlockId, TransactionId}; -use crate::types::log_entry::{LocalizedLogEntry, LogEntry}; -use crate::types::transaction::{Action, SignedTransaction}; -use cita_merklehash; -use cita_types::traits::LowerHex; -use cita_types::{Address, H256, U256}; -use hashable::Hashable; -use libproto::executor::ExecutedResult; -use libproto::router::{MsgType, RoutingKey, SubModules}; -use libproto::TryInto; -use libproto::{BlockTxHashes, FullTransaction, Message}; +use libproto::{ + executor::ExecutedResult, router::MsgType, router::RoutingKey, router::SubModules, + BlockTxHashes, FullTransaction, Message, TryInto, +}; use proof::BftProof; use pubsub::channel::Sender; -use rlp::{self, Encodable}; use std::collections::{BTreeMap, HashMap, HashSet}; use std::convert::Into; use std::sync::atomic::{AtomicBool, AtomicUsize, Ordering}; use std::sync::Arc; -use util::HeapSizeOf; use util::{Mutex, RwLock}; +use crate::db_indexes::{ + BlockNumber2Body, BlockNumber2Header, CurrentHash, CurrentHeight, CurrentProof, + Hash2BlockNumber, Hash2BlockReceipts, Hash2TransactionIndex, LogGroupPosition, +}; + +use crate::types::block::{Block, BlockBody, OpenBlock}; +use crate::types::{ + block_number::BlockTag, block_number::Tag, block_number::TransactionHash, + block_receipts::BlockReceipts, filter::Filter, log::LocalizedLog, log::Log, + transaction::Action, transaction::SignedTransaction, transaction_index::TransactionIndex, +}; +use cita_types::traits::LowerHex; +use cita_types::{Address, Bloom as LogBloom, H256, U256}; + +use crate::cita_db::RocksDB; +use crate::db_indexes::DBIndex; +use crate::filters::filterdb::FilterDB; +use cita_db::Database; +use rlp::{self, decode, Decodable, DecoderError, Encodable, RlpStream, UntrustedRlp}; + pub const VERSION: u32 = 0; const LOG_BLOOMS_LEVELS: usize = 3; const LOG_BLOOMS_ELEMENTS_PER_INDEX: usize = 16; @@ -74,7 +73,7 @@ pub struct RelayInfo { pub cross_chain_nonce: u64, } -#[derive(Debug, Clone, RlpEncodable, RlpDecodable)] +#[derive(Debug, Clone)] pub struct TxProof { tx: SignedTransaction, receipt: Receipt, @@ -84,6 +83,35 @@ pub struct TxProof { proposal_proof: ProtoProof, } +impl Encodable for TxProof { + fn rlp_append(&self, s: &mut RlpStream) { + s.begin_list(6); + s.append(&self.tx); + s.append(&self.receipt); + s.append(&self.receipt_proof); + s.append(&self.block_header); + s.append(&self.next_proposal_header); + s.append(&self.proposal_proof); + } +} + +impl Decodable for TxProof { + fn decode(r: &UntrustedRlp) -> Result { + if r.item_count()? != 6 { + return Err(DecoderError::RlpIncorrectListLen); + } + let tx_proof = TxProof { + tx: r.val_at(0)?, + receipt: r.val_at(1)?, + receipt_proof: r.val_at(2)?, + block_header: r.val_at(3)?, + next_proposal_header: r.val_at(4)?, + proposal_proof: r.val_at(5)?, + }; + Ok(tx_proof) + } +} + impl TxProof { pub fn from_bytes(bytes: &[u8]) -> Self { rlp::decode(bytes) @@ -221,50 +249,32 @@ pub enum BlockSource { NET = 1, } -#[derive(Debug, Hash, Eq, PartialEq, Clone)] -pub enum CacheId { - BlockHeaders(BlockNumber), - BlockBodies(BlockNumber), - BlockHashes(H256), - TransactionAddresses(H256), - BlocksBlooms(LogGroupPosition), - BlockReceipts(H256), -} - #[derive(Debug, Clone, Copy, PartialEq, Deserialize)] pub struct Config { pub prooftype: u8, - pub cache_size: Option, } impl Config { pub fn default() -> Self { - Config { - prooftype: 2, - cache_size: Some(1 << 20), - } + Config { prooftype: 2 } } pub fn new(path: &str) -> Self { - let mut c: Config = parse_config!(Config, path); - if c.cache_size.is_none() { - c.cache_size = Some(1 << 20 as usize); - } + let c: Config = parse_config!(Config, path); c } } impl BloomGroupDatabase for Chain { fn blooms_at(&self, position: &BloomGroupPosition) -> Option { - let position = LogGroupPosition::from(position.clone()); - let result = self - .db - .read_with_cache(db::COL_EXTRA, &self.blocks_blooms, &position) - .map(Into::into); - self.cache_man - .lock() - .note_used(CacheId::BlocksBlooms(position)); - result + let p = LogGroupPosition::from(position.clone()); + self.db + .get(Some(cita_db::DataCategory::Extra), &p.get_index()) + .unwrap_or(None) + .map(|blooms| { + let g: LogBloomGroup = rlp::decode(&blooms); + g.into() + }) } } @@ -284,17 +294,8 @@ pub struct Chain { pub max_store_height: AtomicUsize, pub block_map: RwLock>, pub proof_map: RwLock>, - pub db: Arc, - - // block cache - pub block_headers: RwLock>, - pub block_bodies: RwLock>, + pub db: Arc, - // extra caches - pub block_hashes: RwLock>, - pub transaction_addresses: RwLock>, - pub blocks_blooms: RwLock>, - pub block_receipts: RwLock>, pub nodes: RwLock>, pub validators: RwLock>, pub block_interval: RwLock, @@ -303,47 +304,62 @@ pub struct Chain { pub account_quota_limit: RwLock, pub check_quota: AtomicBool, - pub cache_man: Mutex>, - pub polls_filter: Arc>>, - + /// Filter Database + pub filterdb: Arc>, /// Proof type pub prooftype: u8, - // snapshot flag pub is_snapshot: RwLock, - admin_address: RwLock>, - pub version: RwLock>, } /// Get latest status -pub fn get_chain(db: &KeyValueDB) -> Option
{ - // CANNOT replace CurrentHash & hash with CurrentHeight to get current_height, - // because CurrentHeight is set after BlockBody is stored, and CurrentHash is set after BlockHeader is stored. - let h: Option = db.read(db::COL_EXTRA, &CurrentHash); - if let Some(hash) = h { - let hi: Option = db.read(db::COL_EXTRA, &hash); - if let Some(h) = hi { - trace!("get_chain hash {:?} bn{:?} CurrentHash", hash, h); - db.read(db::COL_HEADERS, &h) - } else { - warn!("not expected get_chain_current_head height"); - None - } - } else { - warn!("not expected get_chain_current_head hash."); - None +pub fn get_chain(db: &RocksDB) -> Option
{ + let res = db + .get( + Some(cita_db::DataCategory::Extra), + &CurrentHash.get_index().to_vec(), + ) + .unwrap_or(None) + .map(|h| decode::(&h)); + + if let Some(hash) = res { + trace!("Get block height from hash : {:?}", hash); + let hash_key = Hash2BlockNumber(hash).get_index(); + let header = db + .get(Some(cita_db::DataCategory::Extra), &hash_key) + .unwrap_or(None) + .map(|n| { + let height = decode::(&n); + trace!("Get chain from height : {:?}", height); + let height_key = BlockNumber2Header(height).get_index(); + db.get(Some(cita_db::DataCategory::Headers), &height_key) + .unwrap_or(None) + .map(|res| { + let header: Header = rlp::decode(&res); + header + }) + }) + .and_then(|x| x); + return header; } + None } -pub fn get_chain_body_height(db: &KeyValueDB) -> Option { - db.read(db::COL_EXTRA, &CurrentHeight) +pub fn get_chain_body_height(db: &RocksDB) -> Option { + db.get( + Some(cita_db::DataCategory::Extra), + &CurrentHeight.get_index(), + ) + .unwrap_or(None) + .map(|res| { + let block_number: BlockNumber = rlp::decode(&res); + block_number + }) } pub fn contract_address(address: &Address, nonce: &U256) -> Address { - use rlp::RlpStream; - let mut stream = RlpStream::new_list(2); stream.append(address); stream.append(nonce); @@ -351,16 +367,9 @@ pub fn contract_address(address: &Address, nonce: &U256) -> Address { } impl Chain { - pub fn init_chain(db: Arc, chain_config: &Config) -> Chain { + pub fn init_chain(db: Arc, chain_config: Config) -> Chain { info!("chain config: {:?}", chain_config); - // 400 is the avarage size of the key - let cache_man = CacheManager::new( - chain_config.cache_size.unwrap() * 3 / 4, - chain_config.cache_size.unwrap(), - 400, - ); - let blooms_config = BloomChainConfig { levels: LOG_BLOOMS_LEVELS, elements_per_index: LOG_BLOOMS_ELEMENTS_PER_INDEX, @@ -385,15 +394,8 @@ impl Chain { current_height, max_store_height, block_map: RwLock::new(BTreeMap::new()), - block_headers: RwLock::new(HashMap::new()), - block_bodies: RwLock::new(HashMap::new()), - block_hashes: RwLock::new(HashMap::new()), - transaction_addresses: RwLock::new(HashMap::new()), - blocks_blooms: RwLock::new(HashMap::new()), - block_receipts: RwLock::new(HashMap::new()), - cache_man: Mutex::new(cache_man), db, - polls_filter: Arc::new(Mutex::new(PollManager::default())), + filterdb: Arc::new(Mutex::new(FilterDB::new())), nodes: RwLock::new(Vec::new()), validators: RwLock::new(Vec::new()), // need to be cautious here @@ -421,14 +423,14 @@ impl Chain { chain } - /// Get block number by BlockId - fn block_number(&self, id: BlockId) -> Option { - match id { - BlockId::Number(number) => Some(number), - BlockId::Hash(hash) => self.block_height_by_hash(hash), - BlockId::Earliest => Some(0), - BlockId::Latest => Some(self.get_latest_height()), - BlockId::Pending => Some(self.get_pending_height()), + /// Get block number by BlockTag + fn block_number(&self, tag: BlockTag) -> Option { + match tag { + BlockTag::Height(number) => Some(number), + BlockTag::Hash(hash) => self.block_height_by_hash(hash), + BlockTag::Tag(Tag::Earliest) => Some(0), + BlockTag::Tag(Tag::Latest) => Some(self.get_latest_height()), + BlockTag::Tag(Tag::Pending) => Some(self.get_pending_height()), } } @@ -447,11 +449,11 @@ impl Chain { } pub fn block_height_by_hash(&self, hash: H256) -> Option { - let result = self - .db - .read_with_cache(db::COL_EXTRA, &self.block_hashes, &hash); - self.cache_man.lock().note_used(CacheId::BlockHashes(hash)); - result + let hash_key = Hash2BlockNumber(hash).get_index(); + self.db + .get(Some(cita_db::DataCategory::Extra), &hash_key) + .unwrap_or(None) + .map(|res| decode::(&res)) } fn set_config(&self, ret: &ExecutedResult) { @@ -493,21 +495,15 @@ impl Chain { let info = ret.get_executed_info(); let number = info.get_header().get_height(); let log_bloom = LogBloom::from(info.get_header().get_log_bloom()); - let hdr = Header::from_executed_info(ret.get_executed_info(), &block.header); + let header = Header::from_executed_info(ret.get_executed_info(), &block.header); + let header_hash = header.hash().unwrap(); - let hash = hdr.hash().unwrap(); - trace!( - "commit block in db hash {:?}, height {:?}, version {}", - hash, - number, - block.version() - ); - let block_transaction_addresses = block.body().transaction_addresses(hash); + let block_transaction_indexes = block.body().transaction_indexes(header_hash); let blocks_blooms: HashMap = if log_bloom.is_zero() { HashMap::new() } else { - let bgroup = BloomGroupChain::new(self.blooms_config, self); - bgroup + let group = BloomGroupChain::new(self.blooms_config, self); + group .insert( number as BloomChainNumber, Bloom::from(Into::<[u8; 256]>::into(log_bloom)), @@ -517,96 +513,79 @@ impl Chain { .collect() }; - let mut batch = DBTransaction::new(); + // Save hash -> receipts if !info.get_receipts().is_empty() { let receipts: Vec = info .get_receipts() .iter() - .map(|receipt_with_option| Receipt::from(receipt_with_option.get_receipt().clone())) + .map(|r| Receipt::from(r.get_receipt().clone())) .collect(); - - let block_receipts = BlockReceipts::new(receipts.clone()); - let mut write_receipts = self.block_receipts.write(); - batch.write_with_cache( - db::COL_EXTRA, - &mut *write_receipts, - hash, - block_receipts, - CacheUpdatePolicy::Overwrite, + let block_receipts = BlockReceipts::new(receipts); + let hash_key = Hash2BlockReceipts(header_hash).get_index(); + let _ = self.db.insert( + Some(cita_db::DataCategory::Extra), + hash_key, + rlp::encode(&block_receipts).into_vec(), ); - self.cache_man - .lock() - .note_used(CacheId::BlockReceipts(hash)); } - if !block_transaction_addresses.is_empty() { - let mut write_txs = self.transaction_addresses.write(); - batch.extend_with_cache( - db::COL_EXTRA, - &mut *write_txs, - block_transaction_addresses, - CacheUpdatePolicy::Overwrite, - ); - for key in block.body.transaction_hashes() { - self.cache_man - .lock() - .note_used(CacheId::TransactionAddresses(key)); + + // Save block transaction indexes + if !block_transaction_indexes.is_empty() { + for (k, v) in block_transaction_indexes.iter() { + let hash_key = Hash2TransactionIndex(*k).get_index(); + let _ = self.db.insert( + Some(cita_db::DataCategory::Extra), + hash_key, + rlp::encode(v).into_vec(), + ); } } - let mut write_headers = self.block_headers.write(); - let mut write_bodies = self.block_bodies.write(); - let mut write_blooms = self.blocks_blooms.write(); - let mut write_hashes = self.block_hashes.write(); - - batch.write_with_cache( - db::COL_HEADERS, - &mut *write_headers, - number as BlockNumber, - hdr.clone(), - CacheUpdatePolicy::Overwrite, + // Save number -> header + trace!("Save ExecutedResult's header: {:?}", header); + let number_key = BlockNumber2Header(number).get_index(); + let _ = self.db.insert( + Some(cita_db::DataCategory::Headers), + number_key, + rlp::encode(&header).into_vec(), ); + + // Save Body let mheight = self.get_max_store_height(); if mheight < number || (number == 0 && mheight == 0) { - batch.write_with_cache( - db::COL_BODIES, - &mut *write_bodies, - number, - block.body().clone(), - CacheUpdatePolicy::Overwrite, + let number_key = BlockNumber2Body(number).get_index(); + let _ = self.db.insert( + Some(cita_db::DataCategory::Bodies), + number_key, + rlp::encode(block.body()).into_vec(), ); } - batch.write_with_cache( - db::COL_EXTRA, - &mut *write_hashes, - hash, - number as BlockNumber, - CacheUpdatePolicy::Overwrite, - ); - batch.extend_with_cache( - db::COL_EXTRA, - &mut *write_blooms, - blocks_blooms.clone(), - CacheUpdatePolicy::Overwrite, + + // Save hash -> blockNumber + let hash_key = Hash2BlockNumber(header_hash).get_index(); + let _ = self.db.insert( + Some(cita_db::DataCategory::Extra), + hash_key, + rlp::encode(&number).into_vec(), ); - //note used - self.cache_man.lock().note_used(CacheId::BlockHashes(hash)); - self.cache_man - .lock() - .note_used(CacheId::BlockHeaders(number as BlockNumber)); - self.cache_man - .lock() - .note_used(CacheId::BlockBodies(number as BlockNumber)); - - for (key, _) in blocks_blooms { - self.cache_man.lock().note_used(CacheId::BlocksBlooms(key)); + // Save blocks blooms + for (k, v) in blocks_blooms.iter() { + let _ = self.db.insert( + Some(cita_db::DataCategory::Extra), + k.get_index(), + rlp::encode(v).into_vec(), + ); } - batch.write(db::COL_EXTRA, &CurrentHash, &hash); - self.db.write(batch).expect("DB write failed."); - { - *self.current_header.write() = hdr; - } + // Save current hash + let _ = self.db.insert( + Some(cita_db::DataCategory::Extra), + CurrentHash.get_index(), + rlp::encode(&header_hash).into_vec(), + ); + + *self.current_header.write() = header; self.current_height.store(number as usize, Ordering::SeqCst); self.clean_proof_with_height(number); } @@ -711,14 +690,14 @@ impl Chain { *guard = new_map; } - /// Get block by BlockId - pub fn block(&self, id: BlockId) -> Option { - match id { - BlockId::Hash(hash) => self.block_by_hash(hash), - BlockId::Number(number) => self.block_by_height(number), - BlockId::Earliest => self.block_by_height(0), - BlockId::Latest => self.block_by_height(self.get_latest_height()), - BlockId::Pending => self.block_by_height(self.get_pending_height()), + /// Get block by BlockTag + pub fn block(&self, tag: BlockTag) -> Option { + match tag { + BlockTag::Hash(hash) => self.block_by_hash(hash), + BlockTag::Height(number) => self.block_by_height(number), + BlockTag::Tag(Tag::Earliest) => self.block_by_height(0), + BlockTag::Tag(Tag::Latest) => self.block_by_height(self.get_latest_height()), + BlockTag::Tag(Tag::Pending) => self.block_by_height(self.get_pending_height()), } } @@ -739,14 +718,14 @@ impl Chain { } } - /// Get block header by BlockId - pub fn block_header(&self, id: BlockId) -> Option
{ - match id { - BlockId::Hash(hash) => self.block_header_by_hash(hash), - BlockId::Number(number) => self.block_header_by_height(number), - BlockId::Earliest => self.block_header_by_height(0), - BlockId::Latest => self.block_header_by_height(self.get_latest_height()), - BlockId::Pending => self.block_header_by_height(self.get_pending_height()), + /// Get block header by BlockTag + pub fn block_header(&self, tag: BlockTag) -> Option
{ + match tag { + BlockTag::Hash(hash) => self.block_header_by_hash(hash), + BlockTag::Height(number) => self.block_header_by_height(number), + BlockTag::Tag(Tag::Earliest) => self.block_header_by_height(0), + BlockTag::Tag(Tag::Latest) => self.block_header_by_height(self.get_latest_height()), + BlockTag::Tag(Tag::Pending) => self.block_header_by_height(self.get_pending_height()), } } @@ -762,28 +741,25 @@ impl Chain { .and_then(|h| self.block_header_by_height(h)) } - fn block_header_by_height(&self, idx: BlockNumber) -> Option
{ - { - let header = self.current_header.read(); - if header.number() == idx { - return Some(header.clone()); - } - } - let result = self - .db - .read_with_cache(db::COL_HEADERS, &self.block_headers, &idx); - self.cache_man.lock().note_used(CacheId::BlockHeaders(idx)); - result - } - - /// Get block body by BlockId - pub fn block_body(&self, id: BlockId) -> Option { - match id { - BlockId::Hash(hash) => self.block_body_by_hash(hash), - BlockId::Number(number) => self.block_body_by_height(number), - BlockId::Earliest => self.block_body_by_height(0), - BlockId::Latest => self.block_body_by_height(self.get_latest_height()), - BlockId::Pending => self.block_body_by_height(self.get_pending_height()), + fn block_header_by_height(&self, number: BlockNumber) -> Option
{ + let number_key = BlockNumber2Header(number).get_index(); + self.db + .get(Some(cita_db::DataCategory::Headers), &number_key) + .unwrap_or(None) + .map(|res| { + let header: Header = rlp::decode(&res); + header + }) + } + + /// Get block body by BlockTag + pub fn block_body(&self, tag: BlockTag) -> Option { + match tag { + BlockTag::Hash(hash) => self.block_body_by_hash(hash), + BlockTag::Height(number) => self.block_body_by_height(number), + BlockTag::Tag(Tag::Earliest) => self.block_body_by_height(0), + BlockTag::Tag(Tag::Latest) => self.block_body_by_height(self.get_latest_height()), + BlockTag::Tag(Tag::Pending) => self.block_body_by_height(self.get_pending_height()), } } @@ -800,13 +776,14 @@ impl Chain { /// Get block body by height fn block_body_by_height(&self, number: BlockNumber) -> Option { - let result = self - .db - .read_with_cache(db::COL_BODIES, &self.block_bodies, &number); - self.cache_man - .lock() - .note_used(CacheId::BlockBodies(number)); - result + let number_key = BlockNumber2Body(number).get_index(); + self.db + .get(Some(cita_db::DataCategory::Bodies), &number_key) + .unwrap_or(None) + .map(|res| { + let body: BlockBody = rlp::decode(&res); + body + }) } /// Get block tx hashes @@ -816,8 +793,8 @@ impl Chain { } /// Get transaction by hash - pub fn transaction(&self, hash: TransactionId) -> Option { - self.transaction_address(hash).and_then(|addr| { + pub fn transaction(&self, hash: TransactionHash) -> Option { + self.transaction_index(hash).and_then(|addr| { let index = addr.index; let hash = addr.block_hash; self.transaction_by_address(hash, index) @@ -825,14 +802,15 @@ impl Chain { } /// Get address of transaction by hash. - fn transaction_address(&self, hash: TransactionId) -> Option { - let result = self - .db - .read_with_cache(db::COL_EXTRA, &self.transaction_addresses, &hash); - self.cache_man - .lock() - .note_used(CacheId::TransactionAddresses(hash)); - result + fn transaction_index(&self, hash: TransactionHash) -> Option { + let hash_key = Hash2TransactionIndex(hash).get_index(); + self.db + .get(Some(cita_db::DataCategory::Extra), &hash_key) + .unwrap_or(None) + .map(|res| { + let tx_index: TransactionIndex = rlp::decode(&res); + tx_index + }) } /// Get transaction by address @@ -842,13 +820,13 @@ impl Chain { } /// Get transaction hashes by block hash - pub fn transaction_hashes(&self, id: BlockId) -> Option> { - self.block_body(id).map(|body| body.transaction_hashes()) + pub fn transaction_hashes(&self, tag: BlockTag) -> Option> { + self.block_body(tag).map(|body| body.transaction_hashes()) } /// Get full transaction by hash - pub fn full_transaction(&self, hash: TransactionId) -> Option { - self.transaction_address(hash).and_then(|addr| { + pub fn full_transaction(&self, hash: TransactionHash) -> Option { + self.transaction_index(hash).and_then(|addr| { let index = addr.index; let hash = addr.block_hash; self.block_by_hash(hash).map(|block| { @@ -864,8 +842,8 @@ impl Chain { }) } - pub fn get_transaction_proof(&self, hash: TransactionId) -> Option<(Vec)> { - self.transaction_address(hash) + pub fn get_transaction_proof(&self, hash: TransactionHash) -> Option<(Vec)> { + self.transaction_index(hash) .and_then(|addr| { self.block_by_hash(addr.block_hash) .map(|block| (addr, block)) @@ -958,78 +936,68 @@ impl Chain { ) } - pub fn get_block_header_bytes(&self, id: BlockId) -> Option> { - self.block_header(id).map(|x| x.rlp_bytes().into_vec()) + pub fn get_block_header_bytes(&self, tag: BlockTag) -> Option> { + self.block_header(tag).map(|x| x.rlp_bytes().into_vec()) } - pub fn localized_receipt(&self, id: TransactionId) -> Option { - trace!("Get receipt id: {:?}", id); - - let address = match self.transaction_address(id) { - Some(addr) => addr, - _ => return None, - }; - let hash = address.block_hash; - let index = address.index; - - let mut receipts = match self.block_receipts(hash) { - Some(r) => r.receipts, - _ => return None, - }; + pub fn get_rich_receipt(&self, tx_hash: TransactionHash) -> Option { + trace!("Get receipt by hash: {:?}", tx_hash); + if let Some(transaction_index) = self.transaction_index(tx_hash) { + let block_hash = transaction_index.block_hash; + let tx_index = transaction_index.index; - receipts.truncate(index + 1); - let last_receipt = receipts.pop().expect("Current receipt is provided; qed"); + if let Some(res) = self.block_receipts(block_hash) { + let mut receipts = res.receipts; + receipts.truncate(tx_index + 1); - let prior_quota_used = match receipts.last() { - Some(ref r) => r.quota_used, - _ => 0.into(), - }; + let last_receipt = receipts.pop().expect("Current receipt is provided; qed"); + let prior_quota_used = receipts.last().map_or(0.into(), |r| r.quota_used); + let log_position_block = receipts.iter().fold(0, |acc, r| acc + r.logs.len()); - let no_of_logs = receipts.iter().fold(0, |acc, r| acc + r.logs.len()); - - if last_receipt.transaction_hash == id { - // Get sender - let stx = self.transaction_by_address(hash, index).unwrap(); - let number = self.block_height_by_hash(hash).unwrap_or(0); - - let contract_address = match *stx.action() { - Action::Create if last_receipt.error.is_none() => { - Some(contract_address(stx.sender(), &last_receipt.account_nonce)) + if last_receipt.transaction_hash == tx_hash { + let stx = self + .transaction_by_address(block_hash, tx_index) + .unwrap_or_default(); + let block_number = self.block_height_by_hash(block_hash).unwrap_or(0); + let contract_address = match *stx.action() { + Action::Create if last_receipt.error.is_none() => { + Some(contract_address(stx.sender(), &last_receipt.account_nonce)) + } + _ => None, + }; + + let receipt = RichReceipt { + transaction_hash: tx_hash, + transaction_index: tx_index, + block_hash, + block_number, + cumulative_quota_used: last_receipt.quota_used, + quota_used: last_receipt.quota_used - prior_quota_used, + contract_address, + logs: last_receipt + .logs + .into_iter() + .enumerate() + .map(|(i, log)| LocalizedLog { + log, + block_hash, + block_number, + transaction_hash: tx_hash, + transaction_index: tx_index, + transaction_log_index: i, + log_index: log_position_block + i, + }) + .collect(), + log_bloom: last_receipt.log_bloom, + state_root: last_receipt.state_root, + error: last_receipt.error, + }; + return Some(receipt); } - _ => None, - }; - - let receipt = LocalizedReceipt { - transaction_hash: id, - transaction_index: index, - block_hash: hash, - block_number: number, - cumulative_quota_used: last_receipt.quota_used, - quota_used: last_receipt.quota_used - prior_quota_used, - contract_address, - logs: last_receipt - .logs - .into_iter() - .enumerate() - .map(|(i, log)| LocalizedLogEntry { - entry: log, - block_hash: hash, - block_number: number, - transaction_hash: id, - transaction_index: index, - transaction_log_index: i, - log_index: no_of_logs + i, - }) - .collect(), - log_bloom: last_receipt.log_bloom, - state_root: last_receipt.state_root, - error: last_receipt.error, - }; - Some(receipt) - } else { - error!("The transaction_hash in receipt is not equal to transaction hash from input."); - None + } } + info!("Get receipt by hash failed {:?}", tx_hash); + None } #[inline] @@ -1070,15 +1038,24 @@ impl Chain { #[inline] pub fn current_block_poof(&self) -> Option { - self.db.read(db::COL_EXTRA, &CurrentProof) + self.db + .get( + Some(cita_db::DataCategory::Extra), + &CurrentProof.get_index(), + ) + .unwrap_or(None) + .map(|res| { + let proto_proof: ProtoProof = rlp::decode(&res); + proto_proof + }) } pub fn save_current_block_poof(&self, proof: &ProtoProof) { - let mut batch = DBTransaction::new(); - batch.write(db::COL_EXTRA, &CurrentProof, proof); - self.db - .write(batch) - .expect("save_current_block_poof DB write failed."); + let _ = self.db.insert( + Some(cita_db::DataCategory::Extra), + CurrentProof.get_index(), + rlp::encode(proof).into_vec(), + ); } pub fn get_chain_prooftype(&self) -> Option { @@ -1095,9 +1072,9 @@ impl Chain { mut blocks: Vec, matches: F, limit: Option, - ) -> Vec + ) -> Vec where - F: Fn(&LogEntry) -> bool, + F: Fn(&Log) -> bool, Self: Sized, { // sort in reverse order @@ -1145,8 +1122,8 @@ impl Chain { logs.reverse(); logs.into_iter().enumerate().map(move |(i, log)| { - LocalizedLogEntry { - entry: log, + LocalizedLog { + log, block_hash: hash, block_number: number, transaction_hash: tx_hash, @@ -1158,9 +1135,9 @@ impl Chain { }) }) }) - .filter(|log_entry| matches(&log_entry.entry)) + .filter(|log| matches(&log.log)) .take(limit.unwrap_or(::std::usize::MAX)) - .collect::>(); + .collect::>(); logs.reverse(); logs } @@ -1180,17 +1157,17 @@ impl Chain { .collect() } - /// Returns numbers of blocks containing given bloom by blockId. + /// Returns numbers of blocks containing given bloom by BlockTag. pub fn blocks_with_bloom_by_id( &self, bloom: &LogBloom, - from_block: BlockId, - to_block: BlockId, + from_block: BlockTag, + to_block: BlockTag, ) -> Option> { match ( self.block_number(from_block), self.block_number(to_block), - self.block_number(BlockId::Pending), + self.block_number(BlockTag::Tag(Tag::Pending)), ) { (Some(from), Some(to), Some(pending)) => { let end = if to > pending { pending } else { to }; @@ -1200,9 +1177,9 @@ impl Chain { } } - pub fn get_logs(&self, filter: &Filter) -> Vec { + pub fn get_logs(&self, filter: &Filter) -> Vec { let blocks = filter - .bloom_possibilities() + .zip_blooms() .iter() .filter_map(|bloom| { self.blocks_with_bloom_by_id(bloom, filter.from_block, filter.to_block) @@ -1296,17 +1273,18 @@ impl Chain { /// Get receipts of block with given hash. pub fn block_receipts(&self, hash: H256) -> Option { - let result = self - .db - .read_with_cache(db::COL_EXTRA, &self.block_receipts, &hash); - self.cache_man - .lock() - .note_used(CacheId::BlockReceipts(hash)); - result + let hash_key = Hash2BlockReceipts(hash).get_index(); + self.db + .get(Some(cita_db::DataCategory::Extra), &hash_key) + .unwrap_or(None) + .map(|res| { + let block_receipts: BlockReceipts = rlp::decode(&res); + block_receipts + }) } /// Get transaction receipt. - pub fn transaction_receipt(&self, address: &TransactionAddress) -> Option { + pub fn transaction_receipt(&self, address: &TransactionIndex) -> Option { self.block_receipts(address.block_hash) .map(|r| r.receipts[address.index].clone()) } @@ -1390,22 +1368,20 @@ impl Chain { } pub fn set_block_body(&self, height: BlockNumber, block: &OpenBlock) { - let mut batch = DBTransaction::new(); - { - let mut write_bodies = self.block_bodies.write(); - batch.write_with_cache( - db::COL_BODIES, - &mut *write_bodies, - height, - block.body().clone(), - CacheUpdatePolicy::Overwrite, - ); - self.cache_man - .lock() - .note_used(CacheId::BlockBodies(height as BlockNumber)); - } - batch.write(db::COL_EXTRA, &CurrentHeight, &height); - let _ = self.db.write(batch); + // Save number -> body + let height_key = BlockNumber2Body(height).get_index(); + let _ = self.db.insert( + Some(cita_db::DataCategory::Bodies), + height_key, + rlp::encode(block.body()).into_vec(), + ); + + // Save current height + let _ = self.db.insert( + Some(cita_db::DataCategory::Extra), + CurrentHeight.get_index(), + rlp::encode(&height).into_vec(), + ); } pub fn compare_status(&self, st: &Status) -> (u64, u64) { @@ -1417,71 +1393,8 @@ impl Chain { } } - /// Get current cache size. - pub fn cache_size(&self) -> CacheSize { - CacheSize { - blocks: self.block_headers.read().heap_size_of_children() - + self.block_bodies.read().heap_size_of_children(), - transaction_addresses: self.transaction_addresses.read().heap_size_of_children(), - blocks_blooms: self.blocks_blooms.read().heap_size_of_children(), - block_receipts: self.block_receipts.read().heap_size_of_children(), - } - } - - /// Ticks our cache system and throws out any old data. - pub fn collect_garbage(&self) { - let current_size = self.cache_size().total(); - - let mut block_headers = self.block_headers.write(); - let mut block_bodies = self.block_bodies.write(); - let mut block_hashes = self.block_hashes.write(); - let mut transaction_addresses = self.transaction_addresses.write(); - let mut blocks_blooms = self.blocks_blooms.write(); - let mut block_receipts = self.block_receipts.write(); - - let mut cache_man = self.cache_man.lock(); - cache_man.collect_garbage(current_size, |ids| { - for id in &ids { - match *id { - CacheId::BlockHeaders(ref h) => { - block_headers.remove(h); - } - CacheId::BlockBodies(ref h) => { - block_bodies.remove(h); - } - CacheId::BlockHashes(ref h) => { - block_hashes.remove(h); - } - CacheId::TransactionAddresses(ref h) => { - transaction_addresses.remove(h); - } - CacheId::BlocksBlooms(ref h) => { - blocks_blooms.remove(h); - } - CacheId::BlockReceipts(ref h) => { - block_receipts.remove(h); - } - } - } - - block_headers.shrink_to_fit(); - block_bodies.shrink_to_fit(); - block_hashes.shrink_to_fit(); - transaction_addresses.shrink_to_fit(); - blocks_blooms.shrink_to_fit(); - block_receipts.shrink_to_fit(); - - block_headers.heap_size_of_children() - + block_bodies.heap_size_of_children() - + block_hashes.heap_size_of_children() - + transaction_addresses.heap_size_of_children() - + blocks_blooms.heap_size_of_children() - + block_receipts.heap_size_of_children() - }); - } - - pub fn poll_filter(&self) -> Arc>> { - Arc::clone(&self.polls_filter) + pub fn filter_db(&self) -> Arc> { + Arc::clone(&self.filterdb) } /// clear sync block @@ -1502,31 +1415,3 @@ impl Chain { self.set_max_store_height(self.get_current_height()); } } - -#[cfg(test)] -mod tests { - use super::*; - use cita_types::H256; - - #[test] - fn test_heapsizeof() { - let test: Vec = Vec::new(); - assert_eq!(test.heap_size_of_children(), 0); - } - #[test] - fn test_cache_size() { - let transaction_addresses: HashMap = HashMap::new(); - let blocks_blooms: HashMap = HashMap::new(); - let mut block_receipts: HashMap = HashMap::new(); - - assert_eq!(transaction_addresses.heap_size_of_children(), 0); - assert_eq!(blocks_blooms.heap_size_of_children(), 0); - assert_eq!(block_receipts.heap_size_of_children(), 0); - - block_receipts.insert( - H256::from("000000000000000000000000000000000000000000000000123456789abcdef0"), - BlockReceipts::new(vec![]), - ); - assert_eq!(block_receipts.heap_size_of_children(), 1856); - } -} diff --git a/cita-chain/core/src/libchain/mod.rs b/cita-chain/core/src/libchain/mod.rs index d57620aa9..b3941f8e9 100644 --- a/cita-chain/core/src/libchain/mod.rs +++ b/cita-chain/core/src/libchain/mod.rs @@ -1,23 +1,17 @@ -// CITA -// Copyright 2016-2019 Cryptape Technologies LLC. +// Copyright Cryptape Technologies LLC. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. -// This program is free software: you can redistribute it -// and/or modify it under the terms of the GNU 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 General Public License for more details. - -// You should have received a copy of the GNU General Public License -// along with this program. If not, see . - -pub mod cache; pub mod chain; pub mod rich_status; pub mod status; -pub use crate::cita_db::journaldb; -pub use crate::types::block::*; diff --git a/cita-chain/core/src/libchain/rich_status.rs b/cita-chain/core/src/libchain/rich_status.rs index 19ea1cd4d..d9a224ab7 100644 --- a/cita-chain/core/src/libchain/rich_status.rs +++ b/cita-chain/core/src/libchain/rich_status.rs @@ -1,19 +1,16 @@ -// CITA -// Copyright 2016-2019 Cryptape Technologies LLC. - -// This program is free software: you can redistribute it -// and/or modify it under the terms of the GNU 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 General Public License for more details. - -// You should have received a copy of the GNU General Public License -// along with this program. If not, see . +// Copyright Cryptape Technologies LLC. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. use cita_types::{Address, H256}; use libproto::blockchain::RichStatus as ProtoRichStatus; diff --git a/cita-chain/core/src/libchain/status.rs b/cita-chain/core/src/libchain/status.rs index 012198fcb..0d6260c11 100644 --- a/cita-chain/core/src/libchain/status.rs +++ b/cita-chain/core/src/libchain/status.rs @@ -1,19 +1,16 @@ -// CITA -// Copyright 2016-2019 Cryptape Technologies LLC. - -// This program is free software: you can redistribute it -// and/or modify it under the terms of the GNU 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 General Public License for more details. - -// You should have received a copy of the GNU General Public License -// along with this program. If not, see . +// Copyright Cryptape Technologies LLC. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. use cita_types::H256; use libproto::blockchain::Status as ProtoStatus; diff --git a/cita-chain/core/src/snapshot/error.rs b/cita-chain/core/src/snapshot/error.rs deleted file mode 100644 index 6d0988a47..000000000 --- a/cita-chain/core/src/snapshot/error.rs +++ /dev/null @@ -1,143 +0,0 @@ -// Copyright 2015-2017 Parity Technologies (UK) Ltd. -// This file is part of Parity. - -// This software is free software: you can redistribute it and/or modify -// it under the terms of the GNU General Public License as published by -// the Free Software Foundation, either version 3 of the License, or -// (at your option) any later version. - -// This software 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 General Public License for more details. - -// You should have received a copy of the GNU General Public License -// along with Parity. If not, see . - -//! Snapshot-related errors. - -use std::fmt; - -use crate::types::ids::BlockId; - -use crate::cita_db::trie::TrieError; -use cita_types::H256; -use rlp::DecoderError; -use snappy::SnappyError; - -/// Snapshot-related errors. -#[derive(Debug)] -pub enum Error { - /// Invalid starting block for snapshot. - InvalidStartingBlock(BlockId), - /// Block not found. - BlockNotFound(H256), - /// Incomplete chain. - IncompleteChain, - /// Best block has wrong state root. - WrongStateRoot(H256, H256), - /// Wrong block hash. - WrongBlockHash(u64, H256, H256), - /// Too many blocks contained within the snapshot. - TooManyBlocks(u64, u64), - /// Old starting block in a pruned database. - OldBlockPrunedDB, - /// Missing code. - MissingCode(Vec), - /// Unrecognized code encoding. - UnrecognizedCodeState(u8), - /// Restoration aborted. - RestorationAborted, - /// Trie error. - Trie(TrieError), - /// Decoder error. - Decoder(DecoderError), - /// Io error. - Io(::std::io::Error), - /// Snapshot version is not supported. - VersionNotSupported(u64), - /// Max chunk size is to small to fit basic account data. - ChunkTooSmall, - /// Snapshots not supported by the consensus engine. - SnapshotsUnsupported, - /// Bad epoch transition. - BadEpochProof(u64), - /// Wrong chunk format. - WrongChunkFormat(String), - /// Snappy error. - Snappy(SnappyError), -} - -impl fmt::Display for Error { - fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { - match *self { - Error::InvalidStartingBlock(ref id) => write!(f, "Invalid starting block: {:?}", id), - Error::BlockNotFound(ref hash) => write!(f, "Block not found in chain: {}", hash), - Error::IncompleteChain => write!(f, "Incomplete blockchain."), - Error::WrongStateRoot(ref expected, ref found) => write!( - f, - "Final block has wrong state root. Expected {:?}, got {:?}", - expected, found - ), - Error::WrongBlockHash(ref num, ref expected, ref found) => write!( - f, - "Block {} had wrong hash. expected {:?}, got {:?}", - num, expected, found - ), - Error::TooManyBlocks(ref expected, ref found) => write!( - f, - "Snapshot contained too many blocks. Expected {}, got {}", - expected, found - ), - Error::OldBlockPrunedDB => write!( - f, - "Attempted to create a snapshot at an old block while using \ - a pruned database. Please re-run with the --pruning archive flag." - ), - Error::MissingCode(ref missing) => write!( - f, - "Incomplete snapshot: {} contract codes not found.", - missing.len() - ), - Error::UnrecognizedCodeState(state) => { - write!(f, "Unrecognized code encoding ({})", state) - } - Error::RestorationAborted => write!(f, "Snapshot restoration aborted."), - Error::Io(ref err) => err.fmt(f), - Error::Decoder(ref err) => err.fmt(f), - Error::Trie(ref err) => err.fmt(f), - Error::VersionNotSupported(ref ver) => { - write!(f, "Snapshot version {} is not supprted.", ver) - } - Error::ChunkTooSmall => write!(f, "Chunk size is too small."), - Error::SnapshotsUnsupported => write!(f, "Snapshots unsupported by consensus engine."), - Error::BadEpochProof(i) => write!(f, "Bad epoch proof for transition to epoch {}", i), - Error::WrongChunkFormat(ref msg) => write!(f, "Wrong chunk format: {}", msg), - Error::Snappy(ref err) => write!(f, "Snappy error: {}", err), - } - } -} - -impl From<::std::io::Error> for Error { - fn from(err: ::std::io::Error) -> Self { - Error::Io(err) - } -} - -impl From for Error { - fn from(err: TrieError) -> Self { - Error::Trie(err) - } -} - -impl From for Error { - fn from(err: DecoderError) -> Self { - Error::Decoder(err) - } -} - -impl From for Error { - fn from(err: SnappyError) -> Self { - Error::Snappy(err) - } -} diff --git a/cita-chain/core/src/snapshot/io.rs b/cita-chain/core/src/snapshot/io.rs deleted file mode 100644 index f0c44f832..000000000 --- a/cita-chain/core/src/snapshot/io.rs +++ /dev/null @@ -1,304 +0,0 @@ -// Copyright 2015-2017 Parity Technologies (UK) Ltd. -// This file is part of Parity. - -// This software is free software: you can redistribute it and/or modify -// it under the terms of the GNU General Public License as published by -// the Free Software Foundation, either version 3 of the License, or -// (at your option) any later version. - -// This software 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 General Public License for more details. - -// You should have received a copy of the GNU General Public License -// along with Parity. If not, see . - -//! Snapshot i/o. -//! Ways of writing and reading snapshots. This module supports writing and reading -//! snapshots of two different formats: packed and loose. -//! Packed snapshots are written to a single file, and loose snapshots are -//! written to multiple files in one directory. - -use std::collections::HashMap; -use std::fs::{self, File}; -use std::io::{self, Read, Seek, SeekFrom, Write}; -use std::path::{Path, PathBuf}; - -use cita_types::traits::LowerHex; -use cita_types::H256; -use rlp::{RlpStream, UntrustedRlp}; -use util::Bytes; - -use super::ManifestData; - -/// Something which can write snapshots. -/// Writing the same chunk multiple times will lead to implementation-defined -/// behavior, and is not advised. -pub trait SnapshotWriter { - /// Write a compressed block chunk. - fn write_block_chunk(&mut self, hash: H256, chunk: &[u8]) -> io::Result<()>; - - /// Complete writing. The manifest's chunk lists must be consistent - /// with the chunks written. - fn finish(self, manifest: ManifestData) -> io::Result<()> - where - Self: Sized; -} - -// (hash, len, offset) -#[derive(RlpEncodable, RlpDecodable)] -pub struct ChunkInfo(H256, u64, u64); - -/// A packed snapshot writer. This writes snapshots to a single concatenated file. -/// -/// The file format is very simple and consists of three parts: -/// [Concatenated chunk data] -/// [manifest as RLP] -/// [manifest start offset (8 bytes little-endian)] -/// -/// The manifest contains all the same information as a standard `ManifestData`, -/// but also maps chunk hashes to their lengths and offsets in the file -/// for easy reading. -pub struct PackedWriter { - pub file: File, - pub block_hashes: Vec, - pub cur_len: u64, -} - -impl PackedWriter { - /// Create a new "PackedWriter", to write into the file at the given path. - pub fn create(path: &Path) -> io::Result { - Ok(PackedWriter { - file: File::create(path)?, - block_hashes: Vec::new(), - cur_len: 0, - }) - } -} - -impl SnapshotWriter for PackedWriter { - fn write_block_chunk(&mut self, hash: H256, chunk: &[u8]) -> io::Result<()> { - self.file.write_all(chunk)?; - - let len = chunk.len() as u64; - self.block_hashes.push(ChunkInfo(hash, len, self.cur_len)); - - self.cur_len += len; - Ok(()) - } - - fn finish(mut self, manifest: ManifestData) -> io::Result<()> { - // we ignore the hashes fields of the manifest under the assumption that - // they are consistent with ours. - let mut stream = RlpStream::new_list(5); - stream - .append_list(&self.block_hashes) - .append(&manifest.state_root) - .append(&manifest.block_number) - .append(&manifest.block_hash) - .append(&manifest.last_proof); - - let manifest_rlp = stream.out(); - - self.file.write_all(&manifest_rlp)?; - let off = self.cur_len; - trace!(target: "snapshot_io", "writing manifest of len {} to offset {}", manifest_rlp.len(), off); - - let off_bytes: [u8; 8] = [ - off as u8, - (off >> 8) as u8, - (off >> 16) as u8, - (off >> 24) as u8, - (off >> 32) as u8, - (off >> 40) as u8, - (off >> 48) as u8, - (off >> 56) as u8, - ]; - - self.file.write_all(&off_bytes[..])?; - Ok(()) - } -} - -/// A "loose" writer writes chunk files into a directory. -pub struct LooseWriter { - dir: PathBuf, -} - -impl LooseWriter { - /// Create a new LooseWriter which will write into the given directory, - /// creating it if it doesn't exist. - pub fn create(path: PathBuf) -> io::Result { - fs::create_dir_all(&path)?; - - Ok(LooseWriter { dir: path }) - } - - // writing logic is the same for both kinds of chunks. - fn write_chunk(&mut self, hash: H256, chunk: &[u8]) -> io::Result<()> { - let mut file_path = self.dir.clone(); - file_path.push(hash.lower_hex()); - - let mut file = File::create(file_path)?; - file.write_all(chunk)?; - - Ok(()) - } -} - -impl SnapshotWriter for LooseWriter { - fn write_block_chunk(&mut self, hash: H256, chunk: &[u8]) -> io::Result<()> { - self.write_chunk(hash, chunk) - } - - fn finish(self, manifest: ManifestData) -> io::Result<()> { - let rlp = manifest.to_rlp(); - let mut path = self.dir.clone(); - path.push("MANIFEST"); - - let mut file = File::create(path)?; - file.write_all(&rlp[..])?; - - Ok(()) - } -} - -/// Something which can read compressed snapshots. -pub trait SnapshotReader { - /// Get the manifest data for this snapshot. - fn manifest(&self) -> &ManifestData; - - /// Get raw chunk data by hash. implementation defined behavior - /// if a chunk not in the manifest is requested. - fn chunk(&self, hash: H256) -> io::Result; -} - -/// Packed snapshot reader. -pub struct PackedReader { - file: File, - block_hashes: HashMap, // len, offset - manifest: ManifestData, -} - -impl PackedReader { - /// Create a new `PackedReader` for the file at the given path. - /// This will fail if any io errors are encountered or the file - /// is not a valid packed snapshot. - pub fn create(path: &Path) -> Result, crate::error::Error> { - let mut file = File::open(path)?; - let file_len = file.metadata()?.len(); - if file_len < 8 { - // ensure we don't seek before beginning. - return Ok(None); - } - - file.seek(SeekFrom::End(-8))?; - let mut off_bytes = [0u8; 8]; - - file.read_exact(&mut off_bytes[..])?; - - let manifest_off: u64 = (u64::from(off_bytes[7]) << 56) - + (u64::from(off_bytes[6]) << 48) - + (u64::from(off_bytes[5]) << 40) - + (u64::from(off_bytes[4]) << 32) - + (u64::from(off_bytes[3]) << 24) - + (u64::from(off_bytes[2]) << 16) - + (u64::from(off_bytes[1]) << 8) - + u64::from(off_bytes[0]); - - let manifest_len = file_len - manifest_off - 8; - trace!( - "loading manifest of length {} from offset {}", - manifest_len, - manifest_off, - ); - - let mut manifest_buf = vec![0; manifest_len as usize]; - - file.seek(SeekFrom::Start(manifest_off))?; - file.read_exact(&mut manifest_buf)?; - - let rlp = UntrustedRlp::new(&manifest_buf); - - let blocks: Vec = rlp.list_at(0)?; - - let manifest = ManifestData { - block_hashes: blocks.iter().map(|c| c.0).collect(), - state_root: rlp.val_at(1)?, - block_number: rlp.val_at(2)?, - block_hash: rlp.val_at(3)?, - last_proof: rlp.val_at(4)?, - }; - - Ok(Some(PackedReader { - file, - block_hashes: blocks.into_iter().map(|c| (c.0, (c.1, c.2))).collect(), - manifest, - })) - } -} - -impl SnapshotReader for PackedReader { - fn manifest(&self) -> &ManifestData { - &self.manifest - } - - fn chunk(&self, hash: H256) -> io::Result { - let &(len, off) = self - .block_hashes - .get(&hash) - .expect("only chunks in the manifest can be requested; qed"); - - let mut file = &self.file; - - file.seek(SeekFrom::Start(off))?; - let mut buf = vec![0u8; len as usize]; - - file.read_exact(&mut buf[..])?; - - Ok(buf) - } -} - -/// reader for "loose" snapshots -pub struct LooseReader { - dir: PathBuf, - manifest: ManifestData, -} - -impl LooseReader { - /// Create a new `LooseReader` which will read the manifest and chunk data from - /// the given directory. - pub fn create(mut dir: PathBuf) -> Result { - let mut manifest_buf = Vec::new(); - - dir.push("MANIFEST"); - let mut manifest_file = File::open(&dir)?; - manifest_file.read_to_end(&mut manifest_buf)?; - - let manifest = ManifestData::from_rlp(&manifest_buf[..])?; - - dir.pop(); - - Ok(LooseReader { dir, manifest }) - } -} - -impl SnapshotReader for LooseReader { - fn manifest(&self) -> &ManifestData { - &self.manifest - } - - fn chunk(&self, hash: H256) -> io::Result { - let mut path = self.dir.clone(); - path.push(hash.lower_hex()); - - let mut buf = Vec::new(); - let mut file = File::open(&path)?; - - file.read_to_end(&mut buf)?; - - Ok(buf) - } -} diff --git a/cita-chain/core/src/snapshot/mod.rs b/cita-chain/core/src/snapshot/mod.rs deleted file mode 100644 index e81ef3785..000000000 --- a/cita-chain/core/src/snapshot/mod.rs +++ /dev/null @@ -1,778 +0,0 @@ -// Copyright 2015-2017 Parity Technologies (UK) Ltd. -// This file is part of Parity. - -// This software is free software: you can redistribute it and/or modify -// it under the terms of the GNU General Public License as published by -// the Free Software Foundation, either version 3 of the License, or -// (at your option) any later version. - -// This software 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 General Public License for more details. - -// You should have received a copy of the GNU General Public License -// along with Parity. If not, see . - -//! Snapshot format and creation. - -//pub mod service; -pub mod error; -pub mod io; -pub mod service; - -// chunks around 4MB before compression -const PREFERRED_CHUNK_SIZE: usize = 4 * 1024 * 1024; - -// Maximal chunk size (decompressed) -// Snappy::decompressed_len estimation may sometimes yield results greater -// than PREFERRED_CHUNK_SIZE so allow some threshold here. -//const MAX_CHUNK_SIZE: usize = PREFERRED_CHUNK_SIZE / 4 * 5; -use crate::header::Header; - -use cita_types::H256; -use rlp::{DecoderError, Encodable, RlpStream, UntrustedRlp}; -use std::collections::{HashMap, VecDeque}; -use std::sync::atomic::{AtomicBool, AtomicUsize, Ordering}; -use std::sync::Arc; -use std::time::Duration; - -use crate::cita_db::kvdb::{DBTransaction, KeyValueDB}; -use hashable::Hashable; -use snappy; -use util::{Bytes, Mutex, BLOCKLIMIT}; - -use crate::basic_types::{LogBloom, LogBloomGroup}; -use crate::bloomchain::group::BloomGroupChain; -use crate::bloomchain::{Bloom, Number as BloomChainNumber}; - -pub use self::error::Error; -use self::io::SnapshotReader; -use self::io::SnapshotWriter; -use self::service::{Service, SnapshotService}; -use super::header::BlockNumber; -use crate::db::{CacheUpdatePolicy, Writable, COL_BODIES, COL_EXTRA, COL_HEADERS}; - -use crate::types::ids::BlockId; - -use crate::libchain::chain::Chain; -use crate::types::block::{Block, BlockBody}; -use crate::types::extras::{ - BlockReceipts, CurrentHash, CurrentHeight, CurrentProof, LogGroupPosition, -}; - -use libproto::Proof; - -use crate::receipt::Receipt; - -//#[cfg(test)] -//mod tests; - -/// A sink for produced chunks. -pub type ChunkSink<'a> = FnMut(&[u8]) -> Result<(), Error> + 'a; - -/// A progress indicator for snapshots. -#[derive(Debug, Default)] -pub struct Progress { - blocks: AtomicUsize, - size: AtomicUsize, - done: AtomicBool, -} - -impl Progress { - /// Get the number of accounts snapshotted thus far. - pub fn blocks(&self) -> usize { - self.blocks.load(Ordering::Relaxed) - } - - /// Get the written size of the snapshot in bytes. - pub fn size(&self) -> usize { - self.size.load(Ordering::Relaxed) - } - - /// Whether the snapshot is complete. - pub fn done(&self) -> bool { - self.done.load(Ordering::SeqCst) - } -} - -/// Statuses for restorations. -#[derive(PartialEq, Eq, Clone, Copy, Debug)] -pub enum RestorationStatus { - /// No restoration. - Inactive, - /// Ongoing restoration. - Ongoing { - /// Total number of block chunks. - block_chunks: u32, - /// Number of block chunks completed. - block_chunks_done: u32, - }, - /// Failed restoration. - Failed, -} - -/// Snapshot manifest type definition. -#[derive(Debug, Clone, PartialEq, Eq)] -pub struct ManifestData { - /// List of block chunk hashes. - pub block_hashes: Vec, - /// The final, expected state root. - pub state_root: H256, - // Block number this snapshot was taken at. - pub block_number: u64, - // Block hash this snapshot was taken at. - pub block_hash: H256, - // Last Block proof - pub last_proof: Proof, -} - -/// Snapshot manifest encode/decode. -impl ManifestData { - /// Encode the manifest data to rlp. - pub fn to_rlp(&self) -> Bytes { - let mut stream = RlpStream::new_list(4); - stream.append_list(&self.block_hashes); - stream.append(&self.state_root); - stream.append(&self.block_number); - stream.append(&self.block_hash); - stream.append(&self.last_proof); - - stream.out() - } - - /// Restore manifest data from raw bytes. - pub fn from_rlp(raw: &[u8]) -> Result { - let decoder = UntrustedRlp::new(raw); - - let block_hashes: Vec = decoder.list_at(0)?; - let state_root: H256 = decoder.val_at(1)?; - let block_number: u64 = decoder.val_at(2)?; - let block_hash: H256 = decoder.val_at(3)?; - let last_proof: Proof = decoder.val_at(4)?; - - Ok(ManifestData { - block_hashes, - state_root, - block_number, - block_hash, - last_proof, - }) - } -} - -/// snapshot using: given Executor+ starting block hash + database; writing into the given writer. -pub fn take_snapshot( - chain: &Arc, - block_at: u64, - writer: W, - p: &Progress, -) -> Result<(), Error> { - let block_hash = chain.block_hash_by_height(block_at).unwrap(); - - let start_header = chain - .block_header_by_hash(block_hash) - .ok_or_else(|| Error::InvalidStartingBlock(BlockId::Hash(block_hash)))?; - let state_root = start_header.state_root(); - - info!("Taking snapshot starting at block {}", block_at); - - let writer = Mutex::new(writer); - let block_hashes = chunk_secondary(chain, block_hash, &writer, p)?; - - info!("produced {} block chunks.", block_hashes.len()); - - // get last_proof from chain, it will be used by cita-bft when restoring. - let last_proof = if block_at == chain.get_current_height() { - chain.current_block_poof() - } else { - chain.get_block_proof_by_height(block_at) - } - .unwrap(); - - let manifest_data = ManifestData { - block_hashes, - state_root: *state_root, - block_number: block_at, - block_hash, - last_proof, - }; - - writer.into_inner().finish(manifest_data)?; - - p.done.store(true, Ordering::SeqCst); - - Ok(()) -} - -/// Returns a list of chunk hashes, with the first having the blocks furthest from the genesis. -pub fn chunk_secondary<'a>( - chain: &'a Chain, - start_hash: H256, - writer: &Mutex, - progress: &'a Progress, -) -> Result, Error> { - let mut chunk_hashes = Vec::new(); - let mut compressed_data = Vec::new(); - - { - let mut chunk_sink = |raw_data: &[u8]| { - compressed_data.clear(); - snappy::compress_to(raw_data, &mut compressed_data)?; - let hash = compressed_data.crypt_hash(); - let size = compressed_data.len(); - - writer.lock().write_block_chunk(hash, &compressed_data)?; - info!( - "wrote secondary chunk. hash: {:?}, size: {}, uncompressed size: {}", - hash, - size, - raw_data.len(), - ); - - progress.size.fetch_add(size, Ordering::SeqCst); - chunk_hashes.push(hash); - Ok(()) - }; - - BlockChunker { - chain, - rlps: VecDeque::new(), - current_hash: start_hash, - writer: &mut chunk_sink, - preferred_size: PREFERRED_CHUNK_SIZE, - } - .chunk_all()? - } - - Ok(chunk_hashes) -} - -/// Used to build block chunks. -struct BlockChunker<'a> { - chain: &'a Chain, - // block, receipt rlp pairs. - rlps: VecDeque, - current_hash: H256, - writer: &'a mut ChunkSink<'a>, - preferred_size: usize, -} - -impl<'a> BlockChunker<'a> { - // Repeatedly fill the buffers and writes out chunks, moving backwards from starting block hash. - // Loops until we reach the first desired block, and writes out the remainder. - fn chunk_all(&mut self) -> Result<(), Error> { - let mut loaded_size = 0; - let mut last = self.current_hash; - - let start_header = self - .chain - .block_header_by_hash(self.current_hash) - .ok_or_else(|| Error::BlockNotFound(self.current_hash))?; - let step = if start_header.number() < 100 { - 1 - } else { - start_header.number() / 100 - }; - - let genesis_hash = self - .chain - .block_hash_by_height(0) - .expect("Genesis hash should always exist"); - info!("Genesis_hash: {:?}", genesis_hash); - let mut blocks_num = 0; - - loop { - if self.current_hash == genesis_hash { - break; - } - - let mut s = RlpStream::new(); - let header = self - .chain - .block_header_by_hash(self.current_hash) - .ok_or_else(|| Error::BlockNotFound(self.current_hash))?; - header.clone().rlp_append(&mut s); - let header_rlp = s.out(); - - if blocks_num % step == 0 { - info!("current height: {:?}", header.number()); - } - - let pair: Vec = if blocks_num < BLOCKLIMIT { - let body_rlp = { - let body: BlockBody = self - .chain - .block_body(BlockId::Hash(self.current_hash)) - .ok_or_else(|| Error::BlockNotFound(self.current_hash))?; - let mut s = RlpStream::new(); - body.rlp_append(&mut s); - s.out() - }; - - let receipts = match self.chain.block_receipts(self.current_hash) { - Some(r) => r.receipts, - _ => Vec::new(), - }; - - let mut pair_stream = RlpStream::new_list(3); - pair_stream - .append_raw(&header_rlp, 1) - .append_list(&receipts) - .append_raw(&body_rlp, 1); - pair_stream.out() - } else { - let mut pair_stream = RlpStream::new_list(1); - pair_stream.append_raw(&header_rlp, 1); - pair_stream.out() - }; - - let new_loaded_size = loaded_size + pair.len(); - - // cut off the chunk if too large. - if new_loaded_size > self.preferred_size && !self.rlps.is_empty() { - self.write_chunk(last)?; - loaded_size = pair.len(); - } else { - loaded_size = new_loaded_size; - } - - self.rlps.push_front(pair); - - last = self.current_hash; - self.current_hash = *header.parent_hash(); - - blocks_num += 1; - } - - if loaded_size != 0 { - self.write_chunk(last)?; - } - - Ok(()) - } - - // write out the data in the buffers to a chunk on disk - // - // we preface each chunk with the parent of the first block's details, - // obtained from the details of the last block written. - fn write_chunk(&mut self, last: H256) -> Result<(), Error> { - trace!("prepared block chunk with {} blocks", self.rlps.len()); - - let last_header = self - .chain - .block_header_by_hash(last) - .ok_or_else(|| Error::BlockNotFound(last))?; - - let parent_number = last_header.number() - 1; - let parent_hash = last_header.parent_hash(); - - trace!("parent last written block: {}", parent_hash); - - let num_entries = self.rlps.len(); - let mut rlp_stream = RlpStream::new_list(2 + num_entries); - rlp_stream.append(&parent_number).append(parent_hash); - - for pair in self.rlps.drain(..) { - rlp_stream.append_raw(&pair, 1); - } - - let raw_data = rlp_stream.out(); - - (self.writer)(&raw_data)?; - - Ok(()) - } -} - -/// Brief info about inserted block. -#[derive(Clone)] -pub struct BlockInfo { - /// Block hash. - pub hash: H256, - /// Block number. - pub number: BlockNumber, -} - -/// Block extras update info. -pub struct ExtrasUpdate { - /// Block info. - pub info: BlockInfo, - /// Current block uncompressed rlp bytes - pub block: Block, - /// Modified block hashes. - pub block_hashes: HashMap, - /// Modified block receipts. - pub block_receipts: HashMap, - /// Modified blocks blooms. - pub blocks_blooms: HashMap, - // Modified transaction addresses (None signifies removed transactions). - //pub transactions_addresses: HashMap, -} - -/// Used to rebuild the state trie piece by piece. -pub struct BlockRebuilder { - chain: Arc, - db: Arc, - //_disconnected: Vec<(u64, H256)>, - best_number: u64, - best_hash: H256, - best_root: H256, - cur_proof: Proof, - fed_blocks: u64, - snapshot_blocks: u64, -} - -impl BlockRebuilder { - /// Create a new state rebuilder to write into the given backing DB. - pub fn new( - chain: Arc, - db: Arc, - manifest: &ManifestData, - snapshot_blocks: u64, - ) -> Self { - BlockRebuilder { - chain, - db, - //_disconnected: Vec::new(), - best_number: manifest.block_number, - best_hash: manifest.block_hash, - best_root: manifest.state_root, - cur_proof: manifest.last_proof.clone(), - fed_blocks: 0, - snapshot_blocks, - } - } - - /// Feed an uncompressed state chunk into the rebuilder. - pub fn feed( - &mut self, - chunk: &[u8], - abort_flag: &AtomicBool, - ) -> Result<(), crate::error::Error> { - let rlp = UntrustedRlp::new(chunk); - let item_count = rlp.item_count()?; - let num_blocks = (item_count - 2) as u64; - info!("restoring block chunk with {} blocks.", num_blocks); - - if self.fed_blocks + num_blocks > self.snapshot_blocks { - info!( - "already {}, now {}, total {}", - self.fed_blocks, num_blocks, self.snapshot_blocks - ); - return Err( - Error::TooManyBlocks(self.snapshot_blocks, self.fed_blocks + num_blocks).into(), - ); - } - - // todo: assert here that these values are consistent with chunks being in order. - let mut cur_number = rlp.val_at::(0)? + 1; - //let mut parent_hash = rlp.val_at::(1)?; - - for idx in 2..item_count { - if !abort_flag.load(Ordering::SeqCst) { - return Err(Error::RestorationAborted.into()); - } - - let mut block = Block::default(); - let pair = rlp.at(idx)?; - //let block_rlp = pair.at(0)?.as_raw().to_owned(); - //let block: Block = ::rlp::decode(block_rlp.as_slice()); - let header_rlp = pair.at(0)?.as_raw().to_owned(); - let header: Header = ::rlp::decode(header_rlp.as_slice()); - { - block.set_header(header.clone()); - } - - // if height + 100 < max_height, there will be bodies and receipts. - let mut have_body: bool = false; - - let receipts: Vec = pair.list_at(1).unwrap_or_default(); - - if let Ok(b) = pair.at(2) { - have_body = true; - let body_rlp = b.as_raw().to_owned(); - let body = ::rlp::decode(body_rlp.as_slice()); - block.set_body(body); - }; - - // TODO: abridged_block - /*let receipts_root = ordered_trie_root(pair.at(1)?.iter().map(|r| r.as_raw())); - let block = abridged_block.to_block(parent_hash, cur_number, receipts_root)?; - let block_bytes = block.rlp_bytes();*/ - - let is_best = cur_number == self.best_number; - - if is_best { - if header.hash().unwrap() != self.best_hash { - return Err(Error::WrongBlockHash( - cur_number, - self.best_hash, - header.hash().unwrap(), - ) - .into()); - } - - if header.state_root() != &self.best_root { - return Err(Error::WrongStateRoot(self.best_root, *header.state_root()).into()); - } - } - - // TODO: verify - //verify_old_block(&mut self.rng, &block.header, engine, &self.chain, is_best)?; - - let mut batch = self.db.transaction(); - - self.insert_unordered_block(&mut batch, &block, receipts, have_body, is_best); - - self.db.write_buffered(batch); - - // TODO: update current Chain. - //self.chain.commit(); - - //parent_hash = view!(BlockView, &block_bytes).hash(); - cur_number += 1; - } - - self.fed_blocks += num_blocks; - - Ok(()) - } - - fn insert_unordered_block( - &mut self, - batch: &mut DBTransaction, - block: &Block, - receipts: Vec, - have_body: bool, - is_best: bool, - ) { - let header = block.header(); - let hash = header.hash().unwrap(); - let height = header.number(); - - // store block in db - batch.write(COL_HEADERS, &height, &header.clone()); - if have_body { - let body = block.body(); - batch.write(COL_BODIES, &height, &body.clone()); - } - - // COL_EXTRA - let info = BlockInfo { - hash, - number: height, - }; - - self.prepare_update( - batch, - ExtrasUpdate { - block_hashes: self.prepare_block_hashes_update(block, &info), - block_receipts: self.prepare_block_receipts_update(receipts, &info, have_body), - blocks_blooms: self.prepare_block_blooms_update(block, &info), - //transactions_addresses: self.prepare_transaction_addresses_update(block, &info), - info, - block: block.clone(), - }, - is_best, - ); - } - - /// This function returns modified block hashes. - fn prepare_block_hashes_update( - &self, - _block: &Block, - info: &BlockInfo, - ) -> HashMap { - let mut block_hashes = HashMap::new(); - - block_hashes.insert(info.hash, info.number); - - block_hashes - } - - /// This function returns modified block receipts. - fn prepare_block_receipts_update( - &self, - receipts: Vec, - info: &BlockInfo, - have_body: bool, - ) -> HashMap { - let mut block_receipts = HashMap::new(); - - if have_body { - block_receipts.insert(info.hash, BlockReceipts::new(receipts)); - } - - block_receipts - } - - /// This functions returns modified blocks blooms. - /// - /// To accelerate blooms lookups, blooms are stored in multiple - /// layers (BLOOM_LEVELS, currently 3). - /// ChainFilter is responsible for building and rebuilding these layers. - /// It returns them in HashMap, where values are Blooms and - /// keys are BloomIndexes. BloomIndex represents bloom location on one - /// of these layers. - /// - /// To reduce number of queries to database, block blooms are stored - /// in BlocksBlooms structure which contains info about several - /// (BLOOM_INDEX_SIZE, currently 16) consecutive blocks blooms. - /// - /// Later, BloomIndexer is used to map bloom location on filter layer (BloomIndex) - /// to bloom location in database (BlocksBloomLocation). - /// - fn prepare_block_blooms_update( - &self, - block: &Block, - info: &BlockInfo, - ) -> HashMap { - let header = block.header(); - - let log_bloom = LogBloom::from(header.log_bloom().to_vec().as_slice()); - let log_blooms: HashMap = if log_bloom.is_zero() { - HashMap::new() - } else { - let bgroup = BloomGroupChain::new(self.chain.blooms_config, &*self.chain); - bgroup - .insert( - info.number as BloomChainNumber, - Bloom::from(Into::<[u8; 256]>::into(log_bloom)), - ) - .into_iter() - .map(|p| (From::from(p.0), From::from(p.1))) - .collect() - }; - log_blooms - } - - fn prepare_update(&self, batch: &mut DBTransaction, update: ExtrasUpdate, is_best: bool) { - { - let mut write_receipts = self.chain.block_receipts.write(); - batch.extend_with_cache( - COL_EXTRA, - &mut *write_receipts, - update.block_receipts, - CacheUpdatePolicy::Remove, - ); - } - - { - let mut write_blocks_blooms = self.chain.blocks_blooms.write(); - // update best block - // update all existing blooms groups - batch.extend_with_cache( - COL_EXTRA, - &mut *write_blocks_blooms, - update.blocks_blooms, - CacheUpdatePolicy::Overwrite, - ); - } - - // These cached values must be updated last with all four locks taken to avoid - // cache decoherence - { - if is_best { - batch.write(COL_EXTRA, &CurrentHash, &update.info.hash); - batch.write(COL_EXTRA, &CurrentHeight, &update.info.number); - } - - let mut write_hashes = self.chain.block_hashes.write(); - batch.write_with_cache( - COL_EXTRA, - &mut *write_hashes, - update.info.hash, - update.info.number as BlockNumber, - CacheUpdatePolicy::Overwrite, - ); - } - } - - /// Glue together any disconnected chunks and check that the chain is complete. - fn finalize(&self) -> Result<(), crate::error::Error> { - let mut batch = self.db.transaction(); - - let genesis_block = self - .chain - .block_by_height(0) - .expect("Get genesis block failed"); - batch.write(COL_HEADERS, &0, &genesis_block.header.clone()); - - batch.write(COL_BODIES, &0, &genesis_block.body.clone()); - batch.write(COL_EXTRA, &CurrentProof, &self.cur_proof); - - self.db.write_buffered(batch); - Ok(()) - } -} - -// helper for reading chunks from arbitrary reader and feeding them into the -// service. -pub fn restore_using( - snapshot: &Arc, - reader: &R, - recover: bool, -) -> Result<(), String> { - let manifest = reader.manifest(); - - info!( - "Restoring to block #{} (0x{:?})", - manifest.block_number, manifest.block_hash - ); - - snapshot - .init_restore(manifest.clone(), recover) - .map_err(|e| format!("Failed to begin restoration: {}", e))?; - - let num_block = manifest.block_hashes.len(); - - let informant_handle = snapshot.clone(); - ::std::thread::spawn(move || { - while let RestorationStatus::Ongoing { - block_chunks_done, .. - } = informant_handle.status() - { - info!( - "Processed {}/{} block chunks.", - block_chunks_done, num_block - ); - ::std::thread::sleep(Duration::from_secs(5)); - } - }); - - info!("Restoring block"); - for &block_hash in &manifest.block_hashes { - if snapshot.status() == RestorationStatus::Failed { - return Err("Restoration failed".into()); - } - - let chunk = reader.chunk(block_hash).map_err(|e| { - format!( - "Encountered error while reading chunk {:?}: {}", - block_hash, e - ) - })?; - - let hash = chunk.crypt_hash(); - if hash != block_hash { - return Err(format!( - "Mismatched chunk hash. Expected {:?}, got {:?}", - block_hash, hash - )); - } - - snapshot.feed_block_chunk(block_hash, &chunk); - } - - match snapshot.status() { - RestorationStatus::Ongoing { .. } => { - Err("Snapshot file is incomplete and missing chunks.".into()) - } - RestorationStatus::Failed => Err("Snapshot restoration failed.".into()), - RestorationStatus::Inactive => { - info!("Restoration complete."); - Ok(()) - } - } -} diff --git a/cita-chain/core/src/snapshot/service.rs b/cita-chain/core/src/snapshot/service.rs deleted file mode 100644 index 2118f64ce..000000000 --- a/cita-chain/core/src/snapshot/service.rs +++ /dev/null @@ -1,509 +0,0 @@ -// Copyright 2015-2017 Parity Technologies (UK) Ltd. -// This file is part of Parity. - -// This software is free software: you can redistribute it and/or modify -// it under the terms of the GNU General Public License as published by -// the Free Software Foundation, either version 3 of the License, or -// (at your option) any later version. - -// This software 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 General Public License for more details. - -// You should have received a copy of the GNU General Public License -// along with Parity. If not, see . - -//! Snapshot network service implementation. - -use std::collections::HashSet; -use std::fs; -use std::io::ErrorKind; -use std::path::PathBuf; -use std::sync::atomic::{AtomicBool, AtomicUsize, Ordering}; -use std::sync::Arc; -use std::usize::MAX; - -use super::io::{LooseReader, LooseWriter, SnapshotReader, SnapshotWriter}; -use super::{BlockRebuilder, ManifestData, RestorationStatus}; - -use crate::error::Error; -use cita_types::H256; - -use crate::cita_db::kvdb::{Database, DatabaseConfig}; -use snappy; -use util::Bytes; -use util::UtilError; -use util::{Mutex, RwLock, RwLockReadGuard}; - -use crate::libchain::chain::{get_chain, get_chain_body_height, Chain}; - -use crate::filters::PollManager; - -/// External database restoration handler -pub trait DatabaseRestore: Send + Sync { - /// Restart with a new backend. Takes ownership of passed database and moves it to a new location. - fn restore_db(&self, new_db: &str) -> Result<(), Error>; -} - -impl DatabaseRestore for Chain { - /// Restart the client with a new backend - fn restore_db(&self, new_db: &str) -> Result<(), Error> { - info!("Replacing client database with {:?}", new_db); - - self.db.restore(new_db)?; - - // replace chain - let header = get_chain(&*self.db.clone()).expect("Get chain failed"); - - let current_height = header.number(); - - // header - *self.current_header.write() = header.clone(); - - self.current_height - .store(current_height as usize, Ordering::SeqCst); - - if let Some(height) = get_chain_body_height(&*self.db.clone()) { - self.max_store_height - .store(height as usize, Ordering::SeqCst); - } - - let mut block_map = self.block_map.write(); - block_map.clear(); - - let mut block_header = self.block_headers.write(); - block_header.clear(); - block_header.shrink_to_fit(); - - let mut block_bodies = self.block_bodies.write(); - block_bodies.clear(); - block_bodies.shrink_to_fit(); - - let mut block_hashes = self.block_hashes.write(); - block_hashes.clear(); - block_hashes.shrink_to_fit(); - - let mut transaction_addresses = self.transaction_addresses.write(); - transaction_addresses.clear(); - transaction_addresses.shrink_to_fit(); - - let mut blocks_blooms = self.blocks_blooms.write(); - blocks_blooms.clear(); - blocks_blooms.shrink_to_fit(); - - let mut block_receipts = self.block_receipts.write(); - block_receipts.clear(); - block_receipts.shrink_to_fit(); - - let mut cache_man = self.cache_man.lock(); - cache_man.collect_garbage(MAX, |_| MAX); - - *self.polls_filter.lock() = PollManager::default(); - - Ok(()) - } -} - -/// State restoration manager. -struct Restoration { - manifest: ManifestData, - block_chunks_left: HashSet, - secondary: Box, - writer: Option, - db: Arc, -} - -struct RestorationParams<'a> { - manifest: ManifestData, // manifest to base restoration on. - db_path: PathBuf, // database path - db_config: &'a DatabaseConfig, // configuration for the database. - writer: Option, // writer for recovered snapshot.. - chain: Arc, -} - -impl Restoration { - // make a new restoration using the given parameters. - fn create(params: RestorationParams) -> Result { - let manifest = params.manifest; - - let block_chunks = manifest.block_hashes.iter().cloned().collect(); - - let raw_db = Arc::new( - Database::open(params.db_config, &*params.db_path.to_string_lossy()) - .map_err(UtilError::from)?, - ); - - let block_rebuilder = BlockRebuilder::new( - params.chain.clone(), - raw_db.clone(), - &manifest, - manifest.block_number, - ); - - Ok(Restoration { - manifest, - block_chunks_left: block_chunks, - secondary: Box::new(block_rebuilder), - writer: params.writer, - db: raw_db, - }) - } - - // feeds a block chunk - fn feed_blocks(&mut self, hash: H256, chunk: &[u8], flag: &AtomicBool) -> Result<(), Error> { - if self.block_chunks_left.contains(&hash) { - let mut decompressed_data = Vec::new(); - snappy::decompress_to(chunk, &mut decompressed_data)?; - - self.secondary.feed(&decompressed_data, flag)?; - - if let Some(ref mut writer) = self.writer.as_mut() { - writer.write_block_chunk(hash, chunk)?; - } - - self.block_chunks_left.remove(&hash); - } - - Ok(()) - } - - // finish up restoration. - fn finalize(self) -> Result<(), Error> { - if !self.is_done() { - return Ok(()); - } - - // connect out-of-order chunks and verify chain integrity. - self.secondary.finalize()?; - - if let Some(writer) = self.writer { - writer.finish(self.manifest)?; - } - - Ok(()) - } - - // is everything done? - fn is_done(&self) -> bool { - self.block_chunks_left.is_empty() - } -} - -/// Snapshot service parameters. -pub struct ServiceParams { - /// Database configuration options. - pub db_config: DatabaseConfig, - /// Usually "/snapshot" - pub snapshot_root: PathBuf, - /// A handle for database restoration. - pub db_restore: Arc, - pub chain: Arc, -} - -/// `SnapshotService` implementation. -/// This controls taking snapshots and restoring from them. -pub struct Service { - restoration: Mutex>, - snapshot_root: PathBuf, - db_config: DatabaseConfig, - status: Mutex, - reader: RwLock>, - block_chunks: AtomicUsize, - db_restore: Arc, - progress: super::Progress, - taking_snapshot: AtomicBool, - restoring_snapshot: AtomicBool, - chain: Arc, -} - -impl Service { - /// Create a new snapshot service from the given parameters. - pub fn create(params: ServiceParams) -> Result { - let mut service = Service { - restoration: Mutex::new(None), - snapshot_root: params.snapshot_root, - db_config: params.db_config, - status: Mutex::new(RestorationStatus::Inactive), - reader: RwLock::new(None), - block_chunks: AtomicUsize::new(0), - db_restore: params.db_restore, - progress: Default::default(), - taking_snapshot: AtomicBool::new(false), - restoring_snapshot: AtomicBool::new(false), - chain: params.chain.clone(), - }; - - // create the root snapshot dir if it doesn't exist. - if let Err(e) = fs::create_dir_all(&service.snapshot_root) { - if e.kind() != ErrorKind::AlreadyExists { - return Err(e.into()); - } - } - - // delete the temporary restoration dir if it does exist. - if let Err(e) = fs::remove_dir_all(service.restoration_dir()) { - if e.kind() != ErrorKind::NotFound { - return Err(e.into()); - } - } - - // delete the temporary snapshot dir if it does exist. - if let Err(e) = fs::remove_dir_all(service.temp_snapshot_dir()) { - if e.kind() != ErrorKind::NotFound { - return Err(e.into()); - } - } - - let reader = LooseReader::create(service.snapshot_dir()).ok(); - *service.reader.get_mut() = reader; - - Ok(service) - } - - // get the current snapshot dir. - fn snapshot_dir(&self) -> PathBuf { - let mut dir = self.snapshot_root.clone(); - dir.push("current"); - dir - } - - // get the temporary snapshot dir. - fn temp_snapshot_dir(&self) -> PathBuf { - let mut dir = self.snapshot_root.clone(); - dir.push("in_progress"); - dir - } - - // get the restoration directory. - fn restoration_dir(&self) -> PathBuf { - let mut dir = self.snapshot_root.clone(); - dir.push("restoration"); - dir - } - - // restoration db path. - fn restoration_db(&self) -> PathBuf { - let mut dir = self.restoration_dir(); - dir.push("db"); - dir - } - - // temporary snapshot recovery path. - fn temp_recovery_dir(&self) -> PathBuf { - let mut dir = self.restoration_dir(); - dir.push("temp"); - dir - } - - // replace one the client's database with our own. - fn replace_client_db(&self) -> Result<(), Error> { - let our_db = self.restoration_db(); - - self.db_restore.restore_db(&*our_db.to_string_lossy())?; - Ok(()) - } - - /// Get a reference to the snapshot reader. - pub fn reader(&self) -> RwLockReadGuard> { - self.reader.read() - } - - /// Tick the snapshot service. This will log any active snapshot - /// being taken. - pub fn tick(&self) { - if self.progress.done() || !self.taking_snapshot.load(Ordering::SeqCst) { - return; - } - - let _p = &self.progress; - } - - /// Initialize the restoration synchronously. - /// The recover flag indicates whether to recover the restored snapshot. - pub fn init_restore(&self, manifest: ManifestData, recover: bool) -> Result<(), Error> { - let rest_dir = self.restoration_dir(); - - let mut res = self.restoration.lock(); - - self.block_chunks.store(0, Ordering::SeqCst); - - // tear down existing restoration. - *res = None; - - // delete and restore the restoration dir. - if let Err(e) = fs::remove_dir_all(&rest_dir) { - match e.kind() { - ErrorKind::NotFound => {} - _ => return Err(e.into()), - } - } - - fs::create_dir_all(&rest_dir)?; - - // make new restoration. - let writer = if recover { - Some(LooseWriter::create(self.temp_recovery_dir())?) - } else { - None - }; - - let params = RestorationParams { - chain: self.chain.clone(), - manifest, - db_path: self.restoration_db(), - db_config: &self.db_config, - writer, - }; - - let block_chunks = params.manifest.block_hashes.len(); - - *res = Some(Restoration::create(params)?); - - *self.status.lock() = RestorationStatus::Ongoing { - block_chunks: block_chunks as u32, - block_chunks_done: self.block_chunks.load(Ordering::SeqCst) as u32, - }; - - self.restoring_snapshot.store(true, Ordering::SeqCst); - Ok(()) - } - - // finalize the restoration. this accepts an already-locked - // restoration as an argument -- so acquiring it again _will_ - // lead to deadlock. - fn finalize_restoration(&self, rest: &mut Option) -> Result<(), Error> { - info!("finalizing restoration"); - - let recover = rest.as_ref().map_or(false, |rest| rest.writer.is_some()); - - // destroy the restoration before replacing databases and snapshot. - rest.take().map(Restoration::finalize).unwrap_or(Ok(()))?; - - self.replace_client_db()?; - - if recover { - let mut reader = self.reader.write(); - *reader = None; // destroy the old reader if it existed. - - let snapshot_dir = self.snapshot_dir(); - - if snapshot_dir.exists() { - trace!( - "removing old snapshot dir at {}", - snapshot_dir.to_string_lossy(), - ); - fs::remove_dir_all(&snapshot_dir)?; - } - - trace!("copying restored snapshot files over"); - fs::rename(self.temp_recovery_dir(), &snapshot_dir)?; - - *reader = Some(LooseReader::create(snapshot_dir)?); - } - - fs::remove_dir_all(&self.snapshot_root)?; - *self.status.lock() = RestorationStatus::Inactive; - - Ok(()) - } - - /// Feed a chunk of either kind. no-op if no restoration or status is wrong. - fn feed_chunk(&self, hash: H256, chunk: &[u8]) -> Result<(), Error> { - let (result, db) = { - let mut restoration = self.restoration.lock(); - - match self.status() { - RestorationStatus::Inactive | RestorationStatus::Failed => return Ok(()), - RestorationStatus::Ongoing { .. } => { - let (res, db) = { - let rest = match *restoration { - Some(ref mut r) => r, - None => return Ok(()), - }; - - ( - rest.feed_blocks(hash, chunk, &self.restoring_snapshot) - .map(|_| rest.is_done()), - rest.db.clone(), - ) - }; - - let res = match res { - Ok(is_done) => { - self.block_chunks.fetch_add(1, Ordering::SeqCst); - - if is_done { - db.flush().map_err(UtilError::from)?; - drop(db); - return self.finalize_restoration(&mut *restoration); - } - Ok(()) - } - other => other.map(drop), - }; - (res, db) - } - } - }; - result.and_then(|_| db.flush().map_err(|e| UtilError::from(e).into())) - } - - /// Feed a state chunk to be processed synchronously. - pub fn feed_block_chunk(&self, hash: H256, chunk: &[u8]) { - match self.feed_chunk(hash, chunk) { - Ok(()) => (), - Err(e) => { - warn!("Encountered error during block restoration: {}", e); - *self.restoration.lock() = None; - *self.status.lock() = RestorationStatus::Failed; - let _ = fs::remove_dir_all(self.restoration_dir()); - } - } - } -} - -impl SnapshotService for Service { - fn chunk(&self, hash: H256) -> Option { - self.reader.read().as_ref().and_then(|r| r.chunk(hash).ok()) - } - - fn status(&self) -> RestorationStatus { - let mut cur_status = self.status.lock(); - if let RestorationStatus::Ongoing { - ref mut block_chunks_done, - .. - } = *cur_status - { - *block_chunks_done = self.block_chunks.load(Ordering::SeqCst) as u32; - } - - *cur_status - } - - fn abort_restore(&self) { - self.restoring_snapshot.store(false, Ordering::SeqCst); - *self.restoration.lock() = None; - *self.status.lock() = RestorationStatus::Inactive; - } -} -/// The interface for a snapshot network service. -/// This handles: -/// - restoration of snapshots to temporary databases. -/// - responding to queries for snapshot manifests and chunks -pub trait SnapshotService: Sync + Send { - /// Get raw chunk for a given hash. - fn chunk(&self, hash: H256) -> Option; - - /// Ask the snapshot service for the restoration status. - fn status(&self) -> RestorationStatus; - - /// Abort an in-progress restoration if there is one. - fn abort_restore(&self); -} - -impl Drop for Service { - fn drop(&mut self) { - self.abort_restore(); - } -} diff --git a/cita-chain/src/block_processor.rs b/cita-chain/src/block_processor.rs index 4ca7dfd7e..6e7e8779b 100644 --- a/cita-chain/src/block_processor.rs +++ b/cita-chain/src/block_processor.rs @@ -1,19 +1,16 @@ -// CITA -// Copyright 2016-2019 Cryptape Technologies LLC. - -// This program is free software: you can redistribute it -// and/or modify it under the terms of the GNU 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 General Public License for more details. - -// You should have received a copy of the GNU General Public License -// along with this program. If not, see . +// Copyright Cryptape Technologies LLC. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. use core::libchain::chain::Chain; use libproto::executor::ExecutedResult; diff --git a/cita-chain/src/forward.rs b/cita-chain/src/forward.rs index d82074f2d..3f8268e0e 100644 --- a/cita-chain/src/forward.rs +++ b/cita-chain/src/forward.rs @@ -1,59 +1,43 @@ -// CITA -// Copyright 2016-2019 Cryptape Technologies LLC. +// Copyright Cryptape Technologies LLC. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. -// This program is free software: you can redistribute it -// and/or modify it under the terms of the GNU 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 General Public License for more details. - -// You should have received a copy of the GNU General Public License -// along with this program. If not, see . +use std::convert::Into; +use std::mem; +use std::sync::atomic::Ordering; +use std::sync::Arc; -use crate::types::filter::Filter; -use crate::types::ids::BlockId; use cita_types::H256; -use core::filters::eth_filter::EthFilter; +use core::filters::rpc_filter::RpcFilter as FilterMethod; use core::libchain::chain::{BlockInQueue, Chain}; -use core::libchain::OpenBlock; use error::ErrorCode; use jsonrpc_types::rpc_types::{ BlockNumber as RpcBlockNumber, BlockParamsByHash, BlockParamsByNumber, Filter as RpcFilter, Log as RpcLog, Receipt as RpcReceipt, RpcBlock, }; use libproto::router::{MsgType, RoutingKey, SubModules}; -use libproto::snapshot::{Cmd, Resp, SnapshotReq, SnapshotResp}; use libproto::{ request, response, Block as ProtobufBlock, BlockTxHashes, BlockTxHashesReq, BlockWithProof, - ExecutedResult, Message, OperateType, Proof, ProofType, Request_oneof_req as Request, - SyncRequest, SyncResponse, + ExecutedResult, Message, OperateType, ProofType, Request_oneof_req as Request, SyncRequest, + SyncResponse, TryFrom, TryInto, }; -use libproto::{TryFrom, TryInto}; use proof::BftProof; use pubsub::channel::Sender; use serde_json; -use std::convert::Into; -use std::mem; -use std::sync::atomic::Ordering; -use std::sync::Arc; -use std::thread; -use std::time::Duration; - -use crate::cita_db::kvdb::DatabaseConfig; -use cita_directories::DataPath; -use core::db; -use std::fs::File; -use std::path::Path; -use core::snapshot; -use core::snapshot::io::{PackedReader, PackedWriter, SnapshotReader}; -use core::snapshot::service::{Service as SnapshotService, ServiceParams as SnapServiceParams}; -use core::snapshot::Progress; +use crate::types::block::OpenBlock; +use crate::types::block_number::BlockTag; +use crate::types::filter::Filter; /// Message forwarding and query data #[derive(Clone)] @@ -122,11 +106,6 @@ impl Forward { self.deal_block_tx_req(&block_tx_hashes_req); } - routing_key!(Snapshot >> SnapshotReq) => { - let snapshot_req = msg.take_snapshot_req().unwrap(); - self.deal_snapshot_req(&snapshot_req); - } - _ => { error!("forward dispatch msg found error key {}!!!!", key); } @@ -220,7 +199,7 @@ impl Forward { Request::transaction_receipt(hash) => { let tx_hash = H256::from_slice(&hash); - let receipt = self.chain.localized_receipt(tx_hash); + let receipt = self.chain.get_rich_receipt(tx_hash); if let Some(receipt) = receipt { let rpc_receipt: RpcReceipt = receipt.into(); let serialized = serde_json::to_string(&rpc_receipt).unwrap(); @@ -312,7 +291,7 @@ impl Forward { Request::filter_changes(filter_id) => { trace!("filter_changes's id is {:?}", filter_id); - let log = self.chain.filter_changes(filter_id as usize).unwrap(); + let log = self.chain.get_filter_changes(filter_id as usize).unwrap(); trace!("Log is: {:?}", log); response.set_filter_changes(serde_json::to_string(&log).unwrap()); } @@ -321,7 +300,7 @@ impl Forward { trace!("filter_log's id is {:?}", filter_id); let log = self .chain - .filter_logs(filter_id as usize) + .get_filter_logs(filter_id as usize) .unwrap_or_default(); trace!("Log is: {:?}", log); response.set_filter_logs(serde_json::to_string(&log).unwrap()); @@ -464,7 +443,7 @@ impl Forward { .into_iter() .filter(|height| *height <= self.chain.get_current_height()) { - if let Some(block) = self.chain.block(BlockId::Number(height)) { + if let Some(block) = self.chain.block(BlockTag::Height(height)) { res_vec.mut_blocks().push(block.protobuf()); //push double if height == self.chain.get_current_height() { @@ -599,7 +578,10 @@ impl Forward { fn deal_block_tx_req(&self, block_tx_hashes_req: &BlockTxHashesReq) { let block_height = block_tx_hashes_req.get_height(); - if let Some(tx_hashes) = self.chain.transaction_hashes(BlockId::Number(block_height)) { + if let Some(tx_hashes) = self + .chain + .transaction_hashes(BlockTag::Height(block_height)) + { //prepare and send the block tx hashes to auth let mut block_tx_hashes = BlockTxHashes::new(); block_tx_hashes.set_height(block_height); @@ -624,153 +606,4 @@ impl Forward { warn!("get block's tx hashes for height:{} error", block_height); } } - - fn deal_snapshot_req(&self, snapshot_req: &SnapshotReq) { - match snapshot_req.cmd { - Cmd::Snapshot => { - info!("snapshot: receive Snapshot::Snapshot {:?}", snapshot_req); - let chain = self.chain.clone(); - let ctx_pub = self.ctx_pub.clone(); - let snapshot_req = snapshot_req.clone(); - let snapshot_builder = thread::Builder::new().name("snapshot_chain".into()); - let _ = snapshot_builder.spawn(move || { - take_snapshot(&chain, &snapshot_req); - snapshot_response(&ctx_pub, Resp::SnapshotAck, true, None, None); - info!("snapshot: Taking snapshot finished!!!"); - }); - } - Cmd::Begin => { - info!("snapshot: receive Snapshot::Begin: {:?}", snapshot_req); - let mut is_snapshot = self.chain.is_snapshot.write(); - *is_snapshot = true; - snapshot_response(&self.ctx_pub, Resp::BeginAck, true, None, None); - } - Cmd::Restore => { - info!("snapshot: receive Snapshot::Restore {:?}", snapshot_req); - match restore_snapshot(&self.chain.clone(), snapshot_req) { - Ok(proof) => { - let height = self.chain.get_current_height(); - snapshot_response( - &self.ctx_pub, - Resp::RestoreAck, - true, - Some(height), - Some(proof), - ); - } - Err(err) => { - error!("snapshot: snapshot restore failed: {:?}", err); - snapshot_response(&self.ctx_pub, Resp::RestoreAck, false, None, None); - } - } - } - Cmd::Clear => { - info!("snapshot: receive Snapshot::Clear: {:?}", snapshot_req); - snapshot_response(&self.ctx_pub, Resp::ClearAck, true, None, None); - } - Cmd::End => { - info!("snapshot: receive Snapshot::End {:?}", snapshot_req); - let chain = self.chain.clone(); - let ctx_pub = self.ctx_pub.clone(); - thread::spawn(move || { - thread::sleep(Duration::new(3, 0)); - // broadcast status and rich-status. - chain.broadcast_current_status(&ctx_pub); - - let mut is_snapshot = chain.is_snapshot.write(); - *is_snapshot = false; - snapshot_response(&ctx_pub, Resp::EndAck, true, None, None); - }); - } - } - } -} - -fn take_snapshot(chain: &Arc, snapshot_req: &SnapshotReq) { - // use given path - let file_name = snapshot_req.file.clone() + "_chain.rlp"; - let writer = PackedWriter { - file: File::create(file_name).unwrap(), //TODO:use given path - block_hashes: Vec::new(), - cur_len: 0, - }; - - // use given height: ancient block, or latest - let mut block_at = snapshot_req.get_end_height(); - let current_height = chain.get_current_height(); - if block_at == 0 || block_at > current_height { - warn!( - "snapshot: snapshot block height is equal to 0 or bigger than current height, \ - and be set to current height!" - ); - block_at = current_height; - } - - let progress = Arc::new(Progress::default()); - - snapshot::take_snapshot(chain, block_at, writer, &*progress).unwrap(); -} - -fn restore_snapshot(chain: &Arc, snapshot_req: &SnapshotReq) -> Result { - let file_name = snapshot_req.file.clone() + "_chain.rlp"; - let reader = PackedReader::create(Path::new(&file_name)) - .map_err(|e| format!("snapshot: Couldn't open snapshot file: {}", e)) - .and_then(|x| x.ok_or_else(|| "snapshot: Snapshot file has invalid format.".into())); - let reader = match reader { - Ok(r) => r, - Err(e) => { - warn!("snapshot: get reader failed: {:?}", e); - return Err(e); - } - }; - - let db_config = DatabaseConfig::with_columns(db::NUM_COLUMNS); - let snap_path = DataPath::root_node_path() + "/snapshot_chain"; - let snapshot_params = SnapServiceParams { - db_config: db_config.clone(), - snapshot_root: snap_path.into(), - db_restore: chain.clone(), - chain: chain.clone(), - }; - - let snapshot = SnapshotService::create(snapshot_params).unwrap(); - let snapshot = Arc::new(snapshot); - match snapshot::restore_using(&snapshot, &reader, true) { - Ok(_) => { - // return proof - let proof = reader.manifest().last_proof.clone(); - Ok(proof) - } - Err(e) => { - warn!("snapshot: restore_using failed: {:?}", e); - Err(e) - } - } -} - -fn snapshot_response( - sender: &Sender<(String, Vec)>, - ack: Resp, - flag: bool, - height: Option, - proof: Option, -) { - info!("snapshot: snapshot_response ack: {:?}, flag: {}", ack, flag); - let mut resp = SnapshotResp::new(); - resp.set_resp(ack); - resp.set_flag(flag); - if let Some(height) = height { - resp.set_height(height); - } - if let Some(proof) = proof { - resp.set_proof(proof); - } - - let msg: Message = resp.into(); - sender - .send(( - routing_key!(Chain >> SnapshotResp).into(), - msg.try_into().unwrap(), - )) - .unwrap(); } diff --git a/cita-chain/src/main.rs b/cita-chain/src/main.rs index 56ec6733d..66469e99a 100644 --- a/cita-chain/src/main.rs +++ b/cita-chain/src/main.rs @@ -1,19 +1,16 @@ -// CITA -// Copyright 2016-2019 Cryptape Technologies LLC. - -// This program is free software: you can redistribute it -// and/or modify it under the terms of the GNU 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 General Public License for more details. - -// You should have received a copy of the GNU General Public License -// along with this program. If not, see . +// Copyright Cryptape Technologies LLC. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. //! ## Summary //! One of CITA's core components that processing blocks and transaction storage, @@ -73,25 +70,24 @@ extern crate libproto; extern crate cita_logger as logger; #[macro_use] extern crate util; -extern crate db as cita_db; mod block_processor; mod forward; +use std::sync::Arc; +use std::thread; +use std::time::Duration; +use util::set_panic_handler; + use crate::block_processor::BlockProcessor; -use crate::cita_db::kvdb::{Database, DatabaseConfig}; use crate::forward::Forward; + +use cita_db::{Config as DatabaseConfig, RocksDB, NUM_COLUMNS}; use cita_directories::DataPath; use clap::App; -use core::db; use core::libchain; use libproto::router::{MsgType, RoutingKey, SubModules}; use pubsub::{channel, start_pubsub}; -use std::sync::Arc; -use std::thread; -use std::time; -use std::time::Duration; -use util::set_panic_handler; include!(concat!(env!("OUT_DIR"), "/build_info.rs")); @@ -133,13 +129,13 @@ fn main() { let nosql_path = DataPath::nosql_path(); trace!("nosql_path is {:?}", nosql_path); - let db_config = DatabaseConfig::with_columns(db::NUM_COLUMNS); - let db = Database::open(&db_config, &nosql_path).unwrap(); + let db_config = DatabaseConfig::with_category_num(NUM_COLUMNS); + let db = RocksDB::open(&nosql_path, &db_config).expect("Open DB failed unexpected."); let chain_config = libchain::chain::Config::new(config_path); let chain = Arc::new(libchain::chain::Chain::init_chain( Arc::new(db), - &chain_config, + chain_config, )); let (write_sender, write_receiver) = channel::unbounded(); @@ -156,41 +152,30 @@ fn main() { }); // Write: add block - thread::spawn(move || { - let mut timeout_factor = 0u8; - loop { - if let Ok(einfo) = write_receiver - .recv_timeout(Duration::new(18 * (2u64.pow(u32::from(timeout_factor))), 0)) - { - block_processor.set_executed_result(&einfo); - timeout_factor = 0; - } else if !*block_processor.chain.is_snapshot.read() { - // Here will be these status: - // 1. Executor process restarts, lost cached block information. - // 2. Executor encountered an invalid block and cleared the block map. - // 3. Bft restarted, lost chain status information, unable to consensus, unable to generate block. - // - // This will trigger: - // 1. Network retransmits block information or initiates a synchronization request, - // and then the executor will receive a block message - // 2. Bft will receive the latest status of chain - info!("Chain enters the timeout retransmission phase"); - block_processor.reset_max_store_height(); - block_processor.signal_to_executor(); - block_processor.broadcast_current_status(); - if timeout_factor < 6 { - timeout_factor += 1 - } - } - } - }); - - //garbage collect + let mut timeout_factor = 0u8; loop { - thread::sleep(time::Duration::from_millis(1000)); - if chain.cache_size().total() > chain_config.cache_size.unwrap() / 2 { - trace!("cache_manager begin collect garbage..."); - chain.collect_garbage(); + if let Ok(einfo) = write_receiver + .recv_timeout(Duration::new(18 * (2u64.pow(u32::from(timeout_factor))), 0)) + { + block_processor.set_executed_result(&einfo); + timeout_factor = 0; + } else if !*block_processor.chain.is_snapshot.read() { + // Here will be these status: + // 1. Executor process restarts, lost cached block information. + // 2. Executor encountered an invalid block and cleared the block map. + // 3. Bft restarted, lost chain status information, unable to consensus, unable to generate block. + // + // This will trigger: + // 1. Network retransmits block information or initiates a synchronization request, + // and then the executor will receive a block message + // 2. Bft will receive the latest status of chain + info!("Chain enters the timeout retransmission phase"); + block_processor.reset_max_store_height(); + block_processor.signal_to_executor(); + block_processor.broadcast_current_status(); + if timeout_factor < 6 { + timeout_factor += 1 + } } } } diff --git a/cita-chain/types/Cargo.toml b/cita-chain/types/Cargo.toml index 31ce19a8f..8cdcd882b 100644 --- a/cita-chain/types/Cargo.toml +++ b/cita-chain/types/Cargo.toml @@ -3,31 +3,41 @@ name = "common-types" description = "Common types used throughout the codebase" version = "0.1.0" authors = ["Cryptape Technologies "] +license = "Apache-2.0" edition = "2018" [dependencies] rlp = { git = "https://github.com/cryptape/cita-common.git", branch = "develop" } -rlp_derive = { git = "https://github.com/cryptape/cita-common.git", branch = "develop" } util = { git = "https://github.com/cryptape/cita-common.git", branch = "develop" } cita-types = { git = "https://github.com/cryptape/cita-common.git", branch = "develop" } hashable = { git = "https://github.com/cryptape/cita-common.git", branch = "develop" } jsonrpc-types = { git = "https://github.com/cryptape/cita-common.git", branch = "develop" } cita-crypto = { git = "https://github.com/cryptape/cita-common.git", branch = "develop" } libproto = { git = "https://github.com/cryptape/cita-common.git", branch = "develop" } +cita-ed25519 = { git = "https://github.com/cryptape/cita-common.git", branch = "develop" } +snappy = { git = "https://github.com/cryptape/cita-common.git", branch = "develop" } serde = "1.0" serde_derive = "1.0" bloomchain = "0.2" lazy_static = "0.2" time = "0.1" +rustc-hex = "1.0" +cita_trie = "2.0.0" cita-logger = "0.1.0" proof = { git = "https://github.com/cryptape/cita-common.git", branch = "develop" } -db = { git = "https://github.com/cryptape/cita-common.git", branch = "develop" } +cita-database = { git = "https://github.com/cryptape/cita-database.git", branch = "develop" } + +[dependencies.cita-vm] +git = "https://github.com/cryptape/cita-vm.git" +branch = "cita" +default-features = false +features = ["sha3hash"] [features] default = ["secp256k1", "sha3hash"] secp256k1 = ["cita-crypto/secp256k1", "libproto/secp256k1"] ed25519 = ["cita-crypto/ed25519", "libproto/ed25519"] sm2 = ["cita-crypto/sm2", "libproto/sm2"] -sha3hash = ["hashable/sha3hash", "db/sha3hash", "libproto/sha3hash"] -blake2bhash = ["hashable/blake2bhash", "db/blake2bhash", "libproto/blake2bhash"] -sm3hash = ["hashable/sm3hash", "db/sm3hash", "libproto/sm3hash"] +sha3hash = ["hashable/sha3hash", "libproto/sha3hash"] +blake2bhash = ["hashable/blake2bhash", "libproto/blake2bhash"] +sm3hash = ["hashable/sm3hash", "libproto/sm3hash"] diff --git a/cita-chain/types/README.md b/cita-chain/types/README.md deleted file mode 100644 index 87d5b16af..000000000 --- a/cita-chain/types/README.md +++ /dev/null @@ -1,16 +0,0 @@ -# Common types for Chain and Executor - -Files below are extracted from [Parity](https://github.com/paritytech/parity): - -- ./src/call_analytics.rs -- ./src/state_diff.rs -- ./src/filter.rs -- ./src/log_entry.rs -- ./src/basic_account.rs -- ./src/ids.rs -- ./src/account_diff.rs -- ./src/log_blooms.rs - -with following modifications: - -- ./src/receipt.rs diff --git a/cita-chain/types/src/account_diff.rs b/cita-chain/types/src/account_diff.rs deleted file mode 100644 index a80c83f65..000000000 --- a/cita-chain/types/src/account_diff.rs +++ /dev/null @@ -1,202 +0,0 @@ -// Copyright 2015-2017 Parity Technologies (UK) Ltd. -// This file is part of Parity. - -// This software is free software: you can redistribute it and/or modify -// it under the terms of the GNU General Public License as published by -// the Free Software Foundation, either version 3 of the License, or -// (at your option) any later version. - -// This software 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 General Public License for more details. - -// You should have received a copy of the GNU General Public License -// along with Parity. If not, see . - -//! Diff between two accounts. - -use cita_types::{H256, U256}; -use std::cmp::*; -use std::collections::BTreeMap; -use std::fmt; -use util::Bytes; - -#[derive(Debug, PartialEq, Eq, Clone)] -/// Diff type for specifying a change (or not). -pub enum Diff -where - T: Eq, -{ - /// Both sides are the same. - Same, - /// Left (pre, source) side doesn't include value, right side (post, destination) does. - Born(T), - /// Both sides include data; it chaged value between them. - Changed(T, T), - /// Left (pre, source) side does include value, right side (post, destination) does not. - Died(T), -} - -impl Diff -where - T: Eq, -{ - /// Construct new object with given `pre` and `post`. - pub fn new(pre: T, post: T) -> Self { - if pre == post { - Diff::Same - } else { - Diff::Changed(pre, post) - } - } - - /// Get the before value, if there is one. - pub fn pre(&self) -> Option<&T> { - match *self { - Diff::Died(ref x) | Diff::Changed(ref x, _) => Some(x), - _ => None, - } - } - - /// Get the after value, if there is one. - pub fn post(&self) -> Option<&T> { - match *self { - Diff::Born(ref x) | Diff::Changed(_, ref x) => Some(x), - _ => None, - } - } - - /// Determine whether there was a change or not. - pub fn is_same(&self) -> bool { - match *self { - Diff::Same => true, - _ => false, - } - } -} - -#[derive(Debug, PartialEq, Eq, Clone)] -#[cfg_attr(feature = "ipc", binary)] -/// Account diff. -pub struct AccountDiff { - /// Change in balance, allowed to be `Diff::Same`. - pub balance: Diff, - /// Change in nonce, allowed to be `Diff::Same`. - pub nonce: Diff, // Allowed to be Same - /// Change in code, allowed to be `Diff::Same`. - pub code: Diff, // Allowed to be Same - /// Change in storage, values are not allowed to be `Diff::Same`. - pub storage: BTreeMap>, -} - -#[derive(Debug, PartialEq, Eq, Clone)] -#[cfg_attr(feature = "ipc", binary)] -/// Change in existance type. -// TODO: include other types of change. -pub enum Existance { - /// Item came into existance. - Born, - /// Item stayed in existance. - Alive, - /// Item went out of existance. - Died, -} - -impl fmt::Display for Existance { - fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { - match *self { - Existance::Born => write!(f, "+++")?, - Existance::Alive => write!(f, "***")?, - Existance::Died => write!(f, "XXX")?, - } - Ok(()) - } -} - -impl AccountDiff { - /// Get `Existance` projection. - pub fn existance(&self) -> Existance { - match self.balance { - Diff::Born(_) => Existance::Born, - Diff::Died(_) => Existance::Died, - _ => Existance::Alive, - } - } -} - -// TODO: refactor into something nicer. -fn interpreted_hash(u: &H256) -> String { - if *u <= H256::from(0xffff_ffff) { - format!( - "{} = {:#x}", - U256::from(&**u).low_u32(), - U256::from(&**u).low_u32() - ) - } else if *u <= H256::from(u64::max_value()) { - format!( - "{} = {:#x}", - U256::from(&**u).low_u64(), - U256::from(&**u).low_u64() - ) - // } else if u <= &H256::from("0xffffffffffffffffffffffffffffffffffffffff") { - // format!("@{}", Address::from(u)) - } else { - format!("#{}", u) - } -} - -impl fmt::Display for AccountDiff { - fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { - use util::bytes::ToPretty; - - match self.nonce { - Diff::Born(ref x) => write!(f, " non {}", x)?, - Diff::Changed(ref pre, ref post) => write!( - f, - "#{} ({} {} {})", - post, - pre, - if pre > post { "-" } else { "+" }, - *max(pre, post) - *min(pre, post) - )?, - _ => {} - } - match self.balance { - Diff::Born(ref x) => write!(f, " bal {}", x)?, - Diff::Changed(ref pre, ref post) => write!( - f, - "${} ({} {} {})", - post, - pre, - if pre > post { "-" } else { "+" }, - *max(pre, post) - *min(pre, post) - )?, - _ => {} - } - if let Diff::Born(ref x) = self.code { - write!(f, " code {}", x.pretty())?; - } - writeln!(f)?; - for (k, dv) in &self.storage { - match *dv { - Diff::Born(ref v) => writeln!( - f, - " + {} => {}", - interpreted_hash(k), - interpreted_hash(v) - )?, - Diff::Changed(ref pre, ref post) => writeln!( - f, - " * {} => {} (was {})", - interpreted_hash(k), - interpreted_hash(post), - interpreted_hash(pre) - )?, - Diff::Died(_) => writeln!(f, " X {}", interpreted_hash(k))?, - _ => {} - } - } - Ok(()) - } -} diff --git a/cita-chain/types/src/basic_account.rs b/cita-chain/types/src/basic_account.rs deleted file mode 100644 index f58e2e706..000000000 --- a/cita-chain/types/src/basic_account.rs +++ /dev/null @@ -1,58 +0,0 @@ -// Copyright 2015-2017 Parity Technologies (UK) Ltd. -// This file is part of Parity. - -// This software is free software: you can redistribute it and/or modify -// it under the terms of the GNU General Public License as published by -// the Free Software Foundation, either version 3 of the License, or -// (at your option) any later version. - -// This software 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 General Public License for more details. - -// You should have received a copy of the GNU General Public License -// along with Parity. If not, see . - -//! Basic account type -- the decoded RLP from the state trie. - -use cita_types::{H256, U256}; -use rlp::*; - -/// Basic account type. -#[derive(Debug, Clone, PartialEq, Eq)] -pub struct BasicAccount { - /// Nonce of the account. - pub nonce: U256, - /// Balance of the account. - pub balance: U256, - /// Storage root of the account. - pub storage_root: H256, - /// Code hash of the account. - pub code_hash: H256, - /// ABI hash of the account. - pub abi_hash: H256, -} - -impl Encodable for BasicAccount { - fn rlp_append(&self, s: &mut RlpStream) { - s.begin_list(5) - .append(&self.nonce) - .append(&self.balance) - .append(&self.storage_root) - .append(&self.code_hash) - .append(&self.abi_hash); - } -} - -impl Decodable for BasicAccount { - fn decode(rlp: &UntrustedRlp) -> Result { - Ok(BasicAccount { - nonce: rlp.val_at(0)?, - balance: rlp.val_at(1)?, - storage_root: rlp.val_at(2)?, - code_hash: rlp.val_at(3)?, - abi_hash: rlp.val_at(4)?, - }) - } -} diff --git a/cita-chain/types/src/basic_types.rs b/cita-chain/types/src/basic_types.rs deleted file mode 100644 index 853571df5..000000000 --- a/cita-chain/types/src/basic_types.rs +++ /dev/null @@ -1,27 +0,0 @@ -// Copyright 2015-2017 Parity Technologies (UK) Ltd. -// This file is part of Parity. - -// This software is free software: you can redistribute it and/or modify -// it under the terms of the GNU General Public License as published by -// the Free Software Foundation, either version 3 of the License, or -// (at your option) any later version. - -// This software 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 General Public License for more details. - -// You should have received a copy of the GNU General Public License -// along with Parity. If not, see . - -//! Ethcore basic typenames. - -/// Type for a 2048-bit log-bloom, as used by our blocks. -pub use crate::log_entry::LogBloom; - -pub use crate::log_blooms::LogBloomGroup; - -/// Constant 2048-bit datum for 0. Often used as a default. -lazy_static! { - pub static ref ZERO_LOGBLOOM: LogBloom = LogBloom::from([0x00; 256]); -} diff --git a/cita-chain/types/src/block.rs b/cita-chain/types/src/block.rs index 3d2c8055c..7dcc61c69 100644 --- a/cita-chain/types/src/block.rs +++ b/cita-chain/types/src/block.rs @@ -1,23 +1,20 @@ -// CITA -// Copyright 2016-2018 Cryptape Technologies LLC. - -// This program is free software: you can redistribute it -// and/or modify it under the terms of the GNU 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 General Public License for more details. - -// You should have received a copy of the GNU General Public License -// along with this program. If not, see . +// Copyright Cryptape Technologies LLC. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. use crate::header::{Header, OpenHeader}; -use crate::extras::TransactionAddress; +use crate::transaction_index::TransactionIndex; use cita_types::H256; use std::collections::HashMap; @@ -28,7 +25,6 @@ use rlp::*; use std::ops::{Deref, DerefMut}; use crate::transaction::SignedTransaction; -use util::HeapSizeOf; #[derive(Default, Debug, Clone, PartialEq)] pub struct OpenBlock { @@ -158,15 +154,25 @@ impl Block { } /// body of block. -#[derive(Default, Debug, Clone, PartialEq, RlpEncodableWrapper, RlpDecodableWrapper)] +#[derive(Default, Debug, Clone, PartialEq)] pub struct BlockBody { /// The transactions in this body. pub transactions: Vec, } -impl HeapSizeOf for BlockBody { - fn heap_size_of_children(&self) -> usize { - self.transactions.heap_size_of_children() +impl Encodable for BlockBody { + fn rlp_append(&self, s: &mut rlp::RlpStream) { + s.append_list(&self.transactions); + } +} + +impl Decodable for BlockBody { + fn decode(r: &UntrustedRlp) -> Result { + let block_body = BlockBody { + transactions: r.as_list()?, + }; + + Ok(block_body) } } @@ -206,19 +212,19 @@ impl BlockBody { self.transactions().iter().map(|ts| ts.hash()).collect() } - pub fn transaction_addresses(&self, hash: H256) -> HashMap { + pub fn transaction_indexes(&self, hash: H256) -> HashMap { let tx_hashs = self.transaction_hashes(); - // Create TransactionAddress - let mut transactions = HashMap::new(); + // Create TransactionIndex + let mut tx_indexes = HashMap::new(); for (i, tx_hash) in tx_hashs.into_iter().enumerate() { - let address = TransactionAddress { + let index = TransactionIndex { block_hash: hash, index: i, }; - transactions.insert(tx_hash, address); + tx_indexes.insert(tx_hash, index); } - trace!("closed block transactions {:?}", transactions); - transactions + trace!("closed block transactions {:?}", tx_indexes); + tx_indexes } } diff --git a/cita-chain/types/src/block_number.rs b/cita-chain/types/src/block_number.rs new file mode 100644 index 000000000..494995743 --- /dev/null +++ b/cita-chain/types/src/block_number.rs @@ -0,0 +1,44 @@ +// Copyright Cryptape Technologies LLC. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +use cita_types::H256; +use jsonrpc_types::rpc_types::{BlockNumber as RpcBlockNumber, BlockTag as RpcBlockTag}; + +pub type TransactionHash = H256; +pub type BlockNumber = u64; + +#[derive(Debug, PartialEq, Clone, Copy)] +pub enum BlockTag { + Tag(Tag), + Height(u64), + Hash(H256), +} + +#[derive(Debug, PartialEq, Clone, Copy)] +pub enum Tag { + Latest, + Earliest, + Pending, +} + +impl From for BlockTag { + fn from(n: RpcBlockNumber) -> BlockTag { + match n { + RpcBlockNumber::Height(height) => BlockTag::Height(height.into()), + RpcBlockNumber::Tag(RpcBlockTag::Latest) => BlockTag::Tag(Tag::Latest), + RpcBlockNumber::Tag(RpcBlockTag::Earliest) => BlockTag::Tag(Tag::Earliest), + RpcBlockNumber::Tag(RpcBlockTag::Pending) => BlockTag::Tag(Tag::Pending), + } + } +} diff --git a/cita-chain/types/src/block_receipts.rs b/cita-chain/types/src/block_receipts.rs new file mode 100644 index 000000000..2dacf9f28 --- /dev/null +++ b/cita-chain/types/src/block_receipts.rs @@ -0,0 +1,60 @@ +// Copyright Cryptape Technologies LLC. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +// FixMe: Rewrite +use crate::receipt::Receipt; +use rlp::{Decodable, DecoderError, Encodable, RlpStream, UntrustedRlp}; + +#[derive(Clone)] +pub struct BlockReceipts { + pub receipts: Vec, +} + +impl BlockReceipts { + pub fn new(receipts: Vec) -> Self { + BlockReceipts { receipts } + } +} + +impl Decodable for BlockReceipts { + fn decode(rlp: &UntrustedRlp) -> Result { + Ok(BlockReceipts { + receipts: rlp.as_list()?, + }) + } +} + +impl Encodable for BlockReceipts { + fn rlp_append(&self, s: &mut RlpStream) { + s.append_list(&self.receipts); + } +} + +#[cfg(test)] +mod tests { + use super::BlockReceipts; + use rlp::*; + + #[test] + fn encode_block_receipts() { + let br = BlockReceipts::new(Vec::new()); + + let mut s = RlpStream::new_list(2); + s.append(&br); + assert!(!s.is_finished(), "List shouldn't finished yet"); + s.append(&br); + assert!(s.is_finished(), "List should be finished now"); + s.out(); + } +} diff --git a/cita-chain/types/src/cache_manager.rs b/cita-chain/types/src/cache_manager.rs deleted file mode 100644 index 9edf5c128..000000000 --- a/cita-chain/types/src/cache_manager.rs +++ /dev/null @@ -1,101 +0,0 @@ -// Copyright 2015-2017 Parity Technologies (UK) Ltd. -// This file is part of Parity. - -// This software is free software: you can redistribute it and/or modify -// it under the terms of the GNU General Public License as published by -// the Free Software Foundation, either version 3 of the License, or -// (at your option) any later version. - -// This software 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 General Public License for more details. - -// You should have received a copy of the GNU General Public License -// along with Parity. If not, see . - -use std::collections::{HashSet, VecDeque}; -use std::hash::Hash; - -const COLLECTION_QUEUE_SIZE: usize = 8; - -pub struct CacheManager -where - T: Eq + Hash, -{ - pref_cache_size: usize, - max_cache_size: usize, - bytes_per_cache_entry: usize, - cache_usage: VecDeque>, -} - -impl CacheManager -where - T: Eq + Hash, -{ - pub fn new( - pref_cache_size: usize, - max_cache_size: usize, - bytes_per_cache_entry: usize, - ) -> Self { - CacheManager { - pref_cache_size, - max_cache_size, - bytes_per_cache_entry, - cache_usage: (0..COLLECTION_QUEUE_SIZE) - .map(|_| Default::default()) - .collect(), - } - } - - pub fn note_used(&mut self, id: T) { - if !self.cache_usage[0].contains(&id) { - if let Some(c) = self - .cache_usage - .iter_mut() - .skip(1) - .find(|e| e.contains(&id)) - { - c.remove(&id); - } - self.cache_usage[0].insert(id); - } - } - - /// Collects unused objects from cache. - /// First params is the current size of the cache. - /// Second one is an with objects to remove. It should also return new size of the cache. - pub fn collect_garbage(&mut self, current_size: usize, mut notify_unused: F) - where - F: FnMut(HashSet) -> usize, - { - if current_size < self.pref_cache_size { - self.rotate_cache_if_needed(); - return; - } - - for _ in 0..COLLECTION_QUEUE_SIZE { - if let Some(back) = self.cache_usage.pop_back() { - let current_size = notify_unused(back); - self.cache_usage.push_front(Default::default()); - if current_size < self.max_cache_size { - break; - } - } - } - } - - fn rotate_cache_if_needed(&mut self) { - if self.cache_usage.is_empty() { - return; - } - - if self.cache_usage[0].len() * self.bytes_per_cache_entry - > self.pref_cache_size / COLLECTION_QUEUE_SIZE - { - if let Some(cache) = self.cache_usage.pop_back() { - self.cache_usage.push_front(cache); - } - } - } -} diff --git a/cita-chain/types/src/call_analytics.rs b/cita-chain/types/src/call_analytics.rs deleted file mode 100644 index 6b8bc6477..000000000 --- a/cita-chain/types/src/call_analytics.rs +++ /dev/null @@ -1,29 +0,0 @@ -// Copyright 2015-2017 Parity Technologies (UK) Ltd. -// This file is part of Parity. - -// This software is free software: you can redistribute it and/or modify -// it under the terms of the GNU General Public License as published by -// the Free Software Foundation, either version 3 of the License, or -// (at your option) any later version. - -// This software 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 General Public License for more details. - -// You should have received a copy of the GNU General Public License -// along with Parity. If not, see . - -//! Call analytics related types - -/// Options concerning what analytics we run on the call. -#[derive(Eq, PartialEq, Default, Clone, Copy, Debug)] -#[cfg_attr(feature = "ipc", binary)] -pub struct CallAnalytics { - /// Make a transaction trace. - pub transaction_tracing: bool, - /// Make a VM trace. - pub vm_tracing: bool, - /// Make a diff. - pub state_diffing: bool, -} diff --git a/cita-chain/types/src/context.rs b/cita-chain/types/src/context.rs new file mode 100644 index 000000000..bdc3628ee --- /dev/null +++ b/cita-chain/types/src/context.rs @@ -0,0 +1,59 @@ +// Copyright Cryptape Technologies LLC. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +use crate::header::BlockNumber; +use cita_types::{Address, H256, U256}; +use std::sync::Arc; + +pub type LastHashes = Vec; + +#[derive(Debug, Clone)] +pub struct Context { + pub block_number: BlockNumber, + pub coin_base: Address, + pub timestamp: u64, + pub difficulty: U256, + pub last_hashes: Arc, + pub quota_used: U256, + pub block_quota_limit: U256, + pub account_quota_limit: U256, +} + +impl Default for Context { + fn default() -> Self { + Context { + block_number: 0, + coin_base: Address::default(), + timestamp: 0, + difficulty: U256::default(), + block_quota_limit: U256::from(u64::max_value()), + last_hashes: Arc::new(vec![]), + quota_used: U256::default(), + account_quota_limit: U256::default(), + } + } +} + +#[cfg(test)] +mod tests { + use super::Context; + use cita_types::U256; + + #[test] + fn test_default() { + let context = Context::default(); + assert_eq!(context.quota_used, U256::zero()); + assert_eq!(context.block_quota_limit, U256::from(u64::max_value())); + } +} diff --git a/cita-chain/types/src/db.rs b/cita-chain/types/src/db.rs deleted file mode 100644 index 37d72f023..000000000 --- a/cita-chain/types/src/db.rs +++ /dev/null @@ -1,300 +0,0 @@ -// Copyright 2015-2017 Parity Technologies (UK) Ltd. -// This file is part of Parity. - -// This software is free software: you can redistribute it and/or modify -// it under the terms of the GNU General Public License as published by -// the Free Software Foundation, either version 3 of the License, or -// (at your option) any later version. - -// This software 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 General Public License for more details. - -// You should have received a copy of the GNU General Public License -// along with Parity. If not, see . - -//! Database utilities and definitions. - -use crate::cita_db::{DBTransaction, KeyValueDB}; -use rlp::{decode, encode, Decodable, Encodable}; -use std::collections::HashMap; -use std::hash::Hash; -use std::ops::Deref; -use util::RwLock; - -// database columns -/// Column for State -pub const COL_STATE: Option = Some(0); -/// Column for Block headers -pub const COL_HEADERS: Option = Some(1); -/// Column for Block bodies -pub const COL_BODIES: Option = Some(2); -/// Column for Extras -pub const COL_EXTRA: Option = Some(3); -/// Column for Traces -pub const COL_TRACE: Option = Some(4); -/// Column for the empty accounts bloom filter. -pub const COL_ACCOUNT_BLOOM: Option = Some(5); -/// Column for general information from the local node which can persist. -pub const COL_NODE_INFO: Option = Some(6); -/// Number of columns in DB -pub const NUM_COLUMNS: Option = Some(7); - -/// Modes for updating caches. -#[derive(Clone, Copy)] -pub enum CacheUpdatePolicy { - /// Overwrite entries. - Overwrite, - /// Remove entries. - Remove, -} - -/// A cache for arbitrary key-value pairs. -pub trait Cache { - /// Insert an entry into the cache and get the old value. - fn insert(&mut self, k: K, v: V) -> Option; - - /// Remove an entry from the cache, getting the old value if it existed. - fn remove(&mut self, k: &K) -> Option; - - /// Query the cache for a key's associated value. - fn get(&self, k: &K) -> Option<&V>; -} - -#[allow(unknown_lints, clippy::implicit_hasher)] // TODO clippy -impl Cache for HashMap -where - K: Hash + Eq, -{ - fn insert(&mut self, k: K, v: V) -> Option { - HashMap::insert(self, k, v) - } - - fn remove(&mut self, k: &K) -> Option { - HashMap::remove(self, k) - } - - fn get(&self, k: &K) -> Option<&V> { - HashMap::get(self, k) - } -} - -/// Should be used to get database key associated with given value. -pub trait Key { - /// The db key associated with this value. - type Target: Deref; - - /// Returns db key. - fn key(&self) -> Self::Target; -} - -/// Should be used to write value into database. -pub trait Writable { - /// Writes the value into the database. - fn write(&mut self, col: Option, key: &Key, value: &T) - where - T: Encodable, - R: Deref; - - /// Deletes key from the databse. - fn delete(&mut self, col: Option, key: &Key) - where - T: Encodable, - R: Deref; - - /// Writes the value into the database and updates the cache. - fn write_with_cache( - &mut self, - col: Option, - cache: &mut Cache, - key: K, - value: T, - policy: CacheUpdatePolicy, - ) where - K: Key + Hash + Eq, - T: Encodable, - R: Deref, - { - self.write(col, &key, &value); - match policy { - CacheUpdatePolicy::Overwrite => { - cache.insert(key, value); - } - CacheUpdatePolicy::Remove => { - cache.remove(&key); - } - } - } - - /// Writes the values into the database and updates the cache. - fn extend_with_cache( - &mut self, - col: Option, - cache: &mut Cache, - values: HashMap, - policy: CacheUpdatePolicy, - ) where - K: Key + Hash + Eq, - T: Encodable, - R: Deref, - { - match policy { - CacheUpdatePolicy::Overwrite => { - for (key, value) in values { - self.write(col, &key, &value); - cache.insert(key, value); - } - } - CacheUpdatePolicy::Remove => { - for (key, value) in &values { - self.write(col, key, value); - cache.remove(key); - } - } - } - } - - /// Writes and removes the values into the database and updates the cache. - fn extend_with_option_cache( - &mut self, - col: Option, - cache: &mut Cache>, - values: HashMap>, - policy: CacheUpdatePolicy, - ) where - K: Key + Hash + Eq, - T: Encodable, - R: Deref, - { - match policy { - CacheUpdatePolicy::Overwrite => { - for (key, value) in values { - match value { - Some(ref v) => self.write(col, &key, v), - None => self.delete(col, &key), - } - cache.insert(key, value); - } - } - CacheUpdatePolicy::Remove => { - for (key, value) in values { - match value { - Some(v) => self.write(col, &key, &v), - None => self.delete(col, &key), - } - cache.remove(&key); - } - } - } - } -} - -/// Should be used to read values from database. -pub trait Readable { - /// Returns value for given key. - fn read(&self, col: Option, key: &Key) -> Option - where - T: Decodable, - R: Deref; - - /// Returns value for given key either in cache or in database. - fn read_with_cache(&self, col: Option, cache: &RwLock, key: &K) -> Option - where - K: Key + Eq + Hash + Clone, - T: Clone + Decodable, - C: Cache, - { - { - let read = cache.read(); - if let Some(v) = read.get(key) { - return Some(v.clone()); - } - } - - self.read(col, key).map(|value: T| { - let mut write = cache.write(); - write.insert(key.clone(), value.clone()); - value - }) - } - - /// Returns true if given value exists. - fn exists(&self, col: Option, key: &Key) -> bool - where - R: Deref; - - /// Returns true if given value exists either in cache or in database. - fn exists_with_cache(&self, col: Option, cache: &RwLock, key: &K) -> bool - where - K: Eq + Hash + Key, - R: Deref, - C: Cache, - { - { - let read = cache.read(); - if read.get(key).is_some() { - return true; - } - } - - self.exists::(col, key) - } -} - -impl Writable for DBTransaction { - fn write(&mut self, col: Option, key: &Key, value: &T) - where - T: Encodable, - R: Deref, - { - self.put(col, &key.key(), &encode(value)); - } - - fn delete(&mut self, col: Option, key: &Key) - where - T: Encodable, - R: Deref, - { - self.delete(col, &key.key()); - } -} - -impl Readable for KVDB { - fn read(&self, col: Option, key: &Key) -> Option - where - T: Decodable, - R: Deref, - { - let result = self.get(col, &key.key()); - - match result { - Ok(option) => option.map(|v| decode(&v)), - Err(err) => { - panic!( - "db get failed, key: {:?}, err: {:?}", - &key.key() as &[u8], - err - ); - } - } - } - - fn exists(&self, col: Option, key: &Key) -> bool - where - R: Deref, - { - let result = self.get(col, &key.key()); - - match result { - Ok(v) => v.is_some(), - Err(err) => { - panic!( - "db get failed, key: {:?}, err: {:?}", - &key.key() as &[u8], - err - ); - } - } - } -} diff --git a/cita-chain/types/src/db_indexes.rs b/cita-chain/types/src/db_indexes.rs new file mode 100644 index 000000000..015342efe --- /dev/null +++ b/cita-chain/types/src/db_indexes.rs @@ -0,0 +1,170 @@ +// Copyright Cryptape Technologies LLC. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +use crate::block_number::BlockNumber; +use bloomchain::group::GroupPosition; +use cita_types::{H256, H264}; + +const TRANSACTION_INDEX: u8 = 0; +const BLOCKRECEIPTS_INDEX: u8 = 1; +const BLOCKSBLOOMS_INDEX: u8 = 2; +const BLOCKHASH_INDEX: u8 = 3; +const BLOCKHEADHASH_INDEX: u8 = 4; +const BLOCKBODYHASH_INDEX: u8 = 5; + +pub trait DBIndex { + fn get_index(&self) -> Vec; +} + +pub struct CurrentHash; + +impl DBIndex for CurrentHash { + fn get_index(&self) -> Vec { + H256::from("7cabfb7709b29c16d9e876e876c9988d03f9c3414e1d3ff77ec1de2d0ee59f66").to_vec() + } +} + +pub struct CurrentProof; + +impl DBIndex for CurrentProof { + fn get_index(&self) -> Vec { + H256::from("7cabfb7709b29c16d9e876e876c9988d03f9c3414e1d3ff77ec1de2d0ee59f67").to_vec() + } +} + +pub struct CurrentHeight; + +impl DBIndex for CurrentHeight { + fn get_index(&self) -> Vec { + H256::from("7cabfb7709b29c16d9e876e876c9988d03f9c3414e1d3ff77ec1de2d0ee59f68").to_vec() + } +} + +pub struct Hash2Header(pub H256); + +impl DBIndex for Hash2Header { + fn get_index(&self) -> Vec { + self.0.to_vec() + } +} + +pub struct Hash2BlockBody(pub H256); + +impl DBIndex for Hash2BlockBody { + fn get_index(&self) -> Vec { + self.0.to_vec() + } +} + +pub struct Hash2BlockNumber(pub H256); + +impl DBIndex for Hash2BlockNumber { + fn get_index(&self) -> Vec { + self.0.to_vec() + } +} + +pub struct BlockNumber2Header(pub BlockNumber); + +impl DBIndex for BlockNumber2Header { + fn get_index(&self) -> Vec { + let mut result = [0u8; 9]; + result[0] = BLOCKHEADHASH_INDEX as u8; + result[1] = (self.0 >> 56) as u8; + result[2] = (self.0 >> 48) as u8; + result[3] = (self.0 >> 40) as u8; + result[4] = (self.0 >> 32) as u8; + result[5] = (self.0 >> 24) as u8; + result[6] = (self.0 >> 16) as u8; + result[7] = (self.0 >> 8) as u8; + result[8] = self.0 as u8; + result.to_vec() + } +} + +pub struct BlockNumber2Body(pub BlockNumber); + +impl DBIndex for BlockNumber2Body { + fn get_index(&self) -> Vec { + let mut result = [0u8; 9]; + result[0] = BLOCKBODYHASH_INDEX as u8; + result[1] = (self.0 >> 56) as u8; + result[2] = (self.0 >> 48) as u8; + result[3] = (self.0 >> 40) as u8; + result[4] = (self.0 >> 32) as u8; + result[5] = (self.0 >> 24) as u8; + result[6] = (self.0 >> 16) as u8; + result[7] = (self.0 >> 8) as u8; + result[8] = self.0 as u8; + result.to_vec() + } +} + +pub struct BlockNumber2Hash(pub BlockNumber); + +impl DBIndex for BlockNumber2Hash { + fn get_index(&self) -> Vec { + let mut result = [0u8; 5]; + result[0] = BLOCKHASH_INDEX as u8; + result[1] = (self.0 >> 24) as u8; + result[2] = (self.0 >> 16) as u8; + result[3] = (self.0 >> 8) as u8; + result[4] = self.0 as u8; + result.to_vec() + } +} + +pub struct Hash2TransactionIndex(pub H256); + +impl DBIndex for Hash2TransactionIndex { + fn get_index(&self) -> Vec { + let mut result = H264::default(); + result[0] = TRANSACTION_INDEX as u8; + (*result)[1..].clone_from_slice(&self.0); + result.to_vec() + } +} + +pub struct Hash2BlockReceipts(pub H256); + +impl DBIndex for Hash2BlockReceipts { + fn get_index(&self) -> Vec { + let mut result = H264::default(); + result[0] = BLOCKRECEIPTS_INDEX as u8; + (*result)[1..].clone_from_slice(&self.0); + result.to_vec() + } +} + +#[derive(Debug, PartialEq, Eq, Hash, Clone)] +pub struct LogGroupPosition(GroupPosition); + +impl From for LogGroupPosition { + fn from(position: GroupPosition) -> Self { + LogGroupPosition(position) + } +} + +impl DBIndex for LogGroupPosition { + fn get_index(&self) -> Vec { + let mut result = [0u8; 6]; + result[0] = BLOCKSBLOOMS_INDEX as u8; + result[1] = self.0.level as u8; + result[2] = (self.0.index >> 24) as u8; + result[3] = (self.0.index >> 16) as u8; + result[4] = (self.0.index >> 8) as u8; + result[5] = self.0.index as u8; + result.to_vec() + } +} diff --git a/cita-chain/types/src/errors/authentication.rs b/cita-chain/types/src/errors/authentication.rs new file mode 100644 index 000000000..c52f4a06b --- /dev/null +++ b/cita-chain/types/src/errors/authentication.rs @@ -0,0 +1,35 @@ +// Copyright Cryptape Technologies LLC. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +use std::fmt; + +#[derive(Debug, PartialEq, Clone)] +pub enum AuthenticationError { + NoTransactionPermission, + NoContractPermission, + NoCallPermission, + InvalidTransaction, +} + +impl fmt::Display for AuthenticationError { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + let printable = match *self { + AuthenticationError::NoTransactionPermission => "No transaction permission.".to_owned(), + AuthenticationError::NoContractPermission => "No create contract permision.".to_owned(), + AuthenticationError::NoCallPermission => "No contract call permission.".to_owned(), + AuthenticationError::InvalidTransaction => "Invalid transaction.".to_owned(), + }; + write!(f, "{}", printable) + } +} diff --git a/cita-chain/types/src/errors/call.rs b/cita-chain/types/src/errors/call.rs new file mode 100644 index 000000000..f615994f3 --- /dev/null +++ b/cita-chain/types/src/errors/call.rs @@ -0,0 +1,46 @@ +// Copyright Cryptape Technologies LLC. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +use super::execution::ExecutionError; +use std::fmt; + +#[derive(Debug)] +pub enum CallError { + /// Couldn't find the transaction in the chain. + TransactionNotFound, + /// Couldn't find requested block's state in the chain. + StatePruned, + /// Couldn't find an amount of gas that didn't result in an exception. + Exceptional, + /// Corrupt state. + StateCorrupt, + /// Error executing. + Execution(ExecutionError), +} + +impl fmt::Display for CallError { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + use self::CallError::*; + + let msg = match *self { + TransactionNotFound => "Transaction couldn't be found in the chain".into(), + StatePruned => "Couldn't find the transaction block's state in the chain".into(), + Exceptional => "An exception happened in the execution".into(), + StateCorrupt => "Stored state found to be corrupted.".into(), + Execution(ref e) => format!("{}", e), + }; + + f.write_fmt(format_args!("Transaction execution error ({}).", msg)) + } +} diff --git a/cita-chain/types/src/errors/execution.rs b/cita-chain/types/src/errors/execution.rs new file mode 100644 index 000000000..e4467d949 --- /dev/null +++ b/cita-chain/types/src/errors/execution.rs @@ -0,0 +1,76 @@ +// Copyright Cryptape Technologies LLC. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +use std::fmt; + +use super::authentication::AuthenticationError; +use super::call::CallError; +use super::native::NativeError; +use cita_vm::state::Error as StateError; + +#[derive(Debug, PartialEq)] +pub enum ExecutionError { + Internal(String), + Authentication(AuthenticationError), + InvalidTransaction, + NotEnoughBaseGas, + InvalidNonce, + NotEnoughBalance, + BlockQuotaLimitReached, + AccountQuotaLimitReached, +} + +impl std::error::Error for ExecutionError {} + +impl fmt::Display for ExecutionError { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + let printable = match *self { + ExecutionError::Internal(ref err) => format!("internal error: {:?}", err), + ExecutionError::Authentication(ref err) => format!("internal error: {:?}", err), + ExecutionError::InvalidTransaction => "invalid transaction".to_owned(), + ExecutionError::NotEnoughBaseGas => "not enough base gas".to_owned(), + ExecutionError::InvalidNonce => "invalid nonce".to_owned(), + ExecutionError::NotEnoughBalance => "not enough balance".to_owned(), + ExecutionError::BlockQuotaLimitReached => "block quota limit reached".to_owned(), + ExecutionError::AccountQuotaLimitReached => "account quota limit reached".to_owned(), + }; + write!(f, "{}", printable) + } +} + +impl From for ExecutionError { + fn from(err: NativeError) -> Self { + match err { + NativeError::Internal(err_str) => ExecutionError::Internal(err_str), + } + } +} + +impl From for ExecutionError { + fn from(err: AuthenticationError) -> Self { + ExecutionError::Authentication(err) + } +} + +impl From for ExecutionError { + fn from(err: StateError) -> Self { + ExecutionError::Internal(format!("{}", err)) + } +} + +impl From for CallError { + fn from(error: ExecutionError) -> Self { + CallError::Execution(error) + } +} diff --git a/cita-chain/types/src/errors/mod.rs b/cita-chain/types/src/errors/mod.rs new file mode 100644 index 000000000..673b79c91 --- /dev/null +++ b/cita-chain/types/src/errors/mod.rs @@ -0,0 +1,74 @@ +// Copyright Cryptape Technologies LLC. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +mod authentication; +mod call; +mod execution; +mod native; +mod receipt; + +pub use authentication::AuthenticationError; +pub use call::CallError; +pub use execution::ExecutionError; +pub use native::NativeError; +pub use receipt::ReceiptError; + +#[derive(Debug)] +pub enum Error { + Execution(ExecutionError), + Receipt(ReceiptError), + Call(CallError), + Native(NativeError), + Authentication(AuthenticationError), +} + +impl std::fmt::Display for Error { + fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result { + let err = match self { + Error::Execution(ref err) => format!("Execution error {:?}", err), + Error::Receipt(ref err) => format!("Receipt error {:?}", err), + Error::Call(ref err) => format!("Call error {:?}", err), + Error::Native(ref err) => format!("Native error {:?}", err), + Error::Authentication(ref err) => format!("Authentication error {:?}", err), + }; + write!(f, "{}", err) + } +} + +impl From for Error { + fn from(err: ExecutionError) -> Error { + Error::Execution(err) + } +} + +impl From for Error { + fn from(err: ReceiptError) -> Error { + Error::Receipt(err) + } +} +impl From for Error { + fn from(err: CallError) -> Error { + Error::Call(err) + } +} +impl From for Error { + fn from(err: NativeError) -> Error { + Error::Native(err) + } +} +impl From for Error { + fn from(err: AuthenticationError) -> Error { + Error::Authentication(err) + } +} diff --git a/cita-chain/types/src/errors/native.rs b/cita-chain/types/src/errors/native.rs new file mode 100644 index 000000000..add996195 --- /dev/null +++ b/cita-chain/types/src/errors/native.rs @@ -0,0 +1,29 @@ +// Copyright Cryptape Technologies LLC. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +use std::fmt; + +#[derive(Debug)] +pub enum NativeError { + Internal(String), +} + +impl fmt::Display for NativeError { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + let printable = match self { + NativeError::Internal(str) => format!("Internal error {:?}", str), + }; + write!(f, "{}", printable) + } +} diff --git a/cita-chain/types/src/errors/receipt.rs b/cita-chain/types/src/errors/receipt.rs new file mode 100644 index 000000000..1106159a2 --- /dev/null +++ b/cita-chain/types/src/errors/receipt.rs @@ -0,0 +1,156 @@ +// Copyright Cryptape Technologies LLC. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +use libproto::executor::ReceiptError as ProtoReceiptError; +use rlp::{Decodable, DecoderError, Encodable, RlpStream, UntrustedRlp}; + +#[derive(Serialize, Deserialize, Debug, PartialEq, Clone, Copy, Eq)] +pub enum ReceiptError { + // ExecutionError + NotEnoughBaseQuota, + BlockQuotaLimitReached, + AccountQuotaLimitReached, + InvalidNonce, + NotEnoughCash, + NoTransactionPermission, + NoContractPermission, + NoCallPermission, + ExecutionInternal, + TransactionMalformed, + // EVM error + OutOfQuota, + BadJumpDestination, + BadInstruction, + StackUnderflow, + OutOfStack, + Internal, + MutableCallInStaticContext, + OutOfBounds, + Reverted, +} + +impl ReceiptError { + /// Returns human-readable description + pub fn description(self) -> String { + let desc = match self { + ReceiptError::NotEnoughBaseQuota => "Not enough base quota.", + ReceiptError::BlockQuotaLimitReached => "Block quota limit reached.", + ReceiptError::AccountQuotaLimitReached => "Account quota limit reached.", + ReceiptError::InvalidNonce => "Invalid transaction nonce.", + ReceiptError::NotEnoughCash => "Cost of transaction exceeds sender balance.", + ReceiptError::NoTransactionPermission => "No transaction permission.", + ReceiptError::NoContractPermission => "No contract permission.", + ReceiptError::NoCallPermission => "No Call contract permission.", + ReceiptError::ExecutionInternal => "Execution internal error.", + ReceiptError::TransactionMalformed => "Malformed transaction.", + ReceiptError::OutOfQuota => "Out of quota.", + ReceiptError::BadJumpDestination => { + "Jump position wasn't marked with JUMPDEST instruction." + } + ReceiptError::BadInstruction => "Instruction is not supported.", + ReceiptError::StackUnderflow => "Not enough stack elements to execute instruction.", + ReceiptError::OutOfStack => "Execution would exceed defined Stack Limit.", + ReceiptError::Internal => "EVM internal error.", + ReceiptError::MutableCallInStaticContext => "Mutable call in static context.", + ReceiptError::OutOfBounds => "Out of bounds.", + ReceiptError::Reverted => "Reverted.", + }; + desc.to_string() + } + + pub fn protobuf(self) -> ProtoReceiptError { + match self { + ReceiptError::NotEnoughBaseQuota => ProtoReceiptError::NotEnoughBaseQuota, + ReceiptError::BlockQuotaLimitReached => ProtoReceiptError::BlockQuotaLimitReached, + ReceiptError::AccountQuotaLimitReached => ProtoReceiptError::AccountQuotaLimitReached, + ReceiptError::InvalidNonce => ProtoReceiptError::InvalidTransactionNonce, + ReceiptError::NotEnoughCash => ProtoReceiptError::NotEnoughCash, + ReceiptError::NoTransactionPermission => ProtoReceiptError::NoTransactionPermission, + ReceiptError::NoContractPermission => ProtoReceiptError::NoContractPermission, + ReceiptError::NoCallPermission => ProtoReceiptError::NoCallPermission, + ReceiptError::ExecutionInternal => ProtoReceiptError::ExecutionInternal, + ReceiptError::TransactionMalformed => ProtoReceiptError::TransactionMalformed, + ReceiptError::OutOfQuota => ProtoReceiptError::OutOfQuota, + ReceiptError::BadJumpDestination => ProtoReceiptError::BadJumpDestination, + ReceiptError::BadInstruction => ProtoReceiptError::BadInstruction, + ReceiptError::StackUnderflow => ProtoReceiptError::StackUnderflow, + ReceiptError::OutOfStack => ProtoReceiptError::OutOfStack, + ReceiptError::Internal => ProtoReceiptError::Internal, + ReceiptError::MutableCallInStaticContext => { + ProtoReceiptError::MutableCallInStaticContext + } + ReceiptError::OutOfBounds => ProtoReceiptError::OutOfBounds, + ReceiptError::Reverted => ProtoReceiptError::Reverted, + } + } + + pub fn from_proto(receipt_error: ProtoReceiptError) -> Self { + match receipt_error { + ProtoReceiptError::NotEnoughBaseQuota => ReceiptError::NotEnoughBaseQuota, + ProtoReceiptError::BlockQuotaLimitReached => ReceiptError::BlockQuotaLimitReached, + ProtoReceiptError::AccountQuotaLimitReached => ReceiptError::AccountQuotaLimitReached, + ProtoReceiptError::InvalidTransactionNonce => ReceiptError::InvalidNonce, + ProtoReceiptError::NotEnoughCash => ReceiptError::NotEnoughCash, + ProtoReceiptError::NoTransactionPermission => ReceiptError::NoTransactionPermission, + ProtoReceiptError::NoContractPermission => ReceiptError::NoContractPermission, + ProtoReceiptError::NoCallPermission => ReceiptError::NoCallPermission, + ProtoReceiptError::ExecutionInternal => ReceiptError::ExecutionInternal, + ProtoReceiptError::TransactionMalformed => ReceiptError::TransactionMalformed, + ProtoReceiptError::OutOfQuota => ReceiptError::OutOfQuota, + ProtoReceiptError::BadJumpDestination => ReceiptError::BadJumpDestination, + ProtoReceiptError::BadInstruction => ReceiptError::BadInstruction, + ProtoReceiptError::StackUnderflow => ReceiptError::StackUnderflow, + ProtoReceiptError::OutOfStack => ReceiptError::OutOfStack, + ProtoReceiptError::Internal => ReceiptError::Internal, + ProtoReceiptError::MutableCallInStaticContext => { + ReceiptError::MutableCallInStaticContext + } + ProtoReceiptError::OutOfBounds => ReceiptError::OutOfBounds, + ProtoReceiptError::Reverted => ReceiptError::Reverted, + } + } +} + +impl Decodable for ReceiptError { + fn decode(rlp: &UntrustedRlp) -> Result { + match rlp.as_val::()? { + 0 => Ok(ReceiptError::NotEnoughBaseQuota), + 1 => Ok(ReceiptError::BlockQuotaLimitReached), + 2 => Ok(ReceiptError::AccountQuotaLimitReached), + 3 => Ok(ReceiptError::InvalidNonce), + 4 => Ok(ReceiptError::NotEnoughCash), + 5 => Ok(ReceiptError::NoTransactionPermission), + 6 => Ok(ReceiptError::NoContractPermission), + 7 => Ok(ReceiptError::NoCallPermission), + 8 => Ok(ReceiptError::ExecutionInternal), + 9 => Ok(ReceiptError::TransactionMalformed), + 10 => Ok(ReceiptError::OutOfQuota), + 11 => Ok(ReceiptError::BadJumpDestination), + 12 => Ok(ReceiptError::BadInstruction), + 13 => Ok(ReceiptError::StackUnderflow), + 14 => Ok(ReceiptError::OutOfStack), + 15 => Ok(ReceiptError::Internal), + 16 => Ok(ReceiptError::MutableCallInStaticContext), + 17 => Ok(ReceiptError::OutOfBounds), + 18 => Ok(ReceiptError::Reverted), + _ => Err(DecoderError::Custom("Unknown Receipt error.")), + } + } +} + +impl Encodable for ReceiptError { + fn rlp_append(&self, s: &mut RlpStream) { + s.append(&(*self as u8)); + } +} diff --git a/cita-chain/types/src/extras.rs b/cita-chain/types/src/extras.rs deleted file mode 100644 index 9782c6914..000000000 --- a/cita-chain/types/src/extras.rs +++ /dev/null @@ -1,324 +0,0 @@ -// Copyright 2015-2017 Parity Technologies (UK) Ltd. -// This file is part of Parity. - -// This software is free software: you can redistribute it and/or modify -// it under the terms of the GNU General Public License as published by -// the Free Software Foundation, either version 3 of the License, or -// (at your option) any later version. - -// This software 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 General Public License for more details. - -// You should have received a copy of the GNU General Public License -// along with Parity. If not, see . - -//! Blockchain DB extras. - -use crate::basic_types::LogBloomGroup; -use crate::block::BlockBody; -use crate::db::Key; -use crate::header::{BlockNumber, Header}; -use crate::receipt::Receipt; -use bloomchain::group::GroupPosition; -use cita_types::{H256, H264}; -use libproto::blockchain::Proof; -use rlp::*; -use std::ops::{Deref, Index}; -use util::*; - -/// Represents index of extra data in database -#[derive(Copy, Debug, Hash, Eq, PartialEq, Clone)] -pub enum ExtrasIndex { - /// Transaction address index - TransactionAddress = 0, - /// Block receipts index - BlockReceipts = 1, - /// Block blooms index - BlocksBlooms = 2, - /// Block hash index - BlockHash = 3, - /// Block head index - BlockHeadHash = 4, - /// Block body index - BlockBodyHash = 5, -} - -pub struct CurrentHash; - -impl Key for CurrentHash { - type Target = H256; - - fn key(&self) -> H256 { - H256::from("7cabfb7709b29c16d9e876e876c9988d03f9c3414e1d3ff77ec1de2d0ee59f66") - } -} - -pub struct CurrentProof; - -impl Key for CurrentProof { - type Target = H256; - - fn key(&self) -> H256 { - H256::from("7cabfb7709b29c16d9e876e876c9988d03f9c3414e1d3ff77ec1de2d0ee59f67") - } -} - -pub struct CurrentHeight; - -impl Key for CurrentHeight { - type Target = H256; - - fn key(&self) -> H256 { - H256::from("7cabfb7709b29c16d9e876e876c9988d03f9c3414e1d3ff77ec1de2d0ee59f68") - } -} - -impl Key
for H256 { - type Target = H256; - - fn key(&self) -> H256 { - *self - } -} - -impl Key for H256 { - type Target = H256; - - fn key(&self) -> H256 { - *self - } -} - -impl Key for H256 { - type Target = H256; - - fn key(&self) -> H256 { - *self - } -} - -pub struct BlockNumberKey([u8; 5]); - -impl Deref for BlockNumberKey { - type Target = [u8]; - - fn deref(&self) -> &Self::Target { - &self.0 - } -} - -pub struct BlockNumberKeyLong([u8; 9]); - -impl Deref for BlockNumberKeyLong { - type Target = [u8]; - - fn deref(&self) -> &Self::Target { - &self.0 - } -} - -impl Key
for BlockNumber { - type Target = BlockNumberKeyLong; - - fn key(&self) -> Self::Target { - let mut result = [0u8; 9]; - result[0] = ExtrasIndex::BlockHeadHash as u8; - result[1] = (self >> 56) as u8; - result[2] = (self >> 48) as u8; - result[3] = (self >> 40) as u8; - result[4] = (self >> 32) as u8; - result[5] = (self >> 24) as u8; - result[6] = (self >> 16) as u8; - result[7] = (self >> 8) as u8; - result[8] = *self as u8; - BlockNumberKeyLong(result) - } -} - -impl Key for BlockNumber { - type Target = BlockNumberKeyLong; - - fn key(&self) -> Self::Target { - let mut result = [0u8; 9]; - result[0] = ExtrasIndex::BlockBodyHash as u8; - result[1] = (self >> 56) as u8; - result[2] = (self >> 48) as u8; - result[3] = (self >> 40) as u8; - result[4] = (self >> 32) as u8; - result[5] = (self >> 24) as u8; - result[6] = (self >> 16) as u8; - result[7] = (self >> 8) as u8; - result[8] = *self as u8; - BlockNumberKeyLong(result) - } -} - -impl Key for BlockNumber { - type Target = BlockNumberKey; - - fn key(&self) -> Self::Target { - let mut result = [0u8; 5]; - result[0] = ExtrasIndex::BlockHash as u8; - result[1] = (self >> 24) as u8; - result[2] = (self >> 16) as u8; - result[3] = (self >> 8) as u8; - result[4] = *self as u8; - BlockNumberKey(result) - } -} - -fn with_index(hash: &H256, i: ExtrasIndex) -> H264 { - let mut result = H264::default(); - result[0] = i as u8; - (*result)[1..].clone_from_slice(hash); - result -} - -impl Key for H256 { - type Target = H264; - - fn key(&self) -> H264 { - with_index(self, ExtrasIndex::TransactionAddress) - } -} - -impl Key for H256 { - type Target = H264; - - fn key(&self) -> H264 { - with_index(self, ExtrasIndex::BlockReceipts) - } -} - -pub struct LogGroupKey([u8; 6]); - -impl Deref for LogGroupKey { - type Target = [u8]; - - fn deref(&self) -> &Self::Target { - &self.0 - } -} - -#[derive(Debug, PartialEq, Eq, Hash, Clone)] -pub struct LogGroupPosition(GroupPosition); - -impl From for LogGroupPosition { - fn from(position: GroupPosition) -> Self { - LogGroupPosition(position) - } -} - -impl HeapSizeOf for LogGroupPosition { - fn heap_size_of_children(&self) -> usize { - 0 - } -} - -impl Key for LogGroupPosition { - type Target = LogGroupKey; - - fn key(&self) -> Self::Target { - let mut result = [0u8; 6]; - result[0] = ExtrasIndex::BlocksBlooms as u8; - result[1] = self.0.level as u8; - result[2] = (self.0.index >> 24) as u8; - result[3] = (self.0.index >> 16) as u8; - result[4] = (self.0.index >> 8) as u8; - result[5] = self.0.index as u8; - LogGroupKey(result) - } -} - -/// Represents address of certain transaction within block -#[derive(Debug, PartialEq, Clone, Serialize, Deserialize)] -pub struct TransactionAddress { - /// Block hash - pub block_hash: H256, - /// Transaction index within the block - pub index: usize, -} - -impl HeapSizeOf for TransactionAddress { - fn heap_size_of_children(&self) -> usize { - 0 - } -} - -impl Decodable for TransactionAddress { - fn decode(rlp: &UntrustedRlp) -> Result { - let tx_address = TransactionAddress { - block_hash: rlp.val_at(0)?, - index: rlp.val_at(1)?, - }; - - Ok(tx_address) - } -} - -impl Encodable for TransactionAddress { - fn rlp_append(&self, s: &mut RlpStream) { - s.begin_list(2); - s.append(&self.block_hash); - s.append(&self.index); - } -} - -/// Contains all block receipts. -#[derive(Clone)] -pub struct BlockReceipts { - pub receipts: Vec, -} - -impl BlockReceipts { - pub fn new(receipts: Vec) -> Self { - BlockReceipts { receipts } - } -} - -impl Decodable for BlockReceipts { - fn decode(rlp: &UntrustedRlp) -> Result { - Ok(BlockReceipts { - receipts: rlp.as_list()?, - }) - } -} - -impl Encodable for BlockReceipts { - fn rlp_append(&self, s: &mut RlpStream) { - s.append_list(&self.receipts); - } -} - -impl HeapSizeOf for BlockReceipts { - fn heap_size_of_children(&self) -> usize { - self.receipts.heap_size_of_children() - } -} - -impl Index for BlockReceipts { - type Output = Receipt; - fn index(&self, i: usize) -> &Receipt { - &self.receipts[i] - } -} - -#[cfg(test)] -mod tests { - use super::BlockReceipts; - use rlp::*; - - #[test] - fn encode_block_receipts() { - let br = BlockReceipts::new(Vec::new()); - - let mut s = RlpStream::new_list(2); - s.append(&br); - assert!(!s.is_finished(), "List shouldn't finished yet"); - s.append(&br); - assert!(s.is_finished(), "List should be finished now"); - s.out(); - } -} diff --git a/cita-chain/types/src/filter.rs b/cita-chain/types/src/filter.rs index 033f34b4c..9685178e7 100644 --- a/cita-chain/types/src/filter.rs +++ b/cita-chain/types/src/filter.rs @@ -1,81 +1,86 @@ -// Copyright 2015-2017 Parity Technologies (UK) Ltd. -// This file is part of Parity. +// Copyright Cryptape Technologies LLC. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. -// This software is free software: you can redistribute it and/or modify -// it under the terms of the GNU General Public License as published by -// the Free Software Foundation, either version 3 of the License, or -// (at your option) any later version. - -// This software 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 General Public License for more details. +use crate::block_number::BlockTag; +#[cfg(test)] +use crate::block_number::Tag; +use crate::log::Log; +use cita_types::traits::BloomTools; +use cita_types::{Address, Bloom, H256}; +use jsonrpc_types::rpc_types::{Filter as RpcFilter, FilterAddress, Topic, VariadicValue}; -// You should have received a copy of the GNU General Public License -// along with Parity. If not, see . +/// Address Filter. +#[derive(Debug, PartialEq, Clone)] +pub struct AddressFilter { + addresses: Option>, +} -//! Blockchain filter +impl AddressFilter { + pub fn new(addresses: Option>) -> Self { + AddressFilter { addresses } + } -use crate::ids::BlockId; -use crate::log_entry::{LogBloom, LogEntry}; -use cita_types::traits::BloomTools; -use cita_types::{Address, H256}; -use jsonrpc_types::rpc_types::{Filter as RpcFilter, VariadicValue}; + pub fn blooms(&self) -> Vec { + match self.addresses { + Some(ref addresses) if !addresses.is_empty() => addresses + .iter() + .map(|ref address| Bloom::from_raw(address)) + .collect(), + _ => vec![Bloom::default()], + } + } -/// Blockchain Filter. -#[derive(Debug, PartialEq)] -pub struct Filter { - /// Blockchain will be searched from this block. - pub from_block: BlockId, - - /// Till this block. - pub to_block: BlockId, - - /// Search addresses. - /// - /// If None, match all. - /// If specified, log must be produced by one of these addresses. - pub address: Option>, - - /// Search topics. - /// - /// If None, match all. - /// If specified, log must contain one of these topics. - pub topics: Vec>>, - - /// Logs limit - /// - /// If None, return all logs - /// If specified, should only return *last* `n` logs. - pub limit: Option, + pub fn matches(&self, log: &Log) -> bool { + match self.addresses { + Some(ref addresses) if !addresses.is_empty() => { + addresses.iter().any(|address| &log.address == address) + } + _ => true, + } + } } -impl Clone for Filter { - fn clone(&self) -> Self { - let mut topics = [None, None, None, None]; - topics[..4].clone_from_slice(&self.topics[..4]); +impl From> for AddressFilter { + fn from(addresses: Option) -> AddressFilter { + let addresses = addresses.and_then(|address| match address { + VariadicValue::Null => None, + VariadicValue::Single(addr) => Some(vec![addr.into()]), + VariadicValue::Multiple(addr) => Some(addr.into_iter().map(Into::into).collect()), + }); - Filter { - from_block: self.from_block, - to_block: self.to_block, - address: self.address.clone(), - topics: topics[..].to_vec(), - limit: self.limit, - } + AddressFilter { addresses } } } -impl Filter { - /// Returns combinations of each address and topic. - pub fn bloom_possibilities(&self) -> Vec { - let blooms = match self.address { - Some(ref addresses) if !addresses.is_empty() => addresses - .iter() - .map(|ref address| LogBloom::from_raw(address)) - .collect(), - _ => vec![LogBloom::default()], - }; +impl Default for AddressFilter { + fn default() -> Self { + AddressFilter { addresses: None } + } +} + +/// Topic Filter. +#[derive(Debug, PartialEq)] +pub struct TopicFilter { + topics: Vec>>, +} + +impl TopicFilter { + pub fn new(topics: Vec>>) -> Self { + TopicFilter { topics } + } + pub fn zip_blooms(&self, blooms: Vec) -> Vec { self.topics.iter().fold(blooms, |bs, topic| match *topic { None => bs, Some(ref topics) => bs @@ -84,36 +89,106 @@ impl Filter { topics .iter() .map(|topic| { - let mut b = bloom; - b.accrue_raw(topic); - b + let mut bloom = bloom; + bloom.accrue_raw(topic); + bloom }) - .collect::>() + .collect::>() }) .collect(), }) } - /// Returns true if given log entry matches filter. - pub fn matches(&self, log: &LogEntry) -> bool { - let matches = match self.address { - Some(ref addresses) if !addresses.is_empty() => { - addresses.iter().any(|address| &log.address == address) - } - _ => true, - }; + pub fn matches(&self, log: &Log) -> bool { + self.topics + .iter() + .enumerate() + .all(|(index, topic)| match *topic { + Some(ref topics) if !topics.is_empty() => topics + .iter() + .any(|topic| log.topics.get(index) == Some(topic)), + _ => true, + }) + } +} - matches - && self - .topics - .iter() - .enumerate() - .all(|(i, topic)| match *topic { - Some(ref topics) if !topics.is_empty() => { - topics.iter().any(|topic| log.topics.get(i) == Some(topic)) - } - _ => true, - }) +impl From>> for TopicFilter { + fn from(topics: Option>) -> TopicFilter { + let mut iter = topics + .map_or_else(Vec::new, |topics| { + topics + .into_iter() + .take(4) + .map(|topic| match topic { + VariadicValue::Null => None, + VariadicValue::Single(t) => Some(vec![t.into()]), + VariadicValue::Multiple(t) => Some(t.into_iter().map(Into::into).collect()), + }) + .collect() + }) + .into_iter(); + + let topics = vec![ + iter.next().unwrap_or(None), + iter.next().unwrap_or(None), + iter.next().unwrap_or(None), + iter.next().unwrap_or(None), + ]; + + TopicFilter { topics } + } +} + +impl Clone for TopicFilter { + fn clone(&self) -> Self { + let mut topics = [None, None, None, None]; + topics[..4].clone_from_slice(&self.topics[..4]); + + TopicFilter { + topics: topics.to_vec(), + } + } +} + +impl Default for TopicFilter { + fn default() -> Self { + let topics = vec![None, None, None, None]; + + TopicFilter { topics } + } +} + +/// All filter. +#[derive(Debug, PartialEq)] +pub struct Filter { + pub from_block: BlockTag, + pub to_block: BlockTag, + pub addresses: AddressFilter, + pub topics: TopicFilter, + pub limit: Option, +} + +impl Filter { + /// Zip blooms with address and topic. + pub fn zip_blooms(&self) -> Vec { + self.topics.zip_blooms(self.addresses.blooms()) + } + + /// Check the given log entry matches address or topic. + pub fn matches(&self, log: &Log) -> bool { + self.addresses.matches(log) && self.topics.matches(log) + } + + // For test + #[cfg(test)] + pub fn new_with_address_and_topic(addresses: AddressFilter, topics: TopicFilter) -> Self { + Filter { + from_block: BlockTag::Tag(Tag::Earliest), + to_block: BlockTag::Tag(Tag::Latest), + addresses, + topics, + limit: None, + } } } @@ -122,36 +197,8 @@ impl From for Filter { Filter { from_block: v.from_block.into(), to_block: v.to_block.into(), - address: v.address.and_then(|address| match address { - VariadicValue::Null => None, - VariadicValue::Single(a) => Some(vec![a.into()]), - VariadicValue::Multiple(a) => Some(a.into_iter().map(Into::into).collect()), - }), - topics: { - let mut iter = v - .topics - .map_or_else(Vec::new, |topics| { - topics - .into_iter() - .take(4) - .map(|topic| match topic { - VariadicValue::Null => None, - VariadicValue::Single(t) => Some(vec![t.into()]), - VariadicValue::Multiple(t) => { - Some(t.into_iter().map(Into::into).collect()) - } - }) - .collect() - }) - .into_iter(); - - vec![ - iter.next().unwrap_or(None), - iter.next().unwrap_or(None), - iter.next().unwrap_or(None), - iter.next().unwrap_or(None), - ] - }, + addresses: v.address.into(), + topics: v.topics.into(), limit: v.limit, } } @@ -159,242 +206,176 @@ impl From for Filter { #[cfg(test)] mod tests { - use crate::filter::Filter; - use crate::ids::BlockId; - use crate::log_entry::{LogBloom, LogEntry}; + use crate::filter::{AddressFilter, Filter, TopicFilter}; + use crate::log::Log; + use cita_types::{Address, Bloom, H256}; #[test] - fn test_bloom_possibilities_none() { - let none_filter = Filter { - from_block: BlockId::Earliest, - to_block: BlockId::Latest, - address: None, - topics: vec![None, None, None, None], - limit: None, - }; + fn test_zip_blooms_none() { + let none_filter = + Filter::new_with_address_and_topic(Default::default(), Default::default()); - let possibilities = none_filter.bloom_possibilities(); - assert_eq!(possibilities.len(), 1); - assert!(possibilities[0].is_zero()) + let blooms = none_filter.zip_blooms(); + assert_eq!(blooms.len(), 1); + assert!(blooms[0].is_zero()) } - // block 399849 #[test] - fn test_bloom_possibilities_single_address_and_topic() { - let filter = Filter { - from_block: BlockId::Earliest, - to_block: BlockId::Latest, - address: Some(vec!["b372018f3be9e171df0581136b59d2faf73a7d5d".into()]), - topics: vec![ - Some(vec![ - "ff74e91598aed6ae5d2fdcf8b24cd2c7be49a0808112a305069355b7160f23f9".into(), - ]), - None, - None, - None, - ], - limit: None, - }; - let possibilities = filter.bloom_possibilities(); - let blooms: Vec = vec![ - "0000000000000000000000000000000000000000000000000000000000000000 - 0000000000000000000000000000000000000000000000000000000000000008 - 0000000000000000000000000000000000000000800000000000000000000000 - 0000000000000000000000000000000000000000000000400000000400000000 - 0000000000000000000000000000000000000000020000000000000000000000 + fn test_zip_blooms_single_address_and_single_topic() { + let topics = vec![Some(vec![H256::zero()]), None, None, None]; + let addresses = Some(vec![Address::default()]); + + let filter = Filter::new_with_address_and_topic( + AddressFilter::new(addresses), + TopicFilter::new(topics), + ); + + let zip_blooms = filter.zip_blooms(); + let blooms: Vec = vec![ + "0000000000000000008000000000000000000000000000000000000000000000 + 0000000000000000000000000000000200000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 - 0000000000000000000000000000000000000000000000000000040000000000 + 0000000002000000000000000000080000000000000000000000000000000000 + 0000000000000000000000000000000100000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000002000 0000000000000000000000000000000000000000000000000000000000000000" .into(), ]; - assert_eq!(possibilities, blooms); + assert_eq!(zip_blooms, blooms); } #[test] - fn test_bloom_possibilities_single_address_and_many_topics() { - let filter = Filter { - from_block: BlockId::Earliest, - to_block: BlockId::Latest, - address: Some(vec!["b372018f3be9e171df0581136b59d2faf73a7d5d".into()]), - topics: vec![ - Some(vec![ - "ff74e91598aed6ae5d2fdcf8b24cd2c7be49a0808112a305069355b7160f23f9".into(), - ]), - Some(vec![ - "ff74e91598aed6ae5d2fdcf8b24cd2c7be49a0808112a305069355b7160f23f9".into(), - ]), - None, - None, - ], - limit: None, - }; - let possibilities = filter.bloom_possibilities(); - let blooms: Vec = vec![ - "0000000000000000000000000000000000000000000000000000000000000000 - 0000000000000000000000000000000000000000000000000000000000000008 - 0000000000000000000000000000000000000000800000000000000000000000 - 0000000000000000000000000000000000000000000000400000000400000000 - 0000000000000000000000000000000000000000020000000000000000000000 + fn test_zip_bloom_single_address_and_mul_topics() { + let topics = vec![ + Some(vec![H256::zero()]), + Some(vec![H256::zero()]), + Some(vec![H256::zero()]), + Some(vec![H256::zero()]), + ]; + let addresses = Some(vec![Address::default()]); + + let filter = Filter::new_with_address_and_topic( + AddressFilter::new(addresses), + TopicFilter::new(topics), + ); + + let zip_blooms = filter.zip_blooms(); + let blooms: Vec = vec![ + "0000000000000000008000000000000000000000000000000000000000000000 + 0000000000000000000000000000000200000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000002000000000000000000080000000000000000000000000000000000 + 0000000000000000000000000000000100000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 - 0000000000000000000000000000000000000000000000000000040000000000 + 0000000000000000000000000000000000000000000000000000000000002000 0000000000000000000000000000000000000000000000000000000000000000" .into(), ]; - assert_eq!(possibilities, blooms); + assert_eq!(zip_blooms, blooms); } #[test] - fn test_bloom_possibilites_multiple_addresses_and_topics() { - let filter = Filter { - from_block: BlockId::Earliest, - to_block: BlockId::Latest, - address: Some(vec![ - "b372018f3be9e171df0581136b59d2faf73a7d5d".into(), - "b372018f3be9e171df0581136b59d2faf73a7d5d".into(), - ]), - topics: vec![ - Some(vec![ - "ff74e91598aed6ae5d2fdcf8b24cd2c7be49a0808112a305069355b7160f23f9".into(), - "ff74e91598aed6ae5d2fdcf8b24cd2c7be49a0808112a305069355b7160f23f9".into(), - ]), - Some(vec![ - "ff74e91598aed6ae5d2fdcf8b24cd2c7be49a0808112a305069355b7160f23f9".into(), - "ff74e91598aed6ae5d2fdcf8b24cd2c7be49a0808112a305069355b7160f23f9".into(), - ]), - Some(vec![ - "ff74e91598aed6ae5d2fdcf8b24cd2c7be49a0808112a305069355b7160f23f9".into(), - ]), - None, - ], - limit: None, - }; + fn test_zip_blooms_mul_addresses_and_mul_topics() { + let topics = vec![ + Some(vec![H256::zero(), H256::zero()]), + Some(vec![H256::zero()]), + Some(vec![H256::zero()]), + Some(vec![H256::zero()]), + ]; + let addresses = Some(vec![Address::default(), Address::default()]); - // number of possibilites should be equal 2 * 2 * 2 * 1 = 8 - let possibilities = filter.bloom_possibilities(); - let blooms: Vec = vec![ - "0000000000000000000000000000000000000000000000000000000000000000 - 0000000000000000000000000000000000000000000000000000000000000008 - 0000000000000000000000000000000000000000800000000000000000000000 - 0000000000000000000000000000000000000000000000400000000400000000 - 0000000000000000000000000000000000000000020000000000000000000000 + let filter = Filter::new_with_address_and_topic( + AddressFilter::new(addresses), + TopicFilter::new(topics), + ); + + let zip_blooms = filter.zip_blooms(); + let blooms: Vec = vec![ + "0000000000000000008000000000000000000000000000000000000000000000 + 0000000000000000000000000000000200000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 - 0000000000000000000000000000000000000000000000000000040000000000 - 0000000000000000000000000000000000000000000000000000000000000000" - .into(), - "0000000000000000000000000000000000000000000000000000000000000000 - 0000000000000000000000000000000000000000000000000000000000000008 - 0000000000000000000000000000000000000000800000000000000000000000 - 0000000000000000000000000000000000000000000000400000000400000000 - 0000000000000000000000000000000000000000020000000000000000000000 + 0000000002000000000000000000080000000000000000000000000000000000 + 0000000000000000000000000000000100000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 - 0000000000000000000000000000000000000000000000000000040000000000 + 0000000000000000000000000000000000000000000000000000000000002000 0000000000000000000000000000000000000000000000000000000000000000" .into(), - "0000000000000000000000000000000000000000000000000000000000000000 - 0000000000000000000000000000000000000000000000000000000000000008 - 0000000000000000000000000000000000000000800000000000000000000000 - 0000000000000000000000000000000000000000000000400000000400000000 - 0000000000000000000000000000000000000000020000000000000000000000 + "0000000000000000008000000000000000000000000000000000000000000000 + 0000000000000000000000000000000200000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 - 0000000000000000000000000000000000000000000000000000040000000000 - 0000000000000000000000000000000000000000000000000000000000000000" - .into(), - "0000000000000000000000000000000000000000000000000000000000000000 - 0000000000000000000000000000000000000000000000000000000000000008 - 0000000000000000000000000000000000000000800000000000000000000000 - 0000000000000000000000000000000000000000000000400000000400000000 - 0000000000000000000000000000000000000000020000000000000000000000 + 0000000002000000000000000000080000000000000000000000000000000000 + 0000000000000000000000000000000100000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 - 0000000000000000000000000000000000000000000000000000040000000000 + 0000000000000000000000000000000000000000000000000000000000002000 0000000000000000000000000000000000000000000000000000000000000000" .into(), - "0000000000000000000000000000000000000000000000000000000000000000 - 0000000000000000000000000000000000000000000000000000000000000008 - 0000000000000000000000000000000000000000800000000000000000000000 - 0000000000000000000000000000000000000000000000400000000400000000 - 0000000000000000000000000000000000000000020000000000000000000000 + "0000000000000000008000000000000000000000000000000000000000000000 + 0000000000000000000000000000000200000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 - 0000000000000000000000000000000000000000000000000000040000000000 - 0000000000000000000000000000000000000000000000000000000000000000" - .into(), - "0000000000000000000000000000000000000000000000000000000000000000 - 0000000000000000000000000000000000000000000000000000000000000008 - 0000000000000000000000000000000000000000800000000000000000000000 - 0000000000000000000000000000000000000000000000400000000400000000 - 0000000000000000000000000000000000000000020000000000000000000000 + 0000000002000000000000000000080000000000000000000000000000000000 + 0000000000000000000000000000000100000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 - 0000000000000000000000000000000000000000000000000000040000000000 + 0000000000000000000000000000000000000000000000000000000000002000 0000000000000000000000000000000000000000000000000000000000000000" .into(), - "0000000000000000000000000000000000000000000000000000000000000000 - 0000000000000000000000000000000000000000000000000000000000000008 - 0000000000000000000000000000000000000000800000000000000000000000 - 0000000000000000000000000000000000000000000000400000000400000000 - 0000000000000000000000000000000000000000020000000000000000000000 + "0000000000000000008000000000000000000000000000000000000000000000 + 0000000000000000000000000000000200000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 - 0000000000000000000000000000000000000000000000000000040000000000 - 0000000000000000000000000000000000000000000000000000000000000000" - .into(), - "0000000000000000000000000000000000000000000000000000000000000000 - 0000000000000000000000000000000000000000000000000000000000000008 - 0000000000000000000000000000000000000000800000000000000000000000 - 0000000000000000000000000000000000000000000000400000000400000000 - 0000000000000000000000000000000000000000020000000000000000000000 + 0000000002000000000000000000080000000000000000000000000000000000 + 0000000000000000000000000000000100000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 - 0000000000000000000000000000000000000000000000000000040000000000 + 0000000000000000000000000000000000000000000000000000000000002000 0000000000000000000000000000000000000000000000000000000000000000" .into(), ]; - assert_eq!(possibilities, blooms); + assert_eq!(zip_blooms, blooms); } #[test] - fn test_filter_matches() { - let filter = Filter { - from_block: BlockId::Earliest, - to_block: BlockId::Latest, - address: Some(vec!["b372018f3be9e171df0581136b59d2faf73a7d5d".into()]), - topics: vec![ - Some(vec![ - "ff74e91598aed6ae5d2fdcf8b24cd2c7be49a0808112a305069355b7160f23f9".into(), - ]), - Some(vec![ - "ff74e91598aed6ae5d2fdcf8b24cd2c7be49a0808112a305069355b7160f23fa".into(), - ]), - None, - None, - ], - limit: None, - }; + fn test_matches() { + let topics = vec![ + Some(vec![H256::zero()]), + Some(vec![H256::zero()]), + None, + None, + ]; + let addresses = Some(vec![Address::default()]); + + let filter = Filter::new_with_address_and_topic( + AddressFilter::new(addresses), + TopicFilter::new(topics), + ); - let entry0 = LogEntry { - address: "b372018f3be9e171df0581136b59d2faf73a7d5d".into(), - topics: vec![ - "ff74e91598aed6ae5d2fdcf8b24cd2c7be49a0808112a305069355b7160f23f9".into(), - "ff74e91598aed6ae5d2fdcf8b24cd2c7be49a0808112a305069355b7160f23fa".into(), - "ff74e91598aed6ae5d2fdcf8b24cd2c7be49a0808112a305069355b7160f23f9".into(), - ], - data: vec![], + let entry0 = Log { + address: Address::default(), + topics: vec![H256::zero(), H256::zero(), H256::random()], + data: Default::default(), }; - let entry1 = LogEntry { - address: "b372018f3be9e171df0581136b59d2faf73a7d5e".into(), - topics: vec![ - "ff74e91598aed6ae5d2fdcf8b24cd2c7be49a0808112a305069355b7160f23f9".into(), - "ff74e91598aed6ae5d2fdcf8b24cd2c7be49a0808112a305069355b7160f23fa".into(), - "ff74e91598aed6ae5d2fdcf8b24cd2c7be49a0808112a305069355b7160f23f9".into(), - ], - data: vec![], + let entry1 = Log { + address: Address::default(), + topics: vec![H256::zero(), H256::random(), H256::random()], + data: Default::default(), }; - let entry2 = LogEntry { - address: "b372018f3be9e171df0581136b59d2faf73a7d5d".into(), - topics: vec!["ff74e91598aed6ae5d2fdcf8b24cd2c7be49a0808112a305069355b7160f23f9".into()], - data: vec![], + let entry2 = Log { + address: Address::random(), + topics: vec![H256::random(), H256::random(), H256::random()], + data: Default::default(), }; + // Filter matches assert_eq!(filter.matches(&entry0), true); assert_eq!(filter.matches(&entry1), false); assert_eq!(filter.matches(&entry2), false); + // Topic filter matches + assert_eq!(filter.topics.matches(&entry0), true); + assert_eq!(filter.topics.matches(&entry1), false); + assert_eq!(filter.topics.matches(&entry2), false); + // Address filter matches + assert_eq!(filter.addresses.matches(&entry0), true); + assert_eq!(filter.addresses.matches(&entry1), true); + assert_eq!(filter.addresses.matches(&entry2), false); } } diff --git a/cita-chain/types/src/header.rs b/cita-chain/types/src/header.rs index 706edb14f..926206cb8 100644 --- a/cita-chain/types/src/header.rs +++ b/cita-chain/types/src/header.rs @@ -1,24 +1,20 @@ -// CITA -// Copyright 2016-2018 Cryptape Technologies LLC. - -// This program is free software: you can redistribute it -// and/or modify it under the terms of the GNU 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 General Public License for more details. - -// You should have received a copy of the GNU General Public License -// along with this program. If not, see . +// Copyright Cryptape Technologies LLC. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. //! Block header. -use crate::basic_types::{LogBloom, ZERO_LOGBLOOM}; -use cita_types::{Address, H256, U256}; +use cita_types::{Address, Bloom, H256, U256}; use libproto::blockchain::{ Block as ProtoBlock, BlockHeader as ProtoBlockHeader, Proof as ProtoProof, ProofType, }; @@ -29,13 +25,17 @@ use std::cmp; use std::ops::{Deref, DerefMut}; use time::get_time; -pub use crate::BlockNumber; +use super::Bytes; +pub use crate::block_number::BlockNumber; use hashable::{Hashable, HASH_NULL_RLP}; -use util::{Bytes, HeapSizeOf}; + +lazy_static! { + pub static ref ZERO_BLOOM: Bloom = Bloom::from([0x00; 256]); +} #[derive(Debug, Clone, Eq)] pub struct OpenHeader { - /// Parent hash. + /// Previous block hash. parent_hash: H256, /// Block timestamp. timestamp: u64, @@ -43,13 +43,13 @@ pub struct OpenHeader { number: BlockNumber, /// Transactions root. transactions_root: H256, - /// Block gas limit. + /// Block quota limit. quota_limit: U256, - /// the proof of the block + /// Block proof proof: ProtoProof, - /// The version of the header. + /// Block version(Protocol version). version: u32, - /// the selected proposer address + /// Block proposer address proposer: Address, } @@ -82,7 +82,6 @@ impl Default for OpenHeader { } impl OpenHeader { - // TODO: trait pub fn from_protobuf(block: &ProtoBlock) -> Self { let header = block.get_header(); let version = block.get_version(); @@ -107,35 +106,33 @@ impl OpenHeader { && self.version() == header.version() } - /// Get the parent_hash field of the header. pub fn parent_hash(&self) -> &H256 { &self.parent_hash } - /// Get the timestamp field of the header. + pub fn timestamp(&self) -> u64 { self.timestamp } - /// Get the number field of the header. + pub fn number(&self) -> BlockNumber { self.number } - /// Get the transactions root field of the header. + pub fn transactions_root(&self) -> &H256 { &self.transactions_root } - /// Get the quota limit field of the header. + pub fn quota_limit(&self) -> &U256 { &self.quota_limit } - /// Get the proof field of the header. + pub fn proof(&self) -> &ProtoProof { &self.proof } - /// Get the version of the block + pub fn version(&self) -> u32 { self.version } - /// Get the proof type field of the header. pub fn proof_type(&self) -> Option { if self.proof == ProtoProof::new() { None @@ -143,35 +140,28 @@ impl OpenHeader { Some(self.proof.get_field_type()) } } - /// Get the selected proposer address of the header pub fn proposer(&self) -> &Address { &self.proposer } - /// Set the number field of the header. + pub fn set_parent_hash(&mut self, a: H256) { self.parent_hash = a; } - /// Set the quota limit field of the header. pub fn set_quota_limit(&mut self, a: U256) { self.quota_limit = a; } - /// Set the version of the header. pub fn set_version(&mut self, a: u32) { self.version = a; } - /// Set the proof the block. pub fn set_proof(&mut self, a: ProtoProof) { self.proof = a; } - /// Set the timestamp field of the header. pub fn set_timestamp(&mut self, a: u64) { self.timestamp = a; } - /// Set the timestamp field of the header to the current time. pub fn set_timestamp_now(&mut self, but_later_than: u64) { self.timestamp = cmp::max(get_time().sec as u64, but_later_than + 1); } - /// Set the number field of the header. pub fn set_number(&mut self, a: BlockNumber) { self.number = a; } @@ -180,15 +170,10 @@ impl OpenHeader { #[derive(Debug, Clone, Eq)] pub struct Header { open_header: OpenHeader, - /// State root. state_root: H256, - /// Block receipts root. receipts_root: H256, - /// Block bloom. - log_bloom: LogBloom, - /// Quota used for contracts execution. + log_bloom: Bloom, quota_used: U256, - /// The hash of the header. hash: Option, } @@ -229,7 +214,7 @@ impl Default for Header { open_header: OpenHeader::default(), state_root: HASH_NULL_RLP, receipts_root: HASH_NULL_RLP, - log_bloom: *ZERO_LOGBLOOM, + log_bloom: *ZERO_BLOOM, quota_used: U256::default(), hash: None, }; @@ -244,7 +229,7 @@ impl Header { open_header: header, state_root: HASH_NULL_RLP, receipts_root: HASH_NULL_RLP, - log_bloom: *ZERO_LOGBLOOM, + log_bloom: *ZERO_BLOOM, quota_used: U256::default(), hash: None, } @@ -254,77 +239,63 @@ impl Header { &self.open_header } - /// Get the state root field of the header. pub fn state_root(&self) -> &H256 { &self.state_root } - /// Get the receipts root field of the header. + pub fn receipts_root(&self) -> &H256 { &self.receipts_root } - /// Get the log bloom field of the header. - pub fn log_bloom(&self) -> &LogBloom { + pub fn log_bloom(&self) -> &Bloom { &self.log_bloom } - /// Get the quota used field of the header. pub fn quota_used(&self) -> &U256 { &self.quota_used } - /// Set the state root field of the header. + /// Need to reset hash with new_dirty(). pub fn set_state_root(&mut self, a: H256) { self.state_root = a; - self.note_dirty(); + self.new_dirty(); } - /// Set the receipts root field of the header. pub fn set_receipts_root(&mut self, a: H256) { self.receipts_root = a; - self.note_dirty(); + self.new_dirty(); } - /// Set the log bloom field of the header. - pub fn set_log_bloom(&mut self, a: LogBloom) { + pub fn set_log_bloom(&mut self, a: Bloom) { self.log_bloom = a; } - /// Set the quota used field of the header. pub fn set_quota_used(&mut self, a: U256) { self.quota_used = a; - self.note_dirty(); + self.new_dirty(); } - /// Set the quota limit field of the header. pub fn set_quota_limit(&mut self, a: U256) { self.quota_limit = a; - self.note_dirty(); + self.new_dirty(); } - /// Set the version of the header. pub fn set_version(&mut self, a: u32) { self.version = a; - self.note_dirty(); + self.new_dirty(); } - /// Set the proof the block. pub fn set_proof(&mut self, a: ProtoProof) { self.proof = a; - self.note_dirty(); + self.new_dirty(); } - /// Set the timestamp field of the header. pub fn set_timestamp(&mut self, a: u64) { self.timestamp = a; - self.note_dirty(); + self.new_dirty(); } - /// Set the timestamp field of the header to the current time. pub fn set_timestamp_now(&mut self, but_later_than: u64) { self.timestamp = cmp::max(get_time().sec as u64, but_later_than + 1); - self.note_dirty(); + self.new_dirty(); } - /// Set the number field of the header. pub fn set_number(&mut self, a: BlockNumber) { self.number = a; - self.note_dirty(); + self.new_dirty(); } - /// Set the number field of the header. pub fn set_parent_hash(&mut self, a: H256) { self.parent_hash = a; - self.note_dirty(); + self.new_dirty(); } - /// Get the hash of this header (sha3 of the RLP). pub fn hash(&self) -> Option { self.hash } @@ -336,14 +307,11 @@ impl Header { } } - /// Note that some fields have changed. Resets the memoised hash. - pub fn note_dirty(&mut self) -> &Self { + pub fn new_dirty(&mut self) -> &Self { self.hash = None; self } - // TODO: make these functions traity - /// Place this header into an RLP stream `s`. pub fn stream_rlp(&self, s: &mut RlpStream) { s.begin_list(12); s.append(&self.parent_hash); @@ -360,7 +328,6 @@ impl Header { s.append(&self.proposer); } - /// Get the RLP of this header. pub fn rlp(&self) -> Bytes { let mut s = RlpStream::new(); self.stream_rlp(&mut s); @@ -402,7 +369,7 @@ impl Header { proposer: self.open_header.proposer, }, hash: None, - log_bloom: *ZERO_LOGBLOOM, + log_bloom: *ZERO_BLOOM, state_root: HASH_NULL_RLP, receipts_root: HASH_NULL_RLP, quota_used: U256::zero(), @@ -450,7 +417,7 @@ impl Header { version: open_header.version, parent_hash: H256::from_slice(info.get_header().get_prevhash()), }, - log_bloom: LogBloom::from(info.get_header().get_log_bloom()), + log_bloom: Bloom::from(info.get_header().get_log_bloom()), quota_used: U256::from(info.get_header().get_quota_used()), receipts_root: H256::from(info.get_header().get_receipts_root()), state_root: H256::from(info.get_header().get_state_root()), @@ -464,29 +431,27 @@ impl Header { pub fn from_bytes(bytes: &[u8]) -> Self { rlp::decode(bytes) } - /// Verify if a header is the next header. + + /// Verify if a header is the next header, used by cross chain pub fn verify_next(&self, next: &Header, authorities: &[Address]) -> bool { // Calculate block header hash, and is should be same as the parent_hash in next header - if self.number() + 1 == next.number() { - } else { + if self.number() + 1 != next.number() { warn!("verify next block header block number failed"); return false; } - if self.hash().unwrap() == *next.parent_hash() { - } else { + if self.hash().unwrap() != *next.parent_hash() { warn!("verify next block header parent hash failed"); return false; }; - let next_proof = BftProof::from(next.proof().clone()); + // Verify block header, use proof.proposal - if self.number() == 0 || self.proposal_protobuf().crypt_hash() == next_proof.proposal { - } else { + let next_proof = BftProof::from(next.proof().clone()); + if self.number() != 0 && self.proposal_protobuf().crypt_hash() != next_proof.proposal { warn!("verify next block header proposal failed"); return false; }; // Verify signatures in proposal proof. - if next_proof.check(self.number() as usize, authorities) { - } else { + if !next_proof.check(self.number() as usize, authorities) { warn!("verify signatures for next block header failed"); return false; }; @@ -524,12 +489,6 @@ impl Encodable for Header { } } -impl HeapSizeOf for Header { - fn heap_size_of_children(&self) -> usize { - 0 - } -} - #[cfg(test)] mod tests { use super::{Header, OpenHeader}; @@ -539,12 +498,11 @@ mod tests { fn decode_and_encode_header() { // that's rlp of block header created with ethash engine. let open_header = OpenHeader::default(); - let header = Header::new(open_header); let header_rlp = rlp::encode(&header).into_vec(); + let header: Header = rlp::decode(&header_rlp); let encoded_header = rlp::encode(&header).into_vec(); - assert_eq!(header_rlp, encoded_header); } } diff --git a/cita-chain/types/src/ids.rs b/cita-chain/types/src/ids.rs deleted file mode 100644 index 0b92316ec..000000000 --- a/cita-chain/types/src/ids.rs +++ /dev/null @@ -1,52 +0,0 @@ -// Copyright 2015-2017 Parity Technologies (UK) Ltd. -// This file is part of Parity. - -// This software is free software: you can redistribute it and/or modify -// it under the terms of the GNU General Public License as published by -// the Free Software Foundation, either version 3 of the License, or -// (at your option) any later version. - -// This software 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 General Public License for more details. - -// You should have received a copy of the GNU General Public License -// along with Parity. If not, see . - -//! Unique identifiers. - -use crate::BlockNumber; -use cita_types::H256; -use jsonrpc_types::rpc_types::{BlockNumber as RpcBlockNumber, BlockTag}; - -/// Uniquely identifies block. -#[derive(Debug, PartialEq, Copy, Clone, Hash, Eq)] -pub enum BlockId { - /// Block's sha3. - // TODO: Query by number faster - /// Querying by hash is always faster. - Hash(H256), - /// Block number within canon blockchain. - // TODO: Change to Height - Number(BlockNumber), - /// Earliest block (genesis). - Earliest, - /// Latest mined block. - Latest, - /// Pending block. - Pending, -} - -pub type TransactionId = H256; - -impl From for BlockId { - fn from(v: RpcBlockNumber) -> BlockId { - match v { - RpcBlockNumber::Height(height) => BlockId::Number(height.into()), - RpcBlockNumber::Tag(BlockTag::Latest) => BlockId::Latest, - RpcBlockNumber::Tag(BlockTag::Earliest) => BlockId::Earliest, - RpcBlockNumber::Tag(BlockTag::Pending) => BlockId::Pending, - } - } -} diff --git a/cita-chain/types/src/lib.rs b/cita-chain/types/src/lib.rs index a446c9c85..0bf60c8b1 100644 --- a/cita-chain/types/src/lib.rs +++ b/cita-chain/types/src/lib.rs @@ -1,50 +1,41 @@ -// CITA -// Copyright 2016-2019 Cryptape Technologies LLC. - -// This program is free software: you can redistribute it -// and/or modify it under the terms of the GNU 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 General Public License for more details. - -// You should have received a copy of the GNU General Public License -// along with this program. If not, see . +// Copyrighttape Technologies LLC. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. extern crate cita_crypto as crypto; #[macro_use] -extern crate rlp_derive; -#[macro_use] extern crate serde_derive; #[macro_use] extern crate lazy_static; #[macro_use] extern crate cita_logger as logger; -extern crate db as cita_db; +extern crate cita_database as cita_db; pub extern crate bloomchain; -pub mod account_diff; -pub mod basic_account; -pub mod basic_types; +pub type Bytes = Vec; pub mod block; -pub mod cache_manager; -pub mod call_analytics; -pub mod db; -pub mod extras; +pub mod block_number; +pub mod block_receipts; +pub mod context; +pub mod db_indexes; +pub mod errors; pub mod filter; pub mod header; -pub mod ids; +pub mod log; pub mod log_blooms; -pub mod log_entry; pub mod receipt; pub mod reserved_addresses; -pub mod state_diff; +pub mod state_proof; pub mod transaction; - -/// Type for block number. -pub type BlockNumber = u64; +pub mod transaction_index; diff --git a/cita-chain/types/src/log.rs b/cita-chain/types/src/log.rs new file mode 100644 index 000000000..59aca86f3 --- /dev/null +++ b/cita-chain/types/src/log.rs @@ -0,0 +1,200 @@ +// Copyright Cryptape Technologies LLC. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +use super::Bytes; +use crate::block_number::BlockNumber; +use cita_types::traits::BloomTools; +use cita_types::{Address, Bloom, H256}; +use jsonrpc_types::rpc_types::Log as RpcLog; +use libproto::executor::LogEntry as ProtoLog; +use rlp::{Decodable, DecoderError, Encodable, RlpStream, UntrustedRlp}; +use std::ops::Deref; + +type Topic = Vec; + +#[derive(Serialize, Deserialize, Default, Debug, Clone, PartialEq, Eq)] +pub struct Log { + pub address: Address, + pub topics: Topic, + pub data: Bytes, +} + +impl Encodable for Log { + fn rlp_append(&self, stream: &mut RlpStream) { + stream.begin_list(3); + stream.append(&self.address); + stream.append_list(&self.topics); + stream.append(&self.data); + } +} + +impl Decodable for Log { + fn decode(rlp: &UntrustedRlp) -> Result { + Ok(Log { + address: rlp.val_at(0)?, + topics: rlp.list_at(1)?, + data: rlp.val_at(2)?, + }) + } +} + +impl Log { + pub fn bloom(&self) -> Bloom { + self.topics + .iter() + .fold(Bloom::from_raw(&self.address), |bloom, topic| { + let mut bloom = bloom; + bloom.accrue_raw(&topic); + bloom + }) + } + + pub fn protobuf(&self) -> ProtoLog { + let mut proto_log = ProtoLog::new(); + + proto_log.set_address(self.address.to_vec()); + proto_log.topics = self + .topics + .clone() + .into_iter() + .map(|topic| topic.to_vec()) + .collect(); + proto_log.set_data(self.data.clone()); + proto_log + } +} + +impl Into for Log { + fn into(self) -> RpcLog { + RpcLog { + address: self.address, + topics: self.topics.into_iter().map(Into::into).collect(), + data: self.data.into(), + block_hash: None, + block_number: None, + transaction_hash: None, + transaction_index: None, + log_index: None, + transaction_log_index: None, + } + } +} + +/// Log localized. +#[derive(Default, Debug, PartialEq, Clone)] +pub struct LocalizedLog { + pub log: Log, + pub block_hash: H256, + pub block_number: BlockNumber, + pub transaction_hash: H256, + pub transaction_index: usize, + pub log_index: usize, + pub transaction_log_index: usize, +} + +impl Deref for LocalizedLog { + type Target = Log; + + fn deref(&self) -> &Self::Target { + &self.log + } +} + +impl Into for LocalizedLog { + fn into(self) -> RpcLog { + RpcLog { + address: self.log.address, + topics: self.log.topics.into_iter().map(Into::into).collect(), + data: self.log.data.into(), + block_hash: Some(self.block_hash), + block_number: Some(self.block_number.into()), + transaction_hash: Some(self.transaction_hash), + transaction_index: Some(self.transaction_index.into()), + log_index: Some(self.log_index.into()), + transaction_log_index: Some(self.transaction_log_index.into()), + } + } +} + +#[cfg(test)] +mod tests { + use super::{Bloom, Log}; + use cita_types::{Address, H256}; + + #[test] + fn test_address_log_bloom() { + let address = Address::default(); + let log = Log { + address, + topics: vec![], + data: vec![], + }; + let bloom: Bloom = " + 0000000000000000008000000000000000000000000000000000000000000000 + 0000000000000000000000000000000200000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000100000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000" + .into(); + assert_eq!(log.bloom(), bloom); + } + + #[test] + fn test_address_and_topic_log_bloom() { + let address = Address::default(); + let topics = vec![H256::zero()]; + let log = Log { + address, + topics, + data: vec![], + }; + let bloom: Bloom = " + 0000000000000000008000000000000000000000000000000000000000000000 + 0000000000000000000000000000000200000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000002000000000000000000080000000000000000000000000000000000 + 0000000000000000000000000000000100000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000002000 + 0000000000000000000000000000000000000000000000000000000000000000" + .into(); + assert_eq!(log.bloom(), bloom); + } + + #[test] + fn test_address_topic_and_data_log_bloom() { + let address = Address::default(); + let topics = vec![H256::zero()]; + let data = b"test".to_vec(); + let log = Log { + address, + topics, + data, + }; + let bloom: Bloom = " + 0000000000000000008000000000000000000000000000000000000000000000 + 0000000000000000000000000000000200000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000002000000000000000000080000000000000000000000000000000000 + 0000000000000000000000000000000100000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000002000 + 0000000000000000000000000000000000000000000000000000000000000000" + .into(); + assert_eq!(log.bloom(), bloom); + } +} diff --git a/cita-chain/types/src/log_blooms.rs b/cita-chain/types/src/log_blooms.rs index 21087926a..595f24f51 100644 --- a/cita-chain/types/src/log_blooms.rs +++ b/cita-chain/types/src/log_blooms.rs @@ -1,28 +1,22 @@ -// Copyright 2015-2017 Parity Technologies (UK) Ltd. -// This file is part of Parity. +// Copyright Cryptape Technologies LLC. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. -// This software is free software: you can redistribute it and/or modify -// it under the terms of the GNU General Public License as published by -// the Free Software Foundation, either version 3 of the License, or -// (at your option) any later version. - -// This software 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 General Public License for more details. - -// You should have received a copy of the GNU General Public License -// along with Parity. If not, see . - -//! Bridge between bloomchain crate types and cita LogBloom. - -use crate::log_entry::LogBloom; use bloomchain::group::BloomGroup; use bloomchain::Bloom; -use rlp::*; -use util::HeapSizeOf; +use cita_types::Bloom as LogBloom; +use rlp::{Decodable, DecoderError, Encodable, RlpStream, UntrustedRlp}; -/// Represents group of X consecutive blooms. #[derive(Debug, Clone)] pub struct LogBloomGroup { blooms: Vec, @@ -63,9 +57,3 @@ impl Encodable for LogBloomGroup { s.append_list(&self.blooms); } } - -impl HeapSizeOf for LogBloomGroup { - fn heap_size_of_children(&self) -> usize { - 0 - } -} diff --git a/cita-chain/types/src/log_entry.rs b/cita-chain/types/src/log_entry.rs deleted file mode 100644 index 0cfc4c409..000000000 --- a/cita-chain/types/src/log_entry.rs +++ /dev/null @@ -1,180 +0,0 @@ -// Copyright 2015-2017 Parity Technologies (UK) Ltd. -// This file is part of Parity. - -// This software is free software: you can redistribute it and/or modify -// it under the terms of the GNU General Public License as published by -// the Free Software Foundation, either version 3 of the License, or -// (at your option) any later version. - -// This software 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 General Public License for more details. - -// You should have received a copy of the GNU General Public License -// along with Parity. If not, see . - -//! Log entry type definition. - -use crate::BlockNumber; -use cita_types::traits::BloomTools; -use cita_types::{Address, Bloom, H256}; -use jsonrpc_types::rpc_types::Log as RpcLog; -use libproto::executor::LogEntry as ProtoLogEntry; -use rlp::*; -use std::ops::Deref; -use util::{Bytes, HeapSizeOf}; - -pub type LogBloom = Bloom; - -/// A record of execution for a `LOG` operation. -#[derive(Serialize, Deserialize, Default, Debug, Clone, PartialEq, Eq)] -pub struct LogEntry { - /// The address of the contract executing at the point of the `LOG` operation. - pub address: Address, - /// The topics associated with the `LOG` operation. - pub topics: Vec, - /// The data associated with the `LOG` operation. - pub data: Bytes, -} - -impl Encodable for LogEntry { - fn rlp_append(&self, s: &mut RlpStream) { - s.begin_list(3); - s.append(&self.address); - s.append_list(&self.topics); - s.append(&self.data); - } -} - -impl Decodable for LogEntry { - fn decode(rlp: &UntrustedRlp) -> Result { - let entry = LogEntry { - address: rlp.val_at(0)?, - topics: rlp.list_at(1)?, - data: rlp.val_at(2)?, - }; - Ok(entry) - } -} - -impl HeapSizeOf for LogEntry { - fn heap_size_of_children(&self) -> usize { - self.topics.heap_size_of_children() + self.data.heap_size_of_children() - } -} - -impl LogEntry { - /// Calculates the bloom of this log entry. - pub fn bloom(&self) -> LogBloom { - self.topics - .iter() - .fold(LogBloom::from_raw(&self.address), |b, t| { - let mut b = b; - b.accrue_raw(&t); - b - }) - } - - pub fn protobuf(&self) -> ProtoLogEntry { - let mut proto_log_entry = ProtoLogEntry::new(); - - proto_log_entry.set_address(self.address.to_vec()); - proto_log_entry.topics = self - .topics - .clone() - .into_iter() - .map(|topic| topic.to_vec()) - .collect(); - proto_log_entry.set_data(self.data.clone()); - proto_log_entry - } -} - -impl Into for LogEntry { - fn into(self) -> RpcLog { - RpcLog { - address: self.address, - topics: self.topics.into_iter().map(Into::into).collect(), - data: self.data.into(), - block_hash: None, - block_number: None, - transaction_hash: None, - transaction_index: None, - log_index: None, - transaction_log_index: None, - } - } -} - -/// Log localized in a blockchain. -#[derive(Default, Debug, PartialEq, Clone)] -pub struct LocalizedLogEntry { - /// Plain log entry. - pub entry: LogEntry, - /// Block in which this log was created. - pub block_hash: H256, - /// Block number. - pub block_number: BlockNumber, - /// Hash of transaction in which this log was created. - pub transaction_hash: H256, - /// Index of transaction within block. - pub transaction_index: usize, - /// Log position in the block. - pub log_index: usize, - /// Log position in the transaction. - pub transaction_log_index: usize, -} - -impl Deref for LocalizedLogEntry { - type Target = LogEntry; - - fn deref(&self) -> &Self::Target { - &self.entry - } -} - -impl Into for LocalizedLogEntry { - fn into(self) -> RpcLog { - RpcLog { - address: self.entry.address, - topics: self.entry.topics.into_iter().map(Into::into).collect(), - data: self.entry.data.into(), - block_hash: Some(self.block_hash), - block_number: Some(self.block_number.into()), - transaction_hash: Some(self.transaction_hash), - transaction_index: Some(self.transaction_index.into()), - log_index: Some(self.log_index.into()), - transaction_log_index: Some(self.transaction_log_index.into()), - } - } -} - -#[cfg(test)] -mod tests { - use super::{LogBloom, LogEntry}; - use cita_types::Address; - - #[test] - fn test_empty_log_bloom() { - let bloom = "0000000000000000000000000000000000000000000000000000000000000000\ - 0000000000000000000000000000000000000000000000000000000000000000\ - 0000000000000000000000000000000000000000000000000000088000000000\ - 0000000000000000000000000000000000000000000000000000000000000000\ - 0000000000000000000000000000000000000000000000000000000000000000\ - 0000000000000000000000000000000000000000000000000000000000000000\ - 0000000000000000000080000000000000000000000000000000000000000000\ - 0000000000000000000000000000000000000000000000000000000000000000" - .parse::() - .unwrap(); - let address = "0f572e5295c57f15886f9b263e2f6d2d6c7b5ec6" - .parse::
() - .unwrap(); - let log = LogEntry { - address, - topics: vec![], - data: vec![], - }; - assert_eq!(log.bloom(), bloom); - } -} diff --git a/cita-chain/types/src/receipt.rs b/cita-chain/types/src/receipt.rs index 8d7a5d0ee..d130faa61 100644 --- a/cita-chain/types/src/receipt.rs +++ b/cita-chain/types/src/receipt.rs @@ -1,198 +1,48 @@ -// Copyright 2015-2017 Parity Technologies (UK) Ltd. -// This file is part of Parity. - -// This software is free software: you can redistribute it and/or modify -// it under the terms of the GNU General Public License as published by -// the Free Software Foundation, either version 3 of the License, or -// (at your option) any later version. - -// This software 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 General Public License for more details. - -// You should have received a copy of the GNU General Public License -// along with Parity. If not, see . +// Copyright Cryptape Technologies LLC. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. //! Receipt -use crate::log_entry::{LocalizedLogEntry, LogBloom, LogEntry}; -use crate::BlockNumber; -use cita_types::traits::LowerHex; -use cita_types::{Address, H256, U256}; -use jsonrpc_types::rpc_types::Receipt as RpcReceipt; -use libproto::executor::{ - Receipt as ProtoReceipt, ReceiptError as ProtoReceiptError, ReceiptErrorWithOption, StateRoot, -}; -use rlp::*; +use super::Bytes; use std::str::FromStr; -use util::{Bytes, HeapSizeOf}; -#[derive(Serialize, Deserialize, Debug, PartialEq, Clone, Copy, Eq)] -pub enum ReceiptError { - // ExecutionError - NotEnoughBaseQuota, - BlockQuotaLimitReached, - AccountQuotaLimitReached, - InvalidNonce, - NotEnoughCash, - NoTransactionPermission, - NoContractPermission, - NoCallPermission, - ExecutionInternal, - TransactionMalformed, - // EVM error(chain/core/src/evm/evm.rs) - OutOfQuota, - BadJumpDestination, - BadInstruction, - StackUnderflow, - OutOfStack, - Internal, - MutableCallInStaticContext, - OutOfBounds, - Reverted, -} +use crate::block_number::BlockNumber; +use crate::errors::ReceiptError; +use crate::log::{LocalizedLog, Log}; -impl ReceiptError { - /// Returns human-readable description - pub fn description(self) -> String { - let desc = match self { - ReceiptError::NotEnoughBaseQuota => "Not enough base quota.", - ReceiptError::BlockQuotaLimitReached => "Block quota limit reached.", - ReceiptError::AccountQuotaLimitReached => "Account quota limit reached.", - ReceiptError::InvalidNonce => "Invalid transaction nonce.", - ReceiptError::NotEnoughCash => "Cost of transaction exceeds sender balance.", - ReceiptError::NoTransactionPermission => "No transaction permission.", - ReceiptError::NoContractPermission => "No contract permission.", - ReceiptError::NoCallPermission => "No Call contract permission.", - ReceiptError::ExecutionInternal => "Execution internal error.", - ReceiptError::TransactionMalformed => "Malformed transaction.", - ReceiptError::OutOfQuota => "Out of quota.", - ReceiptError::BadJumpDestination => { - "Jump position wasn't marked with JUMPDEST instruction." - } - ReceiptError::BadInstruction => "Instruction is not supported.", - ReceiptError::StackUnderflow => "Not enough stack elements to execute instruction.", - ReceiptError::OutOfStack => "Execution would exceed defined Stack Limit.", - ReceiptError::Internal => "EVM internal error.", - ReceiptError::MutableCallInStaticContext => "Mutable call in static context.", - ReceiptError::OutOfBounds => "Out of bounds.", - ReceiptError::Reverted => "Reverted.", - }; - desc.to_string() - } - - pub fn protobuf(self) -> ProtoReceiptError { - match self { - ReceiptError::NotEnoughBaseQuota => ProtoReceiptError::NotEnoughBaseQuota, - ReceiptError::BlockQuotaLimitReached => ProtoReceiptError::BlockQuotaLimitReached, - ReceiptError::AccountQuotaLimitReached => ProtoReceiptError::AccountQuotaLimitReached, - ReceiptError::InvalidNonce => ProtoReceiptError::InvalidTransactionNonce, - ReceiptError::NotEnoughCash => ProtoReceiptError::NotEnoughCash, - ReceiptError::NoTransactionPermission => ProtoReceiptError::NoTransactionPermission, - ReceiptError::NoContractPermission => ProtoReceiptError::NoContractPermission, - ReceiptError::NoCallPermission => ProtoReceiptError::NoCallPermission, - ReceiptError::ExecutionInternal => ProtoReceiptError::ExecutionInternal, - ReceiptError::TransactionMalformed => ProtoReceiptError::TransactionMalformed, - ReceiptError::OutOfQuota => ProtoReceiptError::OutOfQuota, - ReceiptError::BadJumpDestination => ProtoReceiptError::BadJumpDestination, - ReceiptError::BadInstruction => ProtoReceiptError::BadInstruction, - ReceiptError::StackUnderflow => ProtoReceiptError::StackUnderflow, - ReceiptError::OutOfStack => ProtoReceiptError::OutOfStack, - ReceiptError::Internal => ProtoReceiptError::Internal, - ReceiptError::MutableCallInStaticContext => { - ProtoReceiptError::MutableCallInStaticContext - } - ReceiptError::OutOfBounds => ProtoReceiptError::OutOfBounds, - ReceiptError::Reverted => ProtoReceiptError::Reverted, - } - } - - fn from_proto(receipt_error: ProtoReceiptError) -> Self { - match receipt_error { - ProtoReceiptError::NotEnoughBaseQuota => ReceiptError::NotEnoughBaseQuota, - ProtoReceiptError::BlockQuotaLimitReached => ReceiptError::BlockQuotaLimitReached, - ProtoReceiptError::AccountQuotaLimitReached => ReceiptError::AccountQuotaLimitReached, - ProtoReceiptError::InvalidTransactionNonce => ReceiptError::InvalidNonce, - ProtoReceiptError::NotEnoughCash => ReceiptError::NotEnoughCash, - ProtoReceiptError::NoTransactionPermission => ReceiptError::NoTransactionPermission, - ProtoReceiptError::NoContractPermission => ReceiptError::NoContractPermission, - ProtoReceiptError::NoCallPermission => ReceiptError::NoCallPermission, - ProtoReceiptError::ExecutionInternal => ReceiptError::ExecutionInternal, - ProtoReceiptError::TransactionMalformed => ReceiptError::TransactionMalformed, - ProtoReceiptError::OutOfQuota => ReceiptError::OutOfQuota, - ProtoReceiptError::BadJumpDestination => ReceiptError::BadJumpDestination, - ProtoReceiptError::BadInstruction => ReceiptError::BadInstruction, - ProtoReceiptError::StackUnderflow => ReceiptError::StackUnderflow, - ProtoReceiptError::OutOfStack => ReceiptError::OutOfStack, - ProtoReceiptError::Internal => ReceiptError::Internal, - ProtoReceiptError::MutableCallInStaticContext => { - ReceiptError::MutableCallInStaticContext - } - ProtoReceiptError::OutOfBounds => ReceiptError::OutOfBounds, - ProtoReceiptError::Reverted => ReceiptError::Reverted, - } - } -} - -impl Decodable for ReceiptError { - fn decode(rlp: &UntrustedRlp) -> Result { - match rlp.as_val::()? { - 0 => Ok(ReceiptError::NotEnoughBaseQuota), - 1 => Ok(ReceiptError::BlockQuotaLimitReached), - 2 => Ok(ReceiptError::AccountQuotaLimitReached), - 3 => Ok(ReceiptError::InvalidNonce), - 4 => Ok(ReceiptError::NotEnoughCash), - 5 => Ok(ReceiptError::NoTransactionPermission), - 6 => Ok(ReceiptError::NoContractPermission), - 7 => Ok(ReceiptError::NoCallPermission), - 8 => Ok(ReceiptError::ExecutionInternal), - 9 => Ok(ReceiptError::TransactionMalformed), - 10 => Ok(ReceiptError::OutOfQuota), - 11 => Ok(ReceiptError::BadJumpDestination), - 12 => Ok(ReceiptError::BadInstruction), - 13 => Ok(ReceiptError::StackUnderflow), - 14 => Ok(ReceiptError::OutOfStack), - 15 => Ok(ReceiptError::Internal), - 16 => Ok(ReceiptError::MutableCallInStaticContext), - 17 => Ok(ReceiptError::OutOfBounds), - 18 => Ok(ReceiptError::Reverted), - _ => Err(DecoderError::Custom("Unknown Receipt error.")), - } - } -} - -impl Encodable for ReceiptError { - fn rlp_append(&self, s: &mut RlpStream) { - s.append(&(*self as u8)); - } -} +use cita_types::traits::LowerHex; +use cita_types::{Address, Bloom as LogBloom, H256, U256}; +use jsonrpc_types::rpc_types::Receipt as RpcReceipt; +use libproto::executor::{Receipt as ProtoReceipt, ReceiptErrorWithOption, StateRoot}; +use rlp::{Decodable, DecoderError, Encodable, RlpStream, UntrustedRlp}; -/// Information describing execution of a transaction. #[derive(Serialize, Deserialize, Default, Debug, Clone, PartialEq, Eq)] pub struct Receipt { - /// The state root after executing the transaction. Optional since EIP98 pub state_root: Option, - /// The total gas used in the block following execution of the transaction. pub quota_used: U256, - /// The OR-wide combination of all logs' blooms for this transaction. pub log_bloom: LogBloom, - /// The logs stemming from this transaction. - pub logs: Vec, - /// Transaction transact error + pub logs: Vec, pub error: Option, - /// For calculating contract address pub account_nonce: U256, - /// Transaction hash. pub transaction_hash: H256, } impl Receipt { - /// Create a new receipt. pub fn new( state_root: Option, quota_used: U256, - logs: Vec, + logs: Vec, error: Option, account_nonce: U256, transaction_hash: H256, @@ -263,7 +113,7 @@ impl From for Receipt { .map(|topic| H256::from_slice(topic)) .collect(); let data: Bytes = Bytes::from(log_entry.get_data()); - LogEntry { + Log { address, topics, data, @@ -331,40 +181,22 @@ impl Decodable for Receipt { } } -impl HeapSizeOf for Receipt { - fn heap_size_of_children(&self) -> usize { - self.logs.heap_size_of_children() - } -} - -/// Receipt with additional info. -#[derive(Debug, Clone, PartialEq)] -pub struct LocalizedReceipt { - /// Transaction hash. +#[derive(Debug, Clone)] +pub struct RichReceipt { pub transaction_hash: H256, - /// Transaction index. pub transaction_index: usize, - /// Block hash. pub block_hash: H256, - /// Block number. pub block_number: BlockNumber, - /// The total gas used in the block following execution of the transaction. pub cumulative_quota_used: U256, - /// The gas used in the execution of the transaction. Note the difference of meaning to `Receipt::quota_used`. pub quota_used: U256, - /// Contract address. pub contract_address: Option
, - /// Logs - pub logs: Vec, - /// Logs bloom + pub logs: Vec, pub log_bloom: LogBloom, - /// State root pub state_root: Option, - /// Receipt error pub error: Option, } -impl Into for LocalizedReceipt { +impl Into for RichReceipt { fn into(self) -> RpcReceipt { RpcReceipt { transaction_hash: Some(self.transaction_hash), @@ -385,14 +217,14 @@ impl Into for LocalizedReceipt { #[cfg(test)] mod tests { use super::*; - use crate::log_entry::LogEntry; + use crate::log::Log; #[test] fn test_no_state_root() { let r = Receipt::new( None, 0x40cae.into(), - vec![LogEntry { + vec![Log { address: "dcf421d093428b096ca501a7cd1a740855a7976f".into(), topics: vec![], data: vec![0u8; 32], @@ -413,7 +245,7 @@ mod tests { let r = Receipt::new( Some("2f697d671e9ae4ee24a43c4b0d7e15f1cb4ba6de1561120d43b9a4e8c4a8a6ee".into()), 0x40cae.into(), - vec![LogEntry { + vec![Log { address: "dcf421d093428b096ca501a7cd1a740855a7976f".into(), topics: vec![], data: vec![0u8; 32], @@ -433,7 +265,7 @@ mod tests { let r = Receipt::new( Some("2f697d671e9ae4ee24a43c4b0d7e15f1cb4ba6de1561120d43b9a4e8c4a8a6ee".into()), 0x40cae.into(), - vec![LogEntry { + vec![Log { address: "dcf421d093428b096ca501a7cd1a740855a7976f".into(), topics: vec![], data: vec![0u8; 32], diff --git a/cita-chain/types/src/reserved_addresses.rs b/cita-chain/types/src/reserved_addresses.rs index 7b80bc51e..8816ec6b3 100644 --- a/cita-chain/types/src/reserved_addresses.rs +++ b/cita-chain/types/src/reserved_addresses.rs @@ -1,19 +1,16 @@ -// CITA -// Copyright 2016-2019 Cryptape Technologies LLC. - -// This program is free software: you can redistribute it -// and/or modify it under the terms of the GNU 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 General Public License for more details. - -// You should have received a copy of the GNU General Public License -// along with this program. If not, see . +// Copyright Cryptape Technologies LLC. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. // Define all Reserved Addresses. // # Builtin @@ -83,10 +80,6 @@ pub const EDRECOVER_ADDRESS: &str = "0000000000000000000000000000000000ff0001"; pub const STORE_ADDRESS: &str = "ffffffffffffffffffffffffffffffffff010000"; pub const ABI_ADDRESS: &str = "ffffffffffffffffffffffffffffffffff010001"; pub const AMEND_ADDRESS: &str = "ffffffffffffffffffffffffffffffffff010002"; -// Go Action Address -pub const GO_CONTRACT: &str = "ffffffffffffffffffffffffffffffffff018000"; -pub const GO_CONTRACT_MIN: &str = "ffffffffffffffffffffffffffffffffff018001"; -pub const GO_CONTRACT_MAX: &str = "ffffffffffffffffffffffffffffffffff018fff"; // Normal System Contracts pub const SYS_CONFIG: &str = "ffffffffffffffffffffffffffffffffff020000"; pub const NODE_MANAGER: &str = "ffffffffffffffffffffffffffffffffff020001"; diff --git a/cita-chain/types/src/state_diff.rs b/cita-chain/types/src/state_diff.rs deleted file mode 100644 index 6202f9cb8..000000000 --- a/cita-chain/types/src/state_diff.rs +++ /dev/null @@ -1,56 +0,0 @@ -// Copyright 2015-2017 Parity Technologies (UK) Ltd. -// This file is part of Parity. - -// This software is free software: you can redistribute it and/or modify -// it under the terms of the GNU General Public License as published by -// the Free Software Foundation, either version 3 of the License, or -// (at your option) any later version. - -// This software 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 General Public License for more details. - -// You should have received a copy of the GNU General Public License -// along with Parity. If not, see . - -//! State diff module. - -use crate::account_diff::*; -use cita_types::Address; -use std::collections::BTreeMap; -use std::fmt; -use std::ops::*; - -#[derive(Debug, PartialEq, Eq, Clone)] -#[cfg_attr(feature = "ipc", binary)] -/// Expression for the delta between two system states. Encoded the -/// delta of every altered account. -pub struct StateDiff { - /// Raw diff key-value - pub raw: BTreeMap, -} - -impl StateDiff { - /// Get the actual data. - pub fn get(&self) -> &BTreeMap { - &self.raw - } -} - -impl fmt::Display for StateDiff { - fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { - for (add, acc) in &self.raw { - write!(f, "{} {}: {}", acc.existance(), add, acc)?; - } - Ok(()) - } -} - -impl Deref for StateDiff { - type Target = BTreeMap; - - fn deref(&self) -> &Self::Target { - &self.raw - } -} diff --git a/cita-chain/types/src/state_proof.rs b/cita-chain/types/src/state_proof.rs new file mode 100644 index 000000000..d419b77a8 --- /dev/null +++ b/cita-chain/types/src/state_proof.rs @@ -0,0 +1,90 @@ +use super::Bytes; +use cita_types::{Address, H256}; +use rlp::{self, Decodable, DecoderError, Encodable, RlpStream, UntrustedRlp}; + +#[derive(Default, Debug, Clone)] +pub struct StateProof { + address: Address, + account_proof: Vec, + key: H256, + value_proof: Vec, +} + +impl Encodable for StateProof { + fn rlp_append(&self, s: &mut RlpStream) { + s.begin_list(4); + s.append(&self.address); + s.append_list::(&self.account_proof); + s.append(&self.key); + s.append_list::(&self.value_proof); + } +} + +impl Decodable for StateProof { + fn decode(rlp: &UntrustedRlp) -> Result { + Ok(StateProof { + address: rlp.val_at(0)?, + account_proof: rlp.list_at(1)?, + key: rlp.val_at(2)?, + value_proof: rlp.list_at(3)?, + }) + } +} + +impl StateProof { + pub fn from_bytes(bytes: &[u8]) -> Self { + rlp::decode(bytes) + } + + // FixMe: The implementation should be finished while fixing cross chain + pub fn verify(&self, _state_root: H256) -> Option { + // let state = State(); + // state.verify_proof(); + + // let trie = PatriciaTrie::new(db, codec); + // trie.verify_proof(); + // trie.verify_proof(); + + // trie::triedb::verify_value_proof( + // &self.address, + // state_root, + // &self.account_proof, + // Account::from_rlp, + // ) + // .and_then(|a| a.verify_value_proof(&self.key, &self.value_proof)) + None + } + + pub fn address(&self) -> &Address { + &self.address + } + + pub fn account_proof(&self) -> &Vec { + &self.account_proof + } + + pub fn key(&self) -> &H256 { + &self.key + } + + #[cfg(test)] + pub fn set_address(&mut self, new_address: Address) { + self.address = new_address; + } +} + +#[cfg(test)] +mod test { + use super::StateProof; + use rlp; + + #[test] + fn test_encode_and_decode_state_proof() { + let state_proof = StateProof::default(); + + let proof_rlp = rlp::encode(&state_proof).into_vec(); + let decoded_res: StateProof = rlp::decode(&proof_rlp); + let encoded_rlp = rlp::encode(&decoded_res).into_vec(); + assert_eq!(proof_rlp, encoded_rlp); + } +} diff --git a/cita-chain/types/src/transaction.rs b/cita-chain/types/src/transaction.rs index 0f2ebbc03..99737c42d 100644 --- a/cita-chain/types/src/transaction.rs +++ b/cita-chain/types/src/transaction.rs @@ -1,25 +1,23 @@ -// CITA -// Copyright 2016-2017 Cryptape Technologies LLC. - -// This program is free software: you can redistribute it -// and/or modify it under the terms of the GNU 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 General Public License for more details. - -// You should have received a copy of the GNU General Public License -// along with this program. If not, see . - +// Copyright Cryptape Technologies LLC. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +use super::Bytes; +use crate::block_number::BlockNumber; use crate::crypto::{ pubkey_to_address, PubKey, Signature, HASH_BYTES_LEN, PUBKEY_BYTES_LEN, SIGNATURE_BYTES_LEN, }; -use crate::reserved_addresses::{ABI_ADDRESS, AMEND_ADDRESS, GO_CONTRACT, STORE_ADDRESS}; -use crate::BlockNumber; +use crate::reserved_addresses::{ABI_ADDRESS, AMEND_ADDRESS, STORE_ADDRESS}; use cita_types::traits::LowerHex; use cita_types::{clean_0x, Address, H256, U256}; use libproto::blockchain::{ @@ -29,7 +27,6 @@ use libproto::blockchain::{ use rlp::*; use std::ops::{Deref, DerefMut}; use std::str::FromStr; -use util::{Bytes, HeapSizeOf}; #[derive(Debug, PartialEq, Clone)] pub enum Error { @@ -51,8 +48,6 @@ pub enum Action { Call(Address), /// Store the contract ABI AbiStore, - /// Create creates new contract for grpc. - GoCreate, /// amend data in state AmendData, } @@ -70,15 +65,12 @@ impl Decodable for Action { } else { let store_addr: Address = STORE_ADDRESS.into(); let abi_addr: Address = ABI_ADDRESS.into(); - let go_addr: Address = GO_CONTRACT.into(); let amend_addr: Address = AMEND_ADDRESS.into(); let addr: Address = rlp.as_val()?; if addr == store_addr { Ok(Action::Store) } else if addr == abi_addr { Ok(Action::AbiStore) - } else if addr == go_addr { - Ok(Action::GoCreate) } else if addr == amend_addr { Ok(Action::AmendData) } else { @@ -92,14 +84,12 @@ impl Encodable for Action { fn rlp_append(&self, s: &mut RlpStream) { let store_addr: Address = STORE_ADDRESS.into(); let abi_addr: Address = ABI_ADDRESS.into(); - let go_addr: Address = GO_CONTRACT.into(); let amend_addr: Address = AMEND_ADDRESS.into(); match *self { Action::Create => s.append_internal(&""), Action::Call(ref addr) => s.append_internal(addr), Action::Store => s.append_internal(&store_addr), Action::AbiStore => s.append_internal(&abi_addr), - Action::GoCreate => s.append_internal(&go_addr), Action::AmendData => s.append_internal(&amend_addr), }; } @@ -171,12 +161,6 @@ pub struct Transaction { pub version: u32, } -impl HeapSizeOf for Transaction { - fn heap_size_of_children(&self) -> usize { - self.data.heap_size_of_children() - } -} - impl Decodable for Transaction { fn decode(d: &UntrustedRlp) -> Result { if d.item_count()? != 9 { @@ -227,7 +211,6 @@ impl Transaction { "" => Action::Create, STORE_ADDRESS => Action::Store, ABI_ADDRESS => Action::AbiStore, - GO_CONTRACT => Action::GoCreate, AMEND_ADDRESS => Action::AmendData, _ => Action::Call(Address::from_str(to).map_err(|_| Error::ParseError)?), } @@ -240,7 +223,6 @@ impl Transaction { match to_addr.lower_hex().as_str() { STORE_ADDRESS => Action::Store, ABI_ADDRESS => Action::AbiStore, - GO_CONTRACT => Action::GoCreate, AMEND_ADDRESS => Action::AmendData, _ => Action::Call(to_addr), } @@ -325,7 +307,6 @@ impl Transaction { Action::Call(ref to) => pt.set_to(to.lower_hex()), Action::Store => pt.set_to(STORE_ADDRESS.into()), Action::AbiStore => pt.set_to(ABI_ADDRESS.into()), - Action::GoCreate => pt.set_to(GO_CONTRACT.into()), Action::AmendData => pt.set_to(AMEND_ADDRESS.into()), } } else { @@ -334,7 +315,6 @@ impl Transaction { Action::Call(ref to) => pt.set_to_v1(to.to_vec()), Action::Store => pt.set_to_v1(Address::from_str(STORE_ADDRESS).unwrap().to_vec()), Action::AbiStore => pt.set_to_v1(Address::from_str(ABI_ADDRESS).unwrap().to_vec()), - Action::GoCreate => pt.set_to_v1(Address::from_str(GO_CONTRACT).unwrap().to_vec()), Action::AmendData => { pt.set_to_v1(Address::from_str(AMEND_ADDRESS).unwrap().to_vec()) } @@ -511,12 +491,6 @@ impl Encodable for SignedTransaction { } } -impl HeapSizeOf for SignedTransaction { - fn heap_size_of_children(&self) -> usize { - self.transaction.heap_size_of_children() - } -} - impl Deref for SignedTransaction { type Target = UnverifiedTransaction; fn deref(&self) -> &Self::Target { diff --git a/cita-chain/types/src/transaction_index.rs b/cita-chain/types/src/transaction_index.rs new file mode 100644 index 000000000..f9cd43c95 --- /dev/null +++ b/cita-chain/types/src/transaction_index.rs @@ -0,0 +1,42 @@ +// Copyright Cryptape Technologies LLC. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +// FixMe: Rewrite +use cita_types::H256; +use rlp::{Decodable, DecoderError, Encodable, RlpStream, UntrustedRlp}; + +#[derive(Debug)] +pub struct TransactionIndex { + pub block_hash: H256, + pub index: usize, +} + +impl Decodable for TransactionIndex { + fn decode(rlp: &UntrustedRlp) -> Result { + let tx_index = TransactionIndex { + block_hash: rlp.val_at(0)?, + index: rlp.val_at(1)?, + }; + + Ok(tx_index) + } +} + +impl Encodable for TransactionIndex { + fn rlp_append(&self, s: &mut RlpStream) { + s.begin_list(2); + s.append(&self.block_hash); + s.append(&self.index); + } +} diff --git a/cita-executor/Cargo.toml b/cita-executor/Cargo.toml index 7ee943bc5..6fc9153bf 100644 --- a/cita-executor/Cargo.toml +++ b/cita-executor/Cargo.toml @@ -2,17 +2,21 @@ name = "cita-executor" version = "0.1.0" authors = ["Cryptape Technologies "] +license = "Apache-2.0" edition = "2018" [dependencies] dotenv = "0.13.0" clap = "2" serde = "1.0" -crossbeam-channel = "0.2" +crossbeam-channel = "0.3.9" serde_json = "1.0" serde_derive = "1.0" -grpc = "0.5.0" -cita-logger = "0.1.0" +cita-logger = "0.1.1" +itertools = "0.5" + +core-executor = { path = "./core" } +common-types = { path = "../cita-chain/types" } cita-types = { git = "https://github.com/cryptape/cita-common.git", branch = "develop" } cita-directories = { git = "https://github.com/cryptape/cita-common.git", branch = "develop" } hashable = { git = "https://github.com/cryptape/cita-common.git", branch = "develop" } @@ -21,11 +25,8 @@ pubsub = { git = "https://github.com/cryptape/cita-common.git", branch = "develo libproto = { git = "https://github.com/cryptape/cita-common.git", branch = "develop" } error = { git = "https://github.com/cryptape/cita-common.git", branch = "develop" } proof = { git = "https://github.com/cryptape/cita-common.git", branch = "develop" } -core-executor = { path = "./core" } -common-types = { path = "../cita-chain/types" } jsonrpc-types = { git = "https://github.com/cryptape/cita-common.git", branch = "develop" } -evm = { path = "evm" } -db = { git = "https://github.com/cryptape/cita-common.git", branch = "develop" } +cita-database = { git = "https://github.com/cryptape/cita-database.git", branch = "develop" } [build-dependencies] util = { git = "https://github.com/cryptape/cita-common.git", branch = "develop" } @@ -36,6 +37,12 @@ cita-ed25519 = { git = "https://github.com/cryptape/cita-common.git", branch = " cita-crypto = { git = "https://github.com/cryptape/cita-common.git", branch = "develop" } tempdir = "0.3.7" +[dependencies.cita-vm] +git = "https://github.com/cryptape/cita-vm.git" +branch = "cita" +default-features = false +features = ["sha3hash"] + [features] default = ["secp256k1", "sha3hash", "rabbitmq"] secp256k1 = ["libproto/secp256k1", "proof/secp256k1"] @@ -48,5 +55,3 @@ rabbitmq = ["pubsub/rabbitmq"] zeromq = ["pubsub/zeromq"] kafka = ["pubsub/kafka"] privatetx = ["core-executor/privatetx"] -evm-debug = ["core-executor/evm-debug"] -evm-debug-tests = ["evm-debug", "core-executor/evm-debug-tests"] diff --git a/cita-executor/build.rs b/cita-executor/build.rs index 14aad7c92..456b10301 100644 --- a/cita-executor/build.rs +++ b/cita-executor/build.rs @@ -1,19 +1,16 @@ -// CITA -// Copyright 2016-2019 Cryptape Technologies LLC. - -// This program is free software: you can redistribute it -// and/or modify it under the terms of the GNU 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 General Public License for more details. - -// You should have received a copy of the GNU General Public License -// along with this program. If not, see . +// Copyright Cryptape Technologies LLC. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. use std::env; use util::build_info::gen_build_info; diff --git a/cita-executor/core/Cargo.toml b/cita-executor/core/Cargo.toml index c136610e4..b50e9ed6b 100644 --- a/cita-executor/core/Cargo.toml +++ b/cita-executor/core/Cargo.toml @@ -1,28 +1,20 @@ [package] name = "core-executor" version = "0.1.0" -authors = ["Parity Technologies ", "Cryptape Technologies "] +authors = ["Cryptape Technologies "] +license = "Apache-2.0" edition = "2018" [dependencies] -cita-logger = "0.1.0" -libproto = { git = "https://github.com/cryptape/cita-common.git", branch = "develop" } +cita-logger = "0.1.1" byteorder = { version = "1", default-features = false } -cita-merklehash = { git = "https://github.com/cryptape/cita-common.git", branch = "develop" } -snappy = { git = "https://github.com/cryptape/cita-common.git", branch = "develop" } -hashable = { git = "https://github.com/cryptape/cita-common.git", branch = "develop" } bincode = "0.8.0" serde = "1.0" serde_derive = "1.0" serde_json = "1.0" rustc-hex = "1.0" -grpc = "0.5.0" -util = { git = "https://github.com/cryptape/cita-common.git", branch = "develop" } rustc-serialize = "0.3" lru-cache = "0.1.1" -rlp = { git = "https://github.com/cryptape/cita-common.git", branch = "develop" } -rlp_derive = { git = "https://github.com/cryptape/cita-common.git", branch = "develop" } -ethcore-bloom-journal = { git = "https://github.com/cryptape/cita-common.git", branch = "develop" } lazy_static = "0.2" bit-set = "0.4" rust-crypto = "0.2.34" @@ -30,9 +22,29 @@ num = "0.1" rand = "0.3" time = "0.1" hex = "0.3" -crossbeam = "0.2" -crossbeam-channel = "0.2" +crossbeam-channel = "0.3.9" transient-hashmap = "0.4.0" +ethabi = "4.2.0" +enum_primitive = "0.1.1" +largest-remainder-method = "0.1" +parking_lot = "0.8" +cita_trie = "2.0" +ethbloom = "0.6" +sha3 = { version="0.8", optional=true } +tiny-keccak = { version="1.4", optional=true } + +common-types = { path = "../../cita-chain/types" } +core = { path = "../../cita-chain/core" } +cita-merklehash = { git = "https://github.com/cryptape/cita-common.git", branch = "develop" } +snappy = { git = "https://github.com/cryptape/cita-common.git", branch = "develop" } +hashable = { git = "https://github.com/cryptape/cita-common.git", branch = "develop" } +util = { git = "https://github.com/cryptape/cita-common.git", branch = "develop" } +rlp = { git = "https://github.com/cryptape/cita-common.git", branch = "develop" } +libproto = { git = "https://github.com/cryptape/cita-common.git", branch = "develop" } +proof = { git = "https://github.com/cryptape/cita-common.git", branch = "develop" } +jsonrpc-types = { git = "https://github.com/cryptape/cita-common.git", branch = "develop" } +zktx = { git = "https://github.com/cryptape/zktx.git", optional = true } +cita-database = { git = "https://github.com/cryptape/cita-database.git", branch = "develop" } cita-ed25519 = { git = "https://github.com/cryptape/cita-common.git", branch = "develop" } cita-secp256k1 = { git = "https://github.com/cryptape/cita-common.git", branch = "develop" } @@ -40,16 +52,11 @@ cita-types = { git = "https://github.com/cryptape/cita-common.git", branch = "de cita-crypto = { git = "https://github.com/cryptape/cita-common.git", branch = "develop" } cita-crypto-trait = { git = "https://github.com/cryptape/cita-common.git", branch = "develop" } -proof = { git = "https://github.com/cryptape/cita-common.git", branch = "develop" } -common-types = { path = "../../cita-chain/types" } -core = { path = "../../cita-chain/core" } -evm = { path = "../evm" } -jsonrpc-types = { git = "https://github.com/cryptape/cita-common.git", branch = "develop" } -ethabi = "4.2.0" -zktx = { git = "https://github.com/cryptape/zktx.git", optional = true } -enum_primitive = "0.1.1" -largest-remainder-method = "0.1" -db = { git = "https://github.com/cryptape/cita-common.git", branch = "develop" } +[dependencies.cita-vm] +git = "https://github.com/cryptape/cita-vm.git" +branch = "cita" +default-features = false +features = ["sha3hash"] [dev-dependencies] rand = "0.3" @@ -57,7 +64,7 @@ cpuprofiler = "0.0.3" tempdir = "0.3.7" [features] -default = ["secp256k1", "sha3hash"] +default = ["secp256k1", "sha3hash", "hashlib-keccak"] secp256k1 = ["cita-crypto/secp256k1", "libproto/secp256k1", "proof/secp256k1"] ed25519 = ["cita-crypto/ed25519", "libproto/ed25519", "proof/ed25519"] sm2 = ["cita-crypto/sm2", "libproto/sm2", "proof/sm2"] @@ -65,6 +72,5 @@ sha3hash = ["hashable/sha3hash", "libproto/sha3hash", "proof/sha3hash"] blake2bhash = ["hashable/blake2bhash", "libproto/blake2bhash", "proof/blake2bhash"] sm3hash = ["hashable/sm3hash", "libproto/sm3hash", "proof/sm3hash"] privatetx = ["zktx"] -evm-debug = ["evm/evm-debug"] -evm-debug-tests = ["evm-debug", "evm/evm-debug-tests"] - +hashlib-keccak = ["tiny-keccak"] +hashlib-sha3 = ["sha3"] diff --git a/cita-executor/core/README.md b/cita-executor/core/README.md deleted file mode 100644 index 9a00ea091..000000000 --- a/cita-executor/core/README.md +++ /dev/null @@ -1,44 +0,0 @@ -# Executor microservice core for CITA - -Files below are extracted from [Parity](https://github.com/paritytech/parity): - -- ./src/cache_manager.rs -- ./src/substate.rs -- ./src/snapshot/mod.rs -- ./src/snapshot/io.rs -- ./src/snapshot/account.rs -- ./src/snapshot/error.rs -- ./src/snapshot/service.rs -- ./src/account_db.rs -- ./src/error.rs -- ./src/db.rs -- ./src/basic_types.rs -- ./src/libexecutor/cache.rs -- ./src/trace/mod.rs -- ./src/trace/executive_tracer.rs -- ./src/trace/error.rs -- ./src/trace/noop_tracer.rs -- ./src/trace/db.rs -- ./src/trace/types/mod.rs -- ./src/trace/types/localized.rs -- ./src/trace/types/flat.rs -- ./src/trace/types/error.rs -- ./src/trace/types/filter.rs -- ./src/trace/types/trace.rs -- ./src/trace/import.rs -- ./src/trace/config.rs -- ./src/state/mod.rs -- ./src/state/backend.rs -- ./src/externalities.rs -- ./src/state_db.rs -- ./src/pod_account.rs -- ./src/factory.rs - -with following modifications: - -- ./src/builtin.rs -- ./src/executed.rs -- ./src/engines/null_engine.rs -- ./src/executive.rs -- ./src/state/account.rs -- ./src/spec/builtin.rs diff --git a/cita-executor/core/executor.toml b/cita-executor/core/executor.toml index a7a0cc880..367413dab 100644 --- a/cita-executor/core/executor.toml +++ b/cita-executor/core/executor.toml @@ -1,3 +1,2 @@ prooftype = 2 journaldb_type = "archive" -grpc_port = 5000 \ No newline at end of file diff --git a/cita-executor/core/src/account_db.rs b/cita-executor/core/src/account_db.rs deleted file mode 100644 index fc96650a5..000000000 --- a/cita-executor/core/src/account_db.rs +++ /dev/null @@ -1,276 +0,0 @@ -// Copyright 2015-2017 Parity Technologies (UK) Ltd. -// This file is part of Parity. - -// This software is free software: you can redistribute it and/or modify -// it under the terms of the GNU General Public License as published by -// the Free Software Foundation, either version 3 of the License, or -// (at your option) any later version. - -// This software 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 General Public License for more details. - -// You should have received a copy of the GNU General Public License -// along with Parity. If not, see . - -//! DB backend wrapper for Account trie - -use crate::cita_db::{DBValue, HashDB}; -use cita_types::{Address, H256}; -use hashable::{Hashable, HASH_NULL_RLP}; -use rlp::NULL_RLP; -use std::collections::HashMap; - -static NULL_RLP_STATIC: [u8; 1] = [0x80; 1]; - -// combines a key with an address hash to ensure uniqueness. -// leaves the first 96 bits untouched in order to support partial key lookup. -#[inline] -fn combine_key<'a>(address_hash: &'a H256, key: &'a H256) -> H256 { - let mut dst = *key; - { - let last_src: &[u8] = &*address_hash; - let last_dst: &mut [u8] = &mut *dst; - for (k, a) in last_dst[12..].iter_mut().zip(&last_src[12..]) { - *k ^= *a - } - } - - dst -} - -/// A factory for different kinds of account dbs. -#[derive(Debug, Clone)] -pub enum Factory { - /// Mangle hashes based on address. - Mangled, - /// Don't mangle hashes. - Plain, -} - -impl Default for Factory { - fn default() -> Self { - Factory::Mangled - } -} - -impl Factory { - /// Create a read-only accountdb. - /// This will panic when write operations are called. - pub fn readonly<'db>(&self, db: &'db HashDB, address_hash: H256) -> Box { - match *self { - Factory::Mangled => Box::new(AccountDB::from_hash(db, address_hash)), - Factory::Plain => Box::new(Wrapping(db)), - } - } - - /// Create a new mutable hashdb. - pub fn create<'db>(&self, db: &'db mut HashDB, address_hash: H256) -> Box { - match *self { - Factory::Mangled => Box::new(AccountDBMut::from_hash(db, address_hash)), - Factory::Plain => Box::new(WrappingMut(db)), - } - } -} - -// TODO: introduce HashDBMut? -/// DB backend wrapper for Account trie -/// Transforms trie node keys for the database -pub struct AccountDB<'db> { - db: &'db HashDB, - address_hash: H256, -} - -impl<'db> AccountDB<'db> { - /// Create a new AccountDB from an address. - pub fn new(db: &'db HashDB, address: &Address) -> Self { - Self::from_hash(db, address.crypt_hash()) - } - - /// Create a new AcountDB from an address' hash. - pub fn from_hash(db: &'db HashDB, address_hash: H256) -> Self { - AccountDB { db, address_hash } - } -} - -impl<'db> HashDB for AccountDB<'db> { - fn keys(&self) -> HashMap { - unimplemented!() - } - - fn get(&self, key: &H256) -> Option { - if key == &HASH_NULL_RLP { - return Some(DBValue::from_slice(&NULL_RLP_STATIC)); - } - self.db.get(&combine_key(&self.address_hash, key)) - } - - fn contains(&self, key: &H256) -> bool { - if key == &HASH_NULL_RLP { - return true; - } - self.db.contains(&combine_key(&self.address_hash, key)) - } - - fn insert(&mut self, _value: &[u8]) -> H256 { - unimplemented!() - } - - fn emplace(&mut self, _key: H256, _value: DBValue) { - unimplemented!() - } - - fn remove(&mut self, _key: &H256) { - unimplemented!() - } -} - -/// DB backend wrapper for Account trie -pub struct AccountDBMut<'db> { - db: &'db mut HashDB, - address_hash: H256, -} - -impl<'db> AccountDBMut<'db> { - /// Create a new AccountDB from an address. - pub fn new(db: &'db mut HashDB, address: &Address) -> Self { - Self::from_hash(db, address.crypt_hash()) - } - - /// Create a new AcountDB from an address' hash. - pub fn from_hash(db: &'db mut HashDB, address_hash: H256) -> Self { - AccountDBMut { db, address_hash } - } - - #[allow(dead_code)] - pub fn immutable(&'db self) -> AccountDB<'db> { - AccountDB { - db: self.db, - address_hash: self.address_hash, - } - } -} - -impl<'db> HashDB for AccountDBMut<'db> { - fn keys(&self) -> HashMap { - unimplemented!() - } - - fn get(&self, key: &H256) -> Option { - if key == &HASH_NULL_RLP { - return Some(DBValue::from_slice(&NULL_RLP_STATIC)); - } - self.db.get(&combine_key(&self.address_hash, key)) - } - - fn contains(&self, key: &H256) -> bool { - if key == &HASH_NULL_RLP { - return true; - } - self.db.contains(&combine_key(&self.address_hash, key)) - } - - fn insert(&mut self, value: &[u8]) -> H256 { - if value == NULL_RLP { - return HASH_NULL_RLP; - } - let k = value.crypt_hash(); - let ak = combine_key(&self.address_hash, &k); - self.db.emplace(ak, DBValue::from_slice(value)); - k - } - - fn emplace(&mut self, key: H256, value: DBValue) { - if key == HASH_NULL_RLP { - return; - } - let key = combine_key(&self.address_hash, &key); - self.db.emplace(key, value) - } - - fn remove(&mut self, key: &H256) { - if key == &HASH_NULL_RLP { - return; - } - let key = combine_key(&self.address_hash, key); - self.db.remove(&key) - } -} - -struct Wrapping<'db>(&'db HashDB); - -impl<'db> HashDB for Wrapping<'db> { - fn keys(&self) -> HashMap { - unimplemented!() - } - - fn get(&self, key: &H256) -> Option { - if key == &HASH_NULL_RLP { - return Some(DBValue::from_slice(&NULL_RLP_STATIC)); - } - self.0.get(key) - } - - fn contains(&self, key: &H256) -> bool { - if key == &HASH_NULL_RLP { - return true; - } - self.0.contains(key) - } - - fn insert(&mut self, _value: &[u8]) -> H256 { - unimplemented!() - } - - fn emplace(&mut self, _key: H256, _value: DBValue) { - unimplemented!() - } - - fn remove(&mut self, _key: &H256) { - unimplemented!() - } -} - -struct WrappingMut<'db>(&'db mut HashDB); - -impl<'db> HashDB for WrappingMut<'db> { - fn keys(&self) -> HashMap { - unimplemented!() - } - - fn get(&self, key: &H256) -> Option { - if key == &HASH_NULL_RLP { - return Some(DBValue::from_slice(&NULL_RLP_STATIC)); - } - self.0.get(key) - } - - fn contains(&self, key: &H256) -> bool { - if key == &HASH_NULL_RLP { - return true; - } - self.0.contains(key) - } - - fn insert(&mut self, value: &[u8]) -> H256 { - if value == NULL_RLP { - return HASH_NULL_RLP; - } - self.0.insert(value) - } - - fn emplace(&mut self, key: H256, value: DBValue) { - if key == HASH_NULL_RLP { - return; - } - self.0.emplace(key, value) - } - - fn remove(&mut self, key: &H256) { - if key == &HASH_NULL_RLP { - return; - } - self.0.remove(key) - } -} diff --git a/cita-executor/core/src/authentication.rs b/cita-executor/core/src/authentication.rs index 0fe94543f..1d08f52b2 100644 --- a/cita-executor/core/src/authentication.rs +++ b/cita-executor/core/src/authentication.rs @@ -1,28 +1,27 @@ -// CITA -// Copyright 2016-2018 Cryptape Technologies LLC. +// Copyright Cryptape Technologies LLC. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. -// This program is free software: you can redistribute it -// and/or modify it under the terms of the GNU 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 General Public License for more details. +use std::collections::HashMap; +use std::str::FromStr; -// You should have received a copy of the GNU General Public License -// along with this program. If not, see . +use crate::types::transaction::{Action, SignedTransaction}; +use cita_types::{Address, H160}; use crate::contracts::solc::{permission_management::contains_resource, Resource}; -use crate::executed::ExecutionError; use crate::libexecutor::sys_config::CheckOptions; +use crate::types::errors::AuthenticationError; use crate::types::reserved_addresses; -use crate::types::transaction::{Action, SignedTransaction}; -use cita_types::{Address, H160}; -use std::collections::HashMap; -use std::str::FromStr; /// Check the sender's permission #[allow(unknown_lints, clippy::implicit_hasher)] // TODO clippy @@ -31,7 +30,7 @@ pub fn check_permission( account_permissions: &HashMap>, t: &SignedTransaction, options: CheckOptions, -) -> Result<(), ExecutionError> { +) -> Result<(), AuthenticationError> { let sender = *t.sender(); // It's eth_call when the account is zero. // No need to check the options in case that the option is true. @@ -61,16 +60,12 @@ pub fn check_permission( } if t.data.len() < 4 { - return Err(ExecutionError::TransactionMalformed( - "The length of transaction data is less than four bytes".to_string(), - )); + return Err(AuthenticationError::InvalidTransaction); } if address == group_management_addr { if t.data.len() < 36 { - return Err(ExecutionError::TransactionMalformed( - "Data should have at least one parameter".to_string(), - )); + return Err(AuthenticationError::InvalidTransaction); } check_origin_group( account_permissions, @@ -101,7 +96,7 @@ fn check_send_tx( group_accounts: &HashMap>, account_permissions: &HashMap>, account: &Address, -) -> Result<(), ExecutionError> { +) -> Result<(), AuthenticationError> { let cont = Address::from_str(reserved_addresses::PERMISSION_SEND_TX).unwrap(); let func = vec![0; 4]; let has_permission = has_resource( @@ -112,10 +107,14 @@ fn check_send_tx( &func[..], ); - trace!("has send tx permission: {:?}", has_permission); + trace!( + "Account {:?} has send tx permission: {:?}", + account, + has_permission + ); if !has_permission { - return Err(ExecutionError::NoTransactionPermission); + return Err(AuthenticationError::NoTransactionPermission); } Ok(()) @@ -126,7 +125,7 @@ fn check_create_contract( group_accounts: &HashMap>, account_permissions: &HashMap>, account: &Address, -) -> Result<(), ExecutionError> { +) -> Result<(), AuthenticationError> { let cont = Address::from_str(reserved_addresses::PERMISSION_CREATE_CONTRACT).unwrap(); let func = vec![0; 4]; let has_permission = has_resource( @@ -140,7 +139,7 @@ fn check_create_contract( trace!("has create contract permission: {:?}", has_permission); if !has_permission { - return Err(ExecutionError::NoContractPermission); + return Err(AuthenticationError::NoContractPermission); } Ok(()) @@ -153,13 +152,13 @@ fn check_call_contract( account: &Address, cont: &Address, func: &[u8], -) -> Result<(), ExecutionError> { +) -> Result<(), AuthenticationError> { let has_permission = has_resource(group_accounts, account_permissions, account, cont, func); trace!("has call contract permission: {:?}", has_permission); if !has_permission { - return Err(ExecutionError::NoCallPermission); + return Err(AuthenticationError::NoCallPermission); } Ok(()) @@ -172,13 +171,13 @@ fn check_origin_group( cont: &Address, func: &[u8], param: &Address, -) -> Result<(), ExecutionError> { +) -> Result<(), AuthenticationError> { let has_permission = contains_resource(account_permissions, account, *cont, func); trace!("Sender has call contract permission: {:?}", has_permission); if !has_permission && !contains_resource(account_permissions, param, *cont, func) { - return Err(ExecutionError::NoCallPermission); + return Err(AuthenticationError::NoCallPermission); } Ok(()) diff --git a/cita-executor/core/src/benches/executor.rs b/cita-executor/core/src/benches/executor.rs index c4cce0b07..12e10d452 100644 --- a/cita-executor/core/src/benches/executor.rs +++ b/cita-executor/core/src/benches/executor.rs @@ -1,19 +1,16 @@ -// CITA -// Copyright 2016-2019 Cryptape Technologies LLC. - -// This program is free software: you can redistribute it -// and/or modify it under the terms of the GNU 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 General Public License for more details. - -// You should have received a copy of the GNU General Public License -// along with this program. If not, see . +// Copyright Cryptape Technologies LLC. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. use cita_crypto::{CreateKey, KeyPair}; use cita_types::Address; @@ -71,7 +68,8 @@ fn test_block_with_10000_tx_write_db(b: &mut Bencher) { let block = generate_block(&executor, 10000); b.iter(|| { - let closed_block = executor.into_fsm(block.clone()); - executor.grow(closed_block); + let mut closed_block = executor.into_fsm(block.clone()); + executor.grow(&closed_block); + closed_block.clear_cache(); }); } diff --git a/cita-executor/core/src/benches/mod.rs b/cita-executor/core/src/benches/mod.rs index 0db48a3da..dc9f24429 100644 --- a/cita-executor/core/src/benches/mod.rs +++ b/cita-executor/core/src/benches/mod.rs @@ -1,19 +1,16 @@ -// CITA -// Copyright 2016-2019 Cryptape Technologies LLC. - -// This program is free software: you can redistribute it -// and/or modify it under the terms of the GNU 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 General Public License for more details. - -// You should have received a copy of the GNU General Public License -// along with this program. If not, see . +// Copyright Cryptape Technologies LLC. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. #[cfg(all(feature = "benches", test))] pub mod executor; diff --git a/cita-executor/core/src/builtin.rs b/cita-executor/core/src/builtin.rs deleted file mode 100644 index e03081a9d..000000000 --- a/cita-executor/core/src/builtin.rs +++ /dev/null @@ -1,478 +0,0 @@ -// Copyright 2015-2017 Parity Technologies (UK) Ltd. -// This file is part of Parity. - -// This software is free software: you can redistribute it and/or modify -// it under the terms of the GNU General Public License as published by -// the Free Software Foundation, either version 3 of the License, or -// (at your option) any later version. - -// This software 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 General Public License for more details. - -// You should have received a copy of the GNU General Public License -// along with Parity. If not, see . - -use crate::spec; -use cita_crypto_trait::Sign; -use cita_ed25519::{Message as ED_Message, Signature as ED_Signature}; -use cita_secp256k1::Signature; -use cita_types::{H256, U256}; -use crypto::digest::Digest; -use crypto::ripemd160::Ripemd160 as Ripemd160Digest; -use crypto::sha2::Sha256 as Sha256Digest; -use hashable::Hashable; -use std::cmp::min; -use util::BytesRef; - -/// Native implementation of a built-in contract. -pub trait Impl: Send + Sync { - /// execute this built-in on the given input, writing to the given output. - fn execute(&self, input: &[u8], output: &mut BytesRef); -} - -/// A gas pricing scheme for built-in contracts. -pub trait Pricer: Send + Sync { - /// The gas cost of running this built-in for the given size of input data. - fn cost(&self, input: &[u8]) -> U256; -} - -/// A linear pricing model. This computes a price using a base cost and a cost per-word. -struct Linear { - base: usize, - word: usize, -} - -impl Pricer for Linear { - fn cost(&self, input: &[u8]) -> U256 { - U256::from(self.base) + U256::from(self.word) * U256::from((input.len() + 31) / 32) - } -} - -/// Pricing scheme and execution definition for a built-in contract. -pub struct Builtin { - pricer: Box, - native: Box, - activate_at: u64, -} - -impl Builtin { - /// Simple forwarder for cost. - pub fn cost(&self, input: &[u8]) -> U256 { - self.pricer.cost(input) - } - - /// Simple forwarder for execute. - pub fn execute(&self, input: &[u8], output: &mut BytesRef) { - self.native.execute(input, output) - } - - /// Whether the builtin is activated at the given block number. - pub fn is_active(&self, at: u64) -> bool { - at >= self.activate_at - } -} - -impl From for Builtin { - fn from(b: spec::Builtin) -> Self { - let pricer = match b.pricing { - spec::Pricing::Linear(linear) => Box::new(Linear { - base: linear.base, - word: linear.word, - }), - }; - - Builtin { - pricer, - native: ethereum_builtin(&b.name), - activate_at: b.activate_at.unwrap_or(0), - } - } -} - -// Ethereum builtin creator. -fn ethereum_builtin(name: &str) -> Box { - match name { - "identity" => Box::new(Identity) as Box, - "ecrecover" => Box::new(EcRecover) as Box, - "sha256" => Box::new(Sha256) as Box, - "ripemd160" => Box::new(Ripemd160) as Box, - "edrecover" => Box::new(EdRecover) as Box, - _ => panic!("invalid builtin name: {}", name), - } -} - -// Ethereum builtins: -// -// - The identity function -// - ec recovery -// - sha256 -// - ripemd160 - -#[derive(Debug)] -struct Identity; - -#[derive(Debug)] -struct EcRecover; - -#[derive(Debug)] -struct Sha256; - -#[derive(Debug)] -struct Ripemd160; - -#[derive(Debug)] -struct EdRecover; - -impl Impl for Identity { - fn execute(&self, input: &[u8], output: &mut BytesRef) { - output.write(0, input); - } -} - -impl Impl for EcRecover { - fn execute(&self, i: &[u8], output: &mut BytesRef) { - let len = min(i.len(), 128); - - let mut input = [0; 128]; - input[..len].copy_from_slice(&i[..len]); - - let hash = H256::from_slice(&input[0..32]); - let v = H256::from_slice(&input[32..64]); - let r = H256::from_slice(&input[64..96]); - let s = H256::from_slice(&input[96..128]); - - let bit = match v[31] { - 27 | 28 if v.0[..31] == [0; 31] => v[31] - 27, - _ => return, - }; - - let s = Signature::from_rsv(&r, &s, bit); - if s.is_valid() { - if let Ok(p) = s.recover(&hash) { - let r = p.crypt_hash(); - output.write(0, &[0; 12]); - output.write(12, &r[12..r.len()]); - } - } - } -} - -impl Impl for Sha256 { - fn execute(&self, input: &[u8], output: &mut BytesRef) { - let mut sha = Sha256Digest::new(); - sha.input(input); - - let mut out = [0; 32]; - sha.result(&mut out); - - output.write(0, &out); - } -} - -impl Impl for Ripemd160 { - fn execute(&self, input: &[u8], output: &mut BytesRef) { - let mut sha = Ripemd160Digest::new(); - sha.input(input); - - let mut out = [0; 32]; - sha.result(&mut out[12..32]); - - output.write(0, &out); - } -} - -impl Impl for EdRecover { - fn execute(&self, i: &[u8], output: &mut BytesRef) { - let len = min(i.len(), 128); - - let mut input = [0; 128]; - input[..len].copy_from_slice(&i[..len]); - - let hash = ED_Message::from_slice(&input[0..32]); - let sig = ED_Signature::from(&input[32..128]); - - if let Ok(p) = sig.recover(&hash) { - let r = p.crypt_hash(); - output.write(0, &[0; 12]); - output.write(12, &r[12..r.len()]); - } - } -} - -#[cfg(test)] -mod tests { - extern crate rustc_serialize; - - use super::{ethereum_builtin, Builtin, Linear, Pricer}; - use crate::spec; - use cita_crypto_trait::{CreateKey, Sign}; - use cita_ed25519::{pubkey_to_address as ED_pubkey_to_address, KeyPair, Signature}; - use cita_types::{H256, U256}; - use util::BytesRef; - - #[test] - fn identity() { - let f = ethereum_builtin("identity"); - - let i = [0u8, 1, 2, 3]; - - let mut o2 = [255u8; 2]; - f.execute(&i[..], &mut BytesRef::Fixed(&mut o2[..])); - assert_eq!(i[0..2], o2); - - let mut o4 = [255u8; 4]; - f.execute(&i[..], &mut BytesRef::Fixed(&mut o4[..])); - assert_eq!(i, o4); - - let mut o8 = [255u8; 8]; - f.execute(&i[..], &mut BytesRef::Fixed(&mut o8[..])); - assert_eq!(i, o8[..4]); - assert_eq!([255u8; 4], o8[4..]); - } - - #[test] - fn sha256() { - use self::rustc_serialize::hex::FromHex; - let f = ethereum_builtin("sha256"); - - let i = [0u8; 0]; - - let mut o = [255u8; 32]; - f.execute(&i[..], &mut BytesRef::Fixed(&mut o[..])); - assert_eq!( - &o[..], - &(FromHex::from_hex( - "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855" - ) - .unwrap())[..] - ); - - let mut o8 = [255u8; 8]; - f.execute(&i[..], &mut BytesRef::Fixed(&mut o8[..])); - assert_eq!( - &o8[..], - &(FromHex::from_hex("e3b0c44298fc1c14").unwrap())[..] - ); - - let mut o34 = [255u8; 34]; - f.execute(&i[..], &mut BytesRef::Fixed(&mut o34[..])); - assert_eq!( - &o34[..], - &(FromHex::from_hex( - "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855ffff" - ) - .unwrap())[..] - ); - - let mut ov = vec![]; - f.execute(&i[..], &mut BytesRef::Flexible(&mut ov)); - assert_eq!( - &ov[..], - &(FromHex::from_hex( - "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855" - ) - .unwrap())[..] - ); - } - - #[test] - fn ripemd160() { - use self::rustc_serialize::hex::FromHex; - let f = ethereum_builtin("ripemd160"); - - let i = [0u8; 0]; - - let mut o = [255u8; 32]; - f.execute(&i[..], &mut BytesRef::Fixed(&mut o[..])); - assert_eq!( - &o[..], - &(FromHex::from_hex( - "0000000000000000000000009c1185a5c5e9fc54612808977ee8f548b2258d31" - ) - .unwrap())[..] - ); - - let mut o8 = [255u8; 8]; - f.execute(&i[..], &mut BytesRef::Fixed(&mut o8[..])); - assert_eq!( - &o8[..], - &(FromHex::from_hex("0000000000000000").unwrap())[..] - ); - - let mut o34 = [255u8; 34]; - f.execute(&i[..], &mut BytesRef::Fixed(&mut o34[..])); - assert_eq!( - &o34[..], - &(FromHex::from_hex( - "0000000000000000000000009c1185a5c5e9fc54612808977ee8f548b2258d31ffff" - ) - .unwrap())[..] - ); - } - - #[test] - fn ecrecover() { - use self::rustc_serialize::hex::FromHex; - - let f = ethereum_builtin("ecrecover"); - - let i = FromHex::from_hex("47173285a8d7341e5e972fc677286384f802f8ef42a5ec5f03bbfa254cb01fad000000000000000000000000000000000000000000000000000000000000001b650acf9d3f5f0a2c799776a1254355d5f4061762a237396a99a0e0e3fc2bcd6729514a0dacb2e623ac4abd157cb18163ff942280db4d5caad66ddf941ba12e03").unwrap(); - - let mut o = [255u8; 32]; - f.execute(&i[..], &mut BytesRef::Fixed(&mut o[..])); - #[cfg(feature = "sha3hash")] - let expected = "000000000000000000000000c08b5542d177ac6686946920409741463a15dddb"; - #[cfg(feature = "blake2bhash")] - let expected = "0000000000000000000000009f374781e8bf2e7dc910b0ee56baf9c2d475f1d9"; - #[cfg(feature = "sm3hash")] - let expected = "000000000000000000000000040888ccac3826b7b6faf17cef6d6b6f861452c4"; - assert_eq!(&o[..], &(FromHex::from_hex(expected).unwrap())[..]); - - let mut o8 = [255u8; 8]; - f.execute(&i[..], &mut BytesRef::Fixed(&mut o8[..])); - assert_eq!( - &o8[..], - &(FromHex::from_hex("0000000000000000").unwrap())[..] - ); - - let mut o34 = [255u8; 34]; - f.execute(&i[..], &mut BytesRef::Fixed(&mut o34[..])); - #[cfg(feature = "sha3hash")] - let expected = "000000000000000000000000c08b5542d177ac6686946920409741463a15dddbffff"; - #[cfg(feature = "blake2bhash")] - let expected = "0000000000000000000000009f374781e8bf2e7dc910b0ee56baf9c2d475f1d9ffff"; - #[cfg(feature = "sm3hash")] - let expected = "000000000000000000000000040888ccac3826b7b6faf17cef6d6b6f861452c4ffff"; - assert_eq!(&o34[..], &(FromHex::from_hex(expected).unwrap())[..]); - - let i_bad = FromHex::from_hex("47173285a8d7341e5e972fc677286384f802f8ef42a5ec5f03bbfa254cb01fad000000000000000000000000000000000000000000000000000000000000001a650acf9d3f5f0a2c799776a1254355d5f4061762a237396a99a0e0e3fc2bcd6729514a0dacb2e623ac4abd157cb18163ff942280db4d5caad66ddf941ba12e03").unwrap(); - let mut o = [255u8; 32]; - f.execute(&i_bad[..], &mut BytesRef::Fixed(&mut o[..])); - assert_eq!( - &o[..], - &(FromHex::from_hex( - "ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff" - ) - .unwrap())[..] - ); - - let i_bad = FromHex::from_hex("47173285a8d7341e5e972fc677286384f802f8ef42a5ec5f03bbfa254cb01fad000000000000000000000000000000000000000000000000000000000000001b000000000000000000000000000000000000000000000000000000000000001b0000000000000000000000000000000000000000000000000000000000000000").unwrap(); - let mut o = [255u8; 32]; - f.execute(&i_bad[..], &mut BytesRef::Fixed(&mut o[..])); - assert_eq!( - &o[..], - &(FromHex::from_hex( - "ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff" - ) - .unwrap())[..] - ); - - let i_bad = FromHex::from_hex("47173285a8d7341e5e972fc677286384f802f8ef42a5ec5f03bbfa254cb01fad000000000000000000000000000000000000000000000000000000000000001b0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001b").unwrap(); - let mut o = [255u8; 32]; - f.execute(&i_bad[..], &mut BytesRef::Fixed(&mut o[..])); - assert_eq!( - &o[..], - &(FromHex::from_hex( - "ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff" - ) - .unwrap())[..] - ); - - let i_bad = FromHex::from_hex("47173285a8d7341e5e972fc677286384f802f8ef42a5ec5f03bbfa254cb01fad000000000000000000000000000000000000000000000000000000000000001bffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff000000000000000000000000000000000000000000000000000000000000001b").unwrap(); - let mut o = [255u8; 32]; - f.execute(&i_bad[..], &mut BytesRef::Fixed(&mut o[..])); - assert_eq!( - &o[..], - &(FromHex::from_hex( - "ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff" - ) - .unwrap())[..] - ); - - let i_bad = FromHex::from_hex("47173285a8d7341e5e972fc677286384f802f8ef42a5ec5f03bbfa254cb01fad000000000000000000000000000000000000000000000000000000000000001b000000000000000000000000000000000000000000000000000000000000001bffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff").unwrap(); - let mut o = [255u8; 32]; - f.execute(&i_bad[..], &mut BytesRef::Fixed(&mut o[..])); - assert_eq!( - &o[..], - &(FromHex::from_hex( - "ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff" - ) - .unwrap())[..] - ); - - // TODO: Should this (corrupted version of the above) fail rather than returning some address? - } - - #[test] - fn edrecover() { - let key_pair = KeyPair::gen_keypair(); - let message: [u8; 32] = [ - 0x01, 0x02, 0x03, 0x04, 0x19, 0xab, 0xfe, 0x39, 0x6f, 0x28, 0x79, 0x00, 0x08, 0xdf, - 0x9a, 0xef, 0xfb, 0x77, 0x42, 0xae, 0xad, 0xfc, 0xcf, 0x12, 0x24, 0x45, 0x29, 0x89, - 0x29, 0x45, 0x3f, 0xf8, - ]; - let hash = H256::from(message); - let privkey = key_pair.privkey(); - let pubkey = key_pair.pubkey(); - let address = ED_pubkey_to_address(pubkey); - let signature = Signature::sign(privkey, &hash).unwrap(); - let mut buf = Vec::::with_capacity(128); - buf.extend_from_slice(&message[..]); - buf.extend_from_slice(&signature.0[..]); - - let f = ethereum_builtin("edrecover"); - let mut output = [255u8; 32]; - f.execute(&buf, &mut BytesRef::Fixed(&mut output[..])); - - assert_eq!(&output[0..12], &[0u8; 12]); - assert_eq!(&output[12..], &address.0[..]); - } - - #[test] - #[should_panic] - fn from_unknown_linear() { - let _ = ethereum_builtin("foo"); - } - - #[test] - fn from_named_linear() { - let pricer = Box::new(Linear { base: 10, word: 20 }); - let b = Builtin { - pricer: pricer as Box, - native: ethereum_builtin("identity"), - activate_at: 0, - }; - - assert_eq!(b.cost(&[0; 0]), U256::from(10)); - assert_eq!(b.cost(&[0; 1]), U256::from(30)); - assert_eq!(b.cost(&[0; 32]), U256::from(30)); - assert_eq!(b.cost(&[0; 33]), U256::from(50)); - - let i = [0u8, 1, 2, 3]; - let mut o = [255u8; 4]; - b.execute(&i[..], &mut BytesRef::Fixed(&mut o[..])); - assert_eq!(i, o); - } - - #[test] - fn from_json() { - let b = Builtin::from(spec::Builtin { - name: "identity".to_owned(), - pricing: spec::Pricing::Linear(spec::Linear { base: 10, word: 20 }), - activate_at: Some(10000), - }); - - assert_eq!(b.cost(&[0; 0]), U256::from(10)); - assert_eq!(b.cost(&[0; 1]), U256::from(30)); - assert_eq!(b.cost(&[0; 32]), U256::from(30)); - assert_eq!(b.cost(&[0; 33]), U256::from(50)); - assert_eq!(b.activate_at, 10000); - - let i = [0u8, 1, 2, 3]; - let mut o = [255u8; 4]; - b.execute(&i[..], &mut BytesRef::Fixed(&mut o[..])); - assert_eq!(i, o); - } -} diff --git a/cita-executor/core/src/cita_executive.rs b/cita-executor/core/src/cita_executive.rs new file mode 100644 index 000000000..894d09ad7 --- /dev/null +++ b/cita-executor/core/src/cita_executive.rs @@ -0,0 +1,1461 @@ +// Copyright Cryptape Technologies LLC. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +use cita_trie::DB; +use cita_types::{Address, H160, H256, U256, U512}; +use cita_vm::{ + evm::{Context as EVMContext, Error as EVMError, InterpreterResult, Log as EVMLog}, + state::{State, StateObjectInfo}, + BlockDataProvider, Config as VMConfig, DataProvider, Error as VMError, Store as VmSubState, + Transaction as EVMTransaction, +}; +use std::cell::RefCell; +use std::sync::Arc; +use types::Bytes; + +use crate::authentication::check_permission; +use crate::contracts::native::factory::Factory as NativeFactory; +use crate::exception::ExecutedException; +use crate::libexecutor::economical_model::EconomicalModel; +use crate::libexecutor::sys_config::BlockSysConfig; +use crate::tx_gas_schedule::TxGasSchedule; +use crate::types::context::Context; +use crate::types::errors::AuthenticationError; +use crate::types::errors::ExecutionError; +use crate::types::log::Log; +use crate::types::transaction::{Action, SignedTransaction}; +use ethbloom::{Bloom, Input as BloomInput}; + +///amend the abi data +const AMEND_ABI: u32 = 1; +///amend the account code +const AMEND_CODE: u32 = 2; +///amend the kv of db +const AMEND_KV_H256: u32 = 3; +///amend get the value of db +const AMEND_GET_KV_H256: u32 = 4; +///amend account's balance +const AMEND_ACCOUNT_BALANCE: u32 = 5; + +// FIXME: CITAExecutive need rename to Executive after all works ready. +pub struct CitaExecutive<'a, B> { + block_provider: Arc, + state_provider: Arc>>, + native_factory: &'a NativeFactory, + context: &'a Context, + economical_model: EconomicalModel, +} + +impl<'a, B: DB + 'static> CitaExecutive<'a, B> { + pub fn new( + block_provider: Arc, + state: Arc>>, + native_factory: &'a NativeFactory, + context: &'a Context, + economical_model: EconomicalModel, + ) -> Self { + Self { + block_provider, + state_provider: state, + native_factory, + context, + economical_model, + } + } + + pub fn exec( + &mut self, + t: &SignedTransaction, + conf: &BlockSysConfig, + ) -> Result { + let sender = *t.sender(); + let nonce = self.state_provider.borrow_mut().nonce(&sender)?; + trace!("transaction sender: {:?}, nonce: {:?}", sender, nonce); + self.state_provider.borrow_mut().inc_nonce(&sender)?; + + trace!( + "call contract permission should be check: {}", + (*conf).check_options.call_permission + ); + + check_permission( + &conf.group_accounts, + &conf.account_permissions, + t, + conf.check_options, + )?; + + let tx_gas_schedule = TxGasSchedule::default(); + let base_gas_required = match t.action { + Action::Create => tx_gas_schedule.tx_create_gas, + _ => tx_gas_schedule.tx_gas, + } + match t.version { + 0...2 => 0, + _ => t.data.len() * tx_gas_schedule.tx_data_non_zero_gas, + }; + + if sender != Address::zero() && t.gas < U256::from(base_gas_required) { + // FIXME: It is better to change NotEnoughBaseGas to + // NotEnoughBaseGas { + // required: U256, + // got: U256, + // } + // Need to change VMError defined in cita-vm. + return Err(ExecutionError::NotEnoughBaseGas); + } + + if t.action == Action::AbiStore && !self.transact_set_abi(&t.data) { + return Err(ExecutionError::InvalidTransaction); + } + + let init_gas = t.gas - U256::from(base_gas_required); + + let result = match t.action { + Action::Store | Action::AbiStore => { + // Prepaid t.gas for the transaction. + self.prepaid(t.sender(), t.gas, t.gas_price, t.value)?; + + // Maybe use tx_gas_schedule.tx_data_non_zero_gas for each byte store, it is more reasonable. + // But for the data compatible, just let it as tx_gas_schedule.create_data_gas for now. + let store_gas_used = U256::from(t.data.len() * tx_gas_schedule.create_data_gas); + if let Some(gas_left) = init_gas.checked_sub(store_gas_used) { + let mut result = ExecutedResult::default(); + result.quota_left = gas_left; + result.is_evm_call = false; + + Ok(result) + } else { + // FIXME: Should not return an error after self.prepaid(). + // But for compatibility, should keep this. Need to be upgrade in new version. + return Err(ExecutionError::NotEnoughBaseGas); + } + } + Action::Create => { + // Note: Fees has been handle in cita_vm. + let params = VmExecParams { + code_address: None, + sender, + to_address: None, + gas: t.gas, + gas_price: t.gas_price(), + value: t.value, + nonce, + data: Some(t.data.clone()), + }; + + self.call_evm(¶ms) + } + + Action::AmendData => { + trace!("amend action, conf admin {:?}", conf.super_admin_account); + if let Some(admin) = conf.super_admin_account { + if *t.sender() != admin { + return Err(ExecutionError::Authentication( + AuthenticationError::NoTransactionPermission, + )); + } + } else { + return Err(ExecutionError::Authentication( + AuthenticationError::NoTransactionPermission, + )); + } + + // Prepaid for the transaction + self.prepaid(t.sender(), t.gas, t.gas_price, t.value)?; + + // Backup used in case of running error + self.state_provider.borrow_mut().checkpoint(); + + match self.call_amend_data(t.value, Some(t.data.clone())) { + Ok(Some(val)) => { + // Discard the checkpoint because of amend data ok. + self.state_provider.borrow_mut().discard_checkpoint(); + + let mut result = ExecutedResult::default(); + // Refund gas, AmendData do not use any additional gas. + result.quota_left = init_gas; + result.is_evm_call = false; + result.output = val.to_vec(); + Ok(result) + } + Ok(None) => { + // Discard the checkpoint because of amend data ok. + self.state_provider.borrow_mut().discard_checkpoint(); + + let mut result = ExecutedResult::default(); + // Refund gas, AmendData do not use any additional gas. + result.quota_left = init_gas; + result.is_evm_call = false; + Ok(result) + } + Err(e) => { + let mut result = ExecutedResult::default(); + + // Need to revert the state. + self.state_provider.borrow_mut().revert_checkpoint(); + result.exception = Some(ExecutedException::VM(e)); + result.is_evm_call = false; + Ok(result) + } + } + } + Action::Call(ref address) => { + let params = VmExecParams { + code_address: Some(*address), + sender, + to_address: Some(*address), + gas: t.gas, + gas_price: t.gas_price(), + value: t.value, + nonce, + data: Some(t.data.clone()), + }; + self.call(¶ms) + } + }; + + let mut finalize_result = match result { + Ok(res) => { + if let Some(ref e) = res.exception { + if let Some(err) = self.transform_base_gas_err(e) { + return Err(err); + } + } + res + } + Err(_) => { + // Don't care about what is the error info in this situation, just let it as + // ReceiptError::Internal in Receipt. + let mut r = ExecutedResult::default(); + r.quota_left = U256::from(0); + r.quota_used = t.gas; + r.is_evm_call = false; + r + } + }; + + if !finalize_result.is_evm_call { + let refund_value = finalize_result.quota_left * t.gas_price; + // Note: should not be error at refund. + self.refund(t.sender(), refund_value) + .expect("refund balance to sender must success"); + + let quota_used = t.gas - finalize_result.quota_left; + let fee_value = quota_used * t.gas_price; + self.handle_tx_fee(&self.context.coin_base, fee_value) + .expect("Add balance to coin_base must success"); + finalize_result.quota_used = quota_used; + } + + finalize_result.account_nonce = nonce; + Ok(finalize_result) + } + + fn transform_base_gas_err(&self, e: &ExecutedException) -> Option { + match e { + ExecutedException::VM(VMError::ExccedMaxBlockGasLimit) => { + Some(ExecutionError::BlockQuotaLimitReached) + } + ExecutedException::VM(VMError::InvalidNonce) => Some(ExecutionError::InvalidNonce), + ExecutedException::VM(VMError::NotEnoughBaseGas) => { + Some(ExecutionError::NotEnoughBaseGas) + } + ExecutedException::VM(VMError::NotEnoughBalance) => { + Some(ExecutionError::NotEnoughBalance) + } + _ => None, + } + } + + fn payment_required(&self) -> bool { + self.economical_model == EconomicalModel::Charge + } + + fn prepaid( + &mut self, + sender: &H160, + gas: U256, + gas_price: U256, + value: U256, + ) -> Result<(), ExecutionError> { + if self.payment_required() { + let balance = self.state_provider.borrow_mut().balance(&sender)?; + let gas_cost = gas.full_mul(gas_price); + let total_cost = U512::from(value) + gas_cost; + + // Avoid unaffordable transactions + let balance512 = U512::from(balance); + if balance512 < total_cost { + return Err(ExecutionError::NotEnoughBalance); + } + self.state_provider + .borrow_mut() + .sub_balance(&sender, U256::from(gas_cost))?; + } + Ok(()) + } + + fn refund(&mut self, address: &Address, value: U256) -> Result<(), ExecutionError> { + if self.payment_required() { + self.state_provider + .borrow_mut() + .add_balance(address, value) + .map_err(ExecutionError::from) + } else { + Ok(()) + } + } + + fn handle_tx_fee( + &mut self, + coin_base: &Address, + fee_value: U256, + ) -> Result<(), ExecutionError> { + if self.payment_required() { + self.state_provider + .borrow_mut() + .add_balance(coin_base, fee_value) + .map_err(ExecutionError::from) + } else { + Ok(()) + } + } + + fn transfer_balance( + &mut self, + from: &Address, + to: &Address, + value: U256, + ) -> Result<(), ExecutionError> { + if self.payment_required() { + self.state_provider + .borrow_mut() + .transfer_balance(from, to, value) + .map_err(ExecutionError::from) + } else { + Ok(()) + } + } + + fn transact_set_abi(&mut self, data: &[u8]) -> bool { + if data.len() <= 20 { + return false; + } + let account = H160::from(&data[0..20]); + let abi = &data[20..]; + + let account_exist = self + .state_provider + .borrow_mut() + .exist(&account) + .unwrap_or(false); + info!("Account-{:?} in state is {:?}", account, account_exist); + + account_exist + && self + .state_provider + .borrow_mut() + .set_abi(&account, abi.to_vec()) + .is_ok() + } + + fn transact_set_code(&mut self, data: &[u8]) -> bool { + if data.len() <= 20 { + return false; + } + let account = H160::from(&data[0..20]); + let code = &data[20..]; + self.state_provider + .borrow_mut() + .set_code(&account, code.to_vec()) + .is_ok() + } + + fn transact_set_balance(&mut self, data: &[u8]) -> bool { + if data.len() < 52 { + return false; + } + let account = H160::from(&data[0..20]); + let balance = U256::from(&data[20..52]); + + let now_val = self + .state_provider + .borrow_mut() + .balance(&account) + .unwrap_or_default(); + if now_val > balance { + self.state_provider + .borrow_mut() + .sub_balance(&account, now_val - balance) + .is_ok() + } else { + self.state_provider + .borrow_mut() + .add_balance(&account, balance - now_val) + .is_ok() + } + } + + fn transact_set_kv_h256(&mut self, data: &[u8]) -> bool { + let len = data.len(); + if len < 84 { + return false; + } + let loop_num: usize = (len - 20) / (32 * 2); + let account = H160::from(&data[0..20]); + + for i in 0..loop_num { + let base = 20 + 32 * 2 * i; + let key = H256::from_slice(&data[base..base + 32]); + let val = H256::from_slice(&data[base + 32..base + 32 * 2]); + if self + .state_provider + .borrow_mut() + .set_storage(&account, key, val) + .is_err() + { + return false; + } + } + true + } + + fn transact_get_kv_h256(&mut self, data: &[u8]) -> Option { + let account = H160::from(&data[0..20]); + let key = H256::from_slice(&data[20..52]); + self.state_provider + .borrow_mut() + .get_storage(&account, &key) + .ok() + } + + fn call_amend_data( + &mut self, + value: U256, + data: Option, + ) -> Result, VMError> { + let amend_type = value.low_u32(); + match amend_type { + AMEND_ABI => { + if self.transact_set_abi(&(data.to_owned().unwrap())) { + Ok(None) + } else { + Err(VMError::Evm(EVMError::Internal( + "Account doesn't exist".to_owned(), + ))) + } + } + AMEND_CODE => { + if self.transact_set_code(&(data.to_owned().unwrap())) { + Ok(None) + } else { + Err(VMError::Evm(EVMError::Internal( + "Account doesn't exist".to_owned(), + ))) + } + } + AMEND_KV_H256 => { + if self.transact_set_kv_h256(&(data.to_owned().unwrap())) { + Ok(None) + } else { + Err(VMError::Evm(EVMError::Internal( + "Account doesn't exist".to_owned(), + ))) + } + } + AMEND_GET_KV_H256 => { + if let Some(v) = self.transact_get_kv_h256(&(data.to_owned().unwrap())) { + Ok(Some(v)) + } else { + Err(VMError::Evm(EVMError::Internal( + "May be incomplete trie error".to_owned(), + ))) + } + } + AMEND_ACCOUNT_BALANCE => { + if self.transact_set_balance(&(data.to_owned().unwrap())) { + Ok(None) + } else { + Err(VMError::Evm(EVMError::Internal( + "Account doesn't exist or incomplete trie error".to_owned(), + ))) + } + } + _ => Ok(None), + } + } + + pub fn call_evm(&mut self, params: &VmExecParams) -> Result { + let mut evm_transaction = build_evm_transaction(params); + trace!("block quota limit is {:?}", self.context.block_quota_limit); + let mut evm_config = build_evm_config(self.context.block_quota_limit.as_u64()); + let evm_context = build_evm_context(&self.context); + + if !self.payment_required() { + evm_transaction.value = U256::from(0); + evm_config.check_balance = false; + } + + trace!("Call evm with params: {:?}", params); + let mut result = match cita_vm::exec( + self.block_provider.clone(), + self.state_provider.clone(), + evm_context, + evm_config, + evm_transaction, + ) { + Ok(evm_result) => build_result_with_ok(params.gas, evm_result), + Err(e) => build_result_with_err(e), + }; + result.is_evm_call = true; + Ok(result) + } + + fn call(&mut self, params: &VmExecParams) -> Result { + // Check and call Native Contract. + if let Some(mut native_contract) = self + .native_factory + .new_contract(params.code_address.unwrap()) + { + self.prepaid(¶ms.sender, params.gas, params.gas_price, params.value)?; + + // Backup used in case of running out of gas + self.state_provider.borrow_mut().checkpoint(); + + // At first, transfer value to destination. + if self.payment_required() + && self + .transfer_balance(¶ms.sender, ¶ms.to_address.unwrap(), params.value) + .is_err() + { + // Discard the checkpoint + self.state_provider.borrow_mut().revert_checkpoint(); + return Err(ExecutionError::Internal( + "Transfer balance failed while calling native contract.".to_string(), + )); + } + + let store = VmSubState::default(); + let store = Arc::new(RefCell::new(store)); + let mut vm_data_provider = DataProvider::new( + self.block_provider.clone(), + self.state_provider.clone(), + store, + ); + let result = match native_contract.exec(params, &self.context, &mut vm_data_provider) { + Ok(ret) => { + // Discard the checkpoint + self.state_provider.borrow_mut().discard_checkpoint(); + let mut result = build_result_with_ok(params.gas, ret); + result.is_evm_call = false; + result + } + Err(e) => { + // If error, revert the checkpoint + self.state_provider.borrow_mut().revert_checkpoint(); + + let mut result = ExecutedResult::default(); + result.exception = Some(ExecutedException::NativeContract(e)); + result.is_evm_call = false; + result + } + }; + Ok(result) + } else { + // Call EVM contract + self.call_evm(params) + } + } +} + +pub fn build_evm_transaction(params: &VmExecParams) -> EVMTransaction { + EVMTransaction { + from: params.sender, + value: params.value, + gas_limit: params.gas.as_u64(), + gas_price: params.gas_price, + input: params.data.clone().unwrap_or_default(), + to: params.to_address, + nonce: params.nonce, + } +} + +pub fn build_evm_context(context: &Context) -> EVMContext { + EVMContext { + gas_limit: context.block_quota_limit.as_u64(), + coinbase: context.coin_base, + number: U256::from(context.block_number), + timestamp: context.timestamp, + difficulty: context.difficulty, + } +} + +pub fn build_evm_config(block_gas_limit: u64) -> VMConfig { + VMConfig { + // block_gas_limit is meaningless in cita_vm, so let it as default_block_quota_limit. + block_gas_limit, + check_nonce: true, + ..Default::default() + } +} + +fn build_result_with_ok(init_gas: U256, ret: InterpreterResult) -> ExecutedResult { + let mut result = ExecutedResult::default(); + + match ret { + InterpreterResult::Normal(data, quota_left, logs) => { + result.quota_used = init_gas - U256::from(quota_left); + result.quota_left = U256::from(quota_left); + result.logs = transform_logs(logs); + result.logs_bloom = logs_to_bloom(&result.logs); + + trace!( + "Get data after executed the transaction [Normal]: {:?}", + data + ); + result.output = data; + } + InterpreterResult::Revert(data, quota_left) => { + result.quota_used = init_gas - U256::from(quota_left); + result.quota_left = U256::from(quota_left); + result.exception = Some(ExecutedException::Reverted); + + trace!( + "Get data after executed the transaction [Revert]: {:?}", + data + ); + } + InterpreterResult::Create(data, quota_left, logs, contract_address) => { + result.quota_used = init_gas - U256::from(quota_left); + result.quota_left = U256::from(quota_left); + result.logs = transform_logs(logs); + result.logs_bloom = logs_to_bloom(&result.logs); + + result.contract_address = Some(contract_address); + trace!( + "Get data after executed the transaction [Create], contract address: {:?}, contract data : {:?}", + result.contract_address, data + ); + } + }; + result +} + +fn build_result_with_err(err: VMError) -> ExecutedResult { + trace!("EVM run error for the transaction, error info: {:?}", err); + let mut result = ExecutedResult::default(); + result.exception = Some(ExecutedException::VM(err)); + result +} + +fn transform_logs(logs: Vec) -> Vec { + logs.into_iter() + .map(|log| { + let EVMLog(address, topics, data) = log; + + Log { + address, + topics, + data, + } + }) + .collect() +} + +fn logs_to_bloom(logs: &[Log]) -> Bloom { + let mut bloom = Bloom::default(); + + logs.iter().for_each(|log| accrue_log(&mut bloom, log)); + bloom +} + +fn accrue_log(bloom: &mut Bloom, log: &Log) { + bloom.accrue(BloomInput::Raw(&log.address.0)); + for topic in &log.topics { + let input = BloomInput::Hash(&topic.0); + bloom.accrue(input); + } +} + +#[derive(Clone, Debug)] +pub struct VmExecParams { + /// Address of currently executed code. + pub code_address: Option
, + /// Sender of current part of the transaction. + pub sender: Address, + /// Receive address. Usually equal to code_address, + pub to_address: Option
, + /// Gas paid up front for transaction execution + pub gas: U256, + /// Gas price. + pub gas_price: U256, + /// Transaction value. + pub value: U256, + /// nonce + pub nonce: U256, + /// Input data. + pub data: Option, +} + +impl Default for VmExecParams { + /// Returns default ActionParams initialized with zeros + fn default() -> VmExecParams { + VmExecParams { + code_address: None, + sender: Address::new(), + to_address: None, + gas: U256::zero(), + gas_price: U256::zero(), + value: U256::zero(), + nonce: U256::zero(), + data: None, + } + } +} + +#[derive(Default, Debug)] +pub struct ExecutedResult { + pub state_root: H256, + pub transaction_hash: H256, + pub quota_used: U256, + pub quota_left: U256, + pub logs_bloom: Bloom, + pub logs: Vec, + pub exception: Option, + pub contract_address: Option
, + pub account_nonce: U256, + + // Note: if the transaction is a cita-evm call, needn't to handle the refund. + // FIXME: Maybe it is better to handle refund out of evm. + pub is_evm_call: bool, + + /// Transaction output. + pub output: Bytes, +} + +#[cfg(test)] +mod tests { + use super::{CitaExecutive, Context, ExecutionError, TxGasSchedule}; + use crate::contracts::native::factory::Factory as NativeFactory; + use crate::libexecutor::economical_model::EconomicalModel; + use crate::libexecutor::{block::EVMBlockDataProvider, sys_config::BlockSysConfig}; + use crate::tests::helpers::*; + use crate::types::transaction::Action; + use crate::types::transaction::Transaction; + use cita_crypto::{CreateKey, KeyPair}; + use cita_types::{Address, H256, U256}; + use cita_vm::state::StateObjectInfo; + use rustc_hex::FromHex; + use std::cell::RefCell; + use std::str::FromStr; + use std::sync::Arc; + + #[cfg(feature = "sha3hash")] + pub fn contract_address(address: &Address, nonce: &U256) -> Address { + use hashable::Hashable; + use rlp::RlpStream; + + let mut stream = RlpStream::new_list(2); + stream.append(address); + stream.append(nonce); + From::from(stream.out().crypt_hash()) + } + + #[test] + fn test_transfer_for_store() { + let keypair = KeyPair::gen_keypair(); + let data_len = 4096; + let provided_gas = U256::from(100_000); + let t = Transaction { + action: Action::Store, + value: U256::from(0), + data: vec![0; data_len], + gas: provided_gas, + gas_price: U256::one(), + nonce: U256::zero().to_string(), + block_limit: 100u64, + chain_id: 1.into(), + version: 2, + } + .fake_sign(keypair.address().clone()); + + let sender = t.sender(); + let mut state = get_temp_state(); + state + .add_balance(&sender, U256::from(18 + 100_000)) + .unwrap(); + + let mut context = Context::default(); + context.block_quota_limit = U256::from(100_000); + + let block_data_provider = EVMBlockDataProvider::new(context.clone()); + let native_factory = NativeFactory::default(); + + let state = Arc::new(RefCell::new(state)); + + let result = { + CitaExecutive::new( + Arc::new(block_data_provider), + state, + &native_factory, + &context, + EconomicalModel::Charge, + ) + .exec(&t, &BlockSysConfig::default()) + }; + + let expected = ExecutionError::NotEnoughBaseGas; + + assert!(result.is_err()); + assert_eq!(result.err().unwrap(), expected); + } + + #[test] + #[cfg(feature = "sha3hash")] + fn test_transfer_for_charge() { + let keypair = KeyPair::gen_keypair(); + let t = Transaction { + action: Action::Create, + value: U256::from(17), + data: vec![], + gas: U256::from(100_000), + gas_price: U256::one(), + nonce: U256::zero().to_string(), + block_limit: 100u64, + chain_id: 1.into(), + version: 2, + } + .fake_sign(keypair.address().clone()); + let sender = t.sender(); + let contract = contract_address(t.sender(), &U256::zero()); + + let native_factory = NativeFactory::default(); + + let mut state = get_temp_state(); + + state + .add_balance(&sender, U256::from(18 + 100_000)) + .unwrap(); + + let mut context = Context::default(); + context.block_quota_limit = U256::from(100_000); + + let block_data_provider = EVMBlockDataProvider::new(context.clone()); + + let conf = BlockSysConfig::default(); + + let state = Arc::new(RefCell::new(state)); + + let executed = { + CitaExecutive::new( + Arc::new(block_data_provider), + state.clone(), + &native_factory, + &context, + EconomicalModel::Charge, + ) + .exec(&t, &conf) + .unwrap() + }; + + let schedule = TxGasSchedule::default(); + + // Actually, this is an Action::Create transaction + assert_eq!(executed.quota_used, U256::from(schedule.tx_create_gas)); + assert_eq!(executed.logs.len(), 0); + assert_eq!( + state.borrow_mut().balance(&sender).unwrap(), + U256::from(18 + 100_000 - 17 - schedule.tx_create_gas) + ); + assert_eq!( + state.borrow_mut().balance(&contract).unwrap(), + U256::from(17) + ); + assert_eq!(state.borrow_mut().nonce(&sender).unwrap(), U256::from(1)); + } + + #[test] + fn test_not_enough_cash_for_charge() { + let keypair = KeyPair::gen_keypair(); + let t = Transaction { + action: Action::Create, + value: U256::from(43), + data: vec![], + gas: U256::from(100_000), + gas_price: U256::one(), + nonce: U256::zero().to_string(), + block_limit: 100u64, + chain_id: 1.into(), + version: 2, + } + .fake_sign(keypair.address().clone()); + + let native_factory = NativeFactory::default(); + + let mut state = get_temp_state(); + state.add_balance(t.sender(), U256::from(100_042)).unwrap(); + let mut context = Context::default(); + context.block_quota_limit = U256::from(100_000); + let conf = BlockSysConfig::default(); + + let block_data_provider = EVMBlockDataProvider::new(context.clone()); + let state = Arc::new(RefCell::new(state)); + + let result = { + CitaExecutive::new( + Arc::new(block_data_provider), + state.clone(), + &native_factory, + &context, + EconomicalModel::Charge, + ) + .exec(&t, &conf) + }; + + match result { + Err(ExecutionError::NotEnoughBalance) => {} + _ => assert!(false, "Expected not enough cash error. {:?}", result), + } + } + + #[test] + fn test_not_enough_base_gas() { + let keypair = KeyPair::gen_keypair(); + let t = Transaction { + action: Action::Create, + value: U256::from(43), + data: vec![], + gas: U256::from(100), + gas_price: U256::one(), + nonce: U256::zero().to_string(), + block_limit: 100u64, + chain_id: 1.into(), + version: 2, + } + .fake_sign(keypair.address().clone()); + + let native_factory = NativeFactory::default(); + + let mut state = get_temp_state(); + state.add_balance(t.sender(), U256::from(100_042)).unwrap(); + let mut context = Context::default(); + context.block_quota_limit = U256::from(100); + let conf = BlockSysConfig::default(); + + let block_data_provider = EVMBlockDataProvider::new(context.clone()); + let state = Arc::new(RefCell::new(state)); + + let result = { + CitaExecutive::new( + Arc::new(block_data_provider), + state.clone(), + &native_factory, + &context, + EconomicalModel::Charge, + ) + .exec(&t, &conf) + }; + + match result { + Err(ExecutionError::NotEnoughBaseGas) => {} + _ => assert!(false, "Expected not enough base gas error. {:?}", result), + } + } + + #[test] + fn test_not_enough_cash_for_quota() { + let keypair = KeyPair::gen_keypair(); + let t = Transaction { + action: Action::Create, + value: U256::from(43), + data: vec![], + gas: U256::from(100_000), + gas_price: U256::one(), + nonce: U256::zero().to_string(), + block_limit: 100u64, + chain_id: 1.into(), + version: 2, + } + .fake_sign(keypair.address().clone()); + + let native_factory = NativeFactory::default(); + let state = get_temp_state(); + let mut context = Context::default(); + context.block_quota_limit = U256::from(100_000); + let conf = BlockSysConfig::default(); + + let block_data_provider = EVMBlockDataProvider::new(context.clone()); + let state = Arc::new(RefCell::new(state)); + + let result = { + CitaExecutive::new( + Arc::new(block_data_provider), + state.clone(), + &native_factory, + &context, + EconomicalModel::Quota, + ) + .exec(&t, &conf) + }; + + // It's ok for not enough cash for quota. + assert!(result.is_ok()); + } + + #[test] + fn test_create_contract_out_of_gas() { + logger::silent(); + let source = r#" +pragma solidity ^0.4.19; + +contract HelloWorld { + uint balance; + + function update(uint amount) public returns (address, uint) { + balance += amount; + return (msg.sender, balance); + } +} +"#; + let schedule = TxGasSchedule::default(); + + let gas_required = U256::from(schedule.tx_gas + 1000); + + let (deploy_code, _runtime_code) = solc("HelloWorld", source); + let native_factory = NativeFactory::default(); + + let keypair = KeyPair::gen_keypair(); + let t = Transaction { + action: Action::Create, + value: U256::from(0), + data: deploy_code, + gas: gas_required, + gas_price: U256::one(), + nonce: U256::zero().to_string(), + block_limit: 100u64, + chain_id: 1.into(), + version: 2, + } + .fake_sign(keypair.address().clone()); + + let state = get_temp_state(); + + let context = Context::default(); + + let conf = BlockSysConfig::default(); + + let block_data_provider = EVMBlockDataProvider::new(context.clone()); + let state = Arc::new(RefCell::new(state)); + + let res = { + CitaExecutive::new( + Arc::new(block_data_provider), + state.clone(), + &native_factory, + &context, + EconomicalModel::Quota, + ) + .exec(&t, &conf) + }; + + assert!(res.is_err()); + let expected = ExecutionError::NotEnoughBaseGas; + assert_eq!(res.err().unwrap(), expected); + } + + #[test] + #[cfg(feature = "sha3hash")] + fn test_create_contract() { + logger::silent(); + let source = r#" +pragma solidity ^0.4.8; +contract AbiTest { + uint balance; + function AbiTest() {} + function setValue(uint value) { + balance = value; + } +} +"#; + let schedule = TxGasSchedule::default(); + + let gas_required = U256::from(schedule.tx_gas + 100_000); + + let (deploy_code, runtime_code) = solc("AbiTest", source); + let native_factory = NativeFactory::default(); + + let keypair = KeyPair::gen_keypair(); + let t = Transaction { + action: Action::Create, + value: U256::from(0), + data: deploy_code, + gas: gas_required, + gas_price: U256::one(), + nonce: U256::zero().to_string(), + block_limit: 100u64, + chain_id: 1.into(), + version: 2, + } + .fake_sign(keypair.address().clone()); + + let sender = keypair.address().clone(); + let nonce = U256::zero(); + let contract_address = contract_address(&sender, &nonce); + + let state = get_temp_state(); + + let context = Context::default(); + + let conf = BlockSysConfig::default(); + + let block_data_provider = EVMBlockDataProvider::new(context.clone()); + let state = Arc::new(RefCell::new(state)); + + { + let _ = CitaExecutive::new( + Arc::new(block_data_provider), + state.clone(), + &native_factory, + &context, + EconomicalModel::Quota, + ) + .exec(&t, &conf); + } + + assert_eq!( + &state.borrow_mut().code(&contract_address).unwrap(), + &runtime_code + ); + } + + #[test] + fn test_call_contract() { + logger::silent(); + let source = r#" +pragma solidity ^0.4.8; +contract AbiTest { + uint balance; + function AbiTest() {} + function setValue(uint value) { + balance = value; + } +} +"#; + let schedule = TxGasSchedule::default(); + let gas_required = U256::from(schedule.tx_gas + 100_000); + let contract_addr = Address::from_str("62f4b16d67b112409ab4ac87274926382daacfac").unwrap(); + let (_, runtime_code) = solc("AbiTest", source); + + // big endian: value=0x12345678 + let data = "552410770000000000000000000000000000000000000000000000000000000012345678" + .from_hex() + .unwrap(); + let native_factory = NativeFactory::default(); + let mut state = get_temp_state(); + state + .set_code(&contract_addr, runtime_code.clone()) + .unwrap(); + + let keypair = KeyPair::gen_keypair(); + let t = Transaction { + action: Action::Call(contract_addr), + value: U256::from(0), + data, + gas: gas_required, + gas_price: U256::one(), + nonce: U256::zero().to_string(), + block_limit: 100u64, + chain_id: 1.into(), + version: 2, + } + .fake_sign(keypair.address().clone()); + + let context = Context::default(); + + let conf = BlockSysConfig::default(); + + let block_data_provider = EVMBlockDataProvider::new(context.clone()); + let state = Arc::new(RefCell::new(state)); + + { + let _ = CitaExecutive::new( + Arc::new(block_data_provider), + state.clone(), + &native_factory, + &context, + EconomicalModel::Quota, + ) + .exec(&t, &conf); + } + + // it was supposed that value's address is balance. + assert_eq!( + state + .borrow_mut() + .get_storage(&contract_addr, &H256::from(&U256::from(0))) + .unwrap(), + H256::from(&U256::from(0x12345678)) + ); + } + + #[test] + fn test_revert_instruction() { + logger::silent(); + let source = r#" +pragma solidity ^0.4.8; +contract AbiTest { + uint balance; + + modifier Never { + require(false); + _; + } + + function AbiTest() {} + function setValue(uint value) Never { + balance = value; + } +} +"#; + let schedule = TxGasSchedule::default(); + let gas_required = U256::from(schedule.tx_gas + 100_000); + let contract_addr = Address::from_str("62f4b16d67b112409ab4ac87274926382daacfac").unwrap(); + let (_, runtime_code) = solc("AbiTest", source); + // big endian: value=0x12345678 + let data = "552410770000000000000000000000000000000000000000000000000000000012345678" + .from_hex() + .unwrap(); + let native_factory = NativeFactory::default(); + + let mut state = get_temp_state(); + state + .set_code(&contract_addr, runtime_code.clone()) + .unwrap(); + + let keypair = KeyPair::gen_keypair(); + let t = Transaction { + action: Action::Call(contract_addr), + value: U256::from(0), + data, + gas: gas_required, + gas_price: U256::one(), + nonce: U256::zero().to_string(), + block_limit: 100u64, + chain_id: 1.into(), + version: 2, + } + .fake_sign(keypair.address().clone()); + + let context = Context::default(); + + let conf = BlockSysConfig::default(); + + let block_data_provider = EVMBlockDataProvider::new(context.clone()); + let state = Arc::new(RefCell::new(state)); + + { + let res = CitaExecutive::new( + Arc::new(block_data_provider), + state.clone(), + &native_factory, + &context, + EconomicalModel::Quota, + ) + .exec(&t, &conf); + assert!(res.is_ok()); + match res { + Ok(result) => println!("quota used: {:?}", result.quota_used), + Err(e) => println!("e: {:?}", e), + } + }; + + // it was supposed that value's address is balance. + assert_eq!( + state + .borrow_mut() + .get_storage(&contract_addr, &H256::from(&U256::from(0))) + .unwrap(), + H256::from(&U256::from(0x0)) + ); + } + + #[test] + fn test_require_instruction() { + logger::silent(); + let source = r#" +pragma solidity ^0.4.8; +contract AbiTest { + uint balance; + + modifier Never { + require(true); + _; + } + + function AbiTest() {} + function setValue(uint value) Never { + balance = value; + } +} +"#; + let schedule = TxGasSchedule::default(); + let gas_required = U256::from(schedule.tx_gas + 100_000); + let contract_addr = Address::from_str("62f4b16d67b112409ab4ac87274926382daacfac").unwrap(); + let (_, runtime_code) = solc("AbiTest", source); + // big endian: value=0x12345678 + let data = "552410770000000000000000000000000000000000000000000000000000000012345678" + .from_hex() + .unwrap(); + let native_factory = NativeFactory::default(); + + let mut state = get_temp_state(); + state + .set_code(&contract_addr, runtime_code.clone()) + .unwrap(); + + let keypair = KeyPair::gen_keypair(); + let t = Transaction { + action: Action::Call(contract_addr), + value: U256::from(0), + data, + gas: gas_required, + gas_price: U256::one(), + nonce: U256::zero().to_string(), + block_limit: 100u64, + chain_id: 1.into(), + version: 2, + } + .fake_sign(keypair.address().clone()); + + let context = Context::default(); + + let conf = BlockSysConfig::default(); + + let block_data_provider = EVMBlockDataProvider::new(context.clone()); + let state = Arc::new(RefCell::new(state)); + + { + let res = CitaExecutive::new( + Arc::new(block_data_provider), + state.clone(), + &native_factory, + &context, + EconomicalModel::Quota, + ) + .exec(&t, &conf); + assert!(res.is_ok()); + match res { + Ok(result) => println!("quota used: {:?}", result.quota_used), + Err(e) => println!("e: {:?}", e), + } + }; + + // it was supposed that value's address is balance. + assert_eq!( + state + .borrow_mut() + .get_storage(&contract_addr, &H256::from(&U256::from(0))) + .unwrap(), + H256::from(&U256::from(0x12345678)) + ); + } + + #[test] + fn test_call_instruction() { + logger::silent(); + let fake_auth = r#" +pragma solidity ^0.4.18; + +contract FakeAuth { + function setAuth() public pure returns(bool) { + return true; + } +} +"#; + + let fake_permission_manager = r#" +pragma solidity ^0.4.18; + +contract FakeAuth { + function setAuth() public returns(bool); +} + +contract FakePermissionManagement { + function setAuth(address _auth) public returns(bool) { + FakeAuth auth = FakeAuth(_auth); + require(auth.setAuth()); + return true; + } +} +"#; + let schedule = TxGasSchedule::default(); + let gas_required = U256::from(schedule.tx_gas + 100_000); + let auth_addr = Address::from_str("27ec3678e4d61534ab8a87cf8feb8ac110ddeda5").unwrap(); + let permission_addr = + Address::from_str("33f4b16d67b112409ab4ac87274926382daacfac").unwrap(); + + let native_factory = NativeFactory::default(); + + let mut state = get_temp_state(); + let (_, runtime_code) = solc("FakeAuth", fake_auth); + state.set_code(&auth_addr, runtime_code.clone()).unwrap(); + + let (_, runtime_code) = solc("FakePermissionManagement", fake_permission_manager); + state + .set_code(&permission_addr, runtime_code.clone()) + .unwrap(); + + // 2b2e05c1: setAuth(address) + let data = "2b2e05c100000000000000000000000027ec3678e4d61534ab8a87cf8feb8ac110ddeda5" + .from_hex() + .unwrap(); + + let keypair = KeyPair::gen_keypair(); + let t = Transaction { + action: Action::Call(permission_addr), + value: U256::from(0), + data, + gas: gas_required, + gas_price: U256::one(), + nonce: U256::zero().to_string(), + block_limit: 100u64, + chain_id: 1.into(), + version: 2, + } + .fake_sign(keypair.address().clone()); + + let context = Context::default(); + + let conf = BlockSysConfig::default(); + + let block_data_provider = EVMBlockDataProvider::new(context.clone()); + let state = Arc::new(RefCell::new(state)); + + { + let res = CitaExecutive::new( + Arc::new(block_data_provider), + state.clone(), + &native_factory, + &context, + EconomicalModel::Quota, + ) + .exec(&t, &conf); + assert!(res.is_ok()); + match res { + Ok(result) => println!("quota used: {:?}", result.quota_used), + Err(e) => println!("e: {:?}", e), + } + }; + } +} diff --git a/cita-executor/core/src/contracts/grpc/contract.rs b/cita-executor/core/src/contracts/grpc/contract.rs deleted file mode 100644 index b741fcad3..000000000 --- a/cita-executor/core/src/contracts/grpc/contract.rs +++ /dev/null @@ -1,117 +0,0 @@ -// CITA -// Copyright 2016-2019 Cryptape Technologies LLC. - -// This program is free software: you can redistribute it -// and/or modify it under the terms of the GNU 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 General Public License for more details. - -// You should have received a copy of the GNU General Public License -// along with this program. If not, see . - -use crate::contracts::grpc::{contract_state::ConnectInfo, grpc_vm::CallEvmImpl}; -use crate::state::backend::Backend as StateBackend; -use crate::state::State; -use crate::types::reserved_addresses; -use cita_types::traits::LowerHex; -use cita_types::Address; -use evm::action_params::ActionParams; -use evm::env_info::EnvInfo; -use grpc::Result as GrpcResult; -use libproto::citacode::{ - ActionParams as ProtoActionParams, EnvInfo as ProtoEnvInfo, InvokeRequest, InvokeResponse, -}; -use std::str::FromStr; - -lazy_static! { - static ref CONTRACT_CREATION_ADDRESS: Address = - Address::from_str(reserved_addresses::GO_CONTRACT).unwrap(); - static ref LOW_CONTRACT_ADDRESS: Address = - Address::from_str(reserved_addresses::GO_CONTRACT_MIN).unwrap(); - static ref HIGH_CONTRACT_ADDRESS: Address = - Address::from_str(reserved_addresses::GO_CONTRACT_MAX).unwrap(); -} - -pub fn low_contract_address() -> Address { - *LOW_CONTRACT_ADDRESS -} - -pub fn high_contract_address() -> Address { - *HIGH_CONTRACT_ADDRESS -} - -pub fn contract_creation_address() -> Address { - *CONTRACT_CREATION_ADDRESS -} - -pub fn is_create_grpc_address(addr: Address) -> bool { - addr == *CONTRACT_CREATION_ADDRESS -} - -pub fn is_grpc_contract(caddr: Address) -> bool { - caddr >= *LOW_CONTRACT_ADDRESS && caddr <= *HIGH_CONTRACT_ADDRESS -} - -pub fn invoke_grpc_contract( - env_info: &EnvInfo, - params: &ActionParams, - state: &mut State, - _check_quota: bool, - connect_info: &ConnectInfo, -) -> GrpcResult -where - B: StateBackend, -{ - let invoke_request = new_invoke_request(params, connect_info, env_info); - let mut evm_impl = CallEvmImpl::new(state); - evm_impl.call( - connect_info.get_ip(), - connect_info.get_port(), - invoke_request, - ) -} - -pub fn create_grpc_contract( - env_info: &EnvInfo, - params: &ActionParams, - state: &mut State, - _check_quota: bool, - connect_info: &ConnectInfo, -) -> GrpcResult -where - B: StateBackend, -{ - let invoke_request = new_invoke_request(params, connect_info, env_info); - let mut evm_impl = CallEvmImpl::new(state); - evm_impl.create( - connect_info.get_ip(), - connect_info.get_port(), - invoke_request, - ) -} - -fn new_invoke_request( - params: &ActionParams, - connect_info: &ConnectInfo, - env_info: &EnvInfo, -) -> InvokeRequest { - let mut proto_env_info = ProtoEnvInfo::new(); - proto_env_info.set_number(format!("{}", env_info.number)); - proto_env_info.set_author(Address::default().lower_hex()); - let timestamp = env_info.timestamp; - proto_env_info.set_timestamp(format!("{}", timestamp)); - let mut proto_params = ProtoActionParams::new(); - proto_params.set_code_address(connect_info.get_addr().to_string()); - proto_params.set_data(params.data.to_owned().unwrap()); - proto_params.set_sender(params.sender.lower_hex()); - let mut invoke_request = InvokeRequest::new(); - invoke_request.set_param(proto_params); - invoke_request.set_env_info(proto_env_info.clone()); - invoke_request -} diff --git a/cita-executor/core/src/contracts/grpc/contract_state.rs b/cita-executor/core/src/contracts/grpc/contract_state.rs deleted file mode 100644 index 65efa3e2b..000000000 --- a/cita-executor/core/src/contracts/grpc/contract_state.rs +++ /dev/null @@ -1,137 +0,0 @@ -// CITA -// Copyright 2016-2019 Cryptape Technologies LLC. - -// This program is free software: you can redistribute it -// and/or modify it under the terms of the GNU 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 General Public License for more details. - -// You should have received a copy of the GNU General Public License -// along with this program. If not, see . - -use crate::db::Key; -use cita_types::{Address, H160}; -use rlp::*; -use std::str::FromStr; -use util::*; - -#[derive(Clone, Debug)] -pub struct ConnectInfo { - ip: String, - port: u16, - address: String, -} - -impl ConnectInfo { - pub fn new(ip: String, port: u16, address: String) -> Self { - ConnectInfo { ip, port, address } - } - - pub fn get_ip(&self) -> &str { - self.ip.as_ref() - } - - pub fn get_port(&self) -> u16 { - self.port - } - - pub fn get_addr(&self) -> &str { - self.address.as_ref() - } - - pub fn stream_rlp(&self, s: &mut RlpStream) { - s.begin_list(3); - s.append(&self.ip); - s.append(&self.port); - s.append(&self.address); - } - - /// Get the RLP of this header. - pub fn rlp(&self) -> Bytes { - let mut s = RlpStream::new(); - self.stream_rlp(&mut s); - s.out() - } -} - -impl Encodable for ConnectInfo { - fn rlp_append(&self, s: &mut RlpStream) { - self.stream_rlp(s); - } -} - -impl Decodable for ConnectInfo { - fn decode(r: &UntrustedRlp) -> Result { - let conn_info = ConnectInfo { - ip: r.val_at(0)?, - port: r.val_at(1)?, - address: r.val_at(2)?, - }; - - Ok(conn_info) - } -} - -#[derive(Clone)] -pub struct ContractState { - pub conn_info: ConnectInfo, - pub height: u64, -} - -impl ContractState { - // add code here - pub fn new(ip: String, port: u16, address: String, h: u64) -> Self { - ContractState { - conn_info: ConnectInfo::new(ip, port, address), - height: h, - } - } - - pub fn get_address(&self) -> Address { - Address::from_str(&self.conn_info.address).unwrap() - } - - pub fn stream_rlp(&self, s: &mut RlpStream) { - s.begin_list(2); - s.append(&self.conn_info); - s.append(&self.height); - } - - /// Get the RLP of this header. - pub fn rlp(&self) -> Bytes { - let mut s = RlpStream::new(); - self.stream_rlp(&mut s); - s.out() - } -} - -impl Encodable for ContractState { - fn rlp_append(&self, s: &mut RlpStream) { - self.stream_rlp(s); - } -} - -impl Decodable for ContractState { - fn decode(r: &UntrustedRlp) -> Result { - let contract_state = ContractState { - conn_info: r.val_at(0)?, - height: r.val_at(1)?, - }; - - Ok(contract_state) - } -} - -impl Key for H160 { - type Target = H160; - - fn key(&self) -> H160 { - *self - } -} diff --git a/cita-executor/core/src/contracts/grpc/grpc_vm.rs b/cita-executor/core/src/contracts/grpc/grpc_vm.rs deleted file mode 100644 index 495281d9e..000000000 --- a/cita-executor/core/src/contracts/grpc/grpc_vm.rs +++ /dev/null @@ -1,230 +0,0 @@ -// CITA -// Copyright 2016-2019 Cryptape Technologies LLC. - -// This program is free software: you can redistribute it -// and/or modify it under the terms of the GNU 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 General Public License for more details. - -// You should have received a copy of the GNU General Public License -// along with this program. If not, see . - -use crate::authentication::check_permission; -use crate::db::{self as db, Writable}; -use crate::error::{Error, ExecutionError}; -use crate::libexecutor::sys_config::BlockSysConfig; -use cita_types::traits::LowerHex; -use cita_types::{Address, H256, U256}; -use grpc::Result as GrpcResult; - -use crate::contracts::grpc::{ - contract_state::{ConnectInfo, ContractState}, - service_registry, -}; -use crate::libexecutor::executor::Executor; -use crate::log_entry::LogEntry; -use crate::receipt::Receipt; -use crate::state::backend::Backend as StateBackend; -use crate::state::State; -use crate::types::transaction::{Action, SignedTransaction}; -use libproto::citacode::{ActionParams, EnvInfo, InvokeRequest, InvokeResponse}; -use libproto::citacode_grpc::{CitacodeService, CitacodeServiceClient}; -use std::error::Error as StdError; -use std::str::FromStr; -use util::Bytes; - -pub fn extract_logs_from_response(sender: Address, response: &InvokeResponse) -> Vec { - response - .get_logs() - .iter() - .map(|log| { - let mut topics = Vec::new(); - let tdata = log.get_topic(); - - for chunk in tdata.chunks(32) { - let value = H256::from(chunk); - topics.push(value); - } - - let data = Bytes::from(log.get_data()); - LogEntry { - address: sender, - topics, - data: data.to_vec(), - } - }) - .collect() -} - -pub struct CallEvmImpl<'a, B: 'a + StateBackend> { - state: &'a mut State, - gas_used: U256, -} - -impl<'a, B: 'a + StateBackend> CallEvmImpl<'a, B> { - pub fn new(state: &'a mut State) -> Self { - CallEvmImpl { - state, - gas_used: 0.into(), - } - } - - pub fn call( - &mut self, - host: &str, - port: u16, - invoke_request: InvokeRequest, - ) -> GrpcResult { - let client = CitacodeServiceClient::new_plain(host, port, Default::default()).unwrap(); - let resp = client.invoke(::grpc::RequestOptions::new(), invoke_request); - resp.wait_drop_metadata() - } - - pub fn create( - &mut self, - host: &str, - port: u16, - invoke_request: InvokeRequest, - ) -> GrpcResult { - let client = CitacodeServiceClient::new_plain(host, port, Default::default()).unwrap(); - let resp = client.init(::grpc::RequestOptions::new(), invoke_request); - resp.wait_drop_metadata() - } - - pub fn save_contract_state(&mut self, executor: &Executor, contract_state: &ContractState) { - let addr = contract_state.get_address(); - let mut batch = executor.db.transaction(); - batch.write(db::COL_EXTRA, &addr, contract_state); - executor.db.write(batch).unwrap(); - service_registry::set_enable_contract_height(addr, contract_state.height); - } - - pub fn save_response_state(&mut self, contract_address: Address, response: &InvokeResponse) { - for storage in &response.get_storages()[..] { - let mut value = Vec::new(); - let key = H256::from_slice(storage.get_key()); - value.extend_from_slice(storage.get_value()); - - trace!("recv resp: {:?}", storage); - trace!("key: {:?}, value: {:?}", key, value); - self.set_bytes(contract_address, key, &value[..]) - } - } - - pub fn transact( - &mut self, - executor: &Executor, - t: &SignedTransaction, - env_info: &EnvInfo, - action_params: &ActionParams, - connect_info: &ConnectInfo, - conf: &BlockSysConfig, - ) -> Result { - let mut invoke_request = InvokeRequest::new(); - invoke_request.set_param(action_params.to_owned()); - invoke_request.set_env_info(env_info.to_owned()); - - let sender = *t.sender(); - let nonce = self.state.nonce(&sender).map_err(|err| *err)?; - self.state.inc_nonce(&sender).map_err(|err| *err)?; - // TODO There are three option about permission - if (*conf).check_options.call_permission { - check_permission( - &conf.group_accounts, - &conf.account_permissions, - t, - (*conf).check_options, - )?; - } - // FIXME: Need to check the gas required for go vm. - let base_gas_required = U256::from(21_000); - - if sender != Address::zero() && t.action != Action::Store && t.gas < base_gas_required { - return Err(From::from(ExecutionError::NotEnoughBaseGas { - required: base_gas_required, - got: t.gas, - })); - } - - let ip = connect_info.get_ip(); - let port = connect_info.get_port(); - let _addr = connect_info.get_addr(); - let _height: u64 = env_info.number.parse().unwrap(); - - let (resp, contract_address) = { - match t.action { - Action::Call(addr) => { - let resp = self.call(ip, port, invoke_request); - (resp, Address::from_slice(&addr)) - } - Action::GoCreate => { - let resp = self.create(ip, port, invoke_request); - // set enable - let contract_address = Address::from_slice(&t.data); - service_registry::enable_contract(contract_address); - info!( - "enable go contract {} at {}:{}", - contract_address.lower_hex(), - ip, - port - ); - (resp, contract_address) - } - _ => panic!("unknown action {:?}", t.action), - } - }; - - if let Ok(resp) = resp { - let height = env_info.get_number().parse::().unwrap(); - let contract_state = - ContractState::new(ip.to_string(), port, contract_address.to_string(), height); - self.save_contract_state(executor, &contract_state); - self.save_response_state(contract_address, &resp); - // todo cumulative gas - let gas_left = U256::from_str(resp.get_gas_left()).unwrap(); - let gas_used = t.gas - gas_left; - let cumulative_gas_used = self.gas_used + gas_used; - - let logs = extract_logs_from_response(sender, &resp); - let receipt = Receipt::new( - None, - cumulative_gas_used, - logs, - None, - nonce, - t.get_transaction_hash(), - ); - Ok(receipt) - } else { - error!("go contract execute failed {:?}", resp); - Err(Error::StdIo(::std::io::Error::new( - ::std::io::ErrorKind::Other, - resp.err().unwrap().description(), - ))) - } - } - - pub fn set_bytes(&mut self, address: Address, key: H256, info: &[u8]) { - let len = info.len(); - if len == 0 { - return; - } - self.state - .set_storage(&address, key, H256::from(len as u64)) - .expect("grpc set_storage fail"); - let mut pos = U256::from(key) + U256::one(); - for chunk in info.chunks(32) { - let value = H256::from(chunk); - self.state - .set_storage(&address, H256::from(pos), value) - .expect("grpc set_storage fail"); - pos = pos + U256::one(); - } - } -} diff --git a/cita-executor/core/src/contracts/grpc/grpc_vm_adapter.rs b/cita-executor/core/src/contracts/grpc/grpc_vm_adapter.rs deleted file mode 100644 index 7650cee2f..000000000 --- a/cita-executor/core/src/contracts/grpc/grpc_vm_adapter.rs +++ /dev/null @@ -1,164 +0,0 @@ -// CITA -// Copyright 2016-2019 Cryptape Technologies LLC. - -// This program is free software: you can redistribute it -// and/or modify it under the terms of the GNU 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 General Public License for more details. - -// You should have received a copy of the GNU General Public License -// along with this program. If not, see . - -use crate::contracts::grpc::service_registry; -use crate::libexecutor::command; -use crate::types::ids::BlockId; -use cita_types::{Address, H256, U256}; -use crossbeam_channel::{Receiver, Sender}; -use grpc::Server; -use libproto::executor::{LoadRequest, LoadResponse, RegisterRequest, RegisterResponse}; -use libproto::executor_grpc::{ExecutorService, ExecutorServiceServer}; -use std::str::FromStr; -use std::thread; -use std::time::Duration; - -pub struct ExecutorServiceImpl { - command_req_sender: Sender, - command_resp_receiver: Receiver, -} - -impl ExecutorService for ExecutorServiceImpl { - fn register( - &self, - _o: ::grpc::RequestOptions, - req: RegisterRequest, - ) -> ::grpc::SingleResponse { - let mut r = RegisterResponse::new(); - { - let caddr = req.get_contract_address(); - let ip = req.get_ip(); - let port = req.get_port(); - - if let Ok(iport) = port.parse::() { - service_registry::register_contract( - Address::from_str(caddr).unwrap(), - ip, - iport, - 0, - ); - r.set_state(format!("OK {}---{}:{}", caddr, ip, port)); - } else { - r.set_state(format!("Error Register {}---{}:{}", caddr, ip, port)); - } - } - ::grpc::SingleResponse::completed(r) - } - - fn load( - &self, - _o: ::grpc::RequestOptions, - req: LoadRequest, - ) -> ::grpc::SingleResponse { - let mut r = LoadResponse::new(); - - let caddr = req.get_contract_address(); - let req_key = req.get_key(); - let key = H256::from_slice(String::from(req_key).as_bytes()); - - let address = Address::from_str(caddr).unwrap(); - let mut hi: u64 = 0; - if let Some(info) = service_registry::find_contract(address, true) { - hi = info.height; - } - if hi == 0 { - error!("contract address {} have not created", caddr); - r.set_value("".to_string()); - } else { - let out = self.get_bytes(BlockId::Number(hi), &address, key); - let value = String::from_utf8(out).unwrap(); - trace!("load find value: {}", value); - r.set_value(value); - } - ::grpc::SingleResponse::completed(r) - } -} - -impl ExecutorServiceImpl { - pub fn new( - command_req_sender: Sender, - command_resp_receiver: Receiver, - ) -> Self { - ExecutorServiceImpl { - command_req_sender, - command_resp_receiver, - } - } - - // get vec - fn get_bytes(&self, block_id: BlockId, address: &Address, key: H256) -> Vec { - let mut out = Vec::new(); - match command::state_at( - &self.command_req_sender, - &self.command_resp_receiver, - block_id, - ) { - Some(state) => { - if let Ok(len) = state.storage_at(&address, &key) { - let len = len.low_u64(); - let hlen = len / 32; - let modnum = len & 0x1f; - let mut pos = U256::from(key); - - for _ in 0..hlen { - pos = pos + U256::one(); - if let Ok(val) = state.storage_at(&address, &H256::from(pos)) { - out.extend_from_slice(val.as_ref()); - } else { - return Vec::new(); - } - } - - if modnum > 0 { - pos = pos + U256::one(); - if let Ok(val) = state.storage_at(&address, &H256::from(pos)) { - out.extend_from_slice(&(val.as_ref() as &[u8])[0..modnum as usize]) - } - } - } - out - } - None => { - error!("state do not find by height"); - out - } - } - } -} - -pub fn vm_grpc_server( - grpc_port: u16, - command_req_sender: Sender, - command_resp_receiver: Receiver, -) -> Option { - let mut server = ::grpc::ServerBuilder::new_plain(); - server.http.set_port(grpc_port); - server.add_service(ExecutorServiceServer::new_service_def( - ExecutorServiceImpl::new(command_req_sender, command_resp_receiver), - )); - server.http.set_cpu_pool_threads(4); - match server.build() { - Ok(server) => Some(server), - Err(_) => None, - } -} - -pub fn serve(_server: &Server) { - loop { - thread::sleep(Duration::from_secs(5)) - } -} diff --git a/cita-executor/core/src/contracts/grpc/mod.rs b/cita-executor/core/src/contracts/grpc/mod.rs deleted file mode 100644 index 796f2a246..000000000 --- a/cita-executor/core/src/contracts/grpc/mod.rs +++ /dev/null @@ -1,30 +0,0 @@ -// CITA -// Copyright 2016-2019 Cryptape Technologies LLC. - -// This program is free software: you can redistribute it -// and/or modify it under the terms of the GNU 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 General Public License for more details. - -// You should have received a copy of the GNU General Public License -// along with this program. If not, see . - -//! GRPC contracts. -//! You need following steps to use GRPC Contract: -//! 1. Register a contract info through Executor GRPC interface. -//! 2. Enable this GRPC contract by send a transaction (See block.rs file). -//! -//! now you can invoke this GRPC contract from transaction or EVM contract. - -pub mod contract; -pub mod contract_state; -pub mod grpc_vm; -pub mod grpc_vm_adapter; -pub mod service_registry; -pub mod storage; diff --git a/cita-executor/core/src/contracts/grpc/service_registry.rs b/cita-executor/core/src/contracts/grpc/service_registry.rs deleted file mode 100644 index 118ef1ac1..000000000 --- a/cita-executor/core/src/contracts/grpc/service_registry.rs +++ /dev/null @@ -1,108 +0,0 @@ -// CITA -// Copyright 2016-2019 Cryptape Technologies LLC. - -// This program is free software: you can redistribute it -// and/or modify it under the terms of the GNU 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 General Public License for more details. - -// You should have received a copy of the GNU General Public License -// along with this program. If not, see . - -use crate::contracts::grpc::contract_state::ContractState; -use cita_types::traits::LowerHex; -use cita_types::Address; -use std::collections::HashMap; -use std::sync::Mutex; -use util::RwLock; - -lazy_static! { - static ref SERVICE_MAP: Mutex = Mutex::new(ServiceMap::new()); -} - -pub fn register_contract(address: Address, ip: &str, port: u16, height: u64) { - let key = convert_address_to_key(address); - SERVICE_MAP - .lock() - .unwrap() - .insert_disable(&key, &ip, port, height); -} - -pub fn find_contract(address: Address, enable: bool) -> Option { - let key = convert_address_to_key(address); - SERVICE_MAP.lock().unwrap().get(&key, enable) -} - -pub fn enable_contract(contract_address: Address) { - let key = convert_address_to_key(contract_address); - SERVICE_MAP.lock().unwrap().set_enable(&key); -} - -pub fn set_enable_contract_height(contract_address: Address, height: u64) { - let key = convert_address_to_key(contract_address); - SERVICE_MAP.lock().unwrap().set_enable_height(&key, height); -} - -fn convert_address_to_key(address: Address) -> String { - address.lower_hex() -} - -struct ServiceMap { - disable: RwLock>, - enable: RwLock>, -} - -impl ServiceMap { - pub fn new() -> Self { - ServiceMap { - disable: RwLock::new(HashMap::new()), - enable: RwLock::new(HashMap::new()), - } - } - - pub fn set_enable(&self, contract_address: &str) { - match self.disable.write().remove(contract_address) { - Some(value) => { - self.enable - .write() - .insert(contract_address.to_owned(), value); - } - None => { - warn!( - "can't enable go contract address [{}] because it have not registed!", - contract_address - ); - } - } - } - - pub fn set_enable_height(&self, contract_address: &str, height: u64) { - if let Some(value) = self.enable.write().get_mut(contract_address) { - value.height = height; - } - } - - pub fn insert_disable(&self, key: &str, ip: &str, port: u16, height: u64) { - self.disable.write().insert( - key.to_owned(), - ContractState::new(ip.to_owned(), port, "".to_string(), height), - ); - } - - // pub fn contains_key(&self, key: String) -> bool { - // self.enable.write().contains_key(&key) - // } - - pub fn get(&self, key: &str, enable: bool) -> Option { - if enable { &self.enable } else { &self.disable } - .write() - .get(key) - .map(::std::clone::Clone::clone) - } -} diff --git a/cita-executor/core/src/contracts/grpc/storage.rs b/cita-executor/core/src/contracts/grpc/storage.rs deleted file mode 100644 index d567d67d4..000000000 --- a/cita-executor/core/src/contracts/grpc/storage.rs +++ /dev/null @@ -1,48 +0,0 @@ -// CITA -// Copyright 2016-2019 Cryptape Technologies LLC. - -// This program is free software: you can redistribute it -// and/or modify it under the terms of the GNU 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 General Public License for more details. - -// You should have received a copy of the GNU General Public License -// along with this program. If not, see . - -use crate::cita_db::trie; -use crate::state::backend::Backend; -use crate::state::State; -use cita_types::{Address, H256, U256}; - -pub fn set_storage( - state: &mut State, - address: Address, - key: &[u8], - value: &[u8], -) -> trie::Result<()> -where - B: Backend, -{ - let mut v = Vec::new(); - let k = H256::from_slice(key); - v.extend_from_slice(value); - - let len = v.len(); - if len == 0 { - return Ok(()); - } - state.set_storage(&address, k, H256::from(len as u64))?; - let mut pos = U256::from(k) + U256::one(); - for chunk in v.chunks(32) { - let chunk_value = H256::from(chunk); - state.set_storage(&address, H256::from(pos), chunk_value)?; - pos = pos + U256::one(); - } - Ok(()) -} diff --git a/cita-executor/core/src/contracts/mod.rs b/cita-executor/core/src/contracts/mod.rs index 9c38572b7..87e84434b 100644 --- a/cita-executor/core/src/contracts/mod.rs +++ b/cita-executor/core/src/contracts/mod.rs @@ -1,24 +1,19 @@ -// CITA -// Copyright 2016-2018 Cryptape Technologies LLC. - -// This program is free software: you can redistribute it -// and/or modify it under the terms of the GNU 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 General Public License for more details. - -// You should have received a copy of the GNU General Public License -// along with this program. If not, see . +// Copyright Cryptape Technologies LLC. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. //! Contracts. -pub mod grpc; pub mod native; pub mod solc; - pub mod tools; diff --git a/cita-executor/core/src/contracts/native/crosschain_verify.rs b/cita-executor/core/src/contracts/native/crosschain_verify.rs index 40e131c6d..c63fe5aad 100644 --- a/cita-executor/core/src/contracts/native/crosschain_verify.rs +++ b/cita-executor/core/src/contracts/native/crosschain_verify.rs @@ -1,31 +1,32 @@ -// CITA -// Copyright 2016-2018 Cryptape Technologies LLC. - -// This program is free software: you can redistribute it -// and/or modify it under the terms of the GNU 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 General Public License for more details. - -// You should have received a copy of the GNU General Public License -// along with this program. If not, see . - +// Copyright Cryptape Technologies LLC. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +use crate::cita_executive::VmExecParams; use crate::contracts::{ native::factory::Contract, solc::ChainManagement, tools::method as method_tools, }; -use crate::state::StateProof; +// use crate::state::StateProof; use cita_types::{Address, H256, U256}; use core::header::Header; use core::libchain::chain::TxProof; use ethabi; -use evm::action_params::ActionParams; -use evm::storage::Map; -use evm::{Error, Ext, GasLeft, ReturnData}; + +use crate::storage::Map; +use crate::types::context::Context; +use crate::types::errors::NativeError; +use cita_vm::evm::DataProvider; +use cita_vm::evm::InterpreterResult; lazy_static! { static ref VERIFY_TRANSACTION_FUNC: u32 = @@ -46,19 +47,28 @@ pub struct CrossChainVerify { } impl Contract for CrossChainVerify { - fn exec(&mut self, params: &ActionParams, ext: &mut Ext) -> Result { + fn exec( + &mut self, + params: &VmExecParams, + _context: &Context, + data_provider: &mut DataProvider, + ) -> Result { if let Some(ref data) = params.data { method_tools::extract_to_u32(&data[..]).and_then(|signature| match signature { - sig if sig == *VERIFY_TRANSACTION_FUNC => self.verify_transaction(params, ext), - sig if sig == *VERIFY_STATE_FUNC => self.verify_state(params, ext), - sig if sig == *VERIFY_BLOCK_HEADER_FUNC => self.verify_block_header(params, ext), + sig if sig == *VERIFY_TRANSACTION_FUNC => { + self.verify_transaction(params, data_provider) + } + sig if sig == *VERIFY_STATE_FUNC => self.verify_state(params, data_provider), + sig if sig == *VERIFY_BLOCK_HEADER_FUNC => { + self.verify_block_header(params, data_provider) + } sig if sig == *GET_EXPECTED_BLOCK_NUMBER_FUNC => { - self.get_expected_block_number(params, ext) + self.get_expected_block_number(params, data_provider) } - _ => Err(Error::OutOfGas), + _ => Err(NativeError::Internal("out of gas".to_string())), }) } else { - Err(Error::OutOfGas) + Err(NativeError::Internal("out of gas".to_string())) } } fn create(&self) -> Box { @@ -79,17 +89,17 @@ impl Default for CrossChainVerify { impl CrossChainVerify { fn verify_transaction( &mut self, - params: &ActionParams, - ext: &mut Ext, - ) -> Result { + params: &VmExecParams, + data_provider: &mut DataProvider, + ) -> Result { let gas_cost = U256::from(10000); if params.gas < gas_cost { - return Err(Error::OutOfGas); + return Err(NativeError::Internal("out of gas".to_string())); } let gas_left = params.gas - gas_cost; if params.data.is_none() { - return Err(Error::Internal("no data".to_string())); + return Err(NativeError::Internal("no data".to_string())); } let data = params.data.to_owned().unwrap(); @@ -103,20 +113,20 @@ impl CrossChainVerify { let result = ethabi::decode(&tokens, &data[4..]); if result.is_err() { - return Err(Error::Internal("decode failed".to_string())); + return Err(NativeError::Internal("decode failed".to_string())); } let mut decoded = result.unwrap(); trace!("decoded = {:?}", decoded); let result = decoded.remove(0).to_address(); if result.is_none() { - return Err(Error::Internal("decode 1st param failed".to_string())); + return Err(NativeError::Internal("decode 1st param failed".to_string())); } let addr = Address::from(result.unwrap()); trace!("addr = {}", addr); let result = decoded.remove(0).to_fixed_bytes(); if result.is_none() { - return Err(Error::Internal("decode 2nd param failed".to_string())); + return Err(NativeError::Internal("decode 2nd param failed".to_string())); } let hasher = result.unwrap()[..4].iter().take(4).enumerate().fold( [0u8; 4], @@ -128,13 +138,13 @@ impl CrossChainVerify { trace!("hasher = {:?}", hasher); let result = decoded.remove(0).to_uint(); if result.is_none() { - return Err(Error::Internal("decode 3rd param failed".to_string())); + return Err(NativeError::Internal("decode 3rd param failed".to_string())); } let nonce = U256::from_big_endian(&result.unwrap()).low_u64(); trace!("nonce = {}", nonce); let result = decoded.remove(0).to_bytes(); if result.is_none() { - return Err(Error::Internal("decode 4th param failed".to_string())); + return Err(NativeError::Internal("decode 4th param failed".to_string())); } let proof_data = result.unwrap(); trace!("data = {:?}", proof_data); @@ -143,31 +153,33 @@ impl CrossChainVerify { let relay_info = proof.extract_relay_info(); if relay_info.is_none() { - return Err(Error::Internal("extract relay info failed".to_string())); + return Err(NativeError::Internal( + "extract relay info failed".to_string(), + )); } let relay_info = relay_info.unwrap(); trace!("relay_info {:?}", proof_data); - let ret = ChainManagement::ext_chain_id(ext, &gas_left, ¶ms.sender); + let ret = ChainManagement::ext_chain_id(data_provider, &gas_left, ¶ms.sender); if ret.is_none() { - return Err(Error::Internal("get chain id failed".to_owned())); + return Err(NativeError::Internal("get chain id failed".to_owned())); } let (gas_left, chain_id) = ret.unwrap(); let ret = ChainManagement::ext_authorities( - ext, + data_provider, &gas_left, ¶ms.sender, relay_info.from_chain_id, ); if ret.is_none() { - return Err(Error::Internal("get authorities failed".to_owned())); + return Err(NativeError::Internal("get authorities failed".to_owned())); } let (gas_left, authorities) = ret.unwrap(); let ret = proof.extract_crosschain_data(addr, hasher, nonce, chain_id, &authorities[..]); if ret.is_none() { - return Err(Error::Internal( + return Err(NativeError::Internal( "extract_crosschain_data failed".to_string(), )); } @@ -181,124 +193,132 @@ impl CrossChainVerify { trace!("encoded {:?}", result); self.output = result; - - Ok(GasLeft::NeedsReturn { - gas_left, - data: ReturnData::new(self.output.clone(), 0, self.output.len()), - apply_state: true, - }) + Ok(InterpreterResult::Normal( + self.output.clone(), + gas_left.low_u64(), + vec![], + )) } - fn verify_state(&mut self, params: &ActionParams, ext: &mut Ext) -> Result { - let gas_cost = U256::from(10000); - if params.gas < gas_cost { - return Err(Error::OutOfGas); - } - let gas_left = params.gas - gas_cost; - - if params.data.is_none() { - return Err(Error::Internal("no data".to_string())); - } - - let data = params.data.to_owned().unwrap(); - trace!("data = {:?}", data); - let tokens = vec![ - ethabi::ParamType::Uint(32), - ethabi::ParamType::Uint(64), - ethabi::ParamType::Bytes, - ]; - - let result = ethabi::decode(&tokens, &data[4..]); - if result.is_err() { - return Err(Error::Internal("decode failed".to_string())); - } - let mut decoded = result.unwrap(); - trace!("decoded = {:?}", decoded); - - let result = decoded.remove(0).to_uint(); - if result.is_none() { - return Err(Error::Internal("decode 1th param failed".to_string())); - } - let chain_id = U256::from_big_endian(&result.unwrap()); - trace!("chain_id = {}", chain_id); - - let result = decoded.remove(0).to_uint(); - if result.is_none() { - return Err(Error::Internal("decode 2nd param failed".to_string())); - } - let block_number = U256::from_big_endian(&result.unwrap()).low_u64(); - trace!("block_number = {}", block_number); - - let result = self - .state_roots - .get_array(&chain_id) - .unwrap() - .get(ext, block_number); - if result.is_err() { - return Err(Error::Internal("get state root failed".to_string())); - } - let result1 = self - .state_roots - .get_array(&chain_id) - .unwrap() - .get(ext, block_number + 1); - if result1.is_err() { - return Err(Error::Internal("get next state root failed".to_string())); - } - let state_root: H256 = result.unwrap().into(); - trace!("state_root = {:?}", state_root); - let next_state_root: H256 = result1.unwrap().into(); - trace!("next_state_root = {:?}", next_state_root); - if state_root == H256::zero() || next_state_root == H256::zero() { - return Err(Error::Internal("state root have not confirmed".to_string())); - } - - let result = decoded.remove(0).to_bytes(); - if result.is_none() { - return Err(Error::Internal("decode 3rd param failed".to_string())); - } - let state_proof_bytes = result.unwrap(); - trace!("state_proof_bytes = {:?}", state_proof_bytes); - - let state_proof = StateProof::from_bytes(&state_proof_bytes); - - let maybe_val = state_proof.verify(state_root); - if maybe_val.is_none() { - return Err(Error::Internal("state proof verify failed".to_string())); - } - let val = maybe_val.unwrap(); - trace!("val = {:?}", val); - - let tokens = vec![ - ethabi::Token::Address((*state_proof.address()).into()), - ethabi::Token::Uint((*state_proof.key()).into()), - ethabi::Token::Uint(val.into()), - ]; - let result = ethabi::encode(&tokens); - trace!("encoded {:?}", result); - - self.output = result; - - Ok(GasLeft::NeedsReturn { - gas_left, - data: ReturnData::new(self.output.clone(), 0, self.output.len()), - apply_state: true, - }) + fn verify_state( + &mut self, + _params: &VmExecParams, + _data_provider: &mut DataProvider, + ) -> Result { + unimplemented!() + // let gas_cost = U256::from(10000); + // if params.gas < gas_cost { + // return Err(NativeError::Internal("out of gas".to_string())); + // } + // let gas_left = params.gas - gas_cost; + + // if params.data.is_none() { + // return Err(NativeError::Internal("no data".to_string())); + // } + + // let data = params.data.to_owned().unwrap(); + // trace!("data = {:?}", data); + // let tokens = vec![ + // ethabi::ParamType::Uint(32), + // ethabi::ParamType::Uint(64), + // ethabi::ParamType::Bytes, + // ]; + + // let result = ethabi::decode(&tokens, &data[4..]); + // if result.is_err() { + // return Err(NativeError::Internal("decode failed".to_string())); + // } + // let mut decoded = result.unwrap(); + // trace!("decoded = {:?}", decoded); + + // let result = decoded.remove(0).to_uint(); + // if result.is_none() { + // return Err(NativeError::Internal("decode 1th param failed".to_string())); + // } + // let chain_id = U256::from_big_endian(&result.unwrap()); + // trace!("chain_id = {}", chain_id); + + // let result = decoded.remove(0).to_uint(); + // if result.is_none() { + // return Err(NativeError::Internal("decode 2nd param failed".to_string())); + // } + // let block_number = U256::from_big_endian(&result.unwrap()).low_u64(); + // trace!("block_number = {}", block_number); + + // let result = self.state_roots.get_array(&chain_id).unwrap().get( + // data_provider, + // ¶ms.code_address.unwrap(), + // block_number, + // ); + // if result.is_err() { + // return Err(NativeError::Internal("get state root failed".to_string())); + // } + // let result1 = self.state_roots.get_array(&chain_id).unwrap().get( + // data_provider, + // ¶ms.code_address.unwrap(), + // block_number + 1, + // ); + // if result1.is_err() { + // return Err(NativeError::Internal( + // "get next state root failed".to_string(), + // )); + // } + // let state_root: H256 = result.unwrap().into(); + // trace!("state_root = {:?}", state_root); + // let next_state_root: H256 = result1.unwrap().into(); + // trace!("next_state_root = {:?}", next_state_root); + // if state_root == H256::zero() || next_state_root == H256::zero() { + // return Err(NativeError::Internal( + // "state root have not confirmed".to_string(), + // )); + // } + + // let result = decoded.remove(0).to_bytes(); + // if result.is_none() { + // return Err(NativeError::Internal("decode 3rd param failed".to_string())); + // } + // let state_proof_bytes = result.unwrap(); + // trace!("state_proof_bytes = {:?}", state_proof_bytes); + + // let state_proof = StateProof::from_bytes(&state_proof_bytes); + // let maybe_val = state_proof.verify(state_root); + // if maybe_val.is_none() { + // return Err(NativeError::Internal( + // "state proof verify failed".to_string(), + // )); + // } + // let val = maybe_val.unwrap(); + // trace!("val = {:?}", val); + + // let tokens = vec![ + // ethabi::Token::Address((*state_proof.address()).into()), + // ethabi::Token::Uint((*state_proof.key()).into()), + // ethabi::Token::Uint(val.into()), + // ]; + // let result = ethabi::encode(&tokens); + // trace!("encoded {:?}", result); + + // self.output = result; + // Ok(InterpreterResult::Normal( + // self.output.clone(), + // gas_left.low_u64(), + // vec![], + // )) } fn verify_block_header( &mut self, - params: &ActionParams, - ext: &mut Ext, - ) -> Result { + params: &VmExecParams, + data_provider: &mut DataProvider, + ) -> Result { let gas_cost = U256::from(10000); if params.gas < gas_cost { - return Err(Error::OutOfGas); + return Err(NativeError::Internal("out of gas".to_string())); } let mut gas_left = params.gas - gas_cost; if params.data.is_none() { - return Err(Error::Internal("no data".to_string())); + return Err(NativeError::Internal("no data".to_string())); } let data = params.data.to_owned().unwrap(); @@ -307,26 +327,30 @@ impl CrossChainVerify { let result = ethabi::decode(&tokens, &data[4..]); if result.is_err() { - return Err(Error::Internal("decode failed".to_string())); + return Err(NativeError::Internal("decode failed".to_string())); } let mut decoded = result.unwrap(); trace!("decoded = {:?}", decoded); let result = decoded.remove(0).to_uint(); if result.is_none() { - return Err(Error::Internal("decode 1th param failed".to_string())); + return Err(NativeError::Internal("decode 1th param failed".to_string())); } let chain_id = U256::from_big_endian(&result.unwrap()); trace!("chain_id = {}", chain_id); let result = decoded.remove(0).to_bytes(); if result.is_none() { - return Err(Error::Internal("decode 2nd param failed".to_string())); + return Err(NativeError::Internal("decode 2nd param failed".to_string())); } let block_header_curr_bytes = result.unwrap(); trace!("data = {:?}", block_header_curr_bytes); let block_header_curr = Header::from_bytes(&block_header_curr_bytes); - let block_header_prev_bytes: Vec = self.block_headers.get_bytes(ext, &chain_id)?; + let block_header_prev_bytes: Vec = self.block_headers.get_bytes( + data_provider, + ¶ms.code_address.unwrap(), + &chain_id, + )?; let verify_result = if block_header_prev_bytes.is_empty() { trace!("sync first block header"); @@ -334,9 +358,14 @@ impl CrossChainVerify { } else { let block_header_prev = Header::from_bytes(&block_header_prev_bytes); - let ret = ChainManagement::ext_authorities(ext, &gas_left, ¶ms.sender, chain_id); + let ret = ChainManagement::ext_authorities( + data_provider, + &gas_left, + ¶ms.sender, + chain_id, + ); if ret.is_none() { - return Err(Error::Internal("get authorities failed".to_owned())); + return Err(NativeError::Internal("get authorities failed".to_owned())); } let (gas_left_new, authorities) = ret.unwrap(); gas_left = gas_left_new; @@ -346,15 +375,20 @@ impl CrossChainVerify { if verify_result { trace!("store the {} block header", block_header_curr.number()); - self.block_headers - .set_bytes(ext, &chain_id, &block_header_curr_bytes)?; + self.block_headers.set_bytes( + data_provider, + ¶ms.code_address.unwrap(), + &chain_id, + &block_header_curr_bytes, + )?; trace!( "store the {} block state root {}", block_header_curr.number(), block_header_curr.state_root() ); self.state_roots.get_array(&chain_id).unwrap().set( - ext, + data_provider, + ¶ms.code_address.unwrap(), block_header_curr.number(), &U256::from(block_header_curr.state_root()), )?; @@ -365,27 +399,26 @@ impl CrossChainVerify { trace!("encoded {:?}", result); self.output = result; - - Ok(GasLeft::NeedsReturn { - gas_left, - data: ReturnData::new(self.output.clone(), 0, self.output.len()), - apply_state: true, - }) + Ok(InterpreterResult::Normal( + self.output.clone(), + gas_left.low_u64(), + vec![], + )) } fn get_expected_block_number( &mut self, - params: &ActionParams, - ext: &mut Ext, - ) -> Result { + params: &VmExecParams, + data_provider: &mut DataProvider, + ) -> Result { let gas_cost = U256::from(10000); if params.gas < gas_cost { - return Err(Error::OutOfGas); + return Err(NativeError::Internal("out of gas".to_string())); } let gas_left = params.gas - gas_cost; if params.data.is_none() { - return Err(Error::Internal("no data".to_string())); + return Err(NativeError::Internal("no data".to_string())); } let data = params.data.to_owned().unwrap(); @@ -394,19 +427,23 @@ impl CrossChainVerify { let result = ethabi::decode(&tokens, &data[4..]); if result.is_err() { - return Err(Error::Internal("decode failed".to_string())); + return Err(NativeError::Internal("decode failed".to_string())); } let mut decoded = result.unwrap(); trace!("decoded = {:?}", decoded); let result = decoded.remove(0).to_uint(); if result.is_none() { - return Err(Error::Internal("decode 1th param failed".to_string())); + return Err(NativeError::Internal("decode 1th param failed".to_string())); } let chain_id = U256::from_big_endian(&result.unwrap()); trace!("chain_id = {}", chain_id); - let block_header_bytes: Vec = self.block_headers.get_bytes(ext, &chain_id)?; + let block_header_bytes: Vec = self.block_headers.get_bytes( + data_provider, + ¶ms.code_address.unwrap(), + &chain_id, + )?; let block_number = if block_header_bytes.is_empty() { 0 @@ -421,11 +458,10 @@ impl CrossChainVerify { trace!("encoded {:?}", result); self.output = result; - - Ok(GasLeft::NeedsReturn { - gas_left, - data: ReturnData::new(self.output.clone(), 0, self.output.len()), - apply_state: true, - }) + Ok(InterpreterResult::Normal( + self.output.clone(), + gas_left.low_u64(), + vec![], + )) } } diff --git a/cita-executor/core/src/contracts/native/factory.rs b/cita-executor/core/src/contracts/native/factory.rs index e41e5abb0..9dc28c588 100644 --- a/cita-executor/core/src/contracts/native/factory.rs +++ b/cita-executor/core/src/contracts/native/factory.rs @@ -1,28 +1,29 @@ -// CITA -// Copyright 2016-2018 Cryptape Technologies LLC. +// Copyright Cryptape Technologies LLC. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. -// This program is free software: you can redistribute it -// and/or modify it under the terms of the GNU 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 General Public License for more details. - -// You should have received a copy of the GNU General Public License -// along with this program. If not, see . +use std::collections::HashMap; +use std::str::FromStr; +use crate::cita_executive::VmExecParams; +use crate::types::context::Context; +use crate::types::errors::NativeError; use crate::types::reserved_addresses; + use cita_types::Address; -use evm::action_params::ActionParams; -use evm::{self, Ext, GasLeft}; -use std::collections::HashMap; -use std::str::FromStr; +use cita_vm::evm::DataProvider; +use cita_vm::evm::InterpreterResult; -//////////////////////////////////////////////////////////////////////////////// pub type Signature = u32; pub trait ContractClone { fn clone_box(&self) -> Box; @@ -46,11 +47,16 @@ impl Clone for Box { // Contract pub trait Contract: Sync + Send + ContractClone { - fn exec(&mut self, params: &ActionParams, ext: &mut Ext) -> Result; + fn exec( + &mut self, + params: &VmExecParams, + context: &Context, + data_provider: &mut DataProvider, + ) -> Result; + fn create(&self) -> Box; } -//////////////////////////////////////////////////////////////////////////////// #[derive(Clone)] pub struct Factory { contracts: HashMap>, @@ -87,7 +93,7 @@ impl Default for Factory { } #[cfg(test)] { - use super::storage::SimpleStorage; + use super::simple_storage::SimpleStorage; factory.register( Address::from_str(reserved_addresses::NATIVE_SIMPLE_STORAGE).unwrap(), Box::new(SimpleStorage::default()), diff --git a/cita-executor/core/src/contracts/native/mod.rs b/cita-executor/core/src/contracts/native/mod.rs index a547d070b..480a6df68 100644 --- a/cita-executor/core/src/contracts/native/mod.rs +++ b/cita-executor/core/src/contracts/native/mod.rs @@ -1,23 +1,23 @@ -// CITA -// Copyright 2016-2018 Cryptape Technologies LLC. - -// This program is free software: you can redistribute it -// and/or modify it under the terms of the GNU 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 General Public License for more details. - -// You should have received a copy of the GNU General Public License -// along with this program. If not, see . +// Copyright Cryptape Technologies LLC. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. mod crosschain_verify; pub mod factory; #[cfg(test)] -mod storage; +mod simple_storage; + #[cfg(feature = "privatetx")] mod zk_privacy; + +pub use factory::Contract; diff --git a/cita-executor/core/src/contracts/native/simple_storage.rs b/cita-executor/core/src/contracts/native/simple_storage.rs new file mode 100644 index 000000000..20d71b90f --- /dev/null +++ b/cita-executor/core/src/contracts/native/simple_storage.rs @@ -0,0 +1,295 @@ +// Copyright Cryptape Technologies LLC. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +use self::bincode::internal::serialize_into; +use self::bincode::Infinite; +use super::factory::Contract; + +use bincode; +use cita_types::{H256, U256}; +use std::io::Write; + +use crate::cita_executive::VmExecParams; +use crate::context::Context; +use crate::contracts::tools::method as method_tools; +use crate::storage::{Array, Map, Scalar}; +use crate::types::errors::NativeError; + +use byteorder::BigEndian; +use cita_vm::evm::DataProvider; +use cita_vm::evm::InterpreterResult; + +#[derive(Clone)] +pub struct SimpleStorage { + uint_value: Scalar, + string_value: Scalar, + array_value: Array, + map_value: Map, + output: Vec, +} + +impl Contract for SimpleStorage { + fn exec( + &mut self, + params: &VmExecParams, + _context: &Context, + data_provider: &mut DataProvider, + ) -> Result { + if let Some(ref data) = params.data { + method_tools::extract_to_u32(&data[..]).and_then(|signature| match signature { + 0 => self.init(params, data_provider), + 0xaa91543e => self.uint_set(params, data_provider), + 0x832b4580 => self.uint_get(params, data_provider), + 0xc9615770 => self.string_set(params, data_provider), + 0xe3135d14 => self.string_get(params, data_provider), + 0x118b229c => self.array_set(params, data_provider), + 0x180a4bbf => self.array_get(params, data_provider), + 0xaaf27175 => self.map_set(params, data_provider), + 0xc567dff6 => self.map_get(params, data_provider), + _ => Err(NativeError::Internal("out of gas".to_string())), + }) + } else { + Err(NativeError::Internal("out of gas".to_string())) + } + } + fn create(&self) -> Box { + Box::new(SimpleStorage::default()) + } +} + +impl Default for SimpleStorage { + fn default() -> Self { + SimpleStorage { + output: Vec::new(), + uint_value: Scalar::new(H256::from(0)), + string_value: Scalar::new(H256::from(1)), + array_value: Array::new(H256::from(2)), + map_value: Map::new(H256::from(3)), + } + } +} + +impl SimpleStorage { + fn init( + &mut self, + _params: &VmExecParams, + _ext: &mut DataProvider, + ) -> Result { + Ok(InterpreterResult::Normal(vec![], 100, vec![])) + } + + // 1) uint + fn uint_set( + &mut self, + params: &VmExecParams, + data_provider: &mut DataProvider, + ) -> Result { + let value = U256::from( + params + .data + .to_owned() + .expect("invalid data") + .get(4..36) + .expect("no enough data"), + ); + self.uint_value + .set(data_provider, ¶ms.code_address.unwrap(), value)?; + Ok(InterpreterResult::Normal(vec![], 100, vec![])) + } + + fn uint_get( + &mut self, + params: &VmExecParams, + data_provider: &mut DataProvider, + ) -> Result { + self.output.resize(32, 0); + self.uint_value + .get(data_provider, ¶ms.code_address.unwrap())? + .to_big_endian(self.output.as_mut_slice()); + Ok(InterpreterResult::Normal(self.output.clone(), 100, vec![])) + } + + // 2) string + fn string_set( + &mut self, + params: &VmExecParams, + data_provider: &mut DataProvider, + ) -> Result { + let data = params.data.to_owned().expect("invalid data"); + let index = U256::from(data.get(4..36).expect("no enough data")).low_u64() as usize + 4; + let length = + U256::from(data.get(index..(index + 32)).expect("no enough data")).low_u64() as usize; + let index = index + 32; + let value = String::from_utf8(Vec::from( + data.get(index..index + length).expect("no enough data"), + )) + .unwrap(); + + self.string_value + .set_bytes(data_provider, ¶ms.code_address.unwrap(), &value)?; + Ok(InterpreterResult::Normal(vec![], 100, vec![])) + } + + fn string_get( + &mut self, + params: &VmExecParams, + data_provider: &mut DataProvider, + ) -> Result { + self.output.resize(0, 0); + let str = self + .string_value + .get_bytes::(data_provider, ¶ms.code_address.unwrap())?; + for i in U256::from(32).0.iter().rev() { + serialize_into::<_, _, _, BigEndian>(&mut self.output, &i, Infinite) + .expect("failed to serialize u64"); + } + for i in U256::from(str.len()).0.iter().rev() { + serialize_into::<_, _, _, BigEndian>(&mut self.output, &i, Infinite) + .expect("failed to serialize u64"); + } + + for i in str.bytes() { + serialize_into::<_, _, _, BigEndian>(&mut self.output, &i, Infinite) + .expect("failed to serialize "); + } + self.output + .write(&vec![0u8; 32 - str.len() % 32]) + .expect("failed to write [u8]"); + Ok(InterpreterResult::Normal(self.output.clone(), 100, vec![])) + } + + // 3) array + fn array_set( + &mut self, + params: &VmExecParams, + data_provider: &mut DataProvider, + ) -> Result { + let data = params.data.to_owned().expect("invalid data"); + let mut pilot = 4; + let index = U256::from(data.get(pilot..pilot + 32).expect("no enough data")).low_u64(); + pilot += 32; + let value = U256::from(data.get(pilot..pilot + 32).expect("no enough data")); + self.array_value + .set(data_provider, ¶ms.code_address.unwrap(), index, &value)?; + Ok(InterpreterResult::Normal(vec![], 100, vec![])) + } + + fn array_get( + &mut self, + params: &VmExecParams, + data_provider: &mut DataProvider, + ) -> Result { + let data = params.data.to_owned().expect("invalid data"); + let index = U256::from(data.get(4..4 + 32).expect("no enough data")).low_u64(); + for i in self + .array_value + .get(data_provider, ¶ms.code_address.unwrap(), index)? + .0 + .iter() + .rev() + { + serialize_into::<_, _, _, BigEndian>(&mut self.output, &i, Infinite) + .expect("failed to serialize u64"); + } + Ok(InterpreterResult::Normal(self.output.clone(), 100, vec![])) + } + + // 4) map + fn map_set( + &mut self, + params: &VmExecParams, + data_provider: &mut DataProvider, + ) -> Result { + let data = params.data.to_owned().expect("invalid data"); + let mut pilot = 4; + let key = U256::from(data.get(pilot..pilot + 32).expect("no enough data")); + pilot += 32; + let value = U256::from(data.get(pilot..pilot + 32).expect("no enough data")); + self.map_value + .set(data_provider, ¶ms.code_address.unwrap(), &key, value)?; + Ok(InterpreterResult::Normal(vec![], 100, vec![])) + } + + fn map_get( + &mut self, + params: &VmExecParams, + data_provider: &mut DataProvider, + ) -> Result { + let data = params.data.to_owned().expect("invalid data"); + let key = U256::from(data.get(4..4 + 32).expect("no enough data")); + for i in self + .map_value + .get(data_provider, ¶ms.code_address.unwrap(), &key)? + .0 + .iter() + .rev() + { + serialize_into::<_, _, _, BigEndian>(&mut self.output, &i, Infinite) + .expect("failed to serialize u64"); + } + Ok(InterpreterResult::Normal(self.output.clone(), 100, vec![])) + } +} + +#[test] +fn test_native_contract() { + use super::factory::Factory; + use crate::cita_executive::VmExecParams; + use crate::context::Context; + use crate::tests::exemock::DataProviderMock; + use crate::types::reserved_addresses; + use cita_types::Address; + use std::str::FromStr; + + let factory = Factory::default(); + let context = Context::default(); + let native_addr = Address::from_str(reserved_addresses::NATIVE_SIMPLE_STORAGE).unwrap(); + let mut data_provider = DataProviderMock::default(); + let value = U256::from(0x1234); + { + let mut params = VmExecParams::default(); + params.code_address = Some(Address::from("0x4b5ae4567ad5d9fb92bc9afd6a657e6fa13a2523")); + let mut input = Vec::new(); + let index = 0xaa91543eu32; + serialize_into::<_, _, _, BigEndian>(&mut input, &index, Infinite) + .expect("failed to serialize u32"); + for i in value.0.iter().rev() { + serialize_into::<_, _, _, BigEndian>(&mut input, &i, Infinite) + .expect("failed to serialize u64"); + } + params.data = Some(input); + let mut contract = factory.new_contract(native_addr).unwrap(); + let _output = contract + .exec(¶ms, &context, &mut data_provider) + .expect("Set value failed."); + } + { + let mut input = Vec::new(); + let mut params = VmExecParams::default(); + params.code_address = Some(Address::from("0x4b5ae4567ad5d9fb92bc9afd6a657e6fa13a2523")); + let index = 0x832b4580u32; + serialize_into::<_, _, _, BigEndian>(&mut input, &index, Infinite) + .expect("failed to serialize u32"); + params.data = Some(input); + + let mut contract = factory.new_contract(native_addr).unwrap(); + match contract.exec(¶ms, &context, &mut data_provider) { + Ok(InterpreterResult::Normal(return_data, _quota_left, _logs)) => { + let real = U256::from(&*return_data); + assert!(real == value); + } + _ => assert!(false, "no output data"), + }; + } +} diff --git a/cita-executor/core/src/contracts/native/storage.rs b/cita-executor/core/src/contracts/native/storage.rs deleted file mode 100644 index 0147224c4..000000000 --- a/cita-executor/core/src/contracts/native/storage.rs +++ /dev/null @@ -1,242 +0,0 @@ -// CITA -// Copyright 2016-2018 Cryptape Technologies LLC. - -// This program is free software: you can redistribute it -// and/or modify it under the terms of the GNU 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 General Public License for more details. - -// You should have received a copy of the GNU General Public License -// along with this program. If not, see . - -use self::bincode::internal::serialize_into; -use self::bincode::Infinite; -use super::factory::{Contract, Factory}; -use crate::contracts::tools::method as method_tools; -use crate::types::reserved_addresses; -use bincode; -use cita_types::{Address, H256, U256}; -use evm; -use evm::fake_tests::FakeExt; -use std::io::Write; -use std::str::FromStr; - -use byteorder::BigEndian; -use evm::action_params::ActionParams; -use evm::ext::Ext; -use evm::return_data::{GasLeft, ReturnData}; -use evm::storage::*; - -#[derive(Clone)] -pub struct SimpleStorage { - uint_value: Scalar, - string_value: Scalar, - array_value: Array, - map_value: Map, - output: Vec, -} - -impl Contract for SimpleStorage { - fn exec(&mut self, params: &ActionParams, ext: &mut Ext) -> Result { - if let Some(ref data) = params.data { - method_tools::extract_to_u32(&data[..]).and_then(|signature| match signature { - 0 => self.init(params, ext), - 0xaa91543e => self.uint_set(params, ext), - 0x832b4580 => self.uint_get(params, ext), - 0xc9615770 => self.string_set(params, ext), - 0xe3135d14 => self.string_get(params, ext), - 0x118b229c => self.array_set(params, ext), - 0x180a4bbf => self.array_get(params, ext), - 0xaaf27175 => self.map_set(params, ext), - 0xc567dff6 => self.map_get(params, ext), - _ => Err(evm::Error::OutOfGas), - }) - } else { - Err(evm::Error::OutOfGas) - } - } - fn create(&self) -> Box { - Box::new(SimpleStorage::default()) - } -} - -impl Default for SimpleStorage { - fn default() -> Self { - SimpleStorage { - output: Vec::new(), - uint_value: Scalar::new(H256::from(0)), - string_value: Scalar::new(H256::from(1)), - array_value: Array::new(H256::from(2)), - map_value: Map::new(H256::from(3)), - } - } -} - -impl SimpleStorage { - fn init(&mut self, _params: &ActionParams, _ext: &mut Ext) -> Result { - Ok(GasLeft::Known(U256::from(100))) - } - // 1) uint - fn uint_set(&mut self, params: &ActionParams, ext: &mut Ext) -> Result { - let value = U256::from( - params - .data - .to_owned() - .expect("invalid data") - .get(4..36) - .expect("no enough data"), - ); - self.uint_value.set(ext, value)?; - Ok(GasLeft::Known(U256::from(100))) - } - fn uint_get(&mut self, _params: &ActionParams, ext: &mut Ext) -> Result { - self.output.resize(32, 0); - self.uint_value - .get(ext)? - .to_big_endian(self.output.as_mut_slice()); - Ok(GasLeft::NeedsReturn { - gas_left: U256::from(100), - data: ReturnData::new(self.output.clone(), 0, self.output.len()), - apply_state: true, - }) - } - - // 2) string - fn string_set(&mut self, params: &ActionParams, ext: &mut Ext) -> Result { - let data = params.data.to_owned().expect("invalid data"); - let index = U256::from(data.get(4..36).expect("no enough data")).low_u64() as usize + 4; - let length = - U256::from(data.get(index..(index + 32)).expect("no enough data")).low_u64() as usize; - let index = index + 32; - let value = String::from_utf8(Vec::from( - data.get(index..index + length).expect("no enough data"), - )) - .unwrap(); - - self.string_value.set_bytes(ext, &value)?; - Ok(GasLeft::Known(U256::from(100))) - } - fn string_get(&mut self, _params: &ActionParams, ext: &mut Ext) -> Result { - self.output.resize(0, 0); - let str = self.string_value.get_bytes::(ext)?; - for i in U256::from(32).0.iter().rev() { - serialize_into::<_, _, _, BigEndian>(&mut self.output, &i, Infinite) - .expect("failed to serialize u64"); - } - for i in U256::from(str.len()).0.iter().rev() { - serialize_into::<_, _, _, BigEndian>(&mut self.output, &i, Infinite) - .expect("failed to serialize u64"); - } - - for i in str.bytes() { - serialize_into::<_, _, _, BigEndian>(&mut self.output, &i, Infinite) - .expect("failed to serialize "); - } - self.output - .write(&vec![0u8; 32 - str.len() % 32]) - .expect("failed to write [u8]"); - Ok(GasLeft::NeedsReturn { - gas_left: U256::from(100), - data: ReturnData::new(self.output.clone(), 0, self.output.len()), - apply_state: true, - }) - } - - // 3) array - fn array_set(&mut self, params: &ActionParams, ext: &mut Ext) -> Result { - let data = params.data.to_owned().expect("invalid data"); - let mut pilot = 4; - let index = U256::from(data.get(pilot..pilot + 32).expect("no enough data")).low_u64(); - pilot += 32; - let value = U256::from(data.get(pilot..pilot + 32).expect("no enough data")); - self.array_value.set(ext, index, &value)?; - Ok(GasLeft::Known(U256::from(100))) - } - fn array_get(&mut self, params: &ActionParams, ext: &mut Ext) -> Result { - let data = params.data.to_owned().expect("invalid data"); - let index = U256::from(data.get(4..4 + 32).expect("no enough data")).low_u64(); - for i in self.array_value.get(ext, index)?.0.iter().rev() { - serialize_into::<_, _, _, BigEndian>(&mut self.output, &i, Infinite) - .expect("failed to serialize u64"); - } - Ok(GasLeft::NeedsReturn { - gas_left: U256::from(100), - data: ReturnData::new(self.output.clone(), 0, self.output.len()), - apply_state: true, - }) - } - - // 4) map - fn map_set(&mut self, params: &ActionParams, ext: &mut Ext) -> Result { - let data = params.data.to_owned().expect("invalid data"); - let mut pilot = 4; - let key = U256::from(data.get(pilot..pilot + 32).expect("no enough data")); - pilot += 32; - let value = U256::from(data.get(pilot..pilot + 32).expect("no enough data")); - self.map_value.set(ext, &key, value)?; - Ok(GasLeft::Known(U256::from(100))) - } - fn map_get(&mut self, params: &ActionParams, ext: &mut Ext) -> Result { - let data = params.data.to_owned().expect("invalid data"); - let key = U256::from(data.get(4..4 + 32).expect("no enough data")); - for i in self.map_value.get(ext, &key)?.0.iter().rev() { - serialize_into::<_, _, _, BigEndian>(&mut self.output, &i, Infinite) - .expect("failed to serialize u64"); - } - Ok(GasLeft::NeedsReturn { - gas_left: U256::from(100), - data: ReturnData::new(self.output.clone(), 0, self.output.len()), - apply_state: true, - }) - } -} - -#[test] -fn test_native_contract() { - let factory = Factory::default(); - let mut ext = FakeExt::new(); - let native_addr = Address::from_str(reserved_addresses::NATIVE_SIMPLE_STORAGE).unwrap(); - let value = U256::from(0x1234); - { - let mut params = ActionParams::default(); - let mut input = Vec::new(); - let index = 0xaa91543eu32; - serialize_into::<_, _, _, BigEndian>(&mut input, &index, Infinite) - .expect("failed to serialize u32"); - for i in value.0.iter().rev() { - serialize_into::<_, _, _, BigEndian>(&mut input, &i, Infinite) - .expect("failed to serialize u64"); - } - params.data = Some(input); - let mut contract = factory.new_contract(native_addr).unwrap(); - let output = contract.exec(¶ms, &mut ext).unwrap(); - println!("===={:?}", output); - } - { - let mut params = ActionParams::default(); - let mut input = Vec::new(); - let index = 0x832b4580u32; - serialize_into::<_, _, _, BigEndian>(&mut input, &index, Infinite) - .expect("failed to serialize u32"); - params.data = Some(input); - - let mut contract = factory.new_contract(native_addr).unwrap(); - match contract.exec(¶ms, &mut ext) { - Ok(GasLeft::NeedsReturn { - gas_left: _, - data: return_data, - apply_state: true, - }) => { - let real = U256::from(&*return_data); - assert!(real == value); - } - _ => assert!(false, "no output data"), - }; - } -} diff --git a/cita-executor/core/src/contracts/native/zk_privacy.rs b/cita-executor/core/src/contracts/native/zk_privacy.rs index 863c219f0..0e09525b5 100644 --- a/cita-executor/core/src/contracts/native/zk_privacy.rs +++ b/cita-executor/core/src/contracts/native/zk_privacy.rs @@ -1,27 +1,20 @@ -// CITA -// Copyright 2016-2018 Cryptape Technologies LLC. - -// This program is free software: you can redistribute it -// and/or modify it under the terms of the GNU 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 General Public License for more details. - -// You should have received a copy of the GNU General Public License -// along with this program. If not, see . - +// Copyrighttape Technologies LLC. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +use crate::contracts::{native::factory::Contract, tools::method as method_tools}; use cita_types::{H256, U256}; -use contracts::{native::factory::Contract, tools::method as method_tools}; -use evm::action_params::ActionParams; -use evm::storage::*; -use evm::{Ext, GasLeft, ReturnData}; use std::collections::VecDeque; -use std::str::FromStr; use zktx::base::*; use zktx::c2p::*; use zktx::convert::*; @@ -29,6 +22,12 @@ use zktx::incrementalmerkletree::*; use zktx::p2c::*; use zktx::pedersen::PedersenDigest; +use crate::cita_executive::{EnvInfo, VmExecParams}; +use crate::contracts::native::factory::NativeError; +use crate::storage::{Array, Map, Scalar}; +use cita_vm::evm::DataProvider; +use cita_vm::evm::InterpreterResult; + static TREE_DEPTH: usize = 60; #[derive(Clone)] // address 512 balance 512 @@ -46,18 +45,26 @@ pub struct ZkPrivacy { } impl Contract for ZkPrivacy { - fn exec(&mut self, params: &ActionParams, ext: &mut Ext) -> Result { + fn exec( + &mut self, + params: &VmExecParams, + env_info: &EnvInfo, + data_provider: &mut DataProvider, + ) -> Result + where + Self: Sized, + { if let Some(ref data) = params.data { method_tools::extract_to_u32(&data[..]).and_then(|signature| match signature { - 0 => self.init(params, ext), - 0x05e3_cb61 => self.set_balance(params, ext), - 0xd0b0_7e52 => self.get_balance(params, ext), - 0xc73b_5a8f => self.send_verify(params, ext), - 0x882b_30d2 => self.receive_verify(params, ext), - _ => Err(evm::Error::OutOfGas), + 0 => self.init(params, data_provider), + 0x05e3_cb61 => self.set_balance(params, data_provider), + 0xd0b0_7e52 => self.get_balance(params, data_provider), + 0xc73b_5a8f => self.send_verify(params, env_info, data_provider), + 0x882b_30d2 => self.receive_verify(params, data_provider), + _ => Err(NativeError::Internal("out of gas".to_string())), }) } else { - Err(evm::Error::OutOfGas) + Err(NativeError::Internal("out of gas".to_string())) } } fn create(&self) -> Box { @@ -82,20 +89,34 @@ impl Default for ZkPrivacy { } impl ZkPrivacy { - fn init(&mut self, params: &ActionParams, ext: &mut Ext) -> Result { + fn init( + &mut self, + params: &VmExecParams, + data_provider: &mut DataProvider, + ) -> Result { let gas_cost = U256::from(5000); if params.gas < gas_cost { - return Err(evm::Error::OutOfGas); + return Err(NativeError::Internal("out of gas".to_string())); } let sender = U256::from(H256::from(params.sender)); - self.admin.set(ext, sender)?; - Ok(GasLeft::Known(params.gas - gas_cost)) + self.admin + .set(data_provider, ¶ms.code_address.unwrap(), sender)?; + let gas_left = params.gas - gas_cost; + Ok(InterpreterResult::Normal( + vec![], + gas_left.low_u64(), + vec![], + )) } - fn set_balance(&mut self, params: &ActionParams, ext: &mut Ext) -> Result { + fn set_balance( + &mut self, + params: &VmExecParams, + data_provider: &mut DataProvider, + ) -> Result { let gas_cost = U256::from(10000); if params.gas < gas_cost { - return Err(evm::Error::OutOfGas); + return Err(NativeError::Internal("out of gas".to_string())); } let data = params.data.to_owned().expect("invalid data"); let mut index = 4; @@ -115,14 +136,28 @@ impl ZkPrivacy { trace!("set_balance {} {}", addr, balance); - self.balances.set_bytes(ext, &addr, &balance)?; - Ok(GasLeft::Known(params.gas - gas_cost)) + self.balances.set_bytes( + data_provider, + ¶ms.code_address.unwrap(), + &addr, + &balance, + )?; + let gas_left = params.gas - gas_cost; + Ok(InterpreterResult::Normal( + vec![], + gas_left.low_u64(), + vec![], + )) } - fn get_balance(&mut self, params: &ActionParams, ext: &mut Ext) -> Result { + fn get_balance( + &mut self, + params: &VmExecParams, + data_provider: &mut DataProvider, + ) -> Result { let gas_cost = U256::from(10000); if params.gas < gas_cost { - return Err(evm::Error::OutOfGas); + return Err(NativeError::Internal("out of gas".to_string())); } let data = params.data.to_owned().expect("invalid data"); let index = 4; @@ -134,23 +169,31 @@ impl ZkPrivacy { .unwrap(); self.output.clear(); - let balance: String = self.balances.get_bytes(ext, &addr)?; + let balance: String = + self.balances + .get_bytes(data_provider, ¶ms.code_address.unwrap(), &addr)?; for v in balance.as_bytes() { self.output.push(*v); } trace!("get_balance {} {}", addr, balance); - Ok(GasLeft::NeedsReturn { - gas_left: params.gas - gas_cost, - data: ReturnData::new(self.output.clone(), 0, self.output.len()), - apply_state: true, - }) + let gas_left = params.gas - gas_cost; + Ok(InterpreterResult::Normal( + self.output.clone(), + gas_left.low_u64(), + vec![], + )) } - fn send_verify(&mut self, params: &ActionParams, ext: &mut Ext) -> Result { + fn send_verify( + &mut self, + params: &VmExecParams, + env_info: &EnvInfo, + data_provider: &mut DataProvider, + ) -> Result { let gas_cost = U256::from(10_000_000); if params.gas < gas_cost { - return Err(evm::Error::OutOfGas); + return Err(NativeError::Internal("out of gas".to_string())); } let data = params.data.to_owned().expect("invalid data"); let mut index = 4; @@ -195,8 +238,7 @@ impl ZkPrivacy { .unwrap(); // get block_number - let block_number = U256::from(ext.env_info().number); - + let block_number = U256::from(env_info.number); trace!( "send_verify args: {} {} {} {} {} {}", addr, @@ -208,24 +250,33 @@ impl ZkPrivacy { ); // check coin is dup - let coins_len = self.coins.get_len(ext)?; + let coins_len = self + .coins + .get_len(data_provider, ¶ms.code_address.unwrap())?; for i in 0..coins_len { - let coin_added: String = *self.coins.get_bytes(ext, i)?; + let coin_added: String = + *self + .coins + .get_bytes(data_provider, ¶ms.code_address.unwrap(), i)?; if coin == coin_added { - return Err(evm::Error::Internal("dup coin".to_string())); + return Err(NativeError::Internal("dup coin".to_string())); } } // compare block number - let last_block_number = self.last_spent.get(ext, &addr)?; + let last_block_number = + self.last_spent + .get(data_provider, ¶ms.code_address.unwrap(), &addr)?; if last_block_number >= block_number { - return Err(evm::Error::Internal( + return Err(NativeError::Internal( "block_number less than last".to_string(), )); } // get balance - let balance: String = self.balances.get_bytes(ext, &addr)?; + let balance: String = + self.balances + .get_bytes(data_provider, ¶ms.code_address.unwrap(), &addr)?; trace!("balance {}", balance); let ret = p2c_verify( @@ -237,37 +288,57 @@ impl ZkPrivacy { proof, ); if ret.is_err() { - return Err(evm::Error::Internal("p2c_verify error".to_string())); + return Err(NativeError::Internal("p2c_verify error".to_string())); } if !ret.unwrap() { - return Err(evm::Error::Internal("p2c_verify failed".to_string())); + return Err(NativeError::Internal("p2c_verify failed".to_string())); } // update last spent - self.last_spent.set(ext, &addr, block_number)?; + self.last_spent.set( + data_provider, + ¶ms.code_address.unwrap(), + &addr, + block_number, + )?; // add coin - self.coins.set_bytes(ext, coins_len, &coin)?; - self.coins.set_len(ext, coins_len + 1)?; + self.coins.set_bytes( + data_provider, + ¶ms.code_address.unwrap(), + coins_len, + &coin, + )?; + self.coins + .set_len(data_provider, ¶ms.code_address.unwrap(), coins_len + 1)?; // restore merkle tree form storage let mut tree = IncrementalMerkleTree::new(TREE_DEPTH); - let left_str: String = *self.left.get_bytes(ext)?; + let left_str: String = *self + .left + .get_bytes(data_provider, ¶ms.code_address.unwrap())?; let tree_left = if left_str.is_empty() { None } else { Some(PedersenDigest(str2u644(left_str))) }; - let right_str: String = *self.right.get_bytes(ext)?; + let right_str: String = *self + .right + .get_bytes(data_provider, ¶ms.code_address.unwrap())?; let tree_right = if right_str.is_empty() { None } else { Some(PedersenDigest(str2u644(right_str))) }; let mut parents = Vec::new(); - let parents_len = self.parents.get_len(ext)?; + let parents_len = self + .parents + .get_len(data_provider, ¶ms.code_address.unwrap())?; for i in 0..parents_len { - let hash_str: String = *self.parents.get_bytes(ext, i)?; + let hash_str: String = + *self + .parents + .get_bytes(data_provider, ¶ms.code_address.unwrap(), i)?; let hash = if hash_str.is_empty() { None } else { @@ -290,13 +361,15 @@ impl ZkPrivacy { Some(hash) => u6442str(hash.0), None => "".to_string(), }; - self.left.set_bytes(ext, &left)?; + self.left + .set_bytes(data_provider, ¶ms.code_address.unwrap(), &left)?; let right = match tree.export_right() { Some(hash) => u6442str(hash.0), None => "".to_string(), }; - self.right.set_bytes(ext, &right)?; + self.right + .set_bytes(data_provider, ¶ms.code_address.unwrap(), &right)?; let mut i = 0; for opt_hash in tree.export_parents().iter() { @@ -304,14 +377,21 @@ impl ZkPrivacy { Some(ref hash) => u6442str(hash.0), None => "".to_string(), }; - self.parents.set_bytes(ext, i, &str)?; + self.parents + .set_bytes(data_provider, ¶ms.code_address.unwrap(), i, &str)?; i += 1; } - self.parents.set_len(ext, i)?; + self.parents + .set_len(data_provider, ¶ms.code_address.unwrap(), i)?; // sub balance let new_balance = ecc_sub(balance, delt_ba); - self.balances.set_bytes(ext, &addr, &new_balance)?; + self.balances.set_bytes( + data_provider, + ¶ms.code_address.unwrap(), + &addr, + &new_balance, + )?; let mut data = Vec::new(); data.extend_from_slice(coin.as_bytes()); @@ -326,27 +406,24 @@ impl ZkPrivacy { data.push(0u8); } } - let _ = ext.log( - vec![H256::from_str( - "c73b5a8f31a1a078a14123cc93687f4a59389c76caf88d5d2154d3f3ce25ff49", - ) - .unwrap()], - &data, - ); trace!("send_verify OK data len {}", data.len()); - - Ok(GasLeft::Known(params.gas - gas_cost)) + let gas_left = params.gas - gas_cost; + Ok(InterpreterResult::Normal( + vec![], + gas_left.low_u64(), + vec![], + )) } fn receive_verify( &mut self, - params: &ActionParams, - ext: &mut Ext, - ) -> Result { + params: &VmExecParams, + data_provider: &mut DataProvider, + ) -> Result { let gas_cost = U256::from(1_000_000); if params.gas < gas_cost { - return Err(evm::Error::OutOfGas); + return Err(NativeError::Internal("out of gas".to_string())); } let data = params.data.to_owned().expect("invalid data"); let mut index = 4; @@ -400,11 +477,16 @@ impl ZkPrivacy { ); // check nullifier is dup - let nullifier_set_len = self.nullifier_set.get_len(ext)?; + let nullifier_set_len = self + .nullifier_set + .get_len(data_provider, ¶ms.code_address.unwrap())?; for i in 0..nullifier_set_len { - let nullifier_in_set: String = *self.nullifier_set.get_bytes(ext, i)?; + let nullifier_in_set: String = + *self + .nullifier_set + .get_bytes(data_provider, ¶ms.code_address.unwrap(), i)?; if nullifier == nullifier_in_set { - return Err(evm::Error::Internal("dup nullifier".to_string())); + return Err(NativeError::Internal("dup nullifier".to_string())); } } @@ -412,22 +494,31 @@ impl ZkPrivacy { // str2u644(root.clone()) == tree.root() // restore merkle tree form storage let mut tree = IncrementalMerkleTree::new(TREE_DEPTH); - let left_str: String = *self.left.get_bytes(ext)?; + let left_str: String = *self + .left + .get_bytes(data_provider, ¶ms.code_address.unwrap())?; let tree_left = if left_str.is_empty() { None } else { Some(PedersenDigest(str2u644(left_str))) }; - let right_str: String = *self.right.get_bytes(ext)?; + let right_str: String = *self + .right + .get_bytes(data_provider, ¶ms.code_address.unwrap())?; let tree_right = if right_str.is_empty() { None } else { Some(PedersenDigest(str2u644(right_str))) }; let mut parents = Vec::new(); - let parents_len = self.parents.get_len(ext)?; + let parents_len = self + .parents + .get_len(data_provider, ¶ms.code_address.unwrap())?; for i in 0..parents_len { - let hash_str: String = *self.parents.get_bytes(ext, i)?; + let hash_str: String = + *self + .parents + .get_bytes(data_provider, ¶ms.code_address.unwrap(), i)?; let hash = if hash_str.is_empty() { None } else { @@ -437,29 +528,49 @@ impl ZkPrivacy { } tree.restore(tree_left, tree_right, parents); if str2u644(root.clone()) != tree.root().0 { - return Err(evm::Error::Internal("invalid root hash".to_string())); + return Err(NativeError::Internal("invalid root hash".to_string())); } let ret = c2p_verify(nullifier.clone(), root, delt_ba.clone(), proof); if ret.is_err() { - return Err(evm::Error::Internal("c2p_verify error".to_string())); + return Err(NativeError::Internal("c2p_verify error".to_string())); } if !ret.unwrap() { - return Err(evm::Error::Internal("c2p_verify failed".to_string())); + return Err(NativeError::Internal("c2p_verify failed".to_string())); } // add nullifier into nullifier_set - self.nullifier_set - .set_bytes(ext, nullifier_set_len, &nullifier)?; - self.nullifier_set.set_len(ext, nullifier_set_len + 1)?; + self.nullifier_set.set_bytes( + data_provider, + ¶ms.code_address.unwrap(), + nullifier_set_len, + &nullifier, + )?; + self.nullifier_set.set_len( + data_provider, + ¶ms.code_address.unwrap(), + nullifier_set_len + 1, + )?; // add balance - let balance: String = self.balances.get_bytes(ext, &addr)?; + let balance: String = + self.balances + .get_bytes(data_provider, ¶ms.code_address.unwrap(), &addr)?; trace!("balance {}", balance); let new_balance = ecc_add(balance, delt_ba); - self.balances.set_bytes(ext, &addr, &new_balance)?; + self.balances.set_bytes( + data_provider, + ¶ms.code_address.unwrap(), + &addr, + &new_balance, + )?; trace!("receive_verify OK"); - Ok(GasLeft::Known(params.gas - gas_cost)) + let gas_left = params.gas - gas_cost; + Ok(InterpreterResult::Normal( + vec![], + gas_left.low_u64(), + vec![], + )) } } diff --git a/cita-executor/core/src/contracts/solc/admin.rs b/cita-executor/core/src/contracts/solc/admin.rs index 49b1348ec..19f1b319e 100644 --- a/cita-executor/core/src/contracts/solc/admin.rs +++ b/cita-executor/core/src/contracts/solc/admin.rs @@ -1,26 +1,23 @@ -// CITA -// Copyright 2016-2019 Cryptape Technologies LLC. - -// This program is free software: you can redistribute it -// and/or modify it under the terms of the GNU 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 General Public License for more details. - -// You should have received a copy of the GNU General Public License -// along with this program. If not, see . +// Copyright Cryptape Technologies LLC. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. //! Get Admin Info use super::ContractCallExt; use crate::contracts::tools::{decode as decode_tools, method as method_tools}; use crate::libexecutor::executor::Executor; -use crate::types::ids::BlockId; +use crate::types::block_number::BlockTag; use crate::types::reserved_addresses; use cita_types::Address; use std::str::FromStr; @@ -40,9 +37,9 @@ impl<'a> Admin<'a> { } /// Get Admin - pub fn get_admin(&self, block_id: BlockId) -> Option
{ + pub fn get_admin(&self, block_tag: BlockTag) -> Option
{ self.executor - .call_method(&*CONTRACT_ADDRESS, &*GET_ADMIN.as_slice(), None, block_id) + .call_method(&*CONTRACT_ADDRESS, &*GET_ADMIN.as_slice(), None, block_tag) .ok() .and_then(|output| decode_tools::to_address(&output)) } @@ -52,14 +49,14 @@ impl<'a> Admin<'a> { mod tests { use super::Admin; use crate::tests::helpers::init_executor; - use crate::types::ids::BlockId; + use crate::types::block_number::{BlockTag, Tag}; use cita_types::Address; #[test] fn test_admin() { let executor = init_executor(); let admin = Admin::new(&executor); - let addr = admin.get_admin(BlockId::Pending).unwrap(); + let addr = admin.get_admin(BlockTag::Tag(Tag::Pending)).unwrap(); assert_eq!( addr, Address::from("0x4b5ae4567ad5d9fb92bc9afd6a657e6fa13a2523") diff --git a/cita-executor/core/src/contracts/solc/chain_manager.rs b/cita-executor/core/src/contracts/solc/chain_manager.rs index 37d75ee8b..d0f6e0288 100644 --- a/cita-executor/core/src/contracts/solc/chain_manager.rs +++ b/cita-executor/core/src/contracts/solc/chain_manager.rs @@ -1,28 +1,26 @@ -// CITA -// Copyright 2016-2018 Cryptape Technologies LLC. - -// This program is free software: you can redistribute it -// and/or modify it under the terms of the GNU 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 General Public License for more details. - -// You should have received a copy of the GNU General Public License -// along with this program. If not, see . +// Copyright Cryptape Technologies LLC. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. //! Chain manager. +use std::str::FromStr; + use crate::contracts::tools::{decode as decode_tools, method as method_tools}; use crate::types::reserved_addresses; + use cita_types::{Address, H160, H256, U256}; -use evm::call_type::CallType; -use evm::ext::{Ext, MessageCallResult}; -use std::str::FromStr; +use cita_vm::evm::{DataProvider, InterpreterParams, InterpreterResult, OpCode}; const CHAIN_ID: &[u8] = &*b"getChainId()"; const AUTHORITIES: &[u8] = &*b"getAuthorities(uint256)"; @@ -36,63 +34,46 @@ lazy_static! { pub struct ChainManagement; impl ChainManagement { - pub fn ext_chain_id(ext: &mut Ext, gas: &U256, sender: &Address) -> Option<(U256, U256)> { - trace!("call system contract ChainManagement.ext_chain_id()"); - let contract = &*CONTRACT_ADDRESS; - let tx_data = CHAIN_ID_ENCODED.to_vec(); - let data = &tx_data.as_slice(); - let mut output = Vec::::new(); - match ext.call( - gas, - sender, - contract, - None, - data, - contract, - &mut output, - CallType::Call, - ) { - MessageCallResult::Success(gas_left, return_data) => { - decode_tools::to_u256(&*return_data).map(|x| (gas_left, x)) + pub fn ext_chain_id( + data_provider: &mut DataProvider, + gas: &U256, + sender: &Address, + ) -> Option<(U256, U256)> { + trace!("Call chainManagement ext_chain_id()"); + let mut params = InterpreterParams::default(); + params.receiver = *CONTRACT_ADDRESS; + params.sender = *sender; + params.gas_limit = gas.low_u64(); + params.input = CHAIN_ID_ENCODED.to_vec(); + + match data_provider.call(OpCode::CALL, params) { + Ok(InterpreterResult::Normal(output, gas_left, _)) => { + decode_tools::to_u256(&output).map(|x| (U256::from(gas_left), x)) } - MessageCallResult::Reverted(..) | MessageCallResult::Failed => None, + _ => None, } } pub fn ext_authorities( - ext: &mut Ext, + data_provider: &mut DataProvider, gas: &U256, sender: &Address, chain_id: U256, ) -> Option<(U256, Vec
)> { - trace!( - "call system contract ChainManagement.ext_authorities({})", - chain_id - ); - let contract = &*CONTRACT_ADDRESS; + trace!("call chainManagement ext_authorities({})", chain_id); + let mut params = InterpreterParams::default(); + params.receiver = *CONTRACT_ADDRESS; + params.sender = *sender; + params.gas_limit = gas.low_u64(); let mut tx_data = AUTHORITIES_ENCODED.to_vec(); - let param = H256::from(chain_id); - tx_data.extend(param.to_vec()); - let data = &tx_data.as_slice(); - let mut output = Vec::::new(); - match ext.call( - gas, - sender, - contract, - None, - data, - contract, - &mut output, - CallType::Call, - ) { - MessageCallResult::Success(gas_left, return_data) => { - trace!( - "call system contract ChainManagement.ext_authorities() return [{:?}]", - return_data - ); - decode_tools::to_address_vec(&*return_data).map(|addrs| (gas_left, addrs)) + tx_data.extend(H256::from(chain_id).to_vec()); + + match data_provider.call(OpCode::CALL, params) { + Ok(InterpreterResult::Normal(output, gas_left, _logs)) => { + trace!("chainManagement ext_authorities() return [{:?}]", output); + decode_tools::to_address_vec(&output).map(|addrs| (U256::from(gas_left), addrs)) } - MessageCallResult::Reverted(..) | MessageCallResult::Failed => None, + _ => None, } } } diff --git a/cita-executor/core/src/contracts/solc/emergency_intervention.rs b/cita-executor/core/src/contracts/solc/emergency_intervention.rs index 211a5c4dc..d189d8bc7 100644 --- a/cita-executor/core/src/contracts/solc/emergency_intervention.rs +++ b/cita-executor/core/src/contracts/solc/emergency_intervention.rs @@ -1,19 +1,16 @@ -// CITA -// Copyright 2016-2019 Cryptape Technologies LLC. - -// This program is free software: you can redistribute it -// and/or modify it under the terms of the GNU 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 General Public License for more details. - -// You should have received a copy of the GNU General Public License -// along with this program. If not, see . +// Copyrighttape Technologies LLC. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. //! Emergency Intervention @@ -22,9 +19,9 @@ use std::str::FromStr; use super::ContractCallExt; use crate::contracts::tools::method as method_tools; use crate::libexecutor::executor::Executor; - -use crate::types::ids::BlockId; +use crate::types::block_number::BlockTag; use crate::types::reserved_addresses; + use cita_types::Address; use ethabi::{decode, ParamType}; @@ -44,9 +41,9 @@ impl<'a> EmergencyIntervention<'a> { EmergencyIntervention { executor } } - pub fn state(&self, block_id: BlockId) -> Option { + pub fn state(&self, block_tag: BlockTag) -> Option { self.executor - .call_method(&*CONTRACT_ADDRESS, &*STATE_HASH.as_slice(), None, block_id) + .call_method(&*CONTRACT_ADDRESS, &*STATE_HASH.as_slice(), None, block_tag) .and_then(|output| { decode(&[ParamType::Bool], &output).map_err(|_| "decode value error".to_string()) }) @@ -64,13 +61,15 @@ impl<'a> EmergencyIntervention<'a> { mod tests { use super::EmergencyIntervention; use crate::tests::helpers::init_executor; - use crate::types::ids::BlockId; + use crate::types::block_number::{BlockTag, Tag}; #[test] fn test_state() { let executor = init_executor(); let emergency_intervention = EmergencyIntervention::new(&executor); - let state = emergency_intervention.state(BlockId::Pending).unwrap(); + let state = emergency_intervention + .state(BlockTag::Tag(Tag::Pending)) + .unwrap(); assert_eq!(state, false); } } diff --git a/cita-executor/core/src/contracts/solc/mod.rs b/cita-executor/core/src/contracts/solc/mod.rs index f6a4fae51..a8eaf6e41 100644 --- a/cita-executor/core/src/contracts/solc/mod.rs +++ b/cita-executor/core/src/contracts/solc/mod.rs @@ -1,19 +1,16 @@ -// CITA -// Copyright 2016-2019 Cryptape Technologies LLC. - -// This program is free software: you can redistribute it -// and/or modify it under the terms of the GNU 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 General Public License for more details. - -// You should have received a copy of the GNU General Public License -// along with this program. If not, see . +// Copyright Cryptape Technologies LLC. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. //! System contracts. @@ -41,9 +38,9 @@ pub use self::version_management::VersionManager; use crate::libexecutor::call_request::CallRequest; use crate::libexecutor::command::Commander; use crate::libexecutor::executor::Executor; -use crate::types::ids::BlockId; +use crate::types::block_number::BlockTag; use cita_types::Address; -use util::Bytes; +use types::Bytes; /// Extend `Executor` with some methods related to contract trait ContractCallExt { @@ -53,7 +50,7 @@ trait ContractCallExt { address: &Address, encoded_method: &[u8], from: Option
, - block_id: BlockId, + block_id: BlockTag, ) -> Result; } @@ -63,14 +60,14 @@ impl<'a> ContractCallExt for Executor { address: &Address, encoded_method: &[u8], from: Option
, - block_id: BlockId, + block_tag: BlockTag, ) -> Result { let call_request = CallRequest { from, to: *address, data: Some(encoded_method.to_vec()), }; - trace!("data: {:?}", call_request.data); - self.eth_call(call_request, block_id) + trace!("call method request: {:?}", call_request); + self.eth_call(call_request, block_tag) } } diff --git a/cita-executor/core/src/contracts/solc/node_manager.rs b/cita-executor/core/src/contracts/solc/node_manager.rs index fb24b0340..cd6d554ac 100644 --- a/cita-executor/core/src/contracts/solc/node_manager.rs +++ b/cita-executor/core/src/contracts/solc/node_manager.rs @@ -1,33 +1,32 @@ -// CITA -// Copyright 2016-2019 Cryptape Technologies LLC. - -// This program is free software: you can redistribute it -// and/or modify it under the terms of the GNU 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 General Public License for more details. - -// You should have received a copy of the GNU General Public License -// along with this program. If not, see . +// Copyright Cryptape Technologies LLC. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. //! Node manager. use super::ContractCallExt; +use std::iter; +use std::str::FromStr; + use crate::contracts::tools::{decode as decode_tools, method as method_tools}; use crate::libexecutor::economical_model::EconomicalModel; use crate::libexecutor::executor::Executor; -use crate::types::ids::BlockId; +use crate::types::block_number::BlockTag; use crate::types::reserved_addresses; + use cita_types::{Address, H160}; use largest_remainder_method::apportion; use rand::{Rng, SeedableRng, StdRng}; -use std::iter; -use std::str::FromStr; const LIST_NODE: &[u8] = &*b"listNode()"; const LIST_STAKE: &[u8] = &*b"listStake()"; @@ -75,32 +74,32 @@ impl<'a> NodeManager<'a> { NodeManager { executor, rng_seed } } - pub fn nodes(&self, block_id: BlockId) -> Option> { + pub fn nodes(&self, block_tag: BlockTag) -> Option> { self.executor .call_method( &*CONTRACT_ADDRESS, &*LIST_NODE_ENCODED.as_slice(), None, - block_id, + block_tag, ) .ok() .and_then(|output| decode_tools::to_address_vec(&output)) } - pub fn stakes(&self, block_id: BlockId) -> Option> { + pub fn stakes(&self, block_tag: BlockTag) -> Option> { self.executor .call_method( &*CONTRACT_ADDRESS, &*LIST_STAKE_ENCODED.as_slice(), None, - block_id, + block_tag, ) .ok() .and_then(|output| decode_tools::to_u64_vec(&output)) } - pub fn shuffled_stake_nodes(&self, block_id: BlockId) -> Option> { - self.stake_nodes(block_id).map(|mut stake_nodes| { + pub fn shuffled_stake_nodes(&self, block_tag: BlockTag) -> Option> { + self.stake_nodes(block_tag).map(|mut stake_nodes| { shuffle(&mut stake_nodes, self.rng_seed); stake_nodes }) @@ -111,14 +110,14 @@ impl<'a> NodeManager<'a> { Vec::new() } - pub fn stake_nodes(&self, block_id: BlockId) -> Option> { - self.nodes(block_id).and_then(|nodes| { + pub fn stake_nodes(&self, block_tag: BlockTag) -> Option> { + self.nodes(block_tag).and_then(|nodes| { if let EconomicalModel::Quota = self.executor.sys_config.block_sys_config.economical_model { Some(nodes) } else { - self.stakes(block_id).map(|stakes| { + self.stakes(block_tag).map(|stakes| { let total: u64 = stakes.iter().sum(); if total == 0 { nodes diff --git a/cita-executor/core/src/contracts/solc/permission_management.rs b/cita-executor/core/src/contracts/solc/permission_management.rs index 120b91e56..4901097cd 100644 --- a/cita-executor/core/src/contracts/solc/permission_management.rs +++ b/cita-executor/core/src/contracts/solc/permission_management.rs @@ -1,29 +1,29 @@ -// CITA -// Copyright 2016-2019 Cryptape Technologies LLC. - -// This program is free software: you can redistribute it -// and/or modify it under the terms of the GNU 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 General Public License for more details. -// You should have received a copy of the GNU General Public License -// along with this program. If not, see . +// Copyright Cryptape Technologies LLC. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. //! Permission management. use super::ContractCallExt; +use std::collections::HashMap; +use std::str::FromStr; + use crate::contracts::tools::{decode as decode_tools, method as method_tools}; use crate::libexecutor::executor::Executor; -use crate::types::ids::BlockId; +use crate::types::block_number::BlockTag; use crate::types::reserved_addresses; + use cita_types::{Address, H160, H256}; -use std::collections::HashMap; -use std::str::FromStr; const ALLACCOUNTS: &[u8] = &*b"queryAllAccounts()"; const PERMISSIONS: &[u8] = &*b"queryPermissions(address)"; @@ -75,20 +75,20 @@ impl<'a> PermissionManagement<'a> { PermissionManagement { executor } } - pub fn load_account_permissions(&self, block_id: BlockId) -> HashMap> { + pub fn load_account_permissions(&self, block_tag: BlockTag) -> HashMap> { let mut account_permissions = HashMap::new(); let accounts = self - .all_accounts(block_id) + .all_accounts(block_tag) .unwrap_or_else(Self::default_all_accounts); trace!("ALl accounts: {:?}", accounts); for account in accounts { let permissions = self - .permissions(&(H256::from(account)), block_id) + .permissions(&(H256::from(account)), block_tag) .unwrap_or_else(Self::default_permissions); trace!("ALl permissions for account {}: {:?}", account, permissions); let mut resources = vec![]; for permission in permissions { - if let Some(res) = self.resources(&permission, block_id) { + if let Some(res) = self.resources(&permission, block_tag) { resources.extend(res); }; } @@ -99,13 +99,13 @@ impl<'a> PermissionManagement<'a> { } /// Account array - pub fn all_accounts(&self, block_id: BlockId) -> Option> { + pub fn all_accounts(&self, block_tag: BlockTag) -> Option> { self.executor .call_method( &*CONTRACT_ADDRESS, &*ALLACCOUNTS_HASH.as_slice(), None, - block_id, + block_tag, ) .ok() .and_then(|output| decode_tools::to_address_vec(&output)) @@ -116,30 +116,30 @@ impl<'a> PermissionManagement<'a> { Vec::new() } - pub fn get_super_admin_account(&self, block_id: BlockId) -> Option
{ - self.all_accounts(block_id) + pub fn get_super_admin_account(&self, block_tag: BlockTag) -> Option
{ + self.all_accounts(block_tag) .and_then(|accounts| accounts.first().cloned()) } /// Permission array - pub fn permissions(&self, param: &H256, block_id: BlockId) -> Option> { + pub fn permissions(&self, param: &H256, block_tag: BlockTag) -> Option> { let mut tx_data = PERMISSIONS_HASH.to_vec(); tx_data.extend(param.to_vec()); debug!("tx_data: {:?}", tx_data); self.executor - .call_method(&*CONTRACT_ADDRESS, &tx_data.as_slice(), None, block_id) + .call_method(&*CONTRACT_ADDRESS, &tx_data.as_slice(), None, block_tag) .ok() .and_then(|output| decode_tools::to_address_vec(&output)) } - pub fn permission_addresses(&self, block_id: BlockId) -> Vec
{ + pub fn permission_addresses(&self, block_tag: BlockTag) -> Vec
{ let mut res: Vec
= Vec::new(); let accounts = self - .all_accounts(block_id) + .all_accounts(block_tag) .unwrap_or_else(Self::default_all_accounts); for account in accounts { let permissions = self - .permissions(&(H256::from(account)), block_id) + .permissions(&(H256::from(account)), block_tag) .unwrap_or_else(Self::default_permissions); res.extend(permissions); } @@ -152,9 +152,9 @@ impl<'a> PermissionManagement<'a> { } /// Resources array - pub fn resources(&self, address: &Address, block_id: BlockId) -> Option> { + pub fn resources(&self, address: &Address, block_tag: BlockTag) -> Option> { self.executor - .call_method(address, &*RESOURCES_HASH.as_slice(), None, block_id) + .call_method(address, &*RESOURCES_HASH.as_slice(), None, block_tag) .ok() .and_then(|output| decode_tools::to_resource_vec(&output)) } @@ -188,7 +188,7 @@ mod tests { use super::{PermissionManagement, Resource, DEFAULT_SUPER_ADEMIN}; use crate::contracts::tools::method as method_tools; use crate::tests::helpers::init_executor; - use crate::types::ids::BlockId; + use crate::types::block_number::{BlockTag, Tag}; use crate::types::reserved_addresses; use cita_types::{Address, H160, H256}; use std::collections::HashMap; @@ -286,7 +286,7 @@ mod tests { // Test all_accounts let permission_management = PermissionManagement::new(&executor); let all_accounts: Vec
= permission_management - .all_accounts(BlockId::Pending) + .all_accounts(BlockTag::Tag(Tag::Pending)) .unwrap(); assert_eq!( @@ -301,7 +301,10 @@ mod tests { let super_admin_address = Address::from_str(DEFAULT_SUPER_ADEMIN).unwrap(); let mut permissions: Vec
= permission_management - .permissions(&(H256::from(super_admin_address)), BlockId::Pending) + .permissions( + &(H256::from(super_admin_address)), + BlockTag::Tag(Tag::Pending), + ) .unwrap(); permissions.sort(); @@ -337,7 +340,7 @@ mod tests { // Test account permissions let account_permissions: HashMap> = - permission_management.load_account_permissions(BlockId::Pending); + permission_management.load_account_permissions(BlockTag::Tag(Tag::Pending)); assert_eq!(account_permissions.contains_key(&super_admin_address), true); let mut resources = (*account_permissions.get(&super_admin_address).unwrap()).clone(); @@ -528,7 +531,7 @@ mod tests { // Test resources let permission_management = PermissionManagement::new(&executor); let resources: Vec = permission_management - .resources(&permission, BlockId::Pending) + .resources(&permission, BlockTag::Tag(Tag::Pending)) .unwrap(); assert_eq!( resources, @@ -542,7 +545,7 @@ mod tests { let permission = Address::from(0x13); let resources = permission_management - .resources(&permission, BlockId::Pending) + .resources(&permission, BlockTag::Tag(Tag::Pending)) .unwrap(); assert_eq!(resources, vec![]); } diff --git a/cita-executor/core/src/contracts/solc/price_manager.rs b/cita-executor/core/src/contracts/solc/price_manager.rs index 030d50b7c..07b6f86ba 100644 --- a/cita-executor/core/src/contracts/solc/price_manager.rs +++ b/cita-executor/core/src/contracts/solc/price_manager.rs @@ -1,29 +1,28 @@ -// CITA -// Copyright 2016-2018 Cryptape Technologies LLC. - -// This program is free software: you can redistribute it -// and/or modify it under the terms of the GNU 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 General Public License for more details. - -// You should have received a copy of the GNU General Public License -// along with this program. If not, see . +// Copyright Cryptape Technologies LLC. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. //! Quota Price Management use super::ContractCallExt; +use std::str::FromStr; + use crate::contracts::tools::{decode as decode_tools, method as method_tools}; use crate::libexecutor::executor::Executor; -use crate::types::ids::BlockId; +use crate::types::block_number::BlockTag; use crate::types::reserved_addresses; + use cita_types::{Address, U256}; -use std::str::FromStr; lazy_static! { static ref GET_QUOTA_PRICE: Vec = method_tools::encode_to_vec(b"getQuotaPrice()"); @@ -42,13 +41,13 @@ impl<'a> PriceManagement<'a> { } /// Set quota price - pub fn quota_price(&self, block_id: BlockId) -> Option { + pub fn quota_price(&self, block_tag: BlockTag) -> Option { self.executor .call_method( &*CONTRACT_ADDRESS, &*GET_QUOTA_PRICE.as_slice(), None, - block_id, + block_tag, ) .ok() .and_then(|output| decode_tools::to_u256(&output)) @@ -64,14 +63,16 @@ impl<'a> PriceManagement<'a> { mod tests { use super::PriceManagement; use crate::tests::helpers::init_executor; - use crate::types::ids::BlockId; + use crate::types::block_number::{BlockTag, Tag}; use cita_types::U256; #[test] fn test_quota_price() { let executor = init_executor(); let price_management = PriceManagement::new(&executor); - let price = price_management.quota_price(BlockId::Pending).unwrap(); + let price = price_management + .quota_price(BlockTag::Tag(Tag::Pending)) + .unwrap(); assert_eq!(price, U256::from(100_0000)); } } diff --git a/cita-executor/core/src/contracts/solc/quota_manager.rs b/cita-executor/core/src/contracts/solc/quota_manager.rs index f97ca05f4..3dd6a47cb 100644 --- a/cita-executor/core/src/contracts/solc/quota_manager.rs +++ b/cita-executor/core/src/contracts/solc/quota_manager.rs @@ -1,32 +1,30 @@ -// CITA -// Copyright 2016-2019 Cryptape Technologies LLC. - -// This program is free software: you can redistribute it -// and/or modify it under the terms of the GNU 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 General Public License for more details. - -// You should have received a copy of the GNU General Public License -// along with this program. If not, see . +// CopyrightTechnologies LLC. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. //! Quota manager. use super::ContractCallExt; +use std::collections::HashMap; +use std::str::FromStr; + use crate::contracts::tools::{decode as decode_tools, method as method_tools}; use crate::libexecutor::executor::Executor; -use crate::types::ids::BlockId; +use crate::types::block_number::BlockTag; use crate::types::reserved_addresses; -use cita_types::traits::LowerHex; -use cita_types::{Address, H160}; + +use cita_types::{traits::LowerHex, Address, H160}; use libproto::blockchain::AccountGasLimit as ProtoAccountQuotaLimit; -use std::collections::HashMap; -use std::str::FromStr; const QUOTAS: &[u8] = &*b"getQuotas()"; const ACCOUNTS: &[u8] = &*b"getAccounts()"; @@ -102,9 +100,9 @@ impl<'a> QuotaManager<'a> { } /// Special account quota limit - pub fn specific(&self, block_id: BlockId) -> HashMap { - let users = self.users(block_id).unwrap_or_else(Self::default_users); - let quota = self.quota(block_id).unwrap_or_else(Self::default_quota); + pub fn specific(&self, block_tag: BlockTag) -> HashMap { + let users = self.users(block_tag).unwrap_or_else(Self::default_users); + let quota = self.quota(block_tag).unwrap_or_else(Self::default_quota); let mut specific = HashMap::new(); for (k, v) in users.iter().zip(quota.iter()) { specific.insert(*k, *v); @@ -113,9 +111,14 @@ impl<'a> QuotaManager<'a> { } /// Quota array - pub fn quota(&self, block_id: BlockId) -> Option> { + pub fn quota(&self, block_tag: BlockTag) -> Option> { self.executor - .call_method(&*CONTRACT_ADDRESS, &*QUOTAS_HASH.as_slice(), None, block_id) + .call_method( + &*CONTRACT_ADDRESS, + &*QUOTAS_HASH.as_slice(), + None, + block_tag, + ) .ok() .and_then(|output| decode_tools::to_u64_vec(&output)) } @@ -126,13 +129,13 @@ impl<'a> QuotaManager<'a> { } /// Account array - pub fn users(&self, block_id: BlockId) -> Option> { + pub fn users(&self, block_tag: BlockTag) -> Option> { self.executor .call_method( &*CONTRACT_ADDRESS, &*ACCOUNTS_HASH.as_slice(), None, - block_id, + block_tag, ) .ok() .and_then(|output| decode_tools::to_address_vec(&output)) @@ -144,9 +147,9 @@ impl<'a> QuotaManager<'a> { } /// Global quota limit - pub fn block_quota_limit(&self, block_id: BlockId) -> Option { + pub fn block_quota_limit(&self, block_tag: BlockTag) -> Option { self.executor - .call_method(&*CONTRACT_ADDRESS, &*BQL_HASH.as_slice(), None, block_id) + .call_method(&*CONTRACT_ADDRESS, &*BQL_HASH.as_slice(), None, block_tag) .ok() .and_then(|output| decode_tools::to_u64(&output)) } @@ -157,13 +160,13 @@ impl<'a> QuotaManager<'a> { } /// Global account quota limit - pub fn account_quota_limit(&self, block_id: BlockId) -> Option { + pub fn account_quota_limit(&self, block_tag: BlockTag) -> Option { self.executor .call_method( &*CONTRACT_ADDRESS, &*DEFAULT_AQL_HASH.as_slice(), None, - block_id, + block_tag, ) .ok() .and_then(|output| decode_tools::to_u64(&output)) @@ -175,13 +178,13 @@ impl<'a> QuotaManager<'a> { } /// Auto exec quota limit - pub fn auto_exec_quota_limit(&self, block_id: BlockId) -> Option { + pub fn auto_exec_quota_limit(&self, block_tag: BlockTag) -> Option { self.executor .call_method( &*CONTRACT_ADDRESS, &*AUTO_EXEC_QL_HASH.as_slice(), None, - block_id, + block_tag, ) .ok() .and_then(|output| decode_tools::to_u64(&output)) @@ -199,7 +202,7 @@ mod tests { use super::{QuotaManager, AQL_VALUE, AUTO_EXEC_QL_VALUE, BQL_VALUE}; use crate::tests::helpers::init_executor; - use crate::types::ids::BlockId; + use crate::types::block_number::{BlockTag, Tag}; use cita_types::H160; use std::str::FromStr; @@ -208,7 +211,7 @@ mod tests { let executor = init_executor(); let quota_management = QuotaManager::new(&executor); - let users = quota_management.users(BlockId::Pending).unwrap(); + let users = quota_management.users(BlockTag::Tag(Tag::Pending)).unwrap(); assert_eq!( users, vec![H160::from_str("4b5ae4567ad5d9fb92bc9afd6a657e6fa13a2523").unwrap()] @@ -221,24 +224,24 @@ mod tests { let quota_management = QuotaManager::new(&executor); // Test quota - let quota = quota_management.quota(BlockId::Pending).unwrap(); + let quota = quota_management.quota(BlockTag::Tag(Tag::Pending)).unwrap(); assert_eq!(quota, vec![BQL_VALUE]); // Test block quota limit let block_quota_limit = quota_management - .block_quota_limit(BlockId::Pending) + .block_quota_limit(BlockTag::Tag(Tag::Pending)) .unwrap(); assert_eq!(block_quota_limit, BQL_VALUE); // Test account quota limit let account_quota_limit = quota_management - .account_quota_limit(BlockId::Pending) + .account_quota_limit(BlockTag::Tag(Tag::Pending)) .unwrap(); assert_eq!(account_quota_limit, AQL_VALUE); // Test auto exec quota limit let auto_exec_quota_limit = quota_management - .auto_exec_quota_limit(BlockId::Pending) + .auto_exec_quota_limit(BlockTag::Tag(Tag::Pending)) .unwrap(); assert_eq!(auto_exec_quota_limit, AUTO_EXEC_QL_VALUE); } diff --git a/cita-executor/core/src/contracts/solc/sys_config.rs b/cita-executor/core/src/contracts/solc/sys_config.rs index a30fd8a16..d61b14800 100644 --- a/cita-executor/core/src/contracts/solc/sys_config.rs +++ b/cita-executor/core/src/contracts/solc/sys_config.rs @@ -1,31 +1,29 @@ -// CITA -// Copyright 2016-2019 Cryptape Technologies LLC. - -// This program is free software: you can redistribute it -// and/or modify it under the terms of the GNU 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 General Public License for more details. - -// You should have received a copy of the GNU General Public License -// along with this program. If not, see . +// Copyright Cryptape Technologies LLC. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. //! System Config +use super::ContractCallExt; use std::str::FromStr; -use super::ContractCallExt; use crate::contracts::solc::version_management::VersionManager; use crate::contracts::tools::method as method_tools; use crate::libexecutor::economical_model::EconomicalModel; use crate::libexecutor::executor::Executor; -use crate::types::ids::BlockId; +use crate::types::block_number::{BlockTag, Tag}; use crate::types::reserved_addresses; + use cita_types::{Address, H256, U256}; use ethabi::{decode, ParamType, Token}; use num::FromPrimitive; @@ -82,20 +80,22 @@ impl<'a> SysConfig<'a> { &self, param_types: &[ParamType], method: &[u8], - block_id: BlockId, + block_tag: BlockTag, ) -> Result, String> { let address = &*CONTRACT_ADDRESS; - let output = self.executor.call_method(address, method, None, block_id)?; + let output = self + .executor + .call_method(address, method, None, block_tag)?; trace!("sys_config value output: {:?}", output); decode(param_types, &output).map_err(|_| "decode value error".to_string()) } /// Delay block number before validate - pub fn delay_block_number(&self, block_id: BlockId) -> Option { + pub fn delay_block_number(&self, block_tag: BlockTag) -> Option { self.get_value( &[ParamType::Uint(256)], DELAY_BLOCK_NUMBER.as_slice(), - block_id, + block_tag, ) .ok() .and_then(|mut x| x.remove(0).to_uint()) @@ -108,11 +108,11 @@ impl<'a> SysConfig<'a> { } /// Whether check call permission or not - pub fn call_permission_check(&self, block_id: BlockId) -> Option { + pub fn call_permission_check(&self, block_tag: BlockTag) -> Option { self.get_value( &[ParamType::Bool], CALL_PERMISSION_CHECK.as_slice(), - block_id, + block_tag, ) .ok() .and_then(|mut x| x.remove(0).to_bool()) @@ -123,11 +123,11 @@ impl<'a> SysConfig<'a> { false } - pub fn send_tx_permission_check(&self, block_id: BlockId) -> Option { + pub fn send_tx_permission_check(&self, block_tag: BlockTag) -> Option { self.get_value( &[ParamType::Bool], PERMISSION_SEND_TX_CHECK.as_slice(), - block_id, + block_tag, ) .ok() .and_then(|mut x| x.remove(0).to_bool()) @@ -138,11 +138,11 @@ impl<'a> SysConfig<'a> { false } - pub fn create_contract_permission_check(&self, block_id: BlockId) -> Option { + pub fn create_contract_permission_check(&self, block_tag: BlockTag) -> Option { self.get_value( &[ParamType::Bool], PERMISSION_CREATE_CONTRACT_CHECK.as_slice(), - block_id, + block_tag, ) .ok() .and_then(|mut x| x.remove(0).to_bool()) @@ -154,8 +154,8 @@ impl<'a> SysConfig<'a> { } /// Whether check quota or not - pub fn quota_check(&self, block_id: BlockId) -> Option { - self.get_value(&[ParamType::Bool], QUOTA_CHECK.as_slice(), block_id) + pub fn quota_check(&self, block_tag: BlockTag) -> Option { + self.get_value(&[ParamType::Bool], QUOTA_CHECK.as_slice(), block_tag) .ok() .and_then(|mut x| x.remove(0).to_bool()) } @@ -166,11 +166,11 @@ impl<'a> SysConfig<'a> { } /// Check fee back to platform or node - pub fn fee_back_platform_check(&self, block_id: BlockId) -> Option { + pub fn fee_back_platform_check(&self, block_tag: BlockTag) -> Option { self.get_value( &[ParamType::Bool], FEE_BACK_PLATFORM_CHECK.as_slice(), - block_id, + block_tag, ) .ok() .and_then(|mut x| x.remove(0).to_bool()) @@ -182,8 +182,8 @@ impl<'a> SysConfig<'a> { } /// The owner of current chain - pub fn chain_owner(&self, block_id: BlockId) -> Option
{ - self.get_value(&[ParamType::Address], CHAIN_OWNER.as_slice(), block_id) + pub fn chain_owner(&self, block_tag: BlockTag) -> Option
{ + self.get_value(&[ParamType::Address], CHAIN_OWNER.as_slice(), block_tag) .ok() .and_then(|mut x| x.remove(0).to_address()) .map(Address::from) @@ -195,15 +195,15 @@ impl<'a> SysConfig<'a> { } /// The name of current chain - pub fn chain_name(&self, block_id: BlockId) -> Option { - self.get_value(&[ParamType::String], CHAIN_NAME.as_slice(), block_id) + pub fn chain_name(&self, block_tag: BlockTag) -> Option { + self.get_value(&[ParamType::String], CHAIN_NAME.as_slice(), block_tag) .ok() .and_then(|mut x| x.remove(0).to_string()) } /// The id of current chain - pub fn chain_id(&self, block_id: BlockId) -> Option { - self.get_value(&[ParamType::Uint(64)], CHAIN_ID.as_slice(), block_id) + pub fn chain_id(&self, block_tag: BlockTag) -> Option { + self.get_value(&[ParamType::Uint(64)], CHAIN_ID.as_slice(), block_tag) .ok() .and_then(|mut x| x.remove(0).to_uint()) .map(|x| H256::from(x).low_u64() as u32) @@ -215,8 +215,8 @@ impl<'a> SysConfig<'a> { } /// The id v1 of current chain - pub fn chain_id_v1(&self, block_id: BlockId) -> Option { - self.get_value(&[ParamType::Uint(256)], CHAIN_ID_V1.as_slice(), block_id) + pub fn chain_id_v1(&self, block_tag: BlockTag) -> Option { + self.get_value(&[ParamType::Uint(256)], CHAIN_ID_V1.as_slice(), block_tag) .ok() .and_then(|mut x| x.remove(0).to_uint()) .map(U256::from) @@ -228,22 +228,22 @@ impl<'a> SysConfig<'a> { } /// The operator of current chain - pub fn operator(&self, block_id: BlockId) -> Option { - self.get_value(&[ParamType::String], OPERATOR.as_slice(), block_id) + pub fn operator(&self, block_tag: BlockTag) -> Option { + self.get_value(&[ParamType::String], OPERATOR.as_slice(), block_tag) .ok() .and_then(|mut x| x.remove(0).to_string()) } /// Current operator's website URL - pub fn website(&self, block_id: BlockId) -> Option { - self.get_value(&[ParamType::String], WEBSITE.as_slice(), block_id) + pub fn website(&self, block_tag: BlockTag) -> Option { + self.get_value(&[ParamType::String], WEBSITE.as_slice(), block_tag) .ok() .and_then(|mut x| x.remove(0).to_string()) } /// The interval time for creating a block (milliseconds) - pub fn block_interval(&self, block_id: BlockId) -> Option { - self.get_value(&[ParamType::Uint(64)], BLOCK_INTERVAL.as_slice(), block_id) + pub fn block_interval(&self, block_tag: BlockTag) -> Option { + self.get_value(&[ParamType::Uint(64)], BLOCK_INTERVAL.as_slice(), block_tag) .ok() .and_then(|mut x| x.remove(0).to_uint()) .map(|x| H256::from(x).low_u64()) @@ -257,11 +257,11 @@ impl<'a> SysConfig<'a> { /// enum EconomicalModel { Quota, Charge } /// Quota: Default config is quota /// Charge: Charging by gas * gasPrice and reward for proposer - pub fn economical_model(&self, block_id: BlockId) -> Option { + pub fn economical_model(&self, block_tag: BlockTag) -> Option { self.get_value( &[ParamType::Uint(64)], ECONOMICAL_MODEL.as_slice(), - block_id, + block_tag, ) .ok() .and_then(|mut x| x.remove(0).to_uint()) @@ -274,13 +274,13 @@ impl<'a> SysConfig<'a> { EconomicalModel::Quota } - pub fn token_info(&self, block_id: BlockId) -> Option { + pub fn token_info(&self, block_tag: BlockTag) -> Option { self.executor .call_method( &*CONTRACT_ADDRESS, GET_TOKEN_INFO.as_slice(), None, - block_id, + block_tag, ) .ok() .and_then(|output| { @@ -312,18 +312,18 @@ impl<'a> SysConfig<'a> { pub fn deal_chain_id_version(&self, version_manager: &VersionManager) -> Option { let version = version_manager - .get_version(BlockId::Pending) + .get_version(BlockTag::Tag(Tag::Pending)) .unwrap_or_else(VersionManager::default_version); if version == 0 { let id_v0 = self - .chain_id(BlockId::Pending) + .chain_id(BlockTag::Tag(Tag::Pending)) .unwrap_or_else(SysConfig::default_chain_id); Some(ChainId::V0(id_v0)) } else if version < 3 { let id_v1 = self - .chain_id_v1(BlockId::Pending) + .chain_id_v1(BlockTag::Tag(Tag::Pending)) .unwrap_or_else(SysConfig::default_chain_id_v1); Some(ChainId::V1(id_v1)) @@ -334,8 +334,8 @@ impl<'a> SysConfig<'a> { } /// Get the flag of autoExec - pub fn auto_exec(&self, block_id: BlockId) -> Option { - self.get_value(&[ParamType::Bool], AUTO_EXEC.as_slice(), block_id) + pub fn auto_exec(&self, block_tag: BlockTag) -> Option { + self.get_value(&[ParamType::Bool], AUTO_EXEC.as_slice(), block_tag) .ok() .and_then(|mut x| x.remove(0).to_bool()) } @@ -352,7 +352,7 @@ mod tests { use super::{EconomicalModel, SysConfig, TokenInfo}; use crate::tests::helpers::init_executor; - use crate::types::ids::BlockId; + use crate::types::block_number::{BlockTag, Tag}; use cita_types::Address; use std::str::FromStr; @@ -363,64 +363,74 @@ mod tests { let config = SysConfig::new(&executor); // Test delay block number - let number = config.delay_block_number(BlockId::Pending).unwrap(); + let number = config + .delay_block_number(BlockTag::Tag(Tag::Pending)) + .unwrap(); assert_eq!(number, 1); // Test call permission_check - let check_call_permission = config.call_permission_check(BlockId::Pending).unwrap(); + let check_call_permission = config + .call_permission_check(BlockTag::Tag(Tag::Pending)) + .unwrap(); assert_eq!(check_call_permission, false); // Test send_tx_permission_check - let check_send_tx_permission = config.send_tx_permission_check(BlockId::Pending).unwrap(); + let check_send_tx_permission = config + .send_tx_permission_check(BlockTag::Tag(Tag::Pending)) + .unwrap(); assert_eq!(check_send_tx_permission, false); // Test create_contract_permission_check let check_create_contract_permission = config - .create_contract_permission_check(BlockId::Pending) + .create_contract_permission_check(BlockTag::Tag(Tag::Pending)) .unwrap(); assert_eq!(check_create_contract_permission, false); // Test quota_check - let check_quota = config.quota_check(BlockId::Pending).unwrap(); + let check_quota = config.quota_check(BlockTag::Tag(Tag::Pending)).unwrap(); assert_eq!(check_quota, false); // Test fee_back_platform_check - let check_fee_back_platform = config.fee_back_platform_check(BlockId::Pending).unwrap(); + let check_fee_back_platform = config + .fee_back_platform_check(BlockTag::Tag(Tag::Pending)) + .unwrap(); assert_eq!(check_fee_back_platform, false); // Test chain_owner - let value = config.chain_owner(BlockId::Pending).unwrap(); + let value = config.chain_owner(BlockTag::Tag(Tag::Pending)).unwrap(); assert_eq!( value, Address::from_str("0000000000000000000000000000000000000000").unwrap() ); // Test chain_name - let value = config.chain_name(BlockId::Pending).unwrap(); + let value = config.chain_name(BlockTag::Tag(Tag::Pending)).unwrap(); assert_eq!(value, "test-chain"); // Test chain_id - let value = config.chain_id(BlockId::Pending).unwrap(); + let value = config.chain_id(BlockTag::Tag(Tag::Pending)).unwrap(); assert_eq!(value, 1); // Test operator - let value = config.operator(BlockId::Pending).unwrap(); + let value = config.operator(BlockTag::Tag(Tag::Pending)).unwrap(); assert_eq!(value, "test-operator"); // Test website - let value = config.website(BlockId::Pending).unwrap(); + let value = config.website(BlockTag::Tag(Tag::Pending)).unwrap(); assert_eq!(value, "https://www.example.com"); // Test block_interval - let value = config.block_interval(BlockId::Pending).unwrap(); + let value = config.block_interval(BlockTag::Tag(Tag::Pending)).unwrap(); assert_eq!(value, 3000); // Test economical_model - let value = config.economical_model(BlockId::Pending).unwrap(); + let value = config + .economical_model(BlockTag::Tag(Tag::Pending)) + .unwrap(); assert_eq!(value, EconomicalModel::Quota); // Test token info - let value = config.token_info(BlockId::Pending).unwrap(); + let value = config.token_info(BlockTag::Tag(Tag::Pending)).unwrap(); assert_eq!( value, TokenInfo { @@ -431,7 +441,7 @@ mod tests { ); // Test auto_exec - let auto_exec = config.auto_exec(BlockId::Pending).unwrap(); + let auto_exec = config.auto_exec(BlockTag::Tag(Tag::Pending)).unwrap(); assert_eq!(auto_exec, false); } } diff --git a/cita-executor/core/src/contracts/solc/user_management.rs b/cita-executor/core/src/contracts/solc/user_management.rs index 783616283..8a9d6a982 100644 --- a/cita-executor/core/src/contracts/solc/user_management.rs +++ b/cita-executor/core/src/contracts/solc/user_management.rs @@ -1,29 +1,29 @@ -// CITA -// Copyright 2016-2019 Cryptape Technologies LLC. - -// This program is free software: you can redistribute it -// and/or modify it under the terms of the GNU 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 General Public License for more details. -// You should have received a copy of the GNU General Public License -// along with this program. If not, see . +// Copyright Cryptape Technologies LLC. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. //! User management. use super::ContractCallExt; +use std::collections::HashMap; +use std::str::FromStr; + use crate::contracts::tools::{decode as decode_tools, method as method_tools}; use crate::libexecutor::executor::Executor; -use crate::types::ids::BlockId; +use crate::types::block_number::BlockTag; use crate::types::reserved_addresses; + use cita_types::{Address, H160}; -use std::collections::HashMap; -use std::str::FromStr; const ALLGROUPS: &[u8] = &*b"queryGroups()"; const ACCOUNTS: &[u8] = &*b"queryAccounts()"; @@ -44,16 +44,16 @@ impl<'a> UserManagement<'a> { UserManagement { executor } } - pub fn load_group_accounts(&self, block_id: BlockId) -> HashMap> { + pub fn load_group_accounts(&self, block_tag: BlockTag) -> HashMap> { let mut group_accounts = HashMap::new(); let groups = self - .all_groups(block_id) + .all_groups(block_tag) .unwrap_or_else(Self::default_all_groups); trace!("ALl groups: {:?}", groups); for group in groups { let accounts = self - .accounts(&group, block_id) + .accounts(&group, block_tag) .unwrap_or_else(Self::default_accounts); trace!("ALl accounts for group {}: {:?}", group, accounts); group_accounts.insert(group, accounts); @@ -63,13 +63,13 @@ impl<'a> UserManagement<'a> { } /// Group array - pub fn all_groups(&self, block_id: BlockId) -> Option> { + pub fn all_groups(&self, block_tag: BlockTag) -> Option> { self.executor .call_method( &*CONTRACT_ADDRESS, &*ALLGROUPS_HASH.as_slice(), None, - block_id, + block_tag, ) .ok() .and_then(|output| decode_tools::to_address_vec(&output)) @@ -81,9 +81,9 @@ impl<'a> UserManagement<'a> { } /// Accounts array - pub fn accounts(&self, address: &Address, block_id: BlockId) -> Option> { + pub fn accounts(&self, address: &Address, block_tag: BlockTag) -> Option> { self.executor - .call_method(address, &ACCOUNTS_HASH.as_slice(), None, block_id) + .call_method(address, &ACCOUNTS_HASH.as_slice(), None, block_tag) .ok() .and_then(|output| decode_tools::to_address_vec(&output)) } @@ -100,7 +100,7 @@ mod tests { use super::UserManagement; use crate::tests::helpers::init_executor; - use crate::types::ids::BlockId; + use crate::types::block_number::{BlockTag, Tag}; use crate::types::reserved_addresses; use cita_types::{Address, H160}; use std::str::FromStr; @@ -110,7 +110,9 @@ mod tests { let executor = init_executor(); let user_management = UserManagement::new(&executor); - let all_groups: Vec
= user_management.all_groups(BlockId::Pending).unwrap(); + let all_groups: Vec
= user_management + .all_groups(BlockTag::Tag(Tag::Pending)) + .unwrap(); assert_eq!( all_groups, diff --git a/cita-executor/core/src/contracts/solc/version_management.rs b/cita-executor/core/src/contracts/solc/version_management.rs index 701807406..6881cbabd 100644 --- a/cita-executor/core/src/contracts/solc/version_management.rs +++ b/cita-executor/core/src/contracts/solc/version_management.rs @@ -1,32 +1,28 @@ -// CITA -// Copyright 2016-2019 Cryptape Technologies LLC. - -// This program is free software: you can redistribute it -// and/or modify it under the terms of the GNU 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 General Public License for more details. - -// You should have received a copy of the GNU General Public License -// along with this program. If not, see . +// Copyright Cryptape Technologies LLC. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. //! version management +use super::ContractCallExt; use std::str::FromStr; -use super::ContractCallExt; use crate::contracts::tools::method as method_tools; use crate::libexecutor::executor::Executor; - -use crate::types::ids::BlockId; +use crate::types::block_number::BlockTag; use crate::types::reserved_addresses; -use cita_types::Address; -use cita_types::H256; + +use cita_types::{Address, H256}; use ethabi::{decode, ParamType}; lazy_static! { @@ -46,13 +42,13 @@ impl<'a> VersionManager<'a> { VersionManager { executor } } - pub fn get_version(&self, block_id: BlockId) -> Option { + pub fn get_version(&self, block_tag: BlockTag) -> Option { self.executor .call_method( &*CONTRACT_ADDRESS, &*VERSION_HASH.as_slice(), None, - block_id, + block_tag, ) .and_then(|output| { decode(&[ParamType::Uint(64)], &output) @@ -73,13 +69,15 @@ impl<'a> VersionManager<'a> { mod tests { use super::VersionManager; use crate::tests::helpers::init_executor; - use crate::types::ids::BlockId; + use crate::types::block_number::{BlockTag, Tag}; #[test] fn test_get_version() { let executor = init_executor(); let version_management = VersionManager::new(&executor); - let version = version_management.get_version(BlockId::Pending).unwrap(); + let version = version_management + .get_version(BlockTag::Tag(Tag::Pending)) + .unwrap(); assert_eq!(version, 2); } } diff --git a/cita-executor/core/src/contracts/tools/decode.rs b/cita-executor/core/src/contracts/tools/decode.rs index f08fe9213..6b16ed701 100644 --- a/cita-executor/core/src/contracts/tools/decode.rs +++ b/cita-executor/core/src/contracts/tools/decode.rs @@ -1,19 +1,16 @@ -// CITA -// Copyright 2016-2018 Cryptape Technologies LLC. - -// This program is free software: you can redistribute it -// and/or modify it under the terms of the GNU 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 General Public License for more details. - -// You should have received a copy of the GNU General Public License -// along with this program. If not, see . +// Copyright Cryptape Technologies LLC. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. use crate::contracts::solc::permission_management::Resource; use cita_types::{Address, H256, U256}; diff --git a/cita-executor/core/src/contracts/tools/method.rs b/cita-executor/core/src/contracts/tools/method.rs index 5f24d3848..d3e152cef 100644 --- a/cita-executor/core/src/contracts/tools/method.rs +++ b/cita-executor/core/src/contracts/tools/method.rs @@ -1,23 +1,20 @@ -// CITA -// Copyright 2016-2018 Cryptape Technologies LLC. +// Copyright Cryptape Technologies LLC. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. -// This program is free software: you can redistribute it -// and/or modify it under the terms of the GNU 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 General Public License for more details. - -// You should have received a copy of the GNU General Public License -// along with this program. If not, see . - -/// Calculate contract method signature hash and return different types. +use crate::types::errors::NativeError; use byteorder::{BigEndian, ByteOrder}; -use evm::Error as EvmError; +/// Calculate contract method signature hash and return different types. use util::sha3; pub fn encode_to_array(name: &[u8]) -> [u8; 4] { @@ -35,11 +32,11 @@ pub fn encode_to_u32(name: &[u8]) -> u32 { } // Extract first four bytes (function signature hash) as u32. -pub fn extract_to_u32(data: &[u8]) -> Result { +pub fn extract_to_u32(data: &[u8]) -> Result { if let Some(ref bytes4) = data.get(0..4) { Ok(BigEndian::read_u32(bytes4)) } else { - Err(EvmError::OutOfGas) + Err(NativeError::Internal("out of gas".to_string())) } } diff --git a/cita-executor/core/src/contracts/tools/mod.rs b/cita-executor/core/src/contracts/tools/mod.rs index 9f5ca2640..01738b13a 100644 --- a/cita-executor/core/src/contracts/tools/mod.rs +++ b/cita-executor/core/src/contracts/tools/mod.rs @@ -1,19 +1,16 @@ -// CITA -// Copyright 2016-2018 Cryptape Technologies LLC. - -// This program is free software: you can redistribute it -// and/or modify it under the terms of the GNU 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 General Public License for more details. - -// You should have received a copy of the GNU General Public License -// along with this program. If not, see . +// Copyright Cryptape Technologies LLC. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. //! Contracts Tools. diff --git a/cita-executor/core/src/engines/mod.rs b/cita-executor/core/src/engines/mod.rs deleted file mode 100644 index 0303331d9..000000000 --- a/cita-executor/core/src/engines/mod.rs +++ /dev/null @@ -1,125 +0,0 @@ -// CITA -// Copyright 2016-2019 Cryptape Technologies LLC. - -// This program is free software: you can redistribute it -// and/or modify it under the terms of the GNU 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 General Public License for more details. - -// You should have received a copy of the GNU General Public License -// along with this program. If not, see . - -use crate::builtin::Builtin; -use crate::header::BlockNumber; -use crate::spec::Builtin as SpecBuiltin; -use crate::types::reserved_addresses; -use cita_types::Address; -use serde_json; -use std::collections::BTreeMap; -use std::str::FromStr; - -mod null_engine; -pub use self::null_engine::NullEngine; - -pub trait Engine: Sync + Send { - /// The name of this engine. - fn name(&self) -> &str; - - /// Builtin-contracts we would like to see in the chain. - /// (In principle these are just hints for the engine since that has the last word on them.) - fn builtins(&self) -> &BTreeMap; - - /// Attempt to get a handle to a built-in contract. - /// Only returns references to activated built-ins. - fn builtin(&self, a: &Address, block_number: BlockNumber) -> Option<&Builtin> { - self.builtins().get(a).and_then(|b| { - if b.is_active(block_number) { - Some(b) - } else { - None - } - }) - } -} - -impl NullEngine { - // TODO: read from spec file - pub fn cita() -> Self { - let mut builtins = BTreeMap::new(); - - let s = r#"{ "name": "ecrecover", "pricing": { "linear": { "base": 3000, "word": 0 } } }"#; - let deserialized: SpecBuiltin = serde_json::from_str(s).unwrap(); - - builtins.insert( - Address::from_str(reserved_addresses::ECRECOVER_ADDRESS).unwrap(), - Builtin::from(deserialized), - ); - - let s = r#"{ "name": "sha256", "pricing": { "linear": { "base": 60, "word": 12 } } }"#; - let deserialized: SpecBuiltin = serde_json::from_str(s).unwrap(); - builtins.insert( - Address::from_str(reserved_addresses::SHA256_ADDRESS).unwrap(), - Builtin::from(deserialized), - ); - - let s = r#"{ "name": "ripemd160", "pricing": { "linear": { "base": 600, "word": 120 } } }"#; - let deserialized: SpecBuiltin = serde_json::from_str(s).unwrap(); - builtins.insert( - Address::from_str(reserved_addresses::RIPEMD160_ADDRESS).unwrap(), - Builtin::from(deserialized), - ); - - let s = r#"{ "name": "identity", "pricing": { "linear": { "base": 15, "word": 3 } } }"#; - let deserialized: SpecBuiltin = serde_json::from_str(s).unwrap(); - builtins.insert( - Address::from_str(reserved_addresses::IDENTITY_ADDRESS).unwrap(), - Builtin::from(deserialized), - ); - - let s = r#"{ "name": "edrecover", "pricing": { "linear": { "base": 3000, "word": 0 } } }"#; - let deserialized: SpecBuiltin = serde_json::from_str(s).unwrap(); - builtins.insert( - Address::from_str(reserved_addresses::EDRECOVER_ADDRESS).unwrap(), - Builtin::from(deserialized), - ); - - Self::new(builtins) - } -} - -#[cfg(test)] -mod test { - extern crate rustc_serialize; - use self::rustc_serialize::hex::FromHex; - use super::*; - use util::BytesRef; - - #[test] - fn test_cita_correct() { - let cita = NullEngine::cita(); - let sha256 = cita.builtin( - &Address::from(0x0000000000000000000000000000000000000002), - 0, - ); - - assert!(sha256.is_some()); - - let f = sha256.unwrap(); - let i = [0u8; 0]; - let mut o = [255u8; 32]; - f.execute(&i[..], &mut BytesRef::Fixed(&mut o[..])); - assert_eq!( - &o[..], - &(FromHex::from_hex( - "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855" - ) - .unwrap())[..] - ); - } -} diff --git a/cita-executor/core/src/engines/null_engine.rs b/cita-executor/core/src/engines/null_engine.rs deleted file mode 100644 index ce46b3581..000000000 --- a/cita-executor/core/src/engines/null_engine.rs +++ /dev/null @@ -1,48 +0,0 @@ -// Copyright 2015-2018 Parity Technologies (UK) Ltd. -// This file is part of Parity. - -// Parity is free software: you can redistribute it and/or modify -// it under the terms of the GNU General Public License as published by -// the Free Software Foundation, either version 3 of the License, or -// (at your option) any later version. - -// Parity 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 General Public License for more details. - -// You should have received a copy of the GNU General Public License -// along with Parity. If not, see . - -use crate::builtin::Builtin; -use crate::engines::Engine; -use cita_types::Address; -use std::collections::BTreeMap; - -/// An engine which does not provide any consensus mechanism and does not seal blocks. -pub struct NullEngine { - builtins: BTreeMap, -} - -impl NullEngine { - /// Returns new instance of NullEngine with default VM Factory - pub fn new(builtins: BTreeMap) -> Self { - NullEngine { builtins } - } -} - -impl Default for NullEngine { - fn default() -> Self { - Self::new(Default::default()) - } -} - -impl Engine for NullEngine { - fn name(&self) -> &str { - "NullEngine" - } - - fn builtins(&self) -> &BTreeMap { - &self.builtins - } -} diff --git a/cita-executor/core/src/error.rs b/cita-executor/core/src/error.rs deleted file mode 100644 index 370811db3..000000000 --- a/cita-executor/core/src/error.rs +++ /dev/null @@ -1,347 +0,0 @@ -// Copyright 2015-2017 Parity Technologies (UK) Ltd. -// This file is part of Parity. - -// This software is free software: you can redistribute it and/or modify -// it under the terms of the GNU General Public License as published by -// the Free Software Foundation, either version 3 of the License, or -// (at your option) any later version. - -// This software 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 General Public License for more details. - -// You should have received a copy of the GNU General Public License -// along with Parity. If not, see . - -//! General error types for use in ethcore. - -use crate::basic_types::LogBloom; -use cita_ed25519::Error as EthkeyError; -use cita_types::{H256, U256}; - -use crate::cita_db::TrieError; -pub use crate::executed::{CallError, ExecutionError}; -use crate::header::BlockNumber; -use crate::snapshot::Error as SnapshotError; -use snappy; -use std::fmt; -use util::*; - -#[derive(Debug, PartialEq, Clone, Copy)] -/// Errors concerning transaction processing. -pub enum TransactionError { - /// Transaction is already imported to the queue - AlreadyImported, - /// Transaction is not valid anymore (state already has higher nonce) - Old, - /// Transaction has too low fee - /// (there is already a transaction with the same sender-nonce but higher gas price) - TooCheapToReplace, - /// Transaction was not imported to the queue because limit has been reached. - LimitReached, - /// Transaction's gas price is below threshold. - InsufficientGasPrice { - /// Minimal expected gas price - minimal: U256, - /// Transaction gas price - got: U256, - }, - /// Transaction's gas is below currently set minimal gas requirement. - InsufficientGas { - /// Minimal expected gas - minimal: U256, - /// Transaction gas - got: U256, - }, - /// Sender doesn't have enough funds to pay for this transaction - InsufficientBalance { - /// Senders balance - balance: U256, - /// Transaction cost - cost: U256, - }, - /// Transactions gas is higher then current gas limit - GasLimitExceeded { - /// Current gas limit - limit: U256, - /// Declared transaction gas - got: U256, - }, - /// Transaction's gas limit (aka gas) is invalid. - InvalidGasLimit(OutOfBounds), - /// Transaction sender is banned. - SenderBanned, - /// Transaction receipient is banned. - RecipientBanned, - /// Contract creation code is banned. - CodeBanned, - /// Invalid network ID given. - InvalidNetworkId, -} - -impl fmt::Display for TransactionError { - fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { - use self::TransactionError::*; - let msg = match *self { - AlreadyImported => "Already imported".into(), - Old => "No longer valid".into(), - TooCheapToReplace => "Gas price too low to replace".into(), - LimitReached => "Transaction limit reached".into(), - InsufficientGasPrice { minimal, got } => { - format!("Insufficient gas price. Min={}, Given={}", minimal, got) - } - InsufficientGas { minimal, got } => { - format!("Insufficient gas. Min={}, Given={}", minimal, got) - } - InsufficientBalance { balance, cost } => format!( - "Insufficient balance for transaction. Balance={}, Cost={}", - balance, cost - ), - GasLimitExceeded { limit, got } => { - format!("Gas limit exceeded. Limit={}, Given={}", limit, got) - } - InvalidGasLimit(ref err) => format!("Invalid gas limit. {}", err), - SenderBanned => "Sender is temporarily banned.".into(), - RecipientBanned => "Recipient is temporarily banned.".into(), - CodeBanned => "Contract code is temporarily banned.".into(), - InvalidNetworkId => { - "Transaction of this network ID is not allowed on this chain.".into() - } - }; - - f.write_fmt(format_args!("Transaction error ({})", msg)) - } -} - -#[allow(unknown_lints, clippy::large_enum_variant)] // TODO clippy -#[derive(Debug, PartialEq, Clone, Copy, Eq)] -/// Errors concerning block processing. -pub enum BlockError { - /// Extra data is of an invalid length. - ExtraDataOutOfBounds(OutOfBounds), - /// Seal is incorrect format. - InvalidSealArity(Mismatch), - /// Block has too much gas used. - TooMuchGasUsed(OutOfBounds), - /// State root header field is invalid. - InvalidStateRoot(Mismatch), - /// Gas used header field is invalid. - InvalidGasUsed(Mismatch), - /// Transactions root header field is invalid. - InvalidTransactionsRoot(Mismatch), - /// Difficulty is out of range; this can be used as an looser error prior to getting a definitive - /// value for difficulty. This error needs only provide bounds of which it is out. - DifficultyOutOfBounds(OutOfBounds), - /// Difficulty header field is invalid; this is a strong error used after getting a definitive - /// value for difficulty (which is provided). - InvalidDifficulty(Mismatch), - /// Seal element of type H256 (max_hash for Ethash, but could be something else for - /// other seal engines) is out of bounds. - MismatchedH256SealElement(Mismatch), - /// Proof-of-work aspect of seal, which we assume is a 256-bit value, is invalid. - InvalidProofOfWork(OutOfBounds), - /// Some low-level aspect of the seal is incorrect. - InvalidSeal, - /// Gas limit header field is invalid. - InvalidGasLimit(OutOfBounds), - /// Receipts trie root header field is invalid. - InvalidReceiptsRoot(Mismatch), - /// Timestamp header field is invalid. - InvalidTimestamp(OutOfBounds), - /// Log bloom header field is invalid. - InvalidLogBloom(Mismatch), - /// Parent hash field of header is invalid; this is an invalid error indicating a logic flaw in the codebase. - /// TODO: remove and favour an assert!/panic!. - InvalidParentHash(Mismatch), - /// Number field of header is invalid. - InvalidNumber(Mismatch), - /// Block number isn't sensible. - RidiculousNumber(OutOfBounds), - /// Parent given is unknown. - UnknownParent(H256), -} - -impl fmt::Display for BlockError { - fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { - use self::BlockError::*; - - let msg = match *self { - ExtraDataOutOfBounds(ref oob) => format!("Extra block data too long. {}", oob), - InvalidSealArity(ref mis) => format!("Block seal in incorrect format: {}", mis), - TooMuchGasUsed(ref oob) => format!("Block has too much gas used. {}", oob), - InvalidStateRoot(ref mis) => format!("Invalid state root in header: {}", mis), - InvalidGasUsed(ref mis) => format!("Invalid gas used in header: {}", mis), - InvalidTransactionsRoot(ref mis) => { - format!("Invalid transactions root in header: {}", mis) - } - DifficultyOutOfBounds(ref oob) => format!("Invalid block difficulty: {}", oob), - InvalidDifficulty(ref mis) => format!("Invalid block difficulty: {}", mis), - MismatchedH256SealElement(ref mis) => format!("Seal element out of bounds: {}", mis), - InvalidProofOfWork(ref oob) => format!("Block has invalid PoW: {}", oob), - InvalidSeal => "Block has invalid seal.".into(), - InvalidGasLimit(ref oob) => format!("Invalid gas limit: {}", oob), - InvalidReceiptsRoot(ref mis) => { - format!("Invalid receipts trie root in header: {}", mis) - } - InvalidTimestamp(ref oob) => format!("Invalid timestamp in header: {}", oob), - InvalidLogBloom(ref oob) => format!("Invalid log bloom in header: {}", oob), - InvalidParentHash(ref mis) => format!("Invalid parent hash: {}", mis), - InvalidNumber(ref mis) => format!("Invalid number in header: {}", mis), - RidiculousNumber(ref oob) => format!("Implausible block number. {}", oob), - UnknownParent(ref hash) => format!("Unknown parent: {}", hash), - }; - - f.write_fmt(format_args!("Block error ({})", msg)) - } -} - -#[derive(Debug, Clone, Copy, PartialEq)] -/// Import to the block queue result -pub enum ImportError { - /// Already in the block chain. - AlreadyInChain, - /// Already in the block queue. - AlreadyQueued, - /// Already marked as bad from a previous import (could mean parent is bad). - KnownBad, -} - -impl fmt::Display for ImportError { - fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { - let msg = match *self { - ImportError::AlreadyInChain => "block already in chain", - ImportError::AlreadyQueued => "block already in the block queue", - ImportError::KnownBad => "block known to be bad", - }; - - f.write_fmt(format_args!("Block import error ({})", msg)) - } -} - -#[allow(unknown_lints, clippy::large_enum_variant)] // TODO clippy -#[derive(Debug)] -/// General error type which should be capable of representing all errors in ethcore. -pub enum Error { - /// Error concerning a utility. - Util(UtilError), - /// Error concerning block processing. - Block(BlockError), - /// Unknown engine given. - UnknownEngineName(String), - /// Error concerning EVM code execution. - Execution(ExecutionError), - /// Error concerning transaction processing. - Transaction(TransactionError), - /// Error concerning block import. - Import(ImportError), - /// PoW hash is invalid or out of date. - PowHashInvalid, - /// The value of the nonce or mishash is invalid. - PowInvalid, - /// Error concerning TrieDBs - Trie(TrieError), - /// Standard io error. - StdIo(::std::io::Error), - /// Snappy error. - Snappy(snappy::SnappyError), - /// Ethkey error. - Ethkey(EthkeyError), - /// Snapshot error - Snapshot(SnapshotError), -} - -impl fmt::Display for Error { - fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { - match *self { - Error::Util(ref err) => err.fmt(f), - Error::Block(ref err) => err.fmt(f), - Error::Execution(ref err) => err.fmt(f), - Error::Transaction(ref err) => err.fmt(f), - Error::Import(ref err) => err.fmt(f), - Error::UnknownEngineName(ref name) => { - f.write_fmt(format_args!("Unknown engine name ({})", name)) - } - Error::PowHashInvalid => f.write_str("Invalid or out of date PoW hash."), - Error::PowInvalid => f.write_str("Invalid nonce or mishash"), - Error::Trie(ref err) => err.fmt(f), - Error::StdIo(ref err) => err.fmt(f), - Error::Snappy(ref err) => err.fmt(f), - Error::Ethkey(ref err) => err.fmt(f), - Error::Snapshot(ref err) => err.fmt(f), - } - } -} - -/// Result of import block operation. -pub type ImportResult = Result; - -impl From for Error { - fn from(err: TransactionError) -> Error { - Error::Transaction(err) - } -} - -impl From for Error { - fn from(err: ImportError) -> Error { - Error::Import(err) - } -} - -impl From for Error { - fn from(err: BlockError) -> Error { - Error::Block(err) - } -} - -impl From for Error { - fn from(err: ExecutionError) -> Error { - Error::Execution(err) - } -} - -impl From<::rlp::DecoderError> for Error { - fn from(err: ::rlp::DecoderError) -> Error { - Error::Util(UtilError::Decoder(err)) - } -} - -impl From for Error { - fn from(err: UtilError) -> Error { - Error::Util(err) - } -} - -impl From for Error { - fn from(err: TrieError) -> Error { - Error::Trie(err) - } -} - -impl From<::std::io::Error> for Error { - fn from(err: ::std::io::Error) -> Error { - Error::StdIo(err) - } -} - -impl From for Error { - fn from(err: snappy::SnappyError) -> Error { - Error::Snappy(err) - } -} - -impl From for Error { - fn from(err: EthkeyError) -> Error { - Error::Ethkey(err) - } -} - -impl From for Error { - fn from(err: SnapshotError) -> Error { - match err { - SnapshotError::Trie(err) => err.into(), - SnapshotError::Decoder(err) => err.into(), - other => Error::Snapshot(other), - } - } -} diff --git a/cita-executor/core/src/exception.rs b/cita-executor/core/src/exception.rs new file mode 100644 index 000000000..84942373d --- /dev/null +++ b/cita-executor/core/src/exception.rs @@ -0,0 +1,54 @@ +// Copyright Cryptape Technologies LLC. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +use std::error::Error; +use std::fmt; + +use crate::types::errors::NativeError; +use cita_vm::Error as VMError; + +// There is not reverted expcetion in VMError, so handle this in ExecutedException. +#[derive(Debug)] +pub enum ExecutedException { + VM(VMError), + NativeContract(NativeError), + Reverted, +} + +impl Error for ExecutedException {} + +impl fmt::Display for ExecutedException { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + let printable = match *self { + ExecutedException::VM(ref err) => format!("exception in vm: {:?}", err), + ExecutedException::NativeContract(ref err) => { + format!("exception in native contract: {:?}", err) + } + ExecutedException::Reverted => "execution reverted".to_owned(), + }; + write!(f, "{}", printable) + } +} + +impl From for ExecutedException { + fn from(err: VMError) -> Self { + ExecutedException::VM(err) + } +} + +impl From for ExecutedException { + fn from(err: NativeError) -> Self { + ExecutedException::NativeContract(err) + } +} diff --git a/cita-executor/core/src/executed.rs b/cita-executor/core/src/executed.rs deleted file mode 100644 index f32d95c03..000000000 --- a/cita-executor/core/src/executed.rs +++ /dev/null @@ -1,216 +0,0 @@ -// Copyright 2015-2017 Parity Technologies (UK) Ltd. -// This file is part of Parity. - -// This software is free software: you can redistribute it and/or modify -// it under the terms of the GNU General Public License as published by -// the Free Software Foundation, either version 3 of the License, or -// (at your option) any later version. - -// This software 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 General Public License for more details. - -// You should have received a copy of the GNU General Public License -// along with Parity. If not, see . - -//! Transaction execution format module. - -use crate::cita_db::trie; -use crate::receipt::ReceiptError; -use crate::trace::{FlatTrace, VMTrace}; -use crate::types::log_entry::LogEntry; -use crate::types::state_diff::StateDiff; -use cita_types::{Address, U256, U512}; -use evm; -use std::fmt; -use util::Bytes; - -/// Transaction execution receipt. -#[derive(Debug, PartialEq, Clone)] -#[cfg_attr(feature = "ipc", binary)] -pub struct Executed { - /// True if the outer call/create resulted in an exceptional exit. - pub exception: Option, - - /// Gas paid up front for execution of transaction. - pub gas: U256, - - /// Gas used during execution of transaction. - pub gas_used: U256, - - /// Gas refunded after the execution of transaction. - /// To get gas that was required up front, add `refunded` and `gas_used`. - pub refunded: U256, - - /// Cumulative gas used in current block so far. - /// - /// `cumulative_gas_used = gas_used(t0) + gas_used(t1) + ... gas_used(tn)` - /// - /// where `tn` is current transaction. - pub cumulative_gas_used: U256, - - /// Vector of logs generated by transaction. - pub logs: Vec, - - /// Addresses of contracts created during execution of transaction. - /// Ordered from earliest creation. - /// - /// eg. sender creates contract A and A in constructor creates contract B - /// - /// B creation ends first, and it will be the first element of the vector. - pub contracts_created: Vec
, - /// Transaction output. - pub output: Bytes, - /// The trace of this transaction. - pub trace: Vec, - /// The VM trace of this transaction. - pub vm_trace: Option, - /// The state diff, if we traced it. - pub state_diff: Option, - /// Transaction sender account nonce - pub account_nonce: U256, -} - -/// Result of executing the transaction. -#[derive(PartialEq, Debug, Clone)] -#[cfg_attr(feature = "ipc", binary)] -pub enum ExecutionError { - /// Returned when there gas paid for transaction execution is - /// lower than base gas required. - NotEnoughBaseGas { - /// Absolute minimum gas required. - required: U256, - /// Gas provided. - got: U256, - }, - /// Returned when block (gas_used + gas) > gas_limit. - /// - /// If gas =< gas_limit, upstream may try to execute the transaction - /// in next block. - BlockGasLimitReached { - /// Gas limit of block for transaction. - gas_limit: U256, - /// Gas used in block prior to transaction. - gas_used: U256, - /// Amount of gas in block. - gas: U256, - }, - AccountGasLimitReached { - /// Account Gas limit left - gas_limit: U256, - /// Amount of gas in transaction - gas: U256, - }, - /// Returned when transaction nonce does not match state nonce. - InvalidNonce { - /// Nonce expected. - expected: U256, - /// Nonce found. - got: U256, - }, - /// Returned when cost of transaction (value + gas_price * gas) exceeds - /// current sender balance. - NotEnoughCash { - /// Minimum required balance. - required: U512, - /// Actual balance. - got: U512, - }, - NoTransactionPermission, - NoContractPermission, - NoCallPermission, - /// Returned when internal evm error occurs. - ExecutionInternal(String), - /// Returned when generic transaction occurs - TransactionMalformed(String), -} - -impl From> for ExecutionError { - fn from(err: Box) -> Self { - ExecutionError::ExecutionInternal(format!("{}", err)) - } -} - -impl fmt::Display for ExecutionError { - fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { - use self::ExecutionError::*; - - let msg = match *self { - NotEnoughBaseGas { ref required, ref got } => format!("Not enough base quota. {} is required, but only {} paid", required, got), - BlockGasLimitReached { - ref gas_limit, - ref gas_used, - ref gas, - } => format!("Block quota limit reached. The limit is {}, {} has already been used, and {} more is required", gas_limit, gas_used, gas), - AccountGasLimitReached { ref gas_limit, ref gas } => format!("Account quota limit reached. The limit is {}, {} more is required", gas_limit, gas), - InvalidNonce { ref expected, ref got } => format!("Invalid transaction nonce: expected {}, found {}", expected, got), - NotEnoughCash { ref required, ref got } => format!("Cost of transaction exceeds sender balance. {} is required but the sender only has {}", required, got), - ExecutionInternal(ref msg) => msg.clone(), - TransactionMalformed(ref err) => format!("Malformed transaction: {}", err), - NoTransactionPermission => "No transaction permission".to_owned(), - NoContractPermission => "No contract permission".to_owned(), - NoCallPermission => "No call contract permission".to_owned(), - }; - - f.write_fmt(format_args!("Transaction execution error ({}).", msg)) - } -} - -/// Result of executing the transaction. -#[derive(PartialEq, Debug, Clone)] -#[cfg_attr(feature = "ipc", binary)] -pub enum CallError { - /// Couldn't find the transaction in the chain. - TransactionNotFound, - /// Couldn't find requested block's state in the chain. - StatePruned, - /// Couldn't find an amount of gas that didn't result in an exception. - Exceptional, - /// Corrupt state. - StateCorrupt, - /// Error executing. - Execution(ExecutionError), -} - -impl From for CallError { - fn from(error: ExecutionError) -> Self { - CallError::Execution(error) - } -} - -impl fmt::Display for CallError { - fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { - use self::CallError::*; - - let msg = match *self { - TransactionNotFound => "Transaction couldn't be found in the chain".into(), - StatePruned => "Couldn't find the transaction block's state in the chain".into(), - Exceptional => "An exception happened in the execution".into(), - StateCorrupt => "Stored state found to be corrupted.".into(), - Execution(ref e) => format!("{}", e), - }; - - f.write_fmt(format_args!("Transaction execution error ({}).", msg)) - } -} - -/// Transaction execution result. -pub type ExecutionResult = Result; - -impl From for ReceiptError { - fn from(error: ExecutionError) -> Self { - match error { - ExecutionError::NotEnoughBaseGas { .. } => ReceiptError::NotEnoughBaseQuota, - ExecutionError::BlockGasLimitReached { .. } => ReceiptError::BlockQuotaLimitReached, - ExecutionError::AccountGasLimitReached { .. } => ReceiptError::AccountQuotaLimitReached, - ExecutionError::InvalidNonce { .. } => ReceiptError::InvalidNonce, - ExecutionError::NotEnoughCash { .. } => ReceiptError::NotEnoughCash, - ExecutionError::NoTransactionPermission => ReceiptError::NoTransactionPermission, - ExecutionError::NoContractPermission => ReceiptError::NoContractPermission, - ExecutionError::NoCallPermission => ReceiptError::NoCallPermission, - ExecutionError::ExecutionInternal { .. } => ReceiptError::ExecutionInternal, - ExecutionError::TransactionMalformed { .. } => ReceiptError::TransactionMalformed, - } - } -} diff --git a/cita-executor/core/src/executive.rs b/cita-executor/core/src/executive.rs deleted file mode 100644 index 63e7d942e..000000000 --- a/cita-executor/core/src/executive.rs +++ /dev/null @@ -1,1915 +0,0 @@ -// Copyright 2015-2017 Parity Technologies (UK) Ltd. -// This file is part of Parity. - -// This software is free software: you can redistribute it and/or modify -// it under the terms of the GNU General Public License as published by -// the Free Software Foundation, either version 3 of the License, or -// (at your option) any later version. - -// This software 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 General Public License for more details. - -// You should have received a copy of the GNU General Public License -// along with Parity. If not, see . - -//! Transaction Execution environment. - -use crate::authentication::check_permission; -use crate::builtin::Builtin; -use crate::contracts::{ - grpc::{ - self, - contract::{ - create_grpc_contract, invoke_grpc_contract, is_create_grpc_address, is_grpc_contract, - }, - grpc_vm::extract_logs_from_response, - service_registry, - }, - native::factory::{Contract as NativeContract, Factory as NativeFactory}, -}; -use crate::engines::Engine; -use crate::error::ExecutionError; -pub use crate::executed::{Executed, ExecutionResult}; -use crate::externalities::*; -use crate::libexecutor::economical_model::EconomicalModel; -use crate::libexecutor::sys_config::BlockSysConfig; -use crate::state::backend::Backend as StateBackend; -use crate::state::{State, Substate}; -use crate::trace::{ - ExecutiveTracer, ExecutiveVMTracer, FlatTrace, NoopTracer, NoopVMTracer, Tracer, VMTrace, - VMTracer, -}; -use crate::types::reserved_addresses; -use crate::types::transaction::{Action, SignedTransaction}; -use cita_types::{Address, H160, H256, U256, U512}; -use crossbeam; -use evm::action_params::{ActionParams, ActionValue}; -use evm::call_type::CallType; -use evm::env_info::EnvInfo; -use evm::{self, Factory, FinalizationResult, Finalize, ReturnData, Schedule}; -use hashable::{Hashable, HASH_EMPTY}; -use std::cmp; -use std::error::Error; -use std::str::FromStr; -use std::sync::Arc; -use util::*; - -/// Roughly estimate what stack size each level of evm depth will use -/// TODO [todr] We probably need some more sophisticated calculations here -/// (limit on my machine 132) -/// Maybe something like here: -/// `https://github.com/ethereum/libethereum/blob/4db169b8504f2b87f7d5a481819cfb959fc65f6c/libethereum/ExtVM.cpp` -const STACK_SIZE_PER_DEPTH: usize = 24 * 1024; - -thread_local! { - /// Stack size - /// Should be modified if it is changed in Rust since it is no way - /// to know or get it - pub static LOCAL_STACK_SIZE: ::std::cell::Cell = ::std::cell::Cell::new( - ::std::env::var("RUST_MIN_STACK").ok().and_then( - |s| s.parse().ok()).unwrap_or(2 * 1024 * 1024)); -} - -///amend the abi data -const AMEND_ABI: u32 = 1; -///amend the account code -const AMEND_CODE: u32 = 2; -///amend the kv of db -const AMEND_KV_H256: u32 = 3; -///amend get the value of db -const AMEND_GET_KV_H256: u32 = 4; -///amend account's balance -const AMEND_ACCOUNT_BALANCE: u32 = 5; - -/// Returns new address created from address and given nonce. -pub fn contract_address(address: &Address, nonce: &U256) -> Address { - use rlp::RlpStream; - - let mut stream = RlpStream::new_list(2); - stream.append(address); - stream.append(nonce); - From::from(stream.out().crypt_hash()) -} - -/// Transaction execution options. -#[derive(Default, Copy, Clone, PartialEq)] -pub struct TransactOptions { - /// Enable call tracing. - pub tracing: bool, - /// Enable VM tracing. - pub vm_tracing: bool, -} - -/// Transaction executor. -pub struct Executive<'a, B: 'a + StateBackend> { - state: &'a mut State, - info: &'a EnvInfo, - engine: &'a Engine, - vm_factory: &'a Factory, - depth: usize, - static_flag: bool, - native_factory: &'a NativeFactory, - /// Check EconomicalModel - economical_model: EconomicalModel, - chain_version: u32, -} - -impl<'a, B: 'a + StateBackend> Executive<'a, B> { - /// Basic constructor. - #[allow(unknown_lints, clippy::too_many_arguments)] // TODO clippy - pub fn new( - state: &'a mut State, - info: &'a EnvInfo, - engine: &'a Engine, - vm_factory: &'a Factory, - native_factory: &'a NativeFactory, - static_flag: bool, - economical_model: EconomicalModel, - chain_version: u32, - ) -> Self { - Executive { - state, - info, - engine, - vm_factory, - native_factory, - depth: 0, - static_flag, - economical_model, - chain_version, - } - } - - pub fn payment_required(&self) -> bool { - self.economical_model == EconomicalModel::Charge - } - - /// Populates executive from parent properties. Increments executive depth. - #[allow(unknown_lints, clippy::too_many_arguments)] // TODO clippy - pub fn from_parent( - state: &'a mut State, - info: &'a EnvInfo, - engine: &'a Engine, - vm_factory: &'a Factory, - native_factory: &'a NativeFactory, - parent_depth: usize, - static_flag: bool, - economical_model: EconomicalModel, - chain_version: u32, - ) -> Self { - Executive { - state, - info, - engine, - vm_factory, - native_factory, - depth: parent_depth + 1, - static_flag, - economical_model, - chain_version, - } - } - - /// Creates `Externalities` from `Executive`. - #[allow(unknown_lints, clippy::too_many_arguments)] // TODO clippy - pub fn as_externalities<'any, T, V>( - &'any mut self, - origin_info: OriginInfo, - substate: &'any mut Substate, - output: OutputPolicy<'any, 'any>, - tracer: &'any mut T, - vm_tracer: &'any mut V, - static_call: bool, - economical_model: EconomicalModel, - ) -> Externalities<'any, T, V, B> - where - T: Tracer, - V: VMTracer, - { - let is_static = self.static_flag || static_call; - Externalities::new( - self.state, - self.info, - self.engine, - self.vm_factory, - self.native_factory, - self.depth, - origin_info, - substate, - output, - tracer, - vm_tracer, - is_static, - economical_model, - self.chain_version, - ) - } - - /// This function should be used to execute transaction. - pub fn transact( - &'a mut self, - t: &SignedTransaction, - options: TransactOptions, - conf: &BlockSysConfig, - ) -> Result { - match (options.tracing, options.vm_tracing) { - (true, true) => self.transact_with_tracer( - t, - ExecutiveTracer::default(), - ExecutiveVMTracer::toplevel(), - conf, - ), - (true, false) => { - self.transact_with_tracer(t, ExecutiveTracer::default(), NoopVMTracer, conf) - } - (false, true) => { - self.transact_with_tracer(t, NoopTracer, ExecutiveVMTracer::toplevel(), conf) - } - (false, false) => self.transact_with_tracer(t, NoopTracer, NoopVMTracer, conf), - } - } - - fn transact_set_abi(&mut self, data: &[u8]) -> bool { - let account = H160::from(&data[0..20]); - let abi = &data[20..]; - info!("set abi of contract address: {:?}", account); - self.state - .exists(&account) - .map(|exists| exists && self.state.init_abi(&account, abi.to_vec()).is_ok()) - .unwrap_or(false) - } - - fn transact_set_code(&mut self, data: &[u8]) -> bool { - let account = H160::from(&data[0..20]); - let code = &data[20..]; - self.state.reset_code(&account, code.to_vec()).is_ok() - } - - fn transact_set_balance(&mut self, data: &[u8]) -> bool { - if data.len() < 52 { - return false; - } - let account = H160::from(&data[0..20]); - let balance = U256::from(&data[20..52]); - self.state - .balance(&account) - .and_then(|now_val| { - if now_val >= balance { - self.state.sub_balance(&account, &(now_val - balance)) - } else { - self.state.add_balance(&account, &(balance - now_val)) - } - }) - .is_ok() - } - - fn transact_set_kv_h256(&mut self, data: &[u8]) -> bool { - let len = data.len(); - if len < 84 { - return false; - } - let loop_num: usize = (len - 20) / (32 * 2); - let account = H160::from(&data[0..20]); - - for i in 0..loop_num { - let base = 20 + 32 * 2 * i; - let key = H256::from_slice(&data[base..base + 32]); - let val = H256::from_slice(&data[base + 32..base + 32 * 2]); - if self.state.set_storage(&account, key, val).is_err() { - return false; - } - } - true - } - - fn transact_get_kv_h256(&mut self, data: &[u8]) -> Option { - let account = H160::from(&data[0..20]); - let key = H256::from_slice(&data[20..52]); - self.state.storage_at(&account, &key).ok() - } - - pub fn transact_with_tracer( - &'a mut self, - t: &SignedTransaction, - mut tracer: T, - mut vm_tracer: V, - conf: &BlockSysConfig, - ) -> Result - where - T: Tracer, - V: VMTracer, - { - let sender = *t.sender(); - let nonce = self.state.nonce(&sender)?; - - self.state.inc_nonce(&sender)?; - - trace!( - "call contract permission should be check: {}", - (*conf).check_options.call_permission - ); - - check_permission( - &conf.group_accounts, - &conf.account_permissions, - t, - conf.check_options, - )?; - - let schedule = Schedule::new_v1(); - - let base_gas_required = match t.action { - Action::Create => schedule.tx_create_gas, - Action::GoCreate => schedule.tx_create_gas, - _ => schedule.tx_gas, - }; - - if sender != Address::zero() && t.gas < U256::from(base_gas_required) { - return Err(ExecutionError::NotEnoughBaseGas { - required: U256::from(base_gas_required), - got: t.gas, - }); - } - - if t.action == Action::AmendData { - if let Some(admin) = conf.super_admin_account { - if *t.sender() != admin { - return Err(ExecutionError::NoTransactionPermission); - } - } else { - return Err(ExecutionError::NoTransactionPermission); - } - } - - if t.action == Action::AbiStore && !self.transact_set_abi(&t.data) { - return Err(ExecutionError::TransactionMalformed( - "Account doesn't exist".to_owned(), - )); - } - - // NOTE: there can be no invalid transactions from this point - let balance = self.state.balance(&sender)?; - let gas_cost = t.gas.full_mul(t.gas_price()); - let total_cost = U512::from(t.value) + gas_cost; - - // avoid unaffordable transactions - if self.payment_required() { - let balance512 = U512::from(balance); - if balance512 < total_cost { - return Err(ExecutionError::NotEnoughCash { - required: total_cost, - got: balance512, - }); - } - self.state.sub_balance(&sender, &U256::from(gas_cost))?; - } - - let mut substate = Substate::new(); - - let init_gas = t.gas - U256::from(base_gas_required); - let (result, output) = match t.action { - Action::Store | Action::AbiStore => { - let schedule = Schedule::new_v1(); - let store_gas_used = U256::from(t.data.len() * schedule.create_data_gas); - if let Some(gas_left) = init_gas.checked_sub(store_gas_used) { - ( - Ok(FinalizationResult { - gas_left, - return_data: ReturnData::empty(), - apply_state: true, - }), - vec![], - ) - } else { - return Err(ExecutionError::NotEnoughBaseGas { - required: U256::from(base_gas_required).saturating_add(store_gas_used), - got: t.gas, - }); - } - } - Action::GoCreate => { - let address = Address::default(); - let params = ActionParams { - code_address: address, - address, - sender, - origin: sender, - gas: init_gas, - gas_price: t.gas_price(), - value: ActionValue::Transfer(t.value), - code: self.state.code(&address)?, - code_hash: self.state.code_hash(&address)?, - data: Some(t.data.clone()), - call_type: CallType::Call, - }; - trace!(target: "executive", "call: {:?}", params); - let mut out = vec![]; - ( - self.call_grpc_contract(¶ms, &mut substate, &BytesRef::Flexible(&mut out)), - out, - ) - } - Action::Create => { - let new_address = contract_address(&sender, &nonce); - let params = ActionParams { - code_address: new_address, - code_hash: t.data.crypt_hash(), - address: new_address, - sender, - origin: sender, - gas: init_gas, - gas_price: t.gas_price(), - value: ActionValue::Transfer(t.value), - code: Some(Arc::new(t.data.clone())), - data: None, - call_type: CallType::None, - }; - ( - self.create(¶ms, &mut substate, &mut tracer, &mut vm_tracer), - vec![], - ) - } - Action::AmendData => { - let amend_data_address: Address = reserved_addresses::AMEND_ADDRESS.into(); - let params = ActionParams { - code_address: amend_data_address, - address: amend_data_address, - sender, - origin: sender, - gas: init_gas, - gas_price: t.gas_price(), - value: ActionValue::Apparent(t.value), - code: None, - code_hash: HASH_EMPTY, - data: Some(t.data.clone()), - call_type: CallType::Call, - }; - trace!(target: "executive", "amend data: {:?}", params); - let mut out = vec![]; - ( - self.call( - ¶ms, - &mut substate, - BytesRef::Flexible(&mut out), - &mut tracer, - &mut vm_tracer, - ), - out, - ) - } - Action::Call(ref address) => { - let params = ActionParams { - code_address: *address, - address: *address, - sender, - origin: sender, - gas: init_gas, - gas_price: t.gas_price(), - value: ActionValue::Transfer(t.value), - code: self.state.code(address)?, - code_hash: self.state.code_hash(address)?, - data: Some(t.data.clone()), - call_type: CallType::Call, - }; - trace!(target: "executive", "call: {:?}", params); - let mut out = vec![]; - ( - self.call( - ¶ms, - &mut substate, - BytesRef::Flexible(&mut out), - &mut tracer, - &mut vm_tracer, - ), - out, - ) - } - }; - - // finalize here! - Ok(self.finalize( - t, - nonce, - substate, - result, - output, - tracer.traces(), - vm_tracer.drain(), - (*conf).chain_owner, - (*conf).check_options.fee_back_platform, - )?) - } - - fn exec_vm( - &mut self, - params: &ActionParams, - unconfirmed_substate: &mut Substate, - output_policy: OutputPolicy, - tracer: &mut T, - vm_tracer: &mut V, - ) -> evm::Result - where - T: Tracer, - V: VMTracer, - { - let depth_threshold = LOCAL_STACK_SIZE.with(|sz| sz.get() / STACK_SIZE_PER_DEPTH); - let static_call = params.call_type == CallType::StaticCall; - - // Ordinary execution - keep VM in same thread - if (self.depth + 1) % depth_threshold != 0 { - let vm_factory = self.vm_factory; - let economical_model = self.economical_model; - let mut ext = self.as_externalities( - OriginInfo::from(params), - unconfirmed_substate, - output_policy, - tracer, - vm_tracer, - static_call, - economical_model, - ); - return vm_factory - .create(params.gas) - .exec(params, &mut ext) - .finalize(ext); - } - - // Start in new thread to reset stack - // TODO [todr] No thread builder yet, so we need to reset once for a while - // https://github.com/aturon/crossbeam/issues/16 - crossbeam::scope(|scope| { - let vm_factory = self.vm_factory; - let economical_model = self.economical_model; - let mut ext = self.as_externalities( - OriginInfo::from(params), - unconfirmed_substate, - output_policy, - tracer, - vm_tracer, - static_call, - economical_model, - ); - - scope.spawn(move || { - vm_factory - .create(params.gas) - .exec(params, &mut ext) - .finalize(ext) - }) - }) - .join() - } - - /// Calls contract function with given contract params. - /// NOTE. It does not finalize the transaction (doesn't do refunds, nor suicides). - /// Modifies the substate and the output. - /// Returns either gas_left or `evm::Error`. - pub fn call( - &mut self, - params: &ActionParams, - substate: &mut Substate, - output: BytesRef, - tracer: &mut T, - vm_tracer: &mut V, - ) -> evm::Result - where - T: Tracer, - V: VMTracer, - { - if (params.call_type == CallType::StaticCall - || (params.call_type == CallType::Call && self.static_flag)) - && params.value.value() > 0.into() - { - return Err(evm::Error::MutableCallInStaticContext); - } - - // backup used in case of running out of gas - self.state.checkpoint(); - - let static_call = params.call_type == CallType::StaticCall; - - // at first, transfer value to destination - // TODO Keep it for compatibility. Remove it later. - if let (true, ActionValue::Transfer(val)) = (self.payment_required(), ¶ms.value) { - self.state - .transfer_balance(¶ms.sender, ¶ms.address, &val)? - } - - if let Some(native_contract) = self.native_factory.new_contract(params.code_address) { - // check and call Native Contract - self.call_native_contract( - params, - substate, - output, - tracer, - static_call, - native_contract, - ) - } else if self.is_amend_data_address(params.code_address) { - let res = self.call_amend_data(params, substate, &output); - self.enact_self_defined_res(&res); - res - } else if is_create_grpc_address(params.code_address) - || is_grpc_contract(params.code_address) - { - let res = self.call_grpc_contract(params, substate, &output); - self.enact_self_defined_res(&res); - res - } else if let Some(builtin) = self.engine.builtin(¶ms.code_address, self.info.number) { - // check and call Builtin contract - self.call_builtin_contract(params, output, tracer, builtin) - } else { - // call EVM contract - self.call_evm_contract(params, substate, output, tracer, vm_tracer) - } - } - - fn is_amend_data_address(&self, address: Address) -> bool { - let amend_address: Address = reserved_addresses::AMEND_ADDRESS.into(); - amend_address == address - } - - fn enact_self_defined_res(&mut self, result: &evm::Result) { - match *result { - Err(evm::Error::OutOfGas) - | Err(evm::Error::BadJumpDestination { .. }) - | Err(evm::Error::BadInstruction { .. }) - | Err(evm::Error::StackUnderflow { .. }) - | Err(evm::Error::OutOfStack { .. }) - | Err(evm::Error::MutableCallInStaticContext) - | Err(evm::Error::OutOfBounds) - | Err(evm::Error::Reverted) - | Ok(FinalizationResult { - apply_state: false, .. - }) => { - self.state.revert_to_checkpoint(); - } - Ok(_) | Err(evm::Error::Internal(_)) => { - self.state.discard_checkpoint(); - } - } - } - - fn call_amend_data( - &mut self, - params: &ActionParams, - _substate: &mut Substate, - _output: &BytesRef, - ) -> evm::Result { - // Must send from admin address - if Some(params.origin) != self.state.super_admin_account { - return Err(evm::error::Error::Internal("no permission".to_owned())); - } - let atype = params.value.value().low_u32(); - let mut result = FinalizationResult { - gas_left: params.gas, - apply_state: true, - return_data: ReturnData::empty(), - }; - match atype { - AMEND_ABI => { - if self.transact_set_abi(&(params.data.to_owned().unwrap())) { - Ok(result) - } else { - Err(evm::error::Error::Internal( - "Account doesn't exist".to_owned(), - )) - } - } - AMEND_CODE => { - if self.transact_set_code(&(params.data.to_owned().unwrap())) { - Ok(result) - } else { - Err(evm::error::Error::Internal( - "Account doesn't exist".to_owned(), - )) - } - } - AMEND_KV_H256 => { - if self.transact_set_kv_h256(&(params.data.to_owned().unwrap())) { - Ok(result) - } else { - Err(evm::error::Error::Internal( - "Account doesn't exist".to_owned(), - )) - } - } - AMEND_GET_KV_H256 => { - if let Some(v) = self.transact_get_kv_h256(&(params.data.to_owned().unwrap())) { - let data = v.to_vec(); - let size = data.len(); - result.return_data = ReturnData::new(data, 0, size); - Ok(result) - } else { - Err(evm::error::Error::Internal( - "May be incomplete trie error".to_owned(), - )) - } - } - - AMEND_ACCOUNT_BALANCE => { - if self.transact_set_balance(&(params.data.to_owned().unwrap())) { - Ok(result) - } else { - Err(evm::error::Error::Internal( - "Account doesn't exist or incomplete trie error".to_owned(), - )) - } - } - - _ => Ok(result), - } - } - - fn call_grpc_contract( - &mut self, - params: &ActionParams, - substate: &mut Substate, - _output: &BytesRef, - ) -> evm::Result { - let is_create = is_create_grpc_address(params.code_address); - let address = if is_create { - match params.data.clone() { - Some(data) => Address::from_slice(&data), - _ => { - return Err(evm::error::Error::Internal( - "GRPC contract creation without data field".to_string(), - )); - } - } - } else { - params.code_address - }; - - let connect_info = match service_registry::find_contract(address, !is_create) { - Some(contract_state) => contract_state.conn_info, - None => { - return Err(evm::error::Error::Internal(format!( - "can't find grpc contract from address: {:?}", - address - ))); - } - }; - - let response = if is_create { - service_registry::enable_contract(address); - create_grpc_contract(self.info, ¶ms, self.state, true, &connect_info) - } else { - invoke_grpc_contract(self.info, ¶ms, self.state, true, &connect_info) - }; - match response { - Ok(invoke_response) => { - // store grpc return storages to stateDB - for storage in &invoke_response.get_storages()[..] { - let key = storage.get_key(); - let value = storage.get_value(); - trace!("recv resp: {:?}", storage); - trace!("key: {:?}, value: {:?}", key, value); - grpc::storage::set_storage(self.state, params.address, key, value).unwrap(); - } - - // update contract_state.height - service_registry::set_enable_contract_height(params.address, self.info.number); - substate.logs = extract_logs_from_response(params.address, &invoke_response); - let message = invoke_response.get_message(); - - Ok(FinalizationResult { - gas_left: U256::from_str(invoke_response.get_gas_left()).unwrap(), - apply_state: true, - return_data: ReturnData::new(message.as_bytes().to_vec(), 0, message.len()), - }) - } - Err(e) => Err(evm::error::Error::Internal(e.description().to_string())), - } - } - - fn call_evm_contract( - &mut self, - params: &ActionParams, - substate: &mut Substate, - output: BytesRef, - tracer: &mut T, - vm_tracer: &mut V, - ) -> evm::Result - where - T: Tracer, - V: VMTracer, - { - let trace_info = tracer.prepare_trace_call(params); - let mut trace_output = tracer.prepare_trace_output(); - let mut subtracer = tracer.subtracer(); - let gas = params.gas; - if params.code.is_some() { - // part of substate that may be reverted - let mut unconfirmed_substate = Substate::new(); - - // TODO: make ActionParams pass by ref then avoid copy altogether. - let mut subvmtracer = vm_tracer.prepare_subtrace( - params - .code - .as_ref() - .expect("scope is conditional on params.code.is_some(); qed"), - ); - - let res = { - self.exec_vm( - params, - &mut unconfirmed_substate, - OutputPolicy::Return(output, trace_output.as_mut()), - &mut subtracer, - &mut subvmtracer, - ) - }; - - vm_tracer.done_subtrace(subvmtracer); - - trace!(target: "executive", "res={:?}", res); - - let traces = subtracer.traces(); - match res { - Ok(ref res) => { - tracer.trace_call(trace_info, gas - res.gas_left, trace_output, traces) - } - Err(ref e) => tracer.trace_failed_call(trace_info, traces, e.into()), - }; - - trace!(target: "executive", "substate={:?}; unconfirmed_substate={:?}\n", - substate, unconfirmed_substate); - - self.enact_result(&res, substate, unconfirmed_substate); - trace!(target: "executive", "enacted: substate={:?}\n", substate); - res - } else { - // otherwise it's just a basic transaction, only do tracing, if necessary. - self.state.discard_checkpoint(); - - tracer.trace_call(trace_info, U256::zero(), trace_output, vec![]); - Ok(FinalizationResult { - gas_left: params.gas, - return_data: ReturnData::empty(), - apply_state: true, - }) - } - } - - fn call_builtin_contract( - &mut self, - params: &ActionParams, - mut output: BytesRef, - tracer: &mut T, - builtin: &Builtin, - ) -> evm::Result - where - T: Tracer, - { - // if destination is builtin, try to execute it - if !builtin.is_active(self.info.number) { - panic!( - "Consensus failure: engine implementation prematurely enabled built-in at {}", - params.code_address - ); - } - let default = []; - let data = if let Some(ref d) = params.data { - d as &[u8] - } else { - &default as &[u8] - }; - let trace_info = tracer.prepare_trace_call(params); - let cost = builtin.cost(data); - if cost <= params.gas { - builtin.execute(data, &mut output); - self.state.discard_checkpoint(); - - // trace only top level calls to builtins to avoid DDoS attacks - if self.depth == 0 { - let mut trace_output = tracer.prepare_trace_output(); - if let Some(out) = trace_output.as_mut() { - *out = output.to_owned(); - } - - tracer.trace_call(trace_info, cost, trace_output, vec![]); - } - Ok(FinalizationResult { - gas_left: params.gas - cost, - return_data: ReturnData::new(output.to_owned(), 0, output.len()), - apply_state: true, - }) - } else { - // just drain the whole gas - self.state.revert_to_checkpoint(); - - tracer.trace_failed_call(trace_info, vec![], evm::Error::OutOfGas.into()); - - Err(evm::Error::OutOfGas) - } - } - - fn call_native_contract( - &mut self, - params: &ActionParams, - substate: &mut Substate, - output: BytesRef, - tracer: &mut T, - static_call: bool, - mut contract: Box, - ) -> evm::Result - where - T: Tracer, - { - let mut unconfirmed_substate = Substate::new(); - let mut trace_output = tracer.prepare_trace_output(); - let output_policy = OutputPolicy::Return(output, trace_output.as_mut()); - let res = { - let mut tracer = NoopTracer; - let mut vmtracer = NoopVMTracer; - let economical_model = self.economical_model; - let mut ext = self.as_externalities( - OriginInfo::from(¶ms), - &mut unconfirmed_substate, - output_policy, - &mut tracer, - &mut vmtracer, - static_call, - economical_model, - ); - contract.exec(¶ms, &mut ext).finalize(ext) - }; - self.enact_result(&res, substate, unconfirmed_substate); - trace!(target: "executive", "enacted: substate={:?}\n", substate); - res - } - - /// Creates contract with given contract params. - /// NOTE. It does not finalize the transaction (doesn't do refunds, nor suicides). - /// Modifies the substate. - pub fn create( - &mut self, - params: &ActionParams, - substate: &mut Substate, - tracer: &mut T, - vm_tracer: &mut V, - ) -> evm::Result - where - T: Tracer, - V: VMTracer, - { - if self.state.exists_and_has_code_or_nonce(¶ms.address)? { - return Err(evm::Error::OutOfGas); - } - trace!( - "Executive::create( - params.code_address={:?}, params.code_hash={:?}, - params.address={:?}, params.sender={:?}, params.origin={:?} - params.gas={:?}, params.gas_price={:?}, params.value={:?} - ) - self.env_info={:?}, - static={}", - params.code_address, - params.code_hash, - params.address, - params.sender, - params.origin, - params.gas, - params.gas_price, - params.value, - self.info, - self.static_flag - ); - if params.call_type == CallType::StaticCall || self.static_flag { - let trace_info = tracer.prepare_trace_create(¶ms); - tracer.trace_failed_create( - trace_info, - vec![], - evm::Error::MutableCallInStaticContext.into(), - ); - return Err(evm::Error::MutableCallInStaticContext); - } - - // backup used in case of running out of gas - self.state.checkpoint(); - - // part of substate that may be reverted - let mut unconfirmed_substate = Substate::new(); - - // create contract and transfer value to it if necessary - let nonce_offset = U256::from(0); - let prev_bal = self.state.balance(¶ms.address)?; - // TODO Keep it for compatibility. Remove it later. - if let (true, &ActionValue::Transfer(val)) = (self.payment_required(), ¶ms.value) { - self.state.sub_balance(¶ms.sender, &val)?; - self.state - .new_contract(¶ms.address, val + prev_bal, nonce_offset); - } else { - self.state - .new_contract(¶ms.address, prev_bal, nonce_offset); - } - - let trace_info = tracer.prepare_trace_create(¶ms); - let mut trace_output = tracer.prepare_trace_output(); - let mut subtracer = tracer.subtracer(); - let gas = params.gas; - let created = params.address; - - let mut subvmtracer = vm_tracer.prepare_subtrace(params.code.as_ref().expect( - "two ways into create (Externalities::create and Executive::transact_with_tracer) - ; both place `Some(...)` `code` in `params`; qed", - )); - - let res = { - self.exec_vm( - ¶ms, - &mut unconfirmed_substate, - OutputPolicy::InitContract(trace_output.as_mut()), - &mut subtracer, - &mut subvmtracer, - ) - }; - - vm_tracer.done_subtrace(subvmtracer); - - match res { - Ok(ref res) => tracer.trace_create( - trace_info, - gas - res.gas_left, - trace_output, - created, - subtracer.traces(), - ), - Err(ref e) => tracer.trace_failed_create(trace_info, subtracer.traces(), e.into()), - }; - - self.enact_result(&res, substate, unconfirmed_substate); - res - } - - /// Finalizes the transaction (does refunds and suicides). - #[allow(unknown_lints, clippy::too_many_arguments)] // TODO clippy - fn finalize( - &mut self, - t: &SignedTransaction, - account_nonce: U256, - substate: Substate, - result: evm::Result, - output: Bytes, - trace: Vec, - vm_trace: Option, - chain_owner: Address, - fee_back_platform: bool, - ) -> ExecutionResult { - let schedule = Schedule::new_v1(); - // refunds from SSTORE nonzero -> zero - let sstore_refunds = U256::from(schedule.sstore_refund_gas) * substate.sstore_clears_count; - // refunds from contract suicides - let suicide_refunds = - U256::from(schedule.suicide_refund_gas) * U256::from(substate.suicides.len()); - let refunds_bound = sstore_refunds + suicide_refunds; - - // real ammount to refund - let gas_left_prerefund = match result { - Ok(FinalizationResult { gas_left, .. }) => gas_left, - _ => 0.into(), - }; - let refunded = cmp::min(refunds_bound, (t.gas - gas_left_prerefund) >> 1); - let gas_left = gas_left_prerefund + refunded; - - let gas_used = t.gas - gas_left; - let refund_value = gas_left * t.gas_price(); - let fees_value = gas_used * t.gas_price(); - - trace!( - "exec::finalize: t.gas={}, sstore_refunds={}, suicide_refunds={}, refunds_bound={}, - gas_left_prerefund={}, refunded={}, gas_left={}, gas_used={}, refund_value={}, fees_value={}\n", - t.gas, - sstore_refunds, - suicide_refunds, - refunds_bound, - gas_left_prerefund, - refunded, - gas_left, - gas_used, - refund_value, - fees_value - ); - - let sender = t.sender(); - trace!( - "exec::finalize: Refunding refund_value={}, sender={}\n", - refund_value, - sender - ); - - if let EconomicalModel::Charge = self.economical_model { - self.state.add_balance(&sender, &refund_value)?; - } - - trace!( - "exec::finalize: Compensating author: fees_value={}, author={}\n", - fees_value, - &self.info.author - ); - - if let EconomicalModel::Charge = self.economical_model { - if fee_back_platform { - // check_fee_back_platform is true, but chain_owner not set, fee still back to author(miner) - if chain_owner == Address::from(0) { - self.state - .add_balance(&self.info.author, &fees_value) - .expect("Add balance to author(miner) must success"); - } else { - self.state - .add_balance(&chain_owner, &fees_value) - .expect("Add balance to chain owner must success"); - } - } else { - self.state - .add_balance(&self.info.author, &fees_value) - .expect("Add balance to author(miner) must success"); - } - } - - // perform suicides - for address in &substate.suicides { - self.state.kill_account(address); - } - - // TODO: kill_garbage might be used here in future. - // perform garbage-collection - for address in &substate.garbage { - if self.state.exists(address)? && !self.state.exists_and_not_null(address)? { - self.state.kill_account(address); - } - } - - match result { - Err(evm::Error::Internal(msg)) => Err(ExecutionError::ExecutionInternal(msg)), - Err(exception) => Ok(Executed { - exception: Some(exception), - gas: t.gas, - gas_used: t.gas, - refunded: U256::zero(), - cumulative_gas_used: self.info.gas_used + t.gas, - logs: vec![], - contracts_created: vec![], - output, - trace, - vm_trace, - state_diff: None, - account_nonce, - }), - Ok(r) => Ok(Executed { - exception: if r.apply_state { - None - } else { - Some(evm::Error::Reverted) - }, - gas: t.gas, - gas_used, - refunded, - cumulative_gas_used: self.info.gas_used + gas_used, - logs: substate.logs, - contracts_created: substate.contracts_created, - output, - trace, - vm_trace, - state_diff: None, - account_nonce, - }), - } - } - - fn enact_result( - &mut self, - result: &evm::Result, - substate: &mut Substate, - un_substate: Substate, - ) { - match *result { - Err(evm::Error::OutOfGas) - | Err(evm::Error::BadJumpDestination { .. }) - | Err(evm::Error::BadInstruction { .. }) - | Err(evm::Error::StackUnderflow { .. }) - | Err(evm::Error::OutOfStack { .. }) - | Err(evm::Error::MutableCallInStaticContext) - | Err(evm::Error::OutOfBounds) - | Err(evm::Error::Reverted) - | Ok(FinalizationResult { - apply_state: false, .. - }) => { - self.state.revert_to_checkpoint(); - } - Ok(_) | Err(evm::Error::Internal(_)) => { - self.state.discard_checkpoint(); - substate.accrue(un_substate); - } - } - } -} - -#[cfg(test)] -mod tests { - extern crate cita_logger as logger; - extern crate rustc_hex; - //////////////////////////////////////////////////////////////////////////////// - - use self::rustc_hex::FromHex; - use super::*; - use crate::engines::NullEngine; - use crate::libexecutor::sys_config::BlockSysConfig; - use crate::state::Substate; - use crate::tests::helpers::*; - use crate::trace::{ExecutiveTracer, ExecutiveVMTracer}; - use crate::types::transaction::Transaction; - use cita_crypto::{CreateKey, KeyPair}; - use cita_types::{Address, H256, U256}; - use evm::action_params::{ActionParams, ActionValue}; - use evm::env_info::EnvInfo; - use evm::Schedule; - use evm::{Factory, VMType}; - use std::ops::Deref; - use std::str::FromStr; - use std::sync::Arc; - - #[test] - fn test_transfer_for_store() { - let keypair = KeyPair::gen_keypair(); - let data_len = 4096; - let provided_gas = U256::from(100_000); - let t = Transaction { - action: Action::Store, - value: U256::from(0), - data: vec![0; data_len], - gas: provided_gas, - gas_price: U256::one(), - nonce: U256::zero().to_string(), - block_limit: 100u64, - chain_id: 1.into(), - version: 2, - } - .fake_sign(keypair.address().clone()); - let sender = t.sender(); - - let factory = Factory::new(VMType::Interpreter, 1024 * 32); - let native_factory = NativeFactory::default(); - let engine = NullEngine::default(); - let mut state = get_temp_state(); - state - .add_balance(&sender, &U256::from(18 + 100_000)) - .unwrap(); - let mut info = EnvInfo::default(); - info.gas_limit = U256::from(100_000); - - let result = { - let mut ex = Executive::new( - &mut state, - &info, - &engine, - &factory, - &native_factory, - false, - EconomicalModel::Charge, - 0, - ); - let opts = TransactOptions { - tracing: false, - vm_tracing: false, - }; - ex.transact(&t, opts, &BlockSysConfig::default()) - }; - - let schedule = Schedule::new_v1(); - let expected = { - let base_gas_required = U256::from(schedule.tx_gas); - let schedule = Schedule::new_v1(); - let store_gas_used = U256::from(data_len * schedule.create_data_gas); - let required = base_gas_required.saturating_add(store_gas_used); - let got = provided_gas; - ExecutionError::NotEnoughBaseGas { required, got } - }; - - assert!(result.is_err()); - assert_eq!(result.err().unwrap(), expected); - } - - #[test] - fn test_transfer_for_charge() { - let keypair = KeyPair::gen_keypair(); - let t = Transaction { - action: Action::Create, - value: U256::from(17), - data: vec![], - gas: U256::from(100_000), - gas_price: U256::one(), - nonce: U256::zero().to_string(), - block_limit: 100u64, - chain_id: 1.into(), - version: 2, - } - .fake_sign(keypair.address().clone()); - let sender = t.sender(); - let contract = contract_address(t.sender(), &U256::zero()); - - let factory = Factory::new(VMType::Interpreter, 1024 * 32); - let native_factory = NativeFactory::default(); - let engine = NullEngine::default(); - let mut state = get_temp_state(); - state - .add_balance(&sender, &U256::from(18 + 100_000)) - .unwrap(); - let mut info = EnvInfo::default(); - info.gas_limit = U256::from(100_000); - let conf = BlockSysConfig::default(); - - let executed = { - let mut ex = Executive::new( - &mut state, - &info, - &engine, - &factory, - &native_factory, - false, - EconomicalModel::Charge, - conf.chain_version, - ); - let opts = TransactOptions { - tracing: false, - vm_tracing: false, - }; - ex.transact(&t, opts, &conf).unwrap() - }; - - let schedule = Schedule::new_v1(); - assert_eq!(executed.gas, U256::from(100_000)); - - // Actually, this is an Action::Create transaction - assert_eq!(executed.gas_used, U256::from(schedule.tx_create_gas)); - assert_eq!(executed.refunded, U256::from(0)); - assert_eq!(executed.logs.len(), 0); - assert_eq!(executed.contracts_created.len(), 0); - assert_eq!( - state.balance(&sender).unwrap(), - U256::from(18 + 100_000 - 17 - schedule.tx_create_gas) - ); - assert_eq!(state.balance(&contract).unwrap(), U256::from(17)); - assert_eq!(state.nonce(&sender).unwrap(), U256::from(1)); - // assert_eq!(state.storage_at(&contract, &H256::new()).unwrap(), H256::from(&U256::from(1))); - } - - #[test] - fn test_not_enough_cash_for_charge() { - let keypair = KeyPair::gen_keypair(); - let t = Transaction { - action: Action::Create, - value: U256::from(43), - data: vec![], - gas: U256::from(100_000), - gas_price: U256::one(), - nonce: U256::zero().to_string(), - block_limit: 100u64, - chain_id: 1.into(), - version: 2, - } - .fake_sign(keypair.address().clone()); - - let factory = Factory::new(VMType::Interpreter, 1024 * 32); - let native_factory = NativeFactory::default(); - let engine = NullEngine::default(); - let mut state = get_temp_state(); - state.add_balance(t.sender(), &U256::from(100_042)).unwrap(); - let mut info = EnvInfo::default(); - info.gas_limit = U256::from(100_000); - let conf = BlockSysConfig::default(); - - let result = { - let mut ex = Executive::new( - &mut state, - &info, - &engine, - &factory, - &native_factory, - false, - EconomicalModel::Charge, - conf.chain_version, - ); - let opts = TransactOptions { - tracing: false, - vm_tracing: false, - }; - ex.transact(&t, opts, &conf) - }; - - match result { - Err(ExecutionError::NotEnoughCash { required, got }) - if required == U512::from(100_043) && got == U512::from(100_042) => - { - () - } - _ => assert!(false, "Expected not enough cash error. {:?}", result), - } - } - - #[test] - fn test_not_enough_cash_for_quota() { - let keypair = KeyPair::gen_keypair(); - let t = Transaction { - action: Action::Create, - value: U256::from(43), - data: vec![], - gas: U256::from(100_000), - gas_price: U256::one(), - nonce: U256::zero().to_string(), - block_limit: 100u64, - chain_id: 1.into(), - version: 2, - } - .fake_sign(keypair.address().clone()); - - let factory = Factory::new(VMType::Interpreter, 1024 * 32); - let native_factory = NativeFactory::default(); - let engine = NullEngine::default(); - let mut state = get_temp_state(); - let mut info = EnvInfo::default(); - info.gas_limit = U256::from(100_000); - let conf = BlockSysConfig::default(); - - let result = { - let mut ex = Executive::new( - &mut state, - &info, - &engine, - &factory, - &native_factory, - false, - EconomicalModel::Quota, - conf.chain_version, - ); - let opts = TransactOptions { - tracing: false, - vm_tracing: false, - }; - ex.transact(&t, opts, &conf) - }; - - assert!(result.is_ok()); - } - - #[test] - fn test_create_contract_out_of_gas() { - logger::silent(); - let source = r#" -pragma solidity ^0.4.19; - -contract HelloWorld { - uint balance; - - function update(uint amount) public returns (address, uint) { - balance += amount; - return (msg.sender, balance); - } -} -"#; - let schedule = Schedule::new_v1(); - let sender = Address::from_str("cd1722f3947def4cf144679da39c4c32bdc35681").unwrap(); - let nonce = U256::zero(); - let gas_required = U256::from(schedule.tx_gas + 1000); - - let (deploy_code, _runtime_code) = solc("HelloWorld", source); - let factory = Factory::new(VMType::Interpreter, 1024 * 32); - let native_factory = NativeFactory::default(); - let contract_address = contract_address(&sender, &nonce); - let mut params = ActionParams::default(); - params.address = contract_address.clone(); - params.sender = sender.clone(); - params.origin = sender.clone(); - params.gas = gas_required; - params.code = Some(Arc::new(deploy_code)); - params.value = ActionValue::Apparent(0.into()); - let mut state = get_temp_state(); - - let info = EnvInfo::default(); - let engine = NullEngine::default(); - let mut substate = Substate::new(); - let mut tracer = ExecutiveTracer::default(); - let mut vm_tracer = ExecutiveVMTracer::toplevel(); - let conf = BlockSysConfig::default(); - - let mut ex = Executive::new( - &mut state, - &info, - &engine, - &factory, - &native_factory, - false, - EconomicalModel::Quota, - conf.chain_version, - ); - let res = ex.create(¶ms, &mut substate, &mut tracer, &mut vm_tracer); - assert!(res.is_err()); - match res { - Err(e) => assert_eq!(e, evm::Error::OutOfGas), - _ => unreachable!(), - } - } - - #[test] - fn test_create_contract() { - logger::silent(); - let source = r#" -pragma solidity ^0.4.8; -contract AbiTest { - uint balance; - function AbiTest() {} - function setValue(uint value) { - balance = value; - } -} -"#; - let schedule = Schedule::new_v1(); - let sender = Address::from_str("cd1722f3947def4cf144679da39c4c32bdc35681").unwrap(); - let nonce = U256::zero(); - let gas_required = U256::from(schedule.tx_gas + 100_000); - - let (deploy_code, runtime_code) = solc("AbiTest", source); - let factory = Factory::new(VMType::Interpreter, 1024 * 32); - let native_factory = NativeFactory::default(); - let contract_address = contract_address(&sender, &nonce); - let mut params = ActionParams::default(); - params.address = contract_address.clone(); - params.sender = sender.clone(); - params.origin = sender.clone(); - params.gas = gas_required; - params.code = Some(Arc::new(deploy_code)); - params.value = ActionValue::Apparent(0.into()); - let mut state = get_temp_state(); - - let info = EnvInfo::default(); - let engine = NullEngine::default(); - let mut substate = Substate::new(); - let mut tracer = ExecutiveTracer::default(); - let mut vm_tracer = ExecutiveVMTracer::toplevel(); - let conf = BlockSysConfig::default(); - - { - let mut ex = Executive::new( - &mut state, - &info, - &engine, - &factory, - &native_factory, - false, - EconomicalModel::Quota, - conf.chain_version, - ); - let _ = ex.create(¶ms, &mut substate, &mut tracer, &mut vm_tracer); - } - - assert_eq!( - state.code(&contract_address).unwrap().unwrap().deref(), - &runtime_code - ); - } - - #[test] - fn test_call_contract() { - logger::silent(); - let source = r#" -pragma solidity ^0.4.8; -contract AbiTest { - uint balance; - function AbiTest() {} - function setValue(uint value) { - balance = value; - } -} -"#; - let schedule = Schedule::new_v1(); - let sender = Address::from_str("cd1722f3947def4cf144679da39c4c32bdc35681").unwrap(); - let gas_required = U256::from(schedule.tx_gas + 100_000); - let contract_addr = Address::from_str("62f4b16d67b112409ab4ac87274926382daacfac").unwrap(); - let (_, runtime_code) = solc("AbiTest", source); - // big endian: value=0x12345678 - let data = "552410770000000000000000000000000000000000000000000000000000000012345678" - .from_hex() - .unwrap(); - let factory = Factory::new(VMType::Interpreter, 1024 * 32); - let native_factory = NativeFactory::default(); - let mut tracer = ExecutiveTracer::default(); - let mut vm_tracer = ExecutiveVMTracer::toplevel(); - - let mut state = get_temp_state(); - state - .init_code(&contract_addr, runtime_code.clone()) - .unwrap(); - let mut params = ActionParams::default(); - params.address = contract_addr.clone(); - params.sender = sender.clone(); - params.gas = gas_required; - params.code = state.code(&contract_addr).unwrap(); - params.code_hash = state.code_hash(&contract_addr).unwrap(); - params.value = ActionValue::Transfer(U256::from(0)); - params.data = Some(data); - - let info = EnvInfo::default(); - let engine = NullEngine::default(); - let mut substate = Substate::new(); - let conf = BlockSysConfig::default(); - - { - let mut ex = Executive::new( - &mut state, - &info, - &engine, - &factory, - &native_factory, - false, - EconomicalModel::Quota, - conf.chain_version, - ); - let mut out = vec![]; - let _ = ex.call( - ¶ms, - &mut substate, - BytesRef::Fixed(&mut out), - &mut tracer, - &mut vm_tracer, - ); - }; - - // it was supposed that value's address is balance. - assert_eq!( - state - .storage_at(&contract_addr, &H256::from(&U256::from(0))) - .unwrap(), - H256::from(&U256::from(0x12345678)) - ); - } - - #[test] - fn test_revert_instruction() { - logger::silent(); - let source = r#" -pragma solidity ^0.4.8; -contract AbiTest { - uint balance; - - modifier Never { - require(false); - _; - } - - function AbiTest() {} - function setValue(uint value) Never { - balance = value; - } -} -"#; - let schedule = Schedule::new_v1(); - let sender = Address::from_str("cd1722f3947def4cf144679da39c4c32bdc35681").unwrap(); - let gas_required = U256::from(schedule.tx_gas + 100_000); - let contract_addr = Address::from_str("62f4b16d67b112409ab4ac87274926382daacfac").unwrap(); - let (_, runtime_code) = solc("AbiTest", source); - // big endian: value=0x12345678 - let data = "552410770000000000000000000000000000000000000000000000000000000012345678" - .from_hex() - .unwrap(); - let factory = Factory::new(VMType::Interpreter, 1024 * 32); - let native_factory = NativeFactory::default(); - let mut tracer = ExecutiveTracer::default(); - let mut vm_tracer = ExecutiveVMTracer::toplevel(); - - let mut state = get_temp_state(); - state - .init_code(&contract_addr, runtime_code.clone()) - .unwrap(); - let mut params = ActionParams::default(); - params.address = contract_addr.clone(); - params.sender = sender.clone(); - params.gas = gas_required; - params.code = state.code(&contract_addr).unwrap(); - params.code_hash = state.code_hash(&contract_addr).unwrap(); - params.value = ActionValue::Transfer(U256::from(0)); - params.data = Some(data); - - let info = EnvInfo::default(); - let engine = NullEngine::default(); - let mut substate = Substate::new(); - let conf = BlockSysConfig::default(); - - { - let mut ex = Executive::new( - &mut state, - &info, - &engine, - &factory, - &native_factory, - false, - EconomicalModel::Quota, - conf.chain_version, - ); - let mut out = vec![]; - let res = ex.call( - ¶ms, - &mut substate, - BytesRef::Fixed(&mut out), - &mut tracer, - &mut vm_tracer, - ); - assert!(res.is_ok()); - match res { - Ok(gas_used) => println!("gas used: {:?}", gas_used), - Err(e) => println!("e: {:?}", e), - } - }; - - // it was supposed that value's address is balance. - assert_eq!( - state - .storage_at(&contract_addr, &H256::from(&U256::from(0))) - .unwrap(), - H256::from(&U256::from(0x0)) - ); - } - - #[test] - fn test_require_instruction() { - logger::silent(); - let source = r#" -pragma solidity ^0.4.8; -contract AbiTest { - uint balance; - - modifier Never { - require(true); - _; - } - - function AbiTest() {} - function setValue(uint value) Never { - balance = value; - } -} -"#; - let schedule = Schedule::new_v1(); - let sender = Address::from_str("cd1722f3947def4cf144679da39c4c32bdc35681").unwrap(); - let gas_required = U256::from(schedule.tx_gas + 100_000); - let contract_addr = Address::from_str("62f4b16d67b112409ab4ac87274926382daacfac").unwrap(); - let (_, runtime_code) = solc("AbiTest", source); - // big endian: value=0x12345678 - let data = "552410770000000000000000000000000000000000000000000000000000000012345678" - .from_hex() - .unwrap(); - let factory = Factory::new(VMType::Interpreter, 1024 * 32); - let native_factory = NativeFactory::default(); - let mut tracer = ExecutiveTracer::default(); - let mut vm_tracer = ExecutiveVMTracer::toplevel(); - - let mut state = get_temp_state(); - state - .init_code(&contract_addr, runtime_code.clone()) - .unwrap(); - let mut params = ActionParams::default(); - params.address = contract_addr.clone(); - params.sender = sender.clone(); - params.gas = gas_required; - params.code = state.code(&contract_addr).unwrap(); - params.code_hash = state.code_hash(&contract_addr).unwrap(); - params.value = ActionValue::Transfer(U256::from(0)); - params.data = Some(data); - - let info = EnvInfo::default(); - let engine = NullEngine::default(); - let mut substate = Substate::new(); - let conf = BlockSysConfig::default(); - - { - let mut ex = Executive::new( - &mut state, - &info, - &engine, - &factory, - &native_factory, - false, - EconomicalModel::Quota, - conf.chain_version, - ); - let mut out = vec![]; - let res = ex.call( - ¶ms, - &mut substate, - BytesRef::Fixed(&mut out), - &mut tracer, - &mut vm_tracer, - ); - assert!(res.is_ok()); - match res { - Ok(gas_used) => println!("gas used: {:?}", gas_used), - Err(e) => println!("e: {:?}", e), - } - }; - - // it was supposed that value's address is balance. - assert_eq!( - state - .storage_at(&contract_addr, &H256::from(&U256::from(0))) - .unwrap(), - H256::from(&U256::from(0x12345678)) - ); - } - - #[test] - fn test_call_instruction() { - logger::silent(); - let fake_auth = r#" -pragma solidity ^0.4.18; - -contract FakeAuth { - function setAuth() public pure returns(bool) { - return true; - } -} -"#; - - let fake_permission_manager = r#" -pragma solidity ^0.4.18; - -contract FakeAuth { - function setAuth() public returns(bool); -} - -contract FakePermissionManagement { - function setAuth(address _auth) public returns(bool) { - FakeAuth auth = FakeAuth(_auth); - require(auth.setAuth()); - return true; - } -} -"#; - let schedule = Schedule::new_v1(); - let sender = Address::from_str("cd1722f3947def4cf144679da39c4c32bdc35681").unwrap(); - let gas_required = U256::from(schedule.tx_gas + 100_000); - let auth_addr = Address::from_str("27ec3678e4d61534ab8a87cf8feb8ac110ddeda5").unwrap(); - let permission_addr = - Address::from_str("33f4b16d67b112409ab4ac87274926382daacfac").unwrap(); - - let factory = Factory::new(VMType::Interpreter, 1024 * 32); - let native_factory = NativeFactory::default(); - let mut tracer = ExecutiveTracer::default(); - let mut vm_tracer = ExecutiveVMTracer::toplevel(); - - let mut state = get_temp_state(); - let (_, runtime_code) = solc("FakeAuth", fake_auth); - state.init_code(&auth_addr, runtime_code.clone()).unwrap(); - - let (_, runtime_code) = solc("FakePermissionManagement", fake_permission_manager); - state - .init_code(&permission_addr, runtime_code.clone()) - .unwrap(); - - // 2b2e05c1: setAuth(address) - let data = "2b2e05c100000000000000000000000027ec3678e4d61534ab8a87cf8feb8ac110ddeda5" - .from_hex() - .unwrap(); - let mut params = ActionParams::default(); - params.address = permission_addr.clone(); - params.sender = sender.clone(); - params.gas = gas_required; - params.code = state.code(&permission_addr).unwrap(); - params.code_hash = state.code_hash(&permission_addr).unwrap(); - params.value = ActionValue::Transfer(U256::from(0)); - params.data = Some(data); - - let info = EnvInfo::default(); - let engine = NullEngine::default(); - let mut substate = Substate::new(); - let conf = BlockSysConfig::default(); - - { - let mut ex = Executive::new( - &mut state, - &info, - &engine, - &factory, - &native_factory, - false, - EconomicalModel::Quota, - conf.chain_version, - ); - let mut out = vec![]; - let res = ex.call( - ¶ms, - &mut substate, - BytesRef::Fixed(&mut out), - &mut tracer, - &mut vm_tracer, - ); - - assert!(res.is_ok()); - match res { - Ok(gas_used) => println!("gas used: {:?}", gas_used), - Err(e) => println!("e: {:?}", e), - } - }; - } -} diff --git a/cita-executor/core/src/externalities.rs b/cita-executor/core/src/externalities.rs deleted file mode 100644 index 429abed21..000000000 --- a/cita-executor/core/src/externalities.rs +++ /dev/null @@ -1,472 +0,0 @@ -// Copyright 2015-2017 Parity Technologies (UK) Ltd. -// This file is part of Parity. - -// This software is free software: you can redistribute it and/or modify -// it under the terms of the GNU General Public License as published by -// the Free Software Foundation, either version 3 of the License, or -// (at your option) any later version. - -// This software 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 General Public License for more details. - -// You should have received a copy of the GNU General Public License -// along with Parity. If not, see . - -//! Transaction Execution environment. - -//////////////////////////////////////////////////////////////////////////////// - -use crate::contracts::native::factory::Factory as NativeFactory; -use crate::engines::Engine; -use crate::executive::*; -use crate::libexecutor::economical_model::EconomicalModel; -use crate::state::backend::Backend as StateBackend; -use crate::state::State; -use crate::substate::Substate; -use crate::trace::{Tracer, VMTracer}; -use cita_types::{Address, H256, U256}; -use evm::action_params::{ActionParams, ActionValue}; -use evm::call_type::CallType; -use evm::env_info::EnvInfo; -use evm::{ - self, ContractCreateResult, Factory, FinalizationResult, MessageCallResult, ReturnData, - Schedule, -}; -use hashable::Hashable; -use std::cmp; -use std::sync::Arc; -use util::*; - -/// Policy for handling output data on `RETURN` opcode. -pub enum OutputPolicy<'a, 'b> { - /// Return reference to fixed sized output. - /// Used for message calls. - Return(BytesRef<'a>, Option<&'b mut Bytes>), - /// Init new contract as soon as `RETURN` is called. - InitContract(Option<&'b mut Bytes>), -} - -/// Transaction properties that externalities need to know about. -pub struct OriginInfo { - address: Address, - origin: Address, - gas_price: U256, - value: U256, -} - -impl OriginInfo { - /// Populates origin info from action params. - pub fn from(params: &ActionParams) -> Self { - OriginInfo { - address: params.address, - origin: params.origin, - gas_price: params.gas_price, - value: match params.value { - ActionValue::Transfer(val) | ActionValue::Apparent(val) => val, - }, - } - } -} - -/// Implementation of evm Externalities. -pub struct Externalities<'a, T: 'a, V: 'a, B: 'a> -where - T: Tracer, - V: VMTracer, - B: StateBackend, -{ - state: &'a mut State, - env_info: &'a EnvInfo, - engine: &'a Engine, - vm_factory: &'a Factory, - native_factory: &'a NativeFactory, - depth: usize, - origin_info: OriginInfo, - substate: &'a mut Substate, - schedule: Schedule, - output: OutputPolicy<'a, 'a>, - tracer: &'a mut T, - vm_tracer: &'a mut V, - static_flag: bool, - economical_model: EconomicalModel, - chain_version: u32, -} - -impl<'a, T: 'a, V: 'a, B: 'a> Externalities<'a, T, V, B> -where - T: Tracer, - V: VMTracer, - B: StateBackend, -{ - /// Basic `Externalities` constructor. - #[allow(unknown_lints, clippy::too_many_arguments)] // TODO clippy - pub fn new( - state: &'a mut State, - env_info: &'a EnvInfo, - engine: &'a Engine, - vm_factory: &'a Factory, - native_factory: &'a NativeFactory, - depth: usize, - origin_info: OriginInfo, - substate: &'a mut Substate, - output: OutputPolicy<'a, 'a>, - tracer: &'a mut T, - vm_tracer: &'a mut V, - static_flag: bool, - economical_model: EconomicalModel, - chain_version: u32, - ) -> Self { - Externalities { - state, - env_info, - engine, - vm_factory, - native_factory, - depth, - origin_info, - substate, - schedule: Schedule::new_v1(), - output, - tracer, - vm_tracer, - static_flag, - economical_model, - chain_version, - } - } -} - -impl<'a, T: 'a, V: 'a, B: 'a> evm::Ext for Externalities<'a, T, V, B> -where - T: Tracer, - V: VMTracer, - B: StateBackend, -{ - fn storage_at(&self, key: &H256) -> evm::Result { - self.state - .storage_at(&self.origin_info.address, key) - .map_err(Into::into) - } - - fn set_storage(&mut self, key: H256, value: H256) -> evm::Result<()> { - if self.static_flag { - Err(evm::Error::MutableCallInStaticContext) - } else { - self.state - .set_storage(&self.origin_info.address, key, value) - .map_err(Into::into) - } - } - - fn is_static(&self) -> bool { - self.static_flag - } - - fn exists(&self, address: &Address) -> evm::Result { - self.state.exists(address).map_err(Into::into) - } - - fn exists_and_not_null(&self, address: &Address) -> evm::Result { - self.state.exists_and_not_null(address).map_err(Into::into) - } - - fn origin_balance(&self) -> evm::Result { - self.balance(&self.origin_info.address).map_err(Into::into) - } - - fn balance(&self, address: &Address) -> evm::Result { - self.state.balance(address).map_err(Into::into) - } - - fn blockhash(&self, number: &U256) -> H256 { - // TODO: comment out what this function expects from env_info, since it will produce panics if the latter is inconsistent - if *number < U256::from(self.env_info.number) - && number.low_u64() >= cmp::max(256, self.env_info.number) - 256 - { - let index = self.env_info.number - number.low_u64() - 1; - assert!( - index < self.env_info.last_hashes.len() as u64, - format!( - "Inconsistent env_info, should contain at least {:?} last hashes", - index + 1 - ) - ); - let r = self.env_info.last_hashes[index as usize]; - trace!( - "ext: blockhash({}) -> {} self.env_info.number={}\n", - number, - r, - self.env_info.number - ); - r - } else { - trace!( - "ext: blockhash({}) -> null self.env_info.number={}\n", - number, - self.env_info.number - ); - H256::zero() - } - } - - fn create(&mut self, gas: &U256, value: &U256, code: &[u8]) -> evm::ContractCreateResult { - // create new contract address - let address = match self.state.nonce(&self.origin_info.address) { - Ok(nonce) => contract_address(&self.origin_info.address, &nonce), - Err(e) => { - debug!(target: "ext", "Database corruption encountered: {:?}", e); - return evm::ContractCreateResult::Failed; - } - }; - - // prepare the params - let params = ActionParams { - code_address: address, - address, - sender: self.origin_info.address, - origin: self.origin_info.origin, - gas: *gas, - gas_price: self.origin_info.gas_price, - value: ActionValue::Transfer(*value), - code: Some(Arc::new(code.to_vec())), - code_hash: code.crypt_hash(), - data: None, - call_type: CallType::None, - }; - - if !self.static_flag { - if let Err(e) = self.state.inc_nonce(&self.origin_info.address) { - debug!(target: "ext", "Database corruption encountered: {:?}", e); - return evm::ContractCreateResult::Failed; - } - } - let mut ex = Executive::from_parent( - self.state, - self.env_info, - self.engine, - self.vm_factory, - self.native_factory, - self.depth, - self.static_flag, - self.economical_model, - self.chain_version, - ); - - // TODO: handle internal error separately - match ex.create(¶ms, self.substate, self.tracer, self.vm_tracer) { - Ok(FinalizationResult { - gas_left, - apply_state: true, - .. - }) => { - self.substate.contracts_created.push(address); - evm::ContractCreateResult::Created(address, gas_left) - } - Ok(FinalizationResult { - gas_left, - apply_state: false, - return_data, - }) => ContractCreateResult::Reverted(gas_left, return_data), - Err(evm::Error::MutableCallInStaticContext) => ContractCreateResult::FailedInStaticCall, - _ => ContractCreateResult::Failed, - } - } - - fn call( - &mut self, - gas: &U256, - sender_address: &Address, - receive_address: &Address, - value: Option, - data: &[u8], - code_address: &Address, - output: &mut [u8], - call_type: CallType, - ) -> MessageCallResult { - trace!(target: "externalities", "call"); - - let code_res = self - .state - .code(code_address) - .and_then(|code| self.state.code_hash(code_address).map(|hash| (code, hash))); - - let (code, code_hash) = match code_res { - Ok((code, hash)) => (code, hash), - Err(_) => return MessageCallResult::Failed, - }; - - let mut params = ActionParams { - sender: *sender_address, - address: *receive_address, - value: ActionValue::Apparent(self.origin_info.value), - code_address: *code_address, - origin: self.origin_info.origin, - gas: *gas, - gas_price: self.origin_info.gas_price, - code, - code_hash, - data: Some(data.to_vec()), - call_type, - }; - - if let Some(value) = value { - params.value = ActionValue::Transfer(value); - } - - let mut ex = Executive::from_parent( - self.state, - self.env_info, - self.engine, - self.vm_factory, - self.native_factory, - self.depth, - self.static_flag, - self.economical_model, - self.chain_version, - ); - - match ex.call( - ¶ms, - self.substate, - BytesRef::Fixed(output), - self.tracer, - self.vm_tracer, - ) { - Ok(FinalizationResult { - gas_left, - return_data, - apply_state: true, - }) => MessageCallResult::Success(gas_left, return_data), - Ok(FinalizationResult { - gas_left, - return_data, - apply_state: false, - }) => MessageCallResult::Reverted(gas_left, return_data), - _ => MessageCallResult::Failed, - } - } - - fn extcode(&self, address: &Address) -> evm::Result> { - Ok(self - .state - .code(address)? - .unwrap_or_else(|| Arc::new(vec![]))) - } - - fn extcodesize(&self, address: &Address) -> evm::Result { - Ok(self.state.code_size(address)?.unwrap_or(0)) - } - - fn ret(mut self, gas: &U256, data: &ReturnData, apply_state: bool) -> evm::Result - where - Self: Sized, - { - let handle_copy = |to: &mut Option<&mut Bytes>| { - if let Some(b) = to.as_mut() { - **b = data.to_vec(); - } - }; - match self.output { - OutputPolicy::Return(BytesRef::Fixed(ref mut slice), ref mut copy) => { - handle_copy(copy); - - let len = cmp::min(slice.len(), data.len()); - (&mut slice[..len]).copy_from_slice(&data[..len]); - Ok(*gas) - } - OutputPolicy::Return(BytesRef::Flexible(ref mut vec), ref mut copy) => { - handle_copy(copy); - - vec.clear(); - vec.extend_from_slice(&*data); - Ok(*gas) - } - OutputPolicy::InitContract(ref mut copy) if apply_state => { - let return_cost = - U256::from(data.len()) * U256::from(self.schedule.create_data_gas); - if return_cost > *gas || data.len() > self.schedule.create_data_limit { - return Err(evm::Error::OutOfGas); - } - - handle_copy(copy); - - self.state - .init_code(&self.origin_info.address, data.to_vec())?; - Ok(*gas - return_cost) - } - OutputPolicy::InitContract(_) => Ok(*gas), - } - } - - fn log(&mut self, topics: Vec, data: &[u8]) -> evm::Result<()> { - use crate::log_entry::LogEntry; - - if self.static_flag { - return Err(evm::Error::MutableCallInStaticContext); - } - - let address = self.origin_info.address; - self.substate.logs.push(LogEntry { - address, - topics, - data: data.to_vec(), - }); - Ok(()) - } - - fn suicide(&mut self, refund_address: &Address) -> evm::Result<()> { - if self.static_flag { - return Err(evm::Error::MutableCallInStaticContext); - } - - let address = self.origin_info.address; - let balance = self.balance(&address)?; - - if self.chain_version > 1 { - if &address == refund_address { - self.state.sub_balance(&address, &balance)?; - } else { - self.state - .transfer_balance(&address, refund_address, &balance)?; - } - } - - self.tracer.trace_suicide(address, balance, *refund_address); - self.substate.suicides.insert(address); - Ok(()) - } - - fn schedule(&self) -> &Schedule { - &self.schedule - } - - fn env_info(&self) -> &EnvInfo { - self.env_info - } - - fn depth(&self) -> usize { - self.depth - } - - fn inc_sstore_clears(&mut self) { - self.substate.sstore_clears_count = self.substate.sstore_clears_count + U256::one(); - } - - fn trace_prepare_execute(&mut self, pc: usize, instruction: u8, gas_cost: &U256) -> bool { - self.vm_tracer - .trace_prepare_execute(pc, instruction, gas_cost) - } - - fn trace_executed( - &mut self, - gas_used: U256, - stack_push: &[U256], - mem_diff: Option<(usize, &[u8])>, - store_diff: Option<(U256, U256)>, - ) { - self.vm_tracer - .trace_executed(gas_used, stack_push, mem_diff, store_diff) - } -} diff --git a/cita-executor/core/src/factory.rs b/cita-executor/core/src/factory.rs deleted file mode 100644 index 576febae8..000000000 --- a/cita-executor/core/src/factory.rs +++ /dev/null @@ -1,32 +0,0 @@ -// Copyright 2015-2017 Parity Technologies (UK) Ltd. -// This file is part of Parity. - -// This software is free software: you can redistribute it and/or modify -// it under the terms of the GNU General Public License as published by -// the Free Software Foundation, either version 3 of the License, or -// (at your option) any later version. - -// This software 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 General Public License for more details. - -// You should have received a copy of the GNU General Public License -// along with Parity. If not, see . - -use crate::account_db::Factory as AccountFactory; -use crate::cita_db::trie::TrieFactory; -use crate::contracts::native::factory::Factory as NativeFactory; -use evm::Factory as EvmFactory; - -/// Collection of factories. -#[derive(Default, Clone)] -pub struct Factories { - /// factory for evm. - pub vm: EvmFactory, - pub native: NativeFactory, - /// factory for tries. - pub trie: TrieFactory, - /// factory for account databases. - pub accountdb: AccountFactory, -} diff --git a/cita-executor/core/src/lib.rs b/cita-executor/core/src/lib.rs index fa86c4566..98dd9cb0e 100644 --- a/cita-executor/core/src/lib.rs +++ b/cita-executor/core/src/lib.rs @@ -1,103 +1,51 @@ -// CITA -// Copyright 2016-2019 Cryptape Technologies LLC. +// Copyright Cryptape Technologies LLC. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. -// This program is free software: you can redistribute it -// and/or modify it under the terms of the GNU 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 General Public License for more details. - -// You should have received a copy of the GNU General Public License -// along with this program. If not, see . - -extern crate bincode; -extern crate byteorder; -extern crate cita_crypto_trait; -extern crate libproto; -extern crate snappy; #[macro_use] extern crate cita_logger as logger; -extern crate lru_cache; -extern crate proof; -extern crate rlp; #[macro_use] extern crate serde_derive; -extern crate cita_merklehash; -pub extern crate db as cita_db; -extern crate hashable; #[cfg_attr(test, macro_use)] extern crate serde_json; -extern crate util; - #[macro_use] extern crate crossbeam_channel; - -#[macro_use] -extern crate rlp_derive; -extern crate rustc_hex; - -extern crate bit_set; -extern crate cita_ed25519; -extern crate cita_secp256k1; -extern crate cita_types; -pub extern crate common_types as types; -extern crate crossbeam; -extern crate crypto; -extern crate evm; -extern crate jsonrpc_types; #[macro_use] extern crate lazy_static; -extern crate time; -extern crate transient_hashmap; - #[cfg(test)] extern crate cita_crypto; -extern crate core; -extern crate ethabi; - -extern crate grpc; #[cfg(feature = "privatetx")] extern crate zktx; - #[macro_use] extern crate enum_primitive; -extern crate ethcore_bloom_journal; -extern crate largest_remainder_method; -extern crate num; -extern crate rand; - -pub mod account_db; #[cfg(test)] pub mod benches; -pub mod builtin; -pub mod executed; -pub mod executive; -pub mod externalities; -pub mod factory; -pub mod pod_account; -pub mod state; -pub mod state_db; #[cfg(test)] pub mod tests; -pub mod trace; -#[macro_use] -pub mod engines; -pub mod error; -pub mod substate; -pub mod authentication; +pub extern crate common_types as types; +pub extern crate core; + +pub mod cita_executive; pub mod contracts; pub mod libexecutor; -pub mod snapshot; +pub mod storage; +pub mod tx_gas_schedule; -mod spec; +mod authentication; +mod exception; +mod trie_db; -pub use crate::cita_db::journaldb; -pub use crate::factory::*; pub use crate::types::*; -pub use evm::Error; +pub use cita_database as cita_db; +pub use trie_db::TrieDB; diff --git a/cita-executor/core/src/libexecutor/auto_exec.rs b/cita-executor/core/src/libexecutor/auto_exec.rs index fabe60507..0911cfb7e 100644 --- a/cita-executor/core/src/libexecutor/auto_exec.rs +++ b/cita-executor/core/src/libexecutor/auto_exec.rs @@ -1,38 +1,34 @@ -// CITA -// Copyright 2016-2019 Cryptape Technologies LLC. +// Copyright Cryptape Technologies LLC. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. -// This program is free software: you can redistribute it -// and/or modify it under the terms of the GNU 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 General Public License for more details. - -// You should have received a copy of the GNU General Public License -// along with this program. If not, see . - -use crate::contracts::native::factory::Factory as NativeFactory; +// use crate::contracts::native::factory::Factory as NativeFactory; use crate::contracts::tools::method as method_tools; -use crate::engines::NullEngine; -use crate::externalities::{Externalities, OriginInfo, OutputPolicy}; -use crate::libexecutor::economical_model::EconomicalModel; -use crate::state::State; -use crate::state::Substate; -use crate::state_db::StateDB; -use crate::trace::Tracer; -use crate::trace::{NoopTracer, NoopVMTracer}; +// use crate::engines::NullEngine; +use crate::libexecutor::block::EVMBlockDataProvider; use crate::types::reserved_addresses; use cita_types::{Address, H160, U256}; -use evm::action_params::{ActionParams, ActionValue}; -use evm::call_type::CallType; -use evm::env_info::EnvInfo; -use evm::{Factory, Finalize, VMType}; +// use evm::{Factory, VMType}; use std::str::FromStr; -use util::BytesRef; +// use util::BytesRef; +use crate::cita_executive::{build_evm_config, build_evm_context}; +use crate::libexecutor::executor::CitaTrieDB; +use crate::types::context::Context; +use cita_vm::evm::InterpreterResult; +use cita_vm::state::State as CitaState; +use cita_vm::Transaction as EVMTransaction; +use std::cell::RefCell; +use std::sync::Arc; const AUTO_EXEC: &[u8] = &*b"autoExec()"; @@ -42,63 +38,47 @@ lazy_static! { } pub fn auto_exec( - state: &mut State, + state: Arc>>, auto_exec_quota_limit: u64, - economical_model: EconomicalModel, - env_info: EnvInfo, - chain_version: u32, + context: Context, ) { let hash = &*AUTO_EXEC_HASH; - let params = ActionParams { - code_address: *AUTO_EXEC_ADDR, - address: *AUTO_EXEC_ADDR, - sender: Address::from(0x0), - origin: Address::from(0x0), - gas: U256::from(auto_exec_quota_limit), + let evm_transaction = EVMTransaction { + from: Address::from(0x0), + value: U256::from(0), + gas_limit: auto_exec_quota_limit, gas_price: U256::from(1), - value: ActionValue::Transfer(U256::from(0)), - code: state.code(&*AUTO_EXEC_ADDR).unwrap(), - code_hash: state.code_hash(&*AUTO_EXEC_ADDR).unwrap(), - data: Some(hash.to_vec()), - call_type: CallType::Call, + input: hash.to_vec(), + to: Some(*AUTO_EXEC_ADDR), + nonce: U256::from(0), }; - let mut substate = Substate::new(); - let mut tracer = NoopTracer; - let mut out = vec![]; - let mut trace_output = tracer.prepare_trace_output(); - let output = OutputPolicy::Return(BytesRef::Flexible(&mut out), trace_output.as_mut()); - let factory = Factory::new(VMType::Interpreter, 1024 * 32); + let mut evm_config = build_evm_config(auto_exec_quota_limit); - let engine = NullEngine::default(); - let native_factory = NativeFactory::default(); - let origin_info = OriginInfo::from(¶ms); - let mut vm_tracer = NoopVMTracer; - let mut ext = Externalities::new( - state, - &env_info, - &engine, - &factory, - &native_factory, - 0, - origin_info, - &mut substate, - output, - &mut tracer, - &mut vm_tracer, - false, - economical_model, - chain_version, - ); - let res = { - factory - .create(params.gas) - .exec(¶ms, &mut ext) - .finalize(ext) - }; + // Do not check nonce and balance for auto exec + evm_config.check_nonce = false; + evm_config.check_balance = false; + let evm_context = build_evm_context(&context); - match res { - Ok(res) => trace!("Auto exec succeed: {:?}", res), + let block_provider = EVMBlockDataProvider::new(context.clone()); + match cita_vm::exec( + Arc::new(block_provider), + state, + evm_context, + evm_config, + evm_transaction, + ) { + Ok(res) => match res { + InterpreterResult::Normal(_, _, _) => { + trace!("Auto exec run succeed."); + } + InterpreterResult::Revert(_, _) => { + info!("Auto exec run Revert!"); + } + _ => { + info!("Auto exec should not run as create"); + } + }, Err(e) => info!("Auto exec failed: {}", e), } } diff --git a/cita-executor/core/src/libexecutor/blacklist.rs b/cita-executor/core/src/libexecutor/blacklist.rs index 267b9abf3..abfcfe0d3 100644 --- a/cita-executor/core/src/libexecutor/blacklist.rs +++ b/cita-executor/core/src/libexecutor/blacklist.rs @@ -1,19 +1,16 @@ -// CITA -// Copyright 2016-2019 Cryptape Technologies LLC. - -// This program is free software: you can redistribute it -// and/or modify it under the terms of the GNU 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 General Public License for more details. - -// You should have received a copy of the GNU General Public License -// along with this program. If not, see . +// Copyright Cryptape Technologies LLC. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. use cita_types::Address; use libproto::BlackList as ProtoBlackList; diff --git a/cita-executor/core/src/libexecutor/block.rs b/cita-executor/core/src/libexecutor/block.rs index c508f3216..9a56628a0 100644 --- a/cita-executor/core/src/libexecutor/block.rs +++ b/cita-executor/core/src/libexecutor/block.rs @@ -1,41 +1,49 @@ -// CITA -// Copyright 2016-2018 Cryptape Technologies LLC. - -// This program is free software: you can redistribute it -// and/or modify it under the terms of the GNU 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 General Public License for more details. - -// You should have received a copy of the GNU General Public License -// along with this program. If not, see . - -use crate::basic_types::LogBloom; -use crate::engines::Engine; -use crate::error::Error; -use crate::factory::Factories; +// Copyright Cryptape Technologies LLC. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +use std::cell::RefCell; +use std::cmp; +use std::collections::HashMap; +use std::ops::{Deref, DerefMut}; +use std::sync::Arc; + +use cita_merklehash; +use cita_types::{Address, Bloom as LogBloom, H256, U256}; +use cita_vm::{ + evm::Error as EVMError, state::State as CitaState, state::StateObjectInfo, BlockDataProvider, + Error as VMError, +}; +use hashable::Hashable; +use libproto::executor::{ExecutedInfo, ReceiptWithOption}; +use rlp::Encodable; + +use crate::cita_executive::CitaExecutive; +use crate::contracts::native::factory::Factory as NativeFactory; +use crate::core::context::{Context, LastHashes}; +use crate::exception::ExecutedException; use crate::libexecutor::auto_exec::auto_exec; +use crate::libexecutor::economical_model::EconomicalModel; +use crate::libexecutor::executor::CitaTrieDB; use crate::libexecutor::sys_config::BlockSysConfig; +use crate::libexecutor::sys_config::GlobalSysConfig; use crate::receipt::Receipt; -use crate::state::State; -use crate::state_db::StateDB; -use crate::trace::FlatTrace; +use crate::tx_gas_schedule::TxGasSchedule; pub use crate::types::block::{Block, BlockBody, OpenBlock}; +use crate::types::errors::Error; +use crate::types::errors::ReceiptError; +use crate::types::errors::{AuthenticationError, ExecutionError}; use crate::types::transaction::SignedTransaction; -use cita_merklehash; -use cita_types::{Address, H256, U256}; -use evm::env_info::{EnvInfo, LastHashes}; -use hashable::Hashable; -use libproto::executor::{ExecutedInfo, ReceiptWithOption}; -use rlp::*; -use std::collections::HashMap; -use std::ops::{Deref, DerefMut}; -use std::sync::Arc; lazy_static! { /// Block Reward @@ -43,19 +51,12 @@ lazy_static! { pub static ref BLOCK_REWARD: U256 = U256::from(5_000_000_000_000_000_000 as i64); } -/// Trait for a object that has a state database. -pub trait Drain { - /// Drop this object and return the underlieing database. - fn drain(self) -> StateDB; -} - -#[derive(Debug)] pub struct ExecutedBlock { pub block: OpenBlock, pub receipts: Vec, - pub state: State, + pub state: Arc>>, pub current_quota_used: U256, - traces: Option>>, + pub state_root: H256, last_hashes: Arc, account_gas_limit: U256, account_gas: HashMap, @@ -79,22 +80,22 @@ impl DerefMut for ExecutedBlock { impl ExecutedBlock { #[allow(clippy::too_many_arguments)] pub fn create( - factories: Factories, conf: &BlockSysConfig, - tracing: bool, block: OpenBlock, - db: StateDB, + trie_db: Arc, state_root: H256, last_hashes: Arc, eth_compatibility: bool, ) -> Result { - let mut state = State::from_existing(db, state_root, U256::default(), factories)?; - state.super_admin_account = conf.super_admin_account; + let state = CitaState::from_existing(Arc::::clone(&trie_db), state_root) + .expect("Get state from trie db"); + // Need only one state reference for the whole block transaction. + let state = Arc::new(RefCell::new(state)); let r = ExecutedBlock { block, state, - traces: if tracing { Some(Vec::new()) } else { None }, + state_root, last_hashes, account_gas_limit: conf.account_quota_limit.common_quota_limit.into(), account_gas: conf.account_quota_limit.specific_quota_limit.iter().fold( @@ -117,10 +118,10 @@ impl ExecutedBlock { } /// Transaction execution env info. - pub fn env_info(&self) -> EnvInfo { - EnvInfo { - number: self.number(), - author: *self.proposer(), + pub fn get_context(&self) -> Context { + Context { + block_number: self.number(), + coin_base: *self.proposer(), timestamp: if self.eth_compatibility { self.timestamp() / 1000 } else { @@ -128,72 +129,228 @@ impl ExecutedBlock { }, difficulty: U256::default(), last_hashes: Arc::clone(&self.last_hashes), - gas_used: self.current_quota_used, - gas_limit: *self.quota_limit(), - account_gas_limit: 0.into(), + quota_used: self.current_quota_used, + block_quota_limit: *self.quota_limit(), + account_quota_limit: 0.into(), } } - #[allow(unknown_lints, clippy::too_many_arguments)] // TODO clippy - pub fn apply_transaction( - &mut self, - engine: &Engine, - t: &SignedTransaction, - conf: &BlockSysConfig, - ) { - let mut env_info = self.env_info(); + pub fn apply_transaction(&mut self, t: &SignedTransaction, sys_config: &GlobalSysConfig) { + let mut context = self.get_context(); + context.block_quota_limit = U256::from(sys_config.block_quota_limit); + trace!("block quota limit is {:?}", context.block_quota_limit); + + let conf = sys_config.block_sys_config.clone(); self.account_gas .entry(*t.sender()) .or_insert(self.account_gas_limit); - env_info.account_gas_limit = *self + + //FIXME: set coin_base according to conf. + context.account_quota_limit = *self .account_gas .get(t.sender()) .expect("account should exist in account_gas_limit"); - let has_traces = self.traces.is_some(); - match self.state.apply(&env_info, engine, t, has_traces, conf) { - Ok(outcome) => { - trace!("apply signed transaction {} success", t.hash()); - if let Some(ref mut traces) = self.traces { - traces.push(outcome.trace); - } - let transaction_quota_used = outcome.receipt.quota_used - self.current_quota_used; - self.current_quota_used = outcome.receipt.quota_used; - if conf.check_options.quota { - if let Some(value) = self.account_gas.get_mut(t.sender()) { - *value = *value - transaction_quota_used; + // Reset coin_base + if conf.check_options.fee_back_platform { + // Set coin_base to chain_owner if check_fee_back_platform is true, and chain_owner is set. + if conf.chain_owner != Address::from(0) { + context.coin_base = conf.chain_owner; + } + } + let block_data_provider = EVMBlockDataProvider::new(context.clone()); + let native_factory = NativeFactory::default(); + + let tx_quota_used = match CitaExecutive::new( + Arc::new(block_data_provider), + self.state.clone(), + &native_factory, + &context, + conf.economical_model, + ) + .exec(t, &conf) + { + Ok(ret) => { + // Note: ret.quota_used was a current transaction quota used. + // FIXME: hasn't handle some errors + let receipt_error = ret.exception.and_then(|error| match error { + ExecutedException::VM(VMError::Evm(EVMError::OutOfGas)) => { + Some(ReceiptError::OutOfQuota) + } + ExecutedException::VM(VMError::Evm(EVMError::InvalidJumpDestination)) => { + Some(ReceiptError::BadJumpDestination) + } + ExecutedException::VM(VMError::Evm(EVMError::InvalidOpcode)) => { + Some(ReceiptError::BadInstruction) + } + ExecutedException::VM(VMError::Evm(EVMError::OutOfStack)) => { + Some(ReceiptError::OutOfStack) + } + ExecutedException::VM(VMError::Evm(EVMError::MutableCallInStaticContext)) => { + Some(ReceiptError::MutableCallInStaticContext) + } + ExecutedException::VM(VMError::Evm(EVMError::StackUnderflow)) => { + Some(ReceiptError::StackUnderflow) + } + ExecutedException::VM(VMError::Evm(EVMError::OutOfBounds)) => { + Some(ReceiptError::OutOfBounds) } + ExecutedException::Reverted => Some(ReceiptError::Reverted), + _ => Some(ReceiptError::Internal), + }); + + let tx_quota_used = + if receipt_error.is_some() && receipt_error != Some(ReceiptError::Internal) { + t.gas + } else { + ret.quota_used + }; + + // Note: quota_used in Receipt is self.current_quota_used, this will be + // handled by get_rich_receipt() while getting a single transaction receipt. + let cumulative_quota_used = context.quota_used + tx_quota_used; + let receipt = Receipt::new( + None, + cumulative_quota_used, + ret.logs, + receipt_error, + ret.account_nonce, + t.get_transaction_hash(), + ); + + self.receipts.push(receipt); + ret.quota_used + } + Err(err) => { + // FIXME: hasn't handle some errors. + let receipt_error = match err { + ExecutionError::NotEnoughBaseGas => Some(ReceiptError::NotEnoughBaseQuota), + // FIXME: need to handle this two situation. + ExecutionError::BlockQuotaLimitReached => { + Some(ReceiptError::BlockQuotaLimitReached) + } + ExecutionError::AccountQuotaLimitReached => { + Some(ReceiptError::AccountQuotaLimitReached) + } + ExecutionError::InvalidNonce => Some(ReceiptError::InvalidNonce), + ExecutionError::NotEnoughBalance => Some(ReceiptError::NotEnoughCash), + ExecutionError::Authentication( + AuthenticationError::NoTransactionPermission, + ) => Some(ReceiptError::NoTransactionPermission), + ExecutionError::Authentication(AuthenticationError::NoContractPermission) => { + Some(ReceiptError::NoContractPermission) + } + ExecutionError::Authentication(AuthenticationError::NoCallPermission) => { + Some(ReceiptError::NoCallPermission) + } + ExecutionError::Internal { .. } => Some(ReceiptError::ExecutionInternal), + ExecutionError::InvalidTransaction => Some(ReceiptError::TransactionMalformed), + _ => Some(ReceiptError::Internal), + }; + + let schedule = TxGasSchedule::default(); + // Bellow has a error, need gas*price before compare with balance + let tx_quota_used = match err { + ExecutionError::Internal(_) => t.gas, + _ => cmp::min( + self.state + .borrow_mut() + .balance(t.sender()) + .unwrap_or_else(|_| U256::from(0)), + U256::from(schedule.tx_gas), + ), + }; + + if conf.economical_model == EconomicalModel::Charge { + // When charge model, set the min(account.balance,gas_used) + let _ = self.deal_err_quota_cost( + t.sender(), + &context.coin_base, + tx_quota_used, + t.gas_price(), + ); } - self.receipts.push(outcome.receipt); + + let cumulative_quota_used = context.quota_used + tx_quota_used; + trace!( + "context quota used: {:?}, tx quota used: {:?}", + context.quota_used, + tx_quota_used + ); + let receipt = Receipt::new( + None, + cumulative_quota_used, + Vec::new(), + receipt_error, + 0.into(), + t.get_transaction_hash(), + ); + + self.receipts.push(receipt); + tx_quota_used + } + }; + + // Note: current_quota_used: Whole quota used for the ExecutedBlock. + self.current_quota_used += tx_quota_used; + if conf.check_options.quota { + if let Some(value) = self.account_gas.get_mut(t.sender()) { + *value -= tx_quota_used; } - _ => panic!("apply_transaction: There must be something wrong!"), + } + } + + fn deal_err_quota_cost( + &self, + sender: &Address, + coin_base: &Address, + quota: U256, + quota_price: U256, + ) -> U256 { + if quota_price == U256::zero() { + return quota; + } + let sender_balance = self.state.borrow_mut().balance(sender).unwrap(); + let tx_fee = quota * quota_price; + trace!("fee -{:?}, sender balance-{:?}", tx_fee, sender_balance); + let real_fee = cmp::min(sender_balance, tx_fee); + + if self + .state + .borrow_mut() + .sub_balance(sender, real_fee) + .is_err() + { + error!("Sub balance failed. tx_fee: {:?}", real_fee); + } else { + let _ = self.state.borrow_mut().add_balance(&coin_base, real_fee); + } + if real_fee == sender_balance { + sender_balance.checked_div(quota_price).unwrap() + } else { + quota } } /// Turn this into a `ClosedBlock`. - pub fn close(mut self, conf: &BlockSysConfig) -> ClosedBlock { - let mut env_info = self.env_info(); + pub fn close(self, conf: &BlockSysConfig) -> ClosedBlock { + let mut context = self.get_context(); // In protocol version 0, 1: // Auto Execution's env info author is default address // In protocol version > 1: // Auto Execution's env info author is block author if conf.chain_version < 2 { - env_info.author = Address::default(); + context.coin_base = Address::default(); } if conf.auto_exec { - auto_exec( - &mut self.state, - conf.auto_exec_quota_limit, - conf.economical_model, - env_info, - conf.chain_version, - ); - self.state.commit().expect("commit trie error"); + auto_exec(Arc::clone(&self.state), conf.auto_exec_quota_limit, context); + self.state.borrow_mut().commit().expect("commit trie error"); } + // Rebuild block let mut block = Block::new(self.block); - let state_root = *self.state.root(); + let state_root = self.state.borrow().root; block.set_state_root(state_root); let receipts_root = cita_merklehash::Tree::from_hashes( self.receipts @@ -222,28 +379,31 @@ impl ExecutedBlock { block.set_log_bloom(log_bloom); block.rehash(); + // Note: It is ok to new a state, because no cache and checkpoint used. + let mut state = CitaState::from_existing( + Arc::::clone(&self.state.borrow().db), + self.state.borrow().root, + ) + .expect("Get state from trie db"); + + state.cache = RefCell::new(self.state.borrow_mut().cache.to_owned().into_inner()); + ClosedBlock { block, receipts: self.receipts, - state: self.state, + state, } } } // Block that prepared to commit to db. -#[derive(Debug)] +// The CloseBlock will be share in two thread. +// #[derive(Debug)] pub struct ClosedBlock { /// Protobuf Block pub block: Block, pub receipts: Vec, - pub state: State, -} - -impl Drain for ClosedBlock { - /// Drop this object and return the underlieing database. - fn drain(self) -> StateDB { - self.state.drop().1 - } + pub state: CitaState, } impl ClosedBlock { @@ -289,6 +449,10 @@ impl ClosedBlock { .set_proposer(self.proposer().to_vec()); executed_info } + + pub fn clear_cache(&mut self) { + self.state.clear(); + } } impl Deref for ClosedBlock { @@ -305,6 +469,49 @@ impl DerefMut for ClosedBlock { } } +pub struct EVMBlockDataProvider { + context: Context, +} + +impl EVMBlockDataProvider { + pub fn new(context: Context) -> Self { + EVMBlockDataProvider { context } + } +} + +impl BlockDataProvider for EVMBlockDataProvider { + fn get_block_hash(&self, number: &U256) -> H256 { + // TODO: comment out what this function expects from context, since it will produce panics if the latter is inconsistent + if *number < U256::from(self.context.block_number) + && number.low_u64() >= cmp::max(256, self.context.block_number) - 256 + { + let index = self.context.block_number - number.low_u64() - 1; + assert!( + index < self.context.last_hashes.len() as u64, + format!( + "Inconsistent context, should contain at least {:?} last hashes", + index + 1 + ) + ); + let r = self.context.last_hashes[index as usize]; + trace!( + "ext: blockhash({}) -> {} self.context.block_number={}\n", + number, + r, + self.context.block_number + ); + r + } else { + trace!( + "ext: blockhash({}) -> null self.context.block_number={}\n", + number, + self.context.block_number + ); + H256::zero() + } + } +} + #[cfg(test)] mod tests { use super::*; @@ -322,4 +529,15 @@ mod tests { assert_eq!(body_rlp, body_encoded); } + + #[test] + fn test_encode_and_decode_null() { + let transactions = vec![]; + let body = BlockBody { transactions }; + let body_rlp = rlp::encode(&body); + let body: BlockBody = rlp::decode(&body_rlp); + let body_encoded = rlp::encode(&body).into_vec(); + + assert_eq!(body_rlp, body_encoded); + } } diff --git a/cita-executor/core/src/libexecutor/cache.rs b/cita-executor/core/src/libexecutor/cache.rs deleted file mode 100644 index e69de29bb..000000000 diff --git a/cita-executor/core/src/libexecutor/call_request.rs b/cita-executor/core/src/libexecutor/call_request.rs index 38c13dcfc..70de538d0 100644 --- a/cita-executor/core/src/libexecutor/call_request.rs +++ b/cita-executor/core/src/libexecutor/call_request.rs @@ -1,23 +1,20 @@ -// CITA -// Copyright 2016-2019 Cryptape Technologies LLC. - -// This program is free software: you can redistribute it -// and/or modify it under the terms of the GNU 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 General Public License for more details. - -// You should have received a copy of the GNU General Public License -// along with this program. If not, see . +// Copyright Cryptape Technologies LLC. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. use cita_types::Address; use libproto::request::Call; -use util::Bytes; +use types::Bytes; /// Call request #[derive(Debug, Default, PartialEq)] diff --git a/cita-executor/core/src/libexecutor/command.rs b/cita-executor/core/src/libexecutor/command.rs index 84b630df0..8d4a7dfc5 100644 --- a/cita-executor/core/src/libexecutor/command.rs +++ b/cita-executor/core/src/libexecutor/command.rs @@ -1,83 +1,84 @@ -// CITA -// Copyright 2016-2019 Cryptape Technologies LLC. - -// This program is free software: you can redistribute it -// and/or modify it under the terms of the GNU 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 General Public License for more details. - -// You should have received a copy of the GNU General Public License -// along with this program. If not, see . +// Copyright Cryptape Technologies LLC. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. use super::economical_model::EconomicalModel; +use super::executor::CitaTrieDB; use super::executor::{make_consensus_config, Executor}; use super::sys_config::GlobalSysConfig; -use crate::call_analytics::CallAnalytics; +use crate::cita_executive::{CitaExecutive, ExecutedResult as CitaExecuted}; +use crate::contracts::native::factory::Factory as NativeFactory; use crate::contracts::solc::{ sys_config::ChainId, PermissionManagement, SysConfig, VersionManager, }; -use crate::engines::NullEngine; -use crate::error::CallError; -use crate::executive::{Executed, Executive, TransactOptions}; +use crate::libexecutor::block::EVMBlockDataProvider; pub use crate::libexecutor::block::*; use crate::libexecutor::call_request::CallRequest; -use crate::state::State; -use crate::state_db::StateDB; -use crate::types::ids::BlockId; +use crate::trie_db::TrieDB; +use crate::types::block_number::{BlockTag, Tag}; +use crate::types::context::Context; +use crate::types::errors::CallError; use crate::types::transaction::{Action, SignedTransaction, Transaction}; pub use byteorder::{BigEndian, ByteOrder}; +use cita_database::RocksDB; use cita_types::traits::LowerHex; use cita_types::{Address, H256, U256}; +use cita_vm::state::{State as CitaState, StateObjectInfo}; use crossbeam_channel::{Receiver, Sender}; -use evm::env_info::EnvInfo; use jsonrpc_types::rpc_types::{ - BlockNumber, BlockTag, EconomicalModel as RpcEconomicalModel, MetaData, + BlockNumber as RpcBlockNumber, BlockTag as RpcBlockTag, EconomicalModel as RpcEconomicalModel, + MetaData, }; use libproto::ExecutedResult; use serde_json; +use std::cell::RefCell; use std::convert::{From, Into}; use std::fmt; use std::sync::Arc; -use util::Bytes; +use types::Bytes; use util::RwLock; #[cfg_attr(feature = "cargo-clippy", allow(clippy::large_enum_variant))] pub enum Command { - StateAt(BlockId), + StateAt(BlockTag), GenState(H256, H256), - CodeAt(Address, BlockId), - ABIAt(Address, BlockId), - BalanceAt(Address, BlockId), - NonceAt(Address, BlockId), - ETHCall(CallRequest, BlockId), + CodeAt(Address, BlockTag), + ABIAt(Address, BlockTag), + BalanceAt(Address, BlockTag), + NonceAt(Address, BlockTag), + ETHCall(CallRequest, BlockTag), SignCall(CallRequest), - Call(SignedTransaction, BlockId, CallAnalytics), + Call(SignedTransaction, BlockTag), ChainID, Metadata(String), EconomicalModel, LoadExecutedResult(u64), Grow(ClosedBlock), - Exit(BlockId), + Exit(BlockTag), CloneExecutorReader, } #[cfg_attr(feature = "cargo-clippy", allow(clippy::large_enum_variant))] pub enum CommandResp { - StateAt(Option>), - GenState(Option>), + StateAt(Option>), + GenState(Option>), CodeAt(Option), ABIAt(Option), BalanceAt(Option), NonceAt(Option), ETHCall(Result), SignCall(SignedTransaction), - Call(Result), + Call(Result), ChainID(Option), Metadata(Result), EconomicalModel(EconomicalModel), @@ -98,7 +99,7 @@ impl fmt::Display for Command { Command::NonceAt(_, _) => write!(f, "Command::NonceAt"), Command::ETHCall(_, _) => write!(f, "Command::ETHCall"), Command::SignCall(_) => write!(f, "Command::SignCall"), - Command::Call(_, _, _) => write!(f, "Command::Call"), + Command::Call(_, _) => write!(f, "Command::Call"), Command::ChainID => write!(f, "Command::ChainID "), Command::Metadata(_) => write!(f, "Command::Metadata"), Command::EconomicalModel => write!(f, "Command::EconomicalModel"), @@ -135,54 +136,49 @@ impl fmt::Display for CommandResp { pub trait Commander { fn operate(&mut self, command: Command) -> CommandResp; - fn state_at(&self, block_id: BlockId) -> Option>; - fn gen_state(&self, root: H256, parent_hash: H256) -> Option>; - fn code_at(&self, address: &Address, block_id: BlockId) -> Option; - fn abi_at(&self, address: &Address, block_id: BlockId) -> Option; - fn balance_at(&self, address: &Address, block_id: BlockId) -> Option; - fn nonce_at(&self, address: &Address, block_id: BlockId) -> Option; - fn eth_call(&self, request: CallRequest, block_id: BlockId) -> Result; + fn state_at(&self, block_tag: BlockTag) -> Option>; + fn gen_state(&self, root: H256, parent_hash: H256) -> Option>; + fn code_at(&self, address: &Address, block_tag: BlockTag) -> Option; + fn abi_at(&self, address: &Address, block_tag: BlockTag) -> Option; + fn balance_at(&self, address: &Address, block_tag: BlockTag) -> Option; + fn nonce_at(&self, address: &Address, block_tag: BlockTag) -> Option; + fn eth_call(&self, request: CallRequest, block_tag: BlockTag) -> Result; fn sign_call(&self, request: CallRequest) -> SignedTransaction; - fn call( - &self, - t: &SignedTransaction, - block_id: BlockId, - analytics: CallAnalytics, - ) -> Result; + fn call(&self, t: &SignedTransaction, block_tag: BlockTag) -> Result; fn chain_id(&self) -> Option; fn metadata(&self, data: String) -> Result; fn economical_model(&self) -> EconomicalModel; fn load_executed_result(&self, height: u64) -> ExecutedResult; - fn grow(&mut self, closed_block: ClosedBlock) -> ExecutedResult; - fn exit(&mut self, rollback_id: BlockId); + fn grow(&mut self, closed_block: &ClosedBlock) -> ExecutedResult; + fn exit(&mut self, rollback_id: BlockTag); fn clone_executor_reader(&mut self) -> Self; } impl Commander for Executor { fn operate(&mut self, command: Command) -> CommandResp { match command { - Command::StateAt(block_id) => CommandResp::StateAt(self.state_at(block_id)), + Command::StateAt(block_tag) => CommandResp::StateAt(self.state_at(block_tag)), Command::GenState(root, parent_hash) => { CommandResp::GenState(self.gen_state(root, parent_hash)) } - Command::CodeAt(address, block_id) => { - CommandResp::CodeAt(self.code_at(&address, block_id)) + Command::CodeAt(address, block_tag) => { + CommandResp::CodeAt(self.code_at(&address, block_tag)) } - Command::ABIAt(address, block_id) => { - CommandResp::ABIAt(self.abi_at(&address, block_id)) + Command::ABIAt(address, block_tag) => { + CommandResp::ABIAt(self.abi_at(&address, block_tag)) } - Command::BalanceAt(address, block_id) => { - CommandResp::BalanceAt(self.balance_at(&address, block_id)) + Command::BalanceAt(address, block_tag) => { + CommandResp::BalanceAt(self.balance_at(&address, block_tag)) } - Command::NonceAt(address, block_id) => { - CommandResp::NonceAt(self.nonce_at(&address, block_id)) + Command::NonceAt(address, block_tag) => { + CommandResp::NonceAt(self.nonce_at(&address, block_tag)) } - Command::ETHCall(call_request, block_id) => { - CommandResp::ETHCall(self.eth_call(call_request, block_id)) + Command::ETHCall(call_request, block_tag) => { + CommandResp::ETHCall(self.eth_call(call_request, block_tag)) } Command::SignCall(call_request) => CommandResp::SignCall(self.sign_call(call_request)), - Command::Call(signed_transaction, block_id, call_analytics) => { - CommandResp::Call(self.call(&signed_transaction, block_id, call_analytics)) + Command::Call(signed_transaction, block_tag) => { + CommandResp::Call(self.call(&signed_transaction, block_tag)) } Command::ChainID => CommandResp::ChainID(self.chain_id()), Command::Metadata(data) => CommandResp::Metadata(self.metadata(data)), @@ -190,7 +186,11 @@ impl Commander for Executor { Command::LoadExecutedResult(height) => { CommandResp::LoadExecutedResult(self.load_executed_result(height)) } - Command::Grow(closed_block) => CommandResp::Grow(self.grow(closed_block)), + Command::Grow(mut closed_block) => { + let r = self.grow(&closed_block); + closed_block.clear_cache(); + CommandResp::Grow(r) + } Command::Exit(rollback_id) => { self.exit(rollback_id); CommandResp::Exit @@ -202,49 +202,45 @@ impl Commander for Executor { } /// Attempt to get a copy of a specific block's final state. - fn state_at(&self, id: BlockId) -> Option> { + fn state_at(&self, id: BlockTag) -> Option> { self.block_header(id) .and_then(|h| self.gen_state(*h.state_root(), *h.parent_hash())) } /// Generate block's final state. - fn gen_state(&self, root: H256, parent_hash: H256) -> Option> { - let db = self.state_db.read().boxed_clone_canon(&parent_hash); - State::from_existing(db, root, U256::from(0), self.factories.clone()).ok() + fn gen_state(&self, root: H256, _parent_hash: H256) -> Option> { + // FIXME: There is a RWLock for clone a db, is it ok for using Arc::clone? + CitaState::from_existing(Arc::::clone(&self.state_db), root).ok() } /// Get code by address - fn code_at(&self, address: &Address, id: BlockId) -> Option { - self.state_at(id) - .and_then(|s| s.code(address).ok()) - .and_then(|c| c.map(|c| (&*c).clone())) + fn code_at(&self, address: &Address, id: BlockTag) -> Option { + self.state_at(id).and_then(|mut s| s.code(address).ok()) } /// Get abi by address - fn abi_at(&self, address: &Address, id: BlockId) -> Option { - self.state_at(id) - .and_then(|s| s.abi(address).ok()) - .and_then(|c| c.map(|c| (&*c).clone())) + fn abi_at(&self, address: &Address, id: BlockTag) -> Option { + self.state_at(id).and_then(|mut s| s.abi(address).ok()) } /// Get balance by address - fn balance_at(&self, address: &Address, id: BlockId) -> Option { + fn balance_at(&self, address: &Address, id: BlockTag) -> Option { self.state_at(id) - .and_then(|s| s.balance(address).ok()) + .and_then(|mut s| s.balance(address).ok()) .map(|c| { - let mut bytes = [0u8; 32]; - c.to_big_endian(&mut bytes); - bytes.to_vec() + let balance = &mut [0u8; 32]; + c.to_big_endian(balance); + balance.to_vec() }) } - fn nonce_at(&self, address: &Address, id: BlockId) -> Option { - self.state_at(id).and_then(|s| s.nonce(address).ok()) + fn nonce_at(&self, address: &Address, id: BlockTag) -> Option { + self.state_at(id).and_then(|mut s| s.nonce(address).ok()) } - fn eth_call(&self, request: CallRequest, id: BlockId) -> Result { + fn eth_call(&self, request: CallRequest, id: BlockTag) -> Result { let signed = self.sign_call(request); - let result = self.call(&signed, id, Default::default()); + let result = self.call(&signed, id); result .map(|b| b.output) .or_else(|e| Err(format!("Call Error {}", e))) @@ -260,24 +256,18 @@ impl Commander for Executor { value: U256::zero(), data: request.data.map_or_else(Vec::new, |d| d.to_vec()), block_limit: u64::max_value(), - // TODO: Should Fixed? chain_id: U256::default(), version: 0u32, } .fake_sign(from) } - fn call( - &self, - t: &SignedTransaction, - block_id: BlockId, - analytics: CallAnalytics, - ) -> Result { - let header = self.block_header(block_id).ok_or(CallError::StatePruned)?; + fn call(&self, t: &SignedTransaction, block_tag: BlockTag) -> Result { + let header = self.block_header(block_tag).ok_or(CallError::StatePruned)?; let last_hashes = self.build_last_hashes(Some(header.hash().unwrap()), header.number()); - let env_info = EnvInfo { - number: header.number(), - author: *header.proposer(), + let mut context = Context { + block_number: header.number(), + coin_base: *header.proposer(), timestamp: if self.eth_compatibility { header.timestamp() / 1000 } else { @@ -285,33 +275,50 @@ impl Commander for Executor { }, difficulty: U256::default(), last_hashes: ::std::sync::Arc::new(last_hashes), - gas_used: *header.quota_used(), - gas_limit: *header.quota_limit(), - account_gas_limit: u64::max_value().into(), + quota_used: *header.quota_used(), + block_quota_limit: *header.quota_limit(), + account_quota_limit: u64::max_value().into(), }; - // that's just a copy of the state. - let mut state = self.state_at(block_id).ok_or(CallError::StatePruned)?; + context.block_quota_limit = U256::from(self.sys_config.block_quota_limit); - let options = TransactOptions { - tracing: analytics.transaction_tracing, - vm_tracing: analytics.vm_tracing, - }; + // FIXME: Need to implement state_at + // that's just a copy of the state. + // let mut state = self.state_at(block_tag).ok_or(CallError::StatePruned)?; // Never check permission and quota let mut conf = self.sys_config.block_sys_config.clone(); conf.exempt_checking(); - Executive::new( - &mut state, - &env_info, - &*self.engine, - &self.factories.vm, - &self.factories.native, - false, - EconomicalModel::Quota, - self.sys_config.block_sys_config.chain_version, + let block_data_provider = EVMBlockDataProvider::new(context.clone()); + let native_factory = NativeFactory::default(); + + let state_root = if let Some(h) = self.block_header(block_tag) { + (*h.state_root()) + } else { + error!("Can not get state root from trie db!"); + return Err(CallError::StatePruned); + }; + + let state = match CitaState::from_existing( + Arc::>::clone(&self.state_db), + state_root, + ) { + Ok(state_db) => state_db, + Err(e) => { + error!("Can not get state from trie db! error: {:?}", e); + return Err(CallError::StatePruned); + } + }; + + let state = Arc::new(RefCell::new(state)); + CitaExecutive::new( + Arc::new(block_data_provider), + state, + &native_factory, + &context, + conf.economical_model, ) - .transact(t, options, &conf) + .exec(t, &conf) .map_err(Into::into) } @@ -340,15 +347,15 @@ impl Commander for Executor { version: 0, economical_model, }; - let result = serde_json::from_str::(&data) + let result = serde_json::from_str::(&data) .map_err(|err| format!("{:?}", err)) - .and_then(|number: BlockNumber| { + .and_then(|number: RpcBlockNumber| { let current_height = self.get_current_height(); let number = match number { - BlockNumber::Tag(BlockTag::Earliest) => 0, - BlockNumber::Height(n) => n.into(), - BlockNumber::Tag(BlockTag::Latest) => current_height.saturating_sub(1), - BlockNumber::Tag(BlockTag::Pending) => current_height, + RpcBlockNumber::Tag(RpcBlockTag::Earliest) => 0, + RpcBlockNumber::Height(n) => n.into(), + RpcBlockNumber::Tag(RpcBlockTag::Latest) => current_height.saturating_sub(1), + RpcBlockNumber::Tag(RpcBlockTag::Pending) => current_height, }; if number > current_height { Err(format!( @@ -361,35 +368,35 @@ impl Commander for Executor { }) .and_then(|number| { let sys_config = SysConfig::new(&self); - let block_id = BlockId::Number(number); + let block_tag = BlockTag::Height(number); sys_config - .chain_name(block_id) + .chain_name(block_tag) .map(|chain_name| metadata.chain_name = chain_name) .ok_or_else(|| "Query chain name failed".to_owned())?; sys_config - .operator(block_id) + .operator(block_tag) .map(|operator| metadata.operator = operator) .ok_or_else(|| "Query operator failed".to_owned())?; sys_config - .website(block_id) + .website(block_tag) .map(|website| metadata.website = website) .ok_or_else(|| "Query website failed".to_owned())?; - self.block_header(BlockId::Earliest) + self.block_header(BlockTag::Tag(Tag::Earliest)) .map(|header| metadata.genesis_timestamp = header.timestamp()) .ok_or_else(|| "Query genesis_timestamp failed".to_owned())?; self.node_manager() - .shuffled_stake_nodes(block_id) + .shuffled_stake_nodes(block_tag) .map(|validators| { metadata.validators = validators.into_iter().map(Into::into).collect::>() }) .ok_or_else(|| "Query validators failed".to_owned())?; sys_config - .block_interval(block_id) + .block_interval(block_tag) .map(|block_interval| metadata.block_interval = block_interval) .ok_or_else(|| "Query block_interval failed".to_owned())?; sys_config - .token_info(block_id) + .token_info(block_tag) .map(|token_info| { metadata.token_name = token_info.name; metadata.token_avatar = token_info.avatar; @@ -399,7 +406,7 @@ impl Commander for Executor { let version_manager = VersionManager::new(&self); metadata.version = version_manager - .get_version(block_id) + .get_version(block_tag) .unwrap_or_else(VersionManager::default_version); sys_config @@ -425,7 +432,7 @@ impl Commander for Executor { self.executed_result_by_height(height) } - fn grow(&mut self, closed_block: ClosedBlock) -> ExecutedResult { + fn grow(&mut self, closed_block: &ClosedBlock) -> ExecutedResult { info!( "executor grow according to ClosedBlock(height: {}, hash: {:?}, parent_hash: {:?}, \ timestamp: {}, state_root: {:?}, transaction_root: {:?}, proposer: {:?})", @@ -438,10 +445,11 @@ impl Commander for Executor { closed_block.proposer(), ); let are_permissions_changed = { - let cache = closed_block.state.cache(); + let cache = closed_block.state.cache.clone(); let permission_management = PermissionManagement::new(self); - let permissions = permission_management.permission_addresses(BlockId::Pending); - cache.iter().any(|(address, ref _a)| { + let permissions = + permission_management.permission_addresses(BlockTag::Tag(Tag::Pending)); + cache.into_inner().iter().any(|(address, ref _a)| { &address.lower_hex()[..34] == "ffffffffffffffffffffffffffffffffff" || permissions.contains(&address) }) @@ -457,7 +465,8 @@ impl Commander for Executor { self.write_batch(closed_block); if are_permissions_changed { - self.sys_config = GlobalSysConfig::load(&self, BlockId::Pending); + trace!("Permissions changed, reload global sys config."); + self.sys_config = GlobalSysConfig::load(&self, BlockTag::Tag(Tag::Pending)); } let mut executed_result = ExecutedResult::new(); let consensus_config = make_consensus_config(self.sys_config.clone()); @@ -466,19 +475,17 @@ impl Commander for Executor { executed_result } - fn exit(&mut self, rollback_id: BlockId) { + fn exit(&mut self, rollback_id: BlockTag) { self.rollback_current_height(rollback_id); self.close(); } fn clone_executor_reader(&mut self) -> Self { let current_header = self.current_header.read().clone(); + let state_db = self.state_db.clone(); let db = self.db.clone(); - let fake_parent_hash: H256 = Default::default(); - let state_db = self.state_db.read().boxed_clone_canon(&fake_parent_hash); - let factories = self.factories.clone(); + // let fake_parent_hash: H256 = Default::default(); let sys_config = self.sys_config.clone(); - let engine = Box::new(NullEngine::cita()); let fsm_req_receiver = self.fsm_req_receiver.clone(); let fsm_resp_sender = self.fsm_resp_sender.clone(); let command_req_receiver = self.command_req_receiver.clone(); @@ -486,11 +493,9 @@ impl Commander for Executor { let eth_compatibility = self.eth_compatibility; Executor { current_header: RwLock::new(current_header), + state_db, db, - state_db: Arc::new(RwLock::new(state_db)), - factories, sys_config, - engine, fsm_req_receiver, fsm_resp_sender, command_req_receiver, @@ -505,9 +510,9 @@ impl Commander for Executor { pub fn state_at( command_req_sender: &Sender, command_resp_receiver: &Receiver, - block_id: BlockId, -) -> Option> { - command_req_sender.send(Command::StateAt(block_id)); + block_tag: BlockTag, +) -> Option> { + let _ = command_req_sender.send(Command::StateAt(block_tag)); match command_resp_receiver.recv().unwrap() { CommandResp::StateAt(r) => r, _ => unimplemented!(), @@ -519,8 +524,8 @@ pub fn gen_state( command_resp_receiver: &Receiver, root: H256, parent_hash: H256, -) -> Option> { - command_req_sender.send(Command::GenState(root, parent_hash)); +) -> Option> { + let _ = command_req_sender.send(Command::GenState(root, parent_hash)); match command_resp_receiver.recv().unwrap() { CommandResp::GenState(r) => r, _ => unimplemented!(), @@ -531,9 +536,9 @@ pub fn code_at( command_req_sender: &Sender, command_resp_receiver: &Receiver, address: Address, - block_id: BlockId, + block_tag: BlockTag, ) -> Option { - command_req_sender.send(Command::CodeAt(address, block_id)); + let _ = command_req_sender.send(Command::CodeAt(address, block_tag)); match command_resp_receiver.recv().unwrap() { CommandResp::CodeAt(r) => r, _ => unimplemented!(), @@ -544,9 +549,9 @@ pub fn abi_at( command_req_sender: &Sender, command_resp_receiver: &Receiver, address: Address, - block_id: BlockId, + block_tag: BlockTag, ) -> Option { - command_req_sender.send(Command::ABIAt(address, block_id)); + let _ = command_req_sender.send(Command::ABIAt(address, block_tag)); match command_resp_receiver.recv().unwrap() { CommandResp::ABIAt(r) => r, _ => unimplemented!(), @@ -557,9 +562,9 @@ pub fn balance_at( command_req_sender: &Sender, command_resp_receiver: &Receiver, address: Address, - block_id: BlockId, + block_tag: BlockTag, ) -> Option { - command_req_sender.send(Command::BalanceAt(address, block_id)); + let _ = command_req_sender.send(Command::BalanceAt(address, block_tag)); match command_resp_receiver.recv().unwrap() { CommandResp::BalanceAt(r) => r, _ => unimplemented!(), @@ -570,9 +575,9 @@ pub fn nonce_at( command_req_sender: &Sender, command_resp_receiver: &Receiver, address: Address, - block_id: BlockId, + block_tag: BlockTag, ) -> Option { - command_req_sender.send(Command::NonceAt(address, block_id)); + let _ = command_req_sender.send(Command::NonceAt(address, block_tag)); match command_resp_receiver.recv().unwrap() { CommandResp::NonceAt(r) => r, _ => unimplemented!(), @@ -583,9 +588,9 @@ pub fn eth_call( command_req_sender: &Sender, command_resp_receiver: &Receiver, call_request: CallRequest, - block_id: BlockId, + block_tag: BlockTag, ) -> Result { - command_req_sender.send(Command::ETHCall(call_request, block_id)); + let _ = command_req_sender.send(Command::ETHCall(call_request, block_tag)); match command_resp_receiver.recv().unwrap() { CommandResp::ETHCall(r) => r, _ => unimplemented!(), @@ -597,7 +602,7 @@ pub fn sign_call( command_resp_receiver: &Receiver, call_request: CallRequest, ) -> SignedTransaction { - command_req_sender.send(Command::SignCall(call_request)); + let _ = command_req_sender.send(Command::SignCall(call_request)); match command_resp_receiver.recv().unwrap() { CommandResp::SignCall(r) => r, _ => unimplemented!(), @@ -608,10 +613,10 @@ pub fn call( command_req_sender: &Sender, command_resp_receiver: &Receiver, signed_transaction: SignedTransaction, - block_id: BlockId, - call_analytics: CallAnalytics, -) -> Result { - command_req_sender.send(Command::Call(signed_transaction, block_id, call_analytics)); + + block_tag: BlockTag, +) -> Result { + let _ = command_req_sender.send(Command::Call(signed_transaction, block_tag)); match command_resp_receiver.recv().unwrap() { CommandResp::Call(r) => r, _ => unimplemented!(), @@ -622,7 +627,7 @@ pub fn chain_id( command_req_sender: &Sender, command_resp_receiver: &Receiver, ) -> Option { - command_req_sender.send(Command::ChainID); + let _ = command_req_sender.send(Command::ChainID); match command_resp_receiver.recv().unwrap() { CommandResp::ChainID(r) => r, _ => unimplemented!(), @@ -634,7 +639,7 @@ pub fn metadata( command_resp_receiver: &Receiver, data: String, ) -> Result { - command_req_sender.send(Command::Metadata(data)); + let _ = command_req_sender.send(Command::Metadata(data)); match command_resp_receiver.recv().unwrap() { CommandResp::Metadata(r) => r, _ => unimplemented!(), @@ -645,7 +650,7 @@ pub fn economical_model( command_req_sender: &Sender, command_resp_receiver: &Receiver, ) -> EconomicalModel { - command_req_sender.send(Command::EconomicalModel); + let _ = command_req_sender.send(Command::EconomicalModel); match command_resp_receiver.recv().unwrap() { CommandResp::EconomicalModel(r) => r, _ => unimplemented!(), @@ -657,7 +662,7 @@ pub fn load_executed_result( command_resp_receiver: &Receiver, height: u64, ) -> ExecutedResult { - command_req_sender.send(Command::LoadExecutedResult(height)); + let _ = command_req_sender.send(Command::LoadExecutedResult(height)); match command_resp_receiver.recv().unwrap() { CommandResp::LoadExecutedResult(r) => r, _ => unimplemented!(), @@ -669,7 +674,7 @@ pub fn grow( command_resp_receiver: &Receiver, closed_block: ClosedBlock, ) -> ExecutedResult { - command_req_sender.send(Command::Grow(closed_block)); + let _ = command_req_sender.send(Command::Grow(closed_block)); match command_resp_receiver.recv().unwrap() { CommandResp::Grow(r) => r, _ => unimplemented!(), @@ -679,9 +684,9 @@ pub fn grow( pub fn exit( command_req_sender: &Sender, command_resp_receiver: &Receiver, - rollback_id: BlockId, + rollback_id: BlockTag, ) { - command_req_sender.send(Command::Exit(rollback_id)); + let _ = command_req_sender.send(Command::Exit(rollback_id)); match command_resp_receiver.recv().unwrap() { CommandResp::Exit => {} _ => unimplemented!(), @@ -692,7 +697,7 @@ pub fn clone_executor_reader( command_req_sender: &Sender, command_resp_receiver: &Receiver, ) -> Executor { - command_req_sender.send(Command::CloneExecutorReader); + let _ = command_req_sender.send(Command::CloneExecutorReader); match command_resp_receiver.recv().unwrap() { CommandResp::CloneExecutorReader(r) => r, _ => unimplemented!(), diff --git a/cita-executor/core/src/libexecutor/economical_model.rs b/cita-executor/core/src/libexecutor/economical_model.rs index f6b893837..08b8c6b66 100644 --- a/cita-executor/core/src/libexecutor/economical_model.rs +++ b/cita-executor/core/src/libexecutor/economical_model.rs @@ -1,19 +1,16 @@ -// CITA -// Copyright 2016-2019 Cryptape Technologies LLC. - -// This program is free software: you can redistribute it -// and/or modify it under the terms of the GNU 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 General Public License for more details. - -// You should have received a copy of the GNU General Public License -// along with this program. If not, see . +// Copyright Cryptape Technologies LLC. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. use jsonrpc_types::rpc_types::EconomicalModel as RpcEconomicalModel; diff --git a/cita-executor/core/src/libexecutor/executor.rs b/cita-executor/core/src/libexecutor/executor.rs index 874afa13a..2d0ea1cb0 100644 --- a/cita-executor/core/src/libexecutor/executor.rs +++ b/cita-executor/core/src/libexecutor/executor.rs @@ -1,58 +1,48 @@ -// CITA -// Copyright 2016-2019 Cryptape Technologies LLC. - -// This program is free software: you can redistribute it -// and/or modify it under the terms of the GNU 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 General Public License for more details. - -// You should have received a copy of the GNU General Public License -// along with this program. If not, see . +// Copyright Cryptape Technologies LLC. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. use super::command::{Command, CommandResp, Commander}; use super::fsm::FSM; use super::sys_config::GlobalSysConfig; -use crate::bloomchain::group::{BloomGroup, BloomGroupDatabase, GroupPosition}; -use crate::cita_db::kvdb::{DBTransaction, Database, DatabaseConfig}; -use crate::cita_db::trie::{TrieFactory, TrieSpec}; -use crate::cita_db::{journaldb, KeyValueDB}; -use crate::contracts::{native::factory::Factory as NativeFactory, solc::NodeManager}; -use crate::db; -use crate::db::*; -use crate::engines::{Engine, NullEngine}; -use crate::factory::*; + +use crate::contracts::solc::NodeManager; +use crate::core::context::LastHashes; use crate::header::*; pub use crate::libexecutor::block::*; use crate::libexecutor::genesis::Genesis; -use crate::state_db::StateDB; -use crate::types::extras::*; -use crate::types::ids::BlockId; +use crate::trie_db::TrieDB; +use crate::types::block_number::{BlockTag, Tag}; +use crate::types::db_indexes; +use crate::types::db_indexes::DBIndex; pub use byteorder::{BigEndian, ByteOrder}; +use cita_database::{Config, DataCategory, Database, RocksDB, NUM_COLUMNS}; use cita_types::H256; use crossbeam_channel::{Receiver, Sender}; -use evm::env_info::LastHashes; -use evm::Factory as EvmFactory; use libproto::{ConsensusConfig, ExecutedResult}; -use std::convert::{From, Into}; +use rlp::{decode, encode}; +use std::convert::Into; use std::sync::Arc; -use std::time::Instant; use util::RwLock; -use util::UtilError; + +pub type CitaTrieDB = TrieDB; +pub type CitaDB = RocksDB; pub struct Executor { pub current_header: RwLock
, - pub db: Arc, - pub state_db: Arc>, - pub factories: Factories, - + pub state_db: Arc, + pub db: Arc, pub sys_config: GlobalSysConfig, - pub engine: Box, pub fsm_req_receiver: Receiver, pub fsm_resp_sender: Sender, @@ -66,8 +56,6 @@ impl Executor { #[allow(unknown_lints, clippy::too_many_arguments)] // TODO clippy pub fn init( genesis_path: &str, - journaldb_type: &str, - statedb_cache_size: usize, data_path: String, fsm_req_receiver: Receiver, fsm_resp_sender: Sender, @@ -76,37 +64,30 @@ impl Executor { eth_compatibility: bool, ) -> Executor { let mut genesis = Genesis::init(&genesis_path); - let database = open_state_db(data_path); - let database: Arc = Arc::new(database); - let journaldb_type = journaldb_type - .parse() - .unwrap_or(journaldb::Algorithm::Archive); - let journal_db = journaldb::new(Arc::clone(&database), journaldb_type, COL_STATE); - let state_db = StateDB::new(journal_db, statedb_cache_size); - let trie_factory = TrieFactory::new(TrieSpec::Generic); - let factories = Factories { - vm: EvmFactory::default(), - native: NativeFactory::default(), - trie: trie_factory, - accountdb: Default::default(), - }; - let current_header = match get_current_header(&*database) { + + // TODO: Can remove NUM_COLUMNS(useless) + let config = Config::with_category_num(NUM_COLUMNS); + let nosql_path = data_path + "/statedb"; + let rocks_db = RocksDB::open(&nosql_path, &config).unwrap(); + let db = Arc::new(rocks_db); + let state_db = Arc::new(TrieDB::new(db.clone())); + + let current_header = match get_current_header(db.clone()) { Some(header) => header, None => { warn!("Not found exist block within database. Loading genesis block..."); genesis - .lazy_execute(&state_db, &factories) + // FIXME + .lazy_execute(state_db.clone()) .expect("failed to load genesis"); genesis.block.header().clone() } }; let mut executor = Executor { current_header: RwLock::new(current_header), - db: database, - state_db: Arc::new(RwLock::new(state_db)), - factories, + state_db, + db, sys_config: GlobalSysConfig::default(), - engine: Box::new(NullEngine::cita()), fsm_req_receiver, fsm_resp_sender, command_req_receiver, @@ -114,8 +95,7 @@ impl Executor { eth_compatibility, }; - executor.sys_config = GlobalSysConfig::load(&executor, BlockId::Pending); - + executor.sys_config = GlobalSysConfig::load(&executor, BlockTag::Tag(Tag::Pending)); info!( "executor init, current_height: {}, current_hash: {:?}", executor.get_current_height(), @@ -125,10 +105,11 @@ impl Executor { } pub fn close(&mut self) { + // FIXME: Need a close interface for db. // IMPORTANT: close and release database handler so that it will not // compact data/logs in background, which may effect snapshot // changing database when restore snapshot. - self.db.close(); + // self.db.close(); info!( "executor closed, current_height: {}", @@ -144,42 +125,45 @@ impl Executor { trace!("executor receive {}", command); match self.operate(command) { CommandResp::Exit => { - self.command_resp_sender.send(CommandResp::Exit); + let _ = self.command_resp_sender.send(CommandResp::Exit); return; } - command_resp => self.command_resp_sender.send(command_resp), - } + command_resp => { + let _ = self.command_resp_sender.send(command_resp); + } + }; } (None, Some(block)) => { let fsm_resp = self.into_fsm(block); - self.fsm_resp_sender.send(fsm_resp); + let _ = self.fsm_resp_sender.send(fsm_resp); } } } } + #[allow(clippy::zero_ptr, clippy::drop_copy)] fn recv(&self) -> (Option, Option) { let err_flag = (None, None); select! { - recv(self.command_req_receiver, command_req) => { + recv(self.command_req_receiver) -> command_req => { match command_req { - Some(command_req) => (Some(command_req), None), - None => err_flag, + Ok(command_req) => (Some(command_req), None), + Err(_) => err_flag, } }, - recv(self.fsm_req_receiver, fsm_req) => { + recv(self.fsm_req_receiver) -> fsm_req => { match fsm_req { - Some(fsm_req) => (None, Some(fsm_req)), - None => err_flag, + Ok(fsm_req) => (None, Some(fsm_req)), + Err(_) => err_flag, } } } } - pub fn rollback_current_height(&mut self, rollback_id: BlockId) { + pub fn rollback_current_height(&mut self, rollback_id: BlockTag) { let rollback_height: BlockNumber = match rollback_id { - BlockId::Number(height) => height, - BlockId::Earliest => 0, + BlockTag::Height(height) => height, + BlockTag::Tag(Tag::Earliest) => 0, _ => unimplemented!(), }; if self.get_current_height() != rollback_height { @@ -191,9 +175,16 @@ impl Executor { let rollback_hash = self .block_hash(rollback_height) .expect("the target block to roll back should exist"); - let mut batch = self.db.transaction(); - batch.write(db::COL_EXTRA, &CurrentHash, &rollback_hash); - self.db.write(batch).unwrap(); + + let current_hash_key = db_indexes::CurrentHash.get_index(); + let hash_value = encode(&rollback_hash).to_vec(); + self.db + .insert( + Some(DataCategory::Extra), + current_hash_key.to_vec(), + hash_value, + ) + .expect("Insert rollback hash error."); } let rollback_header = self.block_header_by_height(rollback_height).unwrap(); @@ -204,8 +195,7 @@ impl Executor { /// 1. Header /// 2. CurrentHash /// 3. State - pub fn write_batch(&self, block: ClosedBlock) { - let mut batch = self.db.transaction(); + pub fn write_batch(&self, block: &ClosedBlock) { let height = block.number(); let hash = block.hash().unwrap(); let version = block.version(); @@ -216,30 +206,41 @@ impl Executor { version ); - batch.write(db::COL_HEADERS, &hash, block.header()); - batch.write(db::COL_EXTRA, &CurrentHash, &hash); - batch.write(db::COL_EXTRA, &height, &hash); - - let mut state = block.drain(); - // Store triedb changes in journal db - state - .journal_under(&mut batch, height, &hash) - .expect("DB commit failed"); - // state.sync_cache(); - self.db.write_buffered(batch); - - self.prune_ancient(state).expect("mark_canonical failed"); - - // Saving in db - let now = Instant::now(); - self.db.flush().expect("DB write failed."); - let new_now = Instant::now(); - debug!("db write use {:?}", new_now.duration_since(now)); + // Insert [hash : block_header]. + let hash_key = db_indexes::Hash2Header(hash).get_index(); + self.db + .insert( + Some(DataCategory::Headers), + hash_key.to_vec(), + block.header().rlp(), + ) + .expect("Insert block header error."); + + // Insert [CurrentHash : hash]. + let current_hash_key = db_indexes::CurrentHash.get_index(); + let hash_value = encode(&hash).to_vec(); + self.db + .insert( + Some(DataCategory::Extra), + current_hash_key.to_vec(), + hash_value.clone(), + ) + .expect("Insert block hash error."); + + // Insert [height : hash] + let height_key = db_indexes::BlockNumber2Hash(height).get_index(); + self.db + .insert(Some(DataCategory::Extra), height_key.to_vec(), hash_value) + .expect("Insert block hash error."); } /// Get block hash by number - fn block_hash(&self, index: BlockNumber) -> Option { - self.db.read(db::COL_EXTRA, &index) + fn block_hash(&self, number: BlockNumber) -> Option { + let height_key = db_indexes::BlockNumber2Hash(number).get_index(); + self.db + .get(Some(DataCategory::Extra), &height_key.to_vec()) + .map(|h| h.map(|hash| decode::(hash.as_slice()))) + .expect("Get block header error.") } fn current_state_root(&self) -> H256 { @@ -247,18 +248,18 @@ impl Executor { } pub fn genesis_header(&self) -> Header { - self.block_header(BlockId::Earliest) + self.block_header(BlockTag::Tag(Tag::Earliest)) .expect("failed to fetch genesis header") } - /// Get block header by BlockId - pub fn block_header(&self, id: BlockId) -> Option
{ - match id { - BlockId::Latest => self.block_header_by_height(self.get_latest_height()), - BlockId::Hash(hash) => self.block_header_by_hash(hash), - BlockId::Number(number) => self.block_header_by_height(number), - BlockId::Earliest => self.block_header_by_height(0), - BlockId::Pending => self.block_header_by_height(self.get_pending_height()), + /// Get block header by BlockTag + pub fn block_header(&self, tag: BlockTag) -> Option
{ + match tag { + BlockTag::Tag(Tag::Latest) => self.block_header_by_height(self.get_latest_height()), + BlockTag::Hash(hash) => self.block_header_by_hash(hash), + BlockTag::Height(number) => self.block_header_by_height(number), + BlockTag::Tag(Tag::Earliest) => self.block_header_by_height(0), + BlockTag::Tag(Tag::Pending) => self.block_header_by_height(self.get_pending_height()), } } @@ -282,7 +283,12 @@ impl Executor { return Some(header.clone()); } } - self.db.read(db::COL_HEADERS, &hash) + + let hash_key = db_indexes::Hash2Header(hash).get_index(); + self.db + .get(Some(DataCategory::Headers), &hash_key.to_vec()) + .map(|header| header.map(|bytes| decode::
(bytes.as_slice()))) + .expect("Get block header error.") } #[inline] @@ -342,13 +348,13 @@ impl Executor { // Postman do it to acquire recent 2 blocks' ExecutedResult and save them into backlogs, // which be used to validate arrived Proof (ExecutedResult has "validators" config) pub fn executed_result_by_height(&self, height: u64) -> ExecutedResult { - let block_id = BlockId::Number(height); - let sys_config = GlobalSysConfig::load(&self, block_id); + let block_tag = BlockTag::Height(height); + let sys_config = GlobalSysConfig::load(&self, block_tag); let consensus_config = make_consensus_config(sys_config); let executed_header = self - .block_header(block_id) - .unwrap() - .generate_executed_header(); + .block_header(block_tag) + .map(types::header::Header::generate_executed_header) + .unwrap_or_default(); let mut executed_result = ExecutedResult::new(); executed_result.set_config(consensus_config); executed_result @@ -357,34 +363,6 @@ impl Executor { executed_result } - fn prune_ancient(&self, mut state_db: StateDB) -> Result<(), UtilError> { - let number = match state_db.journal_db().latest_era() { - Some(n) => n, - None => return Ok(()), - }; - let history = 2; - // prune all ancient eras until we're below the memory target, - // but have at least the minimum number of states. - loop { - match state_db.journal_db().earliest_era() { - Some(era) if era + history <= number => { - trace!(target: "client", "Pruning state for ancient era {}", era); - match self.block_hash(era) { - Some(ancient_hash) => { - let mut batch = DBTransaction::new(); - state_db.mark_canonical(&mut batch, era, &ancient_hash)?; - self.db.write_buffered(batch); - state_db.journal_db().flush(); - } - None => debug!(target: "client", "Missing expected hash for block {}", era), - } - } - _ => break, // means that every era is kept, no pruning necessary. - } - } - Ok(()) - } - #[inline] pub fn node_manager(&self) -> NodeManager { NodeManager::new(self, self.genesis_header().timestamp()) @@ -393,14 +371,12 @@ impl Executor { pub fn to_executed_block(&self, open_block: OpenBlock) -> ExecutedBlock { let current_state_root = self.current_state_root(); let last_hashes = self.build_last_hashes(None, open_block.number() - 1); - let parent_hash = *open_block.parent_hash(); + // let parent_hash = *open_block.parent_hash(); ExecutedBlock::create( - self.factories.clone(), &self.sys_config.block_sys_config, - false, open_block, - self.state_db.read().boxed_clone_canon(&parent_hash), + self.state_db.clone(), current_state_root, last_hashes.into(), self.eth_compatibility, @@ -409,28 +385,25 @@ impl Executor { } } -impl<'a> BloomGroupDatabase for Executor { - fn blooms_at(&self, position: &GroupPosition) -> Option { - let position = LogGroupPosition::from(position.clone()); - self.db.read(db::COL_EXTRA, &position).map(Into::into) - } -} - -pub fn get_current_header(db: &KeyValueDB) -> Option
{ - let h: Option = db.read(db::COL_EXTRA, &CurrentHash); - if let Some(hash) = h { - db.read(db::COL_HEADERS, &hash) +pub fn get_current_header(db: Arc) -> Option
{ + let current_hash_key = db_indexes::CurrentHash.get_index(); + if let Ok(hash) = db.get(Some(DataCategory::Extra), ¤t_hash_key.to_vec()) { + let hash: H256 = if let Some(h) = hash { + decode(h.as_slice()) + } else { + return None; + }; + let hash_key = db_indexes::Hash2Header(hash).get_index(); + if let Ok(header) = db.get(Some(DataCategory::Headers), &hash_key.to_vec()) { + Some(decode::
(header.unwrap().as_slice())) + } else { + None + } } else { None } } -fn open_state_db(data_path: String) -> Database { - let database_config = DatabaseConfig::with_columns(db::NUM_COLUMNS); - let nosql_path = data_path + "/statedb"; - Database::open(&database_config, &nosql_path).unwrap() -} - pub fn make_consensus_config(sys_config: GlobalSysConfig) -> ConsensusConfig { let block_quota_limit = sys_config.block_quota_limit as u64; let account_quota_limit = sys_config.block_sys_config.account_quota_limit.into(); @@ -471,47 +444,47 @@ mod tests { use crate::libexecutor::command::{Command, CommandResp}; use crate::libexecutor::fsm::FSM; use crate::tests::helpers; - use crate::types::ids::BlockId; + use crate::types::block_number::{BlockTag, Tag}; use cita_crypto::{CreateKey, KeyPair}; use cita_types::Address; use std::thread; use std::time::Duration; - #[test] - #[cfg(feature = "sha3hash")] - fn test_chain_name_valid_block_number() { - use crate::contracts::solc::sys_config::SysConfig; - use crate::types::reserved_addresses; - use cita_types::H256; - use rustc_hex::FromHex; - use std::str::FromStr; - - let privkey = - H256::from("0x5f0258a4778057a8a7d97809bd209055b2fbafa654ce7d31ec7191066b9225e6"); - - let mut executor = helpers::init_executor(); - let to = Address::from_str(reserved_addresses::SYS_CONFIG).unwrap(); - let data = "c0c41f220000000000000000000000000000000000000000000\ - 000000000000000000020000000000000000000000000000000\ - 000000000000000000000000000000000531323334350000000\ - 00000000000000000000000000000000000000000000000"; - let code = data.from_hex().unwrap(); - let block = helpers::create_block(&executor, to, &code, (0, 1), &privkey); - - let closed_block = executor.into_fsm(block); - let _executed_result = executor.grow(closed_block); - - let chain_name_latest = SysConfig::new(&executor) - .chain_name(BlockId::Latest) - .unwrap(); - - let chain_name_pending = SysConfig::new(&executor) - .chain_name(BlockId::Pending) - .unwrap(); - - assert_eq!(chain_name_pending, "12345"); - assert_eq!(chain_name_latest, "test-chain"); - } + // #[test] + // #[cfg(feature = "sha3hash")] + // fn test_chain_name_valid_block_number() { + // use crate::contracts::solc::sys_config::SysConfig; + // use crate::types::reserved_addresses; + // use cita_types::H256; + // use rustc_hex::FromHex; + // use std::str::FromStr; + + // let privkey = + // H256::from("0x5f0258a4778057a8a7d97809bd209055b2fbafa654ce7d31ec7191066b9225e6"); + + // let mut executor = helpers::init_executor(); + // let to = Address::from_str(reserved_addresses::SYS_CONFIG).unwrap(); + // let data = "c0c41f220000000000000000000000000000000000000000000\ + // 000000000000000000020000000000000000000000000000000\ + // 000000000000000000000000000000000531323334350000000\ + // 00000000000000000000000000000000000000000000000"; + // let code = data.from_hex().unwrap(); + // let block = helpers::create_block(&executor, to, &code, (0, 1), &privkey); + + // let closed_block = executor.into_fsm(block); + // let _executed_result = executor.grow(closed_block); + + // let chain_name_latest = SysConfig::new(&executor) + // .chain_name(BlockTag::Tag(Tag::Latest)) + // .unwrap(); + + // let chain_name_pending = SysConfig::new(&executor) + // .chain_name(BlockTag::Tag(Tag::Pending)) + // .unwrap(); + + // assert_eq!(chain_name_pending, "12345"); + // assert_eq!(chain_name_latest, "test-chain"); + // } #[test] fn test_rollback_current_height() { @@ -522,24 +495,25 @@ mod tests { let data = helpers::generate_contract(); for _i in 0..5 { let block = helpers::create_block(&executor, Address::from(0), &data, (0, 1), &privkey); - let closed_block = executor.into_fsm(block.clone()); - executor.grow(closed_block); + let mut closed_block = executor.into_fsm(block.clone()); + executor.grow(&closed_block); + closed_block.clear_cache(); } let current_height = executor.get_current_height(); assert_eq!(current_height, 5); // rollback_height = current_height - executor.rollback_current_height(BlockId::Number(current_height)); + executor.rollback_current_height(BlockTag::Height(current_height)); assert_eq!(executor.get_current_height(), current_height); // rollback height = current_height - 3 let rollback_to_2 = current_height - 3; - executor.rollback_current_height(BlockId::Number(rollback_to_2)); + executor.rollback_current_height(BlockTag::Height(rollback_to_2)); assert_eq!(executor.get_current_height(), 2); // rollback_height = 0 - executor.rollback_current_height(BlockId::Earliest); + executor.rollback_current_height(BlockTag::Tag(Tag::Earliest)); assert_eq!(executor.get_current_height(), 0); } @@ -551,10 +525,11 @@ mod tests { let data = helpers::generate_contract(); let block = helpers::create_block(&executor, Address::from(0), &data, (0, 1), &privkey); - let closed_block = executor.into_fsm(block.clone()); + let mut closed_block = executor.into_fsm(block.clone()); let closed_block_height = closed_block.number(); let closed_block_hash = closed_block.hash(); - executor.grow(closed_block); + executor.grow(&closed_block); + closed_block.clear_cache(); let current_height = executor.get_current_height(); let current_hash = executor.block_hash(current_height); @@ -579,7 +554,7 @@ mod tests { executor.do_loop(); }); // send Command, this cause executor exit - command_req_sender.send(Command::Exit(BlockId::Number(0))); + let _ = command_req_sender.send(Command::Exit(BlockTag::Height(0))); ::std::thread::sleep(Duration::new(2, 0)); let resp: CommandResp = command_resp_receiver.recv().unwrap(); diff --git a/cita-executor/core/src/libexecutor/fsm.rs b/cita-executor/core/src/libexecutor/fsm.rs index fd2c2f1bd..8ccb4561c 100644 --- a/cita-executor/core/src/libexecutor/fsm.rs +++ b/cita-executor/core/src/libexecutor/fsm.rs @@ -1,19 +1,16 @@ -// CITA -// Copyright 2016-2019 Cryptape Technologies LLC. - -// This program is free software: you can redistribute it -// and/or modify it under the terms of the GNU 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 General Public License for more details. - -// You should have received a copy of the GNU General Public License -// along with this program. If not, see . +// Copyright Cryptape Technologies LLC. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. use super::block::{ClosedBlock, ExecutedBlock, OpenBlock}; use super::economical_model::EconomicalModel; @@ -42,7 +39,7 @@ impl std::fmt::Display for StatusOfFSM { "StatusOfFSM::Pause(height: {}, parent_hash: {:?}, state_root: {:?}, timestamp: {}, index: {})", executed_block.number(), executed_block.parent_hash(), - executed_block.state.root(), + executed_block.state_root, executed_block.timestamp(), index, ), @@ -51,7 +48,7 @@ impl std::fmt::Display for StatusOfFSM { "StatusOfFSM::Execute(height: {}, parent_hash: {:?}, state_root: {:?}, timestamp: {}, index: {})", executed_block.number(), executed_block.parent_hash(), - executed_block.state.root(), + executed_block.state_root, executed_block.timestamp(), index, ), @@ -60,7 +57,7 @@ impl std::fmt::Display for StatusOfFSM { "StatusOfFSM::Finalize(height: {}, parent_hash: {:?}, state_root: {:?}, timestamp: {})", executed_block.number(), executed_block.parent_hash(), - executed_block.state.root(), + executed_block.state_root, executed_block.timestamp(), ), } @@ -98,14 +95,14 @@ impl FSM for Executor { fn fsm_pause(&self, executed_block: ExecutedBlock, index: usize) -> StatusOfFSM { match self.fsm_req_receiver.try_recv() { - None => { + Err(_) => { if index == executed_block.body().transactions().len() { StatusOfFSM::Finalize(executed_block) } else { StatusOfFSM::Execute(executed_block, index + 1) } } - Some(open_block) => { + Ok(open_block) => { if executed_block.header().is_equivalent(&open_block.header()) { StatusOfFSM::Pause(executed_block, index) } else { @@ -124,17 +121,16 @@ impl FSM for Executor { transaction.gas_price = quota_price; } - executed_block.apply_transaction(&*self.engine, &transaction, &conf); - + executed_block.apply_transaction(&transaction, &self.sys_config); StatusOfFSM::Pause(executed_block, index) } - fn fsm_finalize(&self, mut executed_block: ExecutedBlock) -> ClosedBlock { - // commit changed-accounts into trie structure + fn fsm_finalize(&self, executed_block: ExecutedBlock) -> ClosedBlock { executed_block .state + .borrow_mut() .commit() - .expect("failed to commit state trie"); + .expect("Commit state error."); executed_block.close(&(self.sys_config.block_sys_config)) } } @@ -183,16 +179,28 @@ mod tests { }; match new_status { StatusOfFSM::Initialize(open_block) => StatusOfFSM::Initialize(open_block), - StatusOfFSM::Pause(mut executed_block, iter) => { - executed_block.state.commit().expect("commit state"); + StatusOfFSM::Pause(executed_block, iter) => { + executed_block + .state + .borrow_mut() + .commit() + .expect("commit state"); StatusOfFSM::Pause(executed_block, iter) } - StatusOfFSM::Execute(mut executed_block, iter) => { - executed_block.state.commit().expect("commit state"); + StatusOfFSM::Execute(executed_block, iter) => { + executed_block + .state + .borrow_mut() + .commit() + .expect("commit state"); StatusOfFSM::Execute(executed_block, iter) } - StatusOfFSM::Finalize(mut executed_block) => { - executed_block.state.commit().expect("commit state"); + StatusOfFSM::Finalize(executed_block) => { + executed_block + .state + .borrow_mut() + .commit() + .expect("commit state"); StatusOfFSM::Finalize(executed_block) } } @@ -269,7 +277,7 @@ mod tests { let mut new_open_block = generate_empty_block(); new_open_block.header.set_timestamp(2); // new_open_block is different from outside open_block - fsm_req_sender.send(new_open_block); + let _ = fsm_req_sender.send(new_open_block); }); ::std::thread::sleep(Duration::new(2, 0)); let status_after_pause_2 = executor.fsm_pause(executed_block, 2); @@ -301,7 +309,7 @@ mod tests { thread::spawn(move || { let new_open_block = generate_empty_block(); // new_open_block the same as outside open_block - fsm_req_sender.send(new_open_block); + let _ = fsm_req_sender.send(new_open_block); }); ::std::thread::sleep(Duration::new(2, 0)); let status_after_pause_2 = executor.fsm_pause(executed_block, 2); @@ -342,13 +350,10 @@ mod tests { // 2. execute 1th transaction let transaction = executed_block.body().transactions[0].clone(); - executed_block.apply_transaction( - &*executor.engine, - &transaction, - &executor.sys_config.block_sys_config.clone(), - ); + executed_block.apply_transaction(&transaction, &executor.sys_config); executed_block .state + .borrow_mut() .commit() .expect("commit state to re-calculate state root"); let (status_of_pause_1th, mut executed_block) = transit_and_assert( @@ -359,17 +364,14 @@ mod tests { // 3. send an equivalent OpenBlock into fsm_req channel let new_open_block = open_block.clone(); - fsm_req_sender.send(new_open_block); + let _ = fsm_req_sender.send(new_open_block); // 4. continue until finalize let transaction = executed_block.body().transactions[1].clone(); - executed_block.apply_transaction( - &*executor.engine, - &transaction, - &executor.sys_config.block_sys_config.clone(), - ); + executed_block.apply_transaction(&transaction, &executor.sys_config); executed_block .state + .borrow_mut() .commit() .expect("commit state to re-calculate state root"); let mut status = status_of_pause_1th; @@ -409,21 +411,18 @@ mod tests { // 3. send an un-equivalent OpenBlock into fsm_req channel let new_open_block = generate_block(&executor, 10); - fsm_req_sender.send(new_open_block.clone()); + let _ = fsm_req_sender.send(new_open_block.clone()); // 4. continue until finalize let mut executed_block = executor.to_executed_block(new_open_block); let mut transactions = { executed_block.body.transactions.clone() }; for transaction in transactions.iter_mut() { // let mut t = transaction.clone(); - executed_block.apply_transaction( - &*executor.engine, - &transaction, - &executor.sys_config.block_sys_config.clone(), - ); + executed_block.apply_transaction(&transaction, &executor.sys_config); } executed_block .state + .borrow_mut() .commit() .expect("commit state to re-calculate state root"); let mut status = status_of_pause; diff --git a/cita-executor/core/src/libexecutor/genesis.rs b/cita-executor/core/src/libexecutor/genesis.rs index dbad1ac00..4ba663377 100644 --- a/cita-executor/core/src/libexecutor/genesis.rs +++ b/cita-executor/core/src/libexecutor/genesis.rs @@ -1,31 +1,28 @@ -// CITA -// Copyright 2016-2019 Cryptape Technologies LLC. +// Copyright Cryptape Technologies LLC. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. -// This program is free software: you can redistribute it -// and/or modify it under the terms of the GNU 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 General Public License for more details. - -// You should have received a copy of the GNU General Public License -// along with this program. If not, see . - -use crate::cita_db::kvdb::KeyValueDB; -use crate::db::{self as db, Writable}; -use crate::factory::Factories; use crate::libexecutor::block::Block; -use crate::state::State; -use crate::state_db::StateDB; -use crate::types::extras::*; +use crate::libexecutor::executor::{CitaDB, CitaTrieDB}; +use crate::types::db_indexes; +use crate::types::db_indexes::DBIndex; +use cita_database::{DataCategory, Database}; use cita_types::traits::ConvertType; use cita_types::{clean_0x, Address, H256, U256}; +use cita_vm::state::{State as CitaState, StateObjectInfo}; use crypto::digest::Digest; use crypto::md5::Md5; +use rlp::encode; use rustc_hex::FromHex; use serde_json; use std::collections::HashMap; @@ -34,6 +31,7 @@ use std::io::BufReader; use std::io::Read; use std::path::Path; use std::sync::Arc; + #[cfg(feature = "privatetx")] use zktx::set_param_path; @@ -104,18 +102,13 @@ impl Genesis { } } - pub fn lazy_execute( - &mut self, - state_db: &StateDB, - factories: &Factories, - ) -> Result<(), String> { - let mut state = State::from_existing( - state_db.boxed_clone_canon(&self.spec.prevhash), + pub fn lazy_execute(&mut self, state_db: Arc) -> Result<(), String> { + let mut state = CitaState::from_existing( + Arc::::clone(&state_db), *self.block.state_root(), - U256::from(0), - factories.clone(), ) - .expect("state db error"); + .expect("Can not get state from db!"); + self.block.set_version(0); self.block.set_parent_hash(self.spec.prevhash); self.block.set_timestamp(self.spec.timestamp); @@ -125,14 +118,14 @@ impl Genesis { trace!("**** begin **** \n"); for (address, contract) in self.spec.alloc.clone() { let address = Address::from_unaligned(address.as_str()).unwrap(); - state.new_contract(&address, U256::from(0), U256::from(0)); + state.new_contract(&address, U256::from(0), U256::from(0), vec![]); { state - .init_code(&address, clean_0x(&contract.code).from_hex().unwrap()) + .set_code(&address, clean_0x(&contract.code).from_hex().unwrap()) .expect("init code fail"); if let Some(value) = contract.value { state - .add_balance(&address, &value) + .add_balance(&address, value) .expect("init balance fail"); } } @@ -152,7 +145,7 @@ impl Genesis { let address = Address::from_unaligned(address.as_str()).unwrap(); for (key, values) in &contract.storage { let result = - state.storage_at(&address, &H256::from_unaligned(key.as_ref()).unwrap()); + state.get_storage(&address, &H256::from_unaligned(key.as_ref()).unwrap()); assert_eq!( H256::from_unaligned(values.as_ref()).unwrap(), result.expect("storage error") @@ -161,27 +154,47 @@ impl Genesis { } trace!("**** end **** \n"); - let root = *state.root(); + let root = state.root; trace!("root {:?}", root); self.block.set_state_root(root); self.block.rehash(); - self.save(state, state_db.journal_db().backing()) + self.save(state_db.database()) } - fn save(&mut self, state: State, db: &Arc) -> Result<(), String> { - let mut batch = db.transaction(); + fn save(&mut self, db: Arc) -> Result<(), String> { + // Note: All the key should be the index from extras.rs, and + // all the value should be a rlp value. let hash = self.block.hash().unwrap(); - let height = self.block.number(); - //初始化的时候需要获取头部信息 - batch.write(db::COL_HEADERS, &hash, self.block.header()); - batch.write(db::COL_EXTRA, &CurrentHash, &hash); - batch.write(db::COL_EXTRA, &height, &hash); - let mut state_db = state.drop().1; - state_db - .journal_under(&mut batch, height, &hash) - .expect("DB commit failed"); - db.write(batch) + + // Insert [hash, block_header] + let hash_key = db_indexes::Hash2Header(hash).get_index(); + + // Need to get header in init function. + db.insert( + Some(DataCategory::Headers), + hash_key.to_vec(), + self.block.header().rlp(), + ) + .expect("Insert block header error."); + + // Insert [current_hash, hash] + let current_hash_key = db_indexes::CurrentHash.get_index(); + let hash_value = encode(&hash).to_vec(); + db.insert( + Some(DataCategory::Extra), + current_hash_key.to_vec(), + hash_value.clone(), + ) + .expect("Insert block hash error."); + + // Insert [block_number, hash] + let height_key = db_indexes::BlockNumber2Hash(self.block.number()).get_index(); + + db.insert(Some(DataCategory::Extra), height_key.to_vec(), hash_value) + .expect("Insert block hash error."); + + Ok(()) } } diff --git a/cita-executor/core/src/libexecutor/lru_cache.rs b/cita-executor/core/src/libexecutor/lru_cache.rs index 2f6f8076c..d7aa15bc9 100644 --- a/cita-executor/core/src/libexecutor/lru_cache.rs +++ b/cita-executor/core/src/libexecutor/lru_cache.rs @@ -1,19 +1,16 @@ -// CITA -// Copyright 2016-2019 Cryptape Technologies LLC. - -// This program is free software: you can redistribute it -// and/or modify it under the terms of the GNU 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 General Public License for more details. - -// You should have received a copy of the GNU General Public License -// along with this program. If not, see . +// Copyright Cryptape Technologies LLC. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. use std::borrow::ToOwned; use std::collections::{btree_map::Keys, btree_map::Values, BTreeMap, HashSet}; diff --git a/cita-executor/core/src/libexecutor/mod.rs b/cita-executor/core/src/libexecutor/mod.rs index afe1963bf..9879c95fa 100644 --- a/cita-executor/core/src/libexecutor/mod.rs +++ b/cita-executor/core/src/libexecutor/mod.rs @@ -1,19 +1,16 @@ -// CITA -// Copyright 2016-2019 Cryptape Technologies LLC. - -// This program is free software: you can redistribute it -// and/or modify it under the terms of the GNU 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 General Public License for more details. - -// You should have received a copy of the GNU General Public License -// along with this program. If not, see . +// Copyright Cryptape Technologies LLC. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. pub mod auto_exec; pub mod blacklist; @@ -28,5 +25,4 @@ pub mod lru_cache; pub mod sys_config; pub use self::genesis::Genesis; -pub use crate::cita_db::journaldb; pub use libproto::*; diff --git a/cita-executor/core/src/libexecutor/sys_config.rs b/cita-executor/core/src/libexecutor/sys_config.rs index 6eaf093f5..40085a31d 100644 --- a/cita-executor/core/src/libexecutor/sys_config.rs +++ b/cita-executor/core/src/libexecutor/sys_config.rs @@ -1,19 +1,16 @@ -// CITA -// Copyright 2016-2019 Cryptape Technologies LLC. - -// This program is free software: you can redistribute it -// and/or modify it under the terms of the GNU 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 General Public License for more details. - -// You should have received a copy of the GNU General Public License -// along with this program. If not, see . +// Copyright Cryptape Technologies LLC. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. use super::executor::Executor; use crate::contracts::solc::{ @@ -21,7 +18,7 @@ use crate::contracts::solc::{ QuotaManager, Resource, SysConfig, UserManagement, VersionManager, AUTO_EXEC_QL_VALUE, }; use crate::libexecutor::economical_model::EconomicalModel; -use crate::types::ids::BlockId; +use crate::types::block_number::BlockTag; use cita_types::{Address, U256}; use std::collections::HashMap; @@ -56,74 +53,74 @@ impl Default for GlobalSysConfig { impl GlobalSysConfig { // TODO We have to update all default value when they was changed in .sol files. // Is there any better solution? - pub fn load(executor: &Executor, block_id: BlockId) -> Self { + pub fn load(executor: &Executor, block_tag: BlockTag) -> Self { let mut conf = GlobalSysConfig::default(); conf.nodes = executor .node_manager() - .shuffled_stake_nodes(block_id) + .shuffled_stake_nodes(block_tag) .unwrap_or_else(NodeManager::default_shuffled_stake_nodes); conf.validators = executor .node_manager() - .nodes(block_id) + .nodes(block_tag) .unwrap_or_else(NodeManager::default_shuffled_stake_nodes); let quota_manager = QuotaManager::new(executor); conf.block_quota_limit = quota_manager - .block_quota_limit(block_id) + .block_quota_limit(block_tag) .unwrap_or_else(QuotaManager::default_block_quota_limit) as usize; conf.block_sys_config.auto_exec_quota_limit = quota_manager - .auto_exec_quota_limit(block_id) + .auto_exec_quota_limit(block_tag) .unwrap_or_else(QuotaManager::default_auto_exec_quota_limit); let sys_config = SysConfig::new(executor); conf.delay_active_interval = sys_config - .delay_block_number(block_id) + .delay_block_number(block_tag) .unwrap_or_else(SysConfig::default_delay_block_number) as usize; conf.block_sys_config.check_options.call_permission = sys_config - .call_permission_check(block_id) + .call_permission_check(block_tag) .unwrap_or_else(SysConfig::default_call_permission_check); conf.block_sys_config.check_options.send_tx_permission = sys_config - .send_tx_permission_check(block_id) + .send_tx_permission_check(block_tag) .unwrap_or_else(SysConfig::default_send_tx_permission_check); conf.block_sys_config .check_options .create_contract_permission = sys_config - .create_contract_permission_check(block_id) + .create_contract_permission_check(block_tag) .unwrap_or_else(SysConfig::default_create_contract_permission_check); conf.block_sys_config.check_options.quota = sys_config - .quota_check(block_id) + .quota_check(block_tag) .unwrap_or_else(SysConfig::default_quota_check); conf.block_sys_config.check_options.fee_back_platform = sys_config - .fee_back_platform_check(block_id) + .fee_back_platform_check(block_tag) .unwrap_or_else(SysConfig::default_fee_back_platform_check); conf.block_sys_config.chain_owner = sys_config - .chain_owner(block_id) + .chain_owner(block_tag) .unwrap_or_else(SysConfig::default_chain_owner); conf.block_interval = sys_config - .block_interval(block_id) + .block_interval(block_tag) .unwrap_or_else(SysConfig::default_block_interval); conf.block_sys_config.auto_exec = sys_config - .auto_exec(block_id) + .auto_exec(block_tag) .unwrap_or_else(SysConfig::default_auto_exec); let permission_manager = PermissionManagement::new(executor); conf.block_sys_config.account_permissions = - permission_manager.load_account_permissions(block_id); + permission_manager.load_account_permissions(block_tag); conf.block_sys_config.super_admin_account = - permission_manager.get_super_admin_account(block_id); + permission_manager.get_super_admin_account(block_tag); let user_manager = UserManagement::new(executor); - conf.block_sys_config.group_accounts = user_manager.load_group_accounts(block_id); + conf.block_sys_config.group_accounts = user_manager.load_group_accounts(block_tag); conf.block_sys_config.economical_model = sys_config - .economical_model(block_id) + .economical_model(block_tag) .unwrap_or_else(SysConfig::default_economical_model); let common_quota_limit = quota_manager - .account_quota_limit(block_id) + .account_quota_limit(block_tag) .unwrap_or_else(QuotaManager::default_account_quota_limit); - let specific = quota_manager.specific(block_id); + let specific = quota_manager.specific(block_tag); conf.block_sys_config .account_quota_limit @@ -135,17 +132,17 @@ impl GlobalSysConfig { let emergency_manager = EmergencyIntervention::new(executor); conf.emergency_intervention = emergency_manager - .state(block_id) + .state(block_tag) .unwrap_or_else(EmergencyIntervention::default_state); let version_manager = VersionManager::new(executor); conf.block_sys_config.chain_version = version_manager - .get_version(block_id) + .get_version(block_tag) .unwrap_or_else(VersionManager::default_version); let price_management = PriceManagement::new(executor); conf.block_sys_config.quota_price = price_management - .quota_price(block_id) + .quota_price(block_tag) .unwrap_or_else(PriceManagement::default_quota_price); conf diff --git a/cita-executor/core/src/pod_account.rs b/cita-executor/core/src/pod_account.rs deleted file mode 100644 index 87b839a6f..000000000 --- a/cita-executor/core/src/pod_account.rs +++ /dev/null @@ -1,120 +0,0 @@ -// Copyright 2015-2017 Parity Technologies (UK) Ltd. -// This file is part of Parity. - -// This software is free software: you can redistribute it and/or modify -// it under the terms of the GNU General Public License as published by -// the Free Software Foundation, either version 3 of the License, or -// (at your option) any later version. - -// This software 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 General Public License for more details. - -// You should have received a copy of the GNU General Public License -// along with Parity. If not, see . - -use crate::account_db::AccountDBMut; -use crate::cita_db::{sec_trie_root, HashDB, TrieFactory}; -use crate::state::Account; -use cita_types::{H256, U256}; -use hashable::Hashable; -use rlp::{self, RlpStream}; -use std::collections::BTreeMap; -use std::fmt; -use util::*; - -#[derive(Debug, Clone, PartialEq, Eq)] -/// An account, expressed as Plain-Old-Data (hence the name). -/// Does not have a DB overlay cache, code hash or anything like that. -pub struct PodAccount { - /// The balance of the account. - pub balance: U256, - /// The nonce of the account. - pub nonce: U256, - /// The code of the account or `None` in the special case that it is unknown. - pub code: Option, - /// The abi of the account or `None` in the special case that it is unknown. - pub abi: Option, - /// The storage of the account. - pub storage: BTreeMap, -} - -impl PodAccount { - /// Convert Account to a PodAccount. - /// NOTE: This will silently fail unless the account is fully cached. - pub fn from_account(acc: &Account) -> PodAccount { - PodAccount { - balance: *acc.balance(), - nonce: *acc.nonce(), - storage: acc - .storage_changes() - .iter() - .fold(BTreeMap::new(), |mut m, (k, v)| { - m.insert(*k, *v); - m - }), - code: acc.code().map(|x| x.to_vec()), - abi: acc.abi().map(|x| x.to_vec()), - } - } - - /// Returns the RLP for this account. - pub fn rlp(&self) -> Bytes { - let mut stream = RlpStream::new_list(5); - stream.append(&self.nonce); - stream.append(&self.balance); - stream.append(&sec_trie_root( - self.storage - .iter() - .map(|(k, v)| (k.to_vec(), rlp::encode(&U256::from(&**v)).to_vec())) - .collect(), - )); - stream.append(&self.code.as_ref().unwrap_or(&vec![]).crypt_hash()); - stream.append(&self.abi.as_ref().unwrap_or(&vec![]).crypt_hash()); - stream.out() - } - - /// Place additional data into given hash DB. - pub fn insert_additional(&self, db: &mut AccountDBMut, factory: &TrieFactory) { - match self.code { - Some(ref c) if !c.is_empty() => { - db.insert(c); - } - _ => {} - } - match self.abi { - Some(ref c) if !c.is_empty() => { - db.insert(c); - } - _ => {} - } - let mut r = H256::new(); - let mut t = factory.create(db, &mut r); - for (k, v) in &self.storage { - if let Err(e) = t.insert(k, &rlp::encode(&U256::from(&**v))) { - warn!("Encountered potential DB corruption: {}", e); - } - } - } -} - -impl fmt::Display for PodAccount { - fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { - write!( - f, - "(bal={}; nonce={}; code={} bytes, #{}; abi={} bytes, #{}; storage={} items)", - self.balance, - self.nonce, - self.code.as_ref().map_or(0, Vec::len), - self.code - .as_ref() - .map_or_else(H256::new, Hashable::crypt_hash), - self.abi.as_ref().map_or(0, Vec::len), - self.abi - .as_ref() - .map_or_else(H256::new, Hashable::crypt_hash), - self.storage.len(), - ) - } -} diff --git a/cita-executor/core/src/snapshot/README.md b/cita-executor/core/src/snapshot/README.md deleted file mode 100644 index 9dbf57b15..000000000 --- a/cita-executor/core/src/snapshot/README.md +++ /dev/null @@ -1,56 +0,0 @@ -# 概述 - -快照含三部分: block chunks, state chunks, 及manifest. - -每个chunk是snappy压缩后的hash. 压缩前的chunks大小为`CHUNK_SIZE`,目前默认4MB. - -这里的数据结构都需进行RLP编码。 - -# 清单(Manifest) - -如下结构的rlp list: -``` -[ - state_hashes: [hash_1: B_32, hash_2: B_32, ...], // list: state chunks (snappy压缩后的hash) - block_hashes: [hash_1: B_32, hash_2: B_32, ...], // list: block chunks (snappy压缩后的hash) - state_root: B_32, // 用于恢复state trie的root - block_number: P, // 快照对应的区块号,state也与其对应 - block_hash: B_32, // 快照对应的区块hash -] -``` - -# 区块chunks(Block chunks) - -区块chunks包含原始区块数据: blocks及交易receipts. blocks格式"abridged block"(简称 `AB`), receipts格式list: `[receipt_1: P, receipt_2: P, ...]` (简称`RC`). - -每个block chunk如下结构的list: -``` -[ - number: P, // chunk中的第一个区块号 - hash: B_32, // chunk中的第一个区块hash - [abridged_1: AB, receipts_1: RC], // 第一个block及receipts的RLP编码(区块连续) - [abridged_2: AB, receipts_2: RC], // 第二个block及receipts的RLP编码 - [abridged_3: AB, receipts_3: RC], // ... - ... -] -``` - -# 状态chunks(State Chunks) - -State chunks存储给定区块的状态. - -每个chunk由list集合构成,每个list含两项:地址的`sha3` hash,及相应的账户结构(ACC). - -`[ [hash1: B_32, acc_1: P], [hash_2: B_32, acc_2: P], ... ]`. - -## 账户(Account) - -如下格式的RLP编码list: -``` -[ - nonce: B_32, - code: P, - storage: [[keyhash1: B_32, val1: B_32], [keyhash2: B_32, val2: B_32], ...] -] -``` -`storage` 为账户storage的RLP list, 每个元素含两项:`sha3(key)`, 及storage值. diff --git a/cita-executor/core/src/snapshot/account.rs b/cita-executor/core/src/snapshot/account.rs deleted file mode 100644 index c1f79ca9a..000000000 --- a/cita-executor/core/src/snapshot/account.rs +++ /dev/null @@ -1,265 +0,0 @@ -// Copyright 2015-2017 Parity Technologies (UK) Ltd. -// This file is part of Parity. - -// This software is free software: you can redistribute it and/or modify -// it under the terms of the GNU General Public License as published by -// the Free Software Foundation, either version 3 of the License, or -// (at your option) any later version. - -// This software 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 General Public License for more details. - -// You should have received a copy of the GNU General Public License -// along with Parity. If not, see . - -//! Account state encoding and decoding - -use crate::account_db::{AccountDB, AccountDBMut}; -use crate::cita_db::hashdb::HashDB; -use crate::cita_db::{Trie, TrieDB, TrieDBMut, TrieMut}; -use crate::snapshot::Error; -use crate::types::basic_account::BasicAccount; -use cita_types::{Address, H256, U256}; -use hashable::{HASH_EMPTY, HASH_NULL_RLP}; -use rlp::{RlpStream, UntrustedRlp}; -use std::collections::HashSet; -use util::Bytes; - -// An empty account -- these were replaced with RLP null data for a space optimization in v1. -const ACC_EMPTY: BasicAccount = BasicAccount { - nonce: U256([0, 0, 0, 0]), - balance: U256([0, 0, 0, 0]), - storage_root: HASH_NULL_RLP, - code_hash: HASH_EMPTY, - abi_hash: HASH_EMPTY, -}; - -// whether an encoded account has code and how it is referred to. -#[repr(u8)] -enum CodeState { - // the account has no code. - Empty = 0, - // raw code is encoded. - Inline = 1, - // the code is referred to by hash. - Hash = 2, -} - -impl CodeState { - fn from(x: u8) -> Result { - match x { - 0 => Ok(CodeState::Empty), - 1 => Ok(CodeState::Inline), - 2 => Ok(CodeState::Hash), - _ => Err(Error::UnrecognizedCodeState(x)), - } - } - - fn raw(self) -> u8 { - self as u8 - } -} - -// walk the account's storage trie, returning a vector of RLP items containing the -// account address hash, account properties and the storage. Each item contains at most `max_storage_items` -// storage records split according to snapshot format definition. -#[allow(unknown_lints, clippy::implicit_hasher)] // TODO clippy -pub fn to_fat_rlps( - address: &Address, - acc: &BasicAccount, - acct_db: &AccountDB, - used_code: &mut HashSet, - used_abi: &mut HashSet, - first_chunk_size: usize, - max_chunk_size: usize, -) -> Result, Error> { - let db = TrieDB::create(acct_db, &acc.storage_root).unwrap(); - let mut chunks = Vec::new(); - let mut db_iter = db.iter().map_err(|err| *err)?; - let mut target_chunk_size = first_chunk_size; - let mut account_stream = RlpStream::new_list(2); - let mut leftover: Option> = None; - - loop { - account_stream.append(address); - account_stream.begin_list(7); - - account_stream.append(&acc.nonce).append(&acc.balance); - - // [has_code, code_hash]. - if acc.code_hash == HASH_EMPTY { - account_stream - .append(&CodeState::Empty.raw()) - .append_empty_data(); - } else if used_code.contains(&acc.code_hash) { - account_stream - .append(&CodeState::Hash.raw()) - .append(&acc.code_hash); - } else { - match acct_db.get(&acc.code_hash) { - Some(c) => { - used_code.insert(acc.code_hash); - account_stream.append(&CodeState::Inline.raw()).append(&&*c); - } - None => { - info!("code lookup failed during snapshot"); - account_stream.append(&false).append_empty_data(); - } - } - } - - // [has_abi, abi_hash]. - if acc.abi_hash == HASH_EMPTY { - account_stream - .append(&CodeState::Empty.raw()) - .append_empty_data(); - } else if used_abi.contains(&acc.abi_hash) { - account_stream - .append(&CodeState::Hash.raw()) - .append(&acc.abi_hash); - } else { - match acct_db.get(&acc.abi_hash) { - Some(c) => { - used_abi.insert(acc.abi_hash); - account_stream.append(&CodeState::Inline.raw()).append(&&*c); - } - None => { - info!("abi lookup failed during snapshot"); - account_stream.append(&false).append_empty_data(); - } - } - } - - account_stream.begin_unbounded_list(); - if account_stream.size() > target_chunk_size { - // account does not fit, push an empty record to mark a new chunk - target_chunk_size = max_chunk_size; - chunks.push(Vec::new()); - } - - if let Some(pair) = leftover.take() { - if !account_stream.append_raw_checked(&pair, 1, target_chunk_size) { - return Err(Error::ChunkTooSmall); - } - } - - loop { - match db_iter.next() { - Some(Ok((k, v))) => { - let pair = { - let mut stream = RlpStream::new_list(2); - stream.append(&k).append(&&*v); - stream.drain() - }; - if !account_stream.append_raw_checked(&pair, 1, target_chunk_size) { - account_stream.complete_unbounded_list(); - let stream = - ::std::mem::replace(&mut account_stream, RlpStream::new_list(2)); - chunks.push(stream.out()); - target_chunk_size = max_chunk_size; - leftover = Some(pair.into_vec()); - - break; - } - } - Some(Err(e)) => { - return Err((*e).into()); - } - None => { - account_stream.complete_unbounded_list(); - let stream = ::std::mem::replace(&mut account_stream, RlpStream::new_list(2)); - chunks.push(stream.out()); - - return Ok(chunks); - } - } - } - } -} - -// decode a fat rlp, and rebuild the storage trie as we go. -// returns the account structure along with its newly recovered code, -// if it exists. -pub fn from_fat_rlp( - acct_db: &mut AccountDBMut, - rlp: &UntrustedRlp, - mut storage_root: H256, -) -> Result<(BasicAccount, Option, Option), Error> { - //use trie::{TrieDBMut, TrieMut}; - - // check for special case of empty account. - if rlp.is_empty() { - return Ok((ACC_EMPTY, None, None)); - } - - let nonce = rlp.val_at(0)?; - let balance = rlp.val_at(1)?; - let code_state: CodeState = { - let raw: u8 = rlp.val_at(2)?; - CodeState::from(raw)? - }; - - // load the code if it exists. - let (code_hash, new_code) = match code_state { - CodeState::Empty => (HASH_EMPTY, None), - CodeState::Inline => { - let code: Bytes = rlp.val_at(3)?; - let code_hash = acct_db.insert(&code); - - (code_hash, Some(code)) - } - CodeState::Hash => { - let code_hash = rlp.val_at(3)?; - - (code_hash, None) - } - }; - - let abi_state: CodeState = { - let raw: u8 = rlp.val_at(4)?; - CodeState::from(raw)? - }; - - // load the abi if it exists. - let (abi_hash, new_abi) = match abi_state { - CodeState::Empty => (HASH_EMPTY, None), - CodeState::Inline => { - let abi: Bytes = rlp.val_at(5)?; - let abi_hash = acct_db.insert(&abi); - - (abi_hash, Some(abi)) - } - CodeState::Hash => { - let abi_hash = rlp.val_at(5)?; - - (abi_hash, None) - } - }; - - { - let mut storage_trie = if storage_root.is_zero() { - TrieDBMut::new(acct_db, &mut storage_root) - } else { - TrieDBMut::from_existing(acct_db, &mut storage_root).map_err(|err| *err)? - }; - let pairs = rlp.at(6)?; - for pair_rlp in pairs.iter() { - let k: Bytes = pair_rlp.val_at(0)?; - let v: Bytes = pair_rlp.val_at(1)?; - - storage_trie.insert(&k, &v).map_err(|err| *err)?; - } - } - - let acc = BasicAccount { - nonce, - storage_root, - code_hash, - balance, - abi_hash, - }; - - Ok((acc, new_code, new_abi)) -} diff --git a/cita-executor/core/src/snapshot/error.rs b/cita-executor/core/src/snapshot/error.rs deleted file mode 100644 index 17dff3cb1..000000000 --- a/cita-executor/core/src/snapshot/error.rs +++ /dev/null @@ -1,150 +0,0 @@ -// Copyright 2015-2017 Parity Technologies (UK) Ltd. -// This file is part of Parity. - -// This software is free software: you can redistribute it and/or modify -// it under the terms of the GNU General Public License as published by -// the Free Software Foundation, either version 3 of the License, or -// (at your option) any later version. - -// This software 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 General Public License for more details. - -// You should have received a copy of the GNU General Public License -// along with Parity. If not, see . - -//! Snapshot-related errors. - -use std::fmt; - -use crate::types::ids::BlockId; - -use crate::cita_db::trie::TrieError; -use cita_types::{Address, H256}; -use rlp::DecoderError; -use snappy::SnappyError; - -/// Snapshot-related errors. -#[derive(Debug)] -pub enum Error { - /// Invalid starting block for snapshot. - InvalidStartingBlock(BlockId), - /// Block not found. - BlockNotFound(H256), - /// Incomplete chain. - IncompleteChain, - /// Best block has wrong state root. - WrongStateRoot(H256, H256), - /// Wrong block hash. - WrongBlockHash(u64, H256, H256), - /// Too many blocks contained within the snapshot. - TooManyBlocks(u64, u64), - /// Old starting block in a pruned database. - OldBlockPrunedDB, - /// Missing code. - MissingCode(Vec
), - /// Missing abi. - MissingAbi(Vec
), - /// Unrecognized code encoding. - UnrecognizedCodeState(u8), - /// Restoration aborted. - RestorationAborted, - /// Trie error. - Trie(TrieError), - /// Decoder error. - Decoder(DecoderError), - /// Io error. - Io(::std::io::Error), - /// Snapshot version is not supported. - VersionNotSupported(u64), - /// Max chunk size is to small to fit basic account data. - ChunkTooSmall, - /// Snapshots not supported by the consensus engine. - SnapshotsUnsupported, - /// Bad epoch transition. - BadEpochProof(u64), - /// Wrong chunk format. - WrongChunkFormat(String), - /// Snappy error. - Snappy(SnappyError), -} - -impl fmt::Display for Error { - fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { - match *self { - Error::InvalidStartingBlock(ref id) => write!(f, "Invalid starting block: {:?}", id), - Error::BlockNotFound(ref hash) => write!(f, "Block not found in chain: {}", hash), - Error::IncompleteChain => write!(f, "Incomplete blockchain."), - Error::WrongStateRoot(ref expected, ref found) => write!( - f, - "Final block has wrong state root. Expected {:?}, got {:?}", - expected, found - ), - Error::WrongBlockHash(ref num, ref expected, ref found) => write!( - f, - "Block {} had wrong hash. expected {:?}, got {:?}", - num, expected, found - ), - Error::TooManyBlocks(ref expected, ref found) => write!( - f, - "Snapshot contained too many blocks. Expected {}, got {}", - expected, found - ), - Error::OldBlockPrunedDB => write!( - f, - "Attempted to create a snapshot at an old block while using \ - a pruned database. Please re-run with the --pruning archive flag." - ), - Error::MissingCode(ref missing) => write!( - f, - "Incomplete snapshot: {} contract codes not found.", - missing.len() - ), - Error::MissingAbi(ref missing) => write!( - f, - "Incomplete snapshot: {} contract abis not found.", - missing.len() - ), - Error::UnrecognizedCodeState(state) => { - write!(f, "Unrecognized code encoding ({})", state) - } - Error::RestorationAborted => write!(f, "Snapshot restoration aborted."), - Error::Io(ref err) => err.fmt(f), - Error::Decoder(ref err) => err.fmt(f), - Error::Trie(ref err) => err.fmt(f), - Error::VersionNotSupported(ref ver) => { - write!(f, "Snapshot version {} is not supprted.", ver) - } - Error::ChunkTooSmall => write!(f, "Chunk size is too small."), - Error::SnapshotsUnsupported => write!(f, "Snapshots unsupported by consensus engine."), - Error::BadEpochProof(i) => write!(f, "Bad epoch proof for transition to epoch {}", i), - Error::WrongChunkFormat(ref msg) => write!(f, "Wrong chunk format: {}", msg), - Error::Snappy(ref err) => write!(f, "Snappy error: {}", err), - } - } -} - -impl From<::std::io::Error> for Error { - fn from(err: ::std::io::Error) -> Self { - Error::Io(err) - } -} - -impl From for Error { - fn from(err: TrieError) -> Self { - Error::Trie(err) - } -} - -impl From for Error { - fn from(err: DecoderError) -> Self { - Error::Decoder(err) - } -} - -impl From for Error { - fn from(err: SnappyError) -> Self { - Error::Snappy(err) - } -} diff --git a/cita-executor/core/src/snapshot/io.rs b/cita-executor/core/src/snapshot/io.rs deleted file mode 100644 index 39bfdeabb..000000000 --- a/cita-executor/core/src/snapshot/io.rs +++ /dev/null @@ -1,333 +0,0 @@ -// Copyright 2015-2017 Parity Technologies (UK) Ltd. -// This file is part of Parity. - -// This software is free software: you can redistribute it and/or modify -// it under the terms of the GNU General Public License as published by -// the Free Software Foundation, either version 3 of the License, or -// (at your option) any later version. - -// This software 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 General Public License for more details. - -// You should have received a copy of the GNU General Public License -// along with Parity. If not, see . - -//! Snapshot i/o. -//! Ways of writing and reading snapshots. This module supports writing and reading -//! snapshots of two different formats: packed and loose. -//! Packed snapshots are written to a single file, and loose snapshots are -//! written to multiple files in one directory. - -use std::collections::HashMap; -use std::fs::{self, File}; -use std::io::{self, Read, Seek, SeekFrom, Write}; -use std::path::{Path, PathBuf}; - -use super::error::Error; -use cita_types::traits::LowerHex; -use cita_types::H256; -use rlp::{RlpStream, UntrustedRlp}; -use util::Bytes; - -use super::ManifestData; - -const SNAPSHOT_VERSION: u64 = 1; - -/// Something which can write snapshots. -/// Writing the same chunk multiple times will lead to implementation-defined -/// behavior, and is not advised. -pub trait SnapshotWriter { - /// Write a compressed state chunk. - fn write_state_chunk(&mut self, hash: H256, chunk: &[u8]) -> io::Result<()>; - - /// Write a compressed block chunk. - fn write_block_chunk(&mut self, hash: H256, chunk: &[u8]) -> io::Result<()>; - - /// Complete writing. The manifest's chunk lists must be consistent - /// with the chunks written. - fn finish(self, manifest: ManifestData) -> io::Result<()> - where - Self: Sized; -} - -// (hash, len, offset) -#[derive(RlpEncodable, RlpDecodable)] -pub struct ChunkInfo(H256, u64, u64); - -/// A packed snapshot writer. This writes snapshots to a single concatenated file. -/// -/// The file format is very simple and consists of three parts: -/// [Concatenated chunk data] -/// [manifest as RLP] -/// [manifest start offset (8 bytes little-endian)] -/// -/// The manifest contains all the same information as a standard `ManifestData`, -/// but also maps chunk hashes to their lengths and offsets in the file -/// for easy reading. -pub struct PackedWriter { - pub file: File, - pub state_hashes: Vec, - pub block_hashes: Vec, - pub cur_len: u64, -} - -impl PackedWriter { - /// Create a new "PackedWriter", to write into the file at the given path. - pub fn create(path: &Path) -> io::Result { - Ok(PackedWriter { - file: File::create(path)?, - state_hashes: Vec::new(), - block_hashes: Vec::new(), - cur_len: 0, - }) - } -} - -impl SnapshotWriter for PackedWriter { - fn write_state_chunk(&mut self, hash: H256, chunk: &[u8]) -> io::Result<()> { - self.file.write_all(chunk)?; - - let len = chunk.len() as u64; - self.state_hashes.push(ChunkInfo(hash, len, self.cur_len)); - - self.cur_len += len; - Ok(()) - } - - fn write_block_chunk(&mut self, hash: H256, chunk: &[u8]) -> io::Result<()> { - self.file.write_all(chunk)?; - - let len = chunk.len() as u64; - self.block_hashes.push(ChunkInfo(hash, len, self.cur_len)); - - self.cur_len += len; - Ok(()) - } - - fn finish(mut self, manifest: ManifestData) -> io::Result<()> { - // we ignore the hashes fields of the manifest under the assumption that - // they are consistent with ours. - let mut stream = RlpStream::new_list(6); - stream - .append(&SNAPSHOT_VERSION) - .append_list(&self.state_hashes) - .append_list(&self.block_hashes) - .append(&manifest.state_root) - .append(&manifest.block_number) - .append(&manifest.block_hash); - - let manifest_rlp = stream.out(); - - self.file.write_all(&manifest_rlp)?; - let off = self.cur_len; - trace!(target: "snapshot_io", "writing manifest of len {} to offset {}", manifest_rlp.len(), off); - - let off_bytes: [u8; 8] = [ - off as u8, - (off >> 8) as u8, - (off >> 16) as u8, - (off >> 24) as u8, - (off >> 32) as u8, - (off >> 40) as u8, - (off >> 48) as u8, - (off >> 56) as u8, - ]; - - self.file.write_all(&off_bytes[..])?; - Ok(()) - } -} - -/// A "loose" writer writes chunk files into a directory. -pub struct LooseWriter { - dir: PathBuf, -} - -impl LooseWriter { - /// Create a new LooseWriter which will write into the given directory, - /// creating it if it doesn't exist. - pub fn create(path: PathBuf) -> io::Result { - fs::create_dir_all(&path)?; - - Ok(LooseWriter { dir: path }) - } - - // writing logic is the same for both kinds of chunks. - fn write_chunk(&mut self, hash: H256, chunk: &[u8]) -> io::Result<()> { - let mut file_path = self.dir.clone(); - file_path.push(hash.lower_hex()); - - let mut file = File::create(file_path)?; - file.write_all(chunk)?; - - Ok(()) - } -} - -impl SnapshotWriter for LooseWriter { - fn write_state_chunk(&mut self, hash: H256, chunk: &[u8]) -> io::Result<()> { - self.write_chunk(hash, chunk) - } - - fn write_block_chunk(&mut self, hash: H256, chunk: &[u8]) -> io::Result<()> { - self.write_chunk(hash, chunk) - } - - fn finish(self, manifest: ManifestData) -> io::Result<()> { - let rlp = manifest.to_rlp(); - let mut path = self.dir.clone(); - path.push("MANIFEST"); - - let mut file = File::create(path)?; - file.write_all(&rlp[..])?; - - Ok(()) - } -} - -/// Something which can read compressed snapshots. -pub trait SnapshotReader { - /// Get the manifest data for this snapshot. - fn manifest(&self) -> &ManifestData; - - /// Get raw chunk data by hash. implementation defined behavior - /// if a chunk not in the manifest is requested. - fn chunk(&self, hash: H256) -> io::Result; -} - -/// Packed snapshot reader. -pub struct PackedReader { - file: File, - state_hashes: HashMap, // len, offset - block_hashes: HashMap, // len, offset - manifest: ManifestData, -} - -impl PackedReader { - /// Create a new `PackedReader` for the file at the given path. - /// This will fail if any io errors are encountered or the file - /// is not a valid packed snapshot. - pub fn create(path: &Path) -> Result, Error> { - let mut file = File::open(path)?; - let file_len = file.metadata()?.len(); - if file_len < 8 { - // ensure we don't seek before beginning. - return Ok(None); - } - - file.seek(SeekFrom::End(-8))?; - let mut off_bytes = [0u8; 8]; - - file.read_exact(&mut off_bytes[..])?; - - let manifest_off: u64 = (u64::from(off_bytes[7]) << 56) - + (u64::from(off_bytes[6]) << 48) - + (u64::from(off_bytes[5]) << 40) - + (u64::from(off_bytes[4]) << 32) - + (u64::from(off_bytes[3]) << 24) - + (u64::from(off_bytes[2]) << 16) - + (u64::from(off_bytes[1]) << 8) - + u64::from(off_bytes[0]); - - let manifest_len = file_len - manifest_off - 8; - trace!(target: "snapshot", "loading manifest of length {} from offset {}", manifest_len, manifest_off); - - let mut manifest_buf = vec![0; manifest_len as usize]; - - file.seek(SeekFrom::Start(manifest_off))?; - file.read_exact(&mut manifest_buf)?; - - let rlp = UntrustedRlp::new(&manifest_buf); - - let version = rlp.val_at(0)?; - - if version > SNAPSHOT_VERSION { - return Err(Error::VersionNotSupported(version)); - } - - let state: Vec = rlp.list_at(1)?; - let blocks: Vec = rlp.list_at(2)?; - - let manifest = ManifestData { - state_hashes: state.iter().map(|c| c.0).collect(), - block_hashes: blocks.iter().map(|c| c.0).collect(), - state_root: rlp.val_at(3)?, - block_number: rlp.val_at(4)?, - block_hash: rlp.val_at(5)?, - }; - - Ok(Some(PackedReader { - file, - state_hashes: state.into_iter().map(|c| (c.0, (c.1, c.2))).collect(), - block_hashes: blocks.into_iter().map(|c| (c.0, (c.1, c.2))).collect(), - manifest, - })) - } -} - -impl SnapshotReader for PackedReader { - fn manifest(&self) -> &ManifestData { - &self.manifest - } - - fn chunk(&self, hash: H256) -> io::Result { - let &(len, off) = self - .state_hashes - .get(&hash) - .or_else(|| self.block_hashes.get(&hash)) - .expect("only chunks in the manifest can be requested; qed"); - - let mut file = &self.file; - - file.seek(SeekFrom::Start(off))?; - let mut buf = vec![0; len as usize]; - - file.read_exact(&mut buf[..])?; - - Ok(buf) - } -} - -/// reader for "loose" snapshots -pub struct LooseReader { - dir: PathBuf, - manifest: ManifestData, -} - -impl LooseReader { - /// Create a new `LooseReader` which will read the manifest and chunk data from - /// the given directory. - pub fn create(mut dir: PathBuf) -> Result { - let mut manifest_buf = Vec::new(); - - dir.push("MANIFEST"); - let mut manifest_file = File::open(&dir)?; - manifest_file.read_to_end(&mut manifest_buf)?; - - let manifest = ManifestData::from_rlp(&manifest_buf[..])?; - - dir.pop(); - - Ok(LooseReader { dir, manifest }) - } -} - -impl SnapshotReader for LooseReader { - fn manifest(&self) -> &ManifestData { - &self.manifest - } - - fn chunk(&self, hash: H256) -> io::Result { - let mut path = self.dir.clone(); - path.push(hash.lower_hex()); - - let mut buf = Vec::new(); - let mut file = File::open(&path)?; - - file.read_to_end(&mut buf)?; - - Ok(buf) - } -} diff --git a/cita-executor/core/src/snapshot/mod.rs b/cita-executor/core/src/snapshot/mod.rs deleted file mode 100644 index 8faa45ee7..000000000 --- a/cita-executor/core/src/snapshot/mod.rs +++ /dev/null @@ -1,955 +0,0 @@ -// Copyright 2015-2017 Parity Technologies (UK) Ltd. -// This file is part of Parity. - -// This software is free software: you can redistribute it and/or modify -// it under the terms of the GNU General Public License as published by -// the Free Software Foundation, either version 3 of the License, or -// (at your option) any later version. - -// This software 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 General Public License for more details. - -// You should have received a copy of the GNU General Public License -// along with Parity. If not, see . - -//! Snapshot format and creation. - -// chunks around 4MB before compression -const PREFERRED_CHUNK_SIZE: usize = 4 * 1024 * 1024; - -use crate::account_db::{AccountDB, AccountDBMut}; - -use crate::cita_db::hashdb::DBValue; -use crate::cita_db::journaldb::{self, Algorithm, JournalDB}; -use crate::cita_db::kvdb::{DBTransaction, Database, KeyValueDB}; -use crate::cita_db::{HashDB, Trie, TrieDB, TrieDBMut, TrieMut}; -use crate::db::{Writable, COL_EXTRA, COL_HEADERS, COL_STATE}; -use crate::libexecutor::executor::Executor; -use cita_types::{Address, H256, U256}; -use hashable::Hashable; -use hashable::{HASH_EMPTY, HASH_NULL_RLP}; -use rlp::{DecoderError, Encodable, RlpStream, UntrustedRlp}; -use snappy; -use std::collections::{HashMap, HashSet, VecDeque}; -use std::sync::atomic::{AtomicBool, AtomicUsize, Ordering}; -use std::sync::Arc; -use std::time::Duration; -use util::{Bytes, Mutex}; - -pub mod account; -pub mod error; -pub mod io; -pub mod service; -pub use self::error::Error; -use self::io::SnapshotReader; -use self::io::SnapshotWriter; -use self::service::Service; -use crate::snapshot::service::SnapshotService; -pub use crate::types::basic_account::BasicAccount; -use crate::types::ids::BlockId; - -use super::state::backend::Backend; -use super::state::Account as StateAccount; -use super::state_db::StateDB; -use crate::header::Header; -use ethcore_bloom_journal::Bloom; - -use crate::types::extras::CurrentHash; - -/// A sink for produced chunks. -pub type ChunkSink<'a> = FnMut(&[u8]) -> Result<(), Error> + 'a; - -/// A progress indicator for snapshots. -#[derive(Debug, Default)] -pub struct Progress { - accounts: AtomicUsize, - blocks: AtomicUsize, - size: AtomicUsize, - done: AtomicBool, -} - -impl Progress { - /// Reset the progress. - pub fn reset(&self) { - self.accounts.store(0, Ordering::Release); - self.blocks.store(0, Ordering::Release); - self.size.store(0, Ordering::Release); - - // atomic fence here to ensure the others are written first? - // logs might very rarely get polluted if not. - self.done.store(false, Ordering::Release); - } - - /// Get the number of accounts snapshotted thus far. - pub fn accounts(&self) -> usize { - self.accounts.load(Ordering::Acquire) - } - - /// Get the number of blocks snapshotted thus far. - pub fn blocks(&self) -> usize { - self.blocks.load(Ordering::Acquire) - } - - /// Get the written size of the snapshot in bytes. - pub fn size(&self) -> usize { - self.size.load(Ordering::Acquire) - } - - /// Whether the snapshot is complete. - pub fn done(&self) -> bool { - self.done.load(Ordering::Acquire) - } -} - -/// Statuses for restorations. -#[derive(PartialEq, Eq, Clone, Copy, Debug)] -pub enum RestorationStatus { - /// No restoration. - Inactive, - /// Ongoing restoration. - Ongoing { - /// Total number of state chunks. - state_chunks: u32, - /// Total number of block chunks. - block_chunks: u32, - /// Number of state chunks completed. - state_chunks_done: u32, - /// Number of block chunks completed. - block_chunks_done: u32, - }, - /// Failed restoration. - Failed, -} - -/// Snapshot manifest type definition. -#[derive(Debug, Clone, PartialEq, Eq)] -pub struct ManifestData { - /// List of state chunk hashes. - pub state_hashes: Vec, - /// List of block chunk hashes. - pub block_hashes: Vec, - /// The final, expected state root. - pub state_root: H256, - // Block number this snapshot was taken at. - pub block_number: u64, - // Block hash this snapshot was taken at. - pub block_hash: H256, -} - -/// Snapshot manifest encode/decode. -impl ManifestData { - /// Encode the manifest data to rlp. - pub fn to_rlp(&self) -> Bytes { - let mut stream = RlpStream::new_list(5); - stream.append_list(&self.state_hashes); - stream.append_list(&self.block_hashes); - stream.append(&self.state_root); - stream.append(&self.block_number); - stream.append(&self.block_hash); - - stream.out() - } - - /// Restore manifest data from raw bytes. - pub fn from_rlp(raw: &[u8]) -> Result { - let decoder = UntrustedRlp::new(raw); - - let state_hashes: Vec = decoder.list_at(0)?; - let block_hashes: Vec = decoder.list_at(1)?; - let state_root: H256 = decoder.val_at(2)?; - let block_number: u64 = decoder.val_at(3)?; - let block_hash: H256 = decoder.val_at(4)?; - - Ok(ManifestData { - state_hashes, - block_hashes, - state_root, - block_number, - block_hash, - }) - } -} - -/// snapshot using: given Executor+ starting block hash + database; writing into the given writer. -pub fn take_snapshot( - executor: &Executor, - highest_height: u64, - writer: W, - p: &Progress, -) -> Result<(), Error> { - let start_header: Header = executor - .block_header(BlockId::Number(highest_height)) - .ok_or_else(|| Error::InvalidStartingBlock(BlockId::Number(highest_height)))?; - let block_number = start_header.number(); - let block_hash = start_header.hash().unwrap(); - let state_root = *start_header.state_root(); - let fake_parent_hash: H256 = Default::default(); - let state_db = executor - .state_db - .read() - .boxed_clone_canon(&fake_parent_hash); - let hash_db = state_db.as_hashdb(); - - info!( - "Taking snapshot starting from {}-th, state_root {:?}", - block_number, state_root, - ); - - let writer = Mutex::new(writer); - let state_hashes = chunk_state(hash_db, &state_root, &writer, p)?; - let block_hashes = chunk_secondary(executor, block_hash, &writer, p)?; - - let manifest_data = ManifestData { - state_hashes, - block_hashes, - state_root, - block_number, - block_hash, - }; - - writer.into_inner().finish(manifest_data)?; - - p.done.store(true, Ordering::SeqCst); - - Ok(()) -} - -/// State trie chunker. -struct StateChunker<'a> { - hashes: Vec, - rlps: Vec, - cur_size: usize, - writer: &'a Mutex, - progress: &'a Progress, -} - -impl<'a> StateChunker<'a> { - // Push a key, value pair to be encoded. - // - // If the buffer is greater than the desired chunk size, - // this will write out the data to disk. - fn push(&mut self, data: Bytes) -> Result<(), Error> { - self.cur_size += data.len(); - self.rlps.push(data); - Ok(()) - } - - // Write out the buffer to disk, pushing the created chunk's hash to - // the list. - fn write_chunk(&mut self) -> Result<(), Error> { - let num_entries = self.rlps.len(); - let mut stream = RlpStream::new_list(num_entries); - for rlp in self.rlps.drain(..) { - stream.append_raw(&rlp, 1); - } - - let raw_data = stream.out(); - - let mut compressed_data = Vec::new(); - snappy::compress_to(&raw_data, &mut compressed_data)?; - let hash = compressed_data.crypt_hash(); - - self.writer - .lock() - .write_state_chunk(hash, &compressed_data)?; - trace!( - "wrote state chunk.compressed size: {}, uncompressed size: {}", - compressed_data.len(), - raw_data.len(), - ); - - self.progress - .accounts - .fetch_add(num_entries, Ordering::SeqCst); - self.progress - .size - .fetch_add(compressed_data.len(), Ordering::SeqCst); - - self.hashes.push(hash); - self.cur_size = 0; - - Ok(()) - } -} - -/// Walk the given state database starting from the given root, -/// creating chunks and writing them out. -/// -/// Returns a list of hashes of chunks created, or any error it may -/// have encountered. -pub fn chunk_state<'a>( - db: &HashDB, - root: &H256, - writer: &Mutex, - progress: &'a Progress, -) -> Result, Error> { - let account_trie = TrieDB::create(db, &root).map_err(|err| *err)?; - - let mut chunker = StateChunker { - hashes: Vec::new(), - rlps: Vec::new(), - cur_size: 0, - writer, - progress, - }; - - let mut used_code = HashSet::new(); - let mut used_abi = HashSet::new(); - - // account_key here is the address' hash. - for item in account_trie.iter().map_err(|err| *err)? { - let (account_key, account_data) = item.map_err(|err| *err)?; - - let basic_account = ::rlp::decode(&*account_data); - let account_key = H256::from_slice(&account_key); - let account_address = Address::from_slice(&account_key); - trace!("taking snapshot of account: {:?}", account_address); - - let account_db = AccountDB::new(db, &account_address); - - let fat_rlps = account::to_fat_rlps( - &account_address, - &basic_account, - &account_db, - &mut used_code, - &mut used_abi, - PREFERRED_CHUNK_SIZE - chunker.cur_size, - PREFERRED_CHUNK_SIZE, - )?; - - for (i, fat_rlp) in fat_rlps.into_iter().enumerate() { - if i > 0 { - chunker.write_chunk()?; - } - chunker.push(fat_rlp)?; - } - } - - if chunker.cur_size != 0 { - chunker.write_chunk()?; - } - - Ok(chunker.hashes) -} - -/// Used to build block chunks. -struct BlockChunker<'a> { - executor: &'a Executor, - // block, receipt rlp pairs. - rlps: VecDeque, - current_hash: H256, - writer: &'a mut ChunkSink<'a>, - preferred_size: usize, -} - -impl<'a> BlockChunker<'a> { - // Repeatedly fill the buffers and writes out chunks, moving backwards from starting block hash. - // Loops until we reach the first desired block, and writes out the remainder. - fn chunk_all(&mut self) -> Result<(), Error> { - let mut loaded_size = 0; - let mut last = self.current_hash; - - let start_header = self - .executor - .block_header_by_hash(self.current_hash) - .ok_or_else(|| Error::BlockNotFound(self.current_hash))?; - let step = if start_header.number() < 100 { - 1 - } else { - start_header.number() / 100 - }; - - let genesis_block = self - .executor - .block_header_by_height(0) - .expect("Get genesis block failed"); - let genesis_hash = genesis_block.hash().unwrap(); - info!("genesis_hash: {:?}", genesis_hash); - let mut blocks_num = 0; - - loop { - if self.current_hash == genesis_hash { - break; - } - - let header = self - .executor - .block_header_by_hash(self.current_hash) - .ok_or_else(|| Error::BlockNotFound(self.current_hash))?; - - let mut s = RlpStream::new(); - header.rlp_append(&mut s); - let header_rlp = s.out(); - - if blocks_num % step == 0 { - info!("taking snapshot of {}-th header", header.number()); - } - - let new_loaded_size = loaded_size + header_rlp.len(); - - // cut off the chunk if too large. - if new_loaded_size > self.preferred_size && !self.rlps.is_empty() { - self.write_chunk(last)?; - loaded_size = header_rlp.len(); - } else { - loaded_size = new_loaded_size; - } - - self.rlps.push_front(header_rlp); - - last = self.current_hash; - self.current_hash = *header.parent_hash(); - - blocks_num += 1; - } - - if loaded_size != 0 { - self.write_chunk(last)?; - } - - Ok(()) - } - - // write out the data in the buffers to a chunk on disk - // - // we preface each chunk with the parent of the first block's details, - // obtained from the details of the last block written. - fn write_chunk(&mut self, last: H256) -> Result<(), Error> { - trace!("prepared block chunk with {} blocks", self.rlps.len()); - - let last_header = self - .executor - .block_header_by_hash(last) - .ok_or_else(|| Error::BlockNotFound(last))?; - - let parent_number = last_header.number() - 1; - let parent_hash = last_header.parent_hash(); - - trace!("parent last written block: {}", parent_hash); - - let num_entries = self.rlps.len(); - let mut rlp_stream = RlpStream::new_list(2 + num_entries); - rlp_stream.append(&parent_number).append(parent_hash); - - for pair in self.rlps.drain(..) { - rlp_stream.append_raw(&pair, 1); - } - - let raw_data = rlp_stream.out(); - - (self.writer)(&raw_data)?; - - Ok(()) - } -} - -/// Returns a list of chunk hashes, with the first having the blocks furthest from the genesis. -pub fn chunk_secondary<'a>( - executor: &'a Executor, - start_hash: H256, - writer: &Mutex, - progress: &'a Progress, -) -> Result, Error> { - let mut chunk_hashes = Vec::new(); - let mut compressed_data = Vec::new(); - - { - let mut chunk_sink = |raw_data: &[u8]| { - compressed_data.clear(); - snappy::compress_to(raw_data, &mut compressed_data)?; - let hash = compressed_data.crypt_hash(); - let size = compressed_data.len(); - - writer.lock().write_block_chunk(hash, &compressed_data)?; - trace!( - "wrote secondary chunk. hash: {:?}, size: {}, uncompressed size: {}", - hash, - size, - raw_data.len(), - ); - - progress.size.fetch_add(size, Ordering::SeqCst); - chunk_hashes.push(hash); - Ok(()) - }; - - BlockChunker { - executor, - rlps: VecDeque::new(), - current_hash: start_hash, - writer: &mut chunk_sink, - preferred_size: PREFERRED_CHUNK_SIZE, - } - .chunk_all()? - } - - Ok(chunk_hashes) -} - -/// Used to rebuild the state trie piece by piece. -pub struct StateRebuilder { - db: Box, - state_root: H256, - known_code: HashMap, // code hashes mapped to first account with this code. - missing_code: HashMap>, // maps code hashes to lists of accounts missing that code. - known_abi: HashMap, // abi hashes mapped to first account with this abi. - missing_abi: HashMap>, // maps abi hashes to lists of accounts missing that abi. - bloom: Bloom, - known_storage_roots: HashMap, // maps account hashes to last known storage root. Only - // filled for last account per chunk. -} - -impl StateRebuilder { - /// Create a new state rebuilder to write into the given backing DB. - pub fn new(db: Arc, pruning: Algorithm) -> Self { - let bloom = StateDB::load_bloom(&*db); - StateRebuilder { - db: journaldb::new(db, pruning, COL_STATE), - state_root: HASH_NULL_RLP, - known_code: HashMap::new(), - missing_code: HashMap::new(), - known_abi: HashMap::new(), - missing_abi: HashMap::new(), - bloom, - known_storage_roots: HashMap::new(), - } - } - - /// Feed an uncompressed state chunk into the rebuilder. - pub fn feed(&mut self, chunk: &[u8], flag: &AtomicBool) -> Result<(), crate::error::Error> { - let rlp = UntrustedRlp::new(chunk); - let empty_rlp = StateAccount::new_basic(U256::zero(), U256::zero()).rlp(); - let mut pairs = Vec::with_capacity(rlp.item_count()?); - - // initialize the pairs vector with empty values so we have slots to write into. - pairs.resize(rlp.item_count()?, (Address::new(), Vec::new())); - - let status = rebuild_accounts( - self.db.as_hashdb_mut(), - &rlp, - &mut pairs, - &self.known_code, - &self.known_abi, - &mut self.known_storage_roots, - flag, - )?; - - for (addr, code_hash) in status.missing_code { - self.missing_code - .entry(code_hash) - .or_insert_with(Vec::new) - .push(addr); - } - - // patch up all missing code. must be done after collecting all new missing code entries. - for (code_hash, code, first_with) in status.new_code { - for addr in self - .missing_code - .remove(&code_hash) - .unwrap_or_else(Vec::new) - { - let mut db = AccountDBMut::new(self.db.as_hashdb_mut(), &addr); - db.emplace(code_hash, DBValue::from_slice(&code)); - } - - self.known_code.insert(code_hash, first_with); - } - - for (addr, abi_hash) in status.missing_abi { - self.missing_abi - .entry(abi_hash) - .or_insert_with(Vec::new) - .push(addr); - } - - // patch up all missing code. must be done after collecting all new missing code entries. - for (abi_hash, abi, first_with) in status.new_abi { - for addr in self.missing_abi.remove(&abi_hash).unwrap_or_else(Vec::new) { - let mut db = AccountDBMut::new(self.db.as_hashdb_mut(), &addr); - db.emplace(abi_hash, DBValue::from_slice(&abi)); - } - - self.known_abi.insert(abi_hash, first_with); - } - - let backing = self.db.backing().clone(); - - // batch trie writes - { - let mut account_trie = - TrieDBMut::from_existing(self.db.as_hashdb_mut(), &mut self.state_root) - .map_err(|err| *err)?; - - for (addr, thin_rlp) in pairs { - if !flag.load(Ordering::SeqCst) { - return Err(Error::RestorationAborted.into()); - } - - if thin_rlp[..] != empty_rlp[..] { - self.bloom.set(addr); - } - - account_trie.insert(&addr, &thin_rlp).map_err(|err| *err)?; - } - } - - let bloom_journal = self.bloom.drain_journal(); - let mut batch = backing.transaction(); - StateDB::commit_bloom(&mut batch, bloom_journal)?; - self.db.inject(&mut batch)?; - backing.write_buffered(batch); - - trace!("current state root: {:?}", self.state_root); - - Ok(()) - } - - /// Finalize the restoration. Check for accounts missing code and make a dummy - /// journal entry. - /// Once all chunks have been fed, there should be nothing missing. - pub fn finalize(mut self, era: u64, id: H256) -> Result, crate::error::Error> { - let mut batch = self.db.backing().transaction(); - self.db.journal_under(&mut batch, era, &id)?; - self.db.backing().write_buffered(batch); - - Ok(self.db) - } - - /// Get the state root of the rebuilder. - pub fn state_root(&self) -> H256 { - self.state_root - } -} - -#[derive(Default)] -struct RebuiltStatus { - // new code that's become available. (code_hash, code, addr_hash) - new_code: Vec<(H256, Bytes, Address)>, - missing_code: Vec<(Address, H256)>, // accounts that are missing code. - new_abi: Vec<(H256, Bytes, Address)>, - missing_abi: Vec<(Address, H256)>, // accounts that are missing abi. -} - -// rebuild a set of accounts and their storage. -// returns a status detailing newly-loaded code, accounts missing code, -// newly-loaded abi and accounts missing abi. -fn rebuild_accounts( - db: &mut HashDB, - account_fat_rlps: &UntrustedRlp, - out_chunk: &mut [(Address, Bytes)], - known_code: &HashMap, - known_abi: &HashMap, - known_storage_roots: &mut HashMap, - abort_flag: &AtomicBool, -) -> Result { - let mut status = RebuiltStatus::default(); - for (account_rlp, out) in account_fat_rlps.into_iter().zip(out_chunk.iter_mut()) { - if !abort_flag.load(Ordering::SeqCst) { - return Err(Error::RestorationAborted.into()); - } - - let address: Address = account_rlp.val_at(0)?; - let fat_rlp = account_rlp.at(1)?; - - let thin_rlp = { - // fill out the storage trie and code while decoding. - let (acc, maybe_code, maybe_abi) = { - let mut acct_db = AccountDBMut::new(db, &address); - let storage_root = known_storage_roots - .get(&address) - .cloned() - .unwrap_or_else(H256::zero); - account::from_fat_rlp(&mut acct_db, &fat_rlp, storage_root).unwrap() - }; - - let code_hash = acc.code_hash; - match maybe_code { - // new inline code - Some(code) => status.new_code.push((code_hash, code, address)), - None => { - if code_hash != HASH_EMPTY { - // see if this code has already been included inline - match known_code.get(&code_hash) { - Some(&first_with) => { - // if so, load it from the database. - let code = AccountDB::new(db, &first_with) - .get(&code_hash) - .ok_or_else(|| Error::MissingCode(vec![first_with])) - .unwrap(); - - // and write it again under a different mangled key - AccountDBMut::new(db, &address).emplace(code_hash, code); - } - // if not, queue it up to be filled later - None => status.missing_code.push((address, code_hash)), - } - } - } - } - let abi_hash = acc.abi_hash; - match maybe_abi { - // new inline abi - Some(abi) => status.new_abi.push((abi_hash, abi, address)), - None => { - if abi_hash != HASH_EMPTY { - // see if this abi has already been included inline - match known_abi.get(&abi_hash) { - Some(&first_with) => { - // if so, load it from the database. - let abi = AccountDB::new(db, &first_with) - .get(&abi_hash) - .ok_or_else(|| Error::MissingAbi(vec![first_with])) - .unwrap(); - - // and write it again under a different mangled key - AccountDBMut::new(db, &address).emplace(abi_hash, abi); - } - // if not, queue it up to be filled later - None => status.missing_abi.push((address, abi_hash)), - } - } - } - } - - ::rlp::encode(&acc).into_vec() - }; - - *out = (address, thin_rlp); - } - if let Some(&(ref address, ref rlp)) = out_chunk.iter().last() { - known_storage_roots.insert(*address, ::rlp::decode::(rlp).storage_root); - } - if let Some(&(ref address, ref rlp)) = out_chunk.iter().next() { - known_storage_roots.insert(*address, ::rlp::decode::(rlp).storage_root); - } - Ok(status) -} - -/// Used to rebuild the state trie piece by piece. -pub struct BlockRebuilder { - executor: Arc, - db: Arc, - //_disconnected: Vec<(u64, H256)>, - best_number: u64, - best_hash: H256, - best_root: H256, - fed_blocks: u64, - snapshot_blocks: u64, -} - -impl BlockRebuilder { - /// Create a new state rebuilder to write into the given backing DB. - pub fn new( - executor: Arc, - db: Arc, - manifest: &ManifestData, - snapshot_blocks: u64, - ) -> Self { - BlockRebuilder { - executor, - db, - //_disconnected: Vec::new(), - best_number: manifest.block_number, - best_hash: manifest.block_hash, - best_root: manifest.state_root, - fed_blocks: 0, - snapshot_blocks, - } - } - - /// Feed an uncompressed state chunk into the rebuilder. - pub fn feed( - &mut self, - chunk: &[u8], - abort_flag: &AtomicBool, - ) -> Result<(), crate::error::Error> { - let rlp = UntrustedRlp::new(chunk); - let item_count = rlp.item_count()?; - let num_blocks = (item_count - 2) as u64; - trace!("restoring block chunk with {} blocks.", num_blocks); - - if self.fed_blocks + num_blocks > self.snapshot_blocks { - return Err( - Error::TooManyBlocks(self.snapshot_blocks, self.fed_blocks + num_blocks).into(), - ); - } - - // todo: assert here that these values are consistent with chunks being in order. - let mut cur_number = rlp.val_at::(0)? + 1; - //let mut parent_hash = rlp.val_at::(1)?; - - for idx in 2..item_count { - if !abort_flag.load(Ordering::SeqCst) { - return Err(Error::RestorationAborted.into()); - } - - let pair = rlp.at(idx)?; - - let header_rlp = pair.as_raw().to_owned(); - let header: Header = ::rlp::decode(header_rlp.as_slice()); - - let is_best = cur_number == self.best_number; - - if is_best { - if header.hash().unwrap() != self.best_hash { - return Err(Error::WrongBlockHash( - cur_number, - self.best_hash, - header.hash().unwrap(), - ) - .into()); - } - - if header.state_root() != &self.best_root { - return Err(Error::WrongStateRoot(self.best_root, *header.state_root()).into()); - } - } - - // TODO: verify - //verify_old_block(&mut self.rng, &header, engine, &self.chain, is_best)?; - - let mut batch = self.db.transaction(); - - self.insert_unordered_block(&mut batch, &header, is_best); - - self.db.write_buffered(batch); - - // TODO: update current Chain. - //self.chain.commit(); - - //parent_hash = view!(BlockView, &block_bytes).hash(); - cur_number += 1; - } - - self.fed_blocks += num_blocks; - - Ok(()) - } - - fn insert_unordered_block(&self, batch: &mut DBTransaction, header: &Header, is_best: bool) { - let height = header.number(); - let hash = header.hash().unwrap(); - - // store block in db - batch.write(COL_HEADERS, &hash, &header.clone()); - - batch.write(COL_EXTRA, &height, &hash); - - if is_best { - info!("snapshot restoration write CURRENT_HASH: {:?}", hash); - batch.write(COL_EXTRA, &CurrentHash, &hash); - } - } - - /// Glue together any disconnected chunks and check that the chain is complete. - fn finalize(&self) -> Result<(), crate::error::Error> { - let mut batch = self.db.transaction(); - let genesis_header = self - .executor - .block_header_by_height(0) - .expect("Get genesis block failed"); - let hash = genesis_header.hash().unwrap(); - batch.write(COL_HEADERS, &hash, &genesis_header); - batch.write(COL_EXTRA, &0, &hash); - - self.db.write_buffered(batch); - Ok(()) - } -} - -// helper for reading chunks from arbitrary reader and feeding them into the -// service. -pub fn restore_using( - snapshot: &Arc, - reader: &R, - recover: bool, -) -> Result<(), String> { - let manifest = reader.manifest(); - - info!( - "Restoring to block #{} (0x{:?})", - manifest.block_number, manifest.block_hash - ); - - snapshot - .init_restore(manifest.clone(), recover) - .map_err(|e| format!("Failed to begin restoration: {}", e))?; - - let (num_state, num_blocks) = (manifest.state_hashes.len(), manifest.block_hashes.len()); - - let informant_handle = snapshot.clone(); - ::std::thread::spawn(move || { - while let RestorationStatus::Ongoing { - state_chunks_done, - block_chunks_done, - .. - } = informant_handle.status() - { - info!( - "Processed {}/{} state chunks and {}/{} block chunks.", - state_chunks_done, num_state, block_chunks_done, num_blocks - ); - ::std::thread::sleep(Duration::from_secs(5)); - } - }); - - info!("Restoring state"); - for &state_hash in &manifest.state_hashes { - if snapshot.status() == RestorationStatus::Failed { - return Err("Restoration failed".into()); - } - - let chunk = reader.chunk(state_hash).map_err(|e| { - format!( - "Encountered error while reading chunk {:?}: {}", - state_hash, e - ) - })?; - - let hash = chunk.crypt_hash(); - if hash != state_hash { - return Err(format!( - "Mismatched chunk hash. Expected {:?}, got {:?}", - state_hash, hash - )); - } - - snapshot.feed_state_chunk(state_hash, &chunk); - } - - info!("Restoring blocks"); - for &block_hash in &manifest.block_hashes { - if snapshot.status() == RestorationStatus::Failed { - return Err("Restoration failed".into()); - } - - let chunk = reader.chunk(block_hash).map_err(|e| { - format!( - "Encountered error while reading chunk {:?}: {}", - block_hash, e - ) - })?; - - let hash = chunk.crypt_hash(); - if hash != block_hash { - return Err(format!( - "Mismatched chunk hash. Expected {:?}, got {:?}", - block_hash, hash - )); - } - snapshot.feed_block_chunk(block_hash, &chunk); - } - - match snapshot.status() { - RestorationStatus::Ongoing { .. } => { - Err("Snapshot file is incomplete and missing chunks.".into()) - } - RestorationStatus::Failed => Err("Snapshot restoration failed.".into()), - RestorationStatus::Inactive => { - info!("Restoration complete."); - Ok(()) - } - } -} diff --git a/cita-executor/core/src/snapshot/service.rs b/cita-executor/core/src/snapshot/service.rs deleted file mode 100644 index aeb83e15d..000000000 --- a/cita-executor/core/src/snapshot/service.rs +++ /dev/null @@ -1,501 +0,0 @@ -// Copyright 2015-2017 Parity Technologies (UK) Ltd. -// This file is part of Parity. - -// This software is free software: you can redistribute it and/or modify -// it under the terms of the GNU General Public License as published by -// the Free Software Foundation, either version 3 of the License, or -// (at your option) any later version. - -// This software 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 General Public License for more details. - -// You should have received a copy of the GNU General Public License -// along with Parity. If not, see . - -//! Snapshot network service implementation. - -use std::collections::HashSet; -use std::fs; -use std::io::ErrorKind; -use std::path::PathBuf; -use std::sync::atomic::{AtomicBool, AtomicUsize, Ordering}; -use std::sync::Arc; - -//use super::{ManifestData, StateRebuilder, RestorationStatus, SnapshotService}; -use super::io::{LooseReader, LooseWriter, SnapshotReader, SnapshotWriter}; -use super::{BlockRebuilder, ManifestData, RestorationStatus, StateRebuilder}; - -use crate::error::Error; - -use crate::libexecutor::executor::Executor; -use cita_types::H256; - -use crate::cita_db::journaldb::Algorithm; -use crate::cita_db::kvdb::{Database, DatabaseConfig, KeyValueDB}; -use crate::cita_db::TrieError; -use snappy; -use util::Bytes; -use util::UtilError; -use util::{Mutex, RwLock, RwLockReadGuard}; - -/// State restoration manager. -struct Restoration { - manifest: ManifestData, - state_chunks_left: HashSet, - block_chunks_left: HashSet, - state: StateRebuilder, - secondary: Box, - writer: Option, - final_state_root: H256, - //guard: Guard, - db: Arc, -} - -struct RestorationParams<'a> { - manifest: ManifestData, // manifest to base restoration on. - pruning: Algorithm, // pruning algorithm for the database. - db_path: PathBuf, // database path - db_config: &'a DatabaseConfig, // configuration for the database. - writer: Option, // writer for recovered snapshot. - executor: Arc, - //guard: Guard, // guard for the restoration directory. -} - -impl Restoration { - // make a new restoration using the given parameters. - fn create(params: RestorationParams) -> Result { - let manifest = params.manifest; - - let state_chunks = manifest.state_hashes.iter().cloned().collect(); - let block_chunks = manifest.block_hashes.iter().cloned().collect(); - - let raw_db = Arc::new( - Database::open(params.db_config, &*params.db_path.to_string_lossy()) - .map_err(UtilError::from)?, - ); - - let secondary = BlockRebuilder::new( - params.executor.clone(), - raw_db.clone(), - &manifest, - manifest.block_number, - ); - - let root = manifest.state_root; - - Ok(Restoration { - manifest, - state_chunks_left: state_chunks, - block_chunks_left: block_chunks, - state: StateRebuilder::new(raw_db.clone(), params.pruning), - secondary: Box::new(secondary), - writer: params.writer, - final_state_root: root, - //guard: params.guard, - db: raw_db, - }) - } - - // feeds a state chunk, aborts early if `flag` becomes false. - fn feed_state(&mut self, hash: H256, chunk: &[u8], flag: &AtomicBool) -> Result<(), Error> { - if self.state_chunks_left.contains(&hash) { - let mut decompressed_data = Vec::new(); - snappy::decompress_to(chunk, &mut decompressed_data)?; - - self.state.feed(&decompressed_data, flag)?; - - if let Some(ref mut writer) = self.writer.as_mut() { - writer.write_state_chunk(hash, chunk)?; - } - - self.state_chunks_left.remove(&hash); - } - - Ok(()) - } - - // feeds a block chunk - fn feed_blocks(&mut self, hash: H256, chunk: &[u8], flag: &AtomicBool) -> Result<(), Error> { - if self.block_chunks_left.contains(&hash) { - let mut decompressed_data = Vec::new(); - snappy::decompress_to(chunk, &mut decompressed_data)?; - - self.secondary.feed(&decompressed_data, flag)?; - if let Some(ref mut writer) = self.writer.as_mut() { - writer.write_block_chunk(hash, chunk)?; - } - - self.block_chunks_left.remove(&hash); - } - - Ok(()) - } - - // finish up restoration. - fn finalize(self) -> Result<(), Error> { - if !self.is_done() { - return Ok(()); - } - - // verify final state root. - let root = self.state.state_root(); - if root != self.final_state_root { - warn!( - "Final restored state has wrong state root: expected {:?}, got {:?}", - self.final_state_root, root - ); - return Err(TrieError::InvalidStateRoot(root).into()); - } - - // check for missing code and abi. - self.state - .finalize(self.manifest.block_number, self.manifest.block_hash)?; - - // connect out-of-order chunks and verify chain integrity. - self.secondary.finalize()?; - - if let Some(writer) = self.writer { - writer.finish(self.manifest)?; - } - - info!("snapshot flush snapshot-database"); - if let Err(reason) = self.db.flush() { - error!("failed to flush snapshot database: {}", reason); - } - - info!("snapshot close snapshot-database"); - self.db.close(); - Ok(()) - } - - // is everything done? - fn is_done(&self) -> bool { - self.block_chunks_left.is_empty() && self.state_chunks_left.is_empty() - } -} - -/// Snapshot service parameters. -pub struct ServiceParams { - /// Database configuration options. - pub db_config: DatabaseConfig, - /// State pruning algorithm. - pub pruning: Algorithm, - /// Usually "/snapshot" - pub snapshot_root: PathBuf, - pub executor: Arc, -} - -/// `SnapshotService` implementation. -/// This controls taking snapshots and restoring from them. -pub struct Service { - restoration: Mutex>, - snapshot_root: PathBuf, - db_config: DatabaseConfig, - pruning: Algorithm, - status: Mutex, - reader: RwLock>, - state_chunks: AtomicUsize, - block_chunks: AtomicUsize, - progress: super::Progress, - taking_snapshot: AtomicBool, - restoring_snapshot: AtomicBool, - executor: Arc, -} - -impl Service { - /// Create a new snapshot service from the given parameters. - pub fn create(params: ServiceParams) -> Result { - let mut service = Service { - restoration: Mutex::new(None), - snapshot_root: params.snapshot_root, - db_config: params.db_config, - pruning: params.pruning, - status: Mutex::new(RestorationStatus::Inactive), - reader: RwLock::new(None), - state_chunks: AtomicUsize::new(0), - block_chunks: AtomicUsize::new(0), - progress: Default::default(), - taking_snapshot: AtomicBool::new(false), - restoring_snapshot: AtomicBool::new(false), - executor: params.executor, - }; - - // create the root snapshot dir if it doesn't exist. - if let Err(e) = fs::create_dir_all(&service.snapshot_root) { - if e.kind() != ErrorKind::AlreadyExists { - return Err(e.into()); - } - } - - // delete the temporary restoration dir if it does exist. - if let Err(e) = fs::remove_dir_all(service.restoration_dir()) { - if e.kind() != ErrorKind::NotFound { - return Err(e.into()); - } - } - - // delete the temporary snapshot dir if it does exist. - if let Err(e) = fs::remove_dir_all(service.temp_snapshot_dir()) { - if e.kind() != ErrorKind::NotFound { - return Err(e.into()); - } - } - - let reader = LooseReader::create(service.snapshot_dir()).ok(); - *service.reader.get_mut() = reader; - - Ok(service) - } - - // get the current snapshot dir. - fn snapshot_dir(&self) -> PathBuf { - let mut dir = self.snapshot_root.clone(); - dir.push("current"); - dir - } - - // get the temporary snapshot dir. - fn temp_snapshot_dir(&self) -> PathBuf { - let mut dir = self.snapshot_root.clone(); - dir.push("in_progress"); - dir - } - - // get the restoration directory. - fn restoration_dir(&self) -> PathBuf { - let mut dir = self.snapshot_root.clone(); - dir.push("restoration"); - dir - } - - // restoration db path. - fn restoration_db(&self) -> PathBuf { - let mut dir = self.restoration_dir(); - dir.push("db"); - dir - } - - // temporary snapshot recovery path. - fn temp_recovery_dir(&self) -> PathBuf { - let mut dir = self.restoration_dir(); - dir.push("temp"); - dir - } - - /// Get a reference to the snapshot reader. - pub fn reader(&self) -> RwLockReadGuard> { - self.reader.read() - } - - /// Tick the snapshot service. This will log any active snapshot - /// being taken. - pub fn tick(&self) { - if self.progress.done() || !self.taking_snapshot.load(Ordering::SeqCst) { - return; - } - - let p = &self.progress; - info!("Snapshot: {} accounts {} bytes", p.accounts(), p.size()); - } - - /// Initialize the restoration synchronously. - /// The recover flag indicates whether to recover the restored snapshot. - pub fn init_restore(&self, manifest: ManifestData, recover: bool) -> Result<(), Error> { - let rest_dir = self.restoration_dir(); - - let mut res = self.restoration.lock(); - - self.state_chunks.store(0, Ordering::SeqCst); - self.block_chunks.store(0, Ordering::SeqCst); - - // tear down existing restoration. - *res = None; - - // delete and restore the restoration dir. - if let Err(e) = fs::remove_dir_all(&rest_dir) { - match e.kind() { - ErrorKind::NotFound => {} - _ => return Err(e.into()), - } - } - - fs::create_dir_all(&rest_dir)?; - - // make new restoration. - let writer = if recover { - Some(LooseWriter::create(self.temp_recovery_dir())?) - } else { - None - }; - - let params = RestorationParams { - executor: self.executor.clone(), - manifest, - pruning: self.pruning, - db_path: self.restoration_db(), - db_config: &self.db_config, - writer, - //guard: Guard::new(rest_dir), - }; - - let state_chunks = params.manifest.state_hashes.len(); - let block_chunks = params.manifest.block_hashes.len(); - - *res = Some(Restoration::create(params)?); - - *self.status.lock() = RestorationStatus::Ongoing { - state_chunks: state_chunks as u32, - block_chunks: block_chunks as u32, - state_chunks_done: self.state_chunks.load(Ordering::SeqCst) as u32, - block_chunks_done: self.block_chunks.load(Ordering::SeqCst) as u32, - }; - - self.restoring_snapshot.store(true, Ordering::SeqCst); - Ok(()) - } - - // finalize the restoration. this accepts an already-locked - // restoration as an argument -- so acquiring it again _will_ - // lead to deadlock. - fn finalize_restoration(&self, rest: &mut Option) -> Result<(), Error> { - trace!("finalizing restoration"); - - // destroy the restoration before replacing databases and snapshot. - rest.take().map(Restoration::finalize).unwrap_or(Ok(()))?; - - *self.status.lock() = RestorationStatus::Inactive; - Ok(()) - } - - /// Feed a chunk of either kind. no-op if no restoration or status is wrong. - fn feed_chunk(&self, hash: H256, chunk: &[u8], is_state: bool) -> Result<(), Error> { - // TODO: be able to process block chunks and state chunks at same time? - let (result, db) = { - let mut restoration = self.restoration.lock(); - - match self.status() { - RestorationStatus::Inactive | RestorationStatus::Failed => return Ok(()), - RestorationStatus::Ongoing { .. } => { - let (res, db) = { - let rest = match *restoration { - Some(ref mut r) => r, - None => return Ok(()), - }; - - ( - if is_state { - rest.feed_state(hash, chunk, &self.restoring_snapshot) - } else { - rest.feed_blocks(hash, chunk, &self.restoring_snapshot) - } - .map(|_| rest.is_done()), - rest.db.clone(), - ) - }; - - let res = match res { - Ok(is_done) => { - if is_state { - self.state_chunks.fetch_add(1, Ordering::SeqCst) - } else { - self.block_chunks.fetch_add(1, Ordering::SeqCst) - }; - - if is_done { - db.flush().map_err(UtilError::from)?; - drop(db); - return self.finalize_restoration(&mut *restoration); - } - Ok(()) - } - other => other.map(drop), - }; - (res, db) - } - } - }; - result.and_then(|_| db.flush().map_err(|e| UtilError::from(e).into())) - } - - /// Feed a state chunk to be processed synchronously. - pub fn feed_state_chunk(&self, hash: H256, chunk: &[u8]) { - match self.feed_chunk(hash, chunk, true) { - Ok(()) => (), - Err(e) => { - warn!("Encountered error during state restoration: {}", e); - *self.restoration.lock() = None; - *self.status.lock() = RestorationStatus::Failed; - let _ = fs::remove_dir_all(self.restoration_dir()); - } - } - } - - /// Feed a block chunk to be processed synchronously. - pub fn feed_block_chunk(&self, hash: H256, chunk: &[u8]) { - match self.feed_chunk(hash, chunk, false) { - Ok(()) => (), - Err(e) => { - warn!("Encountered error during block restoration: {}", e); - *self.restoration.lock() = None; - *self.status.lock() = RestorationStatus::Failed; - let _ = fs::remove_dir_all(self.restoration_dir()); - } - } - } -} - -impl SnapshotService for Service { - //fn manifest(&self) -> Option { - //self.reader.read().as_ref().map(|r| r.manifest().clone()) - //} - - fn chunk(&self, hash: H256) -> Option { - self.reader.read().as_ref().and_then(|r| r.chunk(hash).ok()) - } - - fn status(&self) -> RestorationStatus { - let mut cur_status = self.status.lock(); - if let RestorationStatus::Ongoing { - ref mut state_chunks_done, - ref mut block_chunks_done, - .. - } = *cur_status - { - *state_chunks_done = self.state_chunks.load(Ordering::SeqCst) as u32; - *block_chunks_done = self.block_chunks.load(Ordering::SeqCst) as u32; - } - - *cur_status - } - - fn abort_restore(&self) { - self.restoring_snapshot.store(false, Ordering::SeqCst); - *self.restoration.lock() = None; - *self.status.lock() = RestorationStatus::Inactive; - } -} -/// The interface for a snapshot network service. -/// This handles: -/// - restoration of snapshots to temporary databases. -/// - responding to queries for snapshot manifests and chunks -pub trait SnapshotService: Sync + Send { - /// Query the most recent manifest data. - //fn manifest(&self) -> Option<&ManifestData>; - - /// Get raw chunk for a given hash. - fn chunk(&self, hash: H256) -> Option; - - /// Ask the snapshot service for the restoration status. - fn status(&self) -> RestorationStatus; - - /// Abort an in-progress restoration if there is one. - fn abort_restore(&self); -} - -impl Drop for Service { - fn drop(&mut self) { - self.abort_restore(); - } -} diff --git a/cita-executor/core/src/spec/builtin.rs b/cita-executor/core/src/spec/builtin.rs deleted file mode 100644 index 4d6e2de05..000000000 --- a/cita-executor/core/src/spec/builtin.rs +++ /dev/null @@ -1,96 +0,0 @@ -// Copyright 2015-2018 Parity Technologies (UK) Ltd. -// This file is part of Parity. - -// Parity is free software: you can redistribute it and/or modify -// it under the terms of the GNU General Public License as published by -// the Free Software Foundation, either version 3 of the License, or -// (at your option) any later version. - -// Parity 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 General Public License for more details. - -// You should have received a copy of the GNU General Public License -// along with Parity. If not, see . - -//! Spec builtin deserialization. - -/// Linear pricing. -#[derive(Debug, PartialEq, Deserialize, Clone)] -pub struct Linear { - /// Base price. - pub base: usize, - /// Price for word. - pub word: usize, -} - -/// Pricing for modular exponentiation. -#[derive(Debug, PartialEq, Deserialize, Clone)] -pub struct Modexp { - /// Price divisor. - pub divisor: usize, -} - -/// Pricing variants. -#[derive(Debug, PartialEq, Deserialize, Clone)] -pub enum Pricing { - /// Linear pricing. - #[serde(rename = "linear")] - Linear(Linear), -} - -/// Spec builtin. -#[derive(Debug, PartialEq, Deserialize, Clone)] -pub struct Builtin { - /// Builtin name. - pub name: String, - /// Builtin pricing. - pub pricing: Pricing, - /// Activation block. - pub activate_at: Option, -} - -#[cfg(test)] -mod tests { - use crate::spec::builtin::{Builtin, Linear, Pricing}; - use serde_json; - - #[test] - fn builtin_deserialization() { - let s = r#"{ - "name": "ecrecover", - "pricing": { "linear": { "base": 3000, "word": 0 } } - }"#; - let deserialized: Builtin = serde_json::from_str(s).unwrap(); - assert_eq!(deserialized.name, "ecrecover"); - assert_eq!( - deserialized.pricing, - Pricing::Linear(Linear { - base: 3000, - word: 0 - }) - ); - assert!(deserialized.activate_at.is_none()); - } - - #[test] - fn activate_at() { - let s = r#"{ - "name": "late_start", - "activate_at": 66666, - "pricing": { "linear": { "base": 3000, "word": 0 } } - }"#; - - let deserialized: Builtin = serde_json::from_str(s).unwrap(); - assert_eq!(deserialized.name, "late_start"); - assert_eq!( - deserialized.pricing, - Pricing::Linear(Linear { - base: 3000, - word: 0 - }) - ); - assert_eq!(deserialized.activate_at, Some(66666)); - } -} diff --git a/cita-executor/core/src/spec/mod.rs b/cita-executor/core/src/spec/mod.rs deleted file mode 100644 index a538f403e..000000000 --- a/cita-executor/core/src/spec/mod.rs +++ /dev/null @@ -1,20 +0,0 @@ -// CITA -// Copyright 2016-2018 Cryptape Technologies LLC. - -// This program is free software: you can redistribute it -// and/or modify it under the terms of the GNU 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 General Public License for more details. - -// You should have received a copy of the GNU General Public License -// along with this program. If not, see . - -mod builtin; - -pub use self::builtin::{Builtin, Linear, Pricing}; diff --git a/cita-executor/core/src/state/account.rs b/cita-executor/core/src/state/account.rs deleted file mode 100644 index 20ceac16a..000000000 --- a/cita-executor/core/src/state/account.rs +++ /dev/null @@ -1,1181 +0,0 @@ -// Copyright 2015-2017 Parity Technologies (UK) Ltd. -// This file is part of Parity. - -// This software is free software: you can redistribute it and/or modify -// it under the terms of the GNU General Public License as published by -// the Free Software Foundation, either version 3 of the License, or -// (at your option) any later version. - -// This software 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 General Public License for more details. - -// You should have received a copy of the GNU General Public License -// along with Parity. If not, see . - -// CITA, Copyright 2016-2017 Cryptape Technologies LLC. -// Add abi - -//! Single account in the system. - -use crate::cita_db::{trie, DBValue, HashDB, Trie, TrieFactory}; -use crate::pod_account::*; -use crate::types::basic_account::BasicAccount; -use cita_types::traits::LowerHex; -use cita_types::{Address, H256, U256}; -use hashable::{Hashable, HASH_EMPTY, HASH_NULL_RLP}; -use lru_cache::LruCache; -use rlp::*; -use std::cell::{Cell, RefCell}; -use std::collections::BTreeMap; -use std::collections::HashMap; -use std::convert::Into; -use std::fmt; -use std::sync::Arc; -use util::*; - -const STORAGE_CACHE_ITEMS: usize = 8192; - -/// Single account in the system. -/// Keeps track of changes to the code and storage. -/// The changes are applied in `commit_storage` and `commit_code` -pub struct Account { - // Balance of the account. - balance: U256, - /// Nonce of the account. - nonce: U256, - /// Trie-backed storage. - storage_root: H256, - /// LRU Cache of the trie-backed storage. - /// This is limited to `STORAGE_CACHE_ITEMS` recent queries - storage_cache: RefCell>, - /// Modified storage. Accumulates changes to storage made in `set_storage` - /// Takes precedence over `storage_cache`. - storage_changes: HashMap, - /// Code hash of the account. - code_hash: H256, - /// Size of the account code. - code_size: Option, - /// Code cache of the account. - code_cache: Arc, - /// Account code new or has been modified. - code_filth: Filth, - /// ABI hash of the account. - abi_hash: H256, - /// Size of the account ABI. - abi_size: Option, - /// ABI cache of the account. - abi_cache: Arc, - /// Account ABI new or has been modified. - abi_filth: Filth, - /// Cached address hash. - address_hash: Cell>, -} - -impl From for Account { - fn from(basic: BasicAccount) -> Self { - Account { - balance: basic.balance, - nonce: basic.nonce, - storage_root: basic.storage_root, - storage_cache: Self::empty_storage_cache(), - storage_changes: HashMap::new(), - code_hash: basic.code_hash, - code_size: None, - code_cache: Arc::new(vec![]), - code_filth: Filth::Clean, - abi_hash: basic.abi_hash, - abi_size: None, - abi_cache: Arc::new(vec![]), - abi_filth: Filth::Clean, - address_hash: Cell::new(None), - } - } -} - -impl Account { - #[cfg(test)] - /// General constructor. - pub fn new( - balance: U256, - nonce: U256, - storage: HashMap, - code: Bytes, - abi: Bytes, - ) -> Account { - Account { - balance, - nonce, - storage_root: HASH_NULL_RLP, - storage_cache: Self::empty_storage_cache(), - storage_changes: storage, - code_hash: code.crypt_hash(), - code_size: Some(code.len()), - code_cache: Arc::new(code), - code_filth: Filth::Dirty, - abi_hash: abi.crypt_hash(), - abi_size: Some(abi.len()), - abi_cache: Arc::new(abi), - abi_filth: Filth::Dirty, - address_hash: Cell::new(None), - } - } - - fn empty_storage_cache() -> RefCell> { - RefCell::new(LruCache::new(STORAGE_CACHE_ITEMS)) - } - - /// General constructor. - pub fn from_pod(pod: PodAccount) -> Account { - Account { - balance: pod.balance, - nonce: pod.nonce, - storage_root: HASH_NULL_RLP, - storage_cache: Self::empty_storage_cache(), - storage_changes: pod.storage.into_iter().collect(), - code_hash: pod.code.as_ref().map_or(HASH_EMPTY, Hashable::crypt_hash), - code_filth: Filth::Dirty, - code_size: Some(pod.code.as_ref().map_or(0, Vec::len)), - code_cache: Arc::new(pod.code.map_or_else( - || { - warn!("POD account with unknown code is being created! Assuming no code."); - vec![] - }, - |c| c, - )), - abi_hash: pod.abi.as_ref().map_or(HASH_EMPTY, Hashable::crypt_hash), - abi_filth: Filth::Dirty, - abi_size: Some(pod.abi.as_ref().map_or(0, Vec::len)), - abi_cache: Arc::new(pod.abi.map_or_else( - || { - warn!("POD account with unknown ABI is being created! Assuming no abi."); - vec![] - }, - |c| c, - )), - address_hash: Cell::new(None), - } - } - - /// Create a new account. - pub fn new_basic(balance: U256, nonce: U256) -> Account { - Account { - balance, - nonce, - storage_root: HASH_NULL_RLP, - storage_cache: Self::empty_storage_cache(), - storage_changes: HashMap::new(), - code_hash: HASH_EMPTY, - code_cache: Arc::new(vec![]), - code_size: Some(0), - code_filth: Filth::Clean, - abi_hash: HASH_EMPTY, - abi_cache: Arc::new(vec![]), - abi_size: Some(0), - abi_filth: Filth::Clean, - address_hash: Cell::new(None), - } - } - - /// Create a new account from RLP. - pub fn from_rlp(rlp: &[u8]) -> Account { - let basic: BasicAccount = decode(rlp); - basic.into() - } - - /// Create a new contract account. - /// NOTE: make sure you use `init_code` on this before `commit`ing. - pub fn new_contract(balance: U256, nonce: U256) -> Account { - Account { - balance, - nonce, - storage_root: HASH_NULL_RLP, - storage_cache: Self::empty_storage_cache(), - storage_changes: HashMap::new(), - code_hash: HASH_EMPTY, - code_cache: Arc::new(vec![]), - code_size: None, - code_filth: Filth::Clean, - abi_hash: HASH_EMPTY, - abi_cache: Arc::new(vec![]), - abi_size: None, - abi_filth: Filth::Clean, - address_hash: Cell::new(None), - } - } - - /// Set this account's code to the given code. - /// NOTE: Account should have been created with `new_contract()` - pub fn init_code(&mut self, code: Bytes) { - self.code_hash = code.crypt_hash(); - self.code_cache = Arc::new(code); - self.code_size = Some(self.code_cache.len()); - self.code_filth = Filth::Dirty; - } - - /// Set this account's ABI to the given ABI. - pub fn init_abi(&mut self, abi: Bytes) { - self.abi_hash = abi.crypt_hash(); - self.abi_cache = Arc::new(abi); - self.abi_size = Some(self.abi_cache.len()); - self.abi_filth = Filth::Dirty; - } - - /// Reset this account's code to the given code. - pub fn reset_code(&mut self, code: Bytes) { - self.init_code(code); - } - - /// Reset this account's ABI to the given ABI. - pub fn reset_abi(&mut self, abi: Bytes) { - self.init_abi(abi); - } - - /// Set (and cache) the contents of the trie's storage at `key` to `value`. - pub fn set_storage(&mut self, key: H256, value: H256) { - self.storage_changes.insert(key, value); - } - - /// Get (and cache) the contents of the trie's storage at `key`. - /// Takes modifed storage into account. - pub fn storage_at( - &self, - trie_factory: &TrieFactory, - db: &HashDB, - key: &H256, - ) -> trie::Result { - if let Some(value) = self.cached_storage_at(key) { - return Ok(value); - } - - let t = trie_factory.readonly(db, &self.storage_root)?; - - let item: U256 = t.get_with(key, ::rlp::decode)?.unwrap_or_else(U256::zero); - let value: H256 = item.into(); - self.storage_cache.borrow_mut().insert(*key, value); - Ok(value) - } - - /// Get value proof of the trie's storage at `key`. - pub fn get_value_proof( - &self, - trie_factory: &TrieFactory, - db: &HashDB, - key: &H256, - ) -> Option> { - trie_factory - .readonly(db, &self.storage_root) - .ok() - .and_then(|t| t.get_value_proof(key)) - } - - /// Verify value proof of the trie's storage at `key`. - pub fn verify_value_proof(&self, key: &H256, proof: &[Bytes]) -> Option { - trie::triedb::verify_value_proof(key, self.storage_root, proof, ::rlp::decode) - .map(&Into::into as &Fn(U256) -> H256) - } - - /// Get cached storage value if any. Returns `None` if the - /// key is not in the cache. - pub fn cached_storage_at(&self, key: &H256) -> Option { - if let Some(value) = self.storage_changes.get(key) { - return Some(*value); - } - if let Some(value) = self.storage_cache.borrow_mut().get_mut(key) { - return Some(*value); - } - None - } - - /// return the balance associated with this account. - pub fn balance(&self) -> &U256 { - &self.balance - } - - /// return the nonce associated with this account. - pub fn nonce(&self) -> &U256 { - &self.nonce - } - - /// return the code hash associated with this account. - pub fn code_hash(&self) -> H256 { - self.code_hash - } - - /// return the abi hash associated with this account. - pub fn abi_hash(&self) -> H256 { - self.abi_hash - } - - /// return the code hash associated with this account. - pub fn address_hash(&self, address: &Address) -> H256 { - let hash = self.address_hash.get(); - hash.unwrap_or_else(|| { - let hash = address.crypt_hash(); - self.address_hash.set(Some(hash)); - hash - }) - } - - /// returns the account's code. If `None` then the code cache isn't available - - /// get someone who knows to call `note_code`. - pub fn code(&self) -> Option> { - if self.code_hash != HASH_EMPTY && self.code_cache.is_empty() { - return None; - } - Some(Arc::clone(&self.code_cache)) - } - - /// returns the account's abi. If `None` then the abi cache isn't available - - /// get someone who knows to call `abi_code`. - pub fn abi(&self) -> Option> { - if self.abi_hash != HASH_EMPTY && self.abi_cache.is_empty() { - return None; - } - Some(Arc::clone(&self.abi_cache)) - } - - /// returns the account's code size. If `None` then the code cache or code size cache isn't available - - /// get someone who knows to call `note_code`. - pub fn code_size(&self) -> Option { - self.code_size - } - - /// returns the account's ABI size. If `None` then the ABI cache or ABI size cache isn't available - - /// get someone who knows to call `note_abi`. - pub fn abi_size(&self) -> Option { - self.abi_size - } - - #[cfg(test)] - /// Provide a byte array which hashes to the `code_hash`. returns the hash as a result. - pub fn note_code(&mut self, code: Bytes) -> Result<(), H256> { - let h = code.crypt_hash(); - if self.code_hash == h { - self.code_cache = Arc::new(code); - self.code_size = Some(self.code_cache.len()); - Ok(()) - } else { - Err(h) - } - } - - #[cfg(test)] - /// Provide a byte array which hashes to the `abi_hash`. returns the hash as a result. - pub fn note_abi(&mut self, abi: Bytes) -> Result<(), H256> { - let h = abi.crypt_hash(); - if self.abi_hash == h { - self.abi_cache = Arc::new(abi); - self.abi_size = Some(self.abi_cache.len()); - Ok(()) - } else { - Err(h) - } - } - - /// Is `code_cache` valid; such that code is going to return Some? - pub fn is_cached(&self) -> bool { - !self.code_cache.is_empty() || (self.code_cache.is_empty() && self.code_hash == HASH_EMPTY) - } - - /// Is `abi_cache` valid; such that abi is going to return Some? - pub fn is_abi_cached(&self) -> bool { - !self.abi_cache.is_empty() || (self.abi_cache.is_empty() && self.abi_hash == HASH_EMPTY) - } - - /// Provide a database to get `code_hash`. Should not be called if it is a contract without code. - pub fn cache_code(&mut self, db: &HashDB) -> Option> { - // TODO: fill out self.code_cache; - trace!( - "Account::cache_code: ic={}; self.code_hash={:?}, self.code_cache={}", - self.is_cached(), - self.code_hash, - self.code_cache.lower_hex() - ); - - if self.is_cached() { - return Some(Arc::clone(&self.code_cache)); - } - - match db.get(&self.code_hash) { - Some(x) => { - self.code_size = Some(x.len()); - self.code_cache = Arc::new(x.to_vec()); - Some(Arc::clone(&self.code_cache)) - } - _ => { - warn!("Failed get code of {}", self.code_hash); - None - } - } - } - - /// Provide a database to get `abi_hash`. Should not be called if it is a contract without abi. - pub fn cache_abi(&mut self, db: &HashDB) -> Option> { - // TODO: fill out self.abi_cache; - trace!( - "Account::cache_abi: ic={}; self.abi_hash={:?}, self.abi_cache={}", - self.is_abi_cached(), - self.abi_hash, - self.abi_cache.lower_hex() - ); - - if self.is_abi_cached() { - return Some(Arc::clone(&self.abi_cache)); - } - - match db.get(&self.abi_hash) { - Some(x) => { - self.abi_size = Some(x.len()); - self.abi_cache = Arc::new(x.to_vec()); - Some(Arc::clone(&self.abi_cache)) - } - _ => { - warn!("Failed get abi of {}", self.abi_hash); - None - } - } - } - - /// Provide code to cache. For correctness, should be the correct code for the - /// account. - pub fn cache_given_code(&mut self, code: Arc) { - trace!( - "Account::cache_given_code: ic={}; self.code_hash={:?}, self.code_cache={}", - self.is_cached(), - self.code_hash, - self.code_cache.lower_hex() - ); - - self.code_size = Some(code.len()); - self.code_cache = code; - } - - /// Provide ABI to cache. For correctness, should be the correct ABI for the - /// account. - pub fn cache_given_abi(&mut self, abi: Arc) { - trace!( - "Account::cache_given_abi: ic={}; self.abi_hash={:?}, self.abi_cache={}", - self.is_abi_cached(), - self.abi_hash, - self.abi_cache.lower_hex() - ); - - self.abi_size = Some(abi.len()); - self.abi_cache = abi; - } - - /// Provide a database to get `code_size`. Should not be called if it is a contract without code. - pub fn cache_code_size(&mut self, db: &HashDB) -> bool { - // TODO: fill out self.code_cache; - trace!( - "Account::cache_code_size: ic={}; self.code_hash={:?}, self.code_cache={}", - self.is_cached(), - self.code_hash, - self.code_cache.lower_hex() - ); - self.code_size.is_some() - || if self.code_hash != HASH_EMPTY { - match db.get(&self.code_hash) { - Some(x) => { - self.code_size = Some(x.len()); - true - } - _ => { - warn!("Failed get code of {}", self.code_hash); - false - } - } - } else { - false - } - } - - /// Provide a database to get `abi_size`. Should not be called if it is a contract without abi. - pub fn cache_abi_size(&mut self, db: &HashDB) -> bool { - // TODO: fill out self.abi_cache; - trace!( - "Account::cache_abi_size: ic={}; self.abi_hash={:?}, self.abi_cache={}", - self.is_abi_cached(), - self.abi_hash, - self.abi_cache.lower_hex() - ); - self.abi_size.is_some() - || if self.abi_hash != HASH_EMPTY { - match db.get(&self.abi_hash) { - Some(x) => { - self.abi_size = Some(x.len()); - true - } - _ => { - warn!("Failed get abi of {}", self.abi_hash); - false - } - } - } else { - false - } - } - - /// Determine whether there are any un-`commit()`-ed storage-setting operations. - pub fn storage_is_clean(&self) -> bool { - self.storage_changes.is_empty() - } - - /// Check if account has zero nonce, balance, no code and no storage. - /// - /// NOTE: Will panic if `!self.storage_is_clean()` - pub fn is_empty(&self) -> bool { - assert!( - self.storage_is_clean(), - "Account::is_empty() may only legally be called when storage is clean." - ); - self.is_null() && self.storage_root == HASH_NULL_RLP - } - - /// Check if account has zero nonce, balance, no code, no abi. - pub fn is_null(&self) -> bool { - self.balance.is_zero() - && self.nonce.is_zero() - && self.code_hash == HASH_EMPTY - && self.abi_hash == HASH_EMPTY - } - - /// Check if account is basic (Has no code). - pub fn is_basic(&self) -> bool { - self.code_hash == HASH_EMPTY - } - - /// Return the storage root associated with this account or None if it has been altered via the overlay. - pub fn storage_root(&self) -> Option<&H256> { - if self.storage_is_clean() { - Some(&self.storage_root) - } else { - None - } - } - - /// Return the storage overlay. - pub fn storage_changes(&self) -> &HashMap { - &self.storage_changes - } - - /// Return the storage cache - pub fn storage_cache(&self) -> BTreeMap { - let mut result = BTreeMap::new(); - for (k, v) in self.storage_cache.borrow().iter() { - let key = String::from("0x") + &hex::encode(*k); - let value = String::from("0x") + &hex::encode(*v); - result.insert(key.clone(), value.clone()); - } - result - } - - /// Increment the nonce of the account by one. - pub fn inc_nonce(&mut self) { - self.nonce = self.nonce + U256::from(1u8); - } - - /// Increase account balance. - pub fn add_balance(&mut self, x: &U256) { - self.balance = self.balance.saturating_add(*x); - } - - /// Decrease account balance. - pub fn sub_balance(&mut self, x: &U256) { - self.balance = self.balance.saturating_sub(*x); - } - - /// Commit the `storage_changes` to the backing DB and update `storage_root`. - pub fn commit_storage( - &mut self, - trie_factory: &TrieFactory, - db: &mut HashDB, - ) -> trie::Result<()> { - let mut t = trie_factory.get_from_existing(db, &mut self.storage_root)?; - for (k, v) in self.storage_changes.drain() { - // cast key and value to trait type, - // so we can call overloaded `to_bytes` method - if v.is_zero() { - t.remove(&k)? - } else { - t.insert(&k, &encode(&U256::from(&*v)))? - }; - - self.storage_cache.borrow_mut().insert(k, v); - } - Ok(()) - } - - /// Commit any unsaved code. `code_hash` will always return the hash of the `code_cache` after this. - pub fn commit_code(&mut self, db: &mut HashDB) { - match (self.code_filth == Filth::Dirty, self.code_cache.is_empty()) { - (true, true) => { - self.code_size = Some(0); - self.code_filth = Filth::Clean; - } - (true, false) => { - db.emplace(self.code_hash, DBValue::from_slice(&*self.code_cache)); - self.code_size = Some(self.code_cache.len()); - self.code_filth = Filth::Clean; - } - (false, _) => {} - } - } - - /// Commit any unsaved abi. `abi_hash` will always return the hash of the `abi_cache` after this. - pub fn commit_abi(&mut self, db: &mut HashDB) { - match (self.abi_filth == Filth::Dirty, self.abi_cache.is_empty()) { - (true, true) => { - self.abi_size = Some(0); - self.abi_filth = Filth::Clean; - } - (true, false) => { - db.emplace(self.abi_hash, DBValue::from_slice(&*self.abi_cache)); - self.abi_size = Some(self.abi_cache.len()); - self.abi_filth = Filth::Clean; - } - (false, _) => {} - } - } - - /// Export to RLP. - pub fn rlp(&self) -> Bytes { - let mut stream = RlpStream::new_list(5); - stream.append(&self.nonce); - stream.append(&self.balance); - stream.append(&self.storage_root); - stream.append(&self.code_hash); - stream.append(&self.abi_hash); - stream.out() - } - - /// Clone basic account data - pub fn clone_basic(&self) -> Account { - Account { - balance: self.balance, - nonce: self.nonce, - storage_root: self.storage_root, - storage_cache: Self::empty_storage_cache(), - storage_changes: HashMap::new(), - code_hash: self.code_hash, - code_size: self.code_size, - code_cache: Arc::clone(&self.code_cache), - code_filth: self.code_filth, - abi_hash: self.abi_hash, - abi_size: self.abi_size, - abi_cache: Arc::clone(&self.abi_cache), - abi_filth: self.abi_filth, - address_hash: self.address_hash.clone(), - } - } - - /// Clone account data and dirty storage keys - pub fn clone_dirty(&self) -> Account { - let mut account = self.clone_basic(); - account.storage_changes = self.storage_changes.clone(); - account.code_cache = Arc::clone(&self.code_cache); - account.abi_cache = Arc::clone(&self.abi_cache); - account - } - - /// Clone account data, dirty storage keys and cached storage keys. - pub fn clone_all(&self) -> Account { - let mut account = self.clone_dirty(); - account.storage_cache = self.storage_cache.clone(); - account - } - - /// Replace self with the data from other account merging storage cache. - /// Basic account data and all modifications are overwritten - /// with new values. - pub fn overwrite_with(&mut self, other: Account) { - self.balance = other.balance; - self.nonce = other.nonce; - self.storage_root = other.storage_root; - self.code_hash = other.code_hash; - self.code_filth = other.code_filth; - self.code_cache = other.code_cache; - self.code_size = other.code_size; - self.abi_hash = other.abi_hash; - self.abi_filth = other.abi_filth; - self.abi_cache = other.abi_cache; - self.abi_size = other.abi_size; - self.address_hash = other.address_hash; - let mut cache = self.storage_cache.borrow_mut(); - for (k, v) in other.storage_cache.into_inner() { - cache.insert(k, v); //TODO: cloning should not be required here - } - self.storage_changes = other.storage_changes; - } -} - -impl fmt::Debug for Account { - fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { - write!(f, "{:?}", PodAccount::from_account(self)) - } -} - -#[cfg(test)] -mod tests { - use super::*; - use crate::account_db::*; - use crate::cita_db::MemoryDB; - use rlp::{Compressible, RlpType, UntrustedRlp}; - - #[test] - fn account_compress() { - let raw = Account::new_basic(0.into(), 4.into()).rlp(); - let rlp = UntrustedRlp::new(&raw); - let compact_vec = rlp.compress(RlpType::Snapshot).to_vec(); - //assert!(raw.len() > compact_vec.len()); - let again_raw = UntrustedRlp::new(&compact_vec).decompress(RlpType::Snapshot); - assert_eq!(raw, again_raw.to_vec()); - } - - #[test] - fn storage_at() { - let mut db = MemoryDB::new(); - let mut db = AccountDBMut::new(&mut db, &Address::new()); - let rlp = { - let mut a = Account::new_contract(0.into(), 0.into()); - a.set_storage( - H256::from(&U256::from(0x00u64)), - H256::from(&U256::from(0x1234u64)), - ); - a.commit_storage(&Default::default(), &mut db).unwrap(); - a.init_code(vec![]); - a.commit_code(&mut db); - a.init_abi(vec![]); - a.commit_abi(&mut db); - a.rlp() - }; - - let a = Account::from_rlp(&rlp); - - #[cfg(feature = "sha3hash")] - let expected = "71623f5ec821de33ad5aa81f8c82f0916c6f60de0a536f8c466d440c56715bd5"; - #[cfg(feature = "blake2bhash")] - let expected = "01d418c29a2942a1257a3be24134e125d9ef52ca2c0e9174969cd86fb9bf74e9"; - #[cfg(feature = "sm3hash")] - let expected = "293a5287836ae79f19f88d45b5ac5b2c2fd2f60b7c4250ff595cb228582f49c5"; - - assert_eq!(a.storage_root().unwrap().lower_hex(), expected); - - assert_eq!( - a.storage_at( - &Default::default(), - &db.immutable(), - &H256::from(&U256::from(0x00u64)) - ) - .unwrap(), - H256::from(&U256::from(0x1234u64)) - ); - assert_eq!( - a.storage_at( - &Default::default(), - &db.immutable(), - &H256::from(&U256::from(0x01u64)) - ) - .unwrap(), - H256::new() - ); - } - - #[test] - fn value_proof() { - let mut db = MemoryDB::new(); - let mut db = AccountDBMut::new(&mut db, &Address::new()); - let rlp = { - let mut a = Account::new_contract(0.into(), 0.into()); - a.set_storage( - H256::from(&U256::from(0x1234u64)), - H256::from(&U256::from(0x4321u64)), - ); - a.set_storage( - H256::from(&U256::from(0x123456u64)), - H256::from(&U256::from(0x654321u64)), - ); - a.set_storage( - H256::from(&U256::from(0x12345678u64)), - H256::from(&U256::from(0x87654321u64)), - ); - a.set_storage( - H256::from(&U256::from(0x654321u64)), - H256::from(&U256::from(0x123456u64)), - ); - - a.commit_storage(&Default::default(), &mut db).unwrap(); - a.init_code(vec![]); - a.commit_code(&mut db); - a.init_abi(vec![]); - a.commit_abi(&mut db); - a.rlp() - }; - - let a = Account::from_rlp(&rlp); - - { - let value_proof = a - .get_value_proof( - &Default::default(), - &db.immutable(), - &H256::from(&U256::from(0x1234u64)), - ) - .unwrap(); - let val = a - .verify_value_proof(&H256::from(&U256::from(0x1234u64)), &value_proof) - .unwrap(); - - assert_eq!(val, H256::from(&U256::from(0x4321u64))); - } - - { - let value_proof = a - .get_value_proof( - &Default::default(), - &db.immutable(), - &H256::from(&U256::from(0x123456u64)), - ) - .unwrap(); - let val = a - .verify_value_proof(&H256::from(&U256::from(0x123456u64)), &value_proof) - .unwrap(); - - assert_eq!(val, H256::from(&U256::from(0x654321u64))); - } - - { - let value_proof = a - .get_value_proof( - &Default::default(), - &db.immutable(), - &H256::from(&U256::from(0x12345678u64)), - ) - .unwrap(); - let val = a - .verify_value_proof(&H256::from(&U256::from(0x12345678u64)), &value_proof) - .unwrap(); - - assert_eq!(val, H256::from(&U256::from(0x87654321u64))); - } - - { - let value_proof = a - .get_value_proof( - &Default::default(), - &db.immutable(), - &H256::from(&U256::from(0x654321u64)), - ) - .unwrap(); - let val = a - .verify_value_proof(&H256::from(&U256::from(0x654321u64)), &value_proof) - .unwrap(); - - assert_eq!(val, H256::from(&U256::from(0x123456u64))); - } - - // bad case - { - assert_eq!( - a.get_value_proof( - &Default::default(), - &db.immutable(), - &H256::from(&U256::from(0x65432100u64)), - ), - None - ); - let value_proof = a - .get_value_proof( - &Default::default(), - &db.immutable(), - &H256::from(&U256::from(0x654321u64)), - ) - .unwrap(); - assert_eq!( - a.verify_value_proof(&H256::from(&U256::from(0x65u64)), &value_proof), - None - ) - } - // bad case - { - let value_proof = a - .get_value_proof( - &Default::default(), - &db.immutable(), - &H256::from(&U256::from(0x65u64)), - ) - .unwrap(); - assert_eq!( - a.verify_value_proof(&H256::from(&U256::from(0x65u64)), &value_proof), - None - ) - } - } - - #[test] - fn note_code() { - let mut db = MemoryDB::new(); - let mut db = AccountDBMut::new(&mut db, &Address::new()); - - let rlp = { - let mut a = Account::new_contract(0.into(), 0.into()); - a.init_code(vec![0x55, 0x44, 0xffu8]); - a.commit_code(&mut db); - a.rlp() - }; - - let mut a = Account::from_rlp(&rlp); - assert!(a.cache_code(&db.immutable()).is_some()); - - let mut a = Account::from_rlp(&rlp); - assert_eq!(a.note_code(vec![0x55, 0x44, 0xffu8]), Ok(())); - } - - #[test] - fn note_abi() { - let mut db = MemoryDB::new(); - let mut db = AccountDBMut::new(&mut db, &Address::new()); - - let rlp = { - let mut a = Account::new_contract(0.into(), 0.into()); - a.init_abi(vec![0x55, 0x44, 0xffu8]); - a.commit_abi(&mut db); - a.rlp() - }; - - let mut a = Account::from_rlp(&rlp); - assert!(a.cache_abi(&db.immutable()).is_some()); - - let mut a = Account::from_rlp(&rlp); - assert_eq!(a.note_abi(vec![0x55, 0x44, 0xffu8]), Ok(())); - } - - #[test] - fn commit_storage() { - let mut a = Account::new_contract(0.into(), 0.into()); - let mut db = MemoryDB::new(); - let mut db = AccountDBMut::new(&mut db, &Address::new()); - a.set_storage(0.into(), 0x1234.into()); - assert_eq!(a.storage_root(), None); - - #[cfg(feature = "sha3hash")] - let expected = "71623f5ec821de33ad5aa81f8c82f0916c6f60de0a536f8c466d440c56715bd5"; - #[cfg(feature = "blake2bhash")] - let expected = "01d418c29a2942a1257a3be24134e125d9ef52ca2c0e9174969cd86fb9bf74e9"; - #[cfg(feature = "sm3hash")] - let expected = "293a5287836ae79f19f88d45b5ac5b2c2fd2f60b7c4250ff595cb228582f49c5"; - - a.commit_storage(&Default::default(), &mut db).unwrap(); - assert_eq!(a.storage_root().unwrap().lower_hex(), expected); - } - - #[test] - fn commit_remove_commit_storage() { - let mut a = Account::new_contract(0.into(), 0.into()); - let mut db = MemoryDB::new(); - let mut db = AccountDBMut::new(&mut db, &Address::new()); - a.set_storage(0.into(), 0x1234.into()); - a.commit_storage(&Default::default(), &mut db).unwrap(); - a.set_storage(1.into(), 0x1234.into()); - a.commit_storage(&Default::default(), &mut db).unwrap(); - a.set_storage(1.into(), 0.into()); - - #[cfg(feature = "sha3hash")] - let expected = "71623f5ec821de33ad5aa81f8c82f0916c6f60de0a536f8c466d440c56715bd5"; - #[cfg(feature = "blake2bhash")] - let expected = "01d418c29a2942a1257a3be24134e125d9ef52ca2c0e9174969cd86fb9bf74e9"; - #[cfg(feature = "sm3hash")] - let expected = "293a5287836ae79f19f88d45b5ac5b2c2fd2f60b7c4250ff595cb228582f49c5"; - - a.commit_storage(&Default::default(), &mut db).unwrap(); - assert_eq!(a.storage_root().unwrap().lower_hex(), expected); - } - - #[test] - fn commit_code() { - let mut a = Account::new_contract(0.into(), 0.into()); - let mut db = MemoryDB::new(); - let mut db = AccountDBMut::new(&mut db, &Address::new()); - a.init_code(vec![0x55, 0x44, 0xffu8]); - assert_eq!(a.code_filth, Filth::Dirty); - assert_eq!(a.code_size(), Some(3)); - a.commit_code(&mut db); - - #[cfg(feature = "sha3hash")] - let expected = "af231e631776a517ca23125370d542873eca1fb4d613ed9b5d5335a46ae5b7eb"; - #[cfg(feature = "blake2bhash")] - let expected = "d9c3b9ce5f61497874544e3c8a111295256705ed0c32730db01ed36a1cef9845"; - #[cfg(feature = "sm3hash")] - let expected = "a812a243d71509028ca423a5f1d74514468898389d18c4342e1f2d8683b21d73"; - - assert_eq!(a.code_hash().lower_hex(), expected); - } - - #[test] - fn commit_abi() { - let mut a = Account::new_contract(0.into(), 0.into()); - let mut db = MemoryDB::new(); - let mut db = AccountDBMut::new(&mut db, &Address::new()); - a.init_abi(vec![0x55, 0x44, 0xffu8]); - assert_eq!(a.abi_filth, Filth::Dirty); - assert_eq!(a.abi_size(), Some(3)); - a.commit_abi(&mut db); - - #[cfg(feature = "sha3hash")] - let expected = "af231e631776a517ca23125370d542873eca1fb4d613ed9b5d5335a46ae5b7eb"; - #[cfg(feature = "blake2bhash")] - let expected = "d9c3b9ce5f61497874544e3c8a111295256705ed0c32730db01ed36a1cef9845"; - #[cfg(feature = "sm3hash")] - let expected = "a812a243d71509028ca423a5f1d74514468898389d18c4342e1f2d8683b21d73"; - - assert_eq!(a.abi_hash().lower_hex(), expected); - } - - #[test] - fn reset_code() { - let mut a = Account::new_contract(0.into(), 0.into()); - let mut db = MemoryDB::new(); - let mut db = AccountDBMut::new(&mut db, &Address::new()); - a.init_code(vec![0x55, 0x44, 0xffu8]); - assert_eq!(a.code_filth, Filth::Dirty); - a.commit_code(&mut db); - assert_eq!(a.code_filth, Filth::Clean); - - #[cfg(feature = "sha3hash")] - let expected = "af231e631776a517ca23125370d542873eca1fb4d613ed9b5d5335a46ae5b7eb"; - #[cfg(feature = "blake2bhash")] - let expected = "d9c3b9ce5f61497874544e3c8a111295256705ed0c32730db01ed36a1cef9845"; - #[cfg(feature = "sm3hash")] - let expected = "a812a243d71509028ca423a5f1d74514468898389d18c4342e1f2d8683b21d73"; - - assert_eq!(a.code_hash().lower_hex(), expected); - - a.reset_code(vec![0x55]); - assert_eq!(a.code_filth, Filth::Dirty); - a.commit_code(&mut db); - - #[cfg(feature = "sha3hash")] - let expected = "37bf2238b11b68cdc8382cece82651b59d3c3988873b6e0f33d79694aa45f1be"; - #[cfg(feature = "blake2bhash")] - let expected = "32df85a4ebfe3725d6e19352057c4755aa0f2a4c01ba0c94c18dd5813ce43a01"; - #[cfg(feature = "sm3hash")] - let expected = "657a94d4f15695633005ec909ac5655111599bcd8278b75d183b86feeb778bff"; - - assert_eq!(a.code_hash().lower_hex(), expected); - } - - #[test] - fn reset_abi() { - let mut a = Account::new_contract(0.into(), 0.into()); - let mut db = MemoryDB::new(); - let mut db = AccountDBMut::new(&mut db, &Address::new()); - a.init_abi(vec![0x55, 0x44, 0xffu8]); - assert_eq!(a.abi_filth, Filth::Dirty); - a.commit_abi(&mut db); - assert_eq!(a.abi_filth, Filth::Clean); - - #[cfg(feature = "sha3hash")] - let expected = "af231e631776a517ca23125370d542873eca1fb4d613ed9b5d5335a46ae5b7eb"; - #[cfg(feature = "blake2bhash")] - let expected = "d9c3b9ce5f61497874544e3c8a111295256705ed0c32730db01ed36a1cef9845"; - #[cfg(feature = "sm3hash")] - let expected = "a812a243d71509028ca423a5f1d74514468898389d18c4342e1f2d8683b21d73"; - - assert_eq!(a.abi_hash().lower_hex(), expected); - - a.reset_abi(vec![0x55]); - assert_eq!(a.abi_filth, Filth::Dirty); - a.commit_abi(&mut db); - - #[cfg(feature = "sha3hash")] - let expected = "37bf2238b11b68cdc8382cece82651b59d3c3988873b6e0f33d79694aa45f1be"; - #[cfg(feature = "blake2bhash")] - let expected = "32df85a4ebfe3725d6e19352057c4755aa0f2a4c01ba0c94c18dd5813ce43a01"; - #[cfg(feature = "sm3hash")] - let expected = "657a94d4f15695633005ec909ac5655111599bcd8278b75d183b86feeb778bff"; - - assert_eq!(a.abi_hash().lower_hex(), expected); - } - - #[test] - fn rlpio() { - let a = Account::new( - U256::from(0u8), - U256::from(0u8), - HashMap::new(), - Bytes::new(), - Bytes::new(), - ); - let b = Account::from_rlp(&a.rlp()); - assert_eq!(a.nonce(), b.nonce()); - assert_eq!(a.code_hash(), b.code_hash()); - assert_eq!(a.abi_hash(), b.abi_hash()); - assert_eq!(a.storage_root(), b.storage_root()); - } - - #[test] - fn new_account() { - let a = Account::new( - U256::from(0u8), - U256::from(0u8), - HashMap::new(), - Bytes::new(), - Bytes::new(), - ); - - #[cfg(feature = "sha3hash")] - let expected = "f8658080a056e81f171bcc55a6ff8345e692c0f86e5b48e01b996cadc001622f\ - b5e363b421a0c5d2460186f7233c927e7db2dcc703c0e500b653ca82273b7bfa\ - d8045d85a470a0c5d2460186f7233c927e7db2dcc703c0e500b653ca82273b7b\ - fad8045d85a470"; - #[cfg(feature = "blake2bhash")] - let expected = "f8658080a0c14af59107ef14003e4697a40ea912d865eb1463086a4649977c13\ - ea69b0d9afa0d67f729f8d19ed2e92f817cf5c31c7812dd39ed35b0b1aae41c7\ - 665f46c36b9fa0d67f729f8d19ed2e92f817cf5c31c7812dd39ed35b0b1aae41\ - c7665f46c36b9f"; - #[cfg(feature = "sm3hash")] - let expected = "f8658080a0995b949869f80fa1465a9d8b6fa759ec65c3020d59c2624662bdff\ - 059bdf19b3a01ab21d8355cfa17f8e61194831e81a8f22bec8c728fefb747ed0\ - 35eb5082aa2ba01ab21d8355cfa17f8e61194831e81a8f22bec8c728fefb747e\ - d035eb5082aa2b"; - - assert_eq!(a.rlp().to_hex(), expected); - - assert_eq!(a.nonce(), &U256::from(0u8)); - assert_eq!(a.code_hash(), HASH_EMPTY); - assert_eq!(a.abi_hash(), HASH_EMPTY); - assert_eq!(a.storage_root().unwrap(), &HASH_NULL_RLP); - } - - #[test] - fn create_account() { - let a = Account::new( - U256::from(0u8), - U256::from(0u8), - HashMap::new(), - Bytes::new(), - Bytes::new(), - ); - - #[cfg(feature = "sha3hash")] - let expected = "f8658080a056e81f171bcc55a6ff8345e692c0f86e5b48e01b996cadc001622f\ - b5e363b421a0c5d2460186f7233c927e7db2dcc703c0e500b653ca82273b7bfa\ - d8045d85a470a0c5d2460186f7233c927e7db2dcc703c0e500b653ca82273b7b\ - fad8045d85a470"; - #[cfg(feature = "blake2bhash")] - let expected = "f8658080a0c14af59107ef14003e4697a40ea912d865eb1463086a4649977c13\ - ea69b0d9afa0d67f729f8d19ed2e92f817cf5c31c7812dd39ed35b0b1aae41c7\ - 665f46c36b9fa0d67f729f8d19ed2e92f817cf5c31c7812dd39ed35b0b1aae41\ - c7665f46c36b9f"; - #[cfg(feature = "sm3hash")] - let expected = "f8658080a0995b949869f80fa1465a9d8b6fa759ec65c3020d59c2624662bdff\ - 059bdf19b3a01ab21d8355cfa17f8e61194831e81a8f22bec8c728fefb747ed0\ - 35eb5082aa2ba01ab21d8355cfa17f8e61194831e81a8f22bec8c728fefb747e\ - d035eb5082aa2b"; - - assert_eq!(a.rlp().to_hex(), expected); - } - -} diff --git a/cita-executor/core/src/state/backend.rs b/cita-executor/core/src/state/backend.rs deleted file mode 100644 index 8205d9c39..000000000 --- a/cita-executor/core/src/state/backend.rs +++ /dev/null @@ -1,63 +0,0 @@ -// Copyright 2015-2017 Parity Technologies (UK) Ltd. -// This file is part of Parity. - -// This software is free software: you can redistribute it and/or modify -// it under the terms of the GNU General Public License as published by -// the Free Software Foundation, either version 3 of the License, or -// (at your option) any later version. - -// This software 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 General Public License for more details. - -// You should have received a copy of the GNU General Public License -// along with Parity. If not, see . - -use std::sync::Arc; - -use crate::cita_db::HashDB; -use crate::state::Account; -use cita_types::{Address, H256}; - -/// State backend. See module docs for more details. -pub trait Backend: Send { - /// Treat the backend as a read-only hashdb. - fn as_hashdb(&self) -> &HashDB; - - /// Treat the backend as a writeable hashdb. - fn as_hashdb_mut(&mut self) -> &mut HashDB; - - /// Add an account entry to the cache. - fn add_to_account_cache(&mut self, addr: Address, data: Option, modified: bool); - - /// Sync all account entries from backend's local cache to global cache. - fn sync_account_cache(&mut self); - - /// Add a global code cache entry. This doesn't need to worry about canonicality because - /// it simply maps hashes to raw code and will always be correct in the absence of - /// hash collisions. - fn cache_code(&self, hash: H256, code: Arc>); - - /// Get basic copy of the cached account. Not required to include storage. - /// Returns 'None' if cache is disabled or if the account is not cached. - fn get_cached_account(&self, addr: &Address) -> Option; - - /// Get value from a cached account. - /// `None` is passed to the closure if the account entry cached - /// is known not to exist. - /// `None` is returned if the entry is not cached. - fn get_cached(&self, a: &Address, f: F) -> Option - where - F: FnOnce(Option<&mut Account>) -> U; - - /// Get cached code based on hash. - fn get_cached_code(&self, hash: &H256) -> Option>>; - - /// Note that an account with the given address is non-null. - fn note_non_null_account(&self, address: &Address); - - /// Check whether an account is known to be empty. Returns true if known to be - /// empty, false otherwise. - fn is_known_null(&self, address: &Address) -> bool; -} diff --git a/cita-executor/core/src/state/mod.rs b/cita-executor/core/src/state/mod.rs deleted file mode 100644 index 424e27e94..000000000 --- a/cita-executor/core/src/state/mod.rs +++ /dev/null @@ -1,1612 +0,0 @@ -// Copyright 2015-2017 Parity Technologies (UK) Ltd. -// This file is part of Parity. - -// This software is free software: you can redistribute it and/or modify -// it under the terms of the GNU General Public License as published by -// the Free Software Foundation, either version 3 of the License, or -// (at your option) any later version. - -// This software 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 General Public License for more details. - -// You should have received a copy of the GNU General Public License -// along with Parity. If not, see . - -//! A mutable state representation suitable to execute transactions. -//! Generic over a `Backend`. Deals with `Account`s. -//! Unconfirmed sub-states are managed with `checkpoint`s which may be canonicalized -//! or rolled back. - -use crate::cita_db::{trie, HashDB, Trie, TrieError}; -use crate::engines::Engine; -use crate::error::{Error, ExecutionError}; -use crate::executive::{Executive, TransactOptions}; -use crate::factory::Factories; -use crate::libexecutor::economical_model::EconomicalModel; -use crate::libexecutor::sys_config::BlockSysConfig; -use crate::receipt::{Receipt, ReceiptError}; -use crate::trace::FlatTrace; -use crate::types::transaction::SignedTransaction; -use cita_types::{Address, H256, U256}; -use evm::env_info::EnvInfo; -use evm::Error as EvmError; -use evm::Schedule; -use hashable::HASH_EMPTY; -use rlp::{self, Encodable}; -use std::cell::{Ref, RefCell, RefMut}; -use std::cmp; -use std::collections::hash_map::Entry; -use std::collections::{HashMap, HashSet}; -use std::fmt; -use std::sync::Arc; -use util::*; - -pub mod account; -pub mod backend; - -pub use self::account::Account; -use self::backend::*; -pub use crate::substate::Substate; - -/// Used to return information about an `State::apply` operation. -pub struct ApplyOutcome { - /// The receipt for the applied transaction. - pub receipt: Receipt, - /// The trace for the applied transaction, if None if tracing is disabled. - pub trace: Vec, -} - -/// Result type for the execution ("application") of a transaction. -pub type ApplyResult = Result; - -#[derive(Eq, PartialEq, Clone, Copy, Debug)] -/// Account modification state. Used to check if the account was -/// Modified in between commits and overall. -enum AccountState { - /// Account was loaded from disk and never modified in this state object. - CleanFresh, - /// Account was loaded from the global cache and never modified. - CleanCached, - /// Account has been modified and is not committed to the trie yet. - /// This is set if any of the account data is changed, including - /// storage, code and ABI. - Dirty, - /// Account was modified and committed to the trie. - Committed, -} - -#[derive(Debug)] -/// In-memory copy of the account data. Holds the optional account -/// and the modification status. -/// Account entry can contain existing (`Some`) or non-existing -/// account (`None`) -pub struct AccountEntry { - /// Account entry. `None` if account known to be non-existant. - account: Option, - /// Unmodified account balance. - old_balance: Option, - /// Entry state. - state: AccountState, -} - -// Account cache item. Contains account data and -// modification state -impl AccountEntry { - pub fn is_dirty(&self) -> bool { - self.state == AccountState::Dirty - } - - pub fn is_commited(&self) -> bool { - self.state == AccountState::Committed - } - - fn exists_and_is_null(&self) -> bool { - self.account.as_ref().map_or(false, Account::is_null) - } - - /// Clone dirty data into new `AccountEntry`. This includes - /// basic account data and modified storage keys. - fn clone_dirty(&self) -> AccountEntry { - AccountEntry { - old_balance: self.old_balance, - account: self.account.as_ref().map(Account::clone_dirty), - state: self.state, - } - } - - // Create a new account entry and mark it as dirty. - fn new_dirty(account: Option) -> AccountEntry { - AccountEntry { - old_balance: account.as_ref().map(|a| *a.balance()), - account, - state: AccountState::Dirty, - } - } - - // Create a new account entry and mark it as clean. - fn new_clean(account: Option) -> AccountEntry { - AccountEntry { - old_balance: account.as_ref().map(|a| *a.balance()), - account, - state: AccountState::CleanFresh, - } - } - - // Create a new account entry and mark it as clean and cached. - fn new_clean_cached(account: Option) -> AccountEntry { - AccountEntry { - old_balance: account.as_ref().map(|a| *a.balance()), - account, - state: AccountState::CleanCached, - } - } - - // Replace data with another entry but preserve storage cache. - fn overwrite_with(&mut self, other: AccountEntry) { - self.state = other.state; - match other.account { - Some(acc) => { - if let Some(ref mut ours) = self.account { - ours.overwrite_with(acc); - } - } - None => self.account = None, - } - } - - pub fn account(&self) -> Option<&Account> { - self.account.as_ref() - } -} - -#[derive(Debug, Clone, RlpEncodable, RlpDecodable)] -pub struct StateProof { - address: Address, - account_proof: Vec, - key: H256, - value_proof: Vec, -} - -impl StateProof { - pub fn from_bytes(bytes: &[u8]) -> Self { - rlp::decode(bytes) - } - - pub fn verify(&self, state_root: H256) -> Option { - trie::triedb::verify_value_proof( - &self.address, - state_root, - &self.account_proof, - Account::from_rlp, - ) - .and_then(|a| a.verify_value_proof(&self.key, &self.value_proof)) - } - - /// Get the address field of the StateProof. - pub fn address(&self) -> &Address { - &self.address - } - - /// Get the key field of the StateProof. - pub fn key(&self) -> &H256 { - &self.key - } - - #[cfg(test)] - pub fn set_address(&mut self, new_address: Address) { - self.address = new_address; - } -} - -/// Representation of the entire state of all accounts in the system. -/// -/// `State` can work together with `StateDB` to share account cache. -/// -/// Local cache contains changes made locally and changes accumulated -/// locally from previous commits. Global cache reflects the database -/// state and never contains any changes. -/// -/// Cache items contains account data, or the flag that account does not exist -/// and modification state (see `AccountState`) -/// -/// Account data can be in the following cache states: -/// * In global but not local - something that was queried from the database, -/// but never modified -/// * In local but not global - something that was just added (e.g. new account) -/// * In both with the same value - something that was changed to a new value, -/// but changed back to a previous block in the same block (same State instance) -/// * In both with different values - something that was overwritten with a -/// new value. -/// -/// All read-only state queries check local cache/modifications first, -/// then global state cache. If data is not found in any of the caches -/// it is loaded from the DB to the local cache. -/// -/// **** IMPORTANT ************************************************************* -/// All the modifications to the account data must set the `Dirty` state in the -/// `AccountEntry`. This is done in `require` and `require_or_from`. So just -/// use that. -/// **************************************************************************** -/// -/// Upon destruction all the local cache data propagated into the global cache. -/// Propagated items might be rejected if current state is non-canonical. -/// -/// State checkpointing. -/// -/// A new checkpoint can be created with `checkpoint()`. checkpoints can be -/// created in a hierarchy. -/// When a checkpoint is active all changes are applied directly into -/// `cache` and the original value is copied into an active checkpoint. -/// Reverting a checkpoint with `revert_to_checkpoint` involves copying -/// original values from the latest checkpoint back into `cache`. The code -/// takes care not to overwrite cached storage while doing that. -/// checkpoint can be discarded with `discard_checkpoint`. All of the orignal -/// backed-up values are moved into a parent checkpoint (if any). -/// -pub struct State { - db: B, - root: H256, - cache: RefCell>, - // The original account is preserved in - checkpoints: RefCell>>>, - account_start_nonce: U256, - factories: Factories, - pub super_admin_account: Option
, -} - -#[derive(Copy, Clone)] -enum RequireCache { - None, - CodeSize, - Code, - AbiSize, - Abi, -} - -const SEC_TRIE_DB_UNWRAP_STR: &str = - "A state can only be created with valid root.\ - Creating a SecTrieDB with a valid root will not fail.\ - Therefore creating a SecTrieDB with this state's root will not fail."; - -impl State { - /// Creates new state with empty state root - pub fn new(mut db: B, account_start_nonce: U256, factories: Factories) -> State { - let mut root = H256::new(); - { - // init trie and reset root to null - let _ = factories.trie.create(db.as_hashdb_mut(), &mut root); - } - - State { - db, - root, - cache: RefCell::new(HashMap::new()), - checkpoints: RefCell::new(Vec::new()), - account_start_nonce, - factories, - super_admin_account: None, - } - } - - pub fn cache(&self) -> Ref> { - self.cache.borrow() - } - - /// Creates new state with existing state root - pub fn from_existing( - db: B, - root: H256, - account_start_nonce: U256, - factories: Factories, - ) -> Result, TrieError> { - if !db.as_hashdb().contains(&root) { - return Err(TrieError::InvalidStateRoot(root)); - } - - let state = State { - db, - root, - cache: RefCell::new(HashMap::new()), - checkpoints: RefCell::new(Vec::new()), - account_start_nonce, - factories, - super_admin_account: None, - }; - - Ok(state) - } - - /// Create a recoverable checkpoint of this state. - pub fn checkpoint(&mut self) { - self.checkpoints.get_mut().push(HashMap::new()); - } - - /// Merge last checkpoint with previous. - pub fn discard_checkpoint(&mut self) { - // merge with previous checkpoint - let last = self.checkpoints.get_mut().pop(); - if let Some(mut checkpoint) = last { - if let Some(ref mut prev) = self.checkpoints.get_mut().last_mut() { - if prev.is_empty() { - **prev = checkpoint; - } else { - for (k, v) in checkpoint.drain() { - prev.entry(k).or_insert(v); - } - } - } - } - } - - /// Revert to the last checkpoint and discard it. - pub fn revert_to_checkpoint(&mut self) { - if let Some(mut checkpoint) = self.checkpoints.get_mut().pop() { - for (k, v) in checkpoint.drain() { - match v { - Some(v) => { - match self.cache.get_mut().entry(k) { - Entry::Occupied(mut e) => { - // Merge checkpointed changes back into the main account - // storage preserving the cache. - e.get_mut().overwrite_with(v); - } - Entry::Vacant(e) => { - e.insert(v); - } - } - } - None => { - if let Entry::Occupied(e) = self.cache.get_mut().entry(k) { - if e.get().is_dirty() { - e.remove(); - } - } - } - } - } - } - } - - fn insert_cache(&self, address: &Address, account: AccountEntry) { - // Dirty account which is not in the cache means this is a new account. - // It goes directly into the checkpoint as there's nothing to rever to. - // - // In all other cases account is read as clean first, and after that made - // dirty in and added to the checkpoint with `note_cache`. - let is_dirty = account.is_dirty(); - let old_value = self.cache.borrow_mut().insert(*address, account); - if is_dirty { - if let Some(ref mut checkpoint) = self.checkpoints.borrow_mut().last_mut() { - checkpoint.entry(*address).or_insert(old_value); - } - } - } - - fn note_cache(&self, address: &Address) { - if let Some(ref mut checkpoint) = self.checkpoints.borrow_mut().last_mut() { - checkpoint.entry(*address).or_insert_with(|| { - self.cache - .borrow() - .get(address) - .map(AccountEntry::clone_dirty) - }); - } - } - - /// Destroy the current object and return root and database. - pub fn drop(mut self) -> (H256, B) { - self.propagate_to_global_cache(); - (self.root, self.db) - } - - pub fn db(self) -> B { - self.db - } - - /// Return reference to root - pub fn root(&self) -> &H256 { - &self.root - } - - /// Create a new contract at address `contract`. If there is already an account at the address - /// it will have its code reset, ready for `init_code()`. - pub fn new_contract(&mut self, contract: &Address, balance: U256, nonce_offset: U256) { - self.insert_cache( - contract, - AccountEntry::new_dirty(Some(Account::new_contract( - balance, - self.account_start_nonce + nonce_offset, - ))), - ); - } - - /// Remove an existing account. - pub fn kill_account(&mut self, account: &Address) { - self.insert_cache(account, AccountEntry::new_dirty(None)); - } - - /// Determine whether an account exists. - pub fn exists(&self, a: &Address) -> trie::Result { - // Bloom filter does not contain empty accounts, so it is important here to - // check if account exists in the database directly before EIP-161 is in effect. - self.ensure_cached(a, RequireCache::None, false, |a| a.is_some()) - } - - /// Determine whether an account exists and if not empty. - pub fn exists_and_not_null(&self, a: &Address) -> trie::Result { - self.ensure_cached(a, RequireCache::None, false, |a| { - a.map_or(false, |a| !a.is_null()) - }) - } - - /// Determine whether an account exists and has code or non-zero nonce. - pub fn exists_and_has_code_or_nonce(&self, a: &Address) -> trie::Result { - self.ensure_cached(a, RequireCache::CodeSize, false, |a| { - a.map_or(false, |a| { - a.code_hash() != HASH_EMPTY || *a.nonce() != self.account_start_nonce - }) - }) - } - - /// Get the balance of account `a`. - pub fn balance(&self, a: &Address) -> trie::Result { - self.ensure_cached(a, RequireCache::None, true, |a| { - a.as_ref() - .map_or(U256::zero(), |account| *account.balance()) - }) - } - - /// Get account of `a` - pub fn account(&self, a: &Address) -> trie::Result> { - self.ensure_cached(a, RequireCache::None, false, |a| { - a.as_ref().map(|account| account.clone_all()) - }) - } - - /// Get the nonce of account `a`. - pub fn nonce(&self, a: &Address) -> trie::Result { - self.ensure_cached(a, RequireCache::None, true, |a| { - a.as_ref() - .map_or(self.account_start_nonce, |account| *account.nonce()) - }) - } - - /// Get the storage root of account `a`. - pub fn storage_root(&self, a: &Address) -> trie::Result> { - self.ensure_cached(a, RequireCache::None, true, |a| { - a.as_ref() - .and_then(|account| account.storage_root().cloned()) - }) - } - - /// Mutate storage of account `address` so that it is `value` for `key`. - pub fn storage_at(&self, address: &Address, key: &H256) -> trie::Result { - // Storage key search and update works like this: - // 1. If there's an entry for the account in the local cache check for the key and return it if found. - // 2. If there's an entry for the account in the global cache check for the key or load it into that account. - // 3. If account is missing in the global cache load it into the local cache and cache the key there. - - { - // check local cache first without updating - let local_cache = self.cache.borrow_mut(); - let mut local_account = None; - if let Some(maybe_acc) = local_cache.get(address) { - match maybe_acc.account { - Some(ref account) => { - if let Some(value) = account.cached_storage_at(key) { - return Ok(value); - } else { - local_account = Some(maybe_acc); - } - } - _ => return Ok(H256::new()), - } - } - - // check the global cache and and cache storage key there if found, - let trie_res = self.db.get_cached(address, |acc| match acc { - None => Ok(H256::new()), - Some(a) => { - let account_db = self - .factories - .accountdb - .readonly(self.db.as_hashdb(), a.address_hash(address)); - a.storage_at(&self.factories.trie, account_db.as_hashdb(), key) - } - }); - - if let Some(res) = trie_res { - return res; - } - - // otherwise cache the account localy and cache storage key there. - if let Some(ref mut acc) = local_account { - if let Some(ref account) = acc.account { - let account_db = self - .factories - .accountdb - .readonly(self.db.as_hashdb(), account.address_hash(address)); - return account.storage_at(&self.factories.trie, account_db.as_hashdb(), key); - } else { - return Ok(H256::new()); - } - } - } - - // check if the account could exist before any requests to trie - if self.db.is_known_null(address) { - return Ok(H256::zero()); - } - - // account is not found in the global cache, get from the DB and insert into local - let db = self - .factories - .trie - .readonly(self.db.as_hashdb(), &self.root) - .expect(SEC_TRIE_DB_UNWRAP_STR); - let maybe_acc = db.get_with(address, Account::from_rlp)?; - let r = maybe_acc.as_ref().map_or(Ok(H256::new()), |a| { - let account_db = self - .factories - .accountdb - .readonly(self.db.as_hashdb(), a.address_hash(address)); - a.storage_at(&self.factories.trie, account_db.as_hashdb(), key) - }); - self.insert_cache(address, AccountEntry::new_clean(maybe_acc)); - r - } - - /// Get `value` proof for `key` of account `address`. - pub fn get_state_proof(&self, address: &Address, key: &H256) -> Option> { - // check if the account could exist before any requests to trie - if self.db.is_known_null(address) { - return None; - } - - // get proof from the DB - self.factories - .trie - .readonly(self.db.as_hashdb(), &self.root) - .ok() - .and_then(|db| { - db.get_value_proof(address).and_then(|account_proof| { - db.get_with(address, Account::from_rlp) - .ok() - .and_then(|maybe_acc| { - maybe_acc.as_ref().and_then(|a| { - let account_db = self - .factories - .accountdb - .readonly(self.db.as_hashdb(), a.address_hash(address)); - a.get_value_proof(&self.factories.trie, account_db.as_hashdb(), key) - .map(|value_proof| { - StateProof { - address: *address, - account_proof, - key: *key, - value_proof, - } - .rlp_bytes() - .into_vec() - }) - }) - }) - }) - }) - } - - /// Get accounts' code. - pub fn code(&self, a: &Address) -> trie::Result>> { - self.ensure_cached(a, RequireCache::Code, true, |a| { - a.as_ref().and_then(|a| a.code().clone()) - }) - } - - /// Get an account's code hash. - pub fn code_hash(&self, a: &Address) -> trie::Result { - self.ensure_cached(a, RequireCache::None, true, |a| { - a.as_ref().map_or(HASH_EMPTY, |a| a.code_hash()) - }) - } - - /// Get accounts' code size. - pub fn code_size(&self, a: &Address) -> trie::Result> { - self.ensure_cached(a, RequireCache::CodeSize, true, |a| { - a.as_ref().and_then(|a| a.code_size()) - }) - } - - /// Get accounts' ABI. - pub fn abi(&self, a: &Address) -> trie::Result>> { - self.ensure_cached(a, RequireCache::Abi, true, |a| { - a.as_ref().and_then(|a| a.abi().clone()) - }) - } - - /// Get an account's ABI hash. - pub fn abi_hash(&self, a: &Address) -> trie::Result { - self.ensure_cached(a, RequireCache::None, true, |a| { - a.as_ref().map_or(HASH_EMPTY, |a| a.abi_hash()) - }) - } - - /// Get accounts' ABI size. - pub fn abi_size(&self, a: &Address) -> trie::Result> { - self.ensure_cached(a, RequireCache::AbiSize, true, |a| { - a.as_ref().and_then(|a| a.abi_size()) - }) - } - - /// Add `incr` to the balance of account `a`. - pub fn add_balance(&mut self, a: &Address, incr: &U256) -> trie::Result<()> { - trace!(target: "state", "add_balance({}, {}): {}", a, incr, self.balance(a)?); - let is_value_transfer = !incr.is_zero(); - if is_value_transfer { - self.require(a, false, false)?.add_balance(incr); - } else if self.exists(a)? { - self.touch(a)?; - } - Ok(()) - } - - /// Subtract `decr` from the balance of account `a`. - pub fn sub_balance(&mut self, a: &Address, decr: &U256) -> trie::Result<()> { - trace!(target: "state", "sub_balance({}, {}): {}", a, decr, self.balance(a)?); - if !decr.is_zero() || !self.exists(a)? { - self.require(a, false, false)?.sub_balance(decr); - } - - Ok(()) - } - - /// Subtracts `by` from the balance of `from` and adds it to that of `to`. - pub fn transfer_balance( - &mut self, - from: &Address, - to: &Address, - by: &U256, - ) -> trie::Result<()> { - self.sub_balance(from, by)?; - self.add_balance(to, by)?; - Ok(()) - } - - /// Increment the nonce of account `a` by 1. - pub fn inc_nonce(&mut self, a: &Address) -> trie::Result<()> { - self.require(a, false, false).map(|mut x| x.inc_nonce()) - } - - /// Mutate storage of account `a` so that it is `value` for `key`. - pub fn set_storage(&mut self, a: &Address, key: H256, value: H256) -> trie::Result<()> { - if self.storage_at(a, &key)? != value { - self.require(a, false, false)?.set_storage(key, value) - } - - Ok(()) - } - - /// Initialise the code of account `a` so that it is `code`. - /// NOTE: Account should have been created with `new_contract`. - pub fn init_code(&mut self, a: &Address, code: Bytes) -> trie::Result<()> { - self.require_or_from( - a, - true, - false, - || Account::new_contract(0.into(), self.account_start_nonce), - |_| {}, - )? - .init_code(code); - Ok(()) - } - - /// Reset the code of account `a` so that it is `code`. - pub fn reset_code(&mut self, a: &Address, code: Bytes) -> trie::Result<()> { - self.require_or_from( - a, - true, - false, - || Account::new_contract(0.into(), self.account_start_nonce), - |_| {}, - )? - .reset_code(code); - Ok(()) - } - - /// Initialise the ABI of account `a` so that it is `abi`. - /// NOTE: Account should have been created with `new_contract`. - pub fn init_abi(&mut self, a: &Address, abi: Bytes) -> trie::Result<()> { - self.require_or_from( - a, - false, - true, - || Account::new_contract(0.into(), self.account_start_nonce), - |_| {}, - )? - .init_abi(abi); - Ok(()) - } - - /// Reset the abi of account `a` so that it is `abi`. - pub fn reset_abi(&mut self, a: &Address, abi: Bytes) -> trie::Result<()> { - self.require_or_from( - a, - false, - true, - || Account::new_contract(0.into(), self.account_start_nonce), - |_| {}, - )? - .reset_abi(abi); - Ok(()) - } - - /// Execute a given transaction. - /// This will change the state accordingly. - #[allow(unknown_lints, clippy::too_many_arguments)] // TODO clippy - pub fn apply( - &mut self, - env_info: &EnvInfo, - engine: &Engine, - t: &SignedTransaction, - tracing: bool, - conf: &BlockSysConfig, - ) -> ApplyResult { - let options = TransactOptions { - tracing, - vm_tracing: false, - }; - let vm_factory = self.factories.vm.clone(); - let native_factory = self.factories.native.clone(); - - match Executive::new( - self, - env_info, - engine, - &vm_factory, - &native_factory, - false, - conf.economical_model, - conf.chain_version, - ) - .transact(t, options, conf) - { - Ok(e) => { - // trace!("Applied transaction. Diff:\n{}\n", state_diff::diff_pod(&old, &self.to_pod())); - let receipt_error = e.exception.and_then(|evm_error| match evm_error { - EvmError::OutOfGas => Some(ReceiptError::OutOfQuota), - EvmError::BadJumpDestination { .. } => Some(ReceiptError::BadJumpDestination), - EvmError::BadInstruction { .. } => Some(ReceiptError::BadInstruction), - EvmError::StackUnderflow { .. } => Some(ReceiptError::StackUnderflow), - EvmError::OutOfStack { .. } => Some(ReceiptError::OutOfStack), - EvmError::MutableCallInStaticContext => { - Some(ReceiptError::MutableCallInStaticContext) - } - EvmError::Internal(_) => Some(ReceiptError::Internal), - EvmError::OutOfBounds => Some(ReceiptError::OutOfBounds), - EvmError::Reverted => Some(ReceiptError::Reverted), - }); - let receipt = Receipt::new( - None, - e.cumulative_gas_used, - e.logs, - receipt_error, - e.account_nonce, - t.get_transaction_hash(), - ); - trace!(target: "state", "Transaction receipt: {:?}", receipt); - Ok(ApplyOutcome { - receipt, - trace: e.trace, - }) - } - Err(err) => { - let receipt_error = match err { - ExecutionError::NotEnoughBaseGas { .. } => { - Some(ReceiptError::NotEnoughBaseQuota) - } - ExecutionError::BlockGasLimitReached { .. } => { - Some(ReceiptError::BlockQuotaLimitReached) - } - ExecutionError::AccountGasLimitReached { .. } => { - Some(ReceiptError::AccountQuotaLimitReached) - } - ExecutionError::InvalidNonce { .. } => Some(ReceiptError::InvalidNonce), - ExecutionError::NotEnoughCash { .. } => Some(ReceiptError::NotEnoughCash), - ExecutionError::NoTransactionPermission => { - Some(ReceiptError::NoTransactionPermission) - } - ExecutionError::NoContractPermission => { - Some(ReceiptError::NoContractPermission) - } - ExecutionError::NoCallPermission => Some(ReceiptError::NoCallPermission), - ExecutionError::ExecutionInternal { .. } => { - Some(ReceiptError::ExecutionInternal) - } - ExecutionError::TransactionMalformed { .. } => { - Some(ReceiptError::TransactionMalformed) - } - }; - let schedule = Schedule::new_v1(); - let sender = *t.sender(); - let tx_gas_used = match err { - ExecutionError::ExecutionInternal { .. } => t.gas, - _ => cmp::min( - self.balance(&sender).unwrap_or_else(|_| U256::from(0)), - U256::from(schedule.tx_gas), - ), - }; - - if (*conf).economical_model == EconomicalModel::Charge { - let fee_value = tx_gas_used * t.gas_price(); - let sender_balance = self.balance(&sender).unwrap(); - - let tx_fee_value = if fee_value > sender_balance { - sender_balance - } else { - fee_value - }; - if let Err(err) = self.sub_balance(&sender, &tx_fee_value) { - error!("Sub balance from error transaction sender failed, tx_fee_value={}, error={:?}", tx_fee_value, err); - } - - let chain_owner = (*conf).chain_owner; - if (*conf).check_options.fee_back_platform && chain_owner != Address::from(0) { - self.add_balance(&chain_owner, &tx_fee_value) - .expect("Add balance to chain owner must success"); - } else { - self.add_balance(&env_info.author, &tx_fee_value) - .expect("Add balance to author(miner) must success"); - } - } - let cumulative_gas_used = env_info.gas_used + tx_gas_used; - let receipt = Receipt::new( - None, - cumulative_gas_used, - Vec::new(), - receipt_error, - 0.into(), - t.get_transaction_hash(), - ); - Ok(ApplyOutcome { - receipt, - trace: Vec::new(), - }) - } - } - } - - fn touch(&mut self, a: &Address) -> trie::Result<()> { - self.require(a, false, false)?; - Ok(()) - } - - /// Commits our cached account changes into the trie. - pub fn commit(&mut self) -> Result<(), Error> { - assert!(self.checkpoints.borrow().is_empty()); - - // first, commit the sub trees. - let mut accounts = self.cache.borrow_mut(); - for (address, ref mut a) in accounts.iter_mut().filter(|&(_, ref a)| a.is_dirty()) { - if let Some(ref mut account) = a.account { - let addr_hash = account.address_hash(address); - { - let mut account_db = self - .factories - .accountdb - .create(self.db.as_hashdb_mut(), addr_hash); - account - .commit_storage(&self.factories.trie, account_db.as_hashdb_mut()) - .map_err(|err| *err)?; - - account.commit_code(account_db.as_hashdb_mut()); - account.commit_abi(account_db.as_hashdb_mut()) - } - if !account.is_empty() { - self.db.note_non_null_account(address); - } - } - } - - { - let mut trie = self - .factories - .trie - .get_from_existing(self.db.as_hashdb_mut(), &mut self.root) - .map_err(|err| *err)?; - for (address, ref mut a) in accounts.iter_mut().filter(|&(_, ref a)| a.is_dirty()) { - a.state = AccountState::Committed; - match a.account { - Some(ref mut account) => { - trie.insert(address, &account.rlp()).map_err(|err| *err)?; - } - None => { - trie.remove(address).map_err(|err| *err)?; - } - } - } - } - - Ok(()) - } - - /// Propagate local cache into shared canonical state cache. - fn propagate_to_global_cache(&mut self) { - let mut addresses = self.cache.borrow_mut(); - trace!("Committing cache {:?} entries", addresses.len()); - for (address, a) in addresses.drain().filter(|&(_, ref a)| { - a.state == AccountState::Committed || a.state == AccountState::CleanFresh - }) { - self.db - .add_to_account_cache(address, a.account, a.state == AccountState::Committed); - } - self.db.sync_account_cache(); - } - - /// Clear state cache - pub fn clear(&mut self) { - self.cache.borrow_mut().clear(); - } - - /// Remove any touched empty or dust accounts. - pub fn kill_garbage( - &mut self, - touched: &HashSet
, - remove_empty_touched: bool, - min_balance: &Option, - kill_contracts: bool, - ) -> trie::Result<()> { - let to_kill: HashSet<_> = { - self.cache - .borrow() - .iter() - .filter_map(|(address, ref entry)| { - let should_kill = touched.contains(address) // Check all touched accounts - && ((remove_empty_touched && entry.exists_and_is_null()) // Remove all empty touched accounts. - || min_balance.map_or(false, |ref balance| { - entry.account.as_ref().map_or(false, |account| { - // Remove all basic and optionally contract accounts - // where balance has been decreased. - (account.is_basic() || kill_contracts) - && account.balance() < balance - && entry.old_balance.as_ref().map_or(false, |b| account.balance() < b) - }) - })); - if should_kill { - Some(*address) - } else { - None - } - }) - .collect() - }; - for address in to_kill { - self.kill_account(&address); - } - Ok(()) - } - - // load required account data from the databases. - fn update_account_cache( - require: RequireCache, - account: &mut Account, - state_db: &B, - db: &HashDB, - ) { - match (account.is_cached(), require) { - (false, RequireCache::Code) | (false, RequireCache::CodeSize) => { - // if there's already code in the global cache, always cache it locally. - let hash = account.code_hash(); - match state_db.get_cached_code(&hash) { - Some(code) => account.cache_given_code(code), - None => { - match require { - RequireCache::None => {} - RequireCache::Code => { - if let Some(code) = account.cache_code(db) { - // propagate code loaded from the database to - // the global code cache. - state_db.cache_code(hash, code) - } - } - RequireCache::CodeSize => { - account.cache_code_size(db); - } - _ => {} - } - } - } - } - _ => {} - }; - - match (account.is_abi_cached(), require) { - (false, RequireCache::Abi) | (false, RequireCache::AbiSize) => { - account.cache_abi(db); - } - _ => {} - } - } - - /// Check caches for required data - /// First searches for account in the local, then the shared cache. - /// Populates local cache if nothing found. - fn ensure_cached( - &self, - a: &Address, - require: RequireCache, - check_null: bool, - f: F, - ) -> trie::Result - where - F: Fn(Option<&Account>) -> U, - { - // check local cache first - if let Some(ref mut maybe_acc) = self.cache.borrow_mut().get_mut(a) { - if let Some(ref mut account) = maybe_acc.account { - let accountdb = self - .factories - .accountdb - .readonly(self.db.as_hashdb(), account.address_hash(a)); - Self::update_account_cache(require, account, &self.db, accountdb.as_hashdb()); - return Ok(f(Some(account))); - } - return Ok(f(None)); - } - // check global cache - let result = self.db.get_cached(a, |mut acc| { - if let Some(ref mut account) = acc { - let accountdb = self - .factories - .accountdb - .readonly(self.db.as_hashdb(), account.address_hash(a)); - Self::update_account_cache(require, account, &self.db, accountdb.as_hashdb()); - } - f(acc.map(|a| &*a)) - }); - match result { - Some(r) => Ok(r), - None => { - // first check if it is not in database for sure - if check_null && self.db.is_known_null(a) { - return Ok(f(None)); - } - - // not found in the global cache, get from the DB and insert into local - let db = self - .factories - .trie - .readonly(self.db.as_hashdb(), &self.root)?; - let mut maybe_acc = db.get_with(a, Account::from_rlp)?; - if let Some(ref mut account) = maybe_acc.as_mut() { - let accountdb = self - .factories - .accountdb - .readonly(self.db.as_hashdb(), account.address_hash(a)); - Self::update_account_cache(require, account, &self.db, accountdb.as_hashdb()); - } - let r = f(maybe_acc.as_ref()); - self.insert_cache(a, AccountEntry::new_clean(maybe_acc)); - Ok(r) - } - } - } - - /// Pull account `a` in our cache from the trie DB. - /// `require_code` requires that the code be cached, too. - /// `require_abi` requires that the abi be cached, too. - fn require<'a>( - &'a self, - a: &Address, - require_code: bool, - require_abi: bool, - ) -> trie::Result> { - self.require_or_from( - a, - require_code, - require_abi, - || Account::new_basic(0u8.into(), self.account_start_nonce), - |_| {}, - ) - } - - /// Pull account `a` in our cache from the trie DB. - /// `require_code` requires that the code be cached, too. - /// `require_abi` requires that the abi be cached, too. - /// If it doesn't exist, make account equal the evaluation of `default`. - fn require_or_from<'a, F, G>( - &'a self, - a: &Address, - require_code: bool, - require_abi: bool, - default: F, - not_default: G, - ) -> trie::Result> - where - F: FnOnce() -> Account, - G: FnOnce(&mut Account), - { - let contains_key = self.cache.borrow().contains_key(a); - if !contains_key { - match self.db.get_cached_account(a) { - Some(acc) => self.insert_cache(a, AccountEntry::new_clean_cached(Some(acc))), - None => { - let maybe_acc = if !self.db.is_known_null(a) { - let db = self - .factories - .trie - .readonly(self.db.as_hashdb(), &self.root)?; - AccountEntry::new_clean(db.get_with(a, Account::from_rlp)?) - } else { - AccountEntry::new_clean(None) - }; - self.insert_cache(a, maybe_acc); - } - } - } - self.note_cache(a); - - // at this point the entry is guaranteed to be in the cache. - Ok(RefMut::map(self.cache.borrow_mut(), |c| { - let entry = c - .get_mut(a) - .expect("entry known to exist in the cache; qed"); - - match &mut entry.account { - &mut Some(ref mut acc) => not_default(acc), - slot => *slot = Some(default()), - } - - // set the dirty flag after changing account data. - entry.state = AccountState::Dirty; - match entry.account { - Some(ref mut account) => { - if require_code || require_abi { - let addr_hash = account.address_hash(a); - let accountdb = self - .factories - .accountdb - .readonly(self.db.as_hashdb(), addr_hash); - - if require_code { - Self::update_account_cache( - RequireCache::Code, - account, - &self.db, - accountdb.as_hashdb(), - ); - } - - if require_abi { - Self::update_account_cache( - RequireCache::Abi, - account, - &self.db, - accountdb.as_hashdb(), - ); - } - } - - account - } - _ => panic!("Required account must always exist; qed"), - } - })) - } -} - -impl fmt::Debug for State { - fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { - write!(f, "{:?}", self.cache.borrow()) - } -} - -#[cfg(test)] -mod tests { - extern crate cita_logger as logger; - extern crate libproto; - extern crate rustc_hex; - //////////////////////////////////////////////////////////////////////////////// - - use self::libproto::blockchain; - use self::rustc_hex::FromHex; - use super::*; - use crate::engines::NullEngine; - use crate::libexecutor::sys_config::BlockSysConfig; - use crate::tests::helpers::*; - use cita_crypto::KeyPair; - use cita_crypto_trait::CreateKey; - use cita_types::traits::LowerHex; - use cita_types::{Address, H256}; - use evm::env_info::EnvInfo; - use std::sync::Arc; - - #[test] - #[ignore] - fn should_apply_create_transaction() { - logger::silent(); - - // 1) tx = (to, data(code), nonce, valid_until_block) - let mut tx = blockchain::Transaction::new(); - tx.set_to(String::from("")); - let nonce = "haha".to_owned(); - tx.set_nonce(nonce.clone()); - let block_limit = 100; - tx.set_valid_until_block(block_limit); - tx.set_quota(1844673); - tx.set_data( - "6060604052341561000f57600080fd5b60646000819055507f8fb1356be\ - 6b2a4e49ee94447eb9dcb8783f51c41dcddfe7919f945017d163bf3336064604051808373\ - ffffffffffffffffffffffffffffffffffffffff1673fffffffffffffffffffffffffffff\ - fffffffffff1681526020018281526020019250505060405180910390a161017580610092\ - 6000396000f30060606040526000357c01000000000000000000000000000000000000000\ - 00000000000000000900463ffffffff16806360fe47b1146100485780636d4ce63c146100\ - 6b57600080fd5b341561005357600080fd5b6100696004808035906020019091905050610\ - 094565b005b341561007657600080fd5b61007e610140565b604051808281526020019150\ - 5060405180910390f35b7fc6d8c0af6d21f291e7c359603aa97e0ed500f04db6e983b9fce\ - 75a91c6b8da6b816040518082815260200191505060405180910390a1806000819055507f\ - fd28ec3ec2555238d8ad6f9faf3e4cd10e574ce7e7ef28b73caa53f9512f65b9338260405\ - 1808373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffff\ - ffffffffffffffffff1681526020018281526020019250505060405180910390a150565b6\ - 00080549050905600a165627a7a723058208777d774164b22030e359c5220ad3599f2a294\ - b4a0ae14b78c4f6a3246525c180029" - .from_hex() - .unwrap(), - ); - - // 2) stx = (from, content(code, nonce, signature)) - // TODO: Should get or generate private key that have send transation permission. - // Should work both for ed25519 and secp256k1. - let keypair = KeyPair::gen_keypair(); - let privkey = keypair.privkey(); - let stx = tx.sign(*privkey); - - // 4) signed - let signed = SignedTransaction::create(&stx).unwrap(); - - // 5) - let mut state = get_temp_state(); - let info = EnvInfo { - number: 0, - author: Address::default(), - timestamp: 0, - difficulty: 0.into(), - gas_limit: U256::from(u64::max_value()), - last_hashes: Arc::new(vec![]), - gas_used: 0.into(), - account_gas_limit: 1844674.into(), - }; - let contract_address = crate::executive::contract_address(&signed.sender(), &U256::from(1)); - let engine = NullEngine::cita(); - - println!("contract_address {:?}", contract_address); - - let result = state - .apply(&info, &engine, &signed, true, &BlockSysConfig::default()) - .unwrap(); - println!( - "{:?}", - state - .code(&contract_address) - .expect("result should unwrap.") - .expect("option should unwrap") - ); - println!("{:?}", result.trace); - assert_eq!( - state.code(&contract_address).unwrap().unwrap(), - Arc::new( - "60606040526000357c010000000000000000000000000000000000000000000000\ - 0000000000900463ffffffff1680635524107714603a575bfe5b3415604157fe5b\ - 605560048080359060200190919050506057565b005b806000819055505b505600\ - a165627a7a7230582079b763be08c24124c9fa25c78b9d221bdee3e981ca0b2e37\ - 1628798c41e292ca0029" - .from_hex() - .unwrap() - ) - ); - assert_eq!( - state.abi(&contract_address).unwrap().unwrap(), - Arc::new(vec![]) - ); - } - - #[test] - fn code_from_database() { - let a = Address::zero(); - let (root, db) = { - let mut state = get_temp_state(); - state - .require_or_from( - &a, - false, - false, - || Account::new_contract(42.into(), 0.into()), - |_| {}, - ) - .unwrap(); - state.init_code(&a, vec![1, 2, 3]).unwrap(); - assert_eq!( - state.code(&a).unwrap(), - Some(Arc::new([1u8, 2, 3].to_vec())) - ); - - state.commit().unwrap(); - assert_eq!( - state.code(&a).unwrap(), - Some(Arc::new([1u8, 2, 3].to_vec())) - ); - state.drop() - }; - - let state = State::from_existing(db, root, U256::from(0u8), Default::default()).unwrap(); - - assert_eq!( - state.code(&a).unwrap(), - Some(Arc::new([1u8, 2, 3].to_vec())) - ); - } - - #[test] - fn abi_from_database() { - let a = Address::zero(); - let (root, db) = { - let mut state = get_temp_state(); - state - .require_or_from( - &a, - false, - false, - || Account::new_contract(42.into(), 0.into()), - |_| {}, - ) - .unwrap(); - state.init_abi(&a, vec![1, 2, 3]).unwrap(); - assert_eq!(state.abi(&a).unwrap(), Some(Arc::new([1u8, 2, 3].to_vec()))); - - state.commit().unwrap(); - assert_eq!(state.abi(&a).unwrap(), Some(Arc::new([1u8, 2, 3].to_vec()))); - state.drop() - }; - let state = State::from_existing(db, root, U256::from(0u8), Default::default()).unwrap(); - - assert_eq!(state.abi(&a).unwrap(), Some(Arc::new([1u8, 2, 3].to_vec()))); - } - - #[test] - fn storage_at_from_database() { - let a = Address::zero(); - let (root, db) = { - let mut state = get_temp_state(); - state - .set_storage(&a, H256::from(1u64), H256::from(69u64)) - .unwrap(); - state.commit().unwrap(); - state.drop() - }; - - let s = State::from_existing(db, root, U256::from(0u8), Default::default()).unwrap(); - assert_eq!( - s.storage_at(&a, &H256::from(1u64)).unwrap(), - H256::from(69u64) - ); - } - - #[test] - fn state_proof() { - let a = Address::from(0x1234u64); - let b = Address::from(0x123456u64); - let c = Address::from(0x12345678u64); - let d = Address::from(0x4321u64); - let err_adr = Address::from(0x1u64); - let (root, db) = { - let mut state = get_temp_state(); - state - .set_storage(&a, H256::from(0x12u64), H256::from(69u64)) - .unwrap(); - state - .set_storage(&a, H256::from(0x1234u64), H256::from(70u64)) - .unwrap(); - state - .set_storage(&a, H256::from(0x123456u64), H256::from(71u64)) - .unwrap(); - state - .set_storage(&a, H256::from(0x4321u64), H256::from(72u64)) - .unwrap(); - - state - .set_storage(&b, H256::from(2u64), H256::from(73u64)) - .unwrap(); - - state - .set_storage(&c, H256::from(2u64), H256::from(73u64)) - .unwrap(); - - state - .set_storage(&d, H256::from(2u64), H256::from(73u64)) - .unwrap(); - - state.commit().unwrap(); - state.drop() - }; - - let s = - State::from_existing(db, root.clone(), U256::from(0u8), Default::default()).unwrap(); - let state_proof_bs = s.get_state_proof(&a, &H256::from(0x123456u64)).unwrap(); - let mut state_proof = StateProof::from_bytes(&state_proof_bs); - assert_eq!(state_proof.verify(root).unwrap(), H256::from(71u64)); - // test for error key - assert_eq!(s.get_state_proof(&a, &H256::from(0x12345678u64)), None); - assert_eq!( - s.get_state_proof(&err_adr, &H256::from(0x12345678u64)), - None - ); - state_proof.set_address(err_adr); - assert_eq!(state_proof.verify(root), None); - - let err_state_proof_bs = s.get_state_proof(&a, &H256::from(0x1u64)).unwrap(); - let err_state_proof = StateProof::from_bytes(&err_state_proof_bs); - assert_eq!(err_state_proof.verify(root), None); - } - - #[test] - fn get_from_database() { - let a = Address::zero(); - let (root, db) = { - let mut state = get_temp_state(); - state.inc_nonce(&a).unwrap(); - state.commit().unwrap(); - assert_eq!(state.nonce(&a).unwrap(), U256::from(1)); - state.drop() - }; - - let state = State::from_existing(db, root, U256::from(0u8), Default::default()).unwrap(); - assert_eq!(state.nonce(&a).unwrap(), U256::from(1u64)); - } - - #[test] - fn remove() { - let a = Address::zero(); - let mut state = get_temp_state(); - assert_eq!(state.exists(&a).unwrap(), false); - assert_eq!(state.exists_and_not_null(&a).unwrap(), false); - state.inc_nonce(&a).unwrap(); - assert_eq!(state.exists(&a).unwrap(), true); - assert_eq!(state.exists_and_not_null(&a).unwrap(), true); - assert_eq!(state.nonce(&a).unwrap(), U256::from(1u64)); - state.kill_account(&a); - assert_eq!(state.exists(&a).unwrap(), false); - assert_eq!(state.exists_and_not_null(&a).unwrap(), false); - assert_eq!(state.nonce(&a).unwrap(), U256::from(0u64)); - } - - #[test] - fn empty_account_is_not_created() { - let a = Address::zero(); - let db = get_temp_state_db(); - let (root, db) = { - let mut state = State::new(db, U256::from(0u8), Default::default()); - state.commit().unwrap(); - state.drop() - }; - let state = State::from_existing(db, root, U256::from(0u8), Default::default()).unwrap(); - assert!(!state.exists(&a).unwrap()); - assert!(!state.exists_and_not_null(&a).unwrap()); - } - - #[test] - fn empty_account_exists_when_creation_forced() { - let a = Address::zero(); - let db = get_temp_state_db(); - let (root, db) = { - let mut state = State::new(db, U256::from(0u8), Default::default()); - state.require(&a, false, false).unwrap(); - state.commit().unwrap(); - state.drop() - }; - let state = State::from_existing(db, root, U256::from(0u8), Default::default()).unwrap(); - assert!(state.exists(&a).unwrap()); - assert!(!state.exists_and_not_null(&a).unwrap()); - } - - #[test] - fn remove_from_database() { - let a = Address::zero(); - let (root, db) = { - let mut state = get_temp_state(); - state.inc_nonce(&a).unwrap(); - state.commit().unwrap(); - assert_eq!(state.exists(&a).unwrap(), true); - assert_eq!(state.nonce(&a).unwrap(), U256::from(1u64)); - state.drop() - }; - - let (root, db) = { - let mut state = - State::from_existing(db, root, U256::from(0u8), Default::default()).unwrap(); - assert_eq!(state.exists(&a).unwrap(), true); - assert_eq!(state.nonce(&a).unwrap(), U256::from(1u64)); - state.kill_account(&a); - state.commit().unwrap(); - assert_eq!(state.exists(&a).unwrap(), false); - assert_eq!(state.nonce(&a).unwrap(), U256::from(0u64)); - state.drop() - }; - - let state = State::from_existing(db, root, U256::from(0u8), Default::default()).unwrap(); - assert_eq!(state.exists(&a).unwrap(), false); - assert_eq!(state.nonce(&a).unwrap(), U256::from(0u64)); - } - - #[test] - fn alter_nonce() { - let mut state = get_temp_state(); - let a = Address::zero(); - state.inc_nonce(&a).unwrap(); - assert_eq!(state.nonce(&a).unwrap(), U256::from(1u64)); - state.inc_nonce(&a).unwrap(); - assert_eq!(state.nonce(&a).unwrap(), U256::from(2u64)); - state.commit().unwrap(); - assert_eq!(state.nonce(&a).unwrap(), U256::from(2u64)); - state.inc_nonce(&a).unwrap(); - assert_eq!(state.nonce(&a).unwrap(), U256::from(3u64)); - state.commit().unwrap(); - assert_eq!(state.nonce(&a).unwrap(), U256::from(3u64)); - } - - #[test] - fn nonce() { - let mut state = get_temp_state(); - let a = Address::zero(); - assert_eq!(state.nonce(&a).unwrap(), U256::from(0u64)); - state.commit().unwrap(); - assert_eq!(state.nonce(&a).unwrap(), U256::from(0u64)); - } - - #[test] - fn ensure_cached() { - let mut state = get_temp_state(); - let a = Address::zero(); - state.require(&a, false, false).unwrap(); - state.commit().unwrap(); - - #[cfg(feature = "sha3hash")] - let expected = "530acecc6ec873396bb3e90b6578161f9688ed7eeeb93d6fba5684895a93b78a"; - #[cfg(feature = "blake2bhash")] - let expected = "da6a27e8063dd144a208f56f6b8dd6b3536ce6adbea93a1bcba95ce7fedb802c"; - #[cfg(feature = "sm3hash")] - let expected = "63b984566f02930a2a959cef805ab0b17f68653a1430a2422e62f21a9f878cde"; - - assert_eq!(state.root().lower_hex(), expected); - } - - #[test] - fn checkpoint_basic() { - let mut state = get_temp_state(); - let a = Address::zero(); - state.checkpoint(); - state.inc_nonce(&a).unwrap(); - assert_eq!(state.nonce(&a).unwrap(), U256::from(1)); - state.discard_checkpoint(); - assert_eq!(state.nonce(&a).unwrap(), U256::from(1)); - state.checkpoint(); - state.inc_nonce(&a).unwrap(); - assert_eq!(state.nonce(&a).unwrap(), U256::from(2)); - state.revert_to_checkpoint(); - assert_eq!(state.nonce(&a).unwrap(), U256::from(1)); - } - - #[test] - fn create_empty() { - let mut state = get_temp_state(); - state.commit().unwrap(); - - #[cfg(feature = "sha3hash")] - let expected = "56e81f171bcc55a6ff8345e692c0f86e5b48e01b996cadc001622fb5e363b421"; - #[cfg(feature = "blake2bhash")] - let expected = "c14af59107ef14003e4697a40ea912d865eb1463086a4649977c13ea69b0d9af"; - #[cfg(feature = "sm3hash")] - let expected = "995b949869f80fa1465a9d8b6fa759ec65c3020d59c2624662bdff059bdf19b3"; - - assert_eq!(state.root().lower_hex(), expected); - } -} diff --git a/cita-executor/core/src/state_db.rs b/cita-executor/core/src/state_db.rs deleted file mode 100644 index 3afffcf21..000000000 --- a/cita-executor/core/src/state_db.rs +++ /dev/null @@ -1,431 +0,0 @@ -// Copyright 2015-2017 Parity Technologies (UK) Ltd. -// This file is part of Parity. - -// This software is free software: you can redistribute it and/or modify -// it under the terms of the GNU General Public License as published by -// the Free Software Foundation, either version 3 of the License, or -// (at your option) any later version. - -// This software 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 General Public License for more details. - -// You should have received a copy of the GNU General Public License -// along with Parity. If not, see . - -// CITA, Copyright 2016-2017 Cryptape Technologies LLC. -// Remove some hf code. - -use crate::cita_db::{DBTransaction, HashDB, JournalDB, KeyValueDB}; -use crate::db::COL_ACCOUNT_BLOOM; -use crate::header::BlockNumber; -use crate::state::backend::*; -use crate::state::Account; -use byteorder::{ByteOrder, LittleEndian}; -use cita_types::{Address, H256}; -use ethcore_bloom_journal::{Bloom, BloomJournal}; -use lru_cache::LruCache; -use std::collections::{HashSet, VecDeque}; -use std::sync::Arc; -use util::cache::MemoryLruCache; -use util::{Mutex, UtilError}; - -/// Value used to initialize bloom bitmap size. -/// -/// Bitmap size is the size in bytes (not bits) that will be allocated in memory. -pub const ACCOUNT_BLOOM_SPACE: usize = 1_048_576; - -/// Value used to initialize bloom items count. -/// -/// Items count is an estimation of the maximum number of items to store. -pub const DEFAULT_ACCOUNT_PRESET: usize = 1_000_000; - -/// Key for a value storing amount of hashes -pub const ACCOUNT_BLOOM_HASHCOUNT_KEY: &[u8] = b"account_hash_count"; - -const STATE_CACHE_BLOCKS: usize = 12; - -// The percentage of supplied cache size to go to accounts. -const ACCOUNT_CACHE_RATIO: usize = 90; - -/// Shared canonical state cache. -struct AccountCache { - /// DB Account cache. `None` indicates that account is known to be missing. - // When changing the type of the values here, be sure to update `mem_used` and - // `new`. - accounts: LruCache>, - /// Information on the modifications in recently committed blocks; specifically which addresses - /// changed in which block. Ordered by block number. - modifications: VecDeque, -} - -/// Buffered account cache item. -struct CacheQueueItem { - /// Account address. - address: Address, - /// Acccount data or `None` if account does not exist. - account: SyncAccount, - /// Indicates that the account was modified before being - /// added to the cache. - modified: bool, -} - -#[derive(Debug)] -/// Accumulates a list of accounts changed in a block. -struct BlockChanges { - /// Block number. - number: BlockNumber, - /// Block hash. - hash: H256, - /// Parent block hash. - parent: H256, - /// A set of modified account addresses. - accounts: HashSet
, - /// Block is part of the canonical chain. - is_canon: bool, -} - -pub struct StateDB { - /// Backing database. - db: Box, - /// Shared canonical state cache. - account_cache: Arc>, - /// DB Code cache. Maps code hashes to shared bytes. - code_cache: Arc>>>>, - /// Local dirty account cache. - local_account_cache: Vec, - /// Shared account bloom. Does not handle chain reorganizations. - account_bloom: Arc>, - cache_size: usize, - /// Hash of the block on top of which this instance was created or - /// `None` if cache is disabled - pub parent_hash: Option, - /// Hash of the committing block or `None` if not committed yet. - commit_hash: Option, - /// Number of the committing block or `None` if not committed yet. - commit_number: Option, -} - -impl StateDB { - pub fn new(db: Box, cache_size: usize) -> StateDB { - let bloom = Self::load_bloom(&**db.backing()); - let acc_cache_size = cache_size * ACCOUNT_CACHE_RATIO / 100; - let code_cache_size = cache_size - acc_cache_size; - let cache_items = acc_cache_size / ::std::mem::size_of::>(); - - StateDB { - db, - account_cache: Arc::new(Mutex::new(AccountCache { - accounts: LruCache::new(cache_items), - modifications: VecDeque::new(), - })), - code_cache: Arc::new(Mutex::new(MemoryLruCache::new(code_cache_size))), - local_account_cache: Vec::new(), - account_bloom: Arc::new(Mutex::new(bloom)), - cache_size, - parent_hash: None, - commit_hash: None, - commit_number: None, - } - } - - /// Loads accounts bloom from the database - /// This bloom is used to handle request for the non-existant account fast - pub fn load_bloom(db: &KeyValueDB) -> Bloom { - let hash_count_entry = db - .get(COL_ACCOUNT_BLOOM, ACCOUNT_BLOOM_HASHCOUNT_KEY) - .expect("Low-level database error"); - - let hash_count_bytes = match hash_count_entry { - Some(bytes) => bytes, - None => return Bloom::new(ACCOUNT_BLOOM_SPACE, DEFAULT_ACCOUNT_PRESET), - }; - - assert_eq!(hash_count_bytes.len(), 1); - let hash_count = hash_count_bytes[0]; - - let mut bloom_parts = vec![0u64; ACCOUNT_BLOOM_SPACE / 8]; - let mut key = [0u8; 8]; - for (i, part) in bloom_parts - .iter_mut() - .enumerate() - .take(ACCOUNT_BLOOM_SPACE / 8) - { - LittleEndian::write_u64(&mut key, i as u64); - *part = db - .get(COL_ACCOUNT_BLOOM, &key) - .expect("low-level database error") - .and_then(|val| Some(LittleEndian::read_u64(&val[..]))) - .unwrap_or(0u64); - } - - let bloom = Bloom::from_parts(&bloom_parts, u32::from(hash_count)); - trace!(target: "account_bloom", "Bloom is {:?} full, hash functions count = {:?}", - bloom.saturation(), hash_count); - bloom - } - - /// Commit blooms journal to the database transaction - pub fn commit_bloom(batch: &mut DBTransaction, journal: BloomJournal) -> Result<(), UtilError> { - assert!(journal.hash_functions <= 255); - batch.put( - COL_ACCOUNT_BLOOM, - ACCOUNT_BLOOM_HASHCOUNT_KEY, - &[journal.hash_functions as u8], - ); - let mut key = [0u8; 8]; - let mut val = [0u8; 8]; - - for (bloom_part_index, bloom_part_value) in journal.entries { - LittleEndian::write_u64(&mut key, bloom_part_index as u64); - LittleEndian::write_u64(&mut val, bloom_part_value); - batch.put(COL_ACCOUNT_BLOOM, &key, &val); - } - Ok(()) - } - - /// Journal all recent operations under the given era and ID. - pub fn journal_under( - &mut self, - batch: &mut DBTransaction, - now: u64, - id: &H256, - ) -> Result { - { - let mut bloom_lock = self.account_bloom.lock(); - Self::commit_bloom(batch, bloom_lock.drain_journal())?; - } - let records = self.db.journal_under(batch, now, id)?; - self.commit_hash = Some(*id); - self.commit_number = Some(now); - Ok(records) - } - - /// Mark a given candidate from an ancient era as canonical, enacting its removals from the - /// backing database and reverting any non-canonical historical commit's insertions. - pub fn mark_canonical( - &mut self, - batch: &mut DBTransaction, - now: u64, - id: &H256, - ) -> Result { - self.db.mark_canonical(batch, now, id) - } - - /// Clone the database for a canonical state. - pub fn boxed_clone_canon(&self, parent: &H256) -> StateDB { - StateDB { - db: self.db.boxed_clone(), - account_cache: self.account_cache.clone(), - code_cache: self.code_cache.clone(), - local_account_cache: Vec::new(), - account_bloom: self.account_bloom.clone(), - cache_size: self.cache_size, - parent_hash: Some(*parent), - commit_hash: None, - commit_number: None, - } - } - - /// Heap size used. - pub fn mem_used(&self) -> usize { - // TODO: account for LRU-cache overhead; this is a close approximation. - self.db.mem_used() + { - let accounts = self.account_cache.lock().accounts.len(); - let code_size = self.code_cache.lock().current_size(); - code_size + accounts * ::std::mem::size_of::>() - } - } - - /// Returns underlying `JournalDB`. - pub fn journal_db(&self) -> &JournalDB { - &*self.db - } - - /// Query how much memory is set aside for the accounts cache (in bytes). - pub fn cache_size(&self) -> usize { - self.cache_size - } - - /// Check if the account can be returned from cache by matching current block parent hash against canonical - /// state and filtering out account modified in later blocks. - fn is_allowed( - addr: &Address, - parent_hash: &Option, - modifications: &VecDeque, - ) -> bool { - let mut parent = match *parent_hash { - None => { - trace!("Cache lookup skipped for {:?}: no parent hash", addr); - return false; - } - Some(ref parent) => parent, - }; - if modifications.is_empty() { - return true; - } - // Ignore all accounts modified in later blocks - // Modifications contains block ordered by the number - // We search for our parent in that list first and then for - // all its parent until we hit the canonical block, - // checking against all the intermediate modifications. - for m in modifications { - if &m.hash == parent { - if m.is_canon { - return true; - } - parent = &m.parent; - } - if m.accounts.contains(addr) { - trace!( - "Cache lookup skipped for {:?}: modified in a later block", - addr - ); - return false; - } - } - trace!( - "Cache lookup skipped for {:?}: parent hash is unknown", - addr - ); - false - } -} - -impl Backend for StateDB { - fn as_hashdb(&self) -> &HashDB { - self.db.as_hashdb() - } - - fn as_hashdb_mut(&mut self) -> &mut HashDB { - self.db.as_hashdb_mut() - } - - fn add_to_account_cache(&mut self, address: Address, data: Option, modified: bool) { - self.local_account_cache.push(CacheQueueItem { - address, - account: SyncAccount(data), - modified, - }) - } - - fn cache_code(&self, hash: H256, code: Arc>) { - let mut cache = self.code_cache.lock(); - - cache.insert(hash, code); - } - - fn get_cached_account(&self, addr: &Address) -> Option { - let mut cache = self.account_cache.lock(); - if !Self::is_allowed(addr, &self.parent_hash, &cache.modifications) { - return None; - } - cache - .accounts - .get_mut(addr) - .and_then(|a| a.as_ref().map(Account::clone_basic)) - } - - fn get_cached(&self, a: &Address, f: F) -> Option - where - F: FnOnce(Option<&mut Account>) -> U, - { - let mut cache = self.account_cache.lock(); - if !Self::is_allowed(a, &self.parent_hash, &cache.modifications) { - return None; - } - cache.accounts.get_mut(a).map(|c| f(c.as_mut())) - } - - fn get_cached_code(&self, hash: &H256) -> Option>> { - let mut cache = self.code_cache.lock(); - - cache.get_mut(hash).cloned() - } - - fn note_non_null_account(&self, address: &Address) { - trace!(target: "account_bloom", "Note account bloom: {:?}", address); - let mut bloom = self.account_bloom.lock(); - bloom.set(address); - } - - fn is_known_null(&self, address: &Address) -> bool { - trace!(target: "account_bloom", "Check account bloom: {:?}", address); - !self.account_bloom.lock().check(address) - } - - /// Propagate local cache into the global cache. - /// `sync_cache` should be called after the block has been committed. - fn sync_account_cache(&mut self) { - trace!( - "sync_cache id = (#{:?}, {:?}), parent={:?}", - self.commit_number, - self.commit_hash, - self.parent_hash, - ); - let mut cache = self.account_cache.lock(); - let cache = &mut *cache; - - // Propagate cache only if committing on top of the latest canonical state - // blocks are ordered by number and only one block with a given number is marked as canonical - // (contributed to canonical state cache) - if let (Some(ref number), Some(ref hash), Some(ref parent)) = - (self.commit_number, self.commit_hash, self.parent_hash) - { - if cache.modifications.len() == STATE_CACHE_BLOCKS { - cache.modifications.pop_back(); - } - let mut modifications = HashSet::new(); - trace!( - "committing {} cache entries", - self.local_account_cache.len() - ); - for account in self.local_account_cache.drain(..) { - if account.modified { - modifications.insert(account.address); - } - - let acc = account.account.0; - if let Some(&mut Some(ref mut existing)) = cache.accounts.get_mut(&account.address) - { - if let Some(new) = acc { - if account.modified { - existing.overwrite_with(new); - } - continue; - } - } - cache.accounts.insert(account.address, acc); - } - - // Save modified accounts. These are ordered by the block number. - let block_changes = BlockChanges { - accounts: modifications, - number: *number, - hash: *hash, - is_canon: true, - parent: *parent, - }; - let insert_at = cache - .modifications - .iter() - .enumerate() - .find(|&(_, m)| m.number < *number) - .map(|(i, _)| i); - trace!("inserting modifications at {:?}", insert_at); - if let Some(insert_at) = insert_at { - cache.modifications.insert(insert_at, block_changes); - } else { - cache.modifications.push_back(block_changes); - } - } - } -} - -/// Sync wrapper for the account. -struct SyncAccount(Option); -/// That implementation is safe because account is never modified or accessed in any way. -/// We only need `Sync` here to allow `StateDb` to be kept in a `RwLock`. -/// `Account` is `!Sync` by default because of `RefCell`s inside it. -unsafe impl Sync for SyncAccount {} diff --git a/cita-executor/core/src/storage.rs b/cita-executor/core/src/storage.rs new file mode 100644 index 000000000..3470536aa --- /dev/null +++ b/cita-executor/core/src/storage.rs @@ -0,0 +1,657 @@ +// Copyright Cryptape Technologies LLC. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +use cita_types::{Address, H256, U256}; +use std::boxed::Box; +use std::convert::From; +use util::sha3; + +use crate::types::errors::NativeError; +use cita_vm::evm::DataProvider; + +pub trait Serialize { + fn serialize(&self) -> Result, NativeError>; +} +pub trait Deserialize: Sized { + fn deserialize(bytes: &[u8]) -> Result; +} + +impl Serialize for U256 { + fn serialize(&self) -> Result, NativeError> { + let mut vec = vec![0; 32]; + self.to_big_endian(&mut vec); + Ok(vec) + } +} +impl Deserialize for U256 { + fn deserialize(bytes: &[u8]) -> Result { + Ok(U256::from(bytes)) + } +} + +impl Serialize for String { + fn serialize(&self) -> Result, NativeError> { + Ok(self.to_owned().into_bytes()) + } +} +impl Deserialize for String { + fn deserialize(bytes: &[u8]) -> Result { + Self::from_utf8(bytes.to_owned()).map_err(|_| NativeError::Internal("dup coin".to_string())) + } +} + +impl Serialize for Vec { + fn serialize(&self) -> Result, NativeError> { + Ok(self.clone()) + } +} +impl Deserialize for Vec { + fn deserialize(bytes: &[u8]) -> Result { + Ok(Vec::from(bytes)) + } +} + +#[derive(Debug, PartialEq, Eq, Clone)] +pub struct Scalar { + position: H256, +} + +impl Scalar { + pub fn new(position: H256) -> Self { + Scalar { position } + } + // single element + pub fn set( + self: &Self, + data_provider: &mut DataProvider, + addr: &Address, + value: U256, + ) -> Result<(), NativeError> { + data_provider.set_storage(addr, self.position, H256::from(value)); + Ok(()) + } + + pub fn get( + self: &Self, + data_provider: &DataProvider, + addr: &Address, + ) -> Result { + let value = data_provider.get_storage(addr, &self.position); + Ok(U256::from(value)) + } + + // bytes & string + pub fn set_bytes( + self: &Self, + data_provider: &mut DataProvider, + addr: &Address, + value: &T, + ) -> Result<(), NativeError> + where + T: Serialize, + { + let encoded = value.serialize()?; + let length = encoded.len(); + if length < 32 { + let mut byte32 = [0u8; 32]; + byte32[0..encoded.len()].copy_from_slice(&encoded); + byte32[31] = (length * 2) as u8; + data_provider.set_storage(addr, self.position, H256::from_slice(&byte32)); + } else { + data_provider.set_storage(addr, self.position, H256::from((length * 2 + 1) as u64)); + let mut key = U256::from(H256::from_slice(&sha3::keccak256(&self.position))); + for chunk in encoded.chunks(32) { + let value = H256::from(chunk); + data_provider.set_storage(addr, H256::from(key), value); + key += U256::one(); + } + } + Ok(()) + } + + pub fn get_bytes( + self: &Self, + data_provider: &DataProvider, + addr: &Address, + ) -> Result, NativeError> + where + T: Deserialize, + { + let mut bytes = Vec::::new(); + let first = data_provider.get_storage(addr, &self.position); + if first[31] % 2 == 0 { + let len = (first[31] / 2) as usize; + bytes.extend_from_slice(&first[0..len]); + let decoded = T::deserialize(&bytes)?; + Ok(Box::new(decoded)) + } else { + let mut len = ((first.low_u64() as usize) - 1) / 2; + let mut key = U256::from(H256::from_slice(&sha3::keccak256(&self.position))); + let mut bytes = Vec::new(); + while len > 0 { + let v = data_provider.get_storage(addr, &H256::from(key)); + if len > 32 { + bytes.extend_from_slice(v.as_ref()); + key += U256::one(); + len -= 32; + } else { + bytes.extend_from_slice(&v[0..len]); + len = 0; + } + } + Ok(Box::new(T::deserialize(&bytes)?)) + } + } +} + +#[derive(Debug, PartialEq, Eq, Clone)] +pub struct Array { + position: H256, +} +impl Array { + pub fn new(position: H256) -> Self { + Array { position } + } + + #[inline] + fn key(&self, index: u64) -> H256 { + let mut key = U256::from(H256::from_slice(&sha3::keccak256(&self.position))); + key += U256::from(index); + H256::from(key) + } + + pub fn set( + self: &Self, + data_provider: &mut DataProvider, + addr: &Address, + index: u64, + value: &U256, + ) -> Result<(), NativeError> { + let scalar = Scalar::new(self.key(index)); + scalar.set(data_provider, addr, *value) + } + + pub fn get( + self: &Self, + data_provider: &DataProvider, + addr: &Address, + index: u64, + ) -> Result { + let scalar = Scalar::new(self.key(index)); + scalar.get(data_provider, addr) + } + + pub fn set_bytes( + self: &Self, + data_provider: &mut DataProvider, + addr: &Address, + index: u64, + value: &T, + ) -> Result<(), NativeError> + where + T: Serialize, + { + let scalar = Scalar::new(self.key(index)); + scalar.set_bytes(data_provider, addr, value) + } + + pub fn get_bytes( + self: &Self, + data_provider: &DataProvider, + addr: &Address, + index: u64, + ) -> Result, NativeError> + where + T: Deserialize, + { + let scalar = Scalar::new(self.key(index)); + scalar.get_bytes(data_provider, addr) + } + + pub fn set_len( + self: &Self, + data_provider: &mut DataProvider, + addr: &Address, + len: u64, + ) -> Result<(), NativeError> { + data_provider.set_storage(addr, self.position, H256::from(len)); + Ok(()) + } + + pub fn get_len( + self: &Self, + data_provider: &DataProvider, + addr: &Address, + ) -> Result { + let len = data_provider.get_storage(addr, &self.position); + Ok(len.low_u64()) + } + + pub fn get_array(self: &mut Self, index: u64) -> Array { + Array::new(self.key(index)) + } + pub fn get_map(self: &mut Self, index: u64) -> Map { + Map::new(self.key(index)) + } +} + +#[derive(Debug, PartialEq, Eq, Clone)] +pub struct Map { + position: H256, +} + +impl Map { + pub fn new(position: H256) -> Self { + Map { position } + } + + #[inline] + fn key(&self, key: &Key) -> Result + where + Key: Serialize, + { + let mut bytes = Vec::new(); + bytes.extend_from_slice(&key.serialize()?); + bytes.extend_from_slice(self.position.as_ref()); + Ok(H256::from_slice(&sha3::keccak256(&bytes))) + } + + pub fn set( + self: &Self, + data_provider: &mut DataProvider, + addr: &Address, + key: &Key, + value: U256, + ) -> Result<(), NativeError> + where + Key: Serialize, + { + Scalar::new(self.key(key)?).set(data_provider, addr, value) + } + + pub fn get( + self: &Self, + data_provider: &DataProvider, + addr: &Address, + key: &Key, + ) -> Result + where + Key: Serialize, + { + Scalar::new(self.key(key)?).get(data_provider, addr) + } + + pub fn set_bytes( + self: &Self, + data_provider: &mut DataProvider, + addr: &Address, + key: &Key, + value: &Value, + ) -> Result<(), NativeError> + where + Key: Serialize, + Value: Serialize, + { + Scalar::new(self.key(key)?).set_bytes(data_provider, addr, value) + } + + pub fn get_bytes( + self: &Self, + data_provider: &DataProvider, + addr: &Address, + key: &Key, + ) -> Result + where + Key: Serialize, + Value: Deserialize, + { + Ok(*Scalar::new(self.key(key)?).get_bytes(data_provider, addr)?) + } + + pub fn get_array(self: &mut Self, key: &Key) -> Result + where + Key: Serialize, + { + Ok(Array::new(self.key(key)?)) + } + + pub fn get_map(self: &mut Self, key: &Key) -> Result + where + Key: Serialize, + { + Ok(Map::new(self.key(key)?)) + } +} + +#[cfg(test)] +mod tests { + use super::*; + use cita_vm::evm::extmock::DataProviderMock; + use std::str::FromStr; + + #[test] + + fn test_scalar_bytes() { + // let mut data_provider = DataProviderMock::default(); + let mut data_provider = DataProviderMock::default(); + + let scalar = Scalar::new(H256::from(0)); + let code_address = Address::from_str("ffffffffffffffffffffffffffffffffffffffff").unwrap(); + + // 1) length=30 + let expected = format!("012345678901234567890123456789"); + assert!(scalar + .set_bytes(&mut data_provider, &code_address, &expected) + .is_ok()); + let value = scalar.get_bytes::(&data_provider, &code_address); + assert!(value.is_ok()); + assert_eq!(*value.unwrap().as_ref(), expected.clone()); + + // 2) length=31 + let expected = format!("0123456789012345678901234567890"); + assert!(scalar + .set_bytes(&mut data_provider, &code_address, &expected) + .is_ok()); + let value = scalar.get_bytes::(&data_provider, &code_address); + assert!(value.is_ok()); + assert_eq!(*value.unwrap().as_ref(), expected.clone()); + + // 3) length=32 + let expected = format!("01234567890123456789012345678901"); + assert!(scalar + .set_bytes(&mut data_provider, &code_address, &expected) + .is_ok()); + let value = scalar.get_bytes::(&data_provider, &code_address); + assert!(value.is_ok()); + assert_eq!(*value.unwrap().as_ref(), expected.clone()); + + // 4) length=43 + let expected = format!("012345678901234567890123456789012"); + assert!(scalar + .set_bytes(&mut data_provider, &code_address, &expected) + .is_ok()); + let value = scalar.get_bytes::(&data_provider, &code_address); + assert!(value.is_ok()); + assert_eq!(*value.unwrap().as_ref(), expected.clone()); + } + + #[test] + fn test_scalar_u256() { + let mut data_provider = DataProviderMock::default(); + let scalar = Scalar::new(H256::from(0)); + let code_address = Address::from_str("ffffffffffffffffffffffffffffffffffffffff").unwrap(); + + let expected = U256::from(0x123456); + assert!(scalar + .set(&mut data_provider, &code_address, expected.clone()) + .is_ok()); + let value = scalar.get(&data_provider, &code_address); + assert!(value.is_ok()); + assert_eq!(value.unwrap(), expected.clone()); + } + + #[test] + fn test_array_simple() { + let mut data_provider = DataProviderMock::default(); + let length = 7u64; + let array = Array { + position: H256::from(0), + }; + let code_address = Address::from_str("ffffffffffffffffffffffffffffffffffffffff").unwrap(); + + // 1) length + assert!(array + .set_len(&mut data_provider, &code_address, length) + .is_ok()); + assert_eq!( + array.get_len(&data_provider, &code_address).unwrap(), + length + ); + + // 2) array[1] = 0x1234 + let index = 1; + let expected = U256::from(0x1234); + assert!(array + .set(&mut data_provider, &code_address, index, &expected) + .is_ok()); + let value = array.get(&data_provider, &code_address, index); + assert_eq!(value.unwrap(), expected.clone()); + + // 3) array[3] = 0x2234 + let index = 3; + let expected = U256::from(0x2234); + assert!(array + .set(&mut data_provider, &code_address, index, &expected) + .is_ok()); + let value = array.get(&data_provider, &code_address, index); + assert_eq!(value.unwrap(), expected.clone()); + } + + #[test] + fn test_array_with_sub_array() { + let mut data_provider = DataProviderMock::default(); + let mut array = Array::new(H256::from(0)); + let code_address = Address::from_str("ffffffffffffffffffffffffffffffffffffffff").unwrap(); + + // 1) length = 7 + let length = 7; + assert!(array + .set_len(&mut data_provider, &code_address, length) + .is_ok()); + assert_eq!( + array.get_len(&data_provider, &code_address).unwrap(), + length + ); + + // 2) array[1].len = 8 + let index = 1; + let subarray_length = 8; + let subarray = array.get_array(index); + assert!(subarray + .set_len(&mut data_provider, &code_address, subarray_length) + .is_ok()); + assert_eq!( + subarray.get_len(&mut data_provider, &code_address).unwrap(), + subarray_length + ); + + // 3) array[1][2] = 0x1234 + let index = 2; + let expected = U256::from(0x1234); + assert!(subarray + .set(&mut data_provider, &code_address, index, &expected) + .is_ok()); + assert_eq!( + subarray.get(&data_provider, &code_address, index).unwrap(), + expected + ); + + // 4) array[1][4] = 0x2234 + let index = 4; + let expected = U256::from(0x2234); + assert!(subarray + .set(&mut data_provider, &code_address, index, &expected) + .is_ok()); + assert_eq!( + subarray.get(&data_provider, &code_address, index).unwrap(), + expected + ); + } + + #[test] + fn test_array_with_sub_map() { + let mut data_provider = DataProviderMock::default(); + let mut array = Array::new(H256::from(0)); + let code_address = Address::from_str("ffffffffffffffffffffffffffffffffffffffff").unwrap(); + + // 1) length = 7 + let length = 7; + assert!(array + .set_len(&mut data_provider, &code_address, length) + .is_ok()); + assert_eq!( + array.get_len(&data_provider, &code_address).unwrap(), + length + ); + + // 2) array[1][2] = 0x1234 + let index = 1; + let key = U256::from(2); + let submap = array.get_map(index); + let expected = U256::from(0x1234); + assert!(submap + .set(&mut data_provider, &code_address, &key, expected) + .is_ok()); + assert_eq!( + submap + .get::(&data_provider, &code_address, &key) + .unwrap(), + expected + ); + + // 4) array[1]["key"] = "1234" + let key = String::from("key"); + let expected = String::from("1234"); + assert!(submap + .set_bytes::(&mut data_provider, &code_address, &key, &expected) + .is_ok()); + assert_eq!( + submap + .get_bytes::(&data_provider, &code_address, &key) + .unwrap(), + expected.clone() + ); + } + + #[test] + fn test_map_simple() { + let mut data_provider = DataProviderMock::default(); + let map = Map::new(H256::from(1)); + let code_address = Address::from_str("ffffffffffffffffffffffffffffffffffffffff").unwrap(); + + // 1) map["key"] = "value" + let key = U256::from(1); + let value = U256::from(0x1234); + assert!(map + .set(&mut data_provider, &code_address, &key, value) + .is_ok()); + assert_eq!(map.get(&data_provider, &code_address, &key).unwrap(), value); + + // 2) map[0] = "1234567890" + let key = U256::from(1); + let value = String::from("1234567890"); + assert!(map + .set_bytes(&mut data_provider, &code_address, &key, &value) + .is_ok()); + assert_eq!( + map.get_bytes::(&data_provider, &code_address, &key) + .unwrap(), + value.clone() + ); + + // 3) map[0] = "123456789012345678901234567890123" + let key = U256::from(1); + let value = String::from("123456789012345678901234567890123"); + assert!(map + .set_bytes(&mut data_provider, &code_address, &key, &value) + .is_ok()); + assert_eq!( + map.get_bytes::(&data_provider, &code_address, &key) + .unwrap(), + value + ); + + // 4) map["key"] = 0x1234; + let key = String::from("key"); + let value = U256::from(0x1234); + assert!(map + .set(&mut data_provider, &code_address, &key, value) + .is_ok()); + assert_eq!(map.get(&data_provider, &code_address, &key).unwrap(), value);; + } + + #[test] + fn test_map_with_sub_array() { + let mut data_provider = DataProviderMock::default(); + let mut map = Map::new(H256::from(1)); + let code_address = Address::from_str("ffffffffffffffffffffffffffffffffffffffff").unwrap(); + + // 1) map["key1"]["key2"] = "1234567890" + let key1 = String::from("key1"); + let index = 2u64; + let value = String::from("1234567890"); + let sub_array = map.get_array(&key1).unwrap(); + assert!(sub_array + .set_bytes(&mut data_provider, &code_address, index.clone(), &value) + .is_ok()); + assert_eq!( + *sub_array + .get_bytes::(&data_provider, &code_address, index.clone()) + .unwrap(), + value.clone() + ); + + // 2) map["key1"][2] = "1234567890" + let key1 = String::from("key1"); + let index = 4u64; + let value = String::from("1234567890"); + let sub_array = map.get_array(&key1).unwrap(); + assert!(sub_array + .set_bytes(&mut data_provider, &code_address, index.clone(), &value) + .is_ok()); + assert_eq!( + *sub_array + .get_bytes::(&data_provider, &code_address, index.clone()) + .unwrap(), + value.clone() + ); + } + + #[test] + fn test_map_with_sub_map() { + let mut data_provider = DataProviderMock::default(); + let mut map = Map::new(H256::from(1)); + let code_address = Address::from_str("ffffffffffffffffffffffffffffffffffffffff").unwrap(); + + // 1) map["key1"]["key2"] = "1234567890" + let key1 = String::from("key1"); + let key2 = String::from("key2"); + let value = String::from("1234567890"); + let sub_map = map.get_map(&key1).unwrap(); + assert!(sub_map + .set_bytes(&mut data_provider, &code_address, &key2, &value) + .is_ok()); + assert_eq!( + sub_map + .get_bytes::(&data_provider, &code_address, &key2) + .unwrap(), + value.clone() + ); + + // 2) map["key1"][2] = "1234567890" + let key1 = String::from("key1"); + let key2 = U256::from(2); + let value = String::from("1234567890"); + let sub_map = map.get_map(&key1).unwrap(); + assert!(sub_map + .set_bytes(&mut data_provider, &code_address, &key2, &value) + .is_ok()); + assert_eq!( + sub_map + .get_bytes::<_, String>(&data_provider, &code_address, &key2) + .unwrap(), + value.clone() + ); + } +} diff --git a/cita-executor/core/src/substate.rs b/cita-executor/core/src/substate.rs deleted file mode 100644 index 81087f0b7..000000000 --- a/cita-executor/core/src/substate.rs +++ /dev/null @@ -1,97 +0,0 @@ -// Copyright 2015-2017 Parity Technologies (UK) Ltd. -// This file is part of Parity. - -// This software is free software: you can redistribute it and/or modify -// it under the terms of the GNU General Public License as published by -// the Free Software Foundation, either version 3 of the License, or -// (at your option) any later version. - -// This software 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 General Public License for more details. - -// You should have received a copy of the GNU General Public License -// along with Parity. If not, see . - -//! Execution environment substate. - -use crate::log_entry::LogEntry; -use cita_types::{Address, U256}; -use std::collections::HashSet; - -/// State changes which should be applied in finalize, -/// after transaction is fully executed. -#[derive(Debug, Default)] -pub struct Substate { - /// Any accounts that have suicided. - pub suicides: HashSet
, - - /// Any accounts that are tagged for garbage collection. - pub garbage: HashSet
, - - /// Any logs. - pub logs: Vec, - - /// Refund counter of SSTORE nonzero -> zero. - pub sstore_clears_count: U256, - - /// Created contracts. - pub contracts_created: Vec
, -} - -impl Substate { - /// Creates new substate. - pub fn new() -> Self { - Substate::default() - } - - /// Merge secondary substate `s` into self, accruing each element correspondingly. - pub fn accrue(&mut self, s: Substate) { - self.suicides.extend(s.suicides.into_iter()); - self.garbage.extend(s.garbage.into_iter()); - self.logs.extend(s.logs.into_iter()); - self.sstore_clears_count = self.sstore_clears_count + s.sstore_clears_count; - self.contracts_created - .extend(s.contracts_created.into_iter()); - } -} - -#[cfg(test)] -mod tests { - use super::Substate; - use crate::log_entry::LogEntry; - - #[test] - fn created() { - let sub_state = Substate::new(); - assert_eq!(sub_state.suicides.len(), 0); - } - - #[test] - fn accrue() { - let mut sub_state = Substate::new(); - sub_state.contracts_created.push(1u64.into()); - sub_state.logs.push(LogEntry { - address: 1u64.into(), - topics: vec![], - data: vec![], - }); - sub_state.sstore_clears_count = 5.into(); - sub_state.suicides.insert(10u64.into()); - - let mut sub_state_2 = Substate::new(); - sub_state_2.contracts_created.push(2u64.into()); - sub_state_2.logs.push(LogEntry { - address: 1u64.into(), - topics: vec![], - data: vec![], - }); - sub_state_2.sstore_clears_count = 7.into(); - - sub_state.accrue(sub_state_2); - assert_eq!(sub_state.contracts_created.len(), 2); - assert_eq!(sub_state.sstore_clears_count, 12.into()); - assert_eq!(sub_state.suicides.len(), 1); - } -} diff --git a/cita-executor/core/src/tests/amend_data_test.rs b/cita-executor/core/src/tests/amend_data_test.rs index 802e82c2f..b8c1d5acb 100644 --- a/cita-executor/core/src/tests/amend_data_test.rs +++ b/cita-executor/core/src/tests/amend_data_test.rs @@ -1,121 +1,89 @@ -// CITA -// Copyright 2016-2018 Cryptape Technologies LLC. +// Copyright Cryptape Technologies LLC. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. -// This program is free software: you can redistribute it -// and/or modify it under the terms of the GNU General Public -// License as published by the Free Software Foundation, -// either version 3 of the License, or (at your option) any -// later version. +use std::cell::RefCell; +use std::sync::Arc; -// 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 General Public License for more details. +use crate::cita_executive::CitaExecutive; +use crate::contracts::native::factory::Factory as NativeFactory; +use crate::libexecutor::{economical_model::EconomicalModel, sys_config::BlockSysConfig}; +use crate::tests::helpers::get_temp_state; +use crate::types::context::Context; +use crate::types::transaction::Action; -// You should have received a copy of the GNU General Public License -// along with this program. If not, see . - -use super::helpers::*; -use crate::executive::Executive; -use crate::libexecutor::economical_model::EconomicalModel; -use crate::reserved_addresses; -use crate::state::State; -use crate::state_db::*; use cita_types::{Address, H256, U256}; -use evm; -use evm::action_params::{ActionParams, ActionValue}; -use util::{Bytes, BytesRef}; +use cita_vm::BlockDataProviderMock; +use core::transaction::{SignedTransaction, Transaction}; +use types::Bytes; + +fn build_transaction( + data: &Vec, + value: U256, + use_super_admin: bool, +) -> (SignedTransaction, BlockSysConfig) { + let mut tx = Transaction::default(); + tx.action = Action::AmendData; + tx.data = data.to_vec(); + tx.value = value; + tx.gas = U256::from(100_000); + + let signed_tx = tx.fake_sign(Address::random()); + let mut block_config = BlockSysConfig::default(); + if use_super_admin { + let sender = signed_tx.sender(); + block_config.super_admin_account = Some(*sender); + } + (signed_tx, block_config) +} -fn call_vm( - state: &mut State, - params: ActionParams, -) -> evm::Result { - use crate::contracts::native::factory::Factory as NativeFactory; - use crate::engines::NullEngine; - use crate::state::Substate; - use crate::trace::{ExecutiveTracer, ExecutiveVMTracer}; - use evm::env_info::EnvInfo; - use evm::{Factory, VMType}; - let factory = Factory::new(VMType::Interpreter, 1024 * 32); +#[test] +fn test_amend_tool() { + let state = get_temp_state(); let native_factory = NativeFactory::default(); - let mut tracer = ExecutiveTracer::default(); - let mut vm_tracer = ExecutiveVMTracer::toplevel(); - let info = EnvInfo::default(); - let engine = NullEngine::default(); - let mut substate = Substate::new(); - let mut ex = Executive::new( - state, - &info, - &engine, - &factory, + let context = Context::default(); + + let mut e = CitaExecutive::new( + Arc::new(BlockDataProviderMock::default()), + Arc::new(RefCell::new(state)), &native_factory, - false, - EconomicalModel::Quota, - 0, + &context, + EconomicalModel::default(), ); - let mut out = vec![]; - ex.call( - ¶ms, - &mut substate, - BytesRef::Fixed(&mut out), - &mut tracer, - &mut vm_tracer, - ) -} -#[test] -fn call_amend_data() { - let mut state = get_temp_state(); - let super_admin_address: Address = "0000000000000000000000000000000000012345".into(); - state.super_admin_account = Some(super_admin_address.clone()); - let key = H256::from(42); - let value = H256::from(42); + let (key, value) = (H256::from(42), H256::from(42)); let storage_address: Address = "0000000000000000000000000000000000055555".into(); + let mut data: Bytes = storage_address.to_vec(); data.append(&mut key.to_vec()); data.append(&mut value.to_vec()); - // non admin sender - let sender = Address::default(); - let address: Address = reserved_addresses::AMEND_ADDRESS.into(); - let mut params = ActionParams::default(); - params.address = address; - params.code_address = address; - params.sender = sender.clone(); - params.origin = sender.clone(); - params.gas = U256::from(10000); - params.value = ActionValue::Apparent(3.into()); - params.data = Some(data.clone()); - let result = call_vm(&mut state, params); - assert!(result.is_err()); - // sender is admin - let mut params = ActionParams::default(); - let sender: Address = super_admin_address.clone(); - params.address = address; - params.code_address = address; - params.sender = sender.clone(); - params.origin = sender.clone(); - params.gas = U256::from(10000); - params.value = ActionValue::Apparent(3.into()); - params.data = Some(data.clone()); - let result = call_vm(&mut state, params); - assert!(result.is_ok()); + // Sender is not super admin + // `value=3` means the operation of amending kv + let (tx, config) = build_transaction(&data, U256::from(3), false); + assert!(e.exec(&tx, &config).is_err()); + + // Sender is super admin + let (tx, config) = build_transaction(&data, U256::from(3), true); + assert!(e.exec(&tx, &config).is_ok()); - // get value from key let mut data: Bytes = storage_address.to_vec(); data.append(&mut key.to_vec()); - let mut params = ActionParams::default(); - let sender: Address = super_admin_address.clone(); - params.address = address; - params.code_address = address; - params.sender = sender.clone(); - params.origin = sender.clone(); - params.gas = U256::from(10000); - params.value = ActionValue::Apparent(4.into()); - params.data = Some(data.clone()); - let result = call_vm(&mut state, params); - assert!(result.is_ok()); - let return_data = &*(result.unwrap().return_data); - let return_value: H256 = return_data.into(); - assert!(return_value == value) + + // Get value from key use transact interface + // `value=4` means the operation of getting value from key. + let (tx, config) = build_transaction(&data, U256::from(4), true); + let res = e.exec(&tx, &config).unwrap(); + assert!(e.exec(&tx, &config).is_ok()); + assert_eq!(res.output, value.to_vec()); } diff --git a/cita-executor/core/src/tests/exemock.rs b/cita-executor/core/src/tests/exemock.rs new file mode 100644 index 000000000..93a46c8a3 --- /dev/null +++ b/cita-executor/core/src/tests/exemock.rs @@ -0,0 +1,152 @@ +// Copyrighttape Technologies LLC. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +use std::collections::BTreeMap; + +use cita_types::{Address, H256, U256}; +pub use cita_vm::evm::{ + common, Context, DataProvider, Error, Interpreter, InterpreterConf, InterpreterParams, + InterpreterResult, OpCode, +}; + +#[derive(Clone, Default)] +pub struct Account { + pub balance: U256, + pub code: Vec, + pub nonce: U256, + pub storage: BTreeMap, +} + +#[derive(Default)] +pub struct DataProviderMock { + pub db: BTreeMap, + pub db_origin: BTreeMap, + pub refund: BTreeMap, +} + +impl DataProvider for DataProviderMock { + fn get_balance(&self, address: &Address) -> U256 { + self.db.get(address).map_or(U256::zero(), |v| v.balance) + } + + fn add_refund(&mut self, address: &Address, n: u64) { + self.refund + .entry(*address) + .and_modify(|v| *v += n) + .or_insert(n); + } + + fn sub_refund(&mut self, address: &Address, n: u64) { + self.refund + .entry(*address) + .and_modify(|v| *v -= n) + .or_insert(n); + } + + fn get_refund(&self, address: &Address) -> u64 { + self.refund.get(address).map_or(0, |v| *v) + } + + fn get_code_size(&self, address: &Address) -> u64 { + self.db.get(address).map_or(0, |v| v.code.len() as u64) + } + + fn get_code(&self, address: &Address) -> Vec { + self.db.get(address).map_or(vec![], |v| v.code.clone()) + } + + fn get_code_hash(&self, address: &Address) -> H256 { + self.db + .get(address) + .map_or(H256::zero(), |v| self.sha3(v.code.as_slice())) + } + + fn get_block_hash(&self, _: &U256) -> H256 { + H256::zero() + } + + fn get_storage(&self, address: &Address, key: &H256) -> H256 { + self.db.get(address).map_or(H256::zero(), |v| { + v.storage.get(key).map_or(H256::zero(), |&v| v) + }) + } + + fn set_storage(&mut self, address: &Address, key: H256, value: H256) { + self.db + .entry(*address) + .or_insert_with(Account::default) + .storage + .insert(key, value); + } + + fn get_storage_origin(&self, address: &Address, key: &H256) -> H256 { + self.db_origin.get(address).map_or(H256::zero(), |v| { + v.storage.get(key).map_or(H256::zero(), |&v| v) + }) + } + + fn set_storage_origin(&mut self, address: &Address, key: H256, value: H256) { + self.db_origin + .entry(*address) + .or_insert_with(Account::default) + .storage + .insert(key, value); + } + + fn selfdestruct(&mut self, address: &Address, _: &Address) -> bool { + self.db.remove(address); + true + } + + fn sha3(&self, _data: &[u8]) -> H256 { + unimplemented!() + } + + fn is_empty(&self, address: &Address) -> bool { + match self.db.get(address) { + Some(account) => { + account.balance == U256::zero() + && account.code.is_empty() + && account.nonce == U256::zero() + } + None => true, + } + } + + fn exist(&self, address: &Address) -> bool { + self.db.get(address).is_some() + } + + fn call( + &self, + opcode: OpCode, + params: InterpreterParams, + ) -> (Result) { + match opcode { + OpCode::CALL => { + let mut it = Interpreter::new( + Context::default(), + InterpreterConf::default(), + Box::new(DataProviderMock::default()), + params, + ); + let mut data_provider = DataProviderMock::default(); + data_provider.db = self.db.clone(); + it.data_provider = Box::new(data_provider); + it.run() + } + _ => unimplemented!(), + } + } +} diff --git a/cita-executor/core/src/tests/grpc_test.rs b/cita-executor/core/src/tests/grpc_test.rs deleted file mode 100644 index 90d04fafc..000000000 --- a/cita-executor/core/src/tests/grpc_test.rs +++ /dev/null @@ -1,191 +0,0 @@ -// CITA -// Copyright 2016-2019 Cryptape Technologies LLC. - -// This program is free software: you can redistribute it -// and/or modify it under the terms of the GNU 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 General Public License for more details. - -// You should have received a copy of the GNU General Public License -// along with this program. If not, see . - -use super::helpers::*; -use crate::contracts::{ - grpc::{ - contract::{contract_creation_address, low_contract_address}, - service_registry, - }, - native::factory::Factory as NativeFactory, -}; -use crate::engines::NullEngine; -use crate::executive::Executive; -use crate::libexecutor::economical_model::EconomicalModel; -use crate::state::Substate; -use crate::trace::{ExecutiveTracer, ExecutiveVMTracer}; -use cita_types::{Address, U256}; -use evm; -use evm::action_params::{ActionParams, ActionValue}; -use evm::env_info::EnvInfo; -use evm::{Factory, VMType}; -use util::BytesRef; - -mod grpc_service { - //use contracts::permission_management::contains_resource; - use grpc::{RequestOptions, Server, ServerBuilder, SingleResponse}; - use libproto::citacode::{InvokeRequest, InvokeResponse}; - use libproto::citacode_grpc::{ - CitacodeService as GRPCVMService, CitacodeServiceClient as GRPCVMServiceClient, - CitacodeServiceServer as GRPCVMServiceServer, - }; - use std::str; - use std::sync::{Arc, Mutex}; - - pub struct GRPCVMServiceImpl { - init_count: Arc>, - } - - impl GRPCVMService for GRPCVMServiceImpl { - fn init(&self, _o: RequestOptions, _p: InvokeRequest) -> SingleResponse { - let mut count = self.init_count.lock().unwrap(); - *count += 1; - let mut response = InvokeResponse::new(); - response.set_message((*count).to_string()); - SingleResponse::completed(response) - } - - fn invoke(&self, _o: RequestOptions, p: InvokeRequest) -> SingleResponse { - let param = p.param.into_option().unwrap(); - let command = str::from_utf8(&(param.data)).unwrap(); - let return_value: String = match command { - "inc" => { - let mut count = self.init_count.lock().unwrap(); - *count += 1; - (*count).to_string() - } - "count" => { - let count = self.init_count.lock().unwrap(); - (*count).to_string() - } - "hello" => "hello".to_string(), - _ => { - error!("unknown request {:}", command); - "".to_string() - } - }; - let mut response = InvokeResponse::new(); - response.set_message(return_value); - SingleResponse::completed(response) - } - } - - impl GRPCVMServiceImpl { - pub fn new() -> Self { - GRPCVMServiceImpl { - init_count: Arc::new(Mutex::new(0)), - } - } - } - - pub fn vm_grpc_server(port: u16) -> Option { - let mut server = ServerBuilder::new_plain(); - server.http.set_port(port); - server.add_service(GRPCVMServiceServer::new_service_def( - GRPCVMServiceImpl::new(), - )); - // server.http.set_cpu_pool_threads(1); - match server.build() { - Ok(server) => Some(server), - Err(_) => None, - } - } - - pub fn vm_grpc_client(port: u16) -> GRPCVMServiceClient { - let client_conf = Default::default(); - GRPCVMServiceClient::new_plain("::1", port, client_conf).unwrap() - } -} - -fn call_vm(params: ActionParams) -> evm::Result { - let factory = Factory::new(VMType::Interpreter, 1024 * 32); - let native_factory = NativeFactory::default(); - let mut tracer = ExecutiveTracer::default(); - let mut vm_tracer = ExecutiveVMTracer::toplevel(); - - let mut state = get_temp_state(); - let info = EnvInfo::default(); - let engine = NullEngine::default(); - let mut substate = Substate::new(); - let mut ex = Executive::new( - &mut state, - &info, - &engine, - &factory, - &native_factory, - false, - EconomicalModel::Quota, - 0, - ); - let mut out = vec![]; - ex.call( - ¶ms, - &mut substate, - BytesRef::Fixed(&mut out), - &mut tracer, - &mut vm_tracer, - ) -} - -#[test] -fn call_grpc_contract() { - let server = grpc_service::vm_grpc_server(0).unwrap(); - let port = server.local_addr().port().unwrap(); - let _client = grpc_service::vm_grpc_client(port); - let sender = Address::default(); - let address: Address = low_contract_address(); - let ip = "127.0.0.1"; - let height = 0; - // register GRPC contract - service_registry::register_contract(address, ip, port, height); - assert!(service_registry::find_contract(address, true).is_none()); - // enable GRPC contract - let mut params = ActionParams::default(); - params.address = contract_creation_address(); - params.code_address = contract_creation_address(); - params.sender = sender.clone(); - params.origin = sender.clone(); - params.gas = U256::from(10000); - params.value = ActionValue::Apparent(0.into()); - params.data = Some(address.to_vec()); - let _ = call_vm(params); - assert!(service_registry::find_contract(address, true).is_some()); - // check count value - let mut basic_params = ActionParams::default(); - basic_params.address = address; - basic_params.code_address = address; - basic_params.sender = sender.clone(); - basic_params.origin = sender.clone(); - basic_params.gas = U256::from(10000); - basic_params.value = ActionValue::Apparent(0.into()); - - let mut params = basic_params.clone(); - params.data = Some("count".as_bytes().to_vec()); - let result = call_vm(params); - let value: u32 = String::from_utf8_lossy(&result.unwrap().return_data) - .parse() - .unwrap(); - assert_eq!(value, 1); - // call it again - let mut params = basic_params.clone(); - params.data = Some("inc".as_bytes().to_vec()); - let result = call_vm(params); - let value: u32 = String::from_utf8_lossy(&result.unwrap().return_data) - .parse() - .unwrap(); - assert_eq!(value, 2); -} diff --git a/cita-executor/core/src/tests/helpers.rs b/cita-executor/core/src/tests/helpers.rs index becc834a4..32da9e349 100644 --- a/cita-executor/core/src/tests/helpers.rs +++ b/cita-executor/core/src/tests/helpers.rs @@ -1,68 +1,51 @@ -// CITA -// Copyright 2016-2018 Cryptape Technologies LLC. - -// This program is free software: you can redistribute it -// and/or modify it under the terms of the GNU 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 General Public License for more details. - -// You should have received a copy of the GNU General Public License -// along with this program. If not, see . +// Copyrighttape Technologies LLC. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. extern crate rustc_serialize; extern crate tempdir; +use std::env; +use std::fs::File; +use std::io::Read; +use std::io::Write; +use std::path::Path; +use std::process::Command; +use std::sync::Arc; +use std::time::UNIX_EPOCH; + use self::rustc_serialize::hex::FromHex; use self::tempdir::TempDir; -use crate::cita_db::kvdb::{self, Database, DatabaseConfig}; -use crate::cita_db::KeyValueDB; -use crate::db; -use crate::journaldb; + use crate::libexecutor::block::{BlockBody, ClosedBlock, OpenBlock}; use crate::libexecutor::command; use crate::libexecutor::executor::Executor; -use crate::state::State; -use crate::state_db::*; use crate::types::header::OpenHeader; use crate::types::transaction::SignedTransaction; + use cita_crypto::PrivKey; use cita_types::traits::LowerHex; use cita_types::{Address, U256}; -use core::libchain::chain; +use cita_vm::{state::MemoryDB, state::State}; use crossbeam_channel::{Receiver, Sender}; use libproto::blockchain; -use std::env; -use std::fs::File; -use std::io::Read; -use std::io::Write; -use std::path::Path; -use std::process::Command; -use std::sync::Arc; -use std::time::UNIX_EPOCH; use util::AsMillis; -const CHAIN_CONFIG: &str = "chain.toml"; const SCRIPTS_DIR: &str = "../../scripts"; -pub fn get_temp_state() -> State { - let state_db = get_temp_state_db(); - State::new(state_db, 0.into(), Default::default()) -} - -fn new_db() -> Arc { - Arc::new(kvdb::in_memory(8)) -} - -pub fn get_temp_state_db() -> StateDB { - let db = new_db(); - let journal_db = journaldb::new(db, journaldb::Algorithm::Archive, crate::db::COL_STATE); - StateDB::new(journal_db, 5 * 1024 * 1024) +pub fn get_temp_state() -> State { + let db = Arc::new(MemoryDB::new(false)); + State::new(db).unwrap() } pub fn solc(name: &str, source: &str) -> (Vec, Vec) { @@ -133,8 +116,6 @@ pub fn init_executor2( env::set_var("DATA_PATH", data_path); let executor = Executor::init( genesis_path.to_str().unwrap(), - "archive", - 5 * 1024 * 1024, tempdir.to_str().unwrap().to_string(), fsm_req_receiver, fsm_resp_sender, @@ -145,14 +126,6 @@ pub fn init_executor2( executor } -pub fn init_chain() -> Arc { - let tempdir = TempDir::new("solc_output").unwrap().into_path(); - let config = DatabaseConfig::with_columns(db::NUM_COLUMNS); - let db = Database::open(&config, &tempdir.to_str().unwrap()).unwrap(); - let chain_config = chain::Config::new(CHAIN_CONFIG); - Arc::new(chain::Chain::init_chain(Arc::new(db), &chain_config)) -} - pub fn create_block( executor: &Executor, to: Address, @@ -220,7 +193,6 @@ pub fn generate_block_header() -> OpenHeader { pub fn generate_block_body() -> BlockBody { let mut stx = SignedTransaction::default(); - use crate::types::transaction::SignedTransaction; stx.data = vec![1; 200]; let transactions = vec![stx; 200]; BlockBody { transactions } diff --git a/cita-executor/core/src/tests/mod.rs b/cita-executor/core/src/tests/mod.rs index bec6ef0ef..4a6e64ccc 100644 --- a/cita-executor/core/src/tests/mod.rs +++ b/cita-executor/core/src/tests/mod.rs @@ -1,20 +1,17 @@ -// CITA -// Copyright 2016-2017 Cryptape Technologies LLC. - -// This program is free software: you can redistribute it -// and/or modify it under the terms of the GNU 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 General Public License for more details. - -// You should have received a copy of the GNU General Public License -// along with this program. If not, see . +// Copyright Cryptape Technologies LLC. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. pub mod amend_data_test; -pub mod grpc_test; +pub mod exemock; pub mod helpers; diff --git a/cita-executor/core/src/trace/config.rs b/cita-executor/core/src/trace/config.rs deleted file mode 100644 index f7252adbe..000000000 --- a/cita-executor/core/src/trace/config.rs +++ /dev/null @@ -1,47 +0,0 @@ -// Copyright 2015-2017 Parity Technologies (UK) Ltd. -// This file is part of Parity. - -// This software is free software: you can redistribute it and/or modify -// it under the terms of the GNU General Public License as published by -// the Free Software Foundation, either version 3 of the License, or -// (at your option) any later version. - -// This software 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 General Public License for more details. - -// You should have received a copy of the GNU General Public License -// along with Parity. If not, see . - -//! Traces config. - -use crate::bloomchain::Config as BloomConfig; - -/// Traces config. -#[derive(Debug, PartialEq, Clone, Copy)] -pub struct Config { - /// Indicates if tracing should be enabled or not. - /// If it's None, it will be automatically configured. - pub enabled: bool, - /// Traces blooms configuration. - pub blooms: BloomConfig, - /// Preferef cache-size. - pub pref_cache_size: usize, - /// Max cache-size. - pub max_cache_size: usize, -} - -impl Default for Config { - fn default() -> Self { - Config { - enabled: false, - blooms: BloomConfig { - levels: 3, - elements_per_index: 16, - }, - pref_cache_size: 15 * 1024 * 1024, - max_cache_size: 20 * 1024 * 1024, - } - } -} diff --git a/cita-executor/core/src/trace/db.rs b/cita-executor/core/src/trace/db.rs deleted file mode 100644 index 0dfda5f5d..000000000 --- a/cita-executor/core/src/trace/db.rs +++ /dev/null @@ -1,847 +0,0 @@ -// Copyright 2015-2017 Parity Technologies (UK) Ltd. -// This file is part of Parity. - -// This software is free software: you can redistribute it and/or modify -// it under the terms of the GNU General Public License as published by -// the Free Software Foundation, either version 3 of the License, or -// (at your option) any later version. - -// This software 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 General Public License for more details. - -// You should have received a copy of the GNU General Public License -// along with Parity. If not, see . - -//! Trace database. - -use super::flat::{FlatBlockTraces, FlatTrace, FlatTransactionTraces}; -use crate::bloomchain::group::{BloomGroup, BloomGroupChain, BloomGroupDatabase, GroupPosition}; -use crate::bloomchain::{Bloom, Config as BloomChainConfig, Number as BloomChainNumber}; -use crate::cache_manager::CacheManager; -use crate::cita_db::{DBTransaction, KeyValueDB}; -use crate::db::{self, CacheUpdatePolicy, Key, Readable, Writable}; -use crate::header::BlockNumber; -use crate::log_blooms::LogBloomGroup; -use crate::trace::{ - Config, Database as TraceDatabase, DatabaseExtras, Filter, ImportRequest, LocalizedTrace, -}; -use cita_types::{H256, H264}; -use std::collections::{HashMap, VecDeque}; -use std::ops::Deref; -use std::sync::Arc; -use util::{HeapSizeOf, RwLock}; - -const TRACE_DB_VER: &[u8] = b"1.0"; - -#[derive(Debug, Copy, Clone)] -enum TraceDBIndex { - /// Block traces index. - BlockTraces = 0, - /// Trace bloom group index. - BloomGroups = 1, -} - -impl Key for H256 { - type Target = H264; - - fn key(&self) -> H264 { - let mut result = H264::default(); - result[0] = TraceDBIndex::BlockTraces as u8; - result[1..33].copy_from_slice(self); - result - } -} - -/// Wrapper around `GroupPosition` so it could be -/// uniquely identified in the database. -#[derive(Debug, PartialEq, Eq, Hash, Clone)] -struct TraceGroupPosition(GroupPosition); - -impl From for TraceGroupPosition { - fn from(position: GroupPosition) -> Self { - TraceGroupPosition(position) - } -} - -impl HeapSizeOf for TraceGroupPosition { - fn heap_size_of_children(&self) -> usize { - 0 - } -} - -/// Helper data structure created cause [u8; 6] does not implement Deref to &[u8]. -pub struct TraceGroupKey([u8; 6]); - -impl Deref for TraceGroupKey { - type Target = [u8]; - - fn deref(&self) -> &Self::Target { - &self.0 - } -} - -impl Key for TraceGroupPosition { - type Target = TraceGroupKey; - - fn key(&self) -> Self::Target { - let mut result = [0u8; 6]; - result[0] = TraceDBIndex::BloomGroups as u8; - result[1] = self.0.level as u8; - result[2] = self.0.index as u8; - result[3] = (self.0.index >> 8) as u8; - result[4] = (self.0.index >> 16) as u8; - result[5] = (self.0.index >> 24) as u8; - TraceGroupKey(result) - } -} - -#[derive(Debug, Hash, Eq, PartialEq)] -enum CacheId { - Trace(H256), - Bloom(TraceGroupPosition), -} - -/// Trace database. -pub struct TraceDB -where - T: DatabaseExtras, -{ - // cache - traces: RwLock>, - blooms: RwLock>, - cache_manager: RwLock>, - // db - tracesdb: Arc, - // config, - bloom_config: BloomChainConfig, - // tracing enabled - enabled: bool, - // extras - extras: Arc, -} - -impl BloomGroupDatabase for TraceDB -where - T: DatabaseExtras, -{ - fn blooms_at(&self, position: &GroupPosition) -> Option { - let position = TraceGroupPosition::from(position.clone()); - let result = self - .tracesdb - .read_with_cache(db::COL_TRACE, &self.blooms, &position) - .map(Into::into); - self.note_used(CacheId::Bloom(position)); - result - } -} - -impl TraceDB -where - T: DatabaseExtras, -{ - /// Creates new instance of `TraceDB`. - pub fn new(config: &Config, tracesdb: Arc, extras: Arc) -> Self { - let mut batch = DBTransaction::new(); - let genesis = extras - .block_hash(0) - .expect("Genesis block is always inserted upon extras db creation qed"); - batch.write(db::COL_TRACE, &genesis, &FlatBlockTraces::default()); - batch.put(db::COL_TRACE, b"version", TRACE_DB_VER); - tracesdb.write(batch).expect("failed to update version"); - - TraceDB { - traces: RwLock::new(HashMap::new()), - blooms: RwLock::new(HashMap::new()), - cache_manager: RwLock::new(CacheManager::new( - config.pref_cache_size, - config.max_cache_size, - 10 * 1024, - )), - tracesdb, - bloom_config: config.blooms, - enabled: config.enabled, - extras, - } - } - - fn cache_size(&self) -> usize { - let traces = self.traces.read().heap_size_of_children(); - let blooms = self.blooms.read().heap_size_of_children(); - traces + blooms - } - - /// Let the cache system know that a cacheable item has been used. - fn note_used(&self, id: CacheId) { - let mut cache_manager = self.cache_manager.write(); - cache_manager.note_used(id); - } - - /// Ticks our cache system and throws out any old data. - pub fn collect_garbage(&self) { - let current_size = self.cache_size(); - - let mut traces = self.traces.write(); - let mut blooms = self.blooms.write(); - let mut cache_manager = self.cache_manager.write(); - - cache_manager.collect_garbage(current_size, |ids| { - for id in &ids { - match *id { - CacheId::Trace(ref h) => { - traces.remove(h); - } - CacheId::Bloom(ref h) => { - blooms.remove(h); - } - } - } - traces.shrink_to_fit(); - blooms.shrink_to_fit(); - - traces.heap_size_of_children() + blooms.heap_size_of_children() - }); - } - - /// Returns traces for block with hash. - fn traces(&self, block_hash: &H256) -> Option { - let result = self - .tracesdb - .read_with_cache(db::COL_TRACE, &self.traces, block_hash); - self.note_used(CacheId::Trace(*block_hash)); - result - } - - /// Returns vector of transaction traces for given block. - fn transactions_traces(&self, block_hash: &H256) -> Option> { - self.traces(block_hash).map(Into::into) - } - - fn matching_block_traces( - &self, - filter: &Filter, - traces: FlatBlockTraces, - block_hash: H256, - block_number: BlockNumber, - ) -> Vec { - let tx_traces: Vec = traces.into(); - tx_traces - .into_iter() - .enumerate() - .flat_map(|(tx_number, tx_trace)| { - self.matching_transaction_traces( - filter, - tx_trace, - block_hash, - block_number, - tx_number, - ) - }) - .collect() - } - - fn matching_transaction_traces( - &self, - filter: &Filter, - traces: FlatTransactionTraces, - block_hash: H256, - block_number: BlockNumber, - tx_number: usize, - ) -> Vec { - let tx_hash = self - .extras - .transaction_hash(block_number, tx_number) - .expect("Expected to find transaction hash. Database is probably corrupted"); - - let flat_traces: Vec = traces.into(); - flat_traces - .into_iter() - .filter_map(|trace| { - if filter.matches(&trace) { - Some(LocalizedTrace { - action: trace.action, - result: trace.result, - subtraces: trace.subtraces, - trace_address: trace.trace_address.into_iter().collect(), - transaction_number: tx_number, - transaction_hash: tx_hash, - block_number, - block_hash, - }) - } else { - None - } - }) - .collect() - } -} - -impl TraceDatabase for TraceDB -where - T: DatabaseExtras, -{ - fn tracing_enabled(&self) -> bool { - self.enabled - } - - /// Traces of import request's enacted blocks are expected to be already in database - /// or to be the currently inserted trace. - fn import(&self, batch: &mut DBTransaction, request: ImportRequest) { - // valid (canon): retracted 0, enacted 1 => false, true, - // valid (branch): retracted 0, enacted 0 => false, false, - // valid (bbcc): retracted 1, enacted 1 => true, true, - // invalid: retracted 1, enacted 0 => true, false, - let ret = request.retracted != 0; - let ena = !request.enacted.is_empty(); - assert!(!(ret && !ena)); - // fast return if tracing is disabled - if !self.tracing_enabled() { - return; - } - - // now let's rebuild the blooms - if !request.enacted.is_empty() { - let range_start = request.block_number as BloomChainNumber + 1 - request.enacted.len(); - let range_end = range_start + request.retracted; - let replaced_range = range_start..range_end; - let enacted_blooms = request - .enacted - .iter() - // all traces are expected to be found here. That's why `expect` has been used - // instead of `filter_map`. If some traces haven't been found, it meens that - // traces database is corrupted or incomplete. - .map(|block_hash| { - if block_hash == &request.block_hash { - request.traces.bloom() - } else { - self.traces(block_hash) - .expect("Traces database is incomplete.") - .bloom() - } - }) - .map(|x| Bloom::from(Into::<[u8; 256]>::into(x))) - .collect(); - - let chain = BloomGroupChain::new(self.bloom_config, self); - let trace_blooms = chain.replace(&replaced_range, enacted_blooms); - let blooms_to_insert = trace_blooms - .into_iter() - .map(|p| (From::from(p.0), From::from(p.1))) - .collect::>(); - - let blooms_keys: Vec<_> = blooms_to_insert.keys().cloned().collect(); - let mut blooms = self.blooms.write(); - batch.extend_with_cache( - db::COL_TRACE, - &mut *blooms, - blooms_to_insert, - CacheUpdatePolicy::Remove, - ); - // note_used must be called after locking blooms to avoid cache/traces deadlock on garbage collection - for key in blooms_keys { - self.note_used(CacheId::Bloom(key)); - } - } - - // insert new block traces into the cache and the database - { - let mut traces = self.traces.write(); - // it's important to use overwrite here, - // cause this value might be queried by hash later - batch.write_with_cache( - db::COL_TRACE, - &mut *traces, - request.block_hash, - request.traces, - CacheUpdatePolicy::Overwrite, - ); - // note_used must be called after locking traces to avoid cache/traces deadlock on garbage collection - self.note_used(CacheId::Trace(request.block_hash)); - } - } - - fn trace( - &self, - block_number: BlockNumber, - tx_position: usize, - trace_position: Vec, - ) -> Option { - let trace_position_deq = VecDeque::from(trace_position); - self.extras.block_hash(block_number).and_then(|block_hash| { - self.transactions_traces(&block_hash) - .and_then(|traces| traces.into_iter().nth(tx_position)) - .map(Into::>::into) - // this may and should be optimized - .and_then(|traces| { - traces - .into_iter() - .find(|trace| trace.trace_address == trace_position_deq) - }) - .map(|trace| { - let tx_hash = self - .extras - .transaction_hash(block_number, tx_position) - .expect( - "Expected to find transaction hash. Database is probably corrupted", - ); - - LocalizedTrace { - action: trace.action, - result: trace.result, - subtraces: trace.subtraces, - trace_address: trace.trace_address.into_iter().collect(), - transaction_number: tx_position, - transaction_hash: tx_hash, - block_number, - block_hash, - } - }) - }) - } - - fn transaction_traces( - &self, - block_number: BlockNumber, - tx_position: usize, - ) -> Option> { - self.extras.block_hash(block_number).and_then(|block_hash| { - self.transactions_traces(&block_hash) - .and_then(|traces| traces.into_iter().nth(tx_position)) - .map(Into::>::into) - .map(|traces| { - let tx_hash = self - .extras - .transaction_hash(block_number, tx_position) - .expect( - "Expected to find transaction hash. Database is probably corrupted", - ); - - traces - .into_iter() - .map(|trace| LocalizedTrace { - action: trace.action, - result: trace.result, - subtraces: trace.subtraces, - trace_address: trace.trace_address.into_iter().collect(), - transaction_number: tx_position, - transaction_hash: tx_hash, - block_number, - block_hash, - }) - .collect() - }) - }) - } - - fn block_traces(&self, block_number: BlockNumber) -> Option> { - self.extras.block_hash(block_number).and_then(|block_hash| { - self.transactions_traces(&block_hash).map(|traces| { - traces - .into_iter() - .map(Into::>::into) - .enumerate() - .flat_map(|(tx_position, traces)| { - let tx_hash = self - .extras - .transaction_hash(block_number, tx_position) - .expect( - "Expected to find transaction hash. Database is probably corrupted", - ); - - traces - .into_iter() - .map(|trace| LocalizedTrace { - action: trace.action, - result: trace.result, - subtraces: trace.subtraces, - trace_address: trace.trace_address.into_iter().collect(), - transaction_number: tx_position, - transaction_hash: tx_hash, - block_number, - block_hash, - }) - .collect::>() - }) - .collect::>() - }) - }) - } - - fn filter(&self, filter: &Filter) -> Vec { - let chain = BloomGroupChain::new(self.bloom_config, self); - let numbers = chain.filter(filter); - numbers - .into_iter() - .flat_map(|n| { - let number = n as BlockNumber; - let hash = self - .extras - .block_hash(number) - .expect("Expected to find block hash. Extras db is probably corrupted"); - let traces = self - .traces(&hash) - .expect("Expected to find a trace. Db is probably corrupted."); - self.matching_block_traces(filter, traces, hash, number) - }) - .collect() - } -} - -#[cfg(test)] -mod tests { - use crate::cita_db::{kvdb, DBTransaction, KeyValueDB}; - use crate::header::BlockNumber; - use crate::trace::flat::{FlatBlockTraces, FlatTrace, FlatTransactionTraces}; - use crate::trace::trace::{Action, Call, Res}; - use crate::trace::{AddressesFilter, Filter, LocalizedTrace, TraceError}; - use crate::trace::{Config, Database as TraceDatabase, DatabaseExtras, ImportRequest, TraceDB}; - use cita_types::{Address, H256, U256}; - use evm::call_type::CallType; - use std::collections::HashMap; - use std::sync::Arc; - - struct NoopExtras; - - impl DatabaseExtras for NoopExtras { - fn block_hash(&self, block_number: BlockNumber) -> Option { - if block_number == 0 { - Some(H256::default()) - } else { - unimplemented!() - } - } - - fn transaction_hash( - &self, - _block_number: BlockNumber, - _tx_position: usize, - ) -> Option { - unimplemented!(); - } - } - - #[derive(Clone)] - struct Extras { - block_hashes: HashMap, - transaction_hashes: HashMap>, - } - - impl Default for Extras { - fn default() -> Self { - Extras { - block_hashes: HashMap::new(), - transaction_hashes: HashMap::new(), - } - } - } - - impl DatabaseExtras for Extras { - fn block_hash(&self, block_number: BlockNumber) -> Option { - self.block_hashes.get(&block_number).cloned() - } - - fn transaction_hash(&self, block_number: BlockNumber, tx_position: usize) -> Option { - self.transaction_hashes - .get(&block_number) - .and_then(|hashes| hashes.iter().cloned().nth(tx_position)) - } - } - - fn new_db() -> Arc { - Arc::new(kvdb::in_memory(crate::db::NUM_COLUMNS.unwrap_or(0))) - } - - #[test] - fn test_reopening_db_with_tracing_off() { - let db = new_db(); - let mut config = Config::default(); - - // set autotracing - config.enabled = false; - - { - let tracedb = TraceDB::new(&config, db.clone(), Arc::new(NoopExtras)); - assert_eq!(tracedb.tracing_enabled(), false); - } - } - - #[test] - fn test_reopening_db_with_tracing_on() { - let db = new_db(); - let mut config = Config::default(); - - // set tracing on - config.enabled = true; - - { - let tracedb = TraceDB::new(&config, db.clone(), Arc::new(NoopExtras)); - assert_eq!(tracedb.tracing_enabled(), true); - } - } - - fn create_simple_import_request(block_number: BlockNumber, block_hash: H256) -> ImportRequest { - ImportRequest { - traces: FlatBlockTraces::from(vec![FlatTransactionTraces::from(vec![FlatTrace { - trace_address: Default::default(), - subtraces: 0, - action: Action::Call(Call { - from: 1.into(), - to: 2.into(), - value: 3.into(), - gas: 4.into(), - input: vec![], - call_type: CallType::Call, - }), - result: Res::FailedCall(TraceError::OutOfGas), - }])]), - block_hash: block_hash.clone(), - block_number, - enacted: vec![block_hash], - retracted: 0, - } - } - - fn create_noncanon_import_request( - block_number: BlockNumber, - block_hash: H256, - ) -> ImportRequest { - ImportRequest { - traces: FlatBlockTraces::from(vec![FlatTransactionTraces::from(vec![FlatTrace { - trace_address: Default::default(), - subtraces: 0, - action: Action::Call(Call { - from: 1.into(), - to: 2.into(), - value: 3.into(), - gas: 4.into(), - input: vec![], - call_type: CallType::Call, - }), - result: Res::FailedCall(TraceError::OutOfGas), - }])]), - block_hash: block_hash.clone(), - block_number, - enacted: vec![], - retracted: 0, - } - } - - fn create_simple_localized_trace( - block_number: BlockNumber, - block_hash: H256, - tx_hash: H256, - ) -> LocalizedTrace { - LocalizedTrace { - action: Action::Call(Call { - from: Address::from(1), - to: Address::from(2), - value: U256::from(3), - gas: U256::from(4), - input: vec![], - call_type: CallType::Call, - }), - result: Res::FailedCall(TraceError::OutOfGas), - trace_address: vec![], - subtraces: 0, - transaction_number: 0, - transaction_hash: tx_hash, - block_number, - block_hash, - } - } - - #[test] - fn test_import_non_canon_traces() { - let db = new_db(); - let mut config = Config::default(); - config.enabled = true; - let block_0 = H256::from(0xa1); - let block_1 = H256::from(0xa2); - let tx_0 = H256::from(0xff); - let tx_1 = H256::from(0xaf); - - let mut extras = Extras::default(); - extras.block_hashes.insert(0, block_0.clone()); - extras.block_hashes.insert(1, block_1.clone()); - extras.transaction_hashes.insert(0, vec![tx_0.clone()]); - extras.transaction_hashes.insert(1, vec![tx_1.clone()]); - - let tracedb = TraceDB::new(&config, db.clone(), Arc::new(extras)); - - // import block 0 - let request = create_noncanon_import_request(0, block_0.clone()); - let mut batch = DBTransaction::new(); - tracedb.import(&mut batch, request); - db.write(batch).unwrap(); - - assert!( - tracedb.traces(&block_0).is_some(), - "Traces should be available even if block is non-canon." - ); - } - - #[test] - fn test_import() { - let db = new_db(); - let mut config = Config::default(); - config.enabled = true; - let block_1 = H256::from(0xa1); - let block_2 = H256::from(0xa2); - let tx_1 = H256::from(0xff); - let tx_2 = H256::from(0xaf); - - let mut extras = Extras::default(); - extras.block_hashes.insert(0, H256::default()); - - extras.block_hashes.insert(1, block_1.clone()); - extras.block_hashes.insert(2, block_2.clone()); - extras.transaction_hashes.insert(1, vec![tx_1.clone()]); - extras.transaction_hashes.insert(2, vec![tx_2.clone()]); - - let tracedb = TraceDB::new(&config, db.clone(), Arc::new(extras)); - - // import block 1 - let request = create_simple_import_request(1, block_1.clone()); - let mut batch = DBTransaction::new(); - tracedb.import(&mut batch, request); - db.write(batch).unwrap(); - - let filter = Filter { - range: (1..1), - from_address: AddressesFilter::from(vec![Address::from(1)]), - to_address: AddressesFilter::from(vec![]), - }; - - let traces = tracedb.filter(&filter); - assert_eq!(traces.len(), 1); - assert_eq!( - traces[0], - create_simple_localized_trace(1, block_1.clone(), tx_1.clone()) - ); - - // import block 2 - let request = create_simple_import_request(2, block_2.clone()); - let mut batch = DBTransaction::new(); - tracedb.import(&mut batch, request); - db.write(batch).unwrap(); - - let filter = Filter { - range: (1..2), - from_address: AddressesFilter::from(vec![Address::from(1)]), - to_address: AddressesFilter::from(vec![]), - }; - - let traces = tracedb.filter(&filter); - assert_eq!(traces.len(), 2); - assert_eq!( - traces[0], - create_simple_localized_trace(1, block_1.clone(), tx_1.clone()) - ); - assert_eq!( - traces[1], - create_simple_localized_trace(2, block_2.clone(), tx_2.clone()) - ); - - assert!( - tracedb.block_traces(0).is_some(), - "Genesis trace should be always present." - ); - - let traces = tracedb.block_traces(1).unwrap(); - assert_eq!(traces.len(), 1); - assert_eq!( - traces[0], - create_simple_localized_trace(1, block_1.clone(), tx_1.clone()) - ); - - let traces = tracedb.block_traces(2).unwrap(); - assert_eq!(traces.len(), 1); - assert_eq!( - traces[0], - create_simple_localized_trace(2, block_2.clone(), tx_2.clone()) - ); - - assert_eq!(None, tracedb.block_traces(3)); - - let traces = tracedb.transaction_traces(1, 0).unwrap(); - assert_eq!(traces.len(), 1); - assert_eq!( - traces[0], - create_simple_localized_trace(1, block_1.clone(), tx_1.clone()) - ); - - let traces = tracedb.transaction_traces(2, 0).unwrap(); - assert_eq!(traces.len(), 1); - assert_eq!( - traces[0], - create_simple_localized_trace(2, block_2.clone(), tx_2.clone()) - ); - - assert_eq!(None, tracedb.transaction_traces(2, 1)); - - assert_eq!( - tracedb.trace(1, 0, vec![]).unwrap(), - create_simple_localized_trace(1, block_1.clone(), tx_1.clone()) - ); - assert_eq!( - tracedb.trace(2, 0, vec![]).unwrap(), - create_simple_localized_trace(2, block_2.clone(), tx_2.clone()) - ); - } - - #[test] - fn query_trace_after_reopen() { - let db = new_db(); - let mut config = Config::default(); - let mut extras = Extras::default(); - let block_0 = H256::from(0xa1); - let tx_0 = H256::from(0xff); - - extras.block_hashes.insert(0, H256::default()); - extras.transaction_hashes.insert(0, vec![]); - extras.block_hashes.insert(1, block_0.clone()); - extras.transaction_hashes.insert(1, vec![tx_0.clone()]); - - // set tracing on - config.enabled = true; - - { - let tracedb = TraceDB::new(&config, db.clone(), Arc::new(extras.clone())); - - // import block 1 - let request = create_simple_import_request(1, block_0.clone()); - let mut batch = DBTransaction::new(); - tracedb.import(&mut batch, request); - db.write(batch).unwrap(); - } - - { - let tracedb = TraceDB::new(&config, db.clone(), Arc::new(extras)); - let traces = tracedb.transaction_traces(1, 0); - assert_eq!( - traces.unwrap(), - vec![create_simple_localized_trace(1, block_0, tx_0)] - ); - } - } - - #[test] - fn query_genesis() { - let db = new_db(); - let mut config = Config::default(); - let mut extras = Extras::default(); - let block_0 = H256::from(0xa1); - - extras.block_hashes.insert(0, block_0.clone()); - extras.transaction_hashes.insert(0, vec![]); - - // set tracing on - config.enabled = true; - - let tracedb = TraceDB::new(&config, db.clone(), Arc::new(extras.clone())); - let traces = tracedb.block_traces(0).unwrap(); - - assert_eq!(traces.len(), 0); - } -} diff --git a/cita-executor/core/src/trace/error.rs b/cita-executor/core/src/trace/error.rs deleted file mode 100644 index 76274fb94..000000000 --- a/cita-executor/core/src/trace/error.rs +++ /dev/null @@ -1,40 +0,0 @@ -// Copyright 2015-2017 Parity Technologies (UK) Ltd. -// This file is part of Parity. - -// This software is free software: you can redistribute it and/or modify -// it under the terms of the GNU General Public License as published by -// the Free Software Foundation, either version 3 of the License, or -// (at your option) any later version. - -// This software 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 General Public License for more details. - -// You should have received a copy of the GNU General Public License -// along with Parity. If not, see . - -//! `TraceDB` errors. - -use std::fmt::{Display, Error as FmtError, Formatter}; - -const RESYNC_ERR: &str = "Your current parity installation has synced without transaction tracing. -To use Parity with transaction tracing, you'll need to resync with tracing. -To do this, remove or move away your current database and restart parity. e.g.: - -> mv ~/.parity/906a34e69aec8c0d /tmp -> parity"; - -/// `TraceDB` errors. -#[derive(Debug)] -pub enum Error { - /// Returned when tracing is enabled, - /// but database does not contain traces of old transactions. - ResyncRequired, -} - -impl Display for Error { - fn fmt(&self, f: &mut Formatter) -> Result<(), FmtError> { - write!(f, "{}", RESYNC_ERR) - } -} diff --git a/cita-executor/core/src/trace/executive_tracer.rs b/cita-executor/core/src/trace/executive_tracer.rs deleted file mode 100644 index 694c48f1a..000000000 --- a/cita-executor/core/src/trace/executive_tracer.rs +++ /dev/null @@ -1,308 +0,0 @@ -// Copyright 2015-2017 Parity Technologies (UK) Ltd. -// This file is part of Parity. - -// This software is free software: you can redistribute it and/or modify -// it under the terms of the GNU General Public License as published by -// the Free Software Foundation, either version 3 of the License, or -// (at your option) any later version. - -// This software 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 General Public License for more details. - -// You should have received a copy of the GNU General Public License -// along with Parity. If not, see . - -//! Simple executive tracer. - -use crate::trace::trace::{ - Action, Call, CallResult, Create, CreateResult, MemoryDiff, Res, StorageDiff, Suicide, - VMExecutedOperation, VMOperation, VMTrace, -}; -use crate::trace::{FlatTrace, TraceError, Tracer, VMTracer}; -use cita_types::{Address, U256}; -use evm::action_params::ActionParams; -use util::Bytes; - -/// Simple executive tracer. Traces all calls and creates. Ignores delegatecalls. -#[derive(Default)] -pub struct ExecutiveTracer { - traces: Vec, -} - -fn top_level_subtraces(traces: &[FlatTrace]) -> usize { - traces.iter().filter(|t| t.trace_address.is_empty()).count() -} - -fn prefix_subtrace_addresses(mut traces: Vec) -> Vec { - // input traces are expected to be ordered like - // [] - // [0] - // [0, 0] - // [0, 1] - // [] - // [0] - // - // so they can be transformed to - // - // [0] - // [0, 0] - // [0, 0, 0] - // [0, 0, 1] - // [1] - // [1, 0] - let mut current_subtrace_index = 0; - let mut first = true; - for trace in &mut traces { - match (first, trace.trace_address.is_empty()) { - (true, _) => first = false, - (_, true) => current_subtrace_index += 1, - _ => {} - } - trace.trace_address.push_front(current_subtrace_index); - } - traces -} - -#[test] -fn should_prefix_address_properly() { - use super::trace::{Action, Res, Suicide}; - - let f = |v: Vec| FlatTrace { - action: Action::Suicide(Suicide { - address: Default::default(), - balance: Default::default(), - refund_address: Default::default(), - }), - result: Res::None, - subtraces: 0, - trace_address: v.into_iter().collect(), - }; - let t = vec![ - vec![], - vec![0], - vec![0, 0], - vec![0], - vec![], - vec![], - vec![0], - vec![], - ] - .into_iter() - .map(&f) - .collect(); - let t = prefix_subtrace_addresses(t); - assert_eq!( - t, - vec![ - vec![0], - vec![0, 0], - vec![0, 0, 0], - vec![0, 0], - vec![1], - vec![2], - vec![2, 0], - vec![3] - ] - .into_iter() - .map(&f) - .collect::>() - ); -} - -impl Tracer for ExecutiveTracer { - fn prepare_trace_call(&self, params: &ActionParams) -> Option { - Some(Call::from(params.clone())) - } - - fn prepare_trace_create(&self, params: &ActionParams) -> Option { - Some(Create::from(params.clone())) - } - - fn prepare_trace_output(&self) -> Option { - Some(vec![]) - } - - fn trace_call( - &mut self, - call: Option, - gas_used: U256, - output: Option, - subs: Vec, - ) { - let trace = FlatTrace { - trace_address: Default::default(), - subtraces: top_level_subtraces(&subs), - action: Action::Call( - call.expect("self.prepare_trace_call().is_some(): so we must be tracing: qed"), - ), - result: Res::Call(CallResult { - gas_used, - output: output - .expect("self.prepare_trace_output().is_some(): so we must be tracing: qed"), - }), - }; - debug!(target: "trace", "Traced call {:?}", trace); - self.traces.push(trace); - self.traces.extend(prefix_subtrace_addresses(subs)); - } - - fn trace_create( - &mut self, - create: Option, - gas_used: U256, - code: Option, - address: Address, - subs: Vec, - ) { - let trace = FlatTrace { - subtraces: top_level_subtraces(&subs), - action: Action::Create( - create.expect("self.prepare_trace_create().is_some(): so we must be tracing: qed"), - ), - result: Res::Create(CreateResult { - gas_used, - code: code - .expect("self.prepare_trace_output.is_some(): so we must be tracing: qed"), - address, - }), - trace_address: Default::default(), - }; - debug!(target: "trace", "Traced create {:?}", trace); - self.traces.push(trace); - self.traces.extend(prefix_subtrace_addresses(subs)); - } - - fn trace_failed_call(&mut self, call: Option, subs: Vec, error: TraceError) { - let trace = FlatTrace { - trace_address: Default::default(), - subtraces: top_level_subtraces(&subs), - action: Action::Call( - call.expect("self.prepare_trace_call().is_some(): so we must be tracing: qed"), - ), - result: Res::FailedCall(error), - }; - debug!(target: "trace", "Traced failed call {:?}", trace); - self.traces.push(trace); - self.traces.extend(prefix_subtrace_addresses(subs)); - } - - fn trace_failed_create( - &mut self, - create: Option, - subs: Vec, - error: TraceError, - ) { - let trace = FlatTrace { - subtraces: top_level_subtraces(&subs), - action: Action::Create( - create.expect("self.prepare_trace_create().is_some(): so we must be tracing: qed"), - ), - result: Res::FailedCreate(error), - trace_address: Default::default(), - }; - debug!(target: "trace", "Traced failed create {:?}", trace); - self.traces.push(trace); - self.traces.extend(prefix_subtrace_addresses(subs)); - } - - fn trace_suicide(&mut self, address: Address, balance: U256, refund_address: Address) { - let trace = FlatTrace { - subtraces: 0, - action: Action::Suicide(Suicide { - address, - refund_address, - balance, - }), - result: Res::None, - trace_address: Default::default(), - }; - debug!(target: "trace", "Traced failed suicide {:?}", trace); - self.traces.push(trace); - } - - fn subtracer(&self) -> Self { - ExecutiveTracer::default() - } - - fn traces(self) -> Vec { - self.traces - } -} - -/// Simple VM tracer. Traces all operations. -pub struct ExecutiveVMTracer { - data: VMTrace, -} - -impl ExecutiveVMTracer { - /// Create a new top-level instance. - pub fn toplevel() -> Self { - ExecutiveVMTracer { - data: VMTrace { - parent_step: 0, - code: vec![], - operations: vec![Default::default()], // prefill with a single entry so that prepare_subtrace can get the parent_step - subs: vec![], - }, - } - } -} - -impl VMTracer for ExecutiveVMTracer { - fn trace_prepare_execute(&mut self, pc: usize, instruction: u8, gas_cost: &U256) -> bool { - self.data.operations.push(VMOperation { - pc, - instruction, - gas_cost: *gas_cost, - executed: None, - }); - true - } - - fn trace_executed( - &mut self, - gas_used: U256, - stack_push: &[U256], - mem_diff: Option<(usize, &[u8])>, - store_diff: Option<(U256, U256)>, - ) { - let ex = VMExecutedOperation { - gas_used, - stack_push: stack_push.to_vec(), - mem_diff: mem_diff.map(|(s, r)| MemoryDiff { - offset: s, - data: r.to_vec(), - }), - store_diff: store_diff.map(|(l, v)| StorageDiff { - location: l, - value: v, - }), - }; - self.data - .operations - .last_mut() - .expect("trace_executed is always called after a trace_prepare_execute") - .executed = Some(ex); - } - - fn prepare_subtrace(&self, code: &[u8]) -> Self { - ExecutiveVMTracer { - data: VMTrace { - parent_step: self.data.operations.len() - 1, // won't overflow since we must already have pushed an operation in trace_prepare_execute. - code: code.to_vec(), - operations: vec![], - subs: vec![], - }, - } - } - - fn done_subtrace(&mut self, sub: Self) { - self.data.subs.push(sub.data); - } - - fn drain(mut self) -> Option { - self.data.subs.pop() - } -} diff --git a/cita-executor/core/src/trace/import.rs b/cita-executor/core/src/trace/import.rs deleted file mode 100644 index d22c91f4f..000000000 --- a/cita-executor/core/src/trace/import.rs +++ /dev/null @@ -1,37 +0,0 @@ -// Copyright 2015-2017 Parity Technologies (UK) Ltd. -// This file is part of Parity. - -// This software is free software: you can redistribute it and/or modify -// it under the terms of the GNU General Public License as published by -// the Free Software Foundation, either version 3 of the License, or -// (at your option) any later version. - -// This software 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 General Public License for more details. - -// You should have received a copy of the GNU General Public License -// along with Parity. If not, see . - -//! Traces import request. - -use crate::header::BlockNumber; -use crate::trace::FlatBlockTraces; -use cita_types::H256; - -/// Traces import request. -pub struct ImportRequest { - /// Traces to import. - pub traces: FlatBlockTraces, - /// Hash of traces block. - pub block_hash: H256, - /// Number of traces block. - pub block_number: BlockNumber, - /// Blocks enacted by this import. - /// - /// They should be ordered from oldest to newest. - pub enacted: Vec, - /// Number of blocks retracted by this import. - pub retracted: usize, -} diff --git a/cita-executor/core/src/trace/mod.rs b/cita-executor/core/src/trace/mod.rs deleted file mode 100644 index 822f04776..000000000 --- a/cita-executor/core/src/trace/mod.rs +++ /dev/null @@ -1,169 +0,0 @@ -// Copyright 2015-2017 Parity Technologies (UK) Ltd. -// This file is part of Parity. - -// This software is free software: you can redistribute it and/or modify -// it under the terms of the GNU General Public License as published by -// the Free Software Foundation, either version 3 of the License, or -// (at your option) any later version. - -// This software 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 General Public License for more details. - -// You should have received a copy of the GNU General Public License -// along with Parity. If not, see . - -//! Tracing - -mod config; -mod db; -mod error; -mod executive_tracer; -mod import; -mod noop_tracer; -mod types; - -pub use self::config::Config; -pub use self::db::TraceDB; -pub use self::error::Error; -pub use self::executive_tracer::{ExecutiveTracer, ExecutiveVMTracer}; -pub use self::import::ImportRequest; -pub use self::localized::LocalizedTrace; -pub use self::noop_tracer::{NoopTracer, NoopVMTracer}; -use self::trace::{Call, Create}; -pub use self::types::error::Error as TraceError; -pub use self::types::filter::{AddressesFilter, Filter}; -pub use self::types::flat::{FlatBlockTraces, FlatTrace, FlatTransactionTraces}; -pub use self::types::trace::{MemoryDiff, StorageDiff, VMExecutedOperation, VMOperation, VMTrace}; -pub use self::types::{filter, flat, localized, trace}; -use crate::cita_db::DBTransaction; -use crate::header::BlockNumber; -use cita_types::{Address, H256, U256}; -use evm::action_params::ActionParams; -use util::Bytes; - -/// This trait is used by executive to build traces. -pub trait Tracer: Send { - /// Prepares call trace for given params. Noop tracer should return None. - fn prepare_trace_call(&self, params: &ActionParams) -> Option; - - /// Prepares create trace for given params. Noop tracer should return None. - fn prepare_trace_create(&self, params: &ActionParams) -> Option; - - /// Prepare trace output. Noop tracer should return None. - fn prepare_trace_output(&self) -> Option; - - /// Stores trace call info. - fn trace_call( - &mut self, - call: Option, - gas_used: U256, - output: Option, - subs: Vec, - ); - - /// Stores trace create info. - fn trace_create( - &mut self, - create: Option, - gas_used: U256, - code: Option, - address: Address, - subs: Vec, - ); - - /// Stores failed call trace. - fn trace_failed_call(&mut self, call: Option, subs: Vec, error: TraceError); - - /// Stores failed create trace. - fn trace_failed_create( - &mut self, - create: Option, - subs: Vec, - error: TraceError, - ); - - /// Stores suicide info. - fn trace_suicide(&mut self, address: Address, balance: U256, refund_address: Address); - - /// Spawn subtracer which will be used to trace deeper levels of execution. - fn subtracer(&self) -> Self - where - Self: Sized; - - /// Consumes self and returns all traces. - fn traces(self) -> Vec; -} - -/// Used by executive to build VM traces. -pub trait VMTracer: Send { - /// Trace the preparation to execute a single instruction. - /// @returns true if `trace_executed` should be called. - fn trace_prepare_execute(&mut self, _pc: usize, _instruction: u8, _gas_cost: &U256) -> bool { - false - } - - /// Trace the finalised execution of a single instruction. - fn trace_executed( - &mut self, - _gas_used: U256, - _stack_push: &[U256], - _mem_diff: Option<(usize, &[u8])>, - _store_diff: Option<(U256, U256)>, - ) { - } - - /// Spawn subtracer which will be used to trace deeper levels of execution. - fn prepare_subtrace(&self, code: &[u8]) -> Self - where - Self: Sized; - - /// Spawn subtracer which will be used to trace deeper levels of execution. - fn done_subtrace(&mut self, sub: Self) - where - Self: Sized; - - /// Consumes self and returns the VM trace. - fn drain(self) -> Option; -} - -/// `DbExtras` provides an interface to query extra data which is not stored in tracesdb, -/// but necessary to work correctly. -pub trait DatabaseExtras { - /// Returns hash of given block number. - fn block_hash(&self, block_number: BlockNumber) -> Option; - - /// Returns hash of transaction at given position. - fn transaction_hash(&self, block_number: BlockNumber, tx_position: usize) -> Option; -} - -/// Db provides an interface to query tracesdb. -pub trait Database { - /// Returns true if tracing is enabled. Otherwise false. - fn tracing_enabled(&self) -> bool; - - /// Imports new block traces. - fn import(&self, batch: &mut DBTransaction, request: ImportRequest); - - /// Returns localized trace at given position. - fn trace( - &self, - block_number: BlockNumber, - tx_position: usize, - trace_position: Vec, - ) -> Option; - - /// Returns localized traces created by a single transaction. - fn transaction_traces( - &self, - block_number: BlockNumber, - tx_position: usize, - ) -> Option>; - - /// Returns localized traces created in given block. - fn block_traces(&self, block_number: BlockNumber) -> Option>; - - /// Filter traces matching given filter. - fn filter(&self, filter: &Filter) -> Vec; -} diff --git a/cita-executor/core/src/trace/noop_tracer.rs b/cita-executor/core/src/trace/noop_tracer.rs deleted file mode 100644 index 70acfcc12..000000000 --- a/cita-executor/core/src/trace/noop_tracer.rs +++ /dev/null @@ -1,132 +0,0 @@ -// Copyright 2015-2017 Parity Technologies (UK) Ltd. -// This file is part of Parity. - -// This software is free software: you can redistribute it and/or modify -// it under the terms of the GNU General Public License as published by -// the Free Software Foundation, either version 3 of the License, or -// (at your option) any later version. - -// This software 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 General Public License for more details. - -// You should have received a copy of the GNU General Public License -// along with Parity. If not, see . - -//! Nonoperative tracer. - -use crate::trace::trace::{Call, Create, VMTrace}; -use crate::trace::{FlatTrace, TraceError, Tracer, VMTracer}; -use cita_types::{Address, U256}; -use evm::action_params::ActionParams; -use util::Bytes; - -/// Nonoperative tracer. Does not trace anything. -pub struct NoopTracer; - -impl Tracer for NoopTracer { - fn prepare_trace_call(&self, _: &ActionParams) -> Option { - None - } - - fn prepare_trace_create(&self, _: &ActionParams) -> Option { - None - } - - fn prepare_trace_output(&self) -> Option { - None - } - - fn trace_call( - &mut self, - call: Option, - _: U256, - output: Option, - _: Vec, - ) { - assert!( - call.is_none(), - "self.prepare_trace_call().is_none(): so we can't be tracing: qed" - ); - assert!( - output.is_none(), - "self.prepare_trace_output().is_none(): so we can't be tracing: qed" - ); - } - - fn trace_create( - &mut self, - create: Option, - _: U256, - code: Option, - _: Address, - _: Vec, - ) { - assert!( - create.is_none(), - "self.prepare_trace_create().is_none(): so we can't be tracing: qed" - ); - assert!( - code.is_none(), - "self.prepare_trace_output().is_none(): so we can't be tracing: qed" - ); - } - - fn trace_failed_call(&mut self, call: Option, _: Vec, _: TraceError) { - assert!( - call.is_none(), - "self.prepare_trace_call().is_none(): so we can't be tracing: qed" - ); - } - - fn trace_failed_create(&mut self, create: Option, _: Vec, _: TraceError) { - assert!( - create.is_none(), - "self.prepare_trace_create().is_none(): so we can't be tracing: qed" - ); - } - - fn trace_suicide(&mut self, _address: Address, _balance: U256, _refund_address: Address) {} - - fn subtracer(&self) -> Self { - NoopTracer - } - - fn traces(self) -> Vec { - vec![] - } -} - -/// Nonoperative VM tracer. Does not trace anything. -pub struct NoopVMTracer; - -impl VMTracer for NoopVMTracer { - /// Trace the preparation to execute a single instruction. - fn trace_prepare_execute(&mut self, _pc: usize, _instruction: u8, _gas_cost: &U256) -> bool { - false - } - - /// Trace the finalised execution of a single instruction. - fn trace_executed( - &mut self, - _gas_used: U256, - _stack_push: &[U256], - _mem_diff: Option<(usize, &[u8])>, - _store_diff: Option<(U256, U256)>, - ) { - } - - /// Spawn subtracer which will be used to trace deeper levels of execution. - fn prepare_subtrace(&self, _code: &[u8]) -> Self { - NoopVMTracer - } - - /// Spawn subtracer which will be used to trace deeper levels of execution. - fn done_subtrace(&mut self, _sub: Self) {} - - /// Consumes self and returns all VM traces. - fn drain(self) -> Option { - None - } -} diff --git a/cita-executor/core/src/trace/types/error.rs b/cita-executor/core/src/trace/types/error.rs deleted file mode 100644 index 4116b8281..000000000 --- a/cita-executor/core/src/trace/types/error.rs +++ /dev/null @@ -1,143 +0,0 @@ -// Copyright 2015-2017 Parity Technologies (UK) Ltd. -// This file is part of Parity. - -// This software is free software: you can redistribute it and/or modify -// it under the terms of the GNU General Public License as published by -// the Free Software Foundation, either version 3 of the License, or -// (at your option) any later version. - -// This software 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 General Public License for more details. - -// You should have received a copy of the GNU General Public License -// along with Parity. If not, see . - -//! Trace errors. - -use evm::Error as EvmError; -use rlp::{Decodable, DecoderError, Encodable, RlpStream, UntrustedRlp}; -use std::fmt; - -/// Trace evm errors. -#[derive(Debug, PartialEq, Clone)] -#[cfg_attr(feature = "ipc", binary)] -pub enum Error { - /// `OutOfGas` is returned when transaction execution runs out of gas. - OutOfGas, - /// `BadJumpDestination` is returned when execution tried to move - /// to position that wasn't marked with JUMPDEST instruction - BadJumpDestination, - /// `BadInstructions` is returned when given instruction is not supported - BadInstruction, - /// `StackUnderflow` when there is not enough stack elements to execute instruction - StackUnderflow, - /// When execution would exceed defined Stack Limit - OutOfStack, - /// Returned on evm internal error. Should never be ignored during development. - /// Likely to cause consensus issues. - Internal, - /// When execution tries to modify the state in static context - MutableCallInStaticContext, - /// Contract tried to access past the return data buffer. - OutOfBounds, - /// Execution has been reverted with REVERT instruction. - Reverted, -} - -impl<'a> From<&'a EvmError> for Error { - fn from(e: &'a EvmError) -> Self { - match *e { - EvmError::OutOfGas => Error::OutOfGas, - EvmError::BadJumpDestination { .. } => Error::BadJumpDestination, - EvmError::BadInstruction { .. } => Error::BadInstruction, - EvmError::StackUnderflow { .. } => Error::StackUnderflow, - EvmError::OutOfStack { .. } => Error::OutOfStack, - EvmError::Internal(_) => Error::Internal, - EvmError::MutableCallInStaticContext => Error::MutableCallInStaticContext, - EvmError::OutOfBounds => Error::OutOfBounds, - EvmError::Reverted => Error::Reverted, - } - } -} - -impl From for Error { - fn from(e: EvmError) -> Self { - Error::from(&e) - } -} - -impl fmt::Display for Error { - fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { - use self::Error::*; - let message = match *self { - OutOfGas => "Out of gas", - BadJumpDestination => "Bad jump destination", - BadInstruction => "Bad instruction", - StackUnderflow => "Stack underflow", - OutOfStack => "Out of stack", - Internal => "Internal error", - MutableCallInStaticContext => "Mutable Call In Static Context", - OutOfBounds => "Out of bounds", - Reverted => "Reverted", - }; - message.fmt(f) - } -} - -impl Encodable for Error { - fn rlp_append(&self, s: &mut RlpStream) { - use self::Error::*; - let value = match *self { - OutOfGas => 0u8, - BadJumpDestination => 1, - BadInstruction => 2, - StackUnderflow => 3, - OutOfStack => 4, - Internal => 5, - MutableCallInStaticContext => 6, - OutOfBounds => 7, - Reverted => 8, - }; - - s.append_internal(&value); - } -} - -impl Decodable for Error { - fn decode(rlp: &UntrustedRlp) -> Result { - use self::Error::*; - let value: u8 = rlp.as_val()?; - match value { - 0 => Ok(OutOfGas), - 1 => Ok(BadJumpDestination), - 2 => Ok(BadInstruction), - 3 => Ok(StackUnderflow), - 4 => Ok(OutOfStack), - 5 => Ok(Internal), - 6 => Ok(MutableCallInStaticContext), - 7 => Ok(OutOfBounds), - 8 => Ok(Reverted), - _ => Err(DecoderError::Custom("Invalid error type")), - } - } -} - -#[cfg(test)] -mod tests { - use super::Error; - use rlp::*; - - #[test] - fn encode_error() { - let err = Error::BadJumpDestination; - - let mut s = RlpStream::new_list(2); - s.append(&err); - assert!(!s.is_finished(), "List shouldn't finished yet"); - s.append(&err); - assert!(s.is_finished(), "List should be finished now"); - s.out(); - } -} diff --git a/cita-executor/core/src/trace/types/filter.rs b/cita-executor/core/src/trace/types/filter.rs deleted file mode 100644 index 87fb5de9e..000000000 --- a/cita-executor/core/src/trace/types/filter.rs +++ /dev/null @@ -1,356 +0,0 @@ -// Copyright 2015-2017 Parity Technologies (UK) Ltd. -// This file is part of Parity. - -// This software is free software: you can redistribute it and/or modify -// it under the terms of the GNU General Public License as published by -// the Free Software Foundation, either version 3 of the License, or -// (at your option) any later version. - -// This software 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 General Public License for more details. - -// You should have received a copy of the GNU General Public License -// along with Parity. If not, see . - -//! Trace filters type definitions - -use super::trace::{Action, Res}; -use crate::basic_types::LogBloom; -use crate::bloomchain::{Bloom, Filter as BloomFilter, Number}; -use crate::trace::flat::FlatTrace; -use cita_types::traits::BloomTools; -use cita_types::Address; -use std::ops::Range; - -/// Addresses filter. -/// -/// Used to create bloom possibilities and match filters. -#[derive(Debug)] -pub struct AddressesFilter { - list: Vec
, -} - -impl From> for AddressesFilter { - fn from(addresses: Vec
) -> Self { - AddressesFilter { list: addresses } - } -} - -impl AddressesFilter { - /// Returns true if address matches one of the searched addresses. - pub fn matches(&self, address: &Address) -> bool { - self.matches_all() || self.list.contains(address) - } - - /// Returns true if this address filter matches everything. - pub fn matches_all(&self) -> bool { - self.list.is_empty() - } - - /// Returns blooms of this addresses filter. - pub fn blooms(&self) -> Vec { - if self.list.is_empty() { - vec![LogBloom::default()] - } else { - self.list - .iter() - .map(|address| LogBloom::from_raw(&address)) - .collect() - } - } - - /// Returns vector of blooms zipped with blooms of this addresses filter. - pub fn with_blooms(&self, blooms: Vec) -> Vec { - if self.list.is_empty() { - blooms - } else { - blooms - .into_iter() - .flat_map(|bloom| { - self.list - .iter() - .map(|address| { - let mut bloom = bloom; - bloom.accrue_raw(&address); - bloom - }) - .collect::>() - }) - .collect() - } - } -} - -#[derive(Debug)] -/// Traces filter. -pub struct Filter { - /// Block range. - pub range: Range, - - /// From address filter. - pub from_address: AddressesFilter, - - /// To address filter. - pub to_address: AddressesFilter, -} - -impl BloomFilter for Filter { - fn bloom_possibilities(&self) -> Vec { - self.bloom_possibilities() - .into_iter() - .map(|b| Bloom::from(b.0)) - .collect() - } - - fn range(&self) -> Range { - self.range.clone() - } -} - -impl Filter { - /// Returns combinations of each address. - fn bloom_possibilities(&self) -> Vec { - self.to_address.with_blooms(self.from_address.blooms()) - } - - /// Returns true if given trace matches the filter. - pub fn matches(&self, trace: &FlatTrace) -> bool { - match trace.action { - Action::Call(ref call) => { - let from_matches = self.from_address.matches(&call.from); - let to_matches = self.to_address.matches(&call.to); - from_matches && to_matches - } - Action::Create(ref create) => { - let from_matches = self.from_address.matches(&create.from); - - let to_matches = match trace.result { - Res::Create(ref create_result) => { - self.to_address.matches(&create_result.address) - } - _ => false, - }; - - from_matches && to_matches - } - Action::Suicide(ref suicide) => { - let from_matches = self.from_address.matches(&suicide.address); - let to_matches = self.to_address.matches(&suicide.refund_address); - from_matches && to_matches - } - } - } -} - -#[cfg(test)] -mod tests { - use crate::basic_types::LogBloom; - use crate::trace::flat::FlatTrace; - use crate::trace::trace::{Action, Call, Create, CreateResult, Res, Suicide}; - use crate::trace::{AddressesFilter, Filter, TraceError}; - use cita_types::traits::BloomTools; - use cita_types::Address; - use evm::call_type::CallType; - - #[test] - fn empty_trace_filter_bloom_possibilities() { - let filter = Filter { - range: (0..0), - from_address: AddressesFilter::from(vec![]), - to_address: AddressesFilter::from(vec![]), - }; - - let blooms = filter.bloom_possibilities(); - assert_eq!(blooms, vec![LogBloom::default()]); - } - - #[test] - fn single_trace_filter_bloom_possibility() { - let filter = Filter { - range: (0..0), - from_address: AddressesFilter::from(vec![Address::from(1)]), - to_address: AddressesFilter::from(vec![Address::from(2)]), - }; - - let blooms = filter.bloom_possibilities(); - assert_eq!(blooms.len(), 1); - - assert!(blooms[0].contains_raw(&Address::from(1))); - assert!(blooms[0].contains_raw(&Address::from(2))); - assert!(!blooms[0].contains_raw(&Address::from(3))); - } - - #[test] - fn only_from_trace_filter_bloom_possibility() { - let filter = Filter { - range: (0..0), - from_address: AddressesFilter::from(vec![Address::from(1)]), - to_address: AddressesFilter::from(vec![]), - }; - - let blooms = filter.bloom_possibilities(); - assert_eq!(blooms.len(), 1); - - assert!(blooms[0].contains_raw(&Address::from(1))); - assert!(!blooms[0].contains_raw(&Address::from(2))); - } - - #[test] - fn only_to_trace_filter_bloom_possibility() { - let filter = Filter { - range: (0..0), - from_address: AddressesFilter::from(vec![]), - to_address: AddressesFilter::from(vec![Address::from(1)]), - }; - - let blooms = filter.bloom_possibilities(); - assert_eq!(blooms.len(), 1); - - assert!(blooms[0].contains_raw(&Address::from(1))); - assert!(!blooms[0].contains_raw(&Address::from(2))); - } - - #[test] - fn multiple_trace_filter_bloom_possibility() { - let filter = Filter { - range: (0..0), - from_address: AddressesFilter::from(vec![Address::from(1), Address::from(3)]), - to_address: AddressesFilter::from(vec![Address::from(2), Address::from(4)]), - }; - - let blooms = filter.bloom_possibilities(); - assert_eq!(blooms.len(), 4); - - assert!(blooms[0].contains_raw(&Address::from(1))); - assert!(blooms[0].contains_raw(&Address::from(2))); - assert!(!blooms[0].contains_raw(&Address::from(3))); - assert!(!blooms[0].contains_raw(&Address::from(4))); - - assert!(blooms[1].contains_raw(&Address::from(1))); - assert!(blooms[1].contains_raw(&Address::from(4))); - assert!(!blooms[1].contains_raw(&Address::from(2))); - assert!(!blooms[1].contains_raw(&Address::from(3))); - - assert!(blooms[2].contains_raw(&Address::from(2))); - assert!(blooms[2].contains_raw(&Address::from(3))); - assert!(!blooms[2].contains_raw(&Address::from(1))); - assert!(!blooms[2].contains_raw(&Address::from(4))); - - assert!(blooms[3].contains_raw(&Address::from(3))); - assert!(blooms[3].contains_raw(&Address::from(4))); - assert!(!blooms[3].contains_raw(&Address::from(1))); - assert!(!blooms[3].contains_raw(&Address::from(2))); - } - - #[test] - fn filter_matches() { - let f0 = Filter { - range: (0..0), - from_address: AddressesFilter::from(vec![Address::from(1)]), - to_address: AddressesFilter::from(vec![]), - }; - - let f1 = Filter { - range: (0..0), - from_address: AddressesFilter::from(vec![Address::from(3), Address::from(1)]), - to_address: AddressesFilter::from(vec![]), - }; - - let f2 = Filter { - range: (0..0), - from_address: AddressesFilter::from(vec![]), - to_address: AddressesFilter::from(vec![]), - }; - - let f3 = Filter { - range: (0..0), - from_address: AddressesFilter::from(vec![]), - to_address: AddressesFilter::from(vec![Address::from(2)]), - }; - - let f4 = Filter { - range: (0..0), - from_address: AddressesFilter::from(vec![]), - to_address: AddressesFilter::from(vec![Address::from(2), Address::from(3)]), - }; - - let f5 = Filter { - range: (0..0), - from_address: AddressesFilter::from(vec![Address::from(1)]), - to_address: AddressesFilter::from(vec![Address::from(2), Address::from(3)]), - }; - - let f6 = Filter { - range: (0..0), - from_address: AddressesFilter::from(vec![Address::from(1)]), - to_address: AddressesFilter::from(vec![Address::from(4)]), - }; - - let trace = FlatTrace { - action: Action::Call(Call { - from: 1.into(), - to: 2.into(), - value: 3.into(), - gas: 4.into(), - input: vec![0x5], - call_type: CallType::Call, - }), - result: Res::FailedCall(TraceError::OutOfGas), - trace_address: vec![0].into_iter().collect(), - subtraces: 0, - }; - - assert!(f0.matches(&trace)); - assert!(f1.matches(&trace)); - assert!(f2.matches(&trace)); - assert!(f3.matches(&trace)); - assert!(f4.matches(&trace)); - assert!(f5.matches(&trace)); - assert!(!f6.matches(&trace)); - - let trace = FlatTrace { - action: Action::Create(Create { - from: 1.into(), - value: 3.into(), - gas: 4.into(), - init: vec![0x5], - }), - result: Res::Create(CreateResult { - gas_used: 10.into(), - code: vec![], - address: 2.into(), - }), - trace_address: vec![0].into_iter().collect(), - subtraces: 0, - }; - - assert!(f0.matches(&trace)); - assert!(f1.matches(&trace)); - assert!(f2.matches(&trace)); - assert!(f3.matches(&trace)); - assert!(f4.matches(&trace)); - assert!(f5.matches(&trace)); - assert!(!f6.matches(&trace)); - - let trace = FlatTrace { - action: Action::Suicide(Suicide { - address: 1.into(), - refund_address: 2.into(), - balance: 3.into(), - }), - result: Res::None, - trace_address: vec![].into_iter().collect(), - subtraces: 0, - }; - - assert!(f0.matches(&trace)); - assert!(f1.matches(&trace)); - assert!(f2.matches(&trace)); - assert!(f3.matches(&trace)); - assert!(f4.matches(&trace)); - assert!(f5.matches(&trace)); - assert!(!f6.matches(&trace)); - } -} diff --git a/cita-executor/core/src/trace/types/flat.rs b/cita-executor/core/src/trace/types/flat.rs deleted file mode 100644 index 49a6f2c8b..000000000 --- a/cita-executor/core/src/trace/types/flat.rs +++ /dev/null @@ -1,254 +0,0 @@ -// Copyright 2015-2017 Parity Technologies (UK) Ltd. -// This file is part of Parity. - -// This software is free software: you can redistribute it and/or modify -// it under the terms of the GNU General Public License as published by -// the Free Software Foundation, either version 3 of the License, or -// (at your option) any later version. - -// This software 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 General Public License for more details. - -// You should have received a copy of the GNU General Public License -// along with Parity. If not, see . - -//! Flat trace module - -use super::trace::{Action, Res}; -use crate::basic_types::LogBloom; -use rlp::*; -use std::collections::VecDeque; -use util::HeapSizeOf; - -/// Trace localized in vector of traces produced by a single transaction. -/// -/// Parent and children indexes refer to positions in this vector. -#[derive(Debug, PartialEq, Clone)] -pub struct FlatTrace { - /// Type of action performed by a transaction. - pub action: Action, - /// Result of this action. - pub result: Res, - /// Number of subtraces. - pub subtraces: usize, - /// Exact location of trace. - /// - /// [index in root, index in first CALL, index in second CALL, ...] - pub trace_address: VecDeque, -} - -impl FlatTrace { - /// Returns bloom of the trace. - pub fn bloom(&self) -> LogBloom { - self.action.bloom() | self.result.bloom() - } -} - -impl HeapSizeOf for FlatTrace { - fn heap_size_of_children(&self) -> usize { - self.trace_address.heap_size_of_children() - } -} - -impl Encodable for FlatTrace { - fn rlp_append(&self, s: &mut RlpStream) { - s.begin_list(4); - s.append(&self.action); - s.append(&self.result); - s.append(&self.subtraces); - s.append_list::(&self.trace_address.iter().collect::>()); - } -} - -impl Decodable for FlatTrace { - fn decode(d: &UntrustedRlp) -> Result { - let v: Vec = d.list_at(3)?; - let res = FlatTrace { - action: d.val_at(0)?, - result: d.val_at(1)?, - subtraces: d.val_at(2)?, - trace_address: v.into_iter().collect(), - }; - - Ok(res) - } -} - -/// Represents all traces produced by a single transaction. -#[derive(Debug, PartialEq, Clone)] -pub struct FlatTransactionTraces(Vec); - -impl From> for FlatTransactionTraces { - fn from(v: Vec) -> Self { - FlatTransactionTraces(v) - } -} - -impl HeapSizeOf for FlatTransactionTraces { - fn heap_size_of_children(&self) -> usize { - self.0.heap_size_of_children() - } -} - -impl FlatTransactionTraces { - /// Returns bloom of all traces in the collection. - pub fn bloom(&self) -> LogBloom { - self.0 - .iter() - .fold(Default::default(), |bloom, trace| bloom | trace.bloom()) - } -} - -impl Encodable for FlatTransactionTraces { - fn rlp_append(&self, s: &mut RlpStream) { - s.append_list(&self.0); - } -} - -impl Decodable for FlatTransactionTraces { - fn decode(rlp: &UntrustedRlp) -> Result { - Ok(FlatTransactionTraces(rlp.as_list()?)) - } -} - -impl Into> for FlatTransactionTraces { - fn into(self) -> Vec { - self.0 - } -} - -/// Represents all traces produced by transactions in a single block. -#[derive(Debug, PartialEq, Clone, Default)] -pub struct FlatBlockTraces(Vec); - -impl HeapSizeOf for FlatBlockTraces { - fn heap_size_of_children(&self) -> usize { - self.0.heap_size_of_children() - } -} - -impl From> for FlatBlockTraces { - fn from(v: Vec) -> Self { - FlatBlockTraces(v) - } -} - -impl FlatBlockTraces { - /// Returns bloom of all traces in the block. - pub fn bloom(&self) -> LogBloom { - self.0.iter().fold(Default::default(), |bloom, tx_traces| { - bloom | tx_traces.bloom() - }) - } -} - -impl Encodable for FlatBlockTraces { - fn rlp_append(&self, s: &mut RlpStream) { - s.append_list(&self.0); - } -} - -impl Decodable for FlatBlockTraces { - fn decode(rlp: &UntrustedRlp) -> Result { - Ok(FlatBlockTraces(rlp.as_list()?)) - } -} - -impl Into> for FlatBlockTraces { - fn into(self) -> Vec { - self.0 - } -} - -#[cfg(test)] -mod tests { - use super::{FlatBlockTraces, FlatTrace, FlatTransactionTraces}; - use crate::trace::trace::{Action, Call, CallResult, Res, Suicide}; - use evm::call_type::CallType; - use rlp::*; - - #[test] - fn encode_flat_transaction_traces() { - let ftt = FlatTransactionTraces::from(Vec::new()); - - let mut s = RlpStream::new_list(2); - s.append(&ftt); - assert!(!s.is_finished(), "List shouldn't finished yet"); - s.append(&ftt); - assert!(s.is_finished(), "List should be finished now"); - s.out(); - } - - #[test] - fn encode_flat_block_traces() { - let fbt = FlatBlockTraces::from(Vec::new()); - - let mut s = RlpStream::new_list(2); - s.append(&fbt); - assert!(!s.is_finished(), "List shouldn't finished yet"); - s.append(&fbt); - assert!(s.is_finished(), "List should be finished now"); - s.out(); - } - - #[test] - fn test_trace_serialization() { - // block #51921 - - let flat_trace = FlatTrace { - action: Action::Call(Call { - from: "8dda5e016e674683241bf671cced51e7239ea2bc".parse().unwrap(), - to: "37a5e19cc2d49f244805d5c268c0e6f321965ab9".parse().unwrap(), - value: "3627e8f712373c0000".parse().unwrap(), - gas: 0x03e8.into(), - input: vec![], - call_type: CallType::Call, - }), - result: Res::Call(CallResult { - gas_used: 0.into(), - output: vec![], - }), - trace_address: Default::default(), - subtraces: 0, - }; - - let flat_trace1 = FlatTrace { - action: Action::Call(Call { - from: "3d0768da09ce77d25e2d998e6a7b6ed4b9116c2d".parse().unwrap(), - to: "412fda7643b37d436cb40628f6dbbb80a07267ed".parse().unwrap(), - value: 0.into(), - gas: 0x010c78.into(), - input: vec![0x41, 0xc0, 0xe1, 0xb5], - call_type: CallType::Call, - }), - result: Res::Call(CallResult { - gas_used: 0x0127.into(), - output: vec![], - }), - trace_address: Default::default(), - subtraces: 1, - }; - - let flat_trace2 = FlatTrace { - action: Action::Suicide(Suicide { - address: "412fda7643b37d436cb40628f6dbbb80a07267ed".parse().unwrap(), - balance: 0.into(), - refund_address: "3d0768da09ce77d25e2d998e6a7b6ed4b9116c2d".parse().unwrap(), - }), - result: Res::None, - trace_address: vec![0].into_iter().collect(), - subtraces: 0, - }; - - let block_traces = FlatBlockTraces(vec![ - FlatTransactionTraces(vec![flat_trace]), - FlatTransactionTraces(vec![flat_trace1, flat_trace2]), - ]); - - let encoded = ::rlp::encode(&block_traces); - let decoded = ::rlp::decode(&encoded); - assert_eq!(block_traces, decoded); - } -} diff --git a/cita-executor/core/src/trace/types/localized.rs b/cita-executor/core/src/trace/types/localized.rs deleted file mode 100644 index 17cd0d3ce..000000000 --- a/cita-executor/core/src/trace/types/localized.rs +++ /dev/null @@ -1,45 +0,0 @@ -// Copyright 2015-2017 Parity Technologies (UK) Ltd. -// This file is part of Parity. - -// This software is free software: you can redistribute it and/or modify -// it under the terms of the GNU General Public License as published by -// the Free Software Foundation, either version 3 of the License, or -// (at your option) any later version. - -// This software 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 General Public License for more details. - -// You should have received a copy of the GNU General Public License -// along with Parity. If not, see . - -//! Localized traces type definitions - -use super::trace::{Action, Res}; -use crate::header::BlockNumber; -use cita_types::H256; - -/// Localized trace. -#[derive(Debug, PartialEq, Clone)] -#[cfg_attr(feature = "ipc", binary)] -pub struct LocalizedTrace { - /// Type of action performed by a transaction. - pub action: Action, - /// Result of this action. - pub result: Res, - /// Number of subtraces. - pub subtraces: usize, - /// Exact location of trace. - /// - /// [index in root, index in first CALL, index in second CALL, ...] - pub trace_address: Vec, - /// Transaction number within the block. - pub transaction_number: usize, - /// Signed transaction hash. - pub transaction_hash: H256, - /// Block number. - pub block_number: BlockNumber, - /// Block hash. - pub block_hash: H256, -} diff --git a/cita-executor/core/src/trace/types/mod.rs b/cita-executor/core/src/trace/types/mod.rs deleted file mode 100644 index a77e8873a..000000000 --- a/cita-executor/core/src/trace/types/mod.rs +++ /dev/null @@ -1,23 +0,0 @@ -// Copyright 2015-2017 Parity Technologies (UK) Ltd. -// This file is part of Parity. - -// This software is free software: you can redistribute it and/or modify -// it under the terms of the GNU General Public License as published by -// the Free Software Foundation, either version 3 of the License, or -// (at your option) any later version. - -// This software 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 General Public License for more details. - -// You should have received a copy of the GNU General Public License -// along with Parity. If not, see . - -//! Types used in the public api - -pub mod error; -pub mod filter; -pub mod flat; -pub mod localized; -pub mod trace; diff --git a/cita-executor/core/src/trace/types/trace.rs b/cita-executor/core/src/trace/types/trace.rs deleted file mode 100644 index 19420d3b2..000000000 --- a/cita-executor/core/src/trace/types/trace.rs +++ /dev/null @@ -1,562 +0,0 @@ -// Copyright 2015-2017 Parity Technologies (UK) Ltd. -// This file is part of Parity. - -// This software is free software: you can redistribute it and/or modify -// it under the terms of the GNU General Public License as published by -// the Free Software Foundation, either version 3 of the License, or -// (at your option) any later version. - -// This software 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 General Public License for more details. - -// You should have received a copy of the GNU General Public License -// along with Parity. If not, see . - -//! Tracing datatypes. - -use super::error::Error; - -use crate::basic_types::LogBloom; -use cita_types::traits::BloomTools; -use cita_types::{Address, U256}; -use evm::action_params::ActionParams; -use evm::call_type::CallType; -use rlp::*; -use util::Bytes; - -/// `Call` result. -#[derive(Debug, Clone, PartialEq, Default)] -#[cfg_attr(feature = "ipc", binary)] -pub struct CallResult { - /// Gas used by call. - pub gas_used: U256, - /// Call Output. - pub output: Bytes, -} - -impl Encodable for CallResult { - fn rlp_append(&self, s: &mut RlpStream) { - s.begin_list(2); - s.append(&self.gas_used); - s.append(&self.output); - } -} - -impl Decodable for CallResult { - fn decode(rlp: &UntrustedRlp) -> Result { - let res = CallResult { - gas_used: rlp.val_at(0)?, - output: rlp.val_at(1)?, - }; - - Ok(res) - } -} - -/// `Create` result. -#[derive(Debug, Clone, PartialEq)] -#[cfg_attr(feature = "ipc", binary)] -pub struct CreateResult { - /// Gas used by create. - pub gas_used: U256, - /// Code of the newly created contract. - pub code: Bytes, - /// Address of the newly created contract. - pub address: Address, -} - -impl Encodable for CreateResult { - fn rlp_append(&self, s: &mut RlpStream) { - s.begin_list(3); - s.append(&self.gas_used); - s.append(&self.code); - s.append(&self.address); - } -} - -impl Decodable for CreateResult { - fn decode(rlp: &UntrustedRlp) -> Result { - let res = CreateResult { - gas_used: rlp.val_at(0)?, - code: rlp.val_at(1)?, - address: rlp.val_at(2)?, - }; - - Ok(res) - } -} - -impl CreateResult { - /// Returns bloom. - pub fn bloom(&self) -> LogBloom { - LogBloom::from_raw(&self.address) - } -} - -/// Description of a _call_ action, either a `CALL` operation or a message transction. -#[derive(Debug, Clone, PartialEq)] -#[cfg_attr(feature = "ipc", binary)] -pub struct Call { - /// The sending account. - pub from: Address, - /// The destination account. - pub to: Address, - /// The value transferred to the destination account. - pub value: U256, - /// The gas available for executing the call. - pub gas: U256, - /// The input data provided to the call. - pub input: Bytes, - /// The type of the call. - pub call_type: CallType, -} - -impl From for Call { - fn from(p: ActionParams) -> Self { - Call { - from: p.sender, - to: p.address, - value: p.value.value(), - gas: p.gas, - input: p.data.unwrap_or_else(Vec::new), - call_type: p.call_type, - } - } -} - -impl Encodable for Call { - fn rlp_append(&self, s: &mut RlpStream) { - s.begin_list(6); - s.append(&self.from); - s.append(&self.to); - s.append(&self.value); - s.append(&self.gas); - s.append(&self.input); - s.append(&self.call_type); - } -} - -impl Decodable for Call { - fn decode(rlp: &UntrustedRlp) -> Result { - let res = Call { - from: rlp.val_at(0)?, - to: rlp.val_at(1)?, - value: rlp.val_at(2)?, - gas: rlp.val_at(3)?, - input: rlp.val_at(4)?, - call_type: rlp.val_at(5)?, - }; - - Ok(res) - } -} - -impl Call { - /// Returns call action bloom. - /// The bloom contains from and to addresses. - pub fn bloom(&self) -> LogBloom { - let mut b = LogBloom::from_raw(&self.from); - b.accrue_raw(&self.to); - b - } -} - -/// Description of a _create_ action, either a `CREATE` operation or a create transction. -#[derive(Debug, Clone, PartialEq)] -#[cfg_attr(feature = "ipc", binary)] -pub struct Create { - /// The address of the creator. - pub from: Address, - /// The value with which the new account is endowed. - pub value: U256, - /// The gas available for the creation init code. - pub gas: U256, - /// The init code. - pub init: Bytes, -} - -impl From for Create { - fn from(p: ActionParams) -> Self { - Create { - from: p.sender, - value: p.value.value(), - gas: p.gas, - init: p.code.map_or_else(Vec::new, |c| (*c).clone()), - } - } -} - -impl Encodable for Create { - fn rlp_append(&self, s: &mut RlpStream) { - s.begin_list(4); - s.append(&self.from); - s.append(&self.value); - s.append(&self.gas); - s.append(&self.init); - } -} - -impl Decodable for Create { - fn decode(rlp: &UntrustedRlp) -> Result { - let res = Create { - from: rlp.val_at(0)?, - value: rlp.val_at(1)?, - gas: rlp.val_at(2)?, - init: rlp.val_at(3)?, - }; - - Ok(res) - } -} - -impl Create { - /// Returns bloom create action bloom. - /// The bloom contains only from address. - pub fn bloom(&self) -> LogBloom { - LogBloom::from_raw(&self.from) - } -} - -/// Suicide action. -#[derive(Debug, Clone, PartialEq)] -#[cfg_attr(feature = "ipc", binary)] -pub struct Suicide { - /// Suicided address. - pub address: Address, - /// Suicided contract heir. - pub refund_address: Address, - /// Balance of the contract just before suicide. - pub balance: U256, -} - -impl Suicide { - /// Return suicide action bloom. - pub fn bloom(&self) -> LogBloom { - let mut b = LogBloom::from_raw(&self.address); - b.accrue_raw(&self.refund_address); - b - } -} - -impl Encodable for Suicide { - fn rlp_append(&self, s: &mut RlpStream) { - s.begin_list(3); - s.append(&self.address); - s.append(&self.refund_address); - s.append(&self.balance); - } -} - -impl Decodable for Suicide { - fn decode(rlp: &UntrustedRlp) -> Result { - let res = Suicide { - address: rlp.val_at(0)?, - refund_address: rlp.val_at(1)?, - balance: rlp.val_at(2)?, - }; - - Ok(res) - } -} - -/// Description of an action that we trace; will be either a call or a create. -#[derive(Debug, Clone, PartialEq)] -#[cfg_attr(feature = "ipc", binary)] -pub enum Action { - /// It's a call action. - Call(Call), - /// It's a create action. - Create(Create), - /// Suicide. - Suicide(Suicide), -} - -impl Encodable for Action { - fn rlp_append(&self, s: &mut RlpStream) { - s.begin_list(2); - match *self { - Action::Call(ref call) => { - s.append(&0u8); - s.append(call); - } - Action::Create(ref create) => { - s.append(&1u8); - s.append(create); - } - Action::Suicide(ref suicide) => { - s.append(&2u8); - s.append(suicide); - } - } - } -} - -impl Decodable for Action { - fn decode(rlp: &UntrustedRlp) -> Result { - let action_type: u8 = rlp.val_at(0)?; - match action_type { - 0 => rlp.val_at(1).map(Action::Call), - 1 => rlp.val_at(1).map(Action::Create), - 2 => rlp.val_at(1).map(Action::Suicide), - _ => Err(DecoderError::Custom("Invalid action type.")), - } - } -} - -impl Action { - /// Returns action bloom. - pub fn bloom(&self) -> LogBloom { - match *self { - Action::Call(ref call) => call.bloom(), - Action::Create(ref create) => create.bloom(), - Action::Suicide(ref suicide) => suicide.bloom(), - } - } -} - -/// The result of the performed action. -#[derive(Debug, Clone, PartialEq)] -#[cfg_attr(feature = "ipc", binary)] -pub enum Res { - /// Successful call action result. - Call(CallResult), - /// Successful create action result. - Create(CreateResult), - /// Failed call. - FailedCall(Error), - /// Failed create. - FailedCreate(Error), - /// None - None, -} - -impl Encodable for Res { - fn rlp_append(&self, s: &mut RlpStream) { - match *self { - Res::Call(ref call) => { - s.begin_list(2); - s.append(&0u8); - s.append(call); - } - Res::Create(ref create) => { - s.begin_list(2); - s.append(&1u8); - s.append(create); - } - Res::FailedCall(ref err) => { - s.begin_list(2); - s.append(&2u8); - s.append(err); - } - Res::FailedCreate(ref err) => { - s.begin_list(2); - s.append(&3u8); - s.append(err); - } - Res::None => { - s.begin_list(1); - s.append(&4u8); - } - } - } -} - -impl Decodable for Res { - fn decode(rlp: &UntrustedRlp) -> Result { - let action_type: u8 = rlp.val_at(0)?; - match action_type { - 0 => rlp.val_at(1).map(Res::Call), - 1 => rlp.val_at(1).map(Res::Create), - 2 => rlp.val_at(1).map(Res::FailedCall), - 3 => rlp.val_at(1).map(Res::FailedCreate), - 4 => Ok(Res::None), - _ => Err(DecoderError::Custom("Invalid result type.")), - } - } -} - -impl Res { - /// Returns result bloom. - pub fn bloom(&self) -> LogBloom { - match *self { - Res::Create(ref create) => create.bloom(), - Res::Call(_) | Res::FailedCall(_) | Res::FailedCreate(_) | Res::None => { - Default::default() - } - } - } - - /// Did this call fail? - pub fn succeeded(&self) -> bool { - match *self { - Res::Call(_) | Res::Create(_) => true, - _ => false, - } - } -} - -#[derive(Debug, Clone, PartialEq)] -#[cfg_attr(feature = "ipc", binary)] -/// A diff of some chunk of memory. -pub struct MemoryDiff { - /// Offset into memory the change begins. - pub offset: usize, - /// The changed data. - pub data: Bytes, -} - -impl Encodable for MemoryDiff { - fn rlp_append(&self, s: &mut RlpStream) { - s.begin_list(2); - s.append(&self.offset); - s.append(&self.data); - } -} - -impl Decodable for MemoryDiff { - fn decode(rlp: &UntrustedRlp) -> Result { - Ok(MemoryDiff { - offset: rlp.val_at(0)?, - data: rlp.val_at(1)?, - }) - } -} - -#[derive(Debug, Clone, PartialEq)] -#[cfg_attr(feature = "ipc", binary)] -/// A diff of some storage value. -pub struct StorageDiff { - /// Which key in storage is changed. - pub location: U256, - /// What the value has been changed to. - pub value: U256, -} - -impl Encodable for StorageDiff { - fn rlp_append(&self, s: &mut RlpStream) { - s.begin_list(2); - s.append(&self.location); - s.append(&self.value); - } -} - -impl Decodable for StorageDiff { - fn decode(rlp: &UntrustedRlp) -> Result { - Ok(StorageDiff { - location: rlp.val_at(0)?, - value: rlp.val_at(1)?, - }) - } -} - -#[derive(Debug, Clone, PartialEq)] -#[cfg_attr(feature = "ipc", binary)] -/// A record of an executed VM operation. -pub struct VMExecutedOperation { - /// The total gas used. - pub gas_used: U256, - /// The stack item placed, if any. - pub stack_push: Vec, - /// If altered, the memory delta. - pub mem_diff: Option, - /// The altered storage value, if any. - pub store_diff: Option, -} - -impl Encodable for VMExecutedOperation { - fn rlp_append(&self, s: &mut RlpStream) { - s.begin_list(4); - s.append(&self.gas_used); - s.append_list(&self.stack_push); - s.append(&self.mem_diff); - s.append(&self.store_diff); - } -} - -impl Decodable for VMExecutedOperation { - fn decode(rlp: &UntrustedRlp) -> Result { - Ok(VMExecutedOperation { - gas_used: rlp.val_at(0)?, - stack_push: rlp.list_at(1)?, - mem_diff: rlp.val_at(2)?, - store_diff: rlp.val_at(3)?, - }) - } -} - -#[derive(Debug, Clone, PartialEq, Default)] -#[cfg_attr(feature = "ipc", binary)] -/// A record of the execution of a single VM operation. -pub struct VMOperation { - /// The program counter. - pub pc: usize, - /// The instruction executed. - pub instruction: u8, - /// The gas cost for this instruction. - pub gas_cost: U256, - /// Information concerning the execution of the operation. - pub executed: Option, -} - -impl Encodable for VMOperation { - fn rlp_append(&self, s: &mut RlpStream) { - s.begin_list(4); - s.append(&self.pc); - s.append(&self.instruction); - s.append(&self.gas_cost); - s.append(&self.executed); - } -} - -impl Decodable for VMOperation { - fn decode(rlp: &UntrustedRlp) -> Result { - let res = VMOperation { - pc: rlp.val_at(0)?, - instruction: rlp.val_at(1)?, - gas_cost: rlp.val_at(2)?, - executed: rlp.val_at(3)?, - }; - - Ok(res) - } -} - -#[derive(Debug, Clone, PartialEq, Default)] -#[cfg_attr(feature = "ipc", binary)] -/// A record of a full VM trace for a CALL/CREATE. -pub struct VMTrace { - /// The step (i.e. index into operations) at which this trace corresponds. - pub parent_step: usize, - /// The code to be executed. - pub code: Bytes, - /// The operations executed. - pub operations: Vec, - /// The sub traces for each interior action performed as part of this call/create. - /// Thre is a 1:1 correspondance between these and a CALL/CREATE/CALLCODE/DELEGATECALL instruction. - pub subs: Vec, -} - -impl Encodable for VMTrace { - fn rlp_append(&self, s: &mut RlpStream) { - s.begin_list(4); - s.append(&self.parent_step); - s.append(&self.code); - s.append_list(&self.operations); - s.append_list(&self.subs); - } -} - -impl Decodable for VMTrace { - fn decode(rlp: &UntrustedRlp) -> Result { - let res = VMTrace { - parent_step: rlp.val_at(0)?, - code: rlp.val_at(1)?, - operations: rlp.list_at(2)?, - subs: rlp.list_at(3)?, - }; - - Ok(res) - } -} diff --git a/cita-executor/core/src/trie_db.rs b/cita-executor/core/src/trie_db.rs new file mode 100644 index 000000000..7a86fbb18 --- /dev/null +++ b/cita-executor/core/src/trie_db.rs @@ -0,0 +1,133 @@ +// Copyright Cryptape Technologies LLC. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +use std::sync::Arc; + +use cita_database::error::DatabaseError; +use cita_database::{DataCategory, Database}; +use cita_types::H256; +use hashable::HASH_NULL_RLP; +use parking_lot::RwLock; +use std::collections::HashMap; + +static NULL_RLP_STATIC: [u8; 1] = [0x80; 1]; + +#[derive(Debug)] +pub struct TrieDB +where + DB: Database, +{ + db: Arc, + cache: Arc, Vec>>>, +} + +impl TrieDB +where + DB: Database, +{ + pub fn new(db: Arc) -> Self { + TrieDB { + db, + cache: Arc::new(RwLock::new(HashMap::new())), + } + } + + pub fn database(&self) -> Arc { + self.db.clone() + } +} + +/// "TrieDB" provides state read/write capabilities for executor. +impl cita_trie::DB for TrieDB +where + DB: Database, +{ + type Error = DatabaseError; + + fn get(&self, key: &[u8]) -> Result>, Self::Error> { + if H256::from(key) == HASH_NULL_RLP { + return Ok(Some(NULL_RLP_STATIC.to_vec())); + } + match self.cache.read().get(key) { + Some(v) => Ok(Some(v.to_vec())), + None => self.db.get(Some(DataCategory::State), key), + } + } + + fn insert(&self, key: Vec, value: Vec) -> Result<(), Self::Error> { + if H256::from(key.as_slice()) == HASH_NULL_RLP { + return Ok(()); + } + self.cache.write().insert(key, value); + Ok(()) + } + + fn contains(&self, key: &[u8]) -> Result { + if H256::from(key) == HASH_NULL_RLP { + return Ok(true); + } + if self.cache.read().contains_key(key) { + Ok(true) + } else { + self.db.contains(Some(DataCategory::State), key) + } + } + + fn remove(&self, _key: &[u8]) -> Result<(), Self::Error> { + Ok(()) + } + + fn insert_batch(&self, keys: Vec>, values: Vec>) -> Result<(), Self::Error> { + let mut cache = self.cache.write(); + for i in 0..keys.len() { + let key = keys[i].clone(); + if H256::from(key.as_slice()) == HASH_NULL_RLP { + continue; + } + let value = values[i].clone(); + cache.insert(key, value); + } + Ok(()) + } + + fn remove_batch(&self, _keys: &[Vec]) -> Result<(), Self::Error> { + Ok(()) + } + + fn flush(&self) -> Result<(), Self::Error> { + let len = self.cache.read().len(); + let mut keys = Vec::with_capacity(len); + let mut values = Vec::with_capacity(len); + + for (key, value) in self.cache.write().drain() { + keys.push(key); + values.push(value); + } + + self.db + .insert_batch(Some(DataCategory::State), keys.to_vec(), values.to_vec()) + } +} + +impl Clone for TrieDB +where + DB: Database, +{ + fn clone(&self) -> Self { + TrieDB { + db: Arc::clone(&self.db), + cache: Arc::clone(&self.cache), + } + } +} diff --git a/cita-executor/core/src/tx_gas_schedule.rs b/cita-executor/core/src/tx_gas_schedule.rs new file mode 100644 index 000000000..43babe46d --- /dev/null +++ b/cita-executor/core/src/tx_gas_schedule.rs @@ -0,0 +1,39 @@ +// Copyright Cryptape Technologies LLC. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +/// Definition of the cost schedule for a transaction. +pub struct TxGasSchedule { + /// Transaction cost + pub tx_gas: usize, + /// `CREATE` transaction cost + pub tx_create_gas: usize, + /// Additional cost for empty data transaction + pub tx_data_zero_gas: usize, + /// Aditional cost for non-empty data transaction + pub tx_data_non_zero_gas: usize, + /// Cost for contract length when executing `CREATE` + pub create_data_gas: usize, +} + +impl Default for TxGasSchedule { + fn default() -> Self { + TxGasSchedule { + tx_gas: 21_000, + tx_create_gas: 53_000, + tx_data_zero_gas: 4, + tx_data_non_zero_gas: 68, + create_data_gas: 200, + } + } +} diff --git a/cita-executor/evm/Cargo.toml b/cita-executor/evm/Cargo.toml deleted file mode 100644 index 9be6efcc6..000000000 --- a/cita-executor/evm/Cargo.toml +++ /dev/null @@ -1,21 +0,0 @@ -[package] -name = "evm" -version = "0.1.0" -authors = ["Parity Technologies ", "Cryptape Technologies "] -edition = "2018" - -[dependencies] -cita-logger = "0.1.0" -cita-types = { git = "https://github.com/cryptape/cita-common.git", branch = "develop" } -hashable = { git = "https://github.com/cryptape/cita-common.git", branch = "develop" } -lazy_static = "0.2" -util = { git = "https://github.com/cryptape/cita-common.git", branch = "develop" } -bit-set = "0.4" -common-types = { path = "../../cita-chain/types" } -rlp = { git = "https://github.com/cryptape/cita-common.git", branch = "develop" } -rustc-hex = "1.0" -db = { git = "https://github.com/cryptape/cita-common.git", branch = "develop" } - -[features] -evm-debug = [] -evm-debug-tests = ["evm-debug"] diff --git a/cita-executor/evm/README.md b/cita-executor/evm/README.md deleted file mode 100644 index 488678037..000000000 --- a/cita-executor/evm/README.md +++ /dev/null @@ -1,3 +0,0 @@ -# EVM for CITA - -This repository is extracted from [Parity](https://github.com/paritytech/parity) diff --git a/cita-executor/evm/src/action_params.rs b/cita-executor/evm/src/action_params.rs deleted file mode 100644 index e279321da..000000000 --- a/cita-executor/evm/src/action_params.rs +++ /dev/null @@ -1,91 +0,0 @@ -// Copyright 2015-2017 Parity Technologies (UK) Ltd. -// This file is part of Parity. - -// This software is free software: you can redistribute it and/or modify -// it under the terms of the GNU General Public License as published by -// the Free Software Foundation, either version 3 of the License, or -// (at your option) any later version. - -// This software 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 General Public License for more details. - -// You should have received a copy of the GNU General Public License -// along with Parity. If not, see . - -//! Evm input params. - -// use ethjson; -use crate::call_type::CallType; - -use cita_types::{Address, H256, U256}; -use hashable::HASH_EMPTY; -use std::sync::Arc; -use util::Bytes; - -/// Transaction value -#[derive(Clone, Debug)] -pub enum ActionValue { - /// Value that should be transfered - Transfer(U256), - /// Apparent value for transaction (not transfered) - Apparent(U256), -} - -impl ActionValue { - /// Returns action value as U256. - pub fn value(&self) -> U256 { - match *self { - ActionValue::Transfer(x) | ActionValue::Apparent(x) => x, - } - } -} - -// TODO: should be a trait, possible to avoid cloning everything from a Transaction(/View). -/// Action (call/create) input params. Everything else should be specified in Externalities. -#[derive(Clone, Debug)] -pub struct ActionParams { - /// Address of currently executed code. - pub code_address: Address, - /// Hash of currently executed code. - pub code_hash: H256, - /// Receive address. Usually equal to code_address, - /// except when called using CALLCODE. - pub address: Address, - /// Sender of current part of the transaction. - pub sender: Address, - /// Transaction initiator. - pub origin: Address, - /// Gas paid up front for transaction execution - pub gas: U256, - /// Gas price. - pub gas_price: U256, - /// Transaction value. - pub value: ActionValue, - /// Code being executed. - pub code: Option>, - /// Input data. - pub data: Option, - /// Type of call - pub call_type: CallType, -} - -impl Default for ActionParams { - /// Returns default ActionParams initialized with zeros - fn default() -> ActionParams { - ActionParams { - code_address: Address::new(), - code_hash: HASH_EMPTY, - address: Address::new(), - sender: Address::new(), - origin: Address::new(), - gas: U256::zero(), - gas_price: U256::zero(), - value: ActionValue::Transfer(U256::zero()), - code: None, - data: None, - call_type: CallType::None, - } - } -} diff --git a/cita-executor/evm/src/benches/mod.rs b/cita-executor/evm/src/benches/mod.rs deleted file mode 100644 index 53238a515..000000000 --- a/cita-executor/evm/src/benches/mod.rs +++ /dev/null @@ -1,127 +0,0 @@ -// Copyright 2015-2017 Parity Technologies (UK) Ltd. -// This file is part of Parity. - -// This software is free software: you can redistribute it and/or modify -// it under the terms of the GNU General Public License as published by -// the Free Software Foundation, either version 3 of the License, or -// (at your option) any later version. - -// This software 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 General Public License for more details. - -// You should have received a copy of the GNU General Public License -// along with Parity. If not, see . - -//! benchmarking for EVM -//! should be started with: -//! ```bash -//! multirust run nightly cargo bench -//! ``` - -use action_params::ActionParams; -use evm::tests::FakeExt; -use evm::{self, Factory, VMType}; -use test::{black_box, Bencher}; - -use util::*; - -#[bench] -fn simple_loop_log0_usize(b: &mut Bencher) { - simple_loop_log0(U256::from(::std::usize::MAX), b) -} - -#[bench] -fn simple_loop_log0_u256(b: &mut Bencher) { - simple_loop_log0(!U256::zero(), b) -} - -fn simple_loop_log0(gas: U256, b: &mut Bencher) { - let mut vm = Factory::new(VMType::Interpreter).create(gas); - let mut ext = FakeExt::new(); - - let address = Address::from_str("0f572e5295c57f15886f9b263e2f6d2d6c7b5ec6").unwrap(); - let code = black_box("62ffffff5b600190036000600fa0600357".from_hex().unwrap()); - - b.iter(|| { - let mut params = ActionParams::default(); - params.address = address.clone(); - params.gas = gas; - params.code = Some(code.clone()); - - result(vm.exec(params, &mut ext)) - }); -} - -#[bench] -fn mem_gas_calculation_same_usize(b: &mut Bencher) { - mem_gas_calculation_same(U256::from(::std::usize::MAX), b) -} - -#[bench] -fn mem_gas_calculation_same_u256(b: &mut Bencher) { - mem_gas_calculation_same(!U256::zero(), b) -} - -fn mem_gas_calculation_same(gas: U256, b: &mut Bencher) { - let mut vm = Factory::new(VMType::Interpreter).create(gas); - let mut ext = FakeExt::new(); - - let address = Address::from_str("0f572e5295c57f15886f9b263e2f6d2d6c7b5ec6").unwrap(); - - b.iter(|| { - let code = black_box( - "6110006001556001546000555b610fff805560016000540380600055600c57" - .from_hex() - .unwrap(), - ); - - let mut params = ActionParams::default(); - params.address = address.clone(); - params.gas = gas; - params.code = Some(code.clone()); - - result(vm.exec(params, &mut ext)) - }); -} - -#[bench] -fn mem_gas_calculation_increasing_usize(b: &mut Bencher) { - mem_gas_calculation_increasing(U256::from(::std::usize::MAX), b) -} - -#[bench] -fn mem_gas_calculation_increasing_u256(b: &mut Bencher) { - mem_gas_calculation_increasing(!U256::zero(), b) -} - -fn mem_gas_calculation_increasing(gas: U256, b: &mut Bencher) { - let mut vm = Factory::new(VMType::Interpreter).create(gas); - let mut ext = FakeExt::new(); - - let address = Address::from_str("0f572e5295c57f15886f9b263e2f6d2d6c7b5ec6").unwrap(); - - b.iter(|| { - let code = black_box( - "6110006001556001546000555b610fff60005401805560016000540380600055600c57" - .from_hex() - .unwrap(), - ); - - let mut params = ActionParams::default(); - params.address = address.clone(); - params.gas = gas; - params.code = Some(code.clone()); - - result(vm.exec(params, &mut ext)) - }); -} - -fn result(r: evm::Result) -> U256 { - match r { - Ok(evm::GasLeft::Known(v)) => v, - Ok(evm::GasLeft::NeedsReturn(v, _)) => v, - _ => U256::zero(), - } -} diff --git a/cita-executor/evm/src/call_type.rs b/cita-executor/evm/src/call_type.rs deleted file mode 100644 index 7d6bb4968..000000000 --- a/cita-executor/evm/src/call_type.rs +++ /dev/null @@ -1,88 +0,0 @@ -// Copyright 2015-2017 Parity Technologies (UK) Ltd. -// This file is part of Parity. - -// This software is free software: you can redistribute it and/or modify -// it under the terms of the GNU General Public License as published by -// the Free Software Foundation, either version 3 of the License, or -// (at your option) any later version. - -// This software 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 General Public License for more details. - -// You should have received a copy of the GNU General Public License -// along with Parity. If not, see . - -//! EVM call types. - -use rlp::{Decodable, DecoderError, Encodable, RlpStream, UntrustedRlp}; - -/// The type of the call-like instruction. -#[derive(Debug, PartialEq, Clone)] -pub enum CallType { - /// Not a CALL. - None, - /// CALL. - Call, - /// CALLCODE. - CallCode, - /// DELEGATECALL. - DelegateCall, - /// STATICCALL - StaticCall, -} - -impl Encodable for CallType { - fn rlp_append(&self, s: &mut RlpStream) { - let v = match *self { - CallType::None => 0u32, - CallType::Call => 1, - CallType::CallCode => 2, - CallType::DelegateCall => 3, - CallType::StaticCall => 4, - }; - Encodable::rlp_append(&v, s); - } -} - -impl Decodable for CallType { - fn decode(rlp: &UntrustedRlp) -> Result { - rlp.as_val().and_then(|v| { - Ok(match v { - 0u32 => CallType::None, - 1 => CallType::Call, - 2 => CallType::CallCode, - 3 => CallType::DelegateCall, - 4 => CallType::StaticCall, - _ => return Err(DecoderError::Custom("Invalid value of CallType item")), - }) - }) - } -} - -#[cfg(test)] -mod tests { - use super::CallType; - use rlp::*; - - #[test] - fn encode_call_type() { - let ct = CallType::Call; - - let mut s = RlpStream::new_list(2); - s.append(&ct); - assert!(!s.is_finished(), "List shouldn't finished yet"); - s.append(&ct); - assert!(s.is_finished(), "List should be finished now"); - s.out(); - } - - #[test] - fn should_encode_and_decode_call_type() { - let original = CallType::Call; - let encoded = encode(&original); - let decoded = decode(&encoded); - assert_eq!(original, decoded); - } -} diff --git a/cita-executor/evm/src/env_info.rs b/cita-executor/evm/src/env_info.rs deleted file mode 100644 index 090a78ee0..000000000 --- a/cita-executor/evm/src/env_info.rs +++ /dev/null @@ -1,105 +0,0 @@ -// Copyright 2015-2017 Parity Technologies (UK) Ltd. -// This file is part of Parity. - -// This software is free software: you can redistribute it and/or modify -// it under the terms of the GNU General Public License as published by -// the Free Software Foundation, either version 3 of the License, or -// (at your option) any later version. - -// This software 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 General Public License for more details. - -// You should have received a copy of the GNU General Public License -// along with Parity. If not, see . - -// use std::cmp; - -use crate::types::BlockNumber; -use cita_types::{Address, H256, U256}; -use std::sync::Arc; -// use ethjson; - -/// Simple vector of hashes, should be at most 256 items large, can be smaller if being used -/// for a block whose number is less than 257. -pub type LastHashes = Vec; - -/// Information concerning the execution environment for a message-call/contract-creation. -#[derive(Debug)] -pub struct EnvInfo { - /// The block number. - pub number: BlockNumber, - /// The block author. - pub author: Address, - /// The block timestamp. - pub timestamp: u64, - /// The block difficulty. - pub difficulty: U256, - /// The block gas limit. - pub gas_limit: U256, - /// The last 256 block hashes. - pub last_hashes: Arc, - /// The gas used. - pub gas_used: U256, - pub account_gas_limit: U256, -} - -impl Default for EnvInfo { - fn default() -> Self { - EnvInfo { - number: 0, - author: Address::default(), - timestamp: 0, - difficulty: 0.into(), - gas_limit: U256::from(u64::max_value()), - last_hashes: Arc::new(vec![]), - gas_used: 0.into(), - account_gas_limit: 0.into(), - } - } -} - -// impl From for EnvInfo { -// fn from(e: ethjson::vm::Env) -> Self { -// let number = e.number.into(); -// EnvInfo { -// number: number, -// author: e.author.into(), -// difficulty: e.difficulty.into(), -// gas_limit: e.gas_limit.into(), -// timestamp: e.timestamp.into(), -// last_hashes: Arc::new((1..cmp::min(number + 1, 257)).map(|i| format!("{}", number - i).as_bytes().crypt_hash()).collect()), -// gas_used: U256::default(), -// } -// } -// } - -#[cfg(test)] -mod tests { - use super::*; - - // #[test] - // fn it_serializes_form_json() { - // let env_info = EnvInfo::from(ethjson::vm::Env { - // author: ethjson::hash::Address(Address::from_str("000000f00000000f000000000000f00000000f00").unwrap()), - // number: ethjson::uint::Uint(U256::from(1_112_339)), - // difficulty: ethjson::uint::Uint(U256::from(50_000)), - // gas_limit: ethjson::uint::Uint(U256::from(40_000)), - // timestamp: ethjson::uint::Uint(U256::from(1_100)) - // }); - - // assert_eq!(env_info.number, 1112339); - // assert_eq!(env_info.author, Address::from_str("000000f00000000f000000000000f00000000f00").unwrap()); - // assert_eq!(env_info.gas_limit, 40000.into()); - // assert_eq!(env_info.difficulty, 50000.into()); - // assert_eq!(env_info.gas_used, 0.into()); - // } - - #[test] - fn it_can_be_created_as_default() { - let default_env_info = EnvInfo::default(); - - assert_eq!(default_env_info.difficulty, 0.into()); - } -} diff --git a/cita-executor/evm/src/error.rs b/cita-executor/evm/src/error.rs deleted file mode 100644 index db5d6fe04..000000000 --- a/cita-executor/evm/src/error.rs +++ /dev/null @@ -1,103 +0,0 @@ -// Copyright 2015-2017 Parity Technologies (UK) Ltd. -// This file is part of Parity. - -// This software is free software: you can redistribute it and/or modify -// it under the terms of the GNU General Public License as published by -// the Free Software Foundation, either version 3 of the License, or -// (at your option) any later version. - -// This software 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 General Public License for more details. - -// You should have received a copy of the GNU General Public License -// along with Parity. If not, see . - -//! Evm errors - -use crate::cita_db::trie; -use std::fmt; - -#[derive(Debug, Clone, PartialEq)] -pub enum Error { - /// `OutOfGas` is returned when transaction execution runs out of gas. - /// The state should be reverted to the state from before the - /// transaction execution. But it does not mean that transaction - /// was invalid. Balance still should be transfered and nonce - /// should be increased. - OutOfGas, - /// `BadJumpDestination` is returned when execution tried to move - /// to position that wasn't marked with JUMPDEST instruction - BadJumpDestination { - /// Position the code tried to jump to. - destination: usize, - }, - /// `BadInstructions` is returned when given instruction is not supported - BadInstruction { - /// Unrecognized opcode - instruction: u8, - }, - /// `StackUnderflow` when there is not enough stack elements to execute instruction - StackUnderflow { - /// Invoked instruction - instruction: &'static str, - /// How many stack elements was requested by instruction - wanted: usize, - /// How many elements were on stack - on_stack: usize, - }, - /// When execution would exceed defined Stack Limit - OutOfStack { - /// Invoked instruction - instruction: &'static str, - /// How many stack elements instruction wanted to push - wanted: usize, - /// What was the stack limit - limit: usize, - }, - /// When execution tries to modify the state in static context - MutableCallInStaticContext, - /// Likely to cause consensus issues. - Internal(String), - /// Out of bounds access in RETURNDATACOPY. - OutOfBounds, - /// Execution has been reverted with REVERT. - Reverted, -} - -impl From> for Error { - fn from(err: Box) -> Self { - Error::Internal(format!("Internal error: {}", err)) - } -} - -impl fmt::Display for Error { - fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { - use self::Error::*; - match *self { - OutOfGas => write!(f, "Out of gas"), - BadJumpDestination { destination } => { - write!(f, "Bad jump destination {:x}", destination) - } - BadInstruction { instruction } => write!(f, "Bad instruction {:x}", instruction), - StackUnderflow { - instruction, - wanted, - on_stack, - } => write!(f, "Stack underflow {} {}/{}", instruction, wanted, on_stack), - OutOfStack { - instruction, - wanted, - limit, - } => write!(f, "Out of stack {} {}/{}", instruction, wanted, limit), - Internal(ref msg) => write!(f, "Internal error: {}", msg), - MutableCallInStaticContext => write!(f, "Mutable call in static context"), - OutOfBounds => write!(f, "Out of bounds"), - Reverted => write!(f, "Reverted"), - } - } -} - -/// A specialized version of Result over EVM errors. -pub type Result = ::std::result::Result; diff --git a/cita-executor/evm/src/evm.rs b/cita-executor/evm/src/evm.rs deleted file mode 100644 index afc72609e..000000000 --- a/cita-executor/evm/src/evm.rs +++ /dev/null @@ -1,229 +0,0 @@ -// Copyright 2015-2017 Parity Technologies (UK) Ltd. -// This file is part of Parity. - -// This software is free software: you can redistribute it and/or modify -// it under the terms of the GNU General Public License as published by -// the Free Software Foundation, either version 3 of the License, or -// (at your option) any later version. - -// This software 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 General Public License for more details. - -// You should have received a copy of the GNU General Public License -// along with Parity. If not, see . - -//! Evm interface. - -use crate::action_params::ActionParams; -use crate::error::{Error, Result}; -use crate::return_data::{GasLeft, ReturnData}; -use crate::Ext; -use cita_types::{U128, U256, U512}; -use std::{cmp, fmt, ops}; - -/// Finalization result. Gas Left: either it is a known value, or it needs to be computed by processing -/// a return instruction. -#[derive(Debug)] -pub struct FinalizationResult { - /// Final amount of gas left. - pub gas_left: U256, - /// Apply execution state changes or revert them. - pub apply_state: bool, - /// Return data buffer. - pub return_data: ReturnData, -} - -/// Types that can be "finalized" using an EVM. -/// -/// In practice, this is just used to define an inherent impl on -/// `Reult>`. -pub trait Finalize { - /// Consume the externalities, call return if necessary, and produce call result. - fn finalize(self, ext: E) -> Result; -} - -impl Finalize for Result { - fn finalize(self, ext: E) -> Result { - match self { - Ok(GasLeft::Known(gas_left)) => Ok(FinalizationResult { - gas_left, - apply_state: true, - return_data: ReturnData::empty(), - }), - Ok(GasLeft::NeedsReturn { - gas_left, - data, - apply_state, - }) => ext - .ret(&gas_left, &data, apply_state) - .map(|gas_left| FinalizationResult { - gas_left, - apply_state, - return_data: data, - }), - Err(err) => Err(err), - } - } -} - -/// Cost calculation type. For low-gas usage we calculate costs using usize instead of U256 -pub trait CostType: - Sized - + From - + Copy - + ops::Mul - + ops::Div - + ops::Add - + ops::Sub - + ops::Shr - + ops::Shl - + cmp::Ord - + fmt::Debug -{ - /// Converts this cost into `U256` - fn as_u256(&self) -> U256; - /// Tries to fit `U256` into this `Cost` type - fn from_u256(val: U256) -> Result; - /// Convert to usize (may panic) - fn as_usize(&self) -> usize; - /// Add with overflow - fn overflow_add(self, other: Self) -> (Self, bool); - /// Multiple with overflow - fn overflow_mul(self, other: Self) -> (Self, bool); - /// Single-step full multiplication and shift: `(self*other) >> shr` - /// Should not overflow on intermediate steps - fn overflow_mul_shr(self, other: Self, shr: usize) -> (Self, bool); -} - -impl CostType for U256 { - fn as_u256(&self) -> U256 { - *self - } - - fn from_u256(val: U256) -> Result { - Ok(val) - } - - fn as_usize(&self) -> usize { - self.as_u64() as usize - } - - fn overflow_add(self, other: Self) -> (Self, bool) { - self.overflowing_add(other) - } - - fn overflow_mul(self, other: Self) -> (Self, bool) { - self.overflowing_mul(other) - } - - fn overflow_mul_shr(self, other: Self, shr: usize) -> (Self, bool) { - let x = self.full_mul(other); - let U512(parts) = x; - let overflow = (parts[4] | parts[5] | parts[6] | parts[7]) > 0; - let U512(parts) = x >> shr; - (U256([parts[0], parts[1], parts[2], parts[3]]), overflow) - } -} - -impl CostType for usize { - fn as_u256(&self) -> U256 { - U256::from(*self) - } - - fn from_u256(val: U256) -> Result { - let res = val.low_u64() as usize; - - // validate if value fits into usize - if U256::from(res) != val { - return Err(Error::OutOfGas); - } - - Ok(res) - } - - fn as_usize(&self) -> usize { - *self - } - - fn overflow_add(self, other: Self) -> (Self, bool) { - self.overflowing_add(other) - } - - fn overflow_mul(self, other: Self) -> (Self, bool) { - self.overflowing_mul(other) - } - - fn overflow_mul_shr(self, other: Self, shr: usize) -> (Self, bool) { - let (c, o) = U128::from(self).overflowing_mul(U128::from(other)); - let U128(parts) = c; - let overflow = o | (parts[1] > 0); - let U128(parts) = c >> shr; - let result = parts[0] as usize; - let overflow = overflow | (parts[0] > result as u64); - (result, overflow) - } -} - -/// Evm interface -pub trait Evm { - /// This function should be used to execute transaction. - /// - /// It returns either an error, a known amount of gas left, or parameters to be used - /// to compute the final gas left. - fn exec(&mut self, params: &ActionParams, ext: &mut Ext) -> Result; -} - -#[cfg(test)] -mod tests { - use super::CostType; - use cita_types::U256; - - #[test] - fn should_calculate_overflow_mul_shr_without_overflow() { - // given - let num = 1048576; - - // when - let (res1, o1) = U256::from(num).overflow_mul_shr(U256::from(num), 20); - let (res2, o2) = num.overflow_mul_shr(num, 20); - - // then - assert_eq!(res1, U256::from(num)); - assert!(!o1); - assert_eq!(res2, num); - assert!(!o2); - } - - #[test] - fn should_calculate_overflow_mul_shr_with_overflow() { - // given - let max = u64::max_value(); - let num1 = U256([max, max, max, max]); - let num2 = usize::max_value(); - - // when - let (res1, o1) = num1.overflow_mul_shr(num1, 256); - let (res2, o2) = num2.overflow_mul_shr(num2, 64); - - // then - assert_eq!(res2, num2 - 1); - assert!(o2); - - assert_eq!(res1, !U256::zero() - U256::one()); - assert!(o1); - } - - #[test] - fn should_validate_u256_to_usize_conversion() { - // given - let v = U256::from(usize::max_value()) + U256::from(1); - - // when - let res = usize::from_u256(v); - - // then - assert!(res.is_err()); - } -} diff --git a/cita-executor/evm/src/ext.rs b/cita-executor/evm/src/ext.rs deleted file mode 100644 index bf04503d5..000000000 --- a/cita-executor/evm/src/ext.rs +++ /dev/null @@ -1,152 +0,0 @@ -// Copyright 2015-2017 Parity Technologies (UK) Ltd. -// This file is part of Parity. - -// This software is free software: you can redistribute it and/or modify -// it under the terms of the GNU General Public License as published by -// the Free Software Foundation, either version 3 of the License, or -// (at your option) any later version. - -// This software 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 General Public License for more details. - -// You should have received a copy of the GNU General Public License -// along with Parity. If not, see . - -//! Interface for Evm externalities. - -use crate::call_type::CallType; -use crate::env_info::*; -use crate::error::Result; -use crate::return_data::ReturnData; -use crate::Schedule; -use cita_types::{Address, H256, U256}; -use std::sync::Arc; -use util::*; - -/// Result of externalities create function. -pub enum ContractCreateResult { - /// Returned when creation was successfull. - /// Contains an address of newly created contract and gas left. - Created(Address, U256), - /// Returned when contract creation failed. - /// VM doesn't have to know the reason. - Failed, - /// Returned when contract creation failed. - /// VM doesn't have to know the reason. - FailedInStaticCall, - /// Returned when message call was reverted. - /// Contains gas left and output data. - Reverted(U256, ReturnData), -} - -/// Result of externalities call function. -pub enum MessageCallResult { - /// Returned when message call was successfull. - /// Contains gas left and output data. - Success(U256, ReturnData), - /// Returned when message call failed. - /// VM doesn't have to know the reason. - Failed, - /// Returned when message call was reverted. - /// Contains gas left and output data. - Reverted(U256, ReturnData), -} - -/// Externalities interface for EVMs -pub trait Ext { - /// Returns a value for given key. - fn storage_at(&self, key: &H256) -> Result; - - /// Stores a value for given key. - fn set_storage(&mut self, key: H256, value: H256) -> Result<()>; - - /// Determine whether an account exists. - fn exists(&self, address: &Address) -> Result; - - /// Determine whether an account exists and is not null (zero balance/nonce, no code). - fn exists_and_not_null(&self, address: &Address) -> Result; - - /// Balance of the origin account. - fn origin_balance(&self) -> Result; - - /// Returns address balance. - fn balance(&self, address: &Address) -> Result; - - /// Returns the hash of one of the 256 most recent complete blocks. - fn blockhash(&self, number: &U256) -> H256; - - /// Creates new contract. - /// - /// Returns gas_left and contract address if contract creation was succesfull. - fn create(&mut self, gas: &U256, value: &U256, code: &[u8]) -> ContractCreateResult; - - /// Message call. - /// - /// Returns Err, if we run out of gas. - /// Otherwise returns call_result which contains gas left - /// and true if subcall was successfull. - #[allow(unknown_lints, clippy::too_many_arguments)] // TODO clippy - fn call( - &mut self, - gas: &U256, - sender_address: &Address, - receive_address: &Address, - value: Option, - data: &[u8], - code_address: &Address, - output: &mut [u8], - call_type: CallType, - ) -> MessageCallResult; - - /// Returns code at given address - fn extcode(&self, address: &Address) -> Result>; - - /// Returns code size at given address - fn extcodesize(&self, address: &Address) -> Result; - - /// Creates log entry with given topics and data - fn log(&mut self, topics: Vec, data: &[u8]) -> Result<()>; - - /// Should be called when transaction calls `RETURN` opcode. - /// Returns gas_left if cost of returning the data is not too high. - fn ret(self, gas: &U256, data: &ReturnData, apply_state: bool) -> Result; - - /// Should be called when contract commits suicide. - /// Address to which funds should be refunded. - fn suicide(&mut self, refund_address: &Address) -> Result<()>; - - /// Returns schedule. - fn schedule(&self) -> &Schedule; - - /// Returns environment info. - fn env_info(&self) -> &EnvInfo; - - /// Returns current depth of execution. - /// - /// If contract A calls contract B, and contract B calls C, - /// then A depth is 0, B is 1, C is 2 and so on. - fn depth(&self) -> usize; - - /// Increments sstore refunds count by 1. - fn inc_sstore_clears(&mut self); - - /// Prepare to trace an operation. Passthrough for the VM trace. - fn trace_prepare_execute(&mut self, _pc: usize, _instruction: u8, _gas_cost: &U256) -> bool { - false - } - - /// Trace the finalised execution of a single instruction. - fn trace_executed( - &mut self, - _gas_used: U256, - _stack_push: &[U256], - _mem_diff: Option<(usize, &[u8])>, - _store_diff: Option<(U256, U256)>, - ) { - } - - /// Check if running in static context. - fn is_static(&self) -> bool; -} diff --git a/cita-executor/evm/src/factory.rs b/cita-executor/evm/src/factory.rs deleted file mode 100644 index 3eebb4fdf..000000000 --- a/cita-executor/evm/src/factory.rs +++ /dev/null @@ -1,225 +0,0 @@ -// Copyright 2015-2017 Parity Technologies (UK) Ltd. -// This file is part of Parity. - -// This software is free software: you can redistribute it and/or modify -// it under the terms of the GNU General Public License as published by -// the Free Software Foundation, either version 3 of the License, or -// (at your option) any later version. - -// This software 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 General Public License for more details. - -// You should have received a copy of the GNU General Public License -// along with Parity. If not, see . - -//! Evm factory. -//! -//! TODO: consider spliting it into two separate files. - -use super::interpreter::SharedCache; -use crate::evm::Evm; -use cita_types::U256; -use std::fmt; -use std::sync::Arc; - -#[derive(Debug, PartialEq, Clone)] -/// Type of EVM to use. -pub enum VMType { - /// JIT EVM - #[cfg(feature = "jit")] - Jit, - /// RUST EVM - Interpreter, -} - -impl fmt::Display for VMType { - #[cfg(feature = "jit")] - fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { - write!( - f, - "{}", - match *self { - VMType::Jit => "JIT", - VMType::Interpreter => "INT", - } - ) - } - #[cfg(not(feature = "jit"))] - fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { - write!( - f, - "{}", - match *self { - VMType::Interpreter => "INT", - } - ) - } -} - -impl Default for VMType { - fn default() -> Self { - VMType::Interpreter - } -} - -impl VMType { - /// Return all possible VMs (JIT, Interpreter) - #[cfg(feature = "jit")] - pub fn all() -> Vec { - vec![VMType::Jit, VMType::Interpreter] - } - - /// Return all possible VMs (Interpreter) - #[cfg(not(feature = "jit"))] - pub fn all() -> Vec { - vec![VMType::Interpreter] - } - - /// Return new jit if it's possible - #[cfg(not(feature = "jit"))] - pub fn jit() -> Option { - None - } - - /// Return new jit if it's possible - #[cfg(feature = "jit")] - pub fn jit() -> Option { - Some(VMType::Jit) - } -} - -/// Evm factory. Creates appropriate Evm. -#[derive(Clone)] -pub struct Factory { - evm: VMType, - evm_cache: Arc, -} - -impl Factory { - /// Create fresh instance of VM - /// Might choose implementation depending on supplied gas. - #[cfg(feature = "jit")] - pub fn create(&self, gas: U256) -> Box { - match self.evm { - VMType::Jit => Box::new(super::jit::JitEvm::default()), - VMType::Interpreter => { - if Self::can_fit_in_usize(gas) { - Box::new(super::interpreter::Interpreter::::new( - self.evm_cache.clone(), - )) - } else { - Box::new(super::interpreter::Interpreter::::new( - self.evm_cache.clone(), - )) - } - } - } - } - - /// Create fresh instance of VM - /// Might choose implementation depending on supplied gas. - #[cfg(not(feature = "jit"))] - pub fn create(&self, gas: U256) -> Box { - match self.evm { - VMType::Interpreter => { - if Self::can_fit_in_usize(gas) { - Box::new(super::interpreter::Interpreter::::new(Arc::clone( - &self.evm_cache, - ))) - } else { - Box::new(super::interpreter::Interpreter::::new(Arc::clone( - &self.evm_cache, - ))) - } - } - } - } - - /// Create new instance of specific `VMType` factory, with a size in bytes - /// for caching jump destinations. - pub fn new(evm: VMType, cache_size: usize) -> Self { - Factory { - evm, - evm_cache: Arc::new(SharedCache::new(cache_size)), - } - } - - fn can_fit_in_usize(gas: U256) -> bool { - gas == U256::from(gas.low_u64() as usize) - } -} - -impl Default for Factory { - /// Returns jitvm factory - #[cfg(all(feature = "jit", not(test)))] - fn default() -> Factory { - Factory { - evm: VMType::Jit, - evm_cache: Arc::new(SharedCache::default()), - } - } - - /// Returns native rust evm factory - #[cfg(any(not(feature = "jit"), test))] - fn default() -> Factory { - Factory { - evm: VMType::Interpreter, - evm_cache: Arc::new(SharedCache::default()), - } - } -} - -#[test] -fn test_create_vm() { - let _vm = Factory::default().create(U256::zero()); -} - -/// Create tests by injecting different VM factories -#[macro_export] -macro_rules! evm_test( - (ignorejit => $name_test: ident: $name_jit: ident, $name_int: ident) => { - #[test] - #[ignore] - #[cfg(feature = "jit")] - fn $name_jit() { - $name_test(Factory::new(VMType::Jit, 1024 * 32)); - } - #[test] - fn $name_int() { - $name_test(Factory::new(VMType::Interpreter, 1024 * 32)); - } - }; - ($name_test: ident: $name_jit: ident, $name_int: ident) => { - #[test] - #[cfg(feature = "jit")] - fn $name_jit() { - $name_test(Factory::new(VMType::Jit, 1024 * 32)); - } - #[test] - fn $name_int() { - $name_test(Factory::new(VMType::Interpreter, 1024 * 32)); - } - } -); - -/// Create ignored tests by injecting different VM factories -#[macro_export] -macro_rules! evm_test_ignore( - ($name_test: ident: $name_jit: ident, $name_int: ident) => { - #[test] - #[ignore] - #[cfg(feature = "jit")] - #[cfg(feature = "ignored-tests")] - fn $name_jit() { - $name_test(Factory::new(VMType::Jit, 1024 * 32)); - } - #[test] - #[ignore] - #[cfg(feature = "ignored-tests")] - fn $name_int() { - $name_test(Factory::new(VMType::Interpreter, 1024 * 32)); - } - } -); diff --git a/cita-executor/evm/src/fake_tests.rs b/cita-executor/evm/src/fake_tests.rs deleted file mode 100644 index 2ebc58d6d..000000000 --- a/cita-executor/evm/src/fake_tests.rs +++ /dev/null @@ -1,204 +0,0 @@ -// Copyright 2015-2017 Parity Technologies (UK) Ltd. -// This file is part of Parity. - -// This software is free software: you can redistribute it and/or modify -// it under the terms of the GNU General Public License as published by -// the Free Software Foundation, either version 3 of the License, or -// (at your option) any later version. - -// This software 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 General Public License for more details. - -// You should have received a copy of the GNU General Public License -// along with Parity. If not, see . - -use crate::call_type::CallType; -use crate::env_info::EnvInfo; -use crate::error; -use crate::ext::{ContractCreateResult, Ext, MessageCallResult}; -use crate::return_data::{GasLeft, ReturnData}; -use crate::schedule::Schedule; -use cita_types::{Address, H256, U256}; -use std::collections::{HashMap, HashSet}; -use std::sync::Arc; -use util::*; - -pub struct FakeLogEntry { - pub topics: Vec, - pub data: Bytes, -} - -#[derive(PartialEq, Eq, Hash, Debug)] -pub enum FakeCallType { - Call, - Create, -} - -#[derive(PartialEq, Eq, Hash, Debug)] -pub struct FakeCall { - pub call_type: FakeCallType, - pub gas: U256, - pub sender_address: Option
, - pub receive_address: Option
, - pub value: Option, - pub data: Bytes, - pub code_address: Option
, -} - -/// Fake externalities test structure. -/// -/// Can't do recursive calls. -#[derive(Default)] -pub struct FakeExt { - pub sstore_clears: usize, - pub depth: usize, - pub store: HashMap, - pub blockhashes: HashMap, - pub codes: HashMap>, - pub logs: Vec, - pub suicides: HashSet
, - pub info: EnvInfo, - pub schedule: Schedule, - pub balances: HashMap, - pub calls: HashSet, - pub is_static: bool, -} - -// similar to the normal `finalize` function, but ignoring NeedsReturn. -pub fn test_finalize(res: Result) -> Result { - match res { - Ok(GasLeft::Known(gas)) => Ok(gas), - Ok(GasLeft::NeedsReturn { .. }) => unimplemented!(), // since ret is unimplemented. - Err(e) => Err(e), - } -} - -impl FakeExt { - pub fn new() -> Self { - FakeExt::default() - } -} - -impl Default for Schedule { - fn default() -> Self { - Schedule::new_v1() - } -} - -impl Ext for FakeExt { - fn storage_at(&self, key: &H256) -> error::Result { - Ok(self.store.get(key).cloned().unwrap_or_default()) - } - - fn set_storage(&mut self, key: H256, value: H256) -> error::Result<()> { - self.store.insert(key, value); - Ok(()) - } - - fn exists(&self, address: &Address) -> error::Result { - Ok(self.balances.contains_key(address)) - } - - fn exists_and_not_null(&self, address: &Address) -> error::Result { - Ok(self.balances.get(address).map_or(false, |b| !b.is_zero())) - } - - fn origin_balance(&self) -> error::Result { - Ok(U256::from(0)) - } - - fn balance(&self, address: &Address) -> error::Result { - Ok(self.balances[address]) - } - - fn blockhash(&self, number: &U256) -> H256 { - self.blockhashes.get(number).cloned().unwrap_or_default() - } - - fn create(&mut self, gas: &U256, value: &U256, code: &[u8]) -> ContractCreateResult { - self.calls.insert(FakeCall { - call_type: FakeCallType::Create, - gas: *gas, - sender_address: None, - receive_address: None, - value: Some(*value), - data: code.to_vec(), - code_address: None, - }); - ContractCreateResult::Failed - } - - fn call( - &mut self, - gas: &U256, - sender_address: &Address, - receive_address: &Address, - value: Option, - data: &[u8], - code_address: &Address, - _output: &mut [u8], - _call_type: CallType, - ) -> MessageCallResult { - self.calls.insert(FakeCall { - call_type: FakeCallType::Call, - gas: *gas, - sender_address: Some(*sender_address), - receive_address: Some(*receive_address), - value, - data: data.to_vec(), - code_address: Some(*code_address), - }); - MessageCallResult::Success(*gas, ReturnData::empty()) - } - - fn extcode(&self, address: &Address) -> error::Result> { - Ok(self - .codes - .get(address) - .unwrap_or(&Arc::new(Bytes::new())) - .clone()) - } - - fn extcodesize(&self, address: &Address) -> error::Result { - Ok(self.codes.get(address).map_or(0, |c| c.len())) - } - - fn log(&mut self, topics: Vec, data: &[u8]) -> error::Result<()> { - self.logs.push(FakeLogEntry { - topics, - data: data.to_vec(), - }); - Ok(()) - } - - fn ret(self, _gas: &U256, _data: &ReturnData, _apply_state: bool) -> error::Result { - unimplemented!(); - } - - fn suicide(&mut self, _refund_address: &Address) -> error::Result<()> { - self.suicides.insert(_refund_address.clone()); - Ok(()) - } - - fn schedule(&self) -> &Schedule { - &self.schedule - } - - fn env_info(&self) -> &EnvInfo { - &self.info - } - - fn depth(&self) -> usize { - self.depth - } - - fn is_static(&self) -> bool { - self.is_static - } - - fn inc_sstore_clears(&mut self) { - self.sstore_clears += 1; - } -} diff --git a/cita-executor/evm/src/instructions.rs b/cita-executor/evm/src/instructions.rs deleted file mode 100644 index db01f6759..000000000 --- a/cita-executor/evm/src/instructions.rs +++ /dev/null @@ -1,648 +0,0 @@ -// Copyright 2015-2017 Parity Technologies (UK) Ltd. -// This file is part of Parity. - -// This software is free software: you can redistribute it and/or modify -// it under the terms of the GNU General Public License as published by -// the Free Software Foundation, either version 3 of the License, or -// (at your option) any later version. - -// This software 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 General Public License for more details. - -// You should have received a copy of the GNU General Public License -// along with Parity. If not, see . - -//! VM Instructions list and utility functions - -pub type Instruction = u8; - -/// Returns true if given instruction is `PUSHN` instruction. -pub fn is_push(i: Instruction) -> bool { - i >= PUSH1 && i <= PUSH32 -} - -/// Returns number of bytes to read for `PUSHN` instruction -/// PUSH1 -> 1 -pub fn get_push_bytes(i: Instruction) -> usize { - assert!(is_push(i), "Only for PUSH instructions."); - (i - PUSH1 + 1) as usize -} - -#[test] -fn test_get_push_bytes() { - assert_eq!(get_push_bytes(PUSH1), 1); - assert_eq!(get_push_bytes(PUSH3), 3); - assert_eq!(get_push_bytes(PUSH32), 32); -} - -/// Returns stack position of item to duplicate -/// DUP1 -> 0 -pub fn get_dup_position(i: Instruction) -> usize { - assert!(i >= DUP1 && i <= DUP16); - (i - DUP1) as usize -} - -#[test] -fn test_get_dup_position() { - assert_eq!(get_dup_position(DUP1), 0); - assert_eq!(get_dup_position(DUP5), 4); - assert_eq!(get_dup_position(DUP10), 9); -} - -/// Returns stack position of item to SWAP top with -/// SWAP1 -> 1 -pub fn get_swap_position(i: Instruction) -> usize { - assert!(i >= SWAP1 && i <= SWAP16); - (i - SWAP1 + 1) as usize -} - -#[test] -fn test_get_swap_position() { - assert_eq!(get_swap_position(SWAP1), 1); - assert_eq!(get_swap_position(SWAP5), 5); - assert_eq!(get_swap_position(SWAP10), 10); -} - -/// Returns number of topcis to take from stack -/// LOG0 -> 0 -pub fn get_log_topics(i: Instruction) -> usize { - assert!(i >= LOG0 && i <= LOG4); - (i - LOG0) as usize -} - -#[test] -fn test_get_log_topics() { - assert_eq!(get_log_topics(LOG0), 0); - assert_eq!(get_log_topics(LOG2), 2); - assert_eq!(get_log_topics(LOG4), 4); -} - -#[derive(PartialEq, Clone, Copy)] -pub enum GasPriceTier { - /// 0 Zero - Zero, - /// 2 Quick - Base, - /// 3 Fastest - VeryLow, - /// 5 Fast - Low, - /// 8 Mid - Mid, - /// 10 Slow - High, - /// 20 Ext - Ext, - /// Multiparam or otherwise special - Special, - /// Invalid - Invalid, -} - -impl Default for GasPriceTier { - fn default() -> Self { - GasPriceTier::Invalid - } -} - -/// Returns the index in schedule for specific `GasPriceTier` -pub fn get_tier_idx(tier: GasPriceTier) -> usize { - match tier { - GasPriceTier::Zero => 0, - GasPriceTier::Base => 1, - GasPriceTier::VeryLow => 2, - GasPriceTier::Low => 3, - GasPriceTier::Mid => 4, - GasPriceTier::High => 5, - GasPriceTier::Ext => 6, - GasPriceTier::Special => 7, - GasPriceTier::Invalid => 8, - } -} - -#[derive(Copy, Clone, Default)] -pub struct InstructionInfo { - pub name: &'static str, - pub additional: usize, - pub args: usize, - pub ret: usize, - pub side_effects: bool, - pub tier: GasPriceTier, -} - -impl InstructionInfo { - pub fn new( - name: &'static str, - additional: usize, - args: usize, - ret: usize, - side_effects: bool, - tier: GasPriceTier, - ) -> Self { - InstructionInfo { - name, - additional, - args, - ret, - side_effects, - tier, - } - } -} - -lazy_static! { - pub static ref INSTRUCTIONS: [InstructionInfo; 0x100] = { - let mut arr = [InstructionInfo::default(); 0x100]; - arr[STOP as usize] = InstructionInfo::new("STOP", 0, 0, 0, true, GasPriceTier::Zero); - arr[ADD as usize] = InstructionInfo::new("ADD", 0, 2, 1, false, GasPriceTier::VeryLow); - arr[SUB as usize] = InstructionInfo::new("SUB", 0, 2, 1, false, GasPriceTier::VeryLow); - arr[MUL as usize] = InstructionInfo::new("MUL", 0, 2, 1, false, GasPriceTier::Low); - arr[DIV as usize] = InstructionInfo::new("DIV", 0, 2, 1, false, GasPriceTier::Low); - arr[SDIV as usize] = InstructionInfo::new("SDIV", 0, 2, 1, false, GasPriceTier::Low); - arr[MOD as usize] = InstructionInfo::new("MOD", 0, 2, 1, false, GasPriceTier::Low); - arr[SMOD as usize] = InstructionInfo::new("SMOD", 0, 2, 1, false, GasPriceTier::Low); - arr[EXP as usize] = InstructionInfo::new("EXP", 0, 2, 1, false, GasPriceTier::Special); - arr[NOT as usize] = InstructionInfo::new("NOT", 0, 1, 1, false, GasPriceTier::VeryLow); - arr[LT as usize] = InstructionInfo::new("LT", 0, 2, 1, false, GasPriceTier::VeryLow); - arr[GT as usize] = InstructionInfo::new("GT", 0, 2, 1, false, GasPriceTier::VeryLow); - arr[SLT as usize] = InstructionInfo::new("SLT", 0, 2, 1, false, GasPriceTier::VeryLow); - arr[SGT as usize] = InstructionInfo::new("SGT", 0, 2, 1, false, GasPriceTier::VeryLow); - arr[EQ as usize] = InstructionInfo::new("EQ", 0, 2, 1, false, GasPriceTier::VeryLow); - arr[ISZERO as usize] = - InstructionInfo::new("ISZERO", 0, 1, 1, false, GasPriceTier::VeryLow); - arr[AND as usize] = InstructionInfo::new("AND", 0, 2, 1, false, GasPriceTier::VeryLow); - arr[OR as usize] = InstructionInfo::new("OR", 0, 2, 1, false, GasPriceTier::VeryLow); - arr[XOR as usize] = InstructionInfo::new("XOR", 0, 2, 1, false, GasPriceTier::VeryLow); - arr[BYTE as usize] = InstructionInfo::new("BYTE", 0, 2, 1, false, GasPriceTier::VeryLow); - arr[SHL as usize] = InstructionInfo::new("SHL", 0, 2, 1, false, GasPriceTier::VeryLow); - arr[SHR as usize] = InstructionInfo::new("SHR", 0, 2, 1, false, GasPriceTier::VeryLow); - arr[SAR as usize] = InstructionInfo::new("SAR", 0, 2, 1, false, GasPriceTier::VeryLow); - arr[ADDMOD as usize] = InstructionInfo::new("ADDMOD", 0, 3, 1, false, GasPriceTier::Mid); - arr[MULMOD as usize] = InstructionInfo::new("MULMOD", 0, 3, 1, false, GasPriceTier::Mid); - arr[SIGNEXTEND as usize] = - InstructionInfo::new("SIGNEXTEND", 0, 2, 1, false, GasPriceTier::Low); - arr[SHA3 as usize] = InstructionInfo::new("SHA3", 0, 2, 1, false, GasPriceTier::Special); - arr[RETURNDATASIZE as usize] = - InstructionInfo::new("RETURNDATASIZE", 0, 0, 1, false, GasPriceTier::Base); - arr[RETURNDATACOPY as usize] = - InstructionInfo::new("RETURNDATACOPY", 0, 3, 0, true, GasPriceTier::VeryLow); - arr[ADDRESS as usize] = InstructionInfo::new("ADDRESS", 0, 0, 1, false, GasPriceTier::Base); - arr[BALANCE as usize] = - InstructionInfo::new("BALANCE", 0, 1, 1, false, GasPriceTier::Special); - arr[ORIGIN as usize] = InstructionInfo::new("ORIGIN", 0, 0, 1, false, GasPriceTier::Base); - arr[CALLER as usize] = InstructionInfo::new("CALLER", 0, 0, 1, false, GasPriceTier::Base); - arr[CALLVALUE as usize] = - InstructionInfo::new("CALLVALUE", 0, 0, 1, false, GasPriceTier::Base); - arr[CALLDATALOAD as usize] = - InstructionInfo::new("CALLDATALOAD", 0, 1, 1, false, GasPriceTier::VeryLow); - arr[CALLDATASIZE as usize] = - InstructionInfo::new("CALLDATASIZE", 0, 0, 1, false, GasPriceTier::Base); - arr[CALLDATACOPY as usize] = - InstructionInfo::new("CALLDATACOPY", 0, 3, 0, true, GasPriceTier::VeryLow); - arr[CODESIZE as usize] = - InstructionInfo::new("CODESIZE", 0, 0, 1, false, GasPriceTier::Base); - arr[CODECOPY as usize] = - InstructionInfo::new("CODECOPY", 0, 3, 0, true, GasPriceTier::VeryLow); - arr[GASPRICE as usize] = - InstructionInfo::new("GASPRICE", 0, 0, 1, false, GasPriceTier::Base); - arr[EXTCODESIZE as usize] = - InstructionInfo::new("EXTCODESIZE", 0, 1, 1, false, GasPriceTier::Special); - arr[EXTCODECOPY as usize] = - InstructionInfo::new("EXTCODECOPY", 0, 4, 0, true, GasPriceTier::Special); - arr[BLOCKHASH as usize] = - InstructionInfo::new("BLOCKHASH", 0, 1, 1, false, GasPriceTier::Ext); - arr[COINBASE as usize] = - InstructionInfo::new("COINBASE", 0, 0, 1, false, GasPriceTier::Base); - arr[TIMESTAMP as usize] = - InstructionInfo::new("TIMESTAMP", 0, 0, 1, false, GasPriceTier::Base); - arr[NUMBER as usize] = InstructionInfo::new("NUMBER", 0, 0, 1, false, GasPriceTier::Base); - arr[DIFFICULTY as usize] = - InstructionInfo::new("DIFFICULTY", 0, 0, 1, false, GasPriceTier::Base); - arr[GASLIMIT as usize] = - InstructionInfo::new("GASLIMIT", 0, 0, 1, false, GasPriceTier::Base); - arr[POP as usize] = InstructionInfo::new("POP", 0, 1, 0, false, GasPriceTier::Base); - arr[MLOAD as usize] = InstructionInfo::new("MLOAD", 0, 1, 1, false, GasPriceTier::VeryLow); - arr[MSTORE as usize] = InstructionInfo::new("MSTORE", 0, 2, 0, true, GasPriceTier::VeryLow); - arr[MSTORE8 as usize] = - InstructionInfo::new("MSTORE8", 0, 2, 0, true, GasPriceTier::VeryLow); - arr[SLOAD as usize] = InstructionInfo::new("SLOAD", 0, 1, 1, false, GasPriceTier::Special); - arr[SSTORE as usize] = InstructionInfo::new("SSTORE", 0, 2, 0, true, GasPriceTier::Special); - arr[JUMP as usize] = InstructionInfo::new("JUMP", 0, 1, 0, true, GasPriceTier::Mid); - arr[JUMPI as usize] = InstructionInfo::new("JUMPI", 0, 2, 0, true, GasPriceTier::High); - arr[PC as usize] = InstructionInfo::new("PC", 0, 0, 1, false, GasPriceTier::Base); - arr[MSIZE as usize] = InstructionInfo::new("MSIZE", 0, 0, 1, false, GasPriceTier::Base); - arr[GAS as usize] = InstructionInfo::new("GAS", 0, 0, 1, false, GasPriceTier::Base); - arr[JUMPDEST as usize] = - InstructionInfo::new("JUMPDEST", 0, 0, 0, true, GasPriceTier::Special); - arr[PUSH1 as usize] = InstructionInfo::new("PUSH1", 1, 0, 1, false, GasPriceTier::VeryLow); - arr[PUSH2 as usize] = InstructionInfo::new("PUSH2", 2, 0, 1, false, GasPriceTier::VeryLow); - arr[PUSH3 as usize] = InstructionInfo::new("PUSH3", 3, 0, 1, false, GasPriceTier::VeryLow); - arr[PUSH4 as usize] = InstructionInfo::new("PUSH4", 4, 0, 1, false, GasPriceTier::VeryLow); - arr[PUSH5 as usize] = InstructionInfo::new("PUSH5", 5, 0, 1, false, GasPriceTier::VeryLow); - arr[PUSH6 as usize] = InstructionInfo::new("PUSH6", 6, 0, 1, false, GasPriceTier::VeryLow); - arr[PUSH7 as usize] = InstructionInfo::new("PUSH7", 7, 0, 1, false, GasPriceTier::VeryLow); - arr[PUSH8 as usize] = InstructionInfo::new("PUSH8", 8, 0, 1, false, GasPriceTier::VeryLow); - arr[PUSH9 as usize] = InstructionInfo::new("PUSH9", 9, 0, 1, false, GasPriceTier::VeryLow); - arr[PUSH10 as usize] = - InstructionInfo::new("PUSH10", 10, 0, 1, false, GasPriceTier::VeryLow); - arr[PUSH11 as usize] = - InstructionInfo::new("PUSH11", 11, 0, 1, false, GasPriceTier::VeryLow); - arr[PUSH12 as usize] = - InstructionInfo::new("PUSH12", 12, 0, 1, false, GasPriceTier::VeryLow); - arr[PUSH13 as usize] = - InstructionInfo::new("PUSH13", 13, 0, 1, false, GasPriceTier::VeryLow); - arr[PUSH14 as usize] = - InstructionInfo::new("PUSH14", 14, 0, 1, false, GasPriceTier::VeryLow); - arr[PUSH15 as usize] = - InstructionInfo::new("PUSH15", 15, 0, 1, false, GasPriceTier::VeryLow); - arr[PUSH16 as usize] = - InstructionInfo::new("PUSH16", 16, 0, 1, false, GasPriceTier::VeryLow); - arr[PUSH17 as usize] = - InstructionInfo::new("PUSH17", 17, 0, 1, false, GasPriceTier::VeryLow); - arr[PUSH18 as usize] = - InstructionInfo::new("PUSH18", 18, 0, 1, false, GasPriceTier::VeryLow); - arr[PUSH19 as usize] = - InstructionInfo::new("PUSH19", 19, 0, 1, false, GasPriceTier::VeryLow); - arr[PUSH20 as usize] = - InstructionInfo::new("PUSH20", 20, 0, 1, false, GasPriceTier::VeryLow); - arr[PUSH21 as usize] = - InstructionInfo::new("PUSH21", 21, 0, 1, false, GasPriceTier::VeryLow); - arr[PUSH22 as usize] = - InstructionInfo::new("PUSH22", 22, 0, 1, false, GasPriceTier::VeryLow); - arr[PUSH23 as usize] = - InstructionInfo::new("PUSH23", 23, 0, 1, false, GasPriceTier::VeryLow); - arr[PUSH24 as usize] = - InstructionInfo::new("PUSH24", 24, 0, 1, false, GasPriceTier::VeryLow); - arr[PUSH25 as usize] = - InstructionInfo::new("PUSH25", 25, 0, 1, false, GasPriceTier::VeryLow); - arr[PUSH26 as usize] = - InstructionInfo::new("PUSH26", 26, 0, 1, false, GasPriceTier::VeryLow); - arr[PUSH27 as usize] = - InstructionInfo::new("PUSH27", 27, 0, 1, false, GasPriceTier::VeryLow); - arr[PUSH28 as usize] = - InstructionInfo::new("PUSH28", 28, 0, 1, false, GasPriceTier::VeryLow); - arr[PUSH29 as usize] = - InstructionInfo::new("PUSH29", 29, 0, 1, false, GasPriceTier::VeryLow); - arr[PUSH30 as usize] = - InstructionInfo::new("PUSH30", 30, 0, 1, false, GasPriceTier::VeryLow); - arr[PUSH31 as usize] = - InstructionInfo::new("PUSH31", 31, 0, 1, false, GasPriceTier::VeryLow); - arr[PUSH32 as usize] = - InstructionInfo::new("PUSH32", 32, 0, 1, false, GasPriceTier::VeryLow); - arr[DUP1 as usize] = InstructionInfo::new("DUP1", 0, 1, 2, false, GasPriceTier::VeryLow); - arr[DUP2 as usize] = InstructionInfo::new("DUP2", 0, 2, 3, false, GasPriceTier::VeryLow); - arr[DUP3 as usize] = InstructionInfo::new("DUP3", 0, 3, 4, false, GasPriceTier::VeryLow); - arr[DUP4 as usize] = InstructionInfo::new("DUP4", 0, 4, 5, false, GasPriceTier::VeryLow); - arr[DUP5 as usize] = InstructionInfo::new("DUP5", 0, 5, 6, false, GasPriceTier::VeryLow); - arr[DUP6 as usize] = InstructionInfo::new("DUP6", 0, 6, 7, false, GasPriceTier::VeryLow); - arr[DUP7 as usize] = InstructionInfo::new("DUP7", 0, 7, 8, false, GasPriceTier::VeryLow); - arr[DUP8 as usize] = InstructionInfo::new("DUP8", 0, 8, 9, false, GasPriceTier::VeryLow); - arr[DUP9 as usize] = InstructionInfo::new("DUP9", 0, 9, 10, false, GasPriceTier::VeryLow); - arr[DUP10 as usize] = - InstructionInfo::new("DUP10", 0, 10, 11, false, GasPriceTier::VeryLow); - arr[DUP11 as usize] = - InstructionInfo::new("DUP11", 0, 11, 12, false, GasPriceTier::VeryLow); - arr[DUP12 as usize] = - InstructionInfo::new("DUP12", 0, 12, 13, false, GasPriceTier::VeryLow); - arr[DUP13 as usize] = - InstructionInfo::new("DUP13", 0, 13, 14, false, GasPriceTier::VeryLow); - arr[DUP14 as usize] = - InstructionInfo::new("DUP14", 0, 14, 15, false, GasPriceTier::VeryLow); - arr[DUP15 as usize] = - InstructionInfo::new("DUP15", 0, 15, 16, false, GasPriceTier::VeryLow); - arr[DUP16 as usize] = - InstructionInfo::new("DUP16", 0, 16, 17, false, GasPriceTier::VeryLow); - arr[SWAP1 as usize] = InstructionInfo::new("SWAP1", 0, 2, 2, false, GasPriceTier::VeryLow); - arr[SWAP2 as usize] = InstructionInfo::new("SWAP2", 0, 3, 3, false, GasPriceTier::VeryLow); - arr[SWAP3 as usize] = InstructionInfo::new("SWAP3", 0, 4, 4, false, GasPriceTier::VeryLow); - arr[SWAP4 as usize] = InstructionInfo::new("SWAP4", 0, 5, 5, false, GasPriceTier::VeryLow); - arr[SWAP5 as usize] = InstructionInfo::new("SWAP5", 0, 6, 6, false, GasPriceTier::VeryLow); - arr[SWAP6 as usize] = InstructionInfo::new("SWAP6", 0, 7, 7, false, GasPriceTier::VeryLow); - arr[SWAP7 as usize] = InstructionInfo::new("SWAP7", 0, 8, 8, false, GasPriceTier::VeryLow); - arr[SWAP8 as usize] = InstructionInfo::new("SWAP8", 0, 9, 9, false, GasPriceTier::VeryLow); - arr[SWAP9 as usize] = - InstructionInfo::new("SWAP9", 0, 10, 10, false, GasPriceTier::VeryLow); - arr[SWAP10 as usize] = - InstructionInfo::new("SWAP10", 0, 11, 11, false, GasPriceTier::VeryLow); - arr[SWAP11 as usize] = - InstructionInfo::new("SWAP11", 0, 12, 12, false, GasPriceTier::VeryLow); - arr[SWAP12 as usize] = - InstructionInfo::new("SWAP12", 0, 13, 13, false, GasPriceTier::VeryLow); - arr[SWAP13 as usize] = - InstructionInfo::new("SWAP13", 0, 14, 14, false, GasPriceTier::VeryLow); - arr[SWAP14 as usize] = - InstructionInfo::new("SWAP14", 0, 15, 15, false, GasPriceTier::VeryLow); - arr[SWAP15 as usize] = - InstructionInfo::new("SWAP15", 0, 16, 16, false, GasPriceTier::VeryLow); - arr[SWAP16 as usize] = - InstructionInfo::new("SWAP16", 0, 17, 17, false, GasPriceTier::VeryLow); - arr[LOG0 as usize] = InstructionInfo::new("LOG0", 0, 2, 0, true, GasPriceTier::Special); - arr[LOG1 as usize] = InstructionInfo::new("LOG1", 0, 3, 0, true, GasPriceTier::Special); - arr[LOG2 as usize] = InstructionInfo::new("LOG2", 0, 4, 0, true, GasPriceTier::Special); - arr[LOG3 as usize] = InstructionInfo::new("LOG3", 0, 5, 0, true, GasPriceTier::Special); - arr[LOG4 as usize] = InstructionInfo::new("LOG4", 0, 6, 0, true, GasPriceTier::Special); - arr[CREATE as usize] = InstructionInfo::new("CREATE", 0, 3, 1, true, GasPriceTier::Special); - arr[CALL as usize] = InstructionInfo::new("CALL", 0, 7, 1, true, GasPriceTier::Special); - arr[CALLCODE as usize] = - InstructionInfo::new("CALLCODE", 0, 7, 1, true, GasPriceTier::Special); - arr[RETURN as usize] = InstructionInfo::new("RETURN", 0, 2, 0, true, GasPriceTier::Zero); - arr[DELEGATECALL as usize] = - InstructionInfo::new("DELEGATECALL", 0, 6, 1, true, GasPriceTier::Special); - arr[STATICCALL as usize] = - InstructionInfo::new("STATICCALL", 0, 6, 1, true, GasPriceTier::Special); - arr[SUICIDE as usize] = - InstructionInfo::new("SUICIDE", 0, 1, 0, true, GasPriceTier::Special); - arr[REVERT as usize] = InstructionInfo::new("REVERT", 0, 2, 0, true, GasPriceTier::Zero); - arr - }; -} - -/// Virtual machine bytecode instruction. -/// halts execution -pub const STOP: Instruction = 0x00; -/// addition operation -pub const ADD: Instruction = 0x01; -/// mulitplication operation -pub const MUL: Instruction = 0x02; -/// subtraction operation -pub const SUB: Instruction = 0x03; -/// integer division operation -pub const DIV: Instruction = 0x04; -/// signed integer division operation -pub const SDIV: Instruction = 0x05; -/// modulo remainder operation -pub const MOD: Instruction = 0x06; -/// signed modulo remainder operation -pub const SMOD: Instruction = 0x07; -/// unsigned modular addition -pub const ADDMOD: Instruction = 0x08; -/// unsigned modular multiplication -pub const MULMOD: Instruction = 0x09; -/// exponential operation -pub const EXP: Instruction = 0x0a; -/// extend length of signed integer -pub const SIGNEXTEND: Instruction = 0x0b; - -/// less-than comparision -pub const LT: Instruction = 0x10; -/// greater-than comparision -pub const GT: Instruction = 0x11; -/// signed less-than comparision -pub const SLT: Instruction = 0x12; -/// signed greater-than comparision -pub const SGT: Instruction = 0x13; -/// equality comparision -pub const EQ: Instruction = 0x14; -/// simple not operator -pub const ISZERO: Instruction = 0x15; -/// bitwise AND operation -pub const AND: Instruction = 0x16; -/// bitwise OR operation -pub const OR: Instruction = 0x17; -/// bitwise XOR operation -pub const XOR: Instruction = 0x18; -/// bitwise NOT opertation -pub const NOT: Instruction = 0x19; -/// retrieve single byte from word -pub const BYTE: Instruction = 0x1a; -/// shift left operation -pub const SHL: Instruction = 0x1b; -/// logical shift right operation -pub const SHR: Instruction = 0x1c; -/// arithmetic shift right operation -pub const SAR: Instruction = 0x1d; - -/// compute SHA3-256 hash -pub const SHA3: Instruction = 0x20; - -/// get address of currently executing account -pub const ADDRESS: Instruction = 0x30; -/// get balance of the given account -pub const BALANCE: Instruction = 0x31; -/// get execution origination address -pub const ORIGIN: Instruction = 0x32; -/// get caller address -pub const CALLER: Instruction = 0x33; -/// get deposited value by the instruction/transaction responsible for this execution -pub const CALLVALUE: Instruction = 0x34; -/// get input data of current environment -pub const CALLDATALOAD: Instruction = 0x35; -/// get size of input data in current environment -pub const CALLDATASIZE: Instruction = 0x36; -/// copy input data in current environment to memory -pub const CALLDATACOPY: Instruction = 0x37; -/// get size of code running in current environment -pub const CODESIZE: Instruction = 0x38; -/// copy code running in current environment to memory -pub const CODECOPY: Instruction = 0x39; -/// get price of gas in current environment -pub const GASPRICE: Instruction = 0x3a; -/// get external code size (from another contract) -pub const EXTCODESIZE: Instruction = 0x3b; -/// copy external code (from another contract) -pub const EXTCODECOPY: Instruction = 0x3c; - -/// get the size of the return data buffer for the last call -pub const RETURNDATASIZE: Instruction = 0x3d; -/// copy return data buffer to memory -pub const RETURNDATACOPY: Instruction = 0x3e; -/// get hash of most recent complete block -pub const BLOCKHASH: Instruction = 0x40; -/// get the block's coinbase address -pub const COINBASE: Instruction = 0x41; -/// get the block's timestamp -pub const TIMESTAMP: Instruction = 0x42; -/// get the block's number -pub const NUMBER: Instruction = 0x43; -/// get the block's difficulty -pub const DIFFICULTY: Instruction = 0x44; -/// get the block's gas limit -pub const GASLIMIT: Instruction = 0x45; - -/// remove item from stack -pub const POP: Instruction = 0x50; -/// load word from memory -pub const MLOAD: Instruction = 0x51; -/// save word to memory -pub const MSTORE: Instruction = 0x52; -/// save byte to memory -pub const MSTORE8: Instruction = 0x53; -/// load word from storage -pub const SLOAD: Instruction = 0x54; -/// save word to storage -pub const SSTORE: Instruction = 0x55; -/// alter the program counter -pub const JUMP: Instruction = 0x56; -/// conditionally alter the program counter -pub const JUMPI: Instruction = 0x57; -/// get the program counter -pub const PC: Instruction = 0x58; -/// get the size of active memory -pub const MSIZE: Instruction = 0x59; -/// get the amount of available gas -pub const GAS: Instruction = 0x5a; -/// set a potential jump destination -pub const JUMPDEST: Instruction = 0x5b; - -/// place 1 byte item on stack -pub const PUSH1: Instruction = 0x60; -/// place 2 byte item on stack -pub const PUSH2: Instruction = 0x61; -/// place 3 byte item on stack -pub const PUSH3: Instruction = 0x62; -/// place 4 byte item on stack -pub const PUSH4: Instruction = 0x63; -/// place 5 byte item on stack -pub const PUSH5: Instruction = 0x64; -/// place 6 byte item on stack -pub const PUSH6: Instruction = 0x65; -/// place 7 byte item on stack -pub const PUSH7: Instruction = 0x66; -/// place 8 byte item on stack -pub const PUSH8: Instruction = 0x67; -/// place 9 byte item on stack -pub const PUSH9: Instruction = 0x68; -/// place 10 byte item on stack -pub const PUSH10: Instruction = 0x69; -/// place 11 byte item on stack -pub const PUSH11: Instruction = 0x6a; -/// place 12 byte item on stack -pub const PUSH12: Instruction = 0x6b; -/// place 13 byte item on stack -pub const PUSH13: Instruction = 0x6c; -/// place 14 byte item on stack -pub const PUSH14: Instruction = 0x6d; -/// place 15 byte item on stack -pub const PUSH15: Instruction = 0x6e; -/// place 16 byte item on stack -pub const PUSH16: Instruction = 0x6f; -/// place 17 byte item on stack -pub const PUSH17: Instruction = 0x70; -/// place 18 byte item on stack -pub const PUSH18: Instruction = 0x71; -/// place 19 byte item on stack -pub const PUSH19: Instruction = 0x72; -/// place 20 byte item on stack -pub const PUSH20: Instruction = 0x73; -/// place 21 byte item on stack -pub const PUSH21: Instruction = 0x74; -/// place 22 byte item on stack -pub const PUSH22: Instruction = 0x75; -/// place 23 byte item on stack -pub const PUSH23: Instruction = 0x76; -/// place 24 byte item on stack -pub const PUSH24: Instruction = 0x77; -/// place 25 byte item on stack -pub const PUSH25: Instruction = 0x78; -/// place 26 byte item on stack -pub const PUSH26: Instruction = 0x79; -/// place 27 byte item on stack -pub const PUSH27: Instruction = 0x7a; -/// place 28 byte item on stack -pub const PUSH28: Instruction = 0x7b; -/// place 29 byte item on stack -pub const PUSH29: Instruction = 0x7c; -/// place 30 byte item on stack -pub const PUSH30: Instruction = 0x7d; -/// place 31 byte item on stack -pub const PUSH31: Instruction = 0x7e; -/// place 32 byte item on stack -pub const PUSH32: Instruction = 0x7f; - -/// copies the highest item in the stack to the top of the stack -pub const DUP1: Instruction = 0x80; -/// copies the second highest item in the stack to the top of the stack -pub const DUP2: Instruction = 0x81; -/// copies the third highest item in the stack to the top of the stack -pub const DUP3: Instruction = 0x82; -/// copies the 4th highest item in the stack to the top of the stack -pub const DUP4: Instruction = 0x83; -/// copies the 5th highest item in the stack to the top of the stack -pub const DUP5: Instruction = 0x84; -/// copies the 6th highest item in the stack to the top of the stack -pub const DUP6: Instruction = 0x85; -/// copies the 7th highest item in the stack to the top of the stack -pub const DUP7: Instruction = 0x86; -/// copies the 8th highest item in the stack to the top of the stack -pub const DUP8: Instruction = 0x87; -/// copies the 9th highest item in the stack to the top of the stack -pub const DUP9: Instruction = 0x88; -/// copies the 10th highest item in the stack to the top of the stack -pub const DUP10: Instruction = 0x89; -/// copies the 11th highest item in the stack to the top of the stack -pub const DUP11: Instruction = 0x8a; -/// copies the 12th highest item in the stack to the top of the stack -pub const DUP12: Instruction = 0x8b; -/// copies the 13th highest item in the stack to the top of the stack -pub const DUP13: Instruction = 0x8c; -/// copies the 14th highest item in the stack to the top of the stack -pub const DUP14: Instruction = 0x8d; -/// copies the 15th highest item in the stack to the top of the stack -pub const DUP15: Instruction = 0x8e; -/// copies the 16th highest item in the stack to the top of the stack -pub const DUP16: Instruction = 0x8f; - -/// swaps the highest and second highest value on the stack -pub const SWAP1: Instruction = 0x90; -/// swaps the highest and third highest value on the stack -pub const SWAP2: Instruction = 0x91; -/// swaps the highest and 4th highest value on the stack -pub const SWAP3: Instruction = 0x92; -/// swaps the highest and 5th highest value on the stack -pub const SWAP4: Instruction = 0x93; -/// swaps the highest and 6th highest value on the stack -pub const SWAP5: Instruction = 0x94; -/// swaps the highest and 7th highest value on the stack -pub const SWAP6: Instruction = 0x95; -/// swaps the highest and 8th highest value on the stack -pub const SWAP7: Instruction = 0x96; -/// swaps the highest and 9th highest value on the stack -pub const SWAP8: Instruction = 0x97; -/// swaps the highest and 10th highest value on the stack -pub const SWAP9: Instruction = 0x98; -/// swaps the highest and 11th highest value on the stack -pub const SWAP10: Instruction = 0x99; -/// swaps the highest and 12th highest value on the stack -pub const SWAP11: Instruction = 0x9a; -/// swaps the highest and 13th highest value on the stack -pub const SWAP12: Instruction = 0x9b; -/// swaps the highest and 14th highest value on the stack -pub const SWAP13: Instruction = 0x9c; -/// swaps the highest and 15th highest value on the stack -pub const SWAP14: Instruction = 0x9d; -/// swaps the highest and 16th highest value on the stack -pub const SWAP15: Instruction = 0x9e; -/// swaps the highest and 17th highest value on the stack -pub const SWAP16: Instruction = 0x9f; - -/// Makes a log entry; no topics. -pub const LOG0: Instruction = 0xa0; -/// Makes a log entry; 1 topic. -pub const LOG1: Instruction = 0xa1; -/// Makes a log entry; 2 topics. -pub const LOG2: Instruction = 0xa2; -/// Makes a log entry; 3 topics. -pub const LOG3: Instruction = 0xa3; -/// Makes a log entry; 4 topics. -pub const LOG4: Instruction = 0xa4; -/// Maximal number of topics for log instructions -pub const MAX_NO_OF_TOPICS: usize = 4; - -/// create a new account with associated code -pub const CREATE: Instruction = 0xf0; -/// message-call into an account -pub const CALL: Instruction = 0xf1; -/// message-call with another account's code only -pub const CALLCODE: Instruction = 0xf2; -/// halt execution returning output data -pub const RETURN: Instruction = 0xf3; -/// like CALLCODE but keeps caller's value and sender -pub const DELEGATECALL: Instruction = 0xf4; -/// stop execution and revert state changes. Return output data. -pub const REVERT: Instruction = 0xfd; -/// like CALL but it does not take value, nor modify the state -pub const STATICCALL: Instruction = 0xfa; -/// halt execution and register account for later deletion -pub const SUICIDE: Instruction = 0xff; diff --git a/cita-executor/evm/src/interpreter/gasometer.rs b/cita-executor/evm/src/interpreter/gasometer.rs deleted file mode 100644 index a0b5aead5..000000000 --- a/cita-executor/evm/src/interpreter/gasometer.rs +++ /dev/null @@ -1,381 +0,0 @@ -// Copyright 2015-2017 Parity Technologies (UK) Ltd. -// This file is part of Parity. - -// This software is free software: you can redistribute it and/or modify -// it under the terms of the GNU General Public License as published by -// the Free Software Foundation, either version 3 of the License, or -// (at your option) any later version. - -// This software 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 General Public License for more details. - -// You should have received a copy of the GNU General Public License -// along with Parity. If not, see . - -use super::u256_to_address; -use crate::error::{Error, Result}; -use crate::evm::CostType; -use crate::ext::Ext; -use crate::instructions::{self, Instruction, InstructionInfo}; -use crate::interpreter::stack::Stack; -use crate::schedule::Schedule; -use cita_types::{H256, U256}; -use std::cmp; - -macro_rules! overflowing { - ($x: expr) => {{ - let (v, overflow) = $x; - if overflow { - return Err(Error::OutOfGas); - } - v - }}; -} - -enum Request { - Gas(Cost), - GasMem(Cost, Cost), - GasMemProvide(Cost, Cost, Option), - GasMemCopy(Cost, Cost, Cost), -} - -pub struct InstructionRequirements { - pub gas_cost: Cost, - pub provide_gas: Option, - pub memory_total_gas: Cost, - pub memory_required_size: usize, -} - -pub struct Gasometer { - pub current_gas: Gas, - pub current_mem_gas: Gas, -} - -impl Gasometer { - pub fn new(current_gas: Gas) -> Self { - Gasometer { - current_gas, - current_mem_gas: Gas::from(0), - } - } - - pub fn verify_gas(&self, gas_cost: &Gas) -> Result<()> { - if self.current_gas < *gas_cost { - Err(Error::OutOfGas) - } else { - Ok(()) - } - } - - /// How much gas is provided to a CALL/CREATE, given that we need to deduct `needed` for this operation - /// and that we `requested` some. - pub fn gas_provided( - &self, - schedule: &Schedule, - needed: Gas, - requested: Option, - ) -> Result { - // Try converting requested gas to `Gas` (`U256/u64`) - // but in EIP150 even if we request more we should never fail from OOG - let requested = requested.map(Gas::from_u256); - let cap_divisor = schedule.sub_gas_cap_divisor; - - if self.current_gas >= needed { - let gas_remaining = self.current_gas - needed; - let max_gas_provided = match cap_divisor { - 64 => gas_remaining - (gas_remaining >> 6), - cap_divisor => gas_remaining - gas_remaining / Gas::from(cap_divisor), - }; - - if let Some(Ok(r)) = requested { - Ok(cmp::min(r, max_gas_provided)) - } else { - Ok(max_gas_provided) - } - } else if let Some(r) = requested { - r - } else { - Ok(0.into()) - } - } - - /// Determine how much gas is used by the given instruction, given the machine's state. - /// - /// We guarantee that the final element of the returned tuple (`provided`) will be `Some` - /// iff the `instruction` is one of `CREATE`, or any of the `CALL` variants. In this case, - /// it will be the amount of gas that the current context provides to the child context. - pub fn requirements( - &mut self, - ext: &Ext, - instruction: Instruction, - info: &InstructionInfo, - stack: &Stack, - current_mem_size: usize, - ) -> Result> { - let schedule = ext.schedule(); - let tier = instructions::get_tier_idx(info.tier); - let default_gas = Gas::from(schedule.tier_step_gas[tier]); - - let cost = match instruction { - instructions::JUMPDEST => Request::Gas(Gas::from(1)), - instructions::SSTORE => { - let address = H256::from(stack.peek(0)); - let newval = stack.peek(1); - let val = U256::from(&*ext.storage_at(&address)?); - - let gas = if val.is_zero() && !newval.is_zero() { - schedule.sstore_set_gas - } else { - // Refund for below case is added when actually executing sstore - // !is_zero(&val) && is_zero(newval) - schedule.sstore_reset_gas - }; - Request::Gas(Gas::from(gas)) - } - instructions::SLOAD => Request::Gas(Gas::from(schedule.sload_gas)), - instructions::BALANCE => Request::Gas(Gas::from(schedule.balance_gas)), - instructions::EXTCODESIZE => Request::Gas(Gas::from(schedule.extcodesize_gas)), - instructions::SUICIDE => { - let mut gas = Gas::from(schedule.suicide_gas); - - let is_value_transfer = !ext.origin_balance()?.is_zero(); - let address = u256_to_address(stack.peek(0)); - if (!schedule.no_empty && !ext.exists(&address)?) - || (schedule.no_empty - && is_value_transfer - && !ext.exists_and_not_null(&address)?) - { - gas = - overflowing!(gas.overflow_add(schedule.suicide_to_new_account_cost.into())); - } - - Request::Gas(gas) - } - instructions::MSTORE | instructions::MLOAD => { - Request::GasMem(default_gas, mem_needed_const(stack.peek(0), 32)?) - } - instructions::MSTORE8 => { - Request::GasMem(default_gas, mem_needed_const(stack.peek(0), 1)?) - } - instructions::RETURN | instructions::REVERT => { - Request::GasMem(default_gas, mem_needed(stack.peek(0), stack.peek(1))?) - } - instructions::SHA3 => { - let w = overflowing!(add_gas_usize(Gas::from_u256(*stack.peek(1))?, 31)); - let words = w >> 5; - let gas = - Gas::from(schedule.sha3_gas) + (Gas::from(schedule.sha3_word_gas) * words); - Request::GasMem(gas, mem_needed(stack.peek(0), stack.peek(1))?) - } - instructions::CALLDATACOPY | instructions::CODECOPY | instructions::RETURNDATACOPY => { - Request::GasMemCopy( - default_gas, - mem_needed(stack.peek(0), stack.peek(2))?, - Gas::from_u256(*stack.peek(2))?, - ) - } - instructions::EXTCODECOPY => Request::GasMemCopy( - schedule.extcodecopy_base_gas.into(), - mem_needed(stack.peek(1), stack.peek(3))?, - Gas::from_u256(*stack.peek(3))?, - ), - instructions::LOG0...instructions::LOG4 => { - let no_of_topics = instructions::get_log_topics(instruction); - let log_gas = schedule.log_gas + schedule.log_topic_gas * no_of_topics; - - let data_gas = - overflowing!(Gas::from_u256(*stack.peek(1))? - .overflow_mul(Gas::from(schedule.log_data_gas))); - let gas = overflowing!(data_gas.overflow_add(Gas::from(log_gas))); - Request::GasMem(gas, mem_needed(stack.peek(0), stack.peek(1))?) - } - instructions::CALL | instructions::CALLCODE => { - let mut gas = Gas::from(schedule.call_gas); - let mem = cmp::max( - mem_needed(stack.peek(5), stack.peek(6))?, - mem_needed(stack.peek(3), stack.peek(4))?, - ); - - let address = u256_to_address(stack.peek(1)); - let is_value_transfer = !stack.peek(2).is_zero(); - - if instruction == instructions::CALL - && ((!schedule.no_empty && !ext.exists(&address)?) - || (schedule.no_empty - && is_value_transfer - && !ext.exists_and_not_null(&address)?)) - { - gas = overflowing!(gas.overflow_add(schedule.call_new_account_gas.into())); - } - - if is_value_transfer { - gas = overflowing!(gas.overflow_add(schedule.call_value_transfer_gas.into())); - } - - let requested = *stack.peek(0); - - Request::GasMemProvide(gas, mem, Some(requested)) - } - instructions::DELEGATECALL | instructions::STATICCALL => { - let gas = Gas::from(schedule.call_gas); - let mem = cmp::max( - mem_needed(stack.peek(4), stack.peek(5))?, - mem_needed(stack.peek(2), stack.peek(3))?, - ); - let requested = *stack.peek(0); - - Request::GasMemProvide(gas, mem, Some(requested)) - } - instructions::CREATE => { - let gas = Gas::from(schedule.create_gas); - let mem = mem_needed(stack.peek(1), stack.peek(2))?; - - Request::GasMemProvide(gas, mem, None) - } - instructions::EXP => { - let expon = stack.peek(1); - let bytes = ((expon.bits() + 7) / 8) as usize; - let gas = Gas::from(schedule.exp_gas + schedule.exp_byte_gas * bytes); - Request::Gas(gas) - } - _ => Request::Gas(default_gas), - }; - - Ok(match cost { - Request::Gas(gas) => InstructionRequirements { - gas_cost: gas, - provide_gas: None, - memory_required_size: 0, - memory_total_gas: self.current_mem_gas, - }, - Request::GasMem(gas, mem_size) => { - let (mem_gas_cost, new_mem_gas, new_mem_size) = - self.mem_gas_cost(schedule, current_mem_size, &mem_size)?; - let gas = overflowing!(gas.overflow_add(mem_gas_cost)); - InstructionRequirements { - gas_cost: gas, - provide_gas: None, - memory_required_size: new_mem_size, - memory_total_gas: new_mem_gas, - } - } - Request::GasMemProvide(gas, mem_size, requested) => { - let (mem_gas_cost, new_mem_gas, new_mem_size) = - self.mem_gas_cost(schedule, current_mem_size, &mem_size)?; - let gas = overflowing!(gas.overflow_add(mem_gas_cost)); - let provided = self.gas_provided(schedule, gas, requested)?; - let total_gas = overflowing!(gas.overflow_add(provided)); - - InstructionRequirements { - gas_cost: total_gas, - provide_gas: Some(provided), - memory_required_size: new_mem_size, - memory_total_gas: new_mem_gas, - } - } - Request::GasMemCopy(gas, mem_size, copy) => { - let (mem_gas_cost, new_mem_gas, new_mem_size) = - self.mem_gas_cost(schedule, current_mem_size, &mem_size)?; - let copy = overflowing!(add_gas_usize(copy, 31)) >> 5; - let copy_gas = Gas::from(schedule.copy_gas) * copy; - let gas = overflowing!(gas.overflow_add(copy_gas)); - let gas = overflowing!(gas.overflow_add(mem_gas_cost)); - - InstructionRequirements { - gas_cost: gas, - provide_gas: None, - memory_required_size: new_mem_size, - memory_total_gas: new_mem_gas, - } - } - }) - } - - fn mem_gas_cost( - &self, - schedule: &Schedule, - current_mem_size: usize, - mem_size: &Gas, - ) -> Result<(Gas, Gas, usize)> { - let gas_for_mem = |mem_size: Gas| { - let s = mem_size >> 5; - // s * memory_gas + s * s / quad_coeff_div - let a = overflowing!(s.overflow_mul(Gas::from(schedule.memory_gas))); - - // Calculate s*s/quad_coeff_div - assert_eq!(schedule.quad_coeff_div, 512); - let b = overflowing!(s.overflow_mul_shr(s, 9)); - Ok(overflowing!(a.overflow_add(b))) - }; - - let current_mem_size = Gas::from(current_mem_size); - let req_mem_size_rounded = - (overflowing!(mem_size.overflow_add(Gas::from(31 as usize))) >> 5) << 5; - - let (mem_gas_cost, new_mem_gas) = if req_mem_size_rounded > current_mem_size { - let new_mem_gas = gas_for_mem(req_mem_size_rounded)?; - (new_mem_gas - self.current_mem_gas, new_mem_gas) - } else { - (Gas::from(0), self.current_mem_gas) - }; - - Ok((mem_gas_cost, new_mem_gas, req_mem_size_rounded.as_usize())) - } -} - -#[inline] -fn mem_needed_const(mem: &U256, add: usize) -> Result { - Gas::from_u256(overflowing!(mem.overflowing_add(U256::from(add)))) -} - -#[inline] -fn mem_needed(offset: &U256, size: &U256) -> Result { - if size.is_zero() { - return Ok(Gas::from(0)); - } - - Gas::from_u256(overflowing!(offset.overflowing_add(*size))) -} - -#[inline] -fn add_gas_usize(value: Gas, num: usize) -> (Gas, bool) { - value.overflow_add(Gas::from(num)) -} - -#[test] -fn test_mem_gas_cost() { - // given - let gasometer = Gasometer::::new(U256::zero()); - let schedule = Schedule::default(); - let current_mem_size = 5; - let mem_size = !U256::zero(); - - // when - let result = gasometer.mem_gas_cost(&schedule, current_mem_size, &mem_size); - - // then - if result.is_ok() { - assert!(false, "Should fail with OutOfGas"); - } -} - -#[test] -fn test_calculate_mem_cost() { - // given - let gasometer = Gasometer::::new(0); - let schedule = Schedule::default(); - let current_mem_size = 0; - let mem_size = 5; - - // when - let (mem_cost, new_mem_gas, mem_size) = gasometer - .mem_gas_cost(&schedule, current_mem_size, &mem_size) - .unwrap(); - - // then - assert_eq!(mem_cost, 3); - assert_eq!(new_mem_gas, 3); - assert_eq!(mem_size, 32); -} diff --git a/cita-executor/evm/src/interpreter/informant.rs b/cita-executor/evm/src/interpreter/informant.rs deleted file mode 100644 index 5a0d44836..000000000 --- a/cita-executor/evm/src/interpreter/informant.rs +++ /dev/null @@ -1,173 +0,0 @@ -// Copyright 2015-2017 Parity Technologies (UK) Ltd. -// This file is part of Parity. - -// This software is free software: you can redistribute it and/or modify -// it under the terms of the GNU General Public License as published by -// the Free Software Foundation, either version 3 of the License, or -// (at your option) any later version. - -// This software 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 General Public License for more details. - -// You should have received a copy of the GNU General Public License -// along with Parity. If not, see . - -pub use self::inner::*; -#[macro_use] -#[cfg(not(feature = "evm-debug"))] -mod inner { - macro_rules! evm_debug { - ($x: expr) => {}; - } - - pub struct EvmInformant; - impl EvmInformant { - pub fn new(_depth: usize) -> Self { - EvmInformant {} - } - pub fn done(&mut self) {} - } -} - -#[macro_use] -#[cfg(feature = "evm-debug")] -mod inner { - use instructions::{Instruction, InstructionInfo, INSTRUCTIONS}; - use CostType; - - use interpreter::stack::Stack; - use std::collections::HashMap; - use std::iter; - use std::time::{Duration, Instant}; - - use cita_types::U256; - - macro_rules! evm_debug { - ($x: expr) => { - $x - }; - } - - fn print(data: String) { - if cfg!(feature = "evm-debug-tests") { - println!("{}", data); - } else { - debug!(target: "evm", "{}", data); - } - } - - pub struct EvmInformant { - spacing: String, - last_instruction: Instant, - stats: HashMap, - } - - impl EvmInformant { - fn color(instruction: Instruction, name: &str) -> String { - let c = instruction as usize % 6; - let colors = [31, 34, 33, 32, 35, 36]; - format!("\x1B[1;{}m{}\x1B[0m", colors[c], name) - } - - fn as_micro(duration: &Duration) -> u64 { - let mut sec = duration.as_secs(); - let subsec = duration.subsec_nanos() as u64; - sec = sec.saturating_mul(1_000_000u64); - sec += subsec / 1_000; - sec - } - - pub fn new(depth: usize) -> Self { - EvmInformant { - spacing: iter::repeat(".").take(depth).collect(), - last_instruction: Instant::now(), - stats: HashMap::new(), - } - } - - pub fn before_instruction( - &mut self, - pc: usize, - instruction: Instruction, - info: &InstructionInfo, - current_gas: &Cost, - stack: &Stack, - ) { - let time = self.last_instruction.elapsed(); - self.last_instruction = Instant::now(); - - print(format!( - "{}[0x{:<3x}][{:>19}(0x{:<2x}) Gas Left: {:6?} (Previous took: {:10}μs)", - &self.spacing, - pc, - Self::color(instruction, info.name), - instruction, - current_gas, - Self::as_micro(&time), - )); - - if info.args > 0 { - for (idx, item) in stack.peek_top(info.args).iter().enumerate() { - print(format!("{} |{:2}: {:?}", self.spacing, idx, item)); - } - } - } - - pub fn after_instruction(&mut self, instruction: Instruction) { - let stats = self - .stats - .entry(instruction) - .or_insert_with(|| Stats::default()); - let took = self.last_instruction.elapsed(); - stats.note(took); - } - - pub fn done(&mut self) { - // Print out stats - let infos = &*INSTRUCTIONS; - - let mut stats: Vec<(_, _)> = self.stats.drain().collect(); - stats.sort_by(|ref a, ref b| b.1.avg().cmp(&a.1.avg())); - - print(format!("\n{}-------OPCODE STATS:", self.spacing)); - for (instruction, stats) in stats.into_iter() { - let info = infos[instruction as usize]; - print(format!( - "{}-------{:>19}(0x{:<2x}) count: {:4}, avg: {:10}μs", - self.spacing, - Self::color(instruction, info.name), - instruction, - stats.count, - stats.avg(), - )); - } - } - } - - struct Stats { - count: u64, - total_duration: Duration, - } - - impl Default for Stats { - fn default() -> Self { - Stats { - count: 0, - total_duration: Duration::from_secs(0), - } - } - } - - impl Stats { - fn note(&mut self, took: Duration) { - self.count += 1; - self.total_duration += took; - } - - fn avg(&self) -> u64 { - EvmInformant::as_micro(&self.total_duration) / self.count - } - } -} diff --git a/cita-executor/evm/src/interpreter/memory.rs b/cita-executor/evm/src/interpreter/memory.rs deleted file mode 100644 index 6ee3b3477..000000000 --- a/cita-executor/evm/src/interpreter/memory.rs +++ /dev/null @@ -1,162 +0,0 @@ -// Copyright 2015-2017 Parity Technologies (UK) Ltd. -// This file is part of Parity. - -// This software is free software: you can redistribute it and/or modify -// it under the terms of the GNU General Public License as published by -// the Free Software Foundation, either version 3 of the License, or -// (at your option) any later version. - -// This software 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 General Public License for more details. - -// You should have received a copy of the GNU General Public License -// along with Parity. If not, see . -use crate::return_data::ReturnData; -use cita_types::U256; - -const MAX_RETURN_WASTE_BYTES: usize = 16384; - -pub trait Memory { - /// Retrieve current size of the memory - fn size(&self) -> usize; - /// Resize (shrink or expand) the memory to specified size (fills 0) - fn resize(&mut self, new_size: usize); - /// Resize the memory only if its smaller - fn expand(&mut self, new_size: usize); - /// Write single byte to memory - fn write_byte(&mut self, offset: U256, value: U256); - /// Write a word to memory. Does not resize memory! - fn write(&mut self, offset: U256, value: U256); - /// Read a word from memory - fn read(&self, offset: U256) -> U256; - /// Write slice of bytes to memory. Does not resize memory! - fn write_slice(&mut self, offset: U256, _: &[u8]); - /// Retrieve part of the memory between offset and offset + size - fn read_slice(&self, offset: U256, size: U256) -> &[u8]; - /// Retrieve writeable part of memory - fn writeable_slice(&mut self, offset: U256, size: U256) -> &mut [u8]; - fn dump(&self); - /// Convert memory into return data. - fn into_return_data(self, offset: U256, size: U256) -> ReturnData; -} - -/// Checks whether offset and size is valid memory range -fn is_valid_range(off: usize, size: usize) -> bool { - // When size is zero we haven't actually expanded the memory - let overflow = off.overflowing_add(size).1; - size > 0 && !overflow -} - -impl Memory for Vec { - fn dump(&self) { - println!("MemoryDump:"); - for i in self.iter() { - println!("{:02x} ", i); - } - println!(); - } - - fn size(&self) -> usize { - self.len() - } - - fn read_slice(&self, init_off_u: U256, init_size_u: U256) -> &[u8] { - let off = init_off_u.low_u64() as usize; - let size = init_size_u.low_u64() as usize; - if !is_valid_range(off, size) { - &self[0..0] - } else { - &self[off..off + size] - } - } - - fn read(&self, offset: U256) -> U256 { - let off = offset.low_u64() as usize; - U256::from(&self[off..off + 32]) - } - - fn writeable_slice(&mut self, offset: U256, size: U256) -> &mut [u8] { - let off = offset.low_u64() as usize; - let s = size.low_u64() as usize; - if !is_valid_range(off, s) { - &mut self[0..0] - } else { - &mut self[off..off + s] - } - } - - fn write_slice(&mut self, offset: U256, slice: &[u8]) { - if !slice.is_empty() { - let off = offset.low_u64() as usize; - self[off..(off + slice.len())].copy_from_slice(slice) - } - } - - fn write(&mut self, offset: U256, value: U256) { - let off = offset.low_u64() as usize; - value.to_big_endian(&mut self[off..off + 32]); - } - - fn write_byte(&mut self, offset: U256, value: U256) { - let off = offset.low_u64() as usize; - let val = value.low_u64() as u64; - self[off] = val as u8; - } - - fn resize(&mut self, new_size: usize) { - self.resize(new_size, 0); - } - - fn expand(&mut self, size: usize) { - if size > self.len() { - Memory::resize(self, size) - } - } - - fn into_return_data(mut self, offset: U256, size: U256) -> ReturnData { - let mut offset = offset.low_u64() as usize; - let size = size.low_u64() as usize; - if !is_valid_range(offset, size) { - return ReturnData::empty(); - } - if self.len() - size > MAX_RETURN_WASTE_BYTES { - { - let _ = self.drain(..offset); - } - self.truncate(size); - self.shrink_to_fit(); - offset = 0; - } - ReturnData::new(self, offset, size) - } -} - -#[test] -fn test_memory_read_and_write() { - // given - let mem: &mut Memory = &mut vec![]; - mem.resize(0x80 + 32); - - // when - mem.write(U256::from(0x80), U256::from(0xabcdef)); - - // then - assert_eq!(mem.read(U256::from(0x80)), U256::from(0xabcdef)); -} - -#[test] -fn test_memory_read_and_write_byte() { - // given - let mem: &mut Memory = &mut vec![]; - mem.resize(32); - - // when - mem.write_byte(U256::from(0x1d), U256::from(0xab)); - mem.write_byte(U256::from(0x1e), U256::from(0xcd)); - mem.write_byte(U256::from(0x1f), U256::from(0xef)); - - // then - assert_eq!(mem.read(U256::from(0x00)), U256::from(0xabcdef)); -} diff --git a/cita-executor/evm/src/interpreter/mod.rs b/cita-executor/evm/src/interpreter/mod.rs deleted file mode 100644 index 16158b933..000000000 --- a/cita-executor/evm/src/interpreter/mod.rs +++ /dev/null @@ -1,1045 +0,0 @@ -// Copyright 2015-2017 Parity Technologies (UK) Ltd. -// This file is part of Parity. - -// This software is free software: you can redistribute it and/or modify -// it under the terms of the GNU General Public License as published by -// the Free Software Foundation, either version 3 of the License, or -// (at your option) any later version. - -// This software 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 General Public License for more details. - -// You should have received a copy of the GNU General Public License -// along with Parity. If not, see . - -//! Rust VM implementation - -#[macro_use] -mod informant; -mod gasometer; -mod memory; -mod shared_cache; -mod stack; - -use self::gasometer::Gasometer; -use self::memory::Memory; -pub use self::shared_cache::SharedCache; -use self::stack::{Stack, VecStack}; -use super::call_type::CallType; -use super::error::{Error, Result}; -use super::return_data::{GasLeft, ReturnData}; -use crate::action_params::{ActionParams, ActionValue}; -use crate::evm::{self, CostType}; -use crate::ext::{ContractCreateResult, Ext, MessageCallResult}; -use crate::instructions::{self, Instruction, InstructionInfo}; -use bit_set::BitSet; -use std::cmp; -use std::mem; - -use std::marker::PhantomData; -use std::sync::Arc; - -use cita_types::{Address, H256, U256, U512}; -use util::sha3; - -type ProgramCounter = usize; - -const ONE: U256 = U256([1, 0, 0, 0]); -const TWO: U256 = U256([2, 0, 0, 0]); -const TWO_POW_5: U256 = U256([0x20, 0, 0, 0]); -const TWO_POW_8: U256 = U256([0x100, 0, 0, 0]); -const TWO_POW_16: U256 = U256([0x1_0000, 0, 0, 0]); -const TWO_POW_24: U256 = U256([0x100_0000, 0, 0, 0]); -const TWO_POW_64: U256 = U256([0, 0x1, 0, 0]); // 0x1 00000000 00000000 -const TWO_POW_96: U256 = U256([0, 0x1_0000_0000, 0, 0]); //0x1 00000000 00000000 00000000 -const TWO_POW_224: U256 = U256([0, 0, 0, 0x1_0000_0000]); //0x1 00000000 00000000 00000000 00000000 00000000 00000000 00000000 -const TWO_POW_248: U256 = U256([0, 0, 0, 0x100_0000_0000_0000]); //0x1 00000000 00000000 00000000 00000000 00000000 00000000 00000000 000000 - -/// Abstraction over raw vector of Bytes. Easier state management of PC. -struct CodeReader<'a> { - position: ProgramCounter, - code: &'a [u8], -} - -impl<'a> CodeReader<'a> { - /// Create new code reader - starting at position 0. - fn new(code: &'a [u8]) -> Self { - CodeReader { position: 0, code } - } - - /// Get `no_of_bytes` from code and convert to U256. Move PC - fn read(&mut self, no_of_bytes: usize) -> U256 { - let pos = self.position; - self.position += no_of_bytes; - let max = cmp::min(pos + no_of_bytes, self.code.len()); - U256::from(&self.code[pos..max]) - } - - fn len(&self) -> usize { - self.code.len() - } -} - -enum InstructionResult { - Ok, - UnusedGas(Gas), - JumpToPosition(U256), - StopExecutionNeedsReturn { - /// Gas left. - gas: Gas, - /// Return data offset. - init_off: U256, - /// Return data size. - init_size: U256, - /// Apply or revert state changes. - apply: bool, - }, - StopExecution, -} - -/// Intepreter EVM implementation -pub struct Interpreter { - mem: Vec, - cache: Arc, - return_data: ReturnData, - _type: PhantomData, -} - -impl evm::Evm for Interpreter { - fn exec(&mut self, params: &ActionParams, ext: &mut Ext) -> Result { - self.mem.clear(); - - let mut informant = informant::EvmInformant::new(ext.depth()); - - let code = ¶ms - .code - .as_ref() - .expect("exec always called with code; qed"); - let valid_jump_destinations = self.cache.jump_destinations(¶ms.code_hash, code); - - let mut gasometer = Gasometer::::new(Cost::from_u256(params.gas)?); - let mut stack = VecStack::with_capacity(ext.schedule().stack_limit, U256::zero()); - let mut reader = CodeReader::new(code); - let infos = &*instructions::INSTRUCTIONS; - - while reader.position < code.len() { - let instruction = code[reader.position]; - reader.position += 1; - - let info = &infos[instruction as usize]; - self.verify_instruction(ext, instruction, info, &stack)?; - - // Calculate gas cost - let requirements = - gasometer.requirements(ext, instruction, info, &stack, self.mem.size())?; - // TODO: make compile-time removable if too much of a performance hit. - let trace_executed = ext.trace_prepare_execute( - reader.position - 1, - instruction, - &requirements.gas_cost.as_u256(), - ); - - gasometer.verify_gas(&requirements.gas_cost)?; - self.mem.expand(requirements.memory_required_size); - gasometer.current_mem_gas = requirements.memory_total_gas; - gasometer.current_gas = gasometer.current_gas - requirements.gas_cost; - - evm_debug!({ - informant.before_instruction( - reader.position, - instruction, - info, - &gasometer.current_gas, - &stack, - ) - }); - - let (mem_written, store_written) = if trace_executed { - ( - Self::mem_written(instruction, &stack), - Self::store_written(instruction, &stack), - ) - } else { - (None, None) - }; - - // Execute instruction - let result = self.exec_instruction( - gasometer.current_gas, - params, - ext, - instruction, - &mut reader, - &mut stack, - requirements.provide_gas, - )?; - - evm_debug!({ informant.after_instruction(instruction) }); - - if let InstructionResult::UnusedGas(ref gas) = result { - gasometer.current_gas = gasometer.current_gas + *gas; - } - - let expect_mem_len = - mem_written.unwrap_or_default().0 + mem_written.unwrap_or_default().1; - if trace_executed && expect_mem_len < self.mem.len() { - ext.trace_executed( - gasometer.current_gas.as_u256(), - stack.peek_top(info.ret), - mem_written.map(|(o, s)| (o, &(self.mem[o..(o + s)]))), - store_written, - ); - } - - // Advance - match result { - InstructionResult::JumpToPosition(position) => { - let pos = self.verify_jump(position, &valid_jump_destinations)?; - reader.position = pos; - } - InstructionResult::StopExecutionNeedsReturn { - gas, - init_off, - init_size, - apply, - } => { - informant.done(); - let mem = mem::replace(&mut self.mem, Vec::new()); - return Ok(GasLeft::NeedsReturn { - gas_left: gas.as_u256(), - data: mem.into_return_data(init_off, init_size), - apply_state: apply, - }); - } - InstructionResult::StopExecution => break, - _ => {} - } - } - informant.done(); - Ok(GasLeft::Known(gasometer.current_gas.as_u256())) - } -} - -impl Interpreter { - /// Create a new `Interpreter` instance with shared cache. - pub fn new(cache: Arc) -> Interpreter { - Interpreter { - mem: Vec::new(), - cache, - return_data: ReturnData::empty(), - _type: PhantomData::default(), - } - } - - fn verify_instruction( - &self, - ext: &Ext, - instruction: Instruction, - info: &InstructionInfo, - stack: &Stack, - ) -> Result<()> { - let schedule = ext.schedule(); - - if info.tier == instructions::GasPriceTier::Invalid { - return Err(Error::BadInstruction { instruction }); - } - - if !stack.has(info.args) { - Err(Error::StackUnderflow { - instruction: info.name, - wanted: info.args, - on_stack: stack.size(), - }) - } else if stack.size() - info.args + info.ret > schedule.stack_limit { - Err(Error::OutOfStack { - instruction: info.name, - wanted: info.ret - info.args, - limit: schedule.stack_limit, - }) - } else { - Ok(()) - } - } - - fn mem_written(instruction: Instruction, stack: &Stack) -> Option<(usize, usize)> { - match instruction { - instructions::MSTORE | instructions::MLOAD => { - Some((stack.peek(0).low_u64() as usize, 32)) - } - instructions::MSTORE8 => Some((stack.peek(0).low_u64() as usize, 1)), - instructions::CALLDATACOPY | instructions::CODECOPY | instructions::RETURNDATACOPY => { - Some(( - stack.peek(0).low_u64() as usize, - stack.peek(2).low_u64() as usize, - )) - } - instructions::EXTCODECOPY => Some(( - stack.peek(1).low_u64() as usize, - stack.peek(3).low_u64() as usize, - )), - instructions::CALL | instructions::CALLCODE => Some(( - stack.peek(5).low_u64() as usize, - stack.peek(6).low_u64() as usize, - )), - instructions::DELEGATECALL => Some(( - stack.peek(4).low_u64() as usize, - stack.peek(5).low_u64() as usize, - )), - _ => None, - } - } - - fn store_written(instruction: Instruction, stack: &Stack) -> Option<(U256, U256)> { - match instruction { - instructions::SSTORE => Some((*stack.peek(0), *stack.peek(1))), - _ => None, - } - } - - #[allow(unknown_lints, clippy::too_many_arguments)] // TODO clippy - fn exec_instruction( - &mut self, - gas: Cost, - params: &ActionParams, - ext: &mut Ext, - instruction: Instruction, - code: &mut CodeReader, - stack: &mut Stack, - provided: Option, - ) -> Result> { - match instruction { - instructions::JUMP => { - let jump = stack.pop_back(); - return Ok(InstructionResult::JumpToPosition(jump)); - } - instructions::JUMPI => { - let jump = stack.pop_back(); - let condition = stack.pop_back(); - if !self.is_zero(&condition) { - return Ok(InstructionResult::JumpToPosition(jump)); - } - } - instructions::JUMPDEST => { - // ignore - } - instructions::CREATE => { - let endowment = stack.pop_back(); - let init_off = stack.pop_back(); - let init_size = stack.pop_back(); - let create_gas = provided.expect("`provided` comes through Self::exec from `Gasometer::get_gas_cost_mem`; `gas_gas_mem_cost` guarantees `Some` when instruction is `CALL`/`CALLCODE`/`DELEGATECALL`/`CREATE`; this is `CREATE`; qed"); - - if ext.is_static() { - return Err(Error::MutableCallInStaticContext); - } - - let contract_code = self.mem.read_slice(init_off, init_size); - let can_create = ext.balance(¶ms.address)? >= endowment - && ext.depth() < ext.schedule().max_depth; - - // clear return data buffer before creating new call frame. - self.return_data = ReturnData::empty(); - - if !can_create { - stack.push(U256::zero()); - return Ok(InstructionResult::UnusedGas(create_gas)); - } - - let create_result = ext.create(&create_gas.as_u256(), &endowment, contract_code); - return match create_result { - ContractCreateResult::Created(address, gas_left) => { - stack.push(address_to_u256(address)); - Ok(InstructionResult::UnusedGas( - Cost::from_u256(gas_left).expect("Gas left cannot be greater."), - )) - } - ContractCreateResult::Reverted(gas_left, return_data) => { - stack.push(U256::zero()); - self.return_data = return_data; - Ok(InstructionResult::UnusedGas( - Cost::from_u256(gas_left).expect("Gas left cannot be greater."), - )) - } - ContractCreateResult::Failed => { - stack.push(U256::zero()); - Ok(InstructionResult::Ok) - } - ContractCreateResult::FailedInStaticCall => { - Err(Error::MutableCallInStaticContext) - } - }; - } - instructions::CALL - | instructions::CALLCODE - | instructions::DELEGATECALL - | instructions::STATICCALL => { - assert!( - ext.schedule().call_value_transfer_gas > ext.schedule().call_stipend, - "overflow possible" - ); - stack.pop_back(); - let call_gas = provided.expect("`provided` comes through Self::exec from `Gasometer::get_gas_cost_mem`; `gas_gas_mem_cost` guarantees `Some` when instruction is `CALL`/`CALLCODE`/`DELEGATECALL`/`CREATE`; this is one of `CALL`/`CALLCODE`/`DELEGATECALL`; qed"); - let code_address = stack.pop_back(); - let code_address = u256_to_address(&code_address); - - let value = if instruction == instructions::DELEGATECALL { - None - } else if instruction == instructions::STATICCALL { - Some(U256::zero()) - } else { - Some(stack.pop_back()) - }; - - let in_off = stack.pop_back(); - let in_size = stack.pop_back(); - let out_off = stack.pop_back(); - let out_size = stack.pop_back(); - - // Add stipend (only CALL|CALLCODE when value > 0) - let call_gas = call_gas - + value.map_or_else( - || Cost::from(0), - |val| { - if val.is_zero() { - Cost::from(0) - } else { - Cost::from(ext.schedule().call_stipend) - } - }, - ); - - // Get sender & receive addresses, check if we have balance - let (sender_address, receive_address, has_balance, call_type) = match instruction { - instructions::CALL => { - if ext.is_static() && value.map_or(false, |v| !v.is_zero()) { - return Err(Error::MutableCallInStaticContext); - } - let has_balance = ext.balance(¶ms.address)? - >= value - .expect("value set for all but delegate call and staticcall; qed"); - (¶ms.address, &code_address, has_balance, CallType::Call) - } - instructions::CALLCODE => { - let has_balance = ext.balance(¶ms.address)? - >= value - .expect("value set for all but delegate call and staticcall; qed"); - ( - ¶ms.address, - ¶ms.address, - has_balance, - CallType::CallCode, - ) - } - instructions::DELEGATECALL => ( - ¶ms.sender, - ¶ms.address, - true, - CallType::DelegateCall, - ), - instructions::STATICCALL => { - (¶ms.address, &code_address, true, CallType::StaticCall) - } - _ => panic!(format!( - "Unexpected instruction {} in CALL branch.", - instruction - )), - }; - - // clear return data buffer before creating new call frame. - self.return_data = ReturnData::empty(); - - let can_call = has_balance && ext.depth() < ext.schedule().max_depth; - if !can_call { - stack.push(U256::zero()); - return Ok(InstructionResult::UnusedGas(call_gas)); - } - - let call_result = { - // we need to write and read from memory in the same time - // and we don't want to copy - let input = unsafe { &*(self.mem.read_slice(in_off, in_size) as *const [u8]) }; - let output = self.mem.writeable_slice(out_off, out_size); - ext.call( - &call_gas.as_u256(), - sender_address, - receive_address, - value, - input, - &code_address, - output, - call_type, - ) - }; - - return match call_result { - MessageCallResult::Success(gas_left, data) => { - stack.push(U256::one()); - self.return_data = data; - Ok(InstructionResult::UnusedGas( - Cost::from_u256(gas_left) - .expect("Gas left cannot be greater than current one"), - )) - } - MessageCallResult::Reverted(gas_left, data) => { - stack.push(U256::zero()); - self.return_data = data; - Ok(InstructionResult::UnusedGas( - Cost::from_u256(gas_left) - .expect("Gas left cannot be greater then current one"), - )) - } - MessageCallResult::Failed => { - stack.push(U256::zero()); - Ok(InstructionResult::Ok) - } - }; - } - instructions::RETURN => { - let init_off = stack.pop_back(); - let init_size = stack.pop_back(); - - return Ok(InstructionResult::StopExecutionNeedsReturn { - gas, - init_off, - init_size, - apply: true, - }); - } - instructions::REVERT => { - let init_off = stack.pop_back(); - let init_size = stack.pop_back(); - - return Ok(InstructionResult::StopExecutionNeedsReturn { - gas, - init_off, - init_size, - apply: false, - }); - } - instructions::STOP => { - return Ok(InstructionResult::StopExecution); - } - instructions::SUICIDE => { - let address = stack.pop_back(); - ext.suicide(&u256_to_address(&address))?; - return Ok(InstructionResult::StopExecution); - } - instructions::LOG0...instructions::LOG4 => { - let no_of_topics = instructions::get_log_topics(instruction); - - let offset = stack.pop_back(); - let size = stack.pop_back(); - let topics = stack.pop_n(no_of_topics).iter().map(H256::from).collect(); - ext.log(topics, self.mem.read_slice(offset, size))?; - } - instructions::PUSH1...instructions::PUSH32 => { - let bytes = instructions::get_push_bytes(instruction); - let val = code.read(bytes); - stack.push(val); - } - instructions::MLOAD => { - let word = self.mem.read(stack.pop_back()); - stack.push(word); - } - instructions::MSTORE => { - let offset = stack.pop_back(); - let word = stack.pop_back(); - Memory::write(&mut self.mem, offset, word); - } - instructions::MSTORE8 => { - let offset = stack.pop_back(); - let byte = stack.pop_back(); - self.mem.write_byte(offset, byte); - } - instructions::MSIZE => { - stack.push(U256::from(self.mem.size())); - } - instructions::SHA3 => { - let offset = stack.pop_back(); - let size = stack.pop_back(); - let hash = U256::from(H256::from_slice(&sha3::keccak256( - self.mem.read_slice(offset, size), - ))); - stack.push(hash); - } - instructions::SLOAD => { - let key = H256::from(&stack.pop_back()); - let word = U256::from(&*ext.storage_at(&key)?); - stack.push(word); - } - instructions::SSTORE => { - let address = H256::from(&stack.pop_back()); - let val = stack.pop_back(); - - let current_val = U256::from(&*ext.storage_at(&address)?); - // Increase refund for clear - if !self.is_zero(¤t_val) && self.is_zero(&val) { - ext.inc_sstore_clears(); - } - ext.set_storage(address, H256::from(&val))?; - } - instructions::PC => { - stack.push(U256::from(code.position - 1)); - } - instructions::GAS => { - stack.push(gas.as_u256()); - } - instructions::ADDRESS => { - stack.push(address_to_u256(params.address)); - } - instructions::ORIGIN => { - stack.push(address_to_u256(params.origin)); - } - instructions::BALANCE => { - let address = u256_to_address(&stack.pop_back()); - let balance = ext.balance(&address)?; - stack.push(balance); - } - instructions::CALLER => { - stack.push(address_to_u256(params.sender)); - } - instructions::CALLVALUE => { - stack.push(match params.value { - ActionValue::Transfer(val) | ActionValue::Apparent(val) => val, - }); - } - instructions::CALLDATALOAD => { - let big_id = stack.pop_back(); - let id = big_id.low_u64() as usize; - let max = id.wrapping_add(32); - if let Some(data) = params.data.as_ref() { - let bound = cmp::min(data.len(), max); - if id < bound && big_id < U256::from(data.len()) { - let mut v = [0u8; 32]; - v[0..bound - id].clone_from_slice(&data[id..bound]); - stack.push(U256::from(&v[..])) - } else { - stack.push(U256::zero()) - } - } else { - stack.push(U256::zero()) - } - } - instructions::CALLDATASIZE => { - stack.push(U256::from(params.data.clone().map_or(0, |l| l.len()))); - } - instructions::CODESIZE => { - stack.push(U256::from(code.len())); - } - instructions::RETURNDATASIZE => stack.push(U256::from(self.return_data.len())), - instructions::EXTCODESIZE => { - let address = u256_to_address(&stack.pop_back()); - let len = ext.extcodesize(&address)?; - stack.push(U256::from(len)); - } - instructions::CALLDATACOPY => { - Self::copy_data_to_memory( - &mut self.mem, - stack, - params - .data - .as_ref() - .map_or_else(|| &[] as &[u8], |d| &*d as &[u8]), - ); - } - instructions::RETURNDATACOPY => { - { - let source_offset = stack.peek(1); - let size = stack.peek(2); - let return_data_len = U256::from(self.return_data.len()); - if source_offset.overflow_add(*size).0 > return_data_len { - return Err(Error::OutOfBounds); - } - } - Self::copy_data_to_memory(&mut self.mem, stack, &*self.return_data); - } - instructions::CODECOPY => { - Self::copy_data_to_memory( - &mut self.mem, - stack, - params - .code - .as_ref() - .map_or_else(|| &[] as &[u8], |c| &**c as &[u8]), - ); - } - instructions::EXTCODECOPY => { - let address = u256_to_address(&stack.pop_back()); - let code = ext.extcode(&address)?; - Self::copy_data_to_memory(&mut self.mem, stack, &code); - } - instructions::GASPRICE => { - stack.push(params.gas_price); - } - instructions::BLOCKHASH => { - let block_number = stack.pop_back(); - let block_hash = ext.blockhash(&block_number); - stack.push(U256::from(&*block_hash)); - } - instructions::COINBASE => { - stack.push(address_to_u256(ext.env_info().author)); - } - instructions::TIMESTAMP => { - stack.push(U256::from(ext.env_info().timestamp)); - } - instructions::NUMBER => { - stack.push(U256::from(ext.env_info().number)); - } - instructions::DIFFICULTY => { - stack.push(ext.env_info().difficulty); - } - instructions::GASLIMIT => { - stack.push(ext.env_info().gas_limit); - } - _ => { - self.exec_stack_instruction(instruction, stack)?; - } - }; - Ok(InstructionResult::Ok) - } - - fn copy_data_to_memory(mem: &mut Vec, stack: &mut Stack, source: &[u8]) { - let dest_offset = stack.pop_back(); - let source_offset = stack.pop_back(); - let size = stack.pop_back(); - let source_size = U256::from(source.len()); - - let output_end = if source_offset > source_size - || size > source_size - || source_offset + size > source_size - { - let zero_slice = if source_offset > source_size { - mem.writeable_slice(dest_offset, size) - } else { - mem.writeable_slice( - dest_offset + source_size - source_offset, - source_offset + size - source_size, - ) - }; - for i in zero_slice.iter_mut() { - *i = 0; - } - source.len() - } else { - (size.low_u64() + source_offset.low_u64()) as usize - }; - - if source_offset < source_size { - let output_begin = source_offset.low_u64() as usize; - mem.write_slice(dest_offset, &source[output_begin..output_end]); - } - } - - fn verify_jump(&self, jump_u: U256, valid_jump_destinations: &BitSet) -> Result { - let jump = jump_u.low_u64() as usize; - - if valid_jump_destinations.contains(jump) && U256::from(jump) == jump_u { - Ok(jump) - } else { - Err(Error::BadJumpDestination { destination: jump }) - } - } - - fn is_zero(&self, val: &U256) -> bool { - val.is_zero() - } - - fn bool_to_u256(&self, val: bool) -> U256 { - if val { - U256::one() - } else { - U256::zero() - } - } - - fn exec_stack_instruction( - &self, - instruction: Instruction, - stack: &mut Stack, - ) -> Result<()> { - match instruction { - instructions::DUP1...instructions::DUP16 => { - let position = instructions::get_dup_position(instruction); - let val = *stack.peek(position); - stack.push(val); - } - instructions::SWAP1...instructions::SWAP16 => { - let position = instructions::get_swap_position(instruction); - stack.swap_with_top(position) - } - instructions::POP => { - stack.pop_back(); - } - instructions::ADD => { - let a = stack.pop_back(); - let b = stack.pop_back(); - stack.push(a.overflowing_add(b).0); - } - instructions::MUL => { - let a = stack.pop_back(); - let b = stack.pop_back(); - stack.push(a.overflowing_mul(b).0); - } - instructions::SUB => { - let a = stack.pop_back(); - let b = stack.pop_back(); - stack.push(a.overflowing_sub(b).0); - } - instructions::DIV => { - let a = stack.pop_back(); - let b = stack.pop_back(); - stack.push(if !self.is_zero(&b) { - match b { - ONE => a, - TWO => a >> 1, - TWO_POW_5 => a >> 5, - TWO_POW_8 => a >> 8, - TWO_POW_16 => a >> 16, - TWO_POW_24 => a >> 24, - TWO_POW_64 => a >> 64, - TWO_POW_96 => a >> 96, - TWO_POW_224 => a >> 224, - TWO_POW_248 => a >> 248, - _ => a.overflowing_div(b).0, - } - } else { - U256::zero() - }); - } - instructions::MOD => { - let a = stack.pop_back(); - let b = stack.pop_back(); - stack.push(if !self.is_zero(&b) { - a.overflowing_rem(b).0 - } else { - U256::zero() - }); - } - instructions::SDIV => { - let (a, sign_a) = get_and_reset_sign(stack.pop_back()); - let (b, sign_b) = get_and_reset_sign(stack.pop_back()); - - // -2^255 - let min = (U256::one() << 255) - U256::one(); - stack.push(if self.is_zero(&b) { - U256::zero() - } else if a == min && b == !U256::zero() { - min - } else { - let c = a.overflowing_div(b).0; - set_sign(c, sign_a ^ sign_b) - }); - } - instructions::SMOD => { - let ua = stack.pop_back(); - let ub = stack.pop_back(); - let (a, sign_a) = get_and_reset_sign(ua); - let b = get_and_reset_sign(ub).0; - - stack.push(if !self.is_zero(&b) { - let c = a.overflowing_rem(b).0; - set_sign(c, sign_a) - } else { - U256::zero() - }); - } - instructions::EXP => { - let base = stack.pop_back(); - let expon = stack.pop_back(); - let res = base.overflowing_pow(expon).0; - stack.push(res); - } - instructions::NOT => { - let a = stack.pop_back(); - stack.push(!a); - } - instructions::LT => { - let a = stack.pop_back(); - let b = stack.pop_back(); - stack.push(self.bool_to_u256(a < b)); - } - instructions::SLT => { - let (a, neg_a) = get_and_reset_sign(stack.pop_back()); - let (b, neg_b) = get_and_reset_sign(stack.pop_back()); - - let is_positive_lt = a < b && !(neg_a | neg_b); - let is_negative_lt = a > b && (neg_a & neg_b); - let has_different_signs = neg_a && !neg_b; - - stack - .push(self.bool_to_u256(is_positive_lt | is_negative_lt | has_different_signs)); - } - instructions::GT => { - let a = stack.pop_back(); - let b = stack.pop_back(); - stack.push(self.bool_to_u256(a > b)); - } - instructions::SGT => { - let (a, neg_a) = get_and_reset_sign(stack.pop_back()); - let (b, neg_b) = get_and_reset_sign(stack.pop_back()); - - let is_positive_gt = a > b && !(neg_a | neg_b); - let is_negative_gt = a < b && (neg_a & neg_b); - let has_different_signs = !neg_a && neg_b; - - stack - .push(self.bool_to_u256(is_positive_gt | is_negative_gt | has_different_signs)); - } - instructions::EQ => { - let a = stack.pop_back(); - let b = stack.pop_back(); - stack.push(self.bool_to_u256(a == b)); - } - instructions::ISZERO => { - let a = stack.pop_back(); - stack.push(self.bool_to_u256(self.is_zero(&a))); - } - instructions::AND => { - let a = stack.pop_back(); - let b = stack.pop_back(); - stack.push(a & b); - } - instructions::OR => { - let a = stack.pop_back(); - let b = stack.pop_back(); - stack.push(a | b); - } - instructions::XOR => { - let a = stack.pop_back(); - let b = stack.pop_back(); - stack.push(a ^ b); - } - instructions::BYTE => { - let word = stack.pop_back(); - let val = stack.pop_back(); - let byte = if word < U256::from(32) { - (val >> (8 * (31 - word.low_u64() as usize))) & U256::from(0xff) - } else { - U256::zero() - }; - stack.push(byte); - } - instructions::ADDMOD => { - let a = stack.pop_back(); - let b = stack.pop_back(); - let c = stack.pop_back(); - - stack.push(if !self.is_zero(&c) { - // upcast to 512 - let a5 = U512::from(a); - let res = a5.overflowing_add(U512::from(b)).0; - let x = res.overflowing_rem(U512::from(c)).0; - U256::from(x) - } else { - U256::zero() - }); - } - instructions::MULMOD => { - let a = stack.pop_back(); - let b = stack.pop_back(); - let c = stack.pop_back(); - - stack.push(if !self.is_zero(&c) { - let a5 = U512::from(a); - let res = a5.overflowing_mul(U512::from(b)).0; - let x = res.overflowing_rem(U512::from(c)).0; - U256::from(x) - } else { - U256::zero() - }); - } - instructions::SIGNEXTEND => { - let bit = stack.pop_back(); - if bit < U256::from(32) { - let number = stack.pop_back(); - let bit_position = (bit.low_u64() * 8 + 7) as usize; - - let bit = number.bit(bit_position); - let mask = (U256::one() << bit_position) - U256::one(); - stack.push(if bit { number | !mask } else { number & mask }); - } - } - instructions::SHL => { - const CONST_256: U256 = U256([256, 0, 0, 0]); - - let shift = stack.pop_back(); - let value = stack.pop_back(); - - let result = if shift >= CONST_256 { - U256::zero() - } else { - value << (shift.as_u32() as usize) - }; - stack.push(result); - } - instructions::SHR => { - const CONST_256: U256 = U256([256, 0, 0, 0]); - - let shift = stack.pop_back(); - let value = stack.pop_back(); - - let result = if shift >= CONST_256 { - U256::zero() - } else { - value >> (shift.as_u32() as usize) - }; - stack.push(result); - } - instructions::SAR => { - // We cannot use get_and_reset_sign/set_sign here, because the rounding looks different. - - const CONST_256: U256 = U256([256, 0, 0, 0]); - const CONST_HIBIT: U256 = U256([0, 0, 0, 0x8000_0000_0000_0000]); - - let shift = stack.pop_back(); - let value = stack.pop_back(); - let sign = value & CONST_HIBIT != U256::zero(); - - let result = if shift >= CONST_256 { - if sign { - U256::max_value() - } else { - U256::zero() - } - } else { - let shift = shift.as_u32() as usize; - let mut shifted = value >> shift; - if sign { - shifted = shifted | (U256::max_value() << (256 - shift)); - } - shifted - }; - stack.push(result); - } - _ => { - return Err(Error::BadInstruction { instruction }); - } - } - Ok(()) - } -} - -fn get_and_reset_sign(value: U256) -> (U256, bool) { - let U256(arr) = value; - let sign = arr[3].leading_zeros() == 0; - (set_sign(value, sign), sign) -} - -fn set_sign(value: U256, sign: bool) -> U256 { - if sign { - (!U256::zero() ^ value).overflowing_add(U256::one()).0 - } else { - value - } -} - -#[inline] -fn u256_to_address(value: &U256) -> Address { - Address::from(H256::from(value)) -} - -#[inline] -fn address_to_u256(value: Address) -> U256 { - U256::from(&*H256::from(value)) -} diff --git a/cita-executor/evm/src/interpreter/shared_cache.rs b/cita-executor/evm/src/interpreter/shared_cache.rs deleted file mode 100644 index a0281aa97..000000000 --- a/cita-executor/evm/src/interpreter/shared_cache.rs +++ /dev/null @@ -1,115 +0,0 @@ -// Copyright 2015-2017 Parity Technologies (UK) Ltd. -// This file is part of Parity. - -// This software is free software: you can redistribute it and/or modify -// it under the terms of the GNU General Public License as published by -// the Free Software Foundation, either version 3 of the License, or -// (at your option) any later version. - -// This software 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 General Public License for more details. - -// You should have received a copy of the GNU General Public License -// along with Parity. If not, see . - -use super::super::instructions; -use bit_set::BitSet; -use cita_types::H256; -use hashable::HASH_EMPTY; -use std::sync::Arc; -use util::cache::MemoryLruCache; -use util::{HeapSizeOf, Mutex}; - -const DEFAULT_CACHE_SIZE: usize = 4 * 1024 * 1024; - -// stub for a HeapSizeOf implementation. -struct Bits(Arc); - -impl HeapSizeOf for Bits { - fn heap_size_of_children(&self) -> usize { - // dealing in bits here - self.0.capacity() * 8 - } -} - -/// Global cache for EVM interpreter -pub struct SharedCache { - jump_destinations: Mutex>, -} - -impl SharedCache { - /// Create a jump destinations cache with a maximum size in bytes - /// to cache. - pub fn new(max_size: usize) -> Self { - SharedCache { - jump_destinations: Mutex::new(MemoryLruCache::new(max_size)), - } - } - - /// Get jump destinations bitmap for a contract. - pub fn jump_destinations(&self, code_hash: &H256, code: &[u8]) -> Arc { - if code_hash == &HASH_EMPTY { - return Self::find_jump_destinations(code); - } - - if let Some(d) = self.jump_destinations.lock().get_mut(code_hash) { - return Arc::clone(&d.0); - } - - let d = Self::find_jump_destinations(code); - self.jump_destinations - .lock() - .insert(*code_hash, Bits(Arc::clone(&d))); - - d - } - - fn find_jump_destinations(code: &[u8]) -> Arc { - let mut jump_dests = BitSet::with_capacity(code.len()); - let mut position = 0; - - while position < code.len() { - let instruction = code[position]; - - if instruction == instructions::JUMPDEST { - jump_dests.insert(position); - } else if instructions::is_push(instruction) { - position += instructions::get_push_bytes(instruction); - } - position += 1; - } - - jump_dests.shrink_to_fit(); - Arc::new(jump_dests) - } -} - -impl Default for SharedCache { - fn default() -> Self { - SharedCache::new(DEFAULT_CACHE_SIZE) - } -} - -#[cfg(test)] -mod tests { - extern crate rustc_hex; - - use self::rustc_hex::FromHex; - use super::SharedCache; - - #[test] - fn test_find_jump_destinations() { - // given - let code = "7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff5b01600055" - .from_hex() - .unwrap(); - - // when - let valid_jump_destinations = SharedCache::find_jump_destinations(&code); - - // then - assert!(valid_jump_destinations.contains(66)); - } -} diff --git a/cita-executor/evm/src/interpreter/stack.rs b/cita-executor/evm/src/interpreter/stack.rs deleted file mode 100644 index 82ba73714..000000000 --- a/cita-executor/evm/src/interpreter/stack.rs +++ /dev/null @@ -1,100 +0,0 @@ -// Copyright 2015-2017 Parity Technologies (UK) Ltd. -// This file is part of Parity. - -// This software is free software: you can redistribute it and/or modify -// it under the terms of the GNU General Public License as published by -// the Free Software Foundation, either version 3 of the License, or -// (at your option) any later version. - -// This software 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 General Public License for more details. - -// You should have received a copy of the GNU General Public License -// along with Parity. If not, see . - -use super::instructions; -use std::fmt; - -/// Stack trait with VM-friendly API -pub trait Stack { - /// Returns `Stack[len(Stack) - no_from_top]` - fn peek(&self, no_from_top: usize) -> &T; - /// Swaps Stack[len(Stack)] and Stack[len(Stack) - no_from_top] - fn swap_with_top(&mut self, no_from_top: usize); - /// Returns true if Stack has at least `no_of_elems` elements - fn has(&self, no_of_elems: usize) -> bool; - /// Get element from top and remove it from Stack. Panics if stack is empty. - fn pop_back(&mut self) -> T; - /// Get (up to `instructions::MAX_NO_OF_TOPICS`) elements from top and remove them from Stack. Panics if stack is empty. - fn pop_n(&mut self, no_of_elems: usize) -> &[T]; - /// Add element on top of the Stack - fn push(&mut self, elem: T); - /// Get number of elements on Stack - fn size(&self) -> usize; - /// Returns all data on stack. - fn peek_top(&self, no_of_elems: usize) -> &[T]; -} - -pub struct VecStack { - stack: Vec, - logs: [S; instructions::MAX_NO_OF_TOPICS], -} - -impl VecStack { - pub fn with_capacity(capacity: usize, zero: S) -> Self { - VecStack { - stack: Vec::with_capacity(capacity), - logs: [zero; instructions::MAX_NO_OF_TOPICS], - } - } -} - -impl Stack for VecStack { - fn peek(&self, no_from_top: usize) -> &S { - &self.stack[self.stack.len() - no_from_top - 1] - } - - fn swap_with_top(&mut self, no_from_top: usize) { - let len = self.stack.len(); - self.stack.swap(len - no_from_top - 1, len - 1); - } - - fn has(&self, no_of_elems: usize) -> bool { - self.stack.len() >= no_of_elems - } - - fn pop_back(&mut self) -> S { - let val = self.stack.pop(); - match val { - Some(x) => x, - None => panic!("Tried to pop from empty stack."), - } - } - - fn pop_n(&mut self, no_of_elems: usize) -> &[S] { - assert!(no_of_elems <= instructions::MAX_NO_OF_TOPICS); - - for i in 0..no_of_elems { - self.logs[i] = self.pop_back(); - } - &self.logs[0..no_of_elems] - } - - fn push(&mut self, elem: S) { - self.stack.push(elem); - } - - fn size(&self) -> usize { - self.stack.len() - } - - fn peek_top(&self, no_from_top: usize) -> &[S] { - assert!( - self.stack.len() >= no_from_top, - "peek_top asked for more items than exist." - ); - &self.stack[self.stack.len() - no_from_top..self.stack.len()] - } -} diff --git a/cita-executor/evm/src/lib.rs b/cita-executor/evm/src/lib.rs deleted file mode 100644 index 146457fa8..000000000 --- a/cita-executor/evm/src/lib.rs +++ /dev/null @@ -1,55 +0,0 @@ -// Copyright 2015-2017 Parity Technologies (UK) Ltd. -// This file is part of Parity. - -// This software is free software: you can redistribute it and/or modify -// it under the terms of the GNU General Public License as published by -// the Free Software Foundation, either version 3 of the License, or -// (at your option) any later version. - -// This software 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 General Public License for more details. - -// You should have received a copy of the GNU General Public License -// along with Parity. If not, see . - -//! Ethereum virtual machine. - -#[cfg_attr(feature = "evm-debug", macro_use)] -extern crate cita_logger as logger; -pub extern crate cita_types; -extern crate common_types as types; -extern crate db as cita_db; - -pub mod action_params; -pub mod call_type; -pub mod env_info; -pub mod error; -pub mod evm; -pub mod ext; -pub mod interpreter; -pub mod return_data; -#[macro_use] -pub mod storage; -#[macro_use] -pub mod factory; -pub mod instructions; -pub mod schedule; -#[macro_use] -extern crate lazy_static; - -#[cfg(all(feature = "benches", test))] -mod benches; -#[cfg(test)] -pub mod tests; - -pub mod fake_tests; - -pub use self::error::{Error, Result}; -pub use self::evm::{CostType, Evm, FinalizationResult, Finalize}; -pub use self::ext::{ContractCreateResult, Ext, MessageCallResult}; -pub use self::factory::{Factory, VMType}; -pub use self::instructions::*; -pub use self::return_data::{GasLeft, ReturnData}; -pub use self::schedule::Schedule; diff --git a/cita-executor/evm/src/return_data.rs b/cita-executor/evm/src/return_data.rs deleted file mode 100644 index 1d3b2e9d3..000000000 --- a/cita-executor/evm/src/return_data.rs +++ /dev/null @@ -1,66 +0,0 @@ -// Copyright 2015-2017 Parity Technologies (UK) Ltd. -// This file is part of Parity. - -// This software is free software: you can redistribute it and/or modify -// it under the terms of the GNU General Public License as published by -// the Free Software Foundation, either version 3 of the License, or -// (at your option) any later version. - -// This software 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 General Public License for more details. - -// You should have received a copy of the GNU General Public License -// along with Parity. If not, see . - -//! Evm interface. - -use cita_types::U256; - -/// Return data buffer. Holds memory from a previous call and a slice into that memory. -#[derive(Debug)] -pub struct ReturnData { - mem: Vec, - offset: usize, - size: usize, -} - -impl ::std::ops::Deref for ReturnData { - type Target = [u8]; - fn deref(&self) -> &[u8] { - &self.mem[self.offset..self.offset + self.size] - } -} - -impl ReturnData { - /// Create empty `ReturnData`. - pub fn empty() -> Self { - ReturnData { - mem: Vec::new(), - offset: 0, - size: 0, - } - } - /// Create `ReturnData` from give buffer and slice. - pub fn new(mem: Vec, offset: usize, size: usize) -> Self { - ReturnData { mem, offset, size } - } -} - -/// Gas Left: either it is a known value, or it needs to be computed by processing -/// a return instruction. -#[derive(Debug)] -pub enum GasLeft { - /// Known gas left - Known(U256), - /// Return or Revert instruction must be processed. - NeedsReturn { - /// Amount of gas left. - gas_left: U256, - /// Return data buffer. - data: ReturnData, - /// Apply or revert state changes on revert. - apply_state: bool, - }, -} diff --git a/cita-executor/evm/src/schedule.rs b/cita-executor/evm/src/schedule.rs deleted file mode 100644 index 2beea1487..000000000 --- a/cita-executor/evm/src/schedule.rs +++ /dev/null @@ -1,157 +0,0 @@ -// Copyright 2015-2017 Parity Technologies (UK) Ltd. -// This file is part of Parity. - -// This software is free software: you can redistribute it and/or modify -// it under the terms of the GNU General Public License as published by -// the Free Software Foundation, either version 3 of the License, or -// (at your option) any later version. - -// This software 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 General Public License for more details. - -// You should have received a copy of the GNU General Public License -// along with Parity. If not, see . - -//! Cost schedule and other parameterisations for the EVM. - -/// Definition of the cost schedule and other parameterisations for the EVM. -pub struct Schedule { - /// VM stack limit - pub stack_limit: usize, - /// Max number of nested calls/creates - pub max_depth: usize, - /// Gas prices for instructions in all tiers - pub tier_step_gas: [usize; 8], - /// Gas price for `EXP` opcode - pub exp_gas: usize, - /// Additional gas for `EXP` opcode for each byte of exponent - pub exp_byte_gas: usize, - /// Gas price for `SHA3` opcode - pub sha3_gas: usize, - /// Additional gas for `SHA3` opcode for each word of hashed memory - pub sha3_word_gas: usize, - /// Gas price for loading from storage - pub sload_gas: usize, - /// Gas price for setting new value to storage (`storage==0`, `new!=0`) - pub sstore_set_gas: usize, - /// Gas price for altering value in storage - pub sstore_reset_gas: usize, - /// Gas refund for `SSTORE` clearing (when `storage!=0`, `new==0`) - pub sstore_refund_gas: usize, - /// Gas price for `JUMPDEST` opcode - pub jumpdest_gas: usize, - /// Gas price for `LOG*` - pub log_gas: usize, - /// Additional gas for data in `LOG*` - pub log_data_gas: usize, - /// Additional gas for each topic in `LOG*` - pub log_topic_gas: usize, - /// Gas price for `CREATE` opcode - pub create_gas: usize, - /// Gas price for `*CALL*` opcodes - pub call_gas: usize, - /// Stipend for transfer for `CALL|CALLCODE` opcode when `value>0` - pub call_stipend: usize, - /// Additional gas required for value transfer (`CALL|CALLCODE`) - pub call_value_transfer_gas: usize, - /// Additional gas for creating new account (`CALL|CALLCODE`) - pub call_new_account_gas: usize, - /// Refund for SUICIDE - pub suicide_refund_gas: usize, - /// Gas for used memory - pub memory_gas: usize, - /// Coefficient used to convert memory size to gas price for memory - pub quad_coeff_div: usize, - /// Cost for contract length when executing `CREATE` - pub create_data_gas: usize, - /// Maximum code size when creating a contract. - pub create_data_limit: usize, - /// Transaction cost - pub tx_gas: usize, - /// `CREATE` transaction cost - pub tx_create_gas: usize, - /// Additional cost for empty data transaction - pub tx_data_zero_gas: usize, - /// Aditional cost for non-empty data transaction - pub tx_data_non_zero_gas: usize, - /// Gas price for copying memory - pub copy_gas: usize, - /// Price of EXTCODESIZE - pub extcodesize_gas: usize, - /// Base price of EXTCODECOPY - pub extcodecopy_base_gas: usize, - /// Price of BALANCE - pub balance_gas: usize, - /// Price of SUICIDE - pub suicide_gas: usize, - /// Amount of additional gas to pay when SUICIDE credits a non-existant account - pub suicide_to_new_account_cost: usize, - /// If Some(x): let limit = GAS * (x - 1) / x; let CALL's gas = min(requested, limit). let CREATE's gas = limit. - /// If None: let CALL's gas = (requested > GAS ? [OOG] : GAS). let CREATE's gas = GAS - pub sub_gas_cap_divisor: usize, - /// Don't ever make empty accounts; contracts start with nonce=1. Also, don't charge 25k when sending/suicide zero-value. - pub no_empty: bool, - /// Kill empty accounts if touched. - pub kill_empty: bool, -} - -impl Schedule { - /// Schedule for the v1 of the cita main net. - pub fn new_v1() -> Schedule { - Self::new() - } - - fn new() -> Schedule { - Schedule { - stack_limit: 1024, - max_depth: 1024, - tier_step_gas: [0, 2, 3, 5, 8, 10, 20, 0], - exp_gas: 10, - exp_byte_gas: 10, - sha3_gas: 30, - sha3_word_gas: 6, - sload_gas: 50, - sstore_set_gas: 20_000, - sstore_reset_gas: 5000, - sstore_refund_gas: 15_000, - jumpdest_gas: 1, - log_gas: 375, - log_data_gas: 8, - log_topic_gas: 375, - create_gas: 32_000, - call_gas: 40, - call_stipend: 2300, - call_value_transfer_gas: 9000, - call_new_account_gas: 25_000, - suicide_refund_gas: 24_000, - memory_gas: 3, - quad_coeff_div: 512, - create_data_gas: 200, - create_data_limit: usize::max_value(), - tx_gas: 21_000, - tx_create_gas: 53_000, - tx_data_zero_gas: 4, - tx_data_non_zero_gas: 68, - copy_gas: 3, - extcodesize_gas: 20, - extcodecopy_base_gas: 20, - balance_gas: 20, - suicide_gas: 0, - suicide_to_new_account_cost: 0, - sub_gas_cap_divisor: 64, - no_empty: false, - kill_empty: false, - } - } -} - -#[test] -#[cfg(test)] -fn schedule_evm_assumptions() { - let s1 = Schedule::new_v1(); - - // To optimize division we assume 2**9 for quad_coeff_div - assert_eq!(s1.quad_coeff_div, 512); -} diff --git a/cita-executor/evm/src/storage.rs b/cita-executor/evm/src/storage.rs deleted file mode 100644 index f016f4a58..000000000 --- a/cita-executor/evm/src/storage.rs +++ /dev/null @@ -1,510 +0,0 @@ -// CITA -// Copyright 2016-2017 Cryptape Technologies LLC. - -// This program is free software: you can redistribute it -// and/or modify it under the terms of the GNU 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 General Public License for more details. - -// You should have received a copy of the GNU General Public License -// along with this program. If not, see . - -use crate::Error as EvmError; -use crate::Ext; -use cita_types::{H256, U256}; -use std::boxed::Box; -use std::convert::From; -use std::string::FromUtf8Error; -use util::sha3; - -//////////////////////////////////////////////////////////////////////////////// -pub trait Serialize { - fn serialize(&self) -> Result, EvmError>; -} -pub trait Deserialize: Sized { - fn deserialize(bytes: &[u8]) -> Result; -} - -//////////////////////////////////////////////////////////////////////////////// -impl Serialize for U256 { - fn serialize(&self) -> Result, EvmError> { - //let mut vec = Vec::with_capacity(64); - let mut vec = vec![0; 32]; - self.to_big_endian(&mut vec); - Ok(vec) - } -} -impl Deserialize for U256 { - fn deserialize(bytes: &[u8]) -> Result { - Ok(U256::from(bytes)) - } -} - -//////////////////////////////////////////////////////////////////////////////// -impl Serialize for String { - fn serialize(&self) -> Result, EvmError> { - Ok(self.to_owned().into_bytes()) - } -} -impl Deserialize for String { - fn deserialize(bytes: &[u8]) -> Result { - Ok(Self::from_utf8(bytes.to_owned())?) - } -} - -//////////////////////////////////////////////////////////////////////////////// -impl Serialize for Vec { - fn serialize(&self) -> Result, EvmError> { - Ok(self.clone()) - } -} -impl Deserialize for Vec { - fn deserialize(bytes: &[u8]) -> Result { - Ok(Vec::from(bytes)) - } -} - -//////////////////////////////////////////////////////////////////////////////// -impl From for EvmError { - fn from(err: FromUtf8Error) -> Self { - EvmError::Internal(format!("Internal error: {}", err)) - } -} - -//////////////////////////////////////////////////////////////////////////////// -#[derive(Debug, PartialEq, Eq, Clone)] -pub struct Scalar { - position: H256, -} - -impl Scalar { - pub fn new(position: H256) -> Self { - Scalar { position } - } - // single element - pub fn set(self: &Self, ext: &mut Ext, value: U256) -> Result<(), EvmError> { - ext.set_storage(self.position, H256::from(value))?; - Ok(()) - } - - pub fn get(self: &Self, ext: &Ext) -> Result { - let value = ext.storage_at(&self.position)?; - Ok(U256::from(value)) - } - - // bytes & string - pub fn set_bytes(self: &Self, ext: &mut Ext, value: &T) -> Result<(), EvmError> - where - T: Serialize, - { - let encoded = value.serialize()?; - let length = encoded.len(); - if length < 32 { - let mut byte32 = [0u8; 32]; - byte32[0..encoded.len()].copy_from_slice(&encoded); - byte32[31] = (length * 2) as u8; - ext.set_storage(self.position, H256::from_slice(&byte32))?; - } else { - ext.set_storage(self.position, H256::from((length * 2 + 1) as u64))?; - let mut key = U256::from(H256::from_slice(&sha3::keccak256(&self.position))); - for chunk in encoded.chunks(32) { - let value = H256::from(chunk); - ext.set_storage(H256::from(key), value)?; - key = key + U256::one(); - } - } - Ok(()) - } - - pub fn get_bytes(self: &Self, ext: &Ext) -> Result, EvmError> - where - T: Deserialize, - { - let mut bytes = Vec::::new(); - let first = ext.storage_at(&self.position)?; - if first[31] % 2 == 0 { - let len = (first[31] / 2) as usize; - bytes.extend_from_slice(&first[0..len]); - let decoded = T::deserialize(&bytes)?; - Ok(Box::new(decoded)) - } else { - let mut len = ((first.low_u64() as usize) - 1) / 2; - let mut key = U256::from(H256::from_slice(&sha3::keccak256(&self.position))); - let mut bytes = Vec::new(); - while len > 0 { - let v = ext.storage_at(&H256::from(key))?; - if len > 32 { - bytes.extend_from_slice(v.as_ref()); - key = key + U256::one(); - len -= 32; - } else { - bytes.extend_from_slice(&v[0..len]); - len = 0; - } - } - Ok(Box::new(T::deserialize(&bytes)?)) - } - } -} - -//////////////////////////////////////////////////////////////////////////////// -#[derive(Debug, PartialEq, Eq, Clone)] -pub struct Array { - position: H256, -} -impl Array { - pub fn new(position: H256) -> Self { - Array { position } - } - #[inline] - fn key(&self, index: u64) -> H256 { - let mut key = U256::from(H256::from_slice(&sha3::keccak256(&self.position))); - key = key + U256::from(index); - H256::from(key) - } - pub fn set(self: &Self, ext: &mut Ext, index: u64, value: &U256) -> Result<(), EvmError> { - let scalar = Scalar::new(self.key(index)); - scalar.set(ext, *value) - } - - pub fn get(self: &Self, ext: &Ext, index: u64) -> Result { - let scalar = Scalar::new(self.key(index)); - scalar.get(ext) - } - - pub fn set_bytes(self: &Self, ext: &mut Ext, index: u64, value: &T) -> Result<(), EvmError> - where - T: Serialize, - { - let scalar = Scalar::new(self.key(index)); - scalar.set_bytes(ext, value) - } - - pub fn get_bytes(self: &Self, ext: &Ext, index: u64) -> Result, EvmError> - where - T: Deserialize, - { - let scalar = Scalar::new(self.key(index)); - scalar.get_bytes(ext) - } - - pub fn set_len(self: &Self, ext: &mut Ext, len: u64) -> Result<(), EvmError> { - ext.set_storage(self.position, H256::from(len))?; - Ok(()) - } - - pub fn get_len(self: &Self, ext: &Ext) -> Result { - let len = ext.storage_at(&self.position)?; - Ok(len.low_u64()) - } - - pub fn get_array(self: &mut Self, index: u64) -> Array { - Array::new(self.key(index)) - } - pub fn get_map(self: &mut Self, index: u64) -> Map { - Map::new(self.key(index)) - } -} - -//////////////////////////////////////////////////////////////////////////////// -#[derive(Debug, PartialEq, Eq, Clone)] -pub struct Map { - position: H256, -} - -impl Map { - pub fn new(position: H256) -> Self { - Map { position } - } - #[inline] - fn key(&self, key: &Key) -> Result - where - Key: Serialize, - { - let mut bytes = Vec::new(); - bytes.extend_from_slice(&key.serialize()?); - bytes.extend_from_slice(self.position.as_ref()); - Ok(H256::from_slice(&sha3::keccak256(&bytes))) - } - pub fn set(self: &Self, ext: &mut Ext, key: &Key, value: U256) -> Result<(), EvmError> - where - Key: Serialize, - { - Scalar::new(self.key(key)?).set(ext, value) - } - - pub fn get(self: &Self, ext: &Ext, key: &Key) -> Result - where - Key: Serialize, - { - Scalar::new(self.key(key)?).get(ext) - } - - pub fn set_bytes( - self: &Self, - ext: &mut Ext, - key: &Key, - value: &Value, - ) -> Result<(), EvmError> - where - Key: Serialize, - Value: Serialize, - { - Scalar::new(self.key(key)?).set_bytes(ext, value) - } - - pub fn get_bytes(self: &Self, ext: &Ext, key: &Key) -> Result - where - Key: Serialize, - Value: Deserialize, - { - Ok(*Scalar::new(self.key(key)?).get_bytes(ext)?) - } - - pub fn get_array(self: &mut Self, key: &Key) -> Result - where - Key: Serialize, - { - Ok(Array::new(self.key(key)?)) - } - - pub fn get_map(self: &mut Self, key: &Key) -> Result - where - Key: Serialize, - { - Ok(Map::new(self.key(key)?)) - } -} - -#[cfg(test)] -mod tests { - use super::*; - use crate::fake_tests::FakeExt; - - #[test] - fn test_scalar_bytes() { - let mut ext = FakeExt::new(); - let scalar = Scalar::new(H256::from(0)); - - // 1) length=30 - let expected = format!("012345678901234567890123456789"); - assert!(scalar.set_bytes(&mut ext, &expected).is_ok()); - let value = scalar.get_bytes::(&ext); - assert!(value.is_ok()); - assert_eq!(*value.unwrap().as_ref(), expected.clone()); - - // 2) length=31 - let expected = format!("0123456789012345678901234567890"); - assert!(scalar.set_bytes(&mut ext, &expected).is_ok()); - let value = scalar.get_bytes::(&ext); - assert!(value.is_ok()); - assert_eq!(*value.unwrap().as_ref(), expected.clone()); - - // 3) length=32 - let expected = format!("01234567890123456789012345678901"); - assert!(scalar.set_bytes(&mut ext, &expected).is_ok()); - let value = scalar.get_bytes::(&ext); - assert!(value.is_ok()); - assert_eq!(*value.unwrap().as_ref(), expected.clone()); - - // 4) length=43 - let expected = format!("012345678901234567890123456789012"); - assert!(scalar.set_bytes(&mut ext, &expected).is_ok()); - let value = scalar.get_bytes::(&ext); - assert!(value.is_ok()); - assert_eq!(*value.unwrap().as_ref(), expected.clone()); - } - - #[test] - fn test_scalar_u256() { - let mut ext = FakeExt::new(); - let scalar = Scalar::new(H256::from(0)); - - let expected = U256::from(0x123456); - assert!(scalar.set(&mut ext, expected.clone()).is_ok()); - let value = scalar.get(&ext); - assert!(value.is_ok()); - assert_eq!(value.unwrap(), expected.clone()); - } - - #[test] - fn test_array_simple() { - let mut ext = FakeExt::new(); - let length = 7u64; - let array = Array { - position: H256::from(0), - }; - // 1) length - assert!(array.set_len(&mut ext, length).is_ok()); - assert_eq!(array.get_len(&ext).unwrap(), length); - - // 2) array[1] = 0x1234 - let index = 1; - let expected = U256::from(0x1234); - assert!(array.set(&mut ext, index, &expected).is_ok()); - let value = array.get(&ext, index); - assert_eq!(value.unwrap(), expected.clone()); - - // 3) array[3] = 0x2234 - let index = 3; - let expected = U256::from(0x2234); - assert!(array.set(&mut ext, index, &expected).is_ok()); - let value = array.get(&ext, index); - assert_eq!(value.unwrap(), expected.clone()); - } - - #[test] - fn test_array_with_sub_array() { - let mut ext = FakeExt::new(); - let mut array = Array::new(H256::from(0)); - - // 1) length = 7 - let length = 7; - assert!(array.set_len(&mut ext, length).is_ok()); - assert_eq!(array.get_len(&ext).unwrap(), length); - - // 2) array[1].len = 8 - let index = 1; - let subarray_length = 8; - let subarray = array.get_array(index); - assert!(subarray.set_len(&mut ext, subarray_length).is_ok()); - assert_eq!(subarray.get_len(&mut ext).unwrap(), subarray_length); - - // 3) array[1][2] = 0x1234 - let index = 2; - let expected = U256::from(0x1234); - assert!(subarray.set(&mut ext, index, &expected).is_ok()); - assert_eq!(subarray.get(&ext, index).unwrap(), expected); - - // 4) array[1][4] = 0x2234 - let index = 4; - let expected = U256::from(0x2234); - assert!(subarray.set(&mut ext, index, &expected).is_ok()); - assert_eq!(subarray.get(&ext, index).unwrap(), expected); - } - - #[test] - fn test_array_with_sub_map() { - let mut ext = FakeExt::new(); - let mut array = Array::new(H256::from(0)); - - // 1) length = 7 - let length = 7; - assert!(array.set_len(&mut ext, length).is_ok()); - assert_eq!(array.get_len(&ext).unwrap(), length); - - // 2) array[1][2] = 0x1234 - let index = 1; - let key = U256::from(2); - let submap = array.get_map(index); - let expected = U256::from(0x1234); - assert!(submap.set(&mut ext, &key, expected).is_ok()); - assert_eq!(submap.get::(&ext, &key).unwrap(), expected); - - // 4) array[1]["key"] = "1234" - let key = String::from("key"); - let expected = String::from("1234"); - assert!(submap - .set_bytes::(&mut ext, &key, &expected) - .is_ok()); - assert_eq!( - submap.get_bytes::(&ext, &key).unwrap(), - expected.clone() - ); - } - - #[test] - fn test_map_simple() { - let mut ext = FakeExt::new(); - let map = Map::new(H256::from(1)); - - // 1) map["key"] = "value" - let key = U256::from(1); - let value = U256::from(0x1234); - assert!(map.set(&mut ext, &key, value).is_ok()); - assert_eq!(map.get(&ext, &key).unwrap(), value); - - // 2) map[0] = "1234567890" - let key = U256::from(1); - let value = String::from("1234567890"); - assert!(map.set_bytes(&mut ext, &key, &value).is_ok()); - assert_eq!( - map.get_bytes::(&ext, &key).unwrap(), - value.clone() - ); - - // 3) map[0] = "123456789012345678901234567890123" - let key = U256::from(1); - let value = String::from("123456789012345678901234567890123"); - assert!(map.set_bytes(&mut ext, &key, &value).is_ok()); - assert_eq!(map.get_bytes::(&ext, &key).unwrap(), value); - - // 4) map["key"] = 0x1234; - let key = String::from("key"); - let value = U256::from(0x1234); - assert!(map.set(&mut ext, &key, value).is_ok()); - assert_eq!(map.get(&ext, &key).unwrap(), value);; - } - - #[test] - fn test_map_with_sub_array() { - let mut ext = FakeExt::new(); - let mut map = Map::new(H256::from(1)); - - // 1) map["key1"]["key2"] = "1234567890" - let key1 = String::from("key1"); - let index = 2u64; - let value = String::from("1234567890"); - let sub_array = map.get_array(&key1).unwrap(); - assert!(sub_array.set_bytes(&mut ext, index.clone(), &value).is_ok()); - assert_eq!( - *sub_array.get_bytes::(&ext, index.clone()).unwrap(), - value.clone() - ); - - // 2) map["key1"][2] = "1234567890" - let key1 = String::from("key1"); - let index = 4u64; - let value = String::from("1234567890"); - let sub_array = map.get_array(&key1).unwrap(); - assert!(sub_array.set_bytes(&mut ext, index.clone(), &value).is_ok()); - assert_eq!( - *sub_array.get_bytes::(&ext, index.clone()).unwrap(), - value.clone() - ); - } - - #[test] - fn test_map_with_sub_map() { - let mut ext = FakeExt::new(); - let mut map = Map::new(H256::from(1)); - - // 1) map["key1"]["key2"] = "1234567890" - let key1 = String::from("key1"); - let key2 = String::from("key2"); - let value = String::from("1234567890"); - let sub_map = map.get_map(&key1).unwrap(); - assert!(sub_map.set_bytes(&mut ext, &key2, &value).is_ok()); - assert_eq!( - sub_map.get_bytes::(&ext, &key2).unwrap(), - value.clone() - ); - - // 2) map["key1"][2] = "1234567890" - let key1 = String::from("key1"); - let key2 = U256::from(2); - let value = String::from("1234567890"); - let sub_map = map.get_map(&key1).unwrap(); - assert!(sub_map.set_bytes(&mut ext, &key2, &value).is_ok()); - assert_eq!( - sub_map.get_bytes::<_, String>(&ext, &key2).unwrap(), - value.clone() - ); - } -} diff --git a/cita-executor/evm/src/tests.rs b/cita-executor/evm/src/tests.rs deleted file mode 100644 index 38ae48202..000000000 --- a/cita-executor/evm/src/tests.rs +++ /dev/null @@ -1,1410 +0,0 @@ -// Copyright 2015-2017 Parity Technologies (UK) Ltd. -// This file is part of Parity. - -// This software is free software: you can redistribute it and/or modify -// it under the terms of the GNU General Public License as published by -// the Free Software Foundation, either version 3 of the License, or -// (at your option) any later version. - -// This software 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 General Public License for more details. - -// You should have received a copy of the GNU General Public License -// along with Parity. If not, see . - -use self::rustc_hex::FromHex; -use crate::action_params::{ActionParams, ActionValue}; -use crate::error; -use crate::evm::Evm; -use crate::factory::{Factory, VMType}; -use crate::fake_tests::{test_finalize, FakeCall, FakeCallType, FakeExt}; -use cita_types::{Address, H256, U256}; -use rustc_hex; -use std::collections::{HashMap, HashSet}; -use std::fmt::Debug; -use std::hash::Hash; -use std::str::FromStr; -use std::sync::Arc; - -#[test] -fn test_stack_underflow() { - let address = Address::from_str("0f572e5295c57f15886f9b263e2f6d2d6c7b5ec6").unwrap(); - let code = "01600055".from_hex().unwrap(); - - let mut params = ActionParams::default(); - params.address = address.clone(); - params.gas = U256::from(100_000); - params.code = Some(Arc::new(code)); - let mut ext = FakeExt::new(); - - let err = { - let mut vm: Box = Box::new(super::interpreter::Interpreter::::new(Arc::new( - super::interpreter::SharedCache::default(), - ))); - test_finalize(vm.exec(¶ms, &mut ext)).unwrap_err() - }; - - match err { - error::Error::StackUnderflow { - wanted, on_stack, .. - } => { - assert_eq!(wanted, 2); - assert_eq!(on_stack, 0); - } - _ => assert!(false, "Expected StackUndeflow"), - }; -} - -evm_test! {test_add: test_add_jit, test_add_int} -fn test_add(factory: super::Factory) { - let address = Address::from_str("0f572e5295c57f15886f9b263e2f6d2d6c7b5ec6").unwrap(); - let code = "7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff01600055" - .from_hex() - .unwrap(); - - let mut params = ActionParams::default(); - params.address = address.clone(); - params.gas = U256::from(100_000); - params.code = Some(Arc::new(code)); - let mut ext = FakeExt::new(); - - let gas_left = { - let mut vm = factory.create(params.gas); - test_finalize(vm.exec(¶ms, &mut ext)).unwrap() - }; - - assert_eq!(gas_left, U256::from(79_988)); - assert_store( - &ext, - 0, - "fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe", - ); -} - -evm_test! {test_sha3: test_sha3_jit, test_sha3_int} -fn test_sha3(factory: super::Factory) { - let address = Address::from_str("0f572e5295c57f15886f9b263e2f6d2d6c7b5ec6").unwrap(); - let code = "6000600020600055".from_hex().unwrap(); - - let mut params = ActionParams::default(); - params.address = address.clone(); - params.gas = U256::from(100_000); - params.code = Some(Arc::new(code)); - let mut ext = FakeExt::new(); - - let gas_left = { - let mut vm = factory.create(params.gas); - test_finalize(vm.exec(¶ms, &mut ext)).unwrap() - }; - - assert_eq!(gas_left, U256::from(79_961)); - assert_store( - &ext, - 0, - "c5d2460186f7233c927e7db2dcc703c0e500b653ca82273b7bfad8045d85a470", - ); -} - -evm_test! {test_address: test_address_jit, test_address_int} -fn test_address(factory: super::Factory) { - let address = Address::from_str("0f572e5295c57f15886f9b263e2f6d2d6c7b5ec6").unwrap(); - let code = "30600055".from_hex().unwrap(); - - let mut params = ActionParams::default(); - params.address = address.clone(); - params.gas = U256::from(100_000); - params.code = Some(Arc::new(code)); - let mut ext = FakeExt::new(); - - let gas_left = { - let mut vm = factory.create(params.gas); - test_finalize(vm.exec(¶ms, &mut ext)).unwrap() - }; - - assert_eq!(gas_left, U256::from(79_995)); - assert_store( - &ext, - 0, - "0000000000000000000000000f572e5295c57f15886f9b263e2f6d2d6c7b5ec6", - ); -} - -evm_test! {test_origin: test_origin_jit, test_origin_int} -fn test_origin(factory: super::Factory) { - let address = Address::from_str("0f572e5295c57f15886f9b263e2f6d2d6c7b5ec6").unwrap(); - let origin = Address::from_str("cd1722f2947def4cf144679da39c4c32bdc35681").unwrap(); - let code = "32600055".from_hex().unwrap(); - - let mut params = ActionParams::default(); - params.address = address.clone(); - params.origin = origin.clone(); - params.gas = U256::from(100_000); - params.code = Some(Arc::new(code)); - let mut ext = FakeExt::new(); - - let gas_left = { - let mut vm = factory.create(params.gas); - test_finalize(vm.exec(¶ms, &mut ext)).unwrap() - }; - - assert_eq!(gas_left, U256::from(79_995)); - assert_store( - &ext, - 0, - "000000000000000000000000cd1722f2947def4cf144679da39c4c32bdc35681", - ); -} - -evm_test! {test_sender: test_sender_jit, test_sender_int} -fn test_sender(factory: super::Factory) { - let address = Address::from_str("0f572e5295c57f15886f9b263e2f6d2d6c7b5ec6").unwrap(); - let sender = Address::from_str("cd1722f2947def4cf144679da39c4c32bdc35681").unwrap(); - let code = "33600055".from_hex().unwrap(); - - let mut params = ActionParams::default(); - params.address = address.clone(); - params.sender = sender.clone(); - params.gas = U256::from(100_000); - params.code = Some(Arc::new(code)); - let mut ext = FakeExt::new(); - - let gas_left = { - let mut vm = factory.create(params.gas); - test_finalize(vm.exec(¶ms, &mut ext)).unwrap() - }; - - assert_eq!(gas_left, U256::from(79_995)); - assert_store( - &ext, - 0, - "000000000000000000000000cd1722f2947def4cf144679da39c4c32bdc35681", - ); -} - -evm_test! {test_extcodecopy: test_extcodecopy_jit, test_extcodecopy_int} -fn test_extcodecopy(factory: super::Factory) { - // 33 - sender - // 3b - extcodesize - // 60 00 - push 0 - // 60 00 - push 0 - // 33 - sender - // 3c - extcodecopy - // 60 00 - push 0 - // 51 - load word from memory - // 60 00 - push 0 - // 55 - sstore - - let address = Address::from_str("0f572e5295c57f15886f9b263e2f6d2d6c7b5ec6").unwrap(); - let sender = Address::from_str("cd1722f2947def4cf144679da39c4c32bdc35681").unwrap(); - let code = "333b60006000333c600051600055".from_hex().unwrap(); - let sender_code = "6005600055".from_hex().unwrap(); - - let mut params = ActionParams::default(); - params.address = address.clone(); - params.sender = sender.clone(); - params.gas = U256::from(100_000); - params.code = Some(Arc::new(code)); - let mut ext = FakeExt::new(); - ext.codes.insert(sender, Arc::new(sender_code)); - - let gas_left = { - let mut vm = factory.create(params.gas); - test_finalize(vm.exec(¶ms, &mut ext)).unwrap() - }; - - assert_eq!(gas_left, U256::from(79_935)); - assert_store( - &ext, - 0, - "6005600055000000000000000000000000000000000000000000000000000000", - ); -} - -evm_test! {test_log_empty: test_log_empty_jit, test_log_empty_int} -fn test_log_empty(factory: super::Factory) { - let address = Address::from_str("0f572e5295c57f15886f9b263e2f6d2d6c7b5ec6").unwrap(); - let code = "60006000a0".from_hex().unwrap(); - - let mut params = ActionParams::default(); - params.address = address.clone(); - params.gas = U256::from(100_000); - params.code = Some(Arc::new(code)); - let mut ext = FakeExt::new(); - - let gas_left = { - let mut vm = factory.create(params.gas); - test_finalize(vm.exec(¶ms, &mut ext)).unwrap() - }; - - assert_eq!(gas_left, U256::from(99_619)); - assert_eq!(ext.logs.len(), 1); - assert_eq!(ext.logs[0].topics.len(), 0); - assert!(ext.logs[0].data.is_empty()); -} - -evm_test! {test_log_sender: test_log_sender_jit, test_log_sender_int} -fn test_log_sender(factory: super::Factory) { - // 60 ff - push ff - // 60 00 - push 00 - // 53 - mstore - // 33 - sender - // 60 20 - push 20 - // 60 00 - push 0 - // a1 - log with 1 topic - - let address = Address::from_str("0f572e5295c57f15886f9b263e2f6d2d6c7b5ec6").unwrap(); - let sender = Address::from_str("cd1722f3947def4cf144679da39c4c32bdc35681").unwrap(); - let code = "60ff6000533360206000a1".from_hex().unwrap(); - - let mut params = ActionParams::default(); - params.address = address.clone(); - params.sender = sender.clone(); - params.gas = U256::from(100_000); - params.code = Some(Arc::new(code)); - let mut ext = FakeExt::new(); - - let gas_left = { - let mut vm = factory.create(params.gas); - test_finalize(vm.exec(¶ms, &mut ext)).unwrap() - }; - - assert_eq!(gas_left, U256::from(98_974)); - assert_eq!(ext.logs.len(), 1); - assert_eq!(ext.logs[0].topics.len(), 1); - assert_eq!( - ext.logs[0].topics[0], - H256::from_str("000000000000000000000000cd1722f3947def4cf144679da39c4c32bdc35681").unwrap() - ); - assert_eq!( - ext.logs[0].data, - "ff00000000000000000000000000000000000000000000000000000000000000" - .from_hex() - .unwrap() - ); -} - -evm_test! {test_blockhash: test_blockhash_jit, test_blockhash_int} -fn test_blockhash(factory: super::Factory) { - let address = Address::from_str("0f572e5295c57f15886f9b263e2f6d2d6c7b5ec6").unwrap(); - let code = "600040600055".from_hex().unwrap(); - let blockhash = - H256::from_str("123400000000000000000000cd1722f2947def4cf144679da39c4c32bdc35681").unwrap(); - - let mut params = ActionParams::default(); - params.address = address.clone(); - params.gas = U256::from(100_000); - params.code = Some(Arc::new(code)); - let mut ext = FakeExt::new(); - ext.blockhashes.insert(U256::zero(), blockhash.clone()); - - let gas_left = { - let mut vm = factory.create(params.gas); - test_finalize(vm.exec(¶ms, &mut ext)).unwrap() - }; - - assert_eq!(gas_left, U256::from(79_974)); - assert_eq!(ext.store.get(&H256::new()).unwrap(), &blockhash); -} - -evm_test! {test_calldataload: test_calldataload_jit, test_calldataload_int} -fn test_calldataload(factory: super::Factory) { - let address = Address::from_str("0f572e5295c57f15886f9b263e2f6d2d6c7b5ec6").unwrap(); - let code = "600135600055".from_hex().unwrap(); - let data = "0123ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff23" - .from_hex() - .unwrap(); - - let mut params = ActionParams::default(); - params.address = address.clone(); - params.gas = U256::from(100_000); - params.code = Some(Arc::new(code)); - params.data = Some(data); - let mut ext = FakeExt::new(); - - let gas_left = { - let mut vm = factory.create(params.gas); - test_finalize(vm.exec(¶ms, &mut ext)).unwrap() - }; - - assert_eq!(gas_left, U256::from(79_991)); - assert_store( - &ext, - 0, - "23ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff23", - ); -} - -evm_test! {test_author: test_author_jit, test_author_int} -fn test_author(factory: super::Factory) { - let author = Address::from_str("0f572e5295c57f15886f9b263e2f6d2d6c7b5ec6").unwrap(); - let code = "41600055".from_hex().unwrap(); - - let mut params = ActionParams::default(); - params.gas = U256::from(100_000); - params.code = Some(Arc::new(code)); - let mut ext = FakeExt::new(); - ext.info.author = author; - - let gas_left = { - let mut vm = factory.create(params.gas); - test_finalize(vm.exec(¶ms, &mut ext)).unwrap() - }; - - assert_eq!(gas_left, U256::from(79_995)); - assert_store( - &ext, - 0, - "0000000000000000000000000f572e5295c57f15886f9b263e2f6d2d6c7b5ec6", - ); -} - -evm_test! {test_timestamp: test_timestamp_jit, test_timestamp_int} -fn test_timestamp(factory: super::Factory) { - let timestamp = 0x1234; - let code = "42600055".from_hex().unwrap(); - - let mut params = ActionParams::default(); - params.gas = U256::from(100_000); - params.code = Some(Arc::new(code)); - let mut ext = FakeExt::new(); - ext.info.timestamp = timestamp; - - let gas_left = { - let mut vm = factory.create(params.gas); - test_finalize(vm.exec(¶ms, &mut ext)).unwrap() - }; - - assert_eq!(gas_left, U256::from(79_995)); - assert_store( - &ext, - 0, - "0000000000000000000000000000000000000000000000000000000000001234", - ); -} - -evm_test! {test_number: test_number_jit, test_number_int} -fn test_number(factory: super::Factory) { - let number = 0x1234; - let code = "43600055".from_hex().unwrap(); - - let mut params = ActionParams::default(); - params.gas = U256::from(100_000); - params.code = Some(Arc::new(code)); - let mut ext = FakeExt::new(); - ext.info.number = number; - - let gas_left = { - let mut vm = factory.create(params.gas); - test_finalize(vm.exec(¶ms, &mut ext)).unwrap() - }; - - assert_eq!(gas_left, U256::from(79_995)); - assert_store( - &ext, - 0, - "0000000000000000000000000000000000000000000000000000000000001234", - ); -} - -evm_test! {test_difficulty: test_difficulty_jit, test_difficulty_int} -fn test_difficulty(factory: super::Factory) { - let difficulty = U256::from(0x1234); - let code = "44600055".from_hex().unwrap(); - - let mut params = ActionParams::default(); - params.gas = U256::from(100_000); - params.code = Some(Arc::new(code)); - let mut ext = FakeExt::new(); - ext.info.difficulty = difficulty; - - let gas_left = { - let mut vm = factory.create(params.gas); - test_finalize(vm.exec(¶ms, &mut ext)).unwrap() - }; - - assert_eq!(gas_left, U256::from(79_995)); - assert_store( - &ext, - 0, - "0000000000000000000000000000000000000000000000000000000000001234", - ); -} - -evm_test! {test_gas_limit: test_gas_limit_jit, test_gas_limit_int} -fn test_gas_limit(factory: super::Factory) { - let gas_limit = U256::from(0x1234); - let code = "45600055".from_hex().unwrap(); - - let mut params = ActionParams::default(); - params.gas = U256::from(100_000); - params.code = Some(Arc::new(code)); - let mut ext = FakeExt::new(); - ext.info.gas_limit = gas_limit; - - let gas_left = { - let mut vm = factory.create(params.gas); - test_finalize(vm.exec(¶ms, &mut ext)).unwrap() - }; - - assert_eq!(gas_left, U256::from(79_995)); - assert_store( - &ext, - 0, - "0000000000000000000000000000000000000000000000000000000000001234", - ); -} - -evm_test! {test_mul: test_mul_jit, test_mul_int} -fn test_mul(factory: super::Factory) { - let code = "65012365124623626543219002600055".from_hex().unwrap(); - - let mut params = ActionParams::default(); - params.gas = U256::from(100_000); - params.code = Some(Arc::new(code)); - let mut ext = FakeExt::new(); - - let gas_left = { - let mut vm = factory.create(params.gas); - test_finalize(vm.exec(¶ms, &mut ext)).unwrap() - }; - - assert_store( - &ext, - 0, - "000000000000000000000000000000000000000000000000734349397b853383", - ); - assert_eq!(gas_left, U256::from(79_983)); -} - -evm_test! {test_sub: test_sub_jit, test_sub_int} -fn test_sub(factory: super::Factory) { - let code = "65012365124623626543219003600055".from_hex().unwrap(); - - let mut params = ActionParams::default(); - params.gas = U256::from(100_000); - params.code = Some(Arc::new(code)); - let mut ext = FakeExt::new(); - - let gas_left = { - let mut vm = factory.create(params.gas); - test_finalize(vm.exec(¶ms, &mut ext)).unwrap() - }; - - assert_store( - &ext, - 0, - "0000000000000000000000000000000000000000000000000000012364ad0302", - ); - assert_eq!(gas_left, U256::from(79_985)); -} - -evm_test! {test_div: test_div_jit, test_div_int} -fn test_div(factory: super::Factory) { - let code = "65012365124623626543219004600055".from_hex().unwrap(); - - let mut params = ActionParams::default(); - params.gas = U256::from(100_000); - params.code = Some(Arc::new(code)); - let mut ext = FakeExt::new(); - - let gas_left = { - let mut vm = factory.create(params.gas); - test_finalize(vm.exec(¶ms, &mut ext)).unwrap() - }; - - assert_store( - &ext, - 0, - "000000000000000000000000000000000000000000000000000000000002e0ac", - ); - assert_eq!(gas_left, U256::from(79_983)); -} - -evm_test! {test_div_zero: test_div_zero_jit, test_div_zero_int} -fn test_div_zero(factory: super::Factory) { - let code = "6501236512462360009004600055".from_hex().unwrap(); - - let mut params = ActionParams::default(); - params.gas = U256::from(100_000); - params.code = Some(Arc::new(code)); - let mut ext = FakeExt::new(); - - let gas_left = { - let mut vm = factory.create(params.gas); - test_finalize(vm.exec(¶ms, &mut ext)).unwrap() - }; - - assert_store( - &ext, - 0, - "0000000000000000000000000000000000000000000000000000000000000000", - ); - assert_eq!(gas_left, U256::from(94_983)); -} - -evm_test! {test_mod: test_mod_jit, test_mod_int} -fn test_mod(factory: super::Factory) { - let code = "650123651246236265432290066000556501236512462360009006600155" - .from_hex() - .unwrap(); - - let mut params = ActionParams::default(); - params.gas = U256::from(100_000); - params.code = Some(Arc::new(code)); - let mut ext = FakeExt::new(); - - let gas_left = { - let mut vm = factory.create(params.gas); - test_finalize(vm.exec(¶ms, &mut ext)).unwrap() - }; - - assert_store( - &ext, - 0, - "0000000000000000000000000000000000000000000000000000000000076b4b", - ); - assert_store( - &ext, - 1, - "0000000000000000000000000000000000000000000000000000000000000000", - ); - assert_eq!(gas_left, U256::from(74_966)); -} - -evm_test! {test_smod: test_smod_jit, test_smod_int} -fn test_smod(factory: super::Factory) { - let code = "650123651246236265432290076000556501236512462360009007600155" - .from_hex() - .unwrap(); - - let mut params = ActionParams::default(); - params.gas = U256::from(100_000); - params.code = Some(Arc::new(code)); - let mut ext = FakeExt::new(); - - let gas_left = { - let mut vm = factory.create(params.gas); - test_finalize(vm.exec(¶ms, &mut ext)).unwrap() - }; - - assert_store( - &ext, - 0, - "0000000000000000000000000000000000000000000000000000000000076b4b", - ); - assert_store( - &ext, - 1, - "0000000000000000000000000000000000000000000000000000000000000000", - ); - assert_eq!(gas_left, U256::from(74_966)); -} - -evm_test! {test_sdiv: test_sdiv_jit, test_sdiv_int} -fn test_sdiv(factory: super::Factory) { - let code = "650123651246236265432290056000556501236512462360009005600155" - .from_hex() - .unwrap(); - - let mut params = ActionParams::default(); - params.gas = U256::from(100_000); - params.code = Some(Arc::new(code)); - let mut ext = FakeExt::new(); - - let gas_left = { - let mut vm = factory.create(params.gas); - test_finalize(vm.exec(¶ms, &mut ext)).unwrap() - }; - - assert_store( - &ext, - 0, - "000000000000000000000000000000000000000000000000000000000002e0ac", - ); - assert_store( - &ext, - 1, - "0000000000000000000000000000000000000000000000000000000000000000", - ); - assert_eq!(gas_left, U256::from(74_966)); -} - -evm_test! {test_exp: test_exp_jit, test_exp_int} -fn test_exp(factory: super::Factory) { - let code = "6016650123651246230a6000556001650123651246230a6001556000650123651246230a600255" - .from_hex() - .unwrap(); - - let mut params = ActionParams::default(); - params.gas = U256::from(100_000); - params.code = Some(Arc::new(code)); - let mut ext = FakeExt::new(); - - let gas_left = { - let mut vm = factory.create(params.gas); - test_finalize(vm.exec(¶ms, &mut ext)).unwrap() - }; - - assert_store( - &ext, - 0, - "90fd23767b60204c3d6fc8aec9e70a42a3f127140879c133a20129a597ed0c59", - ); - assert_store( - &ext, - 1, - "0000000000000000000000000000000000000000000000000000012365124623", - ); - assert_store( - &ext, - 2, - "0000000000000000000000000000000000000000000000000000000000000001", - ); - assert_eq!(gas_left, U256::from(39_923)); -} - -evm_test! {test_comparison: test_comparison_jit, test_comparison_int} -fn test_comparison(factory: super::Factory) { - let code = "601665012365124623818181811060005511600155146002556415235412358014600355" - .from_hex() - .unwrap(); - - let mut params = ActionParams::default(); - params.gas = U256::from(100_000); - params.code = Some(Arc::new(code)); - let mut ext = FakeExt::new(); - - let gas_left = { - let mut vm = factory.create(params.gas); - test_finalize(vm.exec(¶ms, &mut ext)).unwrap() - }; - - assert_store( - &ext, - 0, - "0000000000000000000000000000000000000000000000000000000000000000", - ); - assert_store( - &ext, - 1, - "0000000000000000000000000000000000000000000000000000000000000001", - ); - assert_store( - &ext, - 2, - "0000000000000000000000000000000000000000000000000000000000000000", - ); - assert_store( - &ext, - 3, - "0000000000000000000000000000000000000000000000000000000000000001", - ); - assert_eq!(gas_left, U256::from(49_952)); -} - -evm_test! {test_signed_comparison: test_signed_comparison_jit, test_signed_comparison_int} -fn test_signed_comparison(factory: super::Factory) { - let code = "60106000036010818112600055136001556010601060000381811260025513600355" - .from_hex() - .unwrap(); - - let mut params = ActionParams::default(); - params.gas = U256::from(100_000); - params.code = Some(Arc::new(code)); - let mut ext = FakeExt::new(); - - let gas_left = { - let mut vm = factory.create(params.gas); - test_finalize(vm.exec(¶ms, &mut ext)).unwrap() - }; - - assert_store( - &ext, - 0, - "0000000000000000000000000000000000000000000000000000000000000000", - ); - assert_store( - &ext, - 1, - "0000000000000000000000000000000000000000000000000000000000000001", - ); - assert_store( - &ext, - 2, - "0000000000000000000000000000000000000000000000000000000000000001", - ); - assert_store( - &ext, - 3, - "0000000000000000000000000000000000000000000000000000000000000000", - ); - assert_eq!(gas_left, U256::from(49_940)); -} - -evm_test! {test_bitops: test_bitops_jit, test_bitops_int} -fn test_bitops(factory: super::Factory) { - let code = "60ff610ff08181818116600055176001551860025560008015600355198015600455600555" - .from_hex() - .unwrap(); - - let mut params = ActionParams::default(); - params.gas = U256::from(150_000); - params.code = Some(Arc::new(code)); - let mut ext = FakeExt::new(); - - let gas_left = { - let mut vm = factory.create(params.gas); - test_finalize(vm.exec(¶ms, &mut ext)).unwrap() - }; - - assert_store( - &ext, - 0, - "00000000000000000000000000000000000000000000000000000000000000f0", - ); - assert_store( - &ext, - 1, - "0000000000000000000000000000000000000000000000000000000000000fff", - ); - assert_store( - &ext, - 2, - "0000000000000000000000000000000000000000000000000000000000000f0f", - ); - assert_store( - &ext, - 3, - "0000000000000000000000000000000000000000000000000000000000000001", - ); - assert_store( - &ext, - 4, - "0000000000000000000000000000000000000000000000000000000000000000", - ); - assert_store( - &ext, - 5, - "ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff", - ); - assert_eq!(gas_left, U256::from(44_937)); -} - -evm_test! {test_addmod_mulmod: test_addmod_mulmod_jit, test_addmod_mulmod_int} -fn test_addmod_mulmod(factory: super::Factory) { - let code = "60ff60f060108282820860005509600155600060f0601082828208196002550919600355" - .from_hex() - .unwrap(); - - let mut params = ActionParams::default(); - params.gas = U256::from(100_000); - params.code = Some(Arc::new(code)); - let mut ext = FakeExt::new(); - - let gas_left = { - let mut vm = factory.create(params.gas); - test_finalize(vm.exec(¶ms, &mut ext)).unwrap() - }; - - assert_store( - &ext, - 0, - "0000000000000000000000000000000000000000000000000000000000000001", - ); - assert_store( - &ext, - 1, - "000000000000000000000000000000000000000000000000000000000000000f", - ); - assert_store( - &ext, - 2, - "ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff", - ); - assert_store( - &ext, - 3, - "ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff", - ); - assert_eq!(gas_left, U256::from(19_914)); -} - -evm_test! {test_byte: test_byte_jit, test_byte_int} -fn test_byte(factory: super::Factory) { - let code = "60f061ffff1a600055610fff601f1a600155".from_hex().unwrap(); - - let mut params = ActionParams::default(); - params.gas = U256::from(100_000); - params.code = Some(Arc::new(code)); - let mut ext = FakeExt::new(); - - let gas_left = { - let mut vm = factory.create(params.gas); - test_finalize(vm.exec(¶ms, &mut ext)).unwrap() - }; - - assert_store( - &ext, - 0, - "0000000000000000000000000000000000000000000000000000000000000000", - ); - assert_store( - &ext, - 1, - "00000000000000000000000000000000000000000000000000000000000000ff", - ); - assert_eq!(gas_left, U256::from(74_976)); -} - -evm_test! {test_signextend: test_signextend_jit, test_signextend_int} -fn test_signextend(factory: super::Factory) { - let code = "610fff60020b60005560ff60200b600155".from_hex().unwrap(); - - let mut params = ActionParams::default(); - params.gas = U256::from(100_000); - params.code = Some(Arc::new(code)); - let mut ext = FakeExt::new(); - - let gas_left = { - let mut vm = factory.create(params.gas); - test_finalize(vm.exec(¶ms, &mut ext)).unwrap() - }; - - assert_store( - &ext, - 0, - "0000000000000000000000000000000000000000000000000000000000000fff", - ); - assert_store( - &ext, - 1, - "00000000000000000000000000000000000000000000000000000000000000ff", - ); - assert_eq!(gas_left, U256::from(59_972)); -} - -#[test] // JIT just returns out of gas -fn test_badinstruction_int() { - let factory = super::Factory::new(VMType::Interpreter, 1024 * 32); - let code = "af".from_hex().unwrap(); - - let mut params = ActionParams::default(); - params.gas = U256::from(100_000); - params.code = Some(Arc::new(code)); - let mut ext = FakeExt::new(); - - let err = { - let mut vm = factory.create(params.gas); - test_finalize(vm.exec(¶ms, &mut ext)).unwrap_err() - }; - - match err { - error::Error::BadInstruction { instruction: 0xaf } => (), - _ => assert!(false, "Expected bad instruction"), - } -} - -evm_test! {test_pop: test_pop_jit, test_pop_int} -fn test_pop(factory: super::Factory) { - let code = "60f060aa50600055".from_hex().unwrap(); - - let mut params = ActionParams::default(); - params.gas = U256::from(100_000); - params.code = Some(Arc::new(code)); - let mut ext = FakeExt::new(); - - let gas_left = { - let mut vm = factory.create(params.gas); - test_finalize(vm.exec(¶ms, &mut ext)).unwrap() - }; - - assert_store( - &ext, - 0, - "00000000000000000000000000000000000000000000000000000000000000f0", - ); - assert_eq!(gas_left, U256::from(79_989)); -} - -evm_test! {test_extops: test_extops_jit, test_extops_int} -fn test_extops(factory: super::Factory) { - let code = "5a6001555836553a600255386003553460045560016001526016590454600555" - .from_hex() - .unwrap(); - - let mut params = ActionParams::default(); - params.gas = U256::from(150_000); - params.gas_price = U256::from(0x32); - params.value = ActionValue::Transfer(U256::from(0x99)); - params.code = Some(Arc::new(code)); - let mut ext = FakeExt::new(); - - let gas_left = { - let mut vm = factory.create(params.gas); - test_finalize(vm.exec(¶ms, &mut ext)).unwrap() - }; - - assert_store( - &ext, - 0, - "0000000000000000000000000000000000000000000000000000000000000004", - ); // PC / CALLDATASIZE - assert_store( - &ext, - 1, - "00000000000000000000000000000000000000000000000000000000000249ee", - ); // GAS - assert_store( - &ext, - 2, - "0000000000000000000000000000000000000000000000000000000000000032", - ); // GASPRICE - assert_store( - &ext, - 3, - "0000000000000000000000000000000000000000000000000000000000000020", - ); // CODESIZE - assert_store( - &ext, - 4, - "0000000000000000000000000000000000000000000000000000000000000099", - ); // CALLVALUE - assert_store( - &ext, - 5, - "0000000000000000000000000000000000000000000000000000000000000032", - ); - assert_eq!(gas_left, U256::from(29_898)); -} - -evm_test! {test_jumps: test_jumps_jit, test_jumps_int} -fn test_jumps(factory: super::Factory) { - let code = "600160015560066000555b60016000540380806000551560245760015402600155600a565b" - .from_hex() - .unwrap(); - - let mut params = ActionParams::default(); - params.gas = U256::from(150_000); - params.code = Some(Arc::new(code)); - let mut ext = FakeExt::new(); - - let gas_left = { - let mut vm = factory.create(params.gas); - test_finalize(vm.exec(¶ms, &mut ext)).unwrap() - }; - - assert_eq!(ext.sstore_clears, 1); - assert_store( - &ext, - 0, - "0000000000000000000000000000000000000000000000000000000000000000", - ); // 5! - assert_store( - &ext, - 1, - "0000000000000000000000000000000000000000000000000000000000000078", - ); // 5! - assert_eq!(gas_left, U256::from(54_117)); -} - -evm_test! {test_calls: test_calls_jit, test_calls_int} -fn test_calls(factory: super::Factory) { - let code = "600054602d57600160005560006000600060006050610998610100f160006000600060006050610998610100f25b" - .from_hex() - .unwrap(); - - let address = Address::from(0x155); - let code_address = Address::from(0x998); - let mut params = ActionParams::default(); - params.gas = U256::from(150_000); - params.code = Some(Arc::new(code)); - params.address = address.clone(); - let mut ext = FakeExt::new(); - ext.balances = { - let mut s = HashMap::new(); - s.insert(params.address.clone(), params.gas); - s - }; - - let gas_left = { - let mut vm = factory.create(params.gas); - test_finalize(vm.exec(¶ms, &mut ext)).unwrap() - }; - - assert_set_contains( - &ext.calls, - &FakeCall { - call_type: FakeCallType::Call, - gas: U256::from(2556), - sender_address: Some(address.clone()), - receive_address: Some(code_address.clone()), - value: Some(U256::from(0x50)), - data: vec![], - code_address: Some(code_address.clone()), - }, - ); - assert_set_contains( - &ext.calls, - &FakeCall { - call_type: FakeCallType::Call, - gas: U256::from(2556), - sender_address: Some(address.clone()), - receive_address: Some(address.clone()), - value: Some(U256::from(0x50)), - data: vec![], - code_address: Some(code_address.clone()), - }, - ); - assert_eq!(gas_left, U256::from(91_405)); - assert_eq!(ext.calls.len(), 2); -} - -evm_test! {test_create_in_staticcall: test_create_in_staticcall_jit, test_create_in_staticcall_int} -fn test_create_in_staticcall(factory: super::Factory) { - let code = "600060006064f000".from_hex().unwrap(); - - let address = Address::from(0x155); - let mut params = ActionParams::default(); - params.gas = U256::from(100_000); - params.code = Some(Arc::new(code)); - params.address = address.clone(); - let mut ext = FakeExt::new(); - ext.is_static = true; - - let err = { - let mut vm = factory.create(params.gas); - test_finalize(vm.exec(¶ms, &mut ext)).unwrap_err() - }; - - assert_eq!(err, error::Error::MutableCallInStaticContext); - assert_eq!(ext.calls.len(), 0); -} - -evm_test! {test_shl: test_shl_int_jit, test_shl_int} -fn test_shl(factory: super::Factory) { - push_two_pop_one_constantinople_test( - &factory, - 0x1b, - "0000000000000000000000000000000000000000000000000000000000000001", - "00", - "0000000000000000000000000000000000000000000000000000000000000001", - ); - push_two_pop_one_constantinople_test( - &factory, - 0x1b, - "0000000000000000000000000000000000000000000000000000000000000001", - "01", - "0000000000000000000000000000000000000000000000000000000000000002", - ); - push_two_pop_one_constantinople_test( - &factory, - 0x1b, - "0000000000000000000000000000000000000000000000000000000000000001", - "ff", - "8000000000000000000000000000000000000000000000000000000000000000", - ); - push_two_pop_one_constantinople_test( - &factory, - 0x1b, - "0000000000000000000000000000000000000000000000000000000000000001", - "0100", - "0000000000000000000000000000000000000000000000000000000000000000", - ); - push_two_pop_one_constantinople_test( - &factory, - 0x1b, - "0000000000000000000000000000000000000000000000000000000000000001", - "0101", - "0000000000000000000000000000000000000000000000000000000000000000", - ); - push_two_pop_one_constantinople_test( - &factory, - 0x1b, - "ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff", - "00", - "ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff", - ); - push_two_pop_one_constantinople_test( - &factory, - 0x1b, - "ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff", - "01", - "fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe", - ); - push_two_pop_one_constantinople_test( - &factory, - 0x1b, - "ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff", - "ff", - "8000000000000000000000000000000000000000000000000000000000000000", - ); - push_two_pop_one_constantinople_test( - &factory, - 0x1b, - "ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff", - "0100", - "0000000000000000000000000000000000000000000000000000000000000000", - ); - push_two_pop_one_constantinople_test( - &factory, - 0x1b, - "0000000000000000000000000000000000000000000000000000000000000000", - "01", - "0000000000000000000000000000000000000000000000000000000000000000", - ); - push_two_pop_one_constantinople_test( - &factory, - 0x1b, - "7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff", - "01", - "fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe", - ); -} - -evm_test! {test_shr: test_shr_int_jit, test_shr_int} -fn test_shr(factory: super::Factory) { - push_two_pop_one_constantinople_test( - &factory, - 0x1c, - "0000000000000000000000000000000000000000000000000000000000000001", - "00", - "0000000000000000000000000000000000000000000000000000000000000001", - ); - push_two_pop_one_constantinople_test( - &factory, - 0x1c, - "0000000000000000000000000000000000000000000000000000000000000001", - "01", - "0000000000000000000000000000000000000000000000000000000000000000", - ); - push_two_pop_one_constantinople_test( - &factory, - 0x1c, - "8000000000000000000000000000000000000000000000000000000000000000", - "01", - "4000000000000000000000000000000000000000000000000000000000000000", - ); - push_two_pop_one_constantinople_test( - &factory, - 0x1c, - "8000000000000000000000000000000000000000000000000000000000000000", - "ff", - "0000000000000000000000000000000000000000000000000000000000000001", - ); - push_two_pop_one_constantinople_test( - &factory, - 0x1c, - "8000000000000000000000000000000000000000000000000000000000000000", - "0100", - "0000000000000000000000000000000000000000000000000000000000000000", - ); - push_two_pop_one_constantinople_test( - &factory, - 0x1c, - "8000000000000000000000000000000000000000000000000000000000000000", - "0101", - "0000000000000000000000000000000000000000000000000000000000000000", - ); - push_two_pop_one_constantinople_test( - &factory, - 0x1c, - "ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff", - "00", - "ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff", - ); - push_two_pop_one_constantinople_test( - &factory, - 0x1c, - "ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff", - "01", - "7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff", - ); - push_two_pop_one_constantinople_test( - &factory, - 0x1c, - "ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff", - "ff", - "0000000000000000000000000000000000000000000000000000000000000001", - ); - push_two_pop_one_constantinople_test( - &factory, - 0x1c, - "ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff", - "0100", - "0000000000000000000000000000000000000000000000000000000000000000", - ); - push_two_pop_one_constantinople_test( - &factory, - 0x1c, - "0000000000000000000000000000000000000000000000000000000000000000", - "01", - "0000000000000000000000000000000000000000000000000000000000000000", - ); -} - -evm_test! {test_sar: test_sar_int_jit, test_sar_int} -fn test_sar(factory: super::Factory) { - push_two_pop_one_constantinople_test( - &factory, - 0x1d, - "0000000000000000000000000000000000000000000000000000000000000001", - "00", - "0000000000000000000000000000000000000000000000000000000000000001", - ); - push_two_pop_one_constantinople_test( - &factory, - 0x1d, - "0000000000000000000000000000000000000000000000000000000000000001", - "01", - "0000000000000000000000000000000000000000000000000000000000000000", - ); - push_two_pop_one_constantinople_test( - &factory, - 0x1d, - "8000000000000000000000000000000000000000000000000000000000000000", - "01", - "c000000000000000000000000000000000000000000000000000000000000000", - ); - push_two_pop_one_constantinople_test( - &factory, - 0x1d, - "8000000000000000000000000000000000000000000000000000000000000000", - "ff", - "ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff", - ); - push_two_pop_one_constantinople_test( - &factory, - 0x1d, - "8000000000000000000000000000000000000000000000000000000000000000", - "0100", - "ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff", - ); - push_two_pop_one_constantinople_test( - &factory, - 0x1d, - "8000000000000000000000000000000000000000000000000000000000000000", - "0101", - "ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff", - ); - push_two_pop_one_constantinople_test( - &factory, - 0x1d, - "ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff", - "00", - "ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff", - ); - push_two_pop_one_constantinople_test( - &factory, - 0x1d, - "ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff", - "01", - "ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff", - ); - push_two_pop_one_constantinople_test( - &factory, - 0x1d, - "ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff", - "ff", - "ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff", - ); - push_two_pop_one_constantinople_test( - &factory, - 0x1d, - "ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff", - "0100", - "ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff", - ); - push_two_pop_one_constantinople_test( - &factory, - 0x1d, - "0000000000000000000000000000000000000000000000000000000000000000", - "01", - "0000000000000000000000000000000000000000000000000000000000000000", - ); - push_two_pop_one_constantinople_test( - &factory, - 0x1d, - "4000000000000000000000000000000000000000000000000000000000000000", - "fe", - "0000000000000000000000000000000000000000000000000000000000000001", - ); - push_two_pop_one_constantinople_test( - &factory, - 0x1d, - "7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff", - "f8", - "000000000000000000000000000000000000000000000000000000000000007f", - ); - push_two_pop_one_constantinople_test( - &factory, - 0x1d, - "7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff", - "fe", - "0000000000000000000000000000000000000000000000000000000000000001", - ); - push_two_pop_one_constantinople_test( - &factory, - 0x1d, - "7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff", - "ff", - "0000000000000000000000000000000000000000000000000000000000000000", - ); - push_two_pop_one_constantinople_test( - &factory, - 0x1d, - "7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff", - "0100", - "0000000000000000000000000000000000000000000000000000000000000000", - ); -} - -fn push_two_pop_one_constantinople_test( - factory: &super::Factory, - opcode: u8, - push1: &str, - push2: &str, - result: &str, -) { - let mut push1 = push1.from_hex().unwrap(); - let mut push2 = push2.from_hex().unwrap(); - assert!(push1.len() <= 32 && push1.len() != 0); - assert!(push2.len() <= 32 && push2.len() != 0); - - let mut code = Vec::new(); - code.push(0x60 + ((push1.len() - 1) as u8)); - code.append(&mut push1); - code.push(0x60 + ((push2.len() - 1) as u8)); - code.append(&mut push2); - code.push(opcode); - code.append(&mut vec![0x60, 0x00, 0x55]); - - let mut params = ActionParams::default(); - params.gas = U256::from(100_000); - params.code = Some(Arc::new(code)); - let mut ext = FakeExt::new(); - - let _ = { - let mut vm = factory.create(params.gas); - test_finalize(vm.exec(¶ms, &mut ext)).unwrap() - }; - - assert_store(&ext, 0, result); -} - -fn assert_set_contains(set: &HashSet, val: &T) { - let contains = set.contains(val); - if !contains { - println!("Set: {:?}", set); - println!("Elem: {:?}", val); - } - assert!(contains, "Element not found in HashSet"); -} - -fn assert_store(ext: &FakeExt, pos: u64, val: &str) { - assert_eq!( - ext.store.get(&H256::from(pos)).unwrap(), - &H256::from_str(val).unwrap() - ); -} diff --git a/cita-executor/src/backlogs.rs b/cita-executor/src/backlogs.rs index 1247fd2fa..34159eed0 100644 --- a/cita-executor/src/backlogs.rs +++ b/cita-executor/src/backlogs.rs @@ -1,23 +1,20 @@ -// CITA -// Copyright 2016-2019 Cryptape Technologies LLC. - -// This program is free software: you can redistribute it -// and/or modify it under the terms of the GNU 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 General Public License for more details. - -// You should have received a copy of the GNU General Public License -// along with this program. If not, see . +// Copyright Cryptape Technologies LLC. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. use super::core::libexecutor::block::{ClosedBlock, OpenBlock}; -use crate::cita_db::Itertools; use cita_types::Address; +use itertools::Itertools; use libproto::{ExecutedResult, Proof}; use std::cmp::min; use std::collections::BTreeMap; @@ -414,12 +411,11 @@ pub fn wrap_height(height: usize) -> u64 { #[cfg(test)] mod tests { use super::{wrap_height, Backlog, Backlogs, Priority}; - use crate::cita_db::journaldb; - use crate::cita_db::kvdb::{in_memory, KeyValueDB}; use crate::core::header::OpenHeader; use crate::core::libexecutor::block::{BlockBody, ClosedBlock, ExecutedBlock, OpenBlock}; use crate::core::libexecutor::sys_config::BlockSysConfig; - use crate::core::state_db::StateDB; + use crate::core::TrieDB; + use cita_database::{Config, RocksDB, NUM_COLUMNS}; use hashable::HASH_NULL_RLP; use std::sync::Arc; @@ -456,12 +452,12 @@ mod tests { libproto::ExecutedResult::new() } - fn generate_state_db() -> StateDB { - let database = in_memory(7); - let database: Arc = Arc::new(database); - let journaldb_type = journaldb::Algorithm::Archive; - let journal_db = journaldb::new(Arc::clone(&database), journaldb_type, None); - StateDB::new(journal_db, 5 * 1024 * 1024) + // TODO Use MemoryDB instead of RocksDB. + fn generate_state_db(path: &str) -> TrieDB { + let config = Config::with_category_num(NUM_COLUMNS); + let rocks_db = RocksDB::open(path, &config).unwrap(); + let db = Arc::new(rocks_db); + TrieDB::new(db.clone()) } fn get_open_block(backlogs: &Backlogs, height: u64) -> Option<&OpenBlock> { @@ -476,12 +472,12 @@ mod tests { assert_eq!(false, Backlog::default().is_completed()); } - fn generate_closed_block(open_block: OpenBlock) -> ClosedBlock { - let state_db = generate_state_db(); + fn generate_closed_block(open_block: OpenBlock, path: &str) -> ClosedBlock { + let db = generate_state_db(path); + let state_db = Arc::new(db); + let exec_block = ExecutedBlock::create( - Default::default(), &BlockSysConfig::default(), - false, open_block.clone(), state_db, HASH_NULL_RLP, @@ -495,19 +491,21 @@ mod tests { #[test] fn test_backlog_is_completed_with_none() { let height = 9; + let path = "test-rocksdb/backlog_is_completed_with_none"; + { let backlog = Backlog { priority: Some(Priority::BlockWithProof), open_block: None, proof: Some(generate_proof(height - 1)), - closed_block: Some(generate_closed_block(generate_block(height))), + closed_block: Some(generate_closed_block(generate_block(height), path)), }; assert_eq!(false, backlog.is_completed(), "block is none"); } { let block = generate_block(height); - let closed_block = generate_closed_block(block.clone()); + let closed_block = generate_closed_block(block.clone(), path); let backlog = Backlog { priority: Some(Priority::BlockWithProof), open_block: Some(block), @@ -534,7 +532,8 @@ mod tests { let height = 9; { let mut block = generate_block(height); - let closed_block = generate_closed_block(block.clone()); + let path = "test-rocksdb/is_completed_with_unequal_block"; + let closed_block = generate_closed_block(block.clone(), path); block.header.set_timestamp(1); let backlog = Backlog { priority: Some(Priority::BlockWithProof), @@ -551,7 +550,8 @@ mod tests { { let block = generate_block(height); - let closed_block = generate_closed_block(block.clone()); + let path = "test-rocksdb/is_completed_with_unequal_block"; + let closed_block = generate_closed_block(block.clone(), path); let backlog = Backlog { priority: Some(Priority::BlockWithProof), open_block: Some(block), @@ -567,7 +567,8 @@ mod tests { fn test_complete_but_is_completed_false() { let height = 9; let open_block = generate_block(height); - let closed_block = generate_closed_block(open_block.clone()); + let path = "test-rocksdb/complete_but_is_false"; + let closed_block = generate_closed_block(open_block.clone(), path); let backlog = Backlog { priority: Some(Priority::BlockWithProof), @@ -585,7 +586,8 @@ mod tests { fn test_complete_normal() { let height = 9; let open_block = generate_block(height); - let closed_block = generate_closed_block(open_block.clone()); + let path = "test-rocksdb/complete_normal"; + let closed_block = generate_closed_block(open_block.clone(), path); let backlog = Backlog { priority: Some(Priority::BlockWithProof), @@ -600,7 +602,8 @@ mod tests { #[test] fn test_backlogs_whole_flow() { let open_block = generate_block(2); - let closed_block = generate_closed_block(open_block.clone()); + let path = "test-rocksdb/backlog_whole_flow"; + let closed_block = generate_closed_block(open_block.clone(), path); // insert height 2 should be always failed let mut backlogs = Backlogs::new(2, Default::default()); @@ -625,7 +628,8 @@ mod tests { // insert height 3 should be ok let open_block = generate_block(3); - let closed_block = generate_closed_block(open_block.clone()); + let path = "test-rocksdb/backlog_whole_flow"; + let closed_block = generate_closed_block(open_block.clone(), path); assert_eq!( true, backlogs.insert_open( diff --git a/cita-executor/src/main.rs b/cita-executor/src/main.rs index f711fbf37..960a3a693 100644 --- a/cita-executor/src/main.rs +++ b/cita-executor/src/main.rs @@ -1,19 +1,16 @@ -// CITA -// Copyright 2016-2019 Cryptape Technologies LLC. - -// This program is free software: you can redistribute it -// and/or modify it under the terms of the GNU 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 General Public License for more details. - -// You should have received a copy of the GNU General Public License -// along with this program. If not, see . +// Copyright Cryptape Technologies LLC. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. //! ## Summary //! One of cita's main core components is to execute transaction, @@ -87,7 +84,7 @@ extern crate common_types as types; extern crate core_executor as core; #[macro_use] extern crate crossbeam_channel; -extern crate db as cita_db; +extern crate cita_database as cita_db; #[cfg(test)] extern crate hashable; #[macro_use] @@ -99,7 +96,6 @@ extern crate serde_derive; #[macro_use] extern crate util; -use crate::core::contracts::grpc::grpc_vm_adapter; use crate::core::libexecutor::executor::Executor; use crate::postman::Postman; use cita_directories::DataPath; @@ -112,7 +108,6 @@ use util::set_panic_handler; mod backlogs; mod postman; -mod snapshot; #[cfg(test)] mod tests; @@ -121,7 +116,6 @@ include!(concat!(env!("OUT_DIR"), "/build_info.rs")); #[derive(Debug, PartialEq, Deserialize)] pub struct Options { prooftype: u8, - grpc_port: u16, journaldb_type: String, genesis_path: String, statedb_cache_size: usize, @@ -132,7 +126,6 @@ impl Options { pub fn default() -> Self { Options { prooftype: 2, - grpc_port: 5000, journaldb_type: String::from("archive"), genesis_path: String::from("genesis.json"), statedb_cache_size: 5 * 1024 * 1024, @@ -194,36 +187,27 @@ fn main() { // start threads to forward messages between mpsc::channel and crosebeam::channel thread::spawn(move || loop { match forward_req_receiver.recv() { - Ok(message) => mq_req_sender.send(message), + Ok(message) => { + let _ = mq_req_sender.send(message); + } Err(_) => return, - } + }; }); thread::spawn(move || loop { match mq_resp_receiver.recv() { - Some(message) => forward_resp_sender.send(message).unwrap(), - None => return, + Ok(message) => { + forward_resp_sender.send(message).unwrap(); + } + Err(_) => return, } }); - // start grpc server thread background - let server = grpc_vm_adapter::vm_grpc_server( - options.grpc_port, - command_req_sender.clone(), - command_resp_receiver.clone(), - ) - .expect("failed to initialize grpc server"); - thread::spawn(move || { - grpc_vm_adapter::serve(&server); - }); - loop { // start executor thread // TODO consider to store `data_path` within executor.toml let data_path = DataPath::root_node_path(); let mut executor = Executor::init( &options.genesis_path, - &options.journaldb_type, - options.statedb_cache_size, data_path, fsm_req_receiver.clone(), fsm_resp_sender.clone(), diff --git a/cita-executor/src/postman.rs b/cita-executor/src/postman.rs index e909714a9..922741567 100644 --- a/cita-executor/src/postman.rs +++ b/cita-executor/src/postman.rs @@ -1,28 +1,25 @@ -// CITA -// Copyright 2016-2019 Cryptape Technologies LLC. - -// This program is free software: you can redistribute it -// and/or modify it under the terms of the GNU 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 General Public License for more details. - -// You should have received a copy of the GNU General Public License -// along with this program. If not, see . +// Copyright Cryptape Technologies LLC. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. use crate::core::contracts::solc::sys_config::ChainId; -use crate::core::libexecutor::blacklist::BlackList; use crate::core::libexecutor::block::{ClosedBlock, OpenBlock}; use crate::core::libexecutor::call_request::CallRequest; -use crate::core::libexecutor::economical_model::EconomicalModel; -use crate::core::receipt::ReceiptError; -use crate::types::ids::BlockId; -use cita_types::{Address, H256, U256}; +use crate::core::tx_gas_schedule::TxGasSchedule; +use crate::types::block_number::BlockTag; +use crate::types::errors::ReceiptError; +use cita_types::U256; +use cita_types::{Address, H256}; use crossbeam_channel::{Receiver, Sender}; use error::ErrorCode; use jsonrpc_types::rpc_types::{BlockNumber, CountOrCode}; @@ -30,20 +27,20 @@ use libproto::auth::Miscellaneous; use libproto::blockchain::{RichStatus, StateSignal}; use libproto::request::Request_oneof_req as Request; use libproto::router::{MsgType, RoutingKey, SubModules}; -use libproto::snapshot::{Cmd as SnapshotCommand, SnapshotReq}; use libproto::{request, response, Message}; use libproto::{TryFrom, TryInto}; use serde_json; use std::convert::Into; -use std::sync::RwLock; use std::u8; +use crate::core::libexecutor::blacklist::BlackList; use crate::core::libexecutor::command; use crate::core::libexecutor::lru_cache::LRUCache; -use evm::Schedule; + +use std::sync::RwLock; use super::backlogs::{wrap_height, Backlogs}; -use super::snapshot; +use cita_vm::state::StateObjectInfo; pub struct Postman { backlogs: Backlogs, @@ -128,8 +125,8 @@ impl Postman { } // make sure executor exit also - fn close(&self, rollback_id: BlockId) { - if rollback_id != BlockId::Number(::std::usize::MAX as u64) { + fn close(&self, rollback_id: BlockTag) { + if rollback_id != BlockTag::Height(::std::usize::MAX as u64) { command::exit( &self.command_req_sender, &self.command_resp_receiver, @@ -141,19 +138,22 @@ impl Postman { // listen messages from RabbitMQ and Executor. // // Return `(None, None)` if any channel closed - #[cfg_attr(feature = "cargo-clippy", allow(clippy::type_complexity))] + #[cfg_attr( + feature = "cargo-clippy", + allow(clippy::type_complexity, clippy::zero_ptr, clippy::drop_copy) + )] fn recv(&self) -> (Option<(String, Vec)>, Option) { select! { - recv(self.mq_req_receiver, mq_req) => { + recv(self.mq_req_receiver) -> mq_req => { match mq_req { - Some(mq_req) => (Some(mq_req), None), - None => (None, None), + Ok(mq_req) => (Some(mq_req), None), + Err(_) => (None, None), } }, - recv(self.fsm_resp_receiver, fsm_resp) => { + recv(self.fsm_resp_receiver) -> fsm_resp => { match fsm_resp { - Some(fsm_resp) => (None, Some(fsm_resp)), - None => (None, None), + Ok(fsm_resp) => (None, Some(fsm_resp)), + Err(_) => (None, None), } } } @@ -166,7 +166,7 @@ impl Postman { self.backlogs.insert_closed(height, closed_block); } - fn handle_mq_message(&mut self, key: &str, msg_vec: Vec) -> Result<(), BlockId> { + fn handle_mq_message(&mut self, key: &str, msg_vec: Vec) -> Result<(), BlockTag> { let mut msg = Message::try_from(msg_vec).unwrap(); trace!("receive {} from RabbitMQ", key); match RoutingKey::from(key) { @@ -191,11 +191,6 @@ impl Postman { } } - routing_key!(Snapshot >> SnapshotReq) => { - let snapshot_req = msg.take_snapshot_req().unwrap(); - self.deal_snapshot(snapshot_req)?; - } - routing_key!(Consensus >> SignedProposal) | routing_key!(Consensus >> BlockWithProof) | routing_key!(Net >> SyncResponse) @@ -214,7 +209,7 @@ impl Postman { // cita-chain broadcast StateSignal to indicate its state. So we could figure out // which blocks cita-chain lack of, then re-send the lacking blocks to cita-chain. - fn reply_chain_state_signal(&self, state_signal: &StateSignal) -> Result<(), BlockId> { + fn reply_chain_state_signal(&self, state_signal: &StateSignal) -> Result<(), BlockTag> { let specified_height = state_signal.get_height(); if specified_height < self.get_current_height() { self.send_executed_info_to_chain(specified_height + 1)?; @@ -229,7 +224,7 @@ impl Postman { Ok(()) } - fn send_executed_info_to_chain(&self, height: u64) -> Result<(), BlockId> { + fn send_executed_info_to_chain(&self, height: u64) -> Result<(), BlockTag> { if height > self.get_current_height() { error!("This must be because the Executor database was manually deleted."); return Ok(()); @@ -259,9 +254,9 @@ impl Postman { // `ExecutedResult` based on its persisted data. It has to rollback // to 50 to keep equal to cita-chain, and then re-synchronize. // - // Here the returned value `BlockId::Number(height - 1)` would be passed out to main() + // Here the returned value `BlockTag::Height(height - 1)` would be passed out to main() // thread. Then main() would restart executor thread and let executor starts with - // `BlockId::Number(height - 1)`. + // `BlockTag::Height(height - 1)`. if executed_result.is_none() { warn!( "chain(height={}) is lagging behind executor(height={}). \ @@ -270,7 +265,7 @@ impl Postman { self.get_current_height(), height - 1 ); - return Err(BlockId::Number(height - 1)); + return Err(BlockTag::Height(height - 1)); } trace!("send {}-th ExecutedResult", height); @@ -310,7 +305,7 @@ impl Postman { for proto_block in sync_res.take_blocks().into_iter() { let open_block = OpenBlock::from(proto_block); if !self.backlogs.insert_synchronized(open_block) { - return false; + continue; } } true @@ -358,90 +353,85 @@ impl Postman { match self.backlogs.ready(next_height) { Ok(open_block) => { trace!("postman send {}-th block to executor", next_height); - self.fsm_req_sender.send(open_block.clone()); + let _ = self.fsm_req_sender.send(open_block.clone()); } Err(reason) => trace!("{}", reason), } } - fn get_economical_model(&self) -> EconomicalModel { - command::economical_model(&self.command_req_sender, &self.command_resp_receiver) - } - /// Find the public key of all senders that caused the specified error message, and then publish it // TODO: I think it is not necessary to distinguish economical_model, maybe remove - // this opinion in the future + // this opinion in the future. + // To Be reconside black list,or use other method fn pub_black_list(&self, close_block: &ClosedBlock) { - match self.get_economical_model() { - EconomicalModel::Charge => { - // Get all transaction hash that is reported as not enough quota - let blacklist_transaction_hash: Vec = close_block - .receipts - .iter() - .filter(|ref receipt| match receipt.error { - Some(ReceiptError::NotEnoughBaseQuota) => true, - _ => false, - }) - .map(|receipt| receipt.transaction_hash) - .filter(|hash| hash != &H256::default()) - .collect(); - - let schedule = Schedule::new_v1(); - // Filter out accounts in the black list where the account balance has reached the benchmark value. - // Get the smaller value between tx_create_gas and tx_gas for the benchmark value. - let bm_value = std::cmp::min(schedule.tx_gas, schedule.tx_create_gas); - let mut clear_list: Vec
= self - .black_list_cache - .read() - .unwrap() - .values() - .filter(|address| { - close_block - .state - .balance(address) - .and_then(|x| Ok(x >= U256::from(bm_value))) - .unwrap_or(false) - }) - .cloned() - .collect(); - - // Get address of sending account by transaction hash - let blacklist: Vec
= close_block - .body() - .transactions() - .iter() - .filter(|tx| blacklist_transaction_hash.contains(&tx.get_transaction_hash())) - .map(|tx| *tx.sender()) - .collect(); + // Get all transaction hash that is reported as not enough quota + let blacklist_transaction_hash: Vec = close_block + .receipts + .iter() + .filter(|ref receipt| match receipt.error { + Some(ReceiptError::NotEnoughCash) => true, + _ => false, + }) + .map(|receipt| receipt.transaction_hash) + .filter(|hash| hash != &H256::default()) + .collect(); + + let schedule = TxGasSchedule::default(); + // Filter out accounts in the black list where the account balance has reached the benchmark value. + // Get the smaller value between tx_create_gas and tx_gas for the benchmark value. + let bm_value = std::cmp::min(schedule.tx_gas, schedule.tx_create_gas); + let mut clear_list: Vec
= self + .black_list_cache + .read() + .unwrap() + .values() + .filter(|address| { + command::balance_at( + &self.command_req_sender, + &self.command_resp_receiver, + **address, + BlockTag::Height(close_block.block.header.number()), + ) + .and_then(|x| Some(U256::from(x.as_slice()) >= U256::from(bm_value))) + .unwrap_or(false) + }) + .cloned() + .collect(); + + // Get address of sending account by transaction hash + let blacklist: Vec
= close_block + .body() + .transactions() + .iter() + .filter(|tx| blacklist_transaction_hash.contains(&tx.get_transaction_hash())) + .map(|tx| *tx.sender()) + .collect(); - { - let mut black_list_cache = self.black_list_cache.write().unwrap(); - black_list_cache - .prune(&clear_list) - .extend(&blacklist[..], close_block.number()); - clear_list.extend(black_list_cache.lru().iter()); - } + { + let mut black_list_cache = self.black_list_cache.write().unwrap(); + black_list_cache + .prune(&clear_list) + .extend(&blacklist[..], close_block.number()); + clear_list.extend(black_list_cache.lru().iter()); + } - let black_list = BlackList::new() - .set_black_list(blacklist) - .set_clear_list(clear_list); + let black_list = BlackList::new() + .set_black_list(blacklist) + .set_clear_list(clear_list); - if !black_list.is_empty() { - let black_list_bytes: Message = black_list.protobuf().into(); + if !black_list.is_empty() { + let black_list_bytes: Message = black_list.protobuf().into(); - info!( - "black list is {:?}, clear list is {:?}", - black_list.black_list(), - black_list.clear_list() - ); + info!( + "black list is {:?}, clear list is {:?}", + black_list.black_list(), + black_list.clear_list() + ); - self.response_mq( - routing_key!(Executor >> BlackList).into(), - black_list_bytes.try_into().unwrap(), - ); - } - } - EconomicalModel::Quota => {} + self.response_mq( + routing_key!(Executor >> BlackList).into(), + black_list_bytes.try_into().unwrap(), + ); } } @@ -613,13 +603,16 @@ impl Postman { block_id.into(), ) .and_then(|state| { - state.get_state_proof( - &Address::from(state_info.get_address()), - &H256::from(state_info.get_position()), - ) + state + .get_storage_proof( + &Address::from(state_info.get_address()), + &H256::from(state_info.get_position()), + ) + .ok() }) { Some(state_proof_bs) => { - response.set_state_proof(state_proof_bs); + let buf: Vec = state_proof_bs.into_iter().flatten().collect(); + response.set_state_proof(buf); } None => { response.set_code(ErrorCode::query_error()); @@ -632,6 +625,7 @@ impl Postman { response.set_error_msg(format!("{:?}", err)); }); } + Request::storage_key(skey) => { trace!("storage key info is {:?}", skey); let _ = serde_json::from_str::(&skey.height) @@ -641,9 +635,9 @@ impl Postman { &self.command_resp_receiver, block_id.into(), ) - .and_then(|state| { + .and_then(|mut state| { state - .storage_at( + .get_storage( &Address::from(skey.get_address()), &H256::from(skey.get_position()), ) @@ -692,73 +686,7 @@ impl Postman { fn response_mq(&self, key: String, message: Vec) { trace!("send {} into RabbitMQ", key); - self.mq_resp_sender.send((key, message)); - } - - fn deal_snapshot(&self, req: SnapshotReq) -> Result<(), BlockId> { - match req.cmd { - SnapshotCommand::Snapshot => { - let highest_height = snapshot::handle_snapshot_height( - req.get_end_height(), - self.get_current_height(), - ); - let filename = snapshot::handle_snapshot_filename(req.file); - let _ = snapshot::spawn_take_snapshot( - filename, - highest_height, - &self.command_req_sender, - &self.command_resp_receiver, - &self.mq_resp_sender, - ); - Ok(()) - } - SnapshotCommand::Begin => { - snapshot::response( - &self.mq_resp_sender, - libproto::snapshot::Resp::BeginAck, - Ok(()), - ); - Ok(()) - } - SnapshotCommand::Restore => { - let filename = snapshot::handle_snapshot_filename(req.file); - let _ = snapshot::spawn_restore_snapshot( - &filename, - &self.command_req_sender, - &self.command_resp_receiver, - &self.mq_resp_sender, - ); - Ok(()) - } - SnapshotCommand::Clear => { - // We change Executor's DB with snapshot's DB when receive `SnapshotCommand::Clear` - // 1. Ensure Executor stopped - command::exit( - &self.command_req_sender, - &self.command_resp_receiver, - BlockId::Number(self.get_current_height()), - ); - - // 2. Move snapshot's DB to replace Executor's DB - let origin_db = cita_directories::DataPath::root_node_path() + "/statedb"; - let restoration_db = cita_directories::DataPath::root_node_path() - + "/snapshot_executor/restoration/db"; - snapshot::change_database(&self.mq_resp_sender, origin_db, restoration_db); - - // TODO: This is a dirty trick, for close Postman without noticing Executor. - // Hope refactor it with more graceful way - // 3. Postman exit too so that main() would restart them - Err(BlockId::Number(::std::usize::MAX as u64)) - } - SnapshotCommand::End => { - snapshot::response( - &self.mq_resp_sender, - libproto::snapshot::Resp::EndAck, - Ok(()), - ); - Ok(()) - } - } + let _ = self.mq_resp_sender.send((key, message)); } } @@ -814,9 +742,11 @@ mod tests { ::std::thread::spawn(move || { let command = command_req_receiver.recv().unwrap(); match command { - command::Command::LoadExecutedResult(3) => command_resp_sender.send( - command::CommandResp::LoadExecutedResult(libproto::ExecutedResult::new()), - ), + command::Command::LoadExecutedResult(3) => { + let _ = command_resp_sender.send(command::CommandResp::LoadExecutedResult( + libproto::ExecutedResult::new(), + )); + } _ => panic!("received should be Command::LoadExecutedResult(3)"), } let command = command_req_receiver.recv().unwrap(); @@ -1108,7 +1038,7 @@ mod tests { assert_eq!( res.err(), - Some(BlockId::Number(2)), + Some(BlockTag::Height(2)), "no executed result, executed should roll back" ); } diff --git a/cita-executor/src/snapshot.rs b/cita-executor/src/snapshot.rs deleted file mode 100644 index 92ded9a0b..000000000 --- a/cita-executor/src/snapshot.rs +++ /dev/null @@ -1,250 +0,0 @@ -// CITA -// Copyright 2016-2019 Cryptape Technologies LLC. - -// This program is free software: you can redistribute it -// and/or modify it under the terms of the GNU 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 General Public License for more details. - -// You should have received a copy of the GNU General Public License -// along with this program. If not, see . - -use crate::cita_db::journaldb::Algorithm; -use crate::cita_db::DatabaseConfig; -use crate::core::db::NUM_COLUMNS; -use crate::core::libexecutor::command; -use crate::core::snapshot as CoreSnapshot; -use crate::core::snapshot::io::{PackedReader, PackedWriter}; -use crossbeam_channel::{Receiver, Sender}; -use libproto::router::{MsgType, RoutingKey, SubModules}; -use libproto::snapshot::{Resp as Ack, SnapshotResp}; -use libproto::TryInto; -use std::sync::Arc; - -pub fn handle_snapshot_height(req_height: u64, current_height: u64) -> u64 { - match req_height { - height if height == 0 || height > current_height => { - warn!( - "snapshot.end_height({}) reset to current_height({})", - req_height, current_height, - ); - current_height - } - height => height, - } -} - -pub fn handle_snapshot_filename(filename: String) -> String { - filename + "_executor.rlp" -} - -pub fn spawn_take_snapshot( - filename: String, - highest_height: u64, - command_req_sender: &Sender, - command_resp_receiver: &Receiver, - mq_resp_sender: &Sender<(String, Vec)>, -) -> ::std::thread::JoinHandle<()> { - // Prepare - let executor = command::clone_executor_reader(&command_req_sender, &command_resp_receiver); - let writer = PackedWriter { - file: ::std::fs::File::create(filename).unwrap(), - state_hashes: Vec::new(), - block_hashes: Vec::new(), - cur_len: 0, - }; - let progress = ::std::sync::Arc::new(Default::default()); - - // Spawn -> Take -> Response - let mq_resp_sender = mq_resp_sender.clone(); - ::std::thread::spawn(move || { - let result = CoreSnapshot::take_snapshot(&executor, highest_height, writer, &*progress) - .map_err(|err| err.to_string()); - response(&mq_resp_sender, Ack::SnapshotAck, result); - }) -} - -pub fn spawn_restore_snapshot( - filename: &str, - command_req_sender: &Sender, - command_resp_receiver: &Receiver, - mq_resp_sender: &Sender<(String, Vec)>, -) -> ::std::thread::JoinHandle<()> { - let executor = command::clone_executor_reader(command_req_sender, command_resp_receiver); - let db_config = DatabaseConfig::with_columns(NUM_COLUMNS); - let data_path = cita_directories::DataPath::root_node_path() + "/snapshot_executor"; - let snapshot_params = CoreSnapshot::service::ServiceParams { - db_config, - pruning: Algorithm::Archive, - snapshot_root: data_path.into(), - executor: Arc::new(executor), - }; - let snapshot_service = Arc::new( - CoreSnapshot::service::Service::create(snapshot_params).expect("new snapshot service"), - ); - - // Spawn -> Restore -> Response - let mq_resp_sender = mq_resp_sender.clone(); - let filename = filename.to_owned(); - ::std::thread::spawn(move || { - match PackedReader::create(::std::path::Path::new(&filename)) { - Ok(Some(reader)) => { - let result = CoreSnapshot::restore_using(&snapshot_service, &reader, true); - response(&mq_resp_sender, Ack::RestoreAck, result); - } - Ok(None) => { - response( - &mq_resp_sender, - Ack::RestoreAck, - Err(format!( - "failed to open {} cause: invalid format file", - filename - )), - ); - } - Err(err) => { - response( - &mq_resp_sender, - Ack::RestoreAck, - Err(format!("failed to open {} cause: {:?}", filename, err)), - ); - } - }; - }) -} - -pub fn change_database( - mq_resp_sender: &Sender<(String, Vec)>, - origin_db: String, - snap_db: String, -) { - info!( - "change database {} with snapshot database {}", - origin_db, snap_db - ); - let backup_db = origin_db.clone() + ".backup"; - let _ = ::std::fs::remove_dir_all(backup_db.clone()); - let result = Ok(()) - .and_then(|_| ::std::fs::rename(origin_db.clone(), backup_db.clone())) - .and_then(|_| ::std::fs::rename(snap_db, origin_db)) - .and_then(|_| ::std::fs::remove_dir_all(backup_db)) - .map_err(|err| err.to_string()); - response(mq_resp_sender, Ack::ClearAck, result); -} - -pub fn response(mq_resp_sender: &Sender<(String, Vec)>, ack: Ack, result: Result<(), String>) { - let action = match ack { - Ack::SnapshotAck => "take", - Ack::BeginAck => "begin", - Ack::RestoreAck => "restore", - Ack::ClearAck => "clear", - Ack::EndAck => "end", - }; - - let mut response = SnapshotResp::new(); - response.set_resp(ack); - match result { - Ok(()) => { - info!("successful to {} snapshot", action); - response.set_flag(true) - } - Err(reason) => { - // TODO: impl Display for snapshot.cmd - error!("failed to {} snapshot cause: {}", action, reason); - response.set_flag(false); - } - } - - let message: libproto::Message = response.into(); - mq_resp_sender.send(( - routing_key!(Executor >> SnapshotResp).into(), - message.try_into().unwrap(), - )); -} - -#[cfg(test)] -mod tests { - extern crate tempdir; - - use self::tempdir::TempDir; - use super::*; - use libproto::snapshot::Resp as Ack; - use libproto::Message; - use libproto::TryFrom; - - fn wrap(origin_db: &str, temp_dir: ::std::path::PathBuf) -> String { - match origin_db { - "-" => temp_dir.to_str().unwrap().to_string(), - _ => origin_db.to_string(), - } - } - - #[test] - fn test_change_database() { - let (mq_resp_sender, mq_resp_receiver) = crossbeam_channel::unbounded(); - - let cases = vec![ - ( - "/not/found/hello/i/am/evil/db", - "/not/found/you/are/evil/db", - false, - ), - ("-", "/not/found/you/are/evil/db", false), - ("/not/found/hello/i/am/evil/db", "-", false), - ("-", "-", true), - ]; - for (origin_id, snap_id, expected_flag) in cases.into_iter() { - // Prepare directories as parameters - let origin_db_dir = TempDir::new("snapshot-test").unwrap(); - let snap_db_dir = TempDir::new("snapshot-test").unwrap(); - let origin_db_path = origin_db_dir.path().to_owned(); - let snap_db_path = snap_db_dir.path().to_owned(); - let origin_db = wrap(origin_id, origin_db_path); - let snap_db = wrap(snap_id, snap_db_path); - - // Change database - change_database(&mq_resp_sender, origin_db.clone(), snap_db.clone()); - - // Check sent messages - let (key, msg_vec) = mq_resp_receiver.recv().expect("receive ClearAck"); - assert_eq!(routing_key!(Executor >> SnapshotResp).to_string(), key); - - let mut message: Message = Message::try_from(msg_vec).unwrap(); - let snapshot_resp = message.take_snapshot_resp().unwrap(); - assert_eq!(Ack::ClearAck, snapshot_resp.resp); - assert_eq!( - expected_flag, snapshot_resp.flag, - "change_database with ({}, {}) should be {}", - origin_id, snap_id, expected_flag, - ); - - // Check database existence - if expected_flag { - assert_eq!( - true, - ::std::path::Path::new(&origin_db).exists(), - "the directory of origin database is exist", - ); - assert_eq!( - false, - ::std::path::Path::new(&snap_db).exists(), - "snapshot database has been moved off", - ); - } - } - } - - #[test] - fn test_handle_snapshot_height() { - assert_eq!(8, handle_snapshot_height(0, 8)); - assert_eq!(7, handle_snapshot_height(7, 8)); - assert_eq!(8, handle_snapshot_height(8, 8)); - assert_eq!(8, handle_snapshot_height(9, 8)); - } -} diff --git a/cita-executor/src/tests/helpers.rs b/cita-executor/src/tests/helpers.rs index 21a5fee85..11c8b8512 100644 --- a/cita-executor/src/tests/helpers.rs +++ b/cita-executor/src/tests/helpers.rs @@ -1,19 +1,16 @@ -// CITA -// Copyright 2016-2018 Cryptape Technologies LLC. - -// This program is free software: you can redistribute it -// and/or modify it under the terms of the GNU 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 General Public License for more details. - -// You should have received a copy of the GNU General Public License -// along with this program. If not, see . +// Copyright Cryptape Technologies LLC. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. use crate::postman::Postman; use cita_crypto::{CreateKey, PrivKey, Sign, Signature, Signer}; diff --git a/cita-executor/src/tests/mod.rs b/cita-executor/src/tests/mod.rs index fb29ff297..7fd8be0c8 100644 --- a/cita-executor/src/tests/mod.rs +++ b/cita-executor/src/tests/mod.rs @@ -1,18 +1,15 @@ -// CITA -// Copyright 2016-2018 Cryptape Technologies LLC. - -// This program is free software: you can redistribute it -// and/or modify it under the terms of the GNU 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 General Public License for more details. - -// You should have received a copy of the GNU General Public License -// along with this program. If not, see . +// Copyrighttape Technologies LLC. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. pub mod helpers; diff --git a/cita-forever b/cita-forever index b7ed8570d..05c2c5129 160000 --- a/cita-forever +++ b/cita-forever @@ -1 +1 @@ -Subproject commit b7ed8570d6762c2d3c4c607da7f6379538157eba +Subproject commit 05c2c51295adfb91dc25ac0de821bbca92c1d7f4 diff --git a/cita-jsonrpc/Cargo.toml b/cita-jsonrpc/Cargo.toml index ad2e2cb02..9cf761b2e 100644 --- a/cita-jsonrpc/Cargo.toml +++ b/cita-jsonrpc/Cargo.toml @@ -2,6 +2,7 @@ name = "cita-jsonrpc" version = "0.1.0" authors = ["Cryptape Technologies "] +license = "Apache-2.0" edition = "2018" [dependencies] @@ -15,7 +16,7 @@ serde_json = "1.0" cpuprofiler = "0.0.3" dotenv = "0.13.0" clap = "2" -cita-logger = "0.1.0" +cita-logger = "0.1.1" util = { git = "https://github.com/cryptape/cita-common.git", branch = "develop" } error = { git = "https://github.com/cryptape/cita-common.git", branch = "develop" } pubsub = { git = "https://github.com/cryptape/cita-common.git", branch = "develop" } diff --git a/cita-jsonrpc/build.rs b/cita-jsonrpc/build.rs index c20d26175..03dcbd59d 100644 --- a/cita-jsonrpc/build.rs +++ b/cita-jsonrpc/build.rs @@ -1,19 +1,16 @@ -// CITA -// Copyright 2016-2019 Cryptape Technologies LLC. - -// This program is free software: you can redistribute it -// and/or modify it under the terms of the GNU 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 General Public License for more details. - -// You should have received a copy of the GNU General Public License -// along with this program. If not, see . +// Copyright Cryptape Technologies LLC. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. use std::env; diff --git a/cita-jsonrpc/src/config.rs b/cita-jsonrpc/src/config.rs index 7cceee0c4..3371c690b 100644 --- a/cita-jsonrpc/src/config.rs +++ b/cita-jsonrpc/src/config.rs @@ -1,19 +1,16 @@ -// CITA -// Copyright 2016-2019 Cryptape Technologies LLC. - -// This program is free software: you can redistribute it -// and/or modify it under the terms of the GNU 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 General Public License for more details. - -// You should have received a copy of the GNU General Public License -// along with this program. If not, see . +// Copyright Cryptape Technologies LLC. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. use std::convert::Into; use ws::Settings; diff --git a/cita-jsonrpc/src/extractor.rs b/cita-jsonrpc/src/extractor.rs index 4f4f88693..211dd99de 100644 --- a/cita-jsonrpc/src/extractor.rs +++ b/cita-jsonrpc/src/extractor.rs @@ -1,19 +1,16 @@ -// CITA -// Copyright 2016-2019 Cryptape Technologies LLC. - -// This program is free software: you can redistribute it -// and/or modify it under the terms of the GNU 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 General Public License for more details. - -// You should have received a copy of the GNU General Public License -// along with this program. If not, see . +// Copyright Cryptape Technologies LLC. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. use futures::future::{Future, FutureResult}; use jsonrpc_proto::complete::CompleteInto; diff --git a/cita-jsonrpc/src/fdlimit.rs b/cita-jsonrpc/src/fdlimit.rs index f48307a3c..5aa7684be 100644 --- a/cita-jsonrpc/src/fdlimit.rs +++ b/cita-jsonrpc/src/fdlimit.rs @@ -1,23 +1,19 @@ -// CITA -// Copyright 2016-2019 Cryptape Technologies LLC. - -// This program is free software: you can redistribute it -// and/or modify it under the terms of the GNU 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 General Public License for more details. - -// You should have received a copy of the GNU General Public License -// along with this program. If not, see . +// Copyright Cryptape Technologies LLC. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. #[cfg(any(target_os = "linux"))] pub fn set_fd_limit() { - use libc; use std::io; unsafe { @@ -39,7 +35,6 @@ pub fn set_fd_limit() { #[cfg(any(target_os = "macos", target_os = "ios"))] pub fn set_fd_limit() { - use libc; use std::cmp; use std::io; use std::mem::size_of_val; diff --git a/cita-jsonrpc/src/helper.rs b/cita-jsonrpc/src/helper.rs index 1eb7796ed..1514d3a20 100644 --- a/cita-jsonrpc/src/helper.rs +++ b/cita-jsonrpc/src/helper.rs @@ -1,19 +1,16 @@ -// CITA -// Copyright 2016-2019 Cryptape Technologies LLC. - -// This program is free software: you can redistribute it -// and/or modify it under the terms of the GNU 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 General Public License for more details. - -// You should have received a copy of the GNU General Public License -// along with this program. If not, see . +// Copyright Cryptape Technologies LLC. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. use futures::sync::oneshot; use jsonrpc_types::rpc_request::RequestInfo; diff --git a/cita-jsonrpc/src/http_header.rs b/cita-jsonrpc/src/http_header.rs index 191856a8b..b20c1a201 100644 --- a/cita-jsonrpc/src/http_header.rs +++ b/cita-jsonrpc/src/http_header.rs @@ -1,19 +1,16 @@ -// CITA -// Copyright 2016-2019 Cryptape Technologies LLC. - -// This program is free software: you can redistribute it -// and/or modify it under the terms of the GNU 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 General Public License for more details. - -// You should have received a copy of the GNU General Public License -// along with this program. If not, see . +// Copyright Cryptape Technologies LLC. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. use hyper::header::{HeaderMap, HeaderName, HeaderValue, InvalidHeaderValue}; diff --git a/cita-jsonrpc/src/http_server.rs b/cita-jsonrpc/src/http_server.rs index 878a87000..336db73a5 100644 --- a/cita-jsonrpc/src/http_server.rs +++ b/cita-jsonrpc/src/http_server.rs @@ -1,19 +1,16 @@ -// CITA -// Copyright 2016-2019 Cryptape Technologies LLC. - -// This program is free software: you can redistribute it -// and/or modify it under the terms of the GNU 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 General Public License for more details. - -// You should have received a copy of the GNU General Public License -// along with this program. If not, see . +// Copyright Cryptape Technologies LLC. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. use futures::future::{self as future, Future}; use hyper::header::{ diff --git a/cita-jsonrpc/src/main.rs b/cita-jsonrpc/src/main.rs index 6e45d0259..93059aa01 100644 --- a/cita-jsonrpc/src/main.rs +++ b/cita-jsonrpc/src/main.rs @@ -1,19 +1,16 @@ -// CITA -// Copyright 2016-2019 Cryptape Technologies LLC. - -// This program is free software: you can redistribute it -// and/or modify it under the terms of the GNU 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 General Public License for more details. - -// You should have received a copy of the GNU General Public License -// along with this program. If not, see . +// Copyright Cryptape Technologies LLC. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. //! ## Summary //! diff --git a/cita-jsonrpc/src/mq_handler.rs b/cita-jsonrpc/src/mq_handler.rs index addbffd45..6ba19c95b 100644 --- a/cita-jsonrpc/src/mq_handler.rs +++ b/cita-jsonrpc/src/mq_handler.rs @@ -1,19 +1,16 @@ -// CITA -// Copyright 2016-2019 Cryptape Technologies LLC. - -// This program is free software: you can redistribute it -// and/or modify it under the terms of the GNU 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 General Public License for more details. - -// You should have received a copy of the GNU General Public License -// along with this program. If not, see . +// Copyright Cryptape Technologies LLC. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. use crate::helper::{RpcMap, TransferType}; use jsonrpc_proto::response::OutputExt; diff --git a/cita-jsonrpc/src/mq_publisher.rs b/cita-jsonrpc/src/mq_publisher.rs index 8b450302a..30acd4bd9 100644 --- a/cita-jsonrpc/src/mq_publisher.rs +++ b/cita-jsonrpc/src/mq_publisher.rs @@ -1,19 +1,16 @@ -// CITA -// Copyright 2016-2019 Cryptape Technologies LLC. - -// This program is free software: you can redistribute it -// and/or modify it under the terms of the GNU 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 General Public License for more details. - -// You should have received a copy of the GNU General Public License -// along with this program. If not, see . +// Copyright Cryptape Technologies LLC. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. use std::time::Duration; diff --git a/cita-jsonrpc/src/response.rs b/cita-jsonrpc/src/response.rs index 70ea637f2..c70c8771f 100644 --- a/cita-jsonrpc/src/response.rs +++ b/cita-jsonrpc/src/response.rs @@ -1,19 +1,16 @@ -// CITA -// Copyright 2016-2019 Cryptape Technologies LLC. - -// This program is free software: you can redistribute it -// and/or modify it under the terms of the GNU 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 General Public License for more details. - -// You should have received a copy of the GNU General Public License -// along with this program. If not, see . +// Copyright Cryptape Technologies LLC. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. use futures::stream::{Collect, FuturesOrdered}; use futures::{future::Future, sync::oneshot, Async, Poll}; diff --git a/cita-jsonrpc/src/service_error.rs b/cita-jsonrpc/src/service_error.rs index 3288349e4..958c2a8b4 100644 --- a/cita-jsonrpc/src/service_error.rs +++ b/cita-jsonrpc/src/service_error.rs @@ -1,19 +1,16 @@ -// CITA -// Copyright 2016-2019 Cryptape Technologies LLC. - -// This program is free software: you can redistribute it -// and/or modify it under the terms of the GNU 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 General Public License for more details. - -// You should have received a copy of the GNU General Public License -// along with this program. If not, see . +// Copyright Cryptape Technologies LLC. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. use hyper::{Body, HeaderMap as Headers, Response, StatusCode}; use jsonrpc_types::{rpc_request::RequestInfo, rpc_response::RpcFailure}; diff --git a/cita-jsonrpc/src/soliloquy.rs b/cita-jsonrpc/src/soliloquy.rs index 6d3fb084e..250609f18 100644 --- a/cita-jsonrpc/src/soliloquy.rs +++ b/cita-jsonrpc/src/soliloquy.rs @@ -1,19 +1,16 @@ -// CITA -// Copyright 2016-2019 Cryptape Technologies LLC. - -// This program is free software: you can redistribute it -// and/or modify it under the terms of the GNU 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 General Public License for more details. - -// You should have received a copy of the GNU General Public License -// along with this program. If not, see . +// Copyright Cryptape Technologies LLC. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. use crate::config::Config; use crate::get_build_info_str; diff --git a/cita-jsonrpc/src/ws_handler.rs b/cita-jsonrpc/src/ws_handler.rs index edcaff260..bfef47213 100644 --- a/cita-jsonrpc/src/ws_handler.rs +++ b/cita-jsonrpc/src/ws_handler.rs @@ -1,19 +1,16 @@ -// CITA -// Copyright 2016-2019 Cryptape Technologies LLC. - -// This program is free software: you can redistribute it -// and/or modify it under the terms of the GNU 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 General Public License for more details. - -// You should have received a copy of the GNU General Public License -// along with this program. If not, see . +// Copyright Cryptape Technologies LLC. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. use crate::helper::{select_topic, RpcMap, TransferType}; use jsonrpc_proto::complete::CompleteInto; diff --git a/cita-network/Cargo.toml b/cita-network/Cargo.toml index 27b564956..a2e169f84 100644 --- a/cita-network/Cargo.toml +++ b/cita-network/Cargo.toml @@ -2,14 +2,15 @@ name = "cita-network" version = "0.6.0" authors = ["Cryptape Technologies "] +license = "Apache-2.0" edition = "2018" [dependencies] -tentacle-discovery = "0.2.4" -tentacle = "0.2.1" +tentacle-discovery = "0.2.5" +tentacle = "0.2.3" tokio = "0.1.14" futures = "0.1.25" -cita-logger = "0.1.0" +cita-logger = "0.1.1" cita-types = { git = "https://github.com/cryptape/cita-common.git", branch = "develop" } util = { git = "https://github.com/cryptape/cita-common.git", branch = "develop" } libproto = { git = "https://github.com/cryptape/cita-common.git", branch = "develop" } diff --git a/cita-network/build.rs b/cita-network/build.rs index 11261b092..cfeaa8b9c 100644 --- a/cita-network/build.rs +++ b/cita-network/build.rs @@ -1,19 +1,16 @@ -// CITA -// Copyright 2016-2018 Cryptape Technologies LLC. - -// This program is free software: you can redistribute it -// and/or modify it under the terms of the GNU 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 General Public License for more details. - -// You should have received a copy of the GNU General Public License -// along with this program. If not, see . +// Copyrighttape Technologies LLC. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. use std::env; diff --git a/cita-network/src/cita_protocol.rs b/cita-network/src/cita_protocol.rs index 0ad3b62c9..09cc500c6 100644 --- a/cita-network/src/cita_protocol.rs +++ b/cita-network/src/cita_protocol.rs @@ -1,19 +1,16 @@ -// CITA -// Copyright 2016-2019 Cryptape Technologies LLC. - -// This program is free software: you can redistribute it -// and/or modify it under the terms of the GNU 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 General Public License for more details. - -// You should have received a copy of the GNU General Public License -// along with this program. If not, see . +// Copyright Cryptape Technologies LLC. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. //! A multiplexed cita protocol diff --git a/cita-network/src/config.rs b/cita-network/src/config.rs index 376151232..62fa4142c 100644 --- a/cita-network/src/config.rs +++ b/cita-network/src/config.rs @@ -1,19 +1,16 @@ -// CITA -// Copyright 2016-2019 Cryptape Technologies LLC. - -// This program is free software: you can redistribute it -// and/or modify it under the terms of the GNU 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 General Public License for more details. - -// You should have received a copy of the GNU General Public License -// along with this program. If not, see . +// Copyright Cryptape Technologies LLC. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. use cita_types::{clean_0x, Address}; use serde_derive::Deserialize; diff --git a/cita-network/src/main.rs b/cita-network/src/main.rs index fa2cd4955..ebf3b9fa6 100644 --- a/cita-network/src/main.rs +++ b/cita-network/src/main.rs @@ -1,19 +1,16 @@ -// CITA -// Copyright 2016-2019 Cryptape Technologies LLC. - -// This program is free software: you can redistribute it -// and/or modify it under the terms of the GNU 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 General Public License for more details. - -// You should have received a copy of the GNU General Public License -// along with this program. If not, see . +// Copyright Cryptape Technologies LLC. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. //! ## Summary //! @@ -82,6 +79,8 @@ #[macro_use] extern crate cita_logger as logger; +#[macro_use] +extern crate util; pub mod cita_protocol; pub mod config; pub mod mq_agent; @@ -106,7 +105,6 @@ use std::path::Path; use std::sync::mpsc::channel; use std::thread; use tentacle::{builder::ServiceBuilder, secio::SecioKeyPair}; -use util::micro_service_init; use util::set_panic_handler; include!(concat!(env!("OUT_DIR"), "/build_info.rs")); diff --git a/cita-network/src/mq_agent.rs b/cita-network/src/mq_agent.rs index f88d4662d..5a55cc914 100644 --- a/cita-network/src/mq_agent.rs +++ b/cita-network/src/mq_agent.rs @@ -1,19 +1,16 @@ -// CITA -// Copyright 2016-2019 Cryptape Technologies LLC. - -// This program is free software: you can redistribute it -// and/or modify it under the terms of the GNU 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 General Public License for more details. - -// You should have received a copy of the GNU General Public License -// along with this program. If not, see . +// Copyright Cryptape Technologies LLC. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. use crate::network::{send_message, LocalMessage, NetworkClient}; use crate::node_manager::NodesManagerClient; diff --git a/cita-network/src/network.rs b/cita-network/src/network.rs index c118516dd..cff0ea42b 100644 --- a/cita-network/src/network.rs +++ b/cita-network/src/network.rs @@ -1,19 +1,16 @@ -// CITA -// Copyright 2016-2019 Cryptape Technologies LLC. - -// This program is free software: you can redistribute it -// and/or modify it under the terms of the GNU 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 General Public License for more details. - -// You should have received a copy of the GNU General Public License -// along with this program. If not, see . +// Copyright Cryptape Technologies LLC. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. use crate::mq_agent::{MqAgentClient, PubMessage}; use crate::node_manager::{ diff --git a/cita-network/src/node_manager.rs b/cita-network/src/node_manager.rs index af3f06723..6632d4571 100644 --- a/cita-network/src/node_manager.rs +++ b/cita-network/src/node_manager.rs @@ -1,19 +1,16 @@ -// CITA -// Copyright 2016-2019 Cryptape Technologies LLC. - -// This program is free software: you can redistribute it -// and/or modify it under the terms of the GNU 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 General Public License for more details. - -// You should have received a copy of the GNU General Public License -// along with this program. If not, see . +// Copyrighttape Technologies LLC. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. use crate::cita_protocol::{ pubsub_message_to_network_message, NetMessageUnit, CONSENSUS_STR, CONSENSUS_TTL_NUM, @@ -289,6 +286,8 @@ impl NodesManager { } } + // clippy + #[allow(clippy::drop_copy, clippy::zero_ptr)] pub fn run(&mut self) { loop { select! { diff --git a/cita-network/src/p2p_protocol/mod.rs b/cita-network/src/p2p_protocol/mod.rs index 4c33aa874..56358cc0a 100644 --- a/cita-network/src/p2p_protocol/mod.rs +++ b/cita-network/src/p2p_protocol/mod.rs @@ -1,19 +1,16 @@ -// CITA -// Copyright 2016-2019 Cryptape Technologies LLC. - -// This program is free software: you can redistribute it -// and/or modify it under the terms of the GNU 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 General Public License for more details. - -// You should have received a copy of the GNU General Public License -// along with this program. If not, see . +// Copyrighttape Technologies LLC. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. use crate::node_manager::{ AddRepeatedNodeReq, ConnectedSelfReq, DelConnectedNodeReq, DialedErrorReq, NodesManagerClient, diff --git a/cita-network/src/p2p_protocol/node_discovery.rs b/cita-network/src/p2p_protocol/node_discovery.rs index c1da0da3a..1bd82882d 100644 --- a/cita-network/src/p2p_protocol/node_discovery.rs +++ b/cita-network/src/p2p_protocol/node_discovery.rs @@ -1,19 +1,16 @@ -// CITA -// Copyright 2016-2019 Cryptape Technologies LLC. - -// This program is free software: you can redistribute it -// and/or modify it under the terms of the GNU 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 General Public License for more details. - -// You should have received a copy of the GNU General Public License -// along with this program. If not, see . +// Copyright Cryptape Technologies LLC. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. use crate::node_manager::{AddNodeReq, GetRandomNodesReq, NodeSource, NodesManagerClient}; use pubsub::channel::unbounded; diff --git a/cita-network/src/p2p_protocol/transfer.rs b/cita-network/src/p2p_protocol/transfer.rs index 95a13db22..be20f4cb2 100644 --- a/cita-network/src/p2p_protocol/transfer.rs +++ b/cita-network/src/p2p_protocol/transfer.rs @@ -1,19 +1,16 @@ -// CITA -// Copyright 2016-2019 Cryptape Technologies LLC. - -// This program is free software: you can redistribute it -// and/or modify it under the terms of the GNU 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 General Public License for more details. - -// You should have received a copy of the GNU General Public License -// along with this program. If not, see . +// Copyright Cryptape Technologies LLC. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. use crate::cita_protocol::network_message_to_pubsub_message; use crate::network::{NetworkClient, RemoteMessage}; diff --git a/cita-network/src/synchronizer.rs b/cita-network/src/synchronizer.rs index 813173347..f6aaa7718 100644 --- a/cita-network/src/synchronizer.rs +++ b/cita-network/src/synchronizer.rs @@ -1,19 +1,16 @@ -// CITA -// Copyright 2016-2019 Cryptape Technologies LLC. - -// This program is free software: you can redistribute it -// and/or modify it under the terms of the GNU 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 General Public License for more details. - -// You should have received a copy of the GNU General Public License -// along with this program. If not, see . +// Copyright Cryptape Technologies LLC. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. use crate::mq_agent::{MqAgentClient, PubMessage}; use crate::node_manager::{BroadcastReq, NodesManagerClient, SingleTxReq}; diff --git a/release-guide.md b/docs/release-guide.md similarity index 91% rename from release-guide.md rename to docs/release-guide.md index 4078301a6..8162ed1a8 100644 --- a/release-guide.md +++ b/docs/release-guide.md @@ -119,10 +119,10 @@ git push origin vx.y.z ### Merge into the develop Branch -***The transition branch is named `merge-master-to-develop`*** +***The transition branch is named `merge-master-into-develop`*** Merge the `master` branch into the `develop` branch. -Because of the branch protection, we need to create a middle branch `merge-master-to-develop` via `pull request`. +Because of the branch protection, we need to create a middle branch `merge-master-into-develop` via `pull request`. 1. Update the `master` branch code as follows: @@ -130,21 +130,21 @@ Because of the branch protection, we need to create a middle branch `merge-maste git checkout origin/master && git pull ``` -2. Create `merge-master-to-develop` as follows: +2. Create `merge-master-into-develop` as follows: ```shell -git checkout -b merge-master-to-develop +git checkout -b merge-master-into-develop ``` 3. Push the branch to the code repository as follows: ```shell -git push origin merge-master-to-develop +git push origin merge-master-into-develop ``` 4. Merge into `develop` -Merge the transition branch `merge-master-to-develop` into the `develop` branch via pull request. +Merge the transition branch `merge-master-into-develop` into the `develop` branch via pull request. ## Release @@ -187,7 +187,7 @@ git push --delete origin release-x.y.z 2. Clean up the transition branch as follows: ```shell -git push --delete origin merge-master-to-develop +git push --delete origin merge-master-into-develop ``` ### Update Version of CITAHub Docs @@ -324,9 +324,9 @@ git push origin vx.y.z ### 合并入 `develop` 分支 -***过渡分支命名为 `merge-master-to-develop`*** +***过渡分支命名为 `merge-master-into-develop`*** -把 `master` 分支合并入 `develop` 分支,由于分支保护,创建一个中间分支 `merge-master-to-develop` 通过 `pull request` 合并。 +把 `master` 分支合并入 `develop` 分支,由于分支保护,创建一个中间分支 `merge-master-into-develop` 通过 `pull request` 合并。 1. 更新 `master` 分支代码,具体操作如下: @@ -334,21 +334,21 @@ git push origin vx.y.z git checkout origin/master && git pull ``` -2. 创建 `merge-master-to-develop`,具体操作如下: +2. 创建 `merge-master-into-develop`,具体操作如下: ```shell -git checkout -b merge-master-to-develop +git checkout -b merge-master-into-develop ``` 3. 推送分支到代码仓库,具体操作如下: ```shell -git push origin merge-master-to-develop +git push origin merge-master-into-develop ``` 4. 合并入 `develop` -通过 `pull request` 把过渡分支 `merge-master-to-develop` 合并入 `develop` 分支。 +通过 `pull request` 把过渡分支 `merge-master-into-develop` 合并入 `develop` 分支。 ## 发布 @@ -391,7 +391,7 @@ git push --delete origin release-x.y.z 2. 清理过渡分支,具体操作如下: ```shell -git push --delete origin merge-master-to-develop +git push --delete origin merge-master-into-develop ``` ### CITAHub Docs 版本更新 diff --git a/style-guide/js.md b/docs/style-guide/js.md similarity index 100% rename from style-guide/js.md rename to docs/style-guide/js.md diff --git a/style-guide/logging.md b/docs/style-guide/logging.md similarity index 100% rename from style-guide/logging.md rename to docs/style-guide/logging.md diff --git a/style-guide/naming.md b/docs/style-guide/naming.md similarity index 100% rename from style-guide/naming.md rename to docs/style-guide/naming.md diff --git a/style-guide/python.md b/docs/style-guide/python.md similarity index 100% rename from style-guide/python.md rename to docs/style-guide/python.md diff --git a/style-guide/rust.md b/docs/style-guide/rust.md similarity index 100% rename from style-guide/rust.md rename to docs/style-guide/rust.md diff --git a/style-guide/shell.md b/docs/style-guide/shell.md similarity index 100% rename from style-guide/shell.md rename to docs/style-guide/shell.md diff --git a/style-guide/solidity.md b/docs/style-guide/solidity.md similarity index 100% rename from style-guide/solidity.md rename to docs/style-guide/solidity.md diff --git a/env.sh b/env.sh index eb278ad66..bbbca2354 100755 --- a/env.sh +++ b/env.sh @@ -16,7 +16,7 @@ if test -f "${SOURCE_DIR}/Cargo.toml"; then readonly DOCKER_IMAGE='cita/cita-build:ubuntu-18.04-20190515' else readonly CONTAINER_NAME='cita_run_container' - readonly DOCKER_IMAGE='cita/cita-run:ubuntu-18.04-20190419' + readonly DOCKER_IMAGE='cita/cita-run:ubuntu-18.04-20190829' readonly SOURCE_DIR="$(dirname "$SOURCE_DIR")" fi diff --git a/scripts/amend_system_contracts.sh b/scripts/amend_system_contracts.sh index 6249ec3d4..d91cbcd8b 100755 --- a/scripts/amend_system_contracts.sh +++ b/scripts/amend_system_contracts.sh @@ -28,6 +28,8 @@ scripts/create_cita_config.py create \ --chain_name tmp \ --super_admin "0x4b5ae4567ad5d9fb92bc9afd6a657e6fa13a2523" \ --nodes "127.0.0.1:4000" \ + --contract_arguments SysConfig.chainId="$2" \ + --contract_arguments VersionManager.version="$3" \ && cp tmp/0/genesis.json scripts/ \ && cd ./scripts/txtool/txtool \ && python3 "${SOURCE_DIR}"/scripts/amend_system_contracts.py \ diff --git a/scripts/config_tool/default_config/executor.toml b/scripts/config_tool/default_config/executor.toml index 57bf43787..6ec8ff7e8 100644 --- a/scripts/config_tool/default_config/executor.toml +++ b/scripts/config_tool/default_config/executor.toml @@ -1,6 +1,5 @@ journaldb_type = "archive" prooftype = 2 -grpc_port = 5000 genesis_path = "./genesis.json" statedb_cache_size = 5242880 eth_compatibility = false diff --git a/scripts/config_tool/genesis b/scripts/config_tool/genesis index 0ab5c9947..4d615b05a 160000 --- a/scripts/config_tool/genesis +++ b/scripts/config_tool/genesis @@ -1 +1 @@ -Subproject commit 0ab5c9947df48e55dfc16d2b375c5509a58d5aeb +Subproject commit 4d615b05a828f0b501e1ce91332855e56c054cc4 diff --git a/scripts/contracts/interaction b/scripts/contracts/interaction index 0be3ed1ab..0d18189e9 160000 --- a/scripts/contracts/interaction +++ b/scripts/contracts/interaction @@ -1 +1 @@ -Subproject commit 0be3ed1ab06e69f032c6d5b5fee0d54c108f3a0f +Subproject commit 0d18189e9a063c5ee2c74808d8c092cc532e671d diff --git a/scripts/contracts/tests/package.json b/scripts/contracts/tests/package.json index deb3b54ac..51d1fb94e 100644 --- a/scripts/contracts/tests/package.json +++ b/scripts/contracts/tests/package.json @@ -34,9 +34,9 @@ }, "repository": {}, "author": "Cryptape Technologies ", - "license": "GPL-3.0+", + "license": "Apache 2.0", "dependencies": { - "@cryptape/cita-sdk": "^0.23.1", + "@cryptape/cita-sdk": "^0.25.1", "chai": "^4.2.0", "log4js": "^4.1.0", "mocha": "^6.1.4" diff --git a/scripts/contracts/tests/yarn.lock b/scripts/contracts/tests/yarn.lock index 3d3670655..7d9b75265 100644 --- a/scripts/contracts/tests/yarn.lock +++ b/scripts/contracts/tests/yarn.lock @@ -10,38 +10,39 @@ "@babel/highlight" "^7.0.0" "@babel/highlight@^7.0.0": - version "7.0.0" - resolved "https://registry.yarnpkg.com/@babel/highlight/-/highlight-7.0.0.tgz#f710c38c8d458e6dd9a201afb637fcb781ce99e4" - integrity sha512-UFMC4ZeFC48Tpvj7C8UgLvtkaUuovQX+5xNWrsIoMG8o2z+XFKjKaN9iVmS84dPwVN00W4wPmqvYoZF3EGAsfw== + version "7.5.0" + resolved "https://registry.yarnpkg.com/@babel/highlight/-/highlight-7.5.0.tgz#56d11312bd9248fa619591d02472be6e8cb32540" + integrity sha512-7dV4eu9gBxoM0dAnj/BCFDW9LFU0zvTrkq0ugM7pnHEgguOEeOz1so2ZghEdzviYzQEED0r4EAgpsBChKy1TRQ== dependencies: chalk "^2.0.0" esutils "^2.0.2" js-tokens "^4.0.0" -"@cryptape/cita-sdk@^0.23.1": - version "0.23.1" - resolved "https://registry.yarnpkg.com/@cryptape/cita-sdk/-/cita-sdk-0.23.1.tgz#9d970cba62358f7a20d2500bd3e529211d1833a3" - integrity sha512-S9/WxMdRgCBuESgw9WJumyXZ4XEJFOrER2N0oyu33FlxWfmyN5h0R8jLSfJW17dPiAJxjIzxRypkiy+AK/S41g== +"@cryptape/cita-sdk@^0.25.1": + version "0.25.1" + resolved "https://registry.yarnpkg.com/@cryptape/cita-sdk/-/cita-sdk-0.25.1.tgz#b4d7e95a40a977775634a3773a5190297e5188e3" + integrity sha512-2R224eRYA4qxFVv62LckqBByvWOWqK9xTKjzzDOYEXEgLDSLOP6sRAF5sndxrbAj8WHMUgWH9YPmKITQ9XFZmw== dependencies: - "@cryptape/cita-signer" "^2.3.0" + "@cryptape/cita-signer" "^2.5.2" + fstream "1.0.12" web3 "1.0.0-beta.37" -"@cryptape/cita-signer@^2.3.0": - version "2.3.0" - resolved "https://registry.yarnpkg.com/@cryptape/cita-signer/-/cita-signer-2.3.0.tgz#bb84405b06cf0a6b2dc253375fe23010416ed58f" - integrity sha512-J88vs3+U0XSvcj+nE/zSa/TmLSzRTX/sJYQXSyb/RBTdMcloYpkP5SEYK/kNCVbXYFv7NiXoGpzPP9q6PTWwhQ== +"@cryptape/cita-signer@^2.5.2": + version "2.5.2" + resolved "https://registry.yarnpkg.com/@cryptape/cita-signer/-/cita-signer-2.5.2.tgz#b6fd68d6ab19483499526fe13205e3acf024d350" + integrity sha512-j3DsO4i5DQxwuGev+eiKZkbGYl/3PkwlxUGqLzLHPNAbejVwNdiXg5K+zL6AAPXch8Ci3YQ4cUexLjSWB1sYqQ== dependencies: - ec "^0.0.1" elliptic "^6.4.0" + fstream "1.0.12" google-protobuf "^3.5.0" web3 "1.0.0-beta.37" "@types/node@^10.3.2": - version "10.14.6" - resolved "https://registry.yarnpkg.com/@types/node/-/node-10.14.6.tgz#9cbfcb62c50947217f4d88d4d274cc40c22625a9" - integrity sha512-Fvm24+u85lGmV4hT5G++aht2C5I4Z4dYlWZIh62FAfFO/TfzXtPpoLI6I7AuBWkIFqZCnhFOoTT7RjjaIL5Fjg== + version "10.14.12" + resolved "https://registry.yarnpkg.com/@types/node/-/node-10.14.12.tgz#0eec3155a46e6c4db1f27c3e588a205f767d622f" + integrity sha512-QcAKpaO6nhHLlxWBvpc4WeLrTvPqlHOvaj0s5GriKkA1zq+bsFBPpfYCvQhLqLgYlIko8A9YrPdaMHCo5mBcpg== -accepts@~1.3.5: +accepts@~1.3.7: version "1.3.7" resolved "https://registry.yarnpkg.com/accepts/-/accepts-1.3.7.tgz#531bc726517a3b2b41f850021c6cc15eaab507cd" integrity sha512-Il80Qs2WjYlJIBNzNkK6KYqlVMTbZLXgHx2oT0pU/fjRHyEp+PEfEPY0R3WCwAGVOtauxh1hOxNgIf5bv7dQpA== @@ -55,9 +56,9 @@ acorn-jsx@^5.0.0: integrity sha512-HJ7CfNHrfJLlNTzIEUTj43LNWGkqpRLxm3YjAlcD0ACydk9XynzYsCBHxut+iqt+1aBXkx9UP/w/ZqMr13XIzg== acorn@^6.0.7: - version "6.1.1" - resolved "https://registry.yarnpkg.com/acorn/-/acorn-6.1.1.tgz#7d25ae05bb8ad1f9b699108e1094ecd7884adc1f" - integrity sha512-jPTiwtOxaHNaAPg/dmrJ/beuzLRnXtB0kQPQ8JpotKJgTB6rX6c8mlf315941pyjBSaPg8NHXS9fhP4u17DpGA== + version "6.2.0" + resolved "https://registry.yarnpkg.com/acorn/-/acorn-6.2.0.tgz#67f0da2fc339d6cfb5d6fb244fd449f33cd8bbe3" + integrity sha512-8oe72N3WPMjA+2zVG71Ia0nXZ8DpQH+QyyHO+p06jT8eg8FGG3FbcUIi8KziHlAfheJQZeoqbvq1mQSQHXKYLw== aes-js@3.0.0: version "3.0.0" @@ -65,9 +66,9 @@ aes-js@3.0.0: integrity sha1-4h3xCtbCBTKVvLuNq0Cwnb6ofk0= ajv@^6.5.5, ajv@^6.9.1: - version "6.10.0" - resolved "https://registry.yarnpkg.com/ajv/-/ajv-6.10.0.tgz#90d0d54439da587cd7e843bfb7045f50bd22bdf1" - integrity sha512-nffhOpkymDECQyR0mnsUtoCE8RlX38G0rYP+wgLWFyZuUyuuojSSvi/+euOiQBIn63whYwYVIIH1TvE3tu4OEg== + version "6.10.2" + resolved "https://registry.yarnpkg.com/ajv/-/ajv-6.10.2.tgz#d3cea04d6b017b2894ad69040fec8b623eb4bd52" + integrity sha512-TXtUUEYHuaTEbLZWIKUr5pmBuhDLy+8KYtPYdcV8qC+pOZL+NKqYwvWSRrVXHn+ZmRRAu8vJTAznH7Oag6RVRw== dependencies: fast-deep-equal "^2.0.1" fast-json-stable-stringify "^2.0.0" @@ -167,12 +168,12 @@ async-limiter@~1.0.0: resolved "https://registry.yarnpkg.com/async-limiter/-/async-limiter-1.0.0.tgz#78faed8c3d074ab81f22b4e985d79e8738f720f8" integrity sha512-jp/uFnooOiO+L211eZOoSyzpOITMXx1rBITauYykG3BRYPu8h0UcxsPNB04RR5vo4Tyz3+ay17tR6JVf9qzYWg== -async@^2.6.1: - version "2.6.2" - resolved "https://registry.yarnpkg.com/async/-/async-2.6.2.tgz#18330ea7e6e313887f5d2f2a904bac6fe4dd5381" - integrity sha512-H1qVYh1MYhEEFLsP97cVKqCGo7KfCyTt6uEWqsTBr9SO84oK9Uwbyd/yCW+6rKJLHksBNUVWZDAjfS+Ccx0Bbg== +async@^2.6.2: + version "2.6.3" + resolved "https://registry.yarnpkg.com/async/-/async-2.6.3.tgz#d72625e2344a3656e3a3ad4fa749fa83299d82ff" + integrity sha512-zflvls11DCy+dQWzTW2dzuilv8Z5X/pjfmZOWba6TNIVDm+2UDaJmXSOXlasHKfNBs8oo3M0aT50fDEWfKZjXg== dependencies: - lodash "^4.17.11" + lodash "^4.17.14" asynckit@^0.4.0: version "0.4.0" @@ -227,9 +228,9 @@ bluebird@^2.9.34: integrity sha1-U0uQM8AiyVecVro7Plpcqvu2UOE= bluebird@^3.5.0: - version "3.5.4" - resolved "https://registry.yarnpkg.com/bluebird/-/bluebird-3.5.4.tgz#d6cc661595de30d5b3af5fcedd3c0b3ef6ec5714" - integrity sha512-FG+nFEZChJrbQ9tIccIfZJBz3J7mLrAhxakAbnrJWn8d7aKOC+LWifa0G+p4ZqKp4y13T7juYvdhq9NzKdsrjw== + version "3.5.5" + resolved "https://registry.yarnpkg.com/bluebird/-/bluebird-3.5.5.tgz#a8d0afd73251effbbd5fe384a77d73003c17a71f" + integrity sha512-5am6HnnfN+urzt4yfg7IgTbotDjIT/u8AJpEt0sIU9FtXfVeezXAPKswrG+xKUCOYAINpSdgZVDU6QFh+cuH3w== bn.js@4.11.6: version "4.11.6" @@ -241,23 +242,7 @@ bn.js@^4.0.0, bn.js@^4.1.0, bn.js@^4.1.1, bn.js@^4.11.6, bn.js@^4.4.0: resolved "https://registry.yarnpkg.com/bn.js/-/bn.js-4.11.8.tgz#2cde09eb5ee341f484746bb0309b3253b1b1442f" integrity sha512-ItfYfPLkWHUjckQCk8xC+LwxgK8NYcXywGigJgSwOP8Y2iyWT4f2vsZnoOXTTbo+o5yXmIUJ4gn5538SO5S3gA== -body-parser@1.18.3: - version "1.18.3" - resolved "https://registry.yarnpkg.com/body-parser/-/body-parser-1.18.3.tgz#5b292198ffdd553b3a0f20ded0592b956955c8b4" - integrity sha1-WykhmP/dVTs6DyDe0FkrlWlVyLQ= - dependencies: - bytes "3.0.0" - content-type "~1.0.4" - debug "2.6.9" - depd "~1.1.2" - http-errors "~1.6.3" - iconv-lite "0.4.23" - on-finished "~2.3.0" - qs "6.5.2" - raw-body "2.3.3" - type-is "~1.6.16" - -body-parser@^1.16.0: +body-parser@1.19.0, body-parser@^1.16.0: version "1.19.0" resolved "https://registry.yarnpkg.com/body-parser/-/body-parser-1.19.0.tgz#96b2709e57c9c4e09a6fd66a8fd979844f69f08a" integrity sha512-dhEPs72UPbDnAQJ9ZKMNTP6ptJaionhP5cBb541nXPlW60Jepo9RV/a4fX4XWW9CuFNK22krhrj1+rgzifNCsw== @@ -392,11 +377,6 @@ buffer@^5.0.5, buffer@^5.2.1: base64-js "^1.0.2" ieee754 "^1.1.4" -bytes@3.0.0: - version "3.0.0" - resolved "https://registry.yarnpkg.com/bytes/-/bytes-3.0.0.tgz#d32815404d689699f85a4ea4fa8755dd13a96048" - integrity sha1-0ygVQE1olpn4Wk6k+odV3ROpYEg= - bytes@3.1.0: version "3.1.0" resolved "https://registry.yarnpkg.com/bytes/-/bytes-3.1.0.tgz#f6cf7933a360e0588fa9fde85651cdc7f805d1f6" @@ -495,9 +475,9 @@ color-name@1.1.3: integrity sha1-p9BVi9icQveV3UIyj3QIMcpTvCU= combined-stream@^1.0.6, combined-stream@~1.0.6: - version "1.0.7" - resolved "https://registry.yarnpkg.com/combined-stream/-/combined-stream-1.0.7.tgz#2d1d24317afb8abe95d6d2c0b07b57813539d828" - integrity sha512-brWl9y6vOB1xYPZcpZde3N9zDByXTosAeMDo4p1wzo6UMOX4vumB+TP1RZ76sfE6Md68Q0NJSrE/gbezd4Ul+w== + version "1.0.8" + resolved "https://registry.yarnpkg.com/combined-stream/-/combined-stream-1.0.8.tgz#c3d45a8b34fd730631a110a8a2520682b31d5a7f" + integrity sha512-FQN4MRfuJeHf7cBbBMJFXhKSDq+2kAArBlmRBvcvFE5BB1HZKXtSFASDhdlz9zOYwxh8lDdnvmMOe/+5cdoEdg== dependencies: delayed-stream "~1.0.0" @@ -518,15 +498,22 @@ concat-map@0.0.1: resolved "https://registry.yarnpkg.com/concat-map/-/concat-map-0.0.1.tgz#d8a96bd77fd68df7793a73036a3ba0d5405d477b" integrity sha1-2Klr13/Wjfd5OnMDajug1UBdR3s= +confusing-browser-globals@^1.0.5: + version "1.0.7" + resolved "https://registry.yarnpkg.com/confusing-browser-globals/-/confusing-browser-globals-1.0.7.tgz#5ae852bd541a910e7ffb2dbb864a2d21a36ad29b" + integrity sha512-cgHI1azax5ATrZ8rJ+ODDML9Fvu67PimB6aNxBrc/QwSaDaM9eTfIEUHx3bBLJJ82ioSb+/5zfsMCCEJax3ByQ== + contains-path@^0.1.0: version "0.1.0" resolved "https://registry.yarnpkg.com/contains-path/-/contains-path-0.1.0.tgz#fe8cf184ff6670b6baef01a9d4861a5cbec4120a" integrity sha1-/ozxhP9mcLa67wGp1IYaXL7EEgo= -content-disposition@0.5.2: - version "0.5.2" - resolved "https://registry.yarnpkg.com/content-disposition/-/content-disposition-0.5.2.tgz#0cf68bb9ddf5f2be7961c3a85178cb85dba78cb4" - integrity sha1-DPaLud318r55YcOoUXjLhdunjLQ= +content-disposition@0.5.3: + version "0.5.3" + resolved "https://registry.yarnpkg.com/content-disposition/-/content-disposition-0.5.3.tgz#e130caf7e7279087c5616c2007d0485698984fbd" + integrity sha512-ExO0774ikEObIAEV9kDo50o+79VCUdEB6n6lzKgGwupcVeRlhrj3qGAfwq8G6uBJjkqLrhT0qEYFcWng8z1z0g== + dependencies: + safe-buffer "5.1.2" content-type@~1.0.4: version "1.0.4" @@ -538,10 +525,10 @@ cookie-signature@1.0.6: resolved "https://registry.yarnpkg.com/cookie-signature/-/cookie-signature-1.0.6.tgz#e303a882b342cc3ee8ca513a79999734dab3ae2c" integrity sha1-4wOogrNCzD7oylE6eZmXNNqzriw= -cookie@0.3.1: - version "0.3.1" - resolved "https://registry.yarnpkg.com/cookie/-/cookie-0.3.1.tgz#e7e0a1f9ef43b4c8ba925c5c5a96e806d16873bb" - integrity sha1-5+Ch+e9DtMi6klxcWpboBtFoc7s= +cookie@0.4.0: + version "0.4.0" + resolved "https://registry.yarnpkg.com/cookie/-/cookie-0.4.0.tgz#beb437e7022b3b6d49019d088665303ebe9c14ba" + integrity sha512-+Hp8fLp57wnUSt0tY0tHEXh4voZRDnoIrZPqlo3DPiI4y9lwg/jqx+1Om94/W6ZaPDOUbnjOt/99w66zk+l1Xg== cookiejar@^2.1.1: version "2.1.2" @@ -639,7 +626,7 @@ debug@2.6.9, debug@^2.2.0, debug@^2.6.8, debug@^2.6.9: dependencies: ms "2.0.0" -debug@3.2.6, debug@^3.1.0: +debug@3.2.6, debug@^3.2.6: version "3.2.6" resolved "https://registry.yarnpkg.com/debug/-/debug-3.2.6.tgz#e83d17de16d8a7efb7717edbe5fb10135eee629b" integrity sha512-mel+jf7nrtEl5Pn1Qx46zARXKDpBbvzezse7p7LqINmdoIk8PYP5SySaxEmYv6TZ0JyEKA1hsCId6DIhgITtWQ== @@ -804,11 +791,6 @@ duplexer3@^0.1.4: resolved "https://registry.yarnpkg.com/duplexer3/-/duplexer3-0.1.4.tgz#ee01dd1cac0ed3cbc7fdbea37dc0a8f1ce002ce2" integrity sha1-7gHdHKwO08vH/b6jfcCo8c4ALOI= -ec@^0.0.1: - version "0.0.1" - resolved "https://registry.yarnpkg.com/ec/-/ec-0.0.1.tgz#5579aad6053f2ce337bc712a905188f69450b8e1" - integrity sha1-VXmq1gU/LOM3vHEqkFGI9pRQuOE= - ecc-jsbn@~0.1.1: version "0.1.2" resolved "https://registry.yarnpkg.com/ecc-jsbn/-/ecc-jsbn-0.1.2.tgz#3a83a904e54353287874c564b7549386849a98c9" @@ -833,9 +815,9 @@ elliptic@6.3.3: inherits "^2.0.1" elliptic@^6.0.0, elliptic@^6.4.0: - version "6.4.1" - resolved "https://registry.yarnpkg.com/elliptic/-/elliptic-6.4.1.tgz#c2d0b7776911b86722c632c3c06c60f2f819939a" - integrity sha512-BsXLz5sqX8OHcsh7CqBMztyXARmGQ3LWPtGjJi6DiJHq5C/qvi9P3OqgswKSDftbu8+IoI/QDTAm2fFnQ9SZSQ== + version "6.5.0" + resolved "https://registry.yarnpkg.com/elliptic/-/elliptic-6.5.0.tgz#2b8ed4c891b7de3200e14412a5b8248c7af505ca" + integrity sha512-eFOJTMyCYb7xtE/caJ6JJu+bhi67WCYNbkGSknu20pmM8Ke/bqOfdnZWxyoGN26JgfxTbXrsCkEw4KheCT/KGg== dependencies: bn.js "^4.4.0" brorand "^1.0.1" @@ -901,13 +883,13 @@ escape-string-regexp@1.0.5, escape-string-regexp@^1.0.5: integrity sha1-G2HAViGQqN/2rjuyzwIAyhMLhtQ= eslint-config-airbnb-base@^13.1.0: - version "13.1.0" - resolved "https://registry.yarnpkg.com/eslint-config-airbnb-base/-/eslint-config-airbnb-base-13.1.0.tgz#b5a1b480b80dfad16433d6c4ad84e6605052c05c" - integrity sha512-XWwQtf3U3zIoKO1BbHh6aUhJZQweOwSt4c2JrPDg9FP3Ltv3+YfEv7jIDB8275tVnO/qOHbfuYg3kzw6Je7uWw== + version "13.2.0" + resolved "https://registry.yarnpkg.com/eslint-config-airbnb-base/-/eslint-config-airbnb-base-13.2.0.tgz#f6ea81459ff4dec2dda200c35f1d8f7419d57943" + integrity sha512-1mg/7eoB4AUeB0X1c/ho4vb2gYkNH8Trr/EgCT/aGmKhhG+F6vF5s8+iRBlWAzFIAphxIdp3YfEKgEl0f9Xg+w== dependencies: - eslint-restricted-globals "^0.1.1" + confusing-browser-globals "^1.0.5" object.assign "^4.1.0" - object.entries "^1.0.4" + object.entries "^1.1.0" eslint-import-resolver-node@^0.3.2: version "0.3.2" @@ -926,9 +908,9 @@ eslint-module-utils@^2.4.0: pkg-dir "^2.0.0" eslint-plugin-import@^2.17.2: - version "2.17.2" - resolved "https://registry.yarnpkg.com/eslint-plugin-import/-/eslint-plugin-import-2.17.2.tgz#d227d5c6dc67eca71eb590d2bb62fb38d86e9fcb" - integrity sha512-m+cSVxM7oLsIpmwNn2WXTJoReOF9f/CtLMo7qOVmKd1KntBy0hEcuNZ3erTmWjx+DxRO0Zcrm5KwAvI9wHcV5g== + version "2.18.0" + resolved "https://registry.yarnpkg.com/eslint-plugin-import/-/eslint-plugin-import-2.18.0.tgz#7a5ba8d32622fb35eb9c8db195c2090bd18a3678" + integrity sha512-PZpAEC4gj/6DEMMoU2Df01C5c50r7zdGIN52Yfi7CvvWaYssG7Jt5R9nFG5gmqodxNOz9vQS87xk6Izdtpdrig== dependencies: array-includes "^3.0.3" contains-path "^0.1.0" @@ -940,12 +922,7 @@ eslint-plugin-import@^2.17.2: lodash "^4.17.11" minimatch "^3.0.4" read-pkg-up "^2.0.0" - resolve "^1.10.0" - -eslint-restricted-globals@^0.1.1: - version "0.1.1" - resolved "https://registry.yarnpkg.com/eslint-restricted-globals/-/eslint-restricted-globals-0.1.1.tgz#35f0d5cbc64c2e3ed62e93b4b1a7af05ba7ed4d7" - integrity sha1-NfDVy8ZMLj7WLpO0saevBbp+1Nc= + resolve "^1.11.0" eslint-scope@^4.0.3: version "4.0.3" @@ -956,14 +933,16 @@ eslint-scope@^4.0.3: estraverse "^4.1.1" eslint-utils@^1.3.1: - version "1.3.1" - resolved "https://registry.yarnpkg.com/eslint-utils/-/eslint-utils-1.3.1.tgz#9a851ba89ee7c460346f97cf8939c7298827e512" - integrity sha512-Z7YjnIldX+2XMcjr7ZkgEsOj/bREONV60qYeB/bjMAqqqZ4zxKyWX+BOUkdmRmA9riiIPVvo5x86m5elviOk0Q== + version "1.4.2" + resolved "https://registry.yarnpkg.com/eslint-utils/-/eslint-utils-1.4.2.tgz#166a5180ef6ab7eb462f162fd0e6f2463d7309ab" + integrity sha512-eAZS2sEUMlIeCjBeubdj45dmBHQwPHWyBcT1VSYB7o9x9WRRqKxyUoiXlRjyAwzN7YEzHJlYg0NmzDRWx6GP4Q== + dependencies: + eslint-visitor-keys "^1.0.0" eslint-visitor-keys@^1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/eslint-visitor-keys/-/eslint-visitor-keys-1.0.0.tgz#3f3180fb2e291017716acb4c9d6d5b5c34a6a81d" - integrity sha512-qzm/XxIbxm/FHyH341ZrbnMUpe+5Bocte9xkmFMzPMjRaZMcXww+MpBptFvtU+79L362nqiLhekCxCxDPaUMBQ== + version "1.1.0" + resolved "https://registry.yarnpkg.com/eslint-visitor-keys/-/eslint-visitor-keys-1.1.0.tgz#e2a82cea84ff246ad6fb57f9bde5b46621459ec2" + integrity sha512-8y9YjtM1JBJU/A9Kc+SbaOV4y29sSWckBwMHa+FGtVj5gN/sbnKDf6xJUl+8g7FAij9LVaP8C24DUiH/f/2Z9A== eslint@^5.16.0: version "5.16.0" @@ -1131,38 +1110,38 @@ execa@^1.0.0: strip-eof "^1.0.0" express@^4.14.0: - version "4.16.4" - resolved "https://registry.yarnpkg.com/express/-/express-4.16.4.tgz#fddef61926109e24c515ea97fd2f1bdbf62df12e" - integrity sha512-j12Uuyb4FMrd/qQAm6uCHAkPtO8FDTRJZBDd5D2KOL2eLaz1yUNdUB/NOIyq0iU4q4cFarsUCrnFDPBcnksuOg== + version "4.17.1" + resolved "https://registry.yarnpkg.com/express/-/express-4.17.1.tgz#4491fc38605cf51f8629d39c2b5d026f98a4c134" + integrity sha512-mHJ9O79RqluphRrcw2X/GTh3k9tVv8YcoyY4Kkh4WDMUYKRZUq0h1o0w2rrrxBqM7VoeUVqgb27xlEMXTnYt4g== dependencies: - accepts "~1.3.5" + accepts "~1.3.7" array-flatten "1.1.1" - body-parser "1.18.3" - content-disposition "0.5.2" + body-parser "1.19.0" + content-disposition "0.5.3" content-type "~1.0.4" - cookie "0.3.1" + cookie "0.4.0" cookie-signature "1.0.6" debug "2.6.9" depd "~1.1.2" encodeurl "~1.0.2" escape-html "~1.0.3" etag "~1.8.1" - finalhandler "1.1.1" + finalhandler "~1.1.2" fresh "0.5.2" merge-descriptors "1.0.1" methods "~1.1.2" on-finished "~2.3.0" - parseurl "~1.3.2" + parseurl "~1.3.3" path-to-regexp "0.1.7" - proxy-addr "~2.0.4" - qs "6.5.2" - range-parser "~1.2.0" + proxy-addr "~2.0.5" + qs "6.7.0" + range-parser "~1.2.1" safe-buffer "5.1.2" - send "0.16.2" - serve-static "1.13.2" - setprototypeof "1.1.0" - statuses "~1.4.0" - type-is "~1.6.16" + send "0.17.1" + serve-static "1.14.1" + setprototypeof "1.1.1" + statuses "~1.5.0" + type-is "~1.6.18" utils-merge "1.0.1" vary "~1.1.2" @@ -1172,9 +1151,9 @@ extend@~3.0.2: integrity sha512-fjquC59cD7CyW6urNXK0FBufkZcoiGG80wTuPujX590cB5Ttln20E2UB4S/WARVqhXffZl2LNgS+gQdPIIim/g== external-editor@^3.0.3: - version "3.0.3" - resolved "https://registry.yarnpkg.com/external-editor/-/external-editor-3.0.3.tgz#5866db29a97826dbe4bf3afd24070ead9ea43a27" - integrity sha512-bn71H9+qWoOQKyZDo25mOMVpSmXROAsTJVVVYzrrtol3d4y+AsKjf4Iwl2Q+IuT0kFSQ1qo166UuIwqYq7mGnA== + version "3.1.0" + resolved "https://registry.yarnpkg.com/external-editor/-/external-editor-3.1.0.tgz#cb03f740befae03ea4d283caed2741a83f335495" + integrity sha512-hMQ4CX1p1izmuLYyZqLMO/qGNw10wSv9QDCPfzXfyFrOaCSSoRfqE1Kf1s5an66J5JZC62NewG+mK49jOCtQew== dependencies: chardet "^0.7.0" iconv-lite "^0.4.24" @@ -1241,17 +1220,17 @@ file-type@^6.1.0: resolved "https://registry.yarnpkg.com/file-type/-/file-type-6.2.0.tgz#e50cd75d356ffed4e306dc4f5bcf52a79903a919" integrity sha512-YPcTBDV+2Tm0VqjybVd32MHdlEGAtuxS3VAYsumFokDSMG+ROT5wawGlnHDoz7bfMcMDt9hxuXvXwoKUx2fkOg== -finalhandler@1.1.1: - version "1.1.1" - resolved "https://registry.yarnpkg.com/finalhandler/-/finalhandler-1.1.1.tgz#eebf4ed840079c83f4249038c9d703008301b105" - integrity sha512-Y1GUDo39ez4aHAw7MysnUD5JzYX+WaIj8I57kO3aEPT1fFRL4sr7mjei97FgnwhAyyzRYmQZaTHb2+9uZ1dPtg== +finalhandler@~1.1.2: + version "1.1.2" + resolved "https://registry.yarnpkg.com/finalhandler/-/finalhandler-1.1.2.tgz#b7e7d000ffd11938d0fdb053506f6ebabe9f587d" + integrity sha512-aAWcW57uxVNrQZqFXjITpW3sIUQmHGG3qSb9mUah9MgMC4NeWhNOlNjXEYq3HjRAvL6arUviZGGJsBg6z0zsWA== dependencies: debug "2.6.9" encodeurl "~1.0.2" escape-html "~1.0.3" on-finished "~2.3.0" - parseurl "~1.3.2" - statuses "~1.4.0" + parseurl "~1.3.3" + statuses "~1.5.0" unpipe "~1.0.0" find-up@3.0.0, find-up@^3.0.0: @@ -1285,9 +1264,9 @@ flat@^4.1.0: is-buffer "~2.0.3" flatted@^2.0.0: - version "2.0.0" - resolved "https://registry.yarnpkg.com/flatted/-/flatted-2.0.0.tgz#55122b6536ea496b4b44893ee2608141d10d9916" - integrity sha512-R+H8IZclI8AAkSBRQJLVOsxwAoHd6WC40b4QTNWIjzAa6BXOBfQcM587MXDTVPeYaopFNWHUFLx7eNmHDSxMWg== + version "2.0.1" + resolved "https://registry.yarnpkg.com/flatted/-/flatted-2.0.1.tgz#69e57caa8f0eacbc281d2e2cb458d46fdb449e08" + integrity sha512-a1hQMktqW9Nmqr5aktAux3JMNqaucxGcjtjWnZLHX7yyPCmlSV3M54nGYbqT8K+0GhF3NBgmJCc3ma+WOgX8Jg== for-each@^0.3.3: version "0.3.3" @@ -1333,7 +1312,7 @@ fs-extra@^2.0.0, fs-extra@^2.1.2: graceful-fs "^4.1.2" jsonfile "^2.1.0" -fs-extra@^7.0.0: +fs-extra@^7.0.1: version "7.0.1" resolved "https://registry.yarnpkg.com/fs-extra/-/fs-extra-7.0.1.tgz#4f189c44aa123b895f722804f55ea23eadc348e9" integrity sha512-YJDaCJZEnBmcbw13fvdAM9AwNOJwOzrE4pqMqBq5nFiEqXUqHwlK4B+3pUw6JNvfSPtX05xFHtYy/1ni01eGCw== @@ -1357,7 +1336,7 @@ fs.realpath@^1.0.0: resolved "https://registry.yarnpkg.com/fs.realpath/-/fs.realpath-1.0.0.tgz#1504ad2523158caa40db4a2787cb01411994ea4f" integrity sha1-FQStJSMVjKpA20onh8sBQRmU6k8= -fstream@^1.0.12, fstream@^1.0.8: +fstream@1.0.12, fstream@^1.0.12, fstream@^1.0.8: version "1.0.12" resolved "https://registry.yarnpkg.com/fstream/-/fstream-1.0.12.tgz#4e8ba8ee2d48be4f7d0de505455548eae5932045" integrity sha512-WvJ193OHa0GHPEL+AycEJgxvBEwyfRkN1vhjca23OaPVMCaLCXTd5qAu82AjTcgP1UJmytkOKb63Ypde7raDIg== @@ -1419,7 +1398,7 @@ getpass@^0.1.1: dependencies: assert-plus "^1.0.0" -glob@7.1.3, glob@^7.1.2: +glob@7.1.3: version "7.1.3" resolved "https://registry.yarnpkg.com/glob/-/glob-7.1.3.tgz#3960832d3f1574108342dafd3a67b332c0969df1" integrity sha512-vcfuiIxogLV4DlGBHIUOwI0IbrJ8HWPc4MU7HzviGeNho/UJDfi6B5p3sHeWIQ0KGIU0Jpxi5ZHxemQfLkkAwQ== @@ -1431,7 +1410,7 @@ glob@7.1.3, glob@^7.1.2: once "^1.3.0" path-is-absolute "^1.0.0" -glob@^7.1.3: +glob@^7.1.2, glob@^7.1.3: version "7.1.4" resolved "https://registry.yarnpkg.com/glob/-/glob-7.1.4.tgz#aa608a2f6c577ad357e1ae5a5c26d9a8d1969255" integrity sha512-hkLPepehmnKk41pUGm3sYxoFs/umurYfYJCerbXEyFIWcAzvpipAgVkBqqT9RBKMGjnq6kMuyYwha6csxbiM1A== @@ -1457,9 +1436,9 @@ globals@^11.7.0: integrity sha512-WOBp/EEGUiIsJSp7wcv/y6MO+lV9UoncWqxuFfm8eBwzWNgyfBd6Gz+IeKQ9jCmyhoH99g15M3T+QaVHFjizVA== google-protobuf@^3.5.0: - version "3.7.1" - resolved "https://registry.yarnpkg.com/google-protobuf/-/google-protobuf-3.7.1.tgz#9ef0fa3bc9ee416ba3fbe32b21ec6b7626f898e2" - integrity sha512-6fvlUey6cNKtWSEn1bt4CT4wc2EID1fVluHS1dOnqIlxyIu3cBid2BvWE8Rwl6wN+hRTgiAKhfyydAGV/weZYQ== + version "3.9.0" + resolved "https://registry.yarnpkg.com/google-protobuf/-/google-protobuf-3.9.0.tgz#1f33e51e7993ea51e758a82650ad4347273b9bc6" + integrity sha512-/t/7NvL9jAmfXLdqJG7Nv2c5Z2GTdZSKi/T6kI3hpIS4yA6rXqBAMF4Yx39xbICWDgRv+R+Z79n7ZxuvoUQU4w== got@7.1.0, got@^7.1.0: version "7.1.0" @@ -1482,9 +1461,9 @@ got@7.1.0, got@^7.1.0: url-to-options "^1.0.1" graceful-fs@^4.1.10, graceful-fs@^4.1.2, graceful-fs@^4.1.6: - version "4.1.15" - resolved "https://registry.yarnpkg.com/graceful-fs/-/graceful-fs-4.1.15.tgz#ffb703e1066e8a0eeaa4c8b80ba9253eeefbfb00" - integrity sha512-6uHUhOPEBgQ24HM+r6b/QwWfZq+yiFcipKFrOFiBEnWdy5sdzYoi+pJeQaPI5qOLRFqWmAXUPQNsielzdLoecA== + version "4.2.0" + resolved "https://registry.yarnpkg.com/graceful-fs/-/graceful-fs-4.2.0.tgz#8d8fdc73977cb04104721cb53666c1ca64cd328b" + integrity sha512-jpSvDPV4Cq/bgtpndIWbI5hmYxhQGHPC4d4cqBPb4DLniCfhJokdXhwhaDuLBGLQdvvRum/UiX6ECVIPvDXqdg== "graceful-readlink@>= 1.0.0": version "1.0.1" @@ -1581,16 +1560,6 @@ hosted-git-info@^2.1.4: resolved "https://registry.yarnpkg.com/hosted-git-info/-/hosted-git-info-2.7.1.tgz#97f236977bd6e125408930ff6de3eec6281ec047" integrity sha512-7T/BxH19zbcCTa8XkMlbK5lTo1WtgkFi3GvdWEyNuc4Vex7/9Dqbnpsf4JMydcfj9HCg4zUWFTL3Za6lapg5/w== -http-errors@1.6.3, http-errors@~1.6.2, http-errors@~1.6.3: - version "1.6.3" - resolved "https://registry.yarnpkg.com/http-errors/-/http-errors-1.6.3.tgz#8b55680bb4be283a0b5bf4ea2e38580be1d9320d" - integrity sha1-i1VoC7S+KDoLW/TqLjhYC+HZMg0= - dependencies: - depd "~1.1.2" - inherits "2.0.3" - setprototypeof "1.1.0" - statuses ">= 1.4.0 < 2" - http-errors@1.7.2: version "1.7.2" resolved "https://registry.yarnpkg.com/http-errors/-/http-errors-1.7.2.tgz#4f5029cf13239f31036e5b2e55292bcfbcc85c8f" @@ -1602,6 +1571,17 @@ http-errors@1.7.2: statuses ">= 1.5.0 < 2" toidentifier "1.0.0" +http-errors@~1.7.2: + version "1.7.3" + resolved "https://registry.yarnpkg.com/http-errors/-/http-errors-1.7.3.tgz#6c619e4f9c60308c38519498c14fbb10aacebb06" + integrity sha512-ZTTX0MWrsQ2ZAhA1cejAwDLycFsd7I7nVtnkT3Ol0aqodaKW+0CTZDQ1uBv5whptCnc8e8HeRRJxRs0kmm/Qfw== + dependencies: + depd "~1.1.2" + inherits "2.0.4" + setprototypeof "1.1.1" + statuses ">= 1.5.0 < 2" + toidentifier "1.0.0" + http-https@^1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/http-https/-/http-https-1.0.0.tgz#2f908dd5f1db4068c058cd6e6d4ce392c913389b" @@ -1616,13 +1596,6 @@ http-signature@~1.2.0: jsprim "^1.2.2" sshpk "^1.7.0" -iconv-lite@0.4.23: - version "0.4.23" - resolved "https://registry.yarnpkg.com/iconv-lite/-/iconv-lite-0.4.23.tgz#297871f63be507adcfbfca715d0cd0eed84e9a63" - integrity sha512-neyTUVFtahjf0mB3dZT77u+8O0QB89jFdnBkd5P1JgYPbPaia3gXXOVL2fq8VyU2gMMD7SaN7QukTB/pmXYvDA== - dependencies: - safer-buffer ">= 2.1.2 < 3" - iconv-lite@0.4.24, iconv-lite@^0.4.24: version "0.4.24" resolved "https://registry.yarnpkg.com/iconv-lite/-/iconv-lite-0.4.24.tgz#2022b4b25fbddc21d2f524974a474aafe733908b" @@ -1648,9 +1621,9 @@ ignore@^4.0.6: integrity sha512-cyFDKrqc/YdcWFniJhzI42+AzS+gNwmUzOSFcRCQYwySuBBBy/KjuxWLZ/FHEH6Moq1NizMOBWyTcv8O4OZIMg== import-fresh@^3.0.0: - version "3.0.0" - resolved "https://registry.yarnpkg.com/import-fresh/-/import-fresh-3.0.0.tgz#a3d897f420cab0e671236897f75bc14b4885c390" - integrity sha512-pOnA9tfM3Uwics+SaBLCNyZZZbK+4PTu0OPZtLlMIrv17EdBoC15S9Kn8ckJ9TZTyKb3ywNE5y1yeDxxGA7nTQ== + version "3.1.0" + resolved "https://registry.yarnpkg.com/import-fresh/-/import-fresh-3.1.0.tgz#6d33fa1dcef6df930fae003446f33415af905118" + integrity sha512-PpuksHKGt8rXfWEr9m9EHIpgyyaltBy8+eF6GJM0QCAxMgxCfucMF3mjecK2QsJr0amJW7gTqh5/wht0z2UhEQ== dependencies: parent-module "^1.0.0" resolve-from "^4.0.0" @@ -1668,15 +1641,20 @@ inflight@^1.0.4: once "^1.3.0" wrappy "1" -inherits@2, inherits@2.0.3, inherits@^2.0.1, inherits@^2.0.3, inherits@~2.0.0, inherits@~2.0.3: +inherits@2, inherits@2.0.4, inherits@^2.0.1, inherits@^2.0.3, inherits@~2.0.0, inherits@~2.0.3: + version "2.0.4" + resolved "https://registry.yarnpkg.com/inherits/-/inherits-2.0.4.tgz#0fa2c64f932917c3433a0ded55363aae37416b7c" + integrity sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ== + +inherits@2.0.3: version "2.0.3" resolved "https://registry.yarnpkg.com/inherits/-/inherits-2.0.3.tgz#633c2c83e3da42a502f52466022480f4208261de" integrity sha1-Yzwsg+PaQqUC9SRmAiSA9CCCYd4= inquirer@^6.2.2: - version "6.3.1" - resolved "https://registry.yarnpkg.com/inquirer/-/inquirer-6.3.1.tgz#7a413b5e7950811013a3db491c61d1f3b776e8e7" - integrity sha512-MmL624rfkFt4TG9y/Jvmt8vdmOo836U7Y0Hxr2aFk3RelZEGX4Igk0KabWrcaaZaTv9uzglOqWh1Vly+FAWAXA== + version "6.5.0" + resolved "https://registry.yarnpkg.com/inquirer/-/inquirer-6.5.0.tgz#2303317efc9a4ea7ec2e2df6f86569b734accf42" + integrity sha512-scfHejeG/lVZSpvCXpsB4j/wQNPM5JC8kiElOI0OUTwmc1RTpXr4H32/HOlQHcZiYl2z2VElwuCVDRG8vFmbnA== dependencies: ansi-escapes "^3.2.0" chalk "^2.4.2" @@ -1684,7 +1662,7 @@ inquirer@^6.2.2: cli-width "^2.0.0" external-editor "^3.0.3" figures "^2.0.0" - lodash "^4.17.11" + lodash "^4.17.12" mute-stream "0.0.7" run-async "^2.2.0" rxjs "^6.4.0" @@ -1937,10 +1915,10 @@ locate-path@^3.0.0: p-locate "^3.0.0" path-exists "^3.0.0" -lodash@^4.17.10, lodash@^4.17.11: - version "4.17.11" - resolved "https://registry.yarnpkg.com/lodash/-/lodash-4.17.11.tgz#b39ea6229ef607ecd89e2c8df12536891cac9b8d" - integrity sha512-cQKh8igo5QUhZ7lg38DYWAxMvjSAKG0A8wGSVimP07SIUEK2UO+arSRKbRZWtelMtN5V0Hkwh5ryOto/SshYIg== +lodash@^4.17.11, lodash@^4.17.12, lodash@^4.17.14: + version "4.17.14" + resolved "https://registry.yarnpkg.com/lodash/-/lodash-4.17.14.tgz#9ce487ae66c96254fe20b599f21b6816028078ba" + integrity sha512-mmKYbW3GLuJeX+iGP+Y7Gp1AiGHGbXHCOh/jZmrawMmsE7MS4znI3RL2FsjbqOyMayHInjOeykW7PEajUk1/xw== log-symbols@2.2.0: version "2.2.0" @@ -1950,15 +1928,15 @@ log-symbols@2.2.0: chalk "^2.0.1" log4js@^4.1.0: - version "4.1.0" - resolved "https://registry.yarnpkg.com/log4js/-/log4js-4.1.0.tgz#57983c6a443546a8c8607e9cb045d2a117c27644" - integrity sha512-eDa+zZPeVEeK6QGJAePyXM6pg4P3n3TO5rX9iZMVY48JshsTyLJZLIL5HipI1kQ2qLsSyOpUqNND/C5H4WhhiA== + version "4.5.1" + resolved "https://registry.yarnpkg.com/log4js/-/log4js-4.5.1.tgz#e543625e97d9e6f3e6e7c9fc196dd6ab2cae30b5" + integrity sha512-EEEgFcE9bLgaYUKuozyFfytQM2wDHtXn4tAN41pkaxpNjAykv11GVdeI4tHtmPWW4Xrgh9R/2d7XYghDVjbKKw== dependencies: date-format "^2.0.0" debug "^4.1.1" flatted "^2.0.0" - rfdc "^1.1.2" - streamroller "^1.0.4" + rfdc "^1.1.4" + streamroller "^1.0.6" lowercase-keys@^1.0.0: version "1.0.1" @@ -2032,10 +2010,10 @@ mime-types@^2.1.12, mime-types@^2.1.16, mime-types@~2.1.19, mime-types@~2.1.24: dependencies: mime-db "1.40.0" -mime@1.4.1: - version "1.4.1" - resolved "https://registry.yarnpkg.com/mime/-/mime-1.4.1.tgz#121f9ebc49e3766f311a76e1fa1c8003c4b03aa6" - integrity sha512-KI1+qOZu5DcW6wayYHSzR/tXKCDC5Om4s1z2QJjDULzLcmf3DvzS7oluY4HCTrc+9FiKmWUgeNLg7W3uIQvxtQ== +mime@1.6.0: + version "1.6.0" + resolved "https://registry.yarnpkg.com/mime/-/mime-1.6.0.tgz#32cd9e5c64553bd58d19a568af452acff04981b1" + integrity sha512-x0Vn8spI+wuJ1O6S7gnbaQg8Pxh4NNHb7KSINmEWKiPE4RKOplvijn+NkmYmmRgP68mc70j2EbeTFRsrswaQeg== mimic-fn@^1.0.0: version "1.2.0" @@ -2125,9 +2103,9 @@ mocha@^6.1.4: yargs-unparser "1.5.0" mock-fs@^4.1.0: - version "4.9.0" - resolved "https://registry.yarnpkg.com/mock-fs/-/mock-fs-4.9.0.tgz#7fc0c2f82965050b2776f8eb4eb63ca53a92ff86" - integrity sha512-aUj0qIniTNxzGqAC61Bvro7YD37tIBnMw3wpClucUVgNBS7r6YQn/M4wuoH7SGteKz4SvC1OBeDsfpG0MYC+1Q== + version "4.10.1" + resolved "https://registry.yarnpkg.com/mock-fs/-/mock-fs-4.10.1.tgz#50a07a20114a6cdb119f35762f61f46266a1e323" + integrity sha512-w22rOL5ZYu6HbUehB5deurghGM0hS/xBVyHMGKOuQctkk93J9z9VEOhDsiWrXOprVNQpP9uzGKdl8v9mFspKuw== mout@^0.11.0: version "0.11.1" @@ -2139,11 +2117,16 @@ ms@2.0.0: resolved "https://registry.yarnpkg.com/ms/-/ms-2.0.0.tgz#5608aeadfc00be6c2901df5f9861788de0d597c8" integrity sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g= -ms@2.1.1, ms@^2.1.1: +ms@2.1.1: version "2.1.1" resolved "https://registry.yarnpkg.com/ms/-/ms-2.1.1.tgz#30a5864eb3ebb0a66f2ebe6d727af06a09d86e0a" integrity sha512-tgp+dl5cGk28utYktBsrFqA7HKgrhgPsg6Z/EfhWI4gl1Hwq8B/GmY/0oXZ6nF8hDVesS/FpnYaD/kOWhYQvyg== +ms@^2.1.1: + version "2.1.2" + resolved "https://registry.yarnpkg.com/ms/-/ms-2.1.2.tgz#d09d1f357b443f493382a8eb3ccd183872ae6009" + integrity sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w== + mute-stream@0.0.7: version "0.0.7" resolved "https://registry.yarnpkg.com/mute-stream/-/mute-stream-0.0.7.tgz#3075ce93bc21b8fab43e1bc4da7e8115ed1e7bab" @@ -2158,16 +2141,16 @@ mz@^2.6.0: object-assign "^4.0.1" thenify-all "^1.0.0" -nan@2.10.0: - version "2.10.0" - resolved "https://registry.yarnpkg.com/nan/-/nan-2.10.0.tgz#96d0cd610ebd58d4b4de9cc0c6828cda99c7548f" - integrity sha512-bAdJv7fBLhWC+/Bls0Oza+mvTaNQtP+1RyhhhvD95pgUJz6XM5IzgmxOkItJ9tkoCiplvAnXI1tNmmUD/eScyA== - -nan@^2.0.8, nan@^2.3.3: +nan@2.13.2: version "2.13.2" resolved "https://registry.yarnpkg.com/nan/-/nan-2.13.2.tgz#f51dc7ae66ba7d5d55e1e6d4d8092e802c9aefe7" integrity sha512-TghvYc72wlMGMVMluVo9WRJc0mB8KxxF/gZ4YYFy7V2ZQX9l7rgbPg7vjS9mt6U5HXODVFVI2bOduCzwOMv/lw== +nan@^2.0.8, nan@^2.3.3: + version "2.14.0" + resolved "https://registry.yarnpkg.com/nan/-/nan-2.14.0.tgz#7818f722027b2459a86f0295d434d1fc2336c52c" + integrity sha512-INOFj37C7k3AfaNTtX8RhsTw7qRy7eLET14cROi9+5HAVbbHuIWUHEauBv5qT4Av2tWasiTY1Jw6puUNqRJXQg== + nano-json-stream-parser@^0.1.2: version "0.1.2" resolved "https://registry.yarnpkg.com/nano-json-stream-parser/-/nano-json-stream-parser-0.1.2.tgz#0cc8f6d0e2b622b479c40d499c46d64b755c6f5f" @@ -2251,7 +2234,7 @@ object.assign@4.1.0, object.assign@^4.1.0: has-symbols "^1.0.0" object-keys "^1.0.11" -object.entries@^1.0.4: +object.entries@^1.1.0: version "1.1.0" resolved "https://registry.yarnpkg.com/object.entries/-/object.entries-1.1.0.tgz#2024fc6d6ba246aee38bdb0ffd5cfbcf371b7519" integrity sha512-l+H6EQ8qzGRxbkHOd5I/aHRhHDKoQXQ8g0BYt4uSweQU1/J6dZUOyWh9a2Vky35YCKjzmgxOzta2hH6kf9HuXA== @@ -2422,7 +2405,7 @@ parse-json@^2.2.0: dependencies: error-ex "^1.2.0" -parseurl@~1.3.2: +parseurl@~1.3.3: version "1.3.3" resolved "https://registry.yarnpkg.com/parseurl/-/parseurl-1.3.3.tgz#9da19e7bee8d12dff0513ed5b76957793bc2e8d4" integrity sha512-CiyeOxFT/JZyN5m0z9PfXw4SCBJ6Sygz1Dpl0wqjlhDEGGBP1GnsUVEL0p63hoG1fcj3fHynXi9NYO4nWOL+qQ== @@ -2530,9 +2513,9 @@ prepend-http@^1.0.1: integrity sha1-1PRWKwzjaW5BrFLQ4ALlemNdxtw= process-nextick-args@~2.0.0: - version "2.0.0" - resolved "https://registry.yarnpkg.com/process-nextick-args/-/process-nextick-args-2.0.0.tgz#a37d732f4271b4ab1ad070d35508e8290788ffaa" - integrity sha512-MtEC1TqN0EU5nephaJ4rAtThHtC86dNN9qCuEhtshvpVBkAW5ZO7BASN9REnF9eoXGcRub+pFuKEpOHE+HbEMw== + version "2.0.1" + resolved "https://registry.yarnpkg.com/process-nextick-args/-/process-nextick-args-2.0.1.tgz#7820d9b16120cc55ca9ae7792680ae7dba6d7fe2" + integrity sha512-3ouUOpQhtgrbOa17J7+uxOTpITYWaGP7/AhoR3+A+/1e9skrzelGi/dXzEYyvbxubEF6Wn2ypscTKiKJFFn1ag== process@~0.5.1: version "0.5.2" @@ -2544,7 +2527,7 @@ progress@^2.0.0: resolved "https://registry.yarnpkg.com/progress/-/progress-2.0.3.tgz#7e8cf8d8f5b8f239c1bc68beb4eb78567d572ef8" integrity sha512-7PiHtLll5LdnKIMw100I+8xJXR5gW2QwWYkT6iJva0bXitZKa/XMrSbdmg3r2Xnaidz9Qumd0VPaMrZlF9V9sA== -proxy-addr@~2.0.4: +proxy-addr@~2.0.5: version "2.0.5" resolved "https://registry.yarnpkg.com/proxy-addr/-/proxy-addr-2.0.5.tgz#34cbd64a2d81f4b1fd21e76f9f06c8a45299ee34" integrity sha512-t/7RxHXPH6cJtP0pRG6smSr9QJidhB+3kXu0KgXnbGYMgzEnUxRQ4/LDdfOwZEMyIh3/xHb8PX3t+lfL9z+YVQ== @@ -2553,9 +2536,9 @@ proxy-addr@~2.0.4: ipaddr.js "1.9.0" psl@^1.1.24: - version "1.1.31" - resolved "https://registry.yarnpkg.com/psl/-/psl-1.1.31.tgz#e9aa86d0101b5b105cbe93ac6b784cd547276184" - integrity sha512-/6pt4+C+T+wZUieKR620OpzN/LlnNKuWjy1iFLQ/UG35JqHlR/89MP1d96dUfkf6Dne3TuLQzOYEYshJ+Hx8mw== + version "1.2.0" + resolved "https://registry.yarnpkg.com/psl/-/psl-1.2.0.tgz#df12b5b1b3a30f51c329eacbdef98f3a6e136dc6" + integrity sha512-GEn74ZffufCmkDDLNcl3uuyF/aSD6exEyh1v/ZSdAomB82t6G9hzJVRx0jBmLDW+VfZqks3aScmMw9DszwUalA== public-encrypt@^4.0.0: version "4.0.3" @@ -2592,16 +2575,16 @@ punycode@^2.1.0: resolved "https://registry.yarnpkg.com/punycode/-/punycode-2.1.1.tgz#b58b010ac40c22c5657616c8d2c2c02c7bf479ec" integrity sha512-XRsRjdf+j5ml+y/6GKHPZbrF/8p2Yga0JPtdqTIY2Xe5ohJPD9saDJJLPvp9+NSBprVvevdXZybnj2cv8OEd0A== -qs@6.5.2, qs@~6.5.2: - version "6.5.2" - resolved "https://registry.yarnpkg.com/qs/-/qs-6.5.2.tgz#cb3ae806e8740444584ef154ce8ee98d403f3e36" - integrity sha512-N5ZAX4/LxJmF+7wN74pUD6qAh9/wnvdQcjq9TZjevvXzSUo7bfmw91saqMjzGS2xq91/odN2dW/WOl7qQHNDGA== - qs@6.7.0: version "6.7.0" resolved "https://registry.yarnpkg.com/qs/-/qs-6.7.0.tgz#41dc1a015e3d581f1621776be31afb2876a9b1bc" integrity sha512-VCdBRNFTX1fyE7Nb6FYoURo/SPe62QCaAyzJvUjwRaIsc+NePBEniHlvxFmmX56+HZphIGtV0XeCirBtpDrTyQ== +qs@~6.5.2: + version "6.5.2" + resolved "https://registry.yarnpkg.com/qs/-/qs-6.5.2.tgz#cb3ae806e8740444584ef154ce8ee98d403f3e36" + integrity sha512-N5ZAX4/LxJmF+7wN74pUD6qAh9/wnvdQcjq9TZjevvXzSUo7bfmw91saqMjzGS2xq91/odN2dW/WOl7qQHNDGA== + query-string@^5.0.1: version "5.1.1" resolved "https://registry.yarnpkg.com/query-string/-/query-string-5.1.1.tgz#a78c012b71c17e05f2e3fa2319dd330682efb3cb" @@ -2631,20 +2614,10 @@ randomhex@0.1.5: resolved "https://registry.yarnpkg.com/randomhex/-/randomhex-0.1.5.tgz#baceef982329091400f2a2912c6cd02f1094f585" integrity sha1-us7vmCMpCRQA8qKRLGzQLxCU9YU= -range-parser@~1.2.0: - version "1.2.0" - resolved "https://registry.yarnpkg.com/range-parser/-/range-parser-1.2.0.tgz#f49be6b487894ddc40dcc94a322f611092e00d5e" - integrity sha1-9JvmtIeJTdxA3MlKMi9hEJLgDV4= - -raw-body@2.3.3: - version "2.3.3" - resolved "https://registry.yarnpkg.com/raw-body/-/raw-body-2.3.3.tgz#1b324ece6b5706e153855bc1148c65bb7f6ea0c3" - integrity sha512-9esiElv1BrZoI3rCDuOuKCBRbuApGGaDPQfjSflGxdy4oyzqghxu6klEkkVIvBje+FF0BX9coEv8KqW6X/7njw== - dependencies: - bytes "3.0.0" - http-errors "1.6.3" - iconv-lite "0.4.23" - unpipe "1.0.0" +range-parser@~1.2.1: + version "1.2.1" + resolved "https://registry.yarnpkg.com/range-parser/-/range-parser-1.2.1.tgz#3cf37023d199e1c24d1a55b84800c2f3e6468031" + integrity sha512-Hrgsx+orqoygnmhFbKaHE6c296J+HTAQXoxEF6gNupROmmGJRoyzfG3ccAveqCBrwr/2yxQ5BVd/GTl5agOwSg== raw-body@2.4.0: version "2.4.0" @@ -2737,10 +2710,10 @@ resolve-from@^4.0.0: resolved "https://registry.yarnpkg.com/resolve-from/-/resolve-from-4.0.0.tgz#4abcd852ad32dd7baabfe9b40e00a36db5f392e6" integrity sha512-pb/MYmXstAkysRFx8piNI1tGFNQIFA3vkE3Gq4EuA1dF6gHp/+vgZqsCGJapvy8N3Q+4o7FwvquPJcnZ7RYy4g== -resolve@^1.10.0, resolve@^1.5.0: - version "1.10.1" - resolved "https://registry.yarnpkg.com/resolve/-/resolve-1.10.1.tgz#664842ac960795bbe758221cdccda61fb64b5f18" - integrity sha512-KuIe4mf++td/eFb6wkaPbMDnP6kObCaEtIDuHOUED6MNUo4K670KZUHuuvYPZDxNF0WVLw49n06M2m2dXphEzA== +resolve@^1.10.0, resolve@^1.11.0, resolve@^1.5.0: + version "1.11.1" + resolved "https://registry.yarnpkg.com/resolve/-/resolve-1.11.1.tgz#ea10d8110376982fef578df8fc30b9ac30a07a3e" + integrity sha512-vIpgF6wfuJOZI7KKKSP+HmiKggadPQAdsp5HiC1mvqnfp0gF1vdwgBWZIdrVft9pgqoMFQN+R7BSWZiBxx+BBw== dependencies: path-parse "^1.0.6" @@ -2752,10 +2725,10 @@ restore-cursor@^2.0.0: onetime "^2.0.0" signal-exit "^3.0.2" -rfdc@^1.1.2: - version "1.1.2" - resolved "https://registry.yarnpkg.com/rfdc/-/rfdc-1.1.2.tgz#e6e72d74f5dc39de8f538f65e00c36c18018e349" - integrity sha512-92ktAgvZhBzYTIK0Mja9uen5q5J3NRVMoDkJL2VMwq6SXjVCgqvQeVP2XAaUY6HT+XpQYeLSjb3UoitBryKmdA== +rfdc@^1.1.4: + version "1.1.4" + resolved "https://registry.yarnpkg.com/rfdc/-/rfdc-1.1.4.tgz#ba72cc1367a0ccd9cf81a870b3b58bd3ad07f8c2" + integrity sha512-5C9HXdzK8EAqN7JDif30jqsBzavB7wLpaubisuQIGHWf2gUXSpzy6ArX/+Da8RjFpagWsCn+pIgxTMAmKw9Zug== rimraf@2, rimraf@2.6.3: version "2.6.3" @@ -2780,17 +2753,22 @@ run-async@^2.2.0: is-promise "^2.1.0" rxjs@^6.4.0: - version "6.5.1" - resolved "https://registry.yarnpkg.com/rxjs/-/rxjs-6.5.1.tgz#f7a005a9386361921b8524f38f54cbf80e5d08f4" - integrity sha512-y0j31WJc83wPu31vS1VlAFW5JGrnGC+j+TtGAa1fRQphy48+fDYiDmX8tjGloToEsMkxnouOg/1IzXGKkJnZMg== + version "6.5.2" + resolved "https://registry.yarnpkg.com/rxjs/-/rxjs-6.5.2.tgz#2e35ce815cd46d84d02a209fb4e5921e051dbec7" + integrity sha512-HUb7j3kvb7p7eCUHE3FqjoDsC1xfZQ4AHFWfTKSpZ+sAhhz5X1WX0ZuUqWbzB2QhSLp3DoLUG+hMdEDKqWo2Zg== dependencies: tslib "^1.9.0" -safe-buffer@5.1.2, safe-buffer@^5.0.1, safe-buffer@^5.1.0, safe-buffer@^5.1.1, safe-buffer@^5.1.2, safe-buffer@~5.1.0, safe-buffer@~5.1.1: +safe-buffer@5.1.2, safe-buffer@~5.1.0, safe-buffer@~5.1.1: version "5.1.2" resolved "https://registry.yarnpkg.com/safe-buffer/-/safe-buffer-5.1.2.tgz#991ec69d296e0313747d59bdfd2b745c35f8828d" integrity sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g== +safe-buffer@^5.0.1, safe-buffer@^5.1.0, safe-buffer@^5.1.1, safe-buffer@^5.1.2: + version "5.2.0" + resolved "https://registry.yarnpkg.com/safe-buffer/-/safe-buffer-5.2.0.tgz#b74daec49b1148f88c64b68d49b1e815c1f2f519" + integrity sha512-fZEwUGbVl7kouZs1jCdMLdt95hdIv0ZeHg6L7qPeciMZhZ+/gdesW4wgTARkrFWEpspjEATAzUGPG8N2jJiwbg== + "safer-buffer@>= 2.1.2 < 3", safer-buffer@^2.0.2, safer-buffer@^2.1.0, safer-buffer@~2.1.0: version "2.1.2" resolved "https://registry.yarnpkg.com/safer-buffer/-/safer-buffer-2.1.2.tgz#44fa161b0187b9549dd84bb91802f9bd8385cd6a" @@ -2835,10 +2813,10 @@ seek-bzip@^1.0.5: resolved "https://registry.yarnpkg.com/semver/-/semver-5.7.0.tgz#790a7cf6fea5459bac96110b29b60412dc8ff96b" integrity sha512-Ya52jSX2u7QKghxeoFGpLwCtGlt7j0oY9DYb5apt9nPlJ42ID+ulTXESnt/qAQcoSERyZ5sl3LDIOw0nAn/5DA== -send@0.16.2: - version "0.16.2" - resolved "https://registry.yarnpkg.com/send/-/send-0.16.2.tgz#6ecca1e0f8c156d141597559848df64730a6bbc1" - integrity sha512-E64YFPUssFHEFBvpbbjr44NCLtI1AohxQ8ZSiJjQLskAdKuriYEP6VyGEsRDH8ScozGpkaX1BGvhanqCwkcEZw== +send@0.17.1: + version "0.17.1" + resolved "https://registry.yarnpkg.com/send/-/send-0.17.1.tgz#c1d8b059f7900f7466dd4938bdc44e11ddb376c8" + integrity sha512-BsVKsiGcQMFwT8UxypobUKyv7irCNRHk1T0G680vk88yf6LBByGcZJOTJCrTP2xVN6yI+XjPJcNuE3V4fT9sAg== dependencies: debug "2.6.9" depd "~1.1.2" @@ -2847,22 +2825,22 @@ send@0.16.2: escape-html "~1.0.3" etag "~1.8.1" fresh "0.5.2" - http-errors "~1.6.2" - mime "1.4.1" - ms "2.0.0" + http-errors "~1.7.2" + mime "1.6.0" + ms "2.1.1" on-finished "~2.3.0" - range-parser "~1.2.0" - statuses "~1.4.0" + range-parser "~1.2.1" + statuses "~1.5.0" -serve-static@1.13.2: - version "1.13.2" - resolved "https://registry.yarnpkg.com/serve-static/-/serve-static-1.13.2.tgz#095e8472fd5b46237db50ce486a43f4b86c6cec1" - integrity sha512-p/tdJrO4U387R9oMjb1oj7qSMaMfmOyd4j9hOFoxZe2baQszgHcSWjuya/CiT5kgZZKRudHNOA0pYXOl8rQ5nw== +serve-static@1.14.1: + version "1.14.1" + resolved "https://registry.yarnpkg.com/serve-static/-/serve-static-1.14.1.tgz#666e636dc4f010f7ef29970a88a674320898b2f9" + integrity sha512-JMrvUwE54emCYWlTI+hGrGv5I8dEwmco/00EvkzIIsR7MqrHonbD9pO2MOfFnpFntl7ecpZs+3mW+XbQZu9QCg== dependencies: encodeurl "~1.0.2" escape-html "~1.0.3" - parseurl "~1.3.2" - send "0.16.2" + parseurl "~1.3.3" + send "0.17.1" servify@^0.1.12: version "0.1.12" @@ -2890,11 +2868,6 @@ setimmediate@^1.0.5: resolved "https://registry.yarnpkg.com/setimmediate/-/setimmediate-1.0.5.tgz#290cbb232e306942d7d7ea9b83732ab7856f8285" integrity sha1-KQy7Iy4waULX1+qbg3Mqt4VvgoU= -setprototypeof@1.1.0: - version "1.1.0" - resolved "https://registry.yarnpkg.com/setprototypeof/-/setprototypeof-1.1.0.tgz#d0bd85536887b6fe7c0d818cb962d9d91c54e656" - integrity sha512-BvE/TwpZX4FXExxOxZyRGQQv651MSwmWKZGqvmPcRIjDqWub67kTKuIMx43cZZrS/cBBzwBcNDWoFxt2XEFIpQ== - setprototypeof@1.1.1: version "1.1.1" resolved "https://registry.yarnpkg.com/setprototypeof/-/setprototypeof-1.1.1.tgz#7e95acb24aa92f5885e0abef5ba131330d4ae683" @@ -2909,11 +2882,11 @@ sha.js@^2.4.0, sha.js@^2.4.8: safe-buffer "^5.0.1" sha3@^1.2.2: - version "1.2.2" - resolved "https://registry.yarnpkg.com/sha3/-/sha3-1.2.2.tgz#a66c5098de4c25bc88336ec8b4817d005bca7ba9" - integrity sha1-pmxQmN5MJbyIM27ItIF9AFvKe6k= + version "1.2.3" + resolved "https://registry.yarnpkg.com/sha3/-/sha3-1.2.3.tgz#ed5958fa8331df1b1b8529ca9fdf225a340c5418" + integrity sha512-sOWDZi8cDBRkLfWOw18wvJyNblXDHzwMGnRWut8zNNeIeLnmMRO17bjpLc7OzMuj1ASUgx2IyohzUCAl+Kx5vA== dependencies: - nan "2.10.0" + nan "2.13.2" shebang-command@^1.2.0: version "1.2.0" @@ -2977,9 +2950,9 @@ spdx-expression-parse@^3.0.0: spdx-license-ids "^3.0.0" spdx-license-ids@^3.0.0: - version "3.0.4" - resolved "https://registry.yarnpkg.com/spdx-license-ids/-/spdx-license-ids-3.0.4.tgz#75ecd1a88de8c184ef015eafb51b5b48bfd11bb1" - integrity sha512-7j8LYJLeY/Yb6ACbQ7F76qy5jHkp0U6jgBfJsk97bwWlVUnUWsAgpyaCvo17h0/RQGnQ036tVDomiwoI4pDkQA== + version "3.0.5" + resolved "https://registry.yarnpkg.com/spdx-license-ids/-/spdx-license-ids-3.0.5.tgz#3694b5804567a458d3c8045842a6358632f62654" + integrity sha512-J+FWzZoynJEXGphVIS+XEh3kFSjZX/1i9gFBaWQcB+/tmpe2qUsSBABpcxqxnAxFdiUFEgAX1bjYGQvIZmoz9Q== sprintf-js@~1.0.2: version "1.0.3" @@ -3001,26 +2974,21 @@ sshpk@^1.7.0: safer-buffer "^2.0.2" tweetnacl "~0.14.0" -"statuses@>= 1.4.0 < 2", "statuses@>= 1.5.0 < 2": +"statuses@>= 1.5.0 < 2", statuses@~1.5.0: version "1.5.0" resolved "https://registry.yarnpkg.com/statuses/-/statuses-1.5.0.tgz#161c7dac177659fd9811f43771fa99381478628c" integrity sha1-Fhx9rBd2Wf2YEfQ3cfqZOBR4Yow= -statuses@~1.4.0: - version "1.4.0" - resolved "https://registry.yarnpkg.com/statuses/-/statuses-1.4.0.tgz#bb73d446da2796106efcc1b601a253d6c46bd087" - integrity sha512-zhSCtt8v2NDrRlPQpCNtw/heZLtfUDqxBM1udqikb/Hbk52LK4nQSwr10u77iopCW5LsyHpuXS0GnEc48mLeew== - -streamroller@^1.0.4: - version "1.0.4" - resolved "https://registry.yarnpkg.com/streamroller/-/streamroller-1.0.4.tgz#d485c7624796d5e2eb34190c79afcbf006afb5e6" - integrity sha512-Wc2Gm5ygjSX8ZpW9J7Y9FwiSzTlKSvcl0FTTMd3rn7RoxDXpBW+xD9TY5sWL2n0UR61COB0LG1BQvN6nTUQbLQ== +streamroller@^1.0.6: + version "1.0.6" + resolved "https://registry.yarnpkg.com/streamroller/-/streamroller-1.0.6.tgz#8167d8496ed9f19f05ee4b158d9611321b8cacd9" + integrity sha512-3QC47Mhv3/aZNFpDDVO44qQb9gwB9QggMEE0sQmkTAwBVYdBRWISdsywlkfm5II1Q5y/pmrHflti/IgmIzdDBg== dependencies: - async "^2.6.1" + async "^2.6.2" date-format "^2.0.0" - debug "^3.1.0" - fs-extra "^7.0.0" - lodash "^4.17.10" + debug "^3.2.6" + fs-extra "^7.0.1" + lodash "^4.17.14" strict-uri-encode@^1.0.0: version "1.1.0" @@ -3153,9 +3121,9 @@ swarm-js@0.1.37: xhr-request-promise "^0.1.2" table@^5.2.3: - version "5.2.3" - resolved "https://registry.yarnpkg.com/table/-/table-5.2.3.tgz#cde0cc6eb06751c009efab27e8c820ca5b67b7f2" - integrity sha512-N2RsDAMvDLvYwFcwbPyF3VmVSSkuF+G1e+8inhBLtHpvwXGw4QRPEZhihQNeEN0i1up6/f6ObCJXNdlRG3YVyQ== + version "5.4.1" + resolved "https://registry.yarnpkg.com/table/-/table-5.4.1.tgz#0691ae2ebe8259858efb63e550b6d5f9300171e8" + integrity sha512-E6CK1/pZe2N75rGZQotFOdmzWQ1AILtgYbMAbAjvms0S1l5IDB47zG3nCnFGB/w+7nB3vKofbLXCH7HPBo864w== dependencies: ajv "^6.9.1" lodash "^4.17.11" @@ -3250,9 +3218,9 @@ tough-cookie@~2.4.3: punycode "^1.4.1" tslib@^1.9.0: - version "1.9.3" - resolved "https://registry.yarnpkg.com/tslib/-/tslib-1.9.3.tgz#d7e4dd79245d85428c4d7e4822a79917954ca286" - integrity sha512-4krF8scpejhaOgqzBEcGM7yDIEfi0/8+8zDRZhNZZ2kjmHJ4hv3zCbQWxoJGz1iw5U0Jl0nma13xzHXcncMavQ== + version "1.10.0" + resolved "https://registry.yarnpkg.com/tslib/-/tslib-1.10.0.tgz#c3c19f95973fb0a62973fb09d90d961ee43e5c8a" + integrity sha512-qOebF53frne81cf0S9B41ByenJ3/IuH8yJKngAX35CmiZySA0khhkovshKK+jGCaMnVomla7gVlIcc3EvKPbTQ== tunnel-agent@^0.6.0: version "0.6.0" @@ -3278,7 +3246,7 @@ type-detect@^4.0.0, type-detect@^4.0.5: resolved "https://registry.yarnpkg.com/type-detect/-/type-detect-4.0.8.tgz#7646fb5f18871cfbb7749e69bd39a6388eb7450c" integrity sha512-0fr/mIH1dlO+x7TlcMy+bIDqKPsw/70tVyeHW787goQjhmqaZe10uwLujubK9q9Lg6Fiho1KUKDYz0Z7k7g5/g== -type-is@~1.6.16, type-is@~1.6.17: +type-is@~1.6.17, type-is@~1.6.18: version "1.6.18" resolved "https://registry.yarnpkg.com/type-is/-/type-is-1.6.18.tgz#4e552cd05df09467dcbc4ef739de89f2cf37c131" integrity sha512-TkRKr9sUTxEH8MdfuCSP7VizJyzRNMjj2J2do2Jr3Kym598JVdEksuzPQCnlFPW4ky9Q+iA+ma9BGm06XQBy8g== @@ -3726,9 +3694,9 @@ xmlhttprequest@1.8.0: integrity sha1-Z/4HXFwk/vOfnWX197f+dRcZaPw= xtend@^4.0.0: - version "4.0.1" - resolved "https://registry.yarnpkg.com/xtend/-/xtend-4.0.1.tgz#a5c6d532be656e23db820efb943a1f04998d63af" - integrity sha1-pcbVMr5lbiPbgg77lDofBJmNY68= + version "4.0.2" + resolved "https://registry.yarnpkg.com/xtend/-/xtend-4.0.2.tgz#bb72779f5fa465186b1f438f674fa347fdb5db54" + integrity sha512-LKYU1iAXJXUgAXn9URjiu+MWhyUXHsvfp7mcuYm9dSUKK0/CjtrUwFAxD82/mCWbtLsGjFIad0wIsod4zrTAEQ== "y18n@^3.2.1 || ^4.0.0", y18n@^4.0.0: version "4.0.0" @@ -3740,7 +3708,7 @@ yaeti@^0.0.6: resolved "https://registry.yarnpkg.com/yaeti/-/yaeti-0.0.6.tgz#f26f484d72684cf42bedfb76970aa1608fbf9577" integrity sha1-8m9ITXJoTPQr7ft2lwqhYI+/lXc= -yargs-parser@13.0.0, yargs-parser@^13.0.0: +yargs-parser@13.0.0: version "13.0.0" resolved "https://registry.yarnpkg.com/yargs-parser/-/yargs-parser-13.0.0.tgz#3fc44f3e76a8bdb1cc3602e860108602e5ccde8b" integrity sha512-w2LXjoL8oRdRQN+hOyppuXs+V/fVAYtpcrRxZuF7Kt/Oc+Jr2uAcVntaUTNT6w5ihoWfFDpNY8CPx1QskxZ/pw== @@ -3756,6 +3724,14 @@ yargs-parser@^11.1.1: camelcase "^5.0.0" decamelize "^1.2.0" +yargs-parser@^13.0.0: + version "13.1.1" + resolved "https://registry.yarnpkg.com/yargs-parser/-/yargs-parser-13.1.1.tgz#d26058532aa06d365fe091f6a1fc06b2f7e5eca0" + integrity sha512-oVAVsHz6uFrg3XQheFII8ESO2ssAf9luWuAd6Wexsu4F3OtIW0o8IribPXYrD4WC24LWtPrJlGy87y5udK+dxQ== + dependencies: + camelcase "^5.0.0" + decamelize "^1.2.0" + yargs-unparser@1.5.0: version "1.5.0" resolved "https://registry.yarnpkg.com/yargs-unparser/-/yargs-unparser-1.5.0.tgz#f2bb2a7e83cbc87bb95c8e572828a06c9add6e0d" diff --git a/scripts/create_cita_config.py b/scripts/create_cita_config.py index 5f787473c..1dd034975 100755 --- a/scripts/create_cita_config.py +++ b/scripts/create_cita_config.py @@ -182,14 +182,6 @@ def template_create_from_arguments(self, args, contracts_dir_src, need_directory(self.contracts_docs_dir) shutil.copytree(configs_dir_src, self.configs_dir, False) - - executor_config = os.path.join(self.configs_dir, 'executor.toml') - with open(executor_config, 'rt') as stream: - executor_data = toml.load(stream) - executor_data['grpc_port'] = args.grpc_port - with open(executor_config, 'wt') as stream: - toml.dump(executor_data, stream) - if args.stdout: forever_config = os.path.join(self.configs_dir, 'forever.toml') with open(forever_config, 'rt') as stream: @@ -264,14 +256,6 @@ def append_node(self, node): node_dir = os.path.join(self.output_root, '{}'.format(node_id)) shutil.copytree(self.configs_dir, node_dir, False) - - executor_config = os.path.join(node_dir, 'executor.toml') - with open(executor_config, 'rt') as stream: - executor_data = toml.load(stream) - executor_data['grpc_port'] += node_id - with open(executor_config, 'wt') as stream: - toml.dump(executor_data, stream) - jsonrpc_config = os.path.join(node_dir, 'jsonrpc.toml') with open(jsonrpc_config, 'rt') as stream: jsonrpc_data = toml.load(stream) @@ -404,8 +388,6 @@ def parse_arguments(): pcreate.add_argument('--resource_dir', help='Chain resource directory.') # Modify ports - pcreate.add_argument( - '--grpc_port', type=int, default=5000, help='grpc port for this chain') pcreate.add_argument( '--jsonrpc_port', type=int, diff --git a/scripts/replace_default_feature.sh b/scripts/replace_default_feature.sh index 00b9dc7c4..521f83768 100755 --- a/scripts/replace_default_feature.sh +++ b/scripts/replace_default_feature.sh @@ -10,13 +10,16 @@ function replace_default_feature () { return fi local before_feature='[ \t]*default[ \t]*=[ \t]*\[.*\"' + local before_feature2='[ \t]*features[ \t]*=[ \t]*\[.*\"' + local all_feature='[ \t]*\(features\|default\)[ \t]*=[ \t]*\[.*\"' local after_feature='\".*' find "${workspacedir}" -mindepth 2 -name "Cargo.toml" -print0 \ - | xargs -0 grep -l "^${before_feature}${old_feature}${after_feature}" \ + | xargs -0 grep -l "^${all_feature}${old_feature}${after_feature}" \ | while read -r cargotoml; do if [ -f "${cargotoml}" ]; then echo "[Info ] Replace [${old_feature}] by [${new_feature}] for [${cargotoml}] ..." sed -i "s/\(${before_feature}\)${old_feature}\(${after_feature}\)\$/\1${new_feature}\2/" "${cargotoml}" + sed -i "s/\(${before_feature2}\)${old_feature}\(${after_feature}\)\$/\1${new_feature}\2/" "${cargotoml}" else echo "[Error] [${cargotoml}] is not a file." fi diff --git a/scripts/txtool/txtool/log.py b/scripts/txtool/txtool/log.py index 2bb0c6d99..a1e9624d2 100644 --- a/scripts/txtool/txtool/log.py +++ b/scripts/txtool/txtool/log.py @@ -49,7 +49,7 @@ def getMessage(self): replaceLogRecord() with open('config/logging.yml', 'r') as f_conf: - dict_conf = yaml.load(f_conf) + dict_conf = yaml.load(f_conf, Loader=yaml.FullLoader) logging.config.dictConfig(dict_conf) diff --git a/scripts/txtool/txtool/make_tx.py b/scripts/txtool/txtool/make_tx.py index a79357d5f..6ea478b5d 100644 --- a/scripts/txtool/txtool/make_tx.py +++ b/scripts/txtool/txtool/make_tx.py @@ -82,7 +82,7 @@ def get_chainid(): def get_chainid_v1(): params = ['latest'] - chainid = 0 + chainid = 1 try: url = endpoint() @@ -91,11 +91,11 @@ def get_chainid_v1(): chainid = response['chainIdV1'] logger.debug(response) except: - chainid = "0x0" + chainid = "0x1" # padding to 32 bytes chainid = int(chainid, 16) - logger.debug("final chainId is {}".format(chainid)) + logger.info("final chainId is {}".format(chainid)) return chainid @@ -137,11 +137,13 @@ def _blake2b_ed25519_deploy_data(current_height, tx.version = version if version == 0: chainid = get_chainid() - logger.debug("chainid is {}".format(chainid)) + logger.info("version is {}".format(version)) + logger.info("chainid is {}".format(chainid)) tx.chain_id = chainid elif version < 3: chainid = get_chainid_v1() - logger.debug("chainid_v1 is {}".format(chainid)) + logger.info("version is {}".format(version)) + logger.info("chainid_v1 is {}".format(chainid)) tx.chain_id_v1 = chainid.to_bytes(32, byteorder='big') else: logger.error("unexpected version {}".format(version)) @@ -200,11 +202,11 @@ def _sha3_secp256k1_deploy_data(current_height, tx.version = version if version == 0: chainid = get_chainid() - logger.debug("chainid is {}".format(chainid)) + logger.info("version-{}, chainid-{}".format(version, chainid)) tx.chain_id = chainid elif version < 3: chainid = get_chainid_v1() - logger.debug("chainid_v1 is {}".format(chainid)) + logger.info("version-{}, chainid_v1-{}".format(version, chainid)) tx.chain_id_v1 = chainid.to_bytes(32, byteorder='big') else: logger.error("unexpected version {}".format(version)) diff --git a/scripts/txtool/txtool/proto b/scripts/txtool/txtool/proto index b1409605b..424601382 160000 --- a/scripts/txtool/txtool/proto +++ b/scripts/txtool/txtool/proto @@ -1 +1 @@ -Subproject commit b1409605bd4f7cf9b857d43fcad1b44b435df3a6 +Subproject commit 424601382c096fba26cdf2d0acfa4532794eca45 diff --git a/tests/box-executor/Cargo.toml b/tests/box-executor/Cargo.toml index 87759d52f..b60ed9170 100644 --- a/tests/box-executor/Cargo.toml +++ b/tests/box-executor/Cargo.toml @@ -2,6 +2,7 @@ name = "box-executor" version = "0.1.0" authors = ["Cryptape Technologies "] +license = "Apache-2.0" edition = "2018" [dependencies] diff --git a/tests/box-executor/src/config.rs b/tests/box-executor/src/config.rs index ffec35aeb..9abbb2254 100644 --- a/tests/box-executor/src/config.rs +++ b/tests/box-executor/src/config.rs @@ -1,3 +1,17 @@ +// Copyright Cryptape Technologies LLC. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + extern crate cita_crypto as crypto; use crate::crypto::PrivKey; diff --git a/tests/box-executor/src/generate_block.rs b/tests/box-executor/src/generate_block.rs index 1974737e0..76079a003 100644 --- a/tests/box-executor/src/generate_block.rs +++ b/tests/box-executor/src/generate_block.rs @@ -1,19 +1,16 @@ -// CITA -// Copyright 2016-2017 Cryptape Technologies LLC. - -// This program is free software: you can redistribute it -// and/or modify it under the terms of the GNU 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 General Public License for more details. - -// You should have received a copy of the GNU General Public License -// along with this program. If not, see . +// Copyright Cryptape Technologies LLC. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. use crate::crypto::{CreateKey, KeyPair, PrivKey, Sign, Signature}; use bincode::{serialize, Infinite}; diff --git a/tests/box-executor/src/main.rs b/tests/box-executor/src/main.rs index 1366471d0..d3b28d1e2 100644 --- a/tests/box-executor/src/main.rs +++ b/tests/box-executor/src/main.rs @@ -1,19 +1,16 @@ -// CITA -// Copyright 2016-2019 Cryptape Technologies LLC. - -// This program is free software: you can redistribute it -// and/or modify it under the terms of the GNU 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 General Public License for more details. - -// You should have received a copy of the GNU General Public License -// along with this program. If not, see . +// Copyright Cryptape Technologies LLC. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. extern crate cita_crypto as crypto; #[macro_use] diff --git a/tests/box-executor/src/runner.rs b/tests/box-executor/src/runner.rs index 4ae599818..1190771d8 100644 --- a/tests/box-executor/src/runner.rs +++ b/tests/box-executor/src/runner.rs @@ -1,3 +1,17 @@ +// Copyright Cryptape Technologies LLC. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + extern crate cita_crypto as crypto; extern crate cita_logger as logger; diff --git a/tests/chain-executor-mock/Cargo.toml b/tests/chain-executor-mock/Cargo.toml index 97b76469c..a255b0dc7 100644 --- a/tests/chain-executor-mock/Cargo.toml +++ b/tests/chain-executor-mock/Cargo.toml @@ -2,6 +2,7 @@ name = "chain-executor-mock" version = "0.1.0" authors = ["Cryptape Technologies "] +license = "Apache-2.0" edition = "2018" [dependencies] diff --git a/tests/chain-executor-mock/src/generate_block.rs b/tests/chain-executor-mock/src/generate_block.rs index d1e128d93..55c13fe7f 100644 --- a/tests/chain-executor-mock/src/generate_block.rs +++ b/tests/chain-executor-mock/src/generate_block.rs @@ -1,19 +1,16 @@ -// CITA -// Copyright 2016-2019 Cryptape Technologies LLC. - -// This program is free software: you can redistribute it -// and/or modify it under the terms of the GNU 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 General Public License for more details. - -// You should have received a copy of the GNU General Public License -// along with this program. If not, see . +// Copyrighttape Technologies LLC. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. use crate::crypto::{CreateKey, KeyPair, PrivKey, Sign, Signature}; use bincode::{serialize, Infinite}; diff --git a/tests/chain-executor-mock/src/main.rs b/tests/chain-executor-mock/src/main.rs index 3ee46592e..2b006b0d7 100644 --- a/tests/chain-executor-mock/src/main.rs +++ b/tests/chain-executor-mock/src/main.rs @@ -1,19 +1,16 @@ -// CITA -// Copyright 2016-2019 Cryptape Technologies LLC. - -// This program is free software: you can redistribute it -// and/or modify it under the terms of the GNU 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 General Public License for more details. - -// You should have received a copy of the GNU General Public License -// along with this program. If not, see . +// Copyright Cryptape Technologies LLC. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. extern crate cita_crypto as crypto; #[macro_use] @@ -111,9 +108,8 @@ fn main() { return; } } - let mut repeat = 0u8; - let mut _current_height = 0u8; + let mut repeat = 0u8; loop { let (key, body) = rx_sub.recv().unwrap(); info!("received: key={}", key); @@ -125,7 +121,8 @@ fn main() { // Remove previous block if mock_blocks.remove(&rich_status.height).is_some() { - _current_height = rich_status.height as u8; + let current_height = rich_status.height as u8; + info!("current height-{:?}", current_height); repeat = 0; } else if repeat < u8::MAX { repeat += 1; @@ -149,9 +146,10 @@ fn main() { &privkey, ); } else { - warn!("No data for this block height = {:?}", height); + warn!("no data for this block height = {:?}", height); }; if mock_blocks.is_empty() { + warn!("break for empty..."); break; } } diff --git a/tests/chain-performance-by-mq/Cargo.toml b/tests/chain-performance-by-mq/Cargo.toml index 10e4baaae..6aa9f88c8 100644 --- a/tests/chain-performance-by-mq/Cargo.toml +++ b/tests/chain-performance-by-mq/Cargo.toml @@ -2,6 +2,7 @@ name = "chain-performance-by-mq" version = "0.1.0" authors = ["Cryptape Technologies "] +license = "Apache-2.0" edition = "2018" [dependencies] diff --git a/tests/chain-performance-by-mq/src/generate_block.rs b/tests/chain-performance-by-mq/src/generate_block.rs index 3a6f0519f..7f17c7f2d 100644 --- a/tests/chain-performance-by-mq/src/generate_block.rs +++ b/tests/chain-performance-by-mq/src/generate_block.rs @@ -1,19 +1,16 @@ -// CITA -// Copyright 2016-2017 Cryptape Technologies LLC. - -// This program is free software: you can redistribute it -// and/or modify it under the terms of the GNU 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 General Public License for more details. - -// You should have received a copy of the GNU General Public License -// along with this program. If not, see . +// CopyrightTechnologies LLC. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. use crate::crypto::*; use bincode::{serialize, Infinite}; diff --git a/tests/chain-performance-by-mq/src/main.rs b/tests/chain-performance-by-mq/src/main.rs index e851666a0..6bbb5afce 100644 --- a/tests/chain-performance-by-mq/src/main.rs +++ b/tests/chain-performance-by-mq/src/main.rs @@ -1,19 +1,16 @@ -// CITA -// Copyright 2016-2019 Cryptape Technologies LLC. - -// This program is free software: you can redistribute it -// and/or modify it under the terms of the GNU 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 General Public License for more details. - -// You should have received a copy of the GNU General Public License -// along with this program. If not, see . +// Copyright Cryptape Technologies LLC. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. extern crate cita_crypto as crypto; #[macro_use] diff --git a/tests/consensus-mock/Cargo.toml b/tests/consensus-mock/Cargo.toml index 8e57fad0d..9ef80d7a1 100644 --- a/tests/consensus-mock/Cargo.toml +++ b/tests/consensus-mock/Cargo.toml @@ -2,6 +2,7 @@ name = "consensus-mock" version = "0.1.0" authors = ["Cryptape Technologies "] +license = "Apache-2.0" edition = "2018" [dependencies] diff --git a/tests/consensus-mock/src/main.rs b/tests/consensus-mock/src/main.rs index 93e3e9a11..4031f6ed1 100644 --- a/tests/consensus-mock/src/main.rs +++ b/tests/consensus-mock/src/main.rs @@ -1,19 +1,16 @@ -// CITA -// Copyright 2016-2019 Cryptape Technologies LLC. - -// This program is free software: you can redistribute it -// and/or modify it under the terms of the GNU 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 General Public License for more details. - -// You should have received a copy of the GNU General Public License -// along with this program. If not, see . +// Copyright Cryptape Technologies LLC. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. extern crate cita_crypto as crypto; #[macro_use] diff --git a/tests/contracts b/tests/contracts index 3ed3e5ede..775dc115c 160000 --- a/tests/contracts +++ b/tests/contracts @@ -1 +1 @@ -Subproject commit 3ed3e5ede13bba04bc8c91853584bafd2b230b02 +Subproject commit 775dc115cf372fc9562861cbb5e87ff281a2dbe7 diff --git a/tests/integrate_test/cita_charge_mode.sh b/tests/integrate_test/cita_charge_mode.sh index 804f15411..748d13b95 100755 --- a/tests/integrate_test/cita_charge_mode.sh +++ b/tests/integrate_test/cita_charge_mode.sh @@ -30,13 +30,6 @@ test_charge_mode() { cd ../../.. } -test_fee_back() { - local version=$1 - cd ./scripts/txtool/txtool - python3 "${SOURCE_DIR}"/tests/integrate_test/test_fee_back.py --version="$version" - cd ../../.. -} - update_version() { local version=$1 cd ./scripts/txtool/txtool @@ -56,7 +49,6 @@ main() { --contract_arguments "SysConfig.checkFeeBackPlatform=true" \ --contract_arguments "SysConfig.economicalModel=1" \ --contract_arguments "VersionManager.version=0" \ - --contract_arguments "PriceManager.quotaPrice=1000000" \ --contract_arguments "SysConfig.chainOwner=0x36a60d575b0dee0423abb6a57dbc6ca60bf47545" echo "DONE" @@ -70,29 +62,21 @@ main() { exit 1) echo "${timeout}s DONE" - echo -n "4) Run fee back tests ... " - test_fee_back 0 - echo "DONE" - - echo -n "5) Run charge mode tests in v0 ... " + echo -n "4) Run charge mode tests in v0 ... " test_charge_mode 0 echo "DONE" - echo -n "6) Update to chainIDV1 ... " + echo -n "5) Update to chainIDV1 ... " update_version 0 echo "DONE" - echo -n "7) check alive ... " + echo -n "6) check alive ... " timeout=$(check_height_growth_normal 0 60) || (echo "FAILED" echo "failed to check_height_growth 0: ${timeout}" exit 1) echo "${timeout}s DONE" - echo -n "8) Run fee back tests in v1 ... " - test_fee_back 1 - echo "DONE" - - echo -n "9) Run charge mode tests in v1 ... " + echo -n "7) Run charge mode tests in v1 ... " test_charge_mode 1 echo "DONE" } diff --git a/tests/integrate_test/cita_crosschain.sh b/tests/integrate_test/cita_crosschain.sh index 0bfd1a8b2..63177dc04 100755 --- a/tests/integrate_test/cita_crosschain.sh +++ b/tests/integrate_test/cita_crosschain.sh @@ -494,7 +494,7 @@ function main () { ./scripts/create_cita_config.py create --chain_name mainchain \ --super_admin "0x4b5ae4567ad5d9fb92bc9afd6a657e6fa13a2523" \ --nodes "127.0.0.1:14000,127.0.0.1:14001,127.0.0.1:14002,127.0.0.1:14003" \ - --jsonrpc_port 11337 --ws_port 14337 --grpc_port 15000 \ + --jsonrpc_port 11337 --ws_port 14337 \ --contract_arguments "SysConfig.chainId=${main_chain_id}" start_chain main 4 @@ -511,7 +511,7 @@ function main () { --super_admin "0x4b5ae4567ad5d9fb92bc9afd6a657e6fa13a2523" \ --nodes "127.0.0.1:24000,127.0.0.1:24001,127.0.0.1:24002,127.0.0.1:24003" \ --authorities "${side_auths}" \ - --jsonrpc_port 21337 --ws_port 24337 --grpc_port 25000 \ + --jsonrpc_port 21337 --ws_port 24337 \ --contract_arguments "SysConfig.chainId=${side_chain_id}" \ "ChainManager.parentChainId=${main_chain_id}" \ "ChainManager.parentChainAuthorities=${main_auths}" diff --git a/tests/integrate_test/cita_features_test.sh b/tests/integrate_test/cita_features_test.sh new file mode 100755 index 000000000..69281b7c9 --- /dev/null +++ b/tests/integrate_test/cita_features_test.sh @@ -0,0 +1,60 @@ +#!/bin/bash +set -e + +if [[ $(uname) == 'Darwin' ]] +then + SOURCE_DIR=$(realpath "$(dirname "$0")"/../..) +else + SOURCE_DIR=$(readlink -f "$(dirname "$0")"/../..) +fi +BINARY_DIR=${SOURCE_DIR}/target/install + +test_fee_back() { + local version=$1 + cd ./scripts/txtool/txtool + python3 "${SOURCE_DIR}"/tests/integrate_test/test_fee_back.py --version="$version" + cd ../../.. +} + +test_perm_denied() { + local version=$1 + cd ./scripts/txtool/txtool + python3 "${SOURCE_DIR}"/tests/integrate_test/test_perm_denied.py --version="$version" + cd ../../.. +} + +main() { + echo -n "0) prepare ... " + # shellcheck source=/dev/null + . ${SOURCE_DIR}/tests/integrate_test/util.sh + cd "${BINARY_DIR}" + echo "DONE" + + echo -n "1) generate config ... " + create_config \ + --contract_arguments "SysConfig.checkFeeBackPlatform=true" \ + --contract_arguments "SysConfig.checkCreateContractPermission=true" \ + --contract_arguments "SysConfig.economicalModel=1" \ + --contract_arguments "SysConfig.chainOwner=0x36a60d575b0dee0423abb6a57dbc6ca60bf47545" + echo "DONE" + + echo -n "2) start nodes ... " + start_nodes + echo "DONE" + + echo -n "3) check alive ... " + timeout=$(check_height_growth_normal 0 60) || (echo "FAILED" + echo "failed to check_height_growth 0: ${timeout}" + exit 1) + echo "${timeout}s DONE" + + echo -n "4) Run fee back tests ... " + test_fee_back 2 + echo "DONE" + + echo -n "5) Check permission denied ... " + test_perm_denied 2 + echo "Done" +} + +main "$@" diff --git a/tests/integrate_test/cita_jsonrpc_schema_mock.sh b/tests/integrate_test/cita_jsonrpc_schema_mock.sh index 05e8e47b4..cf9b10996 100755 --- a/tests/integrate_test/cita_jsonrpc_schema_mock.sh +++ b/tests/integrate_test/cita_jsonrpc_schema_mock.sh @@ -1,6 +1,6 @@ #!/usr/bin/env bash -set -e +# set -e ECONOMICAL_MODEL="0" if [[ -n "$1" ]] && [ "$1" = "charge" ]; then @@ -37,7 +37,7 @@ main() { echo -n "2) just start node0 ... " bin/cita bebop setup "$CHAIN_NAME"/0 > /dev/null - bin/cita bebop start "$CHAIN_NAME"/0 + bin/cita bebop start "$CHAIN_NAME"/0 trace echo "DONE" echo -n "3) generate mock data ... " diff --git a/tests/integrate_test/test_charge_mode.py b/tests/integrate_test/test_charge_mode.py index 6c2991d22..1b66fdae7 100644 --- a/tests/integrate_test/test_charge_mode.py +++ b/tests/integrate_test/test_charge_mode.py @@ -3,81 +3,18 @@ Test cases of transfer and check balances in charge economical mode. """ -import functools -import subprocess import argparse import time import binascii - import sha3 + from ecdsa import SigningKey, SECP256k1 from jsonrpcclient.http_client import HTTPClient +from txtool_utils import get_receipt, rpc_request, get_balance, send_tx -LATEST_VERSION = 1 DEFAULT_QUOTA_PRICE = 1000000 -def send_tx(privkey, - to_addr, - value=0, - quota=30000, - code="", - version=LATEST_VERSION): - """ - Send a transfer transaction to a node - - python3 make_tx.py \ - --value 20000 \ - --quota 100000\ - --code "" \ - --privkey 101c286e965ddf8176dd6c0793e9ad5f3d745105fab744eea6ffdae6a98d0553 \ - --to 0xc94bcce78b4e618c6a259d4eb8e7bf45e145f0d0 \ - --no-newcrypto - - python3 send_tx.py - - """ - kwargs = { - '--privkey': privkey, - '--to': to_addr, - '--code': code, - '--value': str(value), - '--quota': str(quota), - '--version': str(version), - } - args = functools.reduce( - lambda lst, kv: lst + list(kv), - kwargs.items(), - [], - ) - print(['python3', 'make_tx.py', *args, '--no-newcrypto']) - subprocess.call(['python3', 'make_tx.py', *args, '--no-newcrypto']) - subprocess.call(['python3', 'send_tx.py']) - with open('../output/transaction/hash') as fobj: - return fobj.read().strip() - - -def rpc_request(method, params): - """ Send a jsonrpc request to default url. """ - client = HTTPClient('http://127.0.0.1:1337') - return client.request(method, params) - - -def get_balance(addr): - """ Get the balance of an address """ - return int(rpc_request('getBalance', [addr, 'pending']), 16) - - -def get_receipt(tx_hash, retry=8): - """ Get receipt of a transaction """ - while retry > 0: - receipt = rpc_request('getTransactionReceipt', [tx_hash]) - if receipt is not None: - return receipt - time.sleep(4) - retry -= 1 - - def test_transfer(sender_privkey, receiver_addr, value, @@ -90,7 +27,12 @@ def test_transfer(sender_privkey, assert sender_balance_old > 0, \ 'Sender balance not enough: address={}'.format(sender_addr) - tx_hash = send_tx(sender_privkey, receiver_addr, value, version=version) + tx_hash = send_tx( + sender_privkey, + to=receiver_addr, + value=value, + quota=29000, + version=version) receipt = get_receipt(tx_hash) assert receipt and receipt['errorMessage'] is None, \ 'Send transaction failed: receipt={}'.format(receipt) @@ -164,15 +106,16 @@ def main(): version = args.version alice_privkey = '0xb5d6f7a1bf4493af95afc96f5bf116a3236038fae25e0287ac847623d4e183e6' - alice_address = key_address(alice_privkey) + alice_address = key_address( + alice_privkey) # 0xc94bcce78b4e618c6a259d4eb8e7bf45e145f0d0 + alice_old_balance = get_balance(alice_address) print('[Alice.address]: {}'.format(alice_address)) bob_privkey = '0x9b9464a30a57702fbfc29cc4afbc676d3dcad1811db3a36ea79b0bde94e10dd9' - bob_address = key_address(bob_privkey) + bob_address = key_address( + bob_privkey) # 0x32c7e8b442f2f67816baef4b2d51c34039aadfcc print('[Bob.address]: {}'.format(bob_address)) - alice_old_balance = get_balance(alice_address) - # Send 10 * 10000 * DEFAULT_QUOTA_PRICE from miner to alice test_transfer( miner_privkey, @@ -192,7 +135,7 @@ def main(): 'Bob({}) should receive 30000 * {} now'.format(bob_address, DEFAULT_QUOTA_PRICE) # Bob send an invalid transaction to chain (Error=NotEnoughCash) - tx_hash = send_tx(bob_privkey, "", quota=29000, code="", version=version) + tx_hash = send_tx(bob_privkey, quota=29000, version=version) # Wait the transaction receipt then check the balance get_receipt(tx_hash) bob_new_balance2 = get_balance(bob_address) diff --git a/tests/integrate_test/test_fee_back.py b/tests/integrate_test/test_fee_back.py index 743b0ac41..d57ca2cef 100644 --- a/tests/integrate_test/test_fee_back.py +++ b/tests/integrate_test/test_fee_back.py @@ -3,65 +3,12 @@ Test case of fee back to operator in charge economical mode. """ -import functools -import subprocess -import time import argparse -from jsonrpcclient.http_client import HTTPClient +from txtool_utils import get_receipt, rpc_request, send_tx, get_balance -LATEST_VERSION = 1 DEFAULT_QUOTA_PRICE = 1000000 -def send_tx(privkey, code="", version=LATEST_VERSION): - """ - Send a transaction - - python3 make_tx.py - --privkey "5f0258a4778057a8a7d97809bd209055b2fbafa654ce7d31ec7191066b9225e6" - --code "" - - python3 send_tx.py - """ - - kwargs = { - '--privkey': privkey, - '--code': code, - '--version': str(version), - } - args = functools.reduce( - lambda lst, kv: lst + list(kv), - kwargs.items(), - [], - ) - print(['python3', 'make_tx.py', *args]) - subprocess.call(['python3', 'make_tx.py', *args]) - subprocess.call(['python3', 'send_tx.py']) - with open('../output/transaction/hash') as fobj: - return fobj.read().strip() - - -def get_balance(addr): - """ Get the balance of an address """ - return int(rpc_request('getBalance', [addr, 'pending']), 16) - - -def get_receipt(tx_hash, retry=8): - """ Get receipt of a transaction """ - while retry > 0: - receipt = rpc_request('getTransactionReceipt', [tx_hash]) - if receipt is not None: - return receipt - time.sleep(4) - retry -= 1 - - -def rpc_request(method, params): - """ Send a jsonrpc request to default url. """ - client = HTTPClient('http://127.0.0.1:1337') - return client.request(method, params) - - def main(): """ Run the test. """ admin_privkey = '0x5f0258a4778057a8a7d97809bd209055b2fbafa654ce7d31ec7191066b9225e6' @@ -72,7 +19,7 @@ def main(): version = opts.version operator_balance_old = get_balance(operator_address) - tx_hash = send_tx(admin_privkey, code, version) + tx_hash = send_tx(admin_privkey, code=code, version=version) receipt = get_receipt(tx_hash) operator_balance_new = get_balance(operator_address) print('[operator.address]:{}'.format(operator_address)) @@ -87,15 +34,9 @@ def main(): def parse_arguments(): parser = argparse.ArgumentParser() - parser.add_argument( - "--version", - help="Tansaction version.", - default=LATEST_VERSION, - type=int) - - opts = parser.parse_args() + parser.add_argument("--version", help="Tansaction version.", type=int) - return opts + return parser.parse_args() if __name__ == '__main__': diff --git a/tests/integrate_test/test_perm_denied.py b/tests/integrate_test/test_perm_denied.py new file mode 100644 index 000000000..cfb42abab --- /dev/null +++ b/tests/integrate_test/test_perm_denied.py @@ -0,0 +1,33 @@ +#!/usr/bin/env python3 +""" +Test case of checkCreateContractPermission in sysconfig +""" + +import argparse +from txtool_utils import get_receipt, rpc_request, send_tx + + +def main(): + user_privkey = '0xb3964278651fd8a24fa00aeef2a831fb7574f25a2be2ee9e951d0226ee01dd5b' + code = '0x608060405234801561001057600080fd5b5060df8061001f6000396000f3006080604052600436106049576000357c0100000000000000000000000000000000000000000000000000000000900463ffffffff16806360fe47b114604e5780636d4ce63c146078575b600080fd5b348015605957600080fd5b5060766004803603810190808035906020019092919050505060a0565b005b348015608357600080fd5b50608a60aa565b6040518082815260200191505060405180910390f35b8060008190555050565b600080549050905600a165627a7a723058205aed214856a5c433292a354261c9eb88eed1396c83dabbe105bde142e49838ac0029' + + opts = parse_arguments() + version = opts.version + + # send create contract tx + tx_hash = send_tx(user_privkey, code=code, version=version) + # get_receipt + receipt = get_receipt(tx_hash) + assert receipt['errorMessage'] == 'No contract permission.' + print(">>> Test create contract permission denied successfully!") + + +def parse_arguments(): + parser = argparse.ArgumentParser() + parser.add_argument("--version", help="Tansaction version.", type=int) + + return parser.parse_args() + + +if __name__ == '__main__': + main() diff --git a/tests/integrate_test/txtool_utils.py b/tests/integrate_test/txtool_utils.py new file mode 100644 index 000000000..2458b7935 --- /dev/null +++ b/tests/integrate_test/txtool_utils.py @@ -0,0 +1,62 @@ +#!/usr/bin/env python3 + +import functools +import subprocess +import time +from jsonrpcclient.http_client import HTTPClient + +LATEST_VERSION = 2 +DEFAULT_QUOTA = 1000000 + + +def send_tx(privkey, + code="", + to="", + value=0, + quota=DEFAULT_QUOTA, + version=LATEST_VERSION): + """ + python3 make_tx.py --privkey "$$" --to "$$" --code "$$" -- version "$$" + + python3 send_tx.py + """ + + kwargs = { + '--privkey': privkey, + '--to': to, + '--code': code, + '--value': str(value), + '--quota': str(quota), + '--version': str(version), + } + args = functools.reduce( + lambda lst, kv: lst + list(kv), + kwargs.items(), + [], + ) + print(['python3', 'make_tx.py', *args]) + subprocess.call(['python3', 'make_tx.py', *args, '--no-newcrypto']) + subprocess.call(['python3', 'send_tx.py']) + with open('../output/transaction/hash') as fobj: + return fobj.read().strip() + + +def get_receipt(tx_hash, retry=8): + """ Get receipt of a transaction """ + while retry > 0: + receipt = rpc_request('getTransactionReceipt', [tx_hash]) + if receipt is not None: + return receipt + time.sleep(4) + retry -= 1 + + +def rpc_request(method, params): + """ Send a jsonrpc request to default url. """ + client = HTTPClient('http://127.0.0.1:1337') + return client.request(method, params) + + +def get_balance(addr): + """ Get the balance of an address """ + return int(rpc_request('getBalance', [addr, 'pending']), 16) diff --git a/tests/integrate_test/update_version.py b/tests/integrate_test/update_version.py index c69031a40..d14a7eb5e 100644 --- a/tests/integrate_test/update_version.py +++ b/tests/integrate_test/update_version.py @@ -3,92 +3,30 @@ Test case of fee back to operator in charge economical mode. """ -import functools -import subprocess -import time import argparse -from jsonrpcclient.http_client import HTTPClient - -LATEST_VERSION = 1 - - -def send_tx(privkey, code="", version=LATEST_VERSION): - """ - Send a transaction - - python3 make_tx.py - --privkey "5f0258a4778057a8a7d97809bd209055b2fbafa654ce7d31ec7191066b9225e6" - --code "" - - python3 send_tx.py - """ - - version_manager = "ffffffffffffffffffffffffffffffffff020011" - - kwargs = { - '--privkey': privkey, - '--to': version_manager, - '--code': code, - '--version': str(version), - } - args = functools.reduce( - lambda lst, kv: lst + list(kv), - kwargs.items(), - [], - ) - print(['python3', 'make_tx.py', *args]) - subprocess.call(['python3', 'make_tx.py', *args]) - subprocess.call(['python3', 'send_tx.py']) - with open('../output/transaction/hash') as fobj: - return fobj.read().strip() - - -def get_balance(addr): - """ Get the balance of an address """ - return int(rpc_request('getBalance', [addr, 'pending']), 16) - - -def get_receipt(tx_hash, retry=8): - """ Get receipt of a transaction """ - while retry > 0: - receipt = rpc_request('getTransactionReceipt', [tx_hash]) - if receipt is not None: - return receipt - time.sleep(4) - retry -= 1 - - -def rpc_request(method, params): - """ Send a jsonrpc request to default url. """ - client = HTTPClient('http://127.0.0.1:1337') - return client.request(method, params) +from txtool_utils import get_receipt, rpc_request, send_tx, get_balance def main(): """ Run the test. """ admin_privkey = '0x5f0258a4778057a8a7d97809bd209055b2fbafa654ce7d31ec7191066b9225e6' code = '0x62ddb8e10000000000000000000000000000000000000000000000000000000000000001' + version_manager = "ffffffffffffffffffffffffffffffffff020011" opts = parse_arguments() version = opts.version - tx_hash = send_tx(admin_privkey, code, version) + tx_hash = send_tx( + admin_privkey, code=code, to=version_manager, version=version) get_receipt(tx_hash) - - print('>>> Test fee back successfully!') + print('>>> Update version successfully!') def parse_arguments(): parser = argparse.ArgumentParser() - parser.add_argument( - "--version", - help="Tansaction version.", - default=LATEST_VERSION, - type=int) - - opts = parser.parse_args() + parser.add_argument("--version", help="Tansaction version.", type=int) - return opts + return parser.parse_args() if __name__ == '__main__': diff --git a/tests/integrate_test/util.sh b/tests/integrate_test/util.sh index 7bdb96662..0e3057099 100644 --- a/tests/integrate_test/util.sh +++ b/tests/integrate_test/util.sh @@ -321,15 +321,15 @@ start_nodes() { num=4 fi for ((i=0; i&1 + bin/cita bebop setup $CHAIN_NAME/$i done for ((i=0; i&1 + bin/cita bebop start $CHAIN_NAME/$i trace done } config_script() { - ./scripts/create_cita_config.py "$@" > /dev/null 2>&1 + ./scripts/create_cita_config.py "$@" } create_config() { diff --git a/tests/interfaces/config/blockchain.yaml b/tests/interfaces/config/blockchain.yaml index 2ba792abc..47ddca881 100644 --- a/tests/interfaces/config/blockchain.yaml +++ b/tests/interfaces/config/blockchain.yaml @@ -42,6 +42,7 @@ blocks: transactions: # Create a Token contract # [Source Code]: tests/contracts/ERC20-Token/StandardToken.sol + # TODO Replace it with tests/contracts/token/ERC20/ERC20.sol - privkey: 'ef98e68db428906d626cd37782cdfb052ac282132beee53a99948738ea553b4a' nonce: 2 quota: 100000 @@ -53,6 +54,7 @@ blocks: transactions: # Create a Token contract # [Source Code]: tests/contracts/ERC20-Token/StandardToken.sol + # TODO Replace it with tests/contracts/token/ERC20/ERC20.sol - privkey: 'ef98e68db428906d626cd37782cdfb052ac282132beee53a99948738ea553b4a' nonce: 3 quota: 100000 @@ -66,6 +68,7 @@ blocks: transactions: # Create a Token contract # [Source Code]: tests/contracts/ERC20-Token/StandardToken.sol + # TODO Replace it with tests/contracts/token/ERC20/ERC20.sol - privkey: 'ef98e68db428906d626cd37782cdfb052ac282132beee53a99948738ea553b4a' nonce: 4 quota: 100000 @@ -91,8 +94,8 @@ blocks: # [Source Code]: tests/contracts/AccountGasLimitReached.sol - privkey: 'ef98e68db428906d626cd37782cdfb052ac282132beee53a99948738ea553b4a' nonce: 6 - # Should be OutOfGas Receipt (1073741824 + 1) - quota: 1073741825 + # Should be NotEnoughBaseGas Receipt + quota: 0 valid_until_block: 100 to: '' data: '6080604052348015600f57600080fd5b5060008090505b64174876e7ff81101560df57600081604051602001808281526020019150506040516020818303038152906040526040518082805190602001908083835b602083101515607757805182526020820191506020810190506020830392506054565b6001836020036101000a0380198251168184511680821785525050505050509050019150506040518091039020908060018154018082558091505090600182039060005260206000200160009091929091909150906000191690555080806001019150506016565b506035806100ee6000396000f3006080604052600080fd00a165627a7a72305820efef3774d87857acd8caa2eb26b23c1f773fdfde17c093d7e81bc808933a83a40029' diff --git a/tests/interfaces/rpc_test_runner.py b/tests/interfaces/rpc_test_runner.py index 89b8f2281..0a214afd8 100644 --- a/tests/interfaces/rpc_test_runner.py +++ b/tests/interfaces/rpc_test_runner.py @@ -99,7 +99,9 @@ def run_test_case(self, test_case, request_schema, response_schema, resolver=response_resolver, ) + print("===> reqeust payload = {}", request_payload) resp = self.session.post(self.rpc_url, json=request_payload) + print("===> response = {}", resp.json()) assert_data = { 'receivedResponse': resp.json(), 'expectedResponse': expected_response diff --git a/tests/json-test/Cargo.toml b/tests/json-test/Cargo.toml index 98d687ba1..ca3ef33fa 100644 --- a/tests/json-test/Cargo.toml +++ b/tests/json-test/Cargo.toml @@ -2,6 +2,7 @@ name = "state-test" version = "0.1.0" authors = ["Cryptape Technologies "] +license = "Apache-2.0" edition = "2018" [dependencies] @@ -16,8 +17,16 @@ env_logger = "0.6.1" log = "0.4.0" libproto = { git = "https://github.com/cryptape/cita-common.git", branch = "develop" } +cita-types = { git = "https://github.com/cryptape/cita-common.git", branch = "develop" } core-executor = { path="../../cita-executor/core"} -evm = { path="../../cita-executor/evm"} +cita-crypto = { git = "https://github.com/cryptape/cita-common.git", branch = "develop" } +cita_trie = "2.0" + +[dependencies.cita-vm] +git = "https://github.com/cryptape/cita-vm.git" +branch = "cita" +default-features = false +features = ["sha3hash"] [features] default = ["secp256k1", "sha3hash"] diff --git a/tests/json-test/src/helper.rs b/tests/json-test/src/helper.rs index 74e6570cd..ec012e585 100644 --- a/tests/json-test/src/helper.rs +++ b/tests/json-test/src/helper.rs @@ -1,10 +1,19 @@ -use core_executor::cita_db::{journaldb, kvdb, KeyValueDB}; -use core_executor::db; -use core_executor::state::State; -use core_executor::state_db::StateDB; +// Copyright Cryptape Technologies LLC. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +use cita_types::{Address, H256, U256}; use ethereum_types::Public; -use evm::cita_types::{Address, H256, U256}; -use std::sync::Arc; pub fn clean_0x(s: &str) -> &str { if s.starts_with("0x") { @@ -54,18 +63,3 @@ pub fn secret_2_address(secret: &str) -> Address { public.copy_from_slice(&serialized[1..65]); public_2_address(&public) } - -pub fn get_temp_state() -> State { - let state_db = get_temp_state_db(); - State::new(state_db, 0.into(), Default::default()) -} - -pub fn new_db() -> Arc { - Arc::new(kvdb::in_memory(8)) -} - -pub fn get_temp_state_db() -> StateDB { - let db = new_db(); - let journal_db = journaldb::new(db, journaldb::Algorithm::Archive, db::COL_STATE); - StateDB::new(journal_db, 5 * 1024 * 1024) -} diff --git a/tests/json-test/src/json/mod.rs b/tests/json-test/src/json/mod.rs index 21d36cfed..b67900988 100644 --- a/tests/json-test/src/json/mod.rs +++ b/tests/json-test/src/json/mod.rs @@ -1,2 +1,16 @@ +// Copyright Cryptape Technologies LLC. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + pub mod state; pub mod vm; diff --git a/tests/json-test/src/json/state.rs b/tests/json-test/src/json/state.rs index 08cdfd8dc..02de85200 100644 --- a/tests/json-test/src/json/state.rs +++ b/tests/json-test/src/json/state.rs @@ -1,4 +1,18 @@ -use evm::cita_types::Address; +// Copyright Cryptape Technologies LLC. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +use cita_types::Address; use serde_derive::Deserialize; use serde_json::Error; use std::collections::BTreeMap; diff --git a/tests/json-test/src/json/vm.rs b/tests/json-test/src/json/vm.rs index 93903193f..fd40a1c34 100644 --- a/tests/json-test/src/json/vm.rs +++ b/tests/json-test/src/json/vm.rs @@ -1,4 +1,18 @@ -use evm::cita_types::Address; +// Copyright Cryptape Technologies LLC. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +use cita_types::Address; use serde_derive::Deserialize; use std::collections::BTreeMap; use std::io::Read; diff --git a/tests/json-test/src/lib.rs b/tests/json-test/src/lib.rs index 80471a472..918c457dc 100644 --- a/tests/json-test/src/lib.rs +++ b/tests/json-test/src/lib.rs @@ -1,7 +1,20 @@ -#[macro_use] -extern crate log; +// Copyright Cryptape Technologies LLC. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +// #[macro_use] +// extern crate log; pub mod helper; pub mod json; pub mod state_test; -pub mod vm_test; diff --git a/tests/json-test/src/state_test.rs b/tests/json-test/src/state_test.rs index 2977c4747..a1658acc2 100644 --- a/tests/json-test/src/state_test.rs +++ b/tests/json-test/src/state_test.rs @@ -1,100 +1,157 @@ -use crate::helper::{ - get_temp_state, secret_2_address, string_2_bytes, string_2_h256, string_2_u256, -}; +// Copyright Cryptape Technologies LLC. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License + +use crate::helper::{secret_2_address, string_2_bytes, string_2_h256, string_2_u256}; use crate::json::state::Test; -use core_executor::engines::NullEngine; -use core_executor::libexecutor::economical_model::EconomicalModel; + +use core_executor::cita_executive::CitaExecutive; +use core_executor::contracts::native::factory::Factory as NativeFactory; use core_executor::libexecutor::sys_config::BlockSysConfig; -use core_executor::state::ApplyResult; -use core_executor::types::transaction::Transaction; -use evm::cita_types::U256; -use evm::env_info::EnvInfo; +use core_executor::libexecutor::{block::EVMBlockDataProvider, economical_model::EconomicalModel}; +use core_executor::types::{context::Context, transaction::Transaction}; //,Action,SignedTransaction}; + +use core_executor::types::errors::ExecutionError; + +use cita_types::U256; +use cita_vm::state::{State, StateObjectInfo}; +use core_executor::tx_gas_schedule::TxGasSchedule; use libproto::blockchain::Transaction as ProtoTransaction; + use std::fs; use std::sync::Arc; pub fn test_json_file(p: &str) { let f = fs::File::open(p).unwrap(); - let tests = Test::load(f).unwrap(); - for (_name, test) in tests.into_iter() { - let data_post_homestead = test.post.unwrap().homestead; + let t = Test::load(f).unwrap(); + + for (name, data) in t.into_iter() { + let data_post_homestead = data.post.unwrap().homestead; if data_post_homestead.is_none() { continue; } - for (_i, postdata) in data_post_homestead.unwrap().into_iter().enumerate() { - // Init state - let mut state = get_temp_state(); - for (address, account) in test.pre.clone().unwrap() { + for (i, postdata) in data_post_homestead.unwrap().iter().enumerate() { + println!("{}::{}::{}\n", p, name, i); + let d = Arc::new(cita_trie::MemoryDB::new(false)); + let mut state_provider = State::new(d).unwrap(); + + for (address, account) in data.pre.clone().unwrap() { let balance = string_2_u256(account.balance); let code = string_2_bytes(account.code); let nonce = string_2_u256(account.nonce); if code.is_empty() { - state.new_contract(&address, balance, nonce); + state_provider.new_contract(&address, balance, nonce, vec![]); } else { - state.new_contract(&address, balance, nonce); - let _ = state.init_code(&address, code); + state_provider.new_contract(&address, balance, nonce, code); } - for (k, v) in account.storage { let kk = string_2_h256(k); let vv = string_2_h256(v); - let _ = state.set_storage(&address, kk, vv); + state_provider.set_storage(&address, kk, vv).unwrap(); } } - state.commit().unwrap(); - - // Set envionment - let mut env_info = EnvInfo::default(); - env_info.difficulty = string_2_u256(test.env.current_difficulty.clone()); - env_info.number = string_2_u256(test.env.current_number.clone()).low_u64(); - env_info.timestamp = string_2_u256(test.env.current_timestamp.clone()).low_u64(); - env_info.gas_limit = string_2_u256(test.env.current_gas_limit.clone()); - env_info.author = test.env.current_coinbase; - let previous_hash = string_2_h256(test.env.previous_hash.clone()); - Arc::make_mut(&mut env_info.last_hashes).push(previous_hash); - - let engine = NullEngine::cita(); - let mut config = BlockSysConfig::default(); - config.quota_price = string_2_u256(test.transaction.gas_price.clone()); - config.economical_model = EconomicalModel::Charge; - config.quota_price = U256::from(1); + state_provider.commit().unwrap(); + + let state_provider = Arc::new(std::cell::RefCell::new(state_provider)); let idx_gas = &postdata.indexes[&String::from("gas")]; let idx_value = &postdata.indexes[&String::from("value")]; let idx_data = &postdata.indexes[&String::from("data")]; - let str_gas = test.transaction.gas_limit.clone()[*idx_gas].clone(); - let str_value = test.transaction.value.clone()[*idx_value].clone(); - let str_data = test.transaction.data.clone()[*idx_data].clone(); + + let str_block_gas = data.env.current_gas_limit.clone(); + let str_prev_hash = data.env.previous_hash.clone(); + let str_gas = data.transaction.gas_limit.clone()[*idx_gas].clone(); + let str_value = data.transaction.value.clone()[*idx_value].clone(); + let str_data = data.transaction.data.clone()[*idx_data].clone(); + + let mut evm_context = Context::default(); + evm_context.block_quota_limit = string_2_u256(str_block_gas.clone()); + evm_context.coin_base = data.env.current_coinbase; + evm_context.block_number = string_2_u256(data.env.current_number.clone()).low_u64(); + evm_context.timestamp = string_2_u256(data.env.current_timestamp.clone()).low_u64(); + evm_context.difficulty = string_2_u256(data.env.current_difficulty.clone()); + evm_context.quota_used = U256::zero(); + evm_context.last_hashes = Arc::new(vec![string_2_h256(str_prev_hash)]); + + let block_data_provider = EVMBlockDataProvider::new(evm_context.clone()); + let native_factory = NativeFactory::default(); + let mut exepinst = CitaExecutive::new( + Arc::new(block_data_provider), + state_provider.clone(), + &native_factory, + &evm_context, + EconomicalModel::Charge, + ); let mut proto_tx = ProtoTransaction::new(); proto_tx.set_data(string_2_bytes(str_data)); proto_tx.set_value(string_2_bytes(str_value)); - proto_tx.set_nonce(test.transaction.nonce.clone()); + proto_tx.set_nonce(data.transaction.nonce.clone()); proto_tx.set_quota(string_2_u256(str_gas).low_u64()); - if !test.transaction.to.is_empty() { - proto_tx.set_to(test.transaction.to.clone()); + if !data.transaction.to.is_empty() { + proto_tx.set_to(data.transaction.to.clone()); } + let mut config = BlockSysConfig::default(); + config.quota_price = string_2_u256(data.transaction.gas_price.clone()); + config.economical_model = EconomicalModel::Charge; + config.chain_version = 2; + config.chain_owner = data.env.current_coinbase; + config.check_options.fee_back_platform = true; + let tx = Transaction::create(&proto_tx).unwrap(); - let sender = secret_2_address(&test.transaction.secret_key); - let signed_transaction = tx.fake_sign(sender); - - // Execute transactions - let result: ApplyResult = - state.apply(&env_info, &engine, &signed_transaction, true, &config); - match result { - Ok(outcome) => { - debug!("lalalal receipt error: {:?}", outcome.receipt.error); + let sender = secret_2_address(&data.transaction.secret_key); + let mut signed_transaction = tx.clone().fake_sign(sender); + signed_transaction.gas_price = config.quota_price; + + let exec_result = exepinst.exec(&signed_transaction, &config); + match exec_result { + Ok(_) => {} + Err(err) => { + let schedule = TxGasSchedule::default(); + // Bellow has a error, need gas*price before compare with balance + let tx_quota_used = match err { + ExecutionError::Internal(_) => tx.gas, + _ => std::cmp::min( + state_provider + .borrow_mut() + .balance(&sender) + .unwrap_or_else(|_| U256::from(0)), + U256::from(schedule.tx_gas), + ), + }; + + let sender_balance = state_provider.borrow_mut().balance(&sender).unwrap(); + let tx_fee = tx_quota_used * config.quota_price; + let real_fee = std::cmp::min(sender_balance, tx_fee); + + if state_provider + .borrow_mut() + .sub_balance(&sender, real_fee) + .is_ok() + { + let _ = state_provider + .borrow_mut() + .add_balance(&config.chain_owner, real_fee); + } } - _ => panic!("apply_transaction: There must be something wrong!"), } - - // check root hash - state.commit().unwrap(); - let root = state.root(); - debug!("state.root {}", root); - assert_eq!(*root, string_2_h256(postdata.hash)); + state_provider.borrow_mut().commit().unwrap(); + assert_eq!( + state_provider.borrow().root, + string_2_h256(postdata.hash.clone()) + ); } } } @@ -174,42 +231,51 @@ mod tests { r"../jsondata/GeneralStateTests/stCallCreateCallCodeTest", ); - test_json_path(r"../jsondata/GeneralStateTests/stRandom"); - test_json_path(r"../jsondata/GeneralStateTests/stSystemOperationsTest"); - test_json_path(r"../jsondata/GeneralStateTests/stRecursiveCreate"); - test_json_path(r"../jsondata/GeneralStateTests/stLogTests"); - test_json_path(r"../jsondata/GeneralStateTests/stCodeCopyTest"); - test_json_path(r"../jsondata/GeneralStateTests/stExtCodeHash"); - test_json_path(r"../jsondata/GeneralStateTests/stCallCodes"); - test_json_path(r"../jsondata/GeneralStateTests/stCreateTest"); - test_json_path(r"../jsondata/GeneralStateTests/stZeroKnowledge"); - test_json_path(r"../jsondata/GeneralStateTests/stRandom2"); - test_json_path(r"../jsondata/GeneralStateTests/stTransitionTest"); - test_json_path(r"../jsondata/GeneralStateTests/stZeroCallsTest"); - test_json_path(r"../jsondata/GeneralStateTests/stBugs"); - test_json_path(r"../jsondata/GeneralStateTests/stBadOpcode"); - test_json_path(r"../jsondata/GeneralStateTests/stWalletTest"); - test_json_path(r"../jsondata/GeneralStateTests/stNonZeroCallsTest"); - test_json_path(r"../jsondata/GeneralStateTests/stCallDelegateCodesHomestead"); - test_json_path(r"../jsondata/GeneralStateTests/stAttackTest"); - test_json_path(r"../jsondata/GeneralStateTests/stStackTests"); - test_json_path(r"../jsondata/GeneralStateTests/stExample"); - test_json_path(r"../jsondata/GeneralStateTests/stSolidityTest"); - test_json_path(r"../jsondata/GeneralStateTests/stQuadraticComplexityTest"); - test_json_path(r"../jsondata/GeneralStateTests/stPreCompiledContracts2"); - test_json_path(r"../jsondata/GeneralStateTests/stInitCodeTest"); - test_json_path(r"../jsondata/GeneralStateTests/stDelegatecallTestHomestead"); - test_json_path(r"../jsondata/GeneralStateTests/stMemoryTest"); - test_json_path(r"../jsondata/GeneralStateTests/stSpecialTest"); - test_json_path(r"../jsondata/GeneralStateTests/stShift"); - test_json_path(r"../jsondata/GeneralStateTests/stHomesteadSpecific"); - test_json_path(r"../jsondata/GeneralStateTests/stCodeSizeLimit"); - test_json_path(r"../jsondata/GeneralStateTests/stReturnDataTest"); - test_json_path(r"../jsondata/GeneralStateTests/stTransactionTest"); - test_json_path(r"../jsondata/GeneralStateTests/stRevertTest"); - test_json_path(r"../jsondata/GeneralStateTests/stMemoryStressTest"); - test_json_path(r"../jsondata/GeneralStateTests/stCallDelegateCodesCallCodeHomestead"); - test_json_path(r"../jsondata/GeneralStateTests/stMemExpandingEIP150Calls"); - test_json_path(r"../jsondata/GeneralStateTests/stRefundTest"); + std::thread::Builder::new() + .stack_size(134_217_728) + .spawn(move || { + test_json_path(r"../jsondata/GeneralStateTests/stRandom"); + test_json_path(r"../jsondata/GeneralStateTests/stSystemOperationsTest"); + test_json_path(r"../jsondata/GeneralStateTests/stRecursiveCreate"); + test_json_path(r"../jsondata/GeneralStateTests/stLogTests"); + test_json_path(r"../jsondata/GeneralStateTests/stCodeCopyTest"); + test_json_path(r"../jsondata/GeneralStateTests/stExtCodeHash"); + test_json_path(r"../jsondata/GeneralStateTests/stCallCodes"); + test_json_path(r"../jsondata/GeneralStateTests/stCreateTest"); + test_json_path(r"../jsondata/GeneralStateTests/stZeroKnowledge"); + test_json_path(r"../jsondata/GeneralStateTests/stRandom2"); + test_json_path(r"../jsondata/GeneralStateTests/stTransitionTest"); + test_json_path(r"../jsondata/GeneralStateTests/stZeroCallsTest"); + test_json_path(r"../jsondata/GeneralStateTests/stBugs"); + //test_json_path(r"../jsondata/GeneralStateTests/stBadOpcode"); + test_json_path(r"../jsondata/GeneralStateTests/stWalletTest"); + test_json_path(r"../jsondata/GeneralStateTests/stNonZeroCallsTest"); + test_json_path(r"../jsondata/GeneralStateTests/stCallDelegateCodesHomestead"); + test_json_path(r"../jsondata/GeneralStateTests/stAttackTest"); + test_json_path(r"../jsondata/GeneralStateTests/stStackTests"); + test_json_path(r"../jsondata/GeneralStateTests/stExample"); + test_json_path(r"../jsondata/GeneralStateTests/stSolidityTest"); + test_json_path(r"../jsondata/GeneralStateTests/stQuadraticComplexityTest"); + test_json_path(r"../jsondata/GeneralStateTests/stPreCompiledContracts2"); + test_json_path(r"../jsondata/GeneralStateTests/stInitCodeTest"); + test_json_path(r"../jsondata/GeneralStateTests/stDelegatecallTestHomestead"); + test_json_path(r"../jsondata/GeneralStateTests/stMemoryTest"); + test_json_path(r"../jsondata/GeneralStateTests/stSpecialTest"); + test_json_path(r"../jsondata/GeneralStateTests/stShift"); + test_json_path(r"../jsondata/GeneralStateTests/stHomesteadSpecific"); + test_json_path(r"../jsondata/GeneralStateTests/stCodeSizeLimit"); + test_json_path(r"../jsondata/GeneralStateTests/stReturnDataTest"); + test_json_path(r"../jsondata/GeneralStateTests/stTransactionTest"); + test_json_path(r"../jsondata/GeneralStateTests/stRevertTest"); + test_json_path(r"../jsondata/GeneralStateTests/stMemoryStressTest"); + test_json_path( + r"../jsondata/GeneralStateTests/stCallDelegateCodesCallCodeHomestead", + ); + test_json_path(r"../jsondata/GeneralStateTests/stMemExpandingEIP150Calls"); + test_json_path(r"../jsondata/GeneralStateTests/stRefundTest"); + }) + .unwrap() + .join() + .unwrap(); } } diff --git a/tests/json-test/src/vm_test.rs b/tests/json-test/src/vm_test.rs deleted file mode 100644 index 206a287b5..000000000 --- a/tests/json-test/src/vm_test.rs +++ /dev/null @@ -1,101 +0,0 @@ -use crate::helper::{string_2_bytes, string_2_h256, string_2_u256}; -use crate::json::vm::Test; -use evm::action_params::{ActionParams, ActionValue}; -use evm::env_info::EnvInfo; -use evm::factory::{Factory, VMType}; -use evm::fake_tests::FakeExt; -use evm::return_data::GasLeft; -use evm::Ext; -use std::fs; -use std::str; -use std::sync::Arc; - -pub fn test_json_file(p: &str) { - let f = fs::File::open(p).unwrap(); - let tests = Test::load(f).unwrap(); - for (_name, vm) in tests.into_iter() { - // Step one: Init params, env_info - let mut params = ActionParams::default(); - params.address = vm.exec.address; - params.sender = vm.exec.caller; - params.code = Some(Arc::new(string_2_bytes(vm.exec.code))); - params.data = Some(string_2_bytes(vm.exec.data)); - params.gas = string_2_u256(vm.exec.gas); - params.gas_price = string_2_u256(vm.exec.gas_price); - params.origin = vm.exec.origin; - params.value = ActionValue::Apparent(string_2_u256(vm.exec.value)); - - let mut env_info = EnvInfo::default(); - env_info.difficulty = string_2_u256(vm.env.current_difficulty); - env_info.number = string_2_u256(vm.env.current_number).low_u64(); - env_info.timestamp = string_2_u256(vm.env.current_timestamp).low_u64(); - env_info.gas_limit = string_2_u256(vm.env.current_gas_limit); - env_info.author = vm.env.current_coinbase; - - // Step two: Vm exec process - let factory = Factory::new(VMType::Interpreter, 1024 * 32); - let mut evm = factory.create(params.gas); - let mut ext = FakeExt::new(); - ext.info = env_info; - - if let Some(pre) = vm.pre { - for (_address, account) in pre.into_iter() { - for (k, v) in account.storage { - ext.set_storage(string_2_h256(k), string_2_h256(v)) - .expect("Init pre state failed."); - } - } - } - - match evm.exec(¶ms, &mut ext) { - Ok(GasLeft::Known(gas_left)) => assert_eq!(gas_left, string_2_u256(vm.gas.unwrap())), - Ok(GasLeft::NeedsReturn { gas_left, data, .. }) => { - assert_eq!(gas_left, string_2_u256(vm.gas.unwrap())); - assert_eq!((*data).to_vec(), string_2_bytes(vm.out.unwrap())); - } - Err(_) => assert!(vm.gas.is_none() && vm.post.is_none() && vm.logs.is_none()), - } - - if let Some(post) = vm.post { - for (_address, account) in post.into_iter() { - for (k, v) in account.storage { - if let Ok(value) = ext.storage_at(&string_2_h256(k)) { - assert_eq!(value, string_2_h256(v)); - } - } - } - } - } -} - -pub fn test_json_path(p: &str) { - let info = fs::metadata(p).unwrap(); - if info.is_dir() { - for entry in fs::read_dir(p).unwrap() { - let entry = entry.unwrap(); - let p = entry.path(); - test_json_path(p.to_str().unwrap()); - } - } else { - test_json_file(p); - } -} - -#[cfg(test)] -mod tests { - use super::test_json_path; - #[test] - fn test_json_vm() { - test_json_path(r"../jsondata/VMTests/vmArithmeticTest"); - test_json_path(r"../jsondata/VMTests/vmBitwiseLogicOperation"); - test_json_path(r"../jsondata/VMTests/vmBlockInfoTest"); - test_json_path(r"../jsondata/VMTests/vmEnvironmentalInfo"); - test_json_path(r"../jsondata/VMTests/vmIOandFlowOperations"); - test_json_path(r"../jsondata/VMTests/vmLogTest"); - test_json_path(r"../jsondata/VMTests/vmRandomTest"); - test_json_path(r"../jsondata/VMTests/vmSha3Test"); - test_json_path(r"../jsondata/VMTests/vmPushDupSwapTest"); - test_json_path(r"../jsondata/VMTests/vmSystemOperations"); - test_json_path(r"../jsondata/VMTests/vmTests"); - } -} diff --git a/tests/jsondata b/tests/jsondata index 712bc67ce..8459ecb3f 160000 --- a/tests/jsondata +++ b/tests/jsondata @@ -1 +1 @@ -Subproject commit 712bc67cef0638d79d76cb182ce89344b5584300 +Subproject commit 8459ecb3fcfe3555d3607bb092aa9ddceca6dd88 diff --git a/tools/create-genesis/Cargo.toml b/tools/create-genesis/Cargo.toml index c3875de7b..1cca8b545 100644 --- a/tools/create-genesis/Cargo.toml +++ b/tools/create-genesis/Cargo.toml @@ -2,6 +2,7 @@ name = "create-genesis" version = "0.1.0" authors = ["Cryptape Technologies "] +license = "Apache-2.0" edition = "2018" [dependencies] @@ -9,14 +10,20 @@ serde = { version = "1.0", features = ["derive"] } serde_yaml = "0.8" json = "0.11.13" serde_json = "1.0.39" -ethabi = "7.0.0" -ethereum-types = "0.5.2" +ethabi = "6.1.0" +ethereum-types = "0.4" hex = "0.3" tiny-keccak = "1.4.2" libsecp256k1 = "0.2.2" clap = "2.33.0" +cita_trie = "2.0" libproto = { git = "https://github.com/cryptape/cita-common.git", branch = "develop" } +cita-types = { git = "https://github.com/cryptape/cita-common.git", branch = "develop" } + +[dependencies.cita-vm] +git = "https://github.com/cryptape/cita-vm.git" +branch = "cita" +default-features = false +features = ["sha3hash"] -core-executor = { path="../../cita-executor/core", default-features = false} -evm = { path="../../cita-executor/evm"} diff --git a/tools/create-genesis/src/common.rs b/tools/create-genesis/src/common.rs index 23302c4aa..037ecba08 100644 --- a/tools/create-genesis/src/common.rs +++ b/tools/create-genesis/src/common.rs @@ -1,59 +1,19 @@ -use ethereum_types::Public; -use evm::cita_types::{Address, U256}; - -use core_executor::cita_db::{journaldb, kvdb, KeyValueDB}; -use core_executor::db; -use core_executor::state::State; -use core_executor::state_db::StateDB; -use std::sync::Arc; - -pub fn clean_0x(s: &str) -> &str { - if s.starts_with("0x") { - &s[2..] - } else { - s - } -} +// Copyright Cryptape Technologies LLC. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. pub fn string_2_bytes(value: String) -> Vec { let v = Box::leak(value.into_boxed_str()); - let v = clean_0x(v); + let v = cita_types::clean_0x(v); hex::decode(v).unwrap() } - -pub fn string_2_u256(value: String) -> U256 { - let v = Box::leak(value.into_boxed_str()); - let v = clean_0x(v); - U256::from(v) -} - -pub fn public_2_address(public: &Public) -> Address { - let hash = tiny_keccak::keccak256(&public.0); - let mut result = Address::default(); - result.copy_from_slice(&hash[12..]); - result -} - -pub fn secret_2_address(secret: &str) -> Address { - let a = hex::decode(clean_0x(secret)).unwrap(); - let secret_key = secp256k1::SecretKey::parse_slice(a.as_slice()).unwrap(); - let public_key = secp256k1::PublicKey::from_secret_key(&secret_key); - let serialized = public_key.serialize(); - let public = Public::from_slice(&serialized[1..65]); - public_2_address(&public) -} - -pub fn get_temp_state() -> State { - let state_db = get_temp_state_db(); - State::new(state_db, 0.into(), Default::default()) -} - -pub fn new_db() -> Arc { - Arc::new(kvdb::in_memory(8)) -} - -pub fn get_temp_state_db() -> StateDB { - let db = new_db(); - let journal_db = journaldb::new(db, journaldb::Algorithm::Archive, db::COL_STATE); - StateDB::new(journal_db, 5 * 1024 * 1024) -} diff --git a/tools/create-genesis/src/contracts.rs b/tools/create-genesis/src/contracts.rs index a5835ffa4..612b61a1e 100644 --- a/tools/create-genesis/src/contracts.rs +++ b/tools/create-genesis/src/contracts.rs @@ -1,10 +1,24 @@ -use crate::common::clean_0x; -use ethabi::Token; -use ethereum_types::Address; -use serde::{Deserialize, Serialize}; +// Copyright Cryptape Technologies LLC. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + use std::collections::BTreeMap; use std::fs::File; use std::str::FromStr; + +use cita_types::{clean_0x, Address}; +use ethabi::Token; +use serde::{Deserialize, Serialize}; use tiny_keccak::keccak256; #[derive(Debug, PartialEq, Serialize, Deserialize)] diff --git a/tools/create-genesis/src/genesis.rs b/tools/create-genesis/src/genesis.rs index 2fc41a552..e455e95d1 100644 --- a/tools/create-genesis/src/genesis.rs +++ b/tools/create-genesis/src/genesis.rs @@ -1,17 +1,33 @@ -use crate::common::{clean_0x, string_2_bytes}; +// Copyright Cryptape Technologies LLC. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +use std::collections::BTreeMap; +use std::fs::File; +use std::io::Write; +use std::path::Path; +use std::str::FromStr; + +use crate::common::string_2_bytes; use crate::contracts::ContractsData; use crate::miner::Miner; use crate::params::InitData; use crate::solc::Solc; + +use cita_types::{clean_0x, U256}; use ethabi::Contract; -use evm::cita_types::U256; use json; use serde::{Deserialize, Serialize}; -use std::collections::BTreeMap; -use std::fs::File; -use std::io::Write; -use std::path::Path; -use std::str::FromStr; pub struct GenesisCreator<'a> { pub contract_dir: &'a str, @@ -110,13 +126,13 @@ impl<'a> GenesisCreator<'a> { .get(*contract_name) .map_or(Vec::new(), |p| (*p).clone()); let bytes = constructor.encode_input(input_data, ¶ms).unwrap(); - let account = Miner::mine(bytes); - self.accounts.insert((*address).clone(), account); - } else { - let account = Miner::mine(input_data); + if let Some(account) = Miner::mine(bytes) { + self.accounts.insert((*address).clone(), account); + } + } else if let Some(account) = Miner::mine(input_data) { self.accounts.insert((*address).clone(), account); + println!("Normal contracts: {:?} {:?} is ok!", contract_name, address); } - println!("Normal contracts: {:?} {:?} is ok!", contract_name, address); } } @@ -140,9 +156,10 @@ impl<'a> GenesisCreator<'a> { let bytes = constructor .encode_input(input_data.clone(), ¶ms) .unwrap(); - let account = Miner::mine(bytes); - self.accounts.insert(address.clone(), account); - println!("Permission contracts: {:?} {:?} is ok!", name, address); + if let Some(account) = Miner::mine(bytes) { + self.accounts.insert(address.clone(), account); + println!("Permission contracts: {:?} {:?} is ok!", name, address); + } } for (name, info) in perm_contracts.contracts.list().iter() { @@ -156,9 +173,10 @@ impl<'a> GenesisCreator<'a> { let bytes = constructor .encode_input(input_data.clone(), ¶ms) .unwrap(); - let account = Miner::mine(bytes); - self.accounts.insert((*perm_address).clone(), account); - println!("Permission contracts: {:?} {:?} is ok!", name, perm_address); + if let Some(account) = Miner::mine(bytes) { + self.accounts.insert((*perm_address).clone(), account); + println!("Permission contracts: {:?} {:?} is ok!", name, perm_address); + } } } } diff --git a/tools/create-genesis/src/main.rs b/tools/create-genesis/src/main.rs index 610eedec7..606a756c1 100644 --- a/tools/create-genesis/src/main.rs +++ b/tools/create-genesis/src/main.rs @@ -1,3 +1,17 @@ +// Copyright Cryptape Technologies LLC. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + mod common; mod contracts; mod genesis; diff --git a/tools/create-genesis/src/miner.rs b/tools/create-genesis/src/miner.rs index 0a5dd1d1a..b78d53ced 100644 --- a/tools/create-genesis/src/miner.rs +++ b/tools/create-genesis/src/miner.rs @@ -1,51 +1,75 @@ -use crate::common::{get_temp_state, secret_2_address, string_2_bytes, string_2_u256}; +// Copyright Cryptape Technologies LLC. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +use std::cell::RefCell; +use std::sync::Arc; + use crate::genesis::Account; -use core_executor::engines::NullEngine; -use core_executor::executive::contract_address; -use core_executor::libexecutor::sys_config::BlockSysConfig; -use core_executor::types::transaction::Transaction; -use evm::cita_types::U256; -use evm::env_info::EnvInfo; -use libproto::blockchain::Transaction as ProtoTransaction; + +use cita_trie::MemoryDB; +use cita_types::{Address, U256}; pub struct Miner; impl Miner { - pub fn mine(code: Vec) -> Account { - let mut state = get_temp_state(); - - // Create a transaction - let mut proto_tx = ProtoTransaction::new(); - proto_tx.set_data(code); - proto_tx.set_value(string_2_bytes(String::from("0x00"))); - proto_tx.set_nonce("0x00".to_string()); - proto_tx.set_quota(string_2_u256(String::from("0x99999999999")).low_u64()); - - let private_key = - String::from("0x5f0258a4778057a8a7d97809bd209055b2fbafa654ce7d31ec7191066b9225e6"); - let tx = Transaction::create(&proto_tx).unwrap(); - let sender = secret_2_address(&private_key); - let signed_transaction = tx.fake_sign(sender); - - let env_info = EnvInfo::default(); - let engine = NullEngine::cita(); - let config = BlockSysConfig::default(); + pub fn mine(code: Vec) -> Option { + let db = Arc::new(MemoryDB::new(false)); + let state = cita_vm::state::State::new(db.clone()).expect("New state failed."); + + let state_data_provider = Arc::new(RefCell::new(state)); + let block_data_provider: Arc = + Arc::new(cita_vm::BlockDataProviderMock::default()); + let context = cita_vm::evm::Context::default(); + let config = cita_vm::Config::default(); + let sender = Address::from("0xd6c8454425135d0cfdb7c1fcba0f8a08a5880bf6"); + + // Contruct transaction and exec + let tx = cita_vm::Transaction { + from: sender, + to: None, + value: U256::from(0), + nonce: U256::from(0), + gas_limit: 7_999_999, + gas_price: U256::from(0), + input: code.clone(), + }; + let _r = cita_vm::exec( + block_data_provider.clone(), + state_data_provider.clone(), + context.clone(), + config.clone(), + tx, + ) + .expect("Create genesis exec error."); // Cal contract address - let contract_address = contract_address(&sender, &U256::from(0)); - // Apply tx and commit to state - let _ = state.apply(&env_info, &engine, &signed_transaction, false, &config); - state.commit().unwrap(); - - // Get account content according to contract address - let account = state.account(&contract_address).unwrap().unwrap(); - let code = account.code().unwrap(); - - Account { - nonce: *account.nonce(), - code: String::from("0x") + &hex::encode(code.to_vec()), - storage: account.storage_cache(), - value: *account.balance(), + let contract_address = + cita_vm::create_address_from_address_and_nonce(&sender, &U256::from(0)); + + if let Some(account) = state_data_provider + .borrow() + .get_state_object(&contract_address) + .expect("Failed to get state object at given address") + { + let a = Account { + nonce: account.nonce, + code: String::from("0x") + &hex::encode(account.clone().code), + storage: account.get_storage_changes(), + value: account.balance, + }; + return Some(a); } + None } } diff --git a/tools/create-genesis/src/params.rs b/tools/create-genesis/src/params.rs index b38743fa8..c8ce14d0b 100644 --- a/tools/create-genesis/src/params.rs +++ b/tools/create-genesis/src/params.rs @@ -1,11 +1,25 @@ -use crate::common::clean_0x; -use ethabi::Token; -use ethereum_types::{Address, U256}; -use serde::{Deserialize, Serialize}; +// Copyright Cryptape Technologies LLC. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + use std::collections::BTreeMap; use std::fs::File; use std::str::FromStr; +use cita_types::{clean_0x, Address, U256}; +use ethabi::Token; +use serde::{Deserialize, Serialize}; + pub trait GetParams { fn as_params(&self) -> Vec; } diff --git a/tools/create-genesis/src/solc.rs b/tools/create-genesis/src/solc.rs index e008a628b..db75925a4 100644 --- a/tools/create-genesis/src/solc.rs +++ b/tools/create-genesis/src/solc.rs @@ -1,3 +1,17 @@ +// Copyright Cryptape Technologies LLC. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + use json; use std::collections::BTreeMap; use std::process::Command; diff --git a/tools/create-key-addr/Cargo.toml b/tools/create-key-addr/Cargo.toml index b7eae4c06..a1ad0022d 100644 --- a/tools/create-key-addr/Cargo.toml +++ b/tools/create-key-addr/Cargo.toml @@ -2,6 +2,7 @@ name = "create-key-addr" version = "0.1.0" authors = ["Cryptape Technologies "] +license = "Apache-2.0" edition = "2018" [dependencies] diff --git a/tools/create-key-addr/src/main.rs b/tools/create-key-addr/src/main.rs index c47e69f7b..64c0540a4 100644 --- a/tools/create-key-addr/src/main.rs +++ b/tools/create-key-addr/src/main.rs @@ -1,19 +1,16 @@ -// CITA -// Copyright 2016-2019 Cryptape Technologies LLC. - -// This program is free software: you can redistribute it -// and/or modify it under the terms of the GNU 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 General Public License for more details. - -// You should have received a copy of the GNU General Public License -// along with this program. If not, see . +// Copyright Cryptape Technologies LLC. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. extern crate cita_crypto as crypto; diff --git a/tools/relayer-parser/Cargo.toml b/tools/relayer-parser/Cargo.toml index ad19d56f4..48036f713 100644 --- a/tools/relayer-parser/Cargo.toml +++ b/tools/relayer-parser/Cargo.toml @@ -2,6 +2,7 @@ name = "cita-relayer-parser" version = "0.1.0" authors = ["Cryptape Technologies "] +license = "Apache-2.0" edition = "2018" [dependencies] diff --git a/tools/relayer-parser/src/arguments.rs b/tools/relayer-parser/src/arguments.rs index bfcee20cf..c3756b74d 100644 --- a/tools/relayer-parser/src/arguments.rs +++ b/tools/relayer-parser/src/arguments.rs @@ -1,19 +1,16 @@ -// CITA -// Copyright 2016-2019 Cryptape Technologies LLC. - -// This program is free software: you can redistribute it -// and/or modify it under the terms of the GNU 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 General Public License for more details. - -// You should have received a copy of the GNU General Public License -// along with this program. If not, see . +// Copyright Cryptape Technologies LLC. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. use cita_types::{H256, U256}; use clap; diff --git a/tools/relayer-parser/src/communication.rs b/tools/relayer-parser/src/communication.rs index 59b756083..a3d96770a 100644 --- a/tools/relayer-parser/src/communication.rs +++ b/tools/relayer-parser/src/communication.rs @@ -1,19 +1,16 @@ -// CITA -// Copyright 2016-2019 Cryptape Technologies LLC. - -// This program is free software: you can redistribute it -// and/or modify it under the terms of the GNU 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 General Public License for more details. - -// You should have received a copy of the GNU General Public License -// along with this program. If not, see . +// Copyright Cryptape Technologies LLC. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. use futures::future::Either; use futures::sync::{mpsc, oneshot}; diff --git a/tools/relayer-parser/src/configuration.rs b/tools/relayer-parser/src/configuration.rs index 96880752a..8eae79904 100644 --- a/tools/relayer-parser/src/configuration.rs +++ b/tools/relayer-parser/src/configuration.rs @@ -1,19 +1,16 @@ -// CITA -// Copyright 2016-2019 Cryptape Technologies LLC. - -// This program is free software: you can redistribute it -// and/or modify it under the terms of the GNU 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 General Public License for more details. - -// You should have received a copy of the GNU General Public License -// along with this program. If not, see . +// Copyright Cryptape Technologies LLC. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. use cita_crypto::PrivKey; use cita_types::U256; diff --git a/tools/relayer-parser/src/main.rs b/tools/relayer-parser/src/main.rs index dda1fa559..137b49bd4 100644 --- a/tools/relayer-parser/src/main.rs +++ b/tools/relayer-parser/src/main.rs @@ -1,19 +1,16 @@ -// CITA -// Copyright 2016-2019 Cryptape Technologies LLC. - -// This program is free software: you can redistribute it -// and/or modify it under the terms of the GNU 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 General Public License for more details. - -// You should have received a copy of the GNU General Public License -// along with this program. If not, see . +// Copyright Cryptape Technologies LLC. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. #[macro_use] extern crate clap; diff --git a/tools/relayer-parser/src/transaction.rs b/tools/relayer-parser/src/transaction.rs index 1779cebd8..f37ecab1f 100644 --- a/tools/relayer-parser/src/transaction.rs +++ b/tools/relayer-parser/src/transaction.rs @@ -1,19 +1,16 @@ -// CITA -// Copyright 2016-2019 Cryptape Technologies LLC. - -// This program is free software: you can redistribute it -// and/or modify it under the terms of the GNU 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 General Public License for more details. - -// You should have received a copy of the GNU General Public License -// along with this program. If not, see . +// Copyright Cryptape Technologies LLC. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. use ethabi; diff --git a/tools/snapshot-tool/Cargo.toml b/tools/snapshot-tool/Cargo.toml index 3743ba7a3..a10c50a4c 100644 --- a/tools/snapshot-tool/Cargo.toml +++ b/tools/snapshot-tool/Cargo.toml @@ -2,6 +2,7 @@ name = "snapshot-tool" version = "0.2.0" authors = ["Cryptape Technologies "] +license = "Apache-2.0" edition = "2018" [dependencies] diff --git a/tools/snapshot-tool/src/main.rs b/tools/snapshot-tool/src/main.rs index a27473617..6bfde2cc9 100644 --- a/tools/snapshot-tool/src/main.rs +++ b/tools/snapshot-tool/src/main.rs @@ -1,19 +1,16 @@ -// CITA -// Copyright 2016-2019 Cryptape Technologies LLC. - -// This program is free software: you can redistribute it -// and/or modify it under the terms of the GNU 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 General Public License for more details. - -// You should have received a copy of the GNU General Public License -// along with this program. If not, see . +// Copyright Cryptape Technologies LLC. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. #[macro_use] extern crate libproto; diff --git a/tools/snapshot-tool/src/postman.rs b/tools/snapshot-tool/src/postman.rs index 27f39b3ad..55ee12fe8 100644 --- a/tools/snapshot-tool/src/postman.rs +++ b/tools/snapshot-tool/src/postman.rs @@ -1,19 +1,16 @@ -// CITA -// Copyright 2016-2019 Cryptape Technologies LLC. - -// This program is free software: you can redistribute it -// and/or modify it under the terms of the GNU 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 General Public License for more details. - -// You should have received a copy of the GNU General Public License -// along with this program. If not, see . +// Copyright Cryptape Technologies LLC. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. use libproto::blockchain::Proof; use libproto::router::{MsgType, RoutingKey, SubModules};