Bitcoin full node and query server

August 2021

Archive of the libbitcoin Slack #general channel.

Friday, August 6, 2021

P
Phil13:35
replied to a thread: view
What is LB’s policy actually: LB will *not* store to persistence a block header for which the parent is not known on the persistence, is it? What about blocks, can LB store to persistence a block where the *block header* of the parent is on persistence but *not* the block of the parent?
P
Phil18:06
replied to a thread: view
Please define exactly what you mean by ‘visible branch’?
P
Phil19:02
replied to a thread: view
What do you mean, for there to be an association between one block header and one transaction (and associations are by nature bidirectional), the whole block structure for the said block must be represented in persistence i.e. either ALL or NONE of the transactions belonging to one block are in the persistence?
P
Phil19:22
the entire chain is retained by the _THREE_ headers->transactions tables.
> If there is a current header, all headers preceding it are downloaded in parallel. You mean: “If there is a current header, all *blocks* preceding it are downloaded in parallel.” right?
evoskuil19:25
Yep
P
Phil23:02
Hi Eric, so I have now carefully re-read your description above of how v4's header+block sync process works. I fully understand that in the context of the full_node class/namespace/problem domain, a “header” and a “block” (generally and especially in the context of subscribe_headers() and subscribe_blocks()) have very specific meanings: * Header means a header for which the whole header chain back to the genesis block is already known by the full_node. (This applies both for a header in the ‘candidate chain’ and a header in the ‘strongest chain’.) * (In respect of a block during the syncing process internally!:) Block means a block where the whole header chain back to the genesis block is already known by the full_node * (In respect of a block that is transitioned from being candidate chain to being strongest chain AND in respect of a block that is part of the strongest chain:) Block means a block where the whole BLOCK chain back to the genesis block is already known by the full_node *and* has been validated Further, I understand LB v4's sync process roughly has these steps: 1. Node asks network for headers. Organizes them into a chain. Track the strongest header chain. -> 2. As soon as the header chain qualifies as being “current”: Parallell-download all blocks for the block headers in the strongest header chain. -> 3. For requested blocks, store such blocks that are received to persistence. 4. Perform validation on the strongest contiguous chain of blocks available???? The candidate chain is defined as strongest contiguous validated chain available. 5. When the candidate chain is stronger than the current strongest chain, then define as strongest chain, this candidate chain. So in the process above, I presume subscribe_blocks() callbacks are really when step 5. trigs. That is, previously there was one given strongest chain and now it’s another one. Can you please explain, where in the process above are subscribe_headers() callbacks made? And now I can explain what I want to do: I want to listen for “header reorgs” defined as, any change to the “strongest header chain” as defined in 1. above. Is exactly that what subscribe_headers() does? If not, what does subscribe_headers() do actually and, what I want to achieve, how do I do that? The reason I want to track the strongest header chain is both to operate an SPV wallet, and also to gauge the full node’s synchronization process as in “Syncing is 12.5% done, ETA 2 days”. Thanks!
> There are arrays of pointers to block headers, allowing blocks to be queried by height in constant time. Do you mean that the confirmed index and the candidate index are/contain arrays, that allow translation within said respective index of block height to block hash, in constant time?

Sunday, August 8, 2021

evoskuil23:20
Step 5 is a block reorg, and that is the source of block notifications. When a header is added to the candidate chain (reorged), that chain is now stronger than the confirmed chain. That triggers a header (reorg) notification. There is actually a third (partial tree) data structure that maintains branches until they are stronger than the persistent candidate chain. The header reorg occurs from the header tree to the candidate chain. The header tree has a configurable maximum depth constraint.
The header indexes are simple arrays of pointers to headers, organized by height. This provides height-based recovery of blocks in constant time. All other data is within hash tables, which also (nominally) provide constant time recovery by block, transaction, or output hash. The hash table does not use the object's natural hash as the hash table (natural) key. The hash table uses a much faster (foreign) key system. The collision rate is ultimately determined by the configured size of the hash table headers.
1 reply · evoskuil · last Aug 08, 2021
evoskuil23:35
To be clear, the hash tables use a foreign key (a hash native to the store) of the object's natural key (e.g. tx hash). I've recently updated the store keying algorithm to DJB2.
(edited)
evoskuil23:24
Other statements are correct.
So the two reorgs are from header_tree -> candidate-index -> confirmed-index. Candidates are validated (and therefore connected) headers and confirmeds are fully validated blocks. The validation chaser is a pointer that walks up the candidate index as blocks arrive. Each time a block is populated, if it is the next block to be validated, blocks are validated until the chaser hits the next gap. It then awaits another block arrival. When a candidate block becomes confirmed and produces a stronger validated candidate branch, that branch is reorged into the confirmed chain (producing block notifications).
We have transitioned form Travis.org (now offline) to Travis.com. This put us offline for a while, as Travis.com is a commercial service. Their free (Open Source) plan credits are very limited and we hit the limit quickly. I have requested, and Travis has granted us 25,000 free credits, and will renew as required. 🎉
👍 1

Monday, August 9, 2021

P
Phil20:07
@evoskuil, thanks for the great description. Just curious, what is the function that translates natural hash to hashtable hash (“foreign key” as you call it)? Also why is it much faster, is it because it’s much smaller than 256 bits?
evoskuil20:11
DJB2 (not merged yet), formerly std::hash<T>. It’s faster because it’s a 64 bit non-cryptographic hash (ie for hash tables). It targets even distribution, not irreversibility. Much, much faster.
(edited)
P
Phil20:12
“Candidates are validated (and therefore connected) headers and confirmeds are fully validated blocks.” - wait what is “confirmeds”?
evoskuil20:13
Confirmed headers.
P
Phil20:15
I see. Great! 😃

Saturday, August 21, 2021

N
nopara7306:00
Hi there!
👋 1
evoskuil18:09
Hola @nopara73

Thursday, August 26, 2021

P
Phil20:28
Hey there. Please @evoskuil, can you confirm to me how the bn.cfg parsing works. If I got it right, the parser::load_settings() function is responsible for adding the options. For the example:
(
    "bitcoin.retargeting_factor",
    value<uint32_t>(&configured.bitcoin.retargeting_factor),
    "The difficulty retargeting factor, defaults to 4."
)
The first line is the name of the option. Here retargeting_factor must be under a [bitcoin] flag. Then the second line tells boost which time the option is and where to store it. Third seems to be just a description. Ok, if I add my custom option here, the only other change that I absolutely need to make is to create the actual variable that will store the option. Following the example, retargeting_factor is declared in the file: libbitcoin-system/include/bitcoin/system/settings.hpp. Is this all I need to add a new option to bn.cfg?
evoskuil20:51
I don’t recommend editing libbitcoin code to build your own projects. It will change over time, sometimes significantly. It is a library, it has public interfaces.
You will become faced with maintaining it all yourself at some point.
However, if you are building your own executable, and only deriving from node that is ideal. The executables are small, for this purpose, and provided as examples
You simply add the statement to the parser, Libbitcoin does the rest.