-
Notifications
You must be signed in to change notification settings - Fork 672
/
context.go
206 lines (170 loc) · 5.6 KB
/
context.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
// Copyright (C) 2019-2021, Ava Labs, Inc. All rights reserved.
// See the file LICENSE for licensing terms.
package snow
import (
"crypto"
"crypto/x509"
"sync"
"github.com/prometheus/client_golang/prometheus"
"github.com/ava-labs/avalanchego/api/keystore"
"github.com/ava-labs/avalanchego/api/metrics"
"github.com/ava-labs/avalanchego/chains/atomic"
"github.com/ava-labs/avalanchego/ids"
"github.com/ava-labs/avalanchego/snow/validators"
"github.com/ava-labs/avalanchego/utils"
"github.com/ava-labs/avalanchego/utils/logging"
)
type EventDispatcher interface {
Issuer
// If the returned error is non-nil, the chain associated with [ctx] should shut
// down and not commit [container] or any other container to its database as accepted.
// Accept must be called before [containerID] is committed to the VM as accepted.
Acceptor
Rejector
}
type SubnetLookup interface {
SubnetID(chainID ids.ID) (ids.ID, error)
}
// ContextInitializable represents an object that can be initialized
// given a *Context object
type ContextInitializable interface {
// InitCtx initializes an object provided a *Context object
InitCtx(ctx *Context)
}
// Context is information about the current execution.
// [NetworkID] is the ID of the network this context exists within.
// [ChainID] is the ID of the chain this context exists within.
// [NodeID] is the ID of this node
type Context struct {
NetworkID uint32
SubnetID ids.ID
ChainID ids.ID
NodeID ids.ShortID
XChainID ids.ID
AVAXAssetID ids.ID
Log logging.Logger
Lock sync.RWMutex
Keystore keystore.BlockchainKeystore
SharedMemory atomic.SharedMemory
BCLookup ids.AliaserReader
SNLookup SubnetLookup
Metrics metrics.OptionalGatherer
// snowman++ attributes
ValidatorState validators.State // interface for P-Chain validators
StakingLeafSigner crypto.Signer // block signer
StakingCertLeaf *x509.Certificate // block certificate
}
type ConsensusContext struct {
*Context
Registerer prometheus.Registerer
DecisionDispatcher EventDispatcher
ConsensusDispatcher EventDispatcher
// Non-zero iff this chain bootstrapped.
state utils.AtomicInterface
// Non-zero iff this chain is executing transactions.
executing utils.AtomicBool
// Indicates this chain is available to only validators.
validatorOnly utils.AtomicBool
}
func (ctx *ConsensusContext) SetState(newState State) {
ctx.state.SetValue(newState)
}
func (ctx *ConsensusContext) GetState() State {
stateInf := ctx.state.GetValue()
return stateInf.(State)
}
// IsExecuting returns true iff this chain is still executing transactions.
func (ctx *ConsensusContext) IsExecuting() bool {
return ctx.executing.GetValue()
}
// Executing marks this chain as executing or not.
// Set to "true" if there's an ongoing transaction.
func (ctx *ConsensusContext) Executing(b bool) {
ctx.executing.SetValue(b)
}
// IsValidatorOnly returns true iff this chain is available only to validators
func (ctx *ConsensusContext) IsValidatorOnly() bool {
return ctx.validatorOnly.GetValue()
}
// SetValidatorOnly marks this chain as available only to validators
func (ctx *ConsensusContext) SetValidatorOnly() {
ctx.validatorOnly.SetValue(true)
}
func DefaultContextTest() *Context {
return &Context{
NetworkID: 0,
SubnetID: ids.Empty,
ChainID: ids.Empty,
NodeID: ids.ShortEmpty,
Log: logging.NoLog{},
BCLookup: ids.NewAliaser(),
Metrics: metrics.NewOptionalGatherer(),
}
}
func DefaultConsensusContextTest() *ConsensusContext {
return &ConsensusContext{
Context: DefaultContextTest(),
Registerer: prometheus.NewRegistry(),
DecisionDispatcher: noOpEventDispatcher{},
ConsensusDispatcher: noOpEventDispatcher{},
}
}
type noOpEventDispatcher struct{}
func (noOpEventDispatcher) Issue(*ConsensusContext, ids.ID, []byte) error { return nil }
func (noOpEventDispatcher) Accept(*ConsensusContext, ids.ID, []byte) error { return nil }
func (noOpEventDispatcher) Reject(*ConsensusContext, ids.ID, []byte) error { return nil }
var _ EventDispatcher = &EventDispatcherTracker{}
func NewEventDispatcherTracker() *EventDispatcherTracker {
return &EventDispatcherTracker{
issued: make(map[ids.ID]int),
accepted: make(map[ids.ID]int),
rejected: make(map[ids.ID]int),
}
}
// EventDispatcherTracker tracks the dispatched events by its ID and counts.
// Useful for testing.
type EventDispatcherTracker struct {
mu sync.RWMutex
// maps "issued" ID to its count
issued map[ids.ID]int
// maps "accepted" ID to its count
accepted map[ids.ID]int
// maps "rejected" ID to its count
rejected map[ids.ID]int
}
func (evd *EventDispatcherTracker) IsIssued(containerID ids.ID) (int, bool) {
evd.mu.RLock()
cnt, ok := evd.issued[containerID]
evd.mu.RUnlock()
return cnt, ok
}
func (evd *EventDispatcherTracker) Issue(ctx *ConsensusContext, containerID ids.ID, container []byte) error {
evd.mu.Lock()
evd.issued[containerID]++
evd.mu.Unlock()
return nil
}
func (evd *EventDispatcherTracker) Accept(ctx *ConsensusContext, containerID ids.ID, container []byte) error {
evd.mu.Lock()
evd.accepted[containerID]++
evd.mu.Unlock()
return nil
}
func (evd *EventDispatcherTracker) IsAccepted(containerID ids.ID) (int, bool) {
evd.mu.RLock()
cnt, ok := evd.accepted[containerID]
evd.mu.RUnlock()
return cnt, ok
}
func (evd *EventDispatcherTracker) Reject(ctx *ConsensusContext, containerID ids.ID, container []byte) error {
evd.mu.Lock()
evd.rejected[containerID]++
evd.mu.Unlock()
return nil
}
func (evd *EventDispatcherTracker) IsRejected(containerID ids.ID) (int, bool) {
evd.mu.RLock()
cnt, ok := evd.rejected[containerID]
evd.mu.RUnlock()
return cnt, ok
}