advanced 75 min

The complete transaction lifecycle

Follow a transaction from creation and signing through submission, validation, consensus, canonical application and final validation.

Prerequisites

Complete these before starting this module:

What you'll learn

  • Trace the stages from submission to full validation.
  • Distinguish preflight, preclaim and doApply.
  • Explain open-ledger tentative application vs canonical application.
  • Read transaction metadata and result codes.
Complete this module by mentor review and a quiz. Jump to assessment

Introduction

≈75 min · Advanced · builds on Navigating the rippled codebase

What really happens between hitting 'send' and a transaction becoming permanent? In this module you'll follow one from creation and signing, through submission and validation, into consensus, and finally to canonical application in a validated ledger. You'll learn to tell tentative (open-ledger) application from the real thing, and to read the result codes and metadata a transaction leaves behind. It's the end-to-end story that every later module zooms into.


Transaction Lifecycle Overview

In brief: the eleven-stage journey from a signed transaction to a permanent one, at a glance.

Complete Journey Diagram

A transactions complete journey in 11 stages: creation, submission, initial validation (invalid rejected with tem codes), preclaim validation (invalid rejected with tec codes), tentative open-ledger application, network propagation, consensus round (not included means deferred to the next round), canonical application (a tec result fails but charges the fee), ledger closure, validation phase, and finally fully validated: immutable and permanent

Typical Timeline

Typical timeline, fast path versus slow path: in ideal conditions a transaction goes from submission to fully validated in about 7 seconds; submitted late in the open phase it waits for the next ledger close and takes about 32 seconds


Phase 1: Transaction Creation

In brief: build and sign the transaction; its hash becomes its identity.

Transaction Structure

Before submission, a transaction must be properly constructed:

{
  "TransactionType": "Payment",
  "Account": "rN7n7otQDd6FczFgLdlqtyMVrn3HMtthca",
  "Destination": "rLNaPoKeeBjZe2qs6x52yVPZpZ8td4dc6w",
  "Amount": "1000000",
  "Fee": "12",
  "Sequence": 42,
  "LastLedgerSequence": 75234567,
  "SigningPubKey": "03AB40A0490F9B7ED8DF29D246BF2D6269820A0EE7742ACDD457BEA7C7D0931EDB",
  "TxnSignature": "30450221008..."
}

Required Fields

Universal Fields (all transaction types):

  • TransactionType - Type of transaction (Payment, OfferCreate, etc.)
  • Account - Source account (sender)
  • Fee - Transaction fee in drops (1 XRP = 1,000,000 drops)
  • Sequence - Account sequence number (nonce)
  • SigningPubKey - Public key used for signing
  • TxnSignature - Cryptographic signature (or multi-signatures)

Optional but Recommended:

  • LastLedgerSequence - Expiration ledger (transaction invalid after this)
  • SourceTag / DestinationTag - Integer tags for routing/identification
  • Memos - Arbitrary data attached to transaction

Transaction Signing

Single Signature:

Multi-Signature:

Transaction Hash

The transaction hash (ID) is calculated from the signed transaction:

// Simplified hash calculation
uint256 calculateTransactionID(STTx const& tx)
{
    // Serialize the entire signed transaction
    Serializer s;
    tx.add(s);
    
    // Hash with SHA-512 and take first 256 bits
    return s.getSHA512Half();
}

Important: The hash is deterministic, the same signed transaction always produces the same hash.


Phase 2: Transaction Submission

Submission Methods

Method 1: RPC Submit

Submit via JSON-RPC:

curl -X POST https://s1.ripple.com:51234/ \
  -H "Content-Type: application/json" \
  -d '{
    "method": "submit",
    "params": [{
      "tx_blob": "120000228000000024..."
    }]
  }'

Response:

Method 2: WebSocket Submit

Real-time submission with streaming updates:

Method 3: Peer Network Submission

Transactions submitted to one node propagate to all nodes:

Client → Node A → Overlay Network → All Nodes

Even if submitted to a non-validator, the transaction reaches validators through peer-to-peer propagation.

Submission Response

Immediate response indicates initial validation result:

Success Codes:

  • tesSUCCESS - Transaction applied to open ledger
  • terQUEUED - Transaction queued (network busy)

Temporary Failure (can retry):

  • terPRE_SEQ - Sequence too high, earlier tx needed
  • tefPAST_SEQ - Sequence too low (already used)

