From 010e63116fc49150cf0f0e09f04f12f235e78783 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bastian=20K=C3=B6cher?= Date: Mon, 21 Jan 2019 14:32:53 +0100 Subject: [PATCH] Make runtime api calls native when possible (#1302) * Add simple benchmark for the runtime api * Make the executor support native calls * Some documentation * Hide behind `feature = "std"` * Rework the native calls * Make all tests compile again * Make every parameter using the Block serialized/deserialized in the native call * Forward `UnwindSafe` requirement * Remove debug stuff * Add some documentation * Fixes warnings * Fixes errors after master rebase * Fixes compilation after master rebase * Fixes compilation after rebase --- substrate/Cargo.lock | 200 ++++++++++++++++ .../basic-authorship/src/basic_authorship.rs | 16 +- .../client/src/block_builder/block_builder.rs | 6 +- substrate/core/client/src/call_executor.rs | 71 ++++-- substrate/core/client/src/client.rs | 62 +++-- .../core/client/src/light/call_executor.rs | 30 ++- substrate/core/client/src/runtime_api.rs | 23 +- substrate/core/consensus/aura/src/lib.rs | 6 +- .../core/executor/src/native_executor.rs | 78 +++++-- .../finality-grandpa/primitives/src/lib.rs | 10 +- substrate/core/finality-grandpa/src/tests.rs | 10 +- substrate/core/primitives/src/lib.rs | 73 +++++- substrate/core/rpc/src/state/mod.rs | 4 +- substrate/core/service/src/components.rs | 13 +- substrate/core/service/test/src/lib.rs | 14 +- substrate/core/sr-api-macros/Cargo.toml | 5 + substrate/core/sr-api-macros/benches/bench.rs | 62 +++++ .../sr-api-macros/src/compile_fail_tests.rs | 18 -- .../sr-api-macros/src/decl_runtime_apis.rs | 200 ++++++++++++++-- .../sr-api-macros/src/impl_runtime_apis.rs | 216 ++++++++++-------- substrate/core/sr-api-macros/src/utils.rs | 73 ++++-- .../core/sr-api-macros/tests/decl_and_impl.rs | 18 +- substrate/core/sr-primitives/src/lib.rs | 2 +- substrate/core/sr-primitives/src/traits.rs | 2 +- substrate/core/state-machine/src/lib.rs | 121 +++++++--- substrate/core/test-client/src/lib.rs | 20 +- substrate/core/test-client/src/trait_tests.rs | 4 +- substrate/core/test-runtime/src/lib.rs | 29 ++- substrate/core/test-runtime/src/system.rs | 2 +- .../substrate_test_runtime.compact.wasm | Bin 45796 -> 47500 bytes .../core/transaction-pool/graph/src/pool.rs | 8 +- substrate/core/transaction-pool/src/api.rs | 2 +- substrate/core/transaction-pool/src/tests.rs | 2 +- substrate/node/executor/src/lib.rs | 107 +++++++-- substrate/node/runtime/src/lib.rs | 6 +- .../release/node_runtime.compact.wasm | Bin 816575 -> 818033 bytes substrate/srml/support/src/lib.rs | 2 +- 37 files changed, 1152 insertions(+), 363 deletions(-) create mode 100644 substrate/core/sr-api-macros/benches/bench.rs diff --git a/substrate/Cargo.lock b/substrate/Cargo.lock index 633e9d1160..456070e27b 100644 --- a/substrate/Cargo.lock +++ b/substrate/Cargo.lock @@ -303,6 +303,11 @@ name = "cast" version = "0.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" +[[package]] +name = "cast" +version = "0.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" + [[package]] name = "cc" version = "1.0.28" @@ -424,6 +429,29 @@ dependencies = [ "simplelog 0.4.4 (registry+https://github.com/rust-lang/crates.io-index)", ] +[[package]] +name = "criterion" +version = "0.2.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "atty 0.2.11 (registry+https://github.com/rust-lang/crates.io-index)", + "clap 2.32.0 (registry+https://github.com/rust-lang/crates.io-index)", + "criterion-plot 0.2.7 (registry+https://github.com/rust-lang/crates.io-index)", + "criterion-stats 0.2.5 (registry+https://github.com/rust-lang/crates.io-index)", + "csv 1.0.5 (registry+https://github.com/rust-lang/crates.io-index)", + "failure 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)", + "failure_derive 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)", + "handlebars 0.32.4 (registry+https://github.com/rust-lang/crates.io-index)", + "itertools 0.7.11 (registry+https://github.com/rust-lang/crates.io-index)", + "itertools-num 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)", + "log 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)", + "serde 1.0.84 (registry+https://github.com/rust-lang/crates.io-index)", + "serde_derive 1.0.84 (registry+https://github.com/rust-lang/crates.io-index)", + "serde_json 1.0.34 (registry+https://github.com/rust-lang/crates.io-index)", + "simplelog 0.5.3 (registry+https://github.com/rust-lang/crates.io-index)", + "walkdir 2.2.7 (registry+https://github.com/rust-lang/crates.io-index)", +] + [[package]] name = "criterion-plot" version = "0.1.3" @@ -434,6 +462,18 @@ dependencies = [ "itertools 0.5.10 (registry+https://github.com/rust-lang/crates.io-index)", ] +[[package]] +name = "criterion-plot" +version = "0.2.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "byteorder 1.2.7 (registry+https://github.com/rust-lang/crates.io-index)", + "cast 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)", + "failure 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)", + "failure_derive 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)", + "itertools 0.7.11 (registry+https://github.com/rust-lang/crates.io-index)", +] + [[package]] name = "criterion-stats" version = "0.1.3" @@ -446,6 +486,18 @@ dependencies = [ "thread-scoped 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)", ] +[[package]] +name = "criterion-stats" +version = "0.2.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "cast 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)", + "num-traits 0.2.6 (registry+https://github.com/rust-lang/crates.io-index)", + "num_cpus 1.9.0 (registry+https://github.com/rust-lang/crates.io-index)", + "rand 0.4.3 (registry+https://github.com/rust-lang/crates.io-index)", + "thread-scoped 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)", +] + [[package]] name = "crossbeam" version = "0.6.0" @@ -561,6 +613,23 @@ dependencies = [ "subtle 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)", ] +[[package]] +name = "csv" +version = "1.0.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "csv-core 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)", + "serde 1.0.84 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "csv-core" +version = "0.1.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "memchr 2.1.2 (registry+https://github.com/rust-lang/crates.io-index)", +] + [[package]] name = "ctr" version = "0.1.1" @@ -913,6 +982,21 @@ dependencies = [ "tokio-io 0.1.11 (registry+https://github.com/rust-lang/crates.io-index)", ] +[[package]] +name = "handlebars" +version = "0.32.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "lazy_static 1.2.0 (registry+https://github.com/rust-lang/crates.io-index)", + "log 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)", + "pest 1.0.6 (registry+https://github.com/rust-lang/crates.io-index)", + "pest_derive 1.0.8 (registry+https://github.com/rust-lang/crates.io-index)", + "quick-error 1.2.2 (registry+https://github.com/rust-lang/crates.io-index)", + "regex 1.1.0 (registry+https://github.com/rust-lang/crates.io-index)", + "serde 1.0.84 (registry+https://github.com/rust-lang/crates.io-index)", + "serde_json 1.0.34 (registry+https://github.com/rust-lang/crates.io-index)", +] + [[package]] name = "hash-db" version = "0.9.0" @@ -1115,6 +1199,22 @@ dependencies = [ "either 1.5.0 (registry+https://github.com/rust-lang/crates.io-index)", ] +[[package]] +name = "itertools" +version = "0.7.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "either 1.5.0 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "itertools-num" +version = "0.1.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "num-traits 0.2.6 (registry+https://github.com/rust-lang/crates.io-index)", +] + [[package]] name = "itoa" version = "0.4.3" @@ -2200,6 +2300,21 @@ name = "percent-encoding" version = "1.0.1" source = "registry+https://github.com/rust-lang/crates.io-index" +[[package]] +name = "pest" +version = "1.0.6" +source = "registry+https://github.com/rust-lang/crates.io-index" + +[[package]] +name = "pest_derive" +version = "1.0.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "pest 1.0.6 (registry+https://github.com/rust-lang/crates.io-index)", + "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)", +] + [[package]] name = "pkg-config" version = "0.3.14" @@ -2289,6 +2404,11 @@ name = "quick-error" version = "1.2.2" source = "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" @@ -2608,6 +2728,14 @@ name = "safemem" version = "0.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" +[[package]] +name = "same-file" +version = "1.0.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "winapi-util 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)", +] + [[package]] name = "schannel" version = "0.1.14" @@ -2742,6 +2870,16 @@ dependencies = [ "time 0.1.41 (registry+https://github.com/rust-lang/crates.io-index)", ] +[[package]] +name = "simplelog" +version = "0.5.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "chrono 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)", + "log 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)", + "term 0.5.1 (registry+https://github.com/rust-lang/crates.io-index)", +] + [[package]] name = "slab" version = "0.4.1" @@ -2796,6 +2934,7 @@ name = "sr-api-macros" version = "0.1.0" dependencies = [ "blake2-rfc 0.2.18 (registry+https://github.com/rust-lang/crates.io-index)", + "criterion 0.2.5 (registry+https://github.com/rust-lang/crates.io-index)", "proc-macro2 0.4.24 (registry+https://github.com/rust-lang/crates.io-index)", "quote 0.6.10 (registry+https://github.com/rust-lang/crates.io-index)", "sr-primitives 0.1.0", @@ -3951,6 +4090,16 @@ name = "subtle" version = "2.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.13.11" @@ -3981,6 +4130,14 @@ 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.1" @@ -4044,6 +4201,15 @@ dependencies = [ "winapi 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)", ] +[[package]] +name = "term" +version = "0.5.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "byteorder 1.2.7 (registry+https://github.com/rust-lang/crates.io-index)", + "winapi 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)", +] + [[package]] name = "termcolor" version = "1.0.4" @@ -4445,6 +4611,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" @@ -4539,6 +4710,16 @@ dependencies = [ "glob 0.2.11 (registry+https://github.com/rust-lang/crates.io-index)", ] +[[package]] +name = "walkdir" +version = "2.2.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "same-file 1.0.4 (registry+https://github.com/rust-lang/crates.io-index)", + "winapi 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)", + "winapi-util 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)", +] + [[package]] name = "want" version = "0.0.6" @@ -4743,6 +4924,7 @@ dependencies = [ "checksum byteorder 1.2.7 (registry+https://github.com/rust-lang/crates.io-index)" = "94f88df23a25417badc922ab0f5716cc1330e87f71ddd9203b3a3ccd9cedf75d" "checksum bytes 0.4.11 (registry+https://github.com/rust-lang/crates.io-index)" = "40ade3d27603c2cb345eb0912aec461a6dec7e06a4ae48589904e808335c7afa" "checksum cast 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "011941fb53da1a8ac3e4132a1becc367c44fe13f630769f3143d8c66c91c6cb6" +"checksum cast 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)" = "926013f2860c46252efceabb19f4a6b308197505082c609025aa6706c011d427" "checksum cc 1.0.28 (registry+https://github.com/rust-lang/crates.io-index)" = "bb4a8b715cb4597106ea87c7c84b2f1d452c7492033765df7f32651e66fcf749" "checksum cexpr 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)" = "8fc0086be9ca82f7fc89fc873435531cb898b86e850005850de1f820e2db6e9b" "checksum cfg-if 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)" = "082bb9b28e00d3c9d39cc03e64ce4cea0f1bb9b3fde493f0cbc008472d22bdf4" @@ -4756,8 +4938,11 @@ dependencies = [ "checksum core-foundation 0.5.1 (registry+https://github.com/rust-lang/crates.io-index)" = "286e0b41c3a20da26536c6000a280585d519fd07b3956b43aed8a79e9edce980" "checksum core-foundation-sys 0.5.1 (registry+https://github.com/rust-lang/crates.io-index)" = "716c271e8613ace48344f723b60b900a93150271e5be206212d052bbc0883efa" "checksum criterion 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)" = "f58b0200bf321214bdda8c797cf0071bcc638171c40ec198c3f652a4edaacde3" +"checksum criterion 0.2.5 (registry+https://github.com/rust-lang/crates.io-index)" = "c47d2b548c5647e1a436dc0cb78d4ebf51b6bf7ab101ed76662828bdd4d3a24a" "checksum criterion-plot 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)" = "885431f7865f9d4956b466126674e5ea40a0f193d42157e56630c356c5501957" +"checksum criterion-plot 0.2.7 (registry+https://github.com/rust-lang/crates.io-index)" = "dd5f81689739e463ece7a6b62c6ec63bdab5c4e28fe05ff451769e87d1511411" "checksum criterion-stats 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)" = "c71521cb4c7b7eac76b540e75447fb0172c4234d6333729001b886aaa21d6da4" +"checksum criterion-stats 0.2.5 (registry+https://github.com/rust-lang/crates.io-index)" = "ff43cac80562f91ead0b617c1be74edf350adfaa195809d355de98dfc8f9237d" "checksum crossbeam 0.6.0 (registry+https://github.com/rust-lang/crates.io-index)" = "ad4c7ea749d9fb09e23c5cb17e3b70650860553a0e2744e38446b1803bf7db94" "checksum crossbeam-channel 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)" = "137bc235f622ffaa0428e3854e24acb53291fc0b3ff6fb2cb75a8be6fb02f06b" "checksum crossbeam-deque 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "f739f8c5363aca78cfb059edf753d8f0d36908c348f3d8d1503f03d8b75d9cf3" @@ -4770,6 +4955,8 @@ dependencies = [ "checksum crunchy 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)" = "c240f247c278fa08a6d4820a6a222bfc6e0d999e51ba67be94f44c905b2161f2" "checksum crypto-mac 0.6.2 (registry+https://github.com/rust-lang/crates.io-index)" = "7afa06d05a046c7a47c3a849907ec303504608c927f4e85f7bfff22b7180d971" "checksum crypto-mac 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)" = "4434400df11d95d556bac068ddfedd482915eb18fe8bea89bc80b6e4b1c179e5" +"checksum csv 1.0.5 (registry+https://github.com/rust-lang/crates.io-index)" = "9fd1c44c58078cfbeaf11fbb3eac9ae5534c23004ed770cc4bfb48e658ae4f04" +"checksum csv-core 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)" = "fa5cdef62f37e6ffe7d1f07a381bc0db32b7a3ff1cac0de56cb0d81e71f53d65" "checksum ctr 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "4b669fcb8e20124db86dbd9b01e74ec0e9e420e65381311ce5249864fc7ff0c0" "checksum ctrlc 3.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "630391922b1b893692c6334369ff528dcc3a9d8061ccf4c803aa8f83cb13db5e" "checksum cuckoofilter 0.3.2 (registry+https://github.com/rust-lang/crates.io-index)" = "8dd43f7cfaffe0a386636a10baea2ee05cc50df3b77bea4a456c9572a939bf1f" @@ -4812,6 +4999,7 @@ dependencies = [ "checksum glob 0.2.11 (registry+https://github.com/rust-lang/crates.io-index)" = "8be18de09a56b60ed0edf84bc9df007e30040691af7acd1c41874faac5895bfb" "checksum globset 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)" = "4743617a7464bbda3c8aec8558ff2f9429047e025771037df561d383337ff865" "checksum h2 0.1.14 (registry+https://github.com/rust-lang/crates.io-index)" = "1ac030ae20dee464c5d0f36544d8b914a6bc606da44a57e052d2b0f5dae129e0" +"checksum handlebars 0.32.4 (registry+https://github.com/rust-lang/crates.io-index)" = "d89ec99d1594f285d4590fc32bac5f75cdab383f1123d504d27862c644a807dd" "checksum hash-db 0.9.0 (git+https://github.com/paritytech/trie)" = "" "checksum hash256-std-hasher 0.9.0 (git+https://github.com/paritytech/trie)" = "" "checksum heapsize 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)" = "1679e6ea370dee694f91f1dc469bf94cf8f52051d147aec3e1f9497c6fc22461" @@ -4835,6 +5023,8 @@ dependencies = [ "checksum isatty 0.1.9 (registry+https://github.com/rust-lang/crates.io-index)" = "e31a8281fc93ec9693494da65fbf28c0c2aa60a2eaec25dc58e2f31952e95edc" "checksum itertools 0.4.19 (registry+https://github.com/rust-lang/crates.io-index)" = "c4a9b56eb56058f43dc66e58f40a214b2ccbc9f3df51861b63d51dec7b65bc3f" "checksum itertools 0.5.10 (registry+https://github.com/rust-lang/crates.io-index)" = "4833d6978da405305126af4ac88569b5d71ff758581ce5a987dbfa3755f694fc" +"checksum itertools 0.7.11 (registry+https://github.com/rust-lang/crates.io-index)" = "0d47946d458e94a1b7bcabbf6521ea7c037062c81f534615abcad76e84d4970d" +"checksum itertools-num 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)" = "a872a22f9e6f7521ca557660adb96dd830e54f0f490fa115bb55dd69d38b27e7" "checksum itoa 0.4.3 (registry+https://github.com/rust-lang/crates.io-index)" = "1306f3464951f30e30d12373d31c79fbd52d236e5e896fd92f96ec7babbbe60b" "checksum jsonrpc-core 9.0.0 (git+https://github.com/paritytech/jsonrpc.git)" = "" "checksum jsonrpc-http-server 9.0.0 (git+https://github.com/paritytech/jsonrpc.git)" = "" @@ -4927,6 +5117,8 @@ dependencies = [ "checksum parking_lot_core 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "94c8c7923936b28d546dfd14d4472eaf34c99b14e1c973a32b3e6d4eb04298c9" "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 pest 1.0.6 (registry+https://github.com/rust-lang/crates.io-index)" = "0fce5d8b5cc33983fc74f78ad552b5522ab41442c4ca91606e4236eb4b5ceefc" +"checksum pest_derive 1.0.8 (registry+https://github.com/rust-lang/crates.io-index)" = "ca3294f437119209b084c797604295f40227cffa35c57220b1e99a6ff3bf8ee4" "checksum pkg-config 0.3.14 (registry+https://github.com/rust-lang/crates.io-index)" = "676e8eb2b1b4c9043511a9b7bea0915320d7e502b0a079fb03f9635a5252b18c" "checksum pretty_assertions 0.4.1 (registry+https://github.com/rust-lang/crates.io-index)" = "28ea5118e2f41bfbc974b28d88c07621befd1fa5d6ec23549be96302a1a59dd2" "checksum pretty_assertions 0.5.1 (registry+https://github.com/rust-lang/crates.io-index)" = "3a029430f0d744bc3d15dd474d591bed2402b645d024583082b9f63bb936dac6" @@ -4939,6 +5131,7 @@ dependencies = [ "checksum pwasm-utils 0.6.2 (registry+https://github.com/rust-lang/crates.io-index)" = "efb0dcbddbb600f47a7098d33762a00552c671992171637f5bb310b37fe1f0e4" "checksum quick-error 0.1.4 (registry+https://github.com/rust-lang/crates.io-index)" = "5fb6ccf8db7bbcb9c2eae558db5ab4f3da1c2a87e4e597ed394726bc8ea6ca1d" "checksum quick-error 1.2.2 (registry+https://github.com/rust-lang/crates.io-index)" = "9274b940887ce9addde99c4eee6b5c44cc494b182b97e73dc8ffdcb3397fd3f0" +"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.10 (registry+https://github.com/rust-lang/crates.io-index)" = "53fa22a1994bd0f9372d7a816207d8a2677ad0325b073f5c5332760f0fb62b5c" "checksum rand 0.3.22 (registry+https://github.com/rust-lang/crates.io-index)" = "15a732abf9d20f0ad8eeb6f909bf6868722d9a06e1e50802b6a70351f40b4eb1" @@ -4976,6 +5169,7 @@ dependencies = [ "checksum ryu 0.2.7 (registry+https://github.com/rust-lang/crates.io-index)" = "eb9e9b8cde282a9fe6a42dd4681319bfb63f121b8a8ee9439c6f4107e58a46f7" "checksum safe-mix 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)" = "7f7bf422d23a88c16d5090d455f182bc99c60af4df6a345c63428acf5129e347" "checksum safemem 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)" = "8dca453248a96cb0749e36ccdfe2b0b4e54a61bfef89fb97ec621eb8e0a93dd9" +"checksum same-file 1.0.4 (registry+https://github.com/rust-lang/crates.io-index)" = "8f20c4be53a8a1ff4c1f1b2bd14570d2f634628709752f0702ecdd2b3f9a5267" "checksum schannel 0.1.14 (registry+https://github.com/rust-lang/crates.io-index)" = "0e1a231dc10abf6749cfa5d7767f25888d484201accbd919b66ab5413c502d56" "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" @@ -4992,6 +5186,7 @@ dependencies = [ "checksum sha2 0.8.0 (registry+https://github.com/rust-lang/crates.io-index)" = "7b4d8bfd0e469f417657573d8451fb33d16cfe0989359b93baf3a1ffc639543d" "checksum shell32-sys 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)" = "9ee04b46101f57121c9da2b151988283b6beb79b34f5bb29a58ee48cb695122c" "checksum simplelog 0.4.4 (registry+https://github.com/rust-lang/crates.io-index)" = "24b615b1a3cc51ffa565d9a1d0cfcc49fe7d64737ada84eca284cddb0292d125" +"checksum simplelog 0.5.3 (registry+https://github.com/rust-lang/crates.io-index)" = "2e95345f185d5adeb8ec93459d2dc99654e294cc6ccf5b75414d8ea262de9a13" "checksum slab 0.4.1 (registry+https://github.com/rust-lang/crates.io-index)" = "5f9776d6b986f77b35c6cf846c11ad986ff128fe0b2b63a3628e3755e8d3102d" "checksum slog 2.4.1 (registry+https://github.com/rust-lang/crates.io-index)" = "1e1a2eec401952cd7b12a84ea120e2d57281329940c3f93c2bf04f462539508e" "checksum slog-async 2.3.0 (registry+https://github.com/rust-lang/crates.io-index)" = "e544d16c6b230d84c866662fe55e31aacfca6ae71e6fc49ae9a311cb379bfc2f" @@ -5011,9 +5206,11 @@ dependencies = [ "checksum structopt-derive 0.2.14 (registry+https://github.com/rust-lang/crates.io-index)" = "ef98172b1a00b0bec738508d3726540edcbd186d50dfd326f2b1febbb3559f04" "checksum subtle 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)" = "2d67a5a62ba6e01cb2192ff309324cb4875d0c451d55fe2319433abe7a05a8ee" "checksum subtle 2.0.0 (registry+https://github.com/rust-lang/crates.io-index)" = "702662512f3ddeb74a64ce2fbbf3707ee1b6bb663d28bb054e0779bbc720d926" +"checksum syn 0.11.11 (registry+https://github.com/rust-lang/crates.io-index)" = "d3b891b9015c88c576343b9b3e41c2c11a51c219ef067b264bd9c8aa9b441dad" "checksum syn 0.13.11 (registry+https://github.com/rust-lang/crates.io-index)" = "14f9bf6292f3a61d2c716723fdb789a41bbe104168e6f496dc6497e531ea1b9b" "checksum syn 0.14.9 (registry+https://github.com/rust-lang/crates.io-index)" = "261ae9ecaa397c42b960649561949d69311f08eeaea86a65696e6e46517cf741" "checksum syn 0.15.24 (registry+https://github.com/rust-lang/crates.io-index)" = "734ecc29cd36e8123850d9bf21dfd62ef8300aaa8f879aabaa899721808be37c" +"checksum synom 0.11.3 (registry+https://github.com/rust-lang/crates.io-index)" = "a393066ed9010ebaed60b9eafa373d4b1baac186dd7e008555b0f702b51945b6" "checksum synstructure 0.10.1 (registry+https://github.com/rust-lang/crates.io-index)" = "73687139bf99285483c96ac0add482c3776528beac1d97d444f6e91f203a2015" "checksum sysinfo 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)" = "4c747a1fbe091faa7bf76c19f40099f9f12495384c811485d81cf3d60c0eae62" "checksum take_mut 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)" = "f764005d11ee5f36500a149ace24e00e3da98b0158b3e2d53a7495660d3f4d60" @@ -5021,6 +5218,7 @@ dependencies = [ "checksum tempdir 0.3.7 (registry+https://github.com/rust-lang/crates.io-index)" = "15f2b5fb00ccdf689e0149d1b1b3c03fead81c2b37735d812fa8bddbbf41b6d8" "checksum tempfile 3.0.5 (registry+https://github.com/rust-lang/crates.io-index)" = "7e91405c14320e5c79b3d148e1c86f40749a36e490642202a31689cb1a3452b2" "checksum term 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)" = "fa63644f74ce96fbeb9b794f66aff2a52d601cbd5e80f4b97123e3899f4570f1" +"checksum term 0.5.1 (registry+https://github.com/rust-lang/crates.io-index)" = "5e6b677dd1e8214ea1ef4297f85dbcbed8e8cdddb561040cc998ca2551c37561" "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" "checksum textwrap 0.10.0 (registry+https://github.com/rust-lang/crates.io-index)" = "307686869c93e71f94da64286f9a9524c0f308a9e1c87a583de8e9c9039ad3f6" @@ -5062,6 +5260,7 @@ dependencies = [ "checksum unicode-normalization 0.1.7 (registry+https://github.com/rust-lang/crates.io-index)" = "6a0180bc61fc5a987082bfa111f4cc95c4caff7f9799f3e46df09163a937aa25" "checksum unicode-segmentation 1.2.1 (registry+https://github.com/rust-lang/crates.io-index)" = "aa6024fc12ddfd1c6dbc14a80fa2324d4568849869b779f6bd37e5e4c03344d1" "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 unreachable 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)" = "382810877fe448991dfc7f0dd6e3ae5d58088fd0ea5e35189655f84e6814fa56" "checksum unsigned-varint 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)" = "5fb8abc4b7d8158bdfbbaaccc35331ed3c30c2673e99000d7ae665a2eb6576f4" @@ -5075,6 +5274,7 @@ dependencies = [ "checksum void 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)" = "6a02e4885ed3bc0f2de90ea6dd45ebcbb66dacffe03547fadbb0eeae2770887d" "checksum wabt 0.7.4 (registry+https://github.com/rust-lang/crates.io-index)" = "74e463a508e390cc7447e70f640fbf44ad52e1bd095314ace1fdf99516d32add" "checksum wabt-sys 0.5.3 (registry+https://github.com/rust-lang/crates.io-index)" = "462336bb61096e64761730e0dea1bc8b777bd4e3689c7e813c81f1cfdf4e8a51" +"checksum walkdir 2.2.7 (registry+https://github.com/rust-lang/crates.io-index)" = "9d9d7ed3431229a144296213105a390676cc49c9b6a72bd19f3176c98e129fa1" "checksum want 0.0.6 (registry+https://github.com/rust-lang/crates.io-index)" = "797464475f30ddb8830cc529aaaae648d581f99e2036a928877dfde027ddf6b3" "checksum wasmi 0.4.3 (registry+https://github.com/rust-lang/crates.io-index)" = "21ef487a11df1ed468cf613c78798c26282da5c30e9d49f824872d4c77b47d1d" "checksum websocket 0.21.1 (registry+https://github.com/rust-lang/crates.io-index)" = "8c9faed2bff8af2ea6b9f8b917d3d00b467583f6781fe3def174a9e33c879703" diff --git a/substrate/core/basic-authorship/src/basic_authorship.rs b/substrate/core/basic-authorship/src/basic_authorship.rs index e524b6aa9e..d3b6421e6a 100644 --- a/substrate/core/basic-authorship/src/basic_authorship.rs +++ b/substrate/core/basic-authorship/src/basic_authorship.rs @@ -22,8 +22,10 @@ use std::sync::Arc; use std::time; use std; -use client::{self, error, Client as SubstrateClient, CallExecutor}; -use client::{block_builder::api::BlockBuilder as BlockBuilderApi, runtime_api::Core}; +use client::{ + self, error, Client as SubstrateClient, CallExecutor, + block_builder::api::BlockBuilder as BlockBuilderApi, runtime_api::{Core, ApiExt} +}; use codec::{Decode, Encode}; use consensus_common::{self, evaluation}; use primitives::{H256, Blake2Hasher}; @@ -68,7 +70,9 @@ where B: client::backend::Backend + 'static, E: CallExecutor + Send + Sync + Clone + 'static, Block: BlockT, - RA: BlockBuilderApi, + RA: Send + Sync + 'static, + SubstrateClient : ProvideRuntimeApi, + as ProvideRuntimeApi>::Api: BlockBuilderApi, { fn push_extrinsic(&mut self, extrinsic: ::Extrinsic) -> Result<(), error::Error> { client::block_builder::BlockBuilder::push(self, extrinsic).map_err(Into::into) @@ -79,7 +83,9 @@ impl AuthoringApi for SubstrateClient where B: client::backend::Backend + Send + Sync + 'static, E: CallExecutor + Send + Sync + Clone + 'static, Block: BlockT, - RA: BlockBuilderApi, + RA: Send + Sync + 'static, + SubstrateClient : ProvideRuntimeApi, + as ProvideRuntimeApi>::Api: BlockBuilderApi, { type Block = Block; type Error = client::error::Error; @@ -94,7 +100,7 @@ impl AuthoringApi for SubstrateClient where let runtime_api = self.runtime_api(); if runtime_api.has_api::>(at)? { - runtime_api.inherent_extrinsics(at, &inherent_data)? + runtime_api.inherent_extrinsics(at, inherent_data)? .into_iter().try_for_each(|i| block_builder.push(i))?; } diff --git a/substrate/core/client/src/block_builder/block_builder.rs b/substrate/core/client/src/block_builder/block_builder.rs index ac09f1e871..a0e9d67827 100644 --- a/substrate/core/client/src/block_builder/block_builder.rs +++ b/substrate/core/client/src/block_builder/block_builder.rs @@ -84,12 +84,12 @@ where /// the error. Otherwise, it will return a mutable reference to self (in order to chain). pub fn push(&mut self, xt: ::Extrinsic) -> error::Result<()> { use crate::runtime_api::ApiExt; - + let block_id = &self.block_id; let extrinsics = &mut self.extrinsics; - + self.api.map_api_result(|api| { - match api.apply_extrinsic(block_id, &xt)? { + match api.apply_extrinsic(block_id, xt.clone())? { Ok(ApplyOutcome::Success) | Ok(ApplyOutcome::Fail) => { extrinsics.push(xt); Ok(()) diff --git a/substrate/core/client/src/call_executor.rs b/substrate/core/client/src/call_executor.rs index 9872cdd97e..263c43596b 100644 --- a/substrate/core/client/src/call_executor.rs +++ b/substrate/core/client/src/call_executor.rs @@ -14,17 +14,17 @@ // You should have received a copy of the GNU General Public License // along with Substrate. If not, see . -use std::sync::Arc; -use std::cmp::Ord; -use codec::Encode; +use std::{sync::Arc, cmp::Ord, panic::UnwindSafe}; +use codec::{Encode, Decode}; use runtime_primitives::generic::BlockId; use runtime_primitives::traits::Block as BlockT; -use state_machine::{self, OverlayedChanges, Ext, - CodeExecutor, ExecutionManager, native_when_possible}; +use state_machine::{ + self, OverlayedChanges, Ext, CodeExecutor, ExecutionManager, native_when_possible +}; use executor::{RuntimeVersion, RuntimeInfo, NativeVersion}; use hash_db::Hasher; use trie::MemoryDB; -use primitives::{H256, Blake2Hasher}; +use primitives::{H256, Blake2Hasher, NativeOrEncoded, NeverNativeValue}; use crate::backend; use crate::error; @@ -56,7 +56,12 @@ where /// of the execution context. fn contextual_call< PB: Fn() -> error::Result, - EM: Fn(Result, Self::Error>, Result, Self::Error>) -> Result, Self::Error>, + EM: Fn( + Result, Self::Error>, + Result, Self::Error> + ) -> Result, Self::Error>, + R: Encode + Decode + PartialEq, + NC: FnOnce() -> R + UnwindSafe, >( &self, at: &BlockId, @@ -66,7 +71,8 @@ where initialised_block: &mut Option>, prepare_environment_block: PB, manager: ExecutionManager, - ) -> error::Result> where ExecutionManager: Clone; + native_call: Option, + ) -> error::Result> where ExecutionManager: Clone; /// Extract RuntimeVersion of given block /// @@ -78,14 +84,20 @@ where /// No changes are made. fn call_at_state< S: state_machine::Backend, - F: FnOnce(Result, Self::Error>, Result, Self::Error>) -> Result, Self::Error>, + F: FnOnce( + Result, Self::Error>, + Result, Self::Error> + ) -> Result, Self::Error>, + R: Encode + Decode + PartialEq, + NC: FnOnce() -> R + UnwindSafe, >(&self, state: &S, overlay: &mut OverlayedChanges, method: &str, call_data: &[u8], - manager: ExecutionManager - ) -> Result<(Vec, S::Transaction, Option>), error::Error>; + manager: ExecutionManager, + native_call: Option, + ) -> Result<(NativeOrEncoded, S::Transaction, Option>), error::Error>; /// Execute a call to a contract on top of given state, gathering execution proof. /// @@ -155,7 +167,9 @@ where ) -> error::Result> { let mut changes = OverlayedChanges::default(); let state = self.backend.state_at(*id)?; - let return_data = state_machine::execute_using_consensus_failure_handler( + let return_data = state_machine::execute_using_consensus_failure_handler::< + _, _, _, _, _, _, fn() -> NeverNativeValue + >( &state, self.backend.changes_trie_storage(), &mut changes, @@ -164,15 +178,21 @@ where call_data, native_when_possible(), false, + None, ) .map(|(result, _, _)| result)?; self.backend.destroy_state(state)?; - Ok(return_data) + Ok(return_data.into_encoded()) } fn contextual_call< PB: Fn() -> error::Result, - EM: Fn(Result, Self::Error>, Result, Self::Error>) -> Result, Self::Error>, + EM: Fn( + Result, Self::Error>, + Result, Self::Error> + ) -> Result, Self::Error>, + R: Encode + Decode + PartialEq, + NC: FnOnce() -> R + UnwindSafe, >( &self, at: &BlockId, @@ -182,12 +202,15 @@ where initialised_block: &mut Option>, prepare_environment_block: PB, manager: ExecutionManager, - ) -> Result, error::Error> where ExecutionManager: Clone { + native_call: Option, + ) -> Result, error::Error> where ExecutionManager: Clone { let state = self.backend.state_at(*at)?; //TODO: Find a better way to prevent double block initialization if method != "Core_initialise_block" && initialised_block.map(|id| id != *at).unwrap_or(true) { let header = prepare_environment_block()?; - state_machine::execute_using_consensus_failure_handler( + state_machine::execute_using_consensus_failure_handler::< + _, _, _, _, _, R, fn() -> R, + >( &state, self.backend.changes_trie_storage(), changes, @@ -196,6 +219,7 @@ where &header.encode(), manager.clone(), false, + None, )?; *initialised_block = Some(*at); } @@ -209,8 +233,8 @@ where call_data, manager, false, - ) - .map(|(result, _, _)| result)?; + native_call, + ).map(|(result, _, _)| result)?; self.backend.destroy_state(state)?; Ok(result) @@ -226,14 +250,20 @@ where fn call_at_state< S: state_machine::Backend, - F: FnOnce(Result, Self::Error>, Result, Self::Error>) -> Result, Self::Error>, + F: FnOnce( + Result, Self::Error>, + Result, Self::Error> + ) -> Result, Self::Error>, + R: Encode + Decode + PartialEq, + NC: FnOnce() -> R + UnwindSafe, >(&self, state: &S, changes: &mut OverlayedChanges, method: &str, call_data: &[u8], manager: ExecutionManager, - ) -> error::Result<(Vec, S::Transaction, Option>)> { + native_call: Option, + ) -> error::Result<(NativeOrEncoded, S::Transaction, Option>)> { state_machine::execute_using_consensus_failure_handler( state, self.backend.changes_trie_storage(), @@ -243,6 +273,7 @@ where call_data, manager, true, + native_call, ) .map(|(result, storage_tx, changes_tx)| ( result, diff --git a/substrate/core/client/src/client.rs b/substrate/core/client/src/client.rs index 10e1570934..67052ff7f1 100644 --- a/substrate/core/client/src/client.rs +++ b/substrate/core/client/src/client.rs @@ -16,25 +16,29 @@ //! Substrate Client -use std::{marker::PhantomData, collections::{HashSet, BTreeMap}, sync::Arc}; +use std::{marker::PhantomData, collections::{HashSet, BTreeMap}, sync::Arc, panic::UnwindSafe}; use crate::error::Error; use futures::sync::mpsc; use parking_lot::{Mutex, RwLock}; +use primitives::NativeOrEncoded; use runtime_primitives::{ Justification, generic::{BlockId, SignedBlock}, }; -use consensus::{Error as ConsensusError, ErrorKind as ConsensusErrorKind, ImportBlock, ImportResult, BlockOrigin, ForkChoiceStrategy}; +use consensus::{ + Error as ConsensusError, ErrorKind as ConsensusErrorKind, ImportBlock, ImportResult, + BlockOrigin, ForkChoiceStrategy +}; use runtime_primitives::traits::{ Block as BlockT, Header as HeaderT, Zero, As, NumberFor, CurrentHeight, BlockNumberToHash, ApiRef, ProvideRuntimeApi, Digest, DigestItem, AuthorityIdFor }; use runtime_primitives::BuildStorage; -use crate::runtime_api::{Core as CoreAPI, CallRuntimeAt, ConstructRuntimeApi}; -use primitives::{Blake2Hasher, H256, ChangesTrieConfiguration, convert_hash}; +use crate::runtime_api::{CallRuntimeAt, ConstructRuntimeApi}; +use primitives::{Blake2Hasher, H256, ChangesTrieConfiguration, convert_hash, NeverNativeValue}; use primitives::storage::{StorageKey, StorageData}; use primitives::storage::well_known_keys; -use codec::Decode; +use codec::{Encode, Decode}; use state_machine::{ DBValue, Backend as StateBackend, CodeExecutor, ChangesTrieAnchorBlockId, ExecutionStrategy, ExecutionManager, prove_read, @@ -557,7 +561,9 @@ impl Client where &self ) -> error::Result> where E: Clone + Send + Sync, - RA: BlockBuilderAPI + RA: Send + Sync, + Self: ProvideRuntimeApi, + ::Api: BlockBuilderAPI { block_builder::BlockBuilder::new(self) } @@ -567,7 +573,9 @@ impl Client where &self, parent: &BlockId ) -> error::Result> where E: Clone + Send + Sync, - RA: BlockBuilderAPI + RA: Send + Sync, + Self: ProvideRuntimeApi, + ::Api: BlockBuilderAPI { block_builder::BlockBuilder::at_block(parent, &self) } @@ -615,7 +623,7 @@ impl Client where let (storage_update, changes_update, storage_changes) = match transaction.state()? { Some(transaction_state) => { let mut overlay = Default::default(); - let r = self.executor.call_at_state( + let r = self.executor.call_at_state::<_, _, NeverNativeValue, fn() -> NeverNativeValue>( transaction_state, &mut overlay, "Core_execute_block", @@ -638,6 +646,7 @@ impl Client where wasm_result }), }, + None, ); let (_, storage_update, changes_update) = r?; overlay.commit_prospective(); @@ -1017,30 +1026,29 @@ impl ProvideRuntimeApi for Client where B: backend::Backend, E: CallExecutor + Clone + Send + Sync, Block: BlockT, - RA: CoreAPI + RA: ConstructRuntimeApi { - type Api = RA; + type Api = >::RuntimeApi; fn runtime_api<'a>(&'a self) -> ApiRef<'a, Self::Api> { - Self::Api::construct_runtime_api(self) + RA::construct_runtime_api(self) } } impl CallRuntimeAt for Client where B: backend::Backend, E: CallExecutor + Clone + Send + Sync, - Block: BlockT, - RA: CoreAPI, // not strictly necessary at the moment - // but we want to bound to make sure the API is actually available. + Block: BlockT { - fn call_api_at( + fn call_api_at R + UnwindSafe>( &self, at: &BlockId, function: &'static str, args: Vec, changes: &mut OverlayedChanges, initialised_block: &mut Option>, - ) -> error::Result> { + native_call: Option, + ) -> error::Result> { let execution_manager = match self.api_execution_strategy { ExecutionStrategy::NativeWhenPossible => ExecutionManager::NativeWhenPossible, ExecutionStrategy::AlwaysWasm => ExecutionManager::AlwaysWasm, @@ -1053,8 +1061,16 @@ impl CallRuntimeAt for Client where }), }; - self.executor.contextual_call(at, function, &args, changes, initialised_block, - || self.prepare_environment_block(at), execution_manager) + self.executor.contextual_call( + at, + function, + &args, + changes, + initialised_block, + || self.prepare_environment_block(at), + execution_manager, + native_call, + ) } fn runtime_version_at(&self, at: &BlockId) -> error::Result { @@ -1268,7 +1284,7 @@ pub(crate) mod tests { use consensus::BlockOrigin; use test_client::client::{backend::Backend as TestBackend, runtime_api::ApiExt}; use test_client::BlockBuilderExt; - use test_client::runtime::{self, Block, Transfer, RuntimeApi, test_api::TestAPI}; + use test_client::runtime::{self, Block, Transfer, RuntimeApi, TestAPI}; /// Returns tuple, consisting of: /// 1) test client pre-filled with blocks changing balances; @@ -1350,14 +1366,14 @@ pub(crate) mod tests { assert_eq!( client.runtime_api().balance_of( &BlockId::Number(client.info().unwrap().chain.best_number), - &Keyring::Alice.to_raw_public().into() + Keyring::Alice.to_raw_public().into() ).unwrap(), 1000 ); assert_eq!( client.runtime_api().balance_of( &BlockId::Number(client.info().unwrap().chain.best_number), - &Keyring::Ferdie.to_raw_public().into() + Keyring::Ferdie.to_raw_public().into() ).unwrap(), 0 ); @@ -1417,14 +1433,14 @@ pub(crate) mod tests { assert_eq!( client.runtime_api().balance_of( &BlockId::Number(client.info().unwrap().chain.best_number), - &Keyring::Alice.to_raw_public().into() + Keyring::Alice.to_raw_public().into() ).unwrap(), 958 ); assert_eq!( client.runtime_api().balance_of( &BlockId::Number(client.info().unwrap().chain.best_number), - &Keyring::Ferdie.to_raw_public().into() + Keyring::Ferdie.to_raw_public().into() ).unwrap(), 42 ); diff --git a/substrate/core/client/src/light/call_executor.rs b/substrate/core/client/src/light/call_executor.rs index 2f748ca0a8..734a1994bf 100644 --- a/substrate/core/client/src/light/call_executor.rs +++ b/substrate/core/client/src/light/call_executor.rs @@ -17,13 +17,11 @@ //! Light client call exector. Executes methods on remote full nodes, fetching //! execution proof and checking it locally. -use std::collections::HashSet; -use std::marker::PhantomData; -use std::sync::Arc; +use std::{collections::HashSet, marker::PhantomData, sync::Arc}; use futures::{IntoFuture, Future}; use codec::{Encode, Decode}; -use primitives::{H256, Blake2Hasher, convert_hash}; +use primitives::{H256, Blake2Hasher, convert_hash, NativeOrEncoded}; use runtime_primitives::generic::BlockId; use runtime_primitives::traits::{As, Block as BlockT, Header as HeaderT}; use state_machine::{self, Backend as StateBackend, CodeExecutor, OverlayedChanges, @@ -88,7 +86,12 @@ where fn contextual_call< PB: Fn() -> ClientResult, - EM: Fn(Result, Self::Error>, Result, Self::Error>) -> Result, Self::Error>, + EM: Fn( + Result, Self::Error>, + Result, Self::Error> + ) -> Result, Self::Error>, + R: Encode + Decode + PartialEq, + NC, >( &self, at: &BlockId, @@ -98,13 +101,14 @@ where initialised_block: &mut Option>, _prepare_environment_block: PB, _manager: ExecutionManager, - ) -> ClientResult> where ExecutionManager: Clone { + _native_call: Option, + ) -> ClientResult> where ExecutionManager: Clone { // it is only possible to execute contextual call if changes are empty if !changes.is_empty() || initialised_block.is_some() { return Err(ClientErrorKind::NotAvailableOnLightClient.into()); } - self.call(at, method, call_data) + self.call(at, method, call_data).map(NativeOrEncoded::Encoded) } fn runtime_version(&self, id: &BlockId) -> ClientResult { @@ -115,14 +119,20 @@ where fn call_at_state< S: StateBackend, - FF: FnOnce(Result, Self::Error>, Result, Self::Error>) -> Result, Self::Error> + FF: FnOnce( + Result, Self::Error>, + Result, Self::Error> + ) -> Result, Self::Error>, + R: Encode + Decode + PartialEq, + NC: FnOnce() -> R, >(&self, _state: &S, _changes: &mut OverlayedChanges, _method: &str, _call_data: &[u8], - _m: ExecutionManager - ) -> ClientResult<(Vec, S::Transaction, Option>)> { + _m: ExecutionManager, + _native_call: Option, + ) -> ClientResult<(NativeOrEncoded, S::Transaction, Option>)> { Err(ClientErrorKind::NotAvailableOnLightClient.into()) } diff --git a/substrate/core/client/src/runtime_api.rs b/substrate/core/client/src/runtime_api.rs index 66d86590f5..fbe5d1378b 100644 --- a/substrate/core/client/src/runtime_api.rs +++ b/substrate/core/client/src/runtime_api.rs @@ -20,6 +20,9 @@ #[cfg(feature = "std")] pub use state_machine::OverlayedChanges; #[doc(hidden)] +#[cfg(feature = "std")] +pub use primitives::NativeOrEncoded; +#[doc(hidden)] pub use runtime_primitives::{ traits::{AuthorityIdFor, Block as BlockT, GetNodeBlockType, GetRuntimeBlockType, ApiRef, RuntimeApiInfo}, generic::BlockId, transaction_validity::TransactionValidity @@ -34,16 +37,19 @@ pub use codec::{Encode, Decode}; #[cfg(feature = "std")] use crate::error; use rstd::vec::Vec; -use primitives::OpaqueMetadata; use sr_api_macros::decl_runtime_apis; +use primitives::OpaqueMetadata; +#[cfg(feature = "std")] +use std::panic::UnwindSafe; /// Something that can be constructed to a runtime api. #[cfg(feature = "std")] -pub trait ConstructRuntimeApi { +pub trait ConstructRuntimeApi> { + /// The actual runtime api that will be constructed. + type RuntimeApi; + /// Construct an instance of the runtime api. - fn construct_runtime_api<'a, T: CallRuntimeAt>( - call: &'a T - ) -> ApiRef<'a, Self> where Self: Sized; + fn construct_runtime_api<'a>(call: &'a C) -> ApiRef<'a, Self::RuntimeApi>; } /// An extension for the `RuntimeApi`. @@ -71,14 +77,15 @@ pub trait ApiExt { pub trait CallRuntimeAt { /// Calls the given api function with the given encoded arguments at the given block /// and returns the encoded result. - fn call_api_at( + fn call_api_at R + UnwindSafe>( &self, at: &BlockId, function: &'static str, args: Vec, changes: &mut OverlayedChanges, initialised_block: &mut Option>, - ) -> error::Result>; + native_call: Option, + ) -> error::Result>; /// Returns the runtime version at the given block. fn runtime_version_at(&self, at: &BlockId) -> error::Result; @@ -95,7 +102,7 @@ decl_runtime_apis! { /// Execute the given block. fn execute_block(block: Block); /// Initialise a block with the given header. - fn initialise_block(header: ::Header); + fn initialise_block(header: &::Header); } /// The `Metadata` api trait that returns metadata for the runtime. diff --git a/substrate/core/consensus/aura/src/lib.rs b/substrate/core/consensus/aura/src/lib.rs index 5906c267b3..374c4d613f 100644 --- a/substrate/core/consensus/aura/src/lib.rs +++ b/substrate/core/consensus/aura/src/lib.rs @@ -492,12 +492,12 @@ impl Verifier for AuraVerifier>( } fn safe_call(f: F) -> Result - where F: ::std::panic::UnwindSafe + FnOnce() -> U + where F: UnwindSafe + FnOnce() -> U { // Substrate uses custom panic hook that terminates process on panic. Disable it for the native call. let hook = ::std::panic::take_hook(); @@ -108,7 +108,7 @@ fn safe_call(f: F) -> Result /// /// If the inner closure panics, it will be caught and return an error. pub fn with_native_environment(ext: &mut Externalities, f: F) -> Result -where F: ::std::panic::UnwindSafe + FnOnce() -> U +where F: UnwindSafe + FnOnce() -> U { ::runtime_io::with_externalities(ext, move || safe_call(f)) } @@ -181,30 +181,78 @@ impl RuntimeInfo for NativeExecutor { impl CodeExecutor for NativeExecutor { type Error = Error; - fn call>( + fn call + < + E: Externalities, + R:Decode + Encode + PartialEq, + NC: FnOnce() -> R + UnwindSafe + >( &self, ext: &mut E, method: &str, data: &[u8], use_native: bool, - ) -> (Result>, bool) { + native_call: Option, + ) -> (Result>, bool) { RUNTIMES_CACHE.with(|c| { let mut c = c.borrow_mut(); let (module, onchain_version) = match fetch_cached_runtime_version(&self.fallback, &mut c, ext) { Ok((module, onchain_version)) => (module, onchain_version), Err(e) => return (Err(e), false), }; - match (use_native, onchain_version.as_ref().map_or(false, |v| v.can_call_with(&self.native_version.runtime_version))) { - (_, false) => { - trace!(target: "executor", "Request for native execution failed (native: {}, chain: {})", self.native_version.runtime_version, onchain_version.as_ref().map_or_else(||"".into(), |v| format!("{}", v))); - (self.fallback.call_in_wasm_module(ext, module, method, data), false) + match ( + use_native, + onchain_version + .as_ref() + .map_or(false, |v| v.can_call_with(&self.native_version.runtime_version)), + native_call, + ) { + (_, false, _) => { + trace!( + target: "executor", + "Request for native execution failed (native: {}, chain: {})", + self.native_version.runtime_version, + onchain_version + .as_ref() + .map_or_else(||"".into(), |v| format!("{}", v)) + ); + ( + self.fallback + .call_in_wasm_module(ext, module, method, data) + .map(NativeOrEncoded::Encoded), + false + ) } - (false, _) => { - (self.fallback.call_in_wasm_module(ext, module, method, data), false) + (false, _, _) => { + ( + self.fallback + .call_in_wasm_module(ext, module, method, data) + .map(NativeOrEncoded::Encoded), + false + ) + } + (true, true, Some(call)) => { + trace!( + target: "executor", + "Request for native execution with native call succeeded (native: {}, chain: {}).", + self.native_version.runtime_version, + onchain_version + .as_ref() + .map_or_else(||"".into(), |v| format!("{}", v)) + ); + ( + with_native_environment(ext, move || (call)()).map(NativeOrEncoded::Native), + true + ) } _ => { - trace!(target: "executor", "Request for native execution succeeded (native: {}, chain: {})", self.native_version.runtime_version, onchain_version.as_ref().map_or_else(||"".into(), |v| format!("{}", v))); - (D::dispatch(ext, method, data), true) + trace!( + target: "executor", + "Request for native execution succeeded (native: {}, chain: {})", + self.native_version.runtime_version, + onchain_version.as_ref().map_or_else(||"".into(), |v| format!("{}", v)) + ); + (D::dispatch(ext, method, data).map(NativeOrEncoded::Encoded), true) } } }) diff --git a/substrate/core/finality-grandpa/primitives/src/lib.rs b/substrate/core/finality-grandpa/primitives/src/lib.rs index 8776c262a0..6e8c10da31 100644 --- a/substrate/core/finality-grandpa/primitives/src/lib.rs +++ b/substrate/core/finality-grandpa/primitives/src/lib.rs @@ -53,14 +53,6 @@ pub const PENDING_CHANGE_CALL: &str = "grandpa_pending_change"; /// WASM function call to get current GRANDPA authorities. pub const AUTHORITIES_CALL: &str = "grandpa_authorities"; -/// The ApiIds for GRANDPA API. -pub mod id { - use client::runtime_api::ApiId; - - /// ApiId for the GrandpaApi trait. - pub const GRANDPA_API: ApiId = *b"fgrandpa"; -} - /// Well-known storage keys for GRANDPA. pub mod well_known_keys { /// The key for the authorities and weights vector in storage. @@ -92,7 +84,7 @@ decl_runtime_apis! { /// This should be a pure function: i.e. as long as the runtime can interpret /// the digest type it should return the same result regardless of the current /// state. - fn grandpa_pending_change(digest: DigestFor) + fn grandpa_pending_change(digest: &DigestFor) -> Option>>; /// Get the current GRANDPA authorities and weights. This should not change except diff --git a/substrate/core/finality-grandpa/src/tests.rs b/substrate/core/finality-grandpa/src/tests.rs index 344958c044..d973481af2 100644 --- a/substrate/core/finality-grandpa/src/tests.rs +++ b/substrate/core/finality-grandpa/src/tests.rs @@ -26,7 +26,7 @@ use keyring::Keyring; use client::{ BlockchainEvents, error::Result, blockchain::Backend as BlockchainBackend, - runtime_api::{Core, RuntimeVersion, ApiExt, ConstructRuntimeApi, CallRuntimeAt}, + runtime_api::{Core, RuntimeVersion, ApiExt}, }; use test_client::{self, runtime::BlockNumber}; use codec::Decode; @@ -265,7 +265,7 @@ impl Core for RuntimeApi { unimplemented!("Not required for testing!") } - fn execute_block(&self, _: &BlockId, _: &Block) -> Result<()> { + fn execute_block(&self, _: &BlockId, _: Block) -> Result<()> { unimplemented!("Not required for testing!") } @@ -291,12 +291,6 @@ impl ApiExt for RuntimeApi { } } -impl ConstructRuntimeApi for RuntimeApi { - fn construct_runtime_api<'a, T: CallRuntimeAt>(_: &'a T) -> ApiRef<'a, Self> { - unimplemented!("Not required for testing!") - } -} - impl GrandpaApi for RuntimeApi { fn grandpa_authorities( &self, diff --git a/substrate/core/primitives/src/lib.rs b/substrate/core/primitives/src/lib.rs index 98289ddc18..c1f427f496 100644 --- a/substrate/core/primitives/src/lib.rs +++ b/substrate/core/primitives/src/lib.rs @@ -81,6 +81,8 @@ macro_rules! map { use rstd::prelude::*; use rstd::ops::Deref; +#[cfg(feature = "std")] +use std::borrow::Cow; #[cfg(feature = "std")] pub use impl_serde::serialize as bytes; @@ -139,7 +141,7 @@ impl Deref for Bytes { } /// Stores the encoded `RuntimeMetadata` for the native side as opaque type. -#[derive(Encode, Decode)] +#[derive(Encode, Decode, PartialEq)] pub struct OpaqueMetadata(Vec); impl OpaqueMetadata { @@ -156,3 +158,72 @@ impl rstd::ops::Deref for OpaqueMetadata { &self.0 } } + +/// Something that is either a native or an encoded value. +#[cfg(feature = "std")] +pub enum NativeOrEncoded { + /// The native representation. + Native(R), + /// The encoded representation. + Encoded(Vec) +} + +#[cfg(feature = "std")] +impl ::std::fmt::Debug for NativeOrEncoded { + fn fmt(&self, f: &mut ::std::fmt::Formatter) -> ::std::fmt::Result { + self.as_encoded().as_ref().fmt(f) + } +} + +#[cfg(feature = "std")] +impl NativeOrEncoded { + /// Return the value as the encoded format. + pub fn as_encoded<'a>(&'a self) -> Cow<'a, [u8]> { + match self { + NativeOrEncoded::Encoded(e) => Cow::Borrowed(e.as_slice()), + NativeOrEncoded::Native(n) => Cow::Owned(n.encode()), + } + } + + /// Return the value as the encoded format. + pub fn into_encoded(self) -> Vec { + match self { + NativeOrEncoded::Encoded(e) => e, + NativeOrEncoded::Native(n) => n.encode(), + } + } +} + +#[cfg(feature = "std")] +impl PartialEq for NativeOrEncoded { + fn eq(&self, other: &Self) -> bool { + match (self, other) { + (NativeOrEncoded::Native(l), NativeOrEncoded::Native(r)) => l == r, + (NativeOrEncoded::Native(n), NativeOrEncoded::Encoded(e)) | + (NativeOrEncoded::Encoded(e), NativeOrEncoded::Native(n)) => + Some(n) == codec::Decode::decode(&mut &e[..]).as_ref(), + (NativeOrEncoded::Encoded(l), NativeOrEncoded::Encoded(r)) => l == r, + } + } +} + +/// A value that is never in a native representation. +/// This is type is useful in conjuction with `NativeOrEncoded`. +#[cfg(feature = "std")] +#[derive(PartialEq)] +pub enum NeverNativeValue {} + +#[cfg(feature = "std")] +impl codec::Encode for NeverNativeValue { + fn encode(&self) -> Vec { + // The enum is not constructable, so this function should never be callable! + unreachable!() + } +} + +#[cfg(feature = "std")] +impl codec::Decode for NeverNativeValue { + fn decode(_: &mut I) -> Option { + None + } +} diff --git a/substrate/core/rpc/src/state/mod.rs b/substrate/core/rpc/src/state/mod.rs index 49dc28137a..5084999679 100644 --- a/substrate/core/rpc/src/state/mod.rs +++ b/substrate/core/rpc/src/state/mod.rs @@ -277,7 +277,9 @@ impl StateApi for State where Block: BlockT + 'static, B: client::backend::Backend + Send + Sync + 'static, E: CallExecutor + Send + Sync + 'static + Clone, - RA: Metadata + RA: Send + Sync + 'static, + Client: ProvideRuntimeApi, + as ProvideRuntimeApi>::Api: Metadata { type Metadata = ::metadata::Metadata; diff --git a/substrate/core/service/src/components.rs b/substrate/core/service/src/components.rs index dc116873b6..8756f58009 100644 --- a/substrate/core/service/src/components.rs +++ b/substrate/core/service/src/components.rs @@ -135,7 +135,8 @@ pub trait StartRPC { } impl StartRPC for C where - C::RuntimeApi: Metadata>, + ComponentClient: ProvideRuntimeApi, + as ProvideRuntimeApi>::Api: Metadata>, { type ServersHandle = (Option, Option>); @@ -189,10 +190,10 @@ fn on_block_imported( client: &Client, transaction_pool: &TransactionPool, ) -> error::Result<()> where - Api: TaggedTransactionQueue, Block: BlockT::Out>, Backend: client::backend::Backend, - Client: ProvideRuntimeApi, + Client: ProvideRuntimeApi, + as ProvideRuntimeApi>::Api: TaggedTransactionQueue, Executor: client::CallExecutor, PoolApi: txpool::ChainApi, { @@ -210,7 +211,7 @@ fn on_block_imported( let parent_id = BlockId::hash(*block.block.header().parent_hash()); let mut tags = vec![]; for tx in block.block.extrinsics() { - let tx = client.runtime_api().validate_transaction(&parent_id, &tx)?; + let tx = client.runtime_api().validate_transaction(&parent_id, tx.clone())?; match tx { TransactionValidity::Valid { mut provides, .. } => { tags.append(&mut provides); @@ -230,8 +231,8 @@ fn on_block_imported( } impl MaintainTransactionPool for C where - ComponentClient: ProvideRuntimeApi, - C::RuntimeApi: TaggedTransactionQueue>, + ComponentClient: ProvideRuntimeApi, + as ProvideRuntimeApi>::Api: TaggedTransactionQueue>, { // TODO [ToDr] Optimize and re-use tags from the pool. fn on_block_imported( diff --git a/substrate/core/service/test/src/lib.rs b/substrate/core/service/test/src/lib.rs index 4335bffe86..2130ae4a83 100644 --- a/substrate/core/service/test/src/lib.rs +++ b/substrate/core/service/test/src/lib.rs @@ -181,10 +181,7 @@ impl TestNet { } } -pub fn connectivity(spec: FactoryChainSpec) where - ::RuntimeApi: - client::block_builder::api::BlockBuilder<::Block, Inherent> -{ +pub fn connectivity(spec: FactoryChainSpec) { const NUM_NODES: u32 = 10; { let temp = TempDir::new("substrate-connectivity-test").expect("Error creating test dir"); @@ -228,9 +225,6 @@ where F: ServiceFactory, B: Fn(&F::FullService) -> ImportBlock, E: Fn(&F::FullService) -> FactoryExtrinsic, - ::RuntimeApi: - client::block_builder::api::BlockBuilder<::Block, ()> + - client::runtime_api::TaggedTransactionQueue<::Block> { const NUM_NODES: u32 = 10; const NUM_BLOCKS: usize = 512; @@ -265,10 +259,8 @@ where } pub fn consensus(spec: FactoryChainSpec, authorities: Vec) -where - F: ServiceFactory, - ::RuntimeApi: - client::block_builder::api::BlockBuilder<::Block, ()> + where + F: ServiceFactory, { const NUM_NODES: u32 = 20; const NUM_BLOCKS: u64 = 200; diff --git a/substrate/core/sr-api-macros/Cargo.toml b/substrate/core/sr-api-macros/Cargo.toml index 5e6140df9d..7cc414a732 100644 --- a/substrate/core/sr-api-macros/Cargo.toml +++ b/substrate/core/sr-api-macros/Cargo.toml @@ -18,3 +18,8 @@ substrate-test-client = { path = "../test-client" } sr-primitives = { path = "../sr-primitives" } sr-version = { path = "../sr-version" } substrate-primitives = { path = "../primitives" } +criterion = "0.2" + +[[bench]] +name = "bench" +harness = false diff --git a/substrate/core/sr-api-macros/benches/bench.rs b/substrate/core/sr-api-macros/benches/bench.rs new file mode 100644 index 0000000000..54f8c8a3d1 --- /dev/null +++ b/substrate/core/sr-api-macros/benches/bench.rs @@ -0,0 +1,62 @@ +// Copyright 2018 Parity Technologies (UK) Ltd. +// This file is part of Substrate. + +// Substrate 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. + +// Substrate 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 Substrate. If not, see . + +#[macro_use] +extern crate criterion; +extern crate substrate_client; +extern crate substrate_test_client as test_client; +extern crate sr_primitives as runtime_primitives; + +use criterion::Criterion; +use test_client::runtime::TestAPI; +use runtime_primitives::{generic::BlockId, traits::ProvideRuntimeApi}; + +fn sr_api_benchmark(c: &mut Criterion) { + c.bench_function("add one with same runtime api", |b| { + let client = test_client::new(); + let runtime_api = client.runtime_api(); + let block_id = BlockId::Number(client.info().unwrap().chain.best_number); + + b.iter(|| runtime_api.benchmark_add_one(&block_id, &1)) + }); + + c.bench_function("add one with recreating runtime api", |b| { + let client = test_client::new(); + let block_id = BlockId::Number(client.info().unwrap().chain.best_number); + + b.iter(|| client.runtime_api().benchmark_add_one(&block_id, &1)) + }); + + c.bench_function("vector add one with same runtime api", |b| { + let client = test_client::new(); + let runtime_api = client.runtime_api(); + let block_id = BlockId::Number(client.info().unwrap().chain.best_number); + let data = vec![0; 1000]; + + b.iter_with_large_drop(|| runtime_api.benchmark_vector_add_one(&block_id, &data)) + }); + + c.bench_function("vector add one with recreating runtime api", |b| { + let client = test_client::new(); + let block_id = BlockId::Number(client.info().unwrap().chain.best_number); + let data = vec![0; 1000]; + + b.iter_with_large_drop(|| client.runtime_api().benchmark_vector_add_one(&block_id, &data)) + }); +} + +criterion_group!(benches, sr_api_benchmark); +criterion_main!(benches); diff --git a/substrate/core/sr-api-macros/src/compile_fail_tests.rs b/substrate/core/sr-api-macros/src/compile_fail_tests.rs index ec2c2387bd..7d7be065fa 100644 --- a/substrate/core/sr-api-macros/src/compile_fail_tests.rs +++ b/substrate/core/sr-api-macros/src/compile_fail_tests.rs @@ -92,24 +92,6 @@ mod adding_at_parameter { */ } -mod adding_parameter_with_type_reference { - /*! - ```compile_fail - #[macro_use] - extern crate substrate_client; - extern crate sr_primitives as runtime_primitives; - - decl_runtime_apis! { - pub trait Api { - fn test(data: &u64); - } - } - - fn main() {} - ``` - */ -} - mod invalid_api_version { /*! ```compile_fail diff --git a/substrate/core/sr-api-macros/src/decl_runtime_apis.rs b/substrate/core/sr-api-macros/src/decl_runtime_apis.rs index 376949a628..54f8d81bef 100644 --- a/substrate/core/sr-api-macros/src/decl_runtime_apis.rs +++ b/substrate/core/sr-api-macros/src/decl_runtime_apis.rs @@ -16,24 +16,28 @@ use utils::{ generate_crate_access, generate_hidden_includes, generate_runtime_mod_name_for_trait, - fold_fn_decl_for_client_side, unwrap_or_error + fold_fn_decl_for_client_side, unwrap_or_error, extract_parameter_names_types_and_borrows, + generate_native_call_generator_fn_name }; use proc_macro; -use proc_macro2::TokenStream; +use proc_macro2::{TokenStream, Span}; use quote::quote; use syn::{ - spanned::Spanned, parse_macro_input, parse::{Parse, ParseStream, Result, Error}, + spanned::Spanned, parse_macro_input, parse::{Parse, ParseStream, Result, Error}, ReturnType, fold::{self, Fold}, FnDecl, parse_quote, ItemTrait, Generics, GenericParam, Attribute, - visit::{Visit, self}, FnArg, Pat, TraitBound, Type, Meta, NestedMeta, Lit + visit::{Visit, self}, FnArg, Pat, TraitBound, Meta, NestedMeta, Lit, TraitItem, Ident, Type }; use std::collections::HashMap; use blake2_rfc; +/// The ident used for the block generic parameter. +const BLOCK_GENERIC_IDENT: &str = "Block"; + /// Unique identifier used to make the hidden includes unique for this macro. const HIDDEN_INCLUDES_ID: &str = "DECL_RUNTIME_APIS"; @@ -88,6 +92,167 @@ fn remove_supported_attributes(attrs: &mut Vec) -> HashMap<&'static s result } +/// Visits the ast and checks if `Block` ident is used somewhere. +struct IsUsingBlock { + result: bool, +} + +impl<'ast> Visit<'ast> for IsUsingBlock { + fn visit_ident(&mut self, i: &'ast Ident) { + if i == BLOCK_GENERIC_IDENT { + self.result = true; + } + } +} + +/// Visits the ast and checks if `Block` ident is used somewhere. +fn type_is_using_block(ty: &Type) -> bool { + let mut visitor = IsUsingBlock { result: false }; + visitor.visit_type(ty); + visitor.result +} + +/// Visits the ast and checks if `Block` ident is used somewhere. +fn return_type_is_using_block(ty: &ReturnType) -> bool { + let mut visitor = IsUsingBlock { result: false }; + visitor.visit_return_type(ty); + visitor.result +} + +/// Replace all occurences of `Block` with `NodeBlock` +struct ReplaceBlockWithNodeBlock {} + +impl Fold for ReplaceBlockWithNodeBlock { + fn fold_ident(&mut self, input: Ident) -> Ident { + if input == BLOCK_GENERIC_IDENT { + Ident::new("NodeBlock", Span::call_site()) + } else { + input + } + } +} + +/// Replace all occurences of `Block` with `NodeBlock` +fn fn_arg_replace_block_with_node_block(fn_arg: FnArg) -> FnArg { + let mut replace = ReplaceBlockWithNodeBlock {}; + fold::fold_fn_arg(&mut replace, fn_arg) +} + +/// Replace all occurences of `Block` with `NodeBlock` +fn return_type_replace_block_with_node_block(return_type: ReturnType) -> ReturnType { + let mut replace = ReplaceBlockWithNodeBlock {}; + fold::fold_return_type(&mut replace, return_type) +} + +fn generate_native_call_generators(decl: &ItemTrait) -> Result { + let fns = decl.items.iter().filter_map(|i| match i { + TraitItem::Method(ref m) => Some(&m.sig), + _ => None, + }); + + let mut result = Vec::new(); + let trait_ = &decl.ident; + let crate_ = generate_crate_access(HIDDEN_INCLUDES_ID); + + // Auxilariy function that is used to convert between types that use different block types. + // The function expects that both a convertable by encoding the one and decoding the other. + result.push(quote!( + fn convert_between_block_types + (input: &I) -> R + { + ::decode( + &mut &#crate_::runtime_api::Encode::encode(input)[..] + ).unwrap() + } + )); + + // Generate a native call generator for each function of the given trait. + for fn_ in fns { + let params = extract_parameter_names_types_and_borrows(&fn_.decl)?; + let trait_fn_name = &fn_.ident; + let fn_name = generate_native_call_generator_fn_name(&fn_.ident); + let output = return_type_replace_block_with_node_block(fn_.decl.output.clone()); + + // Every type that is using the `Block` generic parameter, we need to encode/decode, + // to make it compatible between the runtime/node. + let conversions = params.iter().filter(|v| type_is_using_block(&v.1)).map(|(n, t, _)| { + quote!( + let #n: #t = convert_between_block_types(&#n); + ) + }); + // Same as for the input types, we need to check if we also need to convert the output, + // before returning it. + let output_conversion = if return_type_is_using_block(&fn_.decl.output) { + quote!( convert_between_block_types(&res) ) + } else { + quote!( res ) + }; + + let input_names = params.iter().map(|v| &v.0); + // If the type is using the block generic type, we will encode/decode it to make it + // compatible. To ensure that we forward it by ref/value, we use the value given by the + // the user. Otherwise if it is not using the block, we don't need to add anything. + let input_borrows = params + .iter() + .map(|v| if type_is_using_block(&v.1) { v.2.clone() } else { quote!() }); + + // Replace all `Block` with `NodeBlock`, add `'a` lifetime to references and collect + // all the function inputs. + let fn_inputs = fn_ + .decl + .inputs + .iter() + .map(|v| fn_arg_replace_block_with_node_block(v.clone())) + .map(|v| match v { + FnArg::Captured(ref arg) => { + let mut arg = arg.clone(); + match arg.ty { + Type::Reference(ref mut r) => { + r.lifetime = Some(parse_quote!( 'a )); + }, + _ => {} + } + FnArg::Captured(arg) + }, + r => r.clone(), + }); + + let (impl_generics, ty_generics, where_clause) = decl.generics.split_for_impl(); + // We need to parse them again, to get an easy access to the actual parameters. + let mut impl_generics: Generics = parse_quote!(#impl_generics); + let impl_generics_params = impl_generics.params.iter().map(|p| { + match p { + GenericParam::Type(ref ty) => { + let mut ty = ty.clone(); + ty.bounds.push(parse_quote!( 'a )); + GenericParam::Type(ty) + }, + // We should not see anything different than type params here. + r => r.clone(), + } + }); + + // Generate the generator function + result.push(quote!( + #[cfg(any(feature = "std", test))] + pub fn #fn_name< + 'a, ApiImpl: #trait_ #ty_generics, NodeBlock: #crate_::runtime_api::BlockT + #(, #impl_generics_params)* + >( + #( #fn_inputs ),* + ) -> impl FnOnce() #output + 'a #where_clause { + move || { + #( #conversions )* + let res = ApiImpl::#trait_fn_name(#( #input_borrows #input_names ),*); + #output_conversion + } + } + )); + } + + Ok(quote!( #( #result )* )) +} + /// Generate the decleration of the trait for the runtime. fn generate_runtime_decls(decls: &[ItemTrait]) -> TokenStream { let mut result = Vec::new(); @@ -101,9 +266,11 @@ fn generate_runtime_decls(decls: &[ItemTrait]) -> TokenStream { generate_runtime_api_version(v as u32) })); let id = generate_runtime_api_id(&decl.ident.to_string()); + let native_call_generators = unwrap_or_error(generate_native_call_generators(&decl)); result.push(quote!( #[doc(hidden)] + #[allow(dead_code)] pub mod #mod_name { use super::*; @@ -112,6 +279,8 @@ fn generate_runtime_decls(decls: &[ItemTrait]) -> TokenStream { pub #api_version pub #id + + #native_call_generators } )); } @@ -143,6 +312,7 @@ impl<'a> Fold for ToClientSideDecl<'a> { *self.found_attributes = remove_supported_attributes(&mut input.attrs); // Check if this is the `Core` runtime api trait. let is_core_trait = self.found_attributes.contains_key(CORE_TRAIT_ATTRIBUTE); + let block_ident = Ident::new(BLOCK_GENERIC_IDENT, Span::call_site()); if is_core_trait { // Add all the supertraits we want to have for `Core`. @@ -151,13 +321,12 @@ impl<'a> Fold for ToClientSideDecl<'a> { 'static + Send + Sync - + #crate_::runtime_api::ConstructRuntimeApi - + #crate_::runtime_api::ApiExt + + #crate_::runtime_api::ApiExt<#block_ident> ); } else { // Add the `Core` runtime api as super trait. let crate_ = &self.crate_; - input.supertraits.push(parse_quote!( #crate_::runtime_api::Core )); + input.supertraits.push(parse_quote!( #crate_::runtime_api::Core<#block_ident> )); } // The client side trait is only required when compiling with the feature `std` or `test`. @@ -291,19 +460,6 @@ impl<'ast> Visit<'ast> for CheckTraitDecl { }, _ => {} } - - match arg.ty { - Type::Reference(ref reference) => { - self.errors.push( - Error::new( - reference.span(), - "Do not use type references as arguments. The client side \ - declaration will take all arguments as reference automatically." - ) - ) - }, - _ => {}, - } }, FnArg::SelfRef(_) | FnArg::SelfValue(_) => { self.errors.push(Error::new(input.span(), "Self values are not supported.")) @@ -323,7 +479,7 @@ impl<'ast> Visit<'ast> for CheckTraitDecl { fn visit_generic_param(&mut self, input: &'ast GenericParam) { match input { - GenericParam::Type(ty) if &ty.ident == "Block" => { + GenericParam::Type(ty) if &ty.ident == BLOCK_GENERIC_IDENT => { self.errors.push( Error::new( input.span(), @@ -340,7 +496,7 @@ impl<'ast> Visit<'ast> for CheckTraitDecl { fn visit_trait_bound(&mut self, input: &'ast TraitBound) { if let Some(last_ident) = input.path.segments.last().map(|v| &v.value().ident) { - if last_ident == "BlockT" || last_ident == "Block" { + if last_ident == "BlockT" || last_ident == BLOCK_GENERIC_IDENT { self.errors.push( Error::new( input.span(), diff --git a/substrate/core/sr-api-macros/src/impl_runtime_apis.rs b/substrate/core/sr-api-macros/src/impl_runtime_apis.rs index a6aa4b82a5..6663cae85f 100644 --- a/substrate/core/sr-api-macros/src/impl_runtime_apis.rs +++ b/substrate/core/sr-api-macros/src/impl_runtime_apis.rs @@ -16,7 +16,8 @@ use utils::{ unwrap_or_error, generate_crate_access, generate_hidden_includes, - generate_runtime_mod_name_for_trait, fold_fn_decl_for_client_side + generate_runtime_mod_name_for_trait, fold_fn_decl_for_client_side, generate_unique_pattern, + extract_parameter_names_types_and_borrows, generate_native_call_generator_fn_name }; use proc_macro; @@ -25,9 +26,9 @@ use proc_macro2::{Span, TokenStream}; use quote::quote; use syn::{ - spanned::Spanned, parse_macro_input, Ident, Type, ItemImpl, MethodSig, FnArg, Path, + spanned::Spanned, parse_macro_input, Ident, Type, ItemImpl, MethodSig, Path, ImplItem, parse::{Parse, ParseStream, Result, Error}, PathArguments, GenericArgument, TypePath, - fold::{self, Fold}, FnDecl, parse_quote, Pat + fold::{self, Fold}, FnDecl, parse_quote, FnArg }; use std::{collections::HashSet, iter}; @@ -60,47 +61,17 @@ fn generate_impl_call( input: &Ident, impl_trait: &Path ) -> Result { - let mut pnames = Vec::new(); - let mut ptypes = Vec::new(); - let mut generated_pattern_counter = 0; - for input in signature.decl.inputs.iter() { - match input { - FnArg::Captured(arg) => { - match &arg.ty { - Type::Reference(_) => { - return Err( - Error::new( - arg.ty.span(), - "No type references are allowed in the api traits!" - ) - ) - }, - _ => {}, - } - - pnames.push( - generate_unique_pattern(arg.pat.clone(), &mut generated_pattern_counter) - ); - ptypes.push(&arg.ty); - }, - _ => { - return Err( - Error::new( - input.span(), - "Only function arguments with the following \ - pattern are accepted: `name: type`!" - ) - ) - } - } - } + let params = extract_parameter_names_types_and_borrows(&signature.decl)?; let c = generate_crate_access(HIDDEN_INCLUDES_ID); let c_iter = iter::repeat(&c); let fn_name = &signature.ident; let fn_name_str = iter::repeat(fn_name.to_string()); let input = iter::repeat(input); - let pnames2 = pnames.clone(); + let pnames = params.iter().map(|v| &v.0); + let pnames2 = params.iter().map(|v| &v.0); + let ptypes = params.iter().map(|v| &v.1); + let pborrow = params.iter().map(|v| &v.2); Ok( quote!( @@ -111,7 +82,7 @@ fn generate_impl_call( }; )* - let output = <#runtime as #impl_trait>::#fn_name(#( #pnames2 ),*); + let output = <#runtime as #impl_trait>::#fn_name(#( #pborrow #pnames2 ),*); #c::runtime_api::Encode::encode(&output) ).into() ) @@ -294,10 +265,11 @@ fn generate_runtime_api_base_structures(impls: &[ItemImpl]) -> Result>, + pub struct RuntimeApiImpl + 'static> { + call: &'static C, commit_on_success: ::std::cell::RefCell, initialised_block: ::std::cell::RefCell>, changes: ::std::cell::RefCell<#crate_::runtime_api::OverlayedChanges>, @@ -307,12 +279,14 @@ fn generate_runtime_api_base_structures(impls: &[ItemImpl]) -> Result> Send for RuntimeApiImpl {} #[cfg(any(feature = "std", test))] - unsafe impl Sync for RuntimeApi {} + unsafe impl> Sync for RuntimeApiImpl {} #[cfg(any(feature = "std", test))] - impl #crate_::runtime_api::ApiExt<#block> for RuntimeApi { + impl> #crate_::runtime_api::ApiExt<#block> + for RuntimeApiImpl + { fn map_api_result ::std::result::Result, R, E>( &self, map_call: F @@ -330,22 +304,21 @@ fn generate_runtime_api_base_structures(impls: &[ItemImpl]) -> Result #crate_::error::Result where Self: Sized { - unsafe { self.call.as_ref().runtime_version_at(at) }.map(|r| r.has_api::()) + self.call.runtime_version_at(at).map(|r| r.has_api::()) } } #[cfg(any(feature = "std", test))] - impl #crate_::runtime_api::ConstructRuntimeApi<#block> for RuntimeApi { - fn construct_runtime_api<'a, T: #crate_::runtime_api::CallRuntimeAt<#block>>( - call: &'a T - ) -> #crate_::runtime_api::ApiRef<'a, Self> where Self: Sized { - RuntimeApi { - call: unsafe { - ::std::ptr::NonNull::new_unchecked( - call as - &#crate_::runtime_api::CallRuntimeAt<#block> as *const _ as *mut _ - ) - }, + impl + 'static> + #crate_::runtime_api::ConstructRuntimeApi<#block, C> for RuntimeApi + { + type RuntimeApi = RuntimeApiImpl; + + fn construct_runtime_api<'a>( + call: &'a C, + ) -> #crate_::runtime_api::ApiRef<'a, Self::RuntimeApi> { + RuntimeApiImpl { + call: unsafe { ::std::mem::transmute(call) }, commit_on_success: true.into(), initialised_block: None.into(), changes: Default::default(), @@ -354,25 +327,39 @@ fn generate_runtime_api_base_structures(impls: &[ItemImpl]) -> Result( + impl> RuntimeApiImpl { + fn call_api_at< + R: #crate_::runtime_api::Encode + #crate_::runtime_api::Decode + PartialEq, + NC: FnOnce() -> R + ::std::panic::UnwindSafe, + >( &self, at: &#block_id, function: &'static str, - args: &A + args: Vec, + native_call: NC, ) -> #crate_::error::Result { let res = unsafe { - self.call.as_ref().call_api_at( + self.call.call_api_at( at, function, - args.encode(), + args, &mut *self.changes.borrow_mut(), - &mut *self.initialised_block.borrow_mut() + &mut *self.initialised_block.borrow_mut(), + Some(native_call), ).and_then(|r| - R::decode(&mut &r[..]) - .ok_or_else(|| - #crate_::error::ErrorKind::CallResultDecode(function).into() - ) + match r { + #crate_::runtime_api::NativeOrEncoded::Native(n) => { + Ok(n) + }, + #crate_::runtime_api::NativeOrEncoded::Encoded(r) => { + R::decode(&mut &r[..]) + .ok_or_else(|| + #crate_::error::ErrorKind::CallResultDecode( + function + ).into() + ) + } + } ) }; @@ -431,21 +418,6 @@ fn generate_api_impl_for_runtime(impls: &[ItemImpl]) -> Result { Ok(quote!( #( #impls_prepared )* )) } -/// Generate an unique pattern based on the given counter, if the given pattern is a `_`. -fn generate_unique_pattern(pat: Pat, counter: &mut u32) -> Pat { - match pat { - Pat::Wild(_) => { - let generated_name = Ident::new( - &format!("impl_runtime_api_generated_name_{}", counter), - pat.span() - ); - *counter += 1; - - parse_quote!( #generated_name ) - }, - _ => pat, - } -} /// Auxilariy data structure that is used to convert `impl Api for Runtime` to /// `impl Api for RuntimeApi`. @@ -457,6 +429,9 @@ struct ApiRuntimeImplToApiRuntimeApiImpl<'a> { runtime_block: &'a TypePath, node_block_id: &'a TokenStream, impl_trait_ident: &'a Ident, + runtime_mod_path: &'a Path, + runtime_type: &'a Type, + trait_generic_arguments: &'a [GenericArgument] } impl<'a> Fold for ApiRuntimeImplToApiRuntimeApiImpl<'a> { @@ -482,30 +457,63 @@ impl<'a> Fold for ApiRuntimeImplToApiRuntimeApiImpl<'a> { } fn fold_impl_item_method(&mut self, mut input: syn::ImplItemMethod) -> syn::ImplItemMethod { - { + let block = { + let crate_ = generate_crate_access(HIDDEN_INCLUDES_ID); let mut generated_name_counter = 0; + // Replace `_` with unique patterns and collect all patterns. let arg_names = input.sig.decl.inputs.iter_mut().filter_map(|i| match i { FnArg::Captured(ref mut arg) => Some(&mut arg.pat), _ => None, }).map(|p| { *p = generate_unique_pattern(p.clone(), &mut generated_name_counter); - p - }); - let name = prefix_function_with_trait(self.impl_trait_ident, &input.sig.ident); + p.clone() + }).collect::>(); + + let runtime_mod_path = self.runtime_mod_path; + let runtime = self.runtime_type; + let arg_names2 = arg_names.clone(); + let fn_name = prefix_function_with_trait(self.impl_trait_ident, &input.sig.ident); + let native_call_generator_ident = + generate_native_call_generator_fn_name(&input.sig.ident); + let trait_generic_arguments = self.trait_generic_arguments; + let node_block = self.node_block; // Generate the new method implementation that calls into the runime. - input.block = parse_quote!( { self.call_api_at(at, #name, &( #( #arg_names ),* )) } ); - } + parse_quote!( + { + let args = #crate_::runtime_api::Encode::encode(&( #( &#arg_names ),* )); + self.call_api_at( + at, + #fn_name, + args, + #runtime_mod_path #native_call_generator_ident :: + <#runtime, #node_block #(, #trait_generic_arguments )*> ( + #( #arg_names2 ),* + ) + ) + } + ) + }; - fold::fold_impl_item_method(self, input) + let mut input = fold::fold_impl_item_method(self, input); + // We need to set the block, after we modified the rest of the ast, otherwise we would + // modify our generated block as well. + input.block = block; + input } fn fold_item_impl(&mut self, mut input: ItemImpl) -> ItemImpl { - // Implement the trait for the `RuntimeApi` - input.self_ty = Box::new(parse_quote!( RuntimeApi )); + // Implement the trait for the `RuntimeApiImpl` + input.self_ty = Box::new(parse_quote!( RuntimeApiImpl )); - // The implementation for the `RuntimeApi` is only required when compiling with the feature - // `std` or `test`. + let crate_ = generate_crate_access(HIDDEN_INCLUDES_ID); + let block = self.node_block; + input.generics.params.push( + parse_quote!( RuntimeApiImplCall: #crate_::runtime_api::CallRuntimeAt<#block> + 'static ) + ); + + // The implementation for the `RuntimeApiImpl` is only required when compiling with + // the feature `std` or `test`. input.attrs.push(parse_quote!( #[cfg(any(feature = "std", test))] )); fold::fold_item_impl(self, input) @@ -517,21 +525,33 @@ fn generate_api_impl_for_runtime_api(impls: &[ItemImpl]) -> Result let mut result = Vec::with_capacity(impls.len()); for impl_ in impls { - let impl_trait = extract_impl_trait(&impl_)?; - let impl_trait_ident = &impl_trait + let impl_trait_path = extract_impl_trait(&impl_)?; + let impl_trait = &impl_trait_path .segments .last() - .ok_or_else(|| Error::new(impl_trait.span(), "Empty trait path not possible!"))? - .value() - .ident; - let runtime_block = extract_runtime_block_ident(impl_trait)?; + .ok_or_else(|| Error::new(impl_trait_path.span(), "Empty trait path not possible!"))? + .into_value(); + let impl_trait_ident = &impl_trait.ident; + let runtime_block = extract_runtime_block_ident(impl_trait_path)?; let (node_block, node_block_id) = generate_node_block_and_block_id_ty(&impl_.self_ty); + let runtime_type = &impl_.self_ty; + let mut runtime_mod_path = extend_with_runtime_decl_path(impl_trait_path.clone()); + // remove the trait to get just the module path + runtime_mod_path.segments.pop(); + + let trait_generic_arguments = match impl_trait.arguments { + PathArguments::Parenthesized(_) | PathArguments::None => vec![], + PathArguments::AngleBracketed(ref b) => b.args.iter().cloned().collect(), + }; let mut visitor = ApiRuntimeImplToApiRuntimeApiImpl { runtime_block, node_block: &node_block, node_block_id: &node_block_id, impl_trait_ident: &impl_trait_ident, + runtime_mod_path: &runtime_mod_path, + runtime_type: &*runtime_type, + trait_generic_arguments: &trait_generic_arguments, }; result.push(visitor.fold_item_impl(impl_.clone())); diff --git a/substrate/core/sr-api-macros/src/utils.rs b/substrate/core/sr-api-macros/src/utils.rs index 4c80adf16b..e35ed52084 100644 --- a/substrate/core/sr-api-macros/src/utils.rs +++ b/substrate/core/sr-api-macros/src/utils.rs @@ -15,7 +15,7 @@ // along with Substrate. If not, see . use proc_macro2::{TokenStream, Span}; -use syn::{Result, Ident, FnDecl, parse_quote, Type, FnArg}; +use syn::{Result, Ident, FnDecl, parse_quote, Type, Pat, spanned::Spanned, FnArg, Error}; use quote::quote; use std::env; @@ -64,19 +64,6 @@ pub fn fold_fn_decl_for_client_side( block_id: &TokenStream, crate_: &TokenStream ) -> FnDecl { - // Add `&` to all parameter types. - input.inputs - .iter_mut() - .filter_map(|i| match i { - FnArg::Captured(ref mut arg) => Some(&mut arg.ty), - _ => None, - }) - .filter_map(|i| match i { - Type::Reference(_) => None, - r => Some(r), - }) - .for_each(|i| *i = parse_quote!( &#i )); - // Add `&self, at:& BlockId` as parameters to each function at the beginning. input.inputs.insert(0, parse_quote!( at: &#block_id )); input.inputs.insert(0, parse_quote!( &self )); @@ -95,3 +82,61 @@ pub fn fold_fn_decl_for_client_side( input } + +/// Generate an unique pattern based on the given counter, if the given pattern is a `_`. +pub fn generate_unique_pattern(pat: Pat, counter: &mut u32) -> Pat { + match pat { + Pat::Wild(_) => { + let generated_name = Ident::new( + &format!("runtime_api_generated_name_{}", counter), + pat.span() + ); + *counter += 1; + + parse_quote!( #generated_name ) + }, + _ => pat, + } +} + +/// Extracts the name, the type and `&` or ``(if it is a reference or not) +/// for each parameter in the given function declaration. +pub fn extract_parameter_names_types_and_borrows(fn_decl: &FnDecl) + -> Result> +{ + let mut result = Vec::new(); + let mut generated_pattern_counter = 0; + for input in fn_decl.inputs.iter() { + match input { + FnArg::Captured(arg) => { + let (ty, borrow) = match &arg.ty { + Type::Reference(t) => { + let ty = &t.elem; + (parse_quote!( #ty ), quote!( & )) + }, + t => { (t.clone(), quote!()) }, + }; + + let name = + generate_unique_pattern(arg.pat.clone(), &mut generated_pattern_counter); + result.push((name, ty, borrow)); + }, + _ => { + return Err( + Error::new( + input.span(), + "Only function arguments with the following \ + pattern are accepted: `name: type`!" + ) + ) + } + } + } + + Ok(result) +} + +/// Generates the name for the native call generator function. +pub fn generate_native_call_generator_fn_name(fn_name: &Ident) -> Ident { + Ident::new(&format!("{}_native_call_generator", fn_name.to_string()), Span::call_site()) +} diff --git a/substrate/core/sr-api-macros/tests/decl_and_impl.rs b/substrate/core/sr-api-macros/tests/decl_and_impl.rs index 699c8c01cf..1d87a15201 100644 --- a/substrate/core/sr-api-macros/tests/decl_and_impl.rs +++ b/substrate/core/sr-api-macros/tests/decl_and_impl.rs @@ -1,13 +1,13 @@ #[macro_use] -extern crate substrate_client; +extern crate substrate_client as client; extern crate sr_primitives as runtime_primitives; extern crate substrate_primitives as primitives; extern crate substrate_test_client as test_client; use runtime_primitives::traits::{GetNodeBlockType, Block as BlockT, AuthorityIdFor}; use runtime_primitives::generic::BlockId; -use substrate_client::runtime_api::{self, RuntimeApiInfo}; -use substrate_client::error::Result; +use client::runtime_api::{self, RuntimeApiInfo}; +use client::error::Result; use test_client::runtime::Block; /// The declaration of the `Runtime` type and the implementation of the `GetNodeBlockType` @@ -62,17 +62,21 @@ impl_runtime_apis! { fn execute_block(_: Block) { unimplemented!() } - fn initialise_block(_: ::Header) { + fn initialise_block(_: &::Header) { unimplemented!() } } } +type TestClient = client::Client; + #[test] fn test_client_side_function_signature() { - let _test: fn(&RuntimeApi, &BlockId, &u64) -> Result<()> = RuntimeApi::test; - let _something_with_block: fn(&RuntimeApi, &BlockId, &Block) -> Result = - RuntimeApi::something_with_block; + let _test: fn(&RuntimeApiImpl, &BlockId, u64) -> Result<()> = + RuntimeApiImpl::::test; + let _something_with_block: + fn(&RuntimeApiImpl, &BlockId, Block) -> Result = + RuntimeApiImpl::::something_with_block; } #[test] diff --git a/substrate/core/sr-primitives/src/lib.rs b/substrate/core/sr-primitives/src/lib.rs index 26b26974a2..6ca72cf80c 100644 --- a/substrate/core/sr-primitives/src/lib.rs +++ b/substrate/core/sr-primitives/src/lib.rs @@ -531,7 +531,7 @@ impl BasicInherentData { //TODO: https://github.com/paritytech/substrate/issues/1022 /// Error type used while checking inherents. -#[derive(Encode)] +#[derive(Encode, PartialEq)] #[cfg_attr(feature = "std", derive(Decode))] pub enum CheckInherentError { /// The inherents are generally valid but a delay until the given timestamp diff --git a/substrate/core/sr-primitives/src/traits.rs b/substrate/core/sr-primitives/src/traits.rs index 4db2d580d7..8723dbec91 100644 --- a/substrate/core/sr-primitives/src/traits.rs +++ b/substrate/core/sr-primitives/src/traits.rs @@ -470,7 +470,7 @@ pub trait Header: Clone + Send + Sync + Codec + Eq + MaybeSerializeDebugButNotDe type Number: Member + MaybeSerializeDebug + ::rstd::hash::Hash + Copy + MaybeDisplay + SimpleArithmetic + Codec; type Hash: Member + MaybeSerializeDebug + ::rstd::hash::Hash + Copy + MaybeDisplay + Default + SimpleBitOps + Codec + AsRef<[u8]> + AsMut<[u8]>; type Hashing: Hash; - type Digest: Digest; + type Digest: Digest + Codec; fn new( number: Self::Number, diff --git a/substrate/core/state-machine/src/lib.rs b/substrate/core/state-machine/src/lib.rs index e4fe89e2d2..b10ae42bc8 100644 --- a/substrate/core/state-machine/src/lib.rs +++ b/substrate/core/state-machine/src/lib.rs @@ -30,15 +30,16 @@ extern crate substrate_trie; extern crate parking_lot; extern crate heapsize; -#[cfg_attr(test, macro_use)] extern crate substrate_primitives as primitives; +#[cfg_attr(test, macro_use)] +extern crate substrate_primitives as primitives; extern crate parity_codec as codec; extern crate substrate_trie as trie; -use std::fmt; +use std::{fmt, panic::UnwindSafe}; use hash_db::Hasher; use heapsize::HeapSizeOf; -use codec::Decode; -use primitives::storage::well_known_keys; +use codec::{Decode, Encode}; +use primitives::{storage::well_known_keys, NativeOrEncoded, NeverNativeValue}; pub mod backend; mod changes_trie; @@ -171,13 +172,14 @@ pub trait CodeExecutor: Sized + Send + Sync { /// Call a given method in the runtime. Returns a tuple of the result (either the output data /// or an execution error) together with a `bool`, which is true if native execution was used. - fn call>( + fn call, R: Encode + Decode + PartialEq, NC: FnOnce() -> R + UnwindSafe>( &self, ext: &mut E, method: &str, data: &[u8], - use_native: bool - ) -> (Result, Self::Error>, bool); + use_native: bool, + native_call: Option, + ) -> (Result, Self::Error>, bool); } /// Strategy for executing a call into the runtime. @@ -213,12 +215,26 @@ impl<'a, F> From<&'a ExecutionManager> for ExecutionStrategy { } /// Evaluate to ExecutionManager::NativeWhenPossible, without having to figure out the type. -pub fn native_when_possible() -> ExecutionManager, E>, Result, E>)->Result, E>> { +pub fn native_when_possible() -> + ExecutionManager< + fn( + Result, E>, + Result, E> + ) -> Result, E> + > +{ ExecutionManager::NativeWhenPossible } /// Evaluate to ExecutionManager::NativeWhenPossible, without having to figure out the type. -pub fn always_wasm() -> ExecutionManager, E>, Result, E>)->Result, E>> { +pub fn always_wasm() -> + ExecutionManager< + fn( + Result, E>, + Result, E> + ) -> Result, E> + > +{ ExecutionManager::AlwaysWasm } @@ -246,7 +262,9 @@ where T: ChangesTrieStorage, H::Out: Ord + HeapSizeOf, { - execute_using_consensus_failure_handler( + // We are not giving a native call and thus we are sure that the result can never be a native + // value. + execute_using_consensus_failure_handler::<_, _, _, _, _, NeverNativeValue, fn() -> NeverNativeValue>( backend, changes_trie_storage, overlay, @@ -257,14 +275,19 @@ where ExecutionStrategy::AlwaysWasm => ExecutionManager::AlwaysWasm, ExecutionStrategy::NativeWhenPossible => ExecutionManager::NativeWhenPossible, ExecutionStrategy::Both => ExecutionManager::Both(|wasm_result, native_result| { - warn!("Consensus error between wasm {:?} and native {:?}. Using wasm.", wasm_result, native_result); + warn!( + "Consensus error between wasm {:?} and native {:?}. Using wasm.", + wasm_result, + native_result + ); wasm_result }), }, true, + None, ) .map(|(result, storage_tx, changes_tx)| ( - result, + result.into_encoded(), storage_tx.expect("storage_tx is always computed when compute_tx is true; qed"), changes_tx, )) @@ -278,7 +301,9 @@ where /// /// Note: changes to code will be in place if this call is made again. For running partial /// blocks (e.g. a transaction at a time), ensure a different method is used. -pub fn execute_using_consensus_failure_handler( +pub fn execute_using_consensus_failure_handler< + H, B, T, Exec, Handler, R: Decode + Encode + PartialEq, NC: FnOnce() -> R + UnwindSafe +>( backend: &B, changes_trie_storage: Option<&T>, overlay: &mut OverlayedChanges, @@ -287,14 +312,18 @@ pub fn execute_using_consensus_failure_handler( call_data: &[u8], manager: ExecutionManager, compute_tx: bool, -) -> Result<(Vec, Option, Option>), Box> + mut native_call: Option, +) -> Result<(NativeOrEncoded, Option, Option>), Box> where H: Hasher, Exec: CodeExecutor, B: Backend, T: ChangesTrieStorage, H::Out: Ord + HeapSizeOf, - Handler: FnOnce(Result, Exec::Error>, Result, Exec::Error>) -> Result, Exec::Error> + Handler: FnOnce( + Result, Exec::Error>, + Result, Exec::Error> + ) -> Result, Exec::Error> { let strategy: ExecutionStrategy = (&manager).into(); @@ -325,6 +354,7 @@ where call_data, // attempt to run native first, if we're not directed to run wasm only strategy != ExecutionStrategy::AlwaysWasm, + native_call.take(), ); let (storage_delta, changes_delta) = if compute_tx { let (storage_delta, changes_delta) = externalities.transaction(); @@ -351,6 +381,7 @@ where method, call_data, false, + native_call, ); let (storage_delta, changes_delta) = if compute_tx { let (storage_delta, changes_delta) = externalities.transaction(); @@ -363,9 +394,9 @@ where (result, storage_delta, changes_delta) }; - if (result.is_ok() && wasm_result.is_ok() && result.as_ref().unwrap() == wasm_result.as_ref().unwrap()/* && delta == wasm_delta*/) - || (result.is_err() && wasm_result.is_err()) - { + if (result.is_ok() && wasm_result.is_ok() + && result.as_ref().ok() == wasm_result.as_ref().ok()) + || result.is_err() && wasm_result.is_err() { (result, storage_delta, changes_delta) } else { // Consensus error. @@ -427,7 +458,9 @@ where H::Out: Ord + HeapSizeOf, { let proving_backend = proving_backend::ProvingBackend::new(trie_backend); - let (result, _, _) = execute_using_consensus_failure_handler::, _, _>( + let (result, _, _) = execute_using_consensus_failure_handler:: + , _, _, NeverNativeValue, fn() -> NeverNativeValue> + ( &proving_backend, None, overlay, @@ -436,9 +469,10 @@ where call_data, native_when_possible(), false, + None, )?; let proof = proving_backend.extract_proof(); - Ok((result, proof)) + Ok((result.into_encoded(), proof)) } /// Check execution proof, generated by `prove_execution` call. @@ -472,7 +506,9 @@ where Exec: CodeExecutor, H::Out: Ord + HeapSizeOf, { - execute_using_consensus_failure_handler::, _, _>( + execute_using_consensus_failure_handler:: + , _, _, NeverNativeValue, fn() -> NeverNativeValue> + ( trie_backend, None, overlay, @@ -481,7 +517,8 @@ where call_data, native_when_possible(), false, - ).map(|(result, _, _)| result) + None, + ).map(|(result, _, _)| result.into_encoded()) } /// Generate storage read proof. @@ -588,7 +625,7 @@ mod tests { InMemoryStorage as InMemoryChangesTrieStorage, Configuration as ChangesTrieConfig, }; - use primitives::{Blake2Hasher}; + use primitives::Blake2Hasher; struct DummyCodeExecutor { change_changes_trie_config: bool, @@ -600,24 +637,41 @@ mod tests { impl CodeExecutor for DummyCodeExecutor { type Error = u8; - fn call>( + fn call, R: Encode + Decode + PartialEq, NC: FnOnce() -> R>( &self, ext: &mut E, _method: &str, _data: &[u8], - use_native: bool - ) -> (Result, Self::Error>, bool) { + use_native: bool, + _native_call: Option, + ) -> (Result, Self::Error>, bool) { if self.change_changes_trie_config { - ext.place_storage(well_known_keys::CHANGES_TRIE_CONFIG.to_vec(), Some(ChangesTrieConfig { - digest_interval: 777, - digest_levels: 333, - }.encode())); + ext.place_storage( + well_known_keys::CHANGES_TRIE_CONFIG.to_vec(), + Some( + ChangesTrieConfig { + digest_interval: 777, + digest_levels: 333, + }.encode() + ) + ); } let using_native = use_native && self.native_available; match (using_native, self.native_succeeds, self.fallback_succeeds) { - (true, true, _) | (false, _, true) => - (Ok(vec![ext.storage(b"value1").unwrap()[0] + ext.storage(b"value2").unwrap()[0]]), using_native), + (true, true, _) | (false, _, true) => { + ( + Ok( + NativeOrEncoded::Encoded( + vec![ + ext.storage(b"value1").unwrap()[0] + + ext.storage(b"value2").unwrap()[0] + ] + ) + ), + using_native + ) + }, _ => (Err(0), using_native), } } @@ -646,7 +700,7 @@ mod tests { #[test] fn dual_execution_strategy_detects_consensus_failure() { let mut consensus_failed = false; - assert!(execute_using_consensus_failure_handler( + assert!(execute_using_consensus_failure_handler::<_, _, _, _, _, NeverNativeValue, fn() -> NeverNativeValue>( &trie_backend::tests::test_trie(), Some(&InMemoryChangesTrieStorage::new()), &mut Default::default(), @@ -664,6 +718,7 @@ mod tests { we }), true, + None, ).is_err()); assert!(consensus_failed); } diff --git a/substrate/core/test-client/src/lib.rs b/substrate/core/test-client/src/lib.rs index 66b057350a..c2cd79f3a1 100644 --- a/substrate/core/test-client/src/lib.rs +++ b/substrate/core/test-client/src/lib.rs @@ -50,7 +50,12 @@ mod local_executor { #![allow(missing_docs)] use super::runtime; // TODO: change the macro and pass in the `BlakeHasher` that dispatch needs from here instead - native_executor_instance!(pub LocalExecutor, runtime::api::dispatch, runtime::native_version, include_bytes!("../../test-runtime/wasm/target/wasm32-unknown-unknown/release/substrate_test_runtime.compact.wasm")); + native_executor_instance!( + pub LocalExecutor, + runtime::api::dispatch, + runtime::native_version, + include_bytes!("../../test-runtime/wasm/target/wasm32-unknown-unknown/release/substrate_test_runtime.compact.wasm") + ); } /// Native executor used for tests. @@ -71,7 +76,9 @@ pub fn new() -> client::Client client::Client { +pub fn new_with_changes_trie() + -> client::Client +{ new_with_backend(Arc::new(Backend::new()), true) } @@ -80,9 +87,12 @@ pub fn new_with_changes_trie() -> client::Client( backend: Arc, support_changes_trie: bool -) -> client::Client>, runtime::Block, runtime::RuntimeApi> - where - B: backend::LocalBackend, +) -> client::Client< + B, + client::LocalCallExecutor>, + runtime::Block, + runtime::RuntimeApi +> where B: backend::LocalBackend { let executor = NativeExecutor::new(); client::new_with_backend(backend, executor, genesis_storage(support_changes_trie)).unwrap() diff --git a/substrate/core/test-client/src/trait_tests.rs b/substrate/core/test-client/src/trait_tests.rs index 982c92d291..aef6c75654 100644 --- a/substrate/core/test-client/src/trait_tests.rs +++ b/substrate/core/test-client/src/trait_tests.rs @@ -32,7 +32,7 @@ use runtime::{self, Transfer}; use runtime_primitives::generic::BlockId; /// helper to test the `leaves` implementation for various backends -pub fn test_leaves_for_backend(backend: Arc) where +pub fn test_leaves_for_backend(backend: Arc) where B: backend::LocalBackend, { // block tree: @@ -145,7 +145,7 @@ pub fn test_leaves_for_backend(backend: Arc) where } -pub fn test_blockchain_query_by_number_gets_canonical(backend: Arc) where +pub fn test_blockchain_query_by_number_gets_canonical(backend: Arc) where B: backend::LocalBackend, { // block tree: diff --git a/substrate/core/test-runtime/src/lib.rs b/substrate/core/test-runtime/src/lib.rs index 3d2e9b5ca8..fd87782e38 100644 --- a/substrate/core/test-runtime/src/lib.rs +++ b/substrate/core/test-runtime/src/lib.rs @@ -186,13 +186,14 @@ pub fn changes_trie_config() -> primitives::ChangesTrieConfiguration { } } -pub mod test_api { - use super::AccountId; - - decl_runtime_apis! { - pub trait TestAPI { - fn balance_of(id: AccountId) -> u64; - } +decl_runtime_apis! { + pub trait TestAPI { + fn balance_of(id: AccountId) -> u64; + /// A benchmkark function that adds one to the given value and returns the result. + fn benchmark_add_one(val: &u64) -> u64; + /// A benchmark function that adds one to each value in the given vector and returns the + /// result. + fn benchmark_vector_add_one(vec: &Vec) -> Vec; } } @@ -220,7 +221,7 @@ impl_runtime_apis! { system::execute_block(block) } - fn initialise_block(header: ::Header) { + fn initialise_block(header: &::Header) { system::initialise_block(header) } } @@ -259,10 +260,20 @@ impl_runtime_apis! { } } - impl self::test_api::TestAPI for Runtime { + impl self::TestAPI for Runtime { fn balance_of(id: AccountId) -> u64 { system::balance_of(id) } + + fn benchmark_add_one(val: &u64) -> u64 { + val + 1 + } + + fn benchmark_vector_add_one(vec: &Vec) -> Vec { + let mut vec = vec.clone(); + vec.iter_mut().for_each(|v| *v += 1); + vec + } } impl aura_api::AuraApi for Runtime { diff --git a/substrate/core/test-runtime/src/system.rs b/substrate/core/test-runtime/src/system.rs index d4559b1eb7..5b01ecb500 100644 --- a/substrate/core/test-runtime/src/system.rs +++ b/substrate/core/test-runtime/src/system.rs @@ -62,7 +62,7 @@ pub fn authorities() -> Vec { .collect() } -pub fn initialise_block(header: Header) { +pub fn initialise_block(header: &Header) { // populate environment. ::put(&header.number); ::put(&header.parent_hash); diff --git a/substrate/core/test-runtime/wasm/target/wasm32-unknown-unknown/release/substrate_test_runtime.compact.wasm b/substrate/core/test-runtime/wasm/target/wasm32-unknown-unknown/release/substrate_test_runtime.compact.wasm index b36607245612f8dbfeb80b20d1d03030c10fb8db..991bf00699648a50dfc1f3c6d377f4b31335fd0a 100644 GIT binary patch delta 7085 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 vGn`0g5Un;$E=n|*$g2?N< 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 Q6%|R2&ywU>a&*T30ywomfdBvi diff --git a/substrate/core/transaction-pool/graph/src/pool.rs b/substrate/core/transaction-pool/graph/src/pool.rs index e96d320046..923a4f2295 100644 --- a/substrate/core/transaction-pool/graph/src/pool.rs +++ b/substrate/core/transaction-pool/graph/src/pool.rs @@ -60,7 +60,7 @@ pub trait ChainApi: Send + Sync { type Error: From + error::IntoPoolError; /// Verify extrinsic at given block. - fn validate_transaction(&self, at: &BlockId, uxt: &ExtrinsicFor) -> Result; + fn validate_transaction(&self, at: &BlockId, uxt: ExtrinsicFor) -> Result; /// Returns a block number given the block id. fn block_id_to_number(&self, at: &BlockId) -> Result>, Self::Error>; @@ -105,10 +105,10 @@ impl Pool { bail!(error::Error::from(error::ErrorKind::TemporarilyBanned)) } - match self.api.validate_transaction(at, &xt)? { + match self.api.validate_transaction(at, xt.clone())? { TransactionValidity::Valid { priority, requires, provides, longevity } => { Ok(base::Transaction { - data: xt, + data: xt, hash, priority, requires, @@ -325,7 +325,7 @@ mod tests { type Error = error::Error; /// Verify extrinsic at given block. - fn validate_transaction(&self, at: &BlockId, uxt: &ExtrinsicFor) -> Result { + fn validate_transaction(&self, at: &BlockId, uxt: ExtrinsicFor) -> Result { let block_number = self.block_id_to_number(at)?.unwrap(); let nonce = uxt.transfer().nonce; diff --git a/substrate/core/transaction-pool/src/api.rs b/substrate/core/transaction-pool/src/api.rs index a29010b50c..382f4f6ed8 100644 --- a/substrate/core/transaction-pool/src/api.rs +++ b/substrate/core/transaction-pool/src/api.rs @@ -63,7 +63,7 @@ impl txpool::ChainApi for ChainApi where type Hash = H256; type Error = error::Error; - fn validate_transaction(&self, at: &BlockId, uxt: &txpool::ExtrinsicFor) -> error::Result { + fn validate_transaction(&self, at: &BlockId, uxt: txpool::ExtrinsicFor) -> error::Result { Ok(self.client.runtime_api().validate_transaction(at, uxt)?) } diff --git a/substrate/core/transaction-pool/src/tests.rs b/substrate/core/transaction-pool/src/tests.rs index c79ca5605b..5e00b63ad0 100644 --- a/substrate/core/transaction-pool/src/tests.rs +++ b/substrate/core/transaction-pool/src/tests.rs @@ -40,7 +40,7 @@ impl txpool::ChainApi for TestApi { type Hash = Hash; type Error = error::Error; - fn validate_transaction(&self, at: &BlockId, uxt: &txpool::ExtrinsicFor) -> error::Result { + fn validate_transaction(&self, at: &BlockId, uxt: txpool::ExtrinsicFor) -> error::Result { let expected = index(at); let requires = if expected == uxt.transfer().nonce { vec![] diff --git a/substrate/node/executor/src/lib.rs b/substrate/node/executor/src/lib.rs index af366faf0a..1785a88437 100644 --- a/substrate/node/executor/src/lib.rs +++ b/substrate/node/executor/src/lib.rs @@ -58,8 +58,9 @@ mod tests { use keyring::Keyring; use runtime_support::{Hashable, StorageValue, StorageMap}; use state_machine::{CodeExecutor, Externalities, TestExternalities}; - use primitives::{twox_128, Blake2Hasher, ChangesTrieConfiguration, - ed25519::{Public, Pair}}; + use primitives::{ + twox_128, Blake2Hasher, ChangesTrieConfiguration, ed25519::{Public, Pair}, NeverNativeValue + }; use node_primitives::{Hash, BlockNumber, AccountId}; use runtime_primitives::traits::{Header as HeaderT, Digest as DigestT, Hash as HashT}; use runtime_primitives::{generic, generic::Era, ApplyOutcome, ApplyError, ApplyResult, Perbill}; @@ -135,10 +136,22 @@ mod tests { twox_128(&>::key_for(0)).to_vec() => vec![0u8; 32] ]); - let r = executor().call(&mut t, "Core_initialise_block", &vec![].and(&from_block_number(1u64)), true).0; + let r = executor().call::<_, NeverNativeValue, fn() -> NeverNativeValue>( + &mut t, + "Core_initialise_block", + &vec![].and(&from_block_number(1u64)), + true, + None, + ).0; assert!(r.is_ok()); - let v = executor().call(&mut t, "BlockBuilder_apply_extrinsic", &vec![].and(&xt()), true).0.unwrap(); - let r = ApplyResult::decode(&mut &v[..]).unwrap(); + let v = executor().call::<_, NeverNativeValue, fn() -> NeverNativeValue>( + &mut t, + "BlockBuilder_apply_extrinsic", + &vec![].and(&xt()), + true, + None, + ).0.unwrap(); + let r = ApplyResult::decode(&mut &v.as_encoded()[..]).unwrap(); assert_eq!(r, Err(ApplyError::CantPay)); } @@ -156,10 +169,22 @@ mod tests { twox_128(&>::key_for(0)).to_vec() => vec![0u8; 32] ]); - let r = executor().call(&mut t, "Core_initialise_block", &vec![].and(&from_block_number(1u64)), true).0; + let r = executor().call::<_, NeverNativeValue, fn() -> NeverNativeValue>( + &mut t, + "Core_initialise_block", + &vec![].and(&from_block_number(1u64)), + true, + None, + ).0; assert!(r.is_ok()); - let v = executor().call(&mut t, "BlockBuilder_apply_extrinsic", &vec![].and(&xt()), true).0.unwrap(); - let r = ApplyResult::decode(&mut &v[..]).unwrap(); + let v = executor().call::<_, NeverNativeValue, fn() -> NeverNativeValue>( + &mut t, + "BlockBuilder_apply_extrinsic", + &vec![].and(&xt()), + true, + None, + ).0.unwrap(); + let r = ApplyResult::decode(&mut &v.as_encoded()[..]).unwrap(); assert_eq!(r, Err(ApplyError::CantPay)); } @@ -177,9 +202,21 @@ mod tests { twox_128(&>::key_for(0)).to_vec() => vec![0u8; 32] ]); - let r = executor().call(&mut t, "Core_initialise_block", &vec![].and(&from_block_number(1u64)), true).0; + let r = executor().call::<_, NeverNativeValue, fn() -> NeverNativeValue>( + &mut t, + "Core_initialise_block", + &vec![].and(&from_block_number(1u64)), + true, + None, + ).0; assert!(r.is_ok()); - let r = executor().call(&mut t, "BlockBuilder_apply_extrinsic", &vec![].and(&xt()), true).0; + let r = executor().call::<_, NeverNativeValue, fn() -> NeverNativeValue>( + &mut t, + "BlockBuilder_apply_extrinsic", + &vec![].and(&xt()), + true, + None, + ).0; assert!(r.is_ok()); runtime_io::with_externalities(&mut t, || { @@ -202,9 +239,21 @@ mod tests { twox_128(&>::key_for(0)).to_vec() => vec![0u8; 32] ]); - let r = executor().call(&mut t, "Core_initialise_block", &vec![].and(&from_block_number(1u64)), true).0; + let r = executor().call::<_, NeverNativeValue, fn() -> NeverNativeValue>( + &mut t, + "Core_initialise_block", + &vec![].and(&from_block_number(1u64)), + true, + None, + ).0; assert!(r.is_ok()); - let r = executor().call(&mut t, "BlockBuilder_apply_extrinsic", &vec![].and(&xt()), true).0; + let r = executor().call::<_, NeverNativeValue, fn() -> NeverNativeValue>( + &mut t, + "BlockBuilder_apply_extrinsic", + &vec![].and(&xt()), + true, + None, + ).0; assert!(r.is_ok()); runtime_io::with_externalities(&mut t, || { @@ -391,7 +440,13 @@ mod tests { fn full_native_block_import_works() { let mut t = new_test_ext(COMPACT_CODE, false); - executor().call(&mut t, "Core_execute_block", &block1(false).0, true).0.unwrap(); + executor().call::<_, NeverNativeValue, fn() -> NeverNativeValue>( + &mut t, + "Core_execute_block", + &block1(false).0, + true, + None, + ).0.unwrap(); runtime_io::with_externalities(&mut t, || { assert_eq!(Balances::total_balance(&alice()), 41); @@ -440,7 +495,13 @@ mod tests { ]); }); - executor().call(&mut t, "Core_execute_block", &block2().0, true).0.unwrap(); + executor().call::<_, NeverNativeValue, fn() -> NeverNativeValue>( + &mut t, + "Core_execute_block", + &block2().0, + true, + None, + ).0.unwrap(); runtime_io::with_externalities(&mut t, || { assert_eq!(Balances::total_balance(&alice()), 30); @@ -686,11 +747,12 @@ mod tests { fn native_big_block_import_succeeds() { let mut t = new_test_ext(COMPACT_CODE, false); - Executor::new().call( + Executor::new().call::<_, NeverNativeValue, fn() -> NeverNativeValue>( &mut t, "Core_execute_block", &block1big().0, - true + true, + None, ).0.unwrap(); } @@ -699,11 +761,12 @@ mod tests { let mut t = new_test_ext(COMPACT_CODE, false); assert!( - Executor::new().call( + Executor::new().call::<_, NeverNativeValue, fn() -> NeverNativeValue>( &mut t, "Core_execute_block", &block1big().0, - false + false, + None, ).0.is_err() ); } @@ -760,7 +823,13 @@ mod tests { #[test] fn full_native_block_import_works_with_changes_trie() { let mut t = new_test_ext(COMPACT_CODE, true); - Executor::new().call(&mut t, "Core_execute_block", &block1(true).0, true).0.unwrap(); + Executor::new().call::<_, NeverNativeValue, fn() -> NeverNativeValue>( + &mut t, + "Core_execute_block", + &block1(true).0, + true, + None, + ).0.unwrap(); assert!(t.storage_changes_root(Default::default(), 0).is_some()); } diff --git a/substrate/node/runtime/src/lib.rs b/substrate/node/runtime/src/lib.rs index ad6595cbd5..f8cfae1edf 100644 --- a/substrate/node/runtime/src/lib.rs +++ b/substrate/node/runtime/src/lib.rs @@ -279,8 +279,8 @@ impl_runtime_apis! { Executive::execute_block(block) } - fn initialise_block(header: ::Header) { - Executive::initialise_block(&header) + fn initialise_block(header: &::Header) { + Executive::initialise_block(header) } } @@ -353,7 +353,7 @@ impl_runtime_apis! { } impl fg_primitives::GrandpaApi for Runtime { - fn grandpa_pending_change(digest: DigestFor) + fn grandpa_pending_change(digest: &DigestFor) -> Option>> { for log in digest.logs.iter().filter_map(|l| match l { diff --git a/substrate/node/runtime/wasm/target/wasm32-unknown-unknown/release/node_runtime.compact.wasm b/substrate/node/runtime/wasm/target/wasm32-unknown-unknown/release/node_runtime.compact.wasm index e7964a296fd83baf11e4f3e06177d147f4d87715..cc77de34eb99e46c3c1240efe73991af276d6999 100644 GIT binary patch delta 89598 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

GBc-%&h$43({=n?Z!@Hc6UM`VQU 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