Previously the code performed a database query for every checkpoint (going
backwards) to find the latest known checkpoint on every block. This was
particularly noticabled near the beginning of the block chain when there
are still several checkpoints that haven't been reached yet.
This commit changes the logic to cache the latest known checkpoint while
keeping track of when it needs to be updated once a new later known
checkpoint has been reached.
While here, also add a log message when a checkpoint has been reached and
verified.
It is not necessary to do all of the transaction validation on
blocks if they have been confirmed to be in the block chain leading
up to the final checkpoint in a given blockschain.
This algorithm fetches block headers from the peer, then once it has
established the full blockchain connection, it requests blocks.
Any blocks before the final checkpoint pass true for fastAdd on
btcchain operation, which causes it to do less valiation on the block.
Rather than fetching the hash of each block individually 2k+ times, make
use of the FetchHeightRange function so all of the most recent hashes can
be fetched at once.
The original thought was that chain would also house the transaction
memory pool, but that ultimately was decided against. As a result,
it only makes sense to query chain for blocks rather than generic
inventory.
Rather than using a channel for notifictions, use a callback instead.
There are several issues that arise with async notifications via a
channel, so use a callback instead. The caller can always make the
notifications async by using channels in the provided callback if
needed.
This commit modifies the GenerateInitialIndex function to update the best
chain with each node as it is loaded. This allows the best chain to be
set immediately upon generating the initial index which is a slight
performance optimization.
This commit provides a new exported function, HaveInventory, which can
be used to determine if the already has the item referenced by passed
inventory vector. Currently it only provides support for blocks and
cursory support for transactions in the main chain. Types that are
unrecognized are returned as if they unknown as expected.
This commit provides a new exported function, IsKnownOrphan, which can
be used to determine if the passed hash is currently already known to the
chain as an orphan.
This commit exposes GetOrphanRoot to callers. It also modifies the code
to allow the function to be called in a concurrent safe manner. This
allows the information to be safely obtained from multiple goroutines.
It is not safe to remove elements from a slice while iterating them with
the range statement since it does not reevaluate the slice on each
iteration nor does it adjust the index for the modified slice. This
commit modifies the code to use a for loop with an index (which does
reevaluate on every iteration) and manually adjusts the index when
elements are removed from the slice.
This commit adds a new optional function named GenerateInitialIndex. It
generates the required number of initial block nodes in an optimized
fashion. Since the memory block index is sparse and previous nodes are
dynamically loaded as needed, this function is not stricty needed.
However, during initial startup (when there are no nodes in memory yet),
dynamically loading all of the required nodes on the fly in the usual way
is much slower than preloading them.
The recent pruning code made the parent hash for a node available directly
as a field in the node. Make use of this in the getPrevNodeFromNode
function to avoid having to load the full block data associated with the
node to get the parent hash.
This commit implements pruning for the block nodes that form the memory
chain which are no longer needed. The validation of a block only requires
information from a set number of previous nodes. The initial code did not
prune old nodes as they were no longer needed, but the vast majority of
the infrastructure to support it was already in place as that was always
the goal. This commit finishes implementing the missing bits to make it
a reality.
Previously, the code was using big rational numbers for work values which
resulted in carrying way too much precision around (and ultimately a lot
of extra memory and computation to carry that precision). This commit
converts the work values to big integers and calculates them with integer
division. This is acceptable because the numerator is multiplied by 2^256
which is higher than the maximum possible proof of work. Therefore
anything after the decimal is superfluous precision for the purposes of
chain selection.
Also, add a check for negative difficulty values when calculating the work
value. Negative values won't occur in practice with valid blocks, but
it's possible an invalid block could trigger the code path, so be safe and
check for it.
This commit adds info level log statements when a block causes a chain
fork, extends a side chain (fork), or causes a reorganize. When a reorg
happens, the new and old chain heads along with the fork point are logged.
In addition to returning errors to the caller, log the error with a prefix
in a few key places that helps identify the origin for errors. In some
cases, the underlying error comes from a different subsystem such as the
SQL database driver and the error messages can be fairly generic.
This commit modifies the code to use params based on the active network
which paves the way for supporting the special rules and different genesis
blocks used by the test networks.