Performance - linear searches thru blockchain on checking unpark

Issue #232 new
Woodstock Merkle
created an issue

In CTransaction::CheckInputs():

If the transaction is an 'unpark', one of the checks is see if the parked transaction can be found in the current trusted blockchain.

This check is done by way of a linear search thru the blockchain.

In 2.1.1 with a limited # of blocks being held in memory, this has the consequence of loading a lot of blocks off-disk and into memory

There could be a network stability / security aspect to this problem if a node is at the edge of memory capacity. An attacker can park a very small number of coins, let them sit parked, and then cause a DoS of sorts "on command" when the coin is unparked. The longer an attacker lets the coins stay parked, the greater impact this unpark would have.

Some of these unpark() transactions have to search 300k+ blocks back to find the park() transaction, causing client memory usage to increase rapidly (in the current block cache implementation)

Similar full searches of the blockchain can be found in other parts of the code.

Options / ideas: 1- implement this check a different way, or remove it 2- perform this search on mapPrev, if the beginning and end block hashes are known 3- keep a database of transactions known to be "in the trusted chain" (and then manage this data set if there are forks, etc) 4- change the block load() algorithm to unload blocks if the in-memory cache exceeds a certain number of blocks ... this will still cause thrashing, but it will limit memory usage 5- implement a different method to search the database without loading blocks into memory


bool CTransaction::CheckInputs()

(main.cpp, around line 1668 for (; pindexPark && pindexPark->nHeight != coins.nHeight; pindexPark = pindexPark->pprev) {};

Example blocks that trigger this behavior:

352941 ff383afb7e6f2aa77fe845c1b7e958d0728813efdef19bf132e55015a98dfee3

401521 1c6e5ab67355457cc9d07a9764bf1e50cff9c875f8a7774a7cbeed18c07f6ef8

Comments (3)

  1. Michael Witrant

    In this case since the exact block height is known you could just use the prev method "height" times: https://bitbucket.org/JordanLeePeershares/nubit/src/548b256675a10042c77a3bf1798ec27289d10c57/src/blockmap.h?at=2.1.1-RC&fileviewer=file-view-default#blockmap.h-115

    Similar full searches of the blockchain can be found in other parts of the code.

    I tried to remove or update all of them, so there should not be much more left. If that's not the case then we may have to find a more generic solution as you suggested. Do you have other examples?

  2. Michael Witrant

    3- keep a database of transactions known to be "in the trusted chain" (and then manage this data set if there are forks, etc)

    The "coin" database already does that (and that's how the block height is known in this case).

    4- change the block load() algorithm to unload blocks if the in-memory cache exceeds a certain number of blocks ... this will still cause thrashing, but it will limit memory usage

    That may be a good way to prevent memory exhaustion for processes we have not yet updated. We should log a warning in this case, to know there's something to fix.

    5- implement a different method to search the database without loading blocks into memory

    There are a few. mapPrev is one. The "next" database is another. In B&C I had to add other things in the database.

  3. Log in to comment