From mboxrd@z Thu Jan 1 00:00:00 1970 Delivery-date: Tue, 05 May 2026 18:28:25 -0700 Received: from mail-oi1-f187.google.com ([209.85.167.187]) by mail.fairlystable.org with esmtps (TLS1.3) tls TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256 (Exim 4.94.2) (envelope-from ) id 1wKR3m-0003bh-KC for bitcoindev@gnusha.org; Tue, 05 May 2026 18:28:25 -0700 Received: by mail-oi1-f187.google.com with SMTP id 5614622812f47-467dc3431cbsf4393669b6e.0 for ; Tue, 05 May 2026 18:28:22 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=googlegroups.com; s=20251104; t=1778030893; x=1778635693; darn=gnusha.org; h=list-unsubscribe:list-subscribe:list-archive:list-help:list-post :list-id:mailing-list:precedence:x-original-sender:mime-version :subject:references:in-reply-to:message-id:to:from:date:sender:from :to:cc:subject:date:message-id:reply-to; bh=hS4+IdnEzPoFPXJOBxVZYDrpMwnLvyD5nmSQvKILOSs=; b=tMZ43dayWubQrUm/YVRwb31PPLuHPz2xMKQsuPxXOjv5XcYr+WRwQxW+NajxXeA0Dn 1vtTMr0aG/HI8p+vbYvuFBVnrlrhKZueioM0gI0hDK1QmFGgNZfGksYCgd+0HMCoxM3p AhNanO/jFDU7IVu/EYO3gOWu3sUdQZDgzCSkfxx2Krnd1DAWPbZxgu6FR93yt0kgP7BM xOKp/IlxLfoCUtNSlufk8AmuAulDdvJXl9SbCPpeXbwr4jgr76QQYQ38inWDhVjtpvar M6liRwF05k+RwTRvOsFj/8f8uw9LBw6ZpmDHSJKLVQRhHA8OF3q0uJXyi48wykQg2+f2 wGZQ== DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20251104; t=1778030893; x=1778635693; darn=gnusha.org; h=list-unsubscribe:list-subscribe:list-archive:list-help:list-post :list-id:mailing-list:precedence:x-original-sender:mime-version :subject:references:in-reply-to:message-id:to:from:date:from:to:cc :subject:date:message-id:reply-to; bh=hS4+IdnEzPoFPXJOBxVZYDrpMwnLvyD5nmSQvKILOSs=; b=lHvnvlHEkhRYeFAgzj1jVUIeoehDzXeOtzGshof3o2BcyS5nKCie08KTFp29N2OWwx VXszWQXL48it9fTu2lu2yQTN/K+qELIF55dsZcCEHn9X/KSSiTOLRH6XhW1V5o3Van1/ qtplGTruplwIABa3y0pkGFAM7UBXzMyB5qbISFlP0+iJ+mN7GMmGc9UJI5l06iwD3OLM SG/jd7oU12NnXmYr/YwCXHPuQmuqrvikPOrm1s0tbJD4utG599J9Sv7h9JInLJXxE4KX Lvm/uZq7XppVrVDmsI5SQLnOlJ72QTZet4c7GmJB9rTkZJwisdncDWzRNS5dgr6IF1Zv idpQ== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20251104; t=1778030893; x=1778635693; h=list-unsubscribe:list-subscribe:list-archive:list-help:list-post :list-id:mailing-list:precedence:x-original-sender:mime-version :subject:references:in-reply-to:message-id:to:from:date:x-beenthere :x-gm-message-state:sender:from:to:cc:subject:date:message-id :reply-to; bh=hS4+IdnEzPoFPXJOBxVZYDrpMwnLvyD5nmSQvKILOSs=; b=kxrog8eroFU6MrYo/LXjVRvQioQw+sGEVoru90GNGYuSNAZNI5C0auBfP/+XqiPrs4 fPJ6R8VPsY0UX1+bzius/edWkUj1SSbATZ0yxFnci9hqxlBcLZjiQZrirMZjicI/dXqU tAKFKtp4RIWEqVmmZOAcce9L7yfOuH1W4E8hrw2dZZ1NFhjxIfXHiiSaCdwu5RxA0tDQ nl15MqT5GEa8BaYuxzZSUoKNf/WnwCNoyjxEg/NFd7XEu33BaWC9K9TsgaCASXT7wIJE RLPKVdBhFchCQ2NBI+EM+vdfeCDj6eH7SopYELZEu/qXexe4gsnlV4e69HnvLYZ+rrlk ZePA== Sender: bitcoindev@googlegroups.com X-Forwarded-Encrypted: i=1; AFNElJ/YeXoRBw1x2/iCW74EXiGta99oXUsLKE2E9F+VDB1LLxU836y09c/O7ZAH3yJcmbcludIVMoS8pMSh@gnusha.org X-Gm-Message-State: AOJu0Yws2nOPTCcubHBVJ6Iaz8CO9cZxSQ4JMCOBJsjebqmk0QgylBUl mv2QlbBxz1GjNC2NOov0ut/fssjvVLY7Nrdu7WJciwBGDoK/sDN9FSWc X-Received: by 2002:a05:6808:4f52:b0:479:fca7:4647 with SMTP id 5614622812f47-480420be1a3mr885234b6e.2.1778030893266; Tue, 05 May 2026 18:28:13 -0700 (PDT) X-BeenThere: bitcoindev@googlegroups.com; h="AUV6zMNqV6O9oDdGVlLrmcwlDq8Jis8PsIRGm+pzghLzTPWd1Q==" Received: by 2002:a05:6871:778b:b0:42c:d01:d9e1 with SMTP id 586e51a60fabf-434f42f9fdbls106601fac.0.-pod-prod-00-us-canary; Tue, 05 May 2026 18:28:07 -0700 (PDT) X-Received: by 2002:a05:6808:1645:b0:479:40d4:b140 with SMTP id 5614622812f47-480429af158mr718659b6e.21.1778030887345; Tue, 05 May 2026 18:28:07 -0700 (PDT) Received: by 2002:a05:690c:4dc5:10b0:7ba:f1b3:9504 with SMTP id 00721157ae682-7bd768772bams7b3; Tue, 5 May 2026 18:06:29 -0700 (PDT) X-Received: by 2002:a05:690c:c4e5:b0:7bd:9a25:f39f with SMTP id 00721157ae682-7bda8939c55mr56784257b3.4.1778029588631; Tue, 05 May 2026 18:06:28 -0700 (PDT) Date: Tue, 5 May 2026 18:06:28 -0700 (PDT) From: Antoine Riard To: Bitcoin Development Mailing List Message-Id: In-Reply-To: <19616822-8a03-4de1-99be-72d50479208fn@googlegroups.com> References: <19616822-8a03-4de1-99be-72d50479208fn@googlegroups.com> Subject: [bitcoindev] Re: [BIP Draft] P2P UTXO Set Sharing MIME-Version: 1.0 Content-Type: multipart/mixed; boundary="----=_Part_1093912_417168851.1778029588269" X-Original-Sender: antoine.riard@gmail.com Precedence: list Mailing-list: list bitcoindev@googlegroups.com; contact bitcoindev+owners@googlegroups.com List-ID: X-Google-Group-Id: 786775582512 List-Post: , List-Help: , List-Archive: , List-Unsubscribe: , X-Spam-Score: -0.5 (/) ------=_Part_1093912_417168851.1778029588269 Content-Type: multipart/alternative; boundary="----=_Part_1093913_1427962515.1778029588269" ------=_Part_1093913_1427962515.1778029588269 Content-Type: text/plain; charset="UTF-8" Content-Transfer-Encoding: quoted-printable Hello Fabian, From a short read over the BIP, I'm wondering if the present= =20 BIP proposal wouldn't be better implemented as a feature on top of the BIP= =20 434 (and that would be an opportunity to exercise the proposed mechanism).= =20 Keeping reserved a service bit means implementation that don't wish to=20 support the feature don't have to parse / reserve it. Now, on the other=20 hand it facilitates discovery at the peer layer by any bitcoin software.=20 Second observation, there is no mention of the computational worst-case for= =20 the parsing and validation of the `utxotree`. What if the forwarding peer= =20 is an asshole and share you a crappy utxo set, where validity will be only= =20 asserted when you received and verify the latest utxo with the latest=20 `utxoset`. There could be an intermediary "authentication" step a la BIP157= =20 of the root itself, if you're peers assume-utxo servicing discovery is sane= =20 and you're connected to a least one honest peer that makes it harder to DoS= =20 the recipient. I'm worried it's a bit like BIP157 / BIP158 (or bloom=20 filters fwiw), why a full-node implemention would go to bloat its p2p stack= =20 to support a client-server like flow (independently of the consideration=20 that one find assume-utxo interesting as a validation model). Best, Antoine= =20 OTS hash: ba583724bad6f5251fd793abf626a598f64a1dcd9f5ff6b1f91e1cbd02c09774 Le Tuesday, May 5, 2026 =C3=A0 5:17:53=E2=80=AFPM UTC+1, Eric Voskuil a =C3= =A9crit : > Concept NACK. It's bad enough that nodes are formalizing this off network= ,=20 > but incorporating it into p2p is another level of awful. > > On Tuesday, May 5, 2026 at 11:39:56=E2=80=AFAM UTC-4 Fabian wrote: > >> Dear list, >> >> I am sharing a BIP draft for sharing the UTXO set over the P2P network,= =20 >> an old idea that makes it possible to utilize AssumeUTXO without sourcin= g a=20 >> UTXO set dump from a third party source. You can find the full text belo= w=20 >> or comment on the BIPs repository pull directly:=20 >> https://github.com/bitcoin/bips/pull/2137 >> >> Fabian >> >> >> ``` >> BIP: ? >> Layer: Peer Services >> Title: P2P UTXO Set Sharing >> Authors: Fabian Jahr >> Status: Draft >> Type: Specification >> Assigned: ? >> Discussion: ? >> Version: 0.2.0 >> License: BSD-2-Clause >> ``` >> >> ## Abstract >> >> This BIP defines a P2P protocol extension for sharing full UTXO sets=20 >> between peers. It introduces >> a new service bit `NODE_UTXO_SET`, four new P2P messages (`getutxotree`,= =20 >> `utxotree`, `getutxoset`, >> `utxoset`), and a chunk-hash list anchored to a Merkle root known to the= =20 >> requesting node, enabling >> per-chunk verification. This allows nodes to bootstrap from a recent=20 >> height by obtaining the >> required UTXO set directly from the P2P network via mechanisms such as= =20 >> assumeutxo. >> >> ## Motivation >> >> The assumeutxo feature (implemented in Bitcoin Core) allows nodes to=20 >> begin operating from a serialized >> UTXO set while validating >> historical blocks in the background. However, there is currently no=20 >> canonical source for obtaining this >> data. Users must either generate one themselves from a fully synced node= =20 >> (using `dumptxoutset` in=20 >> Bitcoin Core), or download one from a third party. >> >> By enabling UTXO set sharing over the P2P network, new nodes can obtain= =20 >> the data directly from >> peers, removing the dependency on external infrastructure. >> >> ## Specification >> >> The key words "MUST", "MUST NOT", "SHOULD", "SHOULD NOT", and "MAY" in= =20 >> this document are to be >> interpreted as described in RFC 2119. >> >> ### Service Bit >> >> | Name | Bit | Description | >> |------|-----|-------------| >> | `NODE_UTXO_SET` | 12 (0x1000) | The node can serve complete UTXO set= =20 >> data for at least one height. | >> >> A node MUST NOT set this bit unless it has at least one full UTXO set=20 >> available to serve. >> A node signaling `NODE_UTXO_SET` MUST be capable of responding to=20 >> `getutxotree` and `getutxoset` >> requests for every UTXO set it is willing to serve, including the full= =20 >> chunk-hash list and every >> chunk of those sets. >> >> ### Data Structures >> >> #### Serialized UTXO Set >> >> The serialized UTXO set uses the format established by the Bitcoin Core= =20 >> RPC `dumptxoutset` (as of Bitcoin Core v31). >> >> **Header (55 bytes):** >> >> | Field | Type | Size | Description | >> |-------|------|------|-------------| >> | `magic` | `bytes` | 5 | `0x7574786fff` (ASCII `utxo` + `0xff`). | >> | `version` | `uint16_t` | 2 | Format version. | >> | `network_magic` | `bytes` | 4 | Network message start bytes. | >> | `base_height` | `uint32_t` | 4 | Block height of the UTXO set. | >> | `base_blockhash` | `uint256` | 32 | Block hash of the UTXO set. | >> | `coins_count` | `uint64_t` | 8 | Total number of coins (UTXOs) in the= =20 >> set. | >> >> **Body (coin data):** >> >> Coins are grouped by transaction hash. For each group: >> >> | Field | Type | Size | Description | >> |-------|------|------|-------------| >> | `txid` | `uint256` | 32 | Transaction hash. | >> | `num_coins` | `compact_size` | 1=E2=80=939 | Number of outputs for thi= s txid. | >> >> For each coin in the group: >> >> | Field | Type | Size | Description | >> |-------|------|------|-------------| >> | `vout_index` | `compact_size` | 1=E2=80=939 | Output index. | >> | `coin` | `Coin` | variable | Serialized coin (varint-encoded code for= =20 >> height/coinbase, then compressed txout). | >> >> Coins are ordered lexicographically by outpoint (txid, then vout index),= =20 >> matching the LevelDB iteration >> order of the coins database. >> >> #### Chunk Merkle Tree >> >> The serialized UTXO set (header + body) is split into chunks of exactly= =20 >> 3,900,000 bytes (3.9 MB). The >> last chunk contains the remaining bytes and may be smaller. >> >> The leaf hash for each chunk is `SHA256d(chunk_data)`. The tree is built= =20 >> as a balanced binary tree. When >> the number of nodes at a level is odd, the last node is duplicated befor= e=20 >> hashing the next level. >> Interior nodes are computed as `SHA256d(left_child || right_child)`. >> >> The leaves are delivered to the node in a single `utxotree` response. A= =20 >> node that knows >> the Merkle root for a given UTXO set checks a received list of leaves by= =20 >> recomputing the root and >> comparing. The Merkle root is the sole trust input required to verify th= e=20 >> integrity of the received UTXO set. >> >> `SHA256d` denotes double-SHA256: `SHA256d(x) =3D SHA256(SHA256(x))`. >> >> ### Messages >> >> #### `getutxotree` >> >> Sent to request the chunk-hash list for a specific UTXO set. >> >> | Field | Type | Size | Description | >> |-------|------|------|-------------| >> | `block_hash` | `uint256` | 32 | Block hash identifying the requested= =20 >> UTXO set. | >> >> A node that has advertised `NODE_UTXO_SET` and can serve the requested= =20 >> UTXO set MUST respond with >> `utxotree`. If the serving node cannot fulfill the request, it MUST NOT= =20 >> respond. The requesting >> node SHOULD apply a reasonable timeout and try another peer. >> >> #### `utxotree` >> >> Sent in response to `getutxotree`, delivering the full chunk-hash list= =20 >> along with per-snapshot >> metadata. >> >> | Field | Type | Size | Description | >> |-------|------|------|-------------| >> | `block_hash` | `uint256` | 32 | Block hash this data corresponds to. | >> | `version` | `uint16_t` | 2 | Format version of the serialized UTXO set= .=20 >> | >> | `data_length` | `uint64_t` | 8 | Total size of the serialized UTXO set= =20 >> in bytes (header + body). | >> | `num_chunks` | `compact_size` | 1=E2=80=939 | Number of chunks the ser= ialized=20 >> UTXO set is split into. | >> | `chunk_hashes` | `uint256[]` | 32 =C3=97 `num_chunks` | The ordered li= st of=20 >> chunk hashes. | >> >> Upon receiving a `utxotree` message, the node MUST recompute the Merkle= =20 >> root from >> `chunk_hashes` and compare it against the Merkle root it knows for the= =20 >> corresponding UTXO set. If >> the roots do not match, the node MUST discard the response and MUST=20 >> disconnect the peer. >> >> #### `getutxoset` >> >> Sent to request a single chunk of UTXO set data. The requesting node MUS= T=20 >> have received a `utxotree` >> for the corresponding UTXO set before sending this message. >> >> | Field | Type | Size | Description | >> |-------|------|------|-------------| >> | `block_hash` | `uint256` | 32 | Block hash identifying the requested= =20 >> UTXO set. | >> | `chunk_index` | `uint32_t` | 4 | Zero-based index of the requested=20 >> chunk. | >> >> If the serving node cannot fulfill the request, it MUST NOT respond. The= =20 >> requesting node SHOULD apply >> a reasonable timeout and try another peer. >> >> #### `utxoset` >> >> Sent in response to `getutxoset`, delivering one chunk. >> >> | Field | Type | Size | Description | >> |-------|------|------|-------------| >> | `block_hash` | `uint256` | 32 | Block hash this data corresponds to. | >> | `chunk_index` | `uint32_t` | 4 | Zero-based index of this chunk. | >> | `data` | `bytes` | variable | Chunk payload, exactly 3.9 MB except for= =20 >> the last chunk. | >> >> The transfer is receiver-driven: the requesting node sends one=20 >> `getutxoset` per chunk. Chunks MAY be >> requested in any order and from different peers. >> >> Upon receiving a `utxoset` message, the node MUST compute `SHA256d(data)= `=20 >> and compare it against >> `chunk_hashes[chunk_index]` from the `utxotree` it accepted for this UTX= O=20 >> set. If the hashes do not >> match, the node MUST discard the chunk and MUST disconnect the peer. A= =20 >> node SHOULD also disconnect >> a peer that sends a `utxoset` message with fields (`chunk_index`,=20 >> `block_hash`) that do not match >> the outstanding request. >> >> After all chunks have been received, the node SHOULD parse the=20 >> reassembled UTXO set against the >> serialized UTXO set format to confirm it is well-formed. >> >> ### Protocol Flow >> >> 1. The requesting node identifies peers advertising `NODE_UTXO_SET`. >> 2. The requesting node sends `getutxotree` for the desired block hash to= =20 >> one or more of these peers. >> 3. Each peer responds with `utxotree`. The requesting node verifies the= =20 >> response by recomputing >> the Merkle root against a value it knows for the given UTXO set,=20 >> either from a trusted source >> or by selecting a root with agreement among multiple peers. >> 4. The requesting node downloads chunks via `getutxoset`/`utxoset`=20 >> exchanges, verifying each chunk >> against its entry in the accepted `utxotree` on receipt. On=20 >> verification failure the peer is >> disconnected and download continues from another peer without losing= =20 >> already-verified chunks. >> 5. After all chunks are received, the node parses the reassembled UTXO= =20 >> set against the serialized >> UTXO set format to confirm that it is well-formed. >> >> Serving nodes are free to limit the number of concurrent and repeated=20 >> transfers per peer at their own >> discretion to manage resource consumption. >> >> ## Rationale >> >> **Usage of service bit 12:** Service bits allow selective peer discovery= =20 >> through >> DNS seeds and addr relay. Bit 12 is chosen as the next unassigned bit=20 >> after `NODE_P2P_V2` (bit 11, BIP 324). >> >> **Direct request model:** Peers signal availability of UTXO sets via the= =20 >> `NODE_UTXO_SET` >> service bit; the requesting node identifies the desired UTXO set by bloc= k=20 >> hash when sending >> `getutxotree`. The serving node responds only if it can serve that=20 >> specific UTXO set. >> >> **Per-chunk verification:** The chunk-hash list returned in `utxotree`= =20 >> enables each chunk to be verified >> by direct lookup against the accepted list as it arrives, allowing=20 >> immediate detection of corrupt data, >> peer switching without data loss, and parallel download from multiple=20 >> peers. The list itself is small >> (~80 KB for a ~10 GB set). The specified serialization is deterministic,= =20 >> so all honest nodes produce >> byte-identical output, guaranteeing Merkle root agreement. >> >> **3.9 MB chunk size:** The number balances round trips (~2,560 for a ~10= =20 >> GB set) against memory usage >> for buffering and verifying a single chunk. Smaller chunks would increas= e=20 >> protocol overhead; larger >> chunks would increase memory pressure on constrained devices commonly=20 >> used to run Bitcoin nodes. >> Together with the additional message overhead, the `utxoset` message=20 >> including the chunk data also >> sits just below the theoretical maximum block size which means any=20 >> implementation should be able to >> handle messages of this size. >> >> **Reusing the `dumptxoutset` format:** Avoids introducing a new=20 >> serialization format and ensures >> compatibility with UTXO sets already being generated and shared. >> >> **Relationship to BIP 64:** BIP 64 defined a protocol for querying=20 >> individual UTXOs by outpoint and is >> now closed. This BIP addresses a different use case: bulk transfer of th= e=20 >> entire UTXO set for node >> bootstrapping. >> >> ## Reference Implementation >> >> [Bitcoin Core implementation pull request]( >> https://github.com/bitcoin/bitcoin/pull/35054) >> >> ## Copyright >> >> This BIP is made available under the terms of the 2-clause BSD license.= =20 >> See >> https://opensource.org/license/BSD-2-Clause for more information. >> >> ## Changelog >> >> * __0.2.0__ (2026-05-04): >> * Dropped discovery before download approach, instead request the=20 >> chunk-hash list via `getutxotree`/`utxotree` >> * Dropped per-chunk Merkle proofs; chunks verified directly against= =20 >> the chunk-hash list >> * Dropped `height` from requests (`block_hash` is the sole=20 >> identifier); added format `version` to `utxotree` >> * Dropped references to the serialized hash; the Merkle root is the= =20 >> sole integrity check >> * __0.1.0__ (2026-04-10): >> * Initial draft >> > --=20 You received this message because you are subscribed to the Google Groups "= Bitcoin Development Mailing List" group. To unsubscribe from this group and stop receiving emails from it, send an e= mail to bitcoindev+unsubscribe@googlegroups.com. To view this discussion visit https://groups.google.com/d/msgid/bitcoindev/= aa597737-e07e-4809-82bf-6226080db418n%40googlegroups.com. ------=_Part_1093913_1427962515.1778029588269 Content-Type: text/html; charset="UTF-8" Content-Transfer-Encoding: quoted-printable Hello Fabian, >From a short read over the BIP, I'm wondering if the present BIP proposal wouldn't be better implemented as a feature on top of the BIP 434 (and that would be an opportunity to exercise the proposed mechanism). Keeping reserv= ed a service bit means implementation that don't wish to support the feature d= on't have to parse / reserve it. Now, on the other hand it facilitates discovery= at the peer layer by any bitcoin software. Second observation, there is no mention of the computational worst-case for the parsing and validation of the `utxotree`. What if the forwarding peer i= s an asshole and share you a crappy utxo set, where validity will be only ass= erted when you received and verify the latest utxo with the latest `utxoset`. The= re could be an intermediary "authentication" step a la BIP157 of the root itse= lf, if you're peers assume-utxo servicing discovery is sane and you're connecte= d to a least one honest peer that makes it harder to DoS the recipient. I'm worried it's a bit like BIP157 / BIP158 (or bloom filters fwiw), why a full-node implemention would go to bloat its p2p stack to support a client-server like flow (independently of the consideration that one find assume-utxo interesting as a validation model). Best, Antoine OTS hash: ba583724bad6f5251fd793abf626a598f64a1dcd9f5ff6b1f91e1cbd02c09774<= /span>

