Transaction lifecycle
This page describes transactions submitted to the Dusk L1. DuskEVM has a separate sequencer and finality model.
Transaction shape
Section titled “Transaction shape”A Dusk L1 transaction combines a value model with an optional action:
| Layer | Options | Operational effect |
|---|---|---|
| Value model | Moonlight or Phoenix | Moonlight uses public accounts and sequential nonces. Phoenix uses shielded notes and nullifiers. |
| Action | Transfer, memo, contract call, contract deployment, or blob | The action is carried by either transaction family. A contract call can also deposit DUSK into the called contract. |
Moonlight exposes its sender, optional receiver, value, nonce, fee, and optional memo. Phoenix hides transferred values and participants while exposing the cryptographic data needed to verify note spends.
A memo can accompany a direct transfer and is limited to 512 bytes. The transaction data field holds one of a memo, contract call, deployment, or blob payload; do not assume a memo can accompany the other payload types.
Lifecycle
Section titled “Lifecycle”- Build and sign: the client chooses the transaction family, action, gas limit, gas price, and current spend inputs or nonce.
- Submit: the client sends serialized bytes to a node.
POST /on/transactions/propagatereturning202 Acceptedmeans the node accepted the request for routing; it does not mean the transaction is in a block. - Admit: the node pre-verifies the transaction. A valid transaction enters that node’s real mempool and emits
transactions/included. - Propagate: the receiving node broadcasts an admitted transaction to peers. Each peer performs its own admission checks and maintains its own mempool.
- Select: a block generator considers mempool transactions in descending gas-price order, subject to block limits and execution dependencies.
- Execute: an accepted block emits
transactions/executedfor each spent transaction.err: nullmeans execution succeeded; a non-nullerrrecords a contract panic or other execution failure. Either result consumes the nonce or notes and pays gas. - Finalize: accepted blocks can still be reverted. A
blocks/statechangeevent withstate: "finalized"makes the block and its transactions final.
Do not use included, removed, accepted, or confirmed as a payment-finality signal.
Mempool behavior
Section titled “Mempool behavior”| Question | Current behavior |
|---|---|
| Who can inspect it? | Anyone with GraphQL access to a node can query that node’s real mempool through mempoolTxs or mempoolTx. This is a local view, not a network-wide snapshot. |
| How are transactions prioritized? | Candidate selection iterates by descending gasPrice. Equal-price ordering is not a client contract. |
| How does replacement work? | A transaction that conflicts on a spending ID replaces the existing transaction only when its gas price is strictly higher. Raising only the gas limit is insufficient. Moonlight uses account and nonce as its spending ID; Phoenix conflicts on spent nullifiers. |
| What happens when the mempool is full? | A higher-priced transaction can evict the lowest-priced entry. Node operators configure the capacity; the default is 10,000 transactions. |
| When do transactions expire? | Expiry is local node policy, not a field in the transaction. Rusk’s built-in defaults are three days with hourly checks, while node-installer v0.5.22 configures mainnet and testnet nodes for 30 minutes with checks every five minutes. Clients must use the policy of their node instead of treating either value as a network guarantee. |
| What happens to future Moonlight nonces? | A transaction with a nonce gap is briefly staged outside the real mempool while the node waits for intermediate nonces. It emits deferred, is invisible to mempoolTxs, and is admitted only if the gap is filled before retries end. |
| Can every node publish transactions? | A full Rusk node can receive and rebroadcast transactions. Its operator can disable or restrict public HTTP access, apply ACLs, or rate-limit propagation. |
transactions/removed only says that an entry left the local mempool. Inclusion in a block, replacement, expiry, capacity eviction, or removal of a conflicting transaction can all cause it. Query ledger state before deciding what happened.
Events
Section titled “Events”RUES exposes these transaction topics:
| Topic | Meaning |
|---|---|
deferred |
Staged outside the real mempool because an admission prerequisite is missing |
dropped |
Discarded before entering the real mempool |
included |
Added to the local real mempool |
removed |
Removed from the local real mempool for any reason |
executed |
Executed in an accepted block; inspect err |
Block topics are accepted, statechange, and reverted. See the HTTP API event model for subscription details.
Confirm success
Section titled “Confirm success”For a live transaction watcher:
- Query
tx(hash: ...)after execution and requireerrto be null. - Retain its
blockHeightandblockHash. - On an archive node, require
checkBlock(height: ..., hash: ..., onlyFinalized: true)to returntrue. - Store the transaction ID as an idempotency key.
Archive Moonlight history is populated only when blocks finalize. Deposit systems can therefore use the finalized deposit scanner instead of reconstructing finality from live events.