diff --git a/blockdag/blocknode.go b/blockdag/blocknode.go index 416f4ed43..6263cd86d 100644 --- a/blockdag/blocknode.go +++ b/blockdag/blocknode.go @@ -11,6 +11,7 @@ import ( "time" "github.com/daglabs/btcd/dagconfig/daghash" + "github.com/daglabs/btcd/util" "github.com/daglabs/btcd/wire" ) @@ -131,7 +132,7 @@ func initBlockNode(node *blockNode, blockHeader *wire.BlockHeader, parents block // blockHeader is nil only for the virtual block if blockHeader != nil { node.hash = blockHeader.BlockHash() - node.workSum = CalcWork(blockHeader.Bits) + node.workSum = util.CalcWork(blockHeader.Bits) node.version = blockHeader.Version node.bits = blockHeader.Bits node.nonce = blockHeader.Nonce diff --git a/blockdag/difficulty.go b/blockdag/difficulty.go index 207ffa1e3..edf6528be 100644 --- a/blockdag/difficulty.go +++ b/blockdag/difficulty.go @@ -7,135 +7,10 @@ package blockdag import ( "math/big" "time" + + "github.com/daglabs/btcd/util" ) -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) - - // oneLsh256 is 1 shifted left 256 bits. It is defined here to avoid - // the overhead of creating it multiple times. - oneLsh256 = new(big.Int).Lsh(bigOne, 256) -) - -// CompactToBig converts a compact representation of a whole number N to an -// unsigned 32-bit number. The representation is similar to IEEE754 floating -// point numbers. -// -// Like IEEE754 floating point, there are three basic components: the sign, -// the exponent, and the mantissa. They are broken out as follows: -// -// * the most significant 8 bits represent the unsigned base 256 exponent -// * bit 23 (the 24th bit) represents the sign bit -// * the least significant 23 bits represent the mantissa -// -// ------------------------------------------------- -// | Exponent | Sign | Mantissa | -// ------------------------------------------------- -// | 8 bits [31-24] | 1 bit [23] | 23 bits [22-00] | -// ------------------------------------------------- -// -// The formula to calculate N is: -// N = (-1^sign) * mantissa * 256^(exponent-3) -// -// This compact form is only used in bitcoin to encode unsigned 256-bit numbers -// which represent difficulty targets, thus there really is not a need for a -// sign bit, but it is implemented here to stay consistent with bitcoind. -func CompactToBig(compact uint32) *big.Int { - // Extract the mantissa, sign bit, and exponent. - mantissa := compact & 0x007fffff - isNegative := compact&0x00800000 != 0 - exponent := uint(compact >> 24) - - // Since the base for the exponent is 256, the exponent can be treated - // as the number of bytes to represent the full 256-bit number. So, - // treat the exponent as the number of bytes and shift the mantissa - // right or left accordingly. This is equivalent to: - // N = mantissa * 256^(exponent-3) - var bn *big.Int - if exponent <= 3 { - mantissa >>= 8 * (3 - exponent) - bn = big.NewInt(int64(mantissa)) - } else { - bn = big.NewInt(int64(mantissa)) - bn.Lsh(bn, 8*(exponent-3)) - } - - // Make it negative if the sign bit is set. - if isNegative { - bn = bn.Neg(bn) - } - - return bn -} - -// BigToCompact converts a whole number N to a compact representation using -// an unsigned 32-bit number. The compact representation only provides 23 bits -// of precision, so values larger than (2^23 - 1) only encode the most -// significant digits of the number. See CompactToBig for details. -func BigToCompact(n *big.Int) uint32 { - // No need to do any work if it's zero. - if n.Sign() == 0 { - return 0 - } - - // Since the base for the exponent is 256, the exponent can be treated - // as the number of bytes. So, shift the number right or left - // accordingly. This is equivalent to: - // mantissa = mantissa / 256^(exponent-3) - var mantissa uint32 - exponent := uint(len(n.Bytes())) - if exponent <= 3 { - mantissa = uint32(n.Bits()[0]) - mantissa <<= 8 * (3 - exponent) - } else { - // Use a copy to avoid modifying the caller's original number. - tn := new(big.Int).Set(n) - mantissa = uint32(tn.Rsh(tn, 8*(exponent-3)).Bits()[0]) - } - - // When the mantissa already has the sign bit set, the number is too - // large to fit into the available 23-bits, so divide the number by 256 - // and increment the exponent accordingly. - if mantissa&0x00800000 != 0 { - mantissa >>= 8 - exponent++ - } - - // Pack the exponent, sign bit, and mantissa into an unsigned 32-bit - // int and return it. - compact := uint32(exponent<<24) | mantissa - if n.Sign() < 0 { - compact |= 0x00800000 - } - return compact -} - -// CalcWork calculates a work value from difficulty bits. Bitcoin increases -// the difficulty for generating a block by decreasing the value which the -// generated hash must be less than. This difficulty target is stored in each -// block header using a compact representation as described in the documentation -// for CompactToBig. The main chain is selected by choosing the chain that has -// the most proof of work (highest difficulty). Since a lower target difficulty -// value equates to higher actual difficulty, the work value which will be -// accumulated must be the inverse of the difficulty. Also, in order to avoid -// potential division by zero and really small floating point numbers, the -// result adds 1 to the denominator and multiplies the numerator by 2^256. -func CalcWork(bits uint32) *big.Int { - // Return a work value of zero if the passed difficulty bits represent - // a negative number. Note this should not happen in practice with valid - // blocks, but an invalid block could trigger it. - difficultyNum := CompactToBig(bits) - if difficultyNum.Sign() <= 0 { - return big.NewInt(0) - } - - // (1 << 256) / (difficultyNum + 1) - denominator := new(big.Int).Add(difficultyNum, bigOne) - return new(big.Int).Div(oneLsh256, denominator) -} - // calcEasiestDifficulty calculates the easiest possible difficulty that a block // can have given starting difficulty bits and a duration. It is mainly used to // verify that claimed proof of work by a block is sane as compared to a @@ -160,7 +35,7 @@ func (dag *BlockDAG) calcEasiestDifficulty(bits uint32, duration time.Duration) // difficulty for a given duration is the largest value possible given // the number of retargets for the duration and starting difficulty // multiplied by the max adjustment factor. - newTarget := CompactToBig(bits) + newTarget := util.CompactToBig(bits) for durationVal > 0 && newTarget.Cmp(dag.dagParams.PowLimit) < 0 { newTarget.Mul(newTarget, adjustmentFactor) durationVal -= dag.maxRetargetTimespan @@ -171,7 +46,7 @@ func (dag *BlockDAG) calcEasiestDifficulty(bits uint32, duration time.Duration) newTarget.Set(dag.dagParams.PowLimit) } - return BigToCompact(newTarget) + return util.BigToCompact(newTarget) } // findPrevTestNetDifficulty returns the difficulty of the previous block which @@ -257,7 +132,7 @@ func (dag *BlockDAG) calcNextRequiredDifficulty(bluestParent *blockNode, newBloc // The result uses integer division which means it will be slightly // rounded down. Bitcoind also uses integer division to calculate this // result. - oldTarget := CompactToBig(bluestParent.bits) + oldTarget := util.CompactToBig(bluestParent.bits) newTarget := new(big.Int).Mul(oldTarget, big.NewInt(adjustedTimespan)) targetTimeSpan := int64(dag.dagParams.TargetTimespan / time.Second) newTarget.Div(newTarget, big.NewInt(targetTimeSpan)) @@ -271,10 +146,10 @@ func (dag *BlockDAG) calcNextRequiredDifficulty(bluestParent *blockNode, newBloc // intentionally converting the bits back to a number instead of using // newTarget since conversion to the compact representation loses // precision. - newTargetBits := BigToCompact(newTarget) + newTargetBits := util.BigToCompact(newTarget) log.Debugf("Difficulty retarget at block height %d", bluestParent.height+1) log.Debugf("Old target %08x (%064x)", bluestParent.bits, oldTarget) - log.Debugf("New target %08x (%064x)", newTargetBits, CompactToBig(newTargetBits)) + log.Debugf("New target %08x (%064x)", newTargetBits, util.CompactToBig(newTargetBits)) log.Debugf("Actual timespan %s, adjusted timespan %s, target timespan %s", time.Duration(actualTimespan)*time.Second, time.Duration(adjustedTimespan)*time.Second, diff --git a/blockdag/difficulty_test.go b/blockdag/difficulty_test.go index 3b6350b5c..fa9c47272 100644 --- a/blockdag/difficulty_test.go +++ b/blockdag/difficulty_test.go @@ -7,6 +7,8 @@ package blockdag import ( "math/big" "testing" + + "github.com/daglabs/btcd/util" ) // TestBigToCompact ensures BigToCompact converts big integers to the expected @@ -22,7 +24,7 @@ func TestBigToCompact(t *testing.T) { for x, test := range tests { n := big.NewInt(test.in) - r := BigToCompact(n) + r := util.BigToCompact(n) if r != test.out { t.Errorf("TestBigToCompact test #%d failed: got %d want %d\n", x, r, test.out) @@ -42,7 +44,7 @@ func TestCompactToBig(t *testing.T) { } for x, test := range tests { - n := CompactToBig(test.in) + n := util.CompactToBig(test.in) want := big.NewInt(test.out) if n.Cmp(want) != 0 { t.Errorf("TestCompactToBig test #%d failed: got %d want %d\n", @@ -65,7 +67,7 @@ func TestCalcWork(t *testing.T) { for x, test := range tests { bits := uint32(test.in) - r := CalcWork(bits) + r := util.CalcWork(bits) if r.Int64() != test.out { t.Errorf("TestCalcWork test #%d failed: got %v want %d\n", x, r.Int64(), test.out) diff --git a/blockdag/example_test.go b/blockdag/example_test.go index 8be010fd8..335b526e0 100644 --- a/blockdag/example_test.go +++ b/blockdag/example_test.go @@ -6,7 +6,6 @@ package blockdag_test import ( "fmt" - "math/big" "os" "path/filepath" @@ -72,37 +71,3 @@ func ExampleBlockDAG_ProcessBlock() { // Output: // Failed to process block: already have block 4f0fbe497b98f0ab3dd92a3be968d5c7623cbaa844ff9f19e2b94756337eb0b8 } - -// This example demonstrates how to convert the compact "bits" in a block header -// which represent the target difficulty to a big integer and display it using -// the typical hex notation. -func ExampleCompactToBig() { - // Convert the bits from block 300000 in the main block chain. - bits := uint32(419465580) - targetDifficulty := blockdag.CompactToBig(bits) - - // Display it in hex. - fmt.Printf("%064x\n", targetDifficulty.Bytes()) - - // Output: - // 0000000000000000896c00000000000000000000000000000000000000000000 -} - -// This example demonstrates how to convert a target difficulty into the compact -// "bits" in a block header which represent that target difficulty . -func ExampleBigToCompact() { - // Convert the target difficulty from block 300000 in the main block - // chain to compact form. - t := "0000000000000000896c00000000000000000000000000000000000000000000" - targetDifficulty, success := new(big.Int).SetString(t, 16) - if !success { - fmt.Println("invalid target difficulty") - return - } - bits := blockdag.BigToCompact(targetDifficulty) - - fmt.Println(bits) - - // Output: - // 419465580 -} diff --git a/blockdag/fullblocktests/generate.go b/blockdag/fullblocktests/generate.go index 7ed229dce..0296d3edb 100644 --- a/blockdag/fullblocktests/generate.go +++ b/blockdag/fullblocktests/generate.go @@ -329,7 +329,7 @@ func solveBlock(header *wire.BlockHeader) bool { // solver accepts a block header and a nonce range to test. It is // intended to be run as a goroutine. - targetDifficulty := blockdag.CompactToBig(header.Bits) + targetDifficulty := util.CompactToBig(header.Bits) quit := make(chan bool) results := make(chan sbResult) solver := func(hdr wire.BlockHeader, startNonce, stopNonce uint64) { diff --git a/blockdag/process.go b/blockdag/process.go index 2e5211f07..915603cec 100644 --- a/blockdag/process.go +++ b/blockdag/process.go @@ -197,9 +197,9 @@ func (dag *BlockDAG) ProcessBlock(block *util.Block, flags BehaviorFlags) (bool, // expected based on elapsed time since the last checkpoint and // maximum adjustment allowed by the retarget rules. duration := blockHeader.Timestamp.Sub(checkpointTime) - requiredTarget := CompactToBig(dag.calcEasiestDifficulty( + requiredTarget := util.CompactToBig(dag.calcEasiestDifficulty( checkpointNode.bits, duration)) - currentTarget := CompactToBig(blockHeader.Bits) + currentTarget := util.CompactToBig(blockHeader.Bits) if currentTarget.Cmp(requiredTarget) > 0 { str := fmt.Sprintf("block target difficulty of %064x "+ "is too low when compared to the previous "+ diff --git a/blockdag/validate.go b/blockdag/validate.go index d2d55d2cd..122696eb5 100644 --- a/blockdag/validate.go +++ b/blockdag/validate.go @@ -293,7 +293,7 @@ func CheckTransactionSanity(tx *util.Tx, subnetworkID *subnetworkid.SubnetworkID // difficulty is not performed. func (dag *BlockDAG) checkProofOfWork(header *wire.BlockHeader, flags BehaviorFlags) error { // The target difficulty must be larger than zero. - target := CompactToBig(header.Bits) + target := util.CompactToBig(header.Bits) if target.Sign() <= 0 { str := fmt.Sprintf("block target difficulty of %064x is too low", target) diff --git a/btcjson/dagsvrresults.go b/btcjson/dagsvrresults.go index 60a1c9716..7f0df5fc8 100644 --- a/btcjson/dagsvrresults.go +++ b/btcjson/dagsvrresults.go @@ -412,6 +412,7 @@ type GetMiningInfoResult struct { NetworkHashPS int64 `json:"networkHashPs"` PooledTx uint64 `json:"pooledTx"` TestNet bool `json:"testNet"` + DevNet bool `json:"devNet"` } // GetWorkResult models the data from the getwork command. @@ -432,6 +433,7 @@ type InfoDAGResult struct { Proxy string `json:"proxy"` Difficulty float64 `json:"difficulty"` TestNet bool `json:"testNet"` + DevNet bool `json:"devNet"` RelayFee float64 `json:"relayFee"` Errors string `json:"errors"` } diff --git a/cmd/addblock/config.go b/cmd/addblock/config.go index d44d4df86..c8bc897ac 100644 --- a/cmd/addblock/config.go +++ b/cmd/addblock/config.go @@ -40,6 +40,7 @@ type config struct { TestNet3 bool `long:"testnet" description:"Use the test network"` RegressionTest bool `long:"regtest" description:"Use the regression test network"` SimNet bool `long:"simnet" description:"Use the simulation test network"` + DevNet bool `long:"devnet" description:"Use the development test network"` InFile string `short:"i" long:"infile" description:"File containing the block(s)"` TxIndex bool `long:"txindex" description:"Build a full hash-based transaction index which makes all transactions available via the getrawtransaction RPC"` AddrIndex bool `long:"addrindex" description:"Build a full address-based transaction index which makes the searchrawtransactions RPC available"` @@ -122,9 +123,13 @@ func loadConfig() (*config, []string, error) { numNets++ activeNetParams = &dagconfig.SimNetParams } + if cfg.DevNet { + numNets++ + activeNetParams = &dagconfig.DevNetParams + } if numNets > 1 { - str := "%s: The testnet, regtest, and simnet params can't be " + - "used together -- choose one of the three" + str := "%s: The testnet, regtest, simnet and devent params can't be " + + "used together -- choose one of the four" err := fmt.Errorf(str, funcName) fmt.Fprintln(os.Stderr, err) parser.WriteHelp(os.Stderr) diff --git a/cmd/btcctl/config.go b/cmd/btcctl/config.go index a7675679b..01386fc8f 100644 --- a/cmd/btcctl/config.go +++ b/cmd/btcctl/config.go @@ -105,17 +105,20 @@ type config struct { ProxyPass string `long:"proxypass" default-mask:"-" description:"Password for proxy server"` TestNet3 bool `long:"testnet" description:"Connect to testnet"` SimNet bool `long:"simnet" description:"Connect to the simulation test network"` + DevNet bool `long:"devnet" description:"Connect to the development test network"` TLSSkipVerify bool `long:"skipverify" description:"Do not verify tls certificates (not recommended!)"` Wallet bool `long:"wallet" description:"Connect to wallet"` } // normalizeAddress returns addr with the passed default port appended if // there is not already a port specified. -func normalizeAddress(addr string, useTestNet3, useSimNet, useWallet bool) string { +func normalizeAddress(addr string, useTestNet3, useSimNet, useDevNet, useWallet bool) string { _, _, err := net.SplitHostPort(addr) if err != nil { var defaultPort string switch { + case useDevNet: + fallthrough case useTestNet3: if useWallet { defaultPort = "18332" @@ -254,9 +257,12 @@ func loadConfig() (*config, []string, error) { if cfg.SimNet { numNets++ } + if cfg.DevNet { + numNets++ + } if numNets > 1 { - str := "%s: The testnet and simnet params can't be used " + - "together -- choose one of the two" + str := "%s: The multiple net params (testnet, simnet, devnet etc.) can't be used " + + "together -- choose one of them" err := fmt.Errorf(str, "loadConfig") fmt.Fprintln(os.Stderr, err) return nil, nil, err @@ -274,7 +280,7 @@ func loadConfig() (*config, []string, error) { // Add default port to RPC server based on --testnet and --wallet flags // if needed. cfg.RPCServer = normalizeAddress(cfg.RPCServer, cfg.TestNet3, - cfg.SimNet, cfg.Wallet) + cfg.SimNet, cfg.DevNet, cfg.Wallet) return &cfg, remainingArgs, nil } diff --git a/cmd/findcheckpoint/config.go b/cmd/findcheckpoint/config.go index 74c7dd3f9..b63341cf1 100644 --- a/cmd/findcheckpoint/config.go +++ b/cmd/findcheckpoint/config.go @@ -41,6 +41,7 @@ type config struct { TestNet3 bool `long:"testnet" description:"Use the test network"` RegressionTest bool `long:"regtest" description:"Use the regression test network"` SimNet bool `long:"simnet" description:"Use the simulation test network"` + DevNet bool `long:"devnet" description:"Use the development test network"` NumCandidates int `short:"n" long:"numcandidates" description:"Max num of checkpoint candidates to show {1-20}"` UseGoOutput bool `short:"g" long:"gooutput" description:"Display the candidates using Go syntax that is ready to insert into the btcchain checkpoint list"` } @@ -110,9 +111,13 @@ func loadConfig() (*config, []string, error) { numNets++ activeNetParams = &dagconfig.SimNetParams } + if cfg.DevNet { + numNets++ + activeNetParams = &dagconfig.DevNetParams + } if numNets > 1 { - str := "%s: The testnet, regtest, and simnet params can't be " + - "used together -- choose one of the three" + str := "%s: The testnet, regtest, simnet and devnet params can't be " + + "used together -- choose one of the four" err := fmt.Errorf(str, funcName) fmt.Fprintln(os.Stderr, err) parser.WriteHelp(os.Stderr) diff --git a/cmd/genesis/genesis.go b/cmd/genesis/genesis.go new file mode 100644 index 000000000..2f2bf249a --- /dev/null +++ b/cmd/genesis/genesis.go @@ -0,0 +1,67 @@ +// Copyright (c) 2014-2016 The btcsuite developers +// Use of this source code is governed by an ISC +// license that can be found in the LICENSE file. + +package main + +import ( + "encoding/hex" + "fmt" + "math/big" + "time" + + "github.com/daglabs/btcd/dagconfig" + "github.com/daglabs/btcd/dagconfig/daghash" + "github.com/daglabs/btcd/util" + "github.com/daglabs/btcd/wire" +) + +// solveGenesisBlock attempts to find some combination of a nonce and +// current timestamp which makes the passed block hash to a value less than the +// target difficulty. +func solveGenesisBlock(block *wire.MsgBlock, powBits uint32, netName string) { + // Create some convenience variables. + header := &block.Header + targetDifficulty := util.CompactToBig(header.Bits) + header.Bits = powBits + + // Search through the entire nonce range for a solution while + // periodically checking for early quit and stale block + // conditions along with updates to the speed monitor. + maxNonce := ^uint64(0) // 2^64 - 1 + for { + header.Timestamp = time.Unix(time.Now().Unix(), 0) + for i := uint64(0); i <= maxNonce; i++ { + // Update the nonce and hash the block header. Each + // hash is actually a double sha256 (two hashes), so + // increment the number of hashes completed for each + // attempt accordingly. + header.Nonce = i + hash := header.BlockHash() + + // The block is solved when the new block hash is less + // than the target difficulty. Yay! + if daghash.HashToBig(&hash).Cmp(targetDifficulty) <= 0 { + fmt.Printf("\n\nGenesis block of %s is solved:\n", netName) + fmt.Printf("timestamp: 0x%x\n", header.Timestamp.Unix()) + fmt.Printf("bits (difficulty): 0x%x\n", header.Bits) + fmt.Printf("nonce: 0x%x\n", header.Nonce) + fmt.Printf("hash: %v\n\n\n", hex.EncodeToString(hash[:])) + return + } + } + } +} + +// main +func main() { + bigOne := big.NewInt(1) + + // Solve mainnet genesis + solveGenesisBlock(dagconfig.MainNetParams.GenesisBlock, + util.BigToCompact(new(big.Int).Sub(new(big.Int).Lsh(bigOne, 255), bigOne)), "mainnet") + + // Solve devnet genesis + solveGenesisBlock(dagconfig.DevNetParams.GenesisBlock, + util.BigToCompact(new(big.Int).Sub(new(big.Int).Lsh(bigOne, 239), bigOne)), "devnet") +} diff --git a/config/config.go b/config/config.go index 888adc45d..d5a6d905f 100644 --- a/config/config.go +++ b/config/config.go @@ -138,6 +138,7 @@ type configFlags struct { TestNet3 bool `long:"testnet" description:"Use the test network"` RegressionTest bool `long:"regtest" description:"Use the regression test network"` SimNet bool `long:"simnet" description:"Use the simulation test network"` + DevNet bool `long:"devnet" description:"Use the development test network"` AddCheckpoints []string `long:"addcheckpoint" description:"Add a custom checkpoint. Format: ':'"` DisableCheckpoints bool `long:"nocheckpoints" description:"Disable built-in checkpoints. Don't do this unless you know what you're doing."` DbType string `long:"dbtype" description:"Database backend to use for the Block DAG"` @@ -446,8 +447,12 @@ func loadConfig() (*Config, []string, error) { activeNetParams = &dagconfig.SimNetParams cfg.DisableDNSSeed = true } + if cfg.DevNet { + numNets++ + activeNetParams = &dagconfig.DevNetParams + } if numNets > 1 { - str := "%s: The testnet, regtest, segnet, and simnet params " + + str := "%s: The testnet, regtest, devnet, and simnet params " + "can't be used together -- choose one of the four" err := fmt.Errorf(str, funcName) fmt.Fprintln(os.Stderr, err) diff --git a/dagconfig/genesis.go b/dagconfig/genesis.go index e7d29f184..adc2cc202 100644 --- a/dagconfig/genesis.go +++ b/dagconfig/genesis.go @@ -109,3 +109,35 @@ 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 = genesisBlock + +// devNetGenesisCoinbaseTx is the coinbase transaction for the genesis blocks for +// the main network, regression test network, and test network (version 3). +var devNetGenesisCoinbaseTx = genesisCoinbaseTx + +// devGenesisHash is the hash of the first block in the block chain for the development +// network (genesis block). +var devNetGenesisHash = daghash.Hash([daghash.HashSize]byte{ // Make go vet happy. + 0x4d, 0x6a, 0xc5, 0x8c, 0xfd, 0x73, 0xff, 0x60, + 0x5e, 0x0b, 0x03, 0x4f, 0x05, 0xcf, 0x8b, 0xa2, + 0x21, 0x50, 0x05, 0xf4, 0x16, 0xd2, 0xa6, 0x75, + 0x11, 0x36, 0xa9, 0xa3, 0x21, 0x3f, 0x00, 0x00, +}) + +// devNetGenesisMerkleRoot is the hash of the first transaction in the genesis block +// for the devopment network. +var devNetGenesisMerkleRoot = genesisMerkleRoot + +// devNetGenesisBlock defines the genesis block of the block chain which serves as the +// public transaction ledger for the development network. +var devNetGenesisBlock = wire.MsgBlock{ + Header: wire.BlockHeader{ + Version: 1, + ParentHashes: []daghash.Hash{}, + HashMerkleRoot: devNetGenesisMerkleRoot, + IDMerkleRoot: devNetGenesisMerkleRoot, + Timestamp: time.Unix(0x5c922d07, 0), + Bits: 0x1e7fffff, + Nonce: 0x2633, + }, + Transactions: []*wire.MsgTx{devNetGenesisCoinbaseTx}, +} diff --git a/dagconfig/params.go b/dagconfig/params.go index daf7edd0d..f856c7435 100644 --- a/dagconfig/params.go +++ b/dagconfig/params.go @@ -40,6 +40,11 @@ var ( // 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) + + // devNetPowLimit is the highest proof of work value a Bitcoin block + // can have for the development network. It is the value + // 2^239 - 1. + devNetPowLimit = new(big.Int).Sub(new(big.Int).Lsh(bigOne, 239), bigOne) ) const phantomK = 10 @@ -231,9 +236,9 @@ var MainNetParams = Params{ PowLimitBits: 0x207fffff, BlockRewardMaturity: 100, SubsidyReductionInterval: 210000, - TargetTimespan: time.Hour * 24 * 14, // 14 days - TargetTimePerBlock: time.Second * 10, // 10 seconds - RetargetAdjustmentFactor: 4, // 25% less, 400% more + TargetTimespan: time.Hour * 1, // 1 hour + TargetTimePerBlock: time.Second * 1, // 1 second + RetargetAdjustmentFactor: 4, // 25% less, 400% more ReduceMinDifficulty: false, MinDiffReductionTime: 0, GenerateSupported: false, @@ -290,9 +295,9 @@ var RegressionNetParams = Params{ PowLimitBits: 0x207fffff, BlockRewardMaturity: 100, SubsidyReductionInterval: 150, - TargetTimespan: time.Hour * 24 * 14, // 14 days - TargetTimePerBlock: time.Second * 10, // 10 seconds - RetargetAdjustmentFactor: 4, // 25% less, 400% more + TargetTimespan: time.Hour * 1, // 1 hour + TargetTimePerBlock: time.Second * 1, // 1 second + RetargetAdjustmentFactor: 4, // 25% less, 400% more ReduceMinDifficulty: true, MinDiffReductionTime: time.Minute * 20, // TargetTimePerBlock * 2 GenerateSupported: true, @@ -354,9 +359,9 @@ var TestNet3Params = Params{ PowLimitBits: 0x207fffff, BlockRewardMaturity: 100, SubsidyReductionInterval: 210000, - TargetTimespan: time.Hour * 24 * 14, // 14 days - TargetTimePerBlock: time.Second * 10, // 10 seconds - RetargetAdjustmentFactor: 4, // 25% less, 400% more + TargetTimespan: time.Hour * 1, // 1 hour + TargetTimePerBlock: time.Second * 1, // 1 second + RetargetAdjustmentFactor: 4, // 25% less, 400% more ReduceMinDifficulty: true, MinDiffReductionTime: time.Minute * 20, // TargetTimePerBlock * 2 GenerateSupported: true, @@ -417,9 +422,9 @@ var SimNetParams = Params{ PowLimitBits: 0x207fffff, BlockRewardMaturity: 100, SubsidyReductionInterval: 210000, - TargetTimespan: time.Hour * 24 * 14, // 14 days - TargetTimePerBlock: time.Second * 10, // 10 seconds - RetargetAdjustmentFactor: 4, // 25% less, 400% more + TargetTimespan: time.Hour * 1, // 1 hour + TargetTimePerBlock: time.Second * 1, // 1 second + RetargetAdjustmentFactor: 4, // 25% less, 400% more ReduceMinDifficulty: true, MinDiffReductionTime: time.Minute * 20, // TargetTimePerBlock * 2 GenerateSupported: true, @@ -456,6 +461,65 @@ var SimNetParams = Params{ HDCoinType: 115, // ASCII for s } +// DevNetParams defines the network parameters for the development Bitcoin network. +var DevNetParams = Params{ + K: phantomK, + Name: "devnet", + Net: wire.DevNet, + RPCPort: "18334", + DefaultPort: "18333", + DNSSeeds: []DNSSeed{ + {"devnet-dnsseed.daglabs.com", true}, + }, + + // Chain parameters + GenesisBlock: &devNetGenesisBlock, + GenesisHash: &devNetGenesisHash, + PowLimit: devNetPowLimit, + PowLimitBits: util.BigToCompact(devNetPowLimit), // 0x1e7fffff + BlockRewardMaturity: 100, + SubsidyReductionInterval: 210000, + TargetTimespan: time.Hour * 1, // 1 hour + TargetTimePerBlock: time.Second * 1, // 1 second + RetargetAdjustmentFactor: 4, // 25% less, 400% more + ReduceMinDifficulty: true, + MinDiffReductionTime: time.Minute * 20, // TargetTimePerBlock * 2 + GenerateSupported: true, + + // Checkpoints ordered from oldest to newest. + Checkpoints: nil, + + // 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, + StartTime: 1199145601, // January 1, 2008 UTC + ExpireTime: 1230767999, // December 31, 2008 UTC + }, + }, + + // Mempool parameters + RelayNonStdTxs: true, + + // Human-readable part for Bech32 encoded addresses + Prefix: util.Bech32PrefixDAGTest, + + // Address encoding magics + PrivateKeyID: 0xef, // starts with 9 (uncompressed) or c (compressed) + + // BIP32 hierarchical deterministic extended key magics + HDKeyIDPair: hdkeychain.HDKeyPairDevNet, + + // BIP44 coin type used in the hierarchical deterministic path for + // address generation. + HDCoinType: 1, +} + var ( // ErrDuplicateNet describes an error where the parameters for a Bitcoin // network could not be set due to the network already being a standard diff --git a/database/cmd/dbtool/globalconfig.go b/database/cmd/dbtool/globalconfig.go index 0533ede5c..f6f2eccee 100644 --- a/database/cmd/dbtool/globalconfig.go +++ b/database/cmd/dbtool/globalconfig.go @@ -37,6 +37,7 @@ type config struct { TestNet3 bool `long:"testnet" description:"Use the test network"` RegressionTest bool `long:"regtest" description:"Use the regression test network"` SimNet bool `long:"simnet" description:"Use the simulation test network"` + DevNet bool `long:"devnet" description:"Use the development test network"` } // fileExists reports whether the named file or directory exists. @@ -98,9 +99,13 @@ func setupGlobalConfig() error { numNets++ activeNetParams = &dagconfig.SimNetParams } + if cfg.DevNet { + numNets++ + activeNetParams = &dagconfig.DevNetParams + } if numNets > 1 { - return errors.New("The testnet, regtest, and simnet params " + - "can't be used together -- choose one of the three") + return errors.New("The testnet, regtest, simnet and devnet params " + + "can't be used together -- choose one of the four") } // Validate database type. diff --git a/dnsseeder/config.go b/dnsseeder/config.go index 587771401..1eba31234 100644 --- a/dnsseeder/config.go +++ b/dnsseeder/config.go @@ -39,6 +39,7 @@ type config struct { Nameserver string `short:"n" long:"nameserver" description:"hostname of nameserver"` Seeder string `short:"s" long:"default seeder" description:"IP address of a working node"` TestNet bool `long:"testnet" description:"Use testnet"` + DevNet bool `long:"devnet" description:"Use devnet"` } func loadConfig() (*config, error) { @@ -118,8 +119,15 @@ func loadConfig() (*config, error) { cfg.Listen = normalizeAddress(cfg.Listen, defaultListenPort) - if cfg.TestNet { + if cfg.TestNet && cfg.DevNet { + str := "Both testnet and devnet are specified" + err := fmt.Errorf(str) + fmt.Fprintln(os.Stderr, err) + return nil, err + } else if cfg.TestNet { activeNetParams = &dagconfig.TestNet3Params + } else if cfg.DevNet { + activeNetParams = &dagconfig.DevNetParams } return &cfg, nil diff --git a/mining/cpuminer/cpuminer.go b/mining/cpuminer/cpuminer.go index 95233c7bd..ca4890046 100644 --- a/mining/cpuminer/cpuminer.go +++ b/mining/cpuminer/cpuminer.go @@ -206,7 +206,7 @@ func (m *CPUMiner) solveBlock(msgBlock *wire.MsgBlock, blockHeight int32, // Create some convenience variables. header := &msgBlock.Header - targetDifficulty := blockdag.CompactToBig(header.Bits) + targetDifficulty := util.CompactToBig(header.Bits) // Initial state. lastGenerated := time.Now() diff --git a/mining/mining.go b/mining/mining.go index 812eacf22..cf38fae8d 100644 --- a/mining/mining.go +++ b/mining/mining.go @@ -682,7 +682,7 @@ func (g *BlkTmplGenerator) NewBlockTemplate(payToAddress util.Address) (*BlockTe log.Debugf("Created new block template (%d transactions, %d in fees, "+ "%d signature operations, %d bytes, target difficulty %064x)", len(msgBlock.Transactions), totalFees, blockSigOps, blockSize, - blockdag.CompactToBig(msgBlock.Header.Bits)) + util.CompactToBig(msgBlock.Header.Bits)) return &BlockTemplate{ Block: &msgBlock, diff --git a/server/rpc/rpcserver.go b/server/rpc/rpcserver.go index 995eba357..926a8ceab 100644 --- a/server/rpc/rpcserver.go +++ b/server/rpc/rpcserver.go @@ -1085,8 +1085,8 @@ func getDifficultyRatio(bits uint32, params *dagconfig.Params) float64 { // converted back to a number. Note this is not the same as the proof of // work limit directly because the block difficulty is encoded in a block // with the compact form which loses precision. - max := blockdag.CompactToBig(params.PowLimitBits) - target := blockdag.CompactToBig(bits) + max := util.CompactToBig(params.PowLimitBits) + target := util.CompactToBig(bits) difficulty := new(big.Rat).SetFrac(max, target) outString := difficulty.FloatString(8) @@ -1621,7 +1621,7 @@ func (state *gbtWorkState) updateBlockTemplate(s *Server, useCoinbaseValue bool) template = blkTemplate msgBlock = template.Block targetDifficulty = fmt.Sprintf("%064x", - blockdag.CompactToBig(msgBlock.Header.Bits)) + util.CompactToBig(msgBlock.Header.Bits)) // Get the minimum allowed timestamp for the block based on the // median timestamp of the last several blocks per the chain @@ -1682,7 +1682,7 @@ func (state *gbtWorkState) updateBlockTemplate(s *Server, useCoinbaseValue bool) // Set locals for convenience. msgBlock = template.Block targetDifficulty = fmt.Sprintf("%064x", - blockdag.CompactToBig(msgBlock.Header.Bits)) + util.CompactToBig(msgBlock.Header.Bits)) // Update the time of the block template to the current time // while accounting for the median time of the past several @@ -1776,7 +1776,7 @@ func (state *gbtWorkState) blockTemplateResult(useCoinbaseValue bool, submitOld // implied by the included or omission of fields: // Including MinTime -> time/decrement // Omitting CoinbaseTxn -> coinbase, generation - targetDifficulty := fmt.Sprintf("%064x", blockdag.CompactToBig(header.Bits)) + targetDifficulty := fmt.Sprintf("%064x", util.CompactToBig(header.Bits)) longPollID := encodeLongPollID(state.tipHashes, state.lastGenerated) reply := btcjson.GetBlockTemplateResult{ Bits: strconv.FormatInt(int64(header.Bits), 16), @@ -2342,6 +2342,7 @@ func handleGetInfo(s *Server, cmd interface{}, closeChan <-chan struct{}) (inter Proxy: config.MainConfig().Proxy, Difficulty: getDifficultyRatio(s.cfg.DAG.CurrentBits(), s.cfg.DAGParams), TestNet: config.MainConfig().TestNet3, + DevNet: config.MainConfig().DevNet, RelayFee: config.MainConfig().MinRelayTxFee.ToBTC(), } @@ -2411,6 +2412,7 @@ func handleGetMiningInfo(s *Server, cmd interface{}, closeChan <-chan struct{}) NetworkHashPS: networkHashesPerSec, PooledTx: uint64(s.cfg.TxMemPool.Count()), TestNet: config.MainConfig().TestNet3, + DevNet: config.MainConfig().DevNet, } return &result, nil } diff --git a/server/rpc/rpcserverhelp.go b/server/rpc/rpcserverhelp.go index fbfebe055..3f82aabcb 100644 --- a/server/rpc/rpcserverhelp.go +++ b/server/rpc/rpcserverhelp.go @@ -379,6 +379,7 @@ var helpDescsEnUS = map[string]string{ "infoDagResult-proxy": "The proxy used by the server", "infoDagResult-difficulty": "The current target difficulty", "infoDagResult-testNet": "Whether or not server is using testnet", + "infoDagResult-devNet": "Whether or not server is using devnet", "infoDagResult-relayFee": "The minimum relay fee for non-free transactions in BTC/KB", "infoDagResult-errors": "Any current errors", @@ -393,6 +394,7 @@ var helpDescsEnUS = map[string]string{ "infoWalletResult-proxy": "The proxy used by the server", "infoWalletResult-difficulty": "The current target difficulty", "infoWalletResult-testNet": "Whether or not server is using testnet", + "infoWalletResult-devNet": "Whether or not server is using devnet", "infoWalletResult-keypoolOldest": "Seconds since 1 Jan 1970 GMT of the oldest pre-generated key in the key pool", "infoWalletResult-keypoolSize": "The number of new keys that are pre-generated", "infoWalletResult-unlockedUntil": "The timestamp in seconds since 1 Jan 1970 GMT that the wallet is unlocked for transfers, or 0 if the wallet is locked", @@ -428,6 +430,7 @@ var helpDescsEnUS = map[string]string{ "getMiningInfoResult-networkHashPs": "Estimated network hashes per second for the most recent blocks", "getMiningInfoResult-pooledTx": "Number of transactions in the memory pool", "getMiningInfoResult-testNet": "Whether or not server is using testnet", + "getMiningInfoResult-devNet": "Whether or not server is using devnet", // GetMiningInfoCmd help. "getMiningInfo--synopsis": "Returns a JSON object containing mining-related information.", diff --git a/util/btcmath.go b/util/btcmath.go index c5a6a98cb..25e8ea9d3 100644 --- a/util/btcmath.go +++ b/util/btcmath.go @@ -1,9 +1,23 @@ package util -// log2FloorMasks defines the masks to use when quickly calculating -// floor(log2(x)) in a constant log2(32) = 5 steps, where x is a uint32, using -// shifts. They are derived from (2^(2^x) - 1) * (2^(2^x)), for x in 4..0. -var log2FloorMasks = []uint32{0xffff0000, 0xff00, 0xf0, 0xc, 0x2} +import ( + "math/big" +) + +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) + + // oneLsh256 is 1 shifted left 256 bits. It is defined here to avoid + // the overhead of creating it multiple times. + oneLsh256 = new(big.Int).Lsh(bigOne, 256) + + // log2FloorMasks defines the masks to use when quickly calculating + // floor(log2(x)) in a constant log2(32) = 5 steps, where x is a uint32, using + // shifts. They are derived from (2^(2^x) - 1) * (2^(2^x)), for x in 4..0. + log2FloorMasks = []uint32{0xffff0000, 0xff00, 0xf0, 0xc, 0x2} +) // FastLog2Floor calculates and returns floor(log2(x)) in a constant 5 steps. func FastLog2Floor(n uint32) uint8 { @@ -18,3 +32,120 @@ func FastLog2Floor(n uint32) uint8 { } return rv } + +// CompactToBig converts a compact representation of a whole number N to an +// unsigned 32-bit number. The representation is similar to IEEE754 floating +// point numbers. +// +// Like IEEE754 floating point, there are three basic components: the sign, +// the exponent, and the mantissa. They are broken out as follows: +// +// * the most significant 8 bits represent the unsigned base 256 exponent +// * bit 23 (the 24th bit) represents the sign bit +// * the least significant 23 bits represent the mantissa +// +// ------------------------------------------------- +// | Exponent | Sign | Mantissa | +// ------------------------------------------------- +// | 8 bits [31-24] | 1 bit [23] | 23 bits [22-00] | +// ------------------------------------------------- +// +// The formula to calculate N is: +// N = (-1^sign) * mantissa * 256^(exponent-3) +// +// This compact form is only used in bitcoin to encode unsigned 256-bit numbers +// which represent difficulty targets, thus there really is not a need for a +// sign bit, but it is implemented here to stay consistent with bitcoind. +func CompactToBig(compact uint32) *big.Int { + // Extract the mantissa, sign bit, and exponent. + mantissa := compact & 0x007fffff + isNegative := compact&0x00800000 != 0 + exponent := uint(compact >> 24) + + // Since the base for the exponent is 256, the exponent can be treated + // as the number of bytes to represent the full 256-bit number. So, + // treat the exponent as the number of bytes and shift the mantissa + // right or left accordingly. This is equivalent to: + // N = mantissa * 256^(exponent-3) + var bn *big.Int + if exponent <= 3 { + mantissa >>= 8 * (3 - exponent) + bn = big.NewInt(int64(mantissa)) + } else { + bn = big.NewInt(int64(mantissa)) + bn.Lsh(bn, 8*(exponent-3)) + } + + // Make it negative if the sign bit is set. + if isNegative { + bn = bn.Neg(bn) + } + + return bn +} + +// BigToCompact converts a whole number N to a compact representation using +// an unsigned 32-bit number. The compact representation only provides 23 bits +// of precision, so values larger than (2^23 - 1) only encode the most +// significant digits of the number. See CompactToBig for details. +func BigToCompact(n *big.Int) uint32 { + // No need to do any work if it's zero. + if n.Sign() == 0 { + return 0 + } + + // Since the base for the exponent is 256, the exponent can be treated + // as the number of bytes. So, shift the number right or left + // accordingly. This is equivalent to: + // mantissa = mantissa / 256^(exponent-3) + var mantissa uint32 + exponent := uint(len(n.Bytes())) + if exponent <= 3 { + mantissa = uint32(n.Bits()[0]) + mantissa <<= 8 * (3 - exponent) + } else { + // Use a copy to avoid modifying the caller's original number. + tn := new(big.Int).Set(n) + mantissa = uint32(tn.Rsh(tn, 8*(exponent-3)).Bits()[0]) + } + + // When the mantissa already has the sign bit set, the number is too + // large to fit into the available 23-bits, so divide the number by 256 + // and increment the exponent accordingly. + if mantissa&0x00800000 != 0 { + mantissa >>= 8 + exponent++ + } + + // Pack the exponent, sign bit, and mantissa into an unsigned 32-bit + // int and return it. + compact := uint32(exponent<<24) | mantissa + if n.Sign() < 0 { + compact |= 0x00800000 + } + return compact +} + +// CalcWork calculates a work value from difficulty bits. Bitcoin increases +// the difficulty for generating a block by decreasing the value which the +// generated hash must be less than. This difficulty target is stored in each +// block header using a compact representation as described in the documentation +// for CompactToBig. The main chain is selected by choosing the chain that has +// the most proof of work (highest difficulty). Since a lower target difficulty +// value equates to higher actual difficulty, the work value which will be +// accumulated must be the inverse of the difficulty. Also, in order to avoid +// potential division by zero and really small floating point numbers, the +// result adds 1 to the denominator and multiplies the numerator by 2^256. +func CalcWork(bits uint32) *big.Int { + // Return a work value of zero if the passed difficulty bits represent + // a negative number. Note this should not happen in practice with valid + // blocks, but an invalid block could trigger it. + difficultyNum := CompactToBig(bits) + if difficultyNum.Sign() <= 0 { + return big.NewInt(0) + } + + // (1 << 256) / (difficultyNum + 1) + denominator := new(big.Int).Add(difficultyNum, bigOne) + return new(big.Int).Div(oneLsh256, denominator) +} diff --git a/util/example_test.go b/util/example_test.go index bdee2332f..800a6a226 100644 --- a/util/example_test.go +++ b/util/example_test.go @@ -3,6 +3,7 @@ package util_test import ( "fmt" "math" + "math/big" "github.com/daglabs/btcd/util" ) @@ -74,3 +75,37 @@ func ExampleAmount_unitConversions() { // Satoshi to MicroBTC: 444333222111 μBTC // Satoshi to Satoshi: 44433322211100 Satoshi } + +// This example demonstrates how to convert the compact "bits" in a block header +// which represent the target difficulty to a big integer and display it using +// the typical hex notation. +func ExampleCompactToBig() { + // Convert the bits from block 300000 in the main block chain. + bits := uint32(419465580) + targetDifficulty := util.CompactToBig(bits) + + // Display it in hex. + fmt.Printf("%064x\n", targetDifficulty.Bytes()) + + // Output: + // 0000000000000000896c00000000000000000000000000000000000000000000 +} + +// This example demonstrates how to convert a target difficulty into the compact +// "bits" in a block header which represent that target difficulty . +func ExampleBigToCompact() { + // Convert the target difficulty from block 300000 in the main block + // chain to compact form. + t := "0000000000000000896c00000000000000000000000000000000000000000000" + targetDifficulty, success := new(big.Int).SetString(t, 16) + if !success { + fmt.Println("invalid target difficulty") + return + } + bits := util.BigToCompact(targetDifficulty) + + fmt.Println(bits) + + // Output: + // 419465580 +} diff --git a/util/hdkeychain/extendedkey.go b/util/hdkeychain/extendedkey.go index d481f17c7..0ef5ccee9 100644 --- a/util/hdkeychain/extendedkey.go +++ b/util/hdkeychain/extendedkey.go @@ -387,6 +387,10 @@ var ( PrivateKeyID: [4]byte{0x04, 0x20, 0xb9, 0x00}, // starts with sprv PublicKeyID: [4]byte{0x04, 0x20, 0xbd, 0x3a}, // starts with spub } + HDKeyPairDevNet = HDKeyIDPair{ + PrivateKeyID: [4]byte{0x04, 0x88, 0xad, 0xe4}, // starts with xprv + PublicKeyID: [4]byte{0x04, 0x88, 0xb2, 0x1e}, // starts with xpub + } ) // RegisterHDKeyIDPair registers an HDKeyIDPair in the private to public key map @@ -637,4 +641,5 @@ func init() { RegisterHDKeyIDPair(HDKeyPairTestNet) RegisterHDKeyIDPair(HDKeyPairRegressionNet) RegisterHDKeyIDPair(HDKeyPairSimNet) + RegisterHDKeyIDPair(HDKeyPairDevNet) } diff --git a/wire/protocol.go b/wire/protocol.go index a645225f4..5e7c53e6f 100644 --- a/wire/protocol.go +++ b/wire/protocol.go @@ -108,6 +108,9 @@ const ( // SimNet represents the simulation test network. SimNet BitcoinNet = 0x12141c16 + + // DevNet represents the development test network. + DevNet BitcoinNet = 0x01020304 ) // bnStrings is a map of bitcoin networks back to their constant names for @@ -117,6 +120,7 @@ var bnStrings = map[BitcoinNet]string{ TestNet: "TestNet", TestNet3: "TestNet3", SimNet: "SimNet", + DevNet: "DevNet", } // String returns the BitcoinNet in human-readable form.