Le Tuesday, May 5, 2026 =C3=A0 5:17:53=E2=80=AFPM UTC+1, Eric Vosk= uil a =C3=A9crit=C2=A0:
Concept NACK. It's bad enough that nodes are formalizing t= his off network, but incorporating it into p2p is another level of awful.
On = Tuesday, May 5, 2026 at 11:39:56=E2=80=AFAM UTC-4 Fabian wrote:

I am sharing a BIP draft for sharing the UTXO set = over the P2P network, an old idea that makes it possible to utilize AssumeU= TXO without sourcing a UTXO set dump from a third party source. You can fin= d the full text below or comment on the BIPs repository pull directly:=C2= =A0https://github.com/bitcoin/bips/pull/2137
<= div style=3D"font-family:Arial,sans-serif;font-size:14px;color:rgb(0,0,0);b= ackground-color:rgb(255,255,255)">
Fabian


```=
=C2=A0 BIP: ?
=C2=A0 Layer: Peer S= ervices
=C2=A0 Title: P2P UTXO Set Sharing
=C2=A0 Authors: Fabian Jahr <fj...@protonmail.com>
=C2=A0 Statu= s: Draft
=C2=A0 Type: Specification
=C2=A0 Assigned: ?
=C2=A0 Discussion: ?
=C2=A0 Version: 0.2.0
=C2=A0 Licen= se: BSD-2-Clause
```

