@@ -8,11 +8,13 @@ import (
8
8
"errors"
9
9
"fmt"
10
10
"math/big"
11
+ "os"
11
12
"strings"
12
13
"sync"
13
14
"time"
14
15
15
16
txclient "github.com/celestiaorg/celestia-node/api/client"
17
+ node "github.com/celestiaorg/celestia-node/api/rpc/client"
16
18
"github.com/celestiaorg/celestia-node/blob"
17
19
"github.com/celestiaorg/celestia-node/nodebuilder/p2p"
18
20
"github.com/celestiaorg/celestia-node/state"
@@ -31,26 +33,27 @@ import (
31
33
)
32
34
33
35
type DAConfig struct {
34
- Enable bool `koanf:"enable"`
35
- GasPrice float64 `koanf:"gas-price" reload:"hot"`
36
- GasMultiplier float64 `koanf:"gas-multiplier" reload:"hot"`
37
- Rpc string `koanf:"rpc" reload:"hot"`
38
- ReadRpc string `koanf:"read-rpc" reload:"hot"`
39
- NamespaceId string `koanf:"namespace-id" `
40
- AuthToken string `koanf:"auth-token" reload:"hot"`
41
- ReadAuthToken string `koanf:"read-auth-token" reload:"hot"`
42
- CoreToken string `koanf:"core-token" reload:"hot"`
43
- CoreURL string `koanf:"core-url" reload:"hot"`
44
- CoreNetwork string `koanf:"core-network" reload:"hot"`
45
- KeyName string `koanf:"key-name" reload:"hot"`
46
- KeyPath string `koanf:"key-path" reload:"hot"`
47
- BackendName string `koanf:"backend-name" reload:"hot"`
48
- NoopWriter bool `koanf:"noop-writer" reload:"hot"`
49
- EnableDATLS bool `koanf:"enable-da-tls" reload:"hot"`
50
- EnableCoreTLS bool `koanf:"enable-core-tls" reload:"hot"`
51
- ValidatorConfig ValidatorConfig `koanf:"validator-config" reload:"hot"`
52
- ReorgOnReadFailure bool `koanf:"dangerous-reorg-on-read-failure"`
53
- CacheCleanupTime time.Duration `koanf:"cache-time"`
36
+ WithWriter bool `koanf:"with-writer"`
37
+ GasPrice float64 `koanf:"gas-price" reload:"hot"`
38
+ GasMultiplier float64 `koanf:"gas-multiplier" reload:"hot"`
39
+ Rpc string `koanf:"rpc" reload:"hot"`
40
+ ReadRpc string `koanf:"read-rpc" reload:"hot"`
41
+ NamespaceId string `koanf:"namespace-id" `
42
+ AuthToken string `koanf:"auth-token" reload:"hot"`
43
+ ReadAuthToken string `koanf:"read-auth-token" reload:"hot"`
44
+ CoreToken string `koanf:"core-token" reload:"hot"`
45
+ CoreURL string `koanf:"core-url" reload:"hot"`
46
+ CoreNetwork string `koanf:"core-network" reload:"hot"`
47
+ KeyName string `koanf:"key-name" reload:"hot"`
48
+ KeyPath string `koanf:"key-path" reload:"hot"`
49
+ BackendName string `koanf:"backend-name" reload:"hot"`
50
+ NoopWriter bool `koanf:"noop-writer" reload:"hot"`
51
+ EnableDATLS bool `koanf:"enable-da-tls" reload:"hot"`
52
+ EnableCoreTLS bool `koanf:"enable-core-tls" reload:"hot"`
53
+ ValidatorConfig ValidatorConfig `koanf:"validator-config" reload:"hot"`
54
+ ReorgOnReadFailure bool `koanf:"dangerous-reorg-on-read-failure"`
55
+ CacheCleanupTime time.Duration `koanf:"cache-time"`
56
+ ExperimentalTxClient bool `koanf:"experimental-tx-client"`
54
57
}
55
58
56
59
type ValidatorConfig struct {
@@ -96,16 +99,18 @@ func IsCelestiaMessageHeaderByte(header byte) bool {
96
99
97
100
type CelestiaDA struct {
98
101
Cfg * DAConfig
99
- Client * txclient.Client
100
- ReadClient * txclient.Client
102
+ Client * node.Client
103
+ TxClient * txclient.Client
104
+ ReadClient * txclient.ReadClient
101
105
102
106
Namespace * libshare.Namespace
103
107
104
108
messageCache sync.Map
105
109
}
106
110
107
111
func CelestiaDAConfigAddOptions (prefix string , f * pflag.FlagSet ) {
108
- f .Bool (prefix + ".enable" , false , "Enable Celestia DA" )
112
+ f .Bool (prefix + ".with-writer" , false , "Enable using the DA Server for writing data to Celestia" )
113
+ f .Bool (prefix + ".experimental-tx-client" , false , "Enable using the DA Server for writing data to Celestia" )
109
114
f .Float64 (prefix + ".gas-price" , 0.01 , "Gas for retrying Celestia transactions" )
110
115
f .Float64 (prefix + ".gas-multiplier" , 1.01 , "Gas multiplier for Celestia transactions" )
111
116
f .String (prefix + ".rpc" , "" , "Rpc endpoint for celestia-node" )
@@ -116,8 +121,8 @@ func CelestiaDAConfigAddOptions(prefix string, f *pflag.FlagSet) {
116
121
f .String (prefix + ".core-token" , "" , "Auth token for Core Celestia Node Endpoint" )
117
122
f .String (prefix + ".core-url" , "" , "URL to Celestia Core endpoint" )
118
123
f .String (prefix + ".core-network" , "celestia" , "Celestia Network to use" )
119
- f .String (prefix + ".key-name" , "my_key " , "key name to use" )
120
- f .String (prefix + ".key-path" , "./keys " , "key path to use" )
124
+ f .String (prefix + ".key-name" , "my_celes_key " , "key name to use" )
125
+ f .String (prefix + ".key-path" , "" , "key path to use" )
121
126
f .String (prefix + ".backend-name" , "test" , "keyring backend to use" )
122
127
f .Bool (prefix + ".enable-da-tls" , false , "enable TLS for DA node" )
123
128
f .Bool (prefix + ".enable-core-tls" , false , "enable TLS for Core node" )
@@ -129,66 +134,36 @@ func CelestiaDAConfigAddOptions(prefix string, f *pflag.FlagSet) {
129
134
f .Duration (prefix + ".cache-time" , time .Hour / 2 , "how often to clean the in memory cache" )
130
135
}
131
136
132
- func NewCelestiaDA (cfg * DAConfig ) (* CelestiaDA , error ) {
133
- if cfg == nil {
134
- return nil , errors .New ("celestia cfg cannot be blank" )
137
+ // DefaultKeyringPath constructs the default keyring path using the given
138
+ // node type and network.
139
+ var DefaultKeyringPath = func (tp string , network string ) (string , error ) {
140
+ home := os .Getenv ("CELESTIA_HOME" )
141
+ if home != "" {
142
+ return home , nil
135
143
}
136
144
137
- // Create a keyring
138
- _ , err := txclient .KeyringWithNewKey (txclient.KeyringConfig {
139
- KeyName : cfg .KeyName ,
140
- BackendName : cfg .BackendName ,
141
- }, cfg .KeyPath )
145
+ home , err := os .UserHomeDir ()
142
146
if err != nil {
143
- return nil , err
147
+ return "" , err
144
148
}
145
149
146
- // Configure the client
147
- clientCfg := txclient.Config {
148
- ReadConfig : txclient.ReadConfig {
149
- BridgeDAAddr : cfg .Rpc ,
150
- DAAuthToken : cfg .AuthToken ,
151
- EnableDATLS : cfg .EnableDATLS ,
152
- },
153
- SubmitConfig : txclient.SubmitConfig {
154
- DefaultKeyName : cfg .KeyName ,
155
- Network : p2p .Network (cfg .CoreNetwork ),
156
- CoreGRPCConfig : txclient.CoreGRPCConfig {
157
- Addr : cfg .CoreURL ,
158
- TLSEnabled : cfg .EnableCoreTLS ,
159
- AuthToken : cfg .CoreToken ,
160
- },
161
- },
150
+ if network == "mainnet" {
151
+ return fmt .Sprintf ("%s/.celestia-%s/keys" , home , strings .ToLower (tp )), nil
162
152
}
153
+ // only include network name in path for testnets and custom networks
154
+ return fmt .Sprintf (
155
+ "%s/.celestia-%s-%s/keys" ,
156
+ home ,
157
+ strings .ToLower (tp ),
158
+ strings .ToLower (network ),
159
+ ), nil
160
+ }
163
161
164
- readClient , err := txclient .NewReadClient (context .Background (), clientCfg .ReadConfig )
165
- if err != nil {
166
- log .Error ("DEBUG: Failed to create celestia client" , "err" , err , "BridgeDAAddr" , clientCfg .ReadConfig .BridgeDAAddr , "CoreAddr" , clientCfg .SubmitConfig .CoreGRPCConfig .Addr )
167
- return nil , err
162
+ func NewCelestiaDA (cfg * DAConfig ) (* CelestiaDA , error ) {
163
+ if cfg == nil {
164
+ return nil , errors .New ("celestia cfg cannot be blank" )
168
165
}
169
166
170
- celestiaClient := & txclient.Client {
171
- ReadClient : * readClient ,
172
- }
173
- // if cfg.ReadRpc != "" && cfg.ReadAuthToken != "" {
174
- // log.Info("DEBUG: Configuring read client", "cfg.ReadRpc", cfg.ReadRpc)
175
- // readClientCfg := txclient.Config{
176
- // ReadConfig: txclient.ReadConfig{
177
- // BridgeDAAddr: cfg.ReadRpc,
178
- // DAAuthToken: cfg.ReadAuthToken,
179
- // EnableDATLS: cfg.EnableDATLS,
180
- // },
181
- // }
182
- // log.Info("DEBUG: About to create read client", "ReadBridgeDAAddr", readClientCfg.ReadConfig.BridgeDAAddr)
183
- // readClient, err = txclient.New(context.Background(), readClientCfg, kr)
184
- // if err != nil {
185
- // log.Error("DEBUG: Failed to create read client", "err", err, "ReadBridgeDAAddr", readClientCfg.ReadConfig.BridgeDAAddr)
186
- // return nil, err
187
- // }
188
- // } else {
189
- // readClient = celestiaClient
190
- // }
191
-
192
167
if cfg .NamespaceId == "" {
193
168
return nil , errors .New ("namespace id cannot be blank" )
194
169
}
@@ -202,10 +177,106 @@ func NewCelestiaDA(cfg *DAConfig) (*CelestiaDA, error) {
202
177
return nil , err
203
178
}
204
179
180
+ var readClient * txclient.ReadClient
181
+ var writeClient * txclient.Client
182
+ var daClient * node.Client
183
+
184
+ // use dedicated read rpc or use the same as the da-client
185
+ var readConfig txclient.ReadConfig
186
+ if cfg .ReadRpc != "" && cfg .ReadAuthToken != "" {
187
+ readConfig = txclient.ReadConfig {
188
+ BridgeDAAddr : cfg .ReadRpc ,
189
+ DAAuthToken : cfg .ReadAuthToken ,
190
+ EnableDATLS : cfg .EnableDATLS ,
191
+ }
192
+ } else {
193
+ readConfig = txclient.ReadConfig {
194
+ BridgeDAAddr : cfg .Rpc ,
195
+ DAAuthToken : cfg .AuthToken ,
196
+ EnableDATLS : cfg .EnableDATLS ,
197
+ }
198
+ }
199
+
200
+ if cfg .WithWriter {
201
+ // compatibility to connect with a light node / bridge node without grpc
202
+ // grpc client currently under "experimental"
203
+ if cfg .ExperimentalTxClient {
204
+ var err error
205
+ if cfg .KeyPath == "" {
206
+ cfg .KeyPath , err = DefaultKeyringPath ("light" , cfg .CoreNetwork )
207
+ }
208
+
209
+ log .Info ("Key path" , "path" , cfg .KeyPath )
210
+ // Create a keyring
211
+ kr , err := txclient .KeyringWithNewKey (txclient.KeyringConfig {
212
+ KeyName : cfg .KeyName ,
213
+ BackendName : cfg .BackendName ,
214
+ }, cfg .KeyPath )
215
+ if err != nil {
216
+ log .Error ("failed to create keyring" )
217
+ return nil , err
218
+ }
219
+
220
+ if cfg .CoreURL == "" {
221
+ cfg .CoreURL = cfg .Rpc
222
+ }
223
+
224
+ log .Info ("Core URL: " , "url" , cfg .CoreURL )
225
+
226
+ // Configure the client
227
+ clientCfg := txclient.Config {
228
+ ReadConfig : txclient.ReadConfig {
229
+ BridgeDAAddr : cfg .Rpc ,
230
+ DAAuthToken : cfg .AuthToken ,
231
+ EnableDATLS : cfg .EnableDATLS ,
232
+ },
233
+ SubmitConfig : txclient.SubmitConfig {
234
+ DefaultKeyName : cfg .KeyName ,
235
+ Network : p2p .Network (cfg .CoreNetwork ),
236
+ CoreGRPCConfig : txclient.CoreGRPCConfig {
237
+ Addr : cfg .CoreURL ,
238
+ TLSEnabled : cfg .EnableCoreTLS ,
239
+ AuthToken : cfg .CoreToken ,
240
+ },
241
+ },
242
+ }
243
+
244
+ writeClient , err = txclient .New (context .Background (), clientCfg , kr )
245
+ if err != nil {
246
+ log .Error ("failed to initialize client" , "err" , err )
247
+ return nil , err
248
+ }
249
+
250
+ readClient , err = txclient .NewReadClient (context .Background (), readConfig )
251
+ if err != nil {
252
+ log .Error ("error initializing read client" , "err" , err )
253
+ return nil , err
254
+ }
255
+
256
+ log .Info ("Succesfully initialized write and read experimental txclient" , "writeRpc" , cfg .CoreURL , "readRpc" , readConfig .BridgeDAAddr )
257
+ } else {
258
+ daClient , err = node .NewClient (context .Background (), cfg .Rpc , cfg .AuthToken )
259
+ if err != nil {
260
+ log .Error ("could not initialize node client for da rpc" , "err" , err )
261
+ return nil , err
262
+ }
263
+ }
264
+
265
+ } else {
266
+ var err error
267
+ readClient , err = txclient .NewReadClient (context .Background (), readConfig )
268
+ if err != nil {
269
+ log .Error ("could not initialize txclient.ReadClient" , "err" , err )
270
+ return nil , err
271
+ }
272
+ log .Info ("Succesfully initialized read only client" , "rpc" , cfg .Rpc )
273
+ }
274
+
205
275
da := & CelestiaDA {
206
276
Cfg : cfg ,
207
- Client : celestiaClient ,
208
- ReadClient : celestiaClient ,
277
+ Client : daClient ,
278
+ TxClient : writeClient ,
279
+ ReadClient : readClient ,
209
280
Namespace : & namespace ,
210
281
}
211
282
@@ -216,6 +287,10 @@ func NewCelestiaDA(cfg *DAConfig) (*CelestiaDA, error) {
216
287
217
288
func (c * CelestiaDA ) Stop () error {
218
289
c .Client .Close ()
290
+ c .ReadClient .Close ()
291
+ if c .Cfg .ExperimentalTxClient {
292
+ c .TxClient .Close ()
293
+ }
219
294
return nil
220
295
}
221
296
@@ -238,6 +313,11 @@ func (c *CelestiaDA) Store(ctx context.Context, message []byte) ([]byte, error)
238
313
return nil , errors .New ("NoopWriter enabled" )
239
314
}
240
315
316
+ if ! c .Cfg .WithWriter {
317
+ log .Warn ("Attempted to call Store() without writer enabled" , "cfg.withWriter" , c .Cfg .WithWriter )
318
+ return nil , errors .New ("writer not enabled" )
319
+ }
320
+
241
321
// Create hash of message to use as cache key
242
322
msgHash := crypto .Keccak256 (message )
243
323
msgHashHex := hex .EncodeToString (msgHash )
@@ -268,7 +348,12 @@ func (c *CelestiaDA) Store(ctx context.Context, message []byte) ([]byte, error)
268
348
// add submit options
269
349
submitOptions := & blob.SubmitOptions {}
270
350
state .WithGasPrice (gasPrice )(submitOptions )
271
- height , err = c .Client .Blob .Submit (ctx , []* blob.Blob {dataBlob }, submitOptions )
351
+ if c .Cfg .ExperimentalTxClient {
352
+ height , err = c .TxClient .Blob .Submit (ctx , []* blob.Blob {dataBlob }, submitOptions )
353
+
354
+ } else {
355
+ height , err = c .Client .Blob .Submit (ctx , []* blob.Blob {dataBlob }, submitOptions )
356
+ }
272
357
if err != nil {
273
358
switch {
274
359
case strings .Contains (err .Error (), ErrTxTimedout .Error ()), strings .Contains (err .Error (), ErrTxAlreadyInMempool .Error ()), strings .Contains (err .Error (), ErrTxIncorrectAccountSequence .Error ()):
@@ -611,7 +696,7 @@ func (c *CelestiaDA) GetProof(ctx context.Context, msg []byte) ([]byte, error) {
611
696
log .Info ("Verified Celestia Attestation" , "height" , blobPointer .BlockHeight , "valid" , valid )
612
697
613
698
if valid {
614
- rangeResult , err := c .Client .Share .GetRange (ctx , blobPointer .BlockHeight , int (blobPointer .Start ), int (blobPointer .Start + blobPointer .SharesLength ))
699
+ rangeResult , err := c .ReadClient .Share .GetRange (ctx , blobPointer .BlockHeight , int (blobPointer .Start ), int (blobPointer .Start + blobPointer .SharesLength ))
615
700
if err != nil {
616
701
celestiaValidationFailureCounter .Inc (1 )
617
702
log .Error ("Unable to get ShareProof" , "err" , err )
0 commit comments