-
Notifications
You must be signed in to change notification settings - Fork 56
Expand file tree
/
Copy pathoracle.go
More file actions
364 lines (284 loc) · 11.1 KB
/
oracle.go
File metadata and controls
364 lines (284 loc) · 11.1 KB
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
package offchainreporting2plus
import (
"bytes"
"context"
"fmt"
"sync"
"github.com/prometheus/client_golang/prometheus"
"github.com/smartcontractkit/libocr/commontypes"
"github.com/smartcontractkit/libocr/internal/loghelper"
"github.com/smartcontractkit/libocr/offchainreporting2plus/internal/managed"
"github.com/smartcontractkit/libocr/offchainreporting2plus/ocr3types"
"github.com/smartcontractkit/libocr/offchainreporting2plus/types"
"github.com/smartcontractkit/libocr/subprocesses"
)
type OracleArgs interface {
oracleArgsMarker()
localConfig() types.LocalConfig
runManaged(ctx context.Context)
validate() error
}
// OCR2OracleArgs contains the configuration and services a caller must provide, in
// order to run the offchainreporting protocol.
type OCR2OracleArgs struct {
// A factory for producing network endpoints. A network endpoints consists of
// networking methods a consumer must implement to allow a node to
// communicate with other participating nodes.
BinaryNetworkEndpointFactory types.BinaryNetworkEndpointFactory
// V2Bootstrappers is the list of bootstrap node addresses and IDs for the v2 stack.
V2Bootstrappers []commontypes.BootstrapperLocator
// Tracks configuration changes.
ContractConfigTracker types.ContractConfigTracker
// Interfaces with the OCR2Aggregator smart contract's transmission related logic.
ContractTransmitter types.ContractTransmitter
// Database provides persistent storage.
Database types.Database
// LocalConfig contains oracle-specific configuration details which are not
// mandated by the on-chain configuration specification via OffchainAggregatoo.SetConfig.
LocalConfig types.LocalConfig
// Logger logs stuff.
Logger commontypes.Logger
// Used to send logs to a monitor.
MonitoringEndpoint commontypes.MonitoringEndpoint
// Enables adding metrics to track. This may be nil.
MetricsRegisterer prometheus.Registerer
// Computes a config digest using purely offchain logic.
OffchainConfigDigester types.OffchainConfigDigester
// OffchainKeyring contains the secret keys needed for the OCR protocol, and methods
// which use those keys without exposing them to the rest of the application.
OffchainKeyring types.OffchainKeyring
// OnchainKeyring is used to sign reports that can be validated
// offchain and by the target contract.
OnchainKeyring types.OnchainKeyring
// ReportingPluginFactory creates ReportingPlugins that determine the
// "application logic" used in a OCR2 protocol instance.
ReportingPluginFactory types.ReportingPluginFactory
}
func (OCR2OracleArgs) validate() error { return nil } // No validation needed for OCR2
func (OCR2OracleArgs) oracleArgsMarker() {}
func (args OCR2OracleArgs) localConfig() types.LocalConfig { return args.LocalConfig }
func (args OCR2OracleArgs) runManaged(ctx context.Context) {
logger := loghelper.MakeRootLoggerWithContext(args.Logger)
managed.RunManagedOCR2Oracle(
ctx,
args.V2Bootstrappers,
args.ContractConfigTracker,
args.ContractTransmitter,
args.Database,
args.LocalConfig,
logger,
args.MetricsRegisterer,
args.MonitoringEndpoint,
args.BinaryNetworkEndpointFactory,
args.OffchainConfigDigester,
args.OffchainKeyring,
args.OnchainKeyring,
args.ReportingPluginFactory,
)
}
// MercuryOracleArgs is used for OCR3 protocol instances that only use
// the Mercury-specific subset of OCR3 features.
type MercuryOracleArgs struct {
// A factory for producing network endpoints. A network endpoints consists of
// networking methods a consumer must implement to allow a node to
// communicate with other participating nodes.
BinaryNetworkEndpointFactory types.BinaryNetworkEndpointFactory
// V2Bootstrappers is the list of bootstrap node addresses and IDs for the v2 stack.
V2Bootstrappers []commontypes.BootstrapperLocator
// Tracks configuration changes.
ContractConfigTracker types.ContractConfigTracker
// Interfaces with the OCR2Aggregator smart contract's transmission related logic.
ContractTransmitter types.ContractTransmitter
// Database provides persistent storage.
Database ocr3types.Database
// LocalConfig contains oracle-specific configuration details which are not
// mandated by the on-chain configuration specification via OffchainAggregatoo.SetConfig.
LocalConfig types.LocalConfig
// Logger logs stuff.
Logger commontypes.Logger
// Enables adding metrics to track. This may be nil.
MetricsRegisterer prometheus.Registerer
// Used to send logs to a monitor.
MonitoringEndpoint commontypes.MonitoringEndpoint
// Computes a config digest using purely offchain logic.
OffchainConfigDigester types.OffchainConfigDigester
// OffchainKeyring contains the secret keys needed for the OCR protocol, and methods
// which use those keys without exposing them to the rest of the application.
OffchainKeyring types.OffchainKeyring
// OnchainKeyring is used to sign reports that can be validated
// offchain and by the target contract.
OnchainKeyring types.OnchainKeyring
// ReportingPluginFactory creates ReportingPlugins that determine the
// "application logic" used in an OCR protocol instance.
MercuryPluginFactory ocr3types.MercuryPluginFactory
}
func (MercuryOracleArgs) validate() error { return nil } // No validation needed for Mercury
func (MercuryOracleArgs) oracleArgsMarker() {}
func (args MercuryOracleArgs) localConfig() types.LocalConfig { return args.LocalConfig }
func (args MercuryOracleArgs) runManaged(ctx context.Context) {
logger := loghelper.MakeRootLoggerWithContext(args.Logger)
managed.RunManagedMercuryOracle(
ctx,
args.V2Bootstrappers,
args.ContractConfigTracker,
args.ContractTransmitter,
args.Database,
args.LocalConfig,
logger,
args.MetricsRegisterer,
args.MonitoringEndpoint,
args.BinaryNetworkEndpointFactory,
args.OffchainConfigDigester,
args.OffchainKeyring,
args.OnchainKeyring,
args.MercuryPluginFactory,
)
}
type OCR3OracleArgs[RI any] struct {
// A factory for producing network endpoints. A network endpoints consists of
// networking methods a consumer must implement to allow a node to
// communicate with other participating nodes.
BinaryNetworkEndpointFactory types.BinaryNetworkEndpointFactory
// V2Bootstrappers is the list of bootstrap node addresses and IDs for the v2 stack.
V2Bootstrappers []commontypes.BootstrapperLocator
// Tracks configuration changes.
ContractConfigTracker types.ContractConfigTracker
// Transmit reports to the targeted system (e.g. a blockchain)
ContractTransmitter ocr3types.ContractTransmitter[RI]
// Database provides persistent storage.
Database ocr3types.Database
// LocalConfig contains oracle-specific configuration details which are not
// mandated by the on-chain configuration specification via OffchainAggregatoo.SetConfig.
LocalConfig types.LocalConfig
// Logger logs stuff.
Logger commontypes.Logger
// Enables adding metrics to track. This may be nil.
MetricsRegisterer prometheus.Registerer
// Used to send logs to a monitor.
MonitoringEndpoint commontypes.MonitoringEndpoint
// Computes a config digest using purely offchain logic.
OffchainConfigDigester types.OffchainConfigDigester
// OffchainKeyring contains the secret keys needed for the OCR protocol, and methods
// which use those keys without exposing them to the rest of the application.
OffchainKeyring types.OffchainKeyring
// OnchainKeyring is used to sign reports that can be validated
// offchain and by the target contract.
//
// it is an error if both OnchainKeyring and ComparableOnchainKeyring are set
OnchainKeyring ocr3types.OnchainKeyring[RI]
// ComparableOnchainKeyring is used to verify that the onchain keyring
// It enable custom equality check when comparing onchain keys fetch from the contract
//
// it is an error if both OnchainKeyring and ComparableOnchainKeyring are set
ComparableOnchainKeyring ocr3types.ComparableOnchainKeyring[RI]
// PluginFactory creates Plugins that determine the "application logic" used
// in a protocol instance.
ReportingPluginFactory ocr3types.ReportingPluginFactory[RI]
}
func (OCR3OracleArgs[RI]) oracleArgsMarker() {}
func (args OCR3OracleArgs[RI]) localConfig() types.LocalConfig { return args.LocalConfig }
func (args OCR3OracleArgs[RI]) validate() error {
if args.OnchainKeyring != nil && args.ComparableOnchainKeyring != nil {
return fmt.Errorf("cannot set both OnchainKeyring and ComparableOnchainKeyring")
}
return nil
}
func (args OCR3OracleArgs[RI]) onchainKeyRing() ocr3types.ComparableOnchainKeyring[RI] {
if args.ComparableOnchainKeyring != nil {
return args.ComparableOnchainKeyring
}
return &shimComparableKeyRing[RI]{args.OnchainKeyring}
}
func (args OCR3OracleArgs[RI]) runManaged(ctx context.Context) {
logger := loghelper.MakeRootLoggerWithContext(args.Logger)
managed.RunManagedOCR3Oracle(
ctx,
args.V2Bootstrappers,
args.ContractConfigTracker,
args.ContractTransmitter,
args.Database,
args.LocalConfig,
logger,
args.MetricsRegisterer,
args.MonitoringEndpoint,
args.BinaryNetworkEndpointFactory,
args.OffchainConfigDigester,
args.OffchainKeyring,
args.onchainKeyRing(),
args.ReportingPluginFactory,
)
}
type shimComparableKeyRing[RI any] struct {
ocr3types.OnchainKeyring[RI]
}
func (k *shimComparableKeyRing[RI]) Equal(onchainPublicKey types.OnchainPublicKey) bool {
return bytes.Equal(k.PublicKey(), onchainPublicKey)
}
type oracleState int
const (
oracleStateUnstarted oracleState = iota
oracleStateStarted
oracleStateClosed
)
type Oracle interface {
Start() error
Close() error
}
type oracle struct {
lock sync.Mutex
state oracleState
oracleArgs OracleArgs
// subprocesses tracks completion of all go routines on Oracle.Close()
subprocesses subprocesses.Subprocesses
// cancel sends a cancel message to all subprocesses, via a context.Context
cancel context.CancelFunc
}
// NewOracle returns a newly initialized Oracle using the provided services
// and configuration.
func NewOracle(args OracleArgs) (Oracle, error) {
if err := SanityCheckLocalConfig(args.localConfig()); err != nil {
return nil, fmt.Errorf("bad local config while creating new oracle: %w", err)
}
if err := args.validate(); err != nil {
return nil, fmt.Errorf("bad oracle args while creating new oracle: %w", err)
}
return &oracle{
sync.Mutex{},
oracleStateUnstarted,
args,
subprocesses.Subprocesses{},
nil,
}, nil
}
// Start spins up a Oracle.
func (o *oracle) Start() error {
o.lock.Lock()
defer o.lock.Unlock()
if o.state != oracleStateUnstarted {
return fmt.Errorf("can only start Oracle once")
}
o.state = oracleStateStarted
ctx, cancel := context.WithCancel(context.Background())
o.cancel = cancel
o.subprocesses.Go(func() {
defer cancel()
o.oracleArgs.runManaged(ctx)
})
return nil
}
// Close shuts down an oracle. Can safely be called multiple times.
func (o *oracle) Close() error {
o.lock.Lock()
defer o.lock.Unlock()
if o.state != oracleStateStarted {
return fmt.Errorf("can only close a started oracle")
}
o.state = oracleStateClosed
if o.cancel != nil {
o.cancel()
}
// Wait for all subprocesses to shut down, before shutting down other resources.
// (Wouldn't want anything to panic from attempting to use a closed resource.)
o.subprocesses.Wait()
return nil
}