diff --git a/blockchain/accept.go b/blockchain/accept.go index 87927a8d..2b713f21 100644 --- a/blockchain/accept.go +++ b/blockchain/accept.go @@ -96,95 +96,6 @@ func IsFinalizedTransaction(tx *dcrutil.Tx, blockHeight int64, blockTime time.Ti return true } -// checkBlockContext peforms several validation checks on the block which depend -// on its position within the block chain. -// -// The flags modify the behavior of this function as follows: -// - BFFastAdd: The transaction are not checked to see if they are finalized -// and the somewhat expensive duplication transaction check is not performed. -// -// The flags are also passed to checkBlockHeaderContext. See its documentation -// for how the flags modify its behavior. -func (b *BlockChain) checkBlockContext(block *dcrutil.Block, prevNode *blockNode, flags BehaviorFlags) error { - // The genesis block is valid by definition. - if prevNode == nil { - return nil - } - - // Perform all block header related validation checks. - header := &block.MsgBlock().Header - err := b.checkBlockHeaderContext(header, prevNode, flags) - if err != nil { - return err - } - - fastAdd := flags&BFFastAdd == BFFastAdd - if !fastAdd { - // A block must not exceed the maximum allowed size as defined - // by the network parameters and the current status of any hard - // fork votes to change it when serialized. - maxBlockSize, err := b.maxBlockSize(prevNode) - if err != nil { - return err - } - serializedSize := int64(block.MsgBlock().Header.Size) - if serializedSize > maxBlockSize { - str := fmt.Sprintf("serialized block is too big - "+ - "got %d, max %d", serializedSize, - maxBlockSize) - return ruleError(ErrBlockTooBig, str) - } - - // Switch to using the past median time of the block prior to - // the block being checked for all checks related to lock times - // once the stake vote for the agenda is active. - blockTime := header.Timestamp - lnFeaturesActive, err := b.isLNFeaturesAgendaActive(prevNode) - if err != nil { - return err - } - if lnFeaturesActive { - medianTime, err := b.index.CalcPastMedianTime(prevNode) - if err != nil { - return err - } - - blockTime = medianTime - } - - // The height of this block is one more than the referenced - // previous block. - blockHeight := prevNode.height + 1 - - // Ensure all transactions in the block are finalized. - for _, tx := range block.Transactions() { - if !IsFinalizedTransaction(tx, blockHeight, blockTime) { - str := fmt.Sprintf("block contains unfinalized regular "+ - "transaction %v", tx.Hash()) - return ruleError(ErrUnfinalizedTx, str) - } - } - for _, stx := range block.STransactions() { - if !IsFinalizedTransaction(stx, blockHeight, blockTime) { - str := fmt.Sprintf("block contains unfinalized stake "+ - "transaction %v", stx.Hash()) - return ruleError(ErrUnfinalizedTx, str) - } - } - - // Check that the coinbase contains at minimum the block - // height in output 1. - if blockHeight > 1 { - err := checkCoinbaseUniqueHeight(blockHeight, block) - if err != nil { - return err - } - } - } - - return nil -} - // ticketsSpentInBlock fetches a list of tickets that were spent in the // block. func ticketsSpentInBlock(bl *dcrutil.Block) []chainhash.Hash { diff --git a/blockchain/validate.go b/blockchain/validate.go index d14c660c..c9429a97 100644 --- a/blockchain/validate.go +++ b/blockchain/validate.go @@ -852,6 +852,95 @@ func (b *BlockChain) checkBlockHeaderContext(header *wire.BlockHeader, prevNode return nil } +// checkBlockContext peforms several validation checks on the block which depend +// on its position within the block chain. +// +// The flags modify the behavior of this function as follows: +// - BFFastAdd: The transactions are not checked to see if they are finalized +// and the somewhat expensive duplication transaction check is not performed. +// +// The flags are also passed to checkBlockHeaderContext. See its documentation +// for how the flags modify its behavior. +func (b *BlockChain) checkBlockContext(block *dcrutil.Block, prevNode *blockNode, flags BehaviorFlags) error { + // The genesis block is valid by definition. + if prevNode == nil { + return nil + } + + // Perform all block header related validation checks. + header := &block.MsgBlock().Header + err := b.checkBlockHeaderContext(header, prevNode, flags) + if err != nil { + return err + } + + fastAdd := flags&BFFastAdd == BFFastAdd + if !fastAdd { + // A block must not exceed the maximum allowed size as defined + // by the network parameters and the current status of any hard + // fork votes to change it when serialized. + maxBlockSize, err := b.maxBlockSize(prevNode) + if err != nil { + return err + } + serializedSize := int64(block.MsgBlock().Header.Size) + if serializedSize > maxBlockSize { + str := fmt.Sprintf("serialized block is too big - "+ + "got %d, max %d", serializedSize, + maxBlockSize) + return ruleError(ErrBlockTooBig, str) + } + + // Switch to using the past median time of the block prior to + // the block being checked for all checks related to lock times + // once the stake vote for the agenda is active. + blockTime := header.Timestamp + lnFeaturesActive, err := b.isLNFeaturesAgendaActive(prevNode) + if err != nil { + return err + } + if lnFeaturesActive { + medianTime, err := b.index.CalcPastMedianTime(prevNode) + if err != nil { + return err + } + + blockTime = medianTime + } + + // The height of this block is one more than the referenced + // previous block. + blockHeight := prevNode.height + 1 + + // Ensure all transactions in the block are finalized. + for _, tx := range block.Transactions() { + if !IsFinalizedTransaction(tx, blockHeight, blockTime) { + str := fmt.Sprintf("block contains unfinalized regular "+ + "transaction %v", tx.Hash()) + return ruleError(ErrUnfinalizedTx, str) + } + } + for _, stx := range block.STransactions() { + if !IsFinalizedTransaction(stx, blockHeight, blockTime) { + str := fmt.Sprintf("block contains unfinalized stake "+ + "transaction %v", stx.Hash()) + return ruleError(ErrUnfinalizedTx, str) + } + } + + // Check that the coinbase contains at minimum the block + // height in output 1. + if blockHeight > 1 { + err := checkCoinbaseUniqueHeight(blockHeight, block) + if err != nil { + return err + } + } + } + + return nil +} + // checkDupTxs ensures blocks do not contain duplicate transactions which // 'overwrite' older transactions that are not fully spent. This prevents an // attack where a coinbase and all of its dependent transactions could be