2

I know that the payload and extrinsics are dynamic, and even different between parachains/base chains(kusama,polkadot,rococo,westend). But I am struggling to find good documentation on how these payloads/extrinsics are constrcuted from the metadata. I am trying to get a C# code working with the RPC, basing it on the Ajuna.NetApi, but I have so far only managed to write a simple method call.

Now I am trying to write a transaction call, and I am getting "Invalid signature" error. I am very convinced that I have something wrong/missing from my payload generation code. This is the code for the payload construction:

    public byte[] Encode()
    {
        var bytes = new List<byte>();

        SignedExtensionMetadataStruct[] extensions = Globals.LatestMetadata.RuntimeMetadataData.Extrinsic.SignedExtensions.Value;

        if (extensions.Any(e => e.SignedIdentifier.Value == "CheckMortality"))
            bytes.AddRange(_mortality.Encode()); 

        if (extensions.Any(e => e.SignedIdentifier.Value == "CheckNonce"))
            bytes.AddRange(_nonce.Encode());

        if (extensions.Any(e => e.SignedIdentifier.Value == "ChargeTransactionPayment"))
            bytes.AddRange(_assetTxPayment.Encode());

        if (extensions.Any(e => e.SignedIdentifier.Value == "CheckSpecVersion"))
            bytes.AddRange(Utils.Value2Bytes(_specVersion));

        if (extensions.Any(e => e.SignedIdentifier.Value == "CheckTxVersion"))
            bytes.AddRange(Utils.Value2Bytes(_txVersion));

        if (extensions.Any(e => e.SignedIdentifier.Value == "CheckGenesis"))
            bytes.AddRange(_genesis.Encode());

        if (extensions.Any(e => e.SignedIdentifier.Value == "CheckGenesis"))
            bytes.AddRange(_genesis.Bytes);

        // CheckMortality, Additional Blockhash check. Immortal = genesis_hash, Mortal = logic
        if (extensions.Any(e => e.SignedIdentifier.Value == "CheckMortality"))
            bytes.AddRange(_startEra.Bytes);


        return bytes.ToArray();
    }

Is there a good example/documentation on the payload/extrinsic construction other than the text on the wiki page (which is good but barely scratched the issue of reading the metadata and constructing the payload from it) ?

Im also a bit confused as in what order these parameters should be included in the payload.

2 Answers 2

3

If I look at the above, if it is meant to be a full payload there is certainly seems to be information missing, most notable the actual call.

So first the basics - some of the signed extension information appear in the extrinsic itself (something like "nonce" applies here) and some only appear (additionally) in the data being signed (something like "genesisHash" applies here).

Assuming "normal" signed extensions, the data being signed should end up looking more-or-less like the following (from memory, since all this is dynamic from the metadata I could have missed a beat...) -

  • call data (indexes & params)
  • era information
  • nonce
  • tip
  • (everything above is included in the submitted extrinsic, everything below is not)
  • specVersion
  • transactionVersion
  • genesisHash
  • blockHash (same as genesis for immortal)
0

Probably not the answer you want to here, but the desub project can do dynamic decoding. You could build and link to that. I'm not aware of something similar in c# yet.

Your Answer

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

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