Skip to content

XRPL-Commons/xrpl-test

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

6 Commits
 
 
 
 
 
 

Repository files navigation

xrpl-fixtures

A language-agnostic collection of test vectors for the XRP Ledger protocol, extracted from the rippled reference implementation.

Purpose

The XRP Ledger has historically been a single-client network, with rippled as the only production implementation. This repository is a step toward a multi-client future: any implementation that wants to participate in the network must produce identical results to the reference node.

xrpl-fixtures provides a shared, versioned corpus of test vectors that any XRPL client — regardless of language or architecture — can use to verify its correctness. Passing these fixtures is a prerequisite for a client to be considered safe to run on the network.

Scope

These fixtures cover the transaction execution layer only: given a ledger state and a set of transactions, verify that the resulting state and TER codes match the reference implementation. This is equivalent to Ethereum's execution-spec-tests.

The following are explicitly out of scope for this fixture format:

  • RPC/API conformance — testing JSON-RPC methods requires a live node; a separate fixture format and runner are needed.
  • Consensus — multi-node message sequencing cannot be expressed as a state-transition fixture.
  • Networking/P2P — rippled-internal infrastructure not relevant to alternative implementations.

How Fixtures Are Generated

Fixtures are extracted from rippled's own unit test suite using an instrumented recorder (FixtureRecorder) that captures, for each test case:

  • The ledger environment (enabled amendments, fee schedule)
  • The sequence of operations performed (funding accounts, trust lines, ledger closes, transaction submissions)
  • The expected transaction result code (TER)
  • The expected post-state (account balances, owner counts)
  • Both the raw transaction binary (tx_blob) and its JSON representation (tx_json)

This means every fixture is ground truth: it reflects what the reference implementation actually does, not what the specification says it should do.

To regenerate fixtures from a rippled build:

XRPL_FIXTURE_PATH=/path/to/output ./rippled --unittest

Repository Structure

xrpl-fixtures/
└── rippled-<version>/       # One directory per rippled release
    ├── app/                 # Transaction engine tests (80+ suites)
    │   ├── AccountDelete/
    │   ├── AMM/
    │   ├── Batch/
    │   ├── Escrow/
    │   ├── MPToken/
    │   ├── NFTokenAllFeatures/
    │   ├── OfferAllFeatures/
    │   ├── PayChan/
    │   └── ...
    └── ledger/              # Ledger object and directory tests
        ├── Directory/
        └── ...

Each test suite directory contains one JSON file per test case. The filename is the test case name with spaces replaced by underscores.

Versioning

Each rippled release gets its own top-level directory (e.g., rippled-2.6.2). Multiple versions can coexist in the repository, allowing implementations to track specific releases or validate behaviour across version upgrades.

Fixture Format

Each fixture is a JSON file with the following top-level fields:

Field Description
rippled_version The rippled version these vectors were extracted from
suite The fully-qualified C++ test suite name (e.g., ripple.app.PayChan)
testcase The test case name within the suite
env The ledger environment for the first scope (see below)
steps Ordered list of operations to replay (see below)

Environment (env)

{
  "env": {
    "amendments_enabled": ["NonFungibleTokensV1_1", "AMM", "..."],
    "base_fee": "10",
    "reserve_base": "200000000",
    "reserve_increment": "50000000"
  }
}
  • amendments_enabled: The exact set of amendments active at the start of the test. An implementation must enable exactly these amendments and no others.
  • base_fee: The base transaction fee in drops.
  • reserve_base / reserve_increment: Account reserve settings in drops.

The env field describes the initial scope. When a test contains multiple independent ledger scopes (see env_reset below), each subsequent scope's config is carried inline in the step.

Steps

Steps are executed sequentially. There are six operation types:

fund — Create and fund an account

{
  "op": "fund",
  "account": "alice",
  "address": "rG1QQv2nh2gr7RCZ1P8YYcBUKCCN633jCn",
  "amount": "1000000000",
  "set_default_ripple": true
}

Creates the named account with the given XRP balance (in drops), funded from the genesis/master account. account is a human-readable label used to identify the account in subsequent steps.

set_default_ripple indicates whether the asfDefaultRipple flag was set on the account after creation. When false, the account was funded without enabling DefaultRipple — the account's Sequence after funding is ledger_seq (not ledger_seq + 1), and trust lines created on this account default to NoRipple.

trust — Create a trust line

{
  "op": "trust",
  "account": "alice",
  "address": "rG1QQv2nh2gr7RCZ1P8YYcBUKCCN633jCn",
  "limit_amount": { "currency": "USD", "issuer": "rHb9...", "value": "1000" }
}

