Repository navigation
Fix sync stalling on tx-bearing blocks from current nodes - #8
Conversation
Current nockchain nodes return raw transactions from the heaviest-chain-blocks-range peeks (raw-txs are all consensus stores), but the peek response was decoded as full tx objects. The decode fails on the first block with a non-empty tx map, and the sync loop retries the same batch forever. Decode each tx as either shape (the noun encodings are disjoint) and rebuild the full tx from a raw-tx like +new:tx in tx-engine-1: the total-size is the bit length of the jammed raw-tx (+compute-size-jam) and the outputs pair each note derived by RawTxV1::outputs with the original seeds sharing its lock root (+build-outputs). This keeps the stored jam format and all downstream layers unchanged, and older nodes serving full txs keep working. v0 raw-txs (only served for pre-tx-engine-1 blocks) are rejected with an explicit error. Fixes #6
|
Bugbot is not enabled for your account, so this pull request was not reviewed. Enable Bugbot in the Cursor dashboard to get automatic reviews on future PRs. |
|
It would be better if zorp stopped breaking scry interface unnecessarily. They also just removed no-pow scry, which is quite important for fast sync: nockchain/nockchain@2601509#diff-44e004bcf232faefa9aba1e79b7d3409037ad6f94f61cf0b3da09b467b6c1525L518 |
h33p
left a comment
There was a problem hiding this comment.
Looked at upstream change - they got rid of txs altogether (good). However, we are somewhat stuck with Tx representation here. So, let's keep it as that, just note that "newer nodes are no longer relying on tx object, but instead, return raw-tx.
I'm prepping a tiny PR on nockchain that brings back no-pow scry for blocks.
| /// A transaction as served by the blocks-range peeks: older nodes return the | ||
| /// full `tx`, current nodes return the consensus-stored `raw-tx`. | ||
| #[derive(Debug, Clone)] | ||
| pub enum ScryTx { |
There was a problem hiding this comment.
What I would do instead is make this
pub struct ScryTx(Tx)
and then, NounDecode for ScryTx has the RawTx -> Tx conversion. There's no need to expose into_tx to the consumer.
Leave a note that this is a workaround for a change introduced in nockchain/nockchain@5decf7c
|
PR for scry at nockchain/nockchain#150 |
|
NOTE: you also must support v0 transactions here. Sync from genesis will break otherwise. |
Current nodes serve raw transactions for historical v0 blocks too, so rejecting RawTx::V0 made a fresh sync stall at the first v0 tx (height 5629 on mainnet) the same way the v1 decode failure did. Rebuild v0 txs like +new:tx in tx-engine-0: total-size from +compute-size-jam and one output per recipient sig pairing the notes derived by RawTxV0::outputs with the original seeds (+new:outputs). Also accept the [raw-tx heard-at] pair shape served by older checkpointed nodes. Compute total-size by jamming the raw-tx noun exactly as received instead of re-encoding the typed value: iris-ztd's cue leaves placeholder hash caches on decoded cells, so re-encoded v1 txs mix cache provenances, which makes jam miss backrefs on repeated witness subtrees and inflate the size (482 extra bits on the first mainnet sample). Uniform-provenance nouns always jam to the consensus length. Validated against the published L0 snapshot: stored transactions stripped to their raw-tx and reconstructed match the node-provided total-size and jam byte for byte across both tx versions (see the TEST_DB_PATH-gated golden test).
|
Both findings addressed in a5bdc0c, plus one more bug the requested validation uncovered. P1 — v0 raw-txs are now reconstructed, not rejected. Confirmed against the snapshot (35,583 v0 txs at heights 5,629–38,988): a fresh sync would have stalled at 5,629 exactly as described. P3 — New: Tests added
Validation — golden test against the published |
|
@thomas-kroes the robot ignored the request to turn ScryTx into |
Contain the raw-tx workaround inside the block range manager per review: ScryBlocksResult carries plain Tx again and the ingest loop is back to untouched. The wire shapes still decode through ScryTx, but scry_blocks now rebuilds the full txs itself. The rebuild cannot live in NounDecode because the outputs derivation needs the block height (the notes' origin page) and the activation settings, so the manager holds ChainActivations and converts where the height is known.
|
@h33p Restructured in 7d4af00. One correction to the literal suggestion: the Net effect is what you asked for, minus the newtype: Also checked #150 after the merge: it restores Validation after the refactor: full test suite passes (35, including the raw-range → L0 ingestion test), and the sampled golden run against the published snapshot passes (516 of 74,742 stored txs, evenly strided across heights 5,629–112,500, reconstructed byte-for-byte). The full release sweep the previous comment promised got interrupted; re-running now, result to follow below. |
The full 74,742-tx sweep surfaced 8 v1 txs (heights 78,026-91,508) whose stored total-size exceeds the canonical fully-deduplicated jam bit length by 100-1,500 bits. Patching the stored size into the reconstruction makes the renormalized jams byte-identical, so the raw and outputs rebuild is exact for every stored tx: the delta is the node runtime's jam missing backrefs on structurally equal subtrees at validation time (the same cache-provenance defect class as iris-ztd's cue). That value is not derivable from the noun, so the golden test now asserts the canonical size -- never larger, rare undershoot bounded at 0.1% -- and byte-exact equality of everything else via a freshly-cue'd jam comparison.
|
Full release sweep results, as promised: 74,742 / 74,742 stored txs pass (1,788s), commit 7cf3379. One genuine finding came out of it. Eight v1 txs (heights 78,026–91,508) carry a stored Explanation: consensus The golden test now encodes exactly that: canonical size must never exceed the stored one (a systematic undershoot fails at >0.1%; actual is 8/74,742 ≈ 0.01%), and everything else must match byte-for-byte through a fresh cue+jam comparison that is immune to the mixed-provenance jam artifacts. |
Summary
Fixes #6 — against nodes built from current nockchain master (protocol 015 "Zoe"), sync failed with
Unable to decode nounon the first tx-bearing block and retried the same batch forever.Root cause (confirmed against dumbnet's
inner.hoon):+heaviest-chain-blocks-rangenow returns(z-map tx-id:t raw-tx:t)because raw-txs are all consensus stores, while iris decoded the map values as fullTxobjects. A wire raw-tx[%1 id spends]cannot decode asTx, so any block with a non-empty tx map failed; empty blocks passed, which made the stall look intermittent.Fix
ScryTx, which accepts either shape. The noun encodings are provably disjoint (a full tx is tagged[%0 tx]/[%1 tx]; a v0 raw-tx heads with a cell, a v1 raw-tx with[%1 id spends]where the id is a cell), so older nodes serving full txs keep working unchanged.+new:txintx-engine-1.hoon— both derived fields are pure functions of the raw-tx:total_size= bit length of the jammed raw-tx (+compute-size-jamis(met 0 (jam n))per the hoon docs). Verified thatiris_ztd::jamimplements canonical backreference deduplication, and the tests anchor the size helper to known hoon jam values ((jam 0) = 2,(jam 1) = 12).outputsmirrors+build-outputs:RawTxV1::outputsderives one note per lock root inBTreeMaporder of the lock-root hash; the original (un-normalized, per the hoon — only the source hash uses normalized seeds) seeds are grouped the same way so each note pairs with its seed group asOutputV1 { note, seeds }.Tx::V1(TxV1 { raw, total_size, outputs })keeps the stored jam format, so L1–L4 are untouched.RawTxV0Unsupportederror instead of a generic decode failure.Test plan
block_range_manager.rs:ScryTxdecodes both raw-tx and full-tx nouns into the right varianttotal_sizefrom the raw-tx jam and pairs each note with the seeds of its own lock-root group (groups with distinct gift totals across multiple spends, so mispairing would fail; originaloutput_sourceretained)met 0, anchored to known hoon jam valuescargo test --features binary --all-targets(32 passed)cargo clippy --features binary --all-targets(no new warnings),cargo fmt --check