BUIP010 (passed): Xtreme Thinblocks

Peter Tschipper

Active Member
Jan 8, 2016
254
357
BUIP010: Xtreme Thinblocks
Proposer: Peter Tschipper
Submitted on: 01/10/2016
Edit 01/20/2016 - changed name to xtreme thinblocks and added 64 bit tx hashes
Edit 01/23/2016 - removed the need to bump the max bloom filter size
Edit 01/25/2016 - made additions to future strategies

Summary

In order to scale the Bitcoin network, a faster less bandwidth intensive method is needed in order to send larger blocks. The thinblock strategy is designed to speed up the relay of blocks by using the transactions that already exist in the requester's memory pool as a way to rebuild the block, rather than download it in its entirety.

Differing from other thinblock strategies, “Xtreme Thinblocks” uses simple bloom filtering and a new class of transactions to ensure that almost all block requests only require a single round trip, which is essential for good performance on a system where transaction rates are steadily climbing and only a single threaded network layer exists. In addition, Xtreme Thinblocks uses a 64 bit transaction hash which further reduces thinblock size; in doing so a typical 1MB block can be reduced to a 10KB to 25KB thinblock.

Thinblock Relay Network: During the testing of this implementation the need to download blocks only from a specified node was required while at the same time allowing transactions from all nodes into the memory pool. This feature will also allow anyone to easily setup their own “thinblock relay network”. (see section Testing for setup). This might be of benefit until the time comes that thinblocks are more widely supported.


Design

For various reasons memory pools are not in perfect sync which makes it difficult to reconstruct blocks in a fast and reliable manner and with a single round trip. Creating a bloom filter at the time of sending the getdata request is an easy and fast way around that problem which allows the remote node to know with high certainty what transactions are missing in the requester’s memory pool and which need to be sent back in order to re-assemble the block.

The reference implementation works in the following way:

Node A is behind by one block and makes a thinblock request to Node B in the following way:

1. Node A creates a bloom filter seeded with the contents of its memory pool.
2. Node A sends the bloom filter along with a getdata request to Node B.
3. Node B sends back a "thinblock" transaction which contains the block header information, all the transaction hashes that were contained in the block, and any transactions that do not match the bloom filter which Node A had sent.
4. Node A receives the "thinblock" and reconstructs the block using transactions that exist from its own memory pool as well as the transactions that were supplied in the thinblock.​

In the unlikely event that there are transactions still missing, they will be re-requested as follows.

5. If there are still any transactions missing then a "CThinBlockTx" transaction is sent from Node A. This contains a map of the missing transaction hashes seeded with null tx's.
6. Node B upon receiving the “CThinBlockTx” request will take the object and fill in the transaction blanks, getting the transactions from the block on disk rather than memory (in this way we can be sure the transactions can be accessed as they may already have been purged from memory or they may have been unannounced). Once the blanks are filled in the object is sent back to Node A and the block finally reconstructed.​

Generally only one round trip is required to complete the block, but on occasion a transaction has to be re-requested initiating a second round trip.

In addition to the above, the following functionalities and configurations will be needed.

⦁ A new protocol version number​

⦁ If the thinblocks feature is turned off then thinblocks will not be downloaded but requests for thinblocks will still be serviced.​

⦁ The coinbase transaction will always be included in the thinblock, as it was discovered by “dagurval” from the XT project, that this was the most common transaction missing, roughly 80% of the time.​

⦁ During startup when the memory pool has few transactions in it, or when a block is very small and has only 1 or 2 transactions a thinblock may end up being larger than the regular block. In that case a regular block will be returned to the requestor instead of a thinblock. This typically happens when a new block is mined just seconds after the previous one.​

⦁ Bloom Size Decay algorithm: A useful phenomena occurs as the memory pools grow and get closer in sync; the bloom filter can be allowed to become less sparse. That means more false positives but because the memory pool has been “warmed up” there is now a very low likelihood of missing a transaction. This bears out in practice and a simple linear decay algorithm was developed which alters both the number of elements and the false positive rate. However, not knowing how far out of sync our pools are in practice means we can not calculate the with certainty the probability of a false positive and a memory pool miss which will result in a re-requested transaction, so we need to be careful in not cutting too fine a line. Using this approach significantly reduces the needed size of the bloom filter by 50%.​
  • A 64 bit transaction hash is used instead of the full 256 bit hash to further reduce thinblock size while still preventing hash collisions in the memory pool
