Repository navigation
feat: An account takes its address from its key, and a record answers one field at a time - #44
Open
willemneal wants to merge 3 commits into
Open
willemneal wants to merge 3 commits into
willemneal wants to merge 3 commits into
Conversation
The `tx` stages were moved onto `output::write_line`, which treats a closed pipe as a normal ending, when `xrpl tx new … | head -1` was found to panic. The record listings were not, and they have the same reader: `key ls | head`, `account ls | grep -q`, anything that stops reading once it has what it asked for. `head` closing the pipe is the reader doing its job, not an error. `raw_line`'s doc said it was for `server subscribe` alone. It is for any output that is a line rather than a document, which is what these listings are, so the doc now says that instead of naming its first caller. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Every site that builds `SignerError::Unavailable` passes a full clause naming
the signer and the reason, and the variant wrapped them in one of its own:
`Signer {0} is unavailable on this machine`. So a watch-only key read back as
`Signer alice is watch-only: it has a public key and no secret is unavailable
on this machine`, and the credential-store timeout — a paragraph of advice —
read worse.
The payload is the sentence. `Error::Signer` already prefixes "Signer error",
and it is the exit code, not the prose, that tells this apart from a backend
failure.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
… one field at a time `xrpl account add` required `--address`. An account's address derives from its original master public key, so when that key is the one being recorded the address is already on disk — and requiring it anyway meant every caller ran `xrpl key show <id> --json | jq -r .classic_address` first. The ceremony script in `demo/` did exactly that, which is the tell. `--address` is now optional when `--key` is given, and is taken from the key records. It is a default and not a rule: `--address` still wins when given, because a regular key and a signer-list member each derive to their own address and not to the account's, which is the whole reason keys are a list rather than a field. Keys that derive to different addresses are refused with both spelled out, rather than guessed at — guessing wrong records an account that signs for someone else. `--force` will not change an alias's address by omission either: adding a key is the obvious reason to re-run `add --force`, and until now the address had to be restated on every such run. The other half is reading a field back out. `key show` and `account show` grew part flags — `--address`, `--public-key`, `--algorithm`, `--source` on one, `--address`, `--network-id`, `--tag`, `--keys`, `--default-signer` on the other — each writing that one value bare on stdout and nothing else, so a script needs no JSON parser. A field set to nothing prints nothing and says so on stderr, which keeps `$(xrpl account show alice --tag)` empty rather than holding the word "none". `--default-signer` is the exception: an account with no key, or with several and no default, has no answer rather than an empty one. `account show` also names the effective default signer. An account with a single key has no `default_signer` field and that key is still the one it names — the commonest record there is — and the block used to say nothing at all about it. An account with several and no default is named too, since that is the record a person most needs to be told to choose for. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
This was referenced Sep 25, 2026
Open
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Stacked on #43. Review the last three commits.
What prompted it
Both halves were real, and the second was the cause of the first. The address was always in the key record; there was no way to read one field out of a record without a JSON parser. So
account addasked for an address the CLI already knew, and the ceremony script indemo/opened with the proof:It is now:
account add --keysupplies the address--addressis optional when--keyis given, taken from the key records' cachedclassic_address, and disclosed on stderr —address r…, from key alice— for the same reason an inherited--accountsays so.It is a default, not a rule.
--addressstill wins when given, because a regular key and a signer-list member each derive to their own address and not to the account's; that is the whole reasonkeysis a list rather than a field. Three refusals rather than guesses:--addressnor a--key--keytwice, which would otherwise record an account with one key that cannot tell it has oneAnd
--forcewill not change an alias's address by omission. Adding a key is the obvious reason to re-runadd --force, and until--addressbecame optional it had to be restated on every such run, so an alias could not silently change identity. It still cannot.key showandaccount showanswer one fieldOne value, bare on stdout, nothing else —
--json | jq -r .classic_addressis just--address. Mutually exclusive, and each conflicts with--json.A field set to nothing prints nothing and says why on stderr, so
$(xrpl account show alice --tag)comes back empty rather than holding the wordnone.--default-signeris the exception and fails instead: an account with no key, or with several and no default, has no answer rather than an empty one.account showalso names the effective default signer. An account with one key has nodefault_signerfield and that key is still the one the record names — the commonest record there is, and the block used to say nothing at all about it. An account with several and no default is named too, because that is the record a person most needs to be told to choose for.Two fixes found on the way
xrpl key ls | head -1ended in a Rust panic. Thetxstages were moved onto the closed-pipe handling whentx new | head -1was found to panic; the record listings were not, and they have the same reader.SignerError::Unavailablespliced two sentences. Every construction site passes a full clause, and the variant wrapped them in one of its own:Signer alice is watch-only: it has a public key and no secret is unavailable on this machine.One thing this does not do
AccountRecord::signer_key— the resolution that makes a lone key an account's default — had no caller outside its own unit tests, and still has none in the signing path.tx signtakes--sign-with <key-id>and reads no account record, soaccount show --default-signeranswers which key this account names and that value is what you hand--sign-with. An early draft of this PR claimed the two resolved the same way; they do not, and the docs now say so rather than the reverse. Makingtx signresolve through the record is the obvious next step and is a separate change — it would need to decide what it resolves from without breaking the invariant that the unlock happens before the first transaction is read.Verification
tests/records.rs— 11 new, covering every refusal and every part flag against the--jsonrecordcargo clippy --all-targetsclean;CLI.mdregeneratedrippleci/xrpld --standalone, with all six exit codes still assertedtx signclaim above🤖 Generated with Claude Code