8
8
9
9
"github.com/Layr-Labs/eigenda/api"
10
10
disperser_rpc "github.com/Layr-Labs/eigenda/api/grpc/disperser/v2"
11
+ "github.com/Layr-Labs/eigenda/common"
11
12
"github.com/Layr-Labs/eigenda/core"
12
13
corev2 "github.com/Layr-Labs/eigenda/core/v2"
13
14
dispv2 "github.com/Layr-Labs/eigenda/disperser/common/v2"
@@ -23,13 +24,29 @@ type DisperserClientConfig struct {
23
24
UseSecureGrpcFlag bool
24
25
}
25
26
27
+ // DisperserClient manages communication with the disperser server.
26
28
type DisperserClient interface {
29
+ // Close closes the grpc connection to the disperser server.
27
30
Close () error
28
- DisperseBlob (ctx context.Context , data []byte , blobVersion corev2.BlobVersion , quorums []core.QuorumID ) (* dispv2.BlobStatus , corev2.BlobKey , error )
31
+ // DisperseBlob disperses a blob with the given data, blob version, and quorums.
32
+ DisperseBlob (
33
+ ctx context.Context ,
34
+ data []byte ,
35
+ blobVersion corev2.BlobVersion ,
36
+ quorums []core.QuorumID ) (* dispv2.BlobStatus , corev2.BlobKey , error )
37
+ // DisperseBlobWithProbe is similar to DisperseBlob, but also takes a SequenceProbe to capture metrics.
38
+ // If the probe is nil, no metrics are captured.
39
+ DisperseBlobWithProbe (
40
+ ctx context.Context ,
41
+ data []byte ,
42
+ blobVersion corev2.BlobVersion ,
43
+ quorums []core.QuorumID ,
44
+ probe * common.SequenceProbe ) (* dispv2.BlobStatus , corev2.BlobKey , error )
45
+ // GetBlobStatus returns the status of a blob with the given blob key.
29
46
GetBlobStatus (ctx context.Context , blobKey corev2.BlobKey ) (* disperser_rpc.BlobStatusReply , error )
47
+ // GetBlobCommitment returns the blob commitment for a given blob payload.
30
48
GetBlobCommitment (ctx context.Context , data []byte ) (* disperser_rpc.BlobCommitmentReply , error )
31
49
}
32
-
33
50
type disperserClient struct {
34
51
config * DisperserClientConfig
35
52
signer corev2.BlobRequestSigner
@@ -39,7 +56,7 @@ type disperserClient struct {
39
56
client disperser_rpc.DisperserClient
40
57
prover encoding.Prover
41
58
accountant * Accountant
42
- requestMutex sync.Mutex // Mutex to ensure only one dispersal request is sent at a time
59
+ accountantLock sync.Mutex
43
60
}
44
61
45
62
var _ DisperserClient = & disperserClient {}
@@ -128,42 +145,68 @@ func (c *disperserClient) DisperseBlob(
128
145
blobVersion corev2.BlobVersion ,
129
146
quorums []core.QuorumID ,
130
147
) (* dispv2.BlobStatus , corev2.BlobKey , error ) {
131
- c .requestMutex .Lock ()
132
- defer c .requestMutex .Unlock ()
148
+ return c .DisperseBlobWithProbe (ctx , data , blobVersion , quorums , nil )
149
+ }
150
+
151
+ // DisperseBlobWithProbe disperses a blob with the given data, blob version, and quorums. If sequenceProbe is not nil,
152
+ // the probe is used to capture metrics during the dispersal process.
153
+ func (c * disperserClient ) DisperseBlobWithProbe (
154
+ ctx context.Context ,
155
+ data []byte ,
156
+ blobVersion corev2.BlobVersion ,
157
+ quorums []core.QuorumID ,
158
+ probe * common.SequenceProbe ,
159
+ ) (* dispv2.BlobStatus , corev2.BlobKey , error ) {
160
+
161
+ if len (quorums ) == 0 {
162
+ return nil , [32 ]byte {}, api .NewErrorInvalidArg ("quorum numbers must be provided" )
163
+ }
164
+ if c .signer == nil {
165
+ return nil , [32 ]byte {}, api .NewErrorInternal ("uninitialized signer for authenticated dispersal" )
166
+ }
167
+ for _ , q := range quorums {
168
+ if q > corev2 .MaxQuorumID {
169
+ return nil , [32 ]byte {}, api .NewErrorInvalidArg ("quorum number must be less than 256" )
170
+ }
171
+ }
133
172
134
173
err := c .initOnceGrpcConnection ()
135
174
if err != nil {
136
175
return nil , [32 ]byte {}, api .NewErrorFailover (err )
137
176
}
177
+
178
+ probe .SetStage ("acquire_accountant_lock" )
179
+ c .accountantLock .Lock ()
180
+
181
+ probe .SetStage ("prepare_for_dispersal" )
182
+
138
183
err = c .initOncePopulateAccountant (ctx )
139
184
if err != nil {
140
185
return nil , [32 ]byte {}, api .NewErrorFailover (err )
141
186
}
142
187
143
- if c .signer == nil {
144
- return nil , [32 ]byte {}, api .NewErrorInternal ("uninitialized signer for authenticated dispersal" )
145
- }
146
-
147
188
symbolLength := encoding .GetBlobLengthPowerOf2 (uint (len (data )))
148
189
payment , err := c .accountant .AccountBlob (ctx , time .Now ().UnixNano (), uint64 (symbolLength ), quorums )
149
190
if err != nil {
191
+ c .accountantLock .Unlock ()
150
192
return nil , [32 ]byte {}, fmt .Errorf ("error accounting blob: %w" , err )
151
193
}
152
194
153
- if len (quorums ) == 0 {
154
- return nil , [32 ]byte {}, api .NewErrorInvalidArg ("quorum numbers must be provided" )
155
- }
156
-
157
- for _ , q := range quorums {
158
- if q > corev2 .MaxQuorumID {
159
- return nil , [32 ]byte {}, api .NewErrorInvalidArg ("quorum number must be less than 256" )
160
- }
195
+ if payment .CumulativePayment == nil || payment .CumulativePayment .Sign () == 0 {
196
+ // This request is using reserved bandwidth, no need to prevent parallel dispersal.
197
+ c .accountantLock .Unlock ()
198
+ } else {
199
+ // This request is using on-demand bandwidth, current implementation requires sequential dispersal.
200
+ defer c .accountantLock .Unlock ()
161
201
}
162
202
163
203
// check every 32 bytes of data are within the valid range for a bn254 field element
164
204
_ , err = rs .ToFrArray (data )
165
205
if err != nil {
166
- return nil , [32 ]byte {}, fmt .Errorf ("encountered an error to convert a 32-bytes into a valid field element, please use the correct format where every 32bytes(big-endian) is less than 21888242871839275222246405745257275088548364400416034343698204186575808495617 %w" , err )
206
+ return nil , [32 ]byte {}, fmt .Errorf (
207
+ "encountered an error to convert a 32-bytes into a valid field element, " +
208
+ "please use the correct format where every 32bytes(big-endian) is less than " +
209
+ "21888242871839275222246405745257275088548364400416034343698204186575808495617 %w" , err )
167
210
}
168
211
169
212
var blobCommitments encoding.BlobCommitments
@@ -220,6 +263,8 @@ func (c *disperserClient) DisperseBlob(
220
263
BlobHeader : blobHeaderProto ,
221
264
}
222
265
266
+ probe .SetStage ("send_to_disperser" )
267
+
223
268
reply , err := c .client .DisperseBlob (ctx , request )
224
269
if err != nil {
225
270
return nil , [32 ]byte {}, fmt .Errorf ("error while calling DisperseBlob: %w" , err )
@@ -230,6 +275,8 @@ func (c *disperserClient) DisperseBlob(
230
275
return nil , [32 ]byte {}, err
231
276
}
232
277
278
+ probe .SetStage ("verify_blob_key" )
279
+
233
280
if verifyReceivedBlobKey (blobHeader , reply ) != nil {
234
281
return nil , [32 ]byte {}, fmt .Errorf ("verify received blob key: %w" , err )
235
282
}
@@ -245,9 +292,9 @@ func (c *disperserClient) DisperseBlob(
245
292
//
246
293
// This function returns nil if the verification succeeds, and otherwise returns an error describing the failure
247
294
func verifyReceivedBlobKey (
248
- // the blob header which was constructed locally and sent to the disperser
295
+ // the blob header which was constructed locally and sent to the disperser
249
296
blobHeader * corev2.BlobHeader ,
250
- // the reply received back from the disperser
297
+ // the reply received back from the disperser
251
298
disperserReply * disperser_rpc.DisperseBlobReply ,
252
299
) error {
253
300
0 commit comments