Skip to content

v0.7.0

Choose a tag to compare

@github-actions github-actions released this 30 Oct 17:24
· 26 commits to master since this release
v0.7.0
b3c79dc

📄 Canonical release notes: docs/release-notes/0.7.0.md

satd 0.7.0

Released 2026-10-30 · git tag v0.7.0 · Changelog

satd 0.7.0 is a minor release on the 0.x line. It includes every fix shipped
in 0.6.1 to 0.6.3.

Several mempool, relay, RPC and privacy defaults change to match Bitcoin Core;
read the Upgrade notes before upgrading. No reindex is
needed.

Highlights

  • Bitcoin Core's ZMQ notifications, byte for byte, so LND's bitcoind
    backend and Umbrel's apps run against satd unchanged
    (details).
  • Package CPFP in submitpackage, as in Core, so a Lightning commitment
    signed at a stale feerate can still be closed (details).
  • TRUC (version 3) transactions. BIP 431's topology and size limits, with
    sibling eviction, as in Core (details).
  • OP_RETURN data pruning. -pruneopreturn=<N> (off by default) strips
    large OP_RETURN payloads from deep blocks while txids and APIs keep working;
    -restoreopreturns undoes it (details).
  • Headers and P2P messages read as Core reads them. Headers that fork
    below the last checkpoint are refused and their sender banned
    (details); version, addrv2 and other payloads that
    Core accepts are no longer refused (details).

Bitcoin Core ZMQ notifications

satd now publishes Core's ZMQ topics; it used to ignore -zmqpub* with a
warning. -zmqpubhashblock, -zmqpubhashtx, -zmqpubrawblock,
-zmqpubrawtx and -zmqpubsequence take Core's syntax (multi-valued, one
socket per address, unix:<path> or ipc://<path>), -zmqpub<topic>hwm sets
the high-water mark (default 1000, 0 for none), and all ten options take
effect at restart. getzmqnotifications, help's == Zmq == category and
-debug=zmq behave as in Core.

Messages are Core's byte for byte, in Core's order within each event; a reorg
announces each block from the first with more work than the old tip, and
invalidateblock announces none. An unbindable address turns ZMQ off without
stopping the node; an invalid port stops startup with Core's message. Unlike
Core, satd promises no order between block-derived and mempool-derived
messages (per-topic sockets, as LND and Umbrel use, cannot tell), publishes
nothing for blocks connected during IBD or -reindex, drops a subscriber's
messages past 256 MiB queued, and lacks a few address forms; see the
Operator Manual
and CORE_DIFFERENCES.md. The streaming API remains the recommended
interface for new software.

A new PR-gating canary runs LND in bitcoind mode against satd's built-in
ZMTP 3.0 publisher; five of seven interface_zmq.py sub-tests pass.
/metrics gains six satd_zmq_* series. -eventszmqbind is unchanged.

