forked from decred/dcrd
-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathmining.go
3272 lines (2911 loc) · 120 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
889
890
891
892
893
894
895
896
897
898
899
900
901
902
903
904
905
906
907
908
909
910
911
912
913
914
915
916
917
918
919
920
921
922
923
924
925
926
927
928
929
930
931
932
933
934
935
936
937
938
939
940
941
942
943
944
945
946
947
948
949
950
951
952
953
954
955
956
957
958
959
960
961
962
963
964
965
966
967
968
969
970
971
972
973
974
975
976
977
978
979
980
981
982
983
984
985
986
987
988
989
990
991
992
993
994
995
996
997
998
999
1000
// Copyright (c) 2014-2016 The btcsuite developers
// Copyright (c) 2015-2020 The Decred developers
// Use of this source code is governed by an ISC
// license that can be found in the LICENSE file.
package main
import (
"container/heap"
"context"
"encoding/binary"
"fmt"
"math"
"math/rand"
"sort"
"sync"
"time"
"github.com/decred/dcrd/blockchain/stake/v3"
"github.com/decred/dcrd/blockchain/standalone"
"github.com/decred/dcrd/blockchain/v3"
"github.com/decred/dcrd/chaincfg/chainhash"
"github.com/decred/dcrd/chaincfg/v3"
"github.com/decred/dcrd/dcrutil/v3"
"github.com/decred/dcrd/gcs/v2/blockcf2"
"github.com/decred/dcrd/lru"
"github.com/decred/dcrd/mining/v3"
"github.com/decred/dcrd/txscript/v3"
"github.com/decred/dcrd/wire"
)
const (
// generatedBlockVersion is the version of the block being generated for
// the main network. It is defined as a constant here rather than using
// the wire.BlockVersion constant since a change in the block version
// will require changes to the generated block. Using the wire constant
// for generated block version could allow creation of invalid blocks
// for the updated version.
generatedBlockVersion = 7
// generatedBlockVersionTest is the version of the block being generated
// for networks other than the main and simulation networks.
generatedBlockVersionTest = 8
// 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 some extra data appended to the coinbase script
// sig.
coinbaseFlags = "/dcrd/"
// kilobyte is the size of a kilobyte.
kilobyte = 1000
// minVotesTimeoutDuration is the duration that must elapse after a new tip
// block has been received before other variants that also extend the same
// parent and received later are considered for the base of new templates.
minVotesTimeoutDuration = time.Second * 3
// maxVoteTimeoutDuration is the duration elapsed after the minimum number
// of votes for a new tip block has been received that a new template with
// less than the maximum number of votes will be generated.
maxVoteTimeoutDuration = time.Millisecond * 2500 // 2.5 seconds
// templateRegenSecs is the required number of seconds elapsed with
// incoming non vote transactions before template regeneration
// is required.
templateRegenSecs = 30
// merkleRootPairSize is the size in bytes of the merkle root + stake root
// of a block.
merkleRootPairSize = 64
)
// 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 *dcrutil.Tx
txType stake.TxType
fee int64
priority float64
feePerKB float64
// 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)
}
// stakePriority is an integer that is used to sort stake transactions
// by importance when they enter the min heap for block construction.
// 2 is for votes (highest), followed by 1 for tickets (2nd highest),
// followed by 0 for regular transactions and revocations (lowest).
type stakePriority int
const (
regOrRevocPriority stakePriority = iota
ticketPriority
votePriority
)
// stakePriority assigns a stake priority based on a transaction type.
func txStakePriority(txType stake.TxType) stakePriority {
prio := regOrRevocPriority
switch txType {
case stake.TxTypeSSGen:
prio = votePriority
case stake.TxTypeSStx:
prio = ticketPriority
}
return prio
}
// compareStakePriority compares the stake priority of two transactions.
// It uses votes > tickets > regular transactions or revocations. It
// returns 1 if i > j, 0 if i == j, and -1 if i < j in terms of stake
// priority.
func compareStakePriority(i, j *txPrioItem) int {
iStakePriority := txStakePriority(i.txType)
jStakePriority := txStakePriority(j.txType)
if iStakePriority > jStakePriority {
return 1
}
if iStakePriority < jStakePriority {
return -1
}
return 0
}
// txPQByStakeAndFee sorts a txPriorityQueue by stake priority, followed by
// fees per kilobyte, and then transaction priority.
func txPQByStakeAndFee(pq *txPriorityQueue, i, j int) bool {
// Sort by stake priority, continue if they're the same stake priority.
cmp := compareStakePriority(pq.items[i], pq.items[j])
if cmp == 1 {
return true
}
if cmp == -1 {
return false
}
// 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
}
// The stake priorities are equal, so return based on fees
// per KB.
return pq.items[i].feePerKB > pq.items[j].feePerKB
}
// txPQByStakeAndFeeAndThenPriority sorts a txPriorityQueue by stake priority,
// followed by fees per kilobyte, and then if the transaction type is regular
// or a revocation it sorts it by priority.
func txPQByStakeAndFeeAndThenPriority(pq *txPriorityQueue, i, j int) bool {
// Sort by stake priority, continue if they're the same stake priority.
cmp := compareStakePriority(pq.items[i], pq.items[j])
if cmp == 1 {
return true
}
if cmp == -1 {
return false
}
bothAreLowStakePriority :=
txStakePriority(pq.items[i].txType) == regOrRevocPriority &&
txStakePriority(pq.items[j].txType) == regOrRevocPriority
// Use fees per KB on high stake priority transactions.
if !bothAreLowStakePriority {
return pq.items[i].feePerKB > pq.items[j].feePerKB
}
// Both transactions are of low stake importance. Use > 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
}
// newTxPriorityQueue returns a new transaction priority queue that reserves the
// passed amount of space for the elements. The new priority queue uses the
// less than function lessFunc to sort the items in the min heap. 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, lessFunc func(*txPriorityQueue, int, int) bool) *txPriorityQueue {
pq := &txPriorityQueue{
items: make([]*txPrioItem, 0, reserve),
}
pq.SetLessFunc(lessFunc)
return pq
}
// containsTx is a helper function that checks to see if a list of transactions
// contains any of the TxIns of some transaction.
func containsTxIns(txs []*dcrutil.Tx, tx *dcrutil.Tx) bool {
for _, txToCheck := range txs {
for _, txIn := range tx.MsgTx().TxIn {
if txIn.PreviousOutPoint.Hash.IsEqual(txToCheck.Hash()) {
return true
}
}
}
return false
}
// blockWithNumVotes is a block with the number of votes currently present
// for that block. Just used for sorting.
type blockWithNumVotes struct {
Hash chainhash.Hash
NumVotes uint16
}
// byNumberOfVotes implements sort.Interface to sort a slice of blocks by their
// number of votes.
type byNumberOfVotes []*blockWithNumVotes
// Len returns the number of elements in the slice. It is part of the
// sort.Interface implementation.
func (b byNumberOfVotes) Len() int {
return len(b)
}
// Swap swaps the elements at the passed indices. It is part of the
// sort.Interface implementation.
func (b byNumberOfVotes) Swap(i, j int) {
b[i], b[j] = b[j], b[i]
}
// Less returns whether the block with index i should sort before the block with
// index j. It is part of the sort.Interface implementation.
func (b byNumberOfVotes) Less(i, j int) bool {
return b[i].NumVotes < b[j].NumVotes
}
// SortParentsByVotes takes a list of block header hashes and sorts them
// by the number of votes currently available for them in the votes map of
// mempool. It then returns all blocks that are eligible to be used (have
// at least a majority number of votes) sorted by number of votes, descending.
//
// This function is safe for concurrent access.
func SortParentsByVotes(txSource mining.TxSource, currentTopBlock chainhash.Hash, blocks []chainhash.Hash, params *chaincfg.Params) []chainhash.Hash {
// Return now when no blocks were provided.
lenBlocks := len(blocks)
if lenBlocks == 0 {
return nil
}
// Fetch the vote metadata for the provided block hashes from the
// mempool and filter out any blocks that do not have the minimum
// required number of votes.
minVotesRequired := (params.TicketsPerBlock / 2) + 1
voteMetadata := txSource.VotesForBlocks(blocks)
filtered := make([]*blockWithNumVotes, 0, lenBlocks)
for i := range blocks {
numVotes := uint16(len(voteMetadata[i]))
if numVotes >= minVotesRequired {
filtered = append(filtered, &blockWithNumVotes{
Hash: blocks[i],
NumVotes: numVotes,
})
}
}
// Return now if there are no blocks with enough votes to be eligible to
// build on top of.
if len(filtered) == 0 {
return nil
}
// Blocks with the most votes appear at the top of the list.
sort.Sort(sort.Reverse(byNumberOfVotes(filtered)))
sortedUsefulBlocks := make([]chainhash.Hash, 0, len(filtered))
for _, bwnv := range filtered {
sortedUsefulBlocks = append(sortedUsefulBlocks, bwnv.Hash)
}
// Make sure we don't reorganize the chain needlessly if the top block has
// the same amount of votes as the current leader after the sort. After this
// point, all blocks listed in sortedUsefulBlocks definitely also have the
// minimum number of votes required.
curVoteMetadata := txSource.VotesForBlocks([]chainhash.Hash{currentTopBlock})
numTopBlockVotes := uint16(len(curVoteMetadata))
if filtered[0].NumVotes == numTopBlockVotes && filtered[0].Hash !=
currentTopBlock {
// Attempt to find the position of the current block being built
// from in the list.
pos := 0
for i, bwnv := range filtered {
if bwnv.Hash == currentTopBlock {
pos = i
break
}
}
// Swap the top block into the first position. We directly access
// sortedUsefulBlocks useful blocks here with the assumption that
// since the values were accumulated from filtered, they should be
// in the same positions and we shouldn't be able to access anything
// out of bounds.
if pos != 0 {
sortedUsefulBlocks[0], sortedUsefulBlocks[pos] =
sortedUsefulBlocks[pos], sortedUsefulBlocks[0]
}
}
return sortedUsefulBlocks
}
// 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
// SigOpCounts contains the number of signature operations each
// transaction in the generated template performs.
SigOpCounts []int64
// Height is the height at which the block template connects to the main
// chain.
Height int64
// 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
}
// mergeUtxoView adds all of the entries in view 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 fully spent.
func mergeUtxoView(viewA *blockchain.UtxoViewpoint, viewB *blockchain.UtxoViewpoint) {
viewAEntries := viewA.Entries()
for hash, entryB := range viewB.Entries() {
if entryA, exists := viewAEntries[hash]; !exists ||
entryA == nil || entryA.IsFullySpent() {
viewAEntries[hash] = entryB
}
}
}
// hashExistsInList checks if a hash exists in a list of hash pointers.
func hashInSlice(h chainhash.Hash, list []chainhash.Hash) bool {
for i := range list {
if h == list[i] {
return true
}
}
return false
}
// txIndexFromTxList returns a transaction's index in a list, or -1 if it
// can not be found.
func txIndexFromTxList(hash chainhash.Hash, list []*dcrutil.Tx) int {
for i, tx := range list {
h := tx.Hash()
if hash == *h {
return i
}
}
return -1
}
// standardCoinbaseOpReturn creates a standard OP_RETURN output to insert into
// coinbase to use as extranonces. The OP_RETURN pushes 32 bytes.
func standardCoinbaseOpReturn(height uint32, extraNonce uint64) ([]byte, error) {
enData := make([]byte, 12)
binary.LittleEndian.PutUint32(enData[0:4], height)
binary.LittleEndian.PutUint64(enData[4:12], extraNonce)
extraNonceScript, err := txscript.GenerateProvablyPruneableOut(enData)
if err != nil {
return nil, err
}
return extraNonceScript, nil
}
// calcBlockMerkleRoot calculates and returns a merkle root depending on the
// result of the header commitments agenda vote. In particular, before the
// agenda is active, it returns the merkle root of the regular transaction tree.
// Once the agenda is active, it returns the combined merkle root for the
// regular and stake transaction trees in accordance with DCP0005.
func calcBlockMerkleRoot(regularTxns, stakeTxns []*wire.MsgTx, hdrCmtActive bool) chainhash.Hash {
if !hdrCmtActive {
return standalone.CalcTxTreeMerkleRoot(regularTxns)
}
return standalone.CalcCombinedTxTreeMerkleRoot(regularTxns, stakeTxns)
}
// calcBlockCommitmentRootV1 calculates and returns the required v1 block and
// the previous output scripts it references as inputs.
func calcBlockCommitmentRootV1(block *wire.MsgBlock, prevScripts blockcf2.PrevScripter) (chainhash.Hash, error) {
filter, err := blockcf2.Regular(block, prevScripts)
if err != nil {
return chainhash.Hash{}, err
}
return blockchain.CalcCommitmentRootV1(filter.Hash()), nil
}
// 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(subsidyCache *standalone.SubsidyCache, coinbaseScript []byte, opReturnPkScript []byte, nextBlockHeight int64, addr dcrutil.Address, voters uint16, params *chaincfg.Params) (*dcrutil.Tx, error) {
tx := wire.NewMsgTx()
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, wire.TxTreeRegular),
Sequence: wire.MaxTxInSequenceNum,
BlockHeight: wire.NullBlockHeight,
BlockIndex: wire.NullBlockIndex,
SignatureScript: coinbaseScript,
})
// Block one is a special block that might pay out tokens to a ledger.
if nextBlockHeight == 1 && len(params.BlockOneLedger) != 0 {
for _, payout := range params.BlockOneLedger {
tx.AddTxOut(&wire.TxOut{
Value: payout.Amount,
Version: payout.ScriptVersion,
PkScript: payout.Script,
})
}
tx.TxIn[0].ValueIn = params.BlockOneSubsidy()
return dcrutil.NewTx(tx), nil
}
// Create a coinbase with correct block subsidy and extranonce.
workSubsidy := subsidyCache.CalcWorkSubsidy(nextBlockHeight, voters)
treasurySubsidy := subsidyCache.CalcTreasurySubsidy(nextBlockHeight, voters)
// Treasury output.
if params.BlockTaxProportion > 0 {
tx.AddTxOut(&wire.TxOut{
Value: treasurySubsidy,
PkScript: params.OrganizationPkScript,
})
} else {
// Treasury disabled.
scriptBuilder := txscript.NewScriptBuilder()
trueScript, err := scriptBuilder.AddOp(txscript.OP_TRUE).Script()
if err != nil {
return nil, err
}
tx.AddTxOut(&wire.TxOut{
Value: treasurySubsidy,
PkScript: trueScript,
})
}
// Extranonce.
tx.AddTxOut(&wire.TxOut{
Value: 0,
PkScript: opReturnPkScript,
})
// ValueIn.
tx.TxIn[0].ValueIn = workSubsidy + treasurySubsidy
// 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 pksSubsidy []byte
if addr != nil {
var err error
pksSubsidy, err = txscript.PayToAddrScript(addr)
if err != nil {
return nil, err
}
} else {
var err error
scriptBuilder := txscript.NewScriptBuilder()
pksSubsidy, err = scriptBuilder.AddOp(txscript.OP_TRUE).Script()
if err != nil {
return nil, err
}
}
// Subsidy paid to miner.
tx.AddTxOut(&wire.TxOut{
Value: workSubsidy,
PkScript: pksSubsidy,
})
return dcrutil.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 *dcrutil.Tx, height int64) {
for _, txIn := range tx.MsgTx().TxIn {
originHash := &txIn.PreviousOutPoint.Hash
originIndex := txIn.PreviousOutPoint.Index
entry := utxoView.LookupEntry(originHash)
if entry != nil {
entry.SpendOutput(originIndex)
}
}
utxoView.AddTxOuts(tx, height, wire.NullBlockIndex)
}
// 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 *dcrutil.Tx, deps map[chainhash.Hash]*txPrioItem) {
if deps == nil {
return
}
for _, item := range deps {
minrLog.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 current best chain. In particular, it is one second after
// the median timestamp of the last several blocks per the chain consensus
// rules.
func minimumMedianTime(best *blockchain.BestState) time.Time {
return best.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(best *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 support a precision greater than one second.
newTimestamp := timeSource.AdjustedTime()
minTimestamp := minimumMedianTime(best)
if newTimestamp.Before(minTimestamp) {
newTimestamp = minTimestamp
}
// Adjust by the amount requested from the command line argument.
newTimestamp = newTimestamp.Add(
time.Duration(-cfg.MiningTimeOffset) * time.Second)
return newTimestamp
}
// maybeInsertStakeTx checks to make sure that a stake tx is
// valid from the perspective of the mainchain (not necessarily
// the mempool or block) before inserting into a tx tree.
// If it fails the check, it returns false; otherwise true.
func maybeInsertStakeTx(bm *blockManager, stx *dcrutil.Tx, treeValid bool) bool {
missingInput := false
view, err := bm.cfg.Chain.FetchUtxoView(stx, treeValid)
if err != nil {
minrLog.Warnf("Unable to fetch transaction store for "+
"stx %s: %v", stx.Hash(), err)
return false
}
mstx := stx.MsgTx()
isSSGen := stake.IsSSGen(mstx)
for i, txIn := range mstx.TxIn {
// Evaluate if this is a stakebase input or not. If it
// is, continue without evaluation of the input.
// if isStakeBase
if isSSGen && (i == 0) {
txIn.BlockHeight = wire.NullBlockHeight
txIn.BlockIndex = wire.NullBlockIndex
continue
}
originHash := &txIn.PreviousOutPoint.Hash
utxIn := view.LookupEntry(originHash)
if utxIn == nil {
missingInput = true
break
} else {
originIdx := txIn.PreviousOutPoint.Index
txIn.ValueIn = utxIn.AmountByIndex(originIdx)
txIn.BlockHeight = uint32(utxIn.BlockHeight())
txIn.BlockIndex = utxIn.BlockIndex()
}
}
return !missingInput
}
// handleTooFewVoters handles the situation in which there are too few voters on
// of the blockchain. If there are too few voters and a cached parent template to
// work off of is present, it will return a copy of that template to pass to the
// miner.
// Safe for concurrent access.
func handleTooFewVoters(subsidyCache *standalone.SubsidyCache, nextHeight int64, miningAddress dcrutil.Address, bm *blockManager) (*BlockTemplate, error) {
timeSource := bm.cfg.TimeSource
stakeValidationHeight := bm.cfg.ChainParams.StakeValidationHeight
// Handle not enough voters being present if we're set to mine aggressively
// (default behavior).
best := bm.cfg.Chain.BestSnapshot()
if nextHeight >= stakeValidationHeight && bm.AggressiveMining {
// Fetch the latest block and head and begin working off of it with an
// empty transaction tree regular and the contents of that stake tree.
// In the future we should have the option of reading some transactions
// from this block, too.
topBlock, err := bm.cfg.Chain.BlockByHash(&best.Hash)
if err != nil {
str := fmt.Sprintf("unable to get tip block %s", best.PrevHash)
return nil, miningRuleError(ErrGetTopBlock, str)
}
tipHeader := &topBlock.MsgBlock().Header
// Start with a copy of the tip block header.
var block wire.MsgBlock
block.Header = *tipHeader
// Create and populate a new coinbase.
rand, err := wire.RandomUint64()
if err != nil {
return nil, err
}
coinbaseScript := make([]byte, len(coinbaseFlags)+2)
copy(coinbaseScript[2:], coinbaseFlags)
opReturnPkScript, err := standardCoinbaseOpReturn(tipHeader.Height, rand)
if err != nil {
return nil, err
}
coinbaseTx, err := createCoinbaseTx(subsidyCache, coinbaseScript,
opReturnPkScript, topBlock.Height(), miningAddress,
tipHeader.Voters, bm.cfg.ChainParams)
if err != nil {
return nil, err
}
block.AddTransaction(coinbaseTx.MsgTx())
// Copy all of the stake transactions over.
for _, stx := range topBlock.STransactions() {
block.AddSTransaction(stx.MsgTx())
}
// Set a fresh timestamp.
ts := medianAdjustedTime(best, timeSource)
block.Header.Timestamp = ts
// If we're on testnet, the time since this last block listed as the
// parent must be taken into consideration.
if bm.cfg.ChainParams.ReduceMinDifficulty {
parentHash := topBlock.MsgBlock().Header.PrevBlock
requiredDifficulty, err :=
bm.cfg.Chain.CalcNextRequiredDifficulty(&parentHash, ts)
if err != nil {
return nil, miningRuleError(ErrGettingDifficulty,
err.Error())
}
block.Header.Bits = requiredDifficulty
}
// Recalculate the size.
block.Header.Size = uint32(block.SerializeSize())
bt := &BlockTemplate{
Block: &block,
Fees: []int64{0},
SigOpCounts: []int64{0},
Height: int64(tipHeader.Height),
ValidPayAddress: miningAddress != nil,
}
// Calculate the merkle root depending on the result of the header
// commitments agenda vote.
prevHash := &tipHeader.PrevBlock
hdrCmtActive, err := bm.cfg.Chain.IsHeaderCommitmentsAgendaActive(prevHash)
if err != nil {
return nil, err
}
header := &block.Header
header.MerkleRoot = calcBlockMerkleRoot(block.Transactions, block.STransactions, hdrCmtActive)
// Calculate the stake root or commitment root depending on the result
// of the header commitments agenda vote.
var cmtRoot chainhash.Hash
if hdrCmtActive {
// Load all of the previous output scripts the block references as
// inputs since they are needed to create the filter commitment.
blockUtxos, err := bm.cfg.Chain.FetchUtxoViewParentTemplate(&block)
if err != nil {
str := fmt.Sprintf("failed to fetch inputs when making new "+
"block template: %v", err)
return nil, miningRuleError(ErrFetchTxStore, str)
}
cmtRoot, err = calcBlockCommitmentRootV1(&block, blockUtxos)
if err != nil {
str := fmt.Sprintf("failed to calculate commitment root for "+
"block when making new block template: %v", err)
return nil, miningRuleError(ErrCalcCommitmentRoot, str)
}
} else {
cmtRoot = standalone.CalcTxTreeMerkleRoot(block.STransactions)
}
header.StakeRoot = cmtRoot
// Make sure the block validates.
btBlock := dcrutil.NewBlockDeepCopyCoinbase(&block)
err = bm.cfg.Chain.CheckConnectBlockTemplate(btBlock)
if err != nil {
str := fmt.Sprintf("failed to check template: %v while "+
"constructing a new parent", err.Error())
return nil, miningRuleError(ErrCheckConnectBlock, str)
}
return bt, nil
}
bmgrLog.Debugf("Not enough voters on top block to generate " +
"new block template")
return nil, nil
}
// BlkTmplGenerator generates block templates based on a given mining policy
// and a transactions source. It also houses additional state required in
// order to ensure the templates adhere to the consensus rules and are built
// on top of the best chain tip or its parent if the best chain tip is
// unable to get enough votes.
//
// See the NewBlockTemplate method for a detailed description of how the block
// template is generated.
type BlkTmplGenerator struct {
policy *mining.Policy
txSource mining.TxSource
sigCache *txscript.SigCache
subsidyCache *standalone.SubsidyCache
chainParams *chaincfg.Params
chain *blockchain.BlockChain
blockManager *blockManager
timeSource blockchain.MedianTimeSource
}
// newBlkTmplGenerator returns a new block template generator for the given
// policy using transactions from the provided transaction source.
func newBlkTmplGenerator(policy *mining.Policy, txSource mining.TxSource,
timeSource blockchain.MedianTimeSource, sigCache *txscript.SigCache,
subsidyCache *standalone.SubsidyCache, chainParams *chaincfg.Params,
chain *blockchain.BlockChain,
blockManager *blockManager) *BlkTmplGenerator {
return &BlkTmplGenerator{
policy: policy,
txSource: txSource,
sigCache: sigCache,
subsidyCache: subsidyCache,
chainParams: chainParams,
chain: chain,
blockManager: blockManager,
timeSource: timeSource,
}
}
// 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) / 2
// | Transactions prioritized by fee | |
// | until <= policy.TxMinFreeFee | |
// | | |
// | | |
// | | |
// |-----------------------------------| |
// | Low-fee/Non high-priority (free) | |
// | transactions (while block size | |
// | <= policy.BlockMinSize) | |
// ----------------------------------- --
//
// Which also includes a stake tree that looks like the following:
//
// ----------------------------------- -- --
// | | | |
// | Votes | | | --- >= (chaincfg.TicketsPerBlock/2) + 1
// | | | |
// |-----------------------------------| | --
// | | | |
// | Tickets | | | --- <= chaincfg.MaxFreshStakePerBlock
// | | | |
// |-----------------------------------| | --
// | | |
// | Revocations | |
// | | |
// ----------------------------------- --
//
// This function returns nil, nil if there are not enough voters on any of
// the current top blocks to create a new block template.
func (g *BlkTmplGenerator) NewBlockTemplate(payToAddress dcrutil.Address) (*BlockTemplate, error) {
// All transaction scripts are verified using the more strict standard
// flags.
scriptFlags, err := standardScriptVerifyFlags(g.chain)
if err != nil {
return nil, err
}
// Extend the most recently known best block.
// The most recently known best block is the top block that has the most
// ssgen votes for it. We only need this after the height in which stake voting
// has kicked in.
// To figure out which block has the most ssgen votes, we need to run the
// following algorithm:
// 1. Acquire the HEAD block and all of its orphans. Record their block header
// hashes.
// 2. Create a map of [blockHeaderHash] --> [mempoolTxnList].
// 3. for blockHeaderHash in candidateBlocks:
// if mempoolTx.StakeDesc == SSGen &&
// mempoolTx.SSGenParseBlockHeader() == blockHeaderHash:
// map[blockHeaderHash].append(mempoolTx)
// 4. Check len of each map entry and store.
// 5. Query the ticketdb and check how many eligible ticket holders there are
// for the given block you are voting on.
// 6. Divide #ofvotes (len(map entry)) / totalPossibleVotes --> penalty ratio
// 7. Store penalty ratios for all block candidates.
// 8. Select the one with the largest penalty ratio (highest block reward).
// This block is then selected to build upon instead of the others, because
// it yields the greater amount of rewards.
best := g.chain.BestSnapshot()
prevHash := best.Hash
nextBlockHeight := best.Height + 1
stakeValidationHeight := g.chainParams.StakeValidationHeight
if nextBlockHeight >= stakeValidationHeight {
// Obtain the entire generation of blocks stemming from this parent.
children, err := g.blockManager.TipGeneration()
if err != nil {
return nil, miningRuleError(ErrFailedToGetGeneration, err.Error())
}
// Get the list of blocks that we can actually build on top of. If we're
// not currently on the block that has the most votes, switch to that
// block.
eligibleParents := SortParentsByVotes(g.txSource, prevHash, children,
g.chainParams)
if len(eligibleParents) == 0 {
minrLog.Debugf("Too few voters found on any HEAD block, " +
"recycling a parent block to mine on")
return handleTooFewVoters(g.subsidyCache, nextBlockHeight,
payToAddress, g.blockManager)
}
minrLog.Debugf("Found eligible parent %v with enough votes to build "+
"block on, proceeding to create a new block template",
eligibleParents[0])
// Force a reorganization to the parent with the most votes if we need
// to.
if eligibleParents[0] != prevHash {
for i := range eligibleParents {
newHead := &eligibleParents[i]
err := g.blockManager.ForceReorganization(prevHash, *newHead)
if err != nil {
minrLog.Errorf("failed to reorganize to new parent: %v", err)
continue
}
// Check to make sure we actually have the transactions
// (votes) we need in the mempool.
voteHashes := g.txSource.VoteHashesForBlock(newHead)
if len(voteHashes) == 0 {
return nil, fmt.Errorf("no vote metadata for block %v",
newHead)
}