Permanent Failure (don't retry):

  • temMALFORMED - Malformed transaction
  • temBAD_FEE - Invalid fee
  • temBAD_SIGNATURE - Invalid signature

Phase 3: Initial Validation

Preflight Checks

Before accessing ledger state, static validation occurs:

Checks Performed:

  • Cryptographic signature valid
  • Transaction format correct
  • Required fields present
  • Fee sufficient
  • Amounts positive and properly formatted
  • No contradictory fields

Why Preflight Matters: Catches obvious errors before expensive ledger state access.


Phase 4: Preclaim Validation

Ledger State Checks

Read-only validation against current ledger state:

Checks Performed:

  • Source account exists
  • Sequence number correct
  • Sufficient balance (including fee)
  • Destination account requirements met
  • Trust lines exist (for issued currencies)
  • Account flags permit operation

Phase 5: Open Ledger Application

In brief: the transaction is applied tentatively to the open ledger; nothing is final yet.

Tentative Application

Transaction is tentatively applied to provide immediate feedback:

Open Ledger Characteristics:

  • Not Final: Open ledger is tentative, changes frequently
  • No Consensus: Local view only, other nodes may differ
  • Immediate Feedback: Clients get instant response
  • Can Change: Transaction may be removed or re-ordered

Why It Matters:

  • Users get immediate confirmation
  • Wallets can show pending transactions
  • Applications can provide real-time updates

Watch out. A result you see in the open ledger is tentative. It can still change until the transaction lands in a validated ledger. Never treat an open-ledger success as final.


Phase 6: Network Propagation

Transaction Broadcasting

Once applied to open ledger, transaction broadcasts to peers:

Propagation Speed:

  • Local network: < 100ms
  • Global network: 200-500ms
  • All nodes receive transaction within 1 second

Deduplication:

  • Nodes track recently seen transactions
  • Duplicate transactions not re-processed
  • Prevents network flooding

Phase 7: Consensus Round

Transaction Set Building

As ledger close approaches, validators build transaction sets:

Consensus Process

Validators exchange proposals and converge:

Round 1: Initial proposals

Validator A proposes: {TX1, TX2, TX3, TX4}
Validator B proposes: {TX1, TX2, TX3, TX5}
Validator C proposes: {TX1, TX2, TX4, TX5}

Agreement:
TX1: 100% ✓
TX2: 100% ✓
TX3: 67%
TX4: 67%
TX5: 67%

Round 2: Converge on high-agreement transactions

All validators propose: {TX1, TX2}

Agreement:
TX1: 100% ✓ (included)
TX2: 100% ✓ (included)

TX3, TX4, TX5 deferred to next ledger

Transaction Inclusion Criteria:

  • 80% of UNL must agree to include

  • Transaction must still be valid
  • Must not have expired (LastLedgerSequence)

Phase 8: Canonical Application

In brief: after consensus agrees on the set, every node applies it in the same canonical order.

Deterministic Execution

After consensus, transactions are applied in canonical order:

Simplified. The real canonical order is salted: CanonicalTXSet XORs each account key with a salt derived from the previous ledger's hash, so the order is deterministic for everyone but unpredictable in advance (nobody can buy a better position). The sort shown here keeps the idea readable; see the Transaction ordering module for the real mechanics.

DoApply Execution:

Result Codes:

  • tesSUCCESS - Transaction succeeded
  • tecUNFUNDED - Failed but fee charged
  • tecNO_TARGET - Failed but fee charged

Important: Even failed transactions (tec codes) consume the fee and advance the sequence number.


Phase 9: Ledger Closure

Closing the Ledger

After all transactions are applied:

Ledger Hash Calculation:


Phase 10: Validation Phase

Creating Validations

Validators sign the closed ledger:

Broadcasting Validations

Collecting Validations


Phase 11: Fully Validated

In brief: enough validators sign the ledger; now the result is irreversible.

Finalization

When quorum is reached, ledger becomes fully validated:

Characteristics of Validated Ledger:

  • Immutable: Cannot be changed
  • Permanent: Part of ledger history forever
  • Canonical: All nodes have identical copy
  • Final: Transactions cannot be reversed

Transaction Status Querying

Methods to Check Transaction Status

Method 1: tx RPC

Query by transaction hash:

xrpld tx E08D6E9754025BA2534A78707605E0601F03ACE063687A0CA1BDDACFCD1698C7

Response:

Key Fields:

  • validated: true = in validated ledger, false = pending
  • meta.TransactionResult: Final result code
  • ledger_index: Which ledger contains transaction

Method 2: account_tx RPC

Query all transactions for an account:

xrpld account_tx rN7n7otQDd6FczFgLdlqtyMVrn3HMtthca

Lists transactions in reverse chronological order.

Method 3: WebSocket Subscriptions

Real-time transaction monitoring:

ws.send(JSON.stringify({
  command: 'subscribe',
  accounts: ['rN7n7otQDd6FczFgLdlqtyMVrn3HMtthca']
}));

ws.on('message', (data) => {
  const msg = JSON.parse(data);
  if (msg.type === 'transaction') {
    console.log('Transaction:', msg.transaction);
    console.log('Status:', msg.validated ? 'Validated' : 'Pending');
  }
});

Subscription Types:

  • accounts - Transactions affecting specific accounts
  • transactions - All transactions network-wide
  • ledger - Ledger close events

Transaction Metadata

In brief: the record of exactly what a transaction changed in the ledger.

Metadata Structure

Metadata records the effects of a transaction:

AffectedNodes Types:

  • CreatedNode - New ledger object created
  • ModifiedNode - Existing object modified
  • DeletedNode - Object deleted

Key Metadata Fields:

  • TransactionIndex - Position in ledger
  • TransactionResult - Final result code
  • delivered_amount - Actual amount delivered (for partial payments)

Transaction Expiration

LastLedgerSequence

Transactions can specify an expiration:

{
  "TransactionType": "Payment",
  "Account": "rN7n7otQDd6FczFgLdlqtyMVrn3HMtthca",
  "Destination": "rLNaPoKeeBjZe2qs6x52yVPZpZ8td4dc6w",
  "Amount": "1000000",
  "LastLedgerSequence": 75234567
}

Behavior:

  • If not included by ledger 75234567, transaction becomes invalid
  • Prevents transactions from being stuck indefinitely
  • Recommended: Set to current ledger + 4

Checking Expiration:

bool isExpired(STTx const& tx, LedgerIndex currentLedger)
{
    if (!tx.isFieldPresent(sfLastLedgerSequence))
        return false;  // No expiration set
    
    return tx[sfLastLedgerSequence] < currentLedger;
}

Using testnet

xrpld account_info <your_address>

Step 3: Submit and record time

const startTime = Date.now();

const result = await client.submit(signed.tx_blob);

console.log('Submission Time:', Date.now() - startTime, 'ms');
console.log('Initial Result:', result.result.engine_result);
console.log('Applied to Open Ledger:', result.result.engine_result === 'tesSUCCESS');

Part 2: Monitor Progress

Step 4: Subscribe to transaction

Step 5: Poll for status

Part 3: Analyze Results

Step 6: Examine metadata

Analysis Questions

Answer these based on your observations:

  1. How long did each phase take?
  • Submission to initial result: ___ ms
  • Initial result to validated: ___ ms
  • Total time: ___ ms
  1. What was the initial result?
  • Did it apply to open ledger?
  1. Which ledger included the transaction?
  • Ledger index?
  • How many ledgers closed between submission and inclusion?
  1. What was the metadata?
  • Which nodes were affected?
  • What balances changed?
  1. Did the transaction expire?
  • Was LastLedgerSequence set?
  • How close to expiration was it?

Common Issues and Solutions

Issue 1: Transaction Stuck Pending

Symptoms: Transaction not validating after 30+ seconds

Possible Causes:

  • Insufficient fee (transaction queued)
  • Network congestion
  • Sequence gap (earlier transaction missing)

Solutions:

# Check transaction status
xrpld tx <hash>

# Check for sequence gaps
xrpld account_info <account>

# Increase fee and resubmit if needed

Issue 2: tefPAST_SEQ Error

Symptoms: Sequence number already used

Cause: Sequence out of sync or transaction already processed

Solution:

// Always fetch current sequence
const accountInfo = await client.request({
  command: 'account_info',
  account: wallet.address
});

const currentSeq = accountInfo.result.account_data.Sequence;

Issue 3: Transaction Not Found

Symptoms: tx command returns "txnNotFound"

Possible Causes:

  • Transaction not yet in validated ledger
  • Transaction expired (LastLedgerSequence)
  • Transaction rejected during validation

Solution:

// Wait for validation or check expiration
const ledger = await client.request({command: 'ledger_current'});

if (ledger.result.ledger_current_index > tx.LastLedgerSequence) {
  console.log('Transaction expired');
}

Issue 4: tecUNFUNDED_PAYMENT

Symptoms: Transaction failed with fee charged

Cause: Insufficient balance between submission and execution

Prevention:

// Always check balance including reserves
const reserve = (2 + ownerCount) * baseReserve;
const available = balance - reserve;

if (amount + fee > available) {
  throw new Error('Insufficient funds');
}

Additional Resources

Official Documentation

Codebase References

  • Transactors - How transactions are validated and executed
  • Consensus Engine - How transactions are included in consensus
  • Protocols - How transactions are propagated across the network

Summary

This module followed a transaction across its entire journey: creation and signing, submission, the validation phases (preflight, preclaim, doApply), consensus, and finally canonical application in a validated ledger. You learned to tell a tentative open-ledger result from a final one, and to read the result codes and metadata a transaction leaves behind. It is the end-to-end picture that the deeper modules each zoom into.

To remember:

  • Full path: create/sign, submit, preflight, preclaim, open-ledger (tentative), relay, consensus, canonical apply, close, validations, fully validated
  • A transaction is identified by its hash; finality = inclusion in a validated ledger
  • Open-ledger results are provisional; the canonical (salted) order at consensus can even change the outcome
  • Metadata (meta / AffectedNodes) records exactly what the transaction changed
  • Query with tx <hash> or account_tx; the field that matters is "validated": true
  • Dispatch code: src/libxrpl/tx/applySteps.cpp; ledger flow: src/xrpld/app/ledger
  • Typical Mainnet close cadence: a ledger every 3 to 5 seconds
  • Watch out: treating tesSUCCESS from submit as final is the classic integration bug; it only means "applied to the open ledger"

Next up. You watched the happy path. When something goes wrong in that pipeline, how do you see inside the running node? Next: the debugging techniques you will use for the rest of the bootcamp.

Assignments

0 of 2 complete

Unlocks

Finishing this module opens up:

XRPL Academy © 2026