<oembed><type>rich</type><version>1.0</version><author_name>Tomas [ARCHIVE] (npub1rs…9evk4)</author_name><author_url>https://nostr.ae/npub1rsp4w56r24w3zv4xy8zfgesep45qmf9rq6aghxfw3wr7yemqnnwsf9evk4</author_url><provider_name>njump</provider_name><provider_url>https://nostr.ae</provider_url><html>📅 Original date posted:2017-04-06&#xA;📝 Original message:Hi Eric,&#xA;&#xA;Thanks, but I get the impression that the similarity is rather&#xA;superficial.  &#xA;&#xA;To address your points:&#xA;&#xA;&gt; (1) higher than necessary storage space requirement due to storing the&#xA;&gt; indexing data required for correlate the spends, and&#xA;&#xA;Hmm. No. Spends are simply scanned in the spend-tree (full tree,&#xA;prunable, fully 5.6gb), or caught by the spend-index (bit index,&#xA;non-prunable, fully 180mb). Neither impose significant storage&#xA;requirements.&#xA;&#xA;&gt; 2) higher than necessary validation complexity and cost in terms of&#xA;&gt; computing the spent-ness (including spender height) of an output.&#xA;&gt;&#xA;&gt; With the exception of de-linking (not deleted) in the case of reorgs, the&#xA;&gt; entire store is append only, implemented in a small set of memory&#xA;&gt; mapped file&#xA;&#xA;I guess this is the key difference. As the spend-tree stores the spend&#xA;information in a tree structure, no reorgs are required, and the&#xA;resulting code is actually much less complex.&#xA;&#xA;Bitcrust simply scans the tree. Although earlier designs used a&#xA;skip-list, it turns out that accompanied by a spent-index lagging a few&#xA;blocks behind, raw scanning is faster then anything even though it needs&#xA;to scan ~5 blocks times ~4000 inputs before reaching the first&#xA;spent-index,  the actual scan is highly cache efficient and little more&#xA;then a &#34;REP SCASQ&#34;, reaching sub-microsecond per input on each core&#xA;*including* the lookup in the spend index.&#xA;&#xA; &gt; I don&#39;t follow this part, maybe you could clarify. A spends index&#xA;&gt; grows with the size of the spend set (forever) as it cannot be pruned,&#xA;&gt; which certainly exceeds the size of the UTXO set (unless nothing is&#xA;&gt; spent). The advantage is that you don&#39;t have to keep rewriting the&#xA;&gt; store when you use a spends set (because the store can be append only).&#xA;&#xA;My point is, that the spend tree grows per *input* of a transaction&#xA;instead of per *output* of a transaction, because this is what is&#xA;scanned on order validation.&#xA;&#xA;The spend tree can be pruned because the spend index (~200mb) catches&#xA;early spends.&#xA;&#xA;Disregarding the baseload script validation, the peak load order&#xA;validation of bitcrust is more negatively effected by a transaction with&#xA;many inputs than by a transaction of many outputs.&#xA;&#xA;I encourage you to check out the results at https://bitcrust.org&#xA;&#xA;Regards,&#xA;Tomas&#xA;&#xA;On Fri, Apr 7, 2017, at 01:38, Eric Voskuil wrote:&#xA;&gt; -----BEGIN PGP SIGNED MESSAGE-----&#xA;&gt; Hash: SHA256&#xA;&gt; &#xA;&gt; On 04/06/2017 03:12 PM, Tomas via bitcoin-dev wrote:&#xA;&gt; &#xA;&gt; Hi Tomas,&#xA;&gt; &#xA;&gt; &gt; I have been working on a bitcoin implementation that uses a&#xA;&gt; &gt; different approach to indexing for verifying the order of&#xA;&gt; &gt; transactions. Instead of using an index of unspent outputs, double&#xA;&gt; &gt; spends are verified by using a spend-tree where spends are scanned&#xA;&gt; &gt; against spent outputs instead of unspent outputs.&#xA;&gt; &#xA;&gt; This is the approach that genjix used in libbitcoin version2. With the&#xA;&gt; exception of de-linking (not deleted) in the case of reorgs, the&#xA;&gt; entire store is append only, implemented in a small set of memory&#xA;&gt; mapped files. The downsides to the approach are:&#xA;&gt; &#xA;&gt; (1) higher than necessary storage space requirement due to storing the&#xA;&gt; indexing data required for correlate the spends, and&#xA;&gt; &#xA;&gt; (2) higher than necessary validation complexity and cost in terms of&#xA;&gt; computing the spent-ness (including spender height) of an output.&#xA;&gt; &#xA;&gt; His implementation used a hash table, so performance-wise it did quite&#xA;&gt; well and would theoretically outperform a tree, O(1) vs. O(log2(N)).&#xA;&gt; &#xA;&gt; &gt; This allows for much better concurrency, as not only blocks, but&#xA;&gt; &gt; also individual inputs can be verified fully in parallel.&#xA;&gt; &#xA;&gt; I was successful in parallelizing input validation (across the inputs&#xA;&gt; of an unconfirmed tx and across the set of all inputs in a block)&#xA;&gt; using the v2 store. However, it is not the case that the spends&#xA;&gt; approach is necessary for concurrency.&#xA;&gt; &#xA;&gt; To resolve the above two problems the version3 store does not use a&#xA;&gt; spends table/index. Nor does it store any table of UTXOs. Yet&#xA;&gt; validation is highly parallelized. Instead of additional indexes it&#xA;&gt; uses the tx hash table, augmented with 32 bits per output for spender&#xA;&gt; height. So there is a O(1) cost of finding the tx and a O(N) cost of&#xA;&gt; finding the spender height where N is the number of outputs in the tx.&#xA;&gt; But because the number of outputs in a tx is bounded (by block size)&#xA;&gt; this is constant time in the number of transactions.&#xA;&gt; &#xA;&gt; This works out much faster than the spends table, and without the&#xA;&gt; storage cost or complexity disadvantages. It also scales with&#xA;&gt; available hardware, as the memory mapped files become in-memory hash&#xA;&gt; tables. For low memory machines we found it was important to implement&#xA;&gt; an opaque UTXO cache to limit paging, but for higher end systems zero&#xA;&gt; cache is optimal.&#xA;&gt; &#xA;&gt; &gt; I am sharing this not only to ask for your feedback, but also to&#xA;&gt; &gt; call for a clear separation of protocol and implementations: As&#xA;&gt; &gt; this solution, reversing the costs of outputs and inputs, seems to&#xA;&gt; &gt; have excellent performance characteristics (as shown in the test&#xA;&gt; &gt; results), updates to the protocol addressing the UTXO growth, might&#xA;&gt; &gt; not be worth considering *protocol improvements* and it might be&#xA;&gt; &gt; best to address these concerns as implementation details.&#xA;&gt; &#xA;&gt; I don&#39;t follow this part, maybe you could clarify. A spends index&#xA;&gt; grows with the size of the spend set (forever) as it cannot be pruned,&#xA;&gt; which certainly exceeds the size of the UTXO set (unless nothing is&#xA;&gt; spent). The advantage is that you don&#39;t have to keep rewriting the&#xA;&gt; store when you use a spends set (because the store can be append only).&#xA;&gt; &#xA;&gt; Feel free to message me if you&#39;d like to discuss in more detail, or to&#xA;&gt; continue on the libbitcoin mailing list (copied).&#xA;&gt; &#xA;&gt; e&#xA;&gt; -----BEGIN PGP SIGNATURE-----&#xA;&gt; Version: GnuPG v2.0.22 (GNU/Linux)&#xA;&gt; &#xA;&gt; iQEcBAEBCAAGBQJY5tFpAAoJEDzYwH8LXOFOcMgH/2mw5iOvUYNwvZ2z0KKTSUOA&#xA;&gt; Pd8d5mKoWvd94QxhQ+RyTbkEkMhHl75+zcBgRsfUTtZlBIe/Z0+OgVIN6ibEw+WD&#xA;&gt; w7k3HqgQi9gLgydEelxTAX+z3dJ24n4kCCdKAmZbBuK+Yr/7AViugbEqYemKepku&#xA;&gt; pRWZZS74MUvrYesc0xPn4Ao3DTzMjjY0K2mkuqV8jlwdfZjlAQX9pTx+iSCuMhkd&#xA;&gt; HJ8w7s8QnjVnUeOlLe29mZwaFJPyOTLJMqgDE6s2sXacAy5QQbVCatygvDQ8A/wC&#xA;&gt; ktBnKPFb2lGX3bGKu/KwABegBy/hyec+NP0wFR+0MVivCwTK1+SjeHu5MNOSVlM=&#xA;&gt; =tfVj&#xA;&gt; -----END PGP SIGNATURE-----</html></oembed>