<div dir="ltr"><div><div><div>I can understand how Bram&#39;s transaction double sha256 hashed UTXO set patricia trie allows a client to quickly validate inputs because the inputs of a transaction are specified in the same manner.  So to verify that an input is unspent the client simply traverses the patricia trie.<br><br></div><div>It also makes sense that if transaction inputs were specified by a [block height, tx index, output index] triple we&#39;d have a much more size-efficient transaction format.  This format would make look up pretty simple in Peter&#39;s pruned time-ordered TXO merkle mountain range, although you&#39;d have translate the triple to an index, which means we&#39;d have to at a minimum keep track of the number of TXOs in each block, and then probably do a linear search starting from the location where the block&#39;s TXOs begin in the MMR.  (The ultimate option I guess is to specify transaction inputs by a single number which is essentially the index of the TXO in a (never actually created) insertion-ordered TXO array...)<br></div><div><br></div>But since transactions&#39; prevouts are not specified by [block height, tx index, output index] or by TXO index, I don&#39;t understand how an insertion ordered TXO tree can result in efficient lookups.  Can you help me understand this?<br><br></div></div><div><div><br></div></div></div><div class="gmail_extra"><br><div class="gmail_quote">On Sat, Feb 25, 2017 at 1:23 AM, Bram Cohen via bitcoin-dev <span dir="ltr">&lt;<a href="mailto:bitcoin-dev@lists.linuxfoundation.org" target="_blank">bitcoin-dev@lists.linuxfoundation.org</a>&gt;</span> wrote:<br><blockquote class="gmail_quote" style="margin:0 0 0 .8ex;border-left:1px #ccc solid;padding-left:1ex"><div dir="ltr"><div class="gmail_extra"><div class="gmail_quote"><span class="">On Fri, Feb 24, 2017 at 8:12 PM, Peter Todd <span dir="ltr">&lt;<a href="mailto:pete@petertodd.org" target="_blank">pete@petertodd.org</a>&gt;</span> wrote:<br><blockquote class="gmail_quote" style="margin:0 0 0 .8ex;border-left:1px #ccc solid;padding-left:1ex"><span><br>
</span>So to be clear, what you&#39;re proposing there is to use the insertion order as<br>
the index - once you go that far you&#39;ve almost entirely re-invented my<br>
proposal!<br></blockquote><div><br></div></span><div>I&#39;m not &#39;proposing&#39; this, I&#39;m saying it could be done simply but I&#39;m skeptical of the utility. Probably the most compelling argument for it is that the insertion indexed values are much smaller so they can be compacted down a lot resulting in using less memory and more locality and fewer hashes, but your implementation doesn&#39;t take advantage of that.</div><span class=""><div> </div><blockquote class="gmail_quote" style="margin:0 0 0 .8ex;border-left:1px #ccc solid;padding-left:1ex">Your merkle-set implementation is 1500 lines of densely written Python</blockquote><div><br></div></span><div>The reference implementation which is included in those 1500 lines is less than 300 lines and fairly straightforward. The non-reference implementation always behaves semantically identically to the reference implementation, it just does so faster and using less memory.</div><div> </div><blockquote class="gmail_quote" style="margin:0 0 0 .8ex;border-left:1px #ccc solid;padding-left:1ex"> with<br>
almost no comments,</blockquote><div><br></div><div>The comments at the top explain both the proof format and the in-memory data structures very precisely. The whole codebase was reviewed by a coworker of mine and comments were added explaining the subtleties which tripped him up.</div><span class=""><div> </div><blockquote class="gmail_quote" style="margin:0 0 0 .8ex;border-left:1px #ccc solid;padding-left:1ex"> and less than a 100 lines of (also uncommented) tests.</blockquote><div><br></div></span><div>Those tests get 98% code coverage and extensively hit not only the lines of code but the semantic edge cases as well. The lines which aren&#39;t hit are convenience functions and error conditions of the parsing code for when it&#39;s passed bad data.</div><span class=""><div> </div><blockquote class="gmail_quote" style="margin:0 0 0 .8ex;border-left:1px #ccc solid;padding-left:1ex"> By<br>
comparison, my Python MMR implementation is 300 lines of very readable Python<br>
with lots of comments, a 200 line explanation at the top, and 200 lines of<br>
(commented) tests. Yet no-one is taking the (still considerable) effort to<br>
understand and comment on my implementation. :)<br></blockquote><div><br></div></span><div>Given that maaku&#39;s Merkle prefix trees were shelved because of performance problems despite being written in C and operating in basically the same way as your code and my reference code, it&#39;s clear that non-optimized Python won&#39;t be touching the bitcoin codebase any time soon. </div><span class=""><div> </div><blockquote class="gmail_quote" style="margin:0 0 0 .8ex;border-left:1px #ccc solid;padding-left:1ex">
<br>
Fact is, what you&#39;ve written is really daunting to review, and given it&#39;s not<br>
in the final language anyway, it&#39;s unclear what basis to review it on anyway.</blockquote><div><br></div></span><div>It should reviewed based on semantic correctness and performance. Performance can only be accurately and convincingly determined by porting to C and optimizing it, which mostly involves experimenting with different values for the two passed in magic numbers.</div><span class=""><div> </div><blockquote class="gmail_quote" style="margin:0 0 0 .8ex;border-left:1px #ccc solid;padding-left:1ex"> I<br>
suspect you&#39;d get more feedback if the codebase was better commented, in a<br>
production language, and you have actual real-world benchmarks and performance<br>
figures.<br></blockquote><div><br></div></span><div>Porting to C should be straightforward. Several people have already expressed interest in doing so, and it&#39;s written in intentionally C-ish Python, resulting in some rather odd idioms which is a bit part of why you think it looks &#39;dense&#39;. A lot of that weird offset math should be much more readable in C because it&#39;s all structs and x.y notation can be used instead of adding offsets.</div><span class=""><div> </div><blockquote class="gmail_quote" style="margin:0 0 0 .8ex;border-left:1px #ccc solid;padding-left:1ex">In particular, while at the top of merkle_set.py you have a list of advantages,<br>
and a bunch of TODO&#39;s, you don&#39;t explain *why* the code has any of these<br>
advantages. To figure that out, I&#39;d have to read and understand 1500 lines of<br>
densely written Python. Without a human-readable pitch, not many people are<br>
going to do that, myself included.<br></blockquote><div><br></div></span><div>It&#39;s all about cache coherence. When doing operations it pulls in a bunch of things which are near each other in memory instead of jumping all over the place. The improvements it gets should be much greater than the ones gained from insertion ordering, although the two could be accretive.</div><div><br></div></div></div></div>
<br>______________________________<wbr>_________________<br>
bitcoin-dev mailing list<br>
<a href="mailto:bitcoin-dev@lists.linuxfoundation.org">bitcoin-dev@lists.<wbr>linuxfoundation.org</a><br>
<a href="https://lists.linuxfoundation.org/mailman/listinfo/bitcoin-dev" rel="noreferrer" target="_blank">https://lists.linuxfoundation.<wbr>org/mailman/listinfo/bitcoin-<wbr>dev</a><br>
<br></blockquote></div><br></div>