"sync"
"time"
-// "github.com/blockchain/types"
- "github.com/bytom/protocol/bc/legacy"
+ // "github.com/blockchain/types"
+ "github.com/bytom/protocol/bc/legacy"
. "github.com/tendermint/tmlibs/common"
flow "github.com/tendermint/tmlibs/flowrate"
"github.com/tendermint/tmlibs/log"
mtx sync.Mutex
// block requests
requesters map[uint64]*bpRequester
- height uint64 // the lowest key in requesters.
- numPending int32 // number of requests pending assignment or block response
+ height uint64 // the lowest key in requesters.
+ numPending int32 // number of requests pending assignment or block response
// peers
peers map[string]*bpPeer
height := pool.height
// Need at least 1 peer to be considered caught up.
- if len(pool.peers) == 0 {
+ if len(pool.peers) == 0 && time.Now().Sub(pool.startTime) > 60*time.Second {
pool.Logger.Debug("Blockpool has no peers")
return false
}
defer pool.mtx.Unlock()
str := ""
- var h uint64
- for h = pool.height; h < pool.height+ uint64(len(pool.requesters)); h++ {
+ var h uint64
+ for h = pool.height; h < pool.height+uint64(len(pool.requesters)); h++ {
if pool.requesters[h] == nil {
str += Fmt("H(%v):X ", h)
} else {
import (
"bytes"
"context"
- "reflect"
- "time"
- "net/http"
"fmt"
+ "net/http"
+ "reflect"
+ "time"
- wire "github.com/tendermint/go-wire"
- "github.com/bytom/p2p"
- "github.com/bytom/types"
- "github.com/bytom/protocol/bc/legacy"
- "github.com/bytom/protocol"
- "github.com/bytom/blockchain/query"
- "github.com/bytom/encoding/json"
- cmn "github.com/tendermint/tmlibs/common"
- "github.com/bytom/blockchain/txdb"
"github.com/bytom/blockchain/account"
"github.com/bytom/blockchain/asset"
+ "github.com/bytom/blockchain/txbuilder"
+ "github.com/bytom/blockchain/txdb"
"github.com/bytom/blockchain/txfeed"
+ "github.com/bytom/encoding/json"
+ "github.com/bytom/errors"
+ "github.com/bytom/generated/dashboard"
"github.com/bytom/log"
- //"github.com/bytom/net/http/gzip"
+ "github.com/bytom/mining/cpuminer"
"github.com/bytom/net/http/httpjson"
- //"github.com/bytom/net/http/limit"
"github.com/bytom/net/http/static"
- "github.com/bytom/generated/dashboard"
- "github.com/bytom/errors"
- "github.com/bytom/blockchain/txbuilder"
+ "github.com/bytom/p2p"
+ "github.com/bytom/protocol"
+ "github.com/bytom/protocol/bc/legacy"
+ "github.com/bytom/protocol/validation"
+ "github.com/bytom/types"
+ wire "github.com/tendermint/go-wire"
+ cmn "github.com/tendermint/tmlibs/common"
)
const (
// check if we should switch to consensus reactor
switchToConsensusIntervalSeconds = 1
maxBlockchainResponseSize = 22020096 + 2
- crosscoreRPCPrefix = "/rpc/"
+ crosscoreRPCPrefix = "/rpc/"
)
// BlockchainReactor handles long-term catchup syncing.
type BlockchainReactor struct {
p2p.BaseReactor
- chain *protocol.Chain
- store *txdb.Store
- accounts *account.Manager
- assets *asset.Registry
- txFeeds *txfeed.TxFeed
- indexer *query.Indexer
- pool *BlockPool
- mux *http.ServeMux
- handler http.Handler
- fastSync bool
- requestsCh chan BlockRequest
- timeoutsCh chan string
- submitter txbuilder.Submitter
+ chain *protocol.Chain
+ store *txdb.Store
+ accounts *account.Manager
+ assets *asset.Registry
+ txFeeds *txfeed.TxFeed
+ pool *BlockPool
+ txPool *protocol.TxPool
+ mining *cpuminer.CPUMiner
+ mux *http.ServeMux
+ handler http.Handler
+ fastSync bool
+ requestsCh chan BlockRequest
+ timeoutsCh chan string
+ submitter txbuilder.Submitter
evsw types.EventSwitch
}
}
func jsonHandler(f interface{}) http.Handler {
- h, err := httpjson.Handler(f, errorFormatter.Write)
+ h, err := httpjson.Handler(f, errorFormatter.Write)
if err != nil {
panic(err)
}
}
func (bcr *BlockchainReactor) ServeHTTP(rw http.ResponseWriter, req *http.Request) {
- bcr.handler.ServeHTTP(rw, req)
+ bcr.handler.ServeHTTP(rw, req)
}
func (bcr *BlockchainReactor) info(ctx context.Context) (map[string]interface{}, error) {
- //if a.config == nil {
- // never configured
+ //if a.config == nil {
+ // never configured
log.Printf(ctx, "-------info-----")
return map[string]interface{}{
"is_configured": false,
}
func (bcr *BlockchainReactor) createblockkey(ctx context.Context) {
- log.Printf(ctx,"creat-block-key")
+ log.Printf(ctx, "creat-block-key")
}
func webAssetsHandler(next http.Handler) http.Handler {
}
func maxBytes(h http.Handler) http.Handler {
- const maxReqSize = 1e7 // 10MB
+ const maxReqSize = 1e7 // 10MB
return http.HandlerFunc(func(w http.ResponseWriter, req *http.Request) {
// A block can easily be bigger than maxReqSize, but everything
// else should be pretty small.
m := bcr.mux
m.Handle("/create-account", jsonHandler(bcr.createAccount))
m.Handle("/create-asset", jsonHandler(bcr.createAsset))
- m.Handle("/update-account-tags",jsonHandler(bcr.updateAccountTags))
- m.Handle("/update-asset-tags",jsonHandler(bcr.updateAssetTags))
+ m.Handle("/update-account-tags", jsonHandler(bcr.updateAccountTags))
+ m.Handle("/update-asset-tags", jsonHandler(bcr.updateAssetTags))
m.Handle("/build-transaction", jsonHandler(bcr.build))
- m.Handle("/create-control-program",jsonHandler(bcr.createControlProgram))
+ m.Handle("/create-control-program", jsonHandler(bcr.createControlProgram))
m.Handle("/create-account-receiver", jsonHandler(bcr.createAccountReceiver))
m.Handle("/create-transaction-feed", jsonHandler(bcr.createTxFeed))
m.Handle("/get-transaction-feed", jsonHandler(bcr.getTxFeed))
m.Handle("/update-transaction-feed", jsonHandler(bcr.updateTxFeed))
m.Handle("/delete-transaction-feed", jsonHandler(bcr.deleteTxFeed))
m.Handle("/list-accounts", jsonHandler(bcr.listAccounts))
- m.Handle("/list-assets", jsonHandler(bcr.listAssets))
- m.Handle("/list-transaction-feeds", jsonHandler(bcr.listTxFeeds))
- m.Handle("/list-transactions", jsonHandler(bcr.listTransactions))
- m.Handle("/list-balances", jsonHandler(bcr.listBalances))
- m.Handle("/list-unspent-outputs", jsonHandler(bcr.listUnspentOutputs))
+ m.Handle("/list-assets", jsonHandler(bcr.listAssets))
+ m.Handle("/list-transaction-feeds", jsonHandler(bcr.listTxFeeds))
+ m.Handle("/list-transactions", jsonHandler(bcr.listTransactions))
+ m.Handle("/list-balances", jsonHandler(bcr.listBalances))
+ m.Handle("/list-unspent-outputs", jsonHandler(bcr.listUnspentOutputs))
m.Handle("/", alwaysError(errors.New("not Found")))
m.Handle("/info", jsonHandler(bcr.info))
m.Handle("/create-block-key", jsonHandler(bcr.createblockkey))
m.Handle("/submit-transaction", jsonHandler(bcr.submit))
- latencyHandler := http.HandlerFunc(func(w http.ResponseWriter, req *http.Request) {
+ latencyHandler := http.HandlerFunc(func(w http.ResponseWriter, req *http.Request) {
if l := latency(m, req); l != nil {
defer l.RecordSince(time.Now())
}
m.ServeHTTP(w, req)
- })
+ })
handler := maxBytes(latencyHandler) // TODO(tessr): consider moving this to non-core specific mux
handler = webAssetsHandler(handler)
-/* handler = healthHandler(handler)
- for _, l := range a.requestLimits {
- handler = limit.Handler(handler, alwaysError(errRateLimited), l.perSecond, l.burst, l.key)
- }
- handler = gzip.Handler{Handler: handler}
- handler = coreCounter(handler)
- handler = timeoutContextHandler(handler)
- if a.config != nil && a.config.BlockchainId != nil {
- handler = blockchainIDHandler(handler, a.config.BlockchainId.String())
- }
+ /* handler = healthHandler(handler)
+ for _, l := range a.requestLimits {
+ handler = limit.Handler(handler, alwaysError(errRateLimited), l.perSecond, l.burst, l.key)
+ }
+ handler = gzip.Handler{Handler: handler}
+ handler = coreCounter(handler)
+ handler = timeoutContextHandler(handler)
+ if a.config != nil && a.config.BlockchainId != nil {
+ handler = blockchainIDHandler(handler, a.config.BlockchainId.String())
+ }
*/
bcr.handler = handler
}
LastPage bool `json:"last_page"`
}
-func NewBlockchainReactor(store *txdb.Store, chain *protocol.Chain, accounts *account.Manager, assets *asset.Registry, fastSync bool) *BlockchainReactor {
- requestsCh := make(chan BlockRequest, defaultChannelCapacity)
- timeoutsCh := make(chan string, defaultChannelCapacity)
- pool := NewBlockPool(
- store.Height()+1,
- requestsCh,
- timeoutsCh,
- )
- bcR := &BlockchainReactor {
- chain: chain,
- store: store,
- accounts: accounts,
- assets: assets,
- pool: pool,
- mux: http.NewServeMux(),
- fastSync: fastSync,
- requestsCh: requestsCh,
- timeoutsCh: timeoutsCh,
- }
- bcR.BaseReactor = *p2p.NewBaseReactor("BlockchainReactor", bcR)
- return bcR
+func NewBlockchainReactor(store *txdb.Store, chain *protocol.Chain, txPool *protocol.TxPool, accounts *account.Manager, assets *asset.Registry, fastSync bool) *BlockchainReactor {
+ requestsCh := make(chan BlockRequest, defaultChannelCapacity)
+ timeoutsCh := make(chan string, defaultChannelCapacity)
+ pool := NewBlockPool(
+ store.Height()+1,
+ requestsCh,
+ timeoutsCh,
+ )
+ mining := cpuminer.NewCPUMiner(chain, txPool)
+ bcR := &BlockchainReactor{
+ chain: chain,
+ store: store,
+ accounts: accounts,
+ assets: assets,
+ pool: pool,
+ txPool: txPool,
+ mining: mining,
+ mux: http.NewServeMux(),
+ fastSync: fastSync,
+ requestsCh: requestsCh,
+ timeoutsCh: timeoutsCh,
+ }
+ bcR.BaseReactor = *p2p.NewBaseReactor("BlockchainReactor", bcR)
+ return bcR
}
// OnStart implements BaseService
func (bcR *BlockchainReactor) OnStart() error {
bcR.BaseReactor.OnStart()
bcR.BuildHander()
- if bcR.fastSync {
- _, err := bcR.pool.Start()
- if err != nil {
- return err
- }
- go bcR.poolRoutine()
- }
+ if bcR.fastSync {
+ _, err := bcR.pool.Start()
+ if err != nil {
+ return err
+ }
+ go bcR.poolRoutine()
+ }
return nil
}
// AddPeer implements Reactor by sending our state to peer.
func (bcR *BlockchainReactor) AddPeer(peer *p2p.Peer) {
- if !peer.Send(BlockchainChannel, struct{ BlockchainMessage }{&bcStatusResponseMessage{bcR.store.Height()}}) {
+ if !peer.Send(BlockchainChannel, struct{ BlockchainMessage }{&bcStatusResponseMessage{bcR.chain.Height()}}) {
// doing nothing, will try later in `poolRoutine`
}
}
switch msg := msg.(type) {
case *bcBlockRequestMessage:
// Got a request for a block. Respond with block if we have it.
- block, _:= bcR.store.GetBlock(msg.Height)
- if block != nil {
- msg := &bcBlockResponseMessage{Block: block}
+ rawBlock, err := bcR.store.GetRawBlock(msg.Height)
+ //fmt.Printf("sent block %v \n", rawBlock)
+ if err == nil {
+ msg := &bcBlockResponseMessage{RawBlock: rawBlock}
queued := src.TrySend(BlockchainChannel, struct{ BlockchainMessage }{msg})
if !queued {
// queue is full, just ignore.
}
} else {
+ fmt.Println("skip sent the block response due to block is nil")
// TODO peer is asking for things we don't have.
}
case *bcBlockResponseMessage:
// Got a block.
- bcR.pool.AddBlock(src.Key, msg.Block, len(msgBytes))
+ //fmt.Printf("receive block %v \n", msg.Block)
+ bcR.pool.AddBlock(src.Key, msg.GetBlock(), len(msgBytes))
case *bcStatusRequestMessage:
// Send peer our state.
- queued := src.TrySend(BlockchainChannel, struct{ BlockchainMessage }{&bcStatusResponseMessage{bcR.store.Height()}})
+ queued := src.TrySend(BlockchainChannel, struct{ BlockchainMessage }{&bcStatusResponseMessage{bcR.chain.Height()}})
if !queued {
// sorry
}
case *bcStatusResponseMessage:
// Got a peer status. Unverified.
+ //fmt.Printf("reveive peer high is %d \n", msg.Height)
bcR.pool.SetPeerHeight(src.Key, msg.Height)
+ case *bcTransactionMessage:
+ block, _ := bcR.chain.State()
+ tx := msg.GetTransaction()
+ if bcR.txPool.HaveTransaction(&tx.Tx.ID) {
+ return
+ }
+
+ gas, err := validation.ValidateTx(tx.Tx, legacy.MapBlock(block))
+ if err != nil {
+ return
+ }
+ bcR.txPool.AddTransaction(tx, tx.TxData.SerializedSize, block.BlockHeader.Height, uint64(gas))
+ go bcR.BroadcastTransaction(tx)
default:
bcR.Logger.Error(cmn.Fmt("Unknown message type %v", reflect.TypeOf(msg)))
}
}
-
// Handle messages from the poolReactor telling the reactor what to do.
// NOTE: Don't sleep in the FOR_LOOP or otherwise slow it down!
// (Except for the SYNC_LOOP, which is the primary purpose and must be synchronous.)
// ask for status updates
go bcR.BroadcastStatusRequest()
/*case _ = <-switchToConsensusTicker.C:
- height, numPending, _ := bcR.pool.GetStatus()
- outbound, inbound, _ := bcR.Switch.NumPeers()
- bcR.Logger.Info("Consensus ticker", "numPending", numPending, "total", len(bcR.pool.requesters),
- "outbound", outbound, "inbound", inbound)
- if bcR.pool.IsCaughtUp() {
- bcR.Logger.Info("Time to switch to consensus reactor!", "height", height)
- bcR.pool.Stop()
-
- conR := bcR.Switch.Reactor("CONSENSUS").(consensusReactor)
- conR.SwitchToConsensus(bcR.state)
-
- break FOR_LOOP
- }*/
+ height, numPending, _ := bcR.pool.GetStatus()
+ outbound, inbound, _ := bcR.Switch.NumPeers()
+ bcR.Logger.Info("Consensus ticker", "numPending", numPending, "total", len(bcR.pool.requesters),
+ "outbound", outbound, "inbound", inbound)
+ if bcR.pool.IsCaughtUp() {
+ bcR.Logger.Info("Time to switch to consensus reactor!", "height", height)
+ bcR.pool.Stop()
+
+ conR := bcR.Switch.Reactor("CONSENSUS").(consensusReactor)
+ conR.SwitchToConsensus(bcR.state)
+
+ break FOR_LOOP
+ }*/
case _ = <-trySyncTicker.C: // chan time
// This loop can be slow as long as it's doing syncing work.
SYNC_LOOP:
for i := 0; i < 10; i++ {
// See if there are any blocks to sync.
- first, second := bcR.pool.PeekTwoBlocks()
- bcR.Logger.Info("TrySync peeked", "first", first, "second", second)
- if first == nil || second == nil {
- // We need both to sync the first block.
+ block, _ := bcR.pool.PeekTwoBlocks()
+ //bcR.Logger.Info("TrySync peeked", "first", first, "second", second)
+ if block == nil {
+ //bcR.Logger.Info("skip sync loop, nothing need to be sync")
+ break SYNC_LOOP
+ }
+
+ //bcR.Logger.Info("start to sync block", block)
+ bcR.pool.PopRequest()
+ snap, err := bcR.chain.ApplyValidBlock(block)
+ if err != nil {
+ fmt.Printf("Failed to apply valid block: %v \n", err)
break SYNC_LOOP
}
- bcR.pool.PopRequest()
- bcR.store.SaveBlock(first)
+ err = bcR.chain.CommitAppliedBlock(nil, block, snap)
+ if err != nil {
+ fmt.Printf("Failed to commit block: %v \n", err)
+ break SYNC_LOOP
+ }
+ bcR.Logger.Info("finish to sync commit block", block)
}
continue FOR_LOOP
case <-bcR.Quit:
break FOR_LOOP
}
+ if bcR.pool.IsCaughtUp() && !bcR.mining.IsMining() {
+ bcR.Logger.Info("start to mining")
+ bcR.mining.Start()
+ }
}
}
// BroadcastStatusRequest broadcasts `BlockStore` height.
func (bcR *BlockchainReactor) BroadcastStatusRequest() error {
- bcR.Switch.Broadcast(BlockchainChannel, struct{ BlockchainMessage }{&bcStatusRequestMessage{bcR.store.Height()}})
+ bcR.Switch.Broadcast(BlockchainChannel, struct{ BlockchainMessage }{&bcStatusRequestMessage{bcR.chain.Height()}})
return nil
}
+func (bcR *BlockchainReactor) BroadcastTransaction(tx *legacy.Tx) error {
+ rawTx, err := tx.TxData.MarshalText()
+ if err == nil {
+ return err
+ }
+ bcR.Switch.Broadcast(BlockchainChannel, struct{ BlockchainMessage }{&bcTransactionMessage{rawTx}})
+ return nil
+}
/*
// SetEventSwitch implements events.Eventable
// Messages
const (
- msgTypeBlockRequest = byte(0x10)
- msgTypeBlockResponse = byte(0x11)
- msgTypeStatusResponse = byte(0x20)
- msgTypeStatusRequest = byte(0x21)
+ msgTypeBlockRequest = byte(0x10)
+ msgTypeBlockResponse = byte(0x11)
+ msgTypeStatusResponse = byte(0x20)
+ msgTypeStatusRequest = byte(0x21)
+ msgTypeTransactionRequest = byte(0x30)
)
// BlockchainMessage is a generic message for this reactor.
wire.ConcreteType{&bcBlockResponseMessage{}, msgTypeBlockResponse},
wire.ConcreteType{&bcStatusResponseMessage{}, msgTypeStatusResponse},
wire.ConcreteType{&bcStatusRequestMessage{}, msgTypeStatusRequest},
+ wire.ConcreteType{&bcTransactionMessage{}, msgTypeTransactionRequest},
)
// DecodeMessage decodes BlockchainMessage.
//-------------------------------------
+type bcTransactionMessage struct {
+ RawTx []byte
+}
+
+func (m *bcTransactionMessage) GetTransaction() *legacy.Tx {
+ tx := &legacy.Tx{}
+ tx.UnmarshalText(m.RawTx)
+ return tx
+}
+
+//-------------------------------------
+
+//-------------------------------------
+
// NOTE: keep up-to-date with maxBlockchainResponseSize
type bcBlockResponseMessage struct {
- Block *legacy.Block
+ RawBlock []byte
+}
+
+func (m *bcBlockResponseMessage) GetBlock() *legacy.Block {
+ block := &legacy.Block{
+ BlockHeader: legacy.BlockHeader{},
+ Transactions: []*legacy.Tx{},
+ }
+ block.UnmarshalText(m.RawBlock)
+ return block
}
func (m *bcBlockResponseMessage) String() string {
- return cmn.Fmt("[bcBlockResponseMessage %v]", m.Block.Height)
+ block := m.GetBlock()
+ return cmn.Fmt("[bcBlockResponseMessage %v]", block.BlockHeader.Height)
}
//-------------------------------------
--- /dev/null
+package consensus
+
+import (
+ "math/big"
+
+ "github.com/bytom/protocol/bc"
+)
+
+const (
+ subsidyReductionInterval = uint64(560640)
+ baseSubsidy = uint64(624000000000)
+)
+
+// HashToBig converts a *bc.Hash into a big.Int that can be used to
+// perform math comparisons.
+func HashToBig(hash *bc.Hash) *big.Int {
+ buf := hash.Byte32()
+ blen := len(buf)
+ for i := 0; i < blen/2; i++ {
+ buf[i], buf[blen-1-i] = buf[blen-1-i], buf[i]
+ }
+
+ return new(big.Int).SetBytes(buf[:])
+}
+
+// CompactToBig converts a compact representation of a whole number N to an
+// unsigned 64-bit number. The representation is similar to IEEE754 floating
+// point numbers.
+//
+// -------------------------------------------------
+// | Exponent | Sign | Mantissa |
+// -------------------------------------------------
+// | 8 bits [63-56] | 1 bit [55] | 55 bits [54-00] |
+// -------------------------------------------------
+//
+// N = (-1^sign) * mantissa * 256^(exponent-3)
+func CompactToBig(compact uint64) *big.Int {
+ // Extract the mantissa, sign bit, and exponent.
+ mantissa := compact & 0x007fffffffffffff
+ isNegative := compact&0x0080000000000000 != 0
+ exponent := uint(compact >> 56)
+
+ 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))
+ }
+
+ if isNegative {
+ bn = bn.Neg(bn)
+ }
+
+ return bn
+}
+
+// BigToCompact converts a whole number N to a compact representation using
+// an unsigned 64-bit number
+func BigToCompact(n *big.Int) uint64 {
+ if n.Sign() == 0 {
+ return 0
+ }
+
+ var mantissa uint64
+ exponent := uint(len(n.Bytes()))
+ if exponent <= 3 {
+ mantissa = uint64(n.Bits()[0])
+ mantissa <<= 8 * (3 - exponent)
+ } else {
+ tn := new(big.Int).Set(n)
+ mantissa = uint64(tn.Rsh(tn, 8*(exponent-3)).Bits()[0])
+ }
+
+ if mantissa&0x0080000000000000 != 0 {
+ mantissa >>= 8
+ exponent++
+ }
+
+ compact := uint64(exponent<<56) | mantissa
+ if n.Sign() < 0 {
+ compact |= 0x0080000000000000
+ }
+ return compact
+}
+
+func CheckProofOfWork(hash *bc.Hash, bits uint64) bool {
+ if HashToBig(hash).Cmp(CompactToBig(bits)) <= 0 {
+ return true
+ }
+ return false
+}
+
+func CalcNextRequiredDifficulty() uint64 {
+ return uint64(2161727821138738707)
+}
+
+func BlockSubsidy(height uint64) uint64 {
+ return baseSubsidy >> uint(height/subsidyReductionInterval)
+}
-package bc
+package consensus
import (
+ "fmt"
+ "math/big"
"testing"
)
-func TestSubsidy(t *testing.T) {
+func TestCalcNextRequiredDifficulty(t *testing.T) {
+ //fmt.Println(CalcNextRequiredDifficulty())
+ x := big.NewInt(123)
+ y, _ := x.SetString("94847123945178081620347972471576132812524935594538618173381454864040345", 10)
+ fmt.Println(BigToCompact(y))
+}
+
+/*func TestSubsidy(t *testing.T) {
cases := []struct {
bh *BlockHeader
subsidy uint64
t.Errorf("got subsidy %s, want %s", subsidy, c.subsidy)
}
}
-}
+}*/
+++ /dev/null
-mining\r
-======\r
-\r
-[![Build Status](http://img.shields.io/travis/btcsuite/btcd.svg)](https://travis-ci.org/btcsuite/btcd)\r
-[![ISC License](http://img.shields.io/badge/license-ISC-blue.svg)](http://copyfree.org)\r
-[![GoDoc](https://img.shields.io/badge/godoc-reference-blue.svg)](http://godoc.org/github.com/btcsuite/btcd/mining)\r
-\r
-## Overview\r
-\r
-This package is currently a work in progress.\r
-\r
-## Installation and Updating\r
-\r
-```bash\r
-$ go get -u github.com/btcsuite/btcd/mining\r
-```\r
-\r
-## License\r
-\r
-Package mining is licensed under the [copyfree](http://copyfree.org) ISC\r
-License.\r
+++ /dev/null
-cpuminer\r
-========\r
-\r
-[![Build Status](http://img.shields.io/travis/btcsuite/btcd.svg)](https://travis-ci.org/btcsuite/btcd)\r
-[![ISC License](http://img.shields.io/badge/license-ISC-blue.svg)](http://copyfree.org)\r
-[![GoDoc](https://img.shields.io/badge/godoc-reference-blue.svg)](http://godoc.org/github.com/btcsuite/btcd/mining/cpuminer)\r
-\r
-## Overview\r
-\r
-This package is currently a work in progress. It works without issue since it\r
-is used in several of the integration tests, but the API is not really ready for\r
-public consumption as it has simply been refactored out of the main codebase for\r
-now.\r
-\r
-## Installation and Updating\r
-\r
-```bash\r
-$ go get -u github.com/btcsuite/btcd/mining/cpuminer\r
-```\r
-\r
-## License\r
-\r
-Package cpuminer is licensed under the [copyfree](http://copyfree.org) ISC\r
-License.\r
-// Copyright (c) 2014-2016 The btcsuite developers\r
-// Use of this source code is governed by an ISC\r
-// license that can be found in the LICENSE file.\r
-\r
-package cpuminer\r
-\r
-import (\r
- "errors"\r
- "fmt"\r
- "math/rand"\r
- "runtime"\r
- "sync"\r
- "time"\r
-\r
- "github.com/btcsuite/btcd/blockchain"\r
- "github.com/btcsuite/btcd/chaincfg"\r
- "github.com/btcsuite/btcd/chaincfg/chainhash"\r
- "github.com/btcsuite/btcd/mining"\r
- "github.com/btcsuite/btcd/wire"\r
- "github.com/btcsuite/btcutil"\r
-)\r
-\r
-const (\r
- // maxNonce is the maximum value a nonce can be in a block header.\r
- maxNonce = ^uint32(0) // 2^32 - 1\r
-\r
- // maxExtraNonce is the maximum value an extra nonce used in a coinbase\r
- // transaction can be.\r
- maxExtraNonce = ^uint64(0) // 2^64 - 1\r
-\r
- // hpsUpdateSecs is the number of seconds to wait in between each\r
- // update to the hashes per second monitor.\r
- hpsUpdateSecs = 10\r
-\r
- // hashUpdateSec is the number of seconds each worker waits in between\r
- // notifying the speed monitor with how many hashes have been completed\r
- // while they are actively searching for a solution. This is done to\r
- // reduce the amount of syncs between the workers that must be done to\r
- // keep track of the hashes per second.\r
- hashUpdateSecs = 15\r
-)\r
-\r
-var (\r
- // defaultNumWorkers is the default number of workers to use for mining\r
- // and is based on the number of processor cores. This helps ensure the\r
- // system stays reasonably responsive under heavy load.\r
- defaultNumWorkers = uint32(runtime.NumCPU())\r
-)\r
-\r
-// Config is a descriptor containing the cpu miner configuration.\r
-type Config struct {\r
- // ChainParams identifies which chain parameters the cpu miner is\r
- // associated with.\r
- ChainParams *chaincfg.Params\r
-\r
- // BlockTemplateGenerator identifies the instance to use in order to\r
- // generate block templates that the miner will attempt to solve.\r
- BlockTemplateGenerator *mining.BlkTmplGenerator\r
-\r
- // MiningAddrs is a list of payment addresses to use for the generated\r
- // blocks. Each generated block will randomly choose one of them.\r
- MiningAddrs []btcutil.Address\r
-\r
- // ProcessBlock defines the function to call with any solved blocks.\r
- // It typically must run the provided block through the same set of\r
- // rules and handling as any other block coming from the network.\r
- ProcessBlock func(*btcutil.Block, blockchain.BehaviorFlags) (bool, error)\r
-\r
- // ConnectedCount defines the function to use to obtain how many other\r
- // peers the server is connected to. This is used by the automatic\r
- // persistent mining routine to determine whether or it should attempt\r
- // mining. This is useful because there is no point in mining when not\r
- // connected to any peers since there would no be anyone to send any\r
- // found blocks to.\r
- ConnectedCount func() int32\r
-\r
- // IsCurrent defines the function to use to obtain whether or not the\r
- // block chain is current. This is used by the automatic persistent\r
- // mining routine to determine whether or it should attempt mining.\r
- // This is useful because there is no point in mining if the chain is\r
- // not current since any solved blocks would be on a side chain and and\r
- // up orphaned anyways.\r
- IsCurrent func() bool\r
-}\r
-\r
-// CPUMiner provides facilities for solving blocks (mining) using the CPU in\r
-// a concurrency-safe manner. It consists of two main goroutines -- a speed\r
-// monitor and a controller for worker goroutines which generate and solve\r
-// blocks. The number of goroutines can be set via the SetMaxGoRoutines\r
-// function, but the default is based on the number of processor cores in the\r
-// system which is typically sufficient.\r
-type CPUMiner struct {\r
- sync.Mutex\r
- g *mining.BlkTmplGenerator\r
- cfg Config\r
- numWorkers uint32\r
- started bool\r
- discreteMining bool\r
- submitBlockLock sync.Mutex\r
- wg sync.WaitGroup\r
- workerWg sync.WaitGroup\r
- updateNumWorkers chan struct{}\r
- queryHashesPerSec chan float64\r
- updateHashes chan uint64\r
- speedMonitorQuit chan struct{}\r
- quit chan struct{}\r
-}\r
-\r
-// speedMonitor handles tracking the number of hashes per second the mining\r
-// process is performing. It must be run as a goroutine.\r
-func (m *CPUMiner) speedMonitor() {\r
- log.Tracef("CPU miner speed monitor started")\r
-\r
- var hashesPerSec float64\r
- var totalHashes uint64\r
- ticker := time.NewTicker(time.Second * hpsUpdateSecs)\r
- defer ticker.Stop()\r
-\r
-out:\r
- for {\r
- select {\r
- // Periodic updates from the workers with how many hashes they\r
- // have performed.\r
- case numHashes := <-m.updateHashes:\r
- totalHashes += numHashes\r
-\r
- // Time to update the hashes per second.\r
- case <-ticker.C:\r
- curHashesPerSec := float64(totalHashes) / hpsUpdateSecs\r
- if hashesPerSec == 0 {\r
- hashesPerSec = curHashesPerSec\r
- }\r
- hashesPerSec = (hashesPerSec + curHashesPerSec) / 2\r
- totalHashes = 0\r
- if hashesPerSec != 0 {\r
- log.Debugf("Hash speed: %6.0f kilohashes/s",\r
- hashesPerSec/1000)\r
- }\r
-\r
- // Request for the number of hashes per second.\r
- case m.queryHashesPerSec <- hashesPerSec:\r
- // Nothing to do.\r
-\r
- case <-m.speedMonitorQuit:\r
- break out\r
- }\r
- }\r
-\r
- m.wg.Done()\r
- log.Tracef("CPU miner speed monitor done")\r
-}\r
-\r
-// submitBlock submits the passed block to network after ensuring it passes all\r
-// of the consensus validation rules.\r
-func (m *CPUMiner) submitBlock(block *btcutil.Block) bool {\r
- m.submitBlockLock.Lock()\r
- defer m.submitBlockLock.Unlock()\r
-\r
- // Ensure the block is not stale since a new block could have shown up\r
- // while the solution was being found. Typically that condition is\r
- // detected and all work on the stale block is halted to start work on\r
- // a new block, but the check only happens periodically, so it is\r
- // possible a block was found and submitted in between.\r
- msgBlock := block.MsgBlock()\r
- if !msgBlock.Header.PrevBlock.IsEqual(&m.g.BestSnapshot().Hash) {\r
- log.Debugf("Block submitted via CPU miner with previous "+\r
- "block %s is stale", msgBlock.Header.PrevBlock)\r
- return false\r
- }\r
-\r
- // Process this block using the same rules as blocks coming from other\r
- // nodes. This will in turn relay it to the network like normal.\r
- isOrphan, err := m.cfg.ProcessBlock(block, blockchain.BFNone)\r
- if err != nil {\r
- // Anything other than a rule violation is an unexpected error,\r
- // so log that error as an internal error.\r
- if _, ok := err.(blockchain.RuleError); !ok {\r
- log.Errorf("Unexpected error while processing "+\r
- "block submitted via CPU miner: %v", err)\r
- return false\r
- }\r
-\r
- log.Debugf("Block submitted via CPU miner rejected: %v", err)\r
- return false\r
- }\r
- if isOrphan {\r
- log.Debugf("Block submitted via CPU miner is an orphan")\r
- return false\r
- }\r
-\r
- // The block was accepted.\r
- coinbaseTx := block.MsgBlock().Transactions[0].TxOut[0]\r
- log.Infof("Block submitted via CPU miner accepted (hash %s, "+\r
- "amount %v)", block.Hash(), btcutil.Amount(coinbaseTx.Value))\r
- return true\r
-}\r
-\r
-// solveBlock attempts to find some combination of a nonce, extra nonce, and\r
-// current timestamp which makes the passed block hash to a value less than the\r
-// target difficulty. The timestamp is updated periodically and the passed\r
-// block is modified with all tweaks during this process. This means that\r
-// when the function returns true, the block is ready for submission.\r
-//\r
-// This function will return early with false when conditions that trigger a\r
-// stale block such as a new block showing up or periodically when there are\r
-// new transactions and enough time has elapsed without finding a solution.\r
-func (m *CPUMiner) solveBlock(msgBlock *wire.MsgBlock, blockHeight int32,\r
- ticker *time.Ticker, quit chan struct{}) bool {\r
-\r
- // Choose a random extra nonce offset for this block template and\r
- // worker.\r
- enOffset, err := wire.RandomUint64()\r
- if err != nil {\r
- log.Errorf("Unexpected error while generating random "+\r
- "extra nonce offset: %v", err)\r
- enOffset = 0\r
- }\r
-\r
- // Create some convenience variables.\r
- header := &msgBlock.Header\r
- targetDifficulty := blockchain.CompactToBig(header.Bits)\r
-\r
- // Initial state.\r
- lastGenerated := time.Now()\r
- lastTxUpdate := m.g.TxSource().LastUpdated()\r
- hashesCompleted := uint64(0)\r
-\r
- // Note that the entire extra nonce range is iterated and the offset is\r
- // added relying on the fact that overflow will wrap around 0 as\r
- // provided by the Go spec.\r
- for extraNonce := uint64(0); extraNonce < maxExtraNonce; extraNonce++ {\r
- // Update the extra nonce in the block template with the\r
- // new value by regenerating the coinbase script and\r
- // setting the merkle root to the new value.\r
- m.g.UpdateExtraNonce(msgBlock, blockHeight, extraNonce+enOffset)\r
-\r
- // Search through the entire nonce range for a solution while\r
- // periodically checking for early quit and stale block\r
- // conditions along with updates to the speed monitor.\r
- for i := uint32(0); i <= maxNonce; i++ {\r
- select {\r
- case <-quit:\r
- return false\r
-\r
- case <-ticker.C:\r
- m.updateHashes <- hashesCompleted\r
- hashesCompleted = 0\r
-\r
- // The current block is stale if the best block\r
- // has changed.\r
- best := m.g.BestSnapshot()\r
- if !header.PrevBlock.IsEqual(&best.Hash) {\r
- return false\r
- }\r
-\r
- // The current block is stale if the memory pool\r
- // has been updated since the block template was\r
- // generated and it has been at least one\r
- // minute.\r
- if lastTxUpdate != m.g.TxSource().LastUpdated() &&\r
- time.Now().After(lastGenerated.Add(time.Minute)) {\r
-\r
- return false\r
- }\r
-\r
- m.g.UpdateBlockTime(msgBlock)\r
-\r
- default:\r
- // Non-blocking select to fall through\r
- }\r
-\r
- // Update the nonce and hash the block header. Each\r
- // hash is actually a double sha256 (two hashes), so\r
- // increment the number of hashes completed for each\r
- // attempt accordingly.\r
- header.Nonce = i\r
- hash := header.BlockHash()\r
- hashesCompleted += 2\r
-\r
- // The block is solved when the new block hash is less\r
- // than the target difficulty. Yay!\r
- if blockchain.HashToBig(&hash).Cmp(targetDifficulty) <= 0 {\r
- m.updateHashes <- hashesCompleted\r
- return true\r
- }\r
- }\r
- }\r
-\r
- return false\r
-}\r
-\r
-// generateBlocks is a worker that is controlled by the miningWorkerController.\r
-// It is self contained in that it creates block templates and attempts to solve\r
-// them while detecting when it is performing stale work and reacting\r
-// accordingly by generating a new block template. When a block is solved, it\r
-// is submitted.\r
-//\r
-// It must be run as a goroutine.\r
-func (m *CPUMiner) generateBlocks(quit chan struct{}) {\r
- log.Tracef("Starting generate blocks worker")\r
-\r
- // Start a ticker which is used to signal checks for stale work and\r
- // updates to the speed monitor.\r
- ticker := time.NewTicker(time.Second * hashUpdateSecs)\r
- defer ticker.Stop()\r
-out:\r
- for {\r
- // Quit when the miner is stopped.\r
- select {\r
- case <-quit:\r
- break out\r
- default:\r
- // Non-blocking select to fall through\r
- }\r
-\r
- // Wait until there is a connection to at least one other peer\r
- // since there is no way to relay a found block or receive\r
- // transactions to work on when there are no connected peers.\r
- if m.cfg.ConnectedCount() == 0 {\r
- time.Sleep(time.Second)\r
- continue\r
- }\r
-\r
- // No point in searching for a solution before the chain is\r
- // synced. Also, grab the same lock as used for block\r
- // submission, since the current block will be changing and\r
- // this would otherwise end up building a new block template on\r
- // a block that is in the process of becoming stale.\r
- m.submitBlockLock.Lock()\r
- curHeight := m.g.BestSnapshot().Height\r
- if curHeight != 0 && !m.cfg.IsCurrent() {\r
- m.submitBlockLock.Unlock()\r
- time.Sleep(time.Second)\r
- continue\r
- }\r
-\r
- // Choose a payment address at random.\r
- rand.Seed(time.Now().UnixNano())\r
- payToAddr := m.cfg.MiningAddrs[rand.Intn(len(m.cfg.MiningAddrs))]\r
-\r
- // Create a new block template using the available transactions\r
- // in the memory pool as a source of transactions to potentially\r
- // include in the block.\r
- template, err := m.g.NewBlockTemplate(payToAddr)\r
- m.submitBlockLock.Unlock()\r
- if err != nil {\r
- errStr := fmt.Sprintf("Failed to create new block "+\r
- "template: %v", err)\r
- log.Errorf(errStr)\r
- continue\r
- }\r
-\r
- // Attempt to solve the block. The function will exit early\r
- // with false when conditions that trigger a stale block, so\r
- // a new block template can be generated. When the return is\r
- // true a solution was found, so submit the solved block.\r
- if m.solveBlock(template.Block, curHeight+1, ticker, quit) {\r
- block := btcutil.NewBlock(template.Block)\r
- m.submitBlock(block)\r
- }\r
- }\r
-\r
- m.workerWg.Done()\r
- log.Tracef("Generate blocks worker done")\r
-}\r
-\r
-// miningWorkerController launches the worker goroutines that are used to\r
-// generate block templates and solve them. It also provides the ability to\r
-// dynamically adjust the number of running worker goroutines.\r
-//\r
-// It must be run as a goroutine.\r
-func (m *CPUMiner) miningWorkerController() {\r
- // launchWorkers groups common code to launch a specified number of\r
- // workers for generating blocks.\r
- var runningWorkers []chan struct{}\r
- launchWorkers := func(numWorkers uint32) {\r
- for i := uint32(0); i < numWorkers; i++ {\r
- quit := make(chan struct{})\r
- runningWorkers = append(runningWorkers, quit)\r
-\r
- m.workerWg.Add(1)\r
- go m.generateBlocks(quit)\r
- }\r
- }\r
-\r
- // Launch the current number of workers by default.\r
- runningWorkers = make([]chan struct{}, 0, m.numWorkers)\r
- launchWorkers(m.numWorkers)\r
-\r
-out:\r
- for {\r
- select {\r
- // Update the number of running workers.\r
- case <-m.updateNumWorkers:\r
- // No change.\r
- numRunning := uint32(len(runningWorkers))\r
- if m.numWorkers == numRunning {\r
- continue\r
- }\r
-\r
- // Add new workers.\r
- if m.numWorkers > numRunning {\r
- launchWorkers(m.numWorkers - numRunning)\r
- continue\r
- }\r
-\r
- // Signal the most recently created goroutines to exit.\r
- for i := numRunning - 1; i >= m.numWorkers; i-- {\r
- close(runningWorkers[i])\r
- runningWorkers[i] = nil\r
- runningWorkers = runningWorkers[:i]\r
- }\r
-\r
- case <-m.quit:\r
- for _, quit := range runningWorkers {\r
- close(quit)\r
- }\r
- break out\r
- }\r
- }\r
-\r
- // Wait until all workers shut down to stop the speed monitor since\r
- // they rely on being able to send updates to it.\r
- m.workerWg.Wait()\r
- close(m.speedMonitorQuit)\r
- m.wg.Done()\r
-}\r
-\r
-// Start begins the CPU mining process as well as the speed monitor used to\r
-// track hashing metrics. Calling this function when the CPU miner has\r
-// already been started will have no effect.\r
-//\r
-// This function is safe for concurrent access.\r
-func (m *CPUMiner) Start() {\r
- m.Lock()\r
- defer m.Unlock()\r
-\r
- // Nothing to do if the miner is already running or if running in\r
- // discrete mode (using GenerateNBlocks).\r
- if m.started || m.discreteMining {\r
- return\r
- }\r
-\r
- m.quit = make(chan struct{})\r
- m.speedMonitorQuit = make(chan struct{})\r
- m.wg.Add(2)\r
- go m.speedMonitor()\r
- go m.miningWorkerController()\r
-\r
- m.started = true\r
- log.Infof("CPU miner started")\r
-}\r
-\r
-// Stop gracefully stops the mining process by signalling all workers, and the\r
-// speed monitor to quit. Calling this function when the CPU miner has not\r
-// already been started will have no effect.\r
-//\r
-// This function is safe for concurrent access.\r
-func (m *CPUMiner) Stop() {\r
- m.Lock()\r
- defer m.Unlock()\r
-\r
- // Nothing to do if the miner is not currently running or if running in\r
- // discrete mode (using GenerateNBlocks).\r
- if !m.started || m.discreteMining {\r
- return\r
- }\r
-\r
- close(m.quit)\r
- m.wg.Wait()\r
- m.started = false\r
- log.Infof("CPU miner stopped")\r
-}\r
-\r
-// IsMining returns whether or not the CPU miner has been started and is\r
-// therefore currenting mining.\r
-//\r
-// This function is safe for concurrent access.\r
-func (m *CPUMiner) IsMining() bool {\r
- m.Lock()\r
- defer m.Unlock()\r
-\r
- return m.started\r
-}\r
-\r
-// HashesPerSecond returns the number of hashes per second the mining process\r
-// is performing. 0 is returned if the miner is not currently running.\r
-//\r
-// This function is safe for concurrent access.\r
-func (m *CPUMiner) HashesPerSecond() float64 {\r
- m.Lock()\r
- defer m.Unlock()\r
-\r
- // Nothing to do if the miner is not currently running.\r
- if !m.started {\r
- return 0\r
- }\r
-\r
- return <-m.queryHashesPerSec\r
-}\r
-\r
-// SetNumWorkers sets the number of workers to create which solve blocks. Any\r
-// negative values will cause a default number of workers to be used which is\r
-// based on the number of processor cores in the system. A value of 0 will\r
-// cause all CPU mining to be stopped.\r
-//\r
-// This function is safe for concurrent access.\r
-func (m *CPUMiner) SetNumWorkers(numWorkers int32) {\r
- if numWorkers == 0 {\r
- m.Stop()\r
- }\r
-\r
- // Don't lock until after the first check since Stop does its own\r
- // locking.\r
- m.Lock()\r
- defer m.Unlock()\r
-\r
- // Use default if provided value is negative.\r
- if numWorkers < 0 {\r
- m.numWorkers = defaultNumWorkers\r
- } else {\r
- m.numWorkers = uint32(numWorkers)\r
- }\r
-\r
- // When the miner is already running, notify the controller about the\r
- // the change.\r
- if m.started {\r
- m.updateNumWorkers <- struct{}{}\r
- }\r
-}\r
-\r
-// NumWorkers returns the number of workers which are running to solve blocks.\r
-//\r
-// This function is safe for concurrent access.\r
-func (m *CPUMiner) NumWorkers() int32 {\r
- m.Lock()\r
- defer m.Unlock()\r
-\r
- return int32(m.numWorkers)\r
-}\r
-\r
-// GenerateNBlocks generates the requested number of blocks. It is self\r
-// contained in that it creates block templates and attempts to solve them while\r
-// detecting when it is performing stale work and reacting accordingly by\r
-// generating a new block template. When a block is solved, it is submitted.\r
-// The function returns a list of the hashes of generated blocks.\r
-func (m *CPUMiner) GenerateNBlocks(n uint32) ([]*chainhash.Hash, error) {\r
- m.Lock()\r
-\r
- // Respond with an error if server is already mining.\r
- if m.started || m.discreteMining {\r
- m.Unlock()\r
- return nil, errors.New("Server is already CPU mining. Please call " +\r
- "`setgenerate 0` before calling discrete `generate` commands.")\r
- }\r
-\r
- m.started = true\r
- m.discreteMining = true\r
-\r
- m.speedMonitorQuit = make(chan struct{})\r
- m.wg.Add(1)\r
- go m.speedMonitor()\r
-\r
- m.Unlock()\r
-\r
- log.Tracef("Generating %d blocks", n)\r
-\r
- i := uint32(0)\r
- blockHashes := make([]*chainhash.Hash, n)\r
-\r
- // Start a ticker which is used to signal checks for stale work and\r
- // updates to the speed monitor.\r
- ticker := time.NewTicker(time.Second * hashUpdateSecs)\r
- defer ticker.Stop()\r
-\r
- for {\r
- // Read updateNumWorkers in case someone tries a `setgenerate` while\r
- // we're generating. We can ignore it as the `generate` RPC call only\r
- // uses 1 worker.\r
- select {\r
- case <-m.updateNumWorkers:\r
- default:\r
- }\r
-\r
- // Grab the lock used for block submission, since the current block will\r
- // be changing and this would otherwise end up building a new block\r
- // template on a block that is in the process of becoming stale.\r
- m.submitBlockLock.Lock()\r
- curHeight := m.g.BestSnapshot().Height\r
-\r
- // Choose a payment address at random.\r
- rand.Seed(time.Now().UnixNano())\r
- payToAddr := m.cfg.MiningAddrs[rand.Intn(len(m.cfg.MiningAddrs))]\r
-\r
- // Create a new block template using the available transactions\r
- // in the memory pool as a source of transactions to potentially\r
- // include in the block.\r
- template, err := m.g.NewBlockTemplate(payToAddr)\r
- m.submitBlockLock.Unlock()\r
- if err != nil {\r
- errStr := fmt.Sprintf("Failed to create new block "+\r
- "template: %v", err)\r
- log.Errorf(errStr)\r
- continue\r
- }\r
-\r
- // Attempt to solve the block. The function will exit early\r
- // with false when conditions that trigger a stale block, so\r
- // a new block template can be generated. When the return is\r
- // true a solution was found, so submit the solved block.\r
- if m.solveBlock(template.Block, curHeight+1, ticker, nil) {\r
- block := btcutil.NewBlock(template.Block)\r
- m.submitBlock(block)\r
- blockHashes[i] = block.Hash()\r
- i++\r
- if i == n {\r
- log.Tracef("Generated %d blocks", i)\r
- m.Lock()\r
- close(m.speedMonitorQuit)\r
- m.wg.Wait()\r
- m.started = false\r
- m.discreteMining = false\r
- m.Unlock()\r
- return blockHashes, nil\r
- }\r
- }\r
- }\r
-}\r
-\r
-// New returns a new instance of a CPU miner for the provided configuration.\r
-// Use Start to begin the mining process. See the documentation for CPUMiner\r
-// type for more details.\r
-func New(cfg *Config) *CPUMiner {\r
- return &CPUMiner{\r
- g: cfg.BlockTemplateGenerator,\r
- cfg: *cfg,\r
- numWorkers: defaultNumWorkers,\r
- updateNumWorkers: make(chan struct{}),\r
- queryHashesPerSec: make(chan float64),\r
- updateHashes: make(chan uint64),\r
- }\r
-}\r
+// 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 cpuminer
+
+import (
+ "fmt"
+ "sync"
+ "time"
+
+ "github.com/bytom/consensus"
+ "github.com/bytom/mining"
+ "github.com/bytom/protocol"
+ "github.com/bytom/protocol/bc/legacy"
+)
+
+const (
+ maxNonce = ^uint64(0) // 2^32 - 1
+ defaultNumWorkers = 1
+ hashUpdateSecs = 15
+)
+
+// CPUMiner provides facilities for solving blocks (mining) using the CPU in
+// a concurrency-safe manner.
+type CPUMiner struct {
+ sync.Mutex
+ chain *protocol.Chain
+ txPool *protocol.TxPool
+ numWorkers uint64
+ started bool
+ discreteMining bool
+ wg sync.WaitGroup
+ workerWg sync.WaitGroup
+ updateNumWorkers chan struct{}
+ queryHashesPerSec chan float64
+ updateHashes chan uint64
+ speedMonitorQuit chan struct{}
+ quit chan struct{}
+}
+
+// solveBlock attempts to find some combination of a nonce, extra nonce, and
+// current timestamp which makes the passed block hash to a value less than the
+// target difficulty.
+func (m *CPUMiner) solveBlock(block *legacy.Block, ticker *time.Ticker, quit chan struct{}) bool {
+ header := &block.BlockHeader
+ targetDifficulty := consensus.CompactToBig(header.Bits)
+
+ for i := uint64(0); i <= maxNonce; i++ {
+ select {
+ case <-quit:
+ return false
+
+ case <-ticker.C:
+ if m.chain.Height() >= header.Height {
+ return false
+ }
+ default:
+ // Non-blocking select to fall through
+ }
+
+ header.Nonce = i
+ hash := header.Hash()
+
+ // The block is solved when the new block hash is less
+ // than the target difficulty. Yay!
+ //fmt.Printf("hash %v, targe %v \n ", consensus.HashToBig(&hash), targetDifficulty)
+ if consensus.HashToBig(&hash).Cmp(targetDifficulty) <= 0 {
+ return true
+ }
+ }
+ return false
+}
+
+// generateBlocks is a worker that is controlled by the miningWorkerController.
+// It is self contained in that it creates block templates and attempts to solve
+// them while detecting when it is performing stale work and reacting
+// accordingly by generating a new block template. When a block is solved, it
+// is submitted.
+//
+// It must be run as a goroutine.
+func (m *CPUMiner) generateBlocks(quit chan struct{}) {
+ ticker := time.NewTicker(time.Second * hashUpdateSecs)
+ defer ticker.Stop()
+
+out:
+ for {
+ select {
+ case <-quit:
+ break out
+ default:
+ }
+
+ //TODO: No point in searching for a solution before the chain is synced
+
+ //TODO: get address from the wallet
+ payToAddr := []byte{}
+
+ // Create a new block template using the available transactions
+ // in the memory pool as a source of transactions to potentially
+ // include in the block.
+ block, err := mining.NewBlockTemplate(m.chain, m.txPool, payToAddr)
+ //fmt.Printf("finish to generate block template with heigh %d \n", block.BlockHeader.Height)
+ if err != nil {
+ fmt.Printf("Failed to create new block template: %v \n", err)
+ continue
+ }
+
+ if m.solveBlock(block, ticker, quit) {
+ //fmt.Printf("====================================")
+ //fmt.Println(block.BlockHeader.AssetsMerkleRoot)
+ snap, err := m.chain.ApplyValidBlock(block)
+ if err != nil {
+ fmt.Printf("Failed to apply valid block: %v \n", err)
+ continue
+ }
+ err = m.chain.CommitAppliedBlock(nil, block, snap)
+ if err != nil {
+ fmt.Printf("Failed to commit block: %v \n", err)
+ continue
+ }
+ /*fmt.Println(block)
+ x, err := m.chain.GetBlock(block.BlockHeader.Height)
+ if err != nil {
+ fmt.Println(err)
+ }
+ fmt.Println(x)
+ fmt.Println(x == block)
+ fmt.Println(block.Transactions)
+ fmt.Println(x.Transactions)*/
+ fmt.Printf("finish commit block heigh %d \n", block.BlockHeader.Height)
+ }
+ }
+
+ m.workerWg.Done()
+}
+
+// miningWorkerController launches the worker goroutines that are used to
+// generate block templates and solve them. It also provides the ability to
+// dynamically adjust the number of running worker goroutines.
+//
+// It must be run as a goroutine.
+func (m *CPUMiner) miningWorkerController() {
+ // launchWorkers groups common code to launch a specified number of
+ // workers for generating blocks.
+ var runningWorkers []chan struct{}
+ launchWorkers := func(numWorkers uint64) {
+ for i := uint64(0); i < numWorkers; i++ {
+ quit := make(chan struct{})
+ runningWorkers = append(runningWorkers, quit)
+
+ m.workerWg.Add(1)
+ go m.generateBlocks(quit)
+ }
+ }
+
+ // Launch the current number of workers by default.
+ runningWorkers = make([]chan struct{}, 0, m.numWorkers)
+ launchWorkers(m.numWorkers)
+
+out:
+ for {
+ select {
+ // Update the number of running workers.
+ case <-m.updateNumWorkers:
+ // No change.
+ numRunning := uint64(len(runningWorkers))
+ if m.numWorkers == numRunning {
+ continue
+ }
+
+ // Add new workers.
+ if m.numWorkers > numRunning {
+ launchWorkers(m.numWorkers - numRunning)
+ continue
+ }
+
+ // Signal the most recently created goroutines to exit.
+ for i := numRunning - 1; i >= m.numWorkers; i-- {
+ close(runningWorkers[i])
+ runningWorkers[i] = nil
+ runningWorkers = runningWorkers[:i]
+ }
+
+ case <-m.quit:
+ for _, quit := range runningWorkers {
+ close(quit)
+ }
+ break out
+ }
+ }
+
+ // Wait until all workers shut down to stop the speed monitor since
+ // they rely on being able to send updates to it.
+ m.workerWg.Wait()
+ close(m.speedMonitorQuit)
+ m.wg.Done()
+}
+
+// Start begins the CPU mining process as well as the speed monitor used to
+// track hashing metrics. Calling this function when the CPU miner has
+// already been started will have no effect.
+//
+// This function is safe for concurrent access.
+func (m *CPUMiner) Start() {
+ m.Lock()
+ defer m.Unlock()
+
+ // Nothing to do if the miner is already running or if running in
+ // discrete mode (using GenerateNBlocks).
+ if m.started || m.discreteMining {
+ return
+ }
+
+ m.quit = make(chan struct{})
+ m.speedMonitorQuit = make(chan struct{})
+ m.wg.Add(2)
+ go m.miningWorkerController()
+
+ m.started = true
+}
+
+// Stop gracefully stops the mining process by signalling all workers, and the
+// speed monitor to quit. Calling this function when the CPU miner has not
+// already been started will have no effect.
+//
+// This function is safe for concurrent access.
+func (m *CPUMiner) Stop() {
+ m.Lock()
+ defer m.Unlock()
+
+ // Nothing to do if the miner is not currently running or if running in
+ // discrete mode (using GenerateNBlocks).
+ if !m.started || m.discreteMining {
+ return
+ }
+
+ close(m.quit)
+ m.wg.Wait()
+ m.started = false
+}
+
+// IsMining returns whether or not the CPU miner has been started and is
+// therefore currenting mining.
+//
+// This function is safe for concurrent access.
+func (m *CPUMiner) IsMining() bool {
+ m.Lock()
+ defer m.Unlock()
+
+ return m.started
+}
+
+// SetNumWorkers sets the number of workers to create which solve blocks. Any
+// negative values will cause a default number of workers to be used which is
+// based on the number of processor cores in the system. A value of 0 will
+// cause all CPU mining to be stopped.
+//
+// This function is safe for concurrent access.
+func (m *CPUMiner) SetNumWorkers(numWorkers int32) {
+ if numWorkers == 0 {
+ m.Stop()
+ }
+
+ // Don't lock until after the first check since Stop does its own
+ // locking.
+ m.Lock()
+ defer m.Unlock()
+
+ // Use default if provided value is negative.
+ if numWorkers < 0 {
+ m.numWorkers = defaultNumWorkers
+ } else {
+ m.numWorkers = uint64(numWorkers)
+ }
+
+ // When the miner is already running, notify the controller about the
+ // the change.
+ if m.started {
+ m.updateNumWorkers <- struct{}{}
+ }
+}
+
+// NumWorkers returns the number of workers which are running to solve blocks.
+//
+// This function is safe for concurrent access.
+func (m *CPUMiner) NumWorkers() int32 {
+ m.Lock()
+ defer m.Unlock()
+
+ return int32(m.numWorkers)
+}
+
+// New returns a new instance of a CPU miner for the provided configuration.
+// Use Start to begin the mining process. See the documentation for CPUMiner
+// type for more details.
+func NewCPUMiner(c *protocol.Chain, txPool *protocol.TxPool) *CPUMiner {
+ return &CPUMiner{
+ chain: c,
+ txPool: txPool,
+ numWorkers: defaultNumWorkers,
+ updateNumWorkers: make(chan struct{}),
+ queryHashesPerSec: make(chan float64),
+ updateHashes: make(chan uint64),
+ }
+}
+++ /dev/null
-// Copyright (c) 2016 The btcsuite developers\r
-// Use of this source code is governed by an ISC\r
-// license that can be found in the LICENSE file.\r
-\r
-package cpuminer\r
-\r
-import (\r
- "github.com/btcsuite/btclog"\r
-)\r
-\r
-// log is a logger that is initialized with no output filters. This\r
-// means the package will not perform any logging by default until the caller\r
-// requests it.\r
-var log btclog.Logger\r
-\r
-// The default amount of logging is none.\r
-func init() {\r
- DisableLog()\r
-}\r
-\r
-// DisableLog disables all library log output. Logging output is disabled\r
-// by default until UseLogger is called.\r
-func DisableLog() {\r
- log = btclog.Disabled\r
-}\r
-\r
-// UseLogger uses a specified Logger to output package logging info.\r
-func UseLogger(logger btclog.Logger) {\r
- log = logger\r
-}\r
+++ /dev/null
-// Copyright (c) 2016 The btcsuite developers\r
-// Use of this source code is governed by an ISC\r
-// license that can be found in the LICENSE file.\r
-\r
-package mining\r
-\r
-import (\r
- "github.com/btcsuite/btclog"\r
-)\r
-\r
-// log is a logger that is initialized with no output filters. This\r
-// means the package will not perform any logging by default until the caller\r
-// requests it.\r
-var log btclog.Logger\r
-\r
-// The default amount of logging is none.\r
-func init() {\r
- DisableLog()\r
-}\r
-\r
-// DisableLog disables all library log output. Logging output is disabled\r
-// by default until UseLogger is called.\r
-func DisableLog() {\r
- log = btclog.Disabled\r
-}\r
-\r
-// UseLogger uses a specified Logger to output package logging info.\r
-func UseLogger(logger btclog.Logger) {\r
- log = logger\r
-}\r
-// Copyright (c) 2014-2016 The btcsuite developers\r
-// Use of this source code is governed by an ISC\r
-// license that can be found in the LICENSE file.\r
-\r
-package mining\r
-\r
-import (\r
- "container/heap"\r
- "fmt"\r
- "time"\r
-\r
- "github.com/btcsuite/btcd/blockchain"\r
- "github.com/btcsuite/btcd/chaincfg"\r
- "github.com/btcsuite/btcd/chaincfg/chainhash"\r
- "github.com/btcsuite/btcd/txscript"\r
- "github.com/btcsuite/btcd/wire"\r
- "github.com/btcsuite/btcutil"\r
-)\r
-\r
-const (\r
- // MinHighPriority is the minimum priority value that allows a\r
- // transaction to be considered high priority.\r
- MinHighPriority = btcutil.SatoshiPerBitcoin * 144.0 / 250\r
-\r
- // blockHeaderOverhead is the max number of bytes it takes to serialize\r
- // a block header and max possible transaction count.\r
- blockHeaderOverhead = wire.MaxBlockHeaderPayload + wire.MaxVarIntPayload\r
-\r
- // CoinbaseFlags is added to the coinbase script of a generated block\r
- // and is used to monitor BIP16 support as well as blocks that are\r
- // generated via btcd.\r
- CoinbaseFlags = "/P2SH/btcd/"\r
-)\r
-\r
-// TxDesc is a descriptor about a transaction in a transaction source along with\r
-// additional metadata.\r
-type TxDesc struct {\r
- // Tx is the transaction associated with the entry.\r
- Tx *btcutil.Tx\r
-\r
- // Added is the time when the entry was added to the source pool.\r
- Added time.Time\r
-\r
- // Height is the block height when the entry was added to the the source\r
- // pool.\r
- Height int32\r
-\r
- // Fee is the total fee the transaction associated with the entry pays.\r
- Fee int64\r
-\r
- // FeePerKB is the fee the transaction pays in Satoshi per 1000 bytes.\r
- FeePerKB int64\r
-}\r
-\r
-// TxSource represents a source of transactions to consider for inclusion in\r
-// new blocks.\r
-//\r
-// The interface contract requires that all of these methods are safe for\r
-// concurrent access with respect to the source.\r
-type TxSource interface {\r
- // LastUpdated returns the last time a transaction was added to or\r
- // removed from the source pool.\r
- LastUpdated() time.Time\r
-\r
- // MiningDescs returns a slice of mining descriptors for all the\r
- // transactions in the source pool.\r
- MiningDescs() []*TxDesc\r
-\r
- // HaveTransaction returns whether or not the passed transaction hash\r
- // exists in the source pool.\r
- HaveTransaction(hash *chainhash.Hash) bool\r
-}\r
-\r
-// txPrioItem houses a transaction along with extra information that allows the\r
-// transaction to be prioritized and track dependencies on other transactions\r
-// which have not been mined into a block yet.\r
-type txPrioItem struct {\r
- tx *btcutil.Tx\r
- fee int64\r
- priority float64\r
- feePerKB int64\r
-\r
- // dependsOn holds a map of transaction hashes which this one depends\r
- // on. It will only be set when the transaction references other\r
- // transactions in the source pool and hence must come after them in\r
- // a block.\r
- dependsOn map[chainhash.Hash]struct{}\r
-}\r
-\r
-// txPriorityQueueLessFunc describes a function that can be used as a compare\r
-// function for a transaction priority queue (txPriorityQueue).\r
-type txPriorityQueueLessFunc func(*txPriorityQueue, int, int) bool\r
-\r
-// txPriorityQueue implements a priority queue of txPrioItem elements that\r
-// supports an arbitrary compare function as defined by txPriorityQueueLessFunc.\r
-type txPriorityQueue struct {\r
- lessFunc txPriorityQueueLessFunc\r
- items []*txPrioItem\r
-}\r
-\r
-// Len returns the number of items in the priority queue. It is part of the\r
-// heap.Interface implementation.\r
-func (pq *txPriorityQueue) Len() int {\r
- return len(pq.items)\r
-}\r
-\r
-// Less returns whether the item in the priority queue with index i should sort\r
-// before the item with index j by deferring to the assigned less function. It\r
-// is part of the heap.Interface implementation.\r
-func (pq *txPriorityQueue) Less(i, j int) bool {\r
- return pq.lessFunc(pq, i, j)\r
-}\r
-\r
-// Swap swaps the items at the passed indices in the priority queue. It is\r
-// part of the heap.Interface implementation.\r
-func (pq *txPriorityQueue) Swap(i, j int) {\r
- pq.items[i], pq.items[j] = pq.items[j], pq.items[i]\r
-}\r
-\r
-// Push pushes the passed item onto the priority queue. It is part of the\r
-// heap.Interface implementation.\r
-func (pq *txPriorityQueue) Push(x interface{}) {\r
- pq.items = append(pq.items, x.(*txPrioItem))\r
-}\r
-\r
-// Pop removes the highest priority item (according to Less) from the priority\r
-// queue and returns it. It is part of the heap.Interface implementation.\r
-func (pq *txPriorityQueue) Pop() interface{} {\r
- n := len(pq.items)\r
- item := pq.items[n-1]\r
- pq.items[n-1] = nil\r
- pq.items = pq.items[0 : n-1]\r
- return item\r
-}\r
-\r
-// SetLessFunc sets the compare function for the priority queue to the provided\r
-// function. It also invokes heap.Init on the priority queue using the new\r
-// function so it can immediately be used with heap.Push/Pop.\r
-func (pq *txPriorityQueue) SetLessFunc(lessFunc txPriorityQueueLessFunc) {\r
- pq.lessFunc = lessFunc\r
- heap.Init(pq)\r
-}\r
-\r
-// txPQByPriority sorts a txPriorityQueue by transaction priority and then fees\r
-// per kilobyte.\r
-func txPQByPriority(pq *txPriorityQueue, i, j int) bool {\r
- // Using > here so that pop gives the highest priority item as opposed\r
- // to the lowest. Sort by priority first, then fee.\r
- if pq.items[i].priority == pq.items[j].priority {\r
- return pq.items[i].feePerKB > pq.items[j].feePerKB\r
- }\r
- return pq.items[i].priority > pq.items[j].priority\r
-\r
-}\r
-\r
-// txPQByFee sorts a txPriorityQueue by fees per kilobyte and then transaction\r
-// priority.\r
-func txPQByFee(pq *txPriorityQueue, i, j int) bool {\r
- // Using > here so that pop gives the highest fee item as opposed\r
- // to the lowest. Sort by fee first, then priority.\r
- if pq.items[i].feePerKB == pq.items[j].feePerKB {\r
- return pq.items[i].priority > pq.items[j].priority\r
- }\r
- return pq.items[i].feePerKB > pq.items[j].feePerKB\r
-}\r
-\r
-// newTxPriorityQueue returns a new transaction priority queue that reserves the\r
-// passed amount of space for the elements. The new priority queue uses either\r
-// the txPQByPriority or the txPQByFee compare function depending on the\r
-// sortByFee parameter and is already initialized for use with heap.Push/Pop.\r
-// The priority queue can grow larger than the reserved space, but extra copies\r
-// of the underlying array can be avoided by reserving a sane value.\r
-func newTxPriorityQueue(reserve int, sortByFee bool) *txPriorityQueue {\r
- pq := &txPriorityQueue{\r
- items: make([]*txPrioItem, 0, reserve),\r
- }\r
- if sortByFee {\r
- pq.SetLessFunc(txPQByFee)\r
- } else {\r
- pq.SetLessFunc(txPQByPriority)\r
- }\r
- return pq\r
-}\r
-\r
-// BlockTemplate houses a block that has yet to be solved along with additional\r
-// details about the fees and the number of signature operations for each\r
-// transaction in the block.\r
-type BlockTemplate struct {\r
- // Block is a block that is ready to be solved by miners. Thus, it is\r
- // completely valid with the exception of satisfying the proof-of-work\r
- // requirement.\r
- Block *wire.MsgBlock\r
-\r
- // Fees contains the amount of fees each transaction in the generated\r
- // template pays in base units. Since the first transaction is the\r
- // coinbase, the first entry (offset 0) will contain the negative of the\r
- // sum of the fees of all other transactions.\r
- Fees []int64\r
-\r
- // SigOpCounts contains the number of signature operations each\r
- // transaction in the generated template performs.\r
- SigOpCounts []int64\r
-\r
- // Height is the height at which the block template connects to the main\r
- // chain.\r
- Height int32\r
-\r
- // ValidPayAddress indicates whether or not the template coinbase pays\r
- // to an address or is redeemable by anyone. See the documentation on\r
- // NewBlockTemplate for details on which this can be useful to generate\r
- // templates without a coinbase payment address.\r
- ValidPayAddress bool\r
-}\r
-\r
-// mergeUtxoView adds all of the entries in view to viewA. The result is that\r
-// viewA will contain all of its original entries plus all of the entries\r
-// in viewB. It will replace any entries in viewB which also exist in viewA\r
-// if the entry in viewA is fully spent.\r
-func mergeUtxoView(viewA *blockchain.UtxoViewpoint, viewB *blockchain.UtxoViewpoint) {\r
- viewAEntries := viewA.Entries()\r
- for hash, entryB := range viewB.Entries() {\r
- if entryA, exists := viewAEntries[hash]; !exists ||\r
- entryA == nil || entryA.IsFullySpent() {\r
-\r
- viewAEntries[hash] = entryB\r
- }\r
- }\r
-}\r
-\r
-// standardCoinbaseScript returns a standard script suitable for use as the\r
-// signature script of the coinbase transaction of a new block. In particular,\r
-// it starts with the block height that is required by version 2 blocks and adds\r
-// the extra nonce as well as additional coinbase flags.\r
-func standardCoinbaseScript(nextBlockHeight int32, extraNonce uint64) ([]byte, error) {\r
- return txscript.NewScriptBuilder().AddInt64(int64(nextBlockHeight)).\r
- AddInt64(int64(extraNonce)).AddData([]byte(CoinbaseFlags)).\r
- Script()\r
-}\r
-\r
-// createCoinbaseTx returns a coinbase transaction paying an appropriate subsidy\r
-// based on the passed block height to the provided address. When the address\r
-// is nil, the coinbase transaction will instead be redeemable by anyone.\r
-//\r
-// See the comment for NewBlockTemplate for more information about why the nil\r
-// address handling is useful.\r
-func createCoinbaseTx(params *chaincfg.Params, coinbaseScript []byte, nextBlockHeight int32, addr btcutil.Address) (*btcutil.Tx, error) {\r
- // Create the script to pay to the provided payment address if one was\r
- // specified. Otherwise create a script that allows the coinbase to be\r
- // redeemable by anyone.\r
- var pkScript []byte\r
- if addr != nil {\r
- var err error\r
- pkScript, err = txscript.PayToAddrScript(addr)\r
- if err != nil {\r
- return nil, err\r
- }\r
- } else {\r
- var err error\r
- scriptBuilder := txscript.NewScriptBuilder()\r
- pkScript, err = scriptBuilder.AddOp(txscript.OP_TRUE).Script()\r
- if err != nil {\r
- return nil, err\r
- }\r
- }\r
-\r
- tx := wire.NewMsgTx(wire.TxVersion)\r
- tx.AddTxIn(&wire.TxIn{\r
- // Coinbase transactions have no inputs, so previous outpoint is\r
- // zero hash and max index.\r
- PreviousOutPoint: *wire.NewOutPoint(&chainhash.Hash{},\r
- wire.MaxPrevOutIndex),\r
- SignatureScript: coinbaseScript,\r
- Sequence: wire.MaxTxInSequenceNum,\r
- })\r
- tx.AddTxOut(&wire.TxOut{\r
- Value: blockchain.CalcBlockSubsidy(nextBlockHeight, params),\r
- PkScript: pkScript,\r
- })\r
- return btcutil.NewTx(tx), nil\r
-}\r
-\r
-// spendTransaction updates the passed view by marking the inputs to the passed\r
-// transaction as spent. It also adds all outputs in the passed transaction\r
-// which are not provably unspendable as available unspent transaction outputs.\r
-func spendTransaction(utxoView *blockchain.UtxoViewpoint, tx *btcutil.Tx, height int32) error {\r
- for _, txIn := range tx.MsgTx().TxIn {\r
- originHash := &txIn.PreviousOutPoint.Hash\r
- originIndex := txIn.PreviousOutPoint.Index\r
- entry := utxoView.LookupEntry(originHash)\r
- if entry != nil {\r
- entry.SpendOutput(originIndex)\r
- }\r
- }\r
-\r
- utxoView.AddTxOuts(tx, height)\r
- return nil\r
-}\r
-\r
-// logSkippedDeps logs any dependencies which are also skipped as a result of\r
-// skipping a transaction while generating a block template at the trace level.\r
-func logSkippedDeps(tx *btcutil.Tx, deps map[chainhash.Hash]*txPrioItem) {\r
- if deps == nil {\r
- return\r
- }\r
-\r
- for _, item := range deps {\r
- log.Tracef("Skipping tx %s since it depends on %s\n",\r
- item.tx.Hash(), tx.Hash())\r
- }\r
-}\r
-\r
-// MinimumMedianTime returns the minimum allowed timestamp for a block building\r
-// on the end of the provided best chain. In particular, it is one second after\r
-// the median timestamp of the last several blocks per the chain consensus\r
-// rules.\r
-func MinimumMedianTime(chainState *blockchain.BestState) time.Time {\r
- return chainState.MedianTime.Add(time.Second)\r
-}\r
-\r
-// medianAdjustedTime returns the current time adjusted to ensure it is at least\r
-// one second after the median timestamp of the last several blocks per the\r
-// chain consensus rules.\r
-func medianAdjustedTime(chainState *blockchain.BestState, timeSource blockchain.MedianTimeSource) time.Time {\r
- // The timestamp for the block must not be before the median timestamp\r
- // of the last several blocks. Thus, choose the maximum between the\r
- // current time and one second after the past median time. The current\r
- // timestamp is truncated to a second boundary before comparison since a\r
- // block timestamp does not supported a precision greater than one\r
- // second.\r
- newTimestamp := timeSource.AdjustedTime()\r
- minTimestamp := MinimumMedianTime(chainState)\r
- if newTimestamp.Before(minTimestamp) {\r
- newTimestamp = minTimestamp\r
- }\r
-\r
- return newTimestamp\r
-}\r
-\r
-// BlkTmplGenerator provides a type that can be used to generate block templates\r
-// based on a given mining policy and source of transactions to choose from.\r
-// It also houses additional state required in order to ensure the templates\r
-// are built on top of the current best chain and adhere to the consensus rules.\r
-type BlkTmplGenerator struct {\r
- policy *Policy\r
- chainParams *chaincfg.Params\r
- txSource TxSource\r
- chain *blockchain.BlockChain\r
- timeSource blockchain.MedianTimeSource\r
- sigCache *txscript.SigCache\r
-}\r
-\r
-// NewBlkTmplGenerator returns a new block template generator for the given\r
-// policy using transactions from the provided transaction source.\r
-//\r
-// The additional state-related fields are required in order to ensure the\r
-// templates are built on top of the current best chain and adhere to the\r
-// consensus rules.\r
-func NewBlkTmplGenerator(policy *Policy, params *chaincfg.Params,\r
- txSource TxSource, chain *blockchain.BlockChain,\r
- timeSource blockchain.MedianTimeSource,\r
- sigCache *txscript.SigCache) *BlkTmplGenerator {\r
-\r
- return &BlkTmplGenerator{\r
- policy: policy,\r
- chainParams: params,\r
- txSource: txSource,\r
- chain: chain,\r
- timeSource: timeSource,\r
- sigCache: sigCache,\r
- }\r
-}\r
-\r
-// NewBlockTemplate returns a new block template that is ready to be solved\r
-// using the transactions from the passed transaction source pool and a coinbase\r
-// that either pays to the passed address if it is not nil, or a coinbase that\r
-// is redeemable by anyone if the passed address is nil. The nil address\r
-// functionality is useful since there are cases such as the getblocktemplate\r
-// RPC where external mining software is responsible for creating their own\r
-// coinbase which will replace the one generated for the block template. Thus\r
-// the need to have configured address can be avoided.\r
-//\r
-// The transactions selected and included are prioritized according to several\r
-// factors. First, each transaction has a priority calculated based on its\r
-// value, age of inputs, and size. Transactions which consist of larger\r
-// amounts, older inputs, and small sizes have the highest priority. Second, a\r
-// fee per kilobyte is calculated for each transaction. Transactions with a\r
-// higher fee per kilobyte are preferred. Finally, the block generation related\r
-// policy settings are all taken into account.\r
-//\r
-// Transactions which only spend outputs from other transactions already in the\r
-// block chain are immediately added to a priority queue which either\r
-// prioritizes based on the priority (then fee per kilobyte) or the fee per\r
-// kilobyte (then priority) depending on whether or not the BlockPrioritySize\r
-// policy setting allots space for high-priority transactions. Transactions\r
-// which spend outputs from other transactions in the source pool are added to a\r
-// dependency map so they can be added to the priority queue once the\r
-// transactions they depend on have been included.\r
-//\r
-// Once the high-priority area (if configured) has been filled with\r
-// transactions, or the priority falls below what is considered high-priority,\r
-// the priority queue is updated to prioritize by fees per kilobyte (then\r
-// priority).\r
-//\r
-// When the fees per kilobyte drop below the TxMinFreeFee policy setting, the\r
-// transaction will be skipped unless the BlockMinSize policy setting is\r
-// nonzero, in which case the block will be filled with the low-fee/free\r
-// transactions until the block size reaches that minimum size.\r
-//\r
-// Any transactions which would cause the block to exceed the BlockMaxSize\r
-// policy setting, exceed the maximum allowed signature operations per block, or\r
-// otherwise cause the block to be invalid are skipped.\r
-//\r
-// Given the above, a block generated by this function is of the following form:\r
-//\r
-// ----------------------------------- -- --\r
-// | Coinbase Transaction | | |\r
-// |-----------------------------------| | |\r
-// | | | | ----- policy.BlockPrioritySize\r
-// | High-priority Transactions | | |\r
-// | | | |\r
-// |-----------------------------------| | --\r
-// | | |\r
-// | | |\r
-// | | |--- policy.BlockMaxSize\r
-// | Transactions prioritized by fee | |\r
-// | until <= policy.TxMinFreeFee | |\r
-// | | |\r
-// | | |\r
-// | | |\r
-// |-----------------------------------| |\r
-// | Low-fee/Non high-priority (free) | |\r
-// | transactions (while block size | |\r
-// | <= policy.BlockMinSize) | |\r
-// ----------------------------------- --\r
-func (g *BlkTmplGenerator) NewBlockTemplate(payToAddress btcutil.Address) (*BlockTemplate, error) {\r
- // Extend the most recently known best block.\r
- best := g.chain.BestSnapshot()\r
- prevHash := &best.Hash\r
- nextBlockHeight := best.Height + 1\r
-\r
- // Create a standard coinbase transaction paying to the provided\r
- // address. NOTE: The coinbase value will be updated to include the\r
- // fees from the selected transactions later after they have actually\r
- // been selected. It is created here to detect any errors early\r
- // before potentially doing a lot of work below. The extra nonce helps\r
- // ensure the transaction is not a duplicate transaction (paying the\r
- // same value to the same public key address would otherwise be an\r
- // identical transaction for block version 1).\r
- extraNonce := uint64(0)\r
- coinbaseScript, err := standardCoinbaseScript(nextBlockHeight, extraNonce)\r
- if err != nil {\r
- return nil, err\r
- }\r
- coinbaseTx, err := createCoinbaseTx(g.chainParams, coinbaseScript,\r
- nextBlockHeight, payToAddress)\r
- if err != nil {\r
- return nil, err\r
- }\r
- numCoinbaseSigOps := int64(blockchain.CountSigOps(coinbaseTx))\r
-\r
- // Get the current source transactions and create a priority queue to\r
- // hold the transactions which are ready for inclusion into a block\r
- // along with some priority related and fee metadata. Reserve the same\r
- // number of items that are available for the priority queue. Also,\r
- // choose the initial sort order for the priority queue based on whether\r
- // or not there is an area allocated for high-priority transactions.\r
- sourceTxns := g.txSource.MiningDescs()\r
- sortedByFee := g.policy.BlockPrioritySize == 0\r
- priorityQueue := newTxPriorityQueue(len(sourceTxns), sortedByFee)\r
-\r
- // Create a slice to hold the transactions to be included in the\r
- // generated block with reserved space. Also create a utxo view to\r
- // house all of the input transactions so multiple lookups can be\r
- // avoided.\r
- blockTxns := make([]*btcutil.Tx, 0, len(sourceTxns))\r
- blockTxns = append(blockTxns, coinbaseTx)\r
- blockUtxos := blockchain.NewUtxoViewpoint()\r
-\r
- // dependers is used to track transactions which depend on another\r
- // transaction in the source pool. This, in conjunction with the\r
- // dependsOn map kept with each dependent transaction helps quickly\r
- // determine which dependent transactions are now eligible for inclusion\r
- // in the block once each transaction has been included.\r
- dependers := make(map[chainhash.Hash]map[chainhash.Hash]*txPrioItem)\r
-\r
- // Create slices to hold the fees and number of signature operations\r
- // for each of the selected transactions and add an entry for the\r
- // coinbase. This allows the code below to simply append details about\r
- // a transaction as it is selected for inclusion in the final block.\r
- // However, since the total fees aren't known yet, use a dummy value for\r
- // the coinbase fee which will be updated later.\r
- txFees := make([]int64, 0, len(sourceTxns))\r
- txSigOpCounts := make([]int64, 0, len(sourceTxns))\r
- txFees = append(txFees, -1) // Updated once known\r
- txSigOpCounts = append(txSigOpCounts, numCoinbaseSigOps)\r
-\r
- log.Debugf("Considering %d transactions for inclusion to new block",\r
- len(sourceTxns))\r
-\r
-mempoolLoop:\r
- for _, txDesc := range sourceTxns {\r
- // A block can't have more than one coinbase or contain\r
- // non-finalized transactions.\r
- tx := txDesc.Tx\r
- if blockchain.IsCoinBase(tx) {\r
- log.Tracef("Skipping coinbase tx %s", tx.Hash())\r
- continue\r
- }\r
- if !blockchain.IsFinalizedTransaction(tx, nextBlockHeight,\r
- g.timeSource.AdjustedTime()) {\r
-\r
- log.Tracef("Skipping non-finalized tx %s", tx.Hash())\r
- continue\r
- }\r
-\r
- // Fetch all of the utxos referenced by the this transaction.\r
- // NOTE: This intentionally does not fetch inputs from the\r
- // mempool since a transaction which depends on other\r
- // transactions in the mempool must come after those\r
- // dependencies in the final generated block.\r
- utxos, err := g.chain.FetchUtxoView(tx)\r
- if err != nil {\r
- log.Warnf("Unable to fetch utxo view for tx %s: %v",\r
- tx.Hash(), err)\r
- continue\r
- }\r
-\r
- // Setup dependencies for any transactions which reference\r
- // other transactions in the mempool so they can be properly\r
- // ordered below.\r
- prioItem := &txPrioItem{tx: tx}\r
- for _, txIn := range tx.MsgTx().TxIn {\r
- originHash := &txIn.PreviousOutPoint.Hash\r
- originIndex := txIn.PreviousOutPoint.Index\r
- utxoEntry := utxos.LookupEntry(originHash)\r
- if utxoEntry == nil || utxoEntry.IsOutputSpent(originIndex) {\r
- if !g.txSource.HaveTransaction(originHash) {\r
- log.Tracef("Skipping tx %s because it "+\r
- "references unspent output %s "+\r
- "which is not available",\r
- tx.Hash(), txIn.PreviousOutPoint)\r
- continue mempoolLoop\r
- }\r
-\r
- // The transaction is referencing another\r
- // transaction in the source pool, so setup an\r
- // ordering dependency.\r
- deps, exists := dependers[*originHash]\r
- if !exists {\r
- deps = make(map[chainhash.Hash]*txPrioItem)\r
- dependers[*originHash] = deps\r
- }\r
- deps[*prioItem.tx.Hash()] = prioItem\r
- if prioItem.dependsOn == nil {\r
- prioItem.dependsOn = make(\r
- map[chainhash.Hash]struct{})\r
- }\r
- prioItem.dependsOn[*originHash] = struct{}{}\r
-\r
- // Skip the check below. We already know the\r
- // referenced transaction is available.\r
- continue\r
- }\r
- }\r
-\r
- // Calculate the final transaction priority using the input\r
- // value age sum as well as the adjusted transaction size. The\r
- // formula is: sum(inputValue * inputAge) / adjustedTxSize\r
- prioItem.priority = CalcPriority(tx.MsgTx(), utxos,\r
- nextBlockHeight)\r
-\r
- // Calculate the fee in Satoshi/kB.\r
- prioItem.feePerKB = txDesc.FeePerKB\r
- prioItem.fee = txDesc.Fee\r
-\r
- // Add the transaction to the priority queue to mark it ready\r
- // for inclusion in the block unless it has dependencies.\r
- if prioItem.dependsOn == nil {\r
- heap.Push(priorityQueue, prioItem)\r
- }\r
-\r
- // Merge the referenced outputs from the input transactions to\r
- // this transaction into the block utxo view. This allows the\r
- // code below to avoid a second lookup.\r
- mergeUtxoView(blockUtxos, utxos)\r
- }\r
-\r
- log.Tracef("Priority queue len %d, dependers len %d",\r
- priorityQueue.Len(), len(dependers))\r
-\r
- // The starting block size is the size of the block header plus the max\r
- // possible transaction count size, plus the size of the coinbase\r
- // transaction.\r
- blockSize := blockHeaderOverhead + uint32(coinbaseTx.MsgTx().SerializeSize())\r
- blockSigOps := numCoinbaseSigOps\r
- totalFees := int64(0)\r
-\r
- // Choose which transactions make it into the block.\r
- for priorityQueue.Len() > 0 {\r
- // Grab the highest priority (or highest fee per kilobyte\r
- // depending on the sort order) transaction.\r
- prioItem := heap.Pop(priorityQueue).(*txPrioItem)\r
- tx := prioItem.tx\r
-\r
- // Grab any transactions which depend on this one.\r
- deps := dependers[*tx.Hash()]\r
-\r
- // Enforce maximum block size. Also check for overflow.\r
- txSize := uint32(tx.MsgTx().SerializeSize())\r
- blockPlusTxSize := blockSize + txSize\r
- if blockPlusTxSize < blockSize ||\r
- blockPlusTxSize >= g.policy.BlockMaxSize {\r
-\r
- log.Tracef("Skipping tx %s because it would exceed "+\r
- "the max block size", tx.Hash())\r
- logSkippedDeps(tx, deps)\r
- continue\r
- }\r
-\r
- // Enforce maximum signature operations per block. Also check\r
- // for overflow.\r
- numSigOps := int64(blockchain.CountSigOps(tx))\r
- if blockSigOps+numSigOps < blockSigOps ||\r
- blockSigOps+numSigOps > blockchain.MaxSigOpsPerBlock {\r
- log.Tracef("Skipping tx %s because it would exceed "+\r
- "the maximum sigops per block", tx.Hash())\r
- logSkippedDeps(tx, deps)\r
- continue\r
- }\r
- numP2SHSigOps, err := blockchain.CountP2SHSigOps(tx, false,\r
- blockUtxos)\r
- if err != nil {\r
- log.Tracef("Skipping tx %s due to error in "+\r
- "CountP2SHSigOps: %v", tx.Hash(), err)\r
- logSkippedDeps(tx, deps)\r
- continue\r
- }\r
- numSigOps += int64(numP2SHSigOps)\r
- if blockSigOps+numSigOps < blockSigOps ||\r
- blockSigOps+numSigOps > blockchain.MaxSigOpsPerBlock {\r
- log.Tracef("Skipping tx %s because it would exceed "+\r
- "the maximum sigops per block (p2sh)",\r
- tx.Hash())\r
- logSkippedDeps(tx, deps)\r
- continue\r
- }\r
-\r
- // Skip free transactions once the block is larger than the\r
- // minimum block size.\r
- if sortedByFee &&\r
- prioItem.feePerKB < int64(g.policy.TxMinFreeFee) &&\r
- blockPlusTxSize >= g.policy.BlockMinSize {\r
-\r
- log.Tracef("Skipping tx %s with feePerKB %.2f "+\r
- "< TxMinFreeFee %d and block size %d >= "+\r
- "minBlockSize %d", tx.Hash(), prioItem.feePerKB,\r
- g.policy.TxMinFreeFee, blockPlusTxSize,\r
- g.policy.BlockMinSize)\r
- logSkippedDeps(tx, deps)\r
- continue\r
- }\r
-\r
- // Prioritize by fee per kilobyte once the block is larger than\r
- // the priority size or there are no more high-priority\r
- // transactions.\r
- if !sortedByFee && (blockPlusTxSize >= g.policy.BlockPrioritySize ||\r
- prioItem.priority <= MinHighPriority) {\r
-\r
- log.Tracef("Switching to sort by fees per kilobyte "+\r
- "blockSize %d >= BlockPrioritySize %d || "+\r
- "priority %.2f <= minHighPriority %.2f",\r
- blockPlusTxSize, g.policy.BlockPrioritySize,\r
- prioItem.priority, MinHighPriority)\r
-\r
- sortedByFee = true\r
- priorityQueue.SetLessFunc(txPQByFee)\r
-\r
- // Put the transaction back into the priority queue and\r
- // skip it so it is re-priortized by fees if it won't\r
- // fit into the high-priority section or the priority is\r
- // too low. Otherwise this transaction will be the\r
- // final one in the high-priority section, so just fall\r
- // though to the code below so it is added now.\r
- if blockPlusTxSize > g.policy.BlockPrioritySize ||\r
- prioItem.priority < MinHighPriority {\r
-\r
- heap.Push(priorityQueue, prioItem)\r
- continue\r
- }\r
- }\r
-\r
- // Ensure the transaction inputs pass all of the necessary\r
- // preconditions before allowing it to be added to the block.\r
- _, err = blockchain.CheckTransactionInputs(tx, nextBlockHeight,\r
- blockUtxos, g.chainParams)\r
- if err != nil {\r
- log.Tracef("Skipping tx %s due to error in "+\r
- "CheckTransactionInputs: %v", tx.Hash(), err)\r
- logSkippedDeps(tx, deps)\r
- continue\r
- }\r
- err = blockchain.ValidateTransactionScripts(tx, blockUtxos,\r
- txscript.StandardVerifyFlags, g.sigCache)\r
- if err != nil {\r
- log.Tracef("Skipping tx %s due to error in "+\r
- "ValidateTransactionScripts: %v", tx.Hash(),\r
- err)\r
- logSkippedDeps(tx, deps)\r
- continue\r
- }\r
-\r
- // Spend the transaction inputs in the block utxo view and add\r
- // an entry for it to ensure any transactions which reference\r
- // this one have it available as an input and can ensure they\r
- // aren't double spending.\r
- spendTransaction(blockUtxos, tx, nextBlockHeight)\r
-\r
- // Add the transaction to the block, increment counters, and\r
- // save the fees and signature operation counts to the block\r
- // template.\r
- blockTxns = append(blockTxns, tx)\r
- blockSize += txSize\r
- blockSigOps += numSigOps\r
- totalFees += prioItem.fee\r
- txFees = append(txFees, prioItem.fee)\r
- txSigOpCounts = append(txSigOpCounts, numSigOps)\r
-\r
- log.Tracef("Adding tx %s (priority %.2f, feePerKB %.2f)",\r
- prioItem.tx.Hash(), prioItem.priority, prioItem.feePerKB)\r
-\r
- // Add transactions which depend on this one (and also do not\r
- // have any other unsatisified dependencies) to the priority\r
- // queue.\r
- for _, item := range deps {\r
- // Add the transaction to the priority queue if there\r
- // are no more dependencies after this one.\r
- delete(item.dependsOn, *tx.Hash())\r
- if len(item.dependsOn) == 0 {\r
- heap.Push(priorityQueue, item)\r
- }\r
- }\r
- }\r
-\r
- // Now that the actual transactions have been selected, update the\r
- // block size for the real transaction count and coinbase value with\r
- // the total fees accordingly.\r
- blockSize -= wire.MaxVarIntPayload -\r
- uint32(wire.VarIntSerializeSize(uint64(len(blockTxns))))\r
- coinbaseTx.MsgTx().TxOut[0].Value += totalFees\r
- txFees[0] = -totalFees\r
-\r
- // Calculate the required difficulty for the block. The timestamp\r
- // is potentially adjusted to ensure it comes after the median time of\r
- // the last several blocks per the chain consensus rules.\r
- ts := medianAdjustedTime(best, g.timeSource)\r
- reqDifficulty, err := g.chain.CalcNextRequiredDifficulty(ts)\r
- if err != nil {\r
- return nil, err\r
- }\r
-\r
- // Calculate the next expected block version based on the state of the\r
- // rule change deployments.\r
- nextBlockVersion, err := g.chain.CalcNextBlockVersion()\r
- if err != nil {\r
- return nil, err\r
- }\r
-\r
- // Create a new block ready to be solved.\r
- merkles := blockchain.BuildMerkleTreeStore(blockTxns)\r
- var msgBlock wire.MsgBlock\r
- msgBlock.Header = wire.BlockHeader{\r
- Version: nextBlockVersion,\r
- PrevBlock: *prevHash,\r
- MerkleRoot: *merkles[len(merkles)-1],\r
- Timestamp: ts,\r
- Bits: reqDifficulty,\r
- }\r
- for _, tx := range blockTxns {\r
- if err := msgBlock.AddTransaction(tx.MsgTx()); err != nil {\r
- return nil, err\r
- }\r
- }\r
-\r
- // Finally, perform a full check on the created block against the chain\r
- // consensus rules to ensure it properly connects to the current best\r
- // chain with no issues.\r
- block := btcutil.NewBlock(&msgBlock)\r
- block.SetHeight(nextBlockHeight)\r
- if err := g.chain.CheckConnectBlock(block); err != nil {\r
- return nil, err\r
- }\r
-\r
- log.Debugf("Created new block template (%d transactions, %d in fees, "+\r
- "%d signature operations, %d bytes, target difficulty %064x)",\r
- len(msgBlock.Transactions), totalFees, blockSigOps, blockSize,\r
- blockchain.CompactToBig(msgBlock.Header.Bits))\r
-\r
- return &BlockTemplate{\r
- Block: &msgBlock,\r
- Fees: txFees,\r
- SigOpCounts: txSigOpCounts,\r
- Height: nextBlockHeight,\r
- ValidPayAddress: payToAddress != nil,\r
- }, nil\r
-}\r
-\r
-// UpdateBlockTime updates the timestamp in the header of the passed block to\r
-// the current time while taking into account the median time of the last\r
-// several blocks to ensure the new time is after that time per the chain\r
-// consensus rules. Finally, it will update the target difficulty if needed\r
-// based on the new time for the test networks since their target difficulty can\r
-// change based upon time.\r
-func (g *BlkTmplGenerator) UpdateBlockTime(msgBlock *wire.MsgBlock) error {\r
- // The new timestamp is potentially adjusted to ensure it comes after\r
- // the median time of the last several blocks per the chain consensus\r
- // rules.\r
- newTime := medianAdjustedTime(g.chain.BestSnapshot(), g.timeSource)\r
- msgBlock.Header.Timestamp = newTime\r
-\r
- // Recalculate the difficulty if running on a network that requires it.\r
- if g.chainParams.ReduceMinDifficulty {\r
- difficulty, err := g.chain.CalcNextRequiredDifficulty(newTime)\r
- if err != nil {\r
- return err\r
- }\r
- msgBlock.Header.Bits = difficulty\r
- }\r
-\r
- return nil\r
-}\r
-\r
-// UpdateExtraNonce updates the extra nonce in the coinbase script of the passed\r
-// block by regenerating the coinbase script with the passed value and block\r
-// height. It also recalculates and updates the new merkle root that results\r
-// from changing the coinbase script.\r
-func (g *BlkTmplGenerator) UpdateExtraNonce(msgBlock *wire.MsgBlock, blockHeight int32, extraNonce uint64) error {\r
- coinbaseScript, err := standardCoinbaseScript(blockHeight, extraNonce)\r
- if err != nil {\r
- return err\r
- }\r
- if len(coinbaseScript) > blockchain.MaxCoinbaseScriptLen {\r
- return fmt.Errorf("coinbase transaction script length "+\r
- "of %d is out of range (min: %d, max: %d)",\r
- len(coinbaseScript), blockchain.MinCoinbaseScriptLen,\r
- blockchain.MaxCoinbaseScriptLen)\r
- }\r
- msgBlock.Transactions[0].TxIn[0].SignatureScript = coinbaseScript\r
-\r
- // TODO(davec): A btcutil.Block should use saved in the state to avoid\r
- // recalculating all of the other transaction hashes.\r
- // block.Transactions[0].InvalidateCache()\r
-\r
- // Recalculate the merkle root with the updated extra nonce.\r
- block := btcutil.NewBlock(msgBlock)\r
- merkles := blockchain.BuildMerkleTreeStore(block.Transactions())\r
- msgBlock.Header.MerkleRoot = *merkles[len(merkles)-1]\r
- return nil\r
-}\r
-\r
-// BestSnapshot returns information about the current best chain block and\r
-// related state as of the current point in time using the chain instance\r
-// associated with the block template generator. The returned state must be\r
-// treated as immutable since it is shared by all callers.\r
-//\r
-// This function is safe for concurrent access.\r
-func (g *BlkTmplGenerator) BestSnapshot() *blockchain.BestState {\r
- return g.chain.BestSnapshot()\r
-}\r
-\r
-// TxSource returns the associated transaction source.\r
-//\r
-// This function is safe for concurrent access.\r
-func (g *BlkTmplGenerator) TxSource() TxSource {\r
- return g.txSource\r
-}\r
+// 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 mining
+
+import (
+ "time"
+
+ "github.com/bytom/blockchain/txbuilder"
+ "github.com/bytom/consensus"
+ "github.com/bytom/errors"
+ "github.com/bytom/protocol"
+ "github.com/bytom/protocol/bc"
+ "github.com/bytom/protocol/bc/legacy"
+ "github.com/bytom/protocol/state"
+ "github.com/bytom/protocol/validation"
+ "github.com/bytom/protocol/vm"
+ "github.com/bytom/protocol/vm/vmutil"
+)
+
+// standardCoinbaseScript returns a standard script suitable for use as the
+// signature script of the coinbase transaction of a new block.
+func standardCoinbaseScript(blockHeight uint64) ([]byte, error) {
+ //TODO: add verify conditions, block heigh & sign
+ scriptBuild := vmutil.NewBuilder()
+ scriptBuild.AddOp(vm.OP_TRUE)
+ return scriptBuild.Build()
+}
+
+// createCoinbaseTx returns a coinbase transaction paying an appropriate subsidy
+// based on the passed block height to the provided address. When the address
+// is nil, the coinbase transaction will instead be redeemable by anyone.
+func createCoinbaseTx(amount uint64, blockHeight uint64, addr []byte) (*legacy.Tx, error) {
+ //TODO: make sure things works
+ amount += consensus.BlockSubsidy(blockHeight)
+ cbScript, err := standardCoinbaseScript(blockHeight)
+ if err != nil {
+ return nil, err
+ }
+
+ builder := txbuilder.NewBuilder(time.Now())
+ builder.AddOutput(legacy.NewTxOutput(*validation.BTMAssetID, amount, cbScript, nil))
+ _, txData, err := builder.Build()
+ tx := &legacy.Tx{
+ TxData: *txData,
+ Tx: legacy.MapTx(txData),
+ }
+ return tx, err
+}
+
+// NewBlockTemplate returns a new block template that is ready to be solved
+func NewBlockTemplate(c *protocol.Chain, txPool *protocol.TxPool, addr []byte) (*legacy.Block, error) {
+ // Extend the most recently known best block.
+ var err error
+ newSnap := state.Empty()
+ var blockData *bc.Block
+ nextBlockHeight := uint64(1)
+ preBlockHash := bc.Hash{}
+
+ block, snap := c.State()
+ if block != nil {
+ nextBlockHeight = block.BlockHeader.Height + 1
+ preBlockHash = block.Hash()
+ newSnap = state.Copy(snap)
+ blockData = legacy.MapBlock(block)
+ }
+
+ txDescs := txPool.GetTransactions()
+ blockTxns := make([]*legacy.Tx, 0, len(txDescs))
+ blockWeight := uint64(0)
+ txFee := uint64(0)
+
+ b := &legacy.Block{
+ BlockHeader: legacy.BlockHeader{
+ Version: 1,
+ Height: nextBlockHeight,
+ PreviousBlockHash: preBlockHash,
+ TimestampMS: bc.Millis(time.Now()),
+ BlockCommitment: legacy.BlockCommitment{},
+ Bits: consensus.CalcNextRequiredDifficulty(),
+ },
+ }
+ newSnap.PruneNonces(b.BlockHeader.TimestampMS)
+
+ var txEntries []*bc.Tx
+ for _, txDesc := range txDescs {
+ tx := txDesc.Tx.Tx
+ blockPlusTxWeight := blockWeight + txDesc.Weight
+ if blockPlusTxWeight > validation.MaxBlockSzie {
+ break
+ }
+
+ if err := newSnap.ApplyTx(tx); err != nil {
+ txPool.RemoveTransaction(&tx.ID)
+ continue
+ }
+
+ if _, err := validation.ValidateTx(tx, blockData); err != nil {
+ txPool.RemoveTransaction(&tx.ID)
+ continue
+ }
+
+ blockTxns = append(blockTxns, txDesc.Tx)
+ txEntries = append(txEntries, tx)
+ blockWeight = blockPlusTxWeight
+ txFee += txDesc.Fee
+ }
+
+ cbTx, _ := createCoinbaseTx(txFee, nextBlockHeight, addr)
+ newSnap.ApplyTx(cbTx.Tx)
+ blockTxns = append([]*legacy.Tx{cbTx}, blockTxns...)
+
+ b.Transactions = blockTxns
+
+ b.BlockHeader.BlockCommitment.TransactionsMerkleRoot, err = bc.MerkleRoot(txEntries)
+ b.BlockHeader.BlockCommitment.AssetsMerkleRoot = newSnap.Tree.RootHash()
+ if err != nil {
+ return nil, errors.Wrap(err, "calculating tx merkle root")
+ }
+
+ return b, nil
+}
+++ /dev/null
-// Copyright (c) 2014-2016 The btcsuite developers\r
-// Use of this source code is governed by an ISC\r
-// license that can be found in the LICENSE file.\r
-\r
-package mining\r
-\r
-import (\r
- "github.com/btcsuite/btcd/blockchain"\r
- "github.com/btcsuite/btcd/wire"\r
- "github.com/btcsuite/btcutil"\r
-)\r
-\r
-const (\r
- // UnminedHeight is the height used for the "block" height field of the\r
- // contextual transaction information provided in a transaction store\r
- // when it has not yet been mined into a block.\r
- UnminedHeight = 0x7fffffff\r
-)\r
-\r
-// Policy houses the policy (configuration parameters) which is used to control\r
-// the generation of block templates. See the documentation for\r
-// NewBlockTemplate for more details on each of these parameters are used.\r
-type Policy struct {\r
- // BlockMinSize is the minimum block size in bytes to be used when\r
- // generating a block template.\r
- BlockMinSize uint32\r
-\r
- // BlockMaxSize is the maximum block size in bytes to be used when\r
- // generating a block template.\r
- BlockMaxSize uint32\r
-\r
- // BlockPrioritySize is the size in bytes for high-priority / low-fee\r
- // transactions to be used when generating a block template.\r
- BlockPrioritySize uint32\r
-\r
- // TxMinFreeFee is the minimum fee in Satoshi/1000 bytes that is\r
- // required for a transaction to be treated as free for mining purposes\r
- // (block template generation).\r
- TxMinFreeFee btcutil.Amount\r
-}\r
-\r
-// minInt is a helper function to return the minimum of two ints. This avoids\r
-// a math import and the need to cast to floats.\r
-func minInt(a, b int) int {\r
- if a < b {\r
- return a\r
- }\r
- return b\r
-}\r
-\r
-// calcInputValueAge is a helper function used to calculate the input age of\r
-// a transaction. The input age for a txin is the number of confirmations\r
-// since the referenced txout multiplied by its output value. The total input\r
-// age is the sum of this value for each txin. Any inputs to the transaction\r
-// which are currently in the mempool and hence not mined into a block yet,\r
-// contribute no additional input age to the transaction.\r
-func calcInputValueAge(tx *wire.MsgTx, utxoView *blockchain.UtxoViewpoint, nextBlockHeight int32) float64 {\r
- var totalInputAge float64\r
- for _, txIn := range tx.TxIn {\r
- // Don't attempt to accumulate the total input age if the\r
- // referenced transaction output doesn't exist.\r
- originHash := &txIn.PreviousOutPoint.Hash\r
- originIndex := txIn.PreviousOutPoint.Index\r
- txEntry := utxoView.LookupEntry(originHash)\r
- if txEntry != nil && !txEntry.IsOutputSpent(originIndex) {\r
- // Inputs with dependencies currently in the mempool\r
- // have their block height set to a special constant.\r
- // Their input age should computed as zero since their\r
- // parent hasn't made it into a block yet.\r
- var inputAge int32\r
- originHeight := txEntry.BlockHeight()\r
- if originHeight == UnminedHeight {\r
- inputAge = 0\r
- } else {\r
- inputAge = nextBlockHeight - originHeight\r
- }\r
-\r
- // Sum the input value times age.\r
- inputValue := txEntry.AmountByIndex(originIndex)\r
- totalInputAge += float64(inputValue * int64(inputAge))\r
- }\r
- }\r
-\r
- return totalInputAge\r
-}\r
-\r
-// CalcPriority returns a transaction priority given a transaction and the sum\r
-// of each of its input values multiplied by their age (# of confirmations).\r
-// Thus, the final formula for the priority is:\r
-// sum(inputValue * inputAge) / adjustedTxSize\r
-func CalcPriority(tx *wire.MsgTx, utxoView *blockchain.UtxoViewpoint, nextBlockHeight int32) float64 {\r
- // In order to encourage spending multiple old unspent transaction\r
- // outputs thereby reducing the total set, don't count the constant\r
- // overhead for each input as well as enough bytes of the signature\r
- // script to cover a pay-to-script-hash redemption with a compressed\r
- // pubkey. This makes additional inputs free by boosting the priority\r
- // of the transaction accordingly. No more incentive is given to avoid\r
- // encouraging gaming future transactions through the use of junk\r
- // outputs. This is the same logic used in the reference\r
- // implementation.\r
- //\r
- // The constant overhead for a txin is 41 bytes since the previous\r
- // outpoint is 36 bytes + 4 bytes for the sequence + 1 byte the\r
- // signature script length.\r
- //\r
- // A compressed pubkey pay-to-script-hash redemption with a maximum len\r
- // signature is of the form:\r
- // [OP_DATA_73 <73-byte sig> + OP_DATA_35 + {OP_DATA_33\r
- // <33 byte compresed pubkey> + OP_CHECKSIG}]\r
- //\r
- // Thus 1 + 73 + 1 + 1 + 33 + 1 = 110\r
- overhead := 0\r
- for _, txIn := range tx.TxIn {\r
- // Max inputs + size can't possibly overflow here.\r
- overhead += 41 + minInt(110, len(txIn.SignatureScript))\r
- }\r
-\r
- serializedTxSize := tx.SerializeSize()\r
- if overhead >= serializedTxSize {\r
- return 0.0\r
- }\r
-\r
- inputValueAge := calcInputValueAge(tx, utxoView, nextBlockHeight)\r
- return inputValueAge / float64(serializedTxSize-overhead)\r
-}\r
"github.com/tendermint/tmlibs/log"
//rpc "github.com/blockchain/rpc/lib"
"github.com/bytom/blockchain/account"
+ "github.com/bytom/blockchain/asset"
"github.com/bytom/blockchain/txdb"
"github.com/bytom/net/http/reqid"
"github.com/bytom/protocol"
- "github.com/bytom/blockchain/asset"
rpcserver "github.com/bytom/rpc/lib/server"
// "github.com/bytom/net/http/static"
// "github.com/bytom/generated/dashboard"
}
chain, err := protocol.NewChain(context.Background(), genesisBlock.Hash(), store, nil)
+ txPool := protocol.NewTxPool()
/* if err != nil {
cmn.Exit(cmn.Fmt("protocol new chain failed: %v", err))
}
accounts := account.NewManager(accounts_db, chain)
assets_db := dbm.NewDB("asset", config.DBBackend, config.DBDir())
assets := asset.NewRegistry(assets_db, chain)
- bcReactor := bc.NewBlockchainReactor(store, chain, accounts, assets, fastSync)
+ bcReactor := bc.NewBlockchainReactor(store, chain, txPool, accounts, assets, fastSync)
+
bcReactor.SetLogger(logger.With("module", "blockchain"))
sw.AddReactor("BLOCKCHAIN", bcReactor)
import "io"
-const (
- subsidyReductionInterval = uint64(560640)
- baseSubsidy = uint64(624000000000)
-)
-
// BlockHeader contains the header information for a blockchain
// block. It satisfies the Entry interface.
mustWriteForHash(w, bh.TimestampMs)
mustWriteForHash(w, bh.TransactionsRoot)
mustWriteForHash(w, bh.AssetsRoot)
-}
-
-func (bh *BlockHeader) BlockSubsidy() uint64 {
- return baseSubsidy >> uint(bh.Height/subsidyReductionInterval)
+ mustWriteForHash(w, bh.Nonce)
+ mustWriteForHash(w, bh.Bits)
}
// NewBlockHeader creates a new BlockHeader and populates
// ApplyValidBlock creates an updated snapshot without validating the
// block.
func (c *Chain) ApplyValidBlock(block *legacy.Block) (*state.Snapshot, error) {
- newSnapshot := state.Copy(c.state.snapshot)
+ //TODO replace with a pre-defined init blo
+ var newSnapshot *state.Snapshot
+ if c.state.snapshot == nil {
+ newSnapshot = state.Empty()
+ } else {
+ newSnapshot = state.Copy(c.state.snapshot)
+ }
+
err := newSnapshot.ApplyBlock(legacy.MapBlock(block))
if err != nil {
return nil, err
}
+ //fmt.Printf("want %v, ger %v \n", block.BlockHeader.AssetsMerkleRoot, newSnapshot.Tree.RootHash())
if block.AssetsMerkleRoot != newSnapshot.Tree.RootHash() {
return nil, ErrBadStateRoot
}
// SaveBlock is the linearization point. Once the block is committed
// to persistent storage, the block has been applied and everything
// else can be derived from that block.
- /*err := c.store.SaveBlock(ctx, block)
+ err := c.store.SaveBlock(block)
if err != nil {
return errors.Wrap(err, "storing block")
- }*/
+ }
if block.Time().After(c.lastQueuedSnapshot.Add(saveSnapshotFrequency)) {
c.queueSnapshot(ctx, block.Height, block.Time(), snapshot)
}
- err := c.store.FinalizeBlock(ctx, block.Height)
+ err = c.store.FinalizeBlock(ctx, block.Height)
if err != nil {
return errors.Wrap(err, "finalizing block")
}
TransactionsMerkleRoot: root,
},
},
+ Transactions: []*legacy.Tx{},
}
return b, nil
}
-package blockchain
+package protocol
import (
"errors"
"sync/atomic"
"time"
- "github.com/golang/groupcache/lru"
-
"github.com/bytom/protocol/bc"
+ "github.com/bytom/protocol/bc/legacy"
+ "github.com/golang/groupcache/lru"
)
var (
)
type TxDesc struct {
- Tx *bc.Tx
+ Tx *legacy.Tx
Added time.Time
Height uint64
+ Weight uint64
Fee uint64
FeePerKB uint64
}
}
}
-func (mp *TxPool) AddTransaction(tx *bc.Tx, height uint64, fee uint64) *TxDesc {
+func (mp *TxPool) AddTransaction(tx *legacy.Tx, weight, height, fee uint64) *TxDesc {
txD := &TxDesc{
Tx: tx,
Added: time.Now(),
+ Weight: weight,
Height: height,
Fee: fee,
FeePerKB: fee * 1000 / tx.TxHeader.SerializedSize,
mp.mtx.Lock()
defer mp.mtx.Unlock()
- mp.pool[tx.ID] = txD
+ mp.pool[tx.Tx.ID] = txD
atomic.StoreInt64(&mp.lastUpdated, time.Now().Unix())
return txD
}
mp.errCache.Add(txHash, nil)
}
-func (mp *TxPool) removeTransaction(txHash *bc.Hash) {
+func (mp *TxPool) RemoveTransaction(txHash *bc.Hash) {
mp.mtx.Lock()
defer mp.mtx.Unlock()
-package blockchain
+package protocol
import (
"testing"
- "github.com/bytom/protocol/bc"
"github.com/bytom/protocol/bc/legacy"
"github.com/bytom/protocol/validation"
)
txB := mockCoinbaseTx(2000, 2324)
txC := mockCoinbaseTx(3000, 9322)
- p.AddTransaction(txA, 1000, 5000000000)
+ p.AddTransaction(txA, 1, 1000, 5000000000)
if !p.IsTransactionInPool(&txA.ID) {
t.Errorf("fail to find added txA in tx pool")
} else {
if p.IsTransactionInPool(&txB.ID) {
t.Errorf("shouldn't find txB in tx pool")
}
- p.AddTransaction(txB, 1000, 5000000000)
+ p.AddTransaction(txB, 1000, 1, 5000000000)
if !p.IsTransactionInPool(&txB.ID) {
t.Errorf("shouldn find txB in tx pool")
}
+
if p.Count() != 2 {
t.Errorf("get wrong number of tx in the pool")
}
- p.removeTransaction(&txB.ID)
+ p.RemoveTransaction(&txB.ID)
if p.IsTransactionInPool(&txB.ID) {
t.Errorf("shouldn't find txB in tx pool")
}
}
}
-func mockCoinbaseTx(serializedSize uint64, amount uint64) *bc.Tx {
- return legacy.MapTx(&legacy.TxData{
+func mockCoinbaseTx(serializedSize uint64, amount uint64) *legacy.Tx {
+ oldTx := &legacy.TxData{
SerializedSize: serializedSize,
Outputs: []*legacy.TxOutput{
legacy.NewTxOutput(*validation.BTMAssetID, amount, []byte{1}, nil),
},
- })
+ }
+
+ return &legacy.Tx{
+ TxData: *oldTx,
+ Tx: legacy.MapTx(oldTx),
+ }
}
import (
"fmt"
+ "github.com/bytom/consensus"
"github.com/bytom/errors"
"github.com/bytom/math/checked"
"github.com/bytom/protocol/bc"
gasRate = int64(1000)
maxTxSize = uint64(1024)
- maxBlockSzie = uint64(16384)
+ MaxBlockSzie = uint64(16384)
)
var BTMAssetID = &bc.AssetID{
}
}
- if b.BlockHeader.SerializedSize > maxBlockSzie {
+ if b.BlockHeader.SerializedSize > MaxBlockSzie {
return errWrongBlockSize
}
- coinbaseValue := b.BlockHeader.BlockSubsidy()
+ coinbaseValue := consensus.BlockSubsidy(b.BlockHeader.Height)
for i, tx := range b.Transactions {
if b.Version == 1 && tx.Version != 1 {
return errors.WithDetailf(errTxVersion, "block version %d, transaction version %d", b.Version, tx.Version)
+++ /dev/null
-// Copyright (c) 2013-2016 The btcsuite developers
-// Copyright (c) 2015 The Decred developers
-// Use of this source code is governed by an ISC
-// license that can be found in the LICENSE file.
-
-package chainhash
-
-import (
- "encoding/hex"
- "fmt"
-)
-
-// HashSize of array used to store hashes. See Hash.
-const HashSize = 32
-
-// MaxHashStringSize is the maximum length of a Hash hash string.
-const MaxHashStringSize = HashSize * 2
-
-// ErrHashStrSize describes an error that indicates the caller specified a hash
-// string that has too many characters.
-var ErrHashStrSize = fmt.Errorf("max hash string length is %v bytes", MaxHashStringSize)
-
-// Hash is used in several of the bitcoin messages and common structures. It
-// typically represents the double sha256 of data.
-type Hash [HashSize]byte
-
-// String returns the Hash as the hexadecimal string of the byte-reversed
-// hash.
-func (hash Hash) String() string {
- for i := 0; i < HashSize/2; i++ {
- hash[i], hash[HashSize-1-i] = hash[HashSize-1-i], hash[i]
- }
- return hex.EncodeToString(hash[:])
-}
-
-// CloneBytes returns a copy of the bytes which represent the hash as a byte
-// slice.
-//
-// NOTE: It is generally cheaper to just slice the hash directly thereby reusing
-// the same bytes rather than calling this method.
-func (hash *Hash) CloneBytes() []byte {
- newHash := make([]byte, HashSize)
- copy(newHash, hash[:])
-
- return newHash
-}
-
-// SetBytes sets the bytes which represent the hash. An error is returned if
-// the number of bytes passed in is not HashSize.
-func (hash *Hash) SetBytes(newHash []byte) error {
- nhlen := len(newHash)
- if nhlen != HashSize {
- return fmt.Errorf("invalid hash length of %v, want %v", nhlen,
- HashSize)
- }
- copy(hash[:], newHash)
-
- return nil
-}
-
-// IsEqual returns true if target is the same as hash.
-func (hash *Hash) IsEqual(target *Hash) bool {
- if hash == nil && target == nil {
- return true
- }
- if hash == nil || target == nil {
- return false
- }
- return *hash == *target
-}
-
-// NewHash returns a new Hash from a byte slice. An error is returned if
-// the number of bytes passed in is not HashSize.
-func NewHash(newHash []byte) (*Hash, error) {
- var sh Hash
- err := sh.SetBytes(newHash)
- if err != nil {
- return nil, err
- }
- return &sh, err
-}
-
-// NewHashFromStr creates a Hash from a hash string. The string should be
-// the hexadecimal string of a byte-reversed hash, but any missing characters
-// result in zero padding at the end of the Hash.
-func NewHashFromStr(hash string) (*Hash, error) {
- ret := new(Hash)
- err := Decode(ret, hash)
- if err != nil {
- return nil, err
- }
- return ret, nil
-}
-
-// Decode decodes the byte-reversed hexadecimal string encoding of a Hash to a
-// destination.
-func Decode(dst *Hash, src string) error {
- // Return error if hash string is too long.
- if len(src) > MaxHashStringSize {
- return ErrHashStrSize
- }
-
- // Hex decoder expects the hash to be a multiple of two. When not, pad
- // with a leading zero.
- var srcBytes []byte
- if len(src)%2 == 0 {
- srcBytes = []byte(src)
- } else {
- srcBytes = make([]byte, 1+len(src))
- srcBytes[0] = '0'
- copy(srcBytes[1:], src)
- }
-
- // Hex decode the source bytes to a temporary destination.
- var reversedHash Hash
- _, err := hex.Decode(reversedHash[HashSize-hex.DecodedLen(len(srcBytes)):], srcBytes)
- if err != nil {
- return err
- }
-
- // Reverse copy from the temporary hash to destination. Because the
- // temporary was zeroed, the written result will be correctly padded.
- for i, b := range reversedHash[:HashSize/2] {
- dst[i], dst[HashSize-1-i] = reversedHash[HashSize-1-i], b
- }
-
- return nil
-}
+++ /dev/null
-// Copyright (c) 2015 The Decred developers
-// Copyright (c) 2016-2017 The btcsuite developers
-// Use of this source code is governed by an ISC
-// license that can be found in the LICENSE file.
-
-package chainhash
-
-import "crypto/sha256"
-
-// HashB calculates hash(b) and returns the resulting bytes.
-func HashB(b []byte) []byte {
- hash := sha256.Sum256(b)
- return hash[:]
-}
-
-// HashH calculates hash(b) and returns the resulting bytes as a Hash.
-func HashH(b []byte) Hash {
- return Hash(sha256.Sum256(b))
-}
-
-// DoubleHashB calculates hash(hash(b)) and returns the resulting bytes.
-func DoubleHashB(b []byte) []byte {
- first := sha256.Sum256(b)
- second := sha256.Sum256(first[:])
- return second[:]
-}
-
-// DoubleHashH calculates hash(hash(b)) and returns the resulting bytes as a
-// Hash.
-func DoubleHashH(b []byte) Hash {
- first := sha256.Sum256(b)
- return Hash(sha256.Sum256(first[:]))
-}
+++ /dev/null
-package core
-
-import (
- "math/big"
- //"time"
- //"github.com/blockchain/protocol/bc"
-)
-
-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)
-)
+++ /dev/null
-package core
-
-import (
- //"errors"
- "math"
- "math/big"
- "runtime"
- //"time"
-
- //"github.com/blockchain/rpc/chainhash"
- "github.com/bytom/rpc/wire"
-)
-
-func solveBlock(header *wire.BlockHeader, targetDifficulty *big.Int) bool {
- // sbResult is used by the solver goroutines to send results.
- type sbResult struct {
- found bool
- nonce uint32
- }
-
- // solver accepts a block header and a nonce range to test. It is
- // intended to be run as a goroutine.
- quit := make(chan bool)
- results := make(chan sbResult)
- solver := func(hdr wire.BlockHeader, startNonce, stopNonce uint32) {
- // We need to modify the nonce field of the header, so make sure
- // we work with a copy of the original header.
- for i := startNonce; i >= startNonce && i <= stopNonce; i++ {
- select {
- case <-quit:
- return
- default:
- hdr.Nonce = i
- hash := hdr.BlockHash()
- if wire.HashToBig(&hash).Cmp(targetDifficulty) <= 0 {
- results <- sbResult{true, i}
- return
- }
- }
- }
- results <- sbResult{false, 0}
- }
-
- startNonce := uint32(1)
- stopNonce := uint32(math.MaxUint32)
- numCores := uint32(runtime.NumCPU())
- noncesPerCore := (stopNonce - startNonce) / numCores
- for i := uint32(0); i < numCores; i++ {
- rangeStart := startNonce + (noncesPerCore * i)
- rangeStop := startNonce + (noncesPerCore * (i + 1)) - 1
- if i == numCores-1 {
- rangeStop = stopNonce
- }
- go solver(*header, rangeStart, rangeStop)
- }
- for i := uint32(0); i < numCores; i++ {
- result := <-results
- if result.found {
- close(quit)
- header.Nonce = result.nonce
- return true
- }
- }
-
- return false
-}
-
-func checkProofOfWork(header *wire.BlockHeader, targetDifficulty *big.Int) bool {
- hash := header.BlockHash()
- if wire.HashToBig(&hash).Cmp(targetDifficulty) <= 0 {
- return true
- }
- return false
-}
+++ /dev/null
-package wire
-
-import (
- "bytes"
- "io"
- "time"
-
- "github.com/bytom/rpc/chainhash"
-)
-
-// MaxBlockHeaderPayload is the maximum number of bytes a block header can be.
-// Version 4 bytes + Timestamp 4 bytes + Bits 4 bytes + Nonce 4 bytes +
-// PrevBlock and MerkleRoot hashes.
-const MaxBlockHeaderPayload = 16 + (chainhash.HashSize * 2)
-
-type uint32Time time.Time
-
-// BlockHeader defines information about a block and is used in the bitcoin
-// block (MsgBlock) and headers (MsgHeaders) messages.
-type BlockHeader struct {
- // Version of the block. This is not the same as the protocol version.
- Version int32
-
- // Hash of the previous block in the block chain.
- PrevBlock chainhash.Hash
-
- // Merkle tree reference to hash of all transactions for the block.
- MerkleRoot chainhash.Hash
-
- // Time the block was created. This is, unfortunately, encoded as a
- // uint32 on the wire and therefore is limited to 2106.
- Timestamp time.Time
-
- // Difficulty target for the block.
- Bits uint32
-
- // Nonce used to generate the block.
- Nonce uint32
-}
-
-// blockHeaderLen is a constant that represents the number of bytes for a block
-// header.
-const blockHeaderLen = 80
-
-// BlockHash computes the block identifier hash for the given block header.
-func (h *BlockHeader) BlockHash() chainhash.Hash {
- // Encode the header and double sha256 everything prior to the number of
- // transactions. Ignore the error returns since there is no way the
- // encode could fail except being out of memory which would cause a
- // run-time panic.
- buf := bytes.NewBuffer(make([]byte, 0, MaxBlockHeaderPayload))
- _ = writeBlockHeader(buf, 0, h)
-
- return chainhash.DoubleHashH(buf.Bytes())
-}
-
-// BtcDecode decodes r using the bitcoin protocol encoding into the receiver.
-// This is part of the Message interface implementation.
-// See Deserialize for decoding block headers stored to disk, such as in a
-// database, as opposed to decoding block headers from the wire.
-func (h *BlockHeader) BtcDecode(r io.Reader, pver uint32) error {
- return readBlockHeader(r, pver, h)
-}
-
-// BtcEncode encodes the receiver to w using the bitcoin protocol encoding.
-// This is part of the Message interface implementation.
-// See Serialize for encoding block headers to be stored to disk, such as in a
-// database, as opposed to encoding block headers for the wire.
-func (h *BlockHeader) BtcEncode(w io.Writer, pver uint32) error {
- return writeBlockHeader(w, pver, h)
-}
-
-// Deserialize decodes a block header from r into the receiver using a format
-// that is suitable for long-term storage such as a database while respecting
-// the Version field.
-func (h *BlockHeader) Deserialize(r io.Reader) error {
- // At the current time, there is no difference between the wire encoding
- // at protocol version 0 and the stable long-term storage format. As
- // a result, make use of readBlockHeader.
- return readBlockHeader(r, 0, h)
-}
-
-// Serialize encodes a block header from r into the receiver using a format
-// that is suitable for long-term storage such as a database while respecting
-// the Version field.
-func (h *BlockHeader) Serialize(w io.Writer) error {
- // At the current time, there is no difference between the wire encoding
- // at protocol version 0 and the stable long-term storage format. As
- // a result, make use of writeBlockHeader.
- return writeBlockHeader(w, 0, h)
-}
-
-// NewBlockHeader returns a new BlockHeader using the provided version, previous
-// block hash, merkle root hash, difficulty bits, and nonce used to generate the
-// block with defaults for the remaining fields.
-func NewBlockHeader(version int32, prevHash, merkleRootHash *chainhash.Hash,
- bits uint32, nonce uint32) *BlockHeader {
-
- // Limit the timestamp to one second precision since the protocol
- // doesn't support better.
- return &BlockHeader{
- Version: version,
- PrevBlock: *prevHash,
- MerkleRoot: *merkleRootHash,
- Timestamp: time.Unix(time.Now().Unix(), 0),
- Bits: bits,
- Nonce: nonce,
- }
-}
-
-// readBlockHeader reads a bitcoin block header from r. See Deserialize for
-// decoding block headers stored to disk, such as in a database, as opposed to
-// decoding from the wire.
-func readBlockHeader(r io.Reader, pver uint32, bh *BlockHeader) error {
- return readElements(r, &bh.Version, &bh.PrevBlock, &bh.MerkleRoot,
- (*uint32Time)(&bh.Timestamp), &bh.Bits, &bh.Nonce)
-}
-// writeBlockHeader writes a bitcoin block header to w. See Serialize for
-// encoding block headers to be stored to disk, such as in a database, as
-// opposed to encoding for the wire.
-func writeBlockHeader(w io.Writer, pver uint32, bh *BlockHeader) error {
- sec := uint32(bh.Timestamp.Unix())
- return writeElements(w, bh.Version, &bh.PrevBlock, &bh.MerkleRoot,
- sec, bh.Bits, bh.Nonce)
-}
-
-func writeElements(w io.Writer, elements ...interface{}) error {
- /*
- for _, element := range elements {
- err := writeElement(w, element)
- if err != nil {
- return err
- }
- }
-*/
- return nil
-}
-
-func readElements(r io.Reader, elements ...interface{}) error {
-/*
- for _, element := range elements {
- err := readElement(r, element)
- if err != nil {
- return err
- }
- }
-*/
- return nil
-}
+++ /dev/null
-// Copyright (c) 2013-2017 The btcsuite developers\r
-// Use of this source code is governed by an ISC\r
-// license that can be found in the LICENSE file.\r
-\r
-package wire\r
-\r
-import (\r
- "math/big"\r
- //"time"\r
-\r
- "github.com/bytom/rpc/chainhash"\r
-\r
-)\r
-\r
-var (\r
- // bigOne is 1 represented as a big.Int. It is defined here to avoid\r
- // the overhead of creating it multiple times.\r
- bigOne = big.NewInt(1)\r
-\r
- // oneLsh256 is 1 shifted left 256 bits. It is defined here to avoid\r
- // the overhead of creating it multiple times.\r
- oneLsh256 = new(big.Int).Lsh(bigOne, 256)\r
-)\r
-\r
-// HashToBig converts a chainhash.Hash into a big.Int that can be used to\r
-// perform math comparisons.\r
-func HashToBig(hash *chainhash.Hash) *big.Int {\r
- // A Hash is in little-endian, but the big package wants the bytes in\r
- // big-endian, so reverse them.\r
- buf := *hash\r
- blen := len(buf)\r
- for i := 0; i < blen/2; i++ {\r
- buf[i], buf[blen-1-i] = buf[blen-1-i], buf[i]\r
- }\r
-\r
- return new(big.Int).SetBytes(buf[:])\r
-}\r
-/*\r
-// CompactToBig converts a compact representation of a whole number N to an\r
-// unsigned 32-bit number. The representation is similar to IEEE754 floating\r
-// point numbers.\r
-//\r
-// Like IEEE754 floating point, there are three basic components: the sign,\r
-// the exponent, and the mantissa. They are broken out as follows:\r
-//\r
-// * the most significant 8 bits represent the unsigned base 256 exponent\r
-// * bit 23 (the 24th bit) represents the sign bit\r
-// * the least significant 23 bits represent the mantissa\r
-//\r
-// -------------------------------------------------\r
-// | Exponent | Sign | Mantissa |\r
-// -------------------------------------------------\r
-// | 8 bits [31-24] | 1 bit [23] | 23 bits [22-00] |\r
-// -------------------------------------------------\r
-//\r
-// The formula to calculate N is:\r
-// N = (-1^sign) * mantissa * 256^(exponent-3)\r
-//\r
-// This compact form is only used in bitcoin to encode unsigned 256-bit numbers\r
-// which represent difficulty targets, thus there really is not a need for a\r
-// sign bit, but it is implemented here to stay consistent with bitcoind.\r
-func CompactToBig(compact uint32) *big.Int {\r
- // Extract the mantissa, sign bit, and exponent.\r
- mantissa := compact & 0x007fffff\r
- isNegative := compact&0x00800000 != 0\r
- exponent := uint(compact >> 24)\r
-\r
- // Since the base for the exponent is 256, the exponent can be treated\r
- // as the number of bytes to represent the full 256-bit number. So,\r
- // treat the exponent as the number of bytes and shift the mantissa\r
- // right or left accordingly. This is equivalent to:\r
- // N = mantissa * 256^(exponent-3)\r
- var bn *big.Int\r
- if exponent <= 3 {\r
- mantissa >>= 8 * (3 - exponent)\r
- bn = big.NewInt(int64(mantissa))\r
- } else {\r
- bn = big.NewInt(int64(mantissa))\r
- bn.Lsh(bn, 8*(exponent-3))\r
- }\r
-\r
- // Make it negative if the sign bit is set.\r
- if isNegative {\r
- bn = bn.Neg(bn)\r
- }\r
-\r
- return bn\r
-}\r
-\r
-// BigToCompact converts a whole number N to a compact representation using\r
-// an unsigned 32-bit number. The compact representation only provides 23 bits\r
-// of precision, so values larger than (2^23 - 1) only encode the most\r
-// significant digits of the number. See CompactToBig for details.\r
-func BigToCompact(n *big.Int) uint32 {\r
- // No need to do any work if it's zero.\r
- if n.Sign() == 0 {\r
- return 0\r
- }\r
-\r
- // Since the base for the exponent is 256, the exponent can be treated\r
- // as the number of bytes. So, shift the number right or left\r
- // accordingly. This is equivalent to:\r
- // mantissa = mantissa / 256^(exponent-3)\r
- var mantissa uint32\r
- exponent := uint(len(n.Bytes()))\r
- if exponent <= 3 {\r
- mantissa = uint32(n.Bits()[0])\r
- mantissa <<= 8 * (3 - exponent)\r
- } else {\r
- // Use a copy to avoid modifying the caller's original number.\r
- tn := new(big.Int).Set(n)\r
- mantissa = uint32(tn.Rsh(tn, 8*(exponent-3)).Bits()[0])\r
- }\r
-\r
- // When the mantissa already has the sign bit set, the number is too\r
- // large to fit into the available 23-bits, so divide the number by 256\r
- // and increment the exponent accordingly.\r
- if mantissa&0x00800000 != 0 {\r
- mantissa >>= 8\r
- exponent++\r
- }\r
-\r
- // Pack the exponent, sign bit, and mantissa into an unsigned 32-bit\r
- // int and return it.\r
- compact := uint32(exponent<<24) | mantissa\r
- if n.Sign() < 0 {\r
- compact |= 0x00800000\r
- }\r
- return compact\r
-}\r
-\r
-// CalcWork calculates a work value from difficulty bits. Bitcoin increases\r
-// the difficulty for generating a block by decreasing the value which the\r
-// generated hash must be less than. This difficulty target is stored in each\r
-// block header using a compact representation as described in the documentation\r
-// for CompactToBig. The main chain is selected by choosing the chain that has\r
-// the most proof of work (highest difficulty). Since a lower target difficulty\r
-// value equates to higher actual difficulty, the work value which will be\r
-// accumulated must be the inverse of the difficulty. Also, in order to avoid\r
-// potential division by zero and really small floating point numbers, the\r
-// result adds 1 to the denominator and multiplies the numerator by 2^256.\r
-func CalcWork(bits uint32) *big.Int {\r
- // Return a work value of zero if the passed difficulty bits represent\r
- // a negative number. Note this should not happen in practice with valid\r
- // blocks, but an invalid block could trigger it.\r
- difficultyNum := CompactToBig(bits)\r
- if difficultyNum.Sign() <= 0 {\r
- return big.NewInt(0)\r
- }\r
-\r
- // (1 << 256) / (difficultyNum + 1)\r
- denominator := new(big.Int).Add(difficultyNum, bigOne)\r
- return new(big.Int).Div(oneLsh256, denominator)\r
-}\r
-\r
-// calcEasiestDifficulty calculates the easiest possible difficulty that a block\r
-// can have given starting difficulty bits and a duration. It is mainly used to\r
-// verify that claimed proof of work by a block is sane as compared to a\r
-// known good checkpoint.\r
-func (b *BlockChain) calcEasiestDifficulty(bits uint32, duration time.Duration) uint32 {\r
- // Convert types used in the calculations below.\r
- durationVal := int64(duration / time.Second)\r
- adjustmentFactor := big.NewInt(b.chainParams.RetargetAdjustmentFactor)\r
-\r
- // The test network rules allow minimum difficulty blocks after more\r
- // than twice the desired amount of time needed to generate a block has\r
- // elapsed.\r
- if b.chainParams.ReduceMinDifficulty {\r
- reductionTime := int64(b.chainParams.MinDiffReductionTime /\r
- time.Second)\r
- if durationVal > reductionTime {\r
- return b.chainParams.PowLimitBits\r
- }\r
- }\r
-\r
- // Since easier difficulty equates to higher numbers, the easiest\r
- // difficulty for a given duration is the largest value possible given\r
- // the number of retargets for the duration and starting difficulty\r
- // multiplied by the max adjustment factor.\r
- newTarget := CompactToBig(bits)\r
- for durationVal > 0 && newTarget.Cmp(b.chainParams.PowLimit) < 0 {\r
- newTarget.Mul(newTarget, adjustmentFactor)\r
- durationVal -= b.maxRetargetTimespan\r
- }\r
-\r
- // Limit new value to the proof of work limit.\r
- if newTarget.Cmp(b.chainParams.PowLimit) > 0 {\r
- newTarget.Set(b.chainParams.PowLimit)\r
- }\r
-\r
- return BigToCompact(newTarget)\r
-}\r
-\r
-// findPrevTestNetDifficulty returns the difficulty of the previous block which\r
-// did not have the special testnet minimum difficulty rule applied.\r
-//\r
-// This function MUST be called with the chain state lock held (for writes).\r
-func (b *BlockChain) findPrevTestNetDifficulty(startNode *blockNode) (uint32, error) {\r
- // Search backwards through the chain for the last block without\r
- // the special rule applied.\r
- iterNode := startNode\r
- for iterNode != nil && iterNode.height%b.blocksPerRetarget != 0 &&\r
- iterNode.bits == b.chainParams.PowLimitBits {\r
-\r
- // Get the previous block node. This function is used over\r
- // simply accessing iterNode.parent directly as it will\r
- // dynamically create previous block nodes as needed. This\r
- // helps allow only the pieces of the chain that are needed\r
- // to remain in memory.\r
- var err error\r
- iterNode, err = b.index.PrevNodeFromNode(iterNode)\r
- if err != nil {\r
- log.Errorf("PrevNodeFromNode: %v", err)\r
- return 0, err\r
- }\r
- }\r
-\r
- // Return the found difficulty or the minimum difficulty if no\r
- // appropriate block was found.\r
- lastBits := b.chainParams.PowLimitBits\r
- if iterNode != nil {\r
- lastBits = iterNode.bits\r
- }\r
- return lastBits, nil\r
-}\r
-\r
-// calcNextRequiredDifficulty calculates the required difficulty for the block\r
-// after the passed previous block node based on the difficulty retarget rules.\r
-// This function differs from the exported CalcNextRequiredDifficulty in that\r
-// the exported version uses the current best chain as the previous block node\r
-// while this function accepts any block node.\r
-//\r
-// This function MUST be called with the chain state lock held (for writes).\r
-func (b *BlockChain) calcNextRequiredDifficulty(lastNode *blockNode, newBlockTime time.Time) (uint32, error) {\r
- // Genesis block.\r
- if lastNode == nil {\r
- return b.chainParams.PowLimitBits, nil\r
- }\r
-\r
- // Return the previous block's difficulty requirements if this block\r
- // is not at a difficulty retarget interval.\r
- if (lastNode.height+1)%b.blocksPerRetarget != 0 {\r
- // For networks that support it, allow special reduction of the\r
- // required difficulty once too much time has elapsed without\r
- // mining a block.\r
- if b.chainParams.ReduceMinDifficulty {\r
- // Return minimum difficulty when more than the desired\r
- // amount of time has elapsed without mining a block.\r
- reductionTime := int64(b.chainParams.MinDiffReductionTime /\r
- time.Second)\r
- allowMinTime := lastNode.timestamp + reductionTime\r
- if newBlockTime.Unix() > allowMinTime {\r
- return b.chainParams.PowLimitBits, nil\r
- }\r
-\r
- // The block was mined within the desired timeframe, so\r
- // return the difficulty for the last block which did\r
- // not have the special minimum difficulty rule applied.\r
- prevBits, err := b.findPrevTestNetDifficulty(lastNode)\r
- if err != nil {\r
- return 0, err\r
- }\r
- return prevBits, nil\r
- }\r
-\r
- // For the main network (or any unrecognized networks), simply\r
- // return the previous block's difficulty requirements.\r
- return lastNode.bits, nil\r
- }\r
-\r
- // Get the block node at the previous retarget (targetTimespan days\r
- // worth of blocks).\r
- firstNode := lastNode\r
- for i := int32(0); i < b.blocksPerRetarget-1 && firstNode != nil; i++ {\r
- // Get the previous block node. This function is used over\r
- // simply accessing firstNode.parent directly as it will\r
- // dynamically create previous block nodes as needed. This\r
- // helps allow only the pieces of the chain that are needed\r
- // to remain in memory.\r
- var err error\r
- firstNode, err = b.index.PrevNodeFromNode(firstNode)\r
- if err != nil {\r
- return 0, err\r
- }\r
- }\r
-\r
- if firstNode == nil {\r
- return 0, AssertError("unable to obtain previous retarget block")\r
- }\r
-\r
- // Limit the amount of adjustment that can occur to the previous\r
- // difficulty.\r
- actualTimespan := lastNode.timestamp - firstNode.timestamp\r
- adjustedTimespan := actualTimespan\r
- if actualTimespan < b.minRetargetTimespan {\r
- adjustedTimespan = b.minRetargetTimespan\r
- } else if actualTimespan > b.maxRetargetTimespan {\r
- adjustedTimespan = b.maxRetargetTimespan\r
- }\r
-\r
- // Calculate new target difficulty as:\r
- // currentDifficulty * (adjustedTimespan / targetTimespan)\r
- // The result uses integer division which means it will be slightly\r
- // rounded down. Bitcoind also uses integer division to calculate this\r
- // result.\r
- oldTarget := CompactToBig(lastNode.bits)\r
- newTarget := new(big.Int).Mul(oldTarget, big.NewInt(adjustedTimespan))\r
- targetTimeSpan := int64(b.chainParams.TargetTimespan / time.Second)\r
- newTarget.Div(newTarget, big.NewInt(targetTimeSpan))\r
-\r
- // Limit new value to the proof of work limit.\r
- if newTarget.Cmp(b.chainParams.PowLimit) > 0 {\r
- newTarget.Set(b.chainParams.PowLimit)\r
- }\r
-\r
- // Log new target difficulty and return it. The new target logging is\r
- // intentionally converting the bits back to a number instead of using\r
- // newTarget since conversion to the compact representation loses\r
- // precision.\r
- newTargetBits := BigToCompact(newTarget)\r
- log.Debugf("Difficulty retarget at block height %d", lastNode.height+1)\r
- log.Debugf("Old target %08x (%064x)", lastNode.bits, oldTarget)\r
- log.Debugf("New target %08x (%064x)", newTargetBits, CompactToBig(newTargetBits))\r
- log.Debugf("Actual timespan %v, adjusted timespan %v, target timespan %v",\r
- time.Duration(actualTimespan)*time.Second,\r
- time.Duration(adjustedTimespan)*time.Second,\r
- b.chainParams.TargetTimespan)\r
-\r
- return newTargetBits, nil\r
-}\r
-\r
-// CalcNextRequiredDifficulty calculates the required difficulty for the block\r
-// after the end of the current best chain based on the difficulty retarget\r
-// rules.\r
-//\r
-// This function is safe for concurrent access.\r
-func (b *BlockChain) CalcNextRequiredDifficulty(timestamp time.Time) (uint32, error) {\r
- b.chainLock.Lock()\r
- difficulty, err := b.calcNextRequiredDifficulty(b.bestNode, timestamp)\r
- b.chainLock.Unlock()\r
- return difficulty, err\r
-}\r
-*/\r