paritytech / subxt

Interact with Substrate based nodes in Rust or WebAssembly
Other
412 stars 245 forks source link

How to decode extrinsic for raw Vec<u8> #125

Closed yxf closed 4 years ago

yxf commented 4 years ago

I want extract extrinsic from rpc result, but got invalid transaction version error, please help.

use substrate_subxt::{
    ClientBuilder,
    KusamaRuntime,
    runtimes::*,
    frame::system::*,
    frame::balances::*,
    extra::DefaultExtra
};
use sp_runtime::{
    generic::{
        UncheckedExtrinsic
    },
    MultiSignature,
    AnySignature
};
use codec::{Decode, Encode, EncodeLike, Input, Error};
use sp_core::crypto::Pair;

type Address = <KusamaRuntime as System>::Address;
type Call = Vec<u8>;
type Signature = AnySignature;
type Extra = DefaultExtra<KusamaRuntime>;

type UnEx = UncheckedExtrinsic<Address, Call, Signature, Extra>;

#[async_std::main]
async fn main() -> Result<(), Box<dyn std::error::Error>> {
    env_logger::init();

    let client = ClientBuilder::<KusamaRuntime>::new()
        .set_url("wss://kusama-rpc.polkadot.io")
        .build()
        .await?;

    let block_number = 2852995;

    let block_hash = client.block_hash(Some(block_number.into())).await?;

    if let Some(hash) = block_hash {
        println!("Block hash for block number {}: {:?}", block_number, hash);

        let block = client.block(Some(hash)).await?.unwrap();

        println!("block = {:?}", block);

        let extrinsic: sp_runtime::OpaqueExtrinsic = block.block.clone().extrinsics[2].clone();

        let mut input = extrinsic.0.as_slice();
        println!("input  = {:?}", &input);
        // UncheckedExtrinsic<Address, Call, Signature, Extra>
        let uncheck_extrinsic = UnEx::decode(&mut input);

        println!("block extrinsics = {:?}", uncheck_extrinsic);  // Got  `Invalid transaction version` error

    } else {
        println!("Block number {} not found.", block_number);
    }

    Ok(())
}

Outputs:

Block hash for block number 2852995: 0xdbe3277db35554024f68d947b0f2a08bb2a2bb14b5723a60e44c930648dcbca2
block = SignedBlock { block: Block { header: Header { parent_hash: 0x9685770bfbc3b213b63e59dec3d518b6dab61849cb944b066644b56d94eda6c1, number: 2852995, state_root: 0x458ef43522540efc0b4a7be7f2aef470d229bdf4bad31f0bc38e6c67668f5a46, extrinsics_root: 0xc1d6f1f1216393b81bc155cf9f8163c11b51e3225df5a68febd6d1e9096f409b, digest: Digest { logs: [DigestItem::PreRuntime([66, 65, 66, 69], [2, 121, 0, 0, 0, 244, 178, 210, 15, 0, 0, 0, 0]), DigestItem::Seal([66, 65, 66, 69], [90, 217, 174, 195, 252, 86, 236, 170, 4, 204, 232, 209, 46, 172, 53, 117, 143, 194, 177, 184, 203, 42, 251, 157, 120, 136, 50, 141, 133, 137, 240, 90, 3, 229, 135, 210, 32, 181, 154, 216, 14, 61, 108, 141, 218, 110, 63, 172, 113, 128, 209, 228, 180, 66, 218, 161, 136, 38, 94, 73, 62, 160, 102, 137])] } }, extrinsics: [0402000bc03642da7201, 04140000, 84fe56be5933800b45a21ee8e9817eae9f49099fdf4a20076718497092ed43c62b019a7261d479c4b495cfd1fcffcf9daf35600c391e752e99c805e7951388fb17663a8ab4f9c2241835599c1df443630f0c218b3bdc3e83f5e0390cfced7e580b8ef50374000400a8070648f6e43b7d8a8f10418b696130d2046c10645f10085de80e6098b85f0902286bee] }, justification: None }
input  = [132, 254, 86, 190, 89, 51, 128, 11, 69, 162, 30, 232, 233, 129, 126, 174, 159, 73, 9, 159, 223, 74, 32, 7, 103, 24, 73, 112, 146, 237, 67, 198, 43, 1, 154, 114, 97, 212, 121, 196, 180, 149, 207, 209, 252, 255, 207, 157, 175, 53, 96, 12, 57, 30, 117, 46, 153, 200, 5, 231, 149, 19, 136, 251, 23, 102, 58, 138, 180, 249, 194, 36, 24, 53, 89, 156, 29, 244, 67, 99, 15, 12, 33, 139, 59, 220, 62, 131, 245, 224, 57, 12, 252, 237, 126, 88, 11, 142, 245, 3, 116, 0, 4, 0, 168, 7, 6, 72, 246, 228, 59, 125, 138, 143, 16, 65, 139, 105, 97, 48, 210, 4, 108, 16, 100, 95, 16, 8, 93, 232, 14, 96, 152, 184, 95, 9, 2, 40, 107, 238]
block extrinsics = Err(Error("Invalid transaction version"))
dvc94ch commented 4 years ago

