Giter Club home page Giter Club logo

substrate-api-client's Introduction

substrate-api-client

The substrate-api-client is a Rust library for connecting to a substrate-based node via RPC. It's particularly useful for setups with no-std environment (which are typical for trusted execution environmnets or embedded devices). It provides similar functionalities as Polkadot-js, such as easy extrinsic submission and state queries. With an RPC client, developers can easily interact with any Polkadot or Kusama chain. There are several RPC clients available in different programming languages. For Rust, the most popular RPC client is subxt. The substrate-api-client provides a simpler, less extensive alternative to subxt, focused on providing as many features as possible for no-std environments.

The substrate-api-client connects to the substrate's RPC interface via WebSockets allowing to

  • Compose extrinsics, send them (asynchronously and synchronously) and subscribe to updates (synchronously).
  • Support no_std builds. Only the rpc-client is std only. For no_std builds, a custom rpc client needs to be implemented.
  • Watch events and execute code upon events.
  • Parse and print the node metadata.
  • Support async and sync implementations.
  • Support three different websocket crates (jsonrpsee, tungstenite and ws). See Cargo.toml for more information and limitations.

Prerequisites

In order to build the substrate-api-client and the examples, Rust and the wasm target are needed. For Linux:

curl https://sh.rustup.rs -sSf | sh
# Install the rust toolchain specified in rust-toolchain.toml
rustup show

Substrate node

To execute the examples, a running substrate node is needed. You can download a node artifact from substrate directly: https://github.com/paritytech/substrate or run the kitchensink-node with docker:

docker run -p 9944:9944 -p 9933:9933 -p 30333:30333 parity/substrate:latest --dev --rpc-external

For more information, please refer to the substrate repository.

Examples

The api-client provides several examples which show how to fetch node states or submit extrinsic. Examples are differentiated between sync and async implementations. Don't forget to check the feature import of the associated Cargo.toml. It shows how to import the api-client as an async or sync library. To run an example, clone the substrate-api-client repository and run the desired example directly with the cargo command:

git clone https://github.com/scs/substrate-api-client.git
cd substrate-api-client
# Run an async example:
cargo run -p ac-examples-async --example get_storage
# Run a sync example:
cargo run -p ac-examples-sync --example runtime_update_sync

or download the already built binaries from GitHub Actions and run them without any previous building:

# Enter the async or sync example directory and add execution rights to the chosen example.
cd examples-<sync/async>
chmod +x <example>
# And run it.
./<example>

Set the output verbosity by prepending RUST_LOG=info or RUST_LOG=debug.

The following async examples can be found in the async examples folder:

The following sync examples can be found in the sync examples folder:

no_std build

Almost everything in the api-client, except for the rpc-clients and a few additional features, is no_std compatible. Many helpful features, such as extrinsic and call creation (see the macros), metadata and event types (see the node-api and primitives) are available in no_std right away. However, to directly connect to a Substrate node a RPC client is necessary. Because websocket connection features are often hardware dependent, a generic no_std RPC client implementation is hardly possible. So for most use cases a self-implemented RPC client is required. To make this as simple as possible, the interface between the Api, which provides all the features, and the RPC client, providing the node connection, is kept very basic. Check out the following explanations for more info.

Import

To import the api-client in no_std make sure the default features are turned off and disable_target_static_assertions is enabled:

# In the Cargo.toml import the api-client as following:
substrate-api-client = { git = "https://github.com/scs/substrate-api-client.git", default-features = false, features = ["disable_target_static_assertions"] }

RPC Client

Depending on the usage, there are two traits that the RPC Client needs to implement. You can choose between the sync and async implementation. If you decide to use the async implementation, you need to use the library async-trait for now (until it is integrated into the rust toolchain).

Request

For simple requests (send one request and receive one answer) the trait Request is required:

/// Trait to be implemented by the ws-client for sending rpc requests and extrinsic.
pub trait Request {
	/// Sends a RPC request to the substrate node and returns the answer as string.
	(async) fn request<R: DeserializeOwned>(&self, method: &str, params: RpcParams) -> Result<R>;
}

By implementing this trait with a custom RPC client, most basic functionalities of the Api can already be used. Currently, there is no no_std example available. But the tungstenite_client provides a relatively simple std example. If a websocket library is available in your no_std environment, then your implementation may look similar.