## Abstract

This BIP defines a= P2P protocol extension for sharing full UTXO sets between peers. It introd= uces
a new service bit `NODE_UTXO_SET`, four new P2P= messages (`getutxotree`, `utxotree`, `getutxoset`,
= `utxoset`), and a chunk-hash list anchored to a Merkle root known to the re= questing node, enabling
per-chunk verification. This= allows nodes to bootstrap from a recent height by obtaining the
required UTXO set directly from the P2P network via mechanisms= such as assumeutxo.

## Motivation

The assumeutxo feature (implemented in = Bitcoin Core) allows nodes to begin operating from a serialized
UTXO set while validating
historical blo= cks in the background. However, there is currently no canonical source for = obtaining this
data. Users must either generate one = themselves from a fully synced node (using `dumptxoutset` in
<= div>Bitcoin Core), or download one from a third party.

By enabling UTXO set sharing over the P2P network, = new nodes can obtain the data directly from
peers, r= emoving the dependency on external infrastructure.

## Specification

The ke= y words "MUST", "MUST NOT", "SHOULD", "S= HOULD NOT", and "MAY" in this document are to be
interpreted as described in RFC 2119.

### Service Bit

| Name |= Bit | Description |
|------|-----|-------------|
| `NODE_UTXO_SET` | 12 (0x1000) | The node can serve c= omplete UTXO set data for at least one height. |

