2

I have been trying to implement a transaction queue which will store extrinsic call data and later execute it.

Transaction Queue

This is how the queue looks like, which enqueue and dequeue call-data bytes (pallet u8, call u8, call params u8). TransactionQueue: Vec<u8>

I tried to find an easy way to construct extrinsic from call bytes but failed. So I started to implement how subxt constructs extrinsic here

// dequeue transaction call data.
let maybe_call_data = store.dequeue_item(
    SledQueueKey::from_substrate_chain_id(chain_id),
)?;
if let Some(call_data) = maybe_call_data {
    
    let call_data = subxt::Encoded(call_data);
    
    
    // This is the steps to create encoded extrinsic which can be executed by rpc client
    let account_nonce = if let Some(nonce) = signer.nonce() {
        nonce
    } else {
        client
            .rpc()
            .system_account_next_index(signer.account_id())
            .map_err(anyhow::Error::from)
            .await?
    };
    // 1.Construct our custom additional/extra params.
    let additional_and_extra_params = {
        // Obtain spec version and transaction version from the runtime version of the client.
        let runtime = client
            .rpc()
            .runtime_version(None)
            .map_err(anyhow::Error::from)
            .await?;
        subxt::PolkadotExtrinsicParams::<subxt::DefaultConfig>::new(
            runtime.spec_version,
            runtime.transaction_version,
            account_nonce,
            *client.genesis(),
            Default::default(),
        )
    };
    // 2. Construct signature. This is compatible with the Encode impl
    //    for SignedPayload (which is this payload of bytes that we'd like)
    //    to sign. See:
    //    https://github.com/paritytech/substrate/blob/9a6d706d8db00abb6ba183839ec98ecd9924b1f8/primitives/runtime/src/generic/unchecked_extrinsic.rs#L215)
    let signature = {
        let mut bytes = Vec::new();
        call_data.encode_to(&mut bytes);
        additional_and_extra_params.encode_extra_to(&mut bytes);
        additional_and_extra_params
            .encode_additional_to(&mut bytes);
        if bytes.len() > 256 {
            signer.sign(&blake2_256(&bytes))
        } else {
            signer.sign(&bytes)
        }
    };
    // 3. Encode extrinsic, now that we have the parts we need. This is compatible
    //    with the Encode impl for UncheckedExtrinsic (protocol version 4).
    let extrinsic = {
        let mut encoded_inner = Vec::new();
        // "is signed" + transaction protocol version (4)
        (0b10000000 + 4u8).encode_to(&mut encoded_inner);
        // from address for signature
        signer.address().encode_to(&mut encoded_inner);
        // the signature bytes
        signature.encode_to(&mut encoded_inner);
        // attach custom extra params
        additional_and_extra_params
            .encode_extra_to(&mut encoded_inner);
        // and now, call data
        call_data.encode_to(&mut encoded_inner);
        // now, prefix byte length:
        let len = Compact(
            u32::try_from(encoded_inner.len())
                .expect("extrinsic size expected to be <4GB"),
        );
        let mut encoded = Vec::new();
        len.encode_to(&mut encoded);
        encoded.extend(encoded_inner);
        encoded
    };
    
    // encoded extinsic
    let encoded_extrinsic = subxt::Encoded(extrinsic);

    // watch_extrinsic submits and returns transaction subscription
    let result = client
        .rpc()
        .watch_extrinsic(&encoded_extrinsic)
        .map_err(anyhow::Error::from)
        .await;
    let mut progress = match result {
        Ok(d) => d,
        Err(e) => {
            tracing::debug!("extrinsic error : {:?}", e);
            continue;
        }
    };

Error.

I tried to construct extrinsic as per the above code but it fails with code:1002, message: Verification Error: Runtime error.

full error log

{
  "timestamp": "2022-07-27T12:52:10.189639Z",
  "level": "DEBUG",
  "message": "extrinsic error : Rpc error: JSON-RPC call failed: RPC Call failed: code: 1002, message: Verification Error: Runtime error: Execution failed: Execution aborted due to trap: wasm trap: wasm `unreachable` instruction executed\nWASM backtrace:\n\n    0: 0x39248 - <unknown>!rust_begin_unwind\n, data: Some(RawValue(\"RuntimeApi(\\\"Execution failed: Execution aborted due to trap: wasm trap: wasm `unreachable` instruction executed\\\\nWASM backtrace:\\\\n\\\\n    0: 0x39248 - <unknown>!rust_begin_unwind\\\\n\\\")\"))\n\nCaused by:\n    0: JSON-RPC call failed: RPC Call failed: code: 1002, message: Verification Error: Runtime error: Execution failed: Execution aborted due to trap: wasm trap: wasm `unreachable` instruction executed\n       WASM backtrace:\n       \n           0: 0x39248 - <unknown>!rust_begin_unwind\n       , data: Some(RawValue(\"RuntimeApi(\\\"Execution failed: Execution aborted due to trap: wasm trap: wasm `unreachable` instruction executed\\\\nWASM backtrace:\\\\n\\\\n    0: 0x39248 - <unknown>!rust_begin_unwind\\\\n\\\")\"))\n    1: RPC Call failed: code: 1002, message: Verification Error: Runtime error: Execution failed: Execution aborted due to trap: wasm trap: wasm `unreachable` instruction executed\n       WASM backtrace:\n       \n           0: 0x39248 - <unknown>!rust_begin_unwind\n       , data: Some(RawValue(\"RuntimeApi(\\\"Execution failed: Execution aborted due to trap: wasm trap: wasm `unreachable` instruction executed\\\\nWASM backtrace:\\\\n\\\\n    0: 0x39248 - <unknown>!rust_begin_unwind\\\\n\\\")\"))",
  "target": "webb_relayer::tx_queue::substrate_tx_queue",
  "spans": [
    {
      "node": "1080",
      "name": "run"
    }
  ]
}

It would be great if anyone can help me understand what the error msg means and if there is a better way to solve this problem.

Any help or suggestion is most appreciated. Thank you

1 Answer 1

2

I was using the wrong ExtrinsicParams. It should be subxt::SubstrateExtrinsicParams instead of subxt::PolkadotExtrinsicParams.

This solves my problem but I will be also interested if there is any other easy way to solve this problem.

2
  • 2
    Just to point out, a big subxt refactor will land soon hopefully (github.com/paritytech/subxt/pull/593). This will separate the building of tx's from submitting them, so it should make it possible to lean on subxt to build, store and later submit things as you wish!
    – jsdw
    Jul 29, 2022 at 10:36
  • that will be awesome.
    – salman01z
    Jul 29, 2022 at 17:23

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge that you have read and understand our privacy policy and code of conduct.

Not the answer you're looking for? Browse other questions tagged or ask your own question.