Testing

In order to easily test this implementation it was necessary to create a way to download blocks/thinblocks exclusively from another test peer but at the same time allow transactions to be downloaded from all connected peers in order to keep the memory pools fully loaded. A new “bitcoin.conf” entry was created in order to easily activate this feature.

connect-thinblock=<ip>​

When this setting is used the node will connect to the IP address(es) specified and only download blocks or thinblocks from those IP addresses. However, transactions will still be downloaded from all connected peers regardless of this setting.

Test Setup: To test this implementation it is necessary to run two nodes. One can be run normally with the second node being connected to the first using “connect-thinblock=<ip:port>” A note of caution: because you will likely not be able to run both nodes on port 8333 and will have to configure separate ports, you may end up not getting any inbound connections or very few. This can cause your memory pools to get out of sync by wide margins and as a result you may not see full benefits of thinblocks. Therefore when setting up on different ports you should also use the “connect=<ip>” feature to force connections to other nodes and ensure you are getting transactions into your memory pool and/or you should make sure that your requesting node be on port 8333 so that it's memory pool is more up to date as it will have more inbound connections.


Test Results

The following results highlight how thinblock sizes compare to actual block sizes. When the memory pool is sufficiently "warmed up", Xtreme Thinblocks are typically seen at 1/40 to 1/100th the size of regular blocks.

2016-01-20 13:20:20 Send xthinblock size: 13484 vs block size: 949164 => tx hashes: 1657 transactions: 1
2016-01-20 13:49:12 Send xthinblock size: 25024 vs block size: 949173 => tx hashes: 3095 transactions: 1
2016-01-20 13:52:18 Send xthinblock size: 6494 vs block size: 749124 => tx hashes: 781 transactions: 1
2016-01-20 14:15:07 Send xthinblock size: 9846 vs block size: 934453 => tx hashes: 1035 transactions: 4
2016-01-20 14:30:05 Send xthinblock size: 13448 vs block size: 949092 => tx hashes: 1648 transactions: 1



Backward Compatibility

Although thinblocks can not be downloaded from older clients this change will still be compatible with older clients in that regular blocks will still be downloaded from them.


Fall Back

Turning off thinblocks is a straightforward “bitcoin.conf” entry. By setting “use-thinblocks” to zero the downloading of thinblocks will be turned off. However we will still service requests for thinblocks.

use-thinblocks=0​


Deployment

This enhancement does not require a hard or soft fork.


Future Strategies

Datastream compression:
Testing various compression libraries such as LZO-1x and Zlib have shown it is possible to further reduce block and transaction sizes by 20 to 30% without affecting response times which could also be applied to thinblocks.

Bloom Filters: There is further research that could be done to further reduce the size of Bloom Filters by either by compressing sparse filters or researching a better decay algorithm.

Tx Hashes: Further work could be done to reduce the size of the tx hashes and make a smaller thinblock. @YarkoL has come up with a framework that could be implemented in a phase 2.​


Copyright

This document is placed in the public domain.
 
Last edited:

bitcartel

Member
Nov 19, 2015
95
93
@Peter Tschipper I think the data compression would make a good BUIP (I had some positive comments on the dev mailing list!). Time permitting, would be interesting to see what the compression rates also look like under Segwit.
 

Peter Tschipper

Active Member
Jan 8, 2016
254
357
@bitcartel Are you talking about datastream compression in addition to thinblocks? I did some work back in November on datastream compression and have the code all working but the Core team didn't seem all too interested. (I'm sorry to say but I don't think they have any interest in any enhancements that could be used as an argument to raise block size). Datastream compression rates are about 20 to 30% so it's not a huge win but it's a win nevertheless and easy to implement. I think though doing thin blocks first, then 10 byte transaction hashes, and then datastream compression is the way to go but then again datastream compression can be applied to other things as well.
 

YarkoL

Active Member
Dec 18, 2015
176
258
Tuusula
yarkol.github.io
Maybe @jtoomim could chime in, as I remember
him testing thinblocks and saying on BCT "it works 99% of the
time" - not sure if that meant just that one round trip was
sufficient for 99% of cases or that the 1% failed in some way.