Establishes a trust line from account to the issuer in limit_amount. rippled's test framework reimburses the transaction fee to the account after the TrustSet, so the account's XRP balance is unchanged by this step.

close — Close the current ledger

{ "op": "close" }

Advances the ledger, applying all pending transactions. Corresponds to env.close() in rippled's test framework. Any enable_amendment step that precedes a close takes effect at this close.

tx — Submit a transaction

{
  "op": "tx",
  "tx_blob": "1200192400000004...",
  "tx_json": {
    "Account": "rG1QQv2nh2gr7RCZ1P8YYcBUKCCN633jCn",
    "TransactionType": "NFTokenMint",
    "Fee": "10",
    "Sequence": 4,
    "NFTokenTaxon": 0,
    "SigningPubKey": "...",
    "TxnSignature": "..."
  },
  "expect_ter": "tesSUCCESS",
  "post_state": {
    "accounts": [
      {
        "name": "alice",
        "address": "rG1QQv2nh2gr7RCZ1P8YYcBUKCCN633jCn",
        "xrp_balance": "999999990",
        "owner_count": 1
      }
    ]
  }
}

Submits the transaction to the current open ledger. The implementation must:

  1. Apply tx_blob (the canonical serialised transaction) to the current ledger state.
  2. Assert that the resulting TER code matches expect_ter.
  3. Assert that the post-ledger state matches post_state for every account listed.

tx_json is provided for human readability and debugging; tx_blob is the authoritative input.

env_reset — Start a fresh ledger scope

{
  "op": "env_reset",
  "env": {
    "amendments_enabled": ["..."],
    "base_fee": "10",
    "reserve_base": "200000000",
    "reserve_increment": "50000000"
  }
}

Resets the ledger to a clean state and applies the new environment config. This corresponds to the construction of a new Env object within the same C++ test function (a new { } scope). The runner must:

  1. Discard all current ledger state and accounts.
  2. Create a fresh genesis ledger with the provided env config.
  3. Advance the ledger once (matching rippled's Env constructor behaviour).

All subsequent fund/trust/tx steps operate on this fresh ledger until the next env_reset or end of file.

enable_amendment — Activate an amendment mid-test

{ "op": "enable_amendment", "amendment": "TicketBatch" }

Signals that the named amendment should be activated. It takes effect on the next close step, matching rippled's semantics (Env::enableFeature() requires a subsequent close() to take effect). Steps between enable_amendment and the next close execute without the amendment active.

TER Codes

expect_ter uses rippled's standard transaction result codes:

Prefix Meaning
tes Success (tesSUCCESS)
tec Fee claimed, transaction failed (e.g., tecINSUFFICIENT_RESERVE)
tem Malformed transaction (e.g., temMALFORMED)
ter Retry (e.g., terQUEUED)
tef Failure, fee not claimed

Coverage

The rippled-2.6.2 corpus contains:

  • 1,518 fixture files across app/ and ledger/
  • 80+ application-level test suites covering: AMM, Batch, Clawback, Credentials, DID, Escrow, MPToken, NFToken, Offers, PayChan, PermissionedDEX, PermissionedDomains, SetTrust, Tickets, XChain, and more
  • 1,285 env_reset steps (previously untestable multi-scope tests, now fully replayable)
  • 37 enable_amendment steps (previously untestable amendment-activation tests, now fully replayable)
  • 114 fund steps with set_default_ripple: false (noripple-funded accounts, previously causing sequence mismatches)
  • All major TER result codes exercised across both success and failure paths

Using These Fixtures

To validate your XRPL implementation against these vectors:

  1. Pick a rippled version directory (e.g., rippled-2.6.2).
  2. For each fixture file: a. Read the top-level env and configure a fresh genesis ledger (amendments, fees, reserves). b. Advance the ledger once (rippled's Env constructor does this on init). c. Replay steps in order, handling all six op types.
  3. For each tx step, assert expect_ter and validate post_state.

An implementation that passes all fixtures for a given version can be considered behaviourally equivalent to rippled at that version for the transaction execution layer.

Contributing

New fixtures should be generated by running the rippled extractor against a specific tagged release and placing the output under a new versioned directory. Do not hand-author fixture files — they must come from the reference implementation to be authoritative.

When a new rippled version is released:

  1. Apply the FixtureRecorder patch from this repository to the new rippled source.
  2. Build rippled and run: XRPL_FIXTURE_PATH=/path/to/rippled-<version> ./rippled --unittest
  3. Create a rippled-<new-version>/ directory with the output.
  4. Keep older version directories intact for implementations tracking specific releases.

About

tests vector to all xrpl client to test against

Resources

Stars

Watchers

Forks

Releases

No releases published

Packages

 
 
 

Contributors