A node MUST NOT set this bit unless it has at least one full UT= XO set available to serve.
A node signaling `NODE_UT= XO_SET` MUST be capable of responding to `getutxotree` and `getutxoset`
requests for every UTXO set it is willing to serve, inc= luding the full chunk-hash list and every
chunk of t= hose sets.

### Data Structures=

#### Serialized UTXO Set
<= br>
The serialized UTXO set uses the format established by = the Bitcoin Core RPC `dumptxoutset` (as of Bitcoin Core v31).
<= div>
**Header (55 bytes):**

=
| Field | Type | Size | Description |
|--= -----|------|------|-------------|
| `magic` | `byte= s` | 5 | `0x7574786fff` (ASCII `utxo` + `0xff`). |
|= `version` | `uint16_t` | 2 | Format version. |
| `n= etwork_magic` | `bytes` | 4 | Network message start bytes. |
| `base_height` | `uint32_t` | 4 | Block height of the UTXO set. |=
| `base_blockhash` | `uint256` | 32 | Block hash of= the UTXO set. |
| `coins_count` | `uint64_t` | 8 | = Total number of coins (UTXOs) in the set. |

**Body (coin data):**

Coins ar= e grouped by transaction hash. For each group:

<= div>| Field | Type | Size | Description |
|---= ----|------|------|-------------|
| `txid` | `uint25= 6` | 32 | Transaction hash. |
| `num_coins` | `compa= ct_size` | 1=E2=80=939 | Number of outputs for this txid. |

