Transaction Validation Lifecycle
Transactions are the most fundamental entities for interacting with Nervos CKB. When you interact with the CKB, you are submitting state transitions through transactions. This document will explain the lifecycle of CKB transaction validation.
Submit the transaction through RPC
First, a sender constructs a transaction, then submits it through RPC. The transaction will be validated by the outputs_validator
(introduced in v0.27.0) which has been submitted.
The default validation logic involves checking various things:
transaction.outputs.all{ |output|
let script = output.script
(script.code_hash == secp256k1_blake160_sighash_all && script.hash_type == "type" && script.args.size == 20) ||
(script.code_hash == secp256k1_blake160_multisig_all && script.hash_type == "type" && (script.args.size == 20 || (script.args.size == 28 && script.args[20..28].is_valid_since_format))
}
transaction.outputs.all{ |output|
let script = output.type
script.is_null || script.code_hash == dao && script.hash_type == "type"
|| (script.has_lock_period() && since.is_absolute())
}
This validation is intended to prevent improperly constructed transactions, such as mentioned in https://github.com/nervosnetwork/ckb/wiki/Common-Gotchas#nervos-dao
Although the node can be configured to passthrough
to skip this validation, once the transaction has been submitted to your local node, the node also exports the transaction id, which can then be used to track transaction status.
Verification
Before the transaction is broadcasted and enters into the mempool, it should be verified and executed locally.
STEP 1 — Resolve
Essentially, transaction inputs are just pointers, as shown here:
struct OutPoint {
tx_hash: Byte32,
index: Uint32,
}
We gather the referenced data through the pointer prior to transaction execution, this process is called “resolve transaction”. We will also need to check that all inputs of this transaction are valid (no duplicate or double-spending).
STEP 2 — Verify
The process of verification involves checking the following items:
- version (currently must be 0)
- serialized_size is less than limit
- pub fn serialized_size(&self) -> usize {
// the offset in TransactionVec header is u32
self.as_slice().len() + molecule::NUMBER_SIZE
// molecule::NUMBER_SIZE =
size_of::<u32>() 4
}
- pub fn serialized_size(&self) -> usize {
// the offset in TransactionVec header is u32
self.as_slice().len() + molecule::NUMBER_SIZE
// molecule::NUMBER_SIZE =
- inputs are not empty
- inputs().is_empty() || outputs().is_empty()
- inputs are mature
- For each input and dep, if the referenced output transaction is a cellbase, it must have at least 4 epoch confirmations
- capacity
- sum of inputs’ capacity must less than or equal to outputs’ capacity
- duplicate_deps
- deps should not be duplicated
- outputs_data_verifier
- number of ‘output data' fields must equal number of outputs
- since
- ‘since’ value must follow the rules described in https://github.com/nervosnetwork/rfcs/blob/master/rfcs/0017-tx-valid-since/0017-tx-valid-since.md
Then CKB VM will execute the transaction script and output the number of cycles consumed.
Broadcast to the network
If the verification is successful, the current node broadcasts the transaction (with cycles value) to all of its connected peer nodes.
If verification fails, the transaction is not broadcasted anymore. The transaction flows through various “full nodes”, which repeat the verification process described in the previous step, and check that the cycles value matches the actual cycles consumed when the transaction is verified.
Tx-pool (mempool)
CKB uses a two-step process for transaction confirmation. Transactions will be divided into different status (pending and proposed) in the tx-pool. The status of transactions will change when a block is added to the blockchain. When the latest block changes, all transactions in the tx-pool will be re-scanned to ensure they are still valid.
BlockAssembler
will fetch proposals and transactions from the pending pool and proposed pool for block template.
More information about this two-step transaction confirmation process can be found here.
Tx-pool Two-Step Transaction Confirmation
Since CKB v0.101, the tx-pool will not run the two-step transaction confirmation mechanism for non-miner nodes, i.e. nodes that are not configured with block assembler, and the status of the transaction will not be displayed when the transaction is fetched via rpc.