Skip to content

Commit f393b91

Browse files
authored
Load deals once during VerifyDealsForActivation (#1237)
* helper function to load proposals from DealIDs * load deals once in VerifyDealsForActivation * add back extra check for DEAL_EXPIRED case * don't load deals twice in ActivateDeals * load deal amt once * review
1 parent e701cdb commit f393b91

File tree

2 files changed

+46
-59
lines changed

2 files changed

+46
-59
lines changed

actors/market/src/lib.rs

Lines changed: 45 additions & 58 deletions
Original file line numberDiff line numberDiff line change
@@ -496,18 +496,17 @@ impl Actor {
496496
let curr_epoch = rt.curr_epoch();
497497

498498
let st: State = rt.state()?;
499-
let proposals = st.get_proposal_array(rt.store())?;
499+
let proposal_array = st.get_proposal_array(rt.store())?;
500500

501501
let mut sectors_data = Vec::with_capacity(params.sectors.len());
502502
for sector in params.sectors.iter() {
503+
let sector_proposals = get_proposals(&proposal_array, &sector.deal_ids, st.next_id)?;
503504
let sector_size = sector
504505
.sector_type
505506
.sector_size()
506507
.map_err(|e| actor_error!(illegal_argument, "sector size unknown: {}", e))?;
507508
validate_and_return_deal_space(
508-
&proposals,
509-
&sector.deal_ids,
510-
st.next_id,
509+
&sector_proposals,
511510
&miner_addr,
512511
sector.sector_expiry,
513512
curr_epoch,
@@ -518,14 +517,15 @@ impl Actor {
518517
let commd = if sector.deal_ids.is_empty() {
519518
None
520519
} else {
521-
Some(compute_data_commitment(rt, &proposals, sector.sector_type, &sector.deal_ids)?)
520+
Some(compute_data_commitment(rt, &sector_proposals, sector.sector_type)?)
522521
};
523522

524523
sectors_data.push(SectorDealData { commd });
525524
}
526525

527526
Ok(VerifyDealsForActivationReturn { sectors: sectors_data })
528527
}
528+
529529
/// Activate a set of deals, returning the combined deal space and extra info for verified deals.
530530
fn activate_deals(
531531
rt: &impl Runtime,
@@ -536,13 +536,12 @@ impl Actor {
536536
let curr_epoch = rt.curr_epoch();
537537

538538
let (deal_spaces, verified_infos) = rt.transaction(|st: &mut State, rt| {
539-
let proposals = st.get_proposal_array(rt.store())?;
539+
let proposal_array = st.get_proposal_array(rt.store())?;
540+
let proposals = get_proposals(&proposal_array, &params.deal_ids, st.next_id)?;
540541

541542
let deal_spaces = {
542543
validate_and_return_deal_space(
543544
&proposals,
544-
&params.deal_ids,
545-
st.next_id,
546545
&miner_addr,
547546
params.sector_expiry,
548547
curr_epoch,
@@ -555,7 +554,7 @@ impl Actor {
555554
let mut verified_infos = Vec::new();
556555
let mut deal_states: Vec<(DealID, DealState)> = vec![];
557556

558-
for deal_id in params.deal_ids {
557+
for (deal_id, proposal) in proposals {
559558
// This construction could be replaced with a single "update deal state"
560559
// state method, possibly batched over all deal ids at once.
561560
let s = st.find_deal_state(rt.store(), deal_id)?;
@@ -568,8 +567,6 @@ impl Actor {
568567
));
569568
}
570569

571-
let proposal = st.get_proposal(rt.store(), deal_id)?;
572-
573570
let propc = rt_deal_cid(rt, &proposal)?;
574571

575572
// Confirm the deal is in the pending proposals queue.
@@ -690,16 +687,12 @@ impl Actor {
690687
rt.validate_immediate_caller_type(std::iter::once(&Type::Miner))?;
691688

692689
let st: State = rt.state()?;
693-
let proposals = st.get_proposal_array(rt.store())?;
690+
let proposal_array = st.get_proposal_array(rt.store())?;
694691

695692
let mut commds = Vec::with_capacity(params.inputs.len());
696693
for comm_input in params.inputs.iter() {
697-
commds.push(compute_data_commitment(
698-
rt,
699-
&proposals,
700-
comm_input.sector_type,
701-
&comm_input.deal_ids,
702-
)?);
694+
let proposed_deals = get_proposals(&proposal_array, &comm_input.deal_ids, st.next_id)?;
695+
commds.push(compute_data_commitment(rt, &proposed_deals, comm_input.sector_type)?);
703696
}
704697

705698
Ok(ComputeDataCommitmentReturn { commds })
@@ -1022,65 +1015,59 @@ impl Actor {
10221015
}
10231016
}
10241017

1025-
fn compute_data_commitment<BS: Blockstore>(
1026-
rt: &impl Runtime,
1027-
proposals: &DealArray<BS>,
1028-
sector_type: RegisteredSealProof,
1018+
fn get_proposals<BS: Blockstore>(
1019+
proposal_array: &DealArray<BS>,
10291020
deal_ids: &[DealID],
1030-
) -> Result<Cid, ActorError> {
1031-
let mut pieces = Vec::with_capacity(deal_ids.len());
1032-
1021+
next_id: DealID,
1022+
) -> Result<Vec<(DealID, DealProposal)>, ActorError> {
1023+
let mut proposals = Vec::new();
1024+
let mut seen_deal_ids = BTreeSet::new();
10331025
for deal_id in deal_ids {
1034-
let deal = proposals
1026+
if !seen_deal_ids.insert(deal_id) {
1027+
return Err(actor_error!(illegal_argument, "duplicate deal ID {} in sector", deal_id));
1028+
}
1029+
let proposal = proposal_array
10351030
.get(*deal_id)
1036-
.map_err(|e| {
1037-
e.downcast_default(
1038-
ExitCode::USR_ILLEGAL_STATE,
1039-
format!("failed to get deal_id ({})", deal_id),
1040-
)
1041-
})?
1042-
.ok_or_else(|| actor_error!(not_found, "proposal doesn't exist ({})", deal_id))?;
1031+
.context_code(ExitCode::USR_ILLEGAL_STATE, "failed to load deal")?
1032+
.ok_or_else(|| {
1033+
if *deal_id < next_id {
1034+
ActorError::unchecked(EX_DEAL_EXPIRED, format!("deal {} expired", deal_id))
1035+
} else {
1036+
actor_error!(not_found, "no such deal {}", deal_id)
1037+
}
1038+
})?;
1039+
proposals.push((*deal_id, proposal.clone()));
1040+
}
1041+
Ok(proposals)
1042+
}
1043+
1044+
fn compute_data_commitment(
1045+
rt: &impl Runtime,
1046+
proposals: &[(DealID, DealProposal)],
1047+
sector_type: RegisteredSealProof,
1048+
) -> Result<Cid, ActorError> {
1049+
let mut pieces = Vec::with_capacity(proposals.len());
10431050

1051+
for (_, deal) in proposals {
10441052
pieces.push(PieceInfo { cid: deal.piece_cid, size: deal.piece_size });
10451053
}
1054+
10461055
rt.compute_unsealed_sector_cid(sector_type, &pieces).map_err(|e| {
10471056
e.downcast_default(ExitCode::USR_ILLEGAL_ARGUMENT, "failed to compute unsealed sector CID")
10481057
})
10491058
}
10501059

1051-
pub fn validate_and_return_deal_space<BS: Blockstore>(
1052-
proposals: &DealArray<BS>,
1053-
deal_ids: &[DealID],
1054-
next_id: DealID,
1060+
pub fn validate_and_return_deal_space(
1061+
proposals: &[(DealID, DealProposal)],
10551062
miner_addr: &Address,
10561063
sector_expiry: ChainEpoch,
10571064
sector_activation: ChainEpoch,
10581065
sector_size: Option<SectorSize>,
10591066
) -> Result<DealSpaces, ActorError> {
1060-
let mut seen_deal_ids = BTreeSet::new();
10611067
let mut deal_space = BigInt::zero();
10621068
let mut verified_deal_space = BigInt::zero();
10631069

1064-
for deal_id in deal_ids {
1065-
if !seen_deal_ids.insert(deal_id) {
1066-
return Err(actor_error!(
1067-
illegal_argument,
1068-
"deal id {} present multiple times",
1069-
deal_id
1070-
));
1071-
}
1072-
1073-
let proposal = proposals
1074-
.get(*deal_id)
1075-
.context_code(ExitCode::USR_ILLEGAL_STATE, "failed to load deal")?
1076-
.ok_or_else(|| {
1077-
if deal_id < &next_id {
1078-
ActorError::unchecked(EX_DEAL_EXPIRED, format!("deal {} expired", deal_id))
1079-
} else {
1080-
actor_error!(not_found, "no such deal {}", deal_id)
1081-
}
1082-
})?;
1083-
1070+
for (deal_id, proposal) in proposals {
10841071
validate_deal_can_activate(proposal, miner_addr, sector_expiry, sector_activation)
10851072
.with_context(|| format!("cannot activate deal {}", deal_id))?;
10861073

actors/market/tests/verify_deals_for_activation_test.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -313,7 +313,7 @@ fn fail_when_the_same_deal_id_is_passed_multiple_times() {
313313
};
314314
expect_abort_contains_message(
315315
ExitCode::USR_ILLEGAL_ARGUMENT,
316-
"multiple times",
316+
"duplicate deal",
317317
rt.call::<MarketActor>(
318318
Method::VerifyDealsForActivation as u64,
319319
IpldBlock::serialize_cbor(&params).unwrap(),

0 commit comments

Comments
 (0)