From c6df042c7b4b938af40e0b7459a2d368047bce04 Mon Sep 17 00:00:00 2001 From: mDuo13 Date: Fri, 14 Nov 2025 16:37:08 -0800 Subject: [PATCH] Add code sample showing how to walk an owner directory --- _code-samples/walk-owner-directory/README.md | 4 ++ .../js/iterate-owner-directory.js | 55 +++++++++++++++++++ .../walk-owner-directory/js/package.json | 5 ++ .../py/iterate-owner-directory.py | 55 +++++++++++++++++++ .../walk-owner-directory/py/requirements.txt | 1 + 5 files changed, 120 insertions(+) create mode 100644 _code-samples/walk-owner-directory/README.md create mode 100644 _code-samples/walk-owner-directory/js/iterate-owner-directory.js create mode 100644 _code-samples/walk-owner-directory/js/package.json create mode 100644 _code-samples/walk-owner-directory/py/iterate-owner-directory.py create mode 100644 _code-samples/walk-owner-directory/py/requirements.txt diff --git a/_code-samples/walk-owner-directory/README.md b/_code-samples/walk-owner-directory/README.md new file mode 100644 index 00000000000..21c60b4b9c1 --- /dev/null +++ b/_code-samples/walk-owner-directory/README.md @@ -0,0 +1,4 @@ +# Walk Owner Directory +Iterate over an account's owner directory and display how many ledger entries are in each page. In cases of highly active accounts, this can demonstrate the extent of "fragmentation" with skipped page numbers and non-full pages. + +This code sample demonstrates the low-level structure of owner directories. If you don't need to see the breakdown by pages, you can use [`account_objects`](https://xrpl.org/docs/references/http-websocket-apis/public-api-methods/account-methods/account_objects) instead, since it provides a more convenient list of ledger entries attached to an account. diff --git a/_code-samples/walk-owner-directory/js/iterate-owner-directory.js b/_code-samples/walk-owner-directory/js/iterate-owner-directory.js new file mode 100644 index 00000000000..9ef20dc8366 --- /dev/null +++ b/_code-samples/walk-owner-directory/js/iterate-owner-directory.js @@ -0,0 +1,55 @@ +// iterate-owner-directory.js +// Iterate over an account's owner directory and display how many ledger entries +// are in each page. In cases of highly active accounts, it can demonstrate +// the extent of "fragmentation" with skipped page numbers and non-full pages. + +import xrpl from 'xrpl' + +const client = new xrpl.Client('wss://s.altnet.rippletest.net:51233') +await client.connect() + +const owner = "rPT1Sjq2YGrBMTttX4GZHjKu9dyfzbpAYe" // Testnet faucet +// const owner = "rP9jPyP5kyvFRb6ZiRghAGw5u8SGAmU4bd" // TST issuer + +// Set initial values for iterating +let sub_index = 0 // Directory root +let ledger_index = "validated" + +// Query pages from the owner directory until they run out +console.log("Page #\t\t\tEntry count") +console.log("-----------------------------------") +while (true) { + // console.log(`Getting directory page ${sub_index}`) + const resp = await client.request({ + "command": "ledger_entry", + "directory": { + "owner": owner, + "sub_index": sub_index + }, + "ledger_index": ledger_index + }) + if (resp.error) { + console.error("ledger_entry failed with error",resp.error) + break + } + + // Consistently iterate the same ledger: query by index after the first + if (ledger_index === "validated") { + ledger_index = resp.result.ledger_index + } + + console.log(`${sub_index}\t\t\t${resp.result.node.Indexes.length}`) + // console.log(`This page contains ${resp.result.node.Indexes.length} items.`) + + // Continue onto another page if this one has more + if (resp.result.node.hasOwnProperty("IndexNext")) { + // The directory continues onto another page. + // IndexNext is returned as hex but sub_index needs decimal + sub_index = parseInt(resp.result.node.IndexNext, 16) + } else { + console.info("This is the last page of the directory") + break + } +} + +client.disconnect() diff --git a/_code-samples/walk-owner-directory/js/package.json b/_code-samples/walk-owner-directory/js/package.json new file mode 100644 index 00000000000..7df0e16bae3 --- /dev/null +++ b/_code-samples/walk-owner-directory/js/package.json @@ -0,0 +1,5 @@ +{ + "dependencies": { + "xrpl": "^4.4.3" + } +} diff --git a/_code-samples/walk-owner-directory/py/iterate-owner-directory.py b/_code-samples/walk-owner-directory/py/iterate-owner-directory.py new file mode 100644 index 00000000000..5403bec291f --- /dev/null +++ b/_code-samples/walk-owner-directory/py/iterate-owner-directory.py @@ -0,0 +1,55 @@ +# iterate-owner-directory.py +# Iterate over an account's owner directory and display how many ledger entries +# are in each page. In cases of highly active accounts, it can demonstrate +# the extent of "fragmentation" with skipped page numbers and non-full pages. +from xrpl.clients import JsonRpcClient +from xrpl.models.requests import LedgerEntry +from xrpl.clients import XRPLRequestFailureException + +OWNER_ADDRESS = "rPT1Sjq2YGrBMTttX4GZHjKu9dyfzbpAYe" # Testnet faucet +# OWNER_ADDRESS = "rP9jPyP5kyvFRb6ZiRghAGw5u8SGAmU4bd" # TST issuer + +client = JsonRpcClient("https://s.altnet.rippletest.net:51234/") + +# Set initial values for iterating +sub_index = 0 # Directory root +ledger_index = "validated" + +# Query pages from the owner directory until they run out +print("Page #\t\t\tEntry count") +print("-----------------------------------") +while True: + # Construct the LedgerEntry request for the directory page + directory_request = LedgerEntry( + directory={ + "owner": OWNER_ADDRESS, + "sub_index": sub_index + }, + ledger_index=ledger_index + ) + + # Send the request + try: + response = client.request(directory_request) + except Exception as e: + print(f"\nError: ledger_entry failed: {e}") + break + + # The 'ledger_index' is consistently set after the first successful query. + # This ensures subsequent pages are read from the same ledger version. + if ledger_index == "validated": + ledger_index = response.result["ledger_index"] + + # The entries are stored in the 'Indexes' field of the 'DirectoryNode' + entry_count = len(response.result["node"]["Indexes"]) + print(f"{sub_index}\t\t\t{entry_count}") + + # Check for the next page indicator + if "IndexNext" in response.result["node"].keys(): + # The directory continues onto another page. + # Convert IndexNext from hex to decimal for sub_index. + hex_next = response.result["node"]["IndexNext"] + sub_index = int(hex_next, 16) + else: + print("\nThis is the last page of the directory.") + break diff --git a/_code-samples/walk-owner-directory/py/requirements.txt b/_code-samples/walk-owner-directory/py/requirements.txt new file mode 100644 index 00000000000..31f58cc12cb --- /dev/null +++ b/_code-samples/walk-owner-directory/py/requirements.txt @@ -0,0 +1 @@ +xrpl-py==4.3.1