-
Notifications
You must be signed in to change notification settings - Fork 11
/
populate_tx_with_utxo_entries.go
executable file
·126 lines (110 loc) · 5.07 KB
/
populate_tx_with_utxo_entries.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
package consensusstatemanager
import (
"github.com/Nexellia-Network/nexelliad/domain/consensus/model"
"github.com/Nexellia-Network/nexelliad/domain/consensus/model/externalapi"
"github.com/Nexellia-Network/nexelliad/domain/consensus/ruleerrors"
"github.com/Nexellia-Network/nexelliad/domain/consensus/utils/consensushashing"
)
// PopulateTransactionWithUTXOEntries populates the transaction UTXO entries with data from the virtual's UTXO set.
func (csm *consensusStateManager) PopulateTransactionWithUTXOEntries(
stagingArea *model.StagingArea, transaction *externalapi.DomainTransaction) error {
return csm.populateTransactionWithUTXOEntriesFromVirtualOrDiff(stagingArea, transaction, nil)
}
// populateTransactionWithUTXOEntriesFromVirtualOrDiff populates the transaction UTXO entries with data
// from the virtual's UTXO set combined with the provided utxoDiff.
// If utxoDiff == nil UTXO entries are taken from the virtual's UTXO set only
func (csm *consensusStateManager) populateTransactionWithUTXOEntriesFromVirtualOrDiff(stagingArea *model.StagingArea,
transaction *externalapi.DomainTransaction, utxoDiff externalapi.UTXODiff) error {
transactionID := consensushashing.TransactionID(transaction)
log.Tracef("populateTransactionWithUTXOEntriesFromVirtualOrDiff start for transaction %s", transactionID)
defer log.Tracef("populateTransactionWithUTXOEntriesFromVirtualOrDiff end for transaction %s", transactionID)
var missingOutpoints []*externalapi.DomainOutpoint
for _, transactionInput := range transaction.Inputs {
// skip all inputs that have a pre-filled utxo entry
if transactionInput.UTXOEntry != nil {
log.Tracef("Skipping outpoint %s:%d because it is already populated",
transactionInput.PreviousOutpoint.TransactionID, transactionInput.PreviousOutpoint.Index)
continue
}
// check if utxoDiff says anything about the input's outpoint
if utxoDiff != nil {
if utxoEntry, ok := utxoDiff.ToAdd().Get(&transactionInput.PreviousOutpoint); ok {
log.Tracef("Populating outpoint %s:%d from the given utxoDiff",
transactionInput.PreviousOutpoint.TransactionID, transactionInput.PreviousOutpoint.Index)
transactionInput.UTXOEntry = utxoEntry
continue
}
if utxoDiff.ToRemove().Contains(&transactionInput.PreviousOutpoint) {
log.Tracef("Outpoint %s:%d is missing in the given utxoDiff",
transactionInput.PreviousOutpoint.TransactionID, transactionInput.PreviousOutpoint.Index)
missingOutpoints = append(missingOutpoints, &transactionInput.PreviousOutpoint)
continue
}
}
// Check for the input's outpoint in virtual's UTXO set.
hasUTXOEntry, err := csm.consensusStateStore.HasUTXOByOutpoint(
csm.databaseContext, stagingArea, &transactionInput.PreviousOutpoint)
if err != nil {
return err
}
if !hasUTXOEntry {
log.Tracef("Outpoint %s:%d is missing in the database",
transactionInput.PreviousOutpoint.TransactionID, transactionInput.PreviousOutpoint.Index)
missingOutpoints = append(missingOutpoints, &transactionInput.PreviousOutpoint)
continue
}
log.Tracef("Populating outpoint %s:%d from the database",
transactionInput.PreviousOutpoint.TransactionID, transactionInput.PreviousOutpoint.Index)
utxoEntry, err := csm.consensusStateStore.UTXOByOutpoint(
csm.databaseContext, stagingArea, &transactionInput.PreviousOutpoint)
if err != nil {
return err
}
transactionInput.UTXOEntry = utxoEntry
}
if len(missingOutpoints) > 0 {
return ruleerrors.NewErrMissingTxOut(missingOutpoints)
}
return nil
}
func (csm *consensusStateManager) populateTransactionWithUTXOEntriesFromUTXOSet(
pruningPoint *externalapi.DomainBlock, iterator externalapi.ReadOnlyUTXOSetIterator) error {
// Collect the required outpoints from the block
outpointsForPopulation := make(map[externalapi.DomainOutpoint]interface{})
for _, transaction := range pruningPoint.Transactions {
for _, input := range transaction.Inputs {
outpointsForPopulation[input.PreviousOutpoint] = struct{}{}
}
}
// Collect the UTXO entries from the iterator
outpointsToUTXOEntries := make(map[externalapi.DomainOutpoint]externalapi.UTXOEntry, len(outpointsForPopulation))
for ok := iterator.First(); ok; ok = iterator.Next() {
outpoint, utxoEntry, err := iterator.Get()
if err != nil {
return err
}
outpointValue := *outpoint
if _, ok := outpointsForPopulation[outpointValue]; ok {
outpointsToUTXOEntries[outpointValue] = utxoEntry
}
if len(outpointsForPopulation) == len(outpointsToUTXOEntries) {
break
}
}
// Populate the block with the collected UTXO entries
var missingOutpoints []*externalapi.DomainOutpoint
for _, transaction := range pruningPoint.Transactions {
for _, input := range transaction.Inputs {
utxoEntry, ok := outpointsToUTXOEntries[input.PreviousOutpoint]
if !ok {
missingOutpoints = append(missingOutpoints, &input.PreviousOutpoint)
continue
}
input.UTXOEntry = utxoEntry
}
}
if len(missingOutpoints) > 0 {
return ruleerrors.NewErrMissingTxOut(missingOutpoints)
}
return nil
}