Skip to content
Blockchain Association of Cameroon
BAC-L0-FOUND-1113 h

Accounts, transactions and fees

Account model versus UTXO, nonces, fees and priority: the economic machinery that rations scarce block space.

  • Compare the account and UTXO models on the same transfer
  • Explain the nonce's role against replay
  • Break down how a transaction fee is computed

Every blockchain must answer three simple questions: who owns what, how to stop the same value being spent twice, and who decides which transaction gets into scarce block space. In this workshop you compare the two main answers to the first question, the UTXO model and the account model, on one worked transfer. You understand the role of the nonce and of the chain identifier against replay, then break a transaction fee down step by step. You finish by building, signing and diagnosing transactions on a simulated practice network.

Lessons 1/4 · 20 min

UTXO or accounts: one transfer

A matter of cash

Think of your wallet. Either you hold notes and coins: to pay 60 you hand over a 50 note and a 20 note, and you get 10 in change. Or you hold a balance on a mobile-money account: to pay 60, the balance drops by 60. Blockchains made both choices.

  • UTXO model (unspent transaction output). The state is a set of indivisible "outputs", each locked to an owner. Bitcoin works this way.
  • Account model. The state is a table: for each account, a balance and a counter (the nonce, lesson 2). Ethereum, chains built with the Cosmos SDK and Substrate/Polkadot chains work this way.

The same transfer in both models (fictitious figures)

Awa owns 80 units and wants to pay 60 to Bineta, with 2 units of fee.

In UTXO. Awa owns two outputs: one of 50 and one of 30. Neither is enough alone, so the transaction consumes both as inputs (50 + 30 = 80) and creates new outputs:

Amount
Inputs (consumed outputs)50 + 30 = 80
Output 1: to Bineta60
Output 2: change back to Awa18
Fee (inputs − outputs: 80 − 78)2

An output is never spent in part: it is consumed whole, and the change is a new output sent back to yourself. The fee is written nowhere: it is the difference between inputs and outputs. Once consumed, the 50 and 30 outputs disappear from the set.

In accounts. Awa's balance goes from 80 to 80 − 60 − 2 = 18. Bineta's rises by 60. In this simplified example, the 2 of fee go to the proposer. Awa's nonce increases by 1.

How each prevents double spending

  • UTXO: an output can be consumed only once. A second transaction consuming it is invalid, because the output is no longer in the set.
  • Accounts: the balance is checked at execution time, and the nonce imposes a strict order on an account's transactions (lesson 2).

An honest comparison

UTXOAccounts
What the state holdsA set of unspent outputsBalances and nonces, plus code/storage on contract chains
FeesImplicit (inputs − outputs)Explicit transaction fields
Error temptationForgetting the change output: the difference becomes feesSending transactions in the wrong nonce order
Complex contractsPossible, but shared state is less naturalNatural: a contract is an account with code

What this does NOT guarantee

  • The UTXO model is not automatically "anonymous": reusing an address or merging inputs links outputs together.
  • The account model is not "less secure": the nonce and the balance check play there the role that single-consumption plays in UTXO.
  • Neither model protects against sending to the wrong address.

Recap

UTXO: consume whole outputs and create new ones; fee = inputs − outputs. Accounts: update balances; explicit fees; the nonce orders.

Lessons 2/4 · 20 min

The nonce and chain id against replay

The problem: a valid signature stays valid

Awa signs "pay 50 to Bineta". The signature depends only on the message. If a third party copies the signed transaction and broadcasts it a second time, the signature is still valid. With no protection, Bineta would receive another 50 for every copy. That is a replay. A signature alone does not say "only once".

The nonce: a counter per account

The nonce ("number used once", here an order number) is a counter attached to each account. It is part of the signed message. The rule: a transaction is valid only if its nonce is exactly the account's next nonce.

Example: Awa's next nonce is 7.

