Skip to content
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 params #3195

Merged
merged 2 commits into from
Nov 22, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions pkg/chains/bitcoin.go
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ var (
BitcoinMainnet.ChainId: &chaincfg.MainNetParams,
BitcoinTestnet.ChainId: &chaincfg.TestNet3Params,
BitcoinSignetTestnet.ChainId: &chaincfg.SigNetParams,
BitcoinTestnet4.ChainId: &TestNet4Params,
}

// networkNameToChainID maps the Bitcoin network name to the chain ID
Expand All @@ -21,6 +22,7 @@ var (
chaincfg.MainNetParams.Name: BitcoinMainnet.ChainId,
chaincfg.TestNet3Params.Name: BitcoinTestnet.ChainId,
chaincfg.SigNetParams.Name: BitcoinSignetTestnet.ChainId,
TestNet4Params.Name: BitcoinTestnet4.ChainId,
}
)

Expand Down
6 changes: 6 additions & 0 deletions pkg/chains/bitcoin_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@ func TestBitcoinNetParamsFromChainID(t *testing.T) {
{"Mainnet", BitcoinMainnet.ChainId, &chaincfg.MainNetParams, false},
{"Testnet", BitcoinTestnet.ChainId, &chaincfg.TestNet3Params, false},
{"Signet", BitcoinSignetTestnet.ChainId, &chaincfg.SigNetParams, false},
{"Testnet4", BitcoinTestnet4.ChainId, &TestNet4Params, false},
{"Unknown", -1, nil, true},
}

Expand Down Expand Up @@ -46,6 +47,7 @@ func TestBitcoinChainIDFromNetParams(t *testing.T) {
{"Mainnet", chaincfg.MainNetParams.Name, BitcoinMainnet.ChainId, false},
{"Testnet", chaincfg.TestNet3Params.Name, BitcoinTestnet.ChainId, false},
{"Signet", chaincfg.SigNetParams.Name, BitcoinSignetTestnet.ChainId, false},
{"Testnet4", TestNet4Params.Name, BitcoinTestnet4.ChainId, false},
{"Unknown", "Unknown", 0, true},
}

Expand All @@ -67,10 +69,14 @@ func TestIsBitcoinRegnet(t *testing.T) {
require.True(t, IsBitcoinRegnet(BitcoinRegtest.ChainId))
require.False(t, IsBitcoinRegnet(BitcoinMainnet.ChainId))
require.False(t, IsBitcoinRegnet(BitcoinTestnet.ChainId))
require.False(t, IsBitcoinRegnet(BitcoinSignetTestnet.ChainId))
require.False(t, IsBitcoinRegnet(BitcoinTestnet4.ChainId))
}

func TestIsBitcoinMainnet(t *testing.T) {
require.True(t, IsBitcoinMainnet(BitcoinMainnet.ChainId))
require.False(t, IsBitcoinMainnet(BitcoinRegtest.ChainId))
require.False(t, IsBitcoinMainnet(BitcoinTestnet.ChainId))
require.False(t, IsBitcoinMainnet(BitcoinSignetTestnet.ChainId))
require.False(t, IsBitcoinMainnet(BitcoinTestnet4.ChainId))
}
222 changes: 222 additions & 0 deletions pkg/chains/bitcoin_testnet4.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,222 @@
package chains

// ISC License
//
// Copyright (c) 2013-2024 The btcsuite developers
// Copyright (c) 2015-2016 The Decred developers

// this is a copy of the testnet4 parameters from https://github.com/btcsuite/btcd/pull/2275/
// they are not necessarily fully correct but should be sufficient for observation and signing

import (
"math/big"
"time"

"github.com/btcsuite/btcd/chaincfg"
"github.com/btcsuite/btcd/chaincfg/chainhash"
"github.com/btcsuite/btcd/wire"
)

// TestNet4 represents the test network (version 4).
const (
TestNet4 wire.BitcoinNet = 0x283f161c
)

