Add support for params based on active network.

This commit modifies the code to use params based on the active network
which paves the way for supporting the special rules and different genesis
blocks used by the test networks.
This commit is contained in:
Dave Collins 2013-07-24 11:37:45 -05:00
parent 3c4292fae3
commit f219ed5baf
9 changed files with 117 additions and 28 deletions

View file

@ -32,7 +32,7 @@ func (b *BlockChain) maybeAcceptBlock(block *btcutil.Block) error {
// calculated difficulty based on the previous block and difficulty
// retarget rules.
blockHeader := block.MsgBlock().Header
expectedDifficulty, err := b.calcNextRequiredDifficulty(prevNode)
expectedDifficulty, err := b.calcNextRequiredDifficulty(prevNode, block)
if err != nil {
return err
}

View file

@ -339,7 +339,7 @@ func (b *BlockChain) getPrevNodeFromNode(node *blockNode) (*blockNode, error) {
}
// Genesis block.
if node.hash.IsEqual(&btcwire.GenesisHash) {
if node.hash.IsEqual(b.netParams().genesisHash) {
return nil, nil
}
@ -393,7 +393,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 btcwire.GenesisBlock.Header.Timestamp, nil
return b.netParams().genesisBlock.Header.Timestamp, nil
}
// Create a slice of the previous few block timestamps used to calculate

View file

@ -6,6 +6,7 @@ package btcchain
import (
"fmt"
"github.com/conformal/btcutil"
"github.com/conformal/btcwire"
"math/big"
"time"
@ -50,10 +51,6 @@ var (
// oneLsh256 is 1 shifted left 256 bits. It is defined here to avoid
// the overhead of creating it multiple times.
oneLsh256 = new(big.Int).Lsh(bigOne, 256)
// powLimit is the highest proof of work value a bitcoin block can have.
// It is the value 2^224 - 1.
powLimit = new(big.Int).Sub(new(big.Int).Lsh(bigOne, 224), bigOne)
)
// ShaHashToBig converts a btcwire.ShaHash into a big.Int that can be used to
@ -185,11 +182,14 @@ func calcWork(bits uint32) *big.Rat {
// can have given starting difficulty bits and a duration. It is mainly used to
// verify that claimed proof of work by a block is sane as compared to a
// known good checkpoint.
func calcEasiestDifficulty(bits uint32, duration time.Duration) uint32 {
func (b *BlockChain) calcEasiestDifficulty(bits uint32, duration time.Duration) uint32 {
// Convert types used in the calculations below.
durationVal := int64(duration)
adjustmentFactor := big.NewInt(retargetAdjustmentFactor)
// Choose the correct proof of work limit for the active network.
powLimit := b.netParams().powLimit
// TODO(davec): Testnet has special rules.
// Since easier difficulty equates to higher numbers, the easiest
@ -212,7 +212,10 @@ func calcEasiestDifficulty(bits uint32, duration time.Duration) uint32 {
// calcNextRequiredDifficulty calculates the required difficulty for the block
// after the passed previous block node based on the difficulty retarget rules.
func (b *BlockChain) calcNextRequiredDifficulty(lastNode *blockNode) (uint32, error) {
func (b *BlockChain) calcNextRequiredDifficulty(lastNode *blockNode, block *btcutil.Block) (uint32, error) {
// Choose the correct proof of work limit for the active network.
powLimit := b.netParams().powLimit
// Genesis block.
if lastNode == nil {
return BigToCompact(powLimit), nil

View file

@ -18,8 +18,8 @@ import (
// TstCheckBlockSanity makes the internal checkBlockSanity function available to
// the test package.
func TstCheckBlockSanity(block *btcutil.Block) error {
return checkBlockSanity(block)
func (b *BlockChain) TstCheckBlockSanity(block *btcutil.Block) error {
return b.checkBlockSanity(block)
}
// TstSetCoinbaseMaturity makes the ability to set the coinbase maturity

68
params.go Normal file
View file

@ -0,0 +1,68 @@
// 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 (
"github.com/conformal/btcwire"
"math/big"
)
// params is used to group parameters for various networks such as the main
// network and test networks.
type params struct {
genesisBlock *btcwire.MsgBlock
genesisHash *btcwire.ShaHash
powLimit *big.Int
}
// mainNetParams contains parameters specific to the main network
// (btcwire.MainNet).
var mainNetParams = params{
genesisBlock: &btcwire.GenesisBlock,
genesisHash: &btcwire.GenesisHash,
// powLimit is the highest proof of work value a bitcoin block can have.
// It is the value 2^224 - 1 for the main network.
powLimit: new(big.Int).Sub(new(big.Int).Lsh(bigOne, 224), bigOne),
}
// regressionParams contains parameters specific to the regression test network
// (btcwire.TestNet).
var regressionParams = params{
genesisBlock: &btcwire.TestNetGenesisBlock,
genesisHash: &btcwire.TestNetGenesisHash,
// powLimit is the highest proof of work value a bitcoin block can have.
// It is the value 2^256 - 1 for the regression test network.
powLimit: new(big.Int).Sub(new(big.Int).Lsh(bigOne, 255), bigOne),
}
// testNet3Params contains parameters specific to the test network (version 3)
// (btcwire.TestNet3).
var testNet3Params = params{
genesisBlock: &btcwire.TestNet3GenesisBlock,
genesisHash: &btcwire.TestNet3GenesisHash,
// powLimit is the highest proof of work value a bitcoin block can have.
// It is the value 2^224 - 1 for the test network (version 3).
powLimit: new(big.Int).Sub(new(big.Int).Lsh(bigOne, 224), bigOne),
}
// netParams returns parameters specific to the passed bitcoin network.
func (b *BlockChain) netParams() *params {
switch b.btcnet {
case btcwire.TestNet:
return &regressionParams
case btcwire.TestNet3:
return &testNet3Params
// Return main net by default.
case btcwire.MainNet:
fallthrough
default:
return &mainNetParams
}
}

View file

@ -95,7 +95,7 @@ func (b *BlockChain) ProcessBlock(block *btcutil.Block) error {
}
// Perform preliminary sanity checks on the block and its transactions.
err = checkBlockSanity(block)
err = b.checkBlockSanity(block)
if err != nil {
return err
}
@ -129,7 +129,7 @@ func (b *BlockChain) ProcessBlock(block *btcutil.Block) error {
// expected based on elapsed time since the last checkpoint and
// maximum adjustment allowed by the retarget rules.
duration := blockHeader.Timestamp.Sub(checkpointTime)
requiredTarget := CompactToBig(calcEasiestDifficulty(
requiredTarget := CompactToBig(b.calcEasiestDifficulty(
checkpointHeader.Bits, duration))
currentTarget := CompactToBig(blockHeader.Bits)
if currentTarget.Cmp(requiredTarget) > 0 {

View file

@ -2,21 +2,21 @@
github.com/conformal/btcchain/chain.go BlockChain.removeOrphanBlock 100.00% (12/12)
github.com/conformal/btcchain/chain.go BlockChain.getOrphanRoot 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/merkle.go nextPowerOfTwo 100.00% (4/4)
github.com/conformal/btcchain/chain.go newBlockNode 100.00% (4/4)
github.com/conformal/btcchain/difficulty.go calcWork 100.00% (3/3)
github.com/conformal/btcchain/process.go BlockChain.blockExists 100.00% (3/3)
github.com/conformal/btcchain/chain.go New 100.00% (2/2)
github.com/conformal/btcchain/checkpoints.go newShaHashFromStr 100.00% (2/2)
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/timesorter.go timeSorter.Less 100.00% (1/1)
github.com/conformal/btcchain/log.go init 100.00% (1/1)
github.com/conformal/btcchain/timesorter.go timeSorter.Swap 100.00% (1/1)
github.com/conformal/btcchain/checkpoints.go BlockChain.DisableCheckpoints 100.00% (1/1)
github.com/conformal/btcchain/timesorter.go timeSorter.Less 100.00% (1/1)
github.com/conformal/btcchain/timesorter.go timeSorter.Len 100.00% (1/1)
github.com/conformal/btcchain/log.go init 100.00% (1/1)
github.com/conformal/btcchain/log.go DisableLog 100.00% (1/1)
github.com/conformal/btcchain/merkle.go BuildMerkleTreeStore 94.12% (16/17)
github.com/conformal/btcchain/chain.go BlockChain.getReorganizeNodes 92.86% (13/14)
github.com/conformal/btcchain/process.go BlockChain.processOrphans 91.67% (11/12)
@ -37,30 +37,31 @@ github.com/conformal/btcchain/chain.go BlockChain.disconnectBlock 76.92% (10
github.com/conformal/btcchain/chain.go BlockChain.addOrphanBlock 75.00% (12/16)
github.com/conformal/btcchain/difficulty.go CompactToBig 75.00% (9/12)
github.com/conformal/btcchain/validate.go BlockChain.checkConnectBlock 68.52% (37/54)
github.com/conformal/btcchain/validate.go checkBlockSanity 66.67% (30/45)
github.com/conformal/btcchain/validate.go BlockChain.checkBlockSanity 66.67% (30/45)
github.com/conformal/btcchain/validate.go isNullOutpoint 66.67% (2/3)
github.com/conformal/btcchain/scriptval.go validateTxIn 64.71% (11/17)
github.com/conformal/btcchain/validate.go checkTransactionInputs 63.64% (28/44)
github.com/conformal/btcchain/validate.go checkTransactionSanity 62.16% (23/37)
github.com/conformal/btcchain/txlookup.go connectTransactions 60.00% (9/15)
github.com/conformal/btcchain/validate.go isBIP0030Node 60.00% (3/5)
github.com/conformal/btcchain/params.go BlockChain.netParams 60.00% (3/5)
github.com/conformal/btcchain/process.go BlockChain.ProcessBlock 59.09% (26/44)
github.com/conformal/btcchain/validate.go BlockChain.checkProofOfWork 58.82% (10/17)
github.com/conformal/btcchain/validate.go BlockChain.checkBIP0030 57.14% (8/14)
github.com/conformal/btcchain/validate.go checkProofOfWork 56.25% (9/16)
github.com/conformal/btcchain/chain.go BlockChain.loadBlockNode 50.00% (11/22)
github.com/conformal/btcchain/notifications.go BlockChain.sendNotification 50.00% (2/4)
github.com/conformal/btcchain/checkpoints.go BlockChain.LatestCheckpoint 50.00% (2/4)
github.com/conformal/btcchain/notifications.go BlockChain.sendNotification 50.00% (2/4)
github.com/conformal/btcchain/accept.go BlockChain.maybeAcceptBlock 49.23% (32/65)
github.com/conformal/btcchain/chain.go BlockChain.getPrevNodeFromNode 33.33% (4/12)
github.com/conformal/btcchain/checkpoints.go BlockChain.verifyCheckpoint 33.33% (2/6)
github.com/conformal/btcchain/validate.go isFinalizedTransaction 23.08% (3/13)
github.com/conformal/btcchain/checkpoints.go BlockChain.findLatestKnownCheckpoint 18.18% (2/11)
github.com/conformal/btcchain/difficulty.go BlockChain.calcNextRequiredDifficulty 10.71% (3/28)
github.com/conformal/btcchain/difficulty.go BlockChain.calcNextRequiredDifficulty 13.79% (4/29)
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/difficulty.go BigToCompact 0.00% (0/16)
github.com/conformal/btcchain/validate.go checkSerializedHeight 0.00% (0/12)
github.com/conformal/btcchain/difficulty.go calcEasiestDifficulty 0.00% (0/9)
github.com/conformal/btcchain/difficulty.go BlockChain.calcEasiestDifficulty 0.00% (0/10)
github.com/conformal/btcchain/chain.go removeChildNode 0.00% (0/8)
github.com/conformal/btcchain/log.go SetLogWriter 0.00% (0/7)
github.com/conformal/btcchain/checkpoints.go isNonstandardTransaction 0.00% (0/5)
@ -70,8 +71,8 @@ github.com/conformal/btcchain/notifications.go NotificationType.String 0.00%
github.com/conformal/btcchain/chain.go addChildrenWork 0.00% (0/3)
github.com/conformal/btcchain/log.go UseLogger 0.00% (0/1)
github.com/conformal/btcchain/chain.go BlockChain.DisableVerify 0.00% (0/1)
github.com/conformal/btcchain/log.go logClosure.String 0.00% (0/1)
github.com/conformal/btcchain/process.go RuleError.Error 0.00% (0/1)
github.com/conformal/btcchain/log.go newLogClosure 0.00% (0/1)
github.com/conformal/btcchain ------------------------------------- 59.23% (571/964)
github.com/conformal/btcchain/log.go logClosure.String 0.00% (0/1)
github.com/conformal/btcchain ------------------------------------- 59.26% (576/972)

View file

@ -267,7 +267,7 @@ func checkTransactionSanity(tx *btcwire.MsgTx) error {
// checkProofOfWork ensures the block header bits which indicate the target
// difficulty is in min/max range and that the block hash is less than the
// target difficulty as claimed.
func checkProofOfWork(block *btcutil.Block) error {
func (b *BlockChain) checkProofOfWork(block *btcutil.Block) error {
// The target difficulty must be larger than zero.
header := block.MsgBlock().Header
target := CompactToBig(header.Bits)
@ -278,6 +278,7 @@ func checkProofOfWork(block *btcutil.Block) error {
}
// The target difficulty must be less than the maximum allowed.
powLimit := b.netParams().powLimit
if target.Cmp(powLimit) > 0 {
str := fmt.Sprintf("block target difficulty of %064x is "+
"higher than max of %064x", target, powLimit)
@ -407,7 +408,7 @@ func countP2SHSigOps(msgTx *btcwire.MsgTx, isCoinBaseTx bool, txStore map[btcwir
// checkBlockSanity performs some preliminary checks on a block to ensure it is
// sane before continuing with block processing. These checks are context free.
func checkBlockSanity(block *btcutil.Block) error {
func (b *BlockChain) checkBlockSanity(block *btcutil.Block) error {
// NOTE: bitcoind does size limits checking here, but the size limits
// have already been checked by btcwire for incoming blocks. Also,
// btcwire checks the size limits on send too, so there is no need
@ -416,7 +417,7 @@ func checkBlockSanity(block *btcutil.Block) error {
// Ensure the proof of work bits in the block header is in min/max range
// and the block hash is less than the target value described by the
// bits.
err := checkProofOfWork(block)
err := b.checkProofOfWork(block)
if err != nil {
return err
}

View file

@ -6,15 +6,31 @@ package btcchain_test
import (
"github.com/conformal/btcchain"
"github.com/conformal/btcdb"
"github.com/conformal/btcutil"
"github.com/conformal/btcwire"
"os"
"testing"
"time"
)
func TestCheckBlockSanity(t *testing.T) {
// Create a new test database.
dbName := "cbsanitytest.db"
_ = os.Remove(dbName)
db, err := btcdb.CreateDB("sqlite", dbName)
if err != nil {
t.Errorf("Error creating db: %v\n", err)
}
defer os.Remove(dbName)
defer db.Close()
// Create a new BlockChain instance using the underlying database for
// the main bitcoin network and ignore notifications.
chain := btcchain.New(db, btcwire.MainNet, nil)
block := btcutil.NewBlock(&Block100000, btcwire.ProtocolVersion)
err := btcchain.TstCheckBlockSanity(block)
err = chain.TstCheckBlockSanity(block)
if err != nil {
t.Errorf("CheckBlockSanity: %v", err)
}