edit: link
 

Peter Tschipper

Active Member
Jan 8, 2016
254
357
@YarkoL This implementation bares little resemblance to the one @jtoomin had tested. The one he tested was a version that was trying to be backwardly compatible with all nodes currently out there; It was a good first try but it's buggy, kludgey and slow. This one is a complete break from the past, new transaction classes and protocol version. I've been running it and testing it for a couple of weeks now and it really works. It's fast and handles any unannounced tx's, and most of the time requires just a single round trip to get everything.
 

Peter Tschipper

Active Member
Jan 8, 2016
254
357
@YarkoL

https://github.com/ptschip/bitcoinxt/tree/thinblocks

that's not the latest but close enough. Following the instructions in the BUIP to setup test nodes...you'll need two of them. Basically you just need to point one node to the other using connect-thinblock=<ip>

make sure the one your connect with is on 8333 so you still get some incoming connections. Blocks will only get dowloaded from the connect-thinblock ip but transactions will flow in from all connected nodes.

At first you won't see any thinblocks...it takes a while until the memory pool warms up. Best results are after several hours but you should start seeing them after 30 minutes to an hour.
 

Peter Tschipper

Active Member
Jan 8, 2016
254
357
If anyone wants to try this implementation but can only run one node you can point your node to mine at 96.54.102.88 (best to include the port number as I run several nodes on that ip) . Be sure to add the following in bitcoin.conf to get thinblocks and timing information. You will see thinblocks very quickly but it takes a several hours for the mempool to warm up before you see them get to their thinnest.

connect-thinblock=96.54.102.88:8333
debug=thin

https://github.com/ptschip/bitcoin/tree/thinblocks
 

YarkoL

Active Member
Dec 18, 2015
176
258
Tuusula
yarkol.github.io

Peter Tschipper

Active Member
Jan 8, 2016
254
357
@YarkoL @jtoomim

XT's version of thinblocks doesn't work with mempool eviction so it won't work with Core v12.x...to get it to work with XT they have to back out their mempool eviction code - not a good move IMO. On the other hand, this version of thinblocks for BU does works with or without mempool eviction, is faster and more scalable.

I'm currently working on adding 8 byte tx hashes for Xtreme Thinblocks which should make 1MB blocks about 10 to 25KB in size. I should have it ready in a few days to a week or so. But the current Scalable Thinblocks is ready for testing although we haven't accepted it yet as a BUIP. Getting a little ahead of things but I have some time on my hands right now so why not experiment...

I see you got your first thinblock, not bad (1/3rd the size) for the first one...it'll get better as the hours go by.
 

solex

Moderator
Staff member
Aug 22, 2015
1,558
4,693
@Peter Tschipper
I am liking what you have done here a lot.
What is the next step for some real testing with more users? Do we need to group of volunteers to run a test version of BU with your code or does BU needs its own testnet first?
 

Peter Tschipper

Active Member
Jan 8, 2016
254
357
@solex

I've debugged this thoroughly (for a couple of weeks now), I would be highly disappointed if anyone found a bug (not that I'm saying there are none) so I think we can test on mainnet as is. I think getting more volunteers is a good idea. Just connect to my node or any node running on protocol version 80001.

Of course I don't want to discourage anyone from testing on testnet, probably a good idea also and something I haven't really done.

(Also this BUIP needs to get voted on and accepted or not accepted)
 

solex

Moderator
Staff member
Aug 22, 2015
1,558
4,693
OK. That's great.
Well, once the results of the elections are declared official, then I would like to progress with voting on the BUIPs which have passed their 14-day public comment period.

An important point for BUIP010 is whether it should recommend deactivation of the v0.12 mempool change which degrades thin blocks. I suspect that the mempool eviction is needed by Core as part of general changes to help better cope with full 1MB blocks, something which BU is not taking as a given state.
 

Peter Tschipper

Active Member
Jan 8, 2016
254
357
@solex The mempool eviction is there to help better deal with spam attacks. Actually, BUIP010 works better with mempool eviction (v12.x) because v11.2 is actually more aggressive at not letting tx's into the memory pool since they had hardcoded the minrelaytxfee and set it to 5000. All said BUIP010 will work better with v12.x in terms sending slightly thinner blocks.
 
  • Like
Reactions: solex