The transaction pool regularly calls the validate_unsigned
function of the SignedExtension
trait to check transaction validity against current state. This trait then gets used to implement custom extensions in frame_system
, which get passed into the runtime as a single type, for example in a typical runtime/src/lib.rs
file we have:
pub type SignedExtra = (
frame_system::CheckNonZeroSender<Runtime>,
frame_system::CheckSpecVersion<Runtime>,
frame_system::CheckTxVersion<Runtime>,
frame_system::CheckGenesis<Runtime>,
frame_system::CheckEra<Runtime>,
frame_system::CheckNonce<Runtime>,
frame_system::CheckWeight<Runtime>,
pallet_transaction_payment::ChargeTransactionPayment<Runtime>,
);
So, IIUC this then is used to construct all parts of extra
data that a signed call submitted to the runtime expects:
/// Unchecked extrinsic type as expected by this runtime.
pub type UncheckedExtrinsic = generic::UncheckedExtrinsic<Address, Call, Signature, SignedExtra>;
Then, the TaggedTransactionQueue
runtime API provides a way to check that a submitted signed transaction is valid, giving the pool to order transaction by priority etc.
From what I understand, this runtime API verifies all the data in SignedExtra
. My question is how?
How does this extra data gets passed into the signed extension and how does the transaction pool know what and where to check in the encoded call?