diff --git a/chain.go b/chain.go index 4b51e4b0..9d4bb1f3 100644 --- a/chain.go +++ b/chain.go @@ -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 { diff --git a/test_coverage.txt b/test_coverage.txt index 87b56e96..ca3ea7e1 100644 --- a/test_coverage.txt +++ b/test_coverage.txt @@ -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) diff --git a/validate.go b/validate.go index e156a79a..71428570 100644 --- a/validate.go +++ b/validate.go @@ -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) +} diff --git a/validate_test.go b/validate_test.go index 00bd4894..0157cedd 100644 --- a/validate_test.go +++ b/validate_test.go @@ -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)