@@ -73,41 +73,35 @@ func (m *Meterer) Start(ctx context.Context) {
73
73
74
74
// MeterRequest validates a blob header and adds it to the meterer's state
75
75
// TODO: return error if there's a rejection (with reasoning) or internal error (should be very rare)
76
- func (m * Meterer ) MeterRequest (ctx context.Context , header core.PaymentMetadata , numSymbols uint64 , quorumNumbers []uint8 , receivedAt time.Time ) (uint64 , error ) {
76
+ func (m * Meterer ) MeterRequest (ctx context.Context , header core.PaymentMetadata , numSymbols uint64 , quorumNumbers []uint8 , receivedAt time.Time ) (map [core. QuorumID ] uint64 , error ) {
77
77
m .logger .Info ("Validating incoming request's payment metadata" , "paymentMetadata" , header , "numSymbols" , numSymbols , "quorumNumbers" , quorumNumbers )
78
78
79
79
params , err := m .ChainPaymentState .GetPaymentGlobalParams ()
80
80
if err != nil {
81
- return 0 , fmt .Errorf ("failed to get payment global params: %w" , err )
81
+ return nil , fmt .Errorf ("failed to get payment global params: %w" , err )
82
82
}
83
83
// Validate against the payment method
84
84
if ! payment_logic .IsOnDemandPayment (& header ) {
85
85
reservations , err := m .ChainPaymentState .GetReservedPaymentByAccountAndQuorums (ctx , header .AccountID , quorumNumbers )
86
86
if err != nil {
87
- return 0 , fmt .Errorf ("failed to get active reservation by account: %w" , err )
87
+ return nil , fmt .Errorf ("failed to get active reservation by account: %w" , err )
88
88
}
89
- if err := m .serveReservationRequest (ctx , params , header , reservations , numSymbols , quorumNumbers , receivedAt ); err != nil {
90
- return 0 , fmt .Errorf ("invalid reservation request: %w" , err )
91
- }
92
- } else {
93
- onDemandPayment , err := m .ChainPaymentState .GetOnDemandPaymentByAccount (ctx , header .AccountID )
89
+ usage , err := m .serveReservationRequest (ctx , params , header , reservations , numSymbols , quorumNumbers , receivedAt )
94
90
if err != nil {
95
- return 0 , fmt .Errorf ("failed to get on-demand payment by account: %w" , err )
96
- }
97
- if err := m .serveOnDemandRequest (ctx , params , header , onDemandPayment , numSymbols , quorumNumbers , receivedAt ); err != nil {
98
- return 0 , fmt .Errorf ("invalid on-demand request: %w" , err )
91
+ return nil , fmt .Errorf ("invalid reservation request: %w" , err )
99
92
}
93
+ return usage , nil
100
94
}
101
95
102
- // TODO(hopeyen): each quorum can have different min num symbols; the returned symbolsCharged is only for used for metrics.
103
- // for now we simply return the charge for quorum 0, as quorums are likely to share the same min num symbols
104
- // we can make this more granular by adding metrics to the meterer later on
105
- _ , protocolConfig , err := params .GetQuorumConfigs (OnDemandQuorumID )
96
+ onDemandPayment , err := m .ChainPaymentState .GetOnDemandPaymentByAccount (ctx , header .AccountID )
106
97
if err != nil {
107
- return 0 , fmt .Errorf ("failed to get on-demand quorum config : %w" , err )
98
+ return nil , fmt .Errorf ("failed to get on-demand payment by account : %w" , err )
108
99
}
109
- symbolsCharged := payment_logic .SymbolsCharged (numSymbols , protocolConfig .MinNumSymbols )
110
- return symbolsCharged , nil
100
+ usage , err := m .serveOnDemandRequest (ctx , params , header , onDemandPayment , numSymbols , quorumNumbers , receivedAt )
101
+ if err != nil {
102
+ return nil , fmt .Errorf ("invalid on-demand request: %w" , err )
103
+ }
104
+ return usage , nil
111
105
}
112
106
113
107
// serveReservationRequest handles the rate limiting logic for incoming requests
@@ -119,17 +113,18 @@ func (m *Meterer) serveReservationRequest(
119
113
numSymbols uint64 ,
120
114
quorumNumbers []uint8 ,
121
115
receivedAt time.Time ,
122
- ) error {
116
+ ) ( map [core. QuorumID ] uint64 , error ) {
123
117
m .logger .Debug ("Recording and validating reservation usage" , "header" , header , "reservation" , reservations )
124
118
if err := payment_logic .ValidateReservations (reservations , globalParams .QuorumProtocolConfigs , quorumNumbers , header .Timestamp , receivedAt .UnixNano ()); err != nil {
125
- return fmt .Errorf ("invalid reservation: %w" , err )
119
+ return nil , fmt .Errorf ("invalid reservation: %w" , err )
126
120
}
127
121
128
122
// Make atomic batched updates over all reservations identified by the same account and quorum
129
- if err := m .incrementBinUsage (ctx , header , reservations , globalParams , numSymbols ); err != nil {
130
- return fmt .Errorf ("failed to increment bin usages: %w" , err )
123
+ usage , err := m .incrementBinUsage (ctx , header , reservations , globalParams , numSymbols )
124
+ if err != nil {
125
+ return nil , fmt .Errorf ("failed to increment bin usages: %w" , err )
131
126
}
132
- return nil
127
+ return usage , nil
133
128
}
134
129
135
130
// incrementBinUsage increments the bin usage atomically and checks for overflow
@@ -138,15 +133,15 @@ func (m *Meterer) incrementBinUsage(
138
133
reservations map [core.QuorumID ]* core.ReservedPayment ,
139
134
globalParams * PaymentVaultParams ,
140
135
numSymbols uint64 ,
141
- ) error {
136
+ ) ( map [core. QuorumID ] uint64 , error ) {
142
137
charges := make (map [core.QuorumID ]uint64 )
143
138
quorumNumbers := make ([]core.QuorumID , 0 , len (reservations ))
144
139
reservationWindows := make (map [core.QuorumID ]uint64 , len (reservations ))
145
140
requestReservationPeriods := make (map [core.QuorumID ]uint64 , len (reservations ))
146
141
for quorumID := range reservations {
147
142
_ , protocolConfig , err := globalParams .GetQuorumConfigs (quorumID )
148
143
if err != nil {
149
- return fmt .Errorf ("failed to get quorum config for quorum %d: %w" , quorumID , err )
144
+ return nil , fmt .Errorf ("failed to get quorum config for quorum %d: %w" , quorumID , err )
150
145
}
151
146
charges [quorumID ] = payment_logic .SymbolsCharged (numSymbols , protocolConfig .MinNumSymbols )
152
147
quorumNumbers = append (quorumNumbers , quorumID )
@@ -155,13 +150,9 @@ func (m *Meterer) incrementBinUsage(
155
150
}
156
151
// Batch increment all quorums for the current quorums' reservation period
157
152
// For each quorum, increment by its specific symbolsCharged value
158
- updatedUsages := make (map [core.QuorumID ]uint64 )
159
153
usage , err := m .MeteringStore .IncrementBinUsages (ctx , header .AccountID , quorumNumbers , requestReservationPeriods , charges )
160
154
if err != nil {
161
- return err
162
- }
163
- for _ , quorumID := range quorumNumbers {
164
- updatedUsages [quorumID ] = usage [quorumID ]
155
+ return nil , err
165
156
}
166
157
overflowAmounts := make (map [core.QuorumID ]uint64 )
167
158
overflowPeriods := make (map [core.QuorumID ]uint64 )
@@ -170,28 +161,28 @@ func (m *Meterer) incrementBinUsage(
170
161
reservationWindow := reservationWindows [quorumID ]
171
162
requestReservationPeriod := requestReservationPeriods [quorumID ]
172
163
usageLimit := payment_logic .GetBinLimit (reservation .SymbolsPerSecond , reservationWindow )
173
- newUsage , ok := updatedUsages [quorumID ]
164
+ newUsage , ok := usage [quorumID ]
174
165
if ! ok {
175
- return fmt .Errorf ("failed to get updated usage for quorum %d" , quorumID )
166
+ return nil , fmt .Errorf ("failed to get updated usage for quorum %d" , quorumID )
176
167
}
177
168
prevUsage := newUsage - charges [quorumID ]
178
169
if newUsage <= usageLimit {
179
170
continue
180
171
} else if prevUsage >= usageLimit {
181
172
// Bin was already filled before this increment
182
- return fmt .Errorf ("bin has already been filled for quorum %d" , quorumID )
173
+ return nil , fmt .Errorf ("bin has already been filled for quorum %d" , quorumID )
183
174
}
184
175
overflowPeriod := payment_logic .GetOverflowPeriod (requestReservationPeriod , reservationWindow )
185
176
if charges [quorumID ] <= usageLimit && overflowPeriod <= payment_logic .GetReservationPeriod (int64 (reservation .EndTimestamp ), reservationWindow ) {
186
177
// Needs to go to overflow bin
187
178
overflowAmounts [quorumID ] = newUsage - usageLimit
188
179
overflowPeriods [quorumID ] = overflowPeriod
189
180
} else {
190
- return fmt .Errorf ("overflow usage exceeds bin limit for quorum %d" , quorumID )
181
+ return nil , fmt .Errorf ("overflow usage exceeds bin limit for quorum %d" , quorumID )
191
182
}
192
183
}
193
184
if len (overflowAmounts ) != len (overflowPeriods ) {
194
- return fmt .Errorf ("overflow amount and period mismatch" )
185
+ return nil , fmt .Errorf ("overflow amount and period mismatch" )
195
186
}
196
187
// Batch increment overflow bins for all overflown reservation candidates
197
188
if len (overflowAmounts ) > 0 {
@@ -205,55 +196,60 @@ func (m *Meterer) incrementBinUsage(
205
196
// Rollback the increments for the current periods
206
197
rollbackErr := m .MeteringStore .DecrementBinUsages (ctx , header .AccountID , quorumNumbers , requestReservationPeriods , charges )
207
198
if rollbackErr != nil {
208
- return fmt .Errorf ("failed to increment overflow bins: %w; rollback also failed: %v" , err , rollbackErr )
199
+ return nil , fmt .Errorf ("failed to increment overflow bins: %w; rollback also failed: %v" , err , rollbackErr )
209
200
}
210
- return fmt .Errorf ("failed to increment overflow bins: %w; successfully rolled back increments" , err )
201
+ return nil , fmt .Errorf ("failed to increment overflow bins: %w; successfully rolled back increments" , err )
211
202
}
212
203
}
213
204
214
- return nil
205
+ return charges , nil
215
206
}
216
207
217
208
// serveOnDemandRequest handles the rate limiting logic for incoming requests
218
209
// On-demand requests doesn't have additional quorum settings and should only be
219
210
// allowed by ETH and EIGEN quorums
220
- func (m * Meterer ) serveOnDemandRequest (ctx context.Context , globalParams * PaymentVaultParams , header core.PaymentMetadata , onDemandPayment * core.OnDemandPayment , symbolsCharged uint64 , headerQuorums []uint8 , receivedAt time.Time ) error {
211
+ func (m * Meterer ) serveOnDemandRequest (ctx context.Context , globalParams * PaymentVaultParams , header core.PaymentMetadata , onDemandPayment * core.OnDemandPayment , numSymbols uint64 , headerQuorums []uint8 , receivedAt time.Time ) ( map [core. QuorumID ] uint64 , error ) {
221
212
m .logger .Debug ("Recording and validating on-demand usage" , "header" , header , "onDemandPayment" , onDemandPayment )
222
213
223
214
if err := payment_logic .ValidateQuorum (headerQuorums , globalParams .OnDemandQuorumNumbers ); err != nil {
224
- return fmt .Errorf ("invalid quorum for On-Demand Request: %w" , err )
215
+ return nil , fmt .Errorf ("invalid quorum for On-Demand Request: %w" , err )
225
216
}
226
217
227
218
// Verify that the claimed cumulative payment doesn't exceed the on-chain deposit
228
219
if header .CumulativePayment .Cmp (onDemandPayment .CumulativePayment ) > 0 {
229
- return fmt .Errorf ("request claims a cumulative payment greater than the on-chain deposit" )
220
+ return nil , fmt .Errorf ("request claims a cumulative payment greater than the on-chain deposit" )
230
221
}
231
222
232
223
paymentConfig , protocolConfig , err := globalParams .GetQuorumConfigs (OnDemandQuorumID )
233
224
if err != nil {
234
- return fmt .Errorf ("failed to get payment config for on-demand quorum: %w" , err )
225
+ return nil , fmt .Errorf ("failed to get payment config for on-demand quorum: %w" , err )
235
226
}
236
227
237
- symbolsCharged = payment_logic .SymbolsCharged (symbolsCharged , protocolConfig .MinNumSymbols )
228
+ symbolsCharged : = payment_logic .SymbolsCharged (numSymbols , protocolConfig .MinNumSymbols )
238
229
paymentCharged := payment_logic .PaymentCharged (symbolsCharged , paymentConfig .OnDemandPricePerSymbol )
239
230
oldPayment , err := m .MeteringStore .AddOnDemandPayment (ctx , header , paymentCharged )
240
231
if err != nil {
241
- return fmt .Errorf ("failed to update cumulative payment: %w" , err )
232
+ return nil , fmt .Errorf ("failed to update cumulative payment: %w" , err )
242
233
}
243
234
244
235
// Update bin usage atomically and check against bin capacity
245
- if err := m .incrementGlobalBinUsage (ctx , globalParams , uint64 ( symbolsCharged ) , receivedAt ); err != nil {
236
+ if err := m .incrementGlobalBinUsage (ctx , globalParams , symbolsCharged , receivedAt ); err != nil {
246
237
// If global bin usage update fails, roll back the payment to its previous value
247
238
// The rollback will only happen if the current payment value still matches what we just wrote
248
239
// This ensures we don't accidentally roll back a newer payment that might have been processed
249
240
dbErr := m .MeteringStore .RollbackOnDemandPayment (ctx , header .AccountID , header .CumulativePayment , oldPayment )
250
241
if dbErr != nil {
251
- return dbErr
242
+ return nil , dbErr
252
243
}
253
- return fmt .Errorf ("failed global rate limiting: %w" , err )
244
+ return nil , fmt .Errorf ("failed global rate limiting: %w" , err )
254
245
}
255
246
256
- return nil
247
+ // charges is applied to the header quorums
248
+ charges := make (map [core.QuorumID ]uint64 , len (headerQuorums ))
249
+ for _ , quorumID := range headerQuorums {
250
+ charges [core .QuorumID (quorumID )] = symbolsCharged
251
+ }
252
+ return charges , nil
257
253
}
258
254
259
255
// IncrementGlobalBinUsage increments the bin usage atomically and checks for overflow
0 commit comments