Export CheckConnectBlock function.

This commit makes a slight variant of the existing checkConnectBlock
function available to external callers.  The new exported version checks
if the passed block will connect to the end of the current main chain.

In order to support this, a few other small modifications have been made
to the initial index generation and the existing checkConnectBlock since
it previously made some assumptions about the state of genesis block which
can no longer be assumed due accepting blocks from callers directly.

Also, add a quick test to ensure the new function fails when checking if
the genesis block will connect again when it's already inserted.
This commit is contained in:
Dave Collins 2014-03-11 13:18:27 -05:00
parent acdce27f9f
commit 1676ecd7a6
4 changed files with 80 additions and 27 deletions

View file

@ -340,7 +340,7 @@ func (b *BlockChain) GenerateInitialIndex() error {
// Calculate the starting height based on the minimum number of nodes
// needed in memory.
startHeight := endHeight - (minMemoryNodes + 1)
startHeight := endHeight - minMemoryNodes
if startHeight < 0 {
startHeight = 0
}
@ -353,7 +353,7 @@ func (b *BlockChain) GenerateInitialIndex() error {
// is going to be nuked eventually, the bug isn't being fixed in the
// driver. In the mean time, work around the issue by calling
// FetchBlockBySha multiple times with the appropriate indices as needed.
for start := startHeight; start < endHeight; {
for start := startHeight; start <= endHeight; {
hashList, err := b.db.FetchHeightRange(start, endHeight+1)
if err != nil {
return err
@ -368,8 +368,8 @@ func (b *BlockChain) GenerateInitialIndex() error {
// Loop forwards through each block loading the node into the
// index for the block.
for _, hash := range hashList {
// Make a copy of the hash to make sure there are no references
// into the list so it can be freed.
// Make a copy of the hash to make sure there are no
// references into the list so it can be freed.
hashCopy := hash
node, err := b.loadBlockNode(&hashCopy)
if err != nil {

View file

@ -2,27 +2,28 @@
github.com/conformal/btcchain/validate.go checkSerializedHeight 100.00% (17/17)
github.com/conformal/btcchain/chain.go BlockChain.removeOrphanBlock 100.00% (16/16)
github.com/conformal/btcchain/txlookup.go disconnectTransactions 100.00% (13/13)
github.com/conformal/btcchain/validate.go countSigOps 100.00% (9/9)
github.com/conformal/btcchain/validate.go CountSigOps 100.00% (9/9)
github.com/conformal/btcchain/validate.go BlockChain.CheckConnectBlock 100.00% (7/7)
github.com/conformal/btcchain/checkpoints.go init 100.00% (6/6)
github.com/conformal/btcchain/merkle.go hashMerkleBranches 100.00% (5/5)
github.com/conformal/btcchain/difficulty.go ShaHashToBig 100.00% (5/5)
github.com/conformal/btcchain/merkle.go hashMerkleBranches 100.00% (5/5)
github.com/conformal/btcchain/chain.go BlockChain.IsKnownOrphan 100.00% (5/5)
github.com/conformal/btcchain/merkle.go nextPowerOfTwo 100.00% (4/4)
github.com/conformal/btcchain/chain.go newBlockNode 100.00% (3/3)
github.com/conformal/btcchain/process.go BlockChain.blockExists 100.00% (3/3)
github.com/conformal/btcchain/checkpoints.go newShaHashFromStr 100.00% (2/2)
github.com/conformal/btcchain/chain.go New 100.00% (2/2)
github.com/conformal/btcchain/timesorter.go timeSorter.Swap 100.00% (1/1)
github.com/conformal/btcchain/validate.go BlockChain.calcBlockSubsidy 100.00% (1/1)
github.com/conformal/btcchain/checkpoints.go newShaHashFromStr 100.00% (2/2)
github.com/conformal/btcchain/timesorter.go timeSorter.Less 100.00% (1/1)
github.com/conformal/btcchain/chain.go BlockChain.HaveBlock 100.00% (1/1)
github.com/conformal/btcchain/log.go init 100.00% (1/1)
github.com/conformal/btcchain/timesorter.go timeSorter.Less 100.00% (1/1)
github.com/conformal/btcchain/timesorter.go timeSorter.Swap 100.00% (1/1)
github.com/conformal/btcchain/timesorter.go timeSorter.Len 100.00% (1/1)
github.com/conformal/btcchain/scriptval.go newTxValidator 100.00% (1/1)
github.com/conformal/btcchain/checkpoints.go BlockChain.DisableCheckpoints 100.00% (1/1)
github.com/conformal/btcchain/scriptval.go newTxValidator 100.00% (1/1)
github.com/conformal/btcchain/scriptval.go txValidator.sendResult 100.00% (1/1)
github.com/conformal/btcchain/log.go DisableLog 100.00% (1/1)
github.com/conformal/btcchain/params.go BlockChain.chainParams 100.00% (1/1)
github.com/conformal/btcchain/log.go DisableLog 100.00% (1/1)
github.com/conformal/btcchain/validate.go CalcBlockSubsidy 100.00% (1/1)
github.com/conformal/btcchain/txlookup.go fetchTxStoreMain 95.65% (22/23)
github.com/conformal/btcchain/merkle.go BuildMerkleTreeStore 93.33% (14/15)
github.com/conformal/btcchain/chain.go BlockChain.getReorganizeNodes 92.86% (13/14)
@ -35,19 +36,21 @@ github.com/conformal/btcchain/chain.go BlockChain.reorganizeChain 85.29% (29
github.com/conformal/btcchain/process.go BlockChain.processOrphans 84.21% (16/19)
github.com/conformal/btcchain/chain.go BlockChain.connectBlock 83.33% (10/12)
github.com/conformal/btcchain/chain.go BlockChain.calcPastMedianTime 82.35% (14/17)
github.com/conformal/btcchain/validate.go BlockChain.checkBIP0030 82.35% (14/17)
github.com/conformal/btcchain/chain.go BlockChain.isMajorityVersion 80.00% (8/10)
github.com/conformal/btcchain/difficulty.go CalcWork 80.00% (4/5)
github.com/conformal/btcchain/chain.go BlockChain.addOrphanBlock 77.78% (14/18)
github.com/conformal/btcchain/chain.go BlockChain.getPrevNodeFromBlock 77.78% (7/9)
github.com/conformal/btcchain/chain.go BlockChain.GenerateInitialIndex 77.27% (17/22)
github.com/conformal/btcchain/chain.go BlockChain.disconnectBlock 76.92% (10/13)
github.com/conformal/btcchain/txlookup.go BlockChain.fetchInputTransactions 75.00% (18/24)
github.com/conformal/btcchain/difficulty.go BigToCompact 75.00% (12/16)
github.com/conformal/btcchain/difficulty.go CompactToBig 75.00% (9/12)
github.com/conformal/btcchain/validate.go BlockChain.checkConnectBlock 69.23% (36/52)
github.com/conformal/btcchain/validate.go isTransactionSpent 75.00% (3/4)
github.com/conformal/btcchain/validate.go BlockChain.checkConnectBlock 71.15% (37/52)
github.com/conformal/btcchain/validate.go CheckBlockSanity 67.44% (29/43)
github.com/conformal/btcchain/validate.go isNullOutpoint 66.67% (2/3)
github.com/conformal/btcchain/validate.go CheckTransactionInputs 65.12% (28/43)
github.com/conformal/btcchain/validate.go BlockChain.checkBIP0030 64.71% (11/17)
github.com/conformal/btcchain/txlookup.go connectTransactions 61.54% (8/13)
github.com/conformal/btcchain/validate.go CheckTransactionSanity 61.11% (22/36)
github.com/conformal/btcchain/validate.go isBIP0030Node 60.00% (3/5)
@ -63,12 +66,11 @@ github.com/conformal/btcchain/notifications.go BlockChain.sendNotification 50
github.com/conformal/btcchain/chain.go BlockChain.pruneBlockNodes 41.18% (7/17)
github.com/conformal/btcchain/validate.go IsFinalizedTransaction 28.57% (4/14)
github.com/conformal/btcchain/checkpoints.go BlockChain.verifyCheckpoint 22.22% (2/9)
github.com/conformal/btcchain/difficulty.go BlockChain.calcNextRequiredDifficulty 17.07% (7/41)
github.com/conformal/btcchain/difficulty.go BlockChain.calcNextRequiredDifficulty 17.50% (7/40)
github.com/conformal/btcchain/checkpoints.go BlockChain.findPreviousCheckpoint 4.88% (2/41)
github.com/conformal/btcchain/blocklocator.go BlockChain.BlockLocatorFromHash 0.00% (0/39)
github.com/conformal/btcchain/checkpoints.go BlockChain.IsCheckpointCandidate 0.00% (0/32)
github.com/conformal/btcchain/validate.go countP2SHSigOps 0.00% (0/26)
github.com/conformal/btcchain/chain.go BlockChain.GenerateInitialIndex 0.00% (0/22)
github.com/conformal/btcchain/validate.go CountP2SHSigOps 0.00% (0/26)
github.com/conformal/btcchain/difficulty.go BlockChain.calcEasiestDifficulty 0.00% (0/15)
github.com/conformal/btcchain/difficulty.go BlockChain.findPrevTestNetDifficulty 0.00% (0/12)
github.com/conformal/btcchain/chain.go BlockChain.removeBlockNode 0.00% (0/12)
@ -81,14 +83,14 @@ github.com/conformal/btcchain/blocklocator.go BlockChain.LatestBlockLocator 0
github.com/conformal/btcchain/txlookup.go BlockChain.FetchTransactionStore 0.00% (0/6)
github.com/conformal/btcchain/checkpoints.go isNonstandardTransaction 0.00% (0/5)
github.com/conformal/btcchain/checkpoints.go BlockChain.checkpointData 0.00% (0/4)
github.com/conformal/btcchain/validate.go isTransactionSpent 0.00% (0/4)
github.com/conformal/btcchain/chain.go addChildrenWork 0.00% (0/3)
github.com/conformal/btcchain/notifications.go NotificationType.String 0.00% (0/3)
github.com/conformal/btcchain/chain.go addChildrenWork 0.00% (0/3)
github.com/conformal/btcchain/checkpoints.go BlockChain.Checkpoints 0.00% (0/3)
github.com/conformal/btcchain/log.go logClosure.String 0.00% (0/1)
github.com/conformal/btcchain/log.go newLogClosure 0.00% (0/1)
github.com/conformal/btcchain/chain.go BlockChain.DisableVerify 0.00% (0/1)
github.com/conformal/btcchain/log.go UseLogger 0.00% (0/1)
github.com/conformal/btcchain/process.go RuleError.Error 0.00% (0/1)
github.com/conformal/btcchain ------------------------------------- 53.75% (666/1239)
github.com/conformal/btcchain/difficulty.go BlockChain.CalcNextRequiredDifficulty 0.00% (0/1)
github.com/conformal/btcchain/log.go logClosure.String 0.00% (0/1)
github.com/conformal/btcchain/log.go UseLogger 0.00% (0/1)
github.com/conformal/btcchain/log.go newLogClosure 0.00% (0/1)
github.com/conformal/btcchain ------------------------------------- 55.94% (697/1246)

View file

@ -711,6 +711,15 @@ func CheckTransactionInputs(tx *btcutil.Tx, txHeight int64, txStore TxStore) (in
// checkConnectBlock performs several checks to confirm connecting the passed
// block to the main chain (including whatever reorganization might be necessary
// to get this node to the main chain) does not violate any rules.
//
// The CheckConnectBlock function makes use of this function to perform the
// bulk of its work. The only difference is this function accepts a node which
// may or may not require reorganization to connect it to the main chain whereas
// CheckConnectBlock creates a new node which specifically connects to the end
// of the current main chain and then calls this function with that node.
//
// See the comments for CheckConnectBlock for some examples of the type of
// checks performed by this function.
func (b *BlockChain) checkConnectBlock(node *blockNode, block *btcutil.Block) error {
// If the side chain blocks end up in the database, a call to
// checkBlockSanity should be done here in case a previous version
@ -718,12 +727,9 @@ func (b *BlockChain) checkConnectBlock(node *blockNode, block *btcutil.Block) er
// implementation only currently uses memory for the side chain blocks,
// it isn't currently necessary.
// TODO(davec): Keep a flag if this has already been done to avoid
// multiple runs.
// The coinbase for the Genesis block is not spendable, so just return
// now.
if node.hash.IsEqual(b.chainParams().GenesisHash) {
if node.hash.IsEqual(b.chainParams().GenesisHash) && b.bestChain == nil {
return nil
}
@ -864,3 +870,24 @@ func (b *BlockChain) checkConnectBlock(node *blockNode, block *btcutil.Block) er
return nil
}
// CheckConnectBlock performs several checks to confirm connecting the passed
// block to the main chain does not violate any rules. An example of some of
// the checks performed are ensuring connecting the block would not cause any
// duplicate transaction hashes for old transactions that aren't already fully
// spent, double spends, exceeding the maximum allowed signature operations
// per block, invalid values in relation to the expected block subisidy, or
// fail transaction script validation.
//
// This function is NOT safe for concurrent access.
func (b *BlockChain) CheckConnectBlock(block *btcutil.Block) error {
prevNode := b.bestChain
blockSha, _ := block.Sha()
newNode := newBlockNode(&block.MsgBlock().Header, blockSha, block.Height())
if prevNode != nil {
newNode.parent = prevNode
newNode.workSum.Add(prevNode.workSum, newNode.workSum)
}
return b.checkConnectBlock(newNode, block)
}

View file

@ -14,6 +14,30 @@ import (
"time"
)
// TestCheckConnectBlock tests the CheckConnectBlock function to ensure it
// fails
func TestCheckConnectBlock(t *testing.T) {
// Create a new database and chain instance to run tests against.
chain, teardownFunc, err := chainSetup("checkconnectblock")
if err != nil {
t.Errorf("Failed to setup chain instance: %v", err)
return
}
defer teardownFunc()
err = chain.GenerateInitialIndex()
if err != nil {
t.Errorf("GenerateInitialIndex: %v", err)
}
// The genesis block should fail to connect since it's already
// inserted.
err = chain.CheckConnectBlock(btcutil.NewBlock(&btcwire.GenesisBlock))
if err == nil {
t.Errorf("CheckConnectBlock: Did not received expected error")
}
}
func TestCheckBlockSanity(t *testing.T) {
powLimit := btcchain.ChainParams(btcwire.MainNet).PowLimit
block := btcutil.NewBlock(&Block100000)