diff --git a/substrate/Cargo.lock b/substrate/Cargo.lock index c3c3e66c12e95e08a4d7012e19e05462e3baa8c4..f169f7b24e2710840f597a7c7c23587db7b53370 100644 --- a/substrate/Cargo.lock +++ b/substrate/Cargo.lock @@ -539,6 +539,30 @@ dependencies = [ "walkdir 2.2.9 (registry+https://github.com/rust-lang/crates.io-index)", ] +[[package]] +name = "criterion" +version = "0.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "atty 0.2.13 (registry+https://github.com/rust-lang/crates.io-index)", + "cast 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)", + "clap 2.33.0 (registry+https://github.com/rust-lang/crates.io-index)", + "criterion-plot 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)", + "csv 1.1.1 (registry+https://github.com/rust-lang/crates.io-index)", + "itertools 0.8.0 (registry+https://github.com/rust-lang/crates.io-index)", + "lazy_static 1.4.0 (registry+https://github.com/rust-lang/crates.io-index)", + "num-traits 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)", + "rand_core 0.5.1 (registry+https://github.com/rust-lang/crates.io-index)", + "rand_os 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)", + "rand_xoshiro 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)", + "rayon 1.2.0 (registry+https://github.com/rust-lang/crates.io-index)", + "serde 1.0.101 (registry+https://github.com/rust-lang/crates.io-index)", + "serde_derive 1.0.101 (registry+https://github.com/rust-lang/crates.io-index)", + "serde_json 1.0.41 (registry+https://github.com/rust-lang/crates.io-index)", + "tinytemplate 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)", + "walkdir 2.2.9 (registry+https://github.com/rust-lang/crates.io-index)", +] + [[package]] name = "criterion-plot" version = "0.3.1" @@ -549,6 +573,15 @@ dependencies = [ "itertools 0.8.0 (registry+https://github.com/rust-lang/crates.io-index)", ] +[[package]] +name = "criterion-plot" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "cast 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)", + "itertools 0.8.0 (registry+https://github.com/rust-lang/crates.io-index)", +] + [[package]] name = "crossbeam-channel" version = "0.3.9" @@ -3318,6 +3351,15 @@ dependencies = [ "winapi 0.3.8 (registry+https://github.com/rust-lang/crates.io-index)", ] +[[package]] +name = "rand_os" +version = "0.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "getrandom 0.1.12 (registry+https://github.com/rust-lang/crates.io-index)", + "rand_core 0.5.1 (registry+https://github.com/rust-lang/crates.io-index)", +] + [[package]] name = "rand_pcg" version = "0.1.2" @@ -3344,6 +3386,14 @@ dependencies = [ "rand_core 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)", ] +[[package]] +name = "rand_xoshiro" +version = "0.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "rand_core 0.5.1 (registry+https://github.com/rust-lang/crates.io-index)", +] + [[package]] name = "rayon" version = "1.2.0" @@ -3491,7 +3541,7 @@ dependencies = [ [[package]] name = "rustversion" -version = "0.1.4" +version = "1.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "proc-macro2 1.0.5 (registry+https://github.com/rust-lang/crates.io-index)", @@ -3825,12 +3875,12 @@ name = "sr-api-macros" version = "2.0.0" dependencies = [ "blake2-rfc 0.2.18 (registry+https://github.com/rust-lang/crates.io-index)", - "criterion 0.2.11 (registry+https://github.com/rust-lang/crates.io-index)", + "criterion 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)", "parity-scale-codec 1.0.6 (registry+https://github.com/rust-lang/crates.io-index)", "proc-macro-crate 0.1.4 (registry+https://github.com/rust-lang/crates.io-index)", "proc-macro2 0.4.30 (registry+https://github.com/rust-lang/crates.io-index)", "quote 0.6.13 (registry+https://github.com/rust-lang/crates.io-index)", - "rustversion 0.1.4 (registry+https://github.com/rust-lang/crates.io-index)", + "rustversion 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)", "sr-primitives 2.0.0", "sr-version 2.0.0", "substrate-client 2.0.0", @@ -6829,7 +6879,9 @@ dependencies = [ "checksum core-foundation-sys 0.6.2 (registry+https://github.com/rust-lang/crates.io-index)" = "e7ca8a5221364ef15ce201e8ed2f609fc312682a8f4e0e3d4aa5879764e0fa3b" "checksum crc32fast 1.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "ba125de2af0df55319f41944744ad91c71113bf74a4646efff39afe1f6842db1" "checksum criterion 0.2.11 (registry+https://github.com/rust-lang/crates.io-index)" = "0363053954f3e679645fc443321ca128b7b950a6fe288cf5f9335cc22ee58394" +"checksum criterion 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)" = "938703e165481c8d612ea3479ac8342e5615185db37765162e762ec3523e2fc6" "checksum criterion-plot 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)" = "76f9212ddf2f4a9eb2d401635190600656a1f88a932ef53d06e7fa4c7e02fb8e" +"checksum criterion-plot 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "eccdc6ce8bbe352ca89025bee672aa6d24f4eb8c53e3a8b5d1bc58011da072a2" "checksum crossbeam-channel 0.3.9 (registry+https://github.com/rust-lang/crates.io-index)" = "c8ec7fcd21571dc78f96cc96243cab8d8f035247c3efd16c687be154c3fa9efa" "checksum crossbeam-deque 0.7.1 (registry+https://github.com/rust-lang/crates.io-index)" = "b18cd2e169ad86297e6bc0ad9aa679aee9daa4f19e8163860faf7c164e4f5a71" "checksum crossbeam-epoch 0.7.2 (registry+https://github.com/rust-lang/crates.io-index)" = "fedcd6772e37f3da2a9af9bf12ebe046c0dfe657992377b4df982a2b54cd37a9" @@ -7084,9 +7136,11 @@ dependencies = [ "checksum rand_isaac 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "ded997c9d5f13925be2a6fd7e66bf1872597f759fd9dd93513dd7e92e5a5ee08" "checksum rand_jitter 0.1.4 (registry+https://github.com/rust-lang/crates.io-index)" = "1166d5c91dc97b88d1decc3285bb0a99ed84b05cfd0bc2341bdf2d43fc41e39b" "checksum rand_os 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)" = "7b75f676a1e053fc562eafbb47838d67c84801e38fc1ba459e8f180deabd5071" +"checksum rand_os 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)" = "a788ae3edb696cfcba1c19bfd388cc4b8c21f8a408432b199c072825084da58a" "checksum rand_pcg 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)" = "abf9b09b01790cfe0364f52bf32995ea3c39f4d2dd011eac241d2914146d0b44" "checksum rand_xorshift 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "cbf7e9e623549b0e21f6e97cf8ecf247c1a8fd2e8a992ae265314300b2455d5c" "checksum rand_xoshiro 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "03b418169fb9c46533f326efd6eed2576699c44ca92d3052a066214a8d828929" +"checksum rand_xoshiro 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)" = "0e18c91676f670f6f0312764c759405f13afb98d5d73819840cf72a518487bff" "checksum rayon 1.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "83a27732a533a1be0a0035a111fe76db89ad312f6f0347004c220c57f209a123" "checksum rayon-core 1.6.0 (registry+https://github.com/rust-lang/crates.io-index)" = "98dcf634205083b17d0861252431eb2acbfb698ab7478a2d20de07954f47ec7b" "checksum rdrand 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "678054eb77286b51581ba43620cc911abf02758c91f93f479767aed0f90458b2" @@ -7104,7 +7158,7 @@ dependencies = [ "checksum rustc-hex 2.0.1 (registry+https://github.com/rust-lang/crates.io-index)" = "403bb3a286107a04825a5f82e1270acc1e14028d3d554d7a1e08914549575ab8" "checksum rustc_version 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)" = "138e3e0acb6c9fb258b19b67cb8abd63c00679d2851805ea151465464fe9030a" "checksum rustls 0.15.2 (registry+https://github.com/rust-lang/crates.io-index)" = "f271e3552cd835fa28c541c34a7e8fdd8cdff09d77fe4eb8f6c42e87a11b096e" -"checksum rustversion 0.1.4 (registry+https://github.com/rust-lang/crates.io-index)" = "b48139cfc215c6cc70d43c6c555a59e723c3b5adb26a4cfa09f815a5ae5871e8" +"checksum rustversion 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)" = "c48f91977f4ef3be5358c15d131d3f663f6b4d7a112555bf3bf52ad23b6659e5" "checksum rw-stream-sink 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)" = "2f9cbe61c20455d3015b2bb7be39e1872310283b8e5a52f5b242b0ac7581fe78" "checksum ryu 1.0.1 (registry+https://github.com/rust-lang/crates.io-index)" = "19d2271fa48eaf61e53cc88b4ad9adcbafa2d512c531e7fadb6dc11a4d3656c5" "checksum safe-mix 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)" = "7f7bf422d23a88c16d5090d455f182bc99c60af4df6a345c63428acf5129e347" diff --git a/substrate/core/client/src/runtime_api.rs b/substrate/core/client/src/runtime_api.rs index a5700951e9c4c64d1266f6f4f3054d22a93b1af5..68b49e5910b4511a0390bee22231027bb4def391 100644 --- a/substrate/core/client/src/runtime_api.rs +++ b/substrate/core/client/src/runtime_api.rs @@ -23,6 +23,9 @@ pub use state_machine::OverlayedChanges; #[cfg(feature = "std")] pub use primitives::NativeOrEncoded; #[doc(hidden)] +#[cfg(not(feature = "std"))] +pub use primitives::to_substrate_wasm_fn_return_value; +#[doc(hidden)] pub use sr_primitives::{ traits::{ Block as BlockT, GetNodeBlockType, GetRuntimeBlockType, diff --git a/substrate/core/primitives/src/lib.rs b/substrate/core/primitives/src/lib.rs index d1b42766a08f0c970e045f75984dae1d9b4fa1ce..02f28c797c0027b4a42d30c160e2ff95b36d56e7 100644 --- a/substrate/core/primitives/src/lib.rs +++ b/substrate/core/primitives/src/lib.rs @@ -287,3 +287,25 @@ impl From<LogLevel> for log::Level { } } } + +/// Encodes the given value into a buffer and returns the pointer and the length as a single `u64`. +/// +/// When Substrate calls into Wasm it expects a fixed signature for functions exported +/// from the Wasm blob. The return value of this signature is always a `u64`. +/// This `u64` stores the pointer to the encoded return value and the length of this encoded value. +/// The low `32bits` are reserved for the pointer, followed by `32bit` for the length. +#[cfg(not(feature = "std"))] +pub fn to_substrate_wasm_fn_return_value(value: &impl Encode) -> u64 { + let encoded = value.encode(); + + let ptr = encoded.as_ptr() as u64; + let length = encoded.len() as u64; + let res = ptr | (length << 32); + + // Leak the output vector to avoid it being freed. + // This is fine in a WASM context since the heap + // will be discarded after the call. + rstd::mem::forget(encoded); + + res +} diff --git a/substrate/core/primitives/src/testing.rs b/substrate/core/primitives/src/testing.rs index 92a09ff044f773c2f43675040ebdd065e4082a20..e5d301008e3d4fb3344ad7306b797f9b70727964 100644 --- a/substrate/core/primitives/src/testing.rs +++ b/substrate/core/primitives/src/testing.rs @@ -196,15 +196,7 @@ macro_rules! wasm_export_functions { $( $fn_impl )* } - // We need to return *something* - let output = Vec::<u8>::new(); - let res = output.as_ptr() as u64 + ((output.len() as u64) << 32); - - // Leak the output vector to avoid it being freed. - // This is fine in a WASM context since the heap - // will be discarded after the call. - $crate::rstd::mem::forget(output); - res + $crate::to_substrate_wasm_fn_return_value(&()) } }; (@IMPL @@ -232,14 +224,7 @@ macro_rules! wasm_export_functions { $( $fn_impl )* }; - let output = $crate::Encode::encode(&output); - let res = output.as_ptr() as u64 + ((output.len() as u64) << 32); - - // Leak the output vector to avoid it being freed. - // This is fine in a WASM context since the heap - // will be discarded after the call. - $crate::rstd::mem::forget(output); - res + $crate::to_substrate_wasm_fn_return_value(&output) } }; } diff --git a/substrate/core/sr-api-macros/Cargo.toml b/substrate/core/sr-api-macros/Cargo.toml index 6f02e3040986f2842401db5cb7aa6d1d0093928d..022536136b80e31529bfdff4de71ac7ae40ae64a 100644 --- a/substrate/core/sr-api-macros/Cargo.toml +++ b/substrate/core/sr-api-macros/Cargo.toml @@ -21,12 +21,17 @@ state_machine = { package = "substrate-state-machine", path = "../state-machine" sr-primitives = { path = "../sr-primitives" } sr-version = { path = "../sr-version" } primitives = { package = "substrate-primitives", path = "../primitives" } -criterion = "0.2.11" +criterion = "0.3.0" consensus_common = { package = "substrate-consensus-common", path = "../consensus/common" } codec = { package = "parity-scale-codec", version = "1.0.0" } -trybuild = "1.0.14" -rustversion = "0.1.4" +trybuild = "1.0.17" +rustversion = "1.0.0" [[bench]] name = "bench" harness = false + +# We actually don't need the `std` feature in this crate, but the tests require it. +[features] +default = [ "std" ] +std = [] 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 fb154aa1123580a1e35597b1b40f1961b6ebb522..28eb5c60729edda5f4b4b41cad03b6dbc89eb3e9 100644 --- a/substrate/core/sr-api-macros/src/impl_runtime_apis.rs +++ b/substrate/core/sr-api-macros/src/impl_runtime_apis.rs @@ -83,8 +83,7 @@ fn generate_impl_call( )* #[allow(deprecated)] - let output = <#runtime as #impl_trait>::#fn_name(#( #pborrow #pnames2 ),*); - #c::runtime_api::Encode::encode(&output) + <#runtime as #impl_trait>::#fn_name(#( #pborrow #pnames2 ),*) ) ) } @@ -175,11 +174,12 @@ fn generate_impl_calls( /// Generate the dispatch function that is used in native to call into the runtime. fn generate_dispatch_function(impls: &[ItemImpl]) -> Result<TokenStream> { let data = Ident::new("data", Span::call_site()); + let c = generate_crate_access(HIDDEN_INCLUDES_ID); let impl_calls = generate_impl_calls(impls, &data)? .into_iter() .map(|(trait_, fn_name, impl_)| { let name = prefix_function_with_trait(&trait_, &fn_name); - quote!( #name => Some({ #impl_ }), ) + quote!( #name => Some(#c::runtime_api::Encode::encode(&{ #impl_ })), ) }); Ok(quote!( @@ -218,13 +218,7 @@ fn generate_wasm_interface(impls: &[ItemImpl]) -> Result<TokenStream> { }; let output = { #impl_ }; - let res = output.as_ptr() as u64 + ((output.len() as u64) << 32); - - // Leak the output vector to avoid it being freed. - // This is fine in a WASM context since the heap - // will be discarded after the call. - #c::runtime_api::mem::forget(output); - res + #c::runtime_api::to_substrate_wasm_fn_return_value(&output) } ) }); 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 36091d1f85062e6c693e0780383d0d9680b1d258..a539d838221be1409b5bd8ae8ebb451382ef82b0 100644 --- a/substrate/core/sr-api-macros/tests/decl_and_impl.rs +++ b/substrate/core/sr-api-macros/tests/decl_and_impl.rs @@ -93,13 +93,6 @@ fn test_client_side_function_signature() { RuntimeApiImpl::<TestClient>::same_name_before_version_2; } -#[test] -fn test_runtime_side_function_signature() { - let _api_same_name: fn(input_data: *mut u8, input_len: usize) -> u64 = api::Api_same_name; - let _api_with_version_same_name: fn(input_data: *mut u8, input_len: usize) -> u64 = - api::ApiWithCustomVersion_same_name; -} - #[test] fn check_runtime_api_info() { assert_eq!(&Api::<Block>::ID, &runtime_decl_for_Api::ID); diff --git a/substrate/core/sr-api-macros/tests/ui/impl_incorrect_method_signature.rs b/substrate/core/sr-api-macros/tests/ui/impl_incorrect_method_signature.rs index 774d017c190e926e1a4e4d55e6ab9aa6ab46214e..b85431f3ba049b0a55e7e9ddd6a6c0d80e89cb27 100644 --- a/substrate/core/sr-api-macros/tests/ui/impl_incorrect_method_signature.rs +++ b/substrate/core/sr-api-macros/tests/ui/impl_incorrect_method_signature.rs @@ -1,6 +1,6 @@ -use sr_primitives::traits::GetNodeBlockType; +use sr_primitives::traits::{GetNodeBlockType, Block as BlockT}; use test_client::runtime::Block; -use client::{decl_runtime_apis, impl_runtime_apis}; +use client::{decl_runtime_apis, impl_runtime_apis, runtime_api}; /// The declaration of the `Runtime` type and the implementation of the `GetNodeBlockType` /// trait are done by the `construct_runtime!` macro in a real runtime. @@ -19,6 +19,18 @@ impl_runtime_apis! { impl self::Api<Block> for Runtime { fn test(data: String) {} } + + impl runtime_api::Core<Block> for Runtime { + fn version() -> runtime_api::RuntimeVersion { + unimplemented!() + } + fn execute_block(_: Block) { + unimplemented!() + } + fn initialize_block(_: &<Block as BlockT>::Header) { + unimplemented!() + } + } } fn main() {} diff --git a/substrate/core/sr-api-macros/tests/ui/impl_incorrect_method_signature.stderr b/substrate/core/sr-api-macros/tests/ui/impl_incorrect_method_signature.stderr index 15434a52ba8b78ae6876b17e34f72ff9c7e85779..025ca60c48095365e706871c1ec4a2fe3a50d10e 100644 --- a/substrate/core/sr-api-macros/tests/ui/impl_incorrect_method_signature.stderr +++ b/substrate/core/sr-api-macros/tests/ui/impl_incorrect_method_signature.stderr @@ -10,6 +10,37 @@ error[E0053]: method `test` has an incompatible type for trait = note: expected type `fn(u64)` found type `fn(std::string::String)` +error[E0053]: method `Api_test_runtime_api_impl` has an incompatible type for trait + --> $DIR/impl_incorrect_method_signature.rs:18:1 + | +12 | / decl_runtime_apis! { +13 | | pub trait Api { +14 | | fn test(data: u64); +15 | | } +16 | | } + | |_- type in trait +17 | +18 | impl_runtime_apis! { + | ^^^^^^^^^^^^^^^^^^ expected u64, found struct `std::string::String` + | + = note: expected type `fn(&RuntimeApiImpl<RuntimeApiImplCall>, &sr_primitives::generic::block::BlockId<sr_primitives::generic::block::Block<sr_primitives::generic::header::Header<u64, sr_primitives::traits::BlakeTwo256>, substrate_test_runtime::Extrinsic>>, sr_api_hidden_includes_DECL_RUNTIME_APIS::sr_api_client::runtime_api::ExecutionContext, std::option::Option<u64>, std::vec::Vec<u8>) -> std::result::Result<sr_api_hidden_includes_DECL_RUNTIME_APIS::sr_api_client::runtime_api::NativeOrEncoded<()>, sr_api_hidden_includes_DECL_RUNTIME_APIS::sr_api_client::error::Error>` + found type `fn(&RuntimeApiImpl<RuntimeApiImplCall>, &sr_primitives::generic::block::BlockId<sr_primitives::generic::block::Block<sr_primitives::generic::header::Header<u64, sr_primitives::traits::BlakeTwo256>, substrate_test_runtime::Extrinsic>>, sr_api_hidden_includes_DECL_RUNTIME_APIS::sr_api_client::runtime_api::ExecutionContext, std::option::Option<std::string::String>, std::vec::Vec<u8>) -> std::result::Result<sr_api_hidden_includes_DECL_RUNTIME_APIS::sr_api_client::runtime_api::NativeOrEncoded<()>, sr_api_hidden_includes_DECL_RUNTIME_APIS::sr_api_client::error::Error>` + +error[E0308]: mismatched types + --> $DIR/impl_incorrect_method_signature.rs:18:1 + | +18 | / impl_runtime_apis! { +19 | | impl self::Api<Block> for Runtime { +20 | | fn test(data: String) {} +21 | | } +... | +33 | | } +34 | | } + | |_^ expected u64, found struct `std::string::String` + | + = note: expected type `u64` + found type `std::string::String` + error[E0308]: mismatched types --> $DIR/impl_incorrect_method_signature.rs:20:11 | @@ -18,6 +49,3 @@ error[E0308]: mismatched types | = note: expected type `u64` found type `std::string::String` - -Some errors have detailed explanations: E0053, E0308. -For more information about an error, try `rustc --explain E0053`. diff --git a/substrate/core/sr-api-macros/tests/ui/impl_two_traits_with_same_name.rs b/substrate/core/sr-api-macros/tests/ui/impl_two_traits_with_same_name.rs index acca97a73df5bd2464fb736c733d84116b07c994..1664bec577b57a53715fc65b0f3234e12bd78503 100644 --- a/substrate/core/sr-api-macros/tests/ui/impl_two_traits_with_same_name.rs +++ b/substrate/core/sr-api-macros/tests/ui/impl_two_traits_with_same_name.rs @@ -16,6 +16,8 @@ decl_runtime_apis! { } mod second { + use super::*; + decl_runtime_apis! { pub trait Api { fn test2(data: u64); diff --git a/substrate/core/sr-api-macros/tests/ui/impl_two_traits_with_same_name.stderr b/substrate/core/sr-api-macros/tests/ui/impl_two_traits_with_same_name.stderr index 355db2864bb784a7011b5c0b8376a713371f88b2..4c37b6b716a0a97cd19bca6a5f469adc56e58ed4 100644 --- a/substrate/core/sr-api-macros/tests/ui/impl_two_traits_with_same_name.stderr +++ b/substrate/core/sr-api-macros/tests/ui/impl_two_traits_with_same_name.stderr @@ -1,25 +1,17 @@ error: Two traits with the same name detected! The trait name is used to generate its ID. Please rename one trait at the declaration! - --> $DIR/impl_two_traits_with_same_name.rs:31:15 + --> $DIR/impl_two_traits_with_same_name.rs:33:15 | -31 | impl second::Api<Block> for Runtime { +33 | impl second::Api<Block> for Runtime { | ^^^ -error: cannot find macro `decl_runtime_apis!` in this scope - --> $DIR/impl_two_traits_with_same_name.rs:19:2 +error[E0277]: the trait bound `RuntimeApiImpl<RuntimeApiImplCall>: sr_api_hidden_includes_DECL_RUNTIME_APIS::sr_api_client::runtime_api::Core<sr_primitives::generic::block::Block<sr_primitives::generic::header::Header<u64, sr_primitives::traits::BlakeTwo256>, substrate_test_runtime::Extrinsic>>` is not satisfied + --> $DIR/impl_two_traits_with_same_name.rs:29:7 | -19 | decl_runtime_apis! { - | ^^^^^^^^^^^^^^^^^ +29 | impl self::Api<Block> for Runtime { + | ^^^^^^^^^^^^^^^^ the trait `sr_api_hidden_includes_DECL_RUNTIME_APIS::sr_api_client::runtime_api::Core<sr_primitives::generic::block::Block<sr_primitives::generic::header::Header<u64, sr_primitives::traits::BlakeTwo256>, substrate_test_runtime::Extrinsic>>` is not implemented for `RuntimeApiImpl<RuntimeApiImplCall>` -error[E0433]: failed to resolve: could not find `runtime_decl_for_Api` in `second` - --> $DIR/impl_two_traits_with_same_name.rs:26:1 +error[E0277]: the trait bound `RuntimeApiImpl<RuntimeApiImplCall>: sr_api_hidden_includes_DECL_RUNTIME_APIS::sr_api_client::runtime_api::Core<sr_primitives::generic::block::Block<sr_primitives::generic::header::Header<u64, sr_primitives::traits::BlakeTwo256>, substrate_test_runtime::Extrinsic>>` is not satisfied + --> $DIR/impl_two_traits_with_same_name.rs:33:7 | -26 | / impl_runtime_apis! { -27 | | impl self::Api<Block> for Runtime { -28 | | fn test(data: u64) {} -29 | | } -... | -33 | | } -34 | | } - | |_^ could not find `runtime_decl_for_Api` in `second` - -For more information about this error, try `rustc --explain E0433`. +33 | impl second::Api<Block> for Runtime { + | ^^^^^^^^^^^^^^^^^^ the trait `sr_api_hidden_includes_DECL_RUNTIME_APIS::sr_api_client::runtime_api::Core<sr_primitives::generic::block::Block<sr_primitives::generic::header::Header<u64, sr_primitives::traits::BlakeTwo256>, substrate_test_runtime::Extrinsic>>` is not implemented for `RuntimeApiImpl<RuntimeApiImplCall>` diff --git a/substrate/core/sr-api-macros/tests/ui/type_reference_in_impl_runtime_apis_call.rs b/substrate/core/sr-api-macros/tests/ui/type_reference_in_impl_runtime_apis_call.rs index 0e7dc56951647264d532ee41c4a917883e9f5b22..20f114c6bb29e597f7c093c72be7c9ebd9501b7b 100644 --- a/substrate/core/sr-api-macros/tests/ui/type_reference_in_impl_runtime_apis_call.rs +++ b/substrate/core/sr-api-macros/tests/ui/type_reference_in_impl_runtime_apis_call.rs @@ -1,6 +1,6 @@ -use sr_primitives::traits::GetNodeBlockType; +use sr_primitives::traits::{GetNodeBlockType, Block as BlockT}; use test_client::runtime::Block; -use client::{decl_runtime_apis, impl_runtime_apis}; +use client::{decl_runtime_apis, impl_runtime_apis, runtime_api}; /// The declaration of the `Runtime` type and the implementation of the `GetNodeBlockType` /// trait are done by the `construct_runtime!` macro in a real runtime. @@ -21,6 +21,18 @@ impl_runtime_apis! { unimplemented!() } } + + impl runtime_api::Core<Block> for Runtime { + fn version() -> runtime_api::RuntimeVersion { + unimplemented!() + } + fn execute_block(_: Block) { + unimplemented!() + } + fn initialize_block(_: &<Block as BlockT>::Header) { + unimplemented!() + } + } } fn main() {} diff --git a/substrate/core/sr-api-macros/tests/ui/type_reference_in_impl_runtime_apis_call.stderr b/substrate/core/sr-api-macros/tests/ui/type_reference_in_impl_runtime_apis_call.stderr index 9bfc04c8db046ecba4f42d2140143a7ade6b3886..f3abaddd6ea9d757ae1b132a9274c068bc6814c6 100644 --- a/substrate/core/sr-api-macros/tests/ui/type_reference_in_impl_runtime_apis_call.stderr +++ b/substrate/core/sr-api-macros/tests/ui/type_reference_in_impl_runtime_apis_call.stderr @@ -10,6 +10,22 @@ error[E0053]: method `test` has an incompatible type for trait = note: expected type `fn(u64)` found type `fn(&u64)` +error[E0053]: method `Api_test_runtime_api_impl` has an incompatible type for trait + --> $DIR/type_reference_in_impl_runtime_apis_call.rs:18:1 + | +12 | / decl_runtime_apis! { +13 | | pub trait Api { +14 | | fn test(data: u64); +15 | | } +16 | | } + | |_- type in trait +17 | +18 | impl_runtime_apis! { + | ^^^^^^^^^^^^^^^^^^ expected u64, found &u64 + | + = note: expected type `fn(&RuntimeApiImpl<RuntimeApiImplCall>, &sr_primitives::generic::block::BlockId<sr_primitives::generic::block::Block<sr_primitives::generic::header::Header<u64, sr_primitives::traits::BlakeTwo256>, substrate_test_runtime::Extrinsic>>, sr_api_hidden_includes_DECL_RUNTIME_APIS::sr_api_client::runtime_api::ExecutionContext, std::option::Option<u64>, std::vec::Vec<u8>) -> std::result::Result<sr_api_hidden_includes_DECL_RUNTIME_APIS::sr_api_client::runtime_api::NativeOrEncoded<()>, sr_api_hidden_includes_DECL_RUNTIME_APIS::sr_api_client::error::Error>` + found type `fn(&RuntimeApiImpl<RuntimeApiImplCall>, &sr_primitives::generic::block::BlockId<sr_primitives::generic::block::Block<sr_primitives::generic::header::Header<u64, sr_primitives::traits::BlakeTwo256>, substrate_test_runtime::Extrinsic>>, sr_api_hidden_includes_DECL_RUNTIME_APIS::sr_api_client::runtime_api::ExecutionContext, std::option::Option<&u64>, std::vec::Vec<u8>) -> std::result::Result<sr_api_hidden_includes_DECL_RUNTIME_APIS::sr_api_client::runtime_api::NativeOrEncoded<()>, sr_api_hidden_includes_DECL_RUNTIME_APIS::sr_api_client::error::Error>` + error[E0308]: mismatched types --> $DIR/type_reference_in_impl_runtime_apis_call.rs:18:1 | @@ -17,13 +33,10 @@ error[E0308]: mismatched types 19 | | impl self::Api<Block> for Runtime { 20 | | fn test(data: &u64) { 21 | | unimplemented!() -22 | | } -23 | | } -24 | | } +... | +35 | | } +36 | | } | |_^ expected u64, found &u64 | = note: expected type `u64` found type `&u64` - -Some errors have detailed explanations: E0053, E0308. -For more information about an error, try `rustc --explain E0053`. diff --git a/substrate/core/telemetry/src/worker/node.rs b/substrate/core/telemetry/src/worker/node.rs index 11b1f2a81e6996da38c9636f563bbf809922b7a2..0f606e40638024c82c9c2cc96784d4faf3217580 100644 --- a/substrate/core/telemetry/src/worker/node.rs +++ b/substrate/core/telemetry/src/worker/node.rs @@ -58,6 +58,8 @@ struct NodeSocketConnected<TTrans: Transport> { pending: VecDeque<BytesMut>, /// If true, we need to flush the sink. need_flush: bool, + /// A timeout for the socket to write data. + timeout: Option<Delay>, } /// Event that can happen with this node. @@ -66,7 +68,16 @@ pub enum NodeEvent<TSinkErr> { /// We are now connected to this node. Connected, /// We are now disconnected from this node. - Disconnected(TSinkErr), + Disconnected(ConnectionError<TSinkErr>), +} + +/// Reason for disconnecting from a node. +#[derive(Debug)] +pub enum ConnectionError<TSinkErr> { + /// The connection timed-out. + Timeout, + /// The sink errored. + Sink(TSinkErr), } impl<TTrans: Transport> Node<TTrans> { @@ -116,10 +127,12 @@ where TTrans: Clone + Unpin, TTrans::Dial: Unpin, let mut socket = mem::replace(&mut self.socket, NodeSocket::Poisoned); self.socket = loop { match socket { - NodeSocket::Connected(mut conn) => + NodeSocket::Connected(mut conn) => { match NodeSocketConnected::poll(Pin::new(&mut conn), cx, &self.addr) { - Poll::Ready(Ok(v)) => match v {} - Poll::Pending => break NodeSocket::Connected(conn), + Poll::Ready(Ok(v)) => match v {}, + Poll::Pending => { + break NodeSocket::Connected(conn) + }, Poll::Ready(Err(err)) => { warn!(target: "telemetry", "Disconnected from {}: {:?}", self.addr, err); let timeout = gen_rand_reconnect_delay(); @@ -127,10 +140,16 @@ where TTrans: Clone + Unpin, TTrans::Dial: Unpin, return Poll::Ready(NodeEvent::Disconnected(err)) } } + } NodeSocket::Dialing(mut s) => match Future::poll(Pin::new(&mut s), cx) { Poll::Ready(Ok(sink)) => { debug!(target: "telemetry", "Connected to {}", self.addr); - let conn = NodeSocketConnected { sink, pending: VecDeque::new(), need_flush: false }; + let conn = NodeSocketConnected { + sink, + pending: VecDeque::new(), + need_flush: false, + timeout: None, + }; self.socket = NodeSocket::Connected(conn); return Poll::Ready(NodeEvent::Connected) }, @@ -189,18 +208,15 @@ where TTrans::Output: Sink<BytesMut, Error = TSinkErr> fn poll( mut self: Pin<&mut Self>, cx: &mut Context, - my_addr: &Multiaddr - ) -> Poll<Result<futures::never::Never, TSinkErr>> { - loop { - if let Some(item) = self.pending.pop_front() { - if let Poll::Pending = Sink::poll_ready(Pin::new(&mut self.sink), cx) { - self.pending.push_front(item); - return Poll::Pending - } + my_addr: &Multiaddr, + ) -> Poll<Result<futures::never::Never, ConnectionError<TSinkErr>>> { + while let Some(item) = self.pending.pop_front() { + if let Poll::Ready(_) = Sink::poll_ready(Pin::new(&mut self.sink), cx) { let item_len = item.len(); if let Err(err) = Sink::start_send(Pin::new(&mut self.sink), item) { - return Poll::Ready(Err(err)) + self.timeout = None; + return Poll::Ready(Err(ConnectionError::Sink(err))) } trace!( target: "telemetry", "Successfully sent {:?} bytes message to {}", @@ -208,28 +224,59 @@ where TTrans::Output: Sink<BytesMut, Error = TSinkErr> ); self.need_flush = true; - } else if self.need_flush { - match Sink::poll_flush(Pin::new(&mut self.sink), cx) { - Poll::Pending => return Poll::Pending, - Poll::Ready(Err(err)) => return Poll::Ready(Err(err)), - Poll::Ready(Ok(())) => self.need_flush = false, + } else { + self.pending.push_front(item); + if self.timeout.is_none() { + self.timeout = Some(Delay::new(Duration::from_secs(10))); } + break; + } + } - } else { - match Stream::poll_next(Pin::new(&mut self.sink), cx) { - Poll::Ready(Some(Ok(_))) => { - // We poll the telemetry `Stream` because the underlying implementation relies on - // this in order to answer PINGs. - // We don't do anything with incoming messages, however. - }, - Poll::Ready(Some(Err(err))) => { - return Poll::Ready(Err(err)) - }, - Poll::Pending | Poll::Ready(None) => break, + if self.need_flush { + match Sink::poll_flush(Pin::new(&mut self.sink), cx) { + Poll::Pending => { + if self.timeout.is_none() { + self.timeout = Some(Delay::new(Duration::from_secs(10))); + } + }, + Poll::Ready(Err(err)) => { + self.timeout = None; + return Poll::Ready(Err(ConnectionError::Sink(err))) + }, + Poll::Ready(Ok(())) => { + self.timeout = None; + self.need_flush = false; + }, + } + } + + if let Some(timeout) = self.timeout.as_mut() { + match Future::poll(Pin::new(timeout), cx) { + Poll::Pending => {}, + Poll::Ready(Err(err)) => { + self.timeout = None; + warn!(target: "telemetry", "Connection timeout error for {} {:?}", my_addr, err); + } + Poll::Ready(Ok(_)) => { + self.timeout = None; + return Poll::Ready(Err(ConnectionError::Timeout)) } } } + match Stream::poll_next(Pin::new(&mut self.sink), cx) { + Poll::Ready(Some(Ok(_))) => { + // We poll the telemetry `Stream` because the underlying implementation relies on + // this in order to answer PINGs. + // We don't do anything with incoming messages, however. + }, + Poll::Ready(Some(Err(err))) => { + return Poll::Ready(Err(ConnectionError::Sink(err))) + }, + Poll::Pending | Poll::Ready(None) => {}, + } + Poll::Pending } }