var (
// bigOne is 1 represented as a big.Int. It is defined here to avoid
// the overhead of creating it multiple times.
bigOne = big.NewInt(1)
// testNet3PowLimit is the highest proof of work value a Bitcoin block
// can have for the test network (version 3). It is the value
// 2^224 - 1.
testNet3PowLimit = new(big.Int).Sub(new(big.Int).Lsh(bigOne, 224), bigOne)
)

// testNet4GenesisCoinbaseTx is the coinbase transaction for the genesis block
// for the test network (version 4).
var testNet4GenesisCoinbaseTx = wire.MsgTx{
Version: 1,
TxIn: []*wire.TxIn{
{
PreviousOutPoint: wire.OutPoint{
Hash: chainhash.Hash{},
Index: 0xffffffff,
},
SignatureScript: []byte{
0x04, 0xff, 0xff, 0x00, 0x1d, 0x01, 0x04, 0x4c, // |.......L|
0x4c, 0x30, 0x33, 0x2f, 0x4d, 0x61, 0x79, 0x2f, // |L03/May/|
0x32, 0x30, 0x32, 0x34, 0x20, 0x30, 0x30, 0x30, // |2024 000|
0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, // |00000000|
0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, // |00000000|
0x30, 0x31, 0x65, 0x62, 0x64, 0x35, 0x38, 0x63, // |01ebd58c|
0x32, 0x34, 0x34, 0x39, 0x37, 0x30, 0x62, 0x33, // |244970b3|
0x61, 0x61, 0x39, 0x64, 0x37, 0x38, 0x33, 0x62, // |aa9d783b|
0x62, 0x30, 0x30, 0x31, 0x30, 0x31, 0x31, 0x66, // |b001011f|
0x62, 0x65, 0x38, 0x65, 0x61, 0x38, 0x65, 0x39, // |be8ea8e9|
0x38, 0x65, 0x30, 0x30, 0x65, // |8e00e|
},
Sequence: 0xffffffff,
},
},
TxOut: []*wire.TxOut{
{
Value: 0x12a05f200,
PkScript: []byte{
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, // |...|
},
},
},
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).
var testNet4GenesisMerkleRoot = chainhash.Hash([chainhash.HashSize]byte{
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 4).
var testNet4GenesisBlock = wire.MsgBlock{
Header: wire.BlockHeader{
Version: 1,
PrevBlock: chainhash.Hash{}, // 0000000000000000000000000000000000000000000000000000000000000000
MerkleRoot: testNet4GenesisMerkleRoot, // 7aa0a7ae1e223414cb807e40cd57e667b718e42aaf9306db9102fe28912b7b4e
Timestamp: time.Unix(1714777860, 0), // 2024-05-03 23:11:00 +0000 UTC
Bits: 0x1d00ffff, // 486604799 [00000000ffff0000000000000000000000000000000000000000000000000000]
Nonce: 0x17780cbb, // 393743547
},
Transactions: []*wire.MsgTx{&testNet4GenesisCoinbaseTx},
}

// TestNet4Params defines the network parameters for the test Bitcoin network
// (version 4). Not to be confused with the regression test network, this
// network is sometimes simply called "testnet4".
var TestNet4Params = chaincfg.Params{
Name: "testnet4",
Net: TestNet4,
DefaultPort: "48333",
DNSSeeds: []chaincfg.DNSSeed{
{"seed.testnet4.bitcoin.sprovoost.nl", true},
{"seed.testnet4.wiz.biz", true},
},

// Chain parameters
GenesisBlock: &testNet4GenesisBlock,
GenesisHash: &testNet4GenesisHash,
PowLimit: testNet3PowLimit,
PowLimitBits: 0x1d00ffff,
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: []chaincfg.Checkpoint{
//{500, newHashFromStr("00000000c674047be3a7b25fefe0b6416f6f4e88ff9b01ddc05471b8e2ea603a")},
//{1000, newHashFromStr("00000000b747d47c3b38161693ad05e26924b3775a8be669751f969da836311e")},
//{10000, newHashFromStr("000000000037079ff4c37eed57d00eb9ddfde8737b559ffa4101b11e76c97466")},
//{25000, newHashFromStr("00000000000000c207c423ebb2d935e7b867b51710aaf72967666e83696f01e2")},
//{35000, newHashFromStr("0000000047f9360bd7e79d3959bd32366e24b4182caf138a8b10d42add3b7fd7")},
//{45000, newHashFromStr("0000000019ae521883b2597ed74cd21e2efa43fbf487815300cad96206d76f0e")},
},
gartnera marked this conversation as resolved.
Show resolved Hide resolved

// 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: [chaincfg.DefinedDeployments]chaincfg.ConsensusDeployment{
chaincfg.DeploymentTestDummy: {
BitNumber: 28,
DeploymentStarter: chaincfg.NewMedianTimeDeploymentStarter(
time.Time{}, // Always available for vote
),
DeploymentEnder: chaincfg.NewMedianTimeDeploymentEnder(
time.Time{}, // Never expires
),
},
chaincfg.DeploymentTestDummyMinActivation: {
BitNumber: 22,
CustomActivationThreshold: 1815, // Only needs 90% hash rate.
MinActivationHeight: 10_0000, // Can only activate after height 10k.
DeploymentStarter: chaincfg.NewMedianTimeDeploymentStarter(
time.Time{}, // Always available for vote
),
DeploymentEnder: chaincfg.NewMedianTimeDeploymentEnder(
time.Time{}, // Never expires
),
},
chaincfg.DeploymentCSV: {
BitNumber: 0,
DeploymentStarter: chaincfg.NewMedianTimeDeploymentStarter(
time.Time{}, // Always available for vote
),
DeploymentEnder: chaincfg.NewMedianTimeDeploymentEnder(
time.Time{}, // Never expires
),
},
chaincfg.DeploymentSegwit: {
BitNumber: 1,
DeploymentStarter: chaincfg.NewMedianTimeDeploymentStarter(
time.Time{}, // Always available for vote
),
DeploymentEnder: chaincfg.NewMedianTimeDeploymentEnder(
time.Time{}, // Never expires
),
},
chaincfg.DeploymentTaproot: {
BitNumber: 2,
DeploymentStarter: chaincfg.NewMedianTimeDeploymentStarter(
time.Time{}, // Always available for vote
),
DeploymentEnder: chaincfg.NewMedianTimeDeploymentEnder(
time.Time{}, // Never expires
),
CustomActivationThreshold: 1512, // 75%
},
},

// 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,
}
4 changes: 4 additions & 0 deletions pkg/chains/chain.go
Original file line number Diff line number Diff line change
Expand Up @@ -203,6 +203,8 @@ func GetBTCChainParams(chainID int64) (*chaincfg.Params, error) {
return &chaincfg.MainNetParams, nil
case BitcoinSignetTestnet.ChainId:
return &chaincfg.SigNetParams, nil
case BitcoinTestnet4.ChainId:
return &TestNet4Params, nil
default:
return nil, fmt.Errorf("error chainID %d is not a bitcoin chain", chainID)
}
Expand All @@ -219,6 +221,8 @@ func GetBTCChainIDFromChainParams(params *chaincfg.Params) (int64, error) {
return BitcoinMainnet.ChainId, nil
case chaincfg.SigNetParams.Name:
return BitcoinSignetTestnet.ChainId, nil
case TestNet4Params.Name:
return BitcoinTestnet4.ChainId, nil
default:
return 0, fmt.Errorf("error chain %s is not a bitcoin chain", params.Name)
}
Expand Down
45 changes: 44 additions & 1 deletion pkg/chains/chain_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -147,19 +147,54 @@ func TestChain_EncodeAddress(t *testing.T) {
wantErr bool
}{
{
name: "should error if b is not a valid address on the bitcoin network",
name: "should error if b is not a valid address on the bitcoin testnet network",
chain: chains.BitcoinTestnet,
b: []byte("bc1qk0cc73p8m7hswn8y2q080xa4e5pxapnqgp7h9c"),
want: "",
wantErr: true,
},
{
name: "should error if b is not a valid address on the bitcoin signet network",
chain: chains.BitcoinSignetTestnet,
b: []byte("bc1qk0cc73p8m7hswn8y2q080xa4e5pxapnqgp7h9c"),
want: "",
wantErr: true,
},
{
name: "should error if b is not a valid address on the bitcoin testnet4 network",
chain: chains.BitcoinTestnet4,
b: []byte("bc1qk0cc73p8m7hswn8y2q080xa4e5pxapnqgp7h9c"),
want: "",
wantErr: true,
},
gartnera marked this conversation as resolved.
Show resolved Hide resolved
{
name: "should pass if b is a valid address on the network",
chain: chains.BitcoinMainnet,
b: []byte("bc1qk0cc73p8m7hswn8y2q080xa4e5pxapnqgp7h9c"),
want: "bc1qk0cc73p8m7hswn8y2q080xa4e5pxapnqgp7h9c",
wantErr: false,
},
{
name: "valid bitcoin testnet address",
chain: chains.BitcoinTestnet,
b: []byte("tb1qy9pqmk2pd9sv63g27jt8r657wy0d9ueeh0nqur"),
want: "tb1qy9pqmk2pd9sv63g27jt8r657wy0d9ueeh0nqur",
wantErr: false,
},
{
name: "valid bitcoin signet address",
chain: chains.BitcoinSignetTestnet,
b: []byte("tb1qy9pqmk2pd9sv63g27jt8r657wy0d9ueeh0nqur"),
want: "tb1qy9pqmk2pd9sv63g27jt8r657wy0d9ueeh0nqur",
wantErr: false,
},
{
name: "valid bitcoin testnet4 address",
chain: chains.BitcoinTestnet4,
b: []byte("tb1qy9pqmk2pd9sv63g27jt8r657wy0d9ueeh0nqur"),
want: "tb1qy9pqmk2pd9sv63g27jt8r657wy0d9ueeh0nqur",
wantErr: false,
},
{
name: "should pass if b is a valid wallet address on the solana network",
chain: chains.SolanaMainnet,
Expand Down Expand Up @@ -207,6 +242,7 @@ func TestChain_EncodeAddress(t *testing.T) {
require.Error(t, err)
return
}
require.NoError(t, err)
require.Equal(t, tc.want, s)
})
}
Expand Down Expand Up @@ -242,6 +278,7 @@ func TestChain_IsBitcoinChain(t *testing.T) {
{"Bitcoin Testnet", chains.BitcoinTestnet, true},
{"Bitcoin Regtest", chains.BitcoinRegtest, true},
{"Bitcoin Signet Testnet", chains.BitcoinSignetTestnet, true},
{"Bitcoin Testnet4", chains.BitcoinTestnet4, true},
{"Non-Bitcoin", chains.Ethereum, false},
{"Zeta Mainnet", chains.ZetaChainMainnet, false},
}
Expand Down Expand Up @@ -500,6 +537,12 @@ func TestGetBTCChainIDFromChainParams(t *testing.T) {
expectedChainID: chains.BitcoinSignetTestnet.ChainId,
expectedError: require.NoError,
},
{
name: "Bitcoin Testnet4",
params: &chains.TestNet4Params,
expectedChainID: chains.BitcoinTestnet4.ChainId,
expectedError: require.NoError,
},
{
name: "Unknown Chain",
params: &chaincfg.Params{Name: "unknown"},
Expand Down
6 changes: 6 additions & 0 deletions pkg/crypto/tss_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -68,6 +68,12 @@ func TestGetTssAddrBTC(t *testing.T) {
bitcoinParams: &chaincfg.TestNet3Params,
wantErr: false,
},
{
name: "Valid TSS pubkey signet params",
tssPubkey: pk,
bitcoinParams: &chaincfg.SigNetParams,
wantErr: false,
},
gartnera marked this conversation as resolved.
Show resolved Hide resolved
{
name: "Invalid TSS pubkey testnet params",
tssPubkey: "invalid",
Expand Down
Loading
Loading