diff --git a/accept.go b/accept.go index e3087fff5..a10035e0a 100644 --- a/accept.go +++ b/accept.go @@ -7,7 +7,6 @@ package btcchain import ( "fmt" "github.com/conformal/btcutil" - "github.com/conformal/btcwire" ) // maybeAcceptBlock potentially accepts a block into the memory block chain. @@ -109,21 +108,12 @@ func (b *BlockChain) maybeAcceptBlock(block *btcutil.Block, fastAdd bool) error if !fastAdd { // Reject version 1 blocks once a majority of the network has - // upgraded. - // Rules: - // 95% (950 / 1000) for main network - // 75% (75 / 100) for the test network - // This is part of BIP_0034. + // upgraded. This is part of BIP0034. if blockHeader.Version == 1 { - minRequired := uint64(950) - numToCheck := uint64(1000) - if b.btcnet == btcwire.TestNet3 || b.btcnet == - btcwire.TestNet { - minRequired = 75 - numToCheck = 100 - } - if b.isMajorityVersion(2, prevNode, minRequired, - numToCheck) { + if b.isMajorityVersion(2, prevNode, + b.netParams.BlockV1RejectNumRequired, + b.netParams.BlockV1RejectNumToCheck) { + str := "new blocks with version %d are no longer valid" str = fmt.Sprintf(str, blockHeader.Version) return RuleError(str) @@ -132,21 +122,13 @@ func (b *BlockChain) maybeAcceptBlock(block *btcutil.Block, fastAdd bool) error // Ensure coinbase starts with serialized block heights for // blocks whose version is the serializedHeightVersion or - // newer once a majority of the network has upgraded. - // Rules: - // 75% (750 / 1000) for main network - // 51% (51 / 100) for the test network - // This is part of BIP_0034. + // newer once a majority of the network has upgraded. This is + // part of BIP0034. if blockHeader.Version >= serializedHeightVersion { - minRequired := uint64(750) - numToCheck := uint64(1000) - if b.btcnet == btcwire.TestNet3 || b.btcnet == - btcwire.TestNet { - minRequired = 51 - numToCheck = 100 - } if b.isMajorityVersion(serializedHeightVersion, - prevNode, minRequired, numToCheck) { + prevNode, + b.netParams.CoinbaseBlockHeightNumRequired, + b.netParams.CoinbaseBlockHeightNumToCheck) { expectedHeight := int64(0) if prevNode != nil { diff --git a/blocklocator.go b/blocklocator.go index 5a1dd1501..136236cb2 100644 --- a/blocklocator.go +++ b/blocklocator.go @@ -41,7 +41,7 @@ func (b *BlockChain) BlockLocatorFromHash(hash *btcwire.ShaHash) BlockLocator { locator = append(locator, hash) // Nothing more to do if a locator for the genesis hash was requested. - if hash.IsEqual(b.chainParams().GenesisHash) { + if hash.IsEqual(b.netParams.GenesisHash) { return locator } @@ -124,7 +124,7 @@ func (b *BlockChain) BlockLocatorFromHash(hash *btcwire.ShaHash) BlockLocator { } // Append the appropriate genesis block. - locator = append(locator, b.chainParams().GenesisHash) + locator = append(locator, b.netParams.GenesisHash) return locator } diff --git a/chain.go b/chain.go index a587ac24f..f78506a98 100644 --- a/chain.go +++ b/chain.go @@ -9,6 +9,7 @@ import ( "errors" "fmt" "github.com/conformal/btcdb" + "github.com/conformal/btcnet" "github.com/conformal/btcutil" "github.com/conformal/btcwire" "math/big" @@ -140,22 +141,23 @@ func removeChildNode(children []*blockNode, node *blockNode) []*blockNode { // follow all rules, orphan handling, checkpoint handling, and best chain // selection with reorganization. type BlockChain struct { - db btcdb.Db - btcnet btcwire.BitcoinNet - notifications NotificationCallback - 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 - orphanLock sync.RWMutex - blockCache map[btcwire.ShaHash]*btcutil.Block - noVerify bool - noCheckpoints bool - nextCheckpoint *Checkpoint - checkpointBlock *btcutil.Block + db btcdb.Db + netParams *btcnet.Params + checkpointsByHeight map[int64]*btcnet.Checkpoint + notifications NotificationCallback + 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 + orphanLock sync.RWMutex + blockCache map[btcwire.ShaHash]*btcutil.Block + noVerify bool + noCheckpoints bool + nextCheckpoint *btcnet.Checkpoint + checkpointBlock *btcutil.Block } // DisableVerify provides a mechanism to disable transaction script validation @@ -500,7 +502,7 @@ func (b *BlockChain) getPrevNodeFromNode(node *blockNode) (*blockNode, error) { } // Genesis block. - if node.hash.IsEqual(b.chainParams().GenesisHash) { + if node.hash.IsEqual(b.netParams.GenesisHash) { return nil, nil } @@ -633,7 +635,7 @@ func (b *BlockChain) isMajorityVersion(minVer uint32, startNode *blockNode, numR func (b *BlockChain) calcPastMedianTime(startNode *blockNode) (time.Time, error) { // Genesis block. if startNode == nil { - return b.chainParams().GenesisBlock.Header.Timestamp, nil + return b.netParams.GenesisBlock.Header.Timestamp, nil } // Create a slice of the previous few block timestamps used to calculate @@ -1015,18 +1017,29 @@ func (b *BlockChain) IsCurrent() bool { // Notification and NotificationType for details on the types and contents of // notifications. The provided callback can be nil if the caller is not // interested in receiving notifications. -func New(db btcdb.Db, btcnet btcwire.BitcoinNet, c NotificationCallback) *BlockChain { +func New(db btcdb.Db, params *btcnet.Params, c NotificationCallback) *BlockChain { + // Generate a checkpoint by height map from the provided checkpoints. + var checkpointsByHeight map[int64]*btcnet.Checkpoint + if len(params.Checkpoints) > 0 { + checkpointsByHeight = make(map[int64]*btcnet.Checkpoint) + for i := range params.Checkpoints { + checkpoint := ¶ms.Checkpoints[i] + checkpointsByHeight[checkpoint.Height] = checkpoint + } + } + 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), + db: db, + netParams: params, + checkpointsByHeight: checkpointsByHeight, + 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 } diff --git a/checkpoints.go b/checkpoints.go index 696dbdb09..0b6dbc2a7 100644 --- a/checkpoints.go +++ b/checkpoints.go @@ -6,6 +6,7 @@ package btcchain import ( "fmt" + "github.com/conformal/btcnet" "github.com/conformal/btcscript" "github.com/conformal/btcutil" "github.com/conformal/btcwire" @@ -15,64 +16,6 @@ import ( // best block chain that a good checkpoint candidate must be. const CheckpointConfirmations = 2016 -// Checkpoint identifies a known good point in the block chain. Using -// checkpoints allows a few optimizations for old blocks during initial download -// and also prevents forks from old blocks. -// -// Each checkpoint is selected by the core developers based upon several -// factors. See the documentation for IsCheckpointCandidate for details -// on the selection criteria. -// -// As alluded to above, this package provides an IsCheckpointCandidate function -// which programatically identifies a block as a checkpoint candidate. The idea -// is that candidates are reviewed by a developer to make the final decision and -// then manually added to the list of checkpoints. -type Checkpoint struct { - Height int64 - Hash *btcwire.ShaHash -} - -// checkpointData groups checkpoints and other pertinent checkpoint data into -// a single type. -type checkpointData struct { - // Checkpoints ordered from oldest to newest. - checkpoints []Checkpoint - - // A map that will be automatically generated with the heights from - // the checkpoints as keys. - checkpointsByHeight map[int64]*Checkpoint -} - -// checkpointDataMainNet contains checkpoint data for the main network. -var checkpointDataMainNet = checkpointData{ - checkpoints: []Checkpoint{ - {11111, newShaHashFromStr("0000000069e244f73d78e8fd29ba2fd2ed618bd6fa2ee92559f542fdb26e7c1d")}, - {33333, newShaHashFromStr("000000002dd5588a74784eaa7ab0507a18ad16a236e7b1ce69f00d7ddfb5d0a6")}, - {74000, newShaHashFromStr("0000000000573993a3c9e41ce34471c079dcf5f52a0e824a81e7f953b8661a20")}, - {105000, newShaHashFromStr("00000000000291ce28027faea320c8d2b054b2e0fe44a773f3eefb151d6bdc97")}, - {134444, newShaHashFromStr("00000000000005b12ffd4cd315cd34ffd4a594f430ac814c91184a0d42d2b0fe")}, - {168000, newShaHashFromStr("000000000000099e61ea72015e79632f216fe6cb33d7899acb35b75c8303b763")}, - {193000, newShaHashFromStr("000000000000059f452a5f7340de6682a977387c17010ff6e6c3bd83ca8b1317")}, - {210000, newShaHashFromStr("000000000000048b95347e83192f69cf0366076336c639f9b7228e9ba171342e")}, - {216116, newShaHashFromStr("00000000000001b4f4b433e81ee46494af945cf96014816a4e2370f11b23df4e")}, - {225430, newShaHashFromStr("00000000000001c108384350f74090433e7fcf79a606b8e797f065b130575932")}, - {250000, newShaHashFromStr("000000000000003887df1f29024b06fc2200b55f8af8f35453d7be294df2d214")}, - {267300, newShaHashFromStr("000000000000000a83fbd660e918f218bf37edd92b748ad940483c7c116179ac")}, - {279000, newShaHashFromStr("0000000000000001ae8c72a0b0c301f67e3afca10e819efa9041e458e9bd7e40")}, - {300255, newShaHashFromStr("0000000000000000162804527c6e9b9f0563a280525f9d08c12041def0a0f3b2")}, - }, - checkpointsByHeight: nil, // Automatically generated in init. -} - -// checkpointDataTestNet3 contains checkpoint data for the test network (version -// 3). -var checkpointDataTestNet3 = checkpointData{ - checkpoints: []Checkpoint{ - {546, newShaHashFromStr("000000002a936ca763904c3c35fce2f3556c559c0214345d31b1bcebf76acb70")}, - }, - checkpointsByHeight: nil, // Automatically generated in init. -} - // newShaHashFromStr converts the passed big-endian hex string into a // btcwire.ShaHash. It only differs from the one available in btcwire in that // it ignores the error since it will only (and must only) be called with @@ -89,38 +32,26 @@ func (b *BlockChain) DisableCheckpoints(disable bool) { b.noCheckpoints = disable } -// checkpointData returns the appropriate checkpoint data set depending on the -// network configured for the block chain. -func (b *BlockChain) checkpointData() *checkpointData { - switch b.btcnet { - case btcwire.TestNet3: - return &checkpointDataTestNet3 - case btcwire.MainNet: - return &checkpointDataMainNet - } - return nil -} - // Checkpoints returns a slice of checkpoints (regardless of whether they are // already known). When checkpoints are disabled or there are no checkpoints // for the active network, it will return nil. -func (b *BlockChain) Checkpoints() []Checkpoint { - if b.noCheckpoints || b.checkpointData() == nil { +func (b *BlockChain) Checkpoints() []btcnet.Checkpoint { + if b.noCheckpoints || len(b.netParams.Checkpoints) == 0 { return nil } - return b.checkpointData().checkpoints + return b.netParams.Checkpoints } // LatestCheckpoint returns the most recent checkpoint (regardless of whether it // is already known). When checkpoints are disabled or there are no checkpoints // for the active network, it will return nil. -func (b *BlockChain) LatestCheckpoint() *Checkpoint { - if b.noCheckpoints || b.checkpointData() == nil { +func (b *BlockChain) LatestCheckpoint() *btcnet.Checkpoint { + if b.noCheckpoints || len(b.netParams.Checkpoints) == 0 { return nil } - checkpoints := b.checkpointData().checkpoints + checkpoints := b.netParams.Checkpoints return &checkpoints[len(checkpoints)-1] } @@ -128,12 +59,12 @@ func (b *BlockChain) LatestCheckpoint() *Checkpoint { // match the hard-coded checkpoint data. It also returns true if there is no // checkpoint data for the passed block height. func (b *BlockChain) verifyCheckpoint(height int64, hash *btcwire.ShaHash) bool { - if b.noCheckpoints || b.checkpointData() == nil { + if b.noCheckpoints || len(b.netParams.Checkpoints) == 0 { return true } // Nothing to check if there is no checkpoint data for the block height. - checkpoint, exists := b.checkpointData().checkpointsByHeight[height] + checkpoint, exists := b.checkpointsByHeight[height] if !exists { return true } @@ -152,12 +83,12 @@ func (b *BlockChain) verifyCheckpoint(height int64, hash *btcwire.ShaHash) bool // associated block. It returns nil if a checkpoint can't be found (this should // really only happen for blocks before the first checkpoint). func (b *BlockChain) findPreviousCheckpoint() (*btcutil.Block, error) { - if b.noCheckpoints || b.checkpointData() == nil { + if b.noCheckpoints || len(b.netParams.Checkpoints) == 0 { return nil, nil } // No checkpoints. - checkpoints := b.checkpointData().checkpoints + checkpoints := b.netParams.Checkpoints numCheckpoints := len(checkpoints) if numCheckpoints == 0 { return nil, nil @@ -275,6 +206,9 @@ func isNonstandardTransaction(tx *btcutil.Tx) bool { // (due to the median time allowance this is not always the case) // - The block must not contain any strange transaction such as those with // nonstandard scripts +// +// The intent is that candidates are reviewed by a developer to make the final +// decision and then manually added to the list of checkpoints for a network. func (b *BlockChain) IsCheckpointCandidate(block *btcutil.Block) (bool, error) { // Checkpoints must be enabled. if b.noCheckpoints { @@ -339,20 +273,3 @@ func (b *BlockChain) IsCheckpointCandidate(block *btcutil.Block) (bool, error) { return true, nil } - -// init is called on package load. -func init() { - // Generate the checkpoint by height maps from the checkpoint data - // when the package loads. - checkpointInitializeList := []*checkpointData{ - &checkpointDataMainNet, - &checkpointDataTestNet3, - } - for _, data := range checkpointInitializeList { - data.checkpointsByHeight = make(map[int64]*Checkpoint) - for i := range data.checkpoints { - checkpoint := &data.checkpoints[i] - data.checkpointsByHeight[checkpoint.Height] = checkpoint - } - } -} diff --git a/common_test.go b/common_test.go index d84d9f936..b98592b1b 100644 --- a/common_test.go +++ b/common_test.go @@ -10,6 +10,7 @@ import ( "github.com/conformal/btcdb" _ "github.com/conformal/btcdb/ldb" _ "github.com/conformal/btcdb/memdb" + "github.com/conformal/btcnet" "github.com/conformal/btcutil" "github.com/conformal/btcwire" "os" @@ -110,6 +111,6 @@ func chainSetup(dbName string) (*btcchain.BlockChain, func(), error) { return nil, nil, err } - chain := btcchain.New(db, btcwire.MainNet, nil) + chain := btcchain.New(db, btcnet.MainNetParams, nil) return chain, teardown, nil } diff --git a/difficulty.go b/difficulty.go index 99168aea0..08a110ef5 100644 --- a/difficulty.go +++ b/difficulty.go @@ -193,19 +193,12 @@ func (b *BlockChain) calcEasiestDifficulty(bits uint32, duration time.Duration) durationVal := int64(duration) adjustmentFactor := big.NewInt(retargetAdjustmentFactor) - // Choose the correct proof of work limit for the active network. - powLimit := b.chainParams().PowLimit - powLimitBits := b.chainParams().PowLimitBits - // The test network rules allow minimum difficulty blocks after more // than twice the desired amount of time needed to generate a block has // elapsed. - switch b.btcnet { - case btcwire.TestNet: - fallthrough - case btcwire.TestNet3: + if b.netParams.ResetMinDifficulty { if durationVal > int64(targetSpacing)*2 { - return powLimitBits + return b.netParams.PowLimitBits } } @@ -214,14 +207,14 @@ func (b *BlockChain) calcEasiestDifficulty(bits uint32, duration time.Duration) // the number of retargets for the duration and starting difficulty // multiplied by the max adjustment factor. newTarget := CompactToBig(bits) - for durationVal > 0 && newTarget.Cmp(powLimit) < 0 { + for durationVal > 0 && newTarget.Cmp(b.netParams.PowLimit) < 0 { newTarget.Mul(newTarget, adjustmentFactor) durationVal -= maxRetargetTimespan } // Limit new value to the proof of work limit. - if newTarget.Cmp(powLimit) > 0 { - newTarget.Set(powLimit) + if newTarget.Cmp(b.netParams.PowLimit) > 0 { + newTarget.Set(b.netParams.PowLimit) } return BigToCompact(newTarget) @@ -232,9 +225,10 @@ func (b *BlockChain) calcEasiestDifficulty(bits uint32, duration time.Duration) func (b *BlockChain) findPrevTestNetDifficulty(startNode *blockNode) (uint32, error) { // Search backwards through the chain for the last block without // the special rule applied. - powLimitBits := b.chainParams().PowLimitBits iterNode := startNode - for iterNode != nil && iterNode.height%BlocksPerRetarget != 0 && iterNode.bits == powLimitBits { + for iterNode != nil && iterNode.height%BlocksPerRetarget != 0 && + iterNode.bits == b.netParams.PowLimitBits { + // 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 @@ -250,7 +244,7 @@ func (b *BlockChain) findPrevTestNetDifficulty(startNode *blockNode) (uint32, er // Return the found difficulty or the minimum difficulty if no // appropriate block was found. - lastBits := powLimitBits + lastBits := b.netParams.PowLimitBits if iterNode != nil { lastBits = iterNode.bits } @@ -263,32 +257,24 @@ func (b *BlockChain) findPrevTestNetDifficulty(startNode *blockNode) (uint32, er // the exported version uses the current best chain as the previous block node // while this function accepts any block node. func (b *BlockChain) calcNextRequiredDifficulty(lastNode *blockNode, newBlockTime time.Time) (uint32, error) { - // Choose the correct proof of work limit for the active network. - powLimit := b.chainParams().PowLimit - powLimitBits := b.chainParams().PowLimitBits - // Genesis block. if lastNode == nil { - return powLimitBits, nil + return b.netParams.PowLimitBits, nil } // Return the previous block's difficulty requirements if this block // is not at a difficulty retarget interval. if (lastNode.height+1)%BlocksPerRetarget != 0 { - // The difficulty rules differ between networks. - switch b.btcnet { // The test network rules allow minimum difficulty blocks after // more than twice the desired amount of time needed to generate // a block has elapsed. - case btcwire.TestNet: - fallthrough - case btcwire.TestNet3: + if b.netParams.ResetMinDifficulty { // Return minimum difficulty when more than twice the // desired amount of time needed to generate a block has // elapsed. allowMinTime := lastNode.timestamp.Add(targetSpacing * 2) if newBlockTime.After(allowMinTime) { - return powLimitBits, nil + return b.netParams.PowLimitBits, nil } // The block was mined within the desired timeframe, so @@ -299,15 +285,11 @@ func (b *BlockChain) calcNextRequiredDifficulty(lastNode *blockNode, newBlockTim return 0, err } return prevBits, nil + } // For the main network (or any unrecognized networks), simply - // return the previous block's difficulty. - case btcwire.MainNet: - fallthrough - default: - // Return the previous block's difficulty requirements. - return lastNode.bits, nil - } + // return the previous block's difficulty requirements. + return lastNode.bits, nil } // Get the block node at the previous retarget (targetTimespan days @@ -350,8 +332,8 @@ func (b *BlockChain) calcNextRequiredDifficulty(lastNode *blockNode, newBlockTim newTarget.Div(newTarget, big.NewInt(int64(targetTimespan))) // Limit new value to the proof of work limit. - if newTarget.Cmp(powLimit) > 0 { - newTarget.Set(powLimit) + if newTarget.Cmp(b.netParams.PowLimit) > 0 { + newTarget.Set(b.netParams.PowLimit) } // Log new target difficulty and return it. The new target logging is diff --git a/doc.go b/doc.go index 33a27b801..cbe2f9a75 100644 --- a/doc.go +++ b/doc.go @@ -73,8 +73,8 @@ intentionally causes an error by attempting to process a duplicate block. "github.com/conformal/btcchain" "github.com/conformal/btcdb" _ "github.com/conformal/btcdb/ldb" + "github.com/conformal/btcnet" "github.com/conformal/btcutil" - "github.com/conformal/btcwire" "os" ) @@ -85,20 +85,20 @@ intentionally causes an error by attempting to process a duplicate block. // calls to os.Remove would not be used either, but again, we want // a complete working example here, so we make sure to remove the // database. - dbName := "example.db" - _ = os.Remove(dbName) + dbName := "exampledb" + _ = os.RemoveAll(dbName) db, err := btcdb.CreateDB("leveldb", dbName) if err != nil { fmt.Printf("Failed to create database: %v\n", err) return } - defer os.Remove(dbName) // Ignore error. + defer os.RemoveAll(dbName) // Ignore error. defer db.Close() // Insert the main network genesis block. This is part of the initial // database setup. Like above, this typically would not be needed when // opening an existing database. - genesisBlock := btcutil.NewBlock(&btcwire.GenesisBlock) + genesisBlock := btcutil.NewBlock(btcnet.MainNetParams.GenesisBlock) _, err = db.InsertBlock(genesisBlock) if err != nil { fmt.Printf("Failed to insert genesis block: %v\n", err) @@ -107,7 +107,7 @@ intentionally causes an error by attempting to process a duplicate block. // Create a new BlockChain instance using the underlying database for // the main bitcoin network and ignore notifications. - chain := btcchain.New(db, btcwire.MainNet, nil) + chain := btcchain.New(db, btcnet.MainNetParams, nil) // Process a block. For this example, we are going to intentionally // cause an error by trying to process the genesis block which already diff --git a/params.go b/params.go deleted file mode 100644 index 1ce1fec27..000000000 --- a/params.go +++ /dev/null @@ -1,101 +0,0 @@ -// Copyright (c) 2013-2014 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 ( - "github.com/conformal/btcwire" - "math/big" -) - -// Params houses parameters unique to various bitcoin networks such as the main -// network and test networks. See ChainParams. -type Params struct { - // GenesisBlock is the genesis block for the specific network. - GenesisBlock *btcwire.MsgBlock - - // GenesisHash is the genesis block hash for the specific network. - GenesisHash *btcwire.ShaHash - - // PowLimit is the highest proof of work value a bitcoin block can have - // for the specific network. - PowLimit *big.Int - - // PowLimitBits is the highest proof of work value a bitcoin block can - // have represented in compact form. See CompactToBig for more details - // on compact form. - PowLimitBits uint32 - - // SubsidyHalvingInterval is the interval of blocks at which the - // baseSubsidy is continually halved. Mathematically this is: - // baseSubsidy / 2^(height/SubsidyHalvingInterval) - SubsidyHalvingInterval int64 -} - -// mainPowLimit is the highest proof of work value a bitcoin block can have for -// the main network. It is the value 2^224 - 1. -var mainPowLimit = new(big.Int).Sub(new(big.Int).Lsh(bigOne, 224), bigOne) - -// mainNetParams contains parameters specific to the main network -// (btcwire.MainNet). -var mainNetParams = Params{ - GenesisBlock: &btcwire.GenesisBlock, - GenesisHash: &btcwire.GenesisHash, - PowLimit: mainPowLimit, - PowLimitBits: BigToCompact(mainPowLimit), - SubsidyHalvingInterval: 210000, -} - -// regressionPowLimit is the highest proof of work value a bitcoin block can -// have for the regression test network. It is the value 2^255 - 1. -var regressionPowLimit = new(big.Int).Sub(new(big.Int).Lsh(bigOne, 255), bigOne) - -// regressionParams contains parameters specific to the regression test network -// (btcwire.TestNet). -var regressionParams = Params{ - GenesisBlock: &btcwire.TestNetGenesisBlock, - GenesisHash: &btcwire.TestNetGenesisHash, - PowLimit: regressionPowLimit, - PowLimitBits: BigToCompact(regressionPowLimit), - SubsidyHalvingInterval: 150, -} - -// testNetPowLimit is the highest proof of work value a bitcoin block can have -// for the test network (version 3). It is the value 2^224 - 1. -var testNetPowLimit = new(big.Int).Sub(new(big.Int).Lsh(bigOne, 224), bigOne) - -// testNet3Params contains parameters specific to the test network (version 3) -// (btcwire.TestNet3). -var testNet3Params = Params{ - GenesisBlock: &btcwire.TestNet3GenesisBlock, - GenesisHash: &btcwire.TestNet3GenesisHash, - PowLimit: testNetPowLimit, - PowLimitBits: BigToCompact(testNetPowLimit), - SubsidyHalvingInterval: 210000, -} - -// chainParams returns chain parameters specific to the bitcoin network -// associated with the BlockChain instance. -func (b *BlockChain) chainParams() *Params { - return ChainParams(b.btcnet) -} - -// ChainParams returns chain parameters specific to the passed bitcoin network. -// It returns the parameters for btcwire.MainNet if the passed network is not -// supported. -func ChainParams(btcnet btcwire.BitcoinNet) *Params { - switch btcnet { - case btcwire.TestNet: - return ®ressionParams - - case btcwire.TestNet3: - return &testNet3Params - - // Return main net by default. - case btcwire.MainNet: - fallthrough - default: - return &mainNetParams - } -} diff --git a/process.go b/process.go index a9d26a8ca..37d97f585 100644 --- a/process.go +++ b/process.go @@ -112,7 +112,7 @@ func (b *BlockChain) ProcessBlock(block *btcutil.Block, fastAdd bool) error { } // Perform preliminary sanity checks on the block and its transactions. - err = CheckBlockSanity(block, b.chainParams().PowLimit) + err = CheckBlockSanity(block, b.netParams.PowLimit) if err != nil { return err } diff --git a/validate.go b/validate.go index d27387980..f59d31890 100644 --- a/validate.go +++ b/validate.go @@ -8,6 +8,7 @@ import ( "encoding/binary" "fmt" "github.com/conformal/btcdb" + "github.com/conformal/btcnet" "github.com/conformal/btcscript" "github.com/conformal/btcutil" "github.com/conformal/btcwire" @@ -165,10 +166,13 @@ func isBIP0030Node(node *blockNode) bool { // // At the target block generation rate for the main network, this is // approximately every 4 years. -func CalcBlockSubsidy(height int64, btcnet btcwire.BitcoinNet) int64 { +func CalcBlockSubsidy(height int64, netParams *btcnet.Params) int64 { + if netParams.SubsidyHalvingInterval == 0 { + return baseSubsidy + } + // Equivalent to: baseSubsidy / 2^(height/subsidyHalvingInterval) - return baseSubsidy >> - uint(height/ChainParams(btcnet).SubsidyHalvingInterval) + return baseSubsidy >> uint(height/int64(netParams.SubsidyHalvingInterval)) } // CheckTransactionSanity performs some preliminary checks on a transaction to @@ -728,7 +732,7 @@ func (b *BlockChain) checkConnectBlock(node *blockNode, block *btcutil.Block) er // The coinbase for the Genesis block is not spendable, so just return // now. - if node.hash.IsEqual(b.chainParams().GenesisHash) && b.bestChain == nil { + if node.hash.IsEqual(b.netParams.GenesisHash) && b.bestChain == nil { return nil } @@ -836,7 +840,8 @@ func (b *BlockChain) checkConnectBlock(node *blockNode, block *btcutil.Block) er for _, txOut := range transactions[0].MsgTx().TxOut { totalSatoshiOut += txOut.Value } - expectedSatoshiOut := CalcBlockSubsidy(node.height, b.btcnet) + totalFees + expectedSatoshiOut := CalcBlockSubsidy(node.height, b.netParams) + + totalFees if totalSatoshiOut > expectedSatoshiOut { str := fmt.Sprintf("coinbase transaction for block pays %v "+ "which is more than expected value of %v", diff --git a/validate_test.go b/validate_test.go index 0157cedd8..2710e0618 100644 --- a/validate_test.go +++ b/validate_test.go @@ -6,6 +6,7 @@ package btcchain_test import ( "github.com/conformal/btcchain" + "github.com/conformal/btcnet" "github.com/conformal/btcutil" "github.com/conformal/btcwire" "math" @@ -39,7 +40,7 @@ func TestCheckConnectBlock(t *testing.T) { } func TestCheckBlockSanity(t *testing.T) { - powLimit := btcchain.ChainParams(btcwire.MainNet).PowLimit + powLimit := btcnet.MainNetParams.PowLimit block := btcutil.NewBlock(&Block100000) err := btcchain.CheckBlockSanity(block, powLimit) if err != nil {