2013-07-18 16:49:28 +02:00
|
|
|
// Copyright (c) 2013 Conformal Systems LLC.
|
|
|
|
// Use of this source code is governed by an ISC
|
|
|
|
// license that can be found in the LICENSE file.
|
|
|
|
|
|
|
|
package btcchain
|
|
|
|
|
|
|
|
import (
|
|
|
|
"container/list"
|
|
|
|
"fmt"
|
|
|
|
"github.com/conformal/btcdb"
|
|
|
|
"github.com/conformal/btcutil"
|
|
|
|
"github.com/conformal/btcwire"
|
|
|
|
"math/big"
|
|
|
|
"sort"
|
|
|
|
"time"
|
|
|
|
)
|
|
|
|
|
|
|
|
// maxOrphanBlocks is the maximum number of orphan blocks that can be queued.
|
|
|
|
const maxOrphanBlocks = 100
|
|
|
|
|
|
|
|
// blockNode represents a block within the block chain and is primarily used to
|
|
|
|
// aid in selecting the best chain to be the main chain. The main chain is
|
|
|
|
// stored into the block database.
|
|
|
|
type blockNode struct {
|
|
|
|
// parent is the parent block for this node.
|
|
|
|
parent *blockNode
|
|
|
|
|
|
|
|
// children contains the child nodes for this node. Typically there
|
|
|
|
// will only be one, but sometimes there can be more than one and that
|
|
|
|
// is when the best chain selection algorithm is used.
|
|
|
|
children []*blockNode
|
|
|
|
|
|
|
|
// hash is the double sha 256 of the block.
|
|
|
|
hash *btcwire.ShaHash
|
|
|
|
|
|
|
|
// height is the position in the block chain.
|
|
|
|
height int64
|
|
|
|
|
|
|
|
// workSum is the total amount of work in the chain up to and including
|
|
|
|
// this node.
|
|
|
|
workSum *big.Rat
|
|
|
|
|
|
|
|
// inMainChain denotes whether the block node is currently on the
|
|
|
|
// the main chain or not. This is used to help find the common
|
|
|
|
// ancestor when switching chains.
|
|
|
|
inMainChain bool
|
|
|
|
|
|
|
|
// Some fields from block headers to aid in best chain selection.
|
|
|
|
version uint32
|
|
|
|
bits uint32
|
|
|
|
timestamp time.Time
|
|
|
|
}
|
|
|
|
|
|
|
|
// newBlockNode returns a new block node for the given block. It is completely
|
|
|
|
// disconnected from the chain and the workSum value is just the work for the
|
|
|
|
// passed block. The work sum is updated accordingly when the node is inserted
|
|
|
|
// into a chain.
|
|
|
|
func newBlockNode(block *btcutil.Block) *blockNode {
|
|
|
|
// Get the block sha. It's ok to ignore the error here since
|
|
|
|
// sha has already been called and an error there would have caused
|
|
|
|
// an exit before this function is called.
|
|
|
|
blockSha, _ := block.Sha()
|
|
|
|
|
|
|
|
blockHeader := block.MsgBlock().Header
|
|
|
|
node := blockNode{
|
|
|
|
hash: blockSha,
|
|
|
|
workSum: calcWork(blockHeader.Bits),
|
|
|
|
height: block.Height(),
|
|
|
|
version: blockHeader.Version,
|
|
|
|
bits: blockHeader.Bits,
|
|
|
|
timestamp: blockHeader.Timestamp,
|
|
|
|
}
|
|
|
|
return &node
|
|
|
|
}
|
|
|
|
|
|
|
|
// orphanBlock represents a block that we don't yet have the parent for. It
|
|
|
|
// is a normal block plus an expiration time to prevent caching the orphan
|
|
|
|
// forever.
|
|
|
|
type orphanBlock struct {
|
|
|
|
block *btcutil.Block
|
|
|
|
expiration time.Time
|
|
|
|
}
|
|
|
|
|
|
|
|
// addChildrenWork adds the passed work amount to all children all the way
|
|
|
|
// down the chain. It is used primarily to allow a new node to be dynamically
|
|
|
|
// inserted from the database into the memory chain prior to nodes we already
|
|
|
|
// have and update their work values accordingly.
|
|
|
|
func addChildrenWork(node *blockNode, work *big.Rat) {
|
|
|
|
for _, childNode := range node.children {
|
|
|
|
childNode.workSum.Add(childNode.workSum, work)
|
|
|
|
addChildrenWork(childNode, work)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// removeChildNode deletes node from the provided slice of child block
|
|
|
|
// nodes. It ensures the final pointer reference is set to nil to prevent
|
|
|
|
// potential memory leaks. The original slice is returned unmodified if node
|
|
|
|
// is invalid or not in the slice.
|
|
|
|
func removeChildNode(children []*blockNode, node *blockNode) []*blockNode {
|
|
|
|
if node == nil {
|
|
|
|
return children
|
|
|
|
}
|
|
|
|
for i, n := range children {
|
|
|
|
if n.hash.IsEqual(node.hash) {
|
|
|
|
copy(children[i:], children[i+1:])
|
|
|
|
children[len(children)-1] = nil
|
|
|
|
return children[:len(children)-1]
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return children
|
|
|
|
}
|
|
|
|
|
|
|
|
// BlockChain provides functions for working with the bitcoin block chain.
|
|
|
|
// It includes functionality such as rejecting duplicate blocks, ensuring blocks
|
|
|
|
// follow all rules, orphan handling, checkpoint handling, and best chain
|
|
|
|
// selection with reorganization.
|
|
|
|
type BlockChain struct {
|
|
|
|
db btcdb.Db
|
|
|
|
btcnet btcwire.BitcoinNet
|
|
|
|
notifications chan *Notification
|
|
|
|
root *blockNode
|
|
|
|
bestChain *blockNode
|
|
|
|
index map[btcwire.ShaHash]*blockNode
|
|
|
|
depNodes map[btcwire.ShaHash][]*blockNode
|
|
|
|
orphans map[btcwire.ShaHash]*orphanBlock
|
|
|
|
prevOrphans map[btcwire.ShaHash][]*orphanBlock
|
|
|
|
oldestOrphan *orphanBlock
|
|
|
|
blockCache map[btcwire.ShaHash]*btcutil.Block
|
|
|
|
noVerify bool
|
|
|
|
noCheckpoints bool
|
|
|
|
}
|
|
|
|
|
|
|
|
// DisableVerify provides a mechanism to disable transaction script validation
|
|
|
|
// which you DO NOT want to do in production as it could allow double spends
|
|
|
|
// and othe undesirable things. It is provided only for debug purposes since
|
|
|
|
// script validation is extremely intensive and when debugging it is sometimes
|
|
|
|
// nice to quickly get the chain.
|
|
|
|
func (b *BlockChain) DisableVerify(disable bool) {
|
|
|
|
b.noVerify = disable
|
|
|
|
}
|
|
|
|
|
|
|
|
// getOrphanRoot returns the head of the chain for the provided hash from the
|
|
|
|
// map of orphan blocks.
|
|
|
|
func (b *BlockChain) getOrphanRoot(sha *btcwire.ShaHash) *btcwire.ShaHash {
|
|
|
|
// Keep looping while the parent of each orphaned block is
|
|
|
|
// known and is an orphan itself.
|
|
|
|
prevHash := sha
|
|
|
|
for {
|
|
|
|
orphan, exists := b.orphans[*prevHash]
|
|
|
|
if !exists {
|
|
|
|
break
|
|
|
|
}
|
|
|
|
prevHash = &orphan.block.MsgBlock().Header.PrevBlock
|
|
|
|
}
|
|
|
|
|
|
|
|
return prevHash
|
|
|
|
}
|
|
|
|
|
|
|
|
// removeOrphanBlock removes the passed orphan block from the orphan pool and
|
|
|
|
// previous orphan index.
|
|
|
|
func (b *BlockChain) removeOrphanBlock(orphan *orphanBlock) {
|
|
|
|
// Remove the orphan block from the orphan pool. It's safe to ignore
|
|
|
|
// the error on Sha since it's cached.
|
|
|
|
orphanHash, _ := orphan.block.Sha()
|
|
|
|
delete(b.orphans, *orphanHash)
|
|
|
|
|
|
|
|
// Remove the reference from the previous orphan index too.
|
|
|
|
prevHash := &orphan.block.MsgBlock().Header.PrevBlock
|
|
|
|
orphans := b.prevOrphans[*prevHash]
|
|
|
|
for i, ob := range orphans {
|
|
|
|
hash, _ := ob.block.Sha()
|
|
|
|
if hash.IsEqual(orphanHash) {
|
|
|
|
copy(orphans[i:], orphans[i+1:])
|
|
|
|
orphans[len(orphans)-1] = nil
|
|
|
|
b.prevOrphans[*prevHash] = orphans[:len(orphans)-1]
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// Remove the map entry altogether if there are no longer any orphans
|
|
|
|
// which depend on the parent hash.
|
|
|
|
if len(b.prevOrphans[*prevHash]) == 0 {
|
|
|
|
delete(b.prevOrphans, *prevHash)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// addOrphanBlock adds the passed block (which is already determined to be
|
|
|
|
// an orphan prior calling this function) to the orphan pool. It lazily cleans
|
|
|
|
// up any expired blocks so a separate cleanup poller doesn't need to be run.
|
|
|
|
// It also imposes a maximum limit on the number of outstanding orphan
|
|
|
|
// blocks and will remove the oldest received orphan block if the limit is
|
|
|
|
// exceeded.
|
|
|
|
func (b *BlockChain) addOrphanBlock(block *btcutil.Block) {
|
|
|
|
// Remove expired orphan blocks.
|
|
|
|
for _, oBlock := range b.orphans {
|
|
|
|
if time.Now().After(oBlock.expiration) {
|
|
|
|
b.removeOrphanBlock(oBlock)
|
|
|
|
continue
|
|
|
|
}
|
|
|
|
|
|
|
|
// Update the oldest orphan block pointer so it can be discarded
|
|
|
|
// in case the orphan pool fills up.
|
|
|
|
if b.oldestOrphan == nil || oBlock.expiration.Before(b.oldestOrphan.expiration) {
|
|
|
|
b.oldestOrphan = oBlock
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// Limit orphan blocks to prevent memory exhaustion.
|
|
|
|
if len(b.orphans)+1 > maxOrphanBlocks {
|
|
|
|
// Remove the oldest orphan to make room for the new one.
|
|
|
|
b.removeOrphanBlock(b.oldestOrphan)
|
|
|
|
b.oldestOrphan = nil
|
|
|
|
}
|
|
|
|
|
|
|
|
// Get the block sha. It is safe to ignore the error here since any
|
|
|
|
// errors would've been caught prior to calling this function.
|
|
|
|
blockSha, _ := block.Sha()
|
|
|
|
|
|
|
|
// Insert the block into the orphan map with an expiration time
|
|
|
|
// 1 hour from now.
|
|
|
|
expiration := time.Now().Add(time.Hour)
|
|
|
|
oBlock := &orphanBlock{
|
|
|
|
block: block,
|
|
|
|
expiration: expiration,
|
|
|
|
}
|
|
|
|
b.orphans[*blockSha] = oBlock
|
|
|
|
|
|
|
|
// Add to previous hash lookup index for faster dependency lookups.
|
|
|
|
prevHash := &block.MsgBlock().Header.PrevBlock
|
|
|
|
b.prevOrphans[*prevHash] = append(b.prevOrphans[*prevHash], oBlock)
|
|
|
|
|
|
|
|
return
|
|
|
|
}
|
|
|
|
|
|
|
|
// loadBlockNode loads the block identified by hash from the block database,
|
|
|
|
// creates a block node from it, and updates the memory block chain accordingly.
|
|
|
|
// It is used mainly to dynamically load previous blocks from database as they
|
|
|
|
// are needed to avoid needing to put the entire block chain in memory.
|
|
|
|
func (b *BlockChain) loadBlockNode(hash *btcwire.ShaHash) (*blockNode, error) {
|
|
|
|
// Load the block from the db.
|
|
|
|
block, err := b.db.FetchBlockBySha(hash)
|
|
|
|
if err != nil {
|
|
|
|
return nil, err
|
|
|
|
}
|
|
|
|
|
|
|
|
// Create the new block node for the block and set the work.
|
|
|
|
node := newBlockNode(block)
|
|
|
|
node.inMainChain = true
|
|
|
|
|
|
|
|
// Add the node to the chain.
|
|
|
|
// There are several possibilities here:
|
|
|
|
// 1) This node is a child of an existing block node
|
|
|
|
// 2) This node is the parent of one or more nodes
|
|
|
|
// 3) Neither 1 or 2 is true, and this is not the first node being
|
|
|
|
// added to the tree which implies it's an orphan block and
|
|
|
|
// therefore is an error to insert into the chain
|
|
|
|
// 4) Neither 1 or 2 is true, but this is the first node being added
|
|
|
|
// to the tree, so it's the root.
|
|
|
|
prevHash := &block.MsgBlock().Header.PrevBlock
|
|
|
|
if parentNode, ok := b.index[*prevHash]; ok {
|
|
|
|
// Case 1 -- This node is a child of an existing block node.
|
|
|
|
// Update the node's work sum with the sum of the parent node's
|
|
|
|
// work sum and this node's work, append the node as a child of
|
|
|
|
// the parent node and set this node's parent to the parent
|
|
|
|
// node.
|
|
|
|
node.workSum = node.workSum.Add(parentNode.workSum, node.workSum)
|
|
|
|
parentNode.children = append(parentNode.children, node)
|
|
|
|
node.parent = parentNode
|
|
|
|
|
|
|
|
} else if childNodes, ok := b.depNodes[*hash]; ok {
|
|
|
|
// Case 2 -- This node is the parent of one or more nodes.
|
|
|
|
// Connect this block node to all of its children and update
|
|
|
|
// all of the children (and their children) with the new work
|
|
|
|
// sums.
|
|
|
|
for _, childNode := range childNodes {
|
|
|
|
childNode.parent = node
|
|
|
|
node.children = append(node.children, childNode)
|
|
|
|
addChildrenWork(childNode, node.workSum)
|
|
|
|
b.root = node
|
|
|
|
}
|
|
|
|
|
|
|
|
} else {
|
|
|
|
// Case 3 -- The node does't have a parent and is not the parent
|
|
|
|
// of another node. This is only acceptable for the first node
|
|
|
|
// inserted into the chain. Otherwise it means an arbitrary
|
|
|
|
// orphan block is trying to be loaded which is not allowed.
|
|
|
|
if b.root != nil {
|
|
|
|
str := "loadBlockNode: attempt to insert orphan block %v"
|
|
|
|
return nil, fmt.Errorf(str, hash)
|
|
|
|
}
|
|
|
|
|
|
|
|
// Case 4 -- This is the root since it's the first and only node.
|
|
|
|
b.root = node
|
|
|
|
}
|
|
|
|
|
|
|
|
// Add the new node to the indices for faster lookups.
|
|
|
|
b.index[*hash] = node
|
|
|
|
b.depNodes[*prevHash] = append(b.depNodes[*prevHash], node)
|
|
|
|
|
|
|
|
return node, nil
|
|
|
|
}
|
|
|
|
|
|
|
|
// getPrevNodeFromBlock returns a block node for the block previous to the
|
|
|
|
// passed block (the passed block's parent). When it is already in the memory
|
|
|
|
// block chain, it simply returns it. Otherwise, it loads the previous block
|
|
|
|
// from the block database, creates a new block node from it, and returns it.
|
|
|
|
// The returned node will be nil if the genesis block is passed.
|
|
|
|
func (b *BlockChain) getPrevNodeFromBlock(block *btcutil.Block) (*blockNode, error) {
|
|
|
|
// Genesis block.
|
|
|
|
prevHash := &block.MsgBlock().Header.PrevBlock
|
|
|
|
if prevHash.IsEqual(zeroHash) {
|
|
|
|
return nil, nil
|
|
|
|
}
|
|
|
|
|
|
|
|
// Return the existing previous block node if it's already there.
|
|
|
|
if bn, ok := b.index[*prevHash]; ok {
|
|
|
|
return bn, nil
|
|
|
|
}
|
|
|
|
|
|
|
|
// Dynamically load the previous block from the block database, create
|
|
|
|
// a new block node for it, and update the memory chain accordingly.
|
|
|
|
prevBlockNode, err := b.loadBlockNode(prevHash)
|
|
|
|
if err != nil {
|
|
|
|
return nil, err
|
|
|
|
}
|
|
|
|
return prevBlockNode, nil
|
|
|
|
}
|
|
|
|
|
|
|
|
// getPrevNodeFromNode returns a block node for the block previous to the
|
|
|
|
// passed block node (the passed block node's parent). When the node is already
|
|
|
|
// connected to a parent, it simply returns it. Otherwise, it loads the
|
|
|
|
// associated block from the database to obtain the previous hash and uses that
|
|
|
|
// to dynamically create a new block node and return it. The memory block
|
|
|
|
// chain is updated accordingly. The returned node will be nil if the genesis
|
|
|
|
// block is passed.
|
|
|
|
func (b *BlockChain) getPrevNodeFromNode(node *blockNode) (*blockNode, error) {
|
|
|
|
// Return the existing previous block node if it's already there.
|
|
|
|
if node.parent != nil {
|
|
|
|
return node.parent, nil
|
|
|
|
}
|
|
|
|
|
|
|
|
// Genesis block.
|
2013-07-24 18:37:45 +02:00
|
|
|
if node.hash.IsEqual(b.netParams().genesisHash) {
|
2013-07-18 16:49:28 +02:00
|
|
|
return nil, nil
|
|
|
|
}
|
|
|
|
|
|
|
|
// Load the actual block for this block node from the db to ascertain
|
|
|
|
// the previous hash.
|
|
|
|
block, err := b.db.FetchBlockBySha(node.hash)
|
|
|
|
if err != nil {
|
|
|
|
return nil, err
|
|
|
|
}
|
|
|
|
|
|
|
|
// Dynamically load the previous block from the block database, create
|
|
|
|
// a new block node for it, and update the memory chain accordingly.
|
|
|
|
prevHash := &block.MsgBlock().Header.PrevBlock
|
|
|
|
prevBlockNode, err := b.loadBlockNode(prevHash)
|
|
|
|
if err != nil {
|
|
|
|
return nil, err
|
|
|
|
}
|
|
|
|
|
|
|
|
return prevBlockNode, nil
|
|
|
|
}
|
|
|
|
|
|
|
|
// isMajorityVersion determines if a previous number of blocks in the chain
|
|
|
|
// starting with startNode are at least the minimum passed version.
|
|
|
|
func (b *BlockChain) isMajorityVersion(minVer uint32, startNode *blockNode, numRequired, numToCheck uint64) bool {
|
|
|
|
numFound := uint64(0)
|
|
|
|
iterNode := startNode
|
|
|
|
for i := uint64(0); i < numToCheck && iterNode != nil; i++ {
|
|
|
|
// This node has a version that is at least the minimum version.
|
|
|
|
if iterNode.version >= minVer {
|
|
|
|
numFound++
|
|
|
|
}
|
|
|
|
|
|
|
|
// Get the previous block node. This function is used over
|
|
|
|
// simply accessing iterNode.parent directly as it will
|
|
|
|
// dynamically create previous block nodes as needed. This
|
|
|
|
// helps allow only the pieces of the chain that are needed
|
|
|
|
// to remain in memory.
|
|
|
|
var err error
|
|
|
|
iterNode, err = b.getPrevNodeFromNode(iterNode)
|
|
|
|
if err != nil {
|
|
|
|
break
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return numFound >= numRequired
|
|
|
|
}
|
|
|
|
|
|
|
|
// calcPastMedianTime calculates the median time of the previous few blocks
|
|
|
|
// prior to, and including, the passed block node. It is primarily used to
|
|
|
|
// validate new blocks have sane timestamps.
|
|
|
|
func (b *BlockChain) calcPastMedianTime(startNode *blockNode) (time.Time, error) {
|
|
|
|
// Genesis block.
|
|
|
|
if startNode == nil {
|
2013-07-24 18:37:45 +02:00
|
|
|
return b.netParams().genesisBlock.Header.Timestamp, nil
|
2013-07-18 16:49:28 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
// Create a slice of the previous few block timestamps used to calculate
|
|
|
|
// the median per the number defined by the constant medianTimeBlocks.
|
|
|
|
timestamps := make([]time.Time, medianTimeBlocks)
|
|
|
|
numNodes := 0
|
|
|
|
iterNode := startNode
|
|
|
|
for i := 0; i < medianTimeBlocks && iterNode != nil; i++ {
|
|
|
|
timestamps[i] = iterNode.timestamp
|
|
|
|
numNodes++
|
|
|
|
|
|
|
|
// Get the previous block node. This function is used over
|
|
|
|
// simply accessing iterNode.parent directly as it will
|
|
|
|
// dynamically create previous block nodes as needed. This
|
|
|
|
// helps allow only the pieces of the chain that are needed
|
|
|
|
// to remain in memory.
|
|
|
|
var err error
|
|
|
|
iterNode, err = b.getPrevNodeFromNode(iterNode)
|
|
|
|
if err != nil {
|
2013-07-24 19:31:14 +02:00
|
|
|
log.Errorf("getPrevNodeFromNode: %v", err)
|
2013-07-18 16:49:28 +02:00
|
|
|
return time.Time{}, err
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// Prune the slice to the actual number of available timestamps which
|
|
|
|
// will be fewer than desired near the beginning of the block chain
|
|
|
|
// and sort them.
|
|
|
|
timestamps = timestamps[:numNodes]
|
|
|
|
sort.Sort(timeSorter(timestamps))
|
|
|
|
|
|
|
|
// NOTE: bitcoind incorrectly calculates the median for even numbers of
|
|
|
|
// blocks. A true median averages the middle two elements for a set
|
|
|
|
// with an even number of elements in it. Since the constant for the
|
|
|
|
// previous number of blocks to be used is odd, this is only an issue
|
|
|
|
// for a few blocks near the beginning of the chain. I suspect this is
|
|
|
|
// an optimization even though the result is slightly wrong for a few
|
|
|
|
// of the first blocks since after the first few blocks, there will
|
|
|
|
// always be an odd number of blocks in the set per the constant.
|
|
|
|
//
|
|
|
|
// This code follows suit to ensure the same rules are used as bitcoind
|
|
|
|
// however, be aware that should the medianTimeBlocks constant ever be
|
|
|
|
// changed to an even number, this code will be wrong.
|
|
|
|
medianTimestamp := timestamps[numNodes/2]
|
|
|
|
return medianTimestamp, nil
|
|
|
|
}
|
|
|
|
|
|
|
|
// getReorganizeNodes finds the fork point between the main chain and the passed
|
|
|
|
// node and returns a list of block nodes that would need to be detached from
|
|
|
|
// the main chain and a list of block nodes that would need to be attached to
|
|
|
|
// the fork point (which will be the end of the main chain after detaching the
|
|
|
|
// returned list of block nodes) in order to reorganize the chain such that the
|
|
|
|
// passed node is the new end of the main chain. The lists will be empty if the
|
|
|
|
// passed node is not on a side chain.
|
|
|
|
func (b *BlockChain) getReorganizeNodes(node *blockNode) (*list.List, *list.List) {
|
|
|
|
// Nothing to detach or attach if there is no node.
|
|
|
|
attachNodes := list.New()
|
|
|
|
detachNodes := list.New()
|
|
|
|
if node == nil {
|
|
|
|
return detachNodes, attachNodes
|
|
|
|
}
|
|
|
|
|
|
|
|
// Find the fork point (if any) adding each block to the list of nodes
|
|
|
|
// to attach to the main tree. Push them onto the list in reverse order
|
|
|
|
// so they are attached in the appropriate order when iterating the list
|
|
|
|
// later.
|
|
|
|
ancestor := node
|
|
|
|
for ; ancestor.parent != nil; ancestor = ancestor.parent {
|
|
|
|
if ancestor.inMainChain {
|
|
|
|
break
|
|
|
|
}
|
|
|
|
attachNodes.PushFront(ancestor)
|
|
|
|
}
|
|
|
|
|
|
|
|
// TODO(davec): Use prevNodeFromNode function in case the requested
|
|
|
|
// node is further back than the what is in memory. This shouldn't
|
|
|
|
// happen in the normal course of operation, but the ability to fetch
|
|
|
|
// input transactions of arbitrary blocks will likely to be exposed at
|
|
|
|
// some point and that could lead to an issue here.
|
|
|
|
|
|
|
|
// Start from the end of the main chain and work backwards until the
|
|
|
|
// common ancestor adding each block to the list of nodes to detach from
|
|
|
|
// the main chain.
|
|
|
|
for n := b.bestChain; n != nil && n.parent != nil; n = n.parent {
|
|
|
|
if n.hash.IsEqual(ancestor.hash) {
|
|
|
|
break
|
|
|
|
}
|
|
|
|
detachNodes.PushBack(n)
|
|
|
|
}
|
|
|
|
|
|
|
|
return detachNodes, attachNodes
|
|
|
|
}
|
|
|
|
|
|
|
|
// connectBlock handles connecting the passed node/block to the end of the main
|
|
|
|
// (best) chain.
|
|
|
|
func (b *BlockChain) connectBlock(node *blockNode, block *btcutil.Block) error {
|
|
|
|
// Make sure it's extending the end of the best chain.
|
|
|
|
prevHash := &block.MsgBlock().Header.PrevBlock
|
|
|
|
if b.bestChain != nil && !prevHash.IsEqual(b.bestChain.hash) {
|
|
|
|
return fmt.Errorf("connectBlock must be called with a block " +
|
|
|
|
"that extends the main chain")
|
|
|
|
}
|
|
|
|
|
|
|
|
// Insert the block into the database which houses the main chain.
|
|
|
|
_, err := b.db.InsertBlock(block)
|
|
|
|
if err != nil {
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
|
|
|
|
// TODO(davec): Remove transactions from memory transaction pool.
|
|
|
|
|
|
|
|
// Add the new node to the memory main chain indices for faster
|
|
|
|
// lookups.
|
|
|
|
node.inMainChain = true
|
|
|
|
b.index[*node.hash] = node
|
|
|
|
b.depNodes[*prevHash] = append(b.depNodes[*prevHash], node)
|
|
|
|
|
|
|
|
// This node is now the end of the best chain.
|
|
|
|
b.bestChain = node
|
|
|
|
|
|
|
|
// Notify the caller that the block was connected to the main chain.
|
|
|
|
// The caller would typically want to react with actions such as
|
|
|
|
// updating wallets.
|
|
|
|
b.sendNotification(NTBlockConnected, block)
|
|
|
|
|
|
|
|
return nil
|
|
|
|
}
|
|
|
|
|
|
|
|
// disconnectBlock handles disconnecting the passed node/block from the end of
|
|
|
|
// the main (best) chain.
|
|
|
|
func (b *BlockChain) disconnectBlock(node *blockNode, block *btcutil.Block) error {
|
|
|
|
// Make sure the node being disconnected is the end of the best chain.
|
|
|
|
if b.bestChain == nil || !node.hash.IsEqual(b.bestChain.hash) {
|
|
|
|
return fmt.Errorf("disconnectBlock must be called with the " +
|
|
|
|
"block at the end of the main chain")
|
|
|
|
}
|
|
|
|
|
|
|
|
// Remove the block from the database which houses the main chain.
|
|
|
|
prevNode, err := b.getPrevNodeFromNode(node)
|
|
|
|
if err != nil {
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
err = b.db.DropAfterBlockBySha(prevNode.hash)
|
|
|
|
if err != nil {
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
|
|
|
|
// TODO(davec): Put transactions back in memory transaction pool.
|
|
|
|
|
|
|
|
// Put block in the side chain cache.
|
|
|
|
node.inMainChain = false
|
|
|
|
b.blockCache[*node.hash] = block
|
|
|
|
|
|
|
|
// This node's parent is now the end of the best chain.
|
|
|
|
b.bestChain = node.parent
|
|
|
|
|
|
|
|
// Notify the caller that the block was disconnect from the main chain.
|
|
|
|
// The caller would typically want to react with actions such as
|
|
|
|
// updating wallets.
|
|
|
|
b.sendNotification(NTBlockDisconnected, block)
|
|
|
|
|
|
|
|
return nil
|
|
|
|
}
|
|
|
|
|
|
|
|
// reorganizeChain reorganizes the block chain by disconnecting the nodes in the
|
|
|
|
// detachNodes list and connecting the nodes in the attach list. It expects
|
|
|
|
// that the lists are already in the correct order and are in sync with the
|
|
|
|
// end of the current best chain. Specifically, nodes that are being
|
|
|
|
// disconnected must be in reverse order (think of popping them off
|
|
|
|
// the end of the chain) and nodes the are being attached must be in forwards
|
|
|
|
// order (think pushing them onto the end of the chain).
|
|
|
|
func (b *BlockChain) reorganizeChain(detachNodes, attachNodes *list.List) error {
|
|
|
|
// Ensure all of the needed side chain blocks are in the cache.
|
|
|
|
for e := attachNodes.Front(); e != nil; e = e.Next() {
|
|
|
|
n := e.Value.(*blockNode)
|
|
|
|
if _, exists := b.blockCache[*n.hash]; !exists {
|
|
|
|
return fmt.Errorf("block %v is missing from the side "+
|
|
|
|
"chain block cache", n.hash)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// Perform several checks to verify each block that needs to be attached
|
|
|
|
// to the main chain can be connected without violating any rules and
|
|
|
|
// without actually connecting the block.
|
|
|
|
//
|
|
|
|
// NOTE: bitcoind does these checks directly when it connects a block.
|
|
|
|
// The downside to that approach is that if any of these checks fail
|
|
|
|
// after disconneting some blocks or attaching others, all of the
|
|
|
|
// operations have to be rolled back to get the chain back into the
|
|
|
|
// state it was before the rule violation (or other failure). There are
|
|
|
|
// at least a couple of ways accomplish that rollback, but both involve
|
|
|
|
// tweaking the chain. This approach catches these issues before ever
|
|
|
|
// modifying the chain.
|
|
|
|
for e := attachNodes.Front(); e != nil; e = e.Next() {
|
|
|
|
n := e.Value.(*blockNode)
|
|
|
|
block := b.blockCache[*n.hash]
|
|
|
|
err := b.checkConnectBlock(n, block)
|
|
|
|
if err != nil {
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
// Disconnect blocks from the main chain.
|
|
|
|
for e := detachNodes.Front(); e != nil; e = e.Next() {
|
|
|
|
n := e.Value.(*blockNode)
|
|
|
|
block, err := b.db.FetchBlockBySha(n.hash)
|
|
|
|
if err != nil {
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
err = b.disconnectBlock(n, block)
|
|
|
|
if err != nil {
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// Connect the new best chain blocks.
|
|
|
|
for e := attachNodes.Front(); e != nil; e = e.Next() {
|
|
|
|
n := e.Value.(*blockNode)
|
|
|
|
block := b.blockCache[*n.hash]
|
|
|
|
err := b.connectBlock(n, block)
|
|
|
|
if err != nil {
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
delete(b.blockCache, *n.hash)
|
|
|
|
}
|
|
|
|
|
|
|
|
return nil
|
|
|
|
}
|
|
|
|
|
|
|
|
// connectBestChain handles connecting the passed block to the chain while
|
|
|
|
// respecting proper chain selection according to the chain with the most
|
|
|
|
// proof of work. In the typical case, the new block simply extends the main
|
|
|
|
// 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.
|
|
|
|
func (b *BlockChain) connectBestChain(node *blockNode, block *btcutil.Block) error {
|
|
|
|
// 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) {
|
|
|
|
// Perform several checks to verify the block can be connected
|
|
|
|
// to the main chain (including whatever reorganization might
|
|
|
|
// be necessary to get this node to the main chain) without
|
|
|
|
// violating any rules and without actually connecting the
|
|
|
|
// block.
|
|
|
|
err := b.checkConnectBlock(node, block)
|
|
|
|
if err != nil {
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
|
|
|
|
// Connect the block to the main chain.
|
|
|
|
err = b.connectBlock(node, block)
|
|
|
|
if err != nil {
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
|
|
|
|
// Connect the parent node to this node.
|
|
|
|
if node.parent != nil {
|
|
|
|
node.parent.children = append(node.parent.children, node)
|
|
|
|
}
|
|
|
|
|
|
|
|
return nil
|
|
|
|
}
|
|
|
|
|
|
|
|
// We're extending (or creating) a side chain which may or may not
|
|
|
|
// become the main chain, but in either case we need the block stored
|
|
|
|
// for future processing, so add the block to the side chain holding
|
|
|
|
// cache.
|
|
|
|
log.Debugf("Adding block %v to side chain cache", node.hash)
|
|
|
|
b.blockCache[*node.hash] = block
|
|
|
|
b.index[*node.hash] = node
|
|
|
|
|
|
|
|
// We're extending (or creating) a side chain, but the cumulative
|
|
|
|
// work for this new side chain is not enough to make it the new chain.
|
|
|
|
if node.workSum.Cmp(b.bestChain.workSum) <= 0 {
|
|
|
|
// Connect the parent node to this node.
|
|
|
|
node.inMainChain = false
|
|
|
|
if node.parent != nil {
|
|
|
|
node.parent.children = append(node.parent.children, node)
|
|
|
|
}
|
|
|
|
return nil
|
|
|
|
}
|
|
|
|
|
|
|
|
// We're extending (or creating) a side chain and the cumulative work
|
|
|
|
// for this new side chain is more than the old best chain, so this side
|
|
|
|
// chain needs to become the main chain. In order to accomplish that,
|
|
|
|
// find the common ancestor of both sides of the fork, disconnect the
|
|
|
|
// blocks that form the (now) old fork from the main chain, and attach
|
|
|
|
// the blocks that form the new chain to the main chain starting at the
|
|
|
|
// common ancenstor (the point where the chain forked).
|
|
|
|
detachNodes, attachNodes := b.getReorganizeNodes(node)
|
|
|
|
|
|
|
|
// Reorganize the chain.
|
|
|
|
err := b.reorganizeChain(detachNodes, attachNodes)
|
|
|
|
if err != nil {
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
|
|
|
|
return nil
|
|
|
|
}
|
|
|
|
|
|
|
|
// New returns a BlockChain instance for the passed bitcoin network using the
|
|
|
|
// provided backing database. It accepts a channel on which asynchronous
|
|
|
|
// notifications will be sent when various events take place. See the
|
|
|
|
// documentation for Notification and NotificationType for details on the
|
|
|
|
// types and contents of notifications. The provided channel can be nil if the
|
|
|
|
// caller is not interested in receiving notifications.
|
|
|
|
func New(db btcdb.Db, btcnet btcwire.BitcoinNet, c chan *Notification) *BlockChain {
|
|
|
|
b := BlockChain{
|
|
|
|
db: db,
|
|
|
|
btcnet: btcnet,
|
|
|
|
notifications: c,
|
|
|
|
root: nil,
|
|
|
|
bestChain: nil,
|
|
|
|
index: make(map[btcwire.ShaHash]*blockNode),
|
|
|
|
depNodes: make(map[btcwire.ShaHash][]*blockNode),
|
|
|
|
orphans: make(map[btcwire.ShaHash]*orphanBlock),
|
|
|
|
prevOrphans: make(map[btcwire.ShaHash][]*orphanBlock),
|
|
|
|
blockCache: make(map[btcwire.ShaHash]*btcutil.Block),
|
|
|
|
}
|
|
|
|
return &b
|
|
|
|
}
|