For each coin in the group:

| Field | Type | Size | Description |
= |-------|------|------|-------------|
| `vout_index`= | `compact_size` | 1=E2=80=939 | Output index. |
| = `coin` | `Coin` | variable | Serialized coin (varint-encoded code for heigh= t/coinbase, then compressed txout). |

Coins are ordered lexicographically by outpoint (txid, then vout index), m= atching the LevelDB iteration
order of the coins dat= abase.

#### Chunk Merkle Tree<= /div>

The serialized UTXO set (header + body) is s= plit into chunks of exactly 3,900,000 bytes (3.9 MB). The
= last chunk contains the remaining bytes and may be smaller.

The leaf hash for each chunk is `SHA256d(chunk= _data)`. The tree is built as a balanced binary tree. When
the number of nodes at a level is odd, the last node is duplicated b= efore hashing the next level.
Interior nodes are com= puted as `SHA256d(left_child || right_child)`.

<= div>The leaves are delivered to the node in a single `utxotree` respo= nse. A node that knows
the Merkle root for a given U= TXO set checks a received list of leaves by recomputing the root and=
comparing. The Merkle root is the sole trust input require= d to verify the integrity of the received UTXO set.

`SHA256d` denotes double-SHA256: `SHA256d(x) =3D SHA256(SHA2= 56(x))`.

