chaincfg/blockchain: Parameterize more chain consts. (#732)

This moves several of the chain constants to the Params struct in the
chaincfg package which is intended for that purpose.  This is mostly a
backport of the same modifications made in Decred along with a few
additional things cleaned up.

The following is an overview of the changes:

- Comment all fields in the Params struct definition
- Add locals to BlockChain instance for the calculated values based on
  the provided chain params
- Rename the following param fields:
  - SubsidyHalvingInterval -> SubsidyReductionInterval
  - ResetMinDifficulty -> ReduceMinDifficulty
- Add new Param fields:
  - CoinbaseMaturity
  - TargetTimePerBlock
  - TargetTimespan
  - BlocksPerRetarget
  - RetargetAdjustmentFactor
  - MinDiffReductionTime
This commit is contained in:
Dave Collins 2016-08-10 16:02:23 -05:00 committed by GitHub
parent bd4e64d1d4
commit a7b35d9f9e
11 changed files with 183 additions and 123 deletions

View file

@ -24,12 +24,6 @@ const (
// maxOrphanBlocks is the maximum number of orphan blocks that can be // maxOrphanBlocks is the maximum number of orphan blocks that can be
// queued. // queued.
maxOrphanBlocks = 100 maxOrphanBlocks = 100
// minMemoryNodes is the minimum number of consecutive nodes needed
// in memory in order to perform all necessary validation. It is used
// to determine when it's safe to prune nodes from memory without
// causing constant dynamic reloading.
minMemoryNodes = BlocksPerRetarget
) )
// blockNode represents a block within the block chain and is primarily used to // blockNode represents a block within the block chain and is primarily used to
@ -170,6 +164,22 @@ type BlockChain struct {
sigCache *txscript.SigCache sigCache *txscript.SigCache
indexManager IndexManager indexManager IndexManager
// The following fields are calculated based upon the provided chain
// parameters. They are also set when the instance is created and
// can't be changed afterwards, so there is no need to protect them with
// a separate mutex.
//
// minMemoryNodes is the minimum number of consecutive nodes needed
// in memory in order to perform all necessary validation. It is used
// to determine when it's safe to prune nodes from memory without
// causing constant dynamic reloading. This is typically the same value
// as blocksPerRetarget, but it is separated here for tweakability and
// testability.
minRetargetTimespan int64 // target timespan / adjustment factor
maxRetargetTimespan int64 // target timespan * adjustment factor
blocksPerRetarget int32 // target timespan / target time per block
minMemoryNodes int32
// chainLock protects concurrent access to the vast majority of the // chainLock protects concurrent access to the vast majority of the
// fields in this struct below this point. // fields in this struct below this point.
chainLock sync.RWMutex chainLock sync.RWMutex
@ -553,7 +563,7 @@ func (b *BlockChain) pruneBlockNodes() error {
// the latter loads the node and the goal is to find nodes still in // the latter loads the node and the goal is to find nodes still in
// memory that can be pruned. // memory that can be pruned.
newRootNode := b.bestNode newRootNode := b.bestNode
for i := int32(0); i < minMemoryNodes-1 && newRootNode != nil; i++ { for i := int32(0); i < b.minMemoryNodes-1 && newRootNode != nil; i++ {
newRootNode = newRootNode.parent newRootNode = newRootNode.parent
} }
@ -1454,6 +1464,9 @@ func New(config *Config) (*BlockChain, error) {
} }
} }
targetTimespan := int64(params.TargetTimespan)
targetTimePerBlock := int64(params.TargetTimePerBlock)
adjustmentFactor := params.RetargetAdjustmentFactor
b := BlockChain{ b := BlockChain{
checkpointsByHeight: checkpointsByHeight, checkpointsByHeight: checkpointsByHeight,
db: config.DB, db: config.DB,
@ -1462,6 +1475,10 @@ func New(config *Config) (*BlockChain, error) {
notifications: config.Notifications, notifications: config.Notifications,
sigCache: config.SigCache, sigCache: config.SigCache,
indexManager: config.IndexManager, indexManager: config.IndexManager,
minRetargetTimespan: targetTimespan / adjustmentFactor,
maxRetargetTimespan: targetTimespan * adjustmentFactor,
blocksPerRetarget: int32(targetTimespan / targetTimePerBlock),
minMemoryNodes: int32(targetTimespan / targetTimePerBlock),
bestNode: nil, bestNode: nil,
index: make(map[chainhash.Hash]*blockNode), index: make(map[chainhash.Hash]*blockNode),
depNodes: make(map[chainhash.Hash][]*blockNode), depNodes: make(map[chainhash.Hash][]*blockNode),

View file

@ -46,7 +46,7 @@ func TestHaveBlock(t *testing.T) {
// Since we're not dealing with the real block chain, disable // Since we're not dealing with the real block chain, disable
// checkpoints and set the coinbase maturity to 1. // checkpoints and set the coinbase maturity to 1.
chain.DisableCheckpoints(true) chain.DisableCheckpoints(true)
blockchain.TstSetCoinbaseMaturity(1) chain.TstSetCoinbaseMaturity(1)
for i := 1; i < len(blocks); i++ { for i := 1; i < len(blocks); i++ {
isOrphan, err := chain.ProcessBlock(blocks[i], blockchain.BFNone) isOrphan, err := chain.ProcessBlock(blocks[i], blockchain.BFNone)

View file

@ -107,10 +107,14 @@ func chainSetup(dbName string) (*blockchain.BlockChain, func(), error) {
} }
} }
// Copy the chain params to ensure any modifications the tests do to
// the chain parameters do not affect the global instance.
mainNetParams := chaincfg.MainNetParams
// Create the main chain instance. // Create the main chain instance.
chain, err := blockchain.New(&blockchain.Config{ chain, err := blockchain.New(&blockchain.Config{
DB: db, DB: db,
ChainParams: &chaincfg.MainNetParams, ChainParams: &mainNetParams,
TimeSource: blockchain.NewMedianTime(), TimeSource: blockchain.NewMedianTime(),
}) })
if err != nil { if err != nil {

View file

@ -11,37 +11,6 @@ import (
"github.com/btcsuite/btcd/chaincfg/chainhash" "github.com/btcsuite/btcd/chaincfg/chainhash"
) )
const (
// targetTimespan is the desired amount of time that should elapse
// before block difficulty requirement is examined to determine how
// it should be changed in order to maintain the desired block
// generation rate.
targetTimespan = time.Hour * 24 * 14
// targetSpacing is the desired amount of time to generate each block.
targetSpacing = time.Minute * 10
// BlocksPerRetarget is the number of blocks between each difficulty
// retarget. It is calculated based on the desired block generation
// rate.
BlocksPerRetarget = int32(targetTimespan / targetSpacing)
// retargetAdjustmentFactor is the adjustment factor used to limit
// the minimum and maximum amount of adjustment that can occur between
// difficulty retargets.
retargetAdjustmentFactor = 4
// minRetargetTimespan is the minimum amount of adjustment that can
// occur between difficulty retargets. It equates to 25% of the
// previous difficulty.
minRetargetTimespan = int64(targetTimespan / retargetAdjustmentFactor)
// maxRetargetTimespan is the maximum amount of adjustment that can
// occur between difficulty retargets. It equates to 400% of the
// previous difficulty.
maxRetargetTimespan = int64(targetTimespan * retargetAdjustmentFactor)
)
var ( var (
// bigOne is 1 represented as a big.Int. It is defined here to avoid // bigOne is 1 represented as a big.Int. It is defined here to avoid
// the overhead of creating it multiple times. // the overhead of creating it multiple times.
@ -190,13 +159,13 @@ func CalcWork(bits uint32) *big.Int {
func (b *BlockChain) calcEasiestDifficulty(bits uint32, duration time.Duration) uint32 { func (b *BlockChain) calcEasiestDifficulty(bits uint32, duration time.Duration) uint32 {
// Convert types used in the calculations below. // Convert types used in the calculations below.
durationVal := int64(duration) durationVal := int64(duration)
adjustmentFactor := big.NewInt(retargetAdjustmentFactor) adjustmentFactor := big.NewInt(b.chainParams.RetargetAdjustmentFactor)
// The test network rules allow minimum difficulty blocks after more // The test network rules allow minimum difficulty blocks after more
// than twice the desired amount of time needed to generate a block has // than twice the desired amount of time needed to generate a block has
// elapsed. // elapsed.
if b.chainParams.ResetMinDifficulty { if b.chainParams.ReduceMinDifficulty {
if durationVal > int64(targetSpacing)*2 { if durationVal > int64(b.chainParams.MinDiffReductionTime) {
return b.chainParams.PowLimitBits return b.chainParams.PowLimitBits
} }
} }
@ -208,7 +177,7 @@ func (b *BlockChain) calcEasiestDifficulty(bits uint32, duration time.Duration)
newTarget := CompactToBig(bits) newTarget := CompactToBig(bits)
for durationVal > 0 && newTarget.Cmp(b.chainParams.PowLimit) < 0 { for durationVal > 0 && newTarget.Cmp(b.chainParams.PowLimit) < 0 {
newTarget.Mul(newTarget, adjustmentFactor) newTarget.Mul(newTarget, adjustmentFactor)
durationVal -= maxRetargetTimespan durationVal -= b.maxRetargetTimespan
} }
// Limit new value to the proof of work limit. // Limit new value to the proof of work limit.
@ -227,7 +196,7 @@ func (b *BlockChain) findPrevTestNetDifficulty(startNode *blockNode) (uint32, er
// Search backwards through the chain for the last block without // Search backwards through the chain for the last block without
// the special rule applied. // the special rule applied.
iterNode := startNode iterNode := startNode
for iterNode != nil && iterNode.height%BlocksPerRetarget != 0 && for iterNode != nil && iterNode.height%b.blocksPerRetarget != 0 &&
iterNode.bits == b.chainParams.PowLimitBits { iterNode.bits == b.chainParams.PowLimitBits {
// Get the previous block node. This function is used over // Get the previous block node. This function is used over
@ -267,15 +236,15 @@ func (b *BlockChain) calcNextRequiredDifficulty(lastNode *blockNode, newBlockTim
// Return the previous block's difficulty requirements if this block // Return the previous block's difficulty requirements if this block
// is not at a difficulty retarget interval. // is not at a difficulty retarget interval.
if (lastNode.height+1)%BlocksPerRetarget != 0 { if (lastNode.height+1)%b.blocksPerRetarget != 0 {
// The test network rules allow minimum difficulty blocks after // For networks that support it, allow special reduction of the
// more than twice the desired amount of time needed to generate // required difficulty once too much time has elapsed without
// a block has elapsed. // mining a block.
if b.chainParams.ResetMinDifficulty { if b.chainParams.ReduceMinDifficulty {
// Return minimum difficulty when more than twice the // Return minimum difficulty when more than the desired
// desired amount of time needed to generate a block has // amount of time has elapsed without mining a block.
// elapsed. reductionTime := b.chainParams.MinDiffReductionTime
allowMinTime := lastNode.timestamp.Add(targetSpacing * 2) allowMinTime := lastNode.timestamp.Add(reductionTime)
if newBlockTime.After(allowMinTime) { if newBlockTime.After(allowMinTime) {
return b.chainParams.PowLimitBits, nil return b.chainParams.PowLimitBits, nil
} }
@ -298,7 +267,7 @@ func (b *BlockChain) calcNextRequiredDifficulty(lastNode *blockNode, newBlockTim
// Get the block node at the previous retarget (targetTimespan days // Get the block node at the previous retarget (targetTimespan days
// worth of blocks). // worth of blocks).
firstNode := lastNode firstNode := lastNode
for i := int32(0); i < BlocksPerRetarget-1 && firstNode != nil; i++ { for i := int32(0); i < b.blocksPerRetarget-1 && firstNode != nil; i++ {
// Get the previous block node. This function is used over // Get the previous block node. This function is used over
// simply accessing firstNode.parent directly as it will // simply accessing firstNode.parent directly as it will
// dynamically create previous block nodes as needed. This // dynamically create previous block nodes as needed. This
@ -319,10 +288,10 @@ func (b *BlockChain) calcNextRequiredDifficulty(lastNode *blockNode, newBlockTim
// difficulty. // difficulty.
actualTimespan := lastNode.timestamp.UnixNano() - firstNode.timestamp.UnixNano() actualTimespan := lastNode.timestamp.UnixNano() - firstNode.timestamp.UnixNano()
adjustedTimespan := actualTimespan adjustedTimespan := actualTimespan
if actualTimespan < minRetargetTimespan { if actualTimespan < b.minRetargetTimespan {
adjustedTimespan = minRetargetTimespan adjustedTimespan = b.minRetargetTimespan
} else if actualTimespan > maxRetargetTimespan { } else if actualTimespan > b.maxRetargetTimespan {
adjustedTimespan = maxRetargetTimespan adjustedTimespan = b.maxRetargetTimespan
} }
// Calculate new target difficulty as: // Calculate new target difficulty as:
@ -332,7 +301,7 @@ func (b *BlockChain) calcNextRequiredDifficulty(lastNode *blockNode, newBlockTim
// result. // result.
oldTarget := CompactToBig(lastNode.bits) oldTarget := CompactToBig(lastNode.bits)
newTarget := new(big.Int).Mul(oldTarget, big.NewInt(adjustedTimespan)) newTarget := new(big.Int).Mul(oldTarget, big.NewInt(adjustedTimespan))
newTarget.Div(newTarget, big.NewInt(int64(targetTimespan))) newTarget.Div(newTarget, big.NewInt(int64(b.chainParams.TargetTimespan)))
// Limit new value to the proof of work limit. // Limit new value to the proof of work limit.
if newTarget.Cmp(b.chainParams.PowLimit) > 0 { if newTarget.Cmp(b.chainParams.PowLimit) > 0 {
@ -349,7 +318,7 @@ func (b *BlockChain) calcNextRequiredDifficulty(lastNode *blockNode, newBlockTim
log.Debugf("New target %08x (%064x)", newTargetBits, CompactToBig(newTargetBits)) log.Debugf("New target %08x (%064x)", newTargetBits, CompactToBig(newTargetBits))
log.Debugf("Actual timespan %v, adjusted timespan %v, target timespan %v", log.Debugf("Actual timespan %v, adjusted timespan %v, target timespan %v",
time.Duration(actualTimespan), time.Duration(adjustedTimespan), time.Duration(actualTimespan), time.Duration(adjustedTimespan),
targetTimespan) b.chainParams.TargetTimespan)
return newTargetBits, nil return newTargetBits, nil
} }

View file

@ -19,8 +19,8 @@ import (
// TstSetCoinbaseMaturity makes the ability to set the coinbase maturity // TstSetCoinbaseMaturity makes the ability to set the coinbase maturity
// available to the test package. // available to the test package.
func TstSetCoinbaseMaturity(maturity int32) { func (b *BlockChain) TstSetCoinbaseMaturity(maturity uint16) {
coinbaseMaturity = maturity b.chainParams.CoinbaseMaturity = maturity
} }
// TstTimeSorter makes the internal timeSorter type available to the test // TstTimeSorter makes the internal timeSorter type available to the test

View file

@ -56,7 +56,7 @@ func TestReorganization(t *testing.T) {
// Since we're not dealing with the real block chain, disable // Since we're not dealing with the real block chain, disable
// checkpoints and set the coinbase maturity to 1. // checkpoints and set the coinbase maturity to 1.
chain.DisableCheckpoints(true) chain.DisableCheckpoints(true)
blockchain.TstSetCoinbaseMaturity(1) chain.TstSetCoinbaseMaturity(1)
expectedOrphans := map[int]struct{}{5: {}, 6: {}} expectedOrphans := map[int]struct{}{5: {}, 6: {}}
for i := 1; i < len(blocks); i++ { for i := 1; i < len(blocks); i++ {

View file

@ -45,18 +45,9 @@ const (
// baseSubsidy is the starting subsidy amount for mined blocks. This // baseSubsidy is the starting subsidy amount for mined blocks. This
// value is halved every SubsidyHalvingInterval blocks. // value is halved every SubsidyHalvingInterval blocks.
baseSubsidy = 50 * btcutil.SatoshiPerBitcoin baseSubsidy = 50 * btcutil.SatoshiPerBitcoin
// CoinbaseMaturity is the number of blocks required before newly
// mined bitcoins (coinbase transactions) can be spent.
CoinbaseMaturity = 100
) )
var ( var (
// coinbaseMaturity is the internal variable used for validating the
// spending of coinbase outputs. A variable rather than the exported
// constant is used because the tests need the ability to modify it.
coinbaseMaturity = int32(CoinbaseMaturity)
// zeroHash is the zero value for a chainhash.Hash and is defined as // zeroHash is the zero value for a chainhash.Hash and is defined as
// a package level variable to avoid the need to create a new instance // a package level variable to avoid the need to create a new instance
// every time a check is needed. // every time a check is needed.
@ -182,18 +173,18 @@ func isBIP0030Node(node *blockNode) bool {
// newly generated blocks awards as well as validating the coinbase for blocks // newly generated blocks awards as well as validating the coinbase for blocks
// has the expected value. // has the expected value.
// //
// The subsidy is halved every SubsidyHalvingInterval blocks. Mathematically // The subsidy is halved every SubsidyReductionInterval blocks. Mathematically
// this is: baseSubsidy / 2^(height/subsidyHalvingInterval) // this is: baseSubsidy / 2^(height/SubsidyReductionInterval)
// //
// At the target block generation rate for the main network, this is // At the target block generation rate for the main network, this is
// approximately every 4 years. // approximately every 4 years.
func CalcBlockSubsidy(height int32, chainParams *chaincfg.Params) int64 { func CalcBlockSubsidy(height int32, chainParams *chaincfg.Params) int64 {
if chainParams.SubsidyHalvingInterval == 0 { if chainParams.SubsidyReductionInterval == 0 {
return baseSubsidy return baseSubsidy
} }
// Equivalent to: baseSubsidy / 2^(height/subsidyHalvingInterval) // Equivalent to: baseSubsidy / 2^(height/subsidyHalvingInterval)
return baseSubsidy >> uint(height/chainParams.SubsidyHalvingInterval) return baseSubsidy >> uint(height/chainParams.SubsidyReductionInterval)
} }
// CheckTransactionSanity performs some preliminary checks on a transaction to // CheckTransactionSanity performs some preliminary checks on a transaction to
@ -833,7 +824,7 @@ func (b *BlockChain) checkBIP0030(node *blockNode, block *btcutil.Block, view *U
// //
// NOTE: The transaction MUST have already been sanity checked with the // NOTE: The transaction MUST have already been sanity checked with the
// CheckTransactionSanity function prior to calling this function. // CheckTransactionSanity function prior to calling this function.
func CheckTransactionInputs(tx *btcutil.Tx, txHeight int32, utxoView *UtxoViewpoint) (int64, error) { func CheckTransactionInputs(tx *btcutil.Tx, txHeight int32, utxoView *UtxoViewpoint, chainParams *chaincfg.Params) (int64, error) {
// Coinbase transactions have no inputs. // Coinbase transactions have no inputs.
if IsCoinBase(tx) { if IsCoinBase(tx) {
return 0, nil return 0, nil
@ -857,6 +848,7 @@ func CheckTransactionInputs(tx *btcutil.Tx, txHeight int32, utxoView *UtxoViewpo
if utxoEntry.IsCoinBase() { if utxoEntry.IsCoinBase() {
originHeight := int32(utxoEntry.BlockHeight()) originHeight := int32(utxoEntry.BlockHeight())
blocksSincePrev := txHeight - originHeight blocksSincePrev := txHeight - originHeight
coinbaseMaturity := int32(chainParams.CoinbaseMaturity)
if blocksSincePrev < coinbaseMaturity { if blocksSincePrev < coinbaseMaturity {
str := fmt.Sprintf("tried to spend coinbase "+ str := fmt.Sprintf("tried to spend coinbase "+
"transaction %v from height %v at "+ "transaction %v from height %v at "+
@ -1050,7 +1042,8 @@ func (b *BlockChain) checkConnectBlock(node *blockNode, block *btcutil.Block, vi
// bounds. // bounds.
var totalFees int64 var totalFees int64
for _, tx := range transactions { for _, tx := range transactions {
txFee, err := CheckTransactionInputs(tx, node.height, view) txFee, err := CheckTransactionInputs(tx, node.height, view,
b.chainParams)
if err != nil { if err != nil {
return err return err
} }

View file

@ -7,6 +7,7 @@ package chaincfg
import ( import (
"errors" "errors"
"math/big" "math/big"
"time"
"github.com/btcsuite/btcd/chaincfg/chainhash" "github.com/btcsuite/btcd/chaincfg/chainhash"
"github.com/btcsuite/btcd/wire" "github.com/btcsuite/btcd/wire"
@ -53,19 +54,70 @@ type Checkpoint struct {
// used by Bitcoin applications to differentiate networks as well as addresses // used by Bitcoin applications to differentiate networks as well as addresses
// and keys for one network from those intended for use on another network. // and keys for one network from those intended for use on another network.
type Params struct { type Params struct {
Name string // Name defines a human-readable identifier for the network.
Net wire.BitcoinNet Name string
DefaultPort string
DNSSeeds []string
// Chain parameters // Net defines the magic bytes used to identify the network.
GenesisBlock *wire.MsgBlock Net wire.BitcoinNet
GenesisHash *chainhash.Hash
PowLimit *big.Int // DefaultPort defines the default peer-to-peer port for the network.
PowLimitBits uint32 DefaultPort string
SubsidyHalvingInterval int32
ResetMinDifficulty bool // DNSSeeds defines a list of DNS seeds for the network that are used
GenerateSupported bool // as one method to discover peers.
DNSSeeds []string
// GenesisBlock defines the first block of the chain.
GenesisBlock *wire.MsgBlock
// GenesisHash is the starting block hash.
GenesisHash *chainhash.Hash
// PowLimit defines the highest allowed proof of work value for a block
// as a uint256.
PowLimit *big.Int
// PowLimitBits defines the highest allowed proof of work value for a
// block in compact form.
PowLimitBits uint32
// CoinbaseMaturity is the number of blocks required before newly mined
// coins (coinbase transactions) can be spent.
CoinbaseMaturity uint16
// SubsidyReductionInterval is the interval of blocks before the subsidy
// is reduced.
SubsidyReductionInterval int32
// TargetTimespan is the desired amount of time that should elapse
// before the block difficulty requirement is examined to determine how
// it should be changed in order to maintain the desired block
// generation rate.
TargetTimespan time.Duration
// TargetTimePerBlock is the desired amount of time to generate each
// block.
TargetTimePerBlock time.Duration
// RetargetAdjustmentFactor is the adjustment factor used to limit
// the minimum and maximum amount of adjustment that can occur between
// difficulty retargets.
RetargetAdjustmentFactor int64
// ReduceMinDifficulty defines whether the network should reduce the
// minimum required difficulty after a long enough period of time has
// passed without finding a block. This is really only useful for test
// networks and should not be set on a main network.
ReduceMinDifficulty bool
// MinDiffReductionTime is the amount of time after which the minimum
// required difficulty should be reduced when a block hasn't been found.
//
// NOTE: This only applies if ReduceMinDifficulty is true.
MinDiffReductionTime time.Duration
// GenerateSupported specifies whether or not CPU mining is allowed.
GenerateSupported bool
// Checkpoints ordered from oldest to newest. // Checkpoints ordered from oldest to newest.
Checkpoints []Checkpoint Checkpoints []Checkpoint
@ -114,13 +166,18 @@ var MainNetParams = Params{
}, },
// Chain parameters // Chain parameters
GenesisBlock: &genesisBlock, GenesisBlock: &genesisBlock,
GenesisHash: &genesisHash, GenesisHash: &genesisHash,
PowLimit: mainPowLimit, PowLimit: mainPowLimit,
PowLimitBits: 0x1d00ffff, PowLimitBits: 0x1d00ffff,
SubsidyHalvingInterval: 210000, CoinbaseMaturity: 100,
ResetMinDifficulty: false, SubsidyReductionInterval: 210000,
GenerateSupported: false, TargetTimespan: time.Hour * 24 * 14, // 14 days
TargetTimePerBlock: time.Minute * 10, // 10 minutes
RetargetAdjustmentFactor: 4, // 25% less, 400% more
ReduceMinDifficulty: false,
MinDiffReductionTime: 0,
GenerateSupported: false,
// Checkpoints ordered from oldest to newest. // Checkpoints ordered from oldest to newest.
Checkpoints: []Checkpoint{ Checkpoints: []Checkpoint{
@ -181,13 +238,18 @@ var RegressionNetParams = Params{
DNSSeeds: []string{}, DNSSeeds: []string{},
// Chain parameters // Chain parameters
GenesisBlock: &regTestGenesisBlock, GenesisBlock: &regTestGenesisBlock,
GenesisHash: &regTestGenesisHash, GenesisHash: &regTestGenesisHash,
PowLimit: regressionPowLimit, PowLimit: regressionPowLimit,
PowLimitBits: 0x207fffff, PowLimitBits: 0x207fffff,
SubsidyHalvingInterval: 150, CoinbaseMaturity: 100,
ResetMinDifficulty: true, SubsidyReductionInterval: 150,
GenerateSupported: true, TargetTimespan: time.Hour * 24 * 14, // 14 days
TargetTimePerBlock: time.Minute * 10, // 10 minutes
RetargetAdjustmentFactor: 4, // 25% less, 400% more
ReduceMinDifficulty: true,
MinDiffReductionTime: time.Minute * 20, // TargetTimePerBlock * 2
GenerateSupported: true,
// Checkpoints ordered from oldest to newest. // Checkpoints ordered from oldest to newest.
Checkpoints: nil, Checkpoints: nil,
@ -233,13 +295,18 @@ var TestNet3Params = Params{
}, },
// Chain parameters // Chain parameters
GenesisBlock: &testNet3GenesisBlock, GenesisBlock: &testNet3GenesisBlock,
GenesisHash: &testNet3GenesisHash, GenesisHash: &testNet3GenesisHash,
PowLimit: testNet3PowLimit, PowLimit: testNet3PowLimit,
PowLimitBits: 0x1d00ffff, PowLimitBits: 0x1d00ffff,
SubsidyHalvingInterval: 210000, CoinbaseMaturity: 100,
ResetMinDifficulty: true, SubsidyReductionInterval: 210000,
GenerateSupported: false, TargetTimespan: time.Hour * 24 * 14, // 14 days
TargetTimePerBlock: time.Minute * 10, // 10 minutes
RetargetAdjustmentFactor: 4, // 25% less, 400% more
ReduceMinDifficulty: true,
MinDiffReductionTime: time.Minute * 20, // TargetTimePerBlock * 2
GenerateSupported: false,
// Checkpoints ordered from oldest to newest. // Checkpoints ordered from oldest to newest.
Checkpoints: []Checkpoint{ Checkpoints: []Checkpoint{
@ -287,13 +354,18 @@ var SimNetParams = Params{
DNSSeeds: []string{}, // NOTE: There must NOT be any seeds. DNSSeeds: []string{}, // NOTE: There must NOT be any seeds.
// Chain parameters // Chain parameters
GenesisBlock: &simNetGenesisBlock, GenesisBlock: &simNetGenesisBlock,
GenesisHash: &simNetGenesisHash, GenesisHash: &simNetGenesisHash,
PowLimit: simNetPowLimit, PowLimit: simNetPowLimit,
PowLimitBits: 0x207fffff, PowLimitBits: 0x207fffff,
SubsidyHalvingInterval: 210000, CoinbaseMaturity: 100,
ResetMinDifficulty: true, SubsidyReductionInterval: 210000,
GenerateSupported: true, TargetTimespan: time.Hour * 24 * 14, // 14 days
TargetTimePerBlock: time.Minute * 10, // 10 minutes
RetargetAdjustmentFactor: 4, // 25% less, 400% more
ReduceMinDifficulty: true,
MinDiffReductionTime: time.Minute * 20, // TargetTimePerBlock * 2
GenerateSupported: true,
// Checkpoints ordered from oldest to newest. // Checkpoints ordered from oldest to newest.
Checkpoints: nil, Checkpoints: nil,

View file

@ -596,7 +596,7 @@ func (mp *txMemPool) maybeAcceptTransaction(tx *btcutil.Tx, isNew, rateLimit boo
// Also returns the fees associated with the transaction which will be // Also returns the fees associated with the transaction which will be
// used later. // used later.
txFee, err := blockchain.CheckTransactionInputs(tx, nextBlockHeight, txFee, err := blockchain.CheckTransactionInputs(tx, nextBlockHeight,
utxoView) utxoView, activeNetParams.Params)
if err != nil { if err != nil {
if cerr, ok := err.(blockchain.RuleError); ok { if cerr, ok := err.(blockchain.RuleError); ok {
return nil, chainRuleError(cerr) return nil, chainRuleError(cerr)

View file

@ -651,7 +651,7 @@ mempoolLoop:
// Ensure the transaction inputs pass all of the necessary // Ensure the transaction inputs pass all of the necessary
// preconditions before allowing it to be added to the block. // preconditions before allowing it to be added to the block.
_, err = blockchain.CheckTransactionInputs(tx, nextBlockHeight, _, err = blockchain.CheckTransactionInputs(tx, nextBlockHeight,
blockUtxos) blockUtxos, activeNetParams.Params)
if err != nil { if err != nil {
minrLog.Tracef("Skipping tx %s due to error in "+ minrLog.Tracef("Skipping tx %s due to error in "+
"CheckTransactionInputs: %v", tx.Hash(), err) "CheckTransactionInputs: %v", tx.Hash(), err)
@ -781,7 +781,7 @@ func UpdateBlockTime(msgBlock *wire.MsgBlock, bManager *blockManager) error {
// If running on a network that requires recalculating the difficulty, // If running on a network that requires recalculating the difficulty,
// do so now. // do so now.
if activeNetParams.ResetMinDifficulty { if activeNetParams.ReduceMinDifficulty {
difficulty, err := bManager.chain.CalcNextRequiredDifficulty( difficulty, err := bManager.chain.CalcNextRequiredDifficulty(
newTimestamp) newTimestamp)
if err != nil { if err != nil {

View file

@ -2104,6 +2104,11 @@ func handleGetNetworkHashPS(s *rpcServer, cmd interface{}, closeChan <-chan stru
endHeight = best.Height endHeight = best.Height
} }
// Calculate the number of blocks per retarget interval based on the
// chain parameters.
blocksPerRetarget := int32(s.server.chainParams.TargetTimespan /
s.server.chainParams.TargetTimePerBlock)
// Calculate the starting block height based on the passed number of // Calculate the starting block height based on the passed number of
// blocks. When the passed value is negative, use the last block the // blocks. When the passed value is negative, use the last block the
// difficulty changed as the starting height. Also make sure the // difficulty changed as the starting height. Also make sure the
@ -2114,7 +2119,7 @@ func handleGetNetworkHashPS(s *rpcServer, cmd interface{}, closeChan <-chan stru
} }
var startHeight int32 var startHeight int32
if numBlocks <= 0 { if numBlocks <= 0 {
startHeight = endHeight - ((endHeight % blockchain.BlocksPerRetarget) + 1) startHeight = endHeight - ((endHeight % blocksPerRetarget) + 1)
} else { } else {
startHeight = endHeight - numBlocks startHeight = endHeight - numBlocks
} }