templates.go raw

   1  package mining
   2  
   3  //
   4  // import (
   5  // 	"container/heap"
   6  // 	"fmt"
   7  // 	blockchain "github.com/p9c/p9/pkg/chain"
   8  // 	"github.com/p9c/p9/pkg/chain/fork"
   9  // 	chainhash "github.com/p9c/p9/pkg/chain/hash"
  10  // 	txscript "github.com/p9c/p9/pkg/chain/tx/script"
  11  // 	"github.com/p9c/p9/pkg/chain/wire"
  12  // 	"github.com/p9c/p9/pkg/util"
  13  // 	"math/rand"
  14  // 	"time"
  15  // )
  16  //
  17  // // GenBlockHeader generate a block given a version number to use for mining
  18  // // (nonce is empty, date can be updated, version changes merkle and target bits.
  19  // // All the data required for this is in the exported fields that are serialized
  20  // // for over the wire
  21  // func (m *MsgBlockTemplate) GenBlockHeader(vers int32) *wire.BlockHeader {
  22  // 	return &wire.BlockHeader{
  23  // 		Version:    vers,
  24  // 		PrevBlock:  m.PrevBlock,
  25  // 		MerkleRoot: m.Merkles[vers],
  26  // 		Timestamp:  m.Timestamp,
  27  // 		Bits:       m.Bits[vers],
  28  // 	}
  29  // }
  30  //
  31  // // Reconstruct takes a received block from the wire and reattaches the transactions
  32  // func (m *MsgBlockTemplate) Reconstruct(hdr *wire.BlockHeader) *wire.WireBlock {
  33  // 	msgBlock := &wire.WireBlock{Header: *hdr}
  34  // 	// the coinbase is the last transaction
  35  // 	txs := append(m.txs, m.coinbases[msgBlock.Header.Version])
  36  // 	for _, tx := range txs {
  37  // 		if e := msgBlock.AddTransaction(tx.MsgTx()); E.Chk(e) {
  38  // 			return nil
  39  // 		}
  40  // 	}
  41  // 	return msgBlock
  42  // }
  43  //
  44  // // NewBlockTemplates returns a data structure which has methods to construct
  45  // // block version specific block headers and reconstruct their transactions
  46  // func (g *BlkTmplGenerator) NewBlockTemplates(
  47  // 	workerNumber uint32,
  48  // 	payToAddress util.Address,
  49  // ) (*MsgBlockTemplate, error) {
  50  // 	mbt := &MsgBlockTemplate{Bits: make(map[int32]uint32), Merkles: make(map[int32]chainhash.Hash)}
  51  // 	// Extend the most recently known best block.
  52  // 	best := g.Chain.BestSnapshot()
  53  // 	mbt.PrevBlock = best.Hash
  54  // 	mbt.Timestamp = g.Chain.BestChain.Tip().Header().Timestamp.Add(time.Second)
  55  // 	mbt.Height = best.Height + 1
  56  // 	// Create a standard coinbase transaction paying to the provided address.
  57  // 	//
  58  // 	// NOTE: The coinbase value will be updated to include the fees from the
  59  // 	// selected transactions later after they have actually been selected. It is
  60  // 	// created here to detect any errors early before potentially doing a lot of
  61  // 	// work below. The extra nonce helps ensure the transaction is not a duplicate
  62  // 	// transaction (paying the same value to the same public key address would
  63  // 	// otherwise be an identical transaction for block version 1).
  64  // 	rand.Seed(time.Now().UnixNano())
  65  // 	extraNonce := rand.Uint64()
  66  // 	var e error
  67  // 	// numAlgos := fork.GetNumAlgos(mbt.Height)
  68  // 	// coinbaseScripts := make(map[int32][]byte, numAlgos)
  69  // 	// coinbaseTxs := make(map[int32]*util.Tx, numAlgos)
  70  // 	var coinbaseSigOpCost int64
  71  // 	// blockTemplates := make(map[int32]*BlockTemplate, numAlgos)
  72  // 	var priorityQueues *txPriorityQueue
  73  // 	// Get the current source transactions and create a priority queue to hold the
  74  // 	// transactions which are ready for inclusion into a block along with some
  75  // 	// priority related and fee metadata. Reserve the same number of items that are
  76  // 	// available for the priority queue. Also, choose the initial txsort order for the
  77  // 	// priority queue based on whether or not there is an area allocated for
  78  // 	// high-priority transactions.
  79  // 	sourceTxns := g.TxSource.MiningDescs()
  80  // 	sortedByFee := g.Policy.BlockPrioritySize == 0
  81  // 	blockUtxos := blockchain.NewUtxoViewpoint()
  82  // 	// dependers is used to track transactions which depend on another transaction
  83  // 	// in the source pool. This, in conjunction with the dependsOn map kept with
  84  // 	// each dependent transaction helps quickly determine which dependent
  85  // 	// transactions are now eligible for inclusion in the block once each
  86  // 	// transaction has been included.
  87  // 	dependers := make(map[chainhash.Hash]map[chainhash.Hash]*txPrioItem)
  88  // mempoolLoop:
  89  // 	for _, txDesc := range sourceTxns {
  90  // 		// A block can't have more than one coinbase or contain non-finalized
  91  // 		// transactions.
  92  // 		tx := txDesc.Tx
  93  // 		if blockchain.IsCoinBase(tx) {
  94  // 			Tracec(
  95  // 				func() string {
  96  // 					return fmt.Sprintf("skipping coinbase tx %s", tx.Hash())
  97  // 				},
  98  // 			)
  99  // 			continue
 100  // 		}
 101  // 		if !blockchain.IsFinalizedTransaction(
 102  // 			tx, mbt.Height,
 103  // 			g.TimeSource.AdjustedTime(),
 104  // 		) {
 105  // 			Tracec(
 106  // 				func() string {
 107  // 					return "skipping non-finalized tx " + tx.Hash().String()
 108  // 				},
 109  // 			)
 110  // 			continue
 111  // 		}
 112  // 		// Fetch all of the utxos referenced by the this transaction.
 113  // 		//
 114  // 		// NOTE: This intentionally does not fetch inputs from the mempool since a
 115  // 		// transaction which depends on other transactions in the mempool must come
 116  // 		// after those dependencies in the final generated block.
 117  // 		utxos, e := g.Chain.FetchUtxoView(tx)
 118  // 		if e != nil  {
 119  // 			Warnc(
 120  // 				func() string {
 121  // 					return "unable to fetch utxo view for tx " + tx.Hash().String() + ": " + err.Error()
 122  // 				},
 123  // 			)
 124  // 			continue
 125  // 		}
 126  // 		// Setup dependencies for any transactions which reference other transactions in
 127  // 		// the mempool so they can be properly ordered below.
 128  // 		prioItem := &txPrioItem{tx: tx}
 129  // 		for _, txIn := range tx.MsgTx().TxIn {
 130  // 			originHash := &txIn.PreviousOutPoint.Hash
 131  // 			entry := utxos.LookupEntry(txIn.PreviousOutPoint)
 132  // 			if entry == nil || entry.IsSpent() {
 133  // 				if !g.TxSource.HaveTransaction(originHash) {
 134  // 					Tracec(
 135  // 						func() string {
 136  // 							return "skipping tx %s because it references unspent output %s which is not available" +
 137  // 								tx.Hash().String() +
 138  // 								txIn.PreviousOutPoint.String()
 139  // 						},
 140  // 					)
 141  // 					continue mempoolLoop
 142  // 				}
 143  // 				// The transaction is referencing another transaction in the source pool, so
 144  // 				// setup an ordering dependency.
 145  // 				deps, exists := dependers[*originHash]
 146  // 				if !exists {
 147  // 					deps = make(map[chainhash.Hash]*txPrioItem)
 148  // 					dependers[*originHash] = deps
 149  // 				}
 150  // 				deps[*prioItem.tx.Hash()] = prioItem
 151  // 				if prioItem.dependsOn == nil {
 152  // 					prioItem.dependsOn = make(
 153  // 						map[chainhash.Hash]struct{},
 154  // 					)
 155  // 				}
 156  // 				prioItem.dependsOn[*originHash] = struct{}{}
 157  // 				// Skip the check below. We already know the referenced transaction is
 158  // 				// available.
 159  // 				continue
 160  // 			}
 161  // 		}
 162  // 		// Calculate the final transaction priority using the input value age sum as
 163  // 		// well as the adjusted transaction size. The formula is: sum (inputValue *
 164  // 		// inputAge) / adjustedTxSize
 165  // 		prioItem.priority = CalcPriority(
 166  // 			tx.MsgTx(), utxos,
 167  // 			mbt.Height,
 168  // 		)
 169  // 		// Calculate the fee in Satoshi/kB.
 170  // 		prioItem.feePerKB = txDesc.FeePerKB
 171  // 		prioItem.fee = txDesc.Fee
 172  // 		// Add the transaction to the priority queue to mark it ready for inclusion in
 173  // 		// the block unless it has dependencies.
 174  // 		if prioItem.dependsOn == nil {
 175  // 			heap.Push(priorityQueues, prioItem)
 176  // 		}
 177  // 		// Merge the referenced outputs from the input transactions to this transaction
 178  // 		// into the block utxo view. This allows the code below to avoid a second
 179  // 		// lookup.
 180  // 		mergeUtxoView(blockUtxos, utxos)
 181  // 	}
 182  // 	priorityQueues = newTxPriorityQueue(len(sourceTxns), sortedByFee)
 183  // 	var coinbaseScript []byte
 184  // 	if coinbaseScript, e = standardCoinbaseScript(mbt.Height, extraNonce); E.Chk(e) {
 185  // 		return nil, e
 186  // 	}
 187  // 	algos := fork.GetAlgos(mbt.Height)
 188  // 	var alg int32
 189  // 	mbt.coinbases = make(map[int32]*util.Tx)
 190  // 	// Create a slice to hold the transactions to be included in the generated block
 191  // 	var coinbaseTx *util.Tx
 192  // 	for i := range algos {
 193  // 		alg = algos[i].Version
 194  // 		if coinbaseTx, e = createCoinbaseTx(
 195  // 			g.ChainParams, coinbaseScript, mbt.Height, payToAddress, alg,
 196  // 		); E.Chk(e) {
 197  // 			return nil, e
 198  // 		}
 199  // 		mbt.coinbases[alg] = coinbaseTx
 200  // 		// this should be the same for all anyhow, as they are all the same format just
 201  // 		// diff amounts (note: this might be wrawwnnggrrr)
 202  // 		coinbaseSigOpCost = int64(blockchain.CountSigOps(mbt.coinbases[alg]))
 203  // 	}
 204  // 	// Create slices to hold the fees and number of signature operations for each of
 205  // 	// the selected transactions and add an entry for the coinbase. This allows the
 206  // 	// code below to simply append details about a transaction as it is selected for
 207  // 	// inclusion in the final block. However, since the total fees aren't known yet,
 208  // 	// use a dummy value for the coinbase fee which will be updated later.
 209  // 	txFees := make([]int64, 0, len(sourceTxns))
 210  // 	txSigOpCosts := make([]int64, 0, len(sourceTxns))
 211  // 	txFees = append(txFees, -1) // Updated once known
 212  // 	txSigOpCosts = append(txSigOpCosts, coinbaseSigOpCost)
 213  // 	Tracef("considering %d transactions for inclusion to new block", len(sourceTxns))
 214  // 	// The starting block size is the size of the block header plus the max possible
 215  // 	// transaction count size, plus the size of the coinbase transaction.
 216  // 	// with reserved space. Also create a utxo view to house all of the input
 217  // 	// transactions so multiple lookups can be avoided.
 218  // 	blockWeight := uint32((blockHeaderOverhead) + blockchain.GetTransactionWeight(coinbaseTx))
 219  // 	blockSigOpCost := coinbaseSigOpCost
 220  // 	totalFees := int64(0)
 221  // 	mbt.txs = make([]*util.Tx, 0, len(sourceTxns))
 222  // 	// Choose which transactions make it into the block.
 223  // 	for priorityQueues.Len() > 0 {
 224  // 		// Grab the highest priority (or highest fee per kilobyte depending on the txsort
 225  // 		// order) transaction.
 226  // 		prioItem := heap.Pop(priorityQueues).(*txPrioItem)
 227  // 		tx := prioItem.tx
 228  // 		// Grab any transactions which depend on this one.
 229  // 		deps := dependers[*tx.Hash()]
 230  // 		// Enforce maximum block size.  Also check for overflow.
 231  // 		txWeight := uint32(blockchain.GetTransactionWeight(tx))
 232  // 		blockPlusTxWeight := blockWeight + txWeight
 233  // 		if blockPlusTxWeight < blockWeight ||
 234  // 			blockPlusTxWeight >= g.Policy.BlockMaxWeight {
 235  // 			Tracef("skipping tx %s because it would exceed the max block weight", tx.Hash())
 236  // 			logSkippedDeps(tx, deps)
 237  // 			continue
 238  // 		}
 239  // 		// Enforce maximum signature operation cost per block. Also check for overflow.
 240  // 		sigOpCost, e := blockchain.GetSigOpCost(tx, false, blockUtxos, true, false)
 241  // 		if e != nil  {
 242  // 			Tracec(
 243  // 				func() string {
 244  // 					return "skipping tx " + tx.Hash().String() +
 245  // 						"due to error in GetSigOpCost: " + err.Error()
 246  // 				},
 247  // 			)
 248  // 			logSkippedDeps(tx, deps)
 249  // 			continue
 250  // 		}
 251  // 		if blockSigOpCost+int64(sigOpCost) < blockSigOpCost ||
 252  // 			blockSigOpCost+int64(sigOpCost) > blockchain.MaxBlockSigOpsCost {
 253  // 			Tracec(
 254  // 				func() string {
 255  // 					return "skipping tx " + tx.Hash().String() +
 256  // 						" because it would exceed the maximum sigops per block"
 257  // 				},
 258  // 			)
 259  // 			logSkippedDeps(tx, deps)
 260  // 			continue
 261  // 		}
 262  // 		// Skip free transactions once the block is larger than the minimum block size.
 263  // 		if sortedByFee &&
 264  // 			prioItem.feePerKB < int64(g.Policy.TxMinFreeFee) &&
 265  // 			blockPlusTxWeight >= g.Policy.BlockMinWeight {
 266  // 			Tracec(
 267  // 				func() string {
 268  // 					return fmt.Sprintf(
 269  // 						"skipping tx %v with feePerKB %v < TxMinFreeFee %v and block weight %v >= minBlockWeight %v",
 270  // 						tx.Hash(),
 271  // 						prioItem.feePerKB,
 272  // 						g.Policy.TxMinFreeFee,
 273  // 						blockPlusTxWeight,
 274  // 						g.Policy.BlockMinWeight,
 275  // 					)
 276  // 				},
 277  // 			)
 278  // 			logSkippedDeps(tx, deps)
 279  // 			continue
 280  // 		}
 281  // 		// Prioritize by fee per kilobyte once the block is larger than the priority
 282  // 		// size or there are no more high-priority transactions.
 283  // 		if !sortedByFee && (blockPlusTxWeight >= g.Policy.BlockPrioritySize ||
 284  // 			prioItem.priority <= MinHighPriority.ToDUO()) {
 285  // 			Tracef(
 286  // 				"switching to txsort by fees per kilobyte blockSize %d"+
 287  // 					" >= BlockPrioritySize %d || priority %.2f <= minHighPriority %.2f",
 288  // 				blockPlusTxWeight,
 289  // 				g.Policy.BlockPrioritySize,
 290  // 				prioItem.priority,
 291  // 				MinHighPriority,
 292  // 			)
 293  // 			sortedByFee = true
 294  // 			priorityQueues.SetLessFunc(txPQByFee)
 295  // 		}
 296  // 		// Put the transaction back into the priority queue and skip it so it is
 297  // 		// re-prioritized by fees if it won't fit into the high-priority section or the
 298  // 		// priority is too low. Otherwise this transaction will be the final one in the
 299  // 		// high-priority section, so just fall though to the code below so it is added
 300  // 		// now.
 301  // 		if blockPlusTxWeight > g.Policy.BlockPrioritySize ||
 302  // 			prioItem.priority < MinHighPriority.ToDUO() {
 303  // 			heap.Push(priorityQueues, prioItem)
 304  // 			continue
 305  // 		}
 306  //
 307  // 		// Ensure the transaction inputs pass all of the necessary preconditions before
 308  // 		// allowing it to be added to the block.
 309  // 		_, e = blockchain.CheckTransactionInputs(
 310  // 			tx, mbt.Height,
 311  // 			blockUtxos, g.ChainParams,
 312  // 		)
 313  // 		if e != nil  {
 314  // 			Tracef(
 315  // 				"skipping tx %s due to error in CheckTransactionInputs: %v",
 316  // 				tx.Hash(), e,
 317  // 			)
 318  // 			logSkippedDeps(tx, deps)
 319  // 			continue
 320  // 		}
 321  // 		if e = blockchain.ValidateTransactionScripts(
 322  // 			g.Chain, tx, blockUtxos,
 323  // 			txscript.StandardVerifyFlags, g.SigCache,
 324  // 			g.HashCache,
 325  // 		); E.Chk(e) {
 326  // 			Tracef(
 327  // 				"skipping tx %s due to error in ValidateTransactionScripts: %v",
 328  // 				tx.Hash(), e,
 329  // 			)
 330  // 			logSkippedDeps(tx, deps)
 331  // 			continue
 332  // 		}
 333  // 		// Spend the transaction inputs in the block utxo view and add an entry for it
 334  // 		// to ensure any transactions which reference this one have it available as an
 335  // 		// input and can ensure they aren't double spending.
 336  // 		if e = spendTransaction(blockUtxos, tx, mbt.Height); E.Chk(e) {
 337  // 		}
 338  // 		// Add the transaction to the block, increment counters, and save the fees and
 339  // 		// signature operation counts to the block template.
 340  // 		mbt.txs = append(mbt.txs, tx)
 341  // 		blockWeight += txWeight
 342  // 		blockSigOpCost += int64(sigOpCost)
 343  // 		totalFees += prioItem.fee
 344  // 		txFees = append(txFees, prioItem.fee)
 345  // 		txSigOpCosts = append(txSigOpCosts, int64(sigOpCost))
 346  // 		Tracef(
 347  // 			"adding tx %s (priority %.2f, feePerKB %.2f)",
 348  // 			prioItem.tx.Hash(),
 349  // 			prioItem.priority,
 350  // 			prioItem.feePerKB,
 351  // 		)
 352  // 		// Add transactions which depend on this one (and also do not have any other
 353  // 		// unsatisfied dependencies) to the priority queue.
 354  // 		for _, item := range deps {
 355  // 			// Add the transaction to the priority queue if there are no more dependencies
 356  // 			// after this one.
 357  // 			delete(item.dependsOn, *tx.Hash())
 358  // 			if len(item.dependsOn) == 0 {
 359  // 				heap.Push(priorityQueues, item)
 360  // 			}
 361  // 		}
 362  // 	}
 363  // 	if fork.GetCurrent(mbt.Height) < 1 {
 364  // 		// for legacy chain this is the consensus timestamp to use, post hard fork there
 365  // 		// is no allowance for less than 1 second between block timestamps of
 366  // 		// sequential, linked blocks, which was filled earlier by default
 367  // 		mbt.Timestamp = medianAdjustedTime(best, g.TimeSource)
 368  // 	}
 369  //
 370  // 	for next, curr, more := fork.AlgoVerIterator(mbt.Height); more(); next() {
 371  // 		tX := append(mbt.txs, mbt.coinbases[curr()])
 372  // 		// Now that the actual transactions have been selected, update the block weight
 373  // 		// for the real transaction count and coinbase value with the total fees
 374  // 		// accordingly.
 375  // 		blockWeight -= wire.MaxVarIntPayload -
 376  // 			(uint32(wire.VarIntSerializeSize(uint64(len(mbt.txs)))))
 377  // 		mbt.coinbases[curr()].MsgTx().TxOut[0].Value += totalFees
 378  // 		txFees[0] = -totalFees
 379  // 		// Calculate the required difficulty for the block. The timestamp is potentially
 380  // 		// adjusted to ensure it comes after the median time of the last several blocks
 381  // 		// per the chain consensus rules.
 382  // 		algo := fork.GetAlgoName(mbt.Height, curr())
 383  // 		D.Ln("algo", algo)
 384  // 		if mbt.Bits[curr()], e = g.Chain.CalcNextRequiredDifficulty(algo); E.Chk(e) {
 385  // 			return nil, e
 386  // 		}
 387  // 		D.F(
 388  // 			"%s %d reqDifficulty %08x %064x", algo, curr(),
 389  // 			mbt.Bits[curr()], fork.CompactToBig(mbt.Bits[curr()]),
 390  // 		)
 391  // 		// Create a new block ready to be solved.
 392  // 		D.S(tX)
 393  //
 394  // 		merkles := blockchain.BuildMerkleTreeStore(tX, false)
 395  // 		mbt.Merkles[curr()] = *merkles[len(merkles)-1]
 396  // 		// TODO: can we do this once instead of 9 times?
 397  // 		var msgBlock wire.WireBlock
 398  // 		msgBlock.Header = wire.BlockHeader{
 399  // 			Version:    curr(),
 400  // 			PrevBlock:  mbt.PrevBlock,
 401  // 			MerkleRoot: mbt.Merkles[curr()],
 402  // 			Timestamp:  mbt.Timestamp,
 403  // 			Bits:       mbt.Bits[curr()],
 404  // 		}
 405  // 		for _, tx := range tX {
 406  // 			if e := msgBlock.AddTransaction(tx.MsgTx()); E.Chk(e) {
 407  // 				return nil, e
 408  // 			}
 409  // 		}
 410  // 		// Finally, perform a full check on the created block against the chain
 411  // 		// consensus rules to ensure it properly connects to the current best chain with
 412  // 		// no issues.
 413  // 		block := util.NewBlock(&msgBlock)
 414  // 		block.SetHeight(mbt.Height)
 415  // 		e = g.Chain.CheckConnectBlockTemplate(workerNumber, block)
 416  // 		if e != nil  {
 417  // 			D.Ln("checkconnectblocktemplate err:", e)
 418  // 			return nil, e
 419  // 		}
 420  // 		Tracec(
 421  // 			func() string {
 422  // 				bh := msgBlock.Header.BlockHash()
 423  // 				return fmt.Sprintf(
 424  // 					"created new block template (algo %s, %d transactions, "+
 425  // 						"%d in fees, %d signature operations cost, %d weight, "+
 426  // 						"target difficulty %064x prevblockhash %064x %064x subsidy %d)",
 427  // 					algo,
 428  // 					len(msgBlock.Transactions),
 429  // 					totalFees,
 430  // 					blockSigOpCost,
 431  // 					blockWeight,
 432  // 					fork.CompactToBig(msgBlock.Header.Bits),
 433  // 					msgBlock.Header.PrevBlock.CloneBytes(),
 434  // 					bh.CloneBytes(),
 435  // 					msgBlock.Transactions[0].TxOut[0].Value,
 436  // 				)
 437  // 			},
 438  // 		)
 439  // 		// // Tracec(func() string { return spew.Sdump(msgBlock) })
 440  // 		// blockTemplate := &BlockTemplate{
 441  // 		// 	Block:           &msgBlock,
 442  // 		// 	Fees:            txFees,
 443  // 		// 	SigOpCosts:      txSigOpCosts,
 444  // 		// 	Height:          mbt.Height,
 445  // 		// 	ValidPayAddress: payToAddress != nil,
 446  // 		// }
 447  // 		// blockTemplates[curr()] = blockTemplate
 448  // 	}
 449  // 	return mbt, nil
 450  // }
 451