forked from gcash/bchd
-
Notifications
You must be signed in to change notification settings - Fork 0
/
mining.go
888 lines (784 loc) · 33.1 KB
/
mining.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
738
739
740
741
742
743
744
745
746
747
748
749
750
751
752
753
754
755
756
757
758
759
760
761
762
763
764
765
766
767
768
769
770
771
772
773
774
775
776
777
778
779
780
781
782
783
784
785
786
787
788
789
790
791
792
793
794
795
796
797
798
799
800
801
802
803
804
805
806
807
808
809
810
811
812
813
814
815
816
817
818
819
820
821
822
823
824
825
826
827
828
829
830
831
832
833
834
835
836
837
838
839
840
841
842
843
844
845
846
847
848
849
850
851
852
853
854
855
856
857
858
859
860
861
862
863
864
865
866
867
868
869
870
871
872
873
874
875
876
877
878
879
880
881
882
883
884
885
886
887
888
// 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 (
"container/heap"
"fmt"
"time"
"github.com/gcash/bchd/blockchain"
"github.com/gcash/bchd/chaincfg"
"github.com/gcash/bchd/chaincfg/chainhash"
"github.com/gcash/bchd/txscript"
"github.com/gcash/bchd/wire"
"github.com/gcash/bchutil"
"sort"
)
const (
// MinHighPriority is the minimum priority value that allows a
// transaction to be considered high priority.
MinHighPriority = bchutil.SatoshiPerBitcoin * 144.0 / 250
// blockHeaderOverhead is the max number of bytes it takes to serialize
// a block header and max possible transaction count.
blockHeaderOverhead = wire.MaxBlockHeaderPayload + wire.MaxVarIntPayload
// CoinbaseFlags is added to the coinbase script of a generated block
// and is used to monitor BIP16 support as well as blocks that are
// generated via bchd.
CoinbaseFlags = "/bchd/"
)
// TxDesc is a descriptor about a transaction in a transaction source along with
// additional metadata.
type TxDesc struct {
// Tx is the transaction associated with the entry.
Tx *bchutil.Tx
// Added is the time when the entry was added to the source pool.
Added time.Time
// Height is the block height when the entry was added to the the source
// pool.
Height int32
// Fee is the total fee the transaction associated with the entry pays.
Fee int64
// FeePerKB is the fee the transaction pays in Satoshi per 1000 bytes.
FeePerKB int64
}
// TxSource represents a source of transactions to consider for inclusion in
// new blocks.
//
// The interface contract requires that all of these methods are safe for
// concurrent access with respect to the source.
type TxSource interface {
// LastUpdated returns the last time a transaction was added to or
// removed from the source pool.
LastUpdated() time.Time
// MiningDescs returns a slice of mining descriptors for all the
// transactions in the source pool.
MiningDescs() []*TxDesc
// HaveTransaction returns whether or not the passed transaction hash
// exists in the source pool.
HaveTransaction(hash *chainhash.Hash) bool
}
// txPrioItem houses a transaction along with extra information that allows the
// transaction to be prioritized and track dependencies on other transactions
// which have not been mined into a block yet.
type txPrioItem struct {
tx *bchutil.Tx
fee int64
priority float64
feePerKB int64
// dependsOn holds a map of transaction hashes which this one depends
// on. It will only be set when the transaction references other
// transactions in the source pool and hence must come after them in
// a block.
dependsOn map[chainhash.Hash]struct{}
}
// txPriorityQueueLessFunc describes a function that can be used as a compare
// function for a transaction priority queue (txPriorityQueue).
type txPriorityQueueLessFunc func(*txPriorityQueue, int, int) bool
// txPriorityQueue implements a priority queue of txPrioItem elements that
// supports an arbitrary compare function as defined by txPriorityQueueLessFunc.
type txPriorityQueue struct {
lessFunc txPriorityQueueLessFunc
items []*txPrioItem
}
// Len returns the number of items in the priority queue. It is part of the
// heap.Interface implementation.
func (pq *txPriorityQueue) Len() int {
return len(pq.items)
}
// Less returns whether the item in the priority queue with index i should sort
// before the item with index j by deferring to the assigned less function. It
// is part of the heap.Interface implementation.
func (pq *txPriorityQueue) Less(i, j int) bool {
return pq.lessFunc(pq, i, j)
}
// Swap swaps the items at the passed indices in the priority queue. It is
// part of the heap.Interface implementation.
func (pq *txPriorityQueue) Swap(i, j int) {
pq.items[i], pq.items[j] = pq.items[j], pq.items[i]
}
// Push pushes the passed item onto the priority queue. It is part of the
// heap.Interface implementation.
func (pq *txPriorityQueue) Push(x interface{}) {
pq.items = append(pq.items, x.(*txPrioItem))
}
// Pop removes the highest priority item (according to Less) from the priority
// queue and returns it. It is part of the heap.Interface implementation.
func (pq *txPriorityQueue) Pop() interface{} {
n := len(pq.items)
item := pq.items[n-1]
pq.items[n-1] = nil
pq.items = pq.items[0 : n-1]
return item
}
// SetLessFunc sets the compare function for the priority queue to the provided
// function. It also invokes heap.Init on the priority queue using the new
// function so it can immediately be used with heap.Push/Pop.
func (pq *txPriorityQueue) SetLessFunc(lessFunc txPriorityQueueLessFunc) {
pq.lessFunc = lessFunc
heap.Init(pq)
}
// txPQByPriority sorts a txPriorityQueue by transaction priority and then fees
// per kilobyte.
func txPQByPriority(pq *txPriorityQueue, i, j int) bool {
// Using > here so that pop gives the highest priority item as opposed
// to the lowest. Sort by priority first, then fee.
if pq.items[i].priority == pq.items[j].priority {
return pq.items[i].feePerKB > pq.items[j].feePerKB
}
return pq.items[i].priority > pq.items[j].priority
}
// txPQByFee sorts a txPriorityQueue by fees per kilobyte and then transaction
// priority.
func txPQByFee(pq *txPriorityQueue, i, j int) bool {
// Using > here so that pop gives the highest fee item as opposed
// to the lowest. Sort by fee first, then priority.
if pq.items[i].feePerKB == pq.items[j].feePerKB {
return pq.items[i].priority > pq.items[j].priority
}
return pq.items[i].feePerKB > pq.items[j].feePerKB
}
// newTxPriorityQueue returns a new transaction priority queue that reserves the
// passed amount of space for the elements. The new priority queue uses either
// the txPQByPriority or the txPQByFee compare function depending on the
// sortByFee parameter and is already initialized for use with heap.Push/Pop.
// The priority queue can grow larger than the reserved space, but extra copies
// of the underlying array can be avoided by reserving a sane value.
func newTxPriorityQueue(reserve int, sortByFee bool) *txPriorityQueue {
pq := &txPriorityQueue{
items: make([]*txPrioItem, 0, reserve),
}
if sortByFee {
pq.SetLessFunc(txPQByFee)
} else {
pq.SetLessFunc(txPQByPriority)
}
return pq
}
// BlockTemplate houses a block that has yet to be solved along with additional
// details about the fees and the number of signature operations for each
// transaction in the block.
type BlockTemplate struct {
// Block is a block that is ready to be solved by miners. Thus, it is
// completely valid with the exception of satisfying the proof-of-work
// requirement.
Block *wire.MsgBlock
// Fees contains the amount of fees each transaction in the generated
// template pays in base units. Since the first transaction is the
// coinbase, the first entry (offset 0) will contain the negative of the
// sum of the fees of all other transactions.
Fees []int64
// SigOpCosts contains the number of signature operations each
// transaction in the generated template performs.
SigOpCosts []int64
// Height is the height at which the block template connects to the main
// chain.
Height int32
// ValidPayAddress indicates whether or not the template coinbase pays
// to an address or is redeemable by anyone. See the documentation on
// NewBlockTemplate for details on which this can be useful to generate
// templates without a coinbase payment address.
ValidPayAddress bool
// MaxBlockSize is the block size consensus rule used when creating the block
MaxBlockSize uint32
// MaxSigOps is the block size consensus rule used when creating the block
MaxSigOps uint32
}
// mergeUtxoView adds all of the entries in viewB to viewA. The result is that
// viewA will contain all of its original entries plus all of the entries
// in viewB. It will replace any entries in viewB which also exist in viewA
// if the entry in viewA is spent.
func mergeUtxoView(viewA *blockchain.UtxoViewpoint, viewB *blockchain.UtxoViewpoint) {
viewAEntries := viewA.Entries()
for outpoint, entryB := range viewB.Entries() {
if entryA, exists := viewAEntries[outpoint]; !exists ||
entryA == nil || entryA.IsSpent() {
viewAEntries[outpoint] = entryB
}
}
}
// standardCoinbaseScript returns a standard script suitable for use as the
// signature script of the coinbase transaction of a new block. In particular,
// it starts with the block height that is required by version 2 blocks and adds
// the extra nonce as well as additional coinbase flags.
func standardCoinbaseScript(nextBlockHeight int32, extraNonce uint64) ([]byte, error) {
return txscript.NewScriptBuilder().AddInt64(int64(nextBlockHeight)).
AddInt64(int64(extraNonce)).AddData([]byte(CoinbaseFlags)).
Script()
}
// 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 bchutil.Address) (*bchutil.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,
})
// Make sure the coinbase is above the minimum size threshold.
if tx.SerializeSize() < blockchain.MinTransactionSize {
tx.TxIn[0].SignatureScript = append(tx.TxIn[0].SignatureScript,
make([]byte, blockchain.MinTransactionSize-tx.SerializeSize()-1)...)
}
return bchutil.NewTx(tx), nil
}
// spendTransaction updates the passed view by marking the inputs to the passed
// transaction as spent. It also adds all outputs in the passed transaction
// which are not provably unspendable as available unspent transaction outputs.
func spendTransaction(utxoView *blockchain.UtxoViewpoint, tx *bchutil.Tx, height int32) error {
for _, txIn := range tx.MsgTx().TxIn {
entry := utxoView.LookupEntry(txIn.PreviousOutPoint)
if entry != nil {
entry.Spend()
}
}
utxoView.AddTxOuts(tx, height)
return nil
}
// logSkippedDeps logs any dependencies which are also skipped as a result of
// skipping a transaction while generating a block template at the trace level.
func logSkippedDeps(tx *bchutil.Tx, deps map[chainhash.Hash]*txPrioItem) {
if deps == nil {
return
}
for _, item := range deps {
log.Tracef("Skipping tx %s since it depends on %s\n",
item.tx.Hash(), tx.Hash())
}
}
// MinimumMedianTime returns the minimum allowed timestamp for a block building
// on the end of the provided best chain. In particular, it is one second after
// the median timestamp of the last several blocks per the chain consensus
// rules.
func MinimumMedianTime(chainState *blockchain.BestState) time.Time {
return chainState.MedianTime.Add(time.Second)
}
// medianAdjustedTime returns the current time adjusted to ensure it is at least
// one second after the median timestamp of the last several blocks per the
// chain consensus rules.
func medianAdjustedTime(chainState *blockchain.BestState, timeSource blockchain.MedianTimeSource) time.Time {
// The timestamp for the block must not be before the median timestamp
// of the last several blocks. Thus, choose the maximum between the
// current time and one second after the past median time. The current
// timestamp is truncated to a second boundary before comparison since a
// block timestamp does not supported a precision greater than one
// second.
newTimestamp := timeSource.AdjustedTime()
minTimestamp := MinimumMedianTime(chainState)
if newTimestamp.Before(minTimestamp) {
newTimestamp = minTimestamp
}
return newTimestamp
}
// BlkTmplGenerator provides a type that can be used to generate block templates
// based on a given mining policy and source of transactions to choose from.
// It also houses additional state required in order to ensure the templates
// are built on top of the current best chain and adhere to the consensus rules.
type BlkTmplGenerator struct {
policy *Policy
chainParams *chaincfg.Params
txSource TxSource
chain *blockchain.BlockChain
timeSource blockchain.MedianTimeSource
sigCache *txscript.SigCache
hashCache *txscript.HashCache
}
// NewBlkTmplGenerator returns a new block template generator for the given
// policy using transactions from the provided transaction source.
//
// The additional state-related fields are required in order to ensure the
// templates are built on top of the current best chain and adhere to the
// consensus rules.
func NewBlkTmplGenerator(policy *Policy, params *chaincfg.Params,
txSource TxSource, chain *blockchain.BlockChain,
timeSource blockchain.MedianTimeSource,
sigCache *txscript.SigCache,
hashCache *txscript.HashCache) *BlkTmplGenerator {
return &BlkTmplGenerator{
policy: policy,
chainParams: params,
txSource: txSource,
chain: chain,
timeSource: timeSource,
sigCache: sigCache,
hashCache: hashCache,
}
}
// NewBlockTemplate returns a new block template that is ready to be solved
// using the transactions from the passed transaction source pool and a coinbase
// that either pays to the passed address if it is not nil, or a coinbase that
// is redeemable by anyone if the passed address is nil. The nil address
// functionality is useful since there are cases such as the getblocktemplate
// RPC where external mining software is responsible for creating their own
// coinbase which will replace the one generated for the block template. Thus
// the need to have configured address can be avoided.
//
// The transactions selected and included are prioritized according to several
// factors. First, each transaction has a priority calculated based on its
// value, age of inputs, and size. Transactions which consist of larger
// amounts, older inputs, and small sizes have the highest priority. Second, a
// fee per kilobyte is calculated for each transaction. Transactions with a
// higher fee per kilobyte are preferred. Finally, the block generation related
// policy settings are all taken into account.
//
// Transactions which only spend outputs from other transactions already in the
// block chain are immediately added to a priority queue which either
// prioritizes based on the priority (then fee per kilobyte) or the fee per
// kilobyte (then priority) depending on whether or not the BlockPrioritySize
// policy setting allots space for high-priority transactions. Transactions
// which spend outputs from other transactions in the source pool are added to a
// dependency map so they can be added to the priority queue once the
// transactions they depend on have been included.
//
// Once the high-priority area (if configured) has been filled with
// transactions, or the priority falls below what is considered high-priority,
// the priority queue is updated to prioritize by fees per kilobyte (then
// priority).
//
// When the fees per kilobyte drop below the TxMinFreeFee policy setting, the
// transaction will be skipped unless the BlockMinSize policy setting is
// nonzero, in which case the block will be filled with the low-fee/free
// transactions until the block size reaches that minimum size.
//
// Any transactions which would cause the block to exceed the BlockMaxSize
// policy setting, exceed the maximum allowed signature operations per block, or
// otherwise cause the block to be invalid are skipped.
//
// Given the above, a block generated by this function is of the following form:
//
// ----------------------------------- -- --
// | Coinbase Transaction | | |
// |-----------------------------------| | |
// | | | | ----- policy.BlockPrioritySize
// | High-priority Transactions | | |
// | | | |
// |-----------------------------------| | --
// | | |
// | | |
// | | |--- policy.BlockMaxSize
// | Transactions prioritized by fee | |
// | until <= policy.TxMinFreeFee | |
// | | |
// | | |
// | | |
// |-----------------------------------| |
// | Low-fee/Non high-priority (free) | |
// | transactions (while block size | |
// | <= policy.BlockMinSize) | |
// ----------------------------------- --
func (g *BlkTmplGenerator) NewBlockTemplate(payToAddress bchutil.Address) (*BlockTemplate, error) {
// Extend the most recently known best block.
best := g.chain.BestSnapshot()
nextBlockHeight := best.Height + 1
uahfActive := nextBlockHeight >= g.chainParams.UahfForkHeight
maxBlockSize := g.chain.MaxBlockSize(uahfActive)
maxSigOps := g.chain.MaxBlockSigOps(uahfActive)
// Create a standard coinbase transaction paying to the provided
// address. NOTE: The coinbase value will be updated to include the
// fees from the selected transactions later after they have actually
// been selected. It is created here to detect any errors early
// before potentially doing a lot of work below. The extra nonce helps
// ensure the transaction is not a duplicate transaction (paying the
// same value to the same public key address would otherwise be an
// identical transaction for block version 1).
extraNonce := uint64(0)
coinbaseScript, err := standardCoinbaseScript(nextBlockHeight, extraNonce)
if err != nil {
return nil, err
}
coinbaseTx, err := createCoinbaseTx(g.chainParams, coinbaseScript,
nextBlockHeight, payToAddress)
if err != nil {
return nil, err
}
coinbaseSigOps := int64(blockchain.CountSigOps(coinbaseTx))
// Get the current source transactions and create a priority queue to
// hold the transactions which are ready for inclusion into a block
// along with some priority related and fee metadata. Reserve the same
// number of items that are available for the priority queue. Also,
// choose the initial sort order for the priority queue based on whether
// or not there is an area allocated for high-priority transactions.
sourceTxns := g.txSource.MiningDescs()
sortedByFee := g.policy.BlockPrioritySize == 0
priorityQueue := newTxPriorityQueue(len(sourceTxns), sortedByFee)
// Create a slice to hold the transactions to be included in the
// generated block with reserved space. Also create a utxo view to
// house all of the input transactions so multiple lookups can be
// avoided.
blockTxns := make([]*bchutil.Tx, 0, len(sourceTxns))
blockUtxos := blockchain.NewUtxoViewpoint(g.chain.MaxOutputsPerBlock())
// dependers is used to track transactions which depend on another
// transaction in the source pool. This, in conjunction with the
// dependsOn map kept with each dependent transaction helps quickly
// determine which dependent transactions are now eligible for inclusion
// in the block once each transaction has been included.
dependers := make(map[chainhash.Hash]map[chainhash.Hash]*txPrioItem)
// Create slices to hold the fees and number of signature operations
// for each of the selected transactions and add an entry for the
// coinbase. This allows the code below to simply append details about
// a transaction as it is selected for inclusion in the final block.
// However, since the total fees aren't known yet, use a dummy value for
// the coinbase fee which will be updated later.
txFees := make([]int64, 0, len(sourceTxns))
txSigOps := make([]int64, 0, len(sourceTxns))
txFees = append(txFees, -1) // Updated once known
txSigOps = append(txSigOps, coinbaseSigOps)
log.Debugf("Considering %d transactions for inclusion to new block",
len(sourceTxns))
mempoolLoop:
for _, txDesc := range sourceTxns {
// A block can't have more than one coinbase or contain
// non-finalized transactions.
tx := txDesc.Tx
if blockchain.IsCoinBase(tx) {
log.Tracef("Skipping coinbase tx %s", tx.Hash())
continue
}
if !blockchain.IsFinalizedTransaction(tx, nextBlockHeight,
g.timeSource.AdjustedTime()) {
log.Tracef("Skipping non-finalized tx %s", tx.Hash())
continue
}
// Fetch all of the utxos referenced by the this transaction.
// NOTE: This intentionally does not fetch inputs from the
// mempool since a transaction which depends on other
// transactions in the mempool must come after those
// dependencies in the final generated block.
utxos, err := g.chain.FetchUtxoView(tx)
if err != nil {
log.Warnf("Unable to fetch utxo view for tx %s: %v",
tx.Hash(), err)
continue
}
// Setup dependencies for any transactions which reference
// other transactions in the mempool so they can be properly
// ordered below.
prioItem := &txPrioItem{tx: tx}
for _, txIn := range tx.MsgTx().TxIn {
originHash := &txIn.PreviousOutPoint.Hash
entry := utxos.LookupEntry(txIn.PreviousOutPoint)
if entry == nil || entry.IsSpent() {
if !g.txSource.HaveTransaction(originHash) {
log.Tracef("Skipping tx %s because it "+
"references unspent output %s "+
"which is not available",
tx.Hash(), txIn.PreviousOutPoint)
continue mempoolLoop
}
// The transaction is referencing another
// transaction in the source pool, so setup an
// ordering dependency.
deps, exists := dependers[*originHash]
if !exists {
deps = make(map[chainhash.Hash]*txPrioItem)
dependers[*originHash] = deps
}
deps[*prioItem.tx.Hash()] = prioItem
if prioItem.dependsOn == nil {
prioItem.dependsOn = make(
map[chainhash.Hash]struct{})
}
prioItem.dependsOn[*originHash] = struct{}{}
// Skip the check below. We already know the
// referenced transaction is available.
continue
}
}
// Calculate the final transaction priority using the input
// value age sum as well as the adjusted transaction size. The
// formula is: sum(inputValue * inputAge) / adjustedTxSize
prioItem.priority = CalcPriority(tx.MsgTx(), utxos,
nextBlockHeight)
// Calculate the fee in Satoshi/kB.
prioItem.feePerKB = txDesc.FeePerKB
prioItem.fee = txDesc.Fee
// Add the transaction to the priority queue to mark it ready
// for inclusion in the block unless it has dependencies.
if prioItem.dependsOn == nil {
heap.Push(priorityQueue, prioItem)
}
// Merge the referenced outputs from the input transactions to
// this transaction into the block utxo view. This allows the
// code below to avoid a second lookup.
mergeUtxoView(blockUtxos, utxos)
}
log.Tracef("Priority queue len %d, dependers len %d",
priorityQueue.Len(), len(dependers))
// The starting block size is the size of the block header plus the max
// possible transaction count size, plus the size of the coinbase
// transaction.
blockSize := uint32(blockHeaderOverhead * coinbaseTx.MsgTx().SerializeSize())
blockSigOps := coinbaseSigOps
totalFees := int64(0)
// Choose which transactions make it into the block.
for priorityQueue.Len() > 0 {
// Grab the highest priority (or highest fee per kilobyte
// depending on the sort order) transaction.
prioItem := heap.Pop(priorityQueue).(*txPrioItem)
tx := prioItem.tx
// Grab any transactions which depend on this one.
deps := dependers[*tx.Hash()]
// Enforce maximum block size. Also check for overflow.
txSize := uint32(tx.MsgTx().SerializeSize())
blockPlusTxSize := blockSize + txSize
if blockPlusTxSize < txSize ||
blockPlusTxSize >= g.policy.BlockMaxSize {
log.Tracef("Skipping tx %s because it would exceed "+
"the max block size", tx.Hash())
logSkippedDeps(tx, deps)
continue
}
// Enforce maximum signature operation cost per block. Also
// check for overflow.
sigOps, err := blockchain.GetSigOps(tx, false,
blockUtxos, true)
if err != nil {
log.Tracef("Skipping tx %s due to error in "+
"GetSigOpCost: %v", tx.Hash(), err)
logSkippedDeps(tx, deps)
continue
}
if blockSigOps+int64(sigOps) < blockSigOps ||
blockSigOps+int64(sigOps) > int64(maxSigOps) {
log.Tracef("Skipping tx %s because it would "+
"exceed the maximum sigops per block", tx.Hash())
logSkippedDeps(tx, deps)
continue
}
// Skip free transactions once the block is larger than the
// minimum block size.
if sortedByFee &&
prioItem.feePerKB < int64(g.policy.TxMinFreeFee) &&
blockPlusTxSize >= g.policy.BlockMinSize {
log.Tracef("Skipping tx %s with feePerKB %d "+
"< TxMinFreeFee %d and block size %d >= "+
"minBlockSize %d", tx.Hash(), prioItem.feePerKB,
g.policy.TxMinFreeFee, blockPlusTxSize,
g.policy.BlockMinSize)
logSkippedDeps(tx, deps)
continue
}
// Prioritize by fee per kilobyte once the block is larger than
// the priority size or there are no more high-priority
// transactions.
if !sortedByFee && (blockPlusTxSize >= g.policy.BlockPrioritySize ||
prioItem.priority <= MinHighPriority) {
log.Tracef("Switching to sort by fees per "+
"kilobyte blockSize %d >= BlockPrioritySize "+
"%d || priority %.2f <= minHighPriority %.2f",
blockPlusTxSize, g.policy.BlockPrioritySize,
prioItem.priority, MinHighPriority)
sortedByFee = true
priorityQueue.SetLessFunc(txPQByFee)
// Put the transaction back into the priority queue and
// skip it so it is re-priortized by fees if it won't
// fit into the high-priority section or the priority
// is too low. Otherwise this transaction will be the
// final one in the high-priority section, so just fall
// though to the code below so it is added now.
if blockPlusTxSize > g.policy.BlockPrioritySize ||
prioItem.priority < MinHighPriority {
heap.Push(priorityQueue, prioItem)
continue
}
}
// Ensure the transaction inputs pass all of the necessary
// preconditions before allowing it to be added to the block.
_, err = blockchain.CheckTransactionInputs(tx, nextBlockHeight,
blockUtxos, g.chainParams)
if err != nil {
log.Tracef("Skipping tx %s due to error in "+
"CheckTransactionInputs: %v", tx.Hash(), err)
logSkippedDeps(tx, deps)
continue
}
err = blockchain.ValidateTransactionScripts(tx, blockUtxos,
txscript.StandardVerifyFlags, g.sigCache,
g.hashCache)
if err != nil {
log.Tracef("Skipping tx %s due to error in "+
"ValidateTransactionScripts: %v", tx.Hash(), err)
logSkippedDeps(tx, deps)
continue
}
// Spend the transaction inputs in the block utxo view and add
// an entry for it to ensure any transactions which reference
// this one have it available as an input and can ensure they
// aren't double spending.
spendTransaction(blockUtxos, tx, nextBlockHeight)
// Add the transaction to the block, increment counters, and
// save the fees and signature operation counts to the block
// template.
blockTxns = append(blockTxns, tx)
blockSize += txSize
blockSigOps += int64(sigOps)
totalFees += prioItem.fee
txFees = append(txFees, prioItem.fee)
txSigOps = append(txSigOps, int64(sigOps))
log.Tracef("Adding tx %s (priority %.2f, feePerKB %.2f)",
prioItem.tx.Hash(), prioItem.priority, prioItem.feePerKB)
// Add transactions which depend on this one (and also do not
// have any other unsatisified dependencies) to the priority
// queue.
for _, item := range deps {
// Add the transaction to the priority queue if there
// are no more dependencies after this one.
delete(item.dependsOn, *tx.Hash())
if len(item.dependsOn) == 0 {
heap.Push(priorityQueue, item)
}
}
}
// Now that the actual transactions have been selected, update the
// block size for the real transaction count and coinbase value with
// the total fees accordingly.
blockSize -= wire.MaxVarIntPayload - uint32(wire.VarIntSerializeSize(uint64(len(blockTxns))))
coinbaseTx.MsgTx().TxOut[0].Value += totalFees
txFees[0] = -totalFees
// Calculate the required difficulty for the block. The timestamp
// is potentially adjusted to ensure it comes after the median time of
// the last several blocks per the chain consensus rules.
ts := medianAdjustedTime(best, g.timeSource)
reqDifficulty, err := g.chain.CalcNextRequiredDifficulty(ts)
if err != nil {
return nil, err
}
// Calculate the next expected block version based on the state of the
// rule change deployments.
nextBlockVersion, err := g.chain.CalcNextBlockVersion()
if err != nil {
return nil, err
}
// If MagneticAnomaly is enabled we need to sort transactions by txid to
// comply with the CTOR consensus rule.
if g.chain.IsMagneticAnomalyEnabled(best.Hash) {
sort.Sort(TxSorter(blockTxns))
}
blockTxns = append([]*bchutil.Tx{coinbaseTx}, blockTxns...)
// Create a new block ready to be solved.
merkles := blockchain.BuildMerkleTreeStore(blockTxns)
var msgBlock wire.MsgBlock
msgBlock.Header = wire.BlockHeader{
Version: nextBlockVersion,
PrevBlock: best.Hash,
MerkleRoot: *merkles[len(merkles)-1],
Timestamp: ts,
Bits: reqDifficulty,
}
for _, tx := range blockTxns {
if err := msgBlock.AddTransaction(tx.MsgTx()); err != nil {
return nil, err
}
}
// Finally, perform a full check on the created block against the chain
// consensus rules to ensure it properly connects to the current best
// chain with no issues.
block := bchutil.NewBlock(&msgBlock)
block.SetHeight(nextBlockHeight)
if err := g.chain.CheckConnectBlockTemplate(block); err != nil {
return nil, err
}
log.Debugf("Created new block template (%d transactions, %d in "+
"fees, %d signature operations, %d size, target difficulty "+
"%064x)", len(msgBlock.Transactions), totalFees, blockSigOps,
blockSize, blockchain.CompactToBig(msgBlock.Header.Bits))
return &BlockTemplate{
Block: &msgBlock,
Fees: txFees,
SigOpCosts: txSigOps,
Height: nextBlockHeight,
ValidPayAddress: payToAddress != nil,
MaxBlockSize: uint32(maxBlockSize),
MaxSigOps: uint32(maxSigOps),
}, nil
}
// UpdateBlockTime updates the timestamp in the header of the passed block to
// the current time while taking into account the median time of the last
// several blocks to ensure the new time is after that time per the chain
// consensus rules. Finally, it will update the target difficulty if needed
// based on the new time for the test networks since their target difficulty can
// change based upon time.
func (g *BlkTmplGenerator) UpdateBlockTime(msgBlock *wire.MsgBlock) error {
// The new timestamp is potentially adjusted to ensure it comes after
// the median time of the last several blocks per the chain consensus
// rules.
newTime := medianAdjustedTime(g.chain.BestSnapshot(), g.timeSource)
msgBlock.Header.Timestamp = newTime
// Recalculate the difficulty if running on a network that requires it.
if g.chainParams.ReduceMinDifficulty {
difficulty, err := g.chain.CalcNextRequiredDifficulty(newTime)
if err != nil {
return err
}
msgBlock.Header.Bits = difficulty
}
return nil
}
// UpdateExtraNonce updates the extra nonce in the coinbase script of the passed
// block by regenerating the coinbase script with the passed value and block
// height. It also recalculates and updates the new merkle root that results
// from changing the coinbase script.
func (g *BlkTmplGenerator) UpdateExtraNonce(msgBlock *wire.MsgBlock, blockHeight int32, extraNonce uint64) error {
coinbaseScript, err := standardCoinbaseScript(blockHeight, extraNonce)
if err != nil {
return err
}
if len(coinbaseScript) > blockchain.MaxCoinbaseScriptLen {
return fmt.Errorf("coinbase transaction script length "+
"of %d is out of range (min: %d, max: %d)",
len(coinbaseScript), blockchain.MinCoinbaseScriptLen,
blockchain.MaxCoinbaseScriptLen)
}
msgBlock.Transactions[0].TxIn[0].SignatureScript = coinbaseScript
// TODO(davec): A bchutil.Block should use saved in the state to avoid
// recalculating all of the other transaction hashes.
// block.Transactions[0].InvalidateCache()
// Recalculate the merkle root with the updated extra nonce.
block := bchutil.NewBlock(msgBlock)
merkles := blockchain.BuildMerkleTreeStore(block.Transactions())
msgBlock.Header.MerkleRoot = *merkles[len(merkles)-1]
return nil
}
// BestSnapshot returns information about the current best chain block and
// related state as of the current point in time using the chain instance
// associated with the block template generator. The returned state must be
// treated as immutable since it is shared by all callers.
//
// This function is safe for concurrent access.
func (g *BlkTmplGenerator) BestSnapshot() *blockchain.BestState {
return g.chain.BestSnapshot()
}
// TxSource returns the associated transaction source.
//
// This function is safe for concurrent access.
func (g *BlkTmplGenerator) TxSource() TxSource {
return g.txSource
}