Repository navigation
v0.8.3: node fixes (#143 #144 #146 #149) - #150
Merged
Merged
Conversation
…on names no chain rand-node (stdout) and rand-prover (stderr) build their subscriber with `.with_ansi(log_ansi(<stream>.is_terminal(), NO_COLOR))`, so journald gets plain lines and `grep ' INFO randprotocol_node::node: committed'` works again. NO_COLOR follows no-color.org (present and not empty). The `rand` CLI has no subscriber. deploy: cutover-droplet-chain14.sh writes "RAND full node ($NAME)", and update-droplet.sh rewrites a unit's "RAND full node (d, chain 14)" to "RAND full node (d)" on the next roll (later cutovers only swap the datadir). Fixes #143 Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01GFs5h141Ct6RTGGrCTQ1vy
…at debug
The WARN spam "Not publishing a message that has already been published" came
from `broadcast_status`: it runs on every `peer connected` and on the 3 s
status tick, and a `Status { height, head_hash, view, floor }` names no author.
Under the content-only message id (blake3 of the bytes), an unchanged status
was the same id as last time, and every node at one head published the same id
as every other, so the second publisher's status was dropped (and the new peer
a connect-time status was meant for never heard it). The peer-binding announce
is not it: it is signed afresh with the clock every time.
The message id now covers the author and sequence number on the status topic
only (`message_id`). Transactions, consensus and bindings keep the content id,
so one transaction forwarded by two peers is still one message. In a mixed
fleet only IHAVE/IWANT carry ids: an old peer may pull a status it already
holds, a few dozen bytes. `PublishError::Duplicate` is logged at debug.
Tests: a_status_id_covers_its_author_and_sequence_and_every_other_id_is_the_content,
an_unchanged_status_published_again_is_delivered_again.
Fixes #144
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01GFs5h141Ct6RTGGrCTQ1vy
…which method - `rand_getUnsealed` is not refused: the sale proxy's `RPC_ALLOWED` (randprotocol.org server/sale/src/rpc.rs at 8cebd54) and the node's `rpc::PUBLIC_METHODS` are the same 62 methods, and it is on both. - One table names, per method, what the proxy, the node's public listener and its operator listener each do. - The `--public-rpc` note no longer says "not yet done": nothing in the repo records obs1's state after the 2026-10-22 rebuild, so it says that and how to check from the web droplet (rand_getPeers through 127.0.0.1:18545). - The proxy's per-IP read limit is 1200 a minute, not 120. Fixes #149 Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01GFs5h141Ct6RTGGrCTQ1vy
…gned
Every `rand/{chain}/tx` message was `MessageAuthenticity::Signed`, so it
carried the publishing node's PeerId, a signature and a sequence number, and
every node learned which peer first published each transaction.
`MessageAuthenticity` is per behaviour, so transactions get a second gossipsub
behaviour (`RandBehaviour::tx_gossip`): `Anonymous` under
`ValidationMode::Anonymous` (a message naming an author is refused), on its own
protocol `/rand/{chain}/txsub` so it never competes with `/meshsub` for a
stream, topic `rand/{chain}/tx/2`. Consensus, status and peer bindings stay
signed. The derive maps both behaviours' events to one variant, so the lane is
read off the topic (each behaviour subscribes only its own); `GossipId.lane`
routes the verdict back. A transaction's `from` is now its forwarder on either
lane; rate limiting already keyed on `propagation_source`.
Rolling upgrade: by default a node also subscribes to, publishes on and relays
the legacy signed topic, which an older node (under Permissive or Strict) still
accepts because it is signed. A transaction heard on both lanes is handed to
the node once; the other lane's copy is held for that verdict (`TxCross`), so a
transaction the node accepts is relayed on both lanes and an older node behind
it still gets it (without the hold the second copy is a pool duplicate,
`Ignore`, and is not relayed; the transition test fails that way).
`--anonymous-tx-only` drops the legacy topic once no older node is left
(docs/deploy.md).
The two integration tests that pinned a status's content-addressed id
(tests/network.rs) now pin it on a transaction, and check the #144 contrast:
an unchanged status published three times is three deliveries.
Tests: a_gossiped_transaction_carries_no_author_and_the_legacy_copy_follows_the_flag,
during_the_roll_a_transaction_is_judged_once_and_relayed_on_both_lanes,
tx_cross_judges_the_first_copy_and_answers_the_other_lane_with_its_verdict,
the_transaction_lane_is_anonymous_by_configuration.
Fixes #146
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01GFs5h141Ct6RTGGrCTQ1vy
Codecov Report✅ All modified and coverable lines are covered by tests. 📢 Thoughts on this report? Let us know! |
This was referenced Oct 27, 2026
dendisuhubdy
added a commit
that referenced
this pull request
Oct 28, 2026
…fter submit, display-unit token create, fixed-page scan, --proxy (PR #154) CHANGELOG: the Unreleased section is now one v0.8.3 entry, the node items (#150, #155) under "Node" and this branch's items under "Wallet". Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01GFs5h141Ct6RTGGrCTQ1vy
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.
Four fixes from the chain-21 network experiment, one commit each.
#143: no ANSI colour in journald; unit Description names no chain
rand-node(logs to stdout) andrand-prover(logs to stderr) call.with_ansi(log_ansi(<stream>.is_terminal(), NO_COLOR)). Colour is on only at a terminal, and never whenNO_COLORis set and not empty (no-color.org). TherandCLI has no tracing subscriber, so it needs no change.cutover-droplet-chain14.shwroteDescription=RAND full node ($NAME, chain 14). Later cutovers onlysedthe datadir suffix, so live units still say "chain 14". The script now writesRAND full node ($NAME), andupdate-droplet.sh(the roll) rewrites an existing…, chain N)toRAND full node (<host>)and runsdaemon-reload.log_ansi_tests::colour_only_at_a_terminal_and_never_under_no_color(rand-node) andtests::log_colour_only_at_a_terminal_and_never_under_no_color(rand-prover).#144: duplicate-publish WARN spam
broadcast_status. It runs on everyPeerConnectedand on the 3 s status tick.Status { height, head_hash, view, floor }names no author, and the gossip message id was blake3 of the bytes alone. So an unchanged status had the same id as last time, and every node at one head published the same id as every other node. The second publish was dropped with libp2p's own "Not publishing a message that has already been published" WARN. That produced the burst on connect and the steady trickle. It was also a real loss: the status meant for a newly connected peer never went out. The PeerBinding announce is not the cause, since it is re-signed with the clock every time.message_id()covers the author and sequence number on the status topic only. Transactions, consensus messages and bindings keep the content id, so one transaction forwarded by two peers is still one message. In a mixed fleet, ids are compared only in IHAVE/IWANT, so an old peer may at worst pull a status it already holds (a few dozen bytes).PublishError::Duplicateis now logged at debug at the call site.a_status_id_covers_its_author_and_sequence_and_every_other_id_is_the_content,an_unchanged_status_published_again_is_delivered_again. Intests/network.rs, the two tests that pinned a status's content id now pin it on a transaction, and add the contrast that a status published three times is three deliveries.#146: transaction gossip no longer names its author
RandBehaviour::tx_gossip, carries transactions only. It usesMessageAuthenticity::AnonymousunderValidationMode::Anonymous, so a message carrying a source, seqno or signature is refused. It runs on its own protocol/rand/{chain}/txsub(two behaviours cannot share/meshsub), topicrand/{chain}/tx/2. Consensus, status and peer bindings staySigned.NetworkBehaviourderive maps both behaviours' events to one variant, so the lane is taken from the topic: each behaviour subscribes only its own topics, and gossipsub drops messages for unsubscribed topics.GossipId.laneroutes each verdict back to the behaviour that delivered the message.fromis now its forwarder on either lane. Rate limiting is unchanged: it already keyed onpropagation_source(Peer::tx_bucket).Rollout plan (also in
docs/deploy.md, "The anonymous transaction lane")/meshsuband see exactly what they saw before. The legacy copy is still signed, so an older node underStrict(--strict-gossip) orPermissiveaccepts it. A v0.8.3 node never publishes unsigned on/meshsub. An older node's transactions reach v0.8.3 nodes on the legacy topic. The two lanes stay in step throughTxCross: a transaction heard on both is handed to the node once, and the other lane's copy is held for that verdict. Without the hold, the second copy would be a pool duplicate, reportedIgnoreand never relayed on its lane, so older nodes would stop getting transactions past one hop. The transition test fails that way when the hold is disabled. During this phase the legacy copy still names the author.--anonymous-tx-only, in any order. Each flagged node stops publishing on and subscribing torand/{chain}/tx. The privacy gain starts here.Out of scope: timing analysis (the first relayer of a transaction is still the likeliest author). That is the Dandelion++ issue's to close.
a_gossiped_transaction_carries_no_author_and_the_legacy_copy_follows_the_flag: a bare gossipsub listener ontx/2receives the node's transactions withsource == Noneandsequence_number == None. A bare pre-v0.8.3 node receives the signed legacy copy without the flag, and nothing with it.during_the_roll_a_transaction_is_judged_once_and_relayed_on_both_lanes: in B → A → C, with C a legacy-only node behind A, A's node loop sees each transaction once and C still receives B's transactions through A.tx_cross_judges_the_first_copy_and_answers_the_other_lane_with_its_verdictthe_transaction_lane_is_anonymous_by_configuration#149: deploy/caddy/README.md
rand_getUnsealedis not blocked. The sale proxy'sRPC_ALLOWED(randprotocol.orgserver/sale/src/rpc.rsat8cebd54) and the node'srpc::PUBLIC_METHODSare the same 62 methods (compared mechanically).--public-rpcnote no longer says "not yet done". Nothing in the repo records obs1's state after the 2026-10-22 rebuild, so the note says so and gives the check:rand_getPeersthrough127.0.0.1:18545from the web droplet.READS_PER_MINUTE), not 120. The note also flags that the 2026-10-11 sale deploy was built before8cebd54.Tests run
Run locally on macOS:
nice -n 19,CARGO_BUILD_JOBS=4, node crate only.cargo test -p randprotocol-node --lib network::: 82 passed, 0 failedcargo test -p randprotocol-node --test network: 14 passed, 0 failedcargo test -p randprotocol-node --bin rand-node: 63 passed, 0 failedcargo test -p randprotocol-node --lib -- gossip status binding compact: 80 passed, 0 failedcargo test -p randprotocol-prover --features service --bin rand-prover: 3 passed, 0 failedcargo clippy --no-deps -p randprotocol-node -p randprotocol-prover --all-targets -- -D warnings: cleanCloses #143
Closes #144
Closes #146
Closes #149
🤖 Generated with Claude Code
https://claude.ai/code/session_01GFs5h141Ct6RTGGrCTQ1vy