1

From docs :

Create signed transaction.

This trait is meant to be implemented by the runtime and is responsible for constructing a payload to be signed and contained within the extrinsic. This will most likely include creation of SignedExtra (a set of SignedExtensions). Note that the result can be altered by inspecting the Call (for instance adjusting fees, or mortality depending on the pallet being called).

I want to understand more about this trait, regarding what module or system requires to create signed transactions, on whose behalf, and are these limited to extrinsics or may include inherents? When it says the trait is implemented for the Runtime, what are the cases when the runtime would like to do so? Likely I also want to understand what this implementation is doing if someone can break it down for me:

impl<LocalCall> frame_system::offchain::CreateSignedTransaction<LocalCall> for Runtime
where
    Call: From<LocalCall>,
{
    fn create_transaction<C: frame_system::offchain::AppCrypto<Self::Public, Self::Signature>>(
        call: Call,
        public: <Signature as sp_runtime::traits::Verify>::Signer,
        account: AccountId,
        nonce: Index,
    ) -> Option<(Call, <UncheckedExtrinsic as sp_runtime::traits::Extrinsic>::SignaturePayload)> {
        let tip = 0;
        // take the biggest period possible.
        let period =
            BlockHashCount::get().checked_next_power_of_two().map(|c| c / 2).unwrap_or(2) as u64;
        let current_block = System::block_number()
            .saturated_into::<u64>()
            // The `System::block_number` is initialized with `n+1`,
            // so the actual block number is `n`.
            .saturating_sub(1);
        let era = sp_runtime::generic::Era::mortal(period, current_block);
        let extra = (
            frame_system::CheckSpecVersion::<Runtime>::new(),
            frame_system::CheckTxVersion::<Runtime>::new(),
            frame_system::CheckGenesis::<Runtime>::new(),
            frame_system::CheckEra::<Runtime>::from(era),
            frame_system::CheckNonce::<Runtime>::from(nonce),
            frame_system::CheckWeight::<Runtime>::new(),
            pallet_transaction_payment::ChargeTransactionPayment::<Runtime>::from(tip),
        );
        let raw_payload = SignedPayload::new(call, extra)
            .map_err(|e| {
                log::warn!("Unable to create signed payload: {:?}", e);
            })
            .ok()?;
        let signature = raw_payload.using_encoded(|payload| C::sign(payload, public))?;
        let address = Indices::unlookup(account);
        let (call, extra, _) = raw_payload.deconstruct();
        Some((call, (address, signature.into(), extra)))
    }
}

1 Answer 1

1

These traits are used for pallets that need to send transactions. The general problem is that a pallet can not know the environment in which it lives, and therefore cannot, by default, have all the information needed to compose a transaction.

For example, a pallet cannot be aware of the list of other pallets that exist in the runtime, and therefore cannot also build the SignedExtensions type properly.

If you might ask why and when a pallet might need to send a transaction, I refer you to pallet_im_online and pallet_election_provider_multi_phase, both of which use offchain_workers to send unsigned transactions directly back to the chain.

These traits are ways through which the runtime is informing a pallet about how transactions need to be built. If you see, both of the aforementioned pallets bound their Config to also be SendTransactionTypes.

CreateSignedTransaction is a similar trait, which is only needed when a pallet needs to send a signed transaction. A good example of this is pallet-example-offchain-worker, which has its Config be bound to CreateSignedTransaction, which is needed to call into Signer::send_signed_transaction.

2
  • if i try to change type Address = MultiAddress<AccountId, ()> into type Address = MultiAddress<AccountId, AccountIndex> and then use CreateSignedTransaction in this pull request github.com/DataHighway-DHX/DataHighway-Parachain/pull/19, i get the errors shown in the pull request description that UncheckedExtrinsic doesn't satisfy Checkable<ChainContext<Runtime>>, and that the trait bound of UncheckedExtrinsic isn't satisfied and that the trait Checkable<ChainContext<Runtime>> is not implemented. do you know what may be causing this? Mar 14, 2022 at 7:46
  • Apologies to revive this old question, but re-reading your answer I had another question. Why not the aforementioned pallets choose inherents over unsigned transactions? – aren't inherents supposed to bypass the checks by SignedExtensions? Nov 10, 2022 at 8:31

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.