Appearance
mining模块
coinbase 交易长什么样子
这个交易的输入就一个,TxIn引用的OutPoint,hash值是0,index是0xffffffff 这个OutPoint毫无疑问是无效的.
go
// IsCoinBaseTx determines whether or not a transaction is a coinbase. A coinbase
// is a special transaction created by miners that has no inputs. This is
// represented in the block chain by a transaction with a single input that has
// a previous output transaction index set to the maximum value along with a
// zero hash.
//
// This function only differs from IsCoinBase in that it works with a raw wire
// transaction as opposed to a higher level util transaction.
func IsCoinBaseTx(msgTx *wire.MsgTx) bool {
// A coin base must only have one transaction input.
if len(msgTx.TxIn) != 1 {
return false
}
// The previous output of a coin base must have a max value index and
// a zero hash.
prevOut := &msgTx.TxIn[0].PreviousOutPoint
if prevOut.Index != math.MaxUint32 || !prevOut.Hash.IsEqual(zeroHash) {
return false
}
return true
}
// 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.
//
// See the comment for NewBlockTemplate for more information about why the nil
// address handling is useful.
func createCoinbaseTx(params *chaincfg.Params, coinbaseScript []byte, nextBlockHeight int32, addr btcutil.Address) (*btcutil.Tx, error) {
// Create the script to pay to the provided payment address if one was
// specified. Otherwise create a script that allows the coinbase to be
// redeemable by anyone.
var pkScript []byte
if addr != nil {
var err error
pkScript, err = txscript.PayToAddrScript(addr)
if err != nil {
return nil, err
}
} else {
var err error
scriptBuilder := txscript.NewScriptBuilder()
pkScript, err = scriptBuilder.AddOp(txscript.OP_TRUE).Script()
if err != nil {
return nil, err
}
}
tx := wire.NewMsgTx(wire.TxVersion)
tx.AddTxIn(&wire.TxIn{
// Coinbase transactions have no inputs, so previous outpoint is
// zero hash and max index.
PreviousOutPoint: *wire.NewOutPoint(&chainhash.Hash{},
wire.MaxPrevOutIndex),
SignatureScript: coinbaseScript,
Sequence: wire.MaxTxInSequenceNum,
})
tx.AddTxOut(&wire.TxOut{
Value: blockchain.CalcBlockSubsidy(nextBlockHeight, params),
PkScript: pkScript,
})
return btcutil.NewTx(tx), nil
}
挖矿函数
位于cpuminger.go中的solveBlock 就是暴力破解hash值
go
// 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. The timestamp is updated periodically and the passed
// block is modified with all tweaks during this process. This means that
// when the function returns true, the block is ready for submission.
//
// This function will return early with false when conditions that trigger a
// stale block such as a new block showing up or periodically when there are
// new transactions and enough time has elapsed without finding a solution.
func (m *CPUMiner) solveBlock(msgBlock *wire.MsgBlock, blockHeight int32,
ticker *time.Ticker, quit chan struct{}) bool {
// Choose a random extra nonce offset for this block template and
// worker.
enOffset, err := wire.RandomUint64()
if err != nil {
log.Errorf("Unexpected error while generating random "+
"extra nonce offset: %v", err)
enOffset = 0
}
// Create some convenience variables.
header := &msgBlock.Header
targetDifficulty := blockchain.CompactToBig(header.Bits)
// Initial state.
lastGenerated := time.Now()
lastTxUpdate := m.g.TxSource().LastUpdated()
hashesCompleted := uint64(0)
// Note that the entire extra nonce range is iterated and the offset is
// added relying on the fact that overflow will wrap around 0 as
// provided by the Go spec.
for extraNonce := uint64(0); extraNonce < maxExtraNonce; extraNonce++ {
// Update the extra nonce in the block template with the
// new value by regenerating the coinbase script and
// setting the merkle root to the new value.
m.g.UpdateExtraNonce(msgBlock, blockHeight, extraNonce+enOffset)
// Search through the entire nonce range for a solution while
// periodically checking for early quit and stale block
// conditions along with updates to the speed monitor.
for i := uint32(0); i <= maxNonce; i++ {
select {
case <-quit:
return false
case <-ticker.C:
m.updateHashes <- hashesCompleted
hashesCompleted = 0
// The current block is stale if the best block
// has changed.
best := m.g.BestSnapshot()
if !header.PrevBlock.IsEqual(&best.Hash) {
return false
}
// The current block is stale if the memory pool
// has been updated since the block template was
// generated and it has been at least one
// minute.
if lastTxUpdate != m.g.TxSource().LastUpdated() &&
time.Now().After(lastGenerated.Add(time.Minute)) {
return false
}
m.g.UpdateBlockTime(msgBlock)
default:
// Non-blocking select to fall through
}
// Update the nonce and hash the block header. Each
// hash is actually a double sha256 (two hashes), so
// increment the number of hashes completed for each
// attempt accordingly.
header.Nonce = i
hash := header.BlockHash()
hashesCompleted += 2
// The block is solved when the new block hash is less
// than the target difficulty. Yay!
if blockchain.HashToBig(&hash).Cmp(targetDifficulty) <= 0 {
m.updateHashes <- hashesCompleted
return true
}
}
}
return false
}
Transaciton的Priority
可以看到在放进block的时候,会优先选择priority高的Tx.