-
Notifications
You must be signed in to change notification settings - Fork 2.4k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
feat: Add testnet4 chain support #2274
base: master
Are you sure you want to change the base?
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -46,6 +46,8 @@ btcutil/psbt/coverage.txt | |
*.swo | ||
/.vim | ||
|
||
.idea | ||
|
||
# Binaries produced by "make build" | ||
/addblock | ||
/btcctl | ||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -220,6 +220,8 @@ const ( | |
// current chain tip. This is not a block validation rule, but is required | ||
// for block proposals submitted via getblocktemplate RPC. | ||
ErrPrevBlockNotBest | ||
|
||
ErrTimewarpAttack | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. nit: missing Godoc comment. |
||
) | ||
|
||
// Map of ErrorCode values back to their constant names for pretty printing. | ||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -46,6 +46,11 @@ const ( | |
// coinbaseHeightAllocSize is the amount of bytes that the | ||
// ScriptBuilder will allocate when validating the coinbase height. | ||
coinbaseHeightAllocSize = 5 | ||
|
||
// maxTimeWarp is a maximum number of seconds that the timestamp of the first | ||
// block of a difficulty adjustment period is allowed to | ||
// be earlier than the last block of the previous period (BIP94). | ||
maxTimeWarp = 600 * time.Second | ||
) | ||
|
||
var ( | ||
|
@@ -85,7 +90,7 @@ func ShouldHaveSerializedBlockHeight(header *wire.BlockHeader) bool { | |
|
||
// IsCoinBaseTx determines whether or not a transaction is a coinbase. A coinbase | ||
// is a special transaction created by miners that has no inputs. This is | ||
// represented in the block chain by a transaction with a single input that has | ||
// represented in the blockchain by a transaction with a single input that has | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Please revert these. This specifically refer to the chain of blocks, not the package name. IMO "Blockchain" is a marketing term used by people trying to sell you something that isn't Bitcoin. |
||
// a previous output transaction index set to the maximum value along with a | ||
// zero hash. | ||
// | ||
|
@@ -109,7 +114,7 @@ func IsCoinBaseTx(msgTx *wire.MsgTx) bool { | |
|
||
// IsCoinBase determines whether or not a transaction is a coinbase. A coinbase | ||
// is a special transaction created by miners that has no inputs. This is | ||
// represented in the block chain by a transaction with a single input that has | ||
// represented in the blockchain by a transaction with a single input that has | ||
// a previous output transaction index set to the maximum value along with a | ||
// zero hash. | ||
// | ||
|
@@ -446,7 +451,7 @@ func CheckBlockHeaderSanity(header *wire.BlockHeader, powLimit *big.Int, | |
// A block timestamp must not have a greater precision than one second. | ||
// This check is necessary because Go time.Time values support | ||
// nanosecond precision whereas the consensus rules only apply to | ||
// seconds and it's much nicer to deal with standard Go time values | ||
// seconds, and it's much nicer to deal with standard Go time values | ||
// instead of converting to seconds everywhere. | ||
if !header.Timestamp.Equal(time.Unix(header.Timestamp.Unix(), 0)) { | ||
str := fmt.Sprintf("block timestamp of %v has a higher "+ | ||
|
@@ -669,7 +674,7 @@ func compareScript(height int32, script []byte) error { | |
} | ||
|
||
// CheckBlockHeaderContext performs several validation checks on the block header | ||
// which depend on its position within the block chain. | ||
// which depend on its position within the blockchain. | ||
// | ||
// The flags modify the behavior of this function as follows: | ||
// - BFFastAdd: All checks except those involving comparing the header against | ||
|
@@ -684,6 +689,10 @@ func compareScript(height int32, script []byte) error { | |
func CheckBlockHeaderContext(header *wire.BlockHeader, prevNode HeaderCtx, | ||
flags BehaviorFlags, c ChainCtx, skipCheckpoint bool) error { | ||
|
||
// The height of this block is one more than the referenced previous | ||
// block. | ||
blockHeight := prevNode.Height() + 1 | ||
|
||
fastAdd := flags&BFFastAdd == BFFastAdd | ||
if !fastAdd { | ||
// Ensure the difficulty specified in the block header matches | ||
|
@@ -710,11 +719,22 @@ func CheckBlockHeaderContext(header *wire.BlockHeader, prevNode HeaderCtx, | |
str = fmt.Sprintf(str, header.Timestamp, medianTime) | ||
return ruleError(ErrTimeTooOld, str) | ||
} | ||
} | ||
|
||
// The height of this block is one more than the referenced previous | ||
// block. | ||
blockHeight := prevNode.Height() + 1 | ||
// Testnet4 only: Check timestamp against prev for difficulty-adjustment | ||
// blocks to prevent timewarp attacks. | ||
if c.ChainParams().EnforceBIP94 { | ||
// Check timestamp for the first block of each difficulty adjustment | ||
// interval, except the genesis block. | ||
if blockHeight%c.BlocksPerRetarget() == 0 { | ||
prevBlockTimestamp := time.Unix(prevNode.Timestamp(), 0) | ||
if header.Timestamp.Before(prevBlockTimestamp.Add(-maxTimeWarp)) { | ||
str := "block's timestamp %v is too early on diff adjustment block %v" | ||
str = fmt.Sprintf(str, header.Timestamp, prevBlockTimestamp) | ||
return ruleError(ErrTimewarpAttack, str) | ||
} | ||
} | ||
} | ||
} | ||
Comment on lines
+725
to
+737
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. nit: line length. Also, sounds like this whole block could be extracted into a standalone function. Something like |
||
|
||
// Reject outdated block versions once a majority of the network | ||
// has upgraded. These were originally voted on by BIP0034, | ||
|
@@ -762,7 +782,7 @@ func CheckBlockHeaderContext(header *wire.BlockHeader, prevNode HeaderCtx, | |
} | ||
|
||
// checkBlockContext performs several validation checks on the block which depend | ||
// on its position within the block chain. | ||
// on its position within the blockchain. | ||
// | ||
// The flags modify the behavior of this function as follows: | ||
// - BFFastAdd: The transaction are not checked to see if they are finalized | ||
|
@@ -1067,7 +1087,7 @@ func (b *BlockChain) checkConnectBlock(node *blockNode, block *btcutil.Block, vi | |
// | ||
// In addition, as of BIP0034, duplicate coinbases are no longer | ||
// possible due to its requirement for including the block height in the | ||
// coinbase and thus it is no longer possible to create transactions | ||
// coinbase, and thus it is no longer possible to create transactions | ||
// that 'overwrite' older ones. Therefore, only enforce the rule if | ||
// BIP0034 is not yet active. This is a useful optimization because the | ||
// BIP0030 check is expensive since it involves a ton of cache misses in | ||
|
@@ -1230,7 +1250,7 @@ func (b *BlockChain) checkConnectBlock(node *blockNode, block *btcutil.Block, vi | |
if csvState == ThresholdActive { | ||
// If the CSV soft-fork is now active, then modify the | ||
// scriptFlags to ensure that the CSV op code is properly | ||
// validated during the script checks bleow. | ||
// validated during the script checks below. | ||
scriptFlags |= txscript.ScriptVerifyCheckSequenceVerify | ||
|
||
// We obtain the MTP of the *previous* block in order to | ||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -64,6 +64,11 @@ func btcdMain(serverChan chan<- *server) error { | |
// Show version at startup. | ||
btcdLog.Infof("Version %s", version()) | ||
|
||
if cfg.TestNet3 { | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Not sure I agree with that whole block. |
||
btcdLog.Warn("Support for testnet3 is deprecated and will be removed in an upcoming release. " + | ||
"Consider switching to testnet4.") | ||
} | ||
|
||
// Enable http profiling server if requested. | ||
if cfg.Profile != "" { | ||
go func() { | ||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -6,6 +6,7 @@ package chaincfg | |
|
||
import ( | ||
"bytes" | ||
"github.com/stretchr/testify/require" | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. nit: please sort this with the block below where non-std-lib imports go. |
||
"testing" | ||
|
||
"github.com/davecgh/go-spew/spew" | ||
|
@@ -91,6 +92,34 @@ func TestTestNet3GenesisBlock(t *testing.T) { | |
} | ||
} | ||
|
||
// TestTestNet4GenesisBlock tests the genesis block of the test network (version | ||
// 4) for validity by checking the encoded bytes and hashes. | ||
func TestTestNet4GenesisBlock(t *testing.T) { | ||
// Encode the genesis block to raw bytes. | ||
var buf bytes.Buffer | ||
err := TestNet4Params.GenesisBlock.Serialize(&buf) | ||
if err != nil { | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Should use |
||
t.Fatalf("TestTestNet4GenesisBlock: %v", err) | ||
} | ||
|
||
// Ensure the encoded block matches the expected bytes. | ||
if !bytes.Equal(buf.Bytes(), testNet4GenesisBlockBytes) { | ||
t.Fatalf("TestTestNet4GenesisBlock: Genesis block does not "+ | ||
"appear valid - got %v, want %v", | ||
spew.Sdump(buf.Bytes()), | ||
spew.Sdump(testNet4GenesisBlockBytes)) | ||
} | ||
|
||
// Check hash of the block against expected hash. | ||
hash := TestNet4Params.GenesisBlock.BlockHash() | ||
if !TestNet4Params.GenesisHash.IsEqual(&hash) { | ||
t.Fatalf("TestTestNet4GenesisBlock: Genesis block hash does "+ | ||
"not appear valid - got %v, want %v", spew.Sdump(hash), | ||
spew.Sdump(TestNet4Params.GenesisHash)) | ||
} | ||
require.Equal(t, "00000000da84f2bafbbc53dee25a72ae507ff4914b867c565be350b0da8bf043", hash.String()) | ||
} | ||
|
||
// TestSimNetGenesisBlock tests the genesis block of the simulation test network | ||
// for validity by checking the encoded bytes and hashes. | ||
func TestSimNetGenesisBlock(t *testing.T) { | ||
|
@@ -268,6 +297,44 @@ var testNet3GenesisBlockBytes = []byte{ | |
0xac, 0x00, 0x00, 0x00, 0x00, /* |.....| */ | ||
} | ||
|
||
// testNet4GenesisBlockBytes are the wire encoded bytes for the genesis block of | ||
// the test network (version 4) | ||
var testNet4GenesisBlockBytes = []byte{ | ||
0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | ||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | ||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | ||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | ||
0x00, 0x00, 0x00, 0x00, 0x4e, 0x7b, 0x2b, 0x91, | ||
0x28, 0xfe, 0x02, 0x91, 0xdb, 0x06, 0x93, 0xaf, | ||
0x2a, 0xe4, 0x18, 0xb7, 0x67, 0xe6, 0x57, 0xcd, | ||
0x40, 0x7e, 0x80, 0xcb, 0x14, 0x34, 0x22, 0x1e, | ||
0xae, 0xa7, 0xa0, 0x7a, 0x04, 0x6f, 0x35, 0x66, | ||
0xff, 0xff, 0x00, 0x1d, 0xbb, 0x0c, 0x78, 0x17, | ||
0x01, 0x01, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, | ||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | ||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | ||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | ||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, | ||
0xff, 0xff, 0x55, 0x04, 0xff, 0xff, 0x00, 0x1d, | ||
0x01, 0x04, 0x4c, 0x4c, 0x30, 0x33, 0x2f, 0x4d, | ||
0x61, 0x79, 0x2f, 0x32, 0x30, 0x32, 0x34, 0x20, | ||
0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, | ||
0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, | ||
0x30, 0x30, 0x30, 0x30, 0x31, 0x65, 0x62, 0x64, | ||
0x35, 0x38, 0x63, 0x32, 0x34, 0x34, 0x39, 0x37, | ||
0x30, 0x62, 0x33, 0x61, 0x61, 0x39, 0x64, 0x37, | ||
0x38, 0x33, 0x62, 0x62, 0x30, 0x30, 0x31, 0x30, | ||
0x31, 0x31, 0x66, 0x62, 0x65, 0x38, 0x65, 0x61, | ||
0x38, 0x65, 0x39, 0x38, 0x65, 0x30, 0x30, 0x65, | ||
0xff, 0xff, 0xff, 0xff, 0x01, 0x00, 0xf2, 0x05, | ||
0x2a, 0x01, 0x00, 0x00, 0x00, 0x23, 0x21, 0x00, | ||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | ||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | ||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | ||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | ||
0xac, 0x00, 0x00, 0x00, 0x00, | ||
} | ||
|
||
// simNetGenesisBlockBytes are the wire encoded bytes for the genesis block of | ||
// the simulation test network as of protocol version 70002. | ||
var simNetGenesisBlockBytes = []byte{ | ||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Please use full sentences, including punctuation, for comments. Also, if a comment isn't at the beginning of a block, it's nice to have an empty line before it to have some vertical breathing room.
Finally,
else
is kind of discouraged in Go if it can be written in a different way, as it often leads to less readable code.So I'd write this the following way:
Of course the assumption here is that
CompactToBig(lastNode.Bits())
isn't computationally expensive to wanting to avoid calling it twice in the worst case.