Subscription

A little more complex is the second trait Subscribe, which does not only send a subscription request to the node, it also keeps listening and updating accordingly. Two traits need to be implemented for this feature. The Subscribe trait itself:

/// Trait to be implemented by the ws-client for subscribing to the substrate node.
pub trait Subscribe {
	type Subscription<Notification>: HandleSubscription<Notification>
	where
		Notification: DeserializeOwned;

	(async) fn subscribe<Notification: DeserializeOwned>(
		&self,
		sub: &str,
		params: RpcParams,
		unsub: &str,
	) -> Result<Self::Subscription<Notification>>;
}

and the HandleSubscription trait, which is returned by the subscribe function:

/// Trait to use the full functionality of jsonrpseee Subscription type
/// without actually enforcing it.
pub trait HandleSubscription<Notification: DeserializeOwned> {
	/// Returns the next notification from the stream.
	/// This may return `None` if the subscription has been terminated,
	/// which may happen if the channel becomes full or is dropped.
	(async) fn next(&mut self) -> Option<Result<Notification>>;

	/// Unsubscribe and consume the subscription.
	(async) fn unsubscribe(self) -> Result<()>;
}

Refering to the std example of the tungstenite, the HandleSubscription impl can be looked up here. It implements a simple channel receiver, waiting for the sender of the websocket client to send something. The Subscribe implementation can be found here.

A more complex RPC client, but also with more functionalities, is the jsonrpsee client.

Example Upgrades from older to newer versions

There have been some breaking API changes as of late to catch up with the newer Substrate versions and to fully support different Substrate nodes. An example project on how to upgrade from older tags can be found in the Integritee worker repository:

If you still experience issues during upgrading, do not hesitate to create an issue for support.

Alternatives

Parity offers a Rust client with similar functionality: https://github.com/paritytech/subxt

Acknowledgements

The development of the substrate-api-client has been financed by:

We also thank the teams at

Projects using substrate-api-client

If you intend to or are using substrate-api-client, please add your project here

In alphabetical order

FAQ

  1. Q: Everything compiles but the Substrate node does not accept my extrinsic or returns an error even if the extrinsic should be correct.

    A: First, ensure the api-client and the Substrate node have a matching version. E.g. if the node is running on release-polkadot-v1.2.0, checkout and compile a matching branch of the api-client. We are using the same naming scheme as Parity does. Please note: Not all Polkadot releases are published for all api-client releases. Which Polkadot releases are supported by which api-client release are noted in the release notes. Don't find the release-match you're looking for? Feel free to request it via an issue.

  2. Q: I get the error Bad input data provided to validate_transaction from the node when submitting an extrinsic. Even though I made sure the api-client and Polkadot releases are matching.

    A: Every extrinsic contains some node specific data. The tips for example may be provided by the Asset pallet or, by default, by the Balances pallet. The current api-client does not have access to this information. Therefore, these config data must be configured manually. Currently, there are two pre-defined Runtime Configs which should match most of the Substrate nodes:

    Ensure you're using a matching config. If you do not use default parameters as configured in one of the provided configs, you must provide your own config that implements the Config trait.

  3. Q: I want to query a state from a substrate node via the api-client, but I do not get the expected value, respective the decoding fails. How come?

    A: When specifying your own state query, you must provide the return type of the state you're trying to retrieve. This is because the api-client only gets bytes from the node and must be able to deserialize these properly. That is not possible without knowing the type to decode to. This type may be for example a simple u64 for retrieving the Balance of an account. But careful: If you're looking at the pallet code and its return type, don't forget to take the Query type into consideration. The OptionQuery for example automatically wraps the return type into an Option (see the substrate docs "Handling query return values" for more information). Alternatively, you can always double check via polkadot.js. If you're importing a value directly from the runtime, as it's done in this example, remember to adapt it to the node you are querying from.

substrate-api-client's People

Contributors

brenzi avatar burnww avatar clangenb avatar darkfriend77 avatar dependabot[bot] avatar echevrier avatar electronix avatar gaudenzkessler avatar haerdib avatar hoani avatar ivanceras avatar masapr avatar netrikare avatar niederb avatar overorion avatar pmikolajczyk41 avatar shanithkk avatar trevor-crypto avatar whalelephant avatar ziming-zung avatar zktony avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

