Modify ProcessBlock to accept behavior flags.

This commit change the ProcessBlock function to accept a new type named
BehaviorFlags in place of the current fastAdd parameter.

This has been done to pave the way for adding more control over the checks
that are performed such as avoiding the proof of work checks which will be
in an upcoming commit.  A bitmask was chosen because it will allow the
ProcessBlock API to remain a little more stable since new flag additions
that change the behavior are only likely to be used by new code because
adding flags does not change the existing behavior.

ok @jrick
This commit is contained in:
Dave Collins 2014-06-26 15:50:13 -05:00
parent 7d84d801d7
commit 67394ec45d
6 changed files with 44 additions and 18 deletions

View file

@ -13,10 +13,12 @@ import (
// It performs several validation checks which depend on its position within
// the block chain before adding it. The block is expected to have already gone
// through ProcessBlock before calling this function with it.
// The fastAdd argument modifies the behavior of the function by avoiding the
// somewhat expensive operation: BIP34 validation, it also passes the argument
// down to connectBestChain()
func (b *BlockChain) maybeAcceptBlock(block *btcutil.Block, fastAdd bool) error {
//
// The flags modify the behavior of this function as follows:
// - BFFastAdd: The somewhat expensive BIP0034 validation is not performed.
func (b *BlockChain) maybeAcceptBlock(block *btcutil.Block, flags BehaviorFlags) error {
fastAdd := flags&BFFastAdd == BFFastAdd
// Get a block node for the block previous to this one. Will be nil
// if this is the genesis block.
prevNode, err := b.getPrevNodeFromBlock(block)
@ -164,7 +166,7 @@ func (b *BlockChain) maybeAcceptBlock(block *btcutil.Block, fastAdd bool) error
// Connect the passed block to the chain while respecting proper chain
// selection according to the chain with the most proof of work. This
// also handles validation of the transaction scripts.
err = b.connectBestChain(newNode, block, fastAdd)
err = b.connectBestChain(newNode, block, flags)
if err != nil {
return err
}

View file

@ -888,9 +888,13 @@ func (b *BlockChain) reorganizeChain(detachNodes, attachNodes *list.List) error
// chain. However, it may also be extending (or creating) a side chain (fork)
// which may or may not end up becoming the main chain depending on which fork
// cumulatively has the most proof of work.
// The fastAdd argument avoids the call to checkConnectBlock which does
// several expensive transaction validation operations.
func (b *BlockChain) connectBestChain(node *blockNode, block *btcutil.Block, fastAdd bool) error {
//
// The flags modify the behavior of this function as follows:
// - BFFastAdd: Avoids the call to checkConnectBlock which does several
// expensive transaction validation operations.
func (b *BlockChain) connectBestChain(node *blockNode, block *btcutil.Block, flags BehaviorFlags) error {
fastAdd := flags&BFFastAdd == BFFastAdd
// We haven't selected a best chain yet or we are extending the main
// (best) chain with a new block. This is the most common case.
if b.bestChain == nil || node.parent.hash.IsEqual(b.bestChain.hash) {
@ -957,6 +961,7 @@ func (b *BlockChain) connectBestChain(node *blockNode, block *btcutil.Block, fas
"which forks the chain at height %d/block %v",
node.hash, fork.height, fork.hash)
}
return nil
}

View file

@ -48,7 +48,7 @@ func TestHaveBlock(t *testing.T) {
btcchain.TstSetCoinbaseMaturity(1)
for i := 1; i < len(blocks); i++ {
isOrphan, err := chain.ProcessBlock(blocks[i], false)
isOrphan, err := chain.ProcessBlock(blocks[i], btcchain.BFNone)
if err != nil {
t.Errorf("ProcessBlock fail on block %v: %v\n", i, err)
return
@ -61,7 +61,7 @@ func TestHaveBlock(t *testing.T) {
}
// Insert an orphan block.
isOrphan, err := chain.ProcessBlock(btcutil.NewBlock(&Block100000), false)
isOrphan, err := chain.ProcessBlock(btcutil.NewBlock(&Block100000), btcchain.BFNone)
if err != nil {
t.Errorf("Unable to process block: %v", err)
return

2
doc.go
View file

@ -112,7 +112,7 @@ intentionally causes an error by attempting to process a duplicate block.
// Process a block. For this example, we are going to intentionally
// cause an error by trying to process the genesis block which already
// exists.
_, err = chain.ProcessBlock(genesisBlock, false)
_, err = chain.ProcessBlock(genesisBlock, btcchain.BFNone)
if err != nil {
fmt.Printf("Failed to process block: %v\n", err)
return

View file

@ -10,6 +10,21 @@ import (
"github.com/conformal/btcwire"
)
// BehaviorFlags is a bitmask defining tweaks to the normal behavior when
// performing chain processing and consensus rules checks.
type BehaviorFlags uint32
const (
// BFFastAdd may be set to indicate that several checks can be avoided
// for the block since it is already known to fit into the chain due to
// already proving it correct links into the chain up to a known
// checkpoint. This is primarily used for headers-first mode.
BFFastAdd BehaviorFlags = 1 << iota
// BFNone is a convenience value to specifically indicate no flags.
BFNone BehaviorFlags = 0
)
// blockExists determines whether a block with the given hash exists either in
// the main chain or any side chains.
func (b *BlockChain) blockExists(hash *btcwire.ShaHash) bool {
@ -26,7 +41,10 @@ func (b *BlockChain) blockExists(hash *btcwire.ShaHash) bool {
// block hash (they are no longer orphans if true) and potentially accepts them.
// It repeats the process for the newly accepted blocks (to detect further
// orphans which may no longer be orphans) until there are no more.
func (b *BlockChain) processOrphans(hash *btcwire.ShaHash) error {
//
// The flags do not modify the behavior of this function directly, however they
// are needed to pass along to maybeAcceptBlock.
func (b *BlockChain) processOrphans(hash *btcwire.ShaHash, flags BehaviorFlags) error {
// Start with processing at least the passed hash. Leave a little room
// for additional orphan blocks that need to be processed without
// needing to grow the array in the common case.
@ -63,7 +81,7 @@ func (b *BlockChain) processOrphans(hash *btcwire.ShaHash) error {
i--
// Potentially accept the block into the block chain.
err := b.maybeAcceptBlock(orphan.block, false)
err := b.maybeAcceptBlock(orphan.block, flags)
if err != nil {
return err
}
@ -85,7 +103,9 @@ func (b *BlockChain) processOrphans(hash *btcwire.ShaHash) error {
// It returns a bool which indicates whether or not the block is an orphan and
// any errors that occurred during processing. The returned bool is only valid
// when the error is nil.
func (b *BlockChain) ProcessBlock(block *btcutil.Block, fastAdd bool) (bool, error) {
func (b *BlockChain) ProcessBlock(block *btcutil.Block, flags BehaviorFlags) (bool, error) {
fastAdd := flags&BFFastAdd == BFFastAdd
blockHash, err := block.Sha()
if err != nil {
return false, err
@ -154,7 +174,6 @@ func (b *BlockChain) ProcessBlock(block *btcutil.Block, fastAdd bool) (bool, err
// Handle orphan blocks.
prevHash := &blockHeader.PrevBlock
if !prevHash.IsEqual(zeroHash) && !b.blockExists(prevHash) {
// Add the orphan block to the orphan pool.
log.Infof("Adding orphan block %v with parent %v", blockHash,
prevHash)
b.addOrphanBlock(block)
@ -164,7 +183,7 @@ func (b *BlockChain) ProcessBlock(block *btcutil.Block, fastAdd bool) (bool, err
// The block has passed all context independent checks and appears sane
// enough to potentially accept it into the block chain.
err = b.maybeAcceptBlock(block, fastAdd)
err = b.maybeAcceptBlock(block, flags)
if err != nil {
return false, err
}
@ -172,7 +191,7 @@ func (b *BlockChain) ProcessBlock(block *btcutil.Block, fastAdd bool) (bool, err
// Accept any orphan blocks that depend on this block (they are no
// longer orphans) and repeat for those accepted blocks until there are
// no more.
err = b.processOrphans(blockHash)
err = b.processOrphans(blockHash, flags)
if err != nil {
return false, err
}

View file

@ -59,7 +59,7 @@ func TestReorganization(t *testing.T) {
expectedOrphans := map[int]bool{5: true, 6: true}
for i := 1; i < len(blocks); i++ {
isOrphan, err := chain.ProcessBlock(blocks[i], false)
isOrphan, err := chain.ProcessBlock(blocks[i], btcchain.BFNone)
if err != nil {
t.Errorf("ProcessBlock fail on block %v: %v\n", i, err)
return