diff --git a/chaincfg/README.md b/chaincfg/README.md new file mode 100644 index 00000000..c61aaab0 --- /dev/null +++ b/chaincfg/README.md @@ -0,0 +1,98 @@ +chaincfg +======== + +[![Build Status](http://img.shields.io/travis/btcsuite/btcd.svg)] +(https://travis-ci.org/btcsuite/btcd) [![ISC License] +(http://img.shields.io/badge/license-ISC-blue.svg)](http://copyfree.org) + +Package chaincfg defines chain configuration parameters for the three standard +Bitcoin networks and provides the ability for callers to define their own custom +Bitcoin networks. + +Although this package was primarily written for btcd, it has intentionally been +designed so it can be used as a standalone package for any projects needing to +use parameters for the standard Bitcoin networks or for projects needing to +define their own network. + +## Sample Use + +```Go +package main + +import ( + "flag" + "fmt" + "log" + + "github.com/btcsuite/btcutil" + "github.com/btcsuite/btcd/chaincfg" +) + +var testnet = flag.Bool("testnet", false, "operate on the testnet Bitcoin network") + +// By default (without -testnet), use mainnet. +var chainParams = &chaincfg.MainNetParams + +func main() { + flag.Parse() + + // Modify active network parameters if operating on testnet. + if *testnet { + chainParams = &chaincfg.TestNet3Params + } + + // later... + + // Create and print new payment address, specific to the active network. + pubKeyHash := make([]byte, 20) + addr, err := btcutil.NewAddressPubKeyHash(pubKeyHash, chainParams) + if err != nil { + log.Fatal(err) + } + fmt.Println(addr) +} +``` + +## Documentation + +[![GoDoc](https://img.shields.io/badge/godoc-reference-blue.svg)] +(http://godoc.org/github.com/btcsuite/btcd/chaincfg) + +Full `go doc` style documentation for the project can be viewed online without +installing this package by using the GoDoc site +[here](http://godoc.org/github.com/btcsuite/btcd/chaincfg). + +You can also view the documentation locally once the package is installed with +the `godoc` tool by running `godoc -http=":6060"` and pointing your browser to +http://localhost:6060/pkg/github.com/btcsuite/btcd/chaincfg + +## Installation + +```bash +$ go get github.com/btcsuite/btcd/chaincfg +``` + +## GPG Verification Key + +All official release tags are signed by Conformal so users can ensure the code +has not been tampered with and is coming from Conformal. To verify the +signature perform the following: + +- Download the public key from the Conformal website at + https://opensource.conformal.com/GIT-GPG-KEY-conformal.txt + +- Import the public key into your GPG keyring: + ```bash + gpg --import GIT-GPG-KEY-conformal.txt + ``` + +- Verify the release tag with the following command where `TAG_NAME` is a + placeholder for the specific tag: + ```bash + git tag -v TAG_NAME + ``` + +## License + +Package chaincfg is licensed under the [copyfree](http://copyfree.org) ISC +License. diff --git a/chaincfg/doc.go b/chaincfg/doc.go new file mode 100644 index 00000000..3659adbf --- /dev/null +++ b/chaincfg/doc.go @@ -0,0 +1,61 @@ +// Package chaincfg defines chain configuration parameters. +// +// In addition to the main Bitcoin network, which is intended for the transfer +// of monetary value, there also exists two currently active standard networks: +// regression test and testnet (version 3). These networks are incompatible +// with each other (each sharing a different genesis block) and software should +// handle errors where input intended for one network is used on an application +// instance running on a different network. +// +// For library packages, chaincfg provides the ability to lookup chain +// parameters and encoding magics when passed a *Params. Older APIs not updated +// to the new convention of passing a *Params may lookup the parameters for a +// wire.BitcoinNet using ParamsForNet, but be aware that this usage is +// deprecated and will be removed from chaincfg in the future. +// +// For main packages, a (typically global) var may be assigned the address of +// one of the standard Param vars for use as the application's "active" network. +// When a network parameter is needed, it may then be looked up through this +// variable (either directly, or hidden in a library call). +// +// package main +// +// import ( +// "flag" +// "fmt" +// "log" +// +// "github.com/btcsuite/btcutil" +// "github.com/btcsuite/btcd/chaincfg" +// ) +// +// var testnet = flag.Bool("testnet", false, "operate on the testnet Bitcoin network") +// +// // By default (without -testnet), use mainnet. +// var chainParams = &chaincfg.MainNetParams +// +// func main() { +// flag.Parse() +// +// // Modify active network parameters if operating on testnet. +// if *testnet { +// chainParams = &chaincfg.TestNet3Params +// } +// +// // later... +// +// // Create and print new payment address, specific to the active network. +// pubKeyHash := make([]byte, 20) +// addr, err := btcutil.NewAddressPubKeyHash(pubKeyHash, chainParams) +// if err != nil { +// log.Fatal(err) +// } +// fmt.Println(addr) +// } +// +// If an application does not use one of the three standard Bitcoin networks, +// a new Params struct may be created which defines the parameters for the +// non-standard network. As a general rule of thumb, all network parameters +// should be unique to the network, but parameter collisions can still occur +// (unfortunately, this is the case with regtest and testnet3 sharing magics). +package chaincfg diff --git a/chaincfg/genesis.go b/chaincfg/genesis.go new file mode 100644 index 00000000..ffdaaa0f --- /dev/null +++ b/chaincfg/genesis.go @@ -0,0 +1,171 @@ +// Copyright (c) 2014 Conformal Systems LLC. +// Use of this source code is governed by an ISC +// license that can be found in the LICENSE file. + +package chaincfg + +import ( + "time" + + "github.com/btcsuite/btcd/wire" +) + +// genesisCoinbaseTx is the coinbase transaction for the genesis blocks for +// the main network, regression test network, and test network (version 3). +var genesisCoinbaseTx = wire.MsgTx{ + Version: 1, + TxIn: []*wire.TxIn{ + { + PreviousOutPoint: wire.OutPoint{ + Hash: wire.ShaHash{}, + Index: 0xffffffff, + }, + SignatureScript: []byte{ + 0x04, 0xff, 0xff, 0x00, 0x1d, 0x01, 0x04, 0x45, /* |.......E| */ + 0x54, 0x68, 0x65, 0x20, 0x54, 0x69, 0x6d, 0x65, /* |The Time| */ + 0x73, 0x20, 0x30, 0x33, 0x2f, 0x4a, 0x61, 0x6e, /* |s 03/Jan| */ + 0x2f, 0x32, 0x30, 0x30, 0x39, 0x20, 0x43, 0x68, /* |/2009 Ch| */ + 0x61, 0x6e, 0x63, 0x65, 0x6c, 0x6c, 0x6f, 0x72, /* |ancellor| */ + 0x20, 0x6f, 0x6e, 0x20, 0x62, 0x72, 0x69, 0x6e, /* | on brin| */ + 0x6b, 0x20, 0x6f, 0x66, 0x20, 0x73, 0x65, 0x63, /* |k of sec|*/ + 0x6f, 0x6e, 0x64, 0x20, 0x62, 0x61, 0x69, 0x6c, /* |ond bail| */ + 0x6f, 0x75, 0x74, 0x20, 0x66, 0x6f, 0x72, 0x20, /* |out for |*/ + 0x62, 0x61, 0x6e, 0x6b, 0x73, /* |banks| */ + }, + Sequence: 0xffffffff, + }, + }, + TxOut: []*wire.TxOut{ + { + Value: 0x12a05f200, + PkScript: []byte{ + 0x41, 0x04, 0x67, 0x8a, 0xfd, 0xb0, 0xfe, 0x55, /* |A.g....U| */ + 0x48, 0x27, 0x19, 0x67, 0xf1, 0xa6, 0x71, 0x30, /* |H'.g..q0| */ + 0xb7, 0x10, 0x5c, 0xd6, 0xa8, 0x28, 0xe0, 0x39, /* |..\..(.9| */ + 0x09, 0xa6, 0x79, 0x62, 0xe0, 0xea, 0x1f, 0x61, /* |..yb...a| */ + 0xde, 0xb6, 0x49, 0xf6, 0xbc, 0x3f, 0x4c, 0xef, /* |..I..?L.| */ + 0x38, 0xc4, 0xf3, 0x55, 0x04, 0xe5, 0x1e, 0xc1, /* |8..U....| */ + 0x12, 0xde, 0x5c, 0x38, 0x4d, 0xf7, 0xba, 0x0b, /* |..\8M...| */ + 0x8d, 0x57, 0x8a, 0x4c, 0x70, 0x2b, 0x6b, 0xf1, /* |.W.Lp+k.| */ + 0x1d, 0x5f, 0xac, /* |._.| */ + }, + }, + }, + LockTime: 0, +} + +// genesisHash is the hash of the first block in the block chain for the main +// network (genesis block). +var genesisHash = wire.ShaHash([wire.HashSize]byte{ // Make go vet happy. + 0x6f, 0xe2, 0x8c, 0x0a, 0xb6, 0xf1, 0xb3, 0x72, + 0xc1, 0xa6, 0xa2, 0x46, 0xae, 0x63, 0xf7, 0x4f, + 0x93, 0x1e, 0x83, 0x65, 0xe1, 0x5a, 0x08, 0x9c, + 0x68, 0xd6, 0x19, 0x00, 0x00, 0x00, 0x00, 0x00, +}) + +// genesisMerkleRoot is the hash of the first transaction in the genesis block +// for the main network. +var genesisMerkleRoot = wire.ShaHash([wire.HashSize]byte{ // Make go vet happy. + 0x3b, 0xa3, 0xed, 0xfd, 0x7a, 0x7b, 0x12, 0xb2, + 0x7a, 0xc7, 0x2c, 0x3e, 0x67, 0x76, 0x8f, 0x61, + 0x7f, 0xc8, 0x1b, 0xc3, 0x88, 0x8a, 0x51, 0x32, + 0x3a, 0x9f, 0xb8, 0xaa, 0x4b, 0x1e, 0x5e, 0x4a, +}) + +// genesisBlock defines the genesis block of the block chain which serves as the +// public transaction ledger for the main network. +var genesisBlock = wire.MsgBlock{ + Header: wire.BlockHeader{ + Version: 1, + PrevBlock: wire.ShaHash{}, // 0000000000000000000000000000000000000000000000000000000000000000 + MerkleRoot: genesisMerkleRoot, // 4a5e1e4baab89f3a32518a88c31bc87f618f76673e2cc77ab2127b7afdeda33b + Timestamp: time.Unix(0x495fab29, 0), // 2009-01-03 18:15:05 +0000 UTC + Bits: 0x1d00ffff, // 486604799 [00000000ffff0000000000000000000000000000000000000000000000000000] + Nonce: 0x7c2bac1d, // 2083236893 + }, + Transactions: []*wire.MsgTx{&genesisCoinbaseTx}, +} + +// regTestGenesisHash is the hash of the first block in the block chain for the +// regression test network (genesis block). +var regTestGenesisHash = wire.ShaHash([wire.HashSize]byte{ // Make go vet happy. + 0x06, 0x22, 0x6e, 0x46, 0x11, 0x1a, 0x0b, 0x59, + 0xca, 0xaf, 0x12, 0x60, 0x43, 0xeb, 0x5b, 0xbf, + 0x28, 0xc3, 0x4f, 0x3a, 0x5e, 0x33, 0x2a, 0x1f, + 0xc7, 0xb2, 0xb7, 0x3c, 0xf1, 0x88, 0x91, 0x0f, +}) + +// regTestGenesisMerkleRoot is the hash of the first transaction in the genesis +// block for the regression test network. It is the same as the merkle root for +// the main network. +var regTestGenesisMerkleRoot = genesisMerkleRoot + +// regTestGenesisBlock defines the genesis block of the block chain which serves +// as the public transaction ledger for the regression test network. +var regTestGenesisBlock = wire.MsgBlock{ + Header: wire.BlockHeader{ + Version: 1, + PrevBlock: wire.ShaHash{}, // 0000000000000000000000000000000000000000000000000000000000000000 + MerkleRoot: regTestGenesisMerkleRoot, // 4a5e1e4baab89f3a32518a88c31bc87f618f76673e2cc77ab2127b7afdeda33b + Timestamp: time.Unix(1296688602, 0), // 2011-02-02 23:16:42 +0000 UTC + Bits: 0x207fffff, // 545259519 [7fffff0000000000000000000000000000000000000000000000000000000000] + Nonce: 2, + }, + Transactions: []*wire.MsgTx{&genesisCoinbaseTx}, +} + +// testNet3GenesisHash is the hash of the first block in the block chain for the +// test network (version 3). +var testNet3GenesisHash = wire.ShaHash([wire.HashSize]byte{ // Make go vet happy. + 0x43, 0x49, 0x7f, 0xd7, 0xf8, 0x26, 0x95, 0x71, + 0x08, 0xf4, 0xa3, 0x0f, 0xd9, 0xce, 0xc3, 0xae, + 0xba, 0x79, 0x97, 0x20, 0x84, 0xe9, 0x0e, 0xad, + 0x01, 0xea, 0x33, 0x09, 0x00, 0x00, 0x00, 0x00, +}) + +// testNet3GenesisMerkleRoot is the hash of the first transaction in the genesis +// block for the test network (version 3). It is the same as the merkle root +// for the main network. +var testNet3GenesisMerkleRoot = genesisMerkleRoot + +// testNet3GenesisBlock defines the genesis block of the block chain which +// serves as the public transaction ledger for the test network (version 3). +var testNet3GenesisBlock = wire.MsgBlock{ + Header: wire.BlockHeader{ + Version: 1, + PrevBlock: wire.ShaHash{}, // 0000000000000000000000000000000000000000000000000000000000000000 + MerkleRoot: testNet3GenesisMerkleRoot, // 4a5e1e4baab89f3a32518a88c31bc87f618f76673e2cc77ab2127b7afdeda33b + Timestamp: time.Unix(1296688602, 0), // 2011-02-02 23:16:42 +0000 UTC + Bits: 0x1d00ffff, // 486604799 [00000000ffff0000000000000000000000000000000000000000000000000000] + Nonce: 0x18aea41a, // 414098458 + }, + Transactions: []*wire.MsgTx{&genesisCoinbaseTx}, +} + +// simNetGenesisHash is the hash of the first block in the block chain for the +// simulation test network. +var simNetGenesisHash = wire.ShaHash([wire.HashSize]byte{ // Make go vet happy. + 0xf6, 0x7a, 0xd7, 0x69, 0x5d, 0x9b, 0x66, 0x2a, + 0x72, 0xff, 0x3d, 0x8e, 0xdb, 0xbb, 0x2d, 0xe0, + 0xbf, 0xa6, 0x7b, 0x13, 0x97, 0x4b, 0xb9, 0x91, + 0x0d, 0x11, 0x6d, 0x5c, 0xbd, 0x86, 0x3e, 0x68, +}) + +// simNetGenesisMerkleRoot is the hash of the first transaction in the genesis +// block for the simulation test network. It is the same as the merkle root for +// the main network. +var simNetGenesisMerkleRoot = genesisMerkleRoot + +// simNetGenesisBlock defines the genesis block of the block chain which serves +// as the public transaction ledger for the simulation test network. +var simNetGenesisBlock = wire.MsgBlock{ + Header: wire.BlockHeader{ + Version: 1, + PrevBlock: wire.ShaHash{}, // 0000000000000000000000000000000000000000000000000000000000000000 + MerkleRoot: simNetGenesisMerkleRoot, // 4a5e1e4baab89f3a32518a88c31bc87f618f76673e2cc77ab2127b7afdeda33b + Timestamp: time.Unix(1401292357, 0), // 2014-05-28 15:52:37 +0000 UTC + Bits: 0x207fffff, // 545259519 [7fffff0000000000000000000000000000000000000000000000000000000000] + Nonce: 2, + }, + Transactions: []*wire.MsgTx{&genesisCoinbaseTx}, +} diff --git a/chaincfg/genesis_test.go b/chaincfg/genesis_test.go new file mode 100644 index 00000000..39304108 --- /dev/null +++ b/chaincfg/genesis_test.go @@ -0,0 +1,296 @@ +// Copyright (c) 2014 Conformal Systems LLC. +// Use of this source code is governed by an ISC +// license that can be found in the LICENSE file. + +package chaincfg_test + +import ( + "bytes" + "testing" + + "github.com/btcsuite/btcd/chaincfg" + "github.com/davecgh/go-spew/spew" +) + +// TestGenesisBlock tests the genesis block of the main network for validity by +// checking the encoded bytes and hashes. +func TestGenesisBlock(t *testing.T) { + // Encode the genesis block to raw bytes. + var buf bytes.Buffer + err := chaincfg.MainNetParams.GenesisBlock.Serialize(&buf) + if err != nil { + t.Fatalf("TestGenesisBlock: %v", err) + } + + // Ensure the encoded block matches the expected bytes. + if !bytes.Equal(buf.Bytes(), genesisBlockBytes) { + t.Fatalf("TestGenesisBlock: Genesis block does not appear valid - "+ + "got %v, want %v", spew.Sdump(buf.Bytes()), + spew.Sdump(genesisBlockBytes)) + } + + // Check hash of the block against expected hash. + hash, err := chaincfg.MainNetParams.GenesisBlock.BlockSha() + if err != nil { + t.Fatalf("BlockSha: %v", err) + } + if !chaincfg.MainNetParams.GenesisHash.IsEqual(&hash) { + t.Fatalf("TestGenesisBlock: Genesis block hash does not "+ + "appear valid - got %v, want %v", spew.Sdump(hash), + spew.Sdump(chaincfg.MainNetParams.GenesisHash)) + } +} + +// TestRegTestGenesisBlock tests the genesis block of the regression test +// network for validity by checking the encoded bytes and hashes. +func TestRegTestGenesisBlock(t *testing.T) { + // Encode the genesis block to raw bytes. + var buf bytes.Buffer + err := chaincfg.RegressionNetParams.GenesisBlock.Serialize(&buf) + if err != nil { + t.Fatalf("TestRegTestGenesisBlock: %v", err) + } + + // Ensure the encoded block matches the expected bytes. + if !bytes.Equal(buf.Bytes(), regTestGenesisBlockBytes) { + t.Fatalf("TestRegTestGenesisBlock: Genesis block does not "+ + "appear valid - got %v, want %v", + spew.Sdump(buf.Bytes()), + spew.Sdump(regTestGenesisBlockBytes)) + } + + // Check hash of the block against expected hash. + hash, err := chaincfg.RegressionNetParams.GenesisBlock.BlockSha() + if err != nil { + t.Errorf("BlockSha: %v", err) + } + if !chaincfg.RegressionNetParams.GenesisHash.IsEqual(&hash) { + t.Fatalf("TestRegTestGenesisBlock: Genesis block hash does "+ + "not appear valid - got %v, want %v", spew.Sdump(hash), + spew.Sdump(chaincfg.RegressionNetParams.GenesisHash)) + } +} + +// TestTestNet3GenesisBlock tests the genesis block of the test network (version +// 3) for validity by checking the encoded bytes and hashes. +func TestTestNet3GenesisBlock(t *testing.T) { + // Encode the genesis block to raw bytes. + var buf bytes.Buffer + err := chaincfg.TestNet3Params.GenesisBlock.Serialize(&buf) + if err != nil { + t.Fatalf("TestTestNet3GenesisBlock: %v", err) + } + + // Ensure the encoded block matches the expected bytes. + if !bytes.Equal(buf.Bytes(), testNet3GenesisBlockBytes) { + t.Fatalf("TestTestNet3GenesisBlock: Genesis block does not "+ + "appear valid - got %v, want %v", + spew.Sdump(buf.Bytes()), + spew.Sdump(testNet3GenesisBlockBytes)) + } + + // Check hash of the block against expected hash. + hash, err := chaincfg.TestNet3Params.GenesisBlock.BlockSha() + if err != nil { + t.Fatalf("BlockSha: %v", err) + } + if !chaincfg.TestNet3Params.GenesisHash.IsEqual(&hash) { + t.Fatalf("TestTestNet3GenesisBlock: Genesis block hash does "+ + "not appear valid - got %v, want %v", spew.Sdump(hash), + spew.Sdump(chaincfg.TestNet3Params.GenesisHash)) + } +} + +// TestSimNetGenesisBlock tests the genesis block of the simulation test network +// for validity by checking the encoded bytes and hashes. +func TestSimNetGenesisBlock(t *testing.T) { + // Encode the genesis block to raw bytes. + var buf bytes.Buffer + err := chaincfg.SimNetParams.GenesisBlock.Serialize(&buf) + if err != nil { + t.Fatalf("TestSimNetGenesisBlock: %v", err) + } + + // Ensure the encoded block matches the expected bytes. + if !bytes.Equal(buf.Bytes(), simNetGenesisBlockBytes) { + t.Fatalf("TestSimNetGenesisBlock: Genesis block does not "+ + "appear valid - got %v, want %v", + spew.Sdump(buf.Bytes()), + spew.Sdump(simNetGenesisBlockBytes)) + } + + // Check hash of the block against expected hash. + hash, err := chaincfg.SimNetParams.GenesisBlock.BlockSha() + if err != nil { + t.Fatalf("BlockSha: %v", err) + } + if !chaincfg.SimNetParams.GenesisHash.IsEqual(&hash) { + t.Fatalf("TestSimNetGenesisBlock: Genesis block hash does "+ + "not appear valid - got %v, want %v", spew.Sdump(hash), + spew.Sdump(chaincfg.SimNetParams.GenesisHash)) + } +} + +// genesisBlockBytes are the wire encoded bytes for the genesis block of the +// main network as of protocol version 60002. +var genesisBlockBytes = []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, 0x3b, 0xa3, 0xed, 0xfd, /* |....;...| */ + 0x7a, 0x7b, 0x12, 0xb2, 0x7a, 0xc7, 0x2c, 0x3e, /* |z{..z.,>| */ + 0x67, 0x76, 0x8f, 0x61, 0x7f, 0xc8, 0x1b, 0xc3, /* |gv.a....| */ + 0x88, 0x8a, 0x51, 0x32, 0x3a, 0x9f, 0xb8, 0xaa, /* |..Q2:...| */ + 0x4b, 0x1e, 0x5e, 0x4a, 0x29, 0xab, 0x5f, 0x49, /* |K.^J)._I| */ + 0xff, 0xff, 0x00, 0x1d, 0x1d, 0xac, 0x2b, 0x7c, /* |......+|| */ + 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, 0x4d, 0x04, 0xff, 0xff, 0x00, 0x1d, /* |..M.....| */ + 0x01, 0x04, 0x45, 0x54, 0x68, 0x65, 0x20, 0x54, /* |..EThe T| */ + 0x69, 0x6d, 0x65, 0x73, 0x20, 0x30, 0x33, 0x2f, /* |imes 03/| */ + 0x4a, 0x61, 0x6e, 0x2f, 0x32, 0x30, 0x30, 0x39, /* |Jan/2009| */ + 0x20, 0x43, 0x68, 0x61, 0x6e, 0x63, 0x65, 0x6c, /* | Chancel| */ + 0x6c, 0x6f, 0x72, 0x20, 0x6f, 0x6e, 0x20, 0x62, /* |lor on b| */ + 0x72, 0x69, 0x6e, 0x6b, 0x20, 0x6f, 0x66, 0x20, /* |rink of | */ + 0x73, 0x65, 0x63, 0x6f, 0x6e, 0x64, 0x20, 0x62, /* |second b| */ + 0x61, 0x69, 0x6c, 0x6f, 0x75, 0x74, 0x20, 0x66, /* |ailout f| */ + 0x6f, 0x72, 0x20, 0x62, 0x61, 0x6e, 0x6b, 0x73, /* |or banks| */ + 0xff, 0xff, 0xff, 0xff, 0x01, 0x00, 0xf2, 0x05, /* |........| */ + 0x2a, 0x01, 0x00, 0x00, 0x00, 0x43, 0x41, 0x04, /* |*....CA.| */ + 0x67, 0x8a, 0xfd, 0xb0, 0xfe, 0x55, 0x48, 0x27, /* |g....UH'| */ + 0x19, 0x67, 0xf1, 0xa6, 0x71, 0x30, 0xb7, 0x10, /* |.g..q0..| */ + 0x5c, 0xd6, 0xa8, 0x28, 0xe0, 0x39, 0x09, 0xa6, /* |\..(.9..| */ + 0x79, 0x62, 0xe0, 0xea, 0x1f, 0x61, 0xde, 0xb6, /* |yb...a..| */ + 0x49, 0xf6, 0xbc, 0x3f, 0x4c, 0xef, 0x38, 0xc4, /* |I..?L.8.| */ + 0xf3, 0x55, 0x04, 0xe5, 0x1e, 0xc1, 0x12, 0xde, /* |.U......| */ + 0x5c, 0x38, 0x4d, 0xf7, 0xba, 0x0b, 0x8d, 0x57, /* |\8M....W| */ + 0x8a, 0x4c, 0x70, 0x2b, 0x6b, 0xf1, 0x1d, 0x5f, /* |.Lp+k.._|*/ + 0xac, 0x00, 0x00, 0x00, 0x00, /* |.....| */ +} + +// regTestGenesisBlockBytes are the wire encoded bytes for the genesis block of +// the regression test network as of protocol version 60002. +var regTestGenesisBlockBytes = []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, 0x3b, 0xa3, 0xed, 0xfd, /* |....;...| */ + 0x7a, 0x7b, 0x12, 0xb2, 0x7a, 0xc7, 0x2c, 0x3e, /* |z{..z.,>| */ + 0x67, 0x76, 0x8f, 0x61, 0x7f, 0xc8, 0x1b, 0xc3, /* |gv.a....| */ + 0x88, 0x8a, 0x51, 0x32, 0x3a, 0x9f, 0xb8, 0xaa, /* |..Q2:...| */ + 0x4b, 0x1e, 0x5e, 0x4a, 0xda, 0xe5, 0x49, 0x4d, /* |K.^J)._I| */ + 0xff, 0xff, 0x7f, 0x20, 0x02, 0x00, 0x00, 0x00, /* |......+|| */ + 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, 0x4d, 0x04, 0xff, 0xff, 0x00, 0x1d, /* |..M.....| */ + 0x01, 0x04, 0x45, 0x54, 0x68, 0x65, 0x20, 0x54, /* |..EThe T| */ + 0x69, 0x6d, 0x65, 0x73, 0x20, 0x30, 0x33, 0x2f, /* |imes 03/| */ + 0x4a, 0x61, 0x6e, 0x2f, 0x32, 0x30, 0x30, 0x39, /* |Jan/2009| */ + 0x20, 0x43, 0x68, 0x61, 0x6e, 0x63, 0x65, 0x6c, /* | Chancel| */ + 0x6c, 0x6f, 0x72, 0x20, 0x6f, 0x6e, 0x20, 0x62, /* |lor on b| */ + 0x72, 0x69, 0x6e, 0x6b, 0x20, 0x6f, 0x66, 0x20, /* |rink of | */ + 0x73, 0x65, 0x63, 0x6f, 0x6e, 0x64, 0x20, 0x62, /* |second b| */ + 0x61, 0x69, 0x6c, 0x6f, 0x75, 0x74, 0x20, 0x66, /* |ailout f| */ + 0x6f, 0x72, 0x20, 0x62, 0x61, 0x6e, 0x6b, 0x73, /* |or banks| */ + 0xff, 0xff, 0xff, 0xff, 0x01, 0x00, 0xf2, 0x05, /* |........| */ + 0x2a, 0x01, 0x00, 0x00, 0x00, 0x43, 0x41, 0x04, /* |*....CA.| */ + 0x67, 0x8a, 0xfd, 0xb0, 0xfe, 0x55, 0x48, 0x27, /* |g....UH'| */ + 0x19, 0x67, 0xf1, 0xa6, 0x71, 0x30, 0xb7, 0x10, /* |.g..q0..| */ + 0x5c, 0xd6, 0xa8, 0x28, 0xe0, 0x39, 0x09, 0xa6, /* |\..(.9..| */ + 0x79, 0x62, 0xe0, 0xea, 0x1f, 0x61, 0xde, 0xb6, /* |yb...a..| */ + 0x49, 0xf6, 0xbc, 0x3f, 0x4c, 0xef, 0x38, 0xc4, /* |I..?L.8.| */ + 0xf3, 0x55, 0x04, 0xe5, 0x1e, 0xc1, 0x12, 0xde, /* |.U......| */ + 0x5c, 0x38, 0x4d, 0xf7, 0xba, 0x0b, 0x8d, 0x57, /* |\8M....W| */ + 0x8a, 0x4c, 0x70, 0x2b, 0x6b, 0xf1, 0x1d, 0x5f, /* |.Lp+k.._|*/ + 0xac, 0x00, 0x00, 0x00, 0x00, /* |.....| */ +} + +// testNet3GenesisBlockBytes are the wire encoded bytes for the genesis block of +// the test network (version 3) as of protocol version 60002. +var testNet3GenesisBlockBytes = []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, 0x3b, 0xa3, 0xed, 0xfd, /* |....;...| */ + 0x7a, 0x7b, 0x12, 0xb2, 0x7a, 0xc7, 0x2c, 0x3e, /* |z{..z.,>| */ + 0x67, 0x76, 0x8f, 0x61, 0x7f, 0xc8, 0x1b, 0xc3, /* |gv.a....| */ + 0x88, 0x8a, 0x51, 0x32, 0x3a, 0x9f, 0xb8, 0xaa, /* |..Q2:...| */ + 0x4b, 0x1e, 0x5e, 0x4a, 0xda, 0xe5, 0x49, 0x4d, /* |K.^J)._I| */ + 0xff, 0xff, 0x00, 0x1d, 0x1a, 0xa4, 0xae, 0x18, /* |......+|| */ + 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, 0x4d, 0x04, 0xff, 0xff, 0x00, 0x1d, /* |..M.....| */ + 0x01, 0x04, 0x45, 0x54, 0x68, 0x65, 0x20, 0x54, /* |..EThe T| */ + 0x69, 0x6d, 0x65, 0x73, 0x20, 0x30, 0x33, 0x2f, /* |imes 03/| */ + 0x4a, 0x61, 0x6e, 0x2f, 0x32, 0x30, 0x30, 0x39, /* |Jan/2009| */ + 0x20, 0x43, 0x68, 0x61, 0x6e, 0x63, 0x65, 0x6c, /* | Chancel| */ + 0x6c, 0x6f, 0x72, 0x20, 0x6f, 0x6e, 0x20, 0x62, /* |lor on b| */ + 0x72, 0x69, 0x6e, 0x6b, 0x20, 0x6f, 0x66, 0x20, /* |rink of | */ + 0x73, 0x65, 0x63, 0x6f, 0x6e, 0x64, 0x20, 0x62, /* |second b| */ + 0x61, 0x69, 0x6c, 0x6f, 0x75, 0x74, 0x20, 0x66, /* |ailout f| */ + 0x6f, 0x72, 0x20, 0x62, 0x61, 0x6e, 0x6b, 0x73, /* |or banks| */ + 0xff, 0xff, 0xff, 0xff, 0x01, 0x00, 0xf2, 0x05, /* |........| */ + 0x2a, 0x01, 0x00, 0x00, 0x00, 0x43, 0x41, 0x04, /* |*....CA.| */ + 0x67, 0x8a, 0xfd, 0xb0, 0xfe, 0x55, 0x48, 0x27, /* |g....UH'| */ + 0x19, 0x67, 0xf1, 0xa6, 0x71, 0x30, 0xb7, 0x10, /* |.g..q0..| */ + 0x5c, 0xd6, 0xa8, 0x28, 0xe0, 0x39, 0x09, 0xa6, /* |\..(.9..| */ + 0x79, 0x62, 0xe0, 0xea, 0x1f, 0x61, 0xde, 0xb6, /* |yb...a..| */ + 0x49, 0xf6, 0xbc, 0x3f, 0x4c, 0xef, 0x38, 0xc4, /* |I..?L.8.| */ + 0xf3, 0x55, 0x04, 0xe5, 0x1e, 0xc1, 0x12, 0xde, /* |.U......| */ + 0x5c, 0x38, 0x4d, 0xf7, 0xba, 0x0b, 0x8d, 0x57, /* |\8M....W| */ + 0x8a, 0x4c, 0x70, 0x2b, 0x6b, 0xf1, 0x1d, 0x5f, /* |.Lp+k.._|*/ + 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{ + 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, 0x3b, 0xa3, 0xed, 0xfd, /* |....;...| */ + 0x7a, 0x7b, 0x12, 0xb2, 0x7a, 0xc7, 0x2c, 0x3e, /* |z{..z.,>| */ + 0x67, 0x76, 0x8f, 0x61, 0x7f, 0xc8, 0x1b, 0xc3, /* |gv.a....| */ + 0x88, 0x8a, 0x51, 0x32, 0x3a, 0x9f, 0xb8, 0xaa, /* |..Q2:...| */ + 0x4b, 0x1e, 0x5e, 0x4a, 0x45, 0x06, 0x86, 0x53, /* |K.^J)._I| */ + 0xff, 0xff, 0x7f, 0x20, 0x02, 0x00, 0x00, 0x00, /* |......+|| */ + 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, 0x4d, 0x04, 0xff, 0xff, 0x00, 0x1d, /* |..M.....| */ + 0x01, 0x04, 0x45, 0x54, 0x68, 0x65, 0x20, 0x54, /* |..EThe T| */ + 0x69, 0x6d, 0x65, 0x73, 0x20, 0x30, 0x33, 0x2f, /* |imes 03/| */ + 0x4a, 0x61, 0x6e, 0x2f, 0x32, 0x30, 0x30, 0x39, /* |Jan/2009| */ + 0x20, 0x43, 0x68, 0x61, 0x6e, 0x63, 0x65, 0x6c, /* | Chancel| */ + 0x6c, 0x6f, 0x72, 0x20, 0x6f, 0x6e, 0x20, 0x62, /* |lor on b| */ + 0x72, 0x69, 0x6e, 0x6b, 0x20, 0x6f, 0x66, 0x20, /* |rink of | */ + 0x73, 0x65, 0x63, 0x6f, 0x6e, 0x64, 0x20, 0x62, /* |second b| */ + 0x61, 0x69, 0x6c, 0x6f, 0x75, 0x74, 0x20, 0x66, /* |ailout f| */ + 0x6f, 0x72, 0x20, 0x62, 0x61, 0x6e, 0x6b, 0x73, /* |or banks| */ + 0xff, 0xff, 0xff, 0xff, 0x01, 0x00, 0xf2, 0x05, /* |........| */ + 0x2a, 0x01, 0x00, 0x00, 0x00, 0x43, 0x41, 0x04, /* |*....CA.| */ + 0x67, 0x8a, 0xfd, 0xb0, 0xfe, 0x55, 0x48, 0x27, /* |g....UH'| */ + 0x19, 0x67, 0xf1, 0xa6, 0x71, 0x30, 0xb7, 0x10, /* |.g..q0..| */ + 0x5c, 0xd6, 0xa8, 0x28, 0xe0, 0x39, 0x09, 0xa6, /* |\..(.9..| */ + 0x79, 0x62, 0xe0, 0xea, 0x1f, 0x61, 0xde, 0xb6, /* |yb...a..| */ + 0x49, 0xf6, 0xbc, 0x3f, 0x4c, 0xef, 0x38, 0xc4, /* |I..?L.8.| */ + 0xf3, 0x55, 0x04, 0xe5, 0x1e, 0xc1, 0x12, 0xde, /* |.U......| */ + 0x5c, 0x38, 0x4d, 0xf7, 0xba, 0x0b, 0x8d, 0x57, /* |\8M....W| */ + 0x8a, 0x4c, 0x70, 0x2b, 0x6b, 0xf1, 0x1d, 0x5f, /* |.Lp+k.._|*/ + 0xac, 0x00, 0x00, 0x00, 0x00, /* |.....| */ +} diff --git a/chaincfg/internal_test.go b/chaincfg/internal_test.go new file mode 100644 index 00000000..6db2da14 --- /dev/null +++ b/chaincfg/internal_test.go @@ -0,0 +1,14 @@ +package chaincfg + +import ( + "testing" +) + +func TestInvalidShaStr(t *testing.T) { + defer func() { + if r := recover(); r == nil { + t.Errorf("Expected panic for invalid sha string, got nil") + } + }() + newShaHashFromStr("banana") +} diff --git a/chaincfg/params.go b/chaincfg/params.go new file mode 100644 index 00000000..b0225615 --- /dev/null +++ b/chaincfg/params.go @@ -0,0 +1,428 @@ +// Copyright (c) 2014 Conformal Systems LLC. +// Use of this source code is governed by an ISC +// license that can be found in the LICENSE file. + +package chaincfg + +import ( + "errors" + "math/big" + + "github.com/btcsuite/btcd/wire" +) + +// These variables are the chain proof-of-work limit parameters for each default +// network. +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) + + // mainPowLimit is the highest proof of work value a Bitcoin block can + // have for the main network. It is the value 2^224 - 1. + mainPowLimit = new(big.Int).Sub(new(big.Int).Lsh(bigOne, 224), bigOne) + + // regressionPowLimit is the highest proof of work value a Bitcoin block + // can have for the regression test network. It is the value 2^255 - 1. + regressionPowLimit = new(big.Int).Sub(new(big.Int).Lsh(bigOne, 255), bigOne) + + // 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) + + // simNetPowLimit is the highest proof of work value a Bitcoin block + // can have for the simulation test network. It is the value 2^255 - 1. + simNetPowLimit = new(big.Int).Sub(new(big.Int).Lsh(bigOne, 255), bigOne) +) + +// Checkpoint identifies a known good point in the block chain. Using +// checkpoints allows a few optimizations for old blocks during initial download +// and also prevents forks from old blocks. +// +// Each checkpoint is selected based upon several factors. See the +// documentation for blockchain.IsCheckpointCandidate for details on the +// selection criteria. +type Checkpoint struct { + Height int64 + Hash *wire.ShaHash +} + +// Params defines a Bitcoin network by its parameters. These parameters may be +// used by Bitcoin applications to differentiate networks as well as addresses +// and keys for one network from those intended for use on another network. +type Params struct { + Name string + Net wire.BitcoinNet + DefaultPort string + + // Chain parameters + GenesisBlock *wire.MsgBlock + GenesisHash *wire.ShaHash + PowLimit *big.Int + PowLimitBits uint32 + SubsidyHalvingInterval int32 + ResetMinDifficulty bool + + // Checkpoints ordered from oldest to newest. + Checkpoints []Checkpoint + + // Reject version 1 blocks once a majority of the network has upgraded. + // This is part of BIP0034. + BlockV1RejectNumRequired uint64 + BlockV1RejectNumToCheck uint64 + + // Ensure coinbase starts with serialized block heights for version 2 + // blocks or newer once a majority of the network has upgraded. + CoinbaseBlockHeightNumRequired uint64 + CoinbaseBlockHeightNumToCheck uint64 + + // Mempool parameters + RelayNonStdTxs bool + + // Address encoding magics + PubKeyHashAddrID byte // First byte of a P2PKH address + ScriptHashAddrID byte // First byte of a P2SH address + PrivateKeyID byte // First byte of a WIF private key + + // BIP32 hierarchical deterministic extended key magics + HDPrivateKeyID [4]byte + HDPublicKeyID [4]byte + + // BIP44 coin type used in the hierarchical deterministic path for + // address generation. + HDCoinType uint32 +} + +// MainNetParams defines the network parameters for the main Bitcoin network. +var MainNetParams = Params{ + Name: "mainnet", + Net: wire.MainNet, + DefaultPort: "8333", + + // Chain parameters + GenesisBlock: &genesisBlock, + GenesisHash: &genesisHash, + PowLimit: mainPowLimit, + PowLimitBits: 0x1d00ffff, + SubsidyHalvingInterval: 210000, + ResetMinDifficulty: false, + + // Checkpoints ordered from oldest to newest. + Checkpoints: []Checkpoint{ + {11111, newShaHashFromStr("0000000069e244f73d78e8fd29ba2fd2ed618bd6fa2ee92559f542fdb26e7c1d")}, + {33333, newShaHashFromStr("000000002dd5588a74784eaa7ab0507a18ad16a236e7b1ce69f00d7ddfb5d0a6")}, + {74000, newShaHashFromStr("0000000000573993a3c9e41ce34471c079dcf5f52a0e824a81e7f953b8661a20")}, + {105000, newShaHashFromStr("00000000000291ce28027faea320c8d2b054b2e0fe44a773f3eefb151d6bdc97")}, + {134444, newShaHashFromStr("00000000000005b12ffd4cd315cd34ffd4a594f430ac814c91184a0d42d2b0fe")}, + {168000, newShaHashFromStr("000000000000099e61ea72015e79632f216fe6cb33d7899acb35b75c8303b763")}, + {193000, newShaHashFromStr("000000000000059f452a5f7340de6682a977387c17010ff6e6c3bd83ca8b1317")}, + {210000, newShaHashFromStr("000000000000048b95347e83192f69cf0366076336c639f9b7228e9ba171342e")}, + {216116, newShaHashFromStr("00000000000001b4f4b433e81ee46494af945cf96014816a4e2370f11b23df4e")}, + {225430, newShaHashFromStr("00000000000001c108384350f74090433e7fcf79a606b8e797f065b130575932")}, + {250000, newShaHashFromStr("000000000000003887df1f29024b06fc2200b55f8af8f35453d7be294df2d214")}, + {267300, newShaHashFromStr("000000000000000a83fbd660e918f218bf37edd92b748ad940483c7c116179ac")}, + {279000, newShaHashFromStr("0000000000000001ae8c72a0b0c301f67e3afca10e819efa9041e458e9bd7e40")}, + {300255, newShaHashFromStr("0000000000000000162804527c6e9b9f0563a280525f9d08c12041def0a0f3b2")}, + {319400, newShaHashFromStr("000000000000000021c6052e9becade189495d1c539aa37c58917305fd15f13b")}, + }, + + // Reject version 1 blocks once a majority of the network has upgraded. + // 95% (950 / 1000) + // This is part of BIP0034. + BlockV1RejectNumRequired: 950, + BlockV1RejectNumToCheck: 1000, + + // Ensure coinbase starts with serialized block heights for version 2 + // blocks or newer once a majority of the network has upgraded. + // 75% (750 / 1000) + // This is part of BIP0034. + CoinbaseBlockHeightNumRequired: 750, + CoinbaseBlockHeightNumToCheck: 1000, + + // Mempool parameters + RelayNonStdTxs: false, + + // Address encoding magics + PubKeyHashAddrID: 0x00, // starts with 1 + ScriptHashAddrID: 0x05, // starts with 3 + PrivateKeyID: 0x80, // starts with 5 (uncompressed) or K (compressed) + + // BIP32 hierarchical deterministic extended key magics + HDPrivateKeyID: [4]byte{0x04, 0x88, 0xad, 0xe4}, // starts with xprv + HDPublicKeyID: [4]byte{0x04, 0x88, 0xb2, 0x1e}, // starts with xpub + + // BIP44 coin type used in the hierarchical deterministic path for + // address generation. + HDCoinType: 0, +} + +// RegressionNetParams defines the network parameters for the regression test +// Bitcoin network. Not to be confused with the test Bitcoin network (version +// 3), this network is sometimes simply called "testnet". +var RegressionNetParams = Params{ + Name: "regtest", + Net: wire.TestNet, + DefaultPort: "18444", + + // Chain parameters + GenesisBlock: ®TestGenesisBlock, + GenesisHash: ®TestGenesisHash, + PowLimit: regressionPowLimit, + PowLimitBits: 0x207fffff, + SubsidyHalvingInterval: 150, + ResetMinDifficulty: true, + + // Checkpoints ordered from oldest to newest. + Checkpoints: nil, + + // Reject version 1 blocks once a majority of the network has upgraded. + // 75% (75 / 100) + // This is part of BIP0034. + BlockV1RejectNumRequired: 75, + BlockV1RejectNumToCheck: 100, + + // Ensure coinbase starts with serialized block heights for version 2 + // blocks or newer once a majority of the network has upgraded. + // 51% (51 / 100) + // This is part of BIP0034. + CoinbaseBlockHeightNumRequired: 51, + CoinbaseBlockHeightNumToCheck: 100, + + // Mempool parameters + RelayNonStdTxs: true, + + // Address encoding magics + PubKeyHashAddrID: 0x6f, // starts with m or n + ScriptHashAddrID: 0xc4, // starts with 2 + 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, +} + +// TestNet3Params defines the network parameters for the test Bitcoin network +// (version 3). Not to be confused with the regression test network, this +// network is sometimes simply called "testnet". +var TestNet3Params = Params{ + Name: "testnet3", + Net: wire.TestNet3, + DefaultPort: "18333", + + // Chain parameters + GenesisBlock: &testNet3GenesisBlock, + GenesisHash: &testNet3GenesisHash, + PowLimit: testNet3PowLimit, + PowLimitBits: 0x1d00ffff, + SubsidyHalvingInterval: 210000, + ResetMinDifficulty: true, + + // Checkpoints ordered from oldest to newest. + Checkpoints: []Checkpoint{ + {546, newShaHashFromStr("000000002a936ca763904c3c35fce2f3556c559c0214345d31b1bcebf76acb70")}, + }, + + // Reject version 1 blocks once a majority of the network has upgraded. + // 75% (75 / 100) + // This is part of BIP0034. + BlockV1RejectNumRequired: 75, + BlockV1RejectNumToCheck: 100, + + // Ensure coinbase starts with serialized block heights for version 2 + // blocks or newer once a majority of the network has upgraded. + // 51% (51 / 100) + // This is part of BIP0034. + CoinbaseBlockHeightNumRequired: 51, + CoinbaseBlockHeightNumToCheck: 100, + + // Mempool parameters + RelayNonStdTxs: true, + + // Address encoding magics + PubKeyHashAddrID: 0x6f, // starts with m or n + ScriptHashAddrID: 0xc4, // starts with 2 + 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 +// testing. The functionality is intended to differ in that the only nodes +// which are specifically specified are used to create the network rather than +// following normal discovery rules. This is important as otherwise it would +// just turn into another public testnet. +var SimNetParams = Params{ + Name: "simnet", + Net: wire.SimNet, + DefaultPort: "18555", + + // Chain parameters + GenesisBlock: &simNetGenesisBlock, + GenesisHash: &simNetGenesisHash, + PowLimit: simNetPowLimit, + PowLimitBits: 0x207fffff, + SubsidyHalvingInterval: 210000, + ResetMinDifficulty: true, + + // Checkpoints ordered from oldest to newest. + Checkpoints: nil, + + // Reject version 1 blocks once a majority of the network has upgraded. + // 75% (75 / 100) + BlockV1RejectNumRequired: 75, + BlockV1RejectNumToCheck: 100, + + // Ensure coinbase starts with serialized block heights for version 2 + // blocks or newer once a majority of the network has upgraded. + // 51% (51 / 100) + CoinbaseBlockHeightNumRequired: 51, + CoinbaseBlockHeightNumToCheck: 100, + + // Mempool parameters + RelayNonStdTxs: true, + + // Address encoding magics + PubKeyHashAddrID: 0x3f, // starts with S + ScriptHashAddrID: 0x7b, // starts with s + PrivateKeyID: 0x64, // starts with 4 (uncompressed) or F (compressed) + + // BIP32 hierarchical deterministic extended key magics + HDPrivateKeyID: [4]byte{0x04, 0x20, 0xb9, 0x00}, // starts with sprv + HDPublicKeyID: [4]byte{0x04, 0x20, 0xbd, 0x3a}, // starts with spub + + // BIP44 coin type used in the hierarchical deterministic path for + // address generation. + HDCoinType: 115, // ASCII for s +} + +var ( + // ErrDuplicateNet describes an error where the parameters for a Bitcoin + // network could not be set due to the network already being a standard + // network or previously-registered into this package. + ErrDuplicateNet = errors.New("duplicate Bitcoin network") + + // ErrUnknownHDKeyID describes an error where the provided id which + // is intended to identify the network for a hierarchical deterministic + // private extended key is not registered. + ErrUnknownHDKeyID = errors.New("unknown hd private extended key bytes") +) + +var ( + registeredNets = map[wire.BitcoinNet]struct{}{ + MainNetParams.Net: struct{}{}, + TestNet3Params.Net: struct{}{}, + RegressionNetParams.Net: struct{}{}, + SimNetParams.Net: struct{}{}, + } + + pubKeyHashAddrIDs = map[byte]struct{}{ + MainNetParams.PubKeyHashAddrID: struct{}{}, + TestNet3Params.PubKeyHashAddrID: struct{}{}, // shared with regtest + SimNetParams.PubKeyHashAddrID: struct{}{}, + } + + scriptHashAddrIDs = map[byte]struct{}{ + MainNetParams.ScriptHashAddrID: struct{}{}, + TestNet3Params.ScriptHashAddrID: struct{}{}, // shared with regtest + SimNetParams.ScriptHashAddrID: struct{}{}, + } + + // Testnet is shared with regtest. + hdPrivToPubKeyIDs = map[[4]byte][]byte{ + MainNetParams.HDPrivateKeyID: MainNetParams.HDPublicKeyID[:], + TestNet3Params.HDPrivateKeyID: TestNet3Params.HDPublicKeyID[:], + SimNetParams.HDPrivateKeyID: SimNetParams.HDPublicKeyID[:], + } +) + +// Register registers the network parameters for a Bitcoin network. This may +// error with ErrDuplicateNet if the network is already registered (either +// due to a previous Register call, or the network being one of the default +// networks). +// +// Network parameters should be registered into this package by a main package +// as early as possible. Then, library packages may lookup networks or network +// parameters based on inputs and work regardless of the network being standard +// or not. +func Register(params *Params) error { + if _, ok := registeredNets[params.Net]; ok { + return ErrDuplicateNet + } + registeredNets[params.Net] = struct{}{} + pubKeyHashAddrIDs[params.PubKeyHashAddrID] = struct{}{} + scriptHashAddrIDs[params.ScriptHashAddrID] = struct{}{} + hdPrivToPubKeyIDs[params.HDPrivateKeyID] = params.HDPublicKeyID[:] + return nil +} + +// IsPubKeyHashAddrID returns whether the id is an identifier known to prefix a +// pay-to-pubkey-hash address on any default or registered network. This is +// used when decoding an address string into a specific address type. It is up +// to the caller to check both this and IsScriptHashAddrID and decide whether an +// address is a pubkey hash address, script hash address, neither, or +// undeterminable (if both return true). +func IsPubKeyHashAddrID(id byte) bool { + _, ok := pubKeyHashAddrIDs[id] + return ok +} + +// IsScriptHashAddrID returns whether the id is an identifier known to prefix a +// pay-to-script-hash address on any default or registered network. This is +// used when decoding an address string into a specific address type. It is up +// to the caller to check both this and IsPubKeyHashAddrID and decide whether an +// address is a pubkey hash address, script hash address, neither, or +// undeterminable (if both return true). +func IsScriptHashAddrID(id byte) bool { + _, ok := scriptHashAddrIDs[id] + return ok +} + +// HDPrivateKeyToPublicKeyID accepts a private hierarchical deterministic +// extended key id and returns the associated public key id. When the provided +// id is not registered, the ErrUnknownHDKeyID error will be returned. +func HDPrivateKeyToPublicKeyID(id []byte) ([]byte, error) { + if len(id) != 4 { + return nil, ErrUnknownHDKeyID + } + + var key [4]byte + copy(key[:], id) + pubBytes, ok := hdPrivToPubKeyIDs[key] + if !ok { + return nil, ErrUnknownHDKeyID + } + + return pubBytes, nil +} + +// newShaHashFromStr converts the passed big-endian hex string into a +// wire.ShaHash. It only differs from the one available in wire in that +// it panics on an error since it will only (and must only) be called with +// hard-coded, and therefore known good, hashes. +func newShaHashFromStr(hexStr string) *wire.ShaHash { + sha, err := wire.NewShaHashFromStr(hexStr) + if err != nil { + // Ordinarily I don't like panics in library code since it + // can take applications down without them having a chance to + // recover which is extremely annoying, however an exception is + // being made in this case because the only way this can panic + // is if there is an error in the hard-coded hashes. Thus it + // will only ever potentially panic on init and therefore is + // 100% predictable. + panic(err) + } + return sha +} diff --git a/chaincfg/register_test.go b/chaincfg/register_test.go new file mode 100644 index 00000000..b5ac392b --- /dev/null +++ b/chaincfg/register_test.go @@ -0,0 +1,380 @@ +package chaincfg_test + +import ( + "bytes" + "reflect" + "testing" + + . "github.com/btcsuite/btcd/chaincfg" +) + +// Define some of the required parameters for a user-registered +// network. This is necessary to test the registration of and +// lookup of encoding magics from the network. +var mockNetParams = Params{ + Name: "mocknet", + Net: 1<<32 - 1, + PubKeyHashAddrID: 0x9f, + ScriptHashAddrID: 0xf9, + HDPrivateKeyID: [4]byte{0x01, 0x02, 0x03, 0x04}, + HDPublicKeyID: [4]byte{0x05, 0x06, 0x07, 0x08}, +} + +func TestRegister(t *testing.T) { + type registerTest struct { + name string + params *Params + err error + } + type magicTest struct { + magic byte + valid bool + } + type hdTest struct { + priv []byte + want []byte + err error + } + + tests := []struct { + name string + register []registerTest + p2pkhMagics []magicTest + p2shMagics []magicTest + hdMagics []hdTest + }{ + { + name: "default networks", + register: []registerTest{ + { + name: "duplicate mainnet", + params: &MainNetParams, + err: ErrDuplicateNet, + }, + { + name: "duplicate regtest", + params: &RegressionNetParams, + err: ErrDuplicateNet, + }, + { + name: "duplicate testnet3", + params: &TestNet3Params, + err: ErrDuplicateNet, + }, + { + name: "duplicate simnet", + params: &SimNetParams, + err: ErrDuplicateNet, + }, + }, + p2pkhMagics: []magicTest{ + { + magic: MainNetParams.PubKeyHashAddrID, + valid: true, + }, + { + magic: TestNet3Params.PubKeyHashAddrID, + valid: true, + }, + { + magic: RegressionNetParams.PubKeyHashAddrID, + valid: true, + }, + { + magic: SimNetParams.PubKeyHashAddrID, + valid: true, + }, + { + magic: mockNetParams.PubKeyHashAddrID, + valid: false, + }, + { + magic: 0xFF, + valid: false, + }, + }, + p2shMagics: []magicTest{ + { + magic: MainNetParams.ScriptHashAddrID, + valid: true, + }, + { + magic: TestNet3Params.ScriptHashAddrID, + valid: true, + }, + { + magic: RegressionNetParams.ScriptHashAddrID, + valid: true, + }, + { + magic: SimNetParams.ScriptHashAddrID, + valid: true, + }, + { + magic: mockNetParams.ScriptHashAddrID, + valid: false, + }, + { + magic: 0xFF, + valid: false, + }, + }, + hdMagics: []hdTest{ + { + priv: MainNetParams.HDPrivateKeyID[:], + want: MainNetParams.HDPublicKeyID[:], + err: nil, + }, + { + priv: TestNet3Params.HDPrivateKeyID[:], + want: TestNet3Params.HDPublicKeyID[:], + err: nil, + }, + { + priv: RegressionNetParams.HDPrivateKeyID[:], + want: RegressionNetParams.HDPublicKeyID[:], + err: nil, + }, + { + priv: SimNetParams.HDPrivateKeyID[:], + want: SimNetParams.HDPublicKeyID[:], + err: nil, + }, + { + priv: mockNetParams.HDPrivateKeyID[:], + err: ErrUnknownHDKeyID, + }, + { + priv: []byte{0xff, 0xff, 0xff, 0xff}, + err: ErrUnknownHDKeyID, + }, + { + priv: []byte{0xff}, + err: ErrUnknownHDKeyID, + }, + }, + }, + { + name: "register mocknet", + register: []registerTest{ + { + name: "mocknet", + params: &mockNetParams, + err: nil, + }, + }, + p2pkhMagics: []magicTest{ + { + magic: MainNetParams.PubKeyHashAddrID, + valid: true, + }, + { + magic: TestNet3Params.PubKeyHashAddrID, + valid: true, + }, + { + magic: RegressionNetParams.PubKeyHashAddrID, + valid: true, + }, + { + magic: SimNetParams.PubKeyHashAddrID, + valid: true, + }, + { + magic: mockNetParams.PubKeyHashAddrID, + valid: true, + }, + { + magic: 0xFF, + valid: false, + }, + }, + p2shMagics: []magicTest{ + { + magic: MainNetParams.ScriptHashAddrID, + valid: true, + }, + { + magic: TestNet3Params.ScriptHashAddrID, + valid: true, + }, + { + magic: RegressionNetParams.ScriptHashAddrID, + valid: true, + }, + { + magic: SimNetParams.ScriptHashAddrID, + valid: true, + }, + { + magic: mockNetParams.ScriptHashAddrID, + valid: true, + }, + { + magic: 0xFF, + valid: false, + }, + }, + hdMagics: []hdTest{ + { + priv: mockNetParams.HDPrivateKeyID[:], + want: mockNetParams.HDPublicKeyID[:], + err: nil, + }, + }, + }, + { + name: "more duplicates", + register: []registerTest{ + { + name: "duplicate mainnet", + params: &MainNetParams, + err: ErrDuplicateNet, + }, + { + name: "duplicate regtest", + params: &RegressionNetParams, + err: ErrDuplicateNet, + }, + { + name: "duplicate testnet3", + params: &TestNet3Params, + err: ErrDuplicateNet, + }, + { + name: "duplicate simnet", + params: &SimNetParams, + err: ErrDuplicateNet, + }, + { + name: "duplicate mocknet", + params: &mockNetParams, + err: ErrDuplicateNet, + }, + }, + p2pkhMagics: []magicTest{ + { + magic: MainNetParams.PubKeyHashAddrID, + valid: true, + }, + { + magic: TestNet3Params.PubKeyHashAddrID, + valid: true, + }, + { + magic: RegressionNetParams.PubKeyHashAddrID, + valid: true, + }, + { + magic: SimNetParams.PubKeyHashAddrID, + valid: true, + }, + { + magic: mockNetParams.PubKeyHashAddrID, + valid: true, + }, + { + magic: 0xFF, + valid: false, + }, + }, + p2shMagics: []magicTest{ + { + magic: MainNetParams.ScriptHashAddrID, + valid: true, + }, + { + magic: TestNet3Params.ScriptHashAddrID, + valid: true, + }, + { + magic: RegressionNetParams.ScriptHashAddrID, + valid: true, + }, + { + magic: SimNetParams.ScriptHashAddrID, + valid: true, + }, + { + magic: mockNetParams.ScriptHashAddrID, + valid: true, + }, + { + magic: 0xFF, + valid: false, + }, + }, + hdMagics: []hdTest{ + { + priv: MainNetParams.HDPrivateKeyID[:], + want: MainNetParams.HDPublicKeyID[:], + err: nil, + }, + { + priv: TestNet3Params.HDPrivateKeyID[:], + want: TestNet3Params.HDPublicKeyID[:], + err: nil, + }, + { + priv: RegressionNetParams.HDPrivateKeyID[:], + want: RegressionNetParams.HDPublicKeyID[:], + err: nil, + }, + { + priv: SimNetParams.HDPrivateKeyID[:], + want: SimNetParams.HDPublicKeyID[:], + err: nil, + }, + { + priv: mockNetParams.HDPrivateKeyID[:], + want: mockNetParams.HDPublicKeyID[:], + err: nil, + }, + { + priv: []byte{0xff, 0xff, 0xff, 0xff}, + err: ErrUnknownHDKeyID, + }, + { + priv: []byte{0xff}, + err: ErrUnknownHDKeyID, + }, + }, + }, + } + + for _, test := range tests { + for _, regTest := range test.register { + err := Register(regTest.params) + if err != regTest.err { + t.Errorf("%s:%s: Registered network with unexpected error: got %v expected %v", + test.name, regTest.name, err, regTest.err) + } + } + for i, magTest := range test.p2pkhMagics { + valid := IsPubKeyHashAddrID(magTest.magic) + if valid != magTest.valid { + t.Errorf("%s: P2PKH magic %d valid mismatch: got %v expected %v", + test.name, i, valid, magTest.valid) + } + } + for i, magTest := range test.p2shMagics { + valid := IsScriptHashAddrID(magTest.magic) + if valid != magTest.valid { + t.Errorf("%s: P2SH magic %d valid mismatch: got %v expected %v", + test.name, i, valid, magTest.valid) + } + } + for i, magTest := range test.hdMagics { + pubKey, err := HDPrivateKeyToPublicKeyID(magTest.priv[:]) + if !reflect.DeepEqual(err, magTest.err) { + t.Errorf("%s: HD magic %d mismatched error: got %v expected %v ", + test.name, i, err, magTest.err) + continue + } + if magTest.err == nil && !bytes.Equal(pubKey, magTest.want[:]) { + t.Errorf("%s: HD magic %d private and public mismatch: got %v expected %v ", + test.name, i, pubKey, magTest.want[:]) + } + } + } +}