substrate-api-client's Issues

send extrinsics without waiting for finalization

In order to send a high frequency of xt we need a non-blocking way to send extrinsics.

caveat: It's not enough to return after the "ready" msg. The problem is that the nonce needs to increase before the xt is included and the nonce is updated on-chain

test_no_std broken

Cargo build in the test_no_std directory fails with error message

error: failed to resolve patches for `https://github.com/paritytech/substrate`

Caused by:
  patch for `substrate-application-crypto` in `https://github.com/paritytech/substrate` did not resolve to any crates. If this is unexpected, you may wish to consult: https://github.com/rust-lang/cargo/issues/4678

setup CI Jenkins

Please set up CI for this crate

sanity checks:

cargo build --release
cargo build --release --no-default-features
cargo build --examples
cargo test

run examples against substrate-test-node (master?) (possible with jenkins?)

Run examples with panick

thread 'main' panicked at 'called Result::unwrap() on an Err value: Error("Error decoding field RuntimeMetadataPrefixed.1")', src/libcore/result.rs:1192:5

upgrade to v2.0.0-alpha.5

this is rather involved. We need to support generic hashers, as defined in metadata:

       {
        "name": "Account",
        "modifier": "Default",
        "ty": {
         "Map": {
          "hasher": "Blake2_128Concat",
          "key": "T::AccountId",
          "value": "AccountInfo<T::Index, T::AccountData>",
          "unused": false
         }
        },

And for double_map, the two hashers can be different

       {
        "name": "MeetupRegistry",
        "modifier": "Default",
        "ty": {
         "DoubleMap": {
          "hasher": "Blake2_256",
          "key1": "CurrencyCeremony",
          "key2": "MeetupIndexType",
          "value": "Vec<T::AccountId>",
          "key2_hasher": "Blake2_256"
         }
        },

key management

allow smooth DX (dev xperience ;-) for using keys:

  • using keyring::AccountKeyring with all default keys like //Alice
  • generating and persisting new keys on disk with simple password protection
  • get fancy with #9

should probably it's own crate

Unable to import sr25519 in the node metadata example

Hi, with the minimal setup that you have defined in the tutorial:

use substrate_api_client::{node_metadata, Api};

fn main() {
    // instantiate an Api that connects to the given address
    let url = "127.0.0.1:9944";
    // if no signer is set in the whole program, we need to give to Api a specific type instead of an associated type
    // as during compilation the type needs to be defined.
    let api = Api::<sr25519::Pair>::new(format!("ws://{}", url));

    let meta = api.get_metadata();
    println!(
        "Metadata:\n {}",
        node_metadata::pretty_format(&meta).unwrap()
    );
}

and

[package]
name = "api-client-tutorial"
version = "0.1.0"
authors = ["Supercomputing Systems AG <[email protected]>"]
edition = "2018"

[dependencies]
substrate-api-client = { git = "https://github.com/scs/substrate-api-client.git" }

I am getting many errors:

➜  api-client-tutorial git:(master) ✗ cargo run
   Compiling api-client-tutorial v0.1.0 (/Users/aviralsrivastava/dev/api-client-tutorial)
error[E0433]: failed to resolve: use of undeclared type or module `sr25519`
 --> src/main.rs:8:21
  |
8 |     let api = Api::<sr25519::Pair>::new(format!("ws://{}", url));
  |                     ^^^^^^^ use of undeclared type or module `sr25519`

error[E0425]: cannot find function `pretty_format` in module `node_metadata`
  --> src/main.rs:13:24
   |
13 |         node_metadata::pretty_format(&meta).unwrap()
   |                        ^^^^^^^^^^^^^ not found in `node_metadata`

error: aborting due to 2 previous errors

Some errors have detailed explanations: E0425, E0433.
For more information about an error, try `rustc --explain E0425`.
error: could not compile `api-client-tutorial`.

To learn more, run the command again with --verbose.

supply helpers and examples to support ink contracts

write helper functions for deploying and interacting with ink contracts. Write an example for the flipper contract as shown here with Polkadot.js API:

https://substrate.dev/docs/en/contracts/deploying-a-contract

write helpers for

  • put_code()
  • create()
  • call()

This will include parsing a contract's ABI and give some debugging advice with graceful error handling

Hints: Done that before:

get block api

'''rust
pub fn chain_get_block(hash:String) -> Value {
json!({
"method": "chain_getBlock",
"params": [hash],
"jsonrpc": "2.0",
"id":"1"
})
}
'''
Any support for rpc chain_getBlock?

Import `sp_runtime::generic::Era`

From the Substrate Technical channel:

Hello @here,
I am tring to run light clint code :-



use substrate_api_client::{Api, node_metadata::Metadata, XtStatus,compose_extrinsic,extrinsic::xt_primitives::UncheckedExtrinsicV4};
use sp_core::sr25519;
use keyring::AccountKeyring;
use sp_core::crypto::Pair;


fn main() {
    // instantiate an Api that connects to the given address
    let url = "127.0.0.1:9944";
    // if no signer is set in the whole program, we need to give to Api a specific type instead of an associated type
    // as during compilation the type needs to be defined.
    let from = AccountKeyring::Alice.pair();
    let mut api = Api::new(format!("ws://{}", url)).set_signer(from);
    let xt: UncheckedExtrinsicV4<_> = compose_extrinsic!( api.clone(),"System", "create_claim");
    println!("[+] Composed Extrinsic:\n {:?}\n", xt);
    let signer = AccountKeyring::Alice.pair();
    api.signer = Some(signer);
    let tx_hash = api.send_extrinsic(xt.hex_encode(), XtStatus::Finalized).unwrap();
    println!("[+] Transaction got finalized. Hash: {:?}", tx_hash);

}

But getting error :-

error[E0433]: failed to resolve: use of undeclared type or module `sp_runtime`
  --> src/main.rs:14:39
   |
14 |     let xt: UncheckedExtrinsicV4<_> = compose_extrinsic!( api.clone(),"System", "create_claim");
   |                                       ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ use of undeclared type or module `sp_runtime`
   |
   = note: this error originates in a macro (in Nightly builds, run with -Z macro-backtrace for more info)

error[E0433]: failed to resolve: use of undeclared type or module `Era`
  --> src/main.rs:14:39
   |
14 |     let xt: UncheckedExtrinsicV4<_> = compose_extrinsic!( api.clone(),"System", "create_claim");
   |                                       ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ use of undeclared type or module `Era`
   |
   = note: this error originates in a macro (in Nightly builds, run with -Z macro-backtrace for more info)


Cause by:

use sp_runtime::generic::Era;

Some better re-exporting will solve this

ompose_extrinsic_offline fails for payloads that don't implement the copy trait

if the call enum contains a value which doesn't implement copy trait, rustc complains:

error[E0382]: use of moved value: `witnesses`
   --> src/lib.rs:246:87
    |
241 |             let witnesses = witnesses.expect("witnesses are specified");
    |                 --------- move occurs because `witnesses` has type `std::vec::Vec<encointer_node_runtime::encointer_ceremonies::Witness<sr_primitives::AnySignature, substrate_primitives::sr25519::Public>>`, which does not implement the `Copy` trait
...
246 |                 Call::EncointerCeremonies(EncointerCeremoniesCall::register_witnesses(witnesses)),
    |                                                                                       ^^^^^^^^^ value moved here, in previous iteration of loop

The error message is misleading, because there is no loop: due to: rust-lang/rust/issues/46099

support storage keys for double_map

Currently, we don't directly support double_map storage queries

The following function should support double_map

pub fn storage_key_hash(module: &str, storage_key_name: &str, param: Option<Vec<u8>>) -> String {

Which is defined as

  blake256hash(bytes("ModuleName" + " " + "StorageItem") + bytes(scale("FirstStorageItemKey"))) + blake256hash(bytes(scale("SecondStorageItemKey")))

See: https://www.shawntabrizi.com/substrate/querying-substrate-storage-via-rpc/

Error decoding field RuntimeMetadataPrefixed.1

I ran the substrate-api-client with the latest master branch code of the substrate. It worked. However, later on, I made some changes in my substrate-node (diff shown below) and then the client throws RuntimeMetadaPrefixed error. Please note that my code compiles well and is successfully working.

Diff is:

index 5468ee0fb..39b321bd4 100644
--- a/bin/node/runtime/src/lib.rs
+++ b/bin/node/runtime/src/lib.rs
@@ -60,7 +60,7 @@ pub use pallet_balances::Call as BalancesCall;
 pub use pallet_contracts::Gas;
 pub use frame_support::StorageValue;
 pub use pallet_staking::StakerStatus;
-
+mod substratekitties;
 /// Implementations of some helper traits passed into runtime modules as associated types.
 pub mod impls;
 use impls::{CurrencyToVoteHandler, Author, LinearWeightToFee, TargetedFeeAdjustment};
@@ -622,6 +622,8 @@ impl pallet_vesting::Trait for Runtime {
        type MinVestedTransfer = MinVestedTransfer;
 }

+impl substratekitties::Trait for Runtime {}
+
 construct_runtime!(
        pub enum Runtime where
                Block = Block,
@@ -656,6 +658,8 @@ construct_runtime!(
                Society: pallet_society::{Module, Call, Storage, Event<T>, Config<T>},
                Recovery: pallet_recovery::{Module, Call, Storage, Event<T>},
                Vesting: pallet_vesting::{Module, Call, Storage, Event<T>, Config<T>},
+               Substratekitties: substratekitties::{Module, Call, Storage},
+
        }
 );

(END)

And another file that I have added at the same hierarchy level is:

use frame_support::{decl_module, decl_storage, dispatch::result::Result, ensure, StorageMap};
use frame_system::ensure_signed;
use sp_runtime::DispatchError;

// pub trait Trait: balances::Trait {}
pub trait Trait: pallet_balances::Trait {}

decl_storage! {
    trait Store for Module<T: Trait> as KittyStorage {
        // Value: map T::Hash => Option<T::AccountId>;
        // TODO: check whether this is the appropriate datatype(hash).
        Value: map hasher(opaque_blake2_256) T::Hash => Option<T::AccountId>;
        // Balances: map hasher(blake2_256) (T::AssetId, T::AccountId) => T::Balance;
    }
}

decl_module! {
    pub struct Module<T: Trait> for enum Call where origin: T::Origin {
        fn set_value(origin, value: T::Hash) -> Result<(), DispatchError> {
            let sender = ensure_signed(origin)?;
            ensure!(!<Value<T>>::contains_key(value), "key already exists");
            <Value<T>>::insert(value, sender);
            Ok(())
        }
    }
}

The branch that I am using is:

➜  substrate git:(master) ✗ git remote -v
origin	https://github.com/paritytech/substrate (fetch)
origin	https://github.com/paritytech/substrate (push)

with only the aforementioned changes.

wss connection fails after connect

[2020-10-18T17:13:31Z INFO  encointer_client_notee] connecting to wss://gesell.encointer.org:443
[2020-10-18T17:13:31Z INFO  ws] Queuing connection to wss://gesell.encointer.org/
[2020-10-18T17:13:31Z DEBUG ws::handshake] Built request from URL:
    GET / HTTP/1.1
    Connection: Upgrade
    Host: gesell.encointer.org:443
    Sec-WebSocket-Version: 13
    Sec-WebSocket-Key: SJW3hRCu0XmwzjyUiX9fFw==
    Upgrade: websocket
    
    
thread 'client' panicked at 'Panicking on internal error -- Internal Application Error: Failed to parse response after handshake is complete.', /home/abrenzikofer/.cargo/registry/src/github.com-1ecc6299db9ec823/ws-0.7.9/src/connection.rs:410:29
note: run with `RUST_BACKTRACE=1` environment variable to display a backtrace
thread 'main' panicked at 'called `Result::unwrap()` on an `Err` value: RecvError', /home/abrenzikofer/.cargo/git/checkouts/substrate-api-client-9327f54164a9792a/62afbac/src/lib.rs:182:37

can be fixed with updating ws crate to 0.9.1

compose_extrinsic_offline! (without networking requirement)

SubstraTEE-worker needs to compose extrinsics within an enclave without holding an api object / without the possibility to query nonce and genesis hash or metadata

solution needed for:

currently, nonce and genesis hash do not need to be supplied to compose_extrinsic. Instead, the macro queries these directly from the node.

We need another compose_extrinsic_offline function that takes nonce and genesis hash as arguments.

This might get more complicated as metadata is also unknown to the substraTEE-enclave today.
We might want to hard-code the call as well, so we don't need compose_call!.

This way we could use our new function similar to this:

    let xt = compose_extrinsic_offline!(
        AccountKey::new("//Alice", Some(""), CryptoKind::Ed25519),
        Call::SubstraTEERegistry(SubstraTEERegistryCall::register_enclave(...)),
        nonce,
        genesis_hash
    );

compose_extrinsic needs additional dependencies

I'm trying to use this lib within my own crate (example with generic extrinsic). The following occurs:


error[E0432]: unresolved import `codec`
  --> src/lib.rs:38:14
   |
38 |       let xt = compose_extrinsic!(
   |  ______________^
39 | |         api.clone(),
40 | |         "Balances",
41 | |         "transfer",
42 | |         GenericAddress::from(to),
43 | |         Compact(42 as u128)
44 | |     );
   | |_____^ use of undeclared type or module `codec`
   |
   = note: this error originates in a macro outside of the current crate (in Nightly builds, run with -Z external-macro-backtrace for more info)

...
error[E0433]: failed to resolve: use of undeclared type or module `primitives`
...
error[E0432]: unresolved import `log`

all of which probably caused by these imports:

use codec::{Compact, Encode};

Missing field transactionVersion

Following these docs: https://github.com/scs/substrate-api-client/tree/master/tutorials

Getting following error:

Running `target/debug/substrate-api-client-test`
thread 'main' panicked at 'called `Result::unwrap()` on an `Err` value: Error("missing field `transactionVersion`", line: 1, column: 317)', /home/dylan/.cargo/git/checkouts/substrate-api-client-9327f54164a9792a/999d407/src/lib.rs:163:9
note: run with `RUST_BACKTRACE=1` environment variable to display a backtrace

How to read a Storage Map?

The APIs for plain storage values and for storage double maps are given but not for storage maps.
I tried the following but the hash generated for my value is different from what it should be.
What I tried:

fn file_storage_key_hash_vec(module: &str, storage_key_name: &str, param: &str) -> Vec<u8> {
    let mut key = twox_128(module.as_bytes()).to_vec();
    // println!("Keyhash after module hex encoding is: {:?}", key);

    key.extend(&twox_128(storage_key_name.as_bytes()));
    // println!("Key after storage encoding is: {:?}", key);

    key.extend(&blake2_256(param.as_bytes()));

    let module_encoding = hex::encode(&twox_128(module.as_bytes()));
    let storage_key_name_encoding = hex::encode(&twox_128(storage_key_name.as_bytes()));
    let file_hash_encoding = hex::encode(&blake2_256(param.as_bytes()));
    println!("------------------------------------------");
    println!("Module encoding: {:?}", module_encoding);
    println!("Storage Key Name encoding: {:?}", storage_key_name_encoding);
    println!("File Hash encoding: {:?}", file_hash_encoding);
    println!("------------------------------------------");
    

    println!(
        "IMPORTANT: key after file hash encoding of blake2_256 is: {:?}",
        key
    );
    key
}

For hash value: 0x0000000000000000000000000000000000000000000000000000000000000001, the file_hash_encoding generated is 47016246ca22488cf19f5e2e274124494d272c69150c3db5f091c9306b6223fc.

The value that should be generated is:

0x33e423980c9b37d048bd5fadbd4a2aeb95146922045405accc2f468d0ef96988

The correct value generated is achieved by using the function util_crypto.blake2AsHex("0x0000000000000000000000000000000000000000000000000000000000000001") as taken from here

So, how can I read the value given the aforementioned key?

get_block can fail because it misinterprets json msg

The following happens sometimes with substraTEE-worker:

[2020-05-13T19:59:48Z INFO  substrate_api_client::rpc::client] sending request: {"id":"1","jsonrpc":"2.0
","method":"chain_getBlock","params":["0x000000000000000000000000000000000000000000000000000000000000000
0"]}                                                                                                    
[2020-05-13T19:59:48Z DEBUG ws::handler] Handler received:                                              
    <FRAME>                                                                                             
    final: true                                                                                         
    reserved: false false false                                                                         
    opcode: TEXT                                                                                        
    length: 42                                                                                          
    payload length: 40                                                                                  
    payload: 0x7b226a736f6e727063223a22322e30222c22726573756c74223a6e756c6c2c226964223a2231227d         
                                                                                                        
[2020-05-13T19:59:48Z INFO  substrate_api_client::rpc::client] Got get_request_msg {"jsonrpc":"2.0","res
ult":null,"id":"1"}                                                                                     
thread 'main' panicked at 'called `Result::unwrap()` on an `Err` value: Error("invalid type: null, expec
ted struct SignedBlock", line: 1, column: 4)', /home/abrenzikofer/.cargo/git/checkouts/substrate-api-cli
ent-9327f54164a9792a/7798b4a/src/lib.rs:268:18                                                          
note: run with `RUST_BACKTRACE=1` environment variable to display a backtrace                           
[2020-05-13T19:59:48Z DEBUG ws::handler] Handler received:                                              
    <FRAME>                                                                                             
    final: true                                                                                         
    reserved: false false false                                                                         
    opcode: CLOSE                                                                                       
    length: 4                                                                                           
    payload length: 2                                                                                   
    payload: 0x3e8                                                                                      
                                                                                                        
[2020-05-13T19:59:48Z DEBUG ws::handler] Connection closing due to (Normal)                             
[2020-05-13T19:59:48Z DEBUG ws::io] WebSocket connection to 127.0.0.1:9979 disconnected.                
[2020-05-13T19:59:48Z DEBUG ws::io] Shutting down websocket client.                                     
[2020-05-13T19:59:48Z DEBUG ws::factory] Factory received WebSocket shutdown request.                   

The msg is most probably an interfering subscription and not the response to getBock

Getting hex`s OddLength error constructing extrinsic

Reproduce is kind of hard because of our architecture but I can privide compose_extrinsic macro input to check.

#[cfg(test)]
mod tests {
    use super::*;

    #[test]
    fn check_compose_extrinsics() {
        let node_url = "wss://node1-chain.akropolis.io";
        let api = Api::new(node_url.into()).set_signer(get_sr25519_pair(ANY_VALID_MNEMONIC));
        let from = H160::default(); // any eth address would suffice
        let to = AccountId32::default();
        let id = H256::default();
        let ext = compose_extrinsic!(
            api,
            "Bridge",
            "multi_signed_mint",
            id,
            from,
            GenericAddress::from(to),
            Compact(0u32),
            Compact(10000000000000000000u128)
        );
        let hash = api.send_extrinsic(ext.hex_encode(), XtStatus::Finalized);
        //                      ^^^^^^^^^^^^^^^^^---- fails here
    }
}

pub fn get_sr25519_pair(signer_mnemonic_phrase: &str) -> sr25519::Pair {
    sr25519::Pair::from_phrase(signer_mnemonic_phrase, None)
        .expect("invalid mnemonic phrase")
        .0
}

upd: I reproduced this as a test so it should be fairly easy

print_metadata() function

read metadata from node
print metadata in indented tree-style to stdout
Document usage with example

create a library

the code must be compiled into a library (crate) that can be used by substraTEE-client and substraTEE-worker

make extrinsics an independent crate

I wanted to access the types we define in the extrinsics module on their own without accessing functionality of th e api-client itself multiple times already.

I suggest we make it a crate on its own to be able to import it independently.

examples fail: example_transfer / _get_storage / _contract

Interacting with node on 127.0.0.1:9944

[+] Bob's Free Balance is is 1152921504606846976

thread 'main' panicked at 'called `Result::unwrap()` on an `Err` value: InvalidHexCharacter { c: 'n', index: 0 }', src/libcore/result.rs:1084:5
note: run with `RUST_BACKTRACE=1` environment variable to display a backtrace.

debug

[2019-09-16T20:18:11Z INFO  substrate_api_client::rpc::client] sending request: {"id":"1","jsonrpc":"2.0","method":"state_getStorage","params":["0x5c54163a1c72509b5250f0a30b9001fdee9d9b48388b06921f1b210e81e3a1f0"]}
[2019-09-16T20:18:11Z DEBUG ws::handler] Handler received: 
<FRAME>
final: true
reserved: false false false
opcode: TEXT
length: 42
payload length: 40
payload: 0x7b226a736f6e727063223a22322e30222c22726573756c74223a6e756c6c2c226964223a2231227d
            
[2019-09-16T20:18:11Z INFO  substrate_api_client::rpc::client] got message
[2019-09-16T20:18:11Z DEBUG substrate_api_client::rpc::client] {"jsonrpc":"2.0","result":null,"id":"1"}
thread 'main' panicked at 'called `Result::unwrap()` on an `Err` value: InvalidHexCharacter { c: 'n', index: 0 }', src/libcore/result.rs:1084:5
note: run with `RUST_BACKTRACE=1` environment variable to display a backtrace.
[2019-09-16T20:18:11Z DEBUG ws::handler] Handler received: 
<FRAME>
final: true
reserved: false false false
opcode: CLOSE
length: 4
payload length: 2
payload: 0x3e8

reproduce:
run against master : https://github.com/scs/substrate-test-nodes

./target/release/substrate-test-node purge-chain --dev
./target/release/substrate-test-node --dev

then

cargo run --example example_transfer 

is error handling missing in case of returning a null value?

await InBlock or Broadcast status when sending extrinsic

(for v2.0.0-alpha.5 and later)
The lifetime of an extrinsic goes like this:

send {"id":"3","jsonrpc":"2.0","method":"author_submitAndWatchExtrinsic","params":["0x2d0284d43593c715fdd31c61141abd04a99fd6822c8558854ccde39a5684e7a56da27d017693d988ff9b4d3577c0b9d2b9424e647fbec5875fef096644e311cb7499fd2a7cb99850c7e2806ffafecb3c63de17caa382340752077d6ca63e8995564f7d820068000400ce8f99245b836fa93f021c02c14a80d5029e2d43fb6265a0c610e5ac8d043e1b02286bee"]}
get {"jsonrpc":"2.0","result":232,"id":"3"}
get {"jsonrpc":"2.0","method":"author_extrinsicUpdate","params":{"result":"ready","subscription":232}}
get {"jsonrpc":"2.0","method":"author_extrinsicUpdate","params":{"result":{"broadcast":["QmfSF4VYWNqNf5KYHpDEdY8Rt1nPUgSkMweDkYzhSWirGY","Qmchhx9SRFeNvqjUK4ZVQ9jH4zhARFkutf9KhbbAmZWBLx","QmQJAqr98EF1X3YfjVKNwQUG9RryqX4Hv33RqGChbz3Ncg"]},"subscription":232}}
get {"jsonrpc":"2.0","method":"author_extrinsicUpdate","params":{"result":{"inBlock":"0x3104d362365ff5ddb61845e1de441b56c6722e94c1aee362f8aa8ba75bd7a3aa"},"subscription":232}}
get {"jsonrpc":"2.0","method":"author_extrinsicUpdate","params":{"result":{"finalized":"0x3104d362365ff5ddb61845e1de441b56c6722e94c1aee362f8aa8ba75bd7a3aa"},"subscription":232}}

currently, we only offer to submit and await ready or finalized.
It would make sense to support inBlock too and maybe broadcast

generic compose_extrinsic() function

The current version of this library can't compose extrinsics for custom runtimes because there's a dependency clash between custom node_runtime and substrate master node_runtime.

This should be solvable along these lines:

  • not depending on substrate's node_runtime crate with api-client
  • using type arguments, so a depending crate can supply the custom node_runtime dependencies

in addition to generic extrinsics, we should provide very common extrinsic types with easy function calls, probably wrapping the dispatch of the call as well:

write an example for how to compose an extrinsic for a custom runtime module using Gav's Demo:
https://substrate.dev/docs/en/tutorials/creating-your-first-substrate-chain#step-6-interacting-with-our-new-module

Remove or rework hanging examples

The examples

  • contract and
  • event_callback
    dont' terminate and cannot be automatically testet.

Proposal:

  • Introduce an option in example_event_callback to only listen to a certain number of events and then terminate
  • Fix or remove the example_contract

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.