### Messages

#### `getutxotree`

<= span>Sent to request the chunk-hash list for a specific UTXO set.

| Field | Type | Size | Description |
|-------|------|------|-------------|
| `block_hash` | `uint256` | 32 | Block hash identifying the requested UTX= O set. |

A node that has advertised `= NODE_UTXO_SET` and can serve the requested UTXO set MUST respond with
`utxotree`. If the serving node cannot fulfill the reques= t, it MUST NOT respond. The requesting
node SHOULD a= pply a reasonable timeout and try another peer.

=
#### `utxotree`

Sent in re= sponse to `getutxotree`, delivering the full chunk-hash list along with per= -snapshot
metadata.

= | Field | Type | Size | Description |
|-------= |------|------|-------------|
| `block_hash` | `uint= 256` | 32 | Block hash this data corresponds to. |
|= `version` | `uint16_t` | 2 | Format version of the serialized UTXO set. |<= /span>
| `data_length` | `uint64_t` | 8 | Total size of the= serialized UTXO set in bytes (header + body). |
| `= num_chunks` | `compact_size` | 1=E2=80=939 | Number of chunks the serialize= d UTXO set is split into. |
| `chunk_hashes` | `uint= 256[]` | 32 =C3=97 `num_chunks` | The ordered list of chunk hashes. |

