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