@@ -37,6 +37,7 @@ use fil_actors_runtime::{
37
37
} ;
38
38
use fvm_ipld_encoding:: ipld_block:: IpldBlock ;
39
39
use fvm_ipld_encoding:: { RawBytes , DAG_CBOR } ;
40
+ use fvm_shared:: sys:: SendFlags ;
40
41
41
42
use crate :: ext:: verifreg:: { AllocationID , AllocationRequest } ;
42
43
@@ -234,14 +235,31 @@ impl Actor {
234
235
) ) ;
235
236
}
236
237
238
+ // Deals that passed `AuthenticateMessage` and other state-less checks.
239
+ let mut validity_index: Vec < bool > = Vec :: with_capacity ( params. deals . len ( ) ) ;
240
+
237
241
let baseline_power = request_current_baseline_power ( rt) ?;
238
242
let ( network_raw_power, _) = request_current_network_power ( rt) ?;
239
243
244
+ // We perform these checks before loading state since the call to `AuthenticateMessage` could recurse
245
+ for ( di, deal) in params. deals . iter ( ) . enumerate ( ) {
246
+ let valid = if let Err ( e) = validate_deal ( rt, deal, & network_raw_power, & baseline_power)
247
+ {
248
+ info ! ( "invalid deal {}: {}" , di, e) ;
249
+ false
250
+ } else {
251
+ true
252
+ } ;
253
+
254
+ validity_index. push ( valid) ;
255
+ }
256
+
240
257
struct ValidDeal {
241
258
proposal : DealProposal ,
242
259
serialized_proposal : RawBytes ,
243
260
cid : Cid ,
244
261
}
262
+
245
263
// Deals that passed validation.
246
264
let mut valid_deals: Vec < ValidDeal > = Vec :: with_capacity ( params. deals . len ( ) ) ;
247
265
// CIDs of valid proposals.
@@ -260,8 +278,10 @@ impl Actor {
260
278
let state: State = rt. state ( ) ?;
261
279
262
280
for ( di, mut deal) in params. deals . into_iter ( ) . enumerate ( ) {
263
- if let Err ( e) = validate_deal ( rt, & deal, & network_raw_power, & baseline_power) {
264
- info ! ( "invalid deal {}: {}" , di, e) ;
281
+ if !* validity_index. get ( di) . context_code (
282
+ ExitCode :: USR_ASSERTION_FAILED ,
283
+ "validity index has incorrect length" ,
284
+ ) ? {
265
285
continue ;
266
286
}
267
287
@@ -355,7 +375,7 @@ impl Actor {
355
375
client_alloc_reqs
356
376
. entry ( client_id)
357
377
. or_default ( )
358
- . push ( ( pcid, alloc_request_for_deal ( & deal, rt. policy ( ) , curr_epoch) ) ) ;
378
+ . push ( ( pcid, alloc_request_for_deal ( & deal. proposal , rt. policy ( ) , curr_epoch) ) ) ;
359
379
}
360
380
361
381
total_provider_lockup = provider_lockup;
@@ -444,7 +464,9 @@ impl Actor {
444
464
Ok ( ( ) )
445
465
} ) ?;
446
466
447
- // notify clients ignoring any errors
467
+ // notify clients, any failures cause the entire publish_storage_deals method to fail
468
+ // it's unsafe to ignore errors here, since that could be used to attack storage contract clients
469
+ // that might be unaware they're making storage deals
448
470
for ( i, valid_deal) in valid_deals. iter ( ) . enumerate ( ) {
449
471
_ = extract_send_result ( rt. send_simple (
450
472
& valid_deal. proposal . client ,
@@ -454,7 +476,10 @@ impl Actor {
454
476
deal_id : new_deal_ids[ i] ,
455
477
} ) ?,
456
478
TokenAmount :: zero ( ) ,
457
- ) ) ;
479
+ ) )
480
+ . with_context_code ( ExitCode :: USR_ILLEGAL_ARGUMENT , || {
481
+ format ! ( "failed to notify deal with proposal cid {}" , valid_deal. cid)
482
+ } ) ?;
458
483
}
459
484
460
485
Ok ( PublishStorageDealsReturn { ids : new_deal_ids, valid_deals : valid_input_bf } )
@@ -1083,21 +1108,21 @@ pub fn validate_and_return_deal_space<BS: Blockstore>(
1083
1108
1084
1109
fn alloc_request_for_deal (
1085
1110
// Deal proposal must have ID addresses
1086
- deal : & ClientDealProposal ,
1111
+ deal : & DealProposal ,
1087
1112
policy : & Policy ,
1088
1113
curr_epoch : ChainEpoch ,
1089
1114
) -> ext:: verifreg:: AllocationRequest {
1090
- let alloc_term_min = deal. proposal . end_epoch - deal. proposal . start_epoch ;
1115
+ let alloc_term_min = deal. end_epoch - deal. start_epoch ;
1091
1116
let alloc_term_max = min (
1092
1117
alloc_term_min + policy. market_default_allocation_term_buffer ,
1093
1118
policy. maximum_verified_allocation_term ,
1094
1119
) ;
1095
1120
let alloc_expiration =
1096
- min ( deal. proposal . start_epoch , curr_epoch + policy. maximum_verified_allocation_expiration ) ;
1121
+ min ( deal. start_epoch , curr_epoch + policy. maximum_verified_allocation_expiration ) ;
1097
1122
ext:: verifreg:: AllocationRequest {
1098
- provider : deal. proposal . provider . id ( ) . unwrap ( ) ,
1099
- data : deal. proposal . piece_cid ,
1100
- size : deal. proposal . piece_size ,
1123
+ provider : deal. provider . id ( ) . unwrap ( ) ,
1124
+ data : deal. piece_cid ,
1125
+ size : deal. piece_size ,
1101
1126
term_min : alloc_term_min,
1102
1127
term_max : alloc_term_max,
1103
1128
expiration : alloc_expiration,
@@ -1293,14 +1318,16 @@ fn deal_proposal_is_internally_valid(
1293
1318
// Generate unsigned bytes
1294
1319
let proposal_bytes = serialize ( & proposal. proposal , "deal proposal" ) ?;
1295
1320
1296
- extract_send_result ( rt. send_simple (
1321
+ extract_send_result ( rt. send (
1297
1322
& proposal. proposal . client ,
1298
1323
ext:: account:: AUTHENTICATE_MESSAGE_METHOD ,
1299
1324
IpldBlock :: serialize_cbor ( & ext:: account:: AuthenticateMessageParams {
1300
1325
signature : signature_bytes,
1301
1326
message : proposal_bytes. to_vec ( ) ,
1302
1327
} ) ?,
1303
1328
TokenAmount :: zero ( ) ,
1329
+ None ,
1330
+ SendFlags :: READ_ONLY ,
1304
1331
) )
1305
1332
. map_err ( |e| e. wrap ( "proposal authentication failed" ) ) ?;
1306
1333
Ok ( ( ) )
0 commit comments