Upon receiving a `utxotree` message, the n= ode MUST recompute the Merkle root from
`chunk_hashe= s` and compare it against the Merkle root it knows for the corresponding UT= XO set. If
the roots do not match, the node MUST dis= card the response and MUST disconnect the peer.

=
#### `getutxoset`

Sent to = request a single chunk of UTXO set data. The requesting node MUST have rece= ived a `utxotree`
for the corresponding UTXO set bef= ore sending this message.

| Field | T= ype | Size | Description |
|-------|------|------|--= -----------|
| `block_hash` | `uint256` | 32 | Block= hash identifying the requested UTXO set. |
| `chunk= _index` | `uint32_t` | 4 | Zero-based index of the requested chunk. |

If the serving node cannot fulfill the req= uest, it MUST NOT respond. The requesting node SHOULD apply
a reasonable timeout and try another peer.

#### `utxoset`

Sent in = response to `getutxoset`, delivering one chunk.

=
| Field | Type | Size | Description |
|--= -----|------|------|-------------|
| `block_hash` | = `uint256` | 32 | Block hash this data corresponds to. |
| `chunk_index` | `uint32_t` | 4 | Zero-based index of this chunk. |
| `data` | `bytes` | variable | Chunk payload, exactly= 3.9 MB except for the last chunk. |

= The transfer is receiver-driven: the requesting node sends one `getutxoset`= per chunk. Chunks MAY be
requested in any order and= from different peers.

Upon receiving= a `utxoset` message, the node MUST compute `SHA256d(data)` and compare it = against
`chunk_hashes[chunk_index]` from the `utxotr= ee` it accepted for this UTXO set. If the hashes do not
match, the node MUST discard the chunk and MUST disconnect the peer. A = node SHOULD also disconnect
a peer that sends a `utx= oset` message with fields (`chunk_index`, `block_hash`) that do not match
the outstanding request.