Transaction receivedNonceVerdict
Payment to Bineta7Valid; Awa's next nonce becomes 8
Identical copy replayed7Rejected: "nonce too low", since 7 < 8
Payment to Kofi9Gap: the 8 is missing. The practice network rejects it ("nonce ahead")
Payment to Kofi8Valid; the next nonce becomes 9

In real Ethereum clients, a transaction that is ahead may be held pending until the missing nonces arrive, instead of being rejected at once. The BAC practice network, stricter, rejects it. The nonce also gives an order: two payments from the same account run in nonce order.

The chain id: preventing replay across networks

Suppose Awa uses the same key pair on a test network and on a real network. If the signed message does not contain the network's identity, a transaction signed for one is valid on the other, with the same account and nonce. A third party can copy it from one network to the other: that is cross-chain replay. The remedy: include a chain id in the signed message. A node on network 42 rejects a transaction signed for network 77, because the signature covers a different message; and if the id is altered afterwards, the signature no longer matches. Ethereum added a protection of this kind after the fact (EIP-155).

The practice network

In this course's exercise you sign the text bac-practice|chain=<id>|to=<recipient>|amount=<amount>|fee=<fee>|nonce=<nonce>. Every field that matters is inside the signed message: changing a single character invalidates the signature (avalanche, workshop 104). The page's sign tool uses ECDSA on the P-256 curve because the browser offers it natively; real chains mostly use other curves or schemes (for example secp256k1 for Bitcoin and Ethereum, ed25519 or sr25519 elsewhere). That is a simplification of the exercise, not a rule of the field.

What this does NOT guarantee

  • The nonce is not a timestamp: it does not say when the transaction was signed.
  • It prevents neither censorship nor front-running (a third party jumping ahead of your transaction by paying a higher fee).
  • It protects an account's order, not against someone who holds your private key: that actor signs valid nonces.
  • The UTXO model has no nonce: on a single network, replay is impossible there because consumed outputs no longer exist. Between two chains that share a history (after a split), the same output exists on both sides and a transaction can be valid on both: a chain-specific marker is then needed in the signature.

Recap

Exact nonce = a single execution and an order. Chain id inside the signed message = no replay from one network to another.

Interactive tool

ECDSA P-256 signature

Generate a key pair in your browser, sign a message, then verify the signature.

The private key is created with extractable: false: the browser keeps it in memory and never lets it be exported, and it is neither displayed nor stored. It lives only in this tab: reloading the page loses it.

Public key (SPKI, base64)

No key yet. Generate a pair to sign.

Signature (base64, P1363 format: r ‖ s, 64 bytes)

…

ECDSA with SHA-256 on the P-256 curve. WebCrypto returns r and s concatenated (32 + 32 bytes), not DER encoding.

Verify a signature

Interactive tool

SHA-256 digest

Type some text: the digest updates on every keystroke. Compare with a second text to see the avalanche effect.

Digest (64 hex characters)

…

Digest of the second text

…

Differing characters are underlined and bold. Text is UTF-8 encoded with no space or newline added.

Lessons 3/4 · 20 min

Breaking down a transaction fee

Why fees?

A block has a limited size: space is scarce. Without a price, anyone could fill it with thousands of useless transactions (spam) and nobody would pay for the proposer's work. Fees do two jobs: they ration space in favour of those who value it most, and they make spam costly.

Bitcoin: a price per size

