【问题标题】:How to write in the storage of Substrate using Substrate API Client?如何使用 Substrate API Client 写入 Substrate 的存储?
【发布时间】:2020-07-15 06:00:10
【问题描述】:

我的目标是使用substrate-api-client 在 Substrate 的存储映射中写入一个值。我在 Substrate 链中定义的存储映射如下所示:

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(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(())
        }
    }
}

以上存储图位于:

substrate/bin/node/runtime/src/substratekitties.rs

预期的结果是成功地在 Substrate 的存储上写入一个值。正如我在前端所做的那样,成功:

但是,在使用 substrate-api-client 执行相同任务时,我收到以下错误:

[2020-04-03T05:14:12Z ERROR substrate_api_client::rpc::client] ERROR: Object({"code": Number(1010), "data": String("BadProof"), "message": String("Invalid Transaction")})

我尝试在substrate-api-client 中编写自定义外部示例。这就是我编写外在的方式:

let xt = compose_extrinsic!(
        api.clone(),
        "Substratekitties",
        "set_value",
        "0x0000000000000000000000000000000000000000000000000000000000000002"
    );

这是重现错误所需的最少代码:

/*
    Copyright 2019 Supercomputing Systems AG
    Licensed under the Apache License, Version 2.0 (the "License");
    you may not use this file except in compliance with the License.
    You may obtain a copy of the License at

        http://www.apache.org/licenses/LICENSE-2.0

    Unless required by applicable law or agreed to in writing, software
    distributed under the License is distributed on an "AS IS" BASIS,
    WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
    See the License for the specific language governing permissions and
    limitations under the License.
*/

//! This examples shows how to use the compose_extrinsic macro to create an extrinsic for any (custom)
//! module, whereas the desired module and call are supplied as a string.

use clap::{load_yaml, App};
use keyring::AccountKeyring;
use sp_core::crypto::Pair;
// use substrate_api_client::extrinsic::xt_primitives::UncheckedExtrinsicV4;
use substrate_api_client::{
    compose_extrinsic, extrinsic::xt_primitives::UncheckedExtrinsicV4, Api,
};

// use crate::{compose_extrinsic, Api};

fn main() {
    env_logger::init();
    let url = get_node_url_from_cli();
    // initialize api and set the signer (sender) that is used to sign the extrinsics
    let from = AccountKeyring::Alice.pair();
    let mut api = Api::new(format!("ws://{}", url)).set_signer(from);
    // let signer = AccountKeyring::Alice.pair();
    // api.signer = Some(signer);
    // the names are given as strings
    let xt = compose_extrinsic!(
        api.clone(),
        "Substratekitties",
        "set_value",
        "0x0000000000000000000000000000000000000000000000000000000000000002"
    );
    println!("[+] Composed Extrinsic:\n {:?}\n", xt);
    // send and watch extrinsic until finalized
    let signer = AccountKeyring::Alice.pair();
    api.signer = Some(signer);
    let tx_hash = api.send_extrinsic(xt.hex_encode()).unwrap();
    println!("[+] Transaction got finalized. Hash: {:?}", tx_hash);
}

pub fn get_node_url_from_cli() -> String {
    let yml = load_yaml!("../../src/examples/cli.yml");
    let matches = App::from_yaml(yml).get_matches();

    let node_ip = matches.value_of("node-server").unwrap_or("127.0.0.1");
    let node_port = matches.value_of("node-port").unwrap_or("9944");
    let url = format!("{}:{}", node_ip, node_port);
    println!("Interacting with node on {}\n", url);
    url
}

以上代码位于文件:example_writing_file_hash.rs,树为:

substrate-api-client/src/examples/example_writing_file_hash.rs

而完整的代码库可用here

更新 1

根据user13207835answer,我尝试将我的内容声明为哈希但失败了。 PS 我是 Rust、Substrate 的初学者。

let file_hash: Hash = "0x0000000000000000000000000000000000000000000000000000000000000002";

得到错误:

error[E0308]: mismatched types; expected struct `primitive_types::H256`, found `&str`

我理解这个错误,但我不知道如何按照答案中的建议将上述值声明为Hash

【问题讨论】:

    标签: rust substrate polkadot


    【解决方案1】:

    您将函数声明为fn set_value(origin, value: T::Hash)。因此,您必须将Hash 传递给compose_extrinsic! 宏,因为它只是在传递参数时对其进行编码。它不知道"0x...2" 是一个哈希。因此,它会将其编码为字符串。

    因此,您应该传递一个东西,其原始数据的编码与您节点中的Hash 表示相同。有两种选择:

    • 只需使用 [u8, 32] 数组即可。
    • 使用来自基板的原语板条箱之一的哈希

    【讨论】:

    • 嗨!谢谢你的回答!你能指出我的代码应该改变什么吗?如果是原始散列,那么哪个散列? H256还是别的什么? let my_hash = 0x0000000000000000000000000000000000000000000000000000000000000002 应该改成?
    • 我使用了hexstr_to_hash,如here所示。谢谢!
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2020-05-03
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多