Implement testnet specific rules.

This commit adds support for testnet specific rules when a new BlockChain
is created against testnet.
This commit is contained in:
Dave Collins 2013-07-24 16:43:39 -05:00
parent 1deeb05627
commit 9787f46f6a
3 changed files with 88 additions and 16 deletions

View file

@ -114,7 +114,6 @@ intentionally causes an error by attempting to process a duplicate block.
## TODO
- Increase test coverage
- Add testnet specific rules
- Profile and optimize
- Expose some APIs for block verification (without actually inserting it) and
transaction input lookups

View file

@ -190,7 +190,17 @@ func (b *BlockChain) calcEasiestDifficulty(bits uint32, duration time.Duration)
// Choose the correct proof of work limit for the active network.
powLimit := b.netParams().powLimit
// TODO(davec): Testnet has special rules.
// 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 durationVal > int64(targetSpacing)*2 {
return BigToCompact(powLimit)
}
}
// Since easier difficulty equates to higher numbers, the easiest
// difficulty for a given duration is the largest value possible given
@ -210,6 +220,36 @@ func (b *BlockChain) calcEasiestDifficulty(bits uint32, duration time.Duration)
return BigToCompact(newTarget)
}
// findPrevTestNetDifficulty returns the difficulty of the previous block which
// did not have the special testnet minimum difficulty rule applied.
func (b *BlockChain) findPrevTestNetDifficulty(startNode *blockNode) (uint32, error) {
// Search backwards through the chain for the last block without
// the special rule applied.
powLimitBits := BigToCompact(b.netParams().powLimit)
iterNode := startNode
for iterNode != nil && iterNode.height%blocksPerRetarget != 0 && iterNode.bits == 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
// 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 {
log.Errorf("getPrevNodeFromNode: %v", err)
return 0, err
}
}
// Return the found difficulty or the minimum difficulty if no
// appropriate block was found.
lastBits := powLimitBits
if iterNode != nil {
lastBits = iterNode.bits
}
return lastBits, nil
}
// 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, block *btcutil.Block) (uint32, error) {
@ -224,8 +264,40 @@ func (b *BlockChain) calcNextRequiredDifficulty(lastNode *blockNode, block *btcu
// Return the previous block's difficulty requirements if this block
// is not at a difficulty retarget interval.
if (lastNode.height+1)%blocksPerRetarget != 0 {
// TODO(davec): Testnet has special rules.
return lastNode.bits, nil
// 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:
// Return minimum difficulty when more than twice the
// desired amount of time needed to generate a block has
// elapsed.
newBlockTime := block.MsgBlock().Header.Timestamp
allowMinTime := lastNode.timestamp.Add(targetSpacing * 2)
if newBlockTime.After(allowMinTime) {
return BigToCompact(powLimit), nil
}
// The block was mined within the desired timeframe, so
// return the difficulty for the last block which did
// not have the special minimum difficulty rule applied.
prevBits, err := b.findPrevTestNetDifficulty(lastNode)
if err != nil {
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
}
}
// Get the block node at the previous retarget (targetTimespan days

View file

@ -2,33 +2,33 @@
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/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/difficulty.go ShaHashToBig 100.00% (5/5)
github.com/conformal/btcchain/chain.go newBlockNode 100.00% (4/4)
github.com/conformal/btcchain/merkle.go nextPowerOfTwo 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/timesorter.go timeSorter.Less 100.00% (1/1)
github.com/conformal/btcchain/validate.go calcBlockSubsidy 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/log.go init 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)
github.com/conformal/btcchain/txlookup.go disconnectTransactions 90.91% (10/11)
github.com/conformal/btcchain/txlookup.go BlockChain.fetchTxList 88.57% (31/35)
github.com/conformal/btcchain/scriptval.go validateAllTxIn 87.88% (29/33)
github.com/conformal/btcchain/chain.go BlockChain.calcPastMedianTime 87.50% (14/16)
github.com/conformal/btcchain/scriptval.go checkBlockScripts 87.50% (7/8)
github.com/conformal/btcchain/chain.go BlockChain.connectBestChain 86.96% (20/23)
github.com/conformal/btcchain/validate.go countSigOps 86.67% (13/15)
github.com/conformal/btcchain/chain.go BlockChain.connectBlock 83.33% (10/12)
github.com/conformal/btcchain/validate.go isCoinBase 83.33% (5/6)
github.com/conformal/btcchain/chain.go BlockChain.calcPastMedianTime 82.35% (14/17)
github.com/conformal/btcchain/chain.go BlockChain.reorganizeChain 80.77% (21/26)
github.com/conformal/btcchain/chain.go BlockChain.isMajorityVersion 80.00% (8/10)
github.com/conformal/btcchain/txlookup.go BlockChain.fetchInputTransactions 78.26% (18/23)
@ -51,17 +51,18 @@ github.com/conformal/btcchain/validate.go BlockChain.checkBIP0030 57.14% (8/1
github.com/conformal/btcchain/chain.go BlockChain.loadBlockNode 50.00% (11/22)
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/accept.go BlockChain.maybeAcceptBlock 46.38% (32/69)
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 13.79% (4/29)
github.com/conformal/btcchain/difficulty.go BlockChain.calcNextRequiredDifficulty 15.00% (6/40)
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/difficulty.go BlockChain.calcEasiestDifficulty 0.00% (0/14)
github.com/conformal/btcchain/validate.go checkSerializedHeight 0.00% (0/12)
github.com/conformal/btcchain/difficulty.go BlockChain.calcEasiestDifficulty 0.00% (0/10)
github.com/conformal/btcchain/difficulty.go BlockChain.findPrevTestNetDifficulty 0.00% (0/12)
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)
@ -69,10 +70,10 @@ github.com/conformal/btcchain/checkpoints.go BlockChain.checkpointData 0.00%
github.com/conformal/btcchain/validate.go isTransactionSpent 0.00% (0/4)
github.com/conformal/btcchain/notifications.go NotificationType.String 0.00% (0/3)
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/process.go RuleError.Error 0.00% (0/1)
github.com/conformal/btcchain/log.go newLogClosure 0.00% (0/1)
github.com/conformal/btcchain/chain.go BlockChain.DisableVerify 0.00% (0/1)
github.com/conformal/btcchain/log.go UseLogger 0.00% (0/1)
github.com/conformal/btcchain/log.go logClosure.String 0.00% (0/1)
github.com/conformal/btcchain ------------------------------------- 59.26% (576/972)
github.com/conformal/btcchain/log.go newLogClosure 0.00% (0/1)
github.com/conformal/btcchain ------------------------------------- 57.57% (578/1004)