In Bitcoin, as seen in lesson 1, fees are implicit: inputs − outputs. The proposer usually ranks transactions by fee per unit of size (the fee divided by the transaction's size), not by total fee. A transaction merging many inputs is bulkier, hence more expensive at the same rate per unit.

Account chains with gas: a price per work

On Ethereum-style chains, computation work is measured in gas (a unit of work). A transaction sets a gas limit (the maximum it agrees to consume) and the actual computation uses gas used. Since the update known as EIP-1559, the price per gas unit breaks down into:

  • base fee: set by the protocol according to how full recent blocks were, identical for all transactions in a block, and burned (destroyed);
  • tip (priority fee): a supplement paid to the proposer; in the transaction it is a maximum tip that the sender accepts to pay (the maxPriorityFeePerGas field in Ethereum);
  • max fee: the ceiling per gas unit that the sender accepts to pay.

The effective price is min(max fee, base fee + tip). The final cost is gas used × effective price. On Ethereum, at submission, the network reserves gas limit × max fee; the difference from the final cost is refunded (this is not true everywhere: see below).

Worked example (arbitrary units, fictitious figures)

Gas limit 60,000; gas used 48,000; base fee 20; tip 3; max fee 30.

  1. Effective price: min(30, 20 + 3) = 23.
  2. Final cost: 48,000 × 23 = 1,104,000.
  3. Reserved: 60,000 × 30 = 1,800,000.
  4. Refund: 1,800,000 − 1,104,000 = 696,000.

Another case: base fee 28, tip 3, max fee 30. The effective price is min(30, 31) = 30: the ceiling cuts the tip, which is now only 2 per unit. If the base fee rose above 30, the transaction would not be included as long as it stayed above its ceiling.

In Ethereum's protocol, the base fee varies from block to block (by at most about 12.5% per block) depending on whether recent blocks were fuller or emptier than the target. Other chains have other mechanisms: a minimum gas price set by each validator in the Cosmos SDK, for example, and, by default in the Cosmos SDK to our knowledge, a declared fee taken in full with no refund of what was not consumed. Read the documentation of the target chain.

What this does NOT guarantee

  • A high fee does not guarantee inclusion in the next block (a proposer can censor; the network can be congested).
  • A low fee is not "free" on failure: a transaction that fails during execution is still charged. After an explicit contract failure (REVERT), it is the gas used up to that point; after an out-of-gas halt or an invalid instruction, the whole gas limit is consumed (on Ethereum and chains that imitate it).
  • On Ethereum and chains that imitate it, the gas limit is not the cost: only the gas actually used is charged. On other chains (Cosmos SDK by default, to our knowledge), the declared fee is taken in full: read the documentation.
  • Fees do not protect against manipulation: a wealthy attacker can pay to monopolise space.

Recap

Effective price = min(ceiling, base + tip). Cost = gas used × effective price. On Ethereum, reserved − cost = refunded; elsewhere, check.

Lessons 4/4 · 15 min

Reading a transaction rejection

When the wallet says "failed"

A rejected transaction is not a mystery: a node applies a series of rules and stops at the first one violated. Knowing how to read that message avoids wrong repairs (raising the fee when it is the nonce that is wrong). Here are the six causes that the BAC practice network simulates, in the order in which it checks the rules.

OrderReasonWhat it meansRepair
1PAYLOAD_TAMPEREDThe received message no longer matches what was signedRe-sign it; find who alters the data
2WRONG_CHAINThe chain id is not the network'sSign with the right id
3NONCE_TOO_LOWNonce already usedTake the account's next nonce
3NONCE_GAPNonce ahead of the accountSend the missing nonces first
4FEE_TOO_LOWFee below the minimumRaise the fee
5INSUFFICIENT_BALANCEAmount + fee > balanceReduce the amount or fund the account

Real nodes use other messages and other check orders. The idea to keep: an error message names a precise rule; the repair depends on the rule.

Worked example

Network: chain id 42, minimum fee 5, Awa's next nonce 12, Awa's balance 1,000. Awa sends: chain 42, amount 990, fee 15, nonce 12.

  1. The message's digest matches what was signed: rule 1 satisfied.
  2. Chain 42: rule 2 satisfied.
  3. Nonce 12: rule 3 satisfied.
  4. Fee 15 ≥ 5: rule 4 satisfied.
  5. Amount + fee = 990 + 15 = 1,005 > 1,000: INSUFFICIENT_BALANCE, 5 short.

Repair: bring the amount down to 985 (985 + 15 = 1,000) or fund the account. Raising the fee would worsen the imbalance.

Another example: message altered in transit

The server receives a message showing "amount = 120" whose signed digest corresponds to "amount = 100". It computes the SHA-256 of the received message's canonical string "chain|sender|recipient|amount|fee|nonce" and compares it with the signed digest: the two differ. No other rule is examined: PAYLOAD_TAMPERED. This is why the signature protects a transaction's integrity in transit.

Two simplifications in the exercise

In the exercise, signature verification is simulated: the server compares the received message's digest with the digest the signature covers. A digest alone proves nothing, since anyone can recompute it; it is the signature over that digest, verified with the public key, that proves the origin. Also, the workshop uses two different texts: the diagnosis exercise uses the canonical string chain|sender|recipient|amount|fee|nonce, whereas the "build, sign and submit" exercise uses the bac-practice|chain=… text from lesson 2. Do not use one in place of the other.

What this does NOT guarantee

  • A transaction that passes every rule is valid, but not necessarily intended: it may have been signed by mistake or under duress.
  • A rejection by one node is not a rejection by the network: another node with other relay rules (a different minimum fee, for example) may accept it.
  • Succeeding on a practice network does not prove your code works on a real network: formats, curves and rules differ.

Recap

A rejection = a precise rule. Read the order of checks, spot the first rule violated, repair that rule and nothing else.

Interactive tool

SHA-256 digest

Type some text: the digest updates on every keystroke. Compare with a second text to see the avalanche effect.

Digest (64 hex characters)

…

Digest of the second text

…

Differing characters are underlined and bold. Text is UTF-8 encoded with no space or newline added.

Guided lab

A browser cannot broadcast to a real test network: the workshop uses a simulated BAC practice network (no real value) with the same validity rules as lesson 4. The signature, however, is real: ECDSA on P-256, with a key generated in your browser that never leaves it. Sending to a real test network with a token faucet is in the independent lab.

A browser is no substitute for a real terminal: this lab trains reading and reasoning; the real hands-on practice is in the independent lab.

A certified account is required

Graded activities record results in your name and are the basis for a credential. They therefore need a complete certified file and a current consent. Filling in the file does not verify your identity; the Secretariat can verify it afterwards ("Verified" badge).

  1. 1.Change and fees in UTXO

    Answer the multiple-choice question: a UTXO wallet must pay a given amount from several outputs. Compute the sum of the chosen inputs, the change output and the implicit fee (inputs − outputs), following Awa's example from lesson 1.

  2. 2.Compute the fee

    For the transaction described in the exercise, compute the effective price per gas unit, the final cost (gas used × effective price) and the refund (reserved − final cost), using the formulas from lesson 3. Fictitious figures, arbitrary units.

  3. 3.Build, sign and submit

    Choose a fee at least equal to the minimum such that amount + fee ≤ balance. Build the exact text to sign, generate a key pair with the sign tool (the private key never leaves your browser), sign that text, then enter the fee, the public key and the signature. The server verifies the signature then applies the rules.

    Interactive tool

    ECDSA P-256 signature

    Generate a key pair in your browser, sign a message, then verify the signature.

    The private key is created with extractable: false: the browser keeps it in memory and never lets it be exported, and it is neither displayed nor stored. It lives only in this tab: reloading the page loses it.

    Public key (SPKI, base64)

    No key yet. Generate a pair to sign.

    Signature (base64, P1363 format: r ‖ s, 64 bytes)

    …

    ECDSA with SHA-256 on the P-256 curve. WebCrypto returns r and s concatenated (32 + 32 bytes), not DER encoding.

    Verify a signature

  4. 4.Diagnose a rejection

    A transaction was rejected by the practice network. Apply the rules in the order of lesson 4 (use the sha256 tool to check the message digest), name the rejection reason and give the correction value requested.

    Interactive tool

    SHA-256 digest

    Type some text: the digest updates on every keystroke. Compare with a second text to see the avalanche effect.

    Digest (64 hex characters)

    …

    Digest of the second text

    …

    Differing characters are underlined and bold. Text is UTF-8 encoded with no space or newline added.

Security exercise — Cross-chain replay: why this transaction must be rejected

Imagine two fictitious practice networks that share no value: a "bac" network and a "bac-test" network, with different chain ids. Learners often reuse the same key pair on both, for convenience.

A learner, Kofi, signs a 300-unit transfer on the "bac-test" network, where units are free. An observer of the "bac-test" network copies the signed transaction and broadcasts it on the "bac" network, where Kofi really holds practice units. Kofi's nonce is the same on both networks and the signed message does not mention a chain. Result: the transaction is accepted on "bac" although Kofi never intended it.

The defence is to put the chain id in the signed message and check it during validation. In the exercise below, a transaction signed for a chain other than the network's is presented: identify the rejection reason and the value of the correct id.

Workshop quiz

Eight questions drawn from a larger pool, 70% to pass. It opens once every lab checkpoint is passed. You can retake it: the draw changes.

A certified account is required

Graded activities record results in your name and are the basis for a credential. They therefore need a complete certified file and a current consent. Filling in the file does not verify your identity; the Secretariat can verify it afterwards ("Verified" badge).

Independent lab (outside the site)

Not graded online: do it on your own machine and publish it to your Git repository.

To do on your own machine, outside the site

On a public test network of your choice (pick one whose official documentation describes a token faucet, and follow that documentation), carry out the full cycle:

  1. Create a dedicated test account: never put in it a key or phrase used on a real network. Get test tokens from the faucet.
  2. Build, sign and broadcast a transfer transaction with a tool from the stack (test wallet, library or command-line client). Note the transaction id and follow its inclusion in a block.
  3. Deliberately trigger two failures: (a) a wrong nonce: too low (an immediate error is expected), then ahead (depending on the chain: held pending or rejected, to be read in the official documentation); (b) an insufficient fee (max price below the base fee, or below the chain's minimum).
  4. Write an annotated error log: for each failure, the exact message received, the rule violated, what you changed and the result.

Do not paste any private key into the log. Mark as "unverified" any explanation you infer without finding it in the network's official documentation.

Takeaways

  • UTXO: you consume whole outputs and create new ones, including change; the fee equals inputs − outputs.
  • Accounts: the state is a table of balances and nonces; fees are explicit transaction fields.
  • An exact nonce gives an order and prevents replay of a transaction on the same network; a signed chain id prevents replay from one network to another.
  • On Ethereum: effective price = min(max fee, base fee + tip); cost = gas used × effective price; the rest of the reservation is refunded (not on every chain).
  • A rejection names a precise rule: read the order of checks and repair that rule.

Common misconceptions

  • Misconception : In Bitcoin, an account has a balance, like at the bank.

    In fact : Bitcoin records no balance: a wallet adds up the unspent outputs it can spend. The "balance" is a wallet computation.

  • Misconception : The nonce is a random number picked for each transaction.

    In fact : In this context, the nonce is the exact sequence number of the account's transaction: 7, then 8, then 9. Do not confuse it with the mining nonce, which a miner varies to find a hash.

  • Misconception : A higher fee fixes any failed transaction.

    In fact : A higher fee fixes only FEE_TOO_LOW. A wrong nonce, a wrong chain id or insufficient balance each requires a different repair, and raising the fee can even worsen an insufficient balance.

  • Misconception : The gas limit is what the transaction costs.

    In fact : The gas limit is a ceiling. On Ethereum and chains that imitate it, only the gas used is charged and the difference between what was reserved and the final cost is refunded; on other chains, the declared fee may be taken in full.

Glossary

UTXO
Unspent transaction output: an indivisible unit of value, locked to an owner, consumed whole by a transaction.
Account nonce
Sequence number of an account's transactions; a transaction is valid only if its nonce is exactly the next one expected.
Replay
Re-broadcasting an already signed transaction to make it execute again, on the same network or on another.
Chain id
A number identifying a network that is included in the signed message so a transaction is valid only on that network.
Gas
Unit measuring computation work on Ethereum-style chains; the cost is gas used multiplied by a price per unit.
Base fee and tip
Base fee: per-unit price set by the protocol and burned. Tip: supplement paid to the proposer. The effective price is capped by the max fee.