-
Notifications
You must be signed in to change notification settings - Fork 11
/
add_block_to_virtual.go
executable file
·166 lines (136 loc) · 6.22 KB
/
add_block_to_virtual.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
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/utils/utxo"
"github.com/Nexellia-Network/nexelliad/infrastructure/logger"
)
// AddBlock submits the given block to be added to the
// current virtual. This process may result in a new virtual block
// getting created
func (csm *consensusStateManager) AddBlock(stagingArea *model.StagingArea, blockHash *externalapi.DomainHash, updateVirtual bool) (
*externalapi.SelectedChainPath, externalapi.UTXODiff, *model.UTXODiffReversalData, error) {
onEnd := logger.LogAndMeasureExecutionTime(log, "csm.AddBlock")
defer onEnd()
var reversalData *model.UTXODiffReversalData
if updateVirtual {
log.Debugf("Resolving whether the block %s is the next virtual selected parent", blockHash)
isCandidateToBeNextVirtualSelectedParent, err := csm.isCandidateToBeNextVirtualSelectedParent(stagingArea, blockHash)
if err != nil {
return nil, nil, nil, err
}
if isCandidateToBeNextVirtualSelectedParent {
// It's important to check for finality violation before resolving the block status, because the status of
// blocks with a selected chain that doesn't contain the pruning point cannot be resolved because they will
// eventually try to fetch UTXO diffs from the past of the pruning point.
log.Debugf("Block %s is candidate to be the next virtual selected parent. Resolving whether it violates "+
"finality", blockHash)
isViolatingFinality, shouldNotify, err := csm.isViolatingFinality(stagingArea, blockHash)
if err != nil {
return nil, nil, nil, err
}
if shouldNotify {
//TODO: Send finality conflict notification
log.Warnf("Finality Violation Detected! Block %s violates finality!", blockHash)
}
if !isViolatingFinality {
log.Debugf("Block %s doesn't violate finality. Resolving its block status", blockHash)
var blockStatus externalapi.BlockStatus
blockStatus, reversalData, err = csm.resolveBlockStatus(stagingArea, blockHash, true)
if err != nil {
return nil, nil, nil, err
}
log.Debugf("Block %s resolved to status `%s`", blockHash, blockStatus)
}
} else {
log.Debugf("Block %s is not the next virtual selected parent, "+
"therefore its status remains `%s`", blockHash, externalapi.StatusUTXOPendingVerification)
}
}
log.Debugf("Adding block %s to the DAG tips", blockHash)
newTips, err := csm.addTip(stagingArea, blockHash)
if err != nil {
return nil, nil, nil, err
}
log.Debugf("After adding %s, the amount of new tips are %d", blockHash, len(newTips))
if !updateVirtual {
return &externalapi.SelectedChainPath{}, utxo.NewUTXODiff(), nil, nil
}
log.Debugf("Updating the virtual with the new tips")
selectedParentChainChanges, virtualUTXODiff, err := csm.updateVirtual(stagingArea, blockHash, newTips)
if err != nil {
return nil, nil, nil, err
}
return selectedParentChainChanges, virtualUTXODiff, reversalData, nil
}
func (csm *consensusStateManager) isCandidateToBeNextVirtualSelectedParent(
stagingArea *model.StagingArea, blockHash *externalapi.DomainHash) (bool, error) {
log.Tracef("isCandidateToBeNextVirtualSelectedParent start for block %s", blockHash)
defer log.Tracef("isCandidateToBeNextVirtualSelectedParent end for block %s", blockHash)
if blockHash.Equal(csm.genesisHash) {
log.Debugf("Block %s is the genesis block, therefore it is "+
"the selected parent by definition", blockHash)
return true, nil
}
virtualGhostdagData, err := csm.ghostdagDataStore.Get(csm.databaseContext, stagingArea, model.VirtualBlockHash, false)
if err != nil {
return false, err
}
log.Debugf("Selecting the next selected parent between "+
"the block %s the current selected parent %s", blockHash, virtualGhostdagData.SelectedParent())
nextVirtualSelectedParent, err := csm.ghostdagManager.ChooseSelectedParent(
stagingArea, virtualGhostdagData.SelectedParent(), blockHash)
if err != nil {
return false, err
}
log.Debugf("The next selected parent is: %s", nextVirtualSelectedParent)
return blockHash.Equal(nextVirtualSelectedParent), nil
}
func (csm *consensusStateManager) addTip(stagingArea *model.StagingArea, newTipHash *externalapi.DomainHash) (newTips []*externalapi.DomainHash, err error) {
log.Tracef("addTip start for new tip %s", newTipHash)
defer log.Tracef("addTip end for new tip %s", newTipHash)
log.Debugf("Calculating the new tips for new tip %s", newTipHash)
newTips, err = csm.calculateNewTips(stagingArea, newTipHash)
if err != nil {
return nil, err
}
csm.consensusStateStore.StageTips(stagingArea, newTips)
log.Debugf("Staged the new tips, len: %d", len(newTips))
return newTips, nil
}
func (csm *consensusStateManager) calculateNewTips(
stagingArea *model.StagingArea, newTipHash *externalapi.DomainHash) ([]*externalapi.DomainHash, error) {
log.Tracef("calculateNewTips start for new tip %s", newTipHash)
defer log.Tracef("calculateNewTips end for new tip %s", newTipHash)
if newTipHash.Equal(csm.genesisHash) {
log.Debugf("The new tip is the genesis block, therefore it is the only tip by definition")
return []*externalapi.DomainHash{newTipHash}, nil
}
currentTips, err := csm.consensusStateStore.Tips(stagingArea, csm.databaseContext)
if err != nil {
return nil, err
}
log.Debugf("The number of tips is: %d", len(currentTips))
log.Tracef("The current tips are: %s", currentTips)
newTipParents, err := csm.dagTopologyManager.Parents(stagingArea, newTipHash)
if err != nil {
return nil, err
}
log.Debugf("The parents of the new tip are: %s", newTipParents)
newTips := []*externalapi.DomainHash{newTipHash}
for _, currentTip := range currentTips {
isCurrentTipInNewTipParents := false
for _, newTipParent := range newTipParents {
if currentTip.Equal(newTipParent) {
isCurrentTipInNewTipParents = true
break
}
}
if !isCurrentTipInNewTipParents {
newTips = append(newTips, currentTip)
}
}
log.Debugf("The new number of tips is: %d", len(newTips))
log.Tracef("The new tips are: %s", newTips)
return newTips, nil
}