Here is what happens between tapping "Send" in Eoonia and seeing a finalized transfer in EmpooScan. Each stage is a place where a transaction can be rejected, reordered or delayed, and knowing them is what separates an integration that works from one that works on the developer's laptop.
1. Building the envelope
A native EmpoorioChain transaction is a Substrate signed extrinsic: the call (which pallet, which function, which arguments), the signer, the signature, and a set of signed extensions that carry metadata the runtime checks before execution.
EmpoorioChain adds two extensions of its own in front of Substrate's standard eight. In order:
| # | Extension | Bytes in extra |
|---|---|---|
| 1 | CheckPqcPolicy — optional post-quantum signature and batch receipt | 2 when both are absent |
| 2 | CheckDormantAccount — dormant-account policy hook | 0 |
| 3–10 | CheckNonZeroSender, CheckSpecVersion, CheckTxVersion, CheckGenesis, CheckEra, CheckNonce, CheckWeight, ChargeTransactionPayment | standard |
Two bytes. That is the entire difference from a stock Substrate chain — and it is the single most consequential detail for any client. A library that does not know about the first extension does not fail loudly; it omits it, every subsequent byte shifts, and the node answers with a generic Bad input data provided to validate_transaction. For months this looked like five unrelated bugs (no DIDs registered, a reward pool that never paid, frozen staking eras, a sudo key that "had no permissions"). It was one missing two-byte field. The format is now documented byte by byte and verified against the live chain, and the Dart SDK, Eoonia and the Rust SDK all encode it.
The transaction also commits to the chain's genesis hash, spec_version (220) and transaction_version (6) inside the signed payload. A transaction built for the wrong runtime version is rejected before it costs anyone anything.
2. The pool
The RPC node validates the extrinsic (validate_transaction) and admits it to the DAG mempool. There it is a vertex with edges to the transactions it depends on: the sender's earlier nonces, and anything that touches the same storage. Ordering is deterministic — fee priority, then nonce, then id — duplicates are dropped, cycles are detected, and the transaction is gossiped to peers along with its dependency hints.
3. Authoring
When the current Aura slot belongs to a validator, its block builder pulls batches from the pool up to the block's weight and length limits. Because the pool already partitioned independent transactions, the builder can hand batches straight to the parallel executor.
4. Execution
The DeterministicFrameScheduler analyses reads and writes, runs independent batches across cores with rayon, merges the resulting state diffs and re-executes sequentially only what actually conflicted. Every validator that imports the block repeats the same deterministic plan and must arrive at the same state root, or the block is invalid. Fees are charged here according to weight — reference time and proof size — through ChargeTransactionPayment; a native DMS transfer on the testnet snapshot costs about 0.000025 DMS.
5. Inclusion
The block is announced. Peers fetch it, re-execute it, and if the state root matches they extend their chain. Your transaction is now included. Eoonia shows it as pending-confirmed; the balance changes are visible.
6. Finality
GRANDPA validators vote, and when two thirds agree on a prefix of the chain containing your block, it is finalized. On the May 2026 testnet benchmark this took about 17 seconds at the median. Now Eoonia shows it as confirmed, EmpooScan marks the block final, and a merchant can release the goods.
Where things go wrong, in order of frequency
- Wrong envelope — see stage 1. Symptom:
Codec error. Fix: use a client that knowsCheckPqcPolicy. - Wrong chain metadata — a client built against an older
spec_version. Symptom: rejected at validation. Fix: refresh metadata after every runtime upgrade; the metadata does change in every upgrade because the version lives inside it. - Nonce gaps — a client that fires transactions in parallel from one account. Symptom: transactions stuck as "future" in the pool. Fix: serialise per sender or use the DAG-aware batch API.
- Rate limiting — the public RPC nodes sit behind a fail2ban rule that bans an IP for an hour above ~10 requests/s. Symptom:
connection refused. Fix: run your own node or back off.
Based on FORMATO_DE_EXTRINSECOS.md (verified against spec 213), MEMPOOL_DAG_ORDERING.md, PARALLEL_EXECUTION_REPORT.md and CONSENSUS_STATUS.md.


