From 55ef07ca61faaaa1dfe8adaf65ca321658e570cd Mon Sep 17 00:00:00 2001 From: Josh Rickmar Date: Thu, 22 May 2014 12:45:08 -0500 Subject: [PATCH] Initial commit. --- README.md | 92 ++++++++++++++++++++++++++++++ doc.go | 63 +++++++++++++++++++++ params.go | 163 ++++++++++++++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 318 insertions(+) create mode 100644 README.md create mode 100644 doc.go create mode 100644 params.go diff --git a/README.md b/README.md new file mode 100644 index 00000000..6baad9ce --- /dev/null +++ b/README.md @@ -0,0 +1,92 @@ +btcnet +====== + +Package btcnet defines the network parameters for the three standard Bitcoin +networks and provides the ability for callers to define their own custom +Bitcoin networks. + +This package is one of the core packages from btcd, an alternative full-node +implementation of Bitcoin which is under active development by Conformal. +Although it was primarily written for btcd, this package 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" + + "github.com/conformal/btcnet" + "github.com/conformal/btcutil" +) + +var testnet = flag.Bool("testnet", false, "operate on the testnet Bitcoin network") + +// By default (without -testnet), use mainnet. +var netParams = &btcnet.MainNetParams + +func main() { + flag.Parse() + + // Modify active network parameters if operating on testnet. + if *testnet { + netParams = &btcnet.TestNet3Params + } + + // later... + + // Create and print new payment address, specific to the active network. + pubKeyHash := make([]byte, 20) + addr, err := btcutil.NewAddressPubKeyHash(pubKeyHash, netParams.Net) + if err != nil { + // badness + return + } + fmt.Println(addr) +} +``` + +## Documentation + +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/conformal/btcnet). + +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/conformal/btcnet + +## Installation + +```bash +$ go get github.com/conformal/btcnet +``` + +## 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 btcnet is licensed under the liberal ISC License. diff --git a/doc.go b/doc.go new file mode 100644 index 00000000..f3d8d2b1 --- /dev/null +++ b/doc.go @@ -0,0 +1,63 @@ +// Package btcnet defines the network parameters for the three standard Bitcoin +// networks and provides the ability for callers to define their own custom +// Bitcoin networks. +// +// 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, btcnet 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 +// btcwire.BitcoinNet using ParamsForNet, but be aware that this usage is +// deprecated and will be removed from btcnet 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/conformal/btcnet" +// "github.com/conformal/btcutil" +// ) +// +// var testnet = flag.Bool("testnet", false, "operate on the testnet Bitcoin network") +// +// // By default (without -testnet), use mainnet. +// var netParams = &btcnet.MainNetParams +// +// func main() { +// flag.Parse() +// +// // Modify active network parameters if operating on testnet. +// if *testnet { +// netParams = &btcnet.TestNet3Params +// } +// +// // later... +// +// // Create and print new payment address, specific to the active network. +// pubKeyHash := make([]byte, 20) +// addr, err := btcutil.NewAddressPubKeyHash(pubKeyHash, netParams.Net) +// 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 btcnet diff --git a/params.go b/params.go new file mode 100644 index 00000000..c067e720 --- /dev/null +++ b/params.go @@ -0,0 +1,163 @@ +package btcnet + +import ( + "errors" + "math/big" + + "github.com/conformal/btcwire" +) + +// 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) +) + +// 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 btcwire.BitcoinNet + + // Chain parameters + GenesisBlock *btcwire.MsgBlock + GenesisHash *btcwire.ShaHash + PowLimit *big.Int + PowLimitBits uint32 + SubsidyHalvingInterval int32 + + // 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 +} + +// MainNetParams defines the network parameters for the main Bitcoin network. +var MainNetParams = Params{ + Name: "mainnet", + Net: btcwire.MainNet, + + // Chain parameters + GenesisBlock: &btcwire.GenesisBlock, + GenesisHash: &btcwire.GenesisHash, + PowLimit: mainPowLimit, + PowLimitBits: 0x1d00ffff, + SubsidyHalvingInterval: 210000, + + // Encoding magics + PubKeyHashAddrID: 0x00, + ScriptHashAddrID: 0x05, + PrivateKeyID: 0x80, +} + +// 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: btcwire.TestNet, + + // Chain parameters + GenesisBlock: &btcwire.TestNetGenesisBlock, + GenesisHash: &btcwire.TestNetGenesisHash, + PowLimit: regressionPowLimit, + PowLimitBits: 0x207fffff, + SubsidyHalvingInterval: 150, + + // Encoding magics + PubKeyHashAddrID: 0x6f, + ScriptHashAddrID: 0xc4, + PrivateKeyID: 0xef, +} + +// 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: "testnet", + Net: btcwire.TestNet3, + + // Chain parameters + GenesisBlock: &btcwire.TestNet3GenesisBlock, + GenesisHash: &btcwire.TestNet3GenesisHash, + PowLimit: testNet3PowLimit, + PowLimitBits: 0x1d00ffff, + SubsidyHalvingInterval: 210000, + + // Encoding magics + PubKeyHashAddrID: 0x6f, + ScriptHashAddrID: 0xc4, + PrivateKeyID: 0xef, +} + +var ( + // ErrUnknownNet describes an error where the network parameters for a + // network cannot be looked up because the network is non-standard and + // is not registered into this package. + // + // This will be removed when ParamsForNet is eventually removed. + ErrUnknownNet = errors.New("unknown Bitcoin network") + + // 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. + // + // This will be removed when Register is eventually removed. + ErrDuplicateNet = errors.New("duplicate Bitcoin network") +) + +var nets = map[btcwire.BitcoinNet]*Params{ + btcwire.MainNet: &MainNetParams, + btcwire.TestNet: &RegressionNetParams, + btcwire.TestNet3: &TestNet3Params, +} + +// ParamsForNet returns the network parameters for a Bitcoin network, or +// ErrUnknownNet if the network is not a default network (mainnet, regtest, +// or testnet3) and not registered into the package with Register. +// +// This should be considered an unstable API and will be removed when all other +// Conformal btc* packages (btcwire not included) are updated from using +// btcwire.BitcoinNet to *Params. +func ParamsForNet(net btcwire.BitcoinNet) (*Params, error) { + params, ok := nets[net] + if !ok { + return nil, ErrUnknownNet + } + return params, nil +} + +// Register registers the network parameters for a Bitcoin network. This may +// error with ErrDuplicateNet if the network is already registered. +// +// 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. +// +// This should be considered an unstable API and will be removed when all other +// Conformal btc* packages (btcwire not included) are updated from using +// btcwire.BitcoinNet to *Params. +func Register(params *Params) error { + if _, ok := nets[params.Net]; ok { + return ErrDuplicateNet + } + nets[params.Net] = params + return nil +}