<= div>After all chunks have been received, the node SHOULD parse the re= assembled UTXO set against the
serialized UTXO set f= ormat to confirm it is well-formed.

#= ## Protocol Flow

1. The requesting no= de identifies peers advertising `NODE_UTXO_SET`.
2. = The requesting node sends `getutxotree` for the desired block hash to one o= r more of these peers.
3. Each peer responds with `u= txotree`. The requesting node verifies the response by recomputing
=C2=A0 =C2=A0the Merkle root against a value it knows for th= e given UTXO set, either from a trusted source
=C2= =A0 =C2=A0or by selecting a root with agreement among multiple peers.
4. The requesting node downloads chunks via `getutxoset`/= `utxoset` exchanges, verifying each chunk
=C2=A0 =C2= =A0against its entry in the accepted `utxotree` on receipt. On verification= failure the peer is
=C2=A0 =C2=A0disconnected and d= ownload continues from another peer without losing already-verified chunks.=
5. After all chunks are received, the node parses t= he reassembled UTXO set against the serialized
=C2= =A0 =C2=A0UTXO set format to confirm that it is well-formed.

Serving nodes are free to limit the number of concu= rrent and repeated transfers per peer at their own
d= iscretion to manage resource consumption.

<= span>## Rationale

**Usage of service = bit 12:** Service bits allow selective peer discovery through
<= div>DNS seeds and addr relay. Bit 12 is chosen as the next unassigned= bit after `NODE_P2P_V2` (bit 11, BIP 324).

**Direct request model:** Peers signal availability of UTXO sets via= the `NODE_UTXO_SET`
service bit; the requesting nod= e identifies the desired UTXO set by block hash when sending
`getutxotree`. The serving node responds only if it can serve that= specific UTXO set.

**Per-chunk verif= ication:** The chunk-hash list returned in `utxotree` enables each chunk to= be verified
by direct lookup against the accepted l= ist as it arrives, allowing immediate detection of corrupt data,
peer switching without data loss, and parallel download from m= ultiple peers. The list itself is small
(~80 KB for = a ~10 GB set). The specified serialization is deterministic, so all honest = nodes produce
byte-identical output, guaranteeing Me= rkle root agreement.

**3.9 MB chunk s= ize:** The number balances round trips (~2,560 for a ~10 GB set) against me= mory usage
for buffering and verifying a single chun= k. Smaller chunks would increase protocol overhead; larger
chunks would increase memory pressure on constrained devices commonl= y used to run Bitcoin nodes.
Together with the addit= ional message overhead, the `utxoset` message including the chunk data also=
sits just below the theoretical maximum block size = which means any implementation should be able to
han= dle messages of this size.

**Reusing = the `dumptxoutset` format:** Avoids introducing a new serialization format = and ensures
compatibility with UTXO sets already bei= ng generated and shared.

**Relationsh= ip to BIP 64:** BIP 64 defined a protocol for querying individual UTXOs by = outpoint and is
now closed. This BIP addresses a dif= ferent use case: bulk transfer of the entire UTXO set for node
=
bootstrapping.

## Referenc= e Implementation

[Bitcoin Core implem= entation pull request](https://github.com/bitcoin/bitcoin/pu= ll/35054)

## Copyright

This BIP is made available under the terms of t= he 2-clause BSD license. See
=
## Changelog

* _= _0.2.0__ (2026-05-04):
=C2=A0 =C2=A0 * Dropped disco= very before download approach, instead request the chunk-hash list via `get= utxotree`/`utxotree`
=C2=A0 =C2=A0 * Dropped per-chu= nk Merkle proofs; chunks verified directly against the chunk-hash list
=C2=A0 =C2=A0 * Dropped `height` from requests (`block_h= ash` is the sole identifier); added format `version` to `utxotree`
=C2=A0 =C2=A0 * Dropped references to the serialized hash; t= he Merkle root is the sole integrity check
* __0.1.0= __ (2026-04-10):
=C2=A0 =C2=A0 * Initial draft
=

--
You received this message because you are subscribed to the Google Groups &= quot;Bitcoin Development Mailing List" group.
To unsubscribe from this group and stop receiving emails from it, send an e= mail to bitcoind= ev+unsubscribe@googlegroups.com.
To view this discussion visit https://groups.google.com/d/msgid/bitcoind= ev/aa597737-e07e-4809-82bf-6226080db418n%40googlegroups.com.
------=_Part_1093913_1427962515.1778029588269-- ------=_Part_1093912_417168851.1778029588269--