diff --git a/chaincfg/genesis.go b/chaincfg/genesis.go index 73d28610..f734feb2 100644 --- a/chaincfg/genesis.go +++ b/chaincfg/genesis.go @@ -143,6 +143,77 @@ var testNet3GenesisBlock = wire.MsgBlock{ Transactions: []*wire.MsgTx{&genesisCoinbaseTx}, } +// testNet4GenesisTx is the transaction for the genesis blocks for test network (version 4). +var testNet4GenesisTx = wire.MsgTx{ + Version: 1, + TxIn: []*wire.TxIn{ + { + PreviousOutPoint: wire.OutPoint{ + Hash: chainhash.Hash{}, + Index: 0xffffffff, + }, + SignatureScript: []byte{ + // Message: `03/May/2024 000000000000000000001ebd58c244970b3aa9d783bb001011fbe8ea8e98e00e` + 0x4, 0xff, 0xff, 0x0, 0x1d, 0x1, 0x4, 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}, + Sequence: 0xffffffff, + }, + }, + TxOut: []*wire.TxOut{ + { + Value: 0x12a05f200, + PkScript: []byte{ + 0x21, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0xac}, + }, + }, + LockTime: 0, +} + +// testNet4GenesisHash is the hash of the first block in the block chain for the +// test network (version 4). +var testNet4GenesisHash = chainhash.Hash([chainhash.HashSize]byte{ + 0x43, 0xf0, 0x8b, 0xda, 0xb0, 0x50, 0xe3, 0x5b, + 0x56, 0x7c, 0x86, 0x4b, 0x91, 0xf4, 0x7f, 0x50, + 0xae, 0x72, 0x5a, 0xe2, 0xde, 0x53, 0xbc, 0xfb, + 0xba, 0xf2, 0x84, 0xda, 0x00, 0x00, 0x00, 0x00}) + +// testNet4GenesisMerkleRoot is the hash of the first transaction in the genesis +// block for the test network (version 4). It is the same as the merkle root +// for the main network. +var testNet4GenesisMerkleRoot = chainhash.Hash([chainhash.HashSize]byte{ // Make go vet happy. + 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, +}) + +// testNet4GenesisBlock defines the genesis block of the block chain which +// serves as the public transaction ledger for the test network (version 3). +var testNet4GenesisBlock = wire.MsgBlock{ + Header: wire.BlockHeader{ + Version: 1, + PrevBlock: chainhash.Hash{}, // 0000000000000000000000000000000000000000000000000000000000000000 + MerkleRoot: testNet4GenesisMerkleRoot, // 4a5e1e4baab89f3a32518a88c31bc87f618f76673e2cc77ab2127b7afdeda33b + Timestamp: time.Unix(1714777860, 0), // 2024-05-03 23:11:00 +0000 UTC + Bits: 0x1d00ffff, // 486604799 [00000000ffff0000000000000000000000000000000000000000000000000000] + Nonce: 0x17780cbb, // 393743547 + }, + Transactions: []*wire.MsgTx{&testNet4GenesisTx}, +} + // simNetGenesisHash is the hash of the first block in the block chain for the // simulation test network. var simNetGenesisHash = chainhash.Hash([chainhash.HashSize]byte{ // Make go vet happy. diff --git a/chaincfg/genesis_test.go b/chaincfg/genesis_test.go index 1daf8479..b2975ffb 100644 --- a/chaincfg/genesis_test.go +++ b/chaincfg/genesis_test.go @@ -9,6 +9,7 @@ import ( "testing" "github.com/davecgh/go-spew/spew" + "github.com/stretchr/testify/require" ) // TestGenesisBlock tests the genesis block of the main network for validity by @@ -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) + require.NoError(t, 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)) + } + expectedHash := "00000000da84f2bafbbc53dee25a72ae507ff4914b867c565be3" + + "50b0da8bf043" + require.Equal(t, expectedHash, 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, /* |....N{+.| */ + 0x28, 0xfe, 0x02, 0x91, 0xdb, 0x06, 0x93, 0xaf, /* |(.......| */ + 0x2a, 0xe4, 0x18, 0xb7, 0x67, 0xe6, 0x57, 0xcd, /* |*...g.W.| */ + 0x40, 0x7e, 0x80, 0xcb, 0x14, 0x34, 0x22, 0x1e, /* |@~...4".| */ + 0xae, 0xa7, 0xa0, 0x7a, 0x04, 0x6f, 0x35, 0x66, /* |...z.o5f| */ + 0xff, 0xff, 0x00, 0x1d, 0xbb, 0x0c, 0x78, 0x17, /* |......x.| */ + 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, /* |..U.....| */ + 0x01, 0x04, 0x4c, 0x4c, 0x30, 0x33, 0x2f, 0x4d, /* |..LL03/M| */ + 0x61, 0x79, 0x2f, 0x32, 0x30, 0x32, 0x34, 0x20, /* |ay/2024 | */ + 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, /* |00000000| */ + 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, /* |00000000| */ + 0x30, 0x30, 0x30, 0x30, 0x31, 0x65, 0x62, 0x64, /* |00001ebd| */ + 0x35, 0x38, 0x63, 0x32, 0x34, 0x34, 0x39, 0x37, /* |58c24497| */ + 0x30, 0x62, 0x33, 0x61, 0x61, 0x39, 0x64, 0x37, /* |0b3aa9d7| */ + 0x38, 0x33, 0x62, 0x62, 0x30, 0x30, 0x31, 0x30, /* |83bb0010| */ + 0x31, 0x31, 0x66, 0x62, 0x65, 0x38, 0x65, 0x61, /* |11fbe8ea| */ + 0x38, 0x65, 0x39, 0x38, 0x65, 0x30, 0x30, 0x65, /* |8e98e00e| */ + 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{ diff --git a/chaincfg/params.go b/chaincfg/params.go index 1c329cb5..d97353f5 100644 --- a/chaincfg/params.go +++ b/chaincfg/params.go @@ -189,6 +189,10 @@ type Params struct { // regtest like networks. PoWNoRetargeting bool + // EnforceBIP94 enforces timewarp attack mitigation and on testnet4 + // this also enforces the block storm mitigation. + EnforceBIP94 bool + // These fields define the block heights at which the specified softfork // BIP became active. BIP0034Height int32 @@ -673,6 +677,118 @@ var TestNet3Params = Params{ HDCoinType: 1, } +// TestNet4Params defines the network parameters for the test Bitcoin network +// (version 4). +var TestNet4Params = Params{ + Name: "testnet4", + Net: wire.TestNet4, + DefaultPort: "48333", + DNSSeeds: []DNSSeed{ + {"seed.testnet4.bitcoin.sprovoost.nl", true}, + {"seed.testnet4.wiz.biz", true}, + }, + + // Chain parameters + GenesisBlock: &testNet4GenesisBlock, + GenesisHash: &testNet4GenesisHash, + PowLimit: testNet3PowLimit, + PowLimitBits: 0x1d00ffff, + EnforceBIP94: true, + BIP0034Height: 1, + BIP0065Height: 1, + BIP0066Height: 1, + CoinbaseMaturity: 100, + SubsidyReductionInterval: 210000, + 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: []Checkpoint{}, + + // Consensus rule change deployments. + // + // The miner confirmation window is defined as: + // target proof of work timespan / target proof of work spacing + RuleChangeActivationThreshold: 1512, // 75% of MinerConfirmationWindow + MinerConfirmationWindow: 2016, + Deployments: [DefinedDeployments]ConsensusDeployment{ + DeploymentTestDummy: { + BitNumber: 28, + DeploymentStarter: NewMedianTimeDeploymentStarter( + time.Unix(1199145601, 0), // January 1, 2008 UTC + ), + DeploymentEnder: NewMedianTimeDeploymentEnder( + time.Unix(1230767999, 0), // December 31, 2008 UTC + ), + }, + DeploymentTestDummyMinActivation: { + BitNumber: 22, + CustomActivationThreshold: 1815, // Only needs 90% hash rate. + MinActivationHeight: 10_0000, // Can only activate after height 10k. + DeploymentStarter: NewMedianTimeDeploymentStarter( + time.Time{}, // Always available for vote + ), + DeploymentEnder: NewMedianTimeDeploymentEnder( + time.Time{}, // Never expires + ), + }, + DeploymentCSV: { + BitNumber: 29, + DeploymentStarter: NewMedianTimeDeploymentStarter( + time.Time{}, // Always available for vote + ), + DeploymentEnder: NewMedianTimeDeploymentEnder( + time.Time{}, // Never expires + ), + }, + DeploymentSegwit: { + BitNumber: 29, + DeploymentStarter: NewMedianTimeDeploymentStarter( + time.Time{}, // Always available for vote + ), + DeploymentEnder: NewMedianTimeDeploymentEnder( + time.Time{}, // Never expires + ), + }, + DeploymentTaproot: { + BitNumber: 2, + DeploymentStarter: NewMedianTimeDeploymentStarter( + time.Time{}, // Always available for vote + ), + DeploymentEnder: NewMedianTimeDeploymentEnder( + time.Time{}, // Never expires + ), + MinActivationHeight: 0, + }, + }, + + // Mempool parameters + RelayNonStdTxs: true, + + // Human-readable part for Bech32 encoded segwit addresses, as defined in + // BIP 173. + Bech32HRPSegwit: "tb", // always tb for test net + + // Address encoding magics + PubKeyHashAddrID: 0x6f, // starts with m or n + ScriptHashAddrID: 0xc4, // starts with 2 + WitnessPubKeyHashAddrID: 0x03, // starts with QW + WitnessScriptHashAddrID: 0x28, // starts with T7n + PrivateKeyID: 0xef, // starts with 9 (uncompressed) or c (compressed) + + // BIP32 hierarchical deterministic extended key magics + HDPrivateKeyID: [4]byte{0x04, 0x35, 0x83, 0x94}, // starts with tprv + HDPublicKeyID: [4]byte{0x04, 0x35, 0x87, 0xcf}, // starts with tpub + + // BIP44 coin type used in the hierarchical deterministic path for + // address generation. + HDCoinType: 1, +} + // SimNetParams defines the network parameters for the simulation test Bitcoin // network. This network is similar to the normal test network except it is // intended for private use within a group of individuals doing simulation @@ -1075,6 +1191,7 @@ func init() { // Register all default networks when the package is initialized. mustRegister(&MainNetParams) mustRegister(&TestNet3Params) + mustRegister(&TestNet4Params) mustRegister(&RegressionNetParams) mustRegister(&SimNetParams) } diff --git a/chaincfg/register_test.go b/chaincfg/register_test.go index bcb5b3c6..db254415 100644 --- a/chaincfg/register_test.go +++ b/chaincfg/register_test.go @@ -68,6 +68,11 @@ func TestRegister(t *testing.T) { params: &TestNet3Params, err: ErrDuplicateNet, }, + { + name: "duplicate testnet4", + params: &TestNet4Params, + err: ErrDuplicateNet, + }, { name: "duplicate simnet", params: &SimNetParams, @@ -83,6 +88,10 @@ func TestRegister(t *testing.T) { magic: TestNet3Params.PubKeyHashAddrID, valid: true, }, + { + magic: TestNet4Params.PubKeyHashAddrID, + valid: true, + }, { magic: RegressionNetParams.PubKeyHashAddrID, valid: true, @@ -109,6 +118,10 @@ func TestRegister(t *testing.T) { magic: TestNet3Params.ScriptHashAddrID, valid: true, }, + { + magic: TestNet4Params.ScriptHashAddrID, + valid: true, + }, { magic: RegressionNetParams.ScriptHashAddrID, valid: true, @@ -135,6 +148,10 @@ func TestRegister(t *testing.T) { prefix: TestNet3Params.Bech32HRPSegwit + "1", valid: true, }, + { + prefix: TestNet4Params.Bech32HRPSegwit + "1", + valid: true, + }, { prefix: RegressionNetParams.Bech32HRPSegwit + "1", valid: true, @@ -175,6 +192,11 @@ func TestRegister(t *testing.T) { want: TestNet3Params.HDPublicKeyID[:], err: nil, }, + { + priv: TestNet4Params.HDPrivateKeyID[:], + want: TestNet4Params.HDPublicKeyID[:], + err: nil, + }, { priv: RegressionNetParams.HDPrivateKeyID[:], want: RegressionNetParams.HDPublicKeyID[:], @@ -217,6 +239,10 @@ func TestRegister(t *testing.T) { magic: TestNet3Params.PubKeyHashAddrID, valid: true, }, + { + magic: TestNet4Params.PubKeyHashAddrID, + valid: true, + }, { magic: RegressionNetParams.PubKeyHashAddrID, valid: true, @@ -243,6 +269,10 @@ func TestRegister(t *testing.T) { magic: TestNet3Params.ScriptHashAddrID, valid: true, }, + { + magic: TestNet4Params.ScriptHashAddrID, + valid: true, + }, { magic: RegressionNetParams.ScriptHashAddrID, valid: true, @@ -269,6 +299,10 @@ func TestRegister(t *testing.T) { prefix: TestNet3Params.Bech32HRPSegwit + "1", valid: true, }, + { + prefix: TestNet4Params.Bech32HRPSegwit + "1", + valid: true, + }, { prefix: RegressionNetParams.Bech32HRPSegwit + "1", valid: true, @@ -324,6 +358,11 @@ func TestRegister(t *testing.T) { params: &TestNet3Params, err: ErrDuplicateNet, }, + { + name: "duplicate testnet4", + params: &TestNet4Params, + err: ErrDuplicateNet, + }, { name: "duplicate simnet", params: &SimNetParams, @@ -344,6 +383,10 @@ func TestRegister(t *testing.T) { magic: TestNet3Params.PubKeyHashAddrID, valid: true, }, + { + magic: TestNet4Params.PubKeyHashAddrID, + valid: true, + }, { magic: RegressionNetParams.PubKeyHashAddrID, valid: true, @@ -370,6 +413,10 @@ func TestRegister(t *testing.T) { magic: TestNet3Params.ScriptHashAddrID, valid: true, }, + { + magic: TestNet4Params.ScriptHashAddrID, + valid: true, + }, { magic: RegressionNetParams.ScriptHashAddrID, valid: true, @@ -396,6 +443,10 @@ func TestRegister(t *testing.T) { prefix: TestNet3Params.Bech32HRPSegwit + "1", valid: true, }, + { + prefix: TestNet4Params.Bech32HRPSegwit + "1", + valid: true, + }, { prefix: RegressionNetParams.Bech32HRPSegwit + "1", valid: true, @@ -436,6 +487,11 @@ func TestRegister(t *testing.T) { want: TestNet3Params.HDPublicKeyID[:], err: nil, }, + { + priv: TestNet4Params.HDPrivateKeyID[:], + want: TestNet4Params.HDPublicKeyID[:], + err: nil, + }, { priv: RegressionNetParams.HDPrivateKeyID[:], want: RegressionNetParams.HDPublicKeyID[:],