That happens when the client version doesn't match the node version. Update your node to rc3 and the error should disappear

yxf commented 4 years ago

@dvc94ch Thanks for your reply. I use kusama runtime, but still error.

[dev-dependencies]
async-std = { version = "1.5.0", features = ["attributes"] }
env_logger = "0.7"
wabt = "0.9"
frame-system = { version = "2.0.0-rc2", package = "frame-system" }
pallet-balances = { version = "2.0.0-rc2", package = "pallet-balances" }
sp-keyring = { version = "2.0.0-rc2", package = "sp-keyring" }
kusama-runtime = {path = "../polkadot/runtime/kusama" }
        let uncheck_extrinsic = kusama_runtime::UncheckedExtrinsic::decode(&mut input);

The block data at height 2852995 is:

SignedBlock { 
    block: Block { 
        header: Header { 
            parent_hash: 0x9685770bfbc3b213b63e59dec3d518b6dab61849cb944b066644b56d94eda6c1, 
            number: 2852995, 
            state_root: 0x458ef43522540efc0b4a7be7f2aef470d229bdf4bad31f0bc38e6c67668f5a46, 
            extrinsics_root: 0xc1d6f1f1216393b81bc155cf9f8163c11b51e3225df5a68febd6d1e9096f409b, 
            digest: Digest { logs: [DigestItem::PreRuntime([66, 65, 66, 69], [2, 121, 0, 0, 0, 244, 178, 210, 15, 0, 0, 0, 0]), DigestItem::Seal([66, 65, 66, 69], [90, 217, 174, 195, 252, 86, 236, 170, 4, 204, 232, 209, 46, 172, 53, 117, 143, 194, 177, 184, 203, 42, 251, 157, 120, 136, 50, 141, 133, 137, 240, 90, 3, 229, 135, 210, 32, 181, 154, 216, 14, 61, 108, 141, 218, 110, 63, 172, 113, 128, 209, 228, 180, 66, 218, 161, 136, 38, 94, 73, 62, 160, 102, 137])] } 
        }, 
        extrinsics: [
                0402000bc03642da7201, 
                04140000, 
84fe56be5933800b45a21ee8e9817eae9f49099fdf4a20076718497092ed43c62b019a7261d479c4b495cfd1fcffcf9daf35600c391e752e99c805e7951388fb17663a8ab4f9c2241835599c1df443630f0c218b3bdc3e83f5e0390cfced7e580b8ef50374000400a8070648f6e43b7d8a8f10418b696130d2046c10645f10085de80e6098b85f0902286bee
            ] 
        }, 
        justification: None 
}

Got error: Err(Error("Invalid transaction version"))

yxf commented 4 years ago

I found the extrinsic is missing prefix length encode bytes,so UncheckedExtrinsic can not decode the raw bytes array. Why the rpc returns extrinsic is different with the generated extrinsic?