Streaming Consumption API

  • No events lost in a deep reorg. The chain-event channel grows from 64
    to 1024 entries; a reorg of more than about 30 blocks could drop events.
  • A package's parent is announced before its child, on the mempool stream
    and on ZMQ, for a zero-fee parent admitted with its child.
  • A watch descriptor with a hardened step is refused
    (DescriptorError::HardenedDerivation, renamed from HardenedWildcard)
    instead of panicking the events task: xpub…/0h/* cannot be derived from
    a public key.

Block validation

  • Tapscript signature hashes cost what they cost in Core. The Rust engine
    (authoritative under -consensus=rust or cpp-shadow, shadow under
    the default rust-shadow) re-hashed the annex per signature check; it
    now follows Core's SignatureHashSchnorr. Results are unchanged.
  • A custom signet syncs past height 50,000: a -signetchallenge signet no
    longer inherits the default signet's checkpoints or assumevalid block.
  • Contextual header rules on every path. Timestamp (above MTP, at most two
    hours ahead) and BIP 34/66/65 version rules now also apply to headers
    messages and IBD blocks, before indexing, before storing and at connect, as
    Core's AcceptBlockHeader. A header refused only for being ahead of the
    clock no longer penalises its sender.
  • Transaction rules before a block is stored. Context-free checks,
    bad-txns-nonfinal and bad-cb-height run before a block is written, as
    Core's AcceptBlock, so submitblock returns Core's reason instead of
    inconclusive and the header is marked invalid.
  • -assumevalid skips scripts only under Core's conditions (ancestor of
    the assumevalid block on the best-header chain, minimum chain work met, two
    weeks of work deep), logging Core's "Enabling/Disabling script verification"
    lines. Off that branch satd verifies everything (stricter than Core).
  • -minimumchainwork takes effect (it was ignored); a value Core refuses
    stops startup.
  • BIP 30 as Core checks it. Skipped only above the BIP 34 height on a chain
    with the known BIP 34 block, and checked again from height 1,983,702.
    Testnet3 now checks every block; mainnet is unaffected until that height.
  • A failed invalidateblock leaves the node on a valid tip (#977). It now
    disconnects to the invalidated block's parent first, as in Core.
  • A tall chain of low-work headers no longer puts the node in IBD (#1119).
    The header height (getblockchaininfo.headers, the IBD check, readiness)
    is the most-work header's, as Core's m_best_header, not the highest
    header stored, so a minimum-difficulty fork taller than the real chain no
    longer stops transaction relay. The low-work headers are still stored
    until headers presync (#1132).
  • A coin or undo record whose ten-byte varint overflows 64 bits is refused
    as corrupt
    (#975) instead of decoding to a truncated value.
  • No forks below the last checkpoint (#1131). A new header below the
    highest checkpoint already in the block index is refused as
    bad-fork-prior-to-checkpoint and its sender banned, as in Core up to v29,
    so a peer can no longer fill the block index with cheap early-chain forks.
    Blocks that arrive without their header (submitblock, a pushed block)
    are held to the same rule; known headers are skipped, and -checkpoints=0
    turns it off. It covers mainnet and the default signet; testnet4, regtest
    and custom signets have no checkpoints. Core v30 dropped checkpoints for
    headers presync, which satd does not have yet (#1132).

Peers

  • A peer that sends an invalid block is disconnected and banned, as Core's
    MaybePunishNodeForBlock, IBD blocks included; noban and manual peers are
    kept, local ones only disconnected. Compact-block reconstructions,
    future-timestamp refusals and blocks this node could not store are not
    charged (#544).
  • A peer stalling IBD is disconnected (#972), as in Core, with a 15-second
    timeout that doubles per disconnect up to 64 seconds and returns to 15 as
    blocks connect. A peer counts as
    stalling only while another peer has delivered within the timeout, so a local
    link drop does not disconnect every peer; a peer silent for ten minutes is
    dropped regardless.
  • A node with a stale address book seeds itself (#974), as in Core: DNS
    seeds if fewer than two full-relay outbound peers are up after 11 seconds (5
    minutes with 1,000+ addresses), and fixed seeds a minute later if the book
    still has nothing reachable.
  • A dial through -proxy gives the SOCKS5 exchange 20 seconds (or
    -timeout if larger), as in Core; -timeout bounds only the connect to the
    proxy. .onion dials too.
  • An unroutable -externalip is not advertised, as Core's AddLocal:
    private, loopback, 100.64.0.0/10, documentation and (unlike Core)
    fc00::/8 addresses are left out of addr, version and
    getnetworkinfo's localaddresses.
  • P2P messages are read as Core reads them (#1142), on v1 and v2. A
    version that ends before relay (or any later optional field) is
    accepted with Core's defaults, so peers that omit it complete the
    handshake. Bytes after a message's last field are ignored, a sendcmpct
    flag byte other than 0 or 1 means true, and a feefilter outside
    MoneyRange is ignored and the previous filter kept.

Block relay

  • The tip is announced after a parallel-download catch-up; peers relying
    on satd's announcements stayed behind.

Privacy

  • -onlynet takes effect (it was ignored) for automatic outbound
    connections and kept gossip addresses, as in Core; inbound and manual
    connections are unaffected. Startup refuses
    -onlynet=onion without -proxy or -onion (unlike Core, -listenonion
    alone is not enough) or with -onion=0, -onlynet=cjdns without
    -cjdnsreachable, -onlynet=i2p (no I2P transport) and unknown networks.
    DNS seeding is off when IPv4 and IPv6 are excluded, and -dnsseed=1 with
    such an -onlynet is refused.
  • -proxy turns listening off by default, as in Core. -bind or
    -listen=1 keeps it; -listen=0 also disables -listenonion unless set.
  • -proxy=0 and -onion=0 mean "none", as in Core (-onion=0 blocks
    .onion even for manual peers); satd used 0 as an address.
  • Under -proxy, DNS seeds are resolved by the proxy (#994) over
    short-lived addr-fetch connections, as in Core; nothing goes to the local
    resolver and the startup warning is gone. -seednode host names are opened
    the same way (not under -connect), and getpeerinfo shows them by name
    with network not_publicly_routable. Host names in -addnode and
    -connect are still refused under -proxy.
  • The onion address survives a restart (#973): the key is kept in
    onion_v3_private_key in the network's data directory, as in Core. An
    upgrading node gets one last new address.
  • The hidden service comes back after Tor restarts (#973): the address is
    withdrawn while the control connection is down, and satd reconnects (backoff
    up to 10 minutes; unlike Core, also after authentication or ADD_ONION
    failures) and re-adds it with the same key. -externalip takes a v3 onion
    address
    (#973), advertised while the node has no service of its own up.
  • Files satd creates are readable by its own user only (umask(077)):
    new directories 0700, new files 0600; the RPC cookie follows
    -rpccookieperms. Existing files keep their modes until rewritten.
  • v2 (BIP 324) handshakes send 0 to 4095 random garbage bytes, as Core
    does; fixed sizes made satd's connections identifiable.

Health and readiness

  • Unknown soft forks are reported (#976), as Core does: a locked-in bit is
    logged, and an active one adds "Unknown new rules activated (versionbit N)"
    to the warnings of getblockchaininfo, getmininginfo and
    getnetworkinfo and fires -alertnotify.
  • /readyz notices a node that has lost its peers (#979): it is 503,
    naming the detector, while tip_stall (-alerttipstallseconds, default one
    hour) or peer_floor (-alertpeerfloor, default three, held a minute) is
    raised. Both are 0 on regtest; 0 excludes a detector.
  • -alertnotify runs for warnings raised during startup (#884), such as
    reindex.halted and reindex.short.

Address relay

  • getaddr is answered as Core answers it: inbound peers only, once per
    connection, from a per-listener sample of at most 23% of the address book
    (at most 1,000) cached about a day; addr-permission peers get a fresh one.
    -externalip addresses are announced to outbound peers at connect instead.
  • Address service bits follow the peer's version, as in Core.
  • One network group can no longer fill the tried table. Tried entries use
    Core's bucket/position slots (at most 8 of 256 buckets per group) with
    test-before-evict, and tried dials pick a bucket first. addpeeraddress … true into a taken slot answers failed-adding-to-tried. The placement key
    is appended to peers.dat (0.6.x still loads it); an existing file is
    re-placed under a fresh key, trimming each group to its share.
    getrawaddrman reports each entry's slot.
  • One peer can no longer fill the onion candidate list (512, in memory):
    at most 64 per source, and a full list evicts an entry terrible by Core's
    IsTerrible.
  • Outbound peers are asked for addresses, and dials spread over the book,
    as in Core: getaddr to every address-relaying outbound peer, seed
    addresses added to the book as new, dials drawn at random from tried or new,
    and addresses dialled in the last ten minutes skipped.
  • An addrv2 listing a node with a high service bit is read. Its
    services are read without a range check, as in Core, so one entry with
    bit 26 set no longer loses the whole message, and over v2 no longer drops
    the peer. A v2 packet that does not decode is now skipped, as on v1.

Block serving

  • A pruned node no longer claims to be a full node. Pruned nodes and nodes
    behind an AssumeUTXO snapshot advertise NODE_NETWORK_LIMITED without
    NODE_NETWORK; every node sets NODE_NETWORK_LIMITED, so an unpruned node
    reports localservices 0000000000000409 (plus NODE_P2P_V2 and
    NODE_COMPACT_FILTERS when on).
  • Blocks are served as Core serves them (BlockRequestAllowed): off-chain
    blocks only if validated and within 30 days of the best header. A pruned node
    disconnects a non-noban peer asking for a block more than 290 below its
    tip, and getblocks stops 282 below the tip.
  • Old blocks from limited peers that still hold them. A
    NODE_NETWORK_LIMITED peer that also advertises NODE_INTACT_BLOCKS (bit
    28, INTACT_BLOCKS in getpeerinfo) serves every intact block and answers
    notfound for the rest. satd now fetches old blocks from such peers (for
    peer-less getblockfrompeer, only without a NODE_NETWORK peer) but never
    seeks them out.

OP_RETURN data pruning

-pruneopreturn=<N> (off by default; minimum 288, 1 or all mean 288)
starts a worker that, below tip − N − 2, zeroes the payload of each
non-coinbase OP_RETURN output of at least -pruneopreturnsize bytes (default
4096; k/M and KiB/MiB suffixes accepted) and punches it out of the
block file (fallocate(PUNCH_HOLE) on Linux, F_PUNCHHOLE on macOS). Txids
and a hash of the zeroed block are stored first, so -reindex,
-reindex-chainstate and every surface keep real txids; blocks are still
fully validated. The worker pauses during IBD, reindex and AssumeUTXO
background validation, and startup fails if the filesystem cannot punch
holes. Only whole filesystem blocks are freed, so today's chain gives back
little (a 100 KB output frees about 96 KB); on APFS freeing the space is
best-effort, though the payload is gone either way. It is not a secure erase: copies,
snapshots, backups and the last 288 blocks keep the bytes.

A stripping node gives up:

  • Archive-peer status. It advertises NODE_NETWORK_LIMITED, not
    NODE_NETWORK, while any block is stripped, option on or off.
    -pruneopreturnpeers=limited (default) serves the last 288 blocks;
    =intact also serves intact blocks at any depth, advertises
    NODE_INTACT_BLOCKS and answers notfound for stripped ones.
  • Raw bytes of stripped transactions. getblock verbosity 0 returns
    Block not available (pruned data); getrawtransaction hex, Esplora /raw
    and /hex, and non-verbose Electrum blockchain.transaction.get refuse
    (Transaction data not available (OP_RETURN data stripped) over RPC). JSON
    views mark the transaction opreturn_stripped and show each stripped script
    as bare OP_RETURN with its original size. Streaming rescan events
    (ScriptMatched, PrefixMatched, SilentPaymentMatched) carry
    raw_tx_stripped instead of raw_tx; PrefixMatched now always carries
    txid.
  • Deep reorgs. A reorg or invalidateblock that would disconnect a
    stripped block fails, naming it, and changes nothing.
  • Script re-verification on -reindex for stripped transactions' inputs.

getopreturnpruneinfo reports configuration, worker state, progress and
totals, also under getblockchaininfo's opreturn_prune; Prometheus gets
satd_opreturn_* metrics and sat-tui op-prune and op-restore columns.
getblockfrompeer restores one block in place (re-stripped on the next pass
if the option is on). With the option off, restoring the last stripped block
makes the node a full node again without a restart and removes the strip
column family.

-restoreopreturns, with every -pruneopreturn* option removed (it is
refused alongside them), re-downloads all stripped blocks and writes them back
in place, resuming after a restart. It asks only connected NODE_NETWORK +
NODE_WITNESS peers (16 blocks per peer, 1024 in flight, 15-second timeout,
no re-ask after notfound), restores newest first on a pruning node, and waits
while the tip is behind, no full peer is connected, or the blocks volume lacks
the room needed plus 1 GiB. When it finishes the node advertises
NODE_NETWORK again and the log says the option can be removed. Progress and
ETA appear under getopreturnpruneinfo's restore and in
satd_opreturn_restore_* metrics. On a synced mainnet node pruned with
-pruneopreturn=all -pruneopreturnsize=84, restoring re-downloaded 11,184
blocks, 18.0 GB, in 29 minutes from 3 to 7 peers.

The Rust and Go event clients mark a stripped prefix hit
outputs_unavailable / OutputsUnavailable (reported by has_unresolved /
HasUnresolved); their new public struct fields break Rust code that builds
them with literals. See
the Operator Manual.

Mempool policy

  • submitpackage does package CPFP (#984), as Core's AcceptPackage: a
    member refused alone only for feerate is judged with its paying child by
    combined feerate (shared effective-feerate, effective-includes); a short
    package is refused on the child with min relay fee not met or
    mempool min fee not met. The pool is trimmed after the whole package is in
    (a trimmed member reports mempool full), eviction ranks by descendant
    score, and an ephemeral dust parent's child now pays for both.
  • TRUC (BIP 431) for version 3 transactions (#1020), as Core: at most one
    unconfirmed parent and one child, at most 10,000 vbytes (1,000 with an
    unconfirmed parent), only v3 may spend unconfirmed v3, always replaceable. A
    second child may evict the first (refusal
    insufficient fee (including sibling eviction)); other violations are
    TRUC-violation, in package_msg within a package. Reorg-returned
    transactions are exempt; mempool.dat reloads are not. Replacement checks
    now follow the fee floor, so a replacement below it is refused for its fee.
  • Cluster limits: Core v31's -limitclustercount (default and maximum 64)
    and -limitclustersize (default 101 kvB, sigop-adjusted; was an unknown
    option) bound the whole connected cluster, refusing as too-large-cluster
    (satd counted only ancestors). The size also sets the -maxmempool floor
    (40 clusters). After a reorg, oversized clusters are trimmed as Core's
    TxGraph::Trim, reported as reorg evictions.
  • Replacements are judged by full cluster feerate diagrams, as Core v31.
    Some bumps Core accepts now pass; some satd accepted, such as evicting a
    well-paying child, are refused. satd linearizes greedily, so large clusters
    can differ from Core at the margin (see
    CORE_DIFFERENCES.md).
  • Package RBF, as Core v31: a parent and child with no in-mempool parents
    can replace together if they pay the evicted fees plus their own relay, beat
    the parent's feerate, conflict with at most 100 clusters and improve the
    diagram. Refusals go in package_msg (package RBF failed: …); nothing is
    evicted until both are fully checked.
  • Multi-transaction testmempoolaccept is a package evaluation, as Core's
    AcceptMultipleTransactions: transactions may spend earlier ones, replacing
    mempool transactions is bip125-replacement-disallowed, set-wide TRUC or
    cluster violations are each one's package-error, a child must spend its
    parents' ephemeral dust, and the first refusal stops evaluation. Feerates
    are still per transaction. txn-already-known now carries reject-details.
  • Core's script policy. The mempool runs Core's PolicyScriptChecks
    (STANDARD_SCRIPT_VERIFY_FLAGS, Rust engine, any -consensus) and refuses
    spends of soft-fork upgrade hooks, non-standard signatures and pushes,
    unrecognised output types, P2SH with more than 15 sigops, inputs over BIP
    54's 2500 legacy sigops, bloated witnesses, and sigop cost above 16000, with
    Core's reasons (mempool-script-verify-flag-failed (...),
    bad-txns-nonstandard-inputs, bad-witness-nonstandard,
    bad-txns-too-many-sigops), on mempool.dat reload too.
    -acceptnonstdtxn lifts only the input checks; relaying peers are not
    penalised.
  • -bytespersigop takes effect (default 20; was ignored): mempool
    feerates, reported vsize and template ranking use Core's sigop-adjusted
    size. weight is unchanged.
  • Ephemeral dust package parents are checked for output standardness and
    by the transaction policy (policyfile=): a local one the rules would
    quarantine is refused, a peer's is held with its child, and one spending
    another package member is refused if it carries a prioritisetransaction
    delta, as Core's PreCheckEphemeralTx. Their entry time follows the node
    clock (#981).
  • prioritisetransaction deltas for absent transactions survive a restart
    (#981) in mempool.dat; the file version is unchanged and older satd
    ignores them.

Transaction relay

  • A parent and its child are relayed together (Core's opportunistic
    1-parent-1-child relay): a fee-refused parent from a peer is retried with a
    child the same peer sent, judged as submitpackage judges it. A failed pair
    is not retried before the next block.
  • Every peer announcing an orphan is recorded and asked for its parents.
  • The orphanage is limited as Core v30's is, replacing the 100-orphan,
    50-per-peer, 20-minute limits: a latency-score limit of 3,000 and 404,000 WU
    per announcing peer, enforced by evicting the highest-DoS-score peer's
    announcements. Orphans no longer expire and are keyed by wtxid, so a
    malleated copy cannot block the real one; getorphantxs lists in wtxid order.
  • Transactions are announced on Core's schedule, from per-peer queues on
    Poisson timers averaging 2 seconds outbound and 5 inbound, at most 70 per
    inv (up to 1000 for long queues); noban peers are not delayed. A request
    for an unannounced transaction gets notfound, except one from the most
    recent block or returned by a reorg, and a BIP 35 mempool request is
    answered with the peer's next announcement. New txannouncedelay=0
    (satd extension, reloadable) announces at once, giving up that privacy.
    getpeerinfo's inv_to_send and last_inv_sequence are now filled in.
  • An announced transaction is downloaded once, as Core's
    TxRequestTracker: one request in flight per transaction, outbound peers
    preferred, inbound and txid announcements delayed 2 seconds, 60-second
    timeout, at most 5000 tracked announcements per peer without the relay
    permission. Waits follow setmocktime.
  • A refused transaction is not fetched again. The last 120000 refusals
    are remembered by wtxid until the tip moves, as in Core; fee-only refusals
    go to a separate filter so a paying child can still bring them in.

Core functional tests that now pass against satd: mempool_limit.py,
mempool_truc.py, mempool_package_limits.py, mempool_package_rbf.py,
p2p_opportunistic_1p1c.py, mempool_reorg.py, p2p_leak_tx.py,
rpc_orphans.py, p2p_1p1c_network.py and
rpc_signmessagewithprivkey.py.

RPC

  • gettxoutsetinfo refuses the arguments it cannot honour (#896) instead
    of ignoring them: a hash_or_height other than the tip fails with Core's
    no-coinstatsindex error (-8), and hash_type muhash or
    hash_serialized_3 fails by name (-8).
  • verifybip322 (satd's own) verifies BIP 322 signatures (smp, ful or
    unprefixed) for any address type, answering valid, inconclusive or
    invalid; pof is unsupported. Its legacy/P2SH MINIMALIF flag cannot be
    set by block or mempool validation.
  • verifymessage and signmessagewithprivkey, Core's legacy P2PKH message
    signing, byte-compatible with Core.
  • getorphantxs (Core's hidden RPC, verbosity 0–2).
  • getorphaninfo adds announcements, latency_score,
    max_latency_score, weight and max_weight; max_size now holds the
    latency limit.
  • getblock and getrawtransaction answer as Core v31's do (#978):
    getblock adds strippedsize and coinbase_tx; getblock verbosity 2
    adds each transaction's fee and verbosity 3 each input's prevout, and
    getrawtransaction verbosity 2 its fee and prevout, all read from undo
    data so no -txindex is needed; a coinbase input shows txinwitness.
    Fields Core lacks are removed (see Upgrade notes).
  • gettxspendingprevout, as Core v31, served from the address index's
    spend rows. -txospenderindex (previously ignored) enables block lookups,
    requires -addressindex and is refused with pruning. Unlike Core, a spender
    in a block removed by invalidateblock disappears at once.
  • getrawmempool lists in Core's mining order (best chunks first),
    matching Core wherever satd linearizes the same way; it was hash-map order.
    Verbose keys stay sorted by txid.
  • gettxout's scriptPubKey adds desc, address and type, and
    type follows Core's Solver everywhere (pubkey, multisig,
    anchor, witness_unknown instead of nonstandard; nulldata only for
    push-only scripts).

Node attestation

satd can publish and collect Node Attestation Protocol (NAP) attestations:
non-binding statements signed by Bitcoin holders, one key-value pair per coin,
weighted by the coin's value while it stays unspent. The manual's
Node Attestation chapter covers
signing with each kind of wallet, the privacy costs and the statuses.

  • -nap=1 (off by default) publishes. The store is
    <datadir>/nap/attestations.dat plus an append-only
    attestations.journal; an unreadable store stops startup unless
    -napstorerecover=1, which renames both with a .bad-<unix time> suffix
    and starts empty. -napmaxattestations=<n> caps it (default no limit;
    store-full at the cap).
  • createnapattestation "<txid>:<vout>" "key" "value" ( "descriptor" )
    returns the text and a BIP 322 to_sign PSBT, anchored 6 blocks below the
    tip, for a coin of at least 10,000 sats and 4,032 blocks of age (6 on test
    networks; coinbase coins wait for maturity).
  • submitnapattestation "message" "signature" takes BIP 322 signatures,
    legacy signmessage for P2PKH, a signed to_sign transaction or a signed
    PSBT. Refusals are -26 naming the rule (stale, coin-too-small, …). One
    attestation per coin and key, at most 32 keys per coin.
    listnapattestations and removenapattestation manage them.
  • Serving. A publisher advertises NODE_NAP (bit 30, NAP in
    getnetworkinfo) and answers getnapatt in 1 MB pages: one pull per
    connection per 10 minutes, 200 MB an hour (eight times that per network
    group); over-limit requests are ignored, malformed ones are misbehaviour. It
    never sends NAP messages unasked, so Core peers are unaffected. Stale
    attestations and ones whose anchor a reorg removed are kept but not served.
  • Aggregating. -napaggregator=1 (off by default, independent of -nap)
    pulls from NODE_NAP peers at connect and hourly, and over new short
    nap-pull connections that take no outbound slot, with budgeted
    verification (5,000 per pull, 1,000,000 an hour). It keeps at most 256 keys
    per coin and -napaggregatormax attestations (default 1,000,000) in
    <datadir>/nap/aggregate/aggregate.dat; listnapaggregate lists them.
  • Reports. getnapreport (rpc:read) gives each key's weight per
    value, in integers. exportnapsnapshot and replaynapsnapshot
    (rpc:write) let any node reproduce a published report byte for byte.

Electrum and Esplora

  • Electrum subscription caps fit a desktop wallet.
    -electrummaxsubsperconn defaults to 10,000 (was 1000) and the shared
    -addrindexsubscriptions registry to 50,000 (about 230 MB when full);
    explicit values are kept. Subscribing no longer sweeps the registry each
    time.
  • A backfilled address index leaves out unspendable outputs, as a live one
    does; rows from an earlier backfill need no action.
  • A scripthash's history is capped by the work it costs. Electrum
    get_history, get_balance, listunspent and subscribe, and Esplora
    address and scripthash stats, /utxo and /sse, stop reading at the cap
    instead of loading the whole history. Electrum answers code 2,
    history too large (cap = 200000 entries); a refused subscribe is not
    kept, and a subscription that grows past the cap stops notifying. Esplora
    answers 400 Too many history entries (more than 200000 transactions).
    As-of answers built from history are under the same cap; get_first_use
    and paged /txs routes are not. New -addrindexmaxhistory=<n> (default
    200000; 0 for no cap) sets it.
  • Esplora responses name their chain tip in X-Bitcoin-Chain-Tip and
    X-Bitcoin-Chain-Tip-Height (mempool/mempool#6584, as rbitcoin serves).
    Each request answers for the tip it started at and is rerun after a
    disconnect; eight in a row answer 503 chain view moved. Mempool and fee
    routes, POST /tx, /txs/mempool and SSE carry no headers; -esploracors
    exposes them.
  • Esplora ?asof=<blockhash>, with rbitcoin's rules, answers address,
    scripthash, /txs, /utxo, tx status and outspend routes as of a block on
    the best chain, without the mempool. A hash not on the best chain, a
    malformed asof, or asof on another route is 404.
  • Electrum answers name their chain tip in chain_tip and
    chain_tip_height beside result on blockchain.scripthash.get_history,
    get_balance, listunspent and blockchain.transaction.get, get_merkle,
    id_from_pos, as rbitcoin does (server.features: "chain_tip": true),
    with the same rerun rule (error chain view moved). server.version
    accepts and echoes rbitcoin's 1.4.2-asof; the protocol is still 1.4.
  • Electrum trailing asof:<blockhash> (rbitcoin's argument) on the same
    six methods answers as of that block without the mempool; a hash off the
    best chain is asof not on chain. satd does not require 1.4.2-asof
    negotiation; server.features reports "asof": true and
    "asof_protocol": "1.4.2-asof". Clients must check asof there first:
    older servers may read asof:… on transaction.get, get_merkle or
    id_from_pos as a false flag and answer live.

Shutdown

  • Shutdown waits for running RPC calls (#983), as Core's Shutdown(), for
    a quarter of the remaining -maxshutdownsecs; a call still running costs the
    clean-shutdown marker, not the flush. generatetoaddress and
    generatetodescriptor return the blocks mined so far, the waitfor* calls
    return the current tip, and a long-polling getblocktemplate fails with
    -9 "Shutting down".

Mining

  • getblocktemplate's mintime and curtime take the BIP 94 retarget
    floor on every network
    , as Core's GetMinimumTime; on testnet4 a block at
    the advertised mintime could fail as a timewarp. Stratum shares and Job
    Declaration jobs below the floor are refused.
  • getblocktemplate on mainnet waits for peers and IBD, with Core's
    RPC_CLIENT_NOT_CONNECTED (-9) and RPC_CLIENT_IN_INITIAL_DOWNLOAD (-10).
    Test chains and proposal mode are not gated.
  • getblocktemplate transactions carry Core's hash (wtxid) and
    depends
    (#982); gateways that need them, such as OCEAN's DATUM gateway,
    refused every non-empty template.

Configuration

  • List options take both sources (#995). Core's list options (bind,
    whitebind, connect, addnode, seednode, rpcbind, rpcallowip,
    rpcauth, whitelist, externalip, onlynet, signetseednode,
    signetchallenge, debug, debugexclude, loglevel) now merge the command
    line and bitcoin.conf, command line first, as in Core; a trailing negation
    (-noconnect) still drops the file's values. satd's own list options are
    unchanged.
  • The getaddr answer cache follows setmocktime.
  • -maxmempool below 5 MB is refused with Core's
    -maxmempool must be at least 5 MB; 0 is still allowed.

Terminal dashboard

  • A NAP view on key 5 when -nap or -napaggregator is on: published
    attestations and the getnapreport breakdowns.
  • The services row is yellow wherever work is pending (backfills,
    restores); green means done or serving.
  • The mempool view (3) has a Quarantine panel while a policy is loaded
    (held transactions against the quarantinemempool budget, foregone fees, a
    per-rule table); the steady view's Txs line adds the held count.

TLS clients

  • -rpccacert replaces the public roots instead of adding to them in
    sat-cli and sat-tui, so a mis-issued public certificate for the node's
    hostname can no longer receive RPC credentials. Without -rpccacert the
    public roots still apply. Also shipped in 0.6.3.

Dependencies

  • bitcoin 0.32.102 (from 0.32.9), which drops 0.32.9's CompactSize range
    check. satd reads P2P payloads with its own Core-compatible reader, since
    0.32.10 and later refuse some messages Core accepts.
  • rustls-webpki 0.103.16 (RUSTSEC-2026-0382), webpki-roots and
    webpki-root-certs 1.0.10 (RUSTSEC-2026-0381, -0383), as in 0.6.2, for the
    distrusted emSign intermediates.
  • tokio 1.54.1 (RUSTSEC-2026-0386); satd does not use the affected
    AsyncFd constructors.
  • zstd-sys 2.1.2 (RUSTSEC-2026-0410); the advisory is wasm32-only and no
    satd build was affected.

Upgrade notes

  • Headers that fork below the last checkpoint are refused (see Block
    validation), and the peer that sent them is banned. This covers mainnet
    and the default signet; -checkpoints=0 turns it off.

  • Peers satd used to refuse are now accepted (see Peers and Address
    relay): a version without relay, trailing bytes after a message, an
    addrv2 entry with a high service bit. An undecodable v2 packet is
    skipped instead of dropping the peer. No action is needed.

  • gettxoutsetinfo with a historical hash_or_height, or with
    hash_type muhash or hash_serialized_3, now fails
    with -8 (see
    RPC). It used to answer with the tip's stats. Call it with no arguments,
    or with hash_type "none", to get the tip's.

  • -rpccacert is now the only trust anchor for sat-cli and
    sat-tui (see TLS clients). An invocation that names a private CA but
    connects to a node whose certificate a public CA issued now fails the
    handshake. Drop -rpccacert for such a node, or point it at the public
    CA's root or intermediate.

  • Transactions reach peers a few seconds later (see Transaction
    relay): 2 seconds on average for outbound peers and 5 for inbound, as in
    Core. Tooling that expects a transaction on a peer the instant it enters
    this node's mempool should wait for it, give the peer noban, or set
    txannouncedelay=0.

  • The mempool bounds each transaction's whole cluster (see Mempool
    policy). A transaction joining a cluster of 64 is refused as
    too-large-cluster, however its relatives are arranged; before, only its
    ancestors counted. Software that hangs many children off one unconfirmed
    parent (a batch payout spending its own change) sees the 64th refused, as
    on Core v31.

  • Some replacements satd used to accept are now refused (see Mempool
    policy, "Replacements in larger clusters"). A replacement that evicts a
    conflict's high-feerate descendants must now improve the whole cluster,
    as on Core v31. The cluster order satd uses is an approximation of
    Core's, so on large clusters the two can differ at the margin.

  • getblock, getrawtransaction and decoderawtransaction drop the
    fields Core does not have
    (see RPC). Software reading them must change:

    • getrawtransaction no longer has blockheight; read the height from
      getblockheader <blockhash>.
    • A mempool transaction no longer has "confirmations": 0: the field
      is absent, as in Core.
    • At verbosity 2, a mempool transaction has no fee or prevout, as in
      Core; getmempoolentry has its fees.
    • Transactions inside getblock no longer carry blockhash,
      blockheight, confirmations, time or blocktime.
    • decoderawtransaction no longer echoes the transaction's hex.
  • A node with -proxy and no explicit -listen stops accepting inbound
    connections
    , and without an explicit -listenonion it stops publishing
    its hidden service. To keep either, set listen=1 (and listenonion=1).

  • Configs with -onlynet may now refuse to start, with Core's message,
    where they combine options Core refuses (see Privacy).

  • A -maxmempool between 1 and 4 now stops the node from starting (see
    Configuration). Raise it to at least 5.

  • Sigop-dense transactions cost more to relay. A transaction whose sigop
    cost times 20 exceeds its weight now needs a fee for that larger size, and
    its reported vsize grows to match.

  • The mempool refuses non-standard scripts. A transaction Core's
    mempool would refuse for its scripts or what it spends is now refused by
    satd's, including one loaded from an existing mempool.dat. Send such
    spends to a miner directly.

  • A pruned node advertises NODE_NETWORK_LIMITED instead of
    NODE_NETWORK.
    Peers that need the whole chain stop syncing from it, and
    a peer asking it for a block more than 290 below its tip is disconnected.

  • A list option set in both bitcoin.conf and on the command line now
    takes both
    (see Configuration). Check a command line that repeats a
    bind, rpcbind, connect or addnode from the config file: the node now
    gets the union, and a duplicate bind or whitebind stops startup.

  • New files in the data directory are 0600, and new directories 0700,
    as in Core (see Privacy). If another account reads satd's files, grant it
    access explicitly. For the RPC cookie, use -rpccookieperms=group or
    all.

  • Electrum and Esplora refuse scripthashes with more than 200,000
    transactions
    for requests whose cost follows the whole history (see
    Electrum and Esplora): Electrum get_balance, listunspent and
    subscribe (as get_history already did), Esplora address stats, /utxo
    and /sse. Esplora's /txs/chain pages still serve such a history, and
    -addrindexmaxhistory raises or removes the cap.

  • -zmqpub* options now take effect. zmqpub* lines carried over from
    Bitcoin Core, ignored with a warning before, now bind at startup. If a Core
    node on the same machine still holds an address, satd logs the bind failure
    and runs with ZMQ off, as Core would; remove the lines if you do not want
    satd publishing.

  • A datadir that has used -pruneopreturn cannot be opened by satd
    0.6.x or earlier
    (RocksDB reports Column families not opened: opreturn_strip). This is deliberate: older versions would misread the
    zeroed data. Turning the option off restores nothing; -restoreopreturns
    downloads the stripped blocks again, and getblockfrompeer brings back
    one.


About this release

satd is free software under the MIT License.

  • Stability & compatibility — Tier 1 surfaces (Bitcoin Core-compatible
    JSON-RPC wire shape, CLI flag names/defaults, bitcoin.conf keys, on-disk
    layout, Electrum/Esplora surfaces) are governed by
    STABILITY_POLICY.md. satd follows
    semantic versioning; while in the
    0.x pre-1.0 line, deprecations may be accelerated (see the policy).
  • Security & disclosure — report vulnerabilities per
    SECURITY.md. Consensus-affecting bugs are treated as
    P0 with same-day acknowledgement.
  • Verifying this release — tarballs are signed with minisign, container
    images with cosign (keyless OIDC), and git tags with SSH signatures (no GPG).
    The key matrix and verification steps are in
    SECURITY.md.
  • Intentional differences from Bitcoin Core — catalogued in
    CORE_DIFFERENCES.md.
  • Operating satd — observability, the full flag matrix, tuning, and the
    downstream packaging contract live in the
    Operator Manual.

What's Changed

  • packaging: pin the Umbrel and StartOS packages to satd 0.6.0 by @bkeroack in #905
  • Forward-port 0.6.0 to master and open the 0.7.0 cycle by @bkeroack in #901
  • Forward-port #898 and #899 (WatchAddRejected) to master by @bkeroack in #910
  • Forward-port #919 (Go e2e flake) and #913 (release-branch CI) to master by @bkeroack in #920
  • Forward-port #912, #917 and #911 (0.6.1 IBD and drain fixes) to master by @bkeroack in #921
  • Forward-port #923 (getrawaddrman keeps a colliding address in its bucket) to master by @bkeroack in #925
  • Forward-port #914 and #915 (0.6.1 StartOS fixes) to master by @bkeroack in #926
  • Forward-port #927 (reindex scan reads block headers only, #916) to master by @bkeroack in #928
  • Bitcoin Core-compatible ZMQ notifications (-zmqpub*) by @bkeroack in #929
  • Forward-port #932 (genesis append, #931) and #930 (StartOS RUST_LOG) to master by @bkeroack in #934
  • Announce a package's ephemeral-dust parent before its child by @bkeroack in #935
  • deps: rustls 0.23.46 by @bkeroack in #967
  • Forward-port the 0.6.1 fixes to master by @bkeroack in #964
  • Release notes: 0.6.1 on master by @bkeroack in #968
  • packaging: pin the Umbrel package to satd 0.6.1 by @bkeroack in #969
  • docs: correct four statements the code contradicts (#980) by @bkeroack in #988
  • chain: apply Core's contextual header and block checks before indexing and storing by @bkeroack in #985
  • chain: -assumevalid skips scripts only under Core's conditions; honour -minimumchainwork by @bkeroack in #986
  • net: charge the sender of an invalid block, including one judged by the IBD connector (#544) by @bkeroack in #987
  • net: announce the tip a catch-up reaches by @bkeroack in #997
  • storage: refuse a ten-byte varint that does not fit in a u64 (#975) by @bkeroack in #989
  • chain: BIP30's buried-BIP34 skip as Core applies it; cpp engine needs one spent output per input by @bkeroack in #990
  • rpc: getblocktemplate transactions carry Core's hash and depends (#982) by @bkeroack in #991
  • net: apply -onlynet, -proxy's -listen soft-set, and -proxy=0 / -onion=0 as Core does by @bkeroack in #992
  • metrics: /readyz is 503 while tip_stall or peer_floor is raised (#979) by @bkeroack in #993
  • net: answer getaddr as Core does by @bkeroack in #996
  • mempool: apply Core's script policy by @bkeroack in #998
  • net: remember refused transactions until the tip moves by @bkeroack in #1001
  • mempool: price transactions at Core's sigop-adjusted size by @bkeroack in #1000
  • net: serve blocks as Core does by @bkeroack in #1003
  • rpc: shutdown waits for running calls before the flush (#983) by @bkeroack in #1004
  • chain: invalidateblock disconnects to the parent before it activates (#977) by @bkeroack in #1005
  • net: disconnect a peer stalling initial block download (#972) by @bkeroack in #1006
  • mempool: persist out-of-pool fee deltas; a dust parent's time follows mocktime (#981) by @bkeroack in #1007
  • config: merge list options from the command line and bitcoin.conf (#995) by @bkeroack in #1008
  • net: seed the address book after startup, as Core does (#974) by @bkeroack in #1009
  • canary: read the Stratum V1 smoke's start height before the miner starts by @bkeroack in #1010
  • tor: keep the hidden service's key so its address survives a restart (#973) by @bkeroack in #1011
  • chain: warn about unknown version-bits soft forks, as Core does (#976) by @bkeroack in #1012
  • init: set Core's umask(077) at startup by @bkeroack in #1013
  • tests: give the harness's RPC client a minute and stop() thirty seconds by @bkeroack in #1014
  • config: accept a v3 onion -externalip and advertise it (#973) by @bkeroack in #1015
  • tor: reconnect to the control port and withdraw the onion while it is down (#973) by @bkeroack in #1016
  • rpc: getblock and getrawtransaction answer with Core v31's fields (#978) by @bkeroack in #1018
  • mining: getblocktemplate mintime takes Core's BIP 94 retarget floor by @bkeroack in #1017
  • mempool: package CPFP in submitpackage (#984) by @bkeroack in #1019
  • mempool: TRUC (BIP 431) policy for version 3 transactions by @bkeroack in #1021
  • mempool: cluster limits on admission, and -limitclustersize by @bkeroack in #1025
  • mempool: RBF diagrams over the clusters a replacement touches by @bkeroack in #1027
  • rpc: a multi-transaction testmempoolaccept is evaluated as a package by @bkeroack in #1028
  • chain: a custom signet drops the default signet's checkpoints and assumevalid by @bkeroack in #1022
  • ibd: judge a peer stalling only while another peer is delivering by @bkeroack in #1024
  • net: request an announced tx from one peer at a time, as Core's TxRequestTracker by @bkeroack in #1026
  • index: bound scripthash history work and refuse oversized histories by @bkeroack in #1023
  • consensus: build the BIP 341 signature message from precomputed hashes by @bkeroack in #1032
  • consensus: run rbitcoin's Core-checked script corpus by @bkeroack in #1033
  • rpc: gettxspendingprevout, with -txospenderindex served by the address index by @bkeroack in #1030
  • mempool: package RBF in submitpackage, as Core's PackageRBFChecks by @bkeroack in #1031
  • mempool: trim clusters a reorg grows past the limits; getrawmempool in mining order by @bkeroack in #1034
  • net: Core's opportunistic 1-parent-1-child package relay by @bkeroack in #1035
  • net, rpc: getorphantxs, and every announcer of an orphan is recorded by @bkeroack in #1036
  • net: the orphanage has Core v30's limits and keys orphans by wtxid by @bkeroack in #1037
  • net: transaction announcements trickle as Core's do by @bkeroack in #1038
  • sat-tui: show the quarantine class while a filtering policy is loaded by @bkeroack in #1039
  • deps: rustls-webpki 0.103.16, webpki-roots and webpki-root-certs 1.0.10 by @bkeroack in #1041
  • sat-cli, sat-tui: -rpccacert is the only trust anchor by @bkeroack in #1044
  • rpc: verifymessage and signmessagewithprivkey, as Core's by @bkeroack in #1040
  • rpc: verifybip322, BIP 322 message verification on satd's interpreter by @bkeroack in #1042
  • packaging: pin the Umbrel and StartOS packages to satd 0.6.2 by @bkeroack in #1045
  • nap: attestation types, encodings and validity at a tip by @bkeroack in #1046
  • packaging: pin the Umbrel and StartOS packages to satd 0.6.3 by @bkeroack in #1049
  • nap: publisher, attestation store and RPCs (-nap) by @bkeroack in #1048
  • net: send random BIP 324 garbage in the v2 handshake by @bkeroack in #1050
  • events: refuse hardened derivation steps in watch descriptors by @bkeroack in #1052
  • nap: sign attestations through BIP 322's to_sign PSBT (N5) by @bkeroack in #1051
  • nap: a 6-block coin age on the test networks by @bkeroack in #1053
  • nap: submitnapattestation takes the signed to_sign transaction in hex by @bkeroack in #1054
  • ci: run the test suites in parallel and keep the canary caches on master by @bkeroack in #1055
  • ci: save the large caches from master only, never from pull requests by @bkeroack in #1056
  • ci: the release dry-run's Docker build saves its cache off pull requests only by @bkeroack in #1057
  • docker: delete target/ in the final build step, so its layer stays small by @bkeroack in #1058
  • ci: install the Linux build deps from a cache of the .deb files by @bkeroack in #1059
  • nap: test against signatures real wallets made on signet by @bkeroack in #1060
  • Core parity: SOCKS5 dial budget, getblocktemplate gate, gettxout script fields, unroutable -externalip by @bkeroack in #1062
  • deps: tokio 1.54.1 for RUSTSEC-2026-0386 by @bkeroack in #1064
  • nap: serve attestations over P2P (NODE_NAP bit 30, getnapatt/napatt) by @bkeroack in #1061
  • ci: raise the block-differential fuzz timeout to 100 minutes by @bkeroack in #1074
  • ci: nightly mutation testing (cargo-mutants) of the consensus-critical code by @bkeroack in #1063
  • ci: fuzz every self-contained fuzz target nightly by @bkeroack in #1065
  • ci: nightly coverage report (cargo-llvm-cov), counting the satd processes tests spawn by @bkeroack in #1073
  • net: address services follow the peer's version and add up over gossip by @bkeroack in #1077
  • nap: the aggregate set and cheapest-first intake (N7a) by @bkeroack in #1078
  • nap: collect attestations from publishers over P2P (N7b) by @bkeroack in #1079
  • nap: a minimum coin value of 10,000 sats by @bkeroack in #1080
  • ci: report a nightly run whose runner died before its triage step by @bkeroack in #1081
  • nap: the signed message starts "NAP attestation v1" by @bkeroack in #1082
  • ci: split the nightly mutation shard into parallel parts, retry lost ones by @bkeroack in #1084
  • nap: getnapreport and exportnapsnapshot by @bkeroack in #1083
  • nap: stream the snapshot digest and file writes (N9) by @bkeroack in #1086
  • sat-tui: a NAP view on key 5, offered only while the node has NAP on (N9) by @bkeroack in #1085
  • nap: budget measurements; verify up to 1,000,000 signatures an hour (N9) by @bkeroack in #1087
  • nap: the publisher records each change in a journal, not a rewrite of its store by @bkeroack in #1088
  • bip322: a valid proof runs its scripts once by @bkeroack in #1089
  • nap: split reports, snapshots and replays between threads by @bkeroack in #1090
  • index: address backfill skips unspendable outputs, as the live path does by @bkeroack in #1093
  • storage: hole-punch module and filesystem probe by @bkeroack in #1092
  • deps: zstd-sys 2.1.2 for RUSTSEC-2026-0410 by @bkeroack in #1095
  • mutants: stop a runaway mutant taking the runner down by @bkeroack in #1091
  • storage: OP_RETURN strip record, span parser and StoredBlock by @bkeroack in #1094
  • net: download old blocks from NODE_INTACT_BLOCKS peers when connected to one by @bkeroack in #1096
  • storage: OP_RETURN strip records in the store, and a fail-closed get_block by @bkeroack in #1097
  • storage: strip one block's OP_RETURN payloads (strip_block), and a test-only stripopreturns RPC by @bkeroack in #1098
  • rpc: serve OP_RETURN-stripped blocks from their strip record by @bkeroack in #1099
  • chain: replay OP_RETURN-stripped blocks from their strip record by @bkeroack in #1100
  • tests: cover 16 mutants the nightly mutation run missed (shard 5/42) by @bkeroack in #1101
  • esplora: pin each chain read to its starting tip and name it in X-Bitcoin-Chain-Tip headers by @bkeroack in #1102
  • esplora: answer as of a best-chain block with ?asof= by @bkeroack in #1103
  • electrum: pin chain reads to the starting tip and name it in chain_tip by @bkeroack in #1108
  • electrum: answer as of a best-chain block with a trailing asof: by @bkeroack in #1109
  • config: parse the CLI on a 16 MiB thread, and three mempool limits into PolicySizeArgs by @bkeroack in #1112
  • esplora, electrum: serve OP_RETURN-stripped blocks from their strip record by @bkeroack in #1104
  • index: backfill the address, filter and silent-payment indexes over OP_RETURN-stripped blocks by @bkeroack in #1105
  • events: match OP_RETURN-stripped blocks by their recorded txids, and never ship their bytes by @bkeroack in #1106
  • chain, tools: fail closed on OP_RETURN-stripped blocks in reorgs, invalidateblock and the offline tools by @bkeroack in #1107
  • chain: restore an OP_RETURN-stripped block in place through getblockfrompeer by @bkeroack in #1110
  • storage: -pruneopreturn, the background strip worker, getopreturnpruneinfo by @bkeroack in #1111
  • storage: a node that restores its last stripped block is NODE_NETWORK again by @bkeroack in #1113
  • net: -restoreopreturns downloads the stripped blocks again and makes the node NODE_NETWORK by @bkeroack in #1114
  • sat-tui: OP_RETURN pruning and its restore in the services row by @bkeroack in #1115
  • OP_RETURN restore: no per-block INFO line, no empty last pass by @bkeroack in #1116
  • p2p: ask outbound peers for addresses, and spread automatic dials over the book by @bkeroack in #1118
  • sat-tui: op-prune column, and yellow wherever work is pending by @bkeroack in #1117
  • test: sort dials before comparing in the outbound-group netgroup test by @bkeroack in #1129
  • alertnotify: run for warnings raised during startup (#884) by @bkeroack in #1123
  • electrum: default subscription caps a desktop wallet fits in (#1121) by @bkeroack in #1126
  • p2p: under -proxy, reach the DNS seeds and -seednode names through it (#994) by @bkeroack in #1128
  • addrman: a tried table with Core's slots, a per-group bound and test-before-evict by @bkeroack in #1127
  • p2p: bound each source's share of the onion candidate list, and evict terrible onions by @bkeroack in #1130
  • gettxoutsetinfo: refuse hash_or_height / hash_type values it cannot honour (#896) by @bkeroack in #1125
  • docs: condense the 0.7.0 release notes to fit a GitHub release by @bkeroack in #1134
  • Header tip is the most-work header, not the highest one stored (#1119) by @bkeroack in #1124
  • Refuse headers that fork below the last checkpoint (#1131) by @bkeroack in #1133
  • Read addrv2 services as Core does; skip an undecodable v2 packet by @bkeroack in #1136
  • ci: nightly live-peer smoke against testnet4 and signet by @bkeroack in #1137
  • Bump bitcoin to 0.32.102; read P2P payloads as Core does by @bkeroack in #1143
  • storage: on macOS, zero the punch range's edges before punching it by @bkeroack in #1141
  • contrib: remove push-relay files re-added by #1097 by @bkeroack in #1147
  • ci: build rbitcoin over a restored cache without cloning by @bkeroack in #1151
  • docs: NAP protocol specification (draft) by @bkeroack in #1075
  • chore(release): cut 0.7.0 by @bkeroack in #1146

Full Changelog: v0.6.3...v0.7.0