diff --git a/Cargo.lock b/Cargo.lock index bd6df0910..2aaa97f4a 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -608,13 +608,14 @@ dependencies = [ [[package]] name = "const-hex" -version = "1.9.1" +version = "1.11.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c37be52ef5e3b394db27a2341010685ad5103c72ac15ce2e9420a7e8f93f342c" +checksum = "5ba00838774b4ab0233e355d26710fbfc8327a05c017f6dc4873f876d1f79f78" dependencies = [ "cfg-if", "cpufeatures", "hex", + "proptest", "serde", ] @@ -1681,6 +1682,7 @@ version = "12.0.0" dependencies = [ "anyhow", "cid 0.10.1", + "const-hex", "fil_actors_runtime", "frc42_dispatch", "frc46_token", @@ -2721,6 +2723,12 @@ dependencies = [ "thiserror", ] +[[package]] +name = "libm" +version = "0.2.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4ec2a862134d2a7d32d7983ddcdd1c4923530833c9f2ea1a44fc5fa473989058" + [[package]] name = "libsecp256k1" version = "0.7.1" @@ -2975,6 +2983,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "39e3200413f237f41ab11ad6d161bc7239c84dcb631773ccd7de3dfe4b5c267c" dependencies = [ "autocfg", + "libm", ] [[package]] @@ -3329,6 +3338,22 @@ dependencies = [ "unicode-ident", ] +[[package]] +name = "proptest" +version = "1.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "31b476131c3c86cb68032fdc5cb6d5a1045e3e42d96b69fa599fd77701e1f5bf" +dependencies = [ + "bitflags 2.4.1", + "lazy_static", + "num-traits", + "rand", + "rand_chacha", + "rand_xorshift", + "regex-syntax", + "unarray", +] + [[package]] name = "quick-error" version = "1.2.3" @@ -3380,6 +3405,15 @@ dependencies = [ "getrandom", ] +[[package]] +name = "rand_xorshift" +version = "0.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d25bf25ec5ae4a3f1b92f929810509a2f53d7dca2f50b794ff57e3face536c8f" +dependencies = [ + "rand_core", +] + [[package]] name = "redox_syscall" version = "0.3.5" @@ -4319,6 +4353,12 @@ dependencies = [ "static_assertions", ] +[[package]] +name = "unarray" +version = "0.1.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "eaea85b334db583fe3274d12b4cd1880032beab409c0d774be044d4480ab9a94" + [[package]] name = "unicode-bidi" version = "0.3.13" diff --git a/Cargo.toml b/Cargo.toml index 5ca1cb7e3..e61660660 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -95,6 +95,7 @@ pretty_env_logger = "0.4.0" serde_repr = "0.1.8" unsigned-varint = "0.7.1" rand_chacha = "0.3.1" +const-hex = "1.11.3" # Crypto libsecp256k1 = { version = "0.7.1", default-features = false } diff --git a/actors/market/src/state.rs b/actors/market/src/state.rs index 963b2b3ab..1bf7d6265 100644 --- a/actors/market/src/state.rs +++ b/actors/market/src/state.rs @@ -626,16 +626,7 @@ impl State { // Flush if any of the requested sectors were found. if flush { - if sector_deals.is_empty() { - // Remove from top-level map - provider_sectors - .delete(&provider) - .with_context_code(ExitCode::USR_ILLEGAL_STATE, || { - format!("failed to delete sector deals for {}", provider) - })?; - } else { - save_provider_sector_deals(&mut provider_sectors, provider, &mut sector_deals)?; - } + save_provider_sector_deals(&mut provider_sectors, provider, &mut sector_deals)?; self.save_provider_sectors(&mut provider_sectors)?; } @@ -651,6 +642,7 @@ impl State { ) -> Result<(), ActorError> { let mut provider_sectors = self.load_provider_sectors(store)?; for (provider, sector_deal_ids) in provider_sector_deal_ids { + let mut flush = false; let mut sector_deals = load_provider_sector_deals(store, &provider_sectors, *provider)?; for (sector_number, deals_to_remove) in sector_deal_ids { let existing_deal_ids = sector_deals @@ -662,20 +654,39 @@ impl State { // pretty fast. // Loading into a HashSet could be an improvement for large collections of deals // in a single sector being removed at one time. - let new_deals = existing_deal_ids + let new_deals: Vec<_> = existing_deal_ids .iter() .filter(|deal_id| !deals_to_remove.contains(*deal_id)) .cloned() .collect(); - - sector_deals - .set(sector_number, new_deals) - .with_context_code(ExitCode::USR_ILLEGAL_STATE, || { - format!("failed to set sector deals for {} {}", provider, sector_number) - })?; + flush = true; + + if new_deals.is_empty() { + sector_deals.delete(sector_number).with_context_code( + ExitCode::USR_ILLEGAL_STATE, + || { + format!( + "failed to delete sector deals for {} {}", + provider, sector_number + ) + }, + )?; + } else { + sector_deals.set(sector_number, new_deals).with_context_code( + ExitCode::USR_ILLEGAL_STATE, + || { + format!( + "failed to set sector deals for {} {}", + provider, sector_number + ) + }, + )?; + } } } - save_provider_sector_deals(&mut provider_sectors, *provider, &mut sector_deals)?; + if flush { + save_provider_sector_deals(&mut provider_sectors, *provider, &mut sector_deals)?; + } } self.save_provider_sectors(&mut provider_sectors)?; Ok(()) @@ -1273,7 +1284,15 @@ fn save_provider_sector_deals( where BS: Blockstore, { - let sectors_root = sector_deals.flush()?; - provider_sectors.set(&provider, sectors_root)?; + if sector_deals.is_empty() { + provider_sectors + .delete(&provider) + .with_context_code(ExitCode::USR_ILLEGAL_STATE, || { + format!("failed to delete sector deals for {}", provider) + })?; + } else { + let sectors_root = sector_deals.flush()?; + provider_sectors.set(&provider, sectors_root)?; + } Ok(()) } diff --git a/actors/market/tests/activate_deal_failures.rs b/actors/market/tests/activate_deal_failures.rs index 43d17dd4b..517201ed3 100644 --- a/actors/market/tests/activate_deal_failures.rs +++ b/actors/market/tests/activate_deal_failures.rs @@ -107,7 +107,7 @@ fn reject_proposal_expired() { ExitCode::OK, ); cron_tick(&rt); - assert_deal_deleted(&rt, deal_id, &deal, 0); + assert_deal_deleted(&rt, deal_id, &deal, 0, true); assert_activation_failure(&rt, deal_id, &deal, 1, sector_expiry, EX_DEAL_EXPIRED); } diff --git a/actors/market/tests/batch_activate_deals.rs b/actors/market/tests/batch_activate_deals.rs index d37877e05..818e4ff6a 100644 --- a/actors/market/tests/batch_activate_deals.rs +++ b/actors/market/tests/batch_activate_deals.rs @@ -46,7 +46,7 @@ fn activate_deals_one_sector() { assert!(res.activation_results.all_ok()); // Deal IDs are stored under the sector, in correct order. - assert_eq!(deal_ids, get_sector_deal_ids(&rt, PROVIDER_ID, &[1])); + assert_eq!(deal_ids, get_sector_deal_ids(&rt, PROVIDER_ID, &[1]).unwrap()); for id in deal_ids.iter() { let state = get_deal_state(&rt, *id); @@ -392,7 +392,7 @@ fn activate_new_deals_in_existing_sector() { assert_eq!(0, get_deal_state(&rt, deal_ids[2]).sector_start_epoch); // All deals stored under the sector, in order. - assert_eq!(deal_ids, get_sector_deal_ids(&rt, PROVIDER_ID, &[sector_number])); + assert_eq!(deal_ids, get_sector_deal_ids(&rt, PROVIDER_ID, &[sector_number]).unwrap()); check_state(&rt); } diff --git a/actors/market/tests/cron_tick_deal_expiry.rs b/actors/market/tests/cron_tick_deal_expiry.rs index 987c4a572..4e86fc0d8 100644 --- a/actors/market/tests/cron_tick_deal_expiry.rs +++ b/actors/market/tests/cron_tick_deal_expiry.rs @@ -49,7 +49,7 @@ fn deal_is_correctly_processed_if_first_cron_after_expiry() { assert!(slashed.is_zero()); // deal should be deleted as it should have expired - assert_deal_deleted(&rt, deal_id, &deal_proposal, sector_number); + assert_deal_deleted(&rt, deal_id, &deal_proposal, sector_number, true); check_state(&rt); } @@ -124,7 +124,7 @@ fn regular_payments_till_deal_expires_and_then_locked_funds_are_unlocked() { assert!(slashed.is_zero()); // deal should be deleted as it should have expired - assert_deal_deleted(&rt, deal_id, &deal_proposal, sector_number); + assert_deal_deleted(&rt, deal_id, &deal_proposal, sector_number, true); check_state(&rt); } @@ -154,7 +154,7 @@ fn payment_for_a_deal_if_deal_is_already_expired_before_a_cron_tick() { assert_eq!((end - start) * &deal_proposal.storage_price_per_epoch, pay); assert!(slashed.is_zero()); - assert_deal_deleted(&rt, deal_id, &deal_proposal, sector_number); + assert_deal_deleted(&rt, deal_id, &deal_proposal, sector_number, true); // running cron tick again doesn't do anything cron_tick_no_change(&rt, CLIENT_ADDR, PROVIDER_ADDR); @@ -203,7 +203,7 @@ fn expired_deal_should_unlock_the_remaining_client_and_provider_locked_balance_a assert!(provider_acct.locked.is_zero()); // deal should be deleted - assert_deal_deleted(&rt, deal_id, &deal_proposal, sector_number); + assert_deal_deleted(&rt, deal_id, &deal_proposal, sector_number, true); check_state(&rt); } diff --git a/actors/market/tests/cron_tick_deal_slashing.rs b/actors/market/tests/cron_tick_deal_slashing.rs index e9e6eb24c..783a10cab 100644 --- a/actors/market/tests/cron_tick_deal_slashing.rs +++ b/actors/market/tests/cron_tick_deal_slashing.rs @@ -102,7 +102,7 @@ fn deal_is_slashed() { rt.set_epoch(cron_tick_epoch); cron_tick(&rt); - assert_deal_deleted(&rt, deal_id, &deal_proposal, sector_number); + assert_deal_deleted(&rt, deal_id, &deal_proposal, sector_number, true); check_state(&rt); } @@ -142,7 +142,7 @@ fn deal_is_slashed_at_the_end_epoch_should_not_be_slashed_and_should_be_consider assert!(slashed.is_zero()); // deal should be deleted as it should have expired - assert_deal_deleted(&rt, deal_id, &deal_proposal, SECTOR_NUMBER); + assert_deal_deleted(&rt, deal_id, &deal_proposal, SECTOR_NUMBER, true); check_state(&rt); } @@ -192,7 +192,7 @@ fn deal_payment_and_slashing_correctly_processed_in_same_crontick() { cron_tick(&rt); // deal should be deleted as it should have expired - assert_deal_deleted(&rt, deal_id, &deal_proposal, sector_number); + assert_deal_deleted(&rt, deal_id, &deal_proposal, sector_number, true); check_state(&rt); } @@ -249,9 +249,9 @@ fn slash_multiple_deals_in_the_same_epoch() { rt.set_epoch(epoch + 1); cron_tick(&rt); - assert_deal_deleted(&rt, deal_id1, &deal_proposal1, SECTOR_NUMBER); - assert_deal_deleted(&rt, deal_id2, &deal_proposal2, SECTOR_NUMBER); - assert_deal_deleted(&rt, deal_id3, &deal_proposal3, SECTOR_NUMBER); + assert_deal_deleted(&rt, deal_id1, &deal_proposal1, SECTOR_NUMBER, true); + assert_deal_deleted(&rt, deal_id2, &deal_proposal2, SECTOR_NUMBER, true); + assert_deal_deleted(&rt, deal_id3, &deal_proposal3, SECTOR_NUMBER, true); check_state(&rt); } @@ -319,7 +319,7 @@ fn regular_payments_till_deal_is_slashed_and_then_slashing_is_processed() { cron_tick(&rt); // deal should be deleted as it should have expired - assert_deal_deleted(&rt, deal_id, &deal_proposal, SECTOR_NUMBER); + assert_deal_deleted(&rt, deal_id, &deal_proposal, SECTOR_NUMBER, true); check_state(&rt); } @@ -372,6 +372,6 @@ fn regular_payments_till_deal_expires_and_then_we_attempt_to_slash_it_but_it_wil assert!(slashed.is_zero()); // deal should be deleted as it should have expired - assert_deal_deleted(&rt, deal_id, &deal_proposal, SECTOR_NUMBER); + assert_deal_deleted(&rt, deal_id, &deal_proposal, SECTOR_NUMBER, true); check_state(&rt); } diff --git a/actors/market/tests/cron_tick_timedout_deals.rs b/actors/market/tests/cron_tick_timedout_deals.rs index acb03336c..2e117e79f 100644 --- a/actors/market/tests/cron_tick_timedout_deals.rs +++ b/actors/market/tests/cron_tick_timedout_deals.rs @@ -55,7 +55,7 @@ fn timed_out_deal_is_slashed_and_deleted() { assert_eq!(c_escrow, client_acct.balance); assert!(client_acct.locked.is_zero()); assert_account_zero(&rt, PROVIDER_ADDR); - assert_deal_deleted(&rt, deal_id, &deal_proposal, 0); + assert_deal_deleted(&rt, deal_id, &deal_proposal, 0, true); check_state(&rt); } @@ -126,7 +126,7 @@ fn publishing_timed_out_deal_again_should_work_after_cron_tick_as_it_should_no_l ExitCode::OK, ); cron_tick(&rt); - assert_deal_deleted(&rt, deal_id, &deal_proposal, 0); + assert_deal_deleted(&rt, deal_id, &deal_proposal, 0, true); // now publishing should work generate_and_publish_deal(&rt, CLIENT_ADDR, &MinerAddresses::default(), START_EPOCH, END_EPOCH); @@ -192,8 +192,8 @@ fn timed_out_and_verified_deals_are_slashed_deleted() { cron_tick_no_change(&rt, CLIENT_ADDR, PROVIDER_ADDR); assert_account_zero(&rt, PROVIDER_ADDR); - assert_deal_deleted(&rt, deal_ids[0], &deal1, 0); - assert_deal_deleted(&rt, deal_ids[1], &deal2, 0); - assert_deal_deleted(&rt, deal_ids[2], &deal3, 0); + assert_deal_deleted(&rt, deal_ids[0], &deal1, 0, true); + assert_deal_deleted(&rt, deal_ids[1], &deal2, 0, true); + assert_deal_deleted(&rt, deal_ids[2], &deal3, 0, true); check_state(&rt); } diff --git a/actors/market/tests/deal_termination.rs b/actors/market/tests/deal_termination.rs index eebc48b65..a5915e671 100644 --- a/actors/market/tests/deal_termination.rs +++ b/actors/market/tests/deal_termination.rs @@ -106,7 +106,7 @@ fn deal_is_terminated() { assert_eq!(tc.termination_payment, pay); assert_eq!(deal_proposal.provider_collateral, slashed); - assert_deal_deleted(&rt, deal_id, &deal_proposal, sector_number); + assert_deal_deleted(&rt, deal_id, &deal_proposal, sector_number, true); // assert that trying to settle is always a no-op after termination @@ -197,7 +197,7 @@ fn settle_payments_then_terminate_deal_in_the_same_epoch() { &[sector_number], &[deal_id], ); - assert_deal_deleted(&rt, deal_id, &proposal, sector_number); + assert_deal_deleted(&rt, deal_id, &proposal, sector_number, true); // end state should be equivalent to only calling termination let client_after = get_balance(&rt, &CLIENT_ADDR); @@ -245,7 +245,7 @@ fn terminate_a_deal_then_settle_it_in_the_same_epoch() { ); let ret = settle_deal_payments(&rt, PROVIDER_ADDR, &[deal_id], &[], &[]); assert_eq!(ret.results.codes(), vec![EX_DEAL_EXPIRED]); - assert_deal_deleted(&rt, deal_id, &proposal, sector_number); + assert_deal_deleted(&rt, deal_id, &proposal, sector_number, true); check_state(&rt); } diff --git a/actors/market/tests/harness.rs b/actors/market/tests/harness.rs index c40c35efe..1de246da2 100644 --- a/actors/market/tests/harness.rs +++ b/actors/market/tests/harness.rs @@ -543,7 +543,7 @@ pub fn get_sector_deal_ids( rt: &MockRuntime, provider: ActorID, sector_numbers: &[SectorNumber], -) -> Vec { +) -> Option> { let st: State = rt.get_state(); let provider_sectors = ProviderSectorsMap::load( &rt.store, @@ -553,22 +553,31 @@ pub fn get_sector_deal_ids( ) .unwrap(); let sectors_root: Option<&Cid> = provider_sectors.get(&provider).unwrap(); - if let Some(sectors_root) = sectors_root { - let sector_deals = - SectorDealsMap::load(&rt.store, sectors_root, SECTOR_DEALS_CONFIG, "sector deals") - .unwrap(); - sector_numbers - .iter() - .flat_map(|sector_number| { - let deals: Option<&Vec> = sector_deals.get(sector_number).unwrap(); - match deals { - Some(deals) => deals.clone(), - None => vec![], - } - }) - .collect() - } else { - vec![] + match sectors_root { + Some(sectors_root) => { + let sector_deals = + SectorDealsMap::load(&rt.store, sectors_root, SECTOR_DEALS_CONFIG, "sector deals") + .unwrap(); + let deal_ids: Vec<_> = sector_numbers + .iter() + .flat_map(|sector_number| { + let deals: Option<&Vec> = sector_deals.get(sector_number).unwrap(); + match deals { + Some(deals) => { + assert!(!deals.is_empty()); + deals.clone() + } + None => vec![], + } + }) + .collect(); + if deal_ids.is_empty() { + None + } else { + Some(deal_ids) + } + } + None => None, } } @@ -1194,6 +1203,7 @@ pub fn assert_deal_deleted( deal_id: DealID, p: &DealProposal, sector_number: SectorNumber, + empty_sector_deals: bool, ) { use cid::multihash::Code; use cid::multihash::MultihashDigest; @@ -1224,7 +1234,12 @@ pub fn assert_deal_deleted( // Check deal is no longer associated with sector let sector_deals = get_sector_deal_ids(rt, p.provider.id().unwrap(), &[sector_number]); - assert!(!sector_deals.contains(&deal_id)); + if empty_sector_deals { + assert!(sector_deals.is_none()); + } else { + // expect some other deals, but not the one we deleted + assert!(!sector_deals.unwrap().contains(&deal_id)); + } } pub fn assert_deal_failure(add_funds: bool, post_setup: F, exit_code: ExitCode, sig_valid: bool) @@ -1506,8 +1521,10 @@ pub fn terminate_deals_and_assert_balances( ) -> (/*total_paid*/ TokenAmount, /*total_slashed*/ TokenAmount) { // Accumulate deal IDs for all sectors let deal_ids = get_sector_deal_ids(rt, provider_addr.id().unwrap(), sectors); + assert!(deal_ids.is_some()); // get deal state before the are cleaned up in terminate deals let deal_infos: Vec<(DealState, DealProposal)> = deal_ids + .unwrap() .iter() .filter_map(|id| { let proposal = find_deal_proposal(rt, *id); @@ -1599,11 +1616,13 @@ pub fn terminate_deals( // calculate the expected amount to be slashed for the provider that it is burnt let curr_epoch = *rt.epoch.borrow(); let mut total_slashed = TokenAmount::zero(); - for deal_id in deal_ids { - let d = find_deal_proposal(rt, deal_id); - if let Some(d) = d { - if curr_epoch < d.end_epoch { - total_slashed += d.provider_collateral.clone(); + if let Some(deal_ids) = deal_ids { + for deal_id in deal_ids { + let d = find_deal_proposal(rt, deal_id); + if let Some(d) = d { + if curr_epoch < d.end_epoch { + total_slashed += d.provider_collateral.clone(); + } } } } diff --git a/actors/market/tests/market_actor_legacy_tests.rs b/actors/market/tests/market_actor_legacy_tests.rs index 4ab98f551..c7a75bb68 100644 --- a/actors/market/tests/market_actor_legacy_tests.rs +++ b/actors/market/tests/market_actor_legacy_tests.rs @@ -59,7 +59,7 @@ fn slash_a_deal_and_make_payment_for_another_deal_in_the_same_epoch() { terminate_deals(&rt, PROVIDER_ADDR, &[sector_1], &[deal_id1]); cron_tick(&rt); - assert_deal_deleted(&rt, deal_id1, &d1, sector_1); + assert_deal_deleted(&rt, deal_id1, &d1, sector_1, true); let s2 = get_deal_state(&rt, deal_id2); assert_eq!(slash_epoch, s2.last_updated_epoch); check_state(&rt); diff --git a/actors/market/tests/market_actor_test.rs b/actors/market/tests/market_actor_test.rs index 9117f2c8e..8146bf47c 100644 --- a/actors/market/tests/market_actor_test.rs +++ b/actors/market/tests/market_actor_test.rs @@ -344,7 +344,7 @@ fn worker_balance_after_withdrawal_must_account_for_slashed_funds() { // terminate the deal rt.set_epoch(publish_epoch + 1); terminate_deals(&rt, PROVIDER_ADDR, &[sector_number], &[deal_id]); - assert_deal_deleted(&rt, deal_id, &proposal, sector_number); + assert_deal_deleted(&rt, deal_id, &proposal, sector_number, true); // provider cannot withdraw any funds since it's been terminated let withdraw_amount = TokenAmount::from_atto(1); @@ -1369,7 +1369,7 @@ fn terminating_a_deal_removes_proposal_synchronously() { // terminating the deal deletes proposal, state and pending_proposal but leaves deal op in queue terminate_deals(&rt, addrs.provider, &[sector_number], &[deal_id]); - assert_deal_deleted(&rt, deal_id, &proposal, sector_number); + assert_deal_deleted(&rt, deal_id, &proposal, sector_number, true); check_state(&rt); // the next cron_tick will remove the dangling deal op entry diff --git a/actors/market/tests/on_miner_sectors_terminate.rs b/actors/market/tests/on_miner_sectors_terminate.rs index 470423f2e..a9c3f5d55 100644 --- a/actors/market/tests/on_miner_sectors_terminate.rs +++ b/actors/market/tests/on_miner_sectors_terminate.rs @@ -9,7 +9,6 @@ use fil_actors_runtime::runtime::builtins::Type; use fil_actors_runtime::test_utils::*; use fvm_ipld_encoding::ipld_block::IpldBlock; use fvm_shared::address::Address; -use fvm_shared::deal::DealID; use fvm_shared::econ::TokenAmount; use fvm_shared::error::ExitCode; use num_traits::Zero; @@ -41,13 +40,13 @@ fn terminate_multiple_deals_from_single_provider() { activate_deals_legacy(&rt, sector_expiry, PROVIDER_ADDR, current_epoch, id2, &[id2]); terminate_deals(&rt, PROVIDER_ADDR, &[id0], &[id0]); - assert_deal_deleted(&rt, id0, &deal0, id0); + assert_deal_deleted(&rt, id0, &deal0, id0, true); assert_deals_not_marked_terminated(&rt, &[id1, id2]); terminate_deals(&rt, PROVIDER_ADDR, &[id1, id2], &[id1, id2]); - assert_deal_deleted(&rt, id0, &deal0, id0); - assert_deal_deleted(&rt, id1, &deal1, id1); - assert_deal_deleted(&rt, id1, &deal2, id2); + assert_deal_deleted(&rt, id0, &deal0, id0, true); + assert_deal_deleted(&rt, id1, &deal1, id1, true); + assert_deal_deleted(&rt, id1, &deal2, id2, true); } #[test] @@ -92,14 +91,14 @@ fn terminate_multiple_deals_from_multiple_providers() { &[sector_number], &[id0, id1, id2], ); - assert_deal_deleted(&rt, id0, &deal0, sector_number); - assert_deal_deleted(&rt, id1, &deal1, sector_number); - assert_deal_deleted(&rt, id2, &deal2, sector_number); + assert_deal_deleted(&rt, id0, &deal0, sector_number, true); + assert_deal_deleted(&rt, id1, &deal1, sector_number, true); + assert_deal_deleted(&rt, id2, &deal2, sector_number, true); assert_deals_not_marked_terminated(&rt, &[id3, id4]); terminate_deals_and_assert_balances(&rt, CLIENT_ADDR, provider2, &[sector_number], &[id3, id4]); - assert_deal_deleted(&rt, id3, &deal3, sector_number); - assert_deal_deleted(&rt, id4, &deal4, sector_number); + assert_deal_deleted(&rt, id3, &deal3, sector_number, true); + assert_deal_deleted(&rt, id4, &deal4, sector_number, true); } #[test] @@ -133,7 +132,7 @@ fn ignore_sector_that_does_not_exist() { let s = get_deal_state(&rt, deal1); assert_eq!(s.slash_epoch, -1); - assert_eq!(vec![deal1], get_sector_deal_ids(&rt, PROVIDER_ID, &[sector_number])); + assert_eq!(vec![deal1], get_sector_deal_ids(&rt, PROVIDER_ID, &[sector_number]).unwrap()); check_state(&rt); } @@ -190,12 +189,12 @@ fn terminate_valid_deals_along_with_just_expired_deal() { // Deal2 isn't terminated (or cleaned up) because it expired and is waiting for settlement. &[id0, id1], ); - assert_deal_deleted(&rt, id0, &deal0, sector_number); - assert_deal_deleted(&rt, id1, &deal1, sector_number); + assert_deal_deleted(&rt, id0, &deal0, sector_number, true); + assert_deal_deleted(&rt, id1, &deal1, sector_number, true); // Deal2 state still exists, and isn't terminated. assert_deals_not_marked_terminated(&rt, &[id2]); // All deals are removed from sector deals mapping at once. - assert_eq!(Vec::::new(), get_sector_deal_ids(&rt, PROVIDER_ID, &[sector_number])); + assert!(get_sector_deal_ids(&rt, PROVIDER_ID, &[sector_number]).is_none()); check_state(&rt); } @@ -255,7 +254,7 @@ fn terminate_valid_deals_along_with_expired_and_cleaned_up_deal() { cron_tick(&rt); // expired deal deleted normally - assert_deal_deleted(&rt, deal_ids[1], &deal2, sector_number); + assert_deal_deleted(&rt, deal_ids[1], &deal2, sector_number, false); assert_deals_not_marked_terminated(&rt, &deal_ids[0..0]); terminate_deals_and_assert_balances( @@ -266,7 +265,7 @@ fn terminate_valid_deals_along_with_expired_and_cleaned_up_deal() { &[deal_ids[0]], ); // terminated deal deleted - assert_deal_deleted(&rt, deal_ids[0], &deal1, sector_number); + assert_deal_deleted(&rt, deal_ids[0], &deal1, sector_number, true); // terminated deal has a dangling deal op, normally expired deal doesn't check_state(&rt); diff --git a/actors/market/tests/random_cron_epoch_during_publish.rs b/actors/market/tests/random_cron_epoch_during_publish.rs index 51e42971b..805497a0c 100644 --- a/actors/market/tests/random_cron_epoch_during_publish.rs +++ b/actors/market/tests/random_cron_epoch_during_publish.rs @@ -96,7 +96,7 @@ fn deal_is_processed_after_its_end_epoch_should_expire_correctly() { assert!(slashed.is_zero()); let duration = END_EPOCH - START_EPOCH; assert_eq!(duration * &deal_proposal.storage_price_per_epoch, pay); - assert_deal_deleted(&rt, deal_id, &deal_proposal, SECTOR_NUMBER); + assert_deal_deleted(&rt, deal_id, &deal_proposal, SECTOR_NUMBER, true); check_state(&rt); } @@ -152,6 +152,6 @@ fn cron_processing_of_deal_after_missed_activation_should_fail_and_slash() { ); cron_tick(&rt); - assert_deal_deleted(&rt, deal_id, &deal_proposal, SECTOR_NUMBER); + assert_deal_deleted(&rt, deal_id, &deal_proposal, SECTOR_NUMBER, true); check_state(&rt); } diff --git a/actors/market/tests/sector_content_changed.rs b/actors/market/tests/sector_content_changed.rs index 59439d38b..16decb21b 100644 --- a/actors/market/tests/sector_content_changed.rs +++ b/actors/market/tests/sector_content_changed.rs @@ -88,7 +88,7 @@ fn simple_one_sector() { assert!(ret.sectors[0].added.iter().all(|r| r.accepted)); // Deal IDs are stored under the sector, in correct order. - assert_eq!(deal_ids, get_sector_deal_ids(&rt, PROVIDER_ID, &[sno])); + assert_eq!(deal_ids, get_sector_deal_ids(&rt, PROVIDER_ID, &[sno]).unwrap()); // Deal states include allocation IDs from when they were published. for id in deal_ids.iter() { @@ -142,8 +142,8 @@ fn simple_multiple_sectors() { assert_eq!(vec![PieceReturn { accepted: true }], ret.sectors[2].added); // Deal IDs are stored under the right sector, in correct order. - assert_eq!(deal_ids[0..2], get_sector_deal_ids(&rt, PROVIDER_ID, &[1])); - assert_eq!(deal_ids[2..3], get_sector_deal_ids(&rt, PROVIDER_ID, &[2])); + assert_eq!(deal_ids[0..2], get_sector_deal_ids(&rt, PROVIDER_ID, &[1]).unwrap()); + assert_eq!(deal_ids[2..3], get_sector_deal_ids(&rt, PROVIDER_ID, &[2]).unwrap()); } #[test] @@ -188,7 +188,7 @@ fn new_deal_existing_sector() { sector_content_changed(&rt, PROVIDER_ADDR, changes).unwrap(); // All deal IDs are stored under the right sector, in correct order. - assert_eq!(deal_ids[0..3], get_sector_deal_ids(&rt, PROVIDER_ID, &[1])); + assert_eq!(deal_ids[0..3], get_sector_deal_ids(&rt, PROVIDER_ID, &[1]).unwrap()); } #[test] @@ -303,8 +303,8 @@ fn failures_isolated() { assert_eq!(vec![PieceReturn { accepted: true }], ret.sectors[2].added); // Successful deal IDs are stored under the right sector, in correct order. - assert_eq!(deal_ids[0..1], get_sector_deal_ids(&rt, PROVIDER_ID, &[1])); - assert_eq!(deal_ids[3..4], get_sector_deal_ids(&rt, PROVIDER_ID, &[3])); + assert_eq!(deal_ids[0..1], get_sector_deal_ids(&rt, PROVIDER_ID, &[1]).unwrap()); + assert_eq!(deal_ids[3..4], get_sector_deal_ids(&rt, PROVIDER_ID, &[3]).unwrap()); } #[test] @@ -346,8 +346,8 @@ fn rejects_duplicates_in_same_sector() { ); // Deal IDs are stored under the right sector, in correct order. - assert_eq!(deal_ids[0..2], get_sector_deal_ids(&rt, PROVIDER_ID, &[1])); - assert_eq!(Vec::::new(), get_sector_deal_ids(&rt, PROVIDER_ID, &[2])); + assert_eq!(deal_ids[0..2], get_sector_deal_ids(&rt, PROVIDER_ID, &[1]).unwrap()); + assert!(get_sector_deal_ids(&rt, PROVIDER_ID, &[2]).is_none()); } #[test] @@ -407,8 +407,8 @@ fn rejects_duplicates_across_sectors() { ); // Deal IDs are stored under the right sector, in correct order. - assert_eq!(deal_ids[0..2], get_sector_deal_ids(&rt, PROVIDER_ID, &[1])); - assert_eq!(deal_ids[2..3], get_sector_deal_ids(&rt, PROVIDER_ID, &[2])); + assert_eq!(deal_ids[0..2], get_sector_deal_ids(&rt, PROVIDER_ID, &[1]).unwrap()); + assert_eq!(deal_ids[2..3], get_sector_deal_ids(&rt, PROVIDER_ID, &[2]).unwrap()); } #[test] diff --git a/actors/market/tests/settle_deal_payments.rs b/actors/market/tests/settle_deal_payments.rs index c552e3708..f41ec6336 100644 --- a/actors/market/tests/settle_deal_payments.rs +++ b/actors/market/tests/settle_deal_payments.rs @@ -43,7 +43,7 @@ fn timedout_deal_is_slashed_and_deleted() { assert_eq!(c_escrow, client_acct.balance); assert!(client_acct.locked.is_zero()); assert_account_zero(&rt, PROVIDER_ADDR); - assert_deal_deleted(&rt, deal_id, &deal_proposal, 0); + assert_deal_deleted(&rt, deal_id, &deal_proposal, 0, true); check_state(&rt); @@ -112,7 +112,7 @@ fn can_manually_settle_deals_in_the_cron_queue() { assert_eq!(&provider_after.balance, &final_provider_escrow); // cleaned up by cron - assert_deal_deleted(&rt, deal_id, &deal_proposal, sector_number) + assert_deal_deleted(&rt, deal_id, &deal_proposal, sector_number, true) } #[test] @@ -267,9 +267,9 @@ fn batch_settlement_of_deals_allows_partial_success() { finished_summary, DealSettlementSummary { completed: true, payment: finished_payment.clone() } ); - assert_deal_deleted(&rt, finished_id, &finished_proposal, sector_number); - assert_deal_deleted(&rt, terminated_id, &terminated_proposal, sector_number); - assert_deal_deleted(&rt, unactivated_id, &unactivated_proposal, sector_number); + assert_deal_deleted(&rt, finished_id, &finished_proposal, sector_number, false); + assert_deal_deleted(&rt, terminated_id, &terminated_proposal, sector_number, false); + assert_deal_deleted(&rt, unactivated_id, &unactivated_proposal, sector_number, false); // check that the sum total of all payments/slashing has been reflected in the balance table let client_end = get_balance(&rt, &CLIENT_ADDR); diff --git a/actors/market/tests/transient_marked_for_termination.rs b/actors/market/tests/transient_marked_for_termination.rs index cde1866be..aeaebff37 100644 --- a/actors/market/tests/transient_marked_for_termination.rs +++ b/actors/market/tests/transient_marked_for_termination.rs @@ -102,7 +102,7 @@ fn deal_scheduled_for_termination_cannot_be_settled_manually() { cron_tick(&rt); // assert that the slashed deal was terminated - assert_deal_deleted(&rt, slashed_deal, &slashed_prop, sector_number); + assert_deal_deleted(&rt, slashed_deal, &slashed_prop, sector_number, false); // attempt to settle payment for both deals again - partially succeeds because not found deals are ignored rt.set_epoch(scheduled_epoch + 1); diff --git a/actors/miner/src/lib.rs b/actors/miner/src/lib.rs index 80850a44d..433a5a0c7 100644 --- a/actors/miner/src/lib.rs +++ b/actors/miner/src/lib.rs @@ -109,7 +109,7 @@ pub enum Method { ChangePeerID = 4, SubmitWindowedPoSt = 5, //PreCommitSector = 6, // Deprecated - ProveCommitSector = 7, + //ProveCommitSector = 7, // Deprecated ExtendSectorExpiration = 8, TerminateSectors = 9, DeclareFaults = 10, @@ -119,7 +119,7 @@ pub enum Method { ApplyRewards = 14, ReportConsensusFault = 15, WithdrawBalance = 16, - ConfirmSectorProofsValid = 17, + InternalSectorSetupForPreseal = 17, ChangeMultiaddrs = 18, CompactPartitions = 19, CompactSectorNumbers = 20, @@ -1276,7 +1276,7 @@ impl Actor { ) { return Err(actor_error!( forbidden, - "can only dispute window posts during the dispute window\ + "can only dispute window posts during the dispute window \ ({} epochs after the challenge window closes)", policy.wpost_dispute_window )); @@ -1924,8 +1924,8 @@ impl Actor { if !params.aggregate_proof.is_empty() { // Aggregate fee is paid on the sectors successfully proven, - // but without regard to data activation which could subsequently fail - // and prevent sector activation. + // but without regard to data activation which may have subsequently failed + // and prevented sector activation. pay_aggregate_seal_proof_fee(rt, proven_activation_inputs.len())?; } @@ -1950,68 +1950,11 @@ impl Actor { Ok(ProveCommitSectors3Return { activation_results: result }) } - /// Checks state of the corresponding sector pre-commitment, then schedules the proof to be verified in bulk - /// by the power actor. - /// If valid, the power actor will call ConfirmSectorProofsValid at the end of the same epoch as this message. - fn prove_commit_sector( + fn internal_sector_setup_preseal( rt: &impl Runtime, - params: ProveCommitSectorParams, + params: InternalSectorSetupForPresealParams, ) -> Result<(), ActorError> { - // Validate caller and parameters. - let st: State = rt.state()?; - let store = rt.store(); - // Note: this accepts any caller for legacy, but probably shouldn't. - // Since the miner can provide arbitrary control addresses, there's not much advantage - // in allowing any caller, but some risk if there's an exploitable bug. - rt.validate_immediate_caller_accept_any()?; - - if params.sector_number > MAX_SECTOR_NUMBER { - return Err(actor_error!(illegal_argument, "sector number greater than maximum")); - } - - // Validate pre-commit. - let precommit = st - .get_precommitted_sector(store, params.sector_number) - .with_context(|| format!("loading pre-commit {}", params.sector_number))? - .ok_or_else(|| { - actor_error!(not_found, "no pre-commited sector {}", params.sector_number) - })?; - - validate_seal_proofs(precommit.info.seal_proof, &[params.proof.clone()])?; - - let allow_deals = true; // Legacy onboarding entry points allow pre-committed deals. - let all_or_nothing = true; // The singleton must succeed. - let (_, proof_inputs) = - validate_precommits(rt, &vec![precommit], allow_deals, all_or_nothing)?; - let miner_actor_id = rt.message().receiver().id().unwrap(); - - let svi = proof_inputs[0].to_seal_verify_info(miner_actor_id, ¶ms.proof); - extract_send_result(rt.send_simple( - &STORAGE_POWER_ACTOR_ADDR, - ext::power::SUBMIT_POREP_FOR_BULK_VERIFY_METHOD, - IpldBlock::serialize_cbor(&svi)?, - TokenAmount::zero(), - ))?; - - Ok(()) - } - - fn confirm_sector_proofs_valid( - rt: &impl Runtime, - params: ConfirmSectorProofsParams, - ) -> Result<(), ActorError> { - rt.validate_immediate_caller_is(std::iter::once(&STORAGE_POWER_ACTOR_ADDR))?; - - /* validate params */ - // This should be enforced by the power actor. We log here just in case - // something goes wrong. - if params.sectors.len() > ext::power::MAX_MINER_PROVE_COMMITS_PER_EPOCH { - warn!( - "confirmed more prove commits in an epoch than permitted: {} > {}", - params.sectors.len(), - ext::power::MAX_MINER_PROVE_COMMITS_PER_EPOCH - ); - } + rt.validate_immediate_caller_is(std::iter::once(&SYSTEM_ACTOR_ADDR))?; let st: State = rt.state()?; let store = rt.store(); // This skips missing pre-commits. @@ -5711,7 +5654,6 @@ impl ActorCode for Actor { ChangeWorkerAddress|ChangeWorkerAddressExported => change_worker_address, ChangePeerID|ChangePeerIDExported => change_peer_id, SubmitWindowedPoSt => submit_windowed_post, - ProveCommitSector => prove_commit_sector, ExtendSectorExpiration => extend_sector_expiration, TerminateSectors => terminate_sectors, DeclareFaults => declare_faults, @@ -5721,7 +5663,7 @@ impl ActorCode for Actor { ApplyRewards => apply_rewards, ReportConsensusFault => report_consensus_fault, WithdrawBalance|WithdrawBalanceExported => withdraw_balance, - ConfirmSectorProofsValid => confirm_sector_proofs_valid, + InternalSectorSetupForPreseal => internal_sector_setup_preseal, ChangeMultiaddrs|ChangeMultiaddrsExported => change_multiaddresses, CompactPartitions => compact_partitions, CompactSectorNumbers => compact_sector_numbers, diff --git a/actors/miner/src/types.rs b/actors/miner/src/types.rs index 5a5aca822..62f731ea6 100644 --- a/actors/miner/src/types.rs +++ b/actors/miner/src/types.rs @@ -89,7 +89,7 @@ pub struct ChangeMultiaddrsParams { } #[derive(Serialize_tuple, Deserialize_tuple)] -pub struct ConfirmSectorProofsParams { +pub struct InternalSectorSetupForPresealParams { pub sectors: Vec, pub reward_smoothed: FilterEstimate, #[serde(with = "bigint_ser")] @@ -129,6 +129,7 @@ pub struct SubmitWindowedPoStParams { pub chain_commit_rand: Randomness, } +// Deprecated as of FIP 0084 -- kept for legacy testing #[derive(Serialize_tuple, Deserialize_tuple)] pub struct ProveCommitSectorParams { pub sector_number: SectorNumber, diff --git a/actors/miner/tests/exported_getters.rs b/actors/miner/tests/exported_getters.rs index b6c6bf9c8..a54679b74 100644 --- a/actors/miner/tests/exported_getters.rs +++ b/actors/miner/tests/exported_getters.rs @@ -115,8 +115,7 @@ fn collateral_getters() { let precommit_params = h.make_pre_commit_params(sector_no, precommit_epoch - 1, expiration, vec![]); - let precommit = - h.pre_commit_sector_and_get(&rt, precommit_params, PreCommitConfig::empty(), true); + h.pre_commit_sector_and_get(&rt, precommit_params, PreCommitConfig::empty(), true); // run prove commit logic rt.set_epoch(prove_commit_epoch); @@ -125,12 +124,7 @@ fn collateral_getters() { let pcc = ProveCommitConfig::empty(); let sector = h - .prove_commit_sector_and_confirm( - &rt, - &precommit, - h.make_prove_commit_params(sector_no), - pcc, - ) + .deprecated_sector_commit(&rt, &vec![], h.make_prove_commit_params(sector_no), pcc) .unwrap(); // query available balance diff --git a/actors/miner/tests/prove_commit.rs b/actors/miner/tests/prove_commit.rs index 279d5da4a..b5ef41f58 100644 --- a/actors/miner/tests/prove_commit.rs +++ b/actors/miner/tests/prove_commit.rs @@ -3,20 +3,11 @@ use fvm_shared::{ clock::ChainEpoch, econ::TokenAmount, error::ExitCode, - sector::StoragePower, }; -use std::collections::HashMap; -use fil_actor_miner::ext::market::NO_ALLOCATION_ID; -use fil_actor_miner::{ - initial_pledge_for_power, max_prove_commit_duration, pre_commit_deposit_for_power, - qa_power_for_weight, qa_power_max, PowerPair, PreCommitSectorBatchParams, VestSpec, -}; -use fil_actors_runtime::{ - reward::FilterEstimate, runtime::policy_constants::MAX_SECTOR_NUMBER, - test_utils::make_piece_cid, -}; -use fil_actors_runtime::{runtime::Runtime, test_utils::expect_abort, DealWeight}; +use fil_actor_miner::{max_prove_commit_duration, VestSpec}; +use fil_actors_runtime::reward::FilterEstimate; +use fil_actors_runtime::test_utils::expect_abort; use util::*; mod util; @@ -25,397 +16,8 @@ mod util; // between pre and prove commit const DEFAULT_SECTOR_EXPIRATION: ChainEpoch = 220; -const VERIFIED_DEAL_WEIGHT_MULTIPLIER: u64 = 100; -const QUALITY_BASE_MULTIPLIER: u64 = 10; const PERIOD_OFFSET: ChainEpoch = 100; -#[test] -fn prove_single_sector() { - let h = ActorHarness::new(PERIOD_OFFSET); - let rt = h.new_runtime(); - rt.balance.replace(BIG_BALANCE.clone()); - - let precommit_epoch = PERIOD_OFFSET + 1; - rt.set_epoch(precommit_epoch); - - h.construct_and_verify(&rt); - let dl_info = h.deadline(&rt); - - // Make a good commitment for the proof to target. - // Use the max sector number to make sure everything works. - let sector_no = MAX_SECTOR_NUMBER; - let prove_commit_epoch = precommit_epoch + rt.policy.pre_commit_challenge_delay + 1; - let expiration = - dl_info.period_end() + DEFAULT_SECTOR_EXPIRATION * rt.policy.wpost_proving_period; // something on deadline boundary but > 180 days - // Fill the sector with verified deals - let deal_space = BigInt::zero(); - let verified_deal = test_activated_deal(h.sector_size as u64, 1); - let verified_deal_space = BigInt::from(verified_deal.size.0); - - // Pre-commit with a deal in order to exercise non-zero deal weights. - let precommit_params = - h.make_pre_commit_params(sector_no, precommit_epoch - 1, expiration, vec![1]); - let precommit = - h.pre_commit_sector_and_get(&rt, precommit_params, PreCommitConfig::empty(), true); - - let pwr_estimate = qa_power_max(h.sector_size); - let expected_deposit = pre_commit_deposit_for_power( - &h.epoch_reward_smooth, - &h.epoch_qa_power_smooth, - &pwr_estimate, - ); - assert_eq!(expected_deposit, precommit.pre_commit_deposit); - - // expect total precommit deposit to equal our new deposit - let st = h.get_state(&rt); - assert_eq!(expected_deposit, st.pre_commit_deposits); - - // run prove commit logic - rt.set_epoch(prove_commit_epoch); - rt.balance.replace(TokenAmount::from_whole(1000)); - let mut pcc = ProveCommitConfig::empty(); - pcc.add_activated_deals(sector_no, vec![verified_deal]); - - let sector = h - .prove_commit_sector_and_confirm( - &rt, - &precommit, - h.make_prove_commit_params(sector_no), - pcc, - ) - .unwrap(); - - assert_eq!(precommit.info.seal_proof, sector.seal_proof); - assert_eq!(precommit.info.sealed_cid, sector.sealed_cid); - assert_eq!(*rt.epoch.borrow(), sector.activation); - assert_eq!(precommit.info.expiration, sector.expiration); - - // expect precommit to have been removed - let st = h.get_state(&rt); - let found = st.get_precommitted_sector(&rt.store, sector_no).unwrap(); - assert!(found.is_none()); - - // expect deposit to have been transferred to initial pledges - assert!(st.pre_commit_deposits.is_zero()); - - // The sector is exactly full with verified deals, so expect fully verified power. - let duration = precommit.info.expiration - prove_commit_epoch; - let deal_weight = deal_space * duration; - let verified_deal_weight = verified_deal_space * duration; - let expected_power = StoragePower::from(h.sector_size as u64) - * (VERIFIED_DEAL_WEIGHT_MULTIPLIER / QUALITY_BASE_MULTIPLIER); - let qa_power = - qa_power_for_weight(h.sector_size, duration, &deal_weight, &verified_deal_weight); - assert_eq!(expected_power, qa_power); - let sector_power = - PowerPair { raw: StoragePower::from(h.sector_size as u64), qa: qa_power.clone() }; - - // expect deal weights to be transferred to on chain info - assert_eq!(deal_weight, sector.deal_weight); - assert_eq!(verified_deal_weight, sector.verified_deal_weight); - - // expect initial plege of sector to be set, and be total pledge requirement - let expected_initial_pledge = initial_pledge_for_power( - &qa_power, - &h.baseline_power, - &h.epoch_reward_smooth, - &h.epoch_qa_power_smooth, - &rt.total_fil_circ_supply(), - ); - assert_eq!(expected_initial_pledge, sector.initial_pledge); - assert_eq!(expected_initial_pledge, st.initial_pledge); - - // expect sector to be assigned a deadline/partition - let (dl_idx, p_idx) = st.find_sector(rt.store(), sector_no).unwrap(); - let (deadline, partition) = h.get_deadline_and_partition(&rt, dl_idx, p_idx); - assert_eq!(1, deadline.live_sectors); - assert!(deadline.partitions_posted.is_empty()); - assert!(deadline.early_terminations.is_empty()); - - let quant = st.quant_spec_for_deadline(&rt.policy, dl_idx); - let quantized_expiration = quant.quantize_up(precommit.info.expiration); - - let d_queue = h.collect_deadline_expirations(&rt, &deadline); - assert_eq!(HashMap::from([(quantized_expiration, vec![p_idx])]), d_queue); - - assert_bitfield_equals(&partition.sectors, &[sector_no]); - assert!(partition.faults.is_empty()); - assert!(partition.recoveries.is_empty()); - assert!(partition.terminated.is_empty()); - assert_eq!(sector_power, partition.live_power); - assert!(partition.faulty_power.is_zero()); - assert!(partition.recovering_power.is_zero()); - - let p_queue = h.collect_partition_expirations(&rt, &partition); - let entry = &p_queue[&quantized_expiration]; - assert_bitfield_equals(&entry.on_time_sectors, &[sector_no]); - assert!(entry.early_sectors.is_empty()); - assert_eq!(expected_initial_pledge, entry.on_time_pledge); - assert_eq!(sector_power, entry.active_power); - assert!(entry.faulty_power.is_zero()); -} - -#[test] -fn prove_sectors_from_batch_pre_commit() { - let h = ActorHarness::new(PERIOD_OFFSET); - let rt = h.new_runtime(); - rt.balance.replace(BIG_BALANCE.clone()); - - let precommit_epoch = PERIOD_OFFSET + 1; - rt.set_epoch(precommit_epoch); - - h.construct_and_verify(&rt); - let dl_info = h.deadline(&rt); - - let sector_expiration = - dl_info.period_end() + DEFAULT_SECTOR_EXPIRATION * rt.policy.wpost_proving_period; - - let sectors = vec![ - h.make_pre_commit_params(100, precommit_epoch - 1, sector_expiration, vec![]), - h.make_pre_commit_params(101, precommit_epoch - 1, sector_expiration, vec![1]), // 1 * 32GiB verified deal - h.make_pre_commit_params(102, precommit_epoch - 1, sector_expiration, vec![2, 3]), // 2 * 16GiB verified deals - ]; - - let deal_space: i64 = 32 << 30; - let prove_commit_epoch = precommit_epoch + rt.policy.pre_commit_challenge_delay + 1; - let deal_lifespan = sector_expiration - prove_commit_epoch; - let verified_deal1 = test_activated_deal(deal_space as u64, 1); - let verified_deal2 = test_activated_deal(deal_space as u64 / 2, 2); - let verified_deal3 = test_activated_deal(deal_space as u64 / 2, 3); - let deal_weight = DealWeight::zero(); - let verified_deal_weight = deal_space * DealWeight::from(deal_lifespan); - - let conf = PreCommitBatchConfig { - sector_unsealed_cid: vec![None, Some(make_piece_cid(b"1")), Some(make_piece_cid(b"2|3"))], - first_for_miner: true, - }; - - let precommits = h.pre_commit_sector_batch_and_get( - &rt, - PreCommitSectorBatchParams { sectors }, - &conf, - &TokenAmount::zero(), - ); - - rt.set_epoch(prove_commit_epoch); - - let no_deal_power = qa_power_for_weight( - h.sector_size, - sector_expiration - prove_commit_epoch, - &DealWeight::zero(), - &DealWeight::zero(), - ); - let no_deal_pledge = initial_pledge_for_power( - &no_deal_power, - &h.baseline_power, - &h.epoch_reward_smooth, - &h.epoch_qa_power_smooth, - &rt.total_fil_circ_supply(), - ); - let full_deal_power = qa_power_for_weight( - h.sector_size, - sector_expiration - prove_commit_epoch, - &deal_weight, - &verified_deal_weight, - ); - let expected_power = StoragePower::from(h.sector_size as u64) - * (VERIFIED_DEAL_WEIGHT_MULTIPLIER / QUALITY_BASE_MULTIPLIER); - assert_eq!(full_deal_power, expected_power); - let full_deal_pledge = initial_pledge_for_power( - &full_deal_power, - &h.baseline_power, - &h.epoch_reward_smooth, - &h.epoch_qa_power_smooth, - &rt.total_fil_circ_supply(), - ); - - // Prove just the first sector, with no deals - { - let precommit = &precommits[0]; - let sector = h - .prove_commit_sector_and_confirm( - &rt, - precommit, - h.make_prove_commit_params(precommit.info.sector_number), - ProveCommitConfig::default(), - ) - .unwrap(); - assert_eq!(*rt.epoch.borrow(), sector.activation); - let st = h.get_state(&rt); - let expected_deposits = 2 * pre_commit_deposit_for_power( - &h.epoch_reward_smooth, - &h.epoch_qa_power_smooth, - &qa_power_max(h.sector_size), - ); // first sector deposit released - - assert_eq!(expected_deposits, st.pre_commit_deposits); - - // Expect power/pledge for a sector with no deals - assert_eq!(no_deal_pledge, sector.initial_pledge); - assert_eq!(no_deal_pledge, st.initial_pledge); - } - // Prove the next, with one deal - { - let precommit = &precommits[1]; - let mut pcc = ProveCommitConfig::empty(); - pcc.add_activated_deals(precommit.info.sector_number, vec![verified_deal1]); - let sector = h - .prove_commit_sector_and_confirm( - &rt, - precommit, - h.make_prove_commit_params(precommit.info.sector_number), - pcc, - ) - .unwrap(); - assert_eq!(*rt.epoch.borrow(), sector.activation); - let st = h.get_state(&rt); - let expected_deposits = pre_commit_deposit_for_power( - &h.epoch_reward_smooth, - &h.epoch_qa_power_smooth, - &qa_power_max(h.sector_size), - ); // first and second deposit released - - assert_eq!(expected_deposits, st.pre_commit_deposits); - - // Expect power/pledge for the two sectors (only this one having any deal weight) - assert_eq!(full_deal_pledge, sector.initial_pledge); - assert_eq!(&no_deal_pledge + &full_deal_pledge, st.initial_pledge); - } - // Prove the last - { - let precommit = &precommits[2]; - let mut pcc = ProveCommitConfig::empty(); - pcc.add_activated_deals(precommit.info.sector_number, vec![verified_deal2, verified_deal3]); - let sector = h - .prove_commit_sector_and_confirm( - &rt, - precommit, - h.make_prove_commit_params(precommit.info.sector_number), - pcc, - ) - .unwrap(); - assert_eq!(*rt.epoch.borrow(), sector.activation); - let st = h.get_state(&rt); - assert!(st.pre_commit_deposits.is_zero()); - - // Expect power/pledge for the three sectors - assert_eq!(&full_deal_pledge, §or.initial_pledge); - assert_eq!(&no_deal_pledge + &full_deal_pledge + &full_deal_pledge, st.initial_pledge); - } -} - -#[test] -fn invalid_proof_rejected() { - let h = ActorHarness::new(PERIOD_OFFSET); - let rt = h.new_runtime(); - rt.balance.replace(BIG_BALANCE.clone()); - - let precommit_epoch = PERIOD_OFFSET + 1; - rt.set_epoch(precommit_epoch); - - h.construct_and_verify(&rt); - let deadline = h.deadline(&rt); - - // Make a good commitment for the proof to target. - let sector_no = 100; - let params = h.make_pre_commit_params( - sector_no, - precommit_epoch - 1, - deadline.period_end() + DEFAULT_SECTOR_EXPIRATION * rt.policy.wpost_proving_period, - vec![1], - ); - let precommit = h.pre_commit_sector_and_get(&rt, params, PreCommitConfig::default(), true); - - // Sector pre-commitment missing. - rt.set_epoch(precommit_epoch + rt.policy.pre_commit_challenge_delay + 1); - expect_abort( - ExitCode::USR_NOT_FOUND, - h.prove_commit_sector_and_confirm( - &rt, - &precommit, - h.make_prove_commit_params(sector_no + 1), - ProveCommitConfig::empty(), - ), - ); - rt.reset(); - - // Too late. - rt.set_epoch( - precommit_epoch - + max_prove_commit_duration(&rt.policy, precommit.info.seal_proof).unwrap() - + 1, - ); - expect_abort( - ExitCode::USR_ILLEGAL_ARGUMENT, - h.prove_commit_sector_and_confirm( - &rt, - &precommit, - h.make_prove_commit_params(sector_no), - ProveCommitConfig::empty(), - ), - ); - rt.reset(); - - // Too early. - rt.set_epoch(precommit_epoch + rt.policy.pre_commit_challenge_delay - 1); - expect_abort( - ExitCode::USR_FORBIDDEN, - h.prove_commit_sector_and_confirm( - &rt, - &precommit, - h.make_prove_commit_params(sector_no), - ProveCommitConfig::empty(), - ), - ); - rt.reset(); - - // Set the right epoch for all following tests - rt.set_epoch(precommit_epoch + rt.policy.pre_commit_challenge_delay + 1); - - // Invalid deals (market ActivateDeals aborts) - let verify_deals_exit = - HashMap::from([(precommit.info.sector_number, ExitCode::USR_ILLEGAL_ARGUMENT)]); - expect_abort( - ExitCode::USR_ILLEGAL_ARGUMENT, - h.prove_commit_sector_and_confirm( - &rt, - &precommit, - h.make_prove_commit_params(sector_no), - ProveCommitConfig { verify_deals_exit, ..Default::default() }, - ), - ); - rt.reset(); - - rt.balance.replace(TokenAmount::from_whole(1_000)); - - let prove_commit = h.make_prove_commit_params(sector_no); - h.prove_commit_sector_and_confirm(&rt, &precommit, prove_commit, ProveCommitConfig::empty()) - .unwrap(); - let st = h.get_state(&rt); - - // Verify new sectors - // TODO minerstate - //newSectors, err := st.NewSectors.All(miner.SectorsMax) - //require.NoError(t, err) - //assert.Equal(t, []uint64{uint64(sectorNo)}, newSectors) - // Verify pledge lock-up - assert!(st.initial_pledge.is_positive()); - rt.reset(); - - // Duplicate proof (sector no-longer pre-committed) - expect_abort( - ExitCode::USR_NOT_FOUND, - h.prove_commit_sector_and_confirm( - &rt, - &precommit, - h.make_prove_commit_params(sector_no), - ProveCommitConfig::empty(), - ), - ); - rt.reset(); - h.check_state(&rt); -} - #[test] fn prove_commit_aborts_if_pledge_requirement_not_met() { let mut h = ActorHarness::new(PERIOD_OFFSET); @@ -454,9 +56,9 @@ fn prove_commit_aborts_if_pledge_requirement_not_met() { ); expect_abort( ExitCode::USR_INSUFFICIENT_FUNDS, - h.prove_commit_sector_and_confirm( + h.deprecated_sector_commit( &rt, - &precommit, + &vec![], h.make_prove_commit_params(h.next_sector_no), ProveCommitConfig::empty(), ), @@ -467,9 +69,9 @@ fn prove_commit_aborts_if_pledge_requirement_not_met() { rt.balance.replace( &st.pre_commit_deposits + &st.initial_pledge + &st.initial_pledge + &st.locked_funds, ); - h.prove_commit_sector_and_confirm( + h.deprecated_sector_commit( &rt, - &precommit, + &vec![], h.make_prove_commit_params(h.next_sector_no), ProveCommitConfig::empty(), ) @@ -477,55 +79,9 @@ fn prove_commit_aborts_if_pledge_requirement_not_met() { h.check_state(&rt); } -#[test] -fn drop_invalid_prove_commit_while_processing_valid_one() { - let mut h = ActorHarness::new(PERIOD_OFFSET); - let rt = h.new_runtime(); - rt.balance.replace(BIG_BALANCE.clone()); - - h.construct_and_verify(&rt); - - // make two precommits - let expiration = DEFAULT_SECTOR_EXPIRATION * rt.policy.wpost_proving_period + PERIOD_OFFSET - 1; - let precommit_epoch = *rt.epoch.borrow() + 1; - rt.set_epoch(precommit_epoch); - let params_a = - h.make_pre_commit_params(h.next_sector_no, *rt.epoch.borrow() - 1, expiration, vec![1]); - let pre_commit_a = h.pre_commit_sector_and_get(&rt, params_a, PreCommitConfig::default(), true); - let sector_no_a = h.next_sector_no; - h.next_sector_no += 1; - let params_b = - h.make_pre_commit_params(h.next_sector_no, *rt.epoch.borrow() - 1, expiration, vec![2]); - let pre_commit_b = - h.pre_commit_sector_and_get(&rt, params_b, PreCommitConfig::default(), false); - let sector_no_b = h.next_sector_no; - - // handle both prove commits in the same epoch - rt.set_epoch( - precommit_epoch + max_prove_commit_duration(&rt.policy, h.seal_proof_type).unwrap() - 1, - ); - - h.prove_commit_sector(&rt, &pre_commit_a, h.make_prove_commit_params(sector_no_a)).unwrap(); - h.prove_commit_sector(&rt, &pre_commit_b, h.make_prove_commit_params(sector_no_b)).unwrap(); - - let conf = ProveCommitConfig { - verify_deals_exit: HashMap::from([(sector_no_a, ExitCode::USR_ILLEGAL_ARGUMENT)]), - activated_deals: HashMap::from([( - sector_no_b, - vec![test_activated_deal(100, NO_ALLOCATION_ID)], - )]), - ..Default::default() - }; - h.confirm_sector_proofs_valid(&rt, conf, vec![pre_commit_a, pre_commit_b]).unwrap(); - let st = h.get_state(&rt); - assert!(st.get_sector(&rt.store, sector_no_a).unwrap().is_none()); - assert!(st.get_sector(&rt.store, sector_no_b).unwrap().is_some()); - h.check_state(&rt); -} - #[test] fn prove_commit_just_after_period_start_permits_post() { - let h = ActorHarness::new(PERIOD_OFFSET); + let mut h = ActorHarness::new(PERIOD_OFFSET); let rt = h.new_runtime(); rt.balance.replace(BIG_BALANCE.clone()); @@ -536,51 +92,14 @@ fn prove_commit_just_after_period_start_permits_post() { // Commit a sector the very next epoch rt.set_epoch(PERIOD_OFFSET + 2); - let sector = - h.commit_and_prove_sector(&rt, MAX_SECTOR_NUMBER, DEFAULT_SECTOR_EXPIRATION, vec![]); + let sectors = + h.commit_and_prove_sectors(&rt, 1, DEFAULT_SECTOR_EXPIRATION as u64, vec![], true); // advance cron to activate power. - h.advance_and_submit_posts(&rt, &[sector]); + h.advance_and_submit_posts(&rt, &[sectors.first().unwrap().clone()]); h.check_state(&rt); } -#[test] -fn sector_with_non_positive_lifetime_fails_in_confirmation() { - let h = ActorHarness::new(PERIOD_OFFSET); - let rt = h.new_runtime(); - rt.balance.replace(BIG_BALANCE.clone()); - - let precommit_epoch = PERIOD_OFFSET + 1; - rt.set_epoch(precommit_epoch); - - h.construct_and_verify(&rt); - let deadline = h.deadline(&rt); - - let sector_no = 100; - let params = h.make_pre_commit_params( - sector_no, - precommit_epoch - 1, - deadline.period_end() + DEFAULT_SECTOR_EXPIRATION * rt.policy.wpost_proving_period, - vec![], - ); - let precommit = h.pre_commit_sector_and_get(&rt, params, PreCommitConfig::default(), true); - - // precommit at correct epoch - let epoch = *rt.epoch.borrow(); - rt.set_epoch(epoch + rt.policy.pre_commit_challenge_delay + 1); - h.prove_commit_sector(&rt, &precommit, h.make_prove_commit_params(sector_no)).unwrap(); - - // confirm at sector expiration (this probably can't happen) - rt.set_epoch(precommit.info.expiration); - // failure occurs - expect_abort( - ExitCode::USR_ILLEGAL_ARGUMENT, - h.confirm_sector_proofs_valid(&rt, ProveCommitConfig::empty(), vec![precommit]), - ); - h.check_state(&rt); - rt.reset(); -} - #[test] fn verify_proof_does_not_vest_funds() { let h = ActorHarness::new(PERIOD_OFFSET); @@ -599,9 +118,9 @@ fn verify_proof_does_not_vest_funds() { sector_no, precommit_epoch - 1, deadline.period_end() + DEFAULT_SECTOR_EXPIRATION * rt.policy.wpost_proving_period, - vec![1], + vec![], ); - let precommit = h.pre_commit_sector_and_get(&rt, params, PreCommitConfig::default(), true); + h.pre_commit_sector_and_get(&rt, params, PreCommitConfig::default(), true); // add 1000 tokens that vest immediately let mut st = h.get_state(&rt); @@ -620,6 +139,5 @@ fn verify_proof_does_not_vest_funds() { let prove_commit = h.make_prove_commit_params(sector_no); // The below call expects exactly the pledge delta for the proven sector, zero for any other vesting. - h.prove_commit_sector_and_confirm(&rt, &precommit, prove_commit, ProveCommitConfig::empty()) - .unwrap(); + h.deprecated_sector_commit(&rt, &vec![], prove_commit, ProveCommitConfig::empty()).unwrap(); } diff --git a/actors/miner/tests/prove_commit2_failures_test.rs b/actors/miner/tests/prove_commit2_failures_test.rs index 8efabb3c7..028ccb383 100644 --- a/actors/miner/tests/prove_commit2_failures_test.rs +++ b/actors/miner/tests/prove_commit2_failures_test.rs @@ -25,14 +25,14 @@ const FIRST_SECTOR_NUMBER: SectorNumber = 100; #[test] fn reject_unauthorized_caller() { let (h, rt, activations) = setup_precommits(&[(0, 0, 0)]); - let cfg = ProveCommitSectors2Config { + let cfg = ProveCommitSectors3Config { caller: Some(Address::new_id(CLIENT_ID)), ..Default::default() }; expect_abort_contains_message( ExitCode::USR_FORBIDDEN, "caller", - h.prove_commit_sectors2(&rt, &activations, false, false, false, cfg), + h.prove_commit_sectors3(&rt, &activations, false, false, false, cfg), ); h.check_state(&rt); } @@ -40,7 +40,7 @@ fn reject_unauthorized_caller() { #[test] fn reject_no_proof_types() { let (h, rt, activations) = setup_precommits(&[(0, 0, 0)]); - let cfg = ProveCommitSectors2Config { + let cfg = ProveCommitSectors3Config { param_twiddle: Some(Box::new(|p: &mut ProveCommitSectors3Params| { p.sector_proofs = vec![]; p.aggregate_proof = RawBytes::default(); @@ -50,7 +50,7 @@ fn reject_no_proof_types() { expect_abort_contains_message( ExitCode::USR_ILLEGAL_ARGUMENT, "exactly one of sector proofs or aggregate proof must be non-empty", - h.prove_commit_sectors2(&rt, &activations, false, false, false, cfg), + h.prove_commit_sectors3(&rt, &activations, false, false, false, cfg), ); h.check_state(&rt); } @@ -58,7 +58,7 @@ fn reject_no_proof_types() { #[test] fn reject_both_proof_types() { let (h, rt, activations) = setup_precommits(&[(0, 0, 0)]); - let cfg = ProveCommitSectors2Config { + let cfg = ProveCommitSectors3Config { param_twiddle: Some(Box::new(|p: &mut ProveCommitSectors3Params| { p.sector_proofs = vec![RawBytes::new(vec![1, 2, 3, 4])]; p.aggregate_proof = RawBytes::new(vec![1, 2, 3, 4]) @@ -68,7 +68,7 @@ fn reject_both_proof_types() { expect_abort_contains_message( ExitCode::USR_ILLEGAL_ARGUMENT, "exactly one of sector proofs or aggregate proof must be non-empty", - h.prove_commit_sectors2(&rt, &activations, false, false, false, cfg), + h.prove_commit_sectors3(&rt, &activations, false, false, false, cfg), ); h.check_state(&rt); } @@ -76,7 +76,7 @@ fn reject_both_proof_types() { #[test] fn reject_mismatched_proof_len() { let (h, rt, activations) = setup_precommits(&[(0, 0, 0)]); - let cfg = ProveCommitSectors2Config { + let cfg = ProveCommitSectors3Config { param_twiddle: Some(Box::new(|p: &mut ProveCommitSectors3Params| { p.sector_proofs.push(RawBytes::new(vec![1, 2, 3, 4])); })), @@ -85,7 +85,21 @@ fn reject_mismatched_proof_len() { expect_abort_contains_message( ExitCode::USR_ILLEGAL_ARGUMENT, "mismatched lengths", - h.prove_commit_sectors2(&rt, &activations, false, false, false, cfg), + h.prove_commit_sectors3(&rt, &activations, false, false, false, cfg), + ); + h.check_state(&rt); +} + +#[test] +fn reject_too_soon() { + let (h, rt, activations) = setup_precommits(&[(0, 0, 0)]); + let epoch = *rt.epoch.borrow(); + rt.set_epoch(epoch - 2); + let cfg = ProveCommitSectors3Config::default(); + expect_abort_contains_message( + ExitCode::USR_FORBIDDEN, + "too early to prove sector", + h.prove_commit_sectors3(&rt, &activations, false, false, false, cfg), ); h.check_state(&rt); } @@ -95,11 +109,11 @@ fn reject_expired_precommit() { let (h, rt, activations) = setup_precommits(&[(0, 0, 0)]); let epoch = *rt.epoch.borrow(); rt.set_epoch(epoch + 31 * EPOCHS_IN_DAY); // Expired. - let cfg = ProveCommitSectors2Config::default(); + let cfg = ProveCommitSectors3Config::default(); expect_abort_contains_message( ExitCode::USR_ILLEGAL_ARGUMENT, "no valid precommits", - h.prove_commit_sectors2(&rt, &activations, false, false, false, cfg), + h.prove_commit_sectors3(&rt, &activations, false, false, false, cfg), ); h.check_state(&rt); } @@ -128,12 +142,12 @@ fn reject_precommit_deals() { .map(|s| make_activation_manifest(s.sector_number, &[(piece_size, 0, 0, 0)])) .collect(); - let cfg = ProveCommitSectors2Config { validation_failure: vec![0], ..Default::default() }; + let cfg = ProveCommitSectors3Config { validation_failure: vec![0], ..Default::default() }; // Single bad precommit aborts with require_activation_success=true. expect_abort_contains_message( ExitCode::USR_ILLEGAL_ARGUMENT, "invalid pre-commit 0 while requiring activation success", - h.prove_commit_sectors2(&rt, &manifests, true, false, false, cfg), + h.prove_commit_sectors3(&rt, &manifests, true, false, false, cfg), ); h.check_state(&rt); } @@ -141,12 +155,12 @@ fn reject_precommit_deals() { #[test] fn reject_all_proofs_fail() { let (h, rt, activations) = setup_precommits(&[(0, 0, 0), (0, 0, 0)]); - let cfg = ProveCommitSectors2Config { proof_failure: vec![0, 1], ..Default::default() }; + let cfg = ProveCommitSectors3Config { proof_failure: vec![0, 1], ..Default::default() }; // If all proofs fail, no need for require_activation_success=true. expect_abort_contains_message( ExitCode::USR_ILLEGAL_ARGUMENT, "no valid proofs", - h.prove_commit_sectors2(&rt, &activations, false, false, false, cfg), + h.prove_commit_sectors3(&rt, &activations, false, false, false, cfg), ); h.check_state(&rt); } @@ -154,12 +168,12 @@ fn reject_all_proofs_fail() { #[test] fn reject_aggregate_proof_fails() { let (h, rt, activations) = setup_precommits(&[(0, 0, 0); 4]); - let cfg = ProveCommitSectors2Config { proof_failure: vec![0], ..Default::default() }; + let cfg = ProveCommitSectors3Config { proof_failure: vec![0], ..Default::default() }; // If aggregate proof fails, no need for require_activation_success=true. expect_abort_contains_message( ExitCode::USR_ILLEGAL_ARGUMENT, "invalid aggregate proof", - h.prove_commit_sectors2(&rt, &activations, false, false, true, cfg), + h.prove_commit_sectors3(&rt, &activations, false, false, true, cfg), ); h.check_state(&rt); } @@ -167,12 +181,12 @@ fn reject_aggregate_proof_fails() { #[test] fn reject_required_proof_failure() { let (h, rt, activations) = setup_precommits(&[(0, 0, 0); 4]); - let cfg = ProveCommitSectors2Config { proof_failure: vec![0], ..Default::default() }; + let cfg = ProveCommitSectors3Config { proof_failure: vec![0], ..Default::default() }; // Single proof failure aborts with require_activation_success=true. expect_abort_contains_message( ExitCode::USR_ILLEGAL_ARGUMENT, "invalid proof for sector 100 while requiring activation success", - h.prove_commit_sectors2(&rt, &activations, true, false, false, cfg), + h.prove_commit_sectors3(&rt, &activations, true, false, false, cfg), ); h.check_state(&rt); } @@ -183,23 +197,23 @@ fn reject_mismatched_commd() { // Set wrong CID for first sector. activations[0].pieces[0].cid = activations[1].pieces[0].cid; - let cfg = ProveCommitSectors2Config::default(); + let cfg = ProveCommitSectors3Config::default(); expect_abort_contains_message( ExitCode::USR_ILLEGAL_ARGUMENT, "unsealed CID does not match pieces", - h.prove_commit_sectors2(&rt, &activations, false, false, false, cfg), + h.prove_commit_sectors3(&rt, &activations, false, false, false, cfg), ); } #[test] fn reject_required_claim_failure() { let (h, rt, activations) = setup_precommits(&[(0, 0, 0), (CLIENT_ID, 1, 0)]); - let cfg = ProveCommitSectors2Config { claim_failure: vec![0], ..Default::default() }; + let cfg = ProveCommitSectors3Config { claim_failure: vec![0], ..Default::default() }; // Single claim failure aborts with require_activation_success=true. expect_abort_contains_message( ExitCode::USR_ILLEGAL_ARGUMENT, "error claiming allocations", - h.prove_commit_sectors2(&rt, &activations, true, false, false, cfg), + h.prove_commit_sectors3(&rt, &activations, true, false, false, cfg), ); h.check_state(&rt); } @@ -208,14 +222,14 @@ fn reject_required_claim_failure() { fn required_notification_abort() { let deal_id = 2000; let (h, rt, activations) = setup_precommits(&[(0, 0, deal_id)]); - let cfg = ProveCommitSectors2Config { + let cfg = ProveCommitSectors3Config { notification_result: Some(ExitCode::USR_ILLEGAL_ARGUMENT), ..Default::default() }; expect_abort_contains_message( ERR_NOTIFICATION_RECEIVER_ABORTED, "receiver aborted", - h.prove_commit_sectors2(&rt, &activations, true, true, false, cfg), + h.prove_commit_sectors3(&rt, &activations, true, true, false, cfg), ); h.check_state(&rt); } @@ -224,12 +238,12 @@ fn required_notification_abort() { fn require_notification_rejected() { let deal_id = 2000; let (h, rt, activations) = setup_precommits(&[(0, 0, deal_id)]); - let cfg = ProveCommitSectors2Config { notification_rejected: true, ..Default::default() }; + let cfg = ProveCommitSectors3Config { notification_rejected: true, ..Default::default() }; // Require notification success. expect_abort_contains_message( ERR_NOTIFICATION_REJECTED, "sector change rejected", - h.prove_commit_sectors2(&rt, &activations, true, true, false, cfg), + h.prove_commit_sectors3(&rt, &activations, true, true, false, cfg), ); h.check_state(&rt); } diff --git a/actors/miner/tests/prove_commit2_test.rs b/actors/miner/tests/prove_commit2_test.rs index 63fa314b5..a2aaea21c 100644 --- a/actors/miner/tests/prove_commit2_test.rs +++ b/actors/miner/tests/prove_commit2_test.rs @@ -40,9 +40,9 @@ fn commit_batch() { make_activation_manifest(snos[3], &[(piece_size, CLIENT_ID, 1001, 2001)]), // Alloc and deal ]; - let cfg = ProveCommitSectors2Config::default(); + let cfg = ProveCommitSectors3Config::default(); let (result, claims, notifications) = - h.prove_commit_sectors2(&rt, &manifests, true, true, false, cfg).unwrap(); + h.prove_commit_sectors3(&rt, &manifests, true, true, false, cfg).unwrap(); assert_commit_result(&[ExitCode::OK; 4], &result); let sectors: Vec = snos.iter().map(|sno| h.get_sector(&rt, *sno)).collect(); @@ -140,9 +140,9 @@ fn multiple_pieces_in_sector() { ), ]; - let cfg = ProveCommitSectors2Config::default(); + let cfg = ProveCommitSectors3Config::default(); let (result, claims, notifications) = - h.prove_commit_sectors2(&rt, &manifests, true, true, false, cfg).unwrap(); + h.prove_commit_sectors3(&rt, &manifests, true, true, false, cfg).unwrap(); assert_commit_result(&[ExitCode::OK, ExitCode::OK], &result); let sectors: Vec = snos.iter().map(|sno| h.get_sector(&rt, *sno)).collect(); @@ -253,9 +253,9 @@ fn multiple_notifs_for_piece() { payload: RawBytes::from(vec![9, 9, 9, 9]), }); - let cfg = ProveCommitSectors2Config::default(); + let cfg = ProveCommitSectors3Config::default(); let (result, _, notifications) = - h.prove_commit_sectors2(&rt, &manifests, true, true, false, cfg).unwrap(); + h.prove_commit_sectors3(&rt, &manifests, true, true, false, cfg).unwrap(); assert_commit_result(&[ExitCode::OK, ExitCode::OK], &result); let sectors: Vec = snos.iter().map(|sno| h.get_sector(&rt, *sno)).collect(); @@ -325,9 +325,9 @@ fn expired_precommit_dropped_batch() { make_activation_manifest(snos[1], &[(piece_size, CLIENT_ID, 1001, 2001)]), ]; - let cfg = ProveCommitSectors2Config { validation_failure: vec![0], ..Default::default() }; + let cfg = ProveCommitSectors3Config { validation_failure: vec![0], ..Default::default() }; let (result, claims, notifications) = - h.prove_commit_sectors2(&rt, &manifests, false, false, false, cfg).unwrap(); + h.prove_commit_sectors3(&rt, &manifests, false, false, false, cfg).unwrap(); assert_commit_result(&[ExitCode::USR_ILLEGAL_ARGUMENT, ExitCode::OK], &result); // Sector 0: not committed @@ -369,8 +369,8 @@ fn expired_precommit_dropped_aggregate() { make_activation_manifest(snos[3], &[(piece_size, CLIENT_ID, 1003, 2003)]), ]; - let cfg = ProveCommitSectors2Config { validation_failure: vec![0], ..Default::default() }; - let (result, _, _) = h.prove_commit_sectors2(&rt, &manifests, false, false, true, cfg).unwrap(); + let cfg = ProveCommitSectors3Config { validation_failure: vec![0], ..Default::default() }; + let (result, _, _) = h.prove_commit_sectors3(&rt, &manifests, false, false, true, cfg).unwrap(); assert_commit_result( &[ExitCode::USR_ILLEGAL_ARGUMENT, ExitCode::OK, ExitCode::OK, ExitCode::OK], &result, @@ -400,9 +400,9 @@ fn invalid_proof_dropped() { make_activation_manifest(snos[1], &[(piece_size, CLIENT_ID, 1001, 2001)]), ]; - let cfg = ProveCommitSectors2Config { proof_failure: vec![0], ..Default::default() }; + let cfg = ProveCommitSectors3Config { proof_failure: vec![0], ..Default::default() }; let (result, _, _) = - h.prove_commit_sectors2(&rt, &manifests, false, false, false, cfg).unwrap(); + h.prove_commit_sectors3(&rt, &manifests, false, false, false, cfg).unwrap(); assert_commit_result(&[ExitCode::USR_ILLEGAL_ARGUMENT, ExitCode::OK], &result); // Sector 0: not committed @@ -426,9 +426,9 @@ fn invalid_claim_dropped() { make_activation_manifest(snos[1], &[(piece_size, CLIENT_ID, 1001, 2001)]), ]; - let cfg = ProveCommitSectors2Config { claim_failure: vec![0], ..Default::default() }; + let cfg = ProveCommitSectors3Config { claim_failure: vec![0], ..Default::default() }; let (result, _, _) = - h.prove_commit_sectors2(&rt, &manifests, false, false, false, cfg).unwrap(); + h.prove_commit_sectors3(&rt, &manifests, false, false, false, cfg).unwrap(); assert_commit_result(&[ExitCode::USR_ILLEGAL_ARGUMENT, ExitCode::OK], &result); // Sector 0: not committed @@ -451,12 +451,12 @@ fn aborted_notification_dropped() { make_activation_manifest(snos[1], &[(piece_size, CLIENT_ID, 1001, 2001)]), ]; - let cfg = ProveCommitSectors2Config { + let cfg = ProveCommitSectors3Config { notification_result: Some(ExitCode::USR_UNSPECIFIED), ..Default::default() }; let (result, _, _) = - h.prove_commit_sectors2(&rt, &manifests, false, false, false, cfg).unwrap(); + h.prove_commit_sectors3(&rt, &manifests, false, false, false, cfg).unwrap(); // All sectors succeed anyway. assert_commit_result(&[ExitCode::OK; 2], &result); @@ -478,9 +478,9 @@ fn rejected_notification_dropped() { make_activation_manifest(snos[1], &[(piece_size, CLIENT_ID, 1001, 2001)]), ]; - let cfg = ProveCommitSectors2Config { notification_rejected: true, ..Default::default() }; + let cfg = ProveCommitSectors3Config { notification_rejected: true, ..Default::default() }; let (result, _, _) = - h.prove_commit_sectors2(&rt, &manifests, false, false, false, cfg).unwrap(); + h.prove_commit_sectors3(&rt, &manifests, false, false, false, cfg).unwrap(); // All sectors succeed anyway. assert_commit_result(&[ExitCode::OK; 2], &result); diff --git a/actors/miner/tests/util.rs b/actors/miner/tests/util.rs index 28fc9e14b..7de6fe29c 100644 --- a/actors/miner/tests/util.rs +++ b/actors/miner/tests/util.rs @@ -64,15 +64,14 @@ use fil_actor_miner::{ ActiveBeneficiary, Actor, ApplyRewardParams, BeneficiaryTerm, BitFieldQueue, ChangeBeneficiaryParams, ChangeMultiaddrsParams, ChangePeerIDParams, ChangeWorkerAddressParams, CheckSectorProvenParams, CompactCommD, CompactPartitionsParams, CompactSectorNumbersParams, - ConfirmSectorProofsParams, CronEventPayload, DataActivationNotification, Deadline, - DeadlineInfo, Deadlines, DeclareFaultsParams, DeclareFaultsRecoveredParams, - DeferredCronEventParams, DisputeWindowedPoStParams, ExpirationQueue, ExpirationSet, - ExtendSectorExpiration2Params, ExtendSectorExpirationParams, FaultDeclaration, - GetAvailableBalanceReturn, GetBeneficiaryReturn, GetControlAddressesReturn, - GetMultiaddrsReturn, GetPeerIDReturn, Method, Method as MinerMethod, - MinerConstructorParams as ConstructorParams, MinerInfo, Partition, PendingBeneficiaryChange, - PieceActivationManifest, PieceChange, PieceReturn, PoStPartition, PowerPair, - PreCommitSectorBatchParams, PreCommitSectorBatchParams2, PreCommitSectorParams, + CronEventPayload, DataActivationNotification, Deadline, DeadlineInfo, Deadlines, + DeclareFaultsParams, DeclareFaultsRecoveredParams, DeferredCronEventParams, + DisputeWindowedPoStParams, ExpirationQueue, ExpirationSet, ExtendSectorExpiration2Params, + ExtendSectorExpirationParams, FaultDeclaration, GetAvailableBalanceReturn, + GetBeneficiaryReturn, GetControlAddressesReturn, GetMultiaddrsReturn, GetPeerIDReturn, Method, + Method as MinerMethod, MinerConstructorParams as ConstructorParams, MinerInfo, Partition, + PendingBeneficiaryChange, PieceActivationManifest, PieceChange, PieceReturn, PoStPartition, + PowerPair, PreCommitSectorBatchParams, PreCommitSectorBatchParams2, PreCommitSectorParams, ProveCommitAggregateParams, ProveCommitSectorParams, ProveCommitSectors3Params, ProveCommitSectors3Return, QuantSpec, RecoveryDeclaration, ReportConsensusFaultParams, SectorActivationManifest, SectorChanges, SectorContentChangedParams, @@ -97,6 +96,8 @@ use fil_actors_runtime::{ VERIFIED_REGISTRY_ACTOR_ADDR, }; +const DEFAULT_PIECE_SIZE: u64 = 128; + const RECEIVER_ID: u64 = 1000; pub const TEST_RANDOMNESS_ARRAY_FROM_ONE: [u8; 32] = [ @@ -412,19 +413,31 @@ impl ActorHarness { let sector_deal_ids = deal_ids.get(i).and_then(|ids| Some(ids.clone())).unwrap_or_default(); let has_deals = !sector_deal_ids.is_empty(); - let params = self.make_pre_commit_params( + + let compact_commd = if !has_deals { + CompactCommD::empty() + } else { + // Determine CommD from configuration in the same way as prove_commit_and_confirm + let piece_specs = + make_piece_specs_from_configs(sector_no, §or_deal_ids, &prove_cfg); + let manifest = make_activation_manifest(sector_no, &piece_specs); + let piece_cids: Vec = manifest.pieces.iter().map(|p| p.cid).collect(); + sector_commd_from_pieces(&piece_cids) + }; + + let info = self.make_pre_commit_params_v2( sector_no, precommit_epoch - 1, expiration, - sector_deal_ids, + // We may be committing with deals but if so pass their info in CommD as + // PreCommitSector with deal_ids will fail after nv21 + vec![], + compact_commd, ); - let pcc = if !has_deals { - PreCommitConfig::new(None) - } else { - PreCommitConfig::new(Some(make_unsealed_cid("1".as_bytes()))) - }; - let precommit = self.pre_commit_sector_and_get(rt, params, pcc, first && i == 0); - precommits.push(precommit); + + let precommit = + self.pre_commit_sector_batch_v2_and_get(rt, vec![info], first && i == 0); + precommits.extend(precommit); self.next_sector_no += 1; } @@ -434,11 +447,13 @@ impl ActorHarness { ); let mut info = Vec::with_capacity(num_sectors); - for pc in precommits { + for (i, pc) in precommits.iter().enumerate() { + let sector_deal_ids = + deal_ids.get(i).and_then(|ids| Some(ids.clone())).unwrap_or_default(); let sector = self - .prove_commit_sector_and_confirm( + .deprecated_sector_commit( rt, - &pc, + §or_deal_ids, self.make_prove_commit_params(pc.info.sector_number), prove_cfg.clone(), ) @@ -449,44 +464,6 @@ impl ActorHarness { info } - pub fn commit_and_prove_sector( - &self, - rt: &MockRuntime, - sector_no: SectorNumber, - lifetime_periods: i64, - deal_ids: Vec, - ) -> SectorOnChainInfo { - let precommit_epoch = *rt.epoch.borrow(); - let deadline = self.deadline(rt); - let expiration = deadline.period_end() + lifetime_periods * rt.policy.wpost_proving_period; - - // Precommit - let pre_commit_params = - self.make_pre_commit_params(sector_no, precommit_epoch - 1, expiration, deal_ids); - let precommit = self.pre_commit_sector_and_get( - rt, - pre_commit_params.clone(), - PreCommitConfig::default(), - true, - ); - - self.advance_to_epoch_with_cron( - rt, - precommit_epoch + rt.policy.pre_commit_challenge_delay + 1, - ); - - let sector_info = self - .prove_commit_sector_and_confirm( - rt, - &precommit, - self.make_prove_commit_params(pre_commit_params.sector_number), - ProveCommitConfig::empty(), - ) - .unwrap(); - rt.reset(); - sector_info - } - pub fn compact_sector_numbers_raw( &self, rt: &MockRuntime, @@ -703,6 +680,20 @@ impl ActorHarness { result } + pub fn pre_commit_sector_batch_v2_and_get( + &self, + rt: &MockRuntime, + sectors: Vec, + first: bool, + ) -> Vec { + let result = self.pre_commit_sector_batch_v2(rt, §ors, first, &self.base_fee).unwrap(); + + expect_empty(result); + rt.verify(); + + sectors.iter().map(|sector| self.get_precommit(rt, sector.sector_number)).collect() + } + pub fn pre_commit_sector_and_get( &self, rt: &MockRuntime, @@ -763,73 +754,56 @@ impl ActorHarness { ); } - pub fn prove_commit_sector_and_confirm( + // deprecated flow calling prove commit sector and then confirm sector proofs valid + // With FIP 0084 this is no longer realizable. Internally it now calls ProveCommitSectors3 + // The entrypoint is kept in tests + // 1) to ensure backwards compatibility between prove_commit_sector and prove_commit_sectors3 + // 2) to make use of existing test coverage without significant change + // + // This should be removed in favor of something else. Discussion: https://github.com/filecoin-project/builtin-actors/issues/1545 + pub fn deprecated_sector_commit( &self, rt: &MockRuntime, - pc: &SectorPreCommitOnChainInfo, + deal_ids: &Vec, params: ProveCommitSectorParams, cfg: ProveCommitConfig, ) -> Result { let sector_number = params.sector_number; - self.prove_commit_sector(rt, pc, params)?; - self.confirm_sector_proofs_valid(rt, cfg, vec![pc.clone()])?; - - Ok(self.get_sector(rt, sector_number)) - } + let piece_specs = make_piece_specs_from_configs(sector_number, deal_ids, &cfg); - pub fn prove_commit_sector( - &self, - rt: &MockRuntime, - pc: &SectorPreCommitOnChainInfo, - params: ProveCommitSectorParams, - ) -> Result<(), ActorError> { - rt.set_caller(*ACCOUNT_ACTOR_CODE_ID, self.worker); - let seal_rand = TEST_RANDOMNESS_ARRAY_FROM_ONE; - let seal_int_rand = TEST_RANDOMNESS_ARRAY_FROM_TWO; - let interactive_epoch = pc.pre_commit_epoch + rt.policy.pre_commit_challenge_delay; - - // Prepare for and receive call to ProveCommitSector - let entropy = RawBytes::serialize(self.receiver).unwrap(); - rt.expect_get_randomness_from_tickets( - DomainSeparationTag::SealRandomness, - pc.info.seal_rand_epoch, - entropy.to_vec(), - seal_rand.clone(), - ); - rt.expect_get_randomness_from_beacon( - DomainSeparationTag::InteractiveSealChallengeSeed, - interactive_epoch, - entropy.to_vec(), - seal_int_rand.clone(), - ); + let manifest = make_activation_manifest(sector_number, &piece_specs); + let req_activation_succ = true; // Doesn't really matter since there's only 1 + let req_notif_succ = false; // CPSV could not require this as it happened in cron - let actor_id = RECEIVER_ID; - let seal = SealVerifyInfo { - sector_id: SectorID { miner: actor_id, number: pc.info.sector_number }, - sealed_cid: pc.info.sealed_cid, - registered_proof: pc.info.seal_proof, - proof: params.proof.clone().into(), - deal_ids: vec![], - randomness: Randomness(seal_rand.into()), - interactive_randomness: Randomness(seal_int_rand.into()), - unsealed_cid: pc.info.unsealed_cid.get_cid(pc.info.seal_proof).unwrap(), + let claim_failure = if cfg.claim_allocs_exit.contains_key(§or_number) { + vec![0] // only sector activating has claim failure + } else { + vec![] }; - rt.expect_send_simple( - STORAGE_POWER_ACTOR_ADDR, - PowerMethod::SubmitPoRepForBulkVerify as u64, - IpldBlock::serialize_cbor(&seal).unwrap(), - TokenAmount::zero(), - None, - ExitCode::OK, - ); - rt.expect_validate_caller_any(); - let result = rt.call::( - Method::ProveCommitSector as u64, - IpldBlock::serialize_cbor(¶ms).unwrap(), + let notification_result = if cfg.verify_deals_exit.get(§or_number).is_some() { + cfg.verify_deals_exit.get(§or_number).cloned() + } else { + None + }; + let cfg3 = ProveCommitSectors3Config { + proof_failure: vec![], // ProveCommitConfig doesn't support this + param_twiddle: None, + caller: None, + validation_failure: vec![], + claim_failure, + notification_result, + notification_rejected: notification_result.is_some(), + }; + let _ = self.prove_commit_sectors3( + rt, + &[manifest], + req_activation_succ, + req_notif_succ, + false, + cfg3, )?; - expect_empty(result); - rt.verify(); - Ok(()) + + Ok(self.get_sector(rt, sector_number)) } pub fn prove_commit_aggregate_sector( @@ -867,7 +841,7 @@ impl ActorHarness { rt.expect_aggregate_verify_seals(svis, params.aggregate_proof.clone().into(), Ok(())); // confirm sector proofs valid - let pieces = self.confirm_sector_proofs_valid_internal(rt, config, &precommits); + let pieces = self.expect_sectors_activated(rt, config, &precommits); // sector activated event for (i, sc) in precommits.iter().enumerate() { @@ -900,55 +874,9 @@ impl ActorHarness { Ok(()) } - pub fn confirm_sector_proofs_valid( - &self, - rt: &MockRuntime, - cfg: ProveCommitConfig, - pcs: Vec, - ) -> Result<(), ActorError> { - let pieces = self.confirm_sector_proofs_valid_internal(rt, cfg.clone(), &pcs); - - let mut all_sector_numbers = Vec::new(); - for pc in pcs.clone() { - all_sector_numbers.push(pc.info.sector_number); - } - - rt.set_caller(*POWER_ACTOR_CODE_ID, STORAGE_POWER_ACTOR_ADDR); - rt.expect_validate_caller_addr(vec![STORAGE_POWER_ACTOR_ADDR]); - - let params = ConfirmSectorProofsParams { - sectors: all_sector_numbers, - reward_smoothed: self.epoch_reward_smooth.clone(), - reward_baseline_power: self.baseline_power.clone(), - quality_adj_power_smoothed: self.epoch_qa_power_smooth.clone(), - }; - - for sc in pcs.iter() { - if cfg.verify_deals_exit.contains_key(&sc.info.sector_number) - || cfg.claim_allocs_exit.contains_key(&sc.info.sector_number) - { - continue; - } - let unsealed_cid = sc.info.unsealed_cid.0; - let num = &sc.info.sector_number; - expect_sector_event( - rt, - "sector-activated", - &num, - unsealed_cid, - pieces.get(&num).unwrap(), - ); - } - - rt.call::( - Method::ConfirmSectorProofsValid as u64, - IpldBlock::serialize_cbor(¶ms).unwrap(), - )?; - rt.verify(); - Ok(()) - } - - fn confirm_sector_proofs_valid_internal( + // Check that sectors are activating + // This is a separate method because historically this functionality was shared between various commitment entrypoints + fn expect_sectors_activated( &self, rt: &MockRuntime, cfg: ProveCommitConfig, @@ -1120,14 +1048,14 @@ impl ActorHarness { pieces } - pub fn prove_commit_sectors2( + pub fn prove_commit_sectors3( &self, rt: &MockRuntime, sector_activations: &[SectorActivationManifest], require_activation_success: bool, require_notification_success: bool, aggregate: bool, - cfg: ProveCommitSectors2Config, + cfg: ProveCommitSectors3Config, ) -> Result< (ProveCommitSectors3Return, Vec, Vec), ActorError, @@ -3057,7 +2985,7 @@ pub struct ProveReplicaUpdatesConfig { } #[derive(Default)] -pub struct ProveCommitSectors2Config { +pub struct ProveCommitSectors3Config { pub caller: Option
, pub param_twiddle: Option>, pub validation_failure: Vec, // Expect validation failure for these sector indices. @@ -3275,7 +3203,7 @@ pub fn onboard_sectors( // Prove the sectors in batch with ProveCommitSectors2. let prove_epoch = *rt.epoch.borrow() + rt.policy.pre_commit_challenge_delay + 1; rt.set_epoch(prove_epoch); - let cfg = ProveCommitSectors2Config::default(); + let cfg = ProveCommitSectors3Config::default(); let sector_activations: Vec = precommits .iter() .map(|pc| { @@ -3286,7 +3214,7 @@ pub fn onboard_sectors( make_activation_manifest(pc.info.sector_number, &piece_specs) }) .collect(); - h.prove_commit_sectors2(rt, §or_activations, true, false, false, cfg).unwrap(); + h.prove_commit_sectors3(rt, §or_activations, true, false, false, cfg).unwrap(); let sectors: Vec = precommits.iter().map(|pc| h.get_sector(rt, pc.info.sector_number)).collect(); @@ -3417,6 +3345,39 @@ pub fn make_piece_manifest( } } +pub fn make_piece_specs_from_configs( + sector_number: u64, + deal_ids: &Vec, + prove_cfg: &ProveCommitConfig, +) -> Vec<(u64, ActorID, AllocationID, DealID)> { + static EMPTY_VEC: Vec = Vec::new(); + let configured_deals = prove_cfg.activated_deals.get(§or_number).unwrap_or(&EMPTY_VEC); + // The old configuration system had duplicated information between cfg and precommit inputs + // To ensure passed in configuration is internally consistent check that cfg deals are a subset + // of precommitted deal ids + assert!(deal_ids.len() >= configured_deals.len()); + let mut piece_specs = vec![]; + const DEFAULT_CLIENT_ID: ActorID = 1000; + + for (i, deal_id) in deal_ids.iter().enumerate() { + if i < configured_deals.len() { + let deal = configured_deals.get(i).unwrap(); + // Configured deals don't specify deal_id use deal_ids configuration info + // Piece specs don't specify piece cid but deterministically derive it so ignore deal.Cid + piece_specs.push((deal.size.0, deal.client, deal.allocation_id, deal_id.clone())); + } else { + piece_specs.push(( + DEFAULT_PIECE_SIZE, + DEFAULT_CLIENT_ID, + NO_ALLOCATION_ID, + deal_id.clone(), + )); + } + } + + piece_specs +} + pub fn claims_from_pieces(pieces: &[PieceActivationManifest]) -> Vec { pieces .iter() diff --git a/actors/power/src/ext.rs b/actors/power/src/ext.rs index 270ca5591..9c821c1d0 100644 --- a/actors/power/src/ext.rs +++ b/actors/power/src/ext.rs @@ -3,8 +3,7 @@ use fvm_ipld_encoding::tuple::*; use fvm_ipld_encoding::{strict_bytes, BytesDe}; use fvm_shared::address::Address; -use fvm_shared::bigint::bigint_ser; -use fvm_shared::sector::{RegisteredPoStProof, SectorNumber, StoragePower}; +use fvm_shared::sector::RegisteredPoStProof; use fvm_shared::METHOD_CONSTRUCTOR; use num_derive::FromPrimitive; @@ -36,18 +35,8 @@ pub mod init { pub mod miner { use super::*; - pub const CONFIRM_SECTOR_PROOFS_VALID_METHOD: u64 = 17; pub const ON_DEFERRED_CRON_EVENT_METHOD: u64 = 12; - #[derive(Serialize_tuple, Deserialize_tuple)] - pub struct ConfirmSectorProofsParams { - pub sectors: Vec, - pub reward_smoothed: FilterEstimate, - #[serde(with = "bigint_ser")] - pub reward_baseline_power: StoragePower, - pub quality_adj_power_smoothed: FilterEstimate, - } - #[derive(Serialize_tuple, Deserialize_tuple)] pub struct MinerConstructorParams { pub owner: Address, diff --git a/actors/power/src/lib.rs b/actors/power/src/lib.rs index 7937fb4c2..45bc352e2 100644 --- a/actors/power/src/lib.rs +++ b/actors/power/src/lib.rs @@ -1,19 +1,13 @@ // Copyright 2019-2022 ChainSafe Systems // SPDX-License-Identifier: Apache-2.0, MIT -use std::collections::BTreeSet; -use std::convert::TryInto; - -use anyhow::anyhow; use fil_actors_runtime::reward::ThisEpochRewardReturn; use fvm_ipld_encoding::ipld_block::IpldBlock; use fvm_ipld_encoding::RawBytes; -use fvm_shared::address::Address; use fvm_shared::bigint::bigint_ser::BigIntSer; use fvm_shared::econ::TokenAmount; use fvm_shared::error::ExitCode; -use fvm_shared::sector::SealVerifyInfo; -use fvm_shared::{MethodNum, HAMT_BIT_WIDTH, METHOD_CONSTRUCTOR}; +use fvm_shared::{MethodNum, METHOD_CONSTRUCTOR}; use log::{debug, error}; use num_derive::FromPrimitive; use num_traits::Zero; @@ -42,12 +36,6 @@ mod types; // * Updated to specs-actors commit: 999e57a151cc7ada020ca2844b651499ab8c0dec (v3.0.1) -/// GasOnSubmitVerifySeal is amount of gas charged for SubmitPoRepForBulkVerify -/// This number is empirically determined -pub mod detail { - pub const GAS_ON_SUBMIT_VERIFY_SEAL: i64 = 34721049; -} - /// Storage power actor methods available #[derive(FromPrimitive)] #[repr(u64)] @@ -59,9 +47,8 @@ pub enum Method { EnrollCronEvent = 4, OnEpochTickEnd = 5, UpdatePledgeTotal = 6, - // * Deprecated in v2 - // OnConsensusFault = 7, - SubmitPoRepForBulkVerify = 8, + // OnConsensusFault = 7, // Deprecated v2 + // SubmitPoRepForBulkVerify = 8, // Deprecated CurrentTotalPower = 9, // Method numbers derived from FRC-0042 standards CreateMinerExported = frc42_dispatch::method_hash!("CreateMiner"), @@ -223,9 +210,6 @@ impl Actor { .map_err(|e| e.wrap("failed to check epoch baseline power"))?, )?; - if let Err(e) = Self::process_batch_proof_verifies(rt, &rewret) { - error!("unexpected error processing batch proof verifies: {}. Skipping all verification for epoch {}", e, rt.curr_epoch()); - } Self::process_deferred_cron_events(rt, rewret)?; let this_epoch_raw_byte_power = rt.transaction(|st: &mut State, _| { @@ -270,67 +254,6 @@ impl Actor { }) } - fn submit_porep_for_bulk_verify( - rt: &impl Runtime, - params: SubmitPoRepForBulkVerifyParams, - ) -> Result<(), ActorError> { - rt.validate_immediate_caller_type(std::iter::once(&Type::Miner))?; - - rt.transaction(|st: &mut State, rt| { - st.validate_miner_has_claim(rt.store(), &rt.message().caller())?; - - let mut mmap = if let Some(ref batch) = st.proof_validation_batch { - Multimap::from_root( - rt.store(), - batch, - HAMT_BIT_WIDTH, - PROOF_VALIDATION_BATCH_AMT_BITWIDTH, - ) - .map_err(|e| { - e.downcast_default( - ExitCode::USR_ILLEGAL_STATE, - "failed to load proof batching set", - ) - })? - } else { - debug!("ProofValidationBatch created"); - Multimap::new(rt.store(), HAMT_BIT_WIDTH, PROOF_VALIDATION_BATCH_AMT_BITWIDTH) - }; - let miner_addr = rt.message().caller(); - let arr = mmap.get::(&miner_addr.to_bytes()).map_err(|e| { - e.downcast_default( - ExitCode::USR_ILLEGAL_STATE, - format!("failed to get seal verify infos at addr {}", miner_addr), - ) - })?; - if let Some(arr) = arr { - if arr.count() >= MAX_MINER_PROVE_COMMITS_PER_EPOCH { - return Err(ActorError::unchecked( - ERR_TOO_MANY_PROVE_COMMITS, - format!( - "miner {} attempting to prove commit over {} sectors in epoch", - miner_addr, MAX_MINER_PROVE_COMMITS_PER_EPOCH - ), - )); - } - } - - mmap.add(miner_addr.to_bytes().into(), params.seal_info).map_err(|e| { - e.downcast_default(ExitCode::USR_ILLEGAL_STATE, "failed to insert proof into set") - })?; - - let mmrc = mmap.root().map_err(|e| { - e.downcast_default(ExitCode::USR_ILLEGAL_STATE, "failed to flush proofs batch map") - })?; - - rt.charge_gas("OnSubmitVerifySeal", detail::GAS_ON_SUBMIT_VERIFY_SEAL); - st.proof_validation_batch = Some(mmrc); - Ok(()) - })?; - - Ok(()) - } - /// Returns the total power and pledge recorded by the power actor. /// The returned values are frozen during the cron tick before this epoch /// so that this method returns consistent values while processing all messages @@ -393,139 +316,6 @@ impl Actor { Ok(MinerConsensusCountReturn { miner_consensus_count: st.miner_above_min_power_count }) } - fn process_batch_proof_verifies( - rt: &impl Runtime, - rewret: &ThisEpochRewardReturn, - ) -> Result<(), String> { - let mut miners: Vec<(Address, usize)> = Vec::new(); - let mut infos: Vec = Vec::new(); - let mut st_err: Option = None; - let this_epoch_qa_power_smoothed = rt - .transaction(|st: &mut State, rt| { - let result = Ok(st.this_epoch_qa_power_smoothed.clone()); - let batch = match &st.proof_validation_batch { - None => { - debug!("ProofValidationBatch was nil, quitting verification"); - return result; - } - Some(batch) => batch, - }; - let mmap = match Multimap::from_root( - rt.store(), - batch, - HAMT_BIT_WIDTH, - PROOF_VALIDATION_BATCH_AMT_BITWIDTH, - ) { - Ok(mmap) => mmap, - Err(e) => { - st_err = Some(format!("failed to load proofs validation batch {}", e)); - return result; - } - }; - - let claims = match st.load_claims(rt.store()) { - Ok(claims) => claims, - Err(e) => { - st_err = Some(format!("failed to load claims: {}", e)); - return result; - } - }; - - if let Err(e) = mmap.for_all::<_, SealVerifyInfo>(|k, arr| { - let addr = match Address::from_bytes(&k.0) { - Ok(addr) => addr, - Err(e) => { - return Err(anyhow!("failed to parse address key: {}", e)); - } - }; - - let contains_claim = match claims.contains_key(&addr) { - Ok(contains_claim) => contains_claim, - Err(e) => return Err(anyhow!("failed to look up clain: {}", e)), - }; - - if !contains_claim { - debug!("skipping batch verifies for unknown miner: {}", addr); - return Ok(()); - } - - let num_proofs: usize = arr.count().try_into()?; - infos.reserve(num_proofs); - arr.for_each(|_, svi| { - infos.push(svi.clone()); - Ok(()) - }) - .map_err(|e| { - anyhow!( - "failed to iterate over proof verify array for miner {}: {}", - addr, - e - ) - })?; - - miners.push((addr, num_proofs)); - Ok(()) - }) { - // Do not return immediately, all runs that get this far should wipe the ProofValidationBatchQueue. - // If we leave the validation batch then in the case of a repeating state error the queue - // will quickly fill up and repeated traversals will start ballooning cron execution time. - st_err = Some(format!("failed to iterate proof batch: {}", e)); - } - - st.proof_validation_batch = None; - result - }) - .map_err(|e| { - format!("failed to do transaction in process batch proof verifies: {}", e) - })?; - if let Some(st_err) = st_err { - return Err(st_err); - } - - let res = - rt.batch_verify_seals(&infos).map_err(|e| format!("failed to batch verify: {}", e))?; - - let mut res_iter = infos.iter().zip(res.iter().copied()); - for (m, count) in miners { - let successful: Vec<_> = res_iter - .by_ref() - // Take the miner's sectors. - .take(count) - // Filter by successful - .filter(|(_, r)| *r) - // Pull out the sector numbers. - .map(|(info, _)| info.sector_id.number) - // Deduplicate - .filter({ - let mut seen = BTreeSet::<_>::new(); - move |snum| seen.insert(*snum) - }) - .collect(); - - // Result intentionally ignored - if successful.is_empty() { - continue; - } - if let Err(e) = extract_send_result( - rt.send_simple( - &m, - ext::miner::CONFIRM_SECTOR_PROOFS_VALID_METHOD, - IpldBlock::serialize_cbor(&ext::miner::ConfirmSectorProofsParams { - sectors: successful, - reward_smoothed: rewret.this_epoch_reward_smoothed.clone(), - reward_baseline_power: rewret.this_epoch_baseline_power.clone(), - quality_adj_power_smoothed: this_epoch_qa_power_smoothed.clone(), - }) - .map_err(|e| format!("failed to serialize ConfirmSectorProofsParams: {}", e))?, - Default::default(), - ), - ) { - error!("failed to confirm sector proof validity to {}, error code {}", m, e); - } - } - Ok(()) - } - fn process_deferred_cron_events( rt: &impl Runtime, rewret: ThisEpochRewardReturn, @@ -643,7 +433,6 @@ impl ActorCode for Actor { EnrollCronEvent => enroll_cron_event, OnEpochTickEnd => on_epoch_tick_end, UpdatePledgeTotal => update_pledge_total, - SubmitPoRepForBulkVerify => submit_porep_for_bulk_verify, CurrentTotalPower => current_total_power, NetworkRawPowerExported => network_raw_power, MinerRawPowerExported => miner_raw_power, diff --git a/actors/power/src/state.rs b/actors/power/src/state.rs index b3f8c6a24..a30fa6760 100644 --- a/actors/power/src/state.rs +++ b/actors/power/src/state.rs @@ -40,7 +40,6 @@ lazy_static! { pub const CRON_QUEUE_HAMT_BITWIDTH: u32 = 6; pub const CRON_QUEUE_AMT_BITWIDTH: u32 = 6; -pub const PROOF_VALIDATION_BATCH_AMT_BITWIDTH: u32 = 4; pub type ClaimsMap = Map2; pub const CLAIMS_CONFIG: Config = DEFAULT_HAMT_CONFIG; @@ -79,6 +78,7 @@ pub struct State { /// Claimed power for each miner. pub claims: Cid, // Map, HAMT[address]Claim + // Deprecated as of FIP 0084 pub proof_validation_batch: Option, } diff --git a/actors/power/src/testing.rs b/actors/power/src/testing.rs index e6c9d8131..ef920af4f 100644 --- a/actors/power/src/testing.rs +++ b/actors/power/src/testing.rs @@ -2,20 +2,14 @@ use std::collections::HashMap; use fvm_ipld_blockstore::Blockstore; use fvm_ipld_encoding::RawBytes; -use fvm_shared::{ - address::Address, - clock::ChainEpoch, - sector::{SealVerifyInfo, StoragePower}, - HAMT_BIT_WIDTH, -}; +use fvm_shared::{address::Address, clock::ChainEpoch, sector::StoragePower}; use num_traits::{Signed, Zero}; use fil_actors_runtime::{parse_uint_key, runtime::Policy, MessageAccumulator, Multimap}; use crate::{ consensus_miner_min_power, Claim, ClaimsMap, CronEvent, State, CLAIMS_CONFIG, - CRON_QUEUE_AMT_BITWIDTH, CRON_QUEUE_HAMT_BITWIDTH, MAX_MINER_PROVE_COMMITS_PER_EPOCH, - PROOF_VALIDATION_BATCH_AMT_BITWIDTH, + CRON_QUEUE_AMT_BITWIDTH, CRON_QUEUE_HAMT_BITWIDTH, }; pub struct MinerCronEvent { @@ -25,12 +19,10 @@ pub struct MinerCronEvent { type CronEventsByAddress = HashMap>; type ClaimsByAddress = HashMap; -type ProofsByAddress = HashMap; pub struct StateSummary { pub crons: CronEventsByAddress, pub claims: ClaimsByAddress, - pub proofs: ProofsByAddress, } /// Checks internal invariants of power state @@ -90,9 +82,9 @@ pub fn check_state_invariants( let crons = check_cron_invariants(state, store, &acc); let claims = check_claims_invariants(policy, state, store, &acc); - let proofs = check_proofs_invariants(state, store, &claims, &acc); + check_proofs_invariants(state, &acc); - (StateSummary { crons, claims, proofs }, acc) + (StateSummary { crons, claims }, acc) } fn check_cron_invariants( @@ -209,55 +201,8 @@ fn check_claims_invariants( claims_by_address } -fn check_proofs_invariants( - state: &State, - store: &BS, - claims: &ClaimsByAddress, - acc: &MessageAccumulator, -) -> ProofsByAddress { - if state.proof_validation_batch.is_none() { - return ProofsByAddress::default(); +fn check_proofs_invariants(state: &State, acc: &MessageAccumulator) { + if state.proof_validation_batch.is_some() { + acc.add("proof validation batch should be empty after FIP 0084"); } - - let mut proofs_by_address = ProofsByAddress::new(); - match Multimap::from_root( - store, - &state.proof_validation_batch.unwrap(), - HAMT_BIT_WIDTH, - PROOF_VALIDATION_BATCH_AMT_BITWIDTH, - ) { - Ok(queue) => { - let ret = queue.for_all::<_, SealVerifyInfo>(|key, infos| { - let address = Address::from_bytes(key)?; - let claim = if let Some(claim) = claims.get(&address) { - claim - } else { - acc.add(format!("miner {address} has proofs awaiting validation but no claim")); - return Ok(()) - }; - - let ret = infos.for_each(|_, info| { - match info.registered_proof.registered_window_post_proof() { - Ok(sector_window_post_proof_type) => { - acc.require(claim.window_post_proof_type == sector_window_post_proof_type, format!("miner submitted proof with proof type {:?} different from claim {:?}", sector_window_post_proof_type, claim.window_post_proof_type)); - }, - Err(e) => acc.add(format!("Invalid PoSt proof: {e}")) - } - proofs_by_address.insert(address, info.clone()); - Ok(()) - }); - - if ret.is_err() { - return ret.map_err(|e| anyhow::anyhow!("error iterating proof validation batch for address {}: {}", address, e)); - } - - acc.require(proofs_by_address.len() as u64 <= MAX_MINER_PROVE_COMMITS_PER_EPOCH, format!("miner {address} has submitted too many proofs ({}) for batch verification", proofs_by_address.len())); - Ok(()) - }); - acc.require_no_error(ret, "error iterating proof validation queue"); - } - Err(e) => acc.add(format!("error loading proof validation queue: {e}")), - } - - proofs_by_address } diff --git a/actors/power/src/types.rs b/actors/power/src/types.rs index 442079372..983c64dc2 100644 --- a/actors/power/src/types.rs +++ b/actors/power/src/types.rs @@ -8,7 +8,7 @@ use fvm_shared::address::Address; use fvm_shared::bigint::bigint_ser; use fvm_shared::clock::ChainEpoch; use fvm_shared::econ::TokenAmount; -use fvm_shared::sector::{RegisteredPoStProof, SealVerifyInfo, StoragePower}; +use fvm_shared::sector::{RegisteredPoStProof, StoragePower}; use fvm_shared::ActorID; use serde::{Deserialize, Serialize}; @@ -60,12 +60,6 @@ pub struct UpdatePledgeTotalParams { pub pledge_delta: TokenAmount, } -#[derive(Debug, Serialize, Deserialize, PartialEq, Eq, Clone)] -#[serde(transparent)] -pub struct SubmitPoRepForBulkVerifyParams { - pub seal_info: SealVerifyInfo, -} - #[derive(Serialize_tuple, Deserialize_tuple, Debug, Clone, Eq, PartialEq)] pub struct CurrentTotalPowerReturn { #[serde(with = "bigint_ser")] diff --git a/actors/power/tests/harness/mod.rs b/actors/power/tests/harness/mod.rs index 6b484177b..720251d65 100644 --- a/actors/power/tests/harness/mod.rs +++ b/actors/power/tests/harness/mod.rs @@ -10,8 +10,6 @@ use fvm_shared::bigint::BigInt; use fvm_shared::clock::ChainEpoch; use fvm_shared::econ::TokenAmount; use fvm_shared::error::ExitCode; -use fvm_shared::sector::SealVerifyInfo; -use fvm_shared::sector::SectorNumber; use fvm_shared::sector::{RegisteredPoStProof, RegisteredSealProof, StoragePower}; use fvm_shared::MethodNum; use lazy_static::lazy_static; @@ -19,11 +17,8 @@ use num_traits::Zero; use serde::de::DeserializeOwned; use serde::Serialize; -use fil_actor_power::detail::GAS_ON_SUBMIT_VERIFY_SEAL; use fil_actor_power::ext::init::ExecParams; -use fil_actor_power::ext::miner::ConfirmSectorProofsParams; use fil_actor_power::ext::miner::MinerConstructorParams; -use fil_actor_power::ext::miner::CONFIRM_SECTOR_PROOFS_VALID_METHOD; use fil_actor_power::ext::reward::Method::ThisEpochReward; use fil_actor_power::ext::reward::UPDATE_NETWORK_KPI; use fil_actor_power::testing::check_state_invariants; @@ -217,10 +212,6 @@ impl Harness { ret.miner_count } - pub fn this_epoch_baseline_power(&self) -> &StoragePower { - &self.this_epoch_baseline_power - } - pub fn get_claim(&self, rt: &MockRuntime, miner: &Address) -> Option { let st: State = rt.get_state(); st.get_claim(rt.store(), miner).unwrap() @@ -399,34 +390,8 @@ impl Harness { rt: &MockRuntime, current_epoch: ChainEpoch, expected_raw_power: &StoragePower, - confirmed_sectors: Vec, - infos: Vec, ) { self.expect_query_network_info(rt); - - let state: State = rt.get_state(); - - //expect sends for confirmed sectors - for sector in confirmed_sectors { - let param = ConfirmSectorProofsParams { - sectors: sector.sector_nums, - reward_smoothed: self.this_epoch_reward_smoothed.clone(), - reward_baseline_power: self.this_epoch_baseline_power.clone(), - quality_adj_power_smoothed: state.this_epoch_qa_power_smoothed.clone(), - }; - rt.expect_send_simple( - sector.miner, - CONFIRM_SECTOR_PROOFS_VALID_METHOD, - IpldBlock::serialize_cbor(¶m).unwrap(), - TokenAmount::zero(), - None, - ExitCode::new(0), - ); - } - - let verified_seals = batch_verify_default_output(&infos); - rt.expect_batch_verify_seals(infos, anyhow::Ok(verified_seals)); - // expect power sends to reward actor rt.expect_send_simple( REWARD_ACTOR_ADDR, @@ -447,37 +412,7 @@ impl Harness { let state: State = rt.get_state(); assert!(state.proof_validation_batch.is_none()); } - - pub fn submit_porep_for_bulk_verify( - &self, - rt: &MockRuntime, - miner_address: Address, - seal_info: SealVerifyInfo, - expect_success: bool, - ) -> Result<(), ActorError> { - if expect_success { - rt.expect_gas_charge(GAS_ON_SUBMIT_VERIFY_SEAL); - } - rt.expect_validate_caller_type(vec![Type::Miner]); - rt.set_caller(*MINER_ACTOR_CODE_ID, miner_address); - rt.call::( - Method::SubmitPoRepForBulkVerify as u64, - IpldBlock::serialize_cbor(&seal_info).unwrap(), - )?; - rt.verify(); - Ok(()) - } -} - -pub struct ConfirmedSectorSend { - pub miner: Address, - pub sector_nums: Vec, } - -pub fn batch_verify_default_output(infos: &[SealVerifyInfo]) -> Vec { - vec![true; infos.len()] -} - /// Collects all keys from a map into a vector. fn collect_keys(m: Map2) -> Result, ActorError> where diff --git a/actors/power/tests/power_actor_tests.rs b/actors/power/tests/power_actor_tests.rs index ea0bfe95c..554539433 100644 --- a/actors/power/tests/power_actor_tests.rs +++ b/actors/power/tests/power_actor_tests.rs @@ -668,7 +668,6 @@ mod cron_tests { ExitCode::OK, ); rt.set_caller(*CRON_ACTOR_CODE_ID, CRON_ACTOR_ADDR); - rt.expect_batch_verify_seals(Vec::new(), Ok(Vec::new())); rt.call::(Method::OnEpochTickEnd as u64, None).unwrap(); @@ -704,7 +703,7 @@ mod cron_tests { let delta = TokenAmount::from_atto(1u8); h.update_pledge_total(&rt, miner1, &delta); - h.on_epoch_tick_end(&rt, 0, &expected_power, Vec::new(), Vec::new()); + h.on_epoch_tick_end(&rt, 0, &expected_power); let state: State = rt.get_state(); @@ -779,7 +778,6 @@ mod cron_tests { ExitCode::OK, ); rt.set_caller(*CRON_ACTOR_CODE_ID, CRON_ACTOR_ADDR); - rt.expect_batch_verify_seals(Vec::new(), Ok(Vec::new())); rt.call::(Method::OnEpochTickEnd as u64, None).unwrap(); rt.verify(); @@ -808,8 +806,6 @@ mod cron_tests { ); rt.set_caller(*CRON_ACTOR_CODE_ID, CRON_ACTOR_ADDR); - rt.expect_batch_verify_seals(Vec::new(), Ok(Vec::new())); - rt.call::(Method::OnEpochTickEnd as u64, None).unwrap(); rt.verify(); @@ -846,7 +842,6 @@ mod cron_tests { ExitCode::OK, ); rt.set_caller(*CRON_ACTOR_CODE_ID, CRON_ACTOR_ADDR); - rt.expect_batch_verify_seals(Vec::new(), Ok(Vec::new())); rt.call::(Method::OnEpochTickEnd as u64, None).unwrap(); rt.verify(); @@ -893,7 +888,6 @@ mod cron_tests { rt.expect_validate_caller_addr(vec![CRON_ACTOR_ADDR]); // process batch verifies first - rt.expect_batch_verify_seals(Vec::new(), Ok(Vec::new())); h.expect_query_network_info(&rt); let state: State = rt.get_state(); @@ -957,9 +951,6 @@ mod cron_tests { rt.set_epoch(2); rt.expect_validate_caller_addr(vec![CRON_ACTOR_ADDR]); - // process batch verifies first - rt.expect_batch_verify_seals(Vec::new(), Ok(Vec::new())); - h.expect_query_network_info(&rt); let state: State = rt.get_state(); @@ -1027,289 +1018,6 @@ mod cron_tests { ExitCode::OK, ); rt.set_caller(*CRON_ACTOR_CODE_ID, CRON_ACTOR_ADDR); - rt.expect_batch_verify_seals(Vec::new(), Ok(Vec::new())); - - rt.call::(Method::OnEpochTickEnd as u64, None).unwrap(); - rt.verify(); - h.check_state(&rt); - } -} - -#[cfg(test)] -mod cron_batch_proof_verifies_tests { - use super::*; - use fil_actor_power::ext::{ - miner::{ConfirmSectorProofsParams, CONFIRM_SECTOR_PROOFS_VALID_METHOD}, - reward::UPDATE_NETWORK_KPI, - }; - use fil_actors_runtime::{ - test_utils::{make_piece_cid, make_sealed_cid, CRON_ACTOR_CODE_ID}, - CRON_ACTOR_ADDR, REWARD_ACTOR_ADDR, - }; - use fvm_shared::{ - bigint::BigInt, - sector::{InteractiveSealRandomness, SealRandomness, SealVerifyInfo, SectorID}, - }; - - fn create_basic_seal_info(id: u64) -> SealVerifyInfo { - SealVerifyInfo { - registered_proof: fvm_shared::sector::RegisteredSealProof::StackedDRG32GiBV1, - deal_ids: Vec::new(), - randomness: SealRandomness::default(), - interactive_randomness: InteractiveSealRandomness::default(), - proof: Vec::new(), - sealed_cid: make_sealed_cid(format!("CommR-{id}").as_bytes()), - unsealed_cid: make_piece_cid(format!("CommD-{id}").as_bytes()), - sector_id: SectorID { number: id, ..Default::default() }, - } - } - - const MINER_1: Address = Address::new_id(101); - const OWNER: Address = Address::new_id(102); - - #[test] - fn success_with_one_miner_and_one_confirmed_sector() { - let (mut h, rt) = setup(); - - h.create_miner_basic(&rt, OWNER, OWNER, MINER_1).unwrap(); - - let info = create_basic_seal_info(0); - h.submit_porep_for_bulk_verify(&rt, MINER_1, info.clone(), true).unwrap(); - - let confirmed_sectors = - vec![ConfirmedSectorSend { miner: MINER_1, sector_nums: vec![info.sector_id.number] }]; - h.on_epoch_tick_end(&rt, 0, &BigInt::zero(), confirmed_sectors, vec![info]); - - rt.verify(); - h.check_state(&rt); - } - - #[test] - fn success_with_one_miner_and_multiple_confirmed_sectors() { - let (mut h, rt) = setup(); - - h.create_miner_basic(&rt, OWNER, OWNER, MINER_1).unwrap(); - - let infos: Vec<_> = (1..=3).map(create_basic_seal_info).collect(); - infos.iter().for_each(|info| { - h.submit_porep_for_bulk_verify(&rt, MINER_1, info.clone(), true).unwrap() - }); - - let sector_id_nums = infos.iter().map(|info| info.sector_id.number).collect(); - let confirmed_sectors = - vec![ConfirmedSectorSend { miner: MINER_1, sector_nums: sector_id_nums }]; - h.on_epoch_tick_end(&rt, 0, &BigInt::zero(), confirmed_sectors, infos); - - rt.verify(); - h.check_state(&rt); - } - - #[test] - fn duplicate_sector_numbers_are_ignored_for_a_miner() { - let (mut h, rt) = setup(); - - h.create_miner_basic(&rt, OWNER, OWNER, MINER_1).unwrap(); - - // duplicates will be sent to the batch verify call - let infos = - vec![create_basic_seal_info(1), create_basic_seal_info(1), create_basic_seal_info(2)]; - - infos.iter().for_each(|info| { - h.submit_porep_for_bulk_verify(&rt, MINER_1, info.clone(), true).unwrap() - }); - - // however, duplicates will not be sent to the miner as confirmed - let sector_id_nums = vec![infos[0].sector_id.number, infos[2].sector_id.number]; - let confirmed_sectors = - vec![ConfirmedSectorSend { miner: MINER_1, sector_nums: sector_id_nums }]; - h.on_epoch_tick_end(&rt, 0, &BigInt::zero(), confirmed_sectors, infos); - - rt.verify(); - h.check_state(&rt); - } - - #[test] - fn skips_verify_if_miner_has_no_claim() { - let (mut h, rt) = setup(); - h.create_miner_basic(&rt, OWNER, OWNER, MINER_1).unwrap(); - - let info = create_basic_seal_info(1); - - h.submit_porep_for_bulk_verify(&rt, MINER_1, info, true).unwrap(); - - h.delete_claim(&rt, &MINER_1); - - let infos = vec![]; - - let confirmed_sectors = vec![]; - - h.on_epoch_tick_end(&rt, 0, &BigInt::zero(), confirmed_sectors, infos); - - h.check_state(&rt); - } - - #[test] - fn success_with_multiple_miners_and_multiple_confirmed_sectors_and_assert_expected_power() { - let miner1 = Address::new_id(101); - - // TODO: shares an id with constant `OWNER` - // this is a known issue however the ordering of the values - // are vital for this test and have been left as such - let miner2 = Address::new_id(102); - let miner3 = Address::new_id(103); - let miner4 = Address::new_id(104); - - let info1 = create_basic_seal_info(1); - let info2 = create_basic_seal_info(2); - let info3 = create_basic_seal_info(3); - let info4 = create_basic_seal_info(101); - let info5 = create_basic_seal_info(200); - let info6 = create_basic_seal_info(201); - let info7 = create_basic_seal_info(300); - let info8 = create_basic_seal_info(301); - - let (mut h, rt) = setup(); - - h.create_miner_basic(&rt, OWNER, OWNER, miner1).unwrap(); - h.create_miner_basic(&rt, OWNER, OWNER, miner2).unwrap(); - h.create_miner_basic(&rt, OWNER, OWNER, miner3).unwrap(); - h.create_miner_basic(&rt, OWNER, OWNER, miner4).unwrap(); - - h.submit_porep_for_bulk_verify(&rt, miner1, info1.clone(), true).unwrap(); - h.submit_porep_for_bulk_verify(&rt, miner1, info2.clone(), true).unwrap(); - - h.submit_porep_for_bulk_verify(&rt, miner2, info3.clone(), true).unwrap(); - h.submit_porep_for_bulk_verify(&rt, miner2, info4.clone(), true).unwrap(); - - h.submit_porep_for_bulk_verify(&rt, miner3, info5.clone(), true).unwrap(); - h.submit_porep_for_bulk_verify(&rt, miner3, info6.clone(), true).unwrap(); - - h.submit_porep_for_bulk_verify(&rt, miner4, info7.clone(), true).unwrap(); - h.submit_porep_for_bulk_verify(&rt, miner4, info8.clone(), true).unwrap(); - - // TODO Because read order of keys in a multi-map is not as per insertion order, - // we have to move around the expected sends - let confirmed_sectors = vec![ - ConfirmedSectorSend { - miner: MINER_1, - sector_nums: vec![info1.sector_id.number, info2.sector_id.number], - }, - ConfirmedSectorSend { - miner: miner3, - sector_nums: vec![info5.sector_id.number, info6.sector_id.number], - }, - ConfirmedSectorSend { - miner: miner4, - sector_nums: vec![info7.sector_id.number, info8.sector_id.number], - }, - ConfirmedSectorSend { - miner: miner2, - sector_nums: vec![info3.sector_id.number, info4.sector_id.number], - }, - ]; - - let infos = vec![info1, info2, info5, info6, info7, info8, info3, info4]; - - h.on_epoch_tick_end(&rt, 0, &BigInt::zero(), confirmed_sectors, infos); - h.check_state(&rt); - } - - #[test] - fn success_when_no_confirmed_sector() { - let (h, rt) = setup(); - h.on_epoch_tick_end(&rt, 0, &BigInt::zero(), vec![], vec![]); - - h.check_state(&rt); - } - - #[test] - fn verification_for_one_sector_fails_but_others_succeeds_for_a_miner() { - let (mut h, rt) = setup(); - h.create_miner_basic(&rt, OWNER, OWNER, MINER_1).unwrap(); - - let infos: Vec<_> = (1..=3).map(create_basic_seal_info).collect(); - infos.iter().for_each(|info| { - h.submit_porep_for_bulk_verify(&rt, MINER_1, info.clone(), true).unwrap() - }); - - let res = Ok(vec![true, false, true]); - - // send will only be for the first and third sector as the middle sector will fail verification - let cs = ConfirmedSectorSend { - miner: MINER_1, - sector_nums: vec![infos[0].sector_id.number, infos[2].sector_id.number], - }; - - h.expect_query_network_info(&rt); - - let state: State = rt.get_state(); - - // expect sends for confirmed sectors - let params = ConfirmSectorProofsParams { - sectors: cs.sector_nums, - reward_smoothed: h.this_epoch_reward_smoothed.clone(), - reward_baseline_power: h.this_epoch_baseline_power().clone(), - quality_adj_power_smoothed: state.this_epoch_qa_power_smoothed, - }; - - rt.expect_send_simple( - cs.miner, - CONFIRM_SECTOR_PROOFS_VALID_METHOD, - IpldBlock::serialize_cbor(¶ms).unwrap(), - TokenAmount::zero(), - None, - ExitCode::OK, - ); - - rt.expect_batch_verify_seals(infos, res); - - // expect power sends to reward actor - rt.expect_send_simple( - REWARD_ACTOR_ADDR, - UPDATE_NETWORK_KPI, - IpldBlock::serialize_cbor(&BigIntSer(&BigInt::zero())).unwrap(), - TokenAmount::zero(), - None, - ExitCode::OK, - ); - - rt.expect_validate_caller_addr(vec![CRON_ACTOR_ADDR]); - - rt.set_epoch(0); - rt.set_caller(*CRON_ACTOR_CODE_ID, CRON_ACTOR_ADDR); - - rt.call::(Method::OnEpochTickEnd as u64, None).unwrap(); - - rt.verify(); - h.check_state(&rt); - } - - #[test] - fn cron_tick_does_not_fail_if_batch_verify_seals_fails() { - let (mut h, rt) = setup(); - h.create_miner_basic(&rt, OWNER, OWNER, MINER_1).unwrap(); - - let infos: Vec<_> = (1..=3).map(create_basic_seal_info).collect(); - infos.iter().for_each(|info| { - h.submit_porep_for_bulk_verify(&rt, MINER_1, info.clone(), true).unwrap() - }); - - h.expect_query_network_info(&rt); - - rt.expect_batch_verify_seals(infos, Err(anyhow::Error::msg("fail"))); - rt.expect_validate_caller_addr(vec![CRON_ACTOR_ADDR]); - - // expect power sends to reward actor - rt.expect_send_simple( - REWARD_ACTOR_ADDR, - UPDATE_NETWORK_KPI, - IpldBlock::serialize_cbor(&BigIntSer(&BigInt::zero())).unwrap(), - TokenAmount::zero(), - None, - ExitCode::OK, - ); - rt.set_epoch(0); - rt.set_caller(*CRON_ACTOR_CODE_ID, CRON_ACTOR_ADDR); rt.call::(Method::OnEpochTickEnd as u64, None).unwrap(); rt.verify(); @@ -1317,129 +1025,6 @@ mod cron_batch_proof_verifies_tests { } } -#[cfg(test)] -mod submit_porep_for_bulk_verify_tests { - use super::*; - - use fil_actor_power::{ - ERR_TOO_MANY_PROVE_COMMITS, MAX_MINER_PROVE_COMMITS_PER_EPOCH, - PROOF_VALIDATION_BATCH_AMT_BITWIDTH, - }; - use fil_actors_runtime::shared::HAMT_BIT_WIDTH; - use fil_actors_runtime::test_utils::{make_piece_cid, make_sealed_cid}; - use fil_actors_runtime::Multimap; - use fvm_shared::sector::{InteractiveSealRandomness, SealRandomness, SealVerifyInfo, SectorID}; - - const MINER: Address = Address::new_id(101); - const OWNER: Address = Address::new_id(101); - - #[test] - fn registers_porep_and_charges_gas() { - let (mut h, rt) = setup(); - - h.create_miner_basic(&rt, OWNER, OWNER, MINER).unwrap(); - - let comm_r = make_sealed_cid("commR".as_bytes()); - let comm_d = make_piece_cid("commD".as_bytes()); - - let info = SealVerifyInfo { - registered_proof: fvm_shared::sector::RegisteredSealProof::StackedDRG32GiBV1P1, - deal_ids: Vec::new(), - randomness: SealRandomness::default(), - interactive_randomness: InteractiveSealRandomness::default(), - proof: Vec::new(), - sealed_cid: comm_r, - unsealed_cid: comm_d, - sector_id: SectorID { number: 0, ..Default::default() }, - }; - - h.submit_porep_for_bulk_verify(&rt, MINER, info, true).unwrap(); - let st: State = rt.get_state(); - let store = &rt.store; - assert!(st.proof_validation_batch.is_some()); - let mmap = Multimap::from_root( - store, - st.proof_validation_batch.as_ref().unwrap(), - HAMT_BIT_WIDTH, - PROOF_VALIDATION_BATCH_AMT_BITWIDTH, - ) - .unwrap(); - let arr = mmap.get::(&MINER.to_bytes()).unwrap(); - let found = arr.unwrap(); - assert_eq!(1_u64, found.count()); - let sealed_cid = found.get(0).unwrap().unwrap().sealed_cid; - assert_eq!(comm_r, sealed_cid); - h.check_state(&rt); - } - - #[test] - fn aborts_when_too_many_poreps() { - let (mut h, rt) = setup(); - - h.create_miner_basic(&rt, OWNER, OWNER, MINER).unwrap(); - - fn create_basic_seal_info(id: u64) -> SealVerifyInfo { - SealVerifyInfo { - registered_proof: fvm_shared::sector::RegisteredSealProof::StackedDRG32GiBV1P1, - deal_ids: Vec::new(), - randomness: SealRandomness::default(), - interactive_randomness: InteractiveSealRandomness::default(), - proof: Vec::new(), - sealed_cid: make_sealed_cid(format!("CommR-{id}").as_bytes()), - unsealed_cid: make_piece_cid(format!("CommD-{id}").as_bytes()), - sector_id: SectorID { number: id, ..Default::default() }, - } - } - - // Adding MAX_MINER_PROVE_COMMITS_PER_EPOCH works without error - for i in 0..MAX_MINER_PROVE_COMMITS_PER_EPOCH { - h.submit_porep_for_bulk_verify(&rt, MINER, create_basic_seal_info(i), true).unwrap(); - } - - expect_abort( - ERR_TOO_MANY_PROVE_COMMITS, - h.submit_porep_for_bulk_verify( - &rt, - MINER, - create_basic_seal_info(MAX_MINER_PROVE_COMMITS_PER_EPOCH), - false, - ), - ); - - h.check_state(&rt); - } - - #[test] - fn aborts_when_miner_has_no_claim() { - let (mut h, rt) = setup(); - - h.create_miner_basic(&rt, OWNER, OWNER, MINER).unwrap(); - - let comm_r = make_sealed_cid("commR".as_bytes()); - let comm_d = make_piece_cid("commD".as_bytes()); - - let info = SealVerifyInfo { - registered_proof: fvm_shared::sector::RegisteredSealProof::StackedDRG32GiBV1, - deal_ids: Vec::new(), - randomness: SealRandomness::default(), - interactive_randomness: InteractiveSealRandomness::default(), - proof: Vec::new(), - sealed_cid: comm_r, - unsealed_cid: comm_d, - sector_id: SectorID { number: 0, ..Default::default() }, - }; - - // delete miner - h.delete_claim(&rt, &MINER); - - expect_abort( - ExitCode::USR_FORBIDDEN, - h.submit_porep_for_bulk_verify(&rt, MINER, info, false), - ); - h.check_state(&rt); - } -} - #[test] fn create_miner_restricted_correctly() { let (h, rt) = setup(); diff --git a/actors/reward/src/testing.rs b/actors/reward/src/testing.rs index cfddba441..91d658ab8 100644 --- a/actors/reward/src/testing.rs +++ b/actors/reward/src/testing.rs @@ -1,4 +1,4 @@ -use crate::{baseline_power_from_prev, State}; +use crate::State; use fil_actors_runtime::MessageAccumulator; use fvm_shared::{clock::ChainEpoch, econ::TokenAmount}; use num_traits::Signed; @@ -52,17 +52,5 @@ pub fn check_state_invariants( format!("cumsum realized negative ({})", state.cumsum_realized), ); - // Theoretically we should compare effective_baseline_power <= this_epoch_baseline_power but - // because of rounding issues explained and tracked in https://github.com/filecoin-project/builtin-actors/issues/459 - // we settled on this workaround. - let next_epoch_baseline_power = baseline_power_from_prev(&state.this_epoch_baseline_power); - acc.require( - state.effective_baseline_power <= next_epoch_baseline_power, - format!( - "effective baseline power ({}) > next_epoch_baseline_power ({})", - state.effective_baseline_power, next_epoch_baseline_power - ), - ); - (StateSummary::default(), acc) } diff --git a/actors/verifreg/Cargo.toml b/actors/verifreg/Cargo.toml index 09de8588f..66bd676b5 100644 --- a/actors/verifreg/Cargo.toml +++ b/actors/verifreg/Cargo.toml @@ -30,6 +30,7 @@ log = { workspace = true } num-derive = { workspace = true } num-traits = { workspace = true } serde = { workspace = true } +const-hex = { workspace = true } [dev-dependencies] fil_actors_runtime = { workspace = true, features = ["test_utils", "sector-default"] } diff --git a/actors/verifreg/src/emit.rs b/actors/verifreg/src/emit.rs index f9e1759c6..6fc082fed 100644 --- a/actors/verifreg/src/emit.rs +++ b/actors/verifreg/src/emit.rs @@ -1,10 +1,12 @@ // A namespace for helpers that build and emit verified registry events. -use crate::{ActorError, AllocationID}; +use crate::{ActorError, Allocation, AllocationID, Claim}; use crate::{ClaimID, DataCap}; +use cid::Cid; use fil_actors_runtime::runtime::Runtime; use fil_actors_runtime::EventBuilder; use fvm_shared::bigint::bigint_ser::BigIntSer; +use fvm_shared::clock::ChainEpoch; use fvm_shared::ActorID; /// Indicates a new value for a verifier's datacap balance. @@ -14,25 +16,32 @@ pub fn verifier_balance( rt: &impl Runtime, verifier: ActorID, new_balance: &DataCap, + client: Option, ) -> Result<(), ActorError> { - rt.emit_event( - &EventBuilder::new() - .typ("verifier-balance") - .field_indexed("verifier", &verifier) - .field("balance", &BigIntSer(new_balance)) - .build()?, - ) + let mut event: EventBuilder = EventBuilder::new() + .typ("verifier-balance") + .field_indexed("verifier", &verifier) + .field("balance", &BigIntSer(new_balance)); + if let Some(client) = client { + event = event.field_indexed("client", &client); + } + rt.emit_event(&event.build()?) } /// Indicates a new allocation has been made. pub fn allocation( rt: &impl Runtime, id: AllocationID, - client: ActorID, - provider: ActorID, + alloc: &Allocation, ) -> Result<(), ActorError> { rt.emit_event( - &EventBuilder::new().typ("allocation").with_parties(id, client, provider).build()?, + &EventBuilder::new() + .typ("allocation") + .with_parties(id, alloc.client, alloc.provider) + .with_piece(&alloc.data, alloc.size.0) + .with_term(alloc.term_min, alloc.term_max) + .field("expiration", &alloc.expiration) + .build()?, ) } @@ -40,48 +49,58 @@ pub fn allocation( pub fn allocation_removed( rt: &impl Runtime, id: AllocationID, - client: ActorID, - provider: ActorID, + alloc: &Allocation, ) -> Result<(), ActorError> { rt.emit_event( &EventBuilder::new() .typ("allocation-removed") - .with_parties(id, client, provider) + .with_parties(id, alloc.client, alloc.provider) + .with_piece(&alloc.data, alloc.size.0) + .with_term(alloc.term_min, alloc.term_max) + .field("expiration", &alloc.expiration) .build()?, ) } /// Indicates an allocation has been claimed. -pub fn claim( - rt: &impl Runtime, - id: ClaimID, - client: ActorID, - provider: ActorID, -) -> Result<(), ActorError> { - rt.emit_event(&EventBuilder::new().typ("claim").with_parties(id, client, provider).build()?) +pub fn claim(rt: &impl Runtime, id: ClaimID, claim: &Claim) -> Result<(), ActorError> { + rt.emit_event( + &EventBuilder::new() + .typ("claim") + .with_parties(id, claim.client, claim.provider) + .with_piece(&claim.data, claim.size.0) + .with_term(claim.term_min, claim.term_max) + .field("term-start", &claim.term_start) + .field_indexed("sector", &claim.sector) + .build()?, + ) } /// Indicates an existing claim has been updated (e.g. with a longer term). -pub fn claim_updated( - rt: &impl Runtime, - id: ClaimID, - client: ActorID, - provider: ActorID, -) -> Result<(), ActorError> { +pub fn claim_updated(rt: &impl Runtime, id: ClaimID, claim: &Claim) -> Result<(), ActorError> { rt.emit_event( - &EventBuilder::new().typ("claim-updated").with_parties(id, client, provider).build()?, + &EventBuilder::new() + .typ("claim-updated") + .with_parties(id, claim.client, claim.provider) + .with_piece(&claim.data, claim.size.0) + .with_term(claim.term_min, claim.term_max) + .field("term-start", &claim.term_start) + .field_indexed("sector", &claim.sector) + .build()?, ) } /// Indicates an expired claim has been removed. -pub fn claim_removed( - rt: &impl Runtime, - id: ClaimID, - client: ActorID, - provider: ActorID, -) -> Result<(), ActorError> { +pub fn claim_removed(rt: &impl Runtime, id: ClaimID, claim: &Claim) -> Result<(), ActorError> { rt.emit_event( - &EventBuilder::new().typ("claim-removed").with_parties(id, client, provider).build()?, + &EventBuilder::new() + .typ("claim-removed") + .with_parties(id, claim.client, claim.provider) + .with_piece(&claim.data, claim.size.0) + .with_term(claim.term_min, claim.term_max) + .field("term-start", &claim.term_start) + .field_indexed("sector", &claim.sector) + .build()?, ) } @@ -97,3 +116,23 @@ impl WithParties for EventBuilder { .field_indexed("provider", &provider) } } + +trait WithPiece { + fn with_piece(self, piece_cid: &Cid, piece_size: u64) -> EventBuilder; +} + +impl crate::emit::WithPiece for EventBuilder { + fn with_piece(self, piece_cid: &Cid, piece_size: u64) -> EventBuilder { + self.field_indexed("piece-cid", &piece_cid).field("piece-size", &piece_size) + } +} + +trait WithTerm { + fn with_term(self, term_min: ChainEpoch, term_max: ChainEpoch) -> EventBuilder; +} + +impl crate::emit::WithTerm for EventBuilder { + fn with_term(self, term_min: ChainEpoch, term_max: ChainEpoch) -> EventBuilder { + self.field("term-min", &term_min).field("term-max", &term_max) + } +} diff --git a/actors/verifreg/src/lib.rs b/actors/verifreg/src/lib.rs index d44cfa974..a17a19273 100644 --- a/actors/verifreg/src/lib.rs +++ b/actors/verifreg/src/lib.rs @@ -131,7 +131,7 @@ impl Actor { .context("failed to add verifier") })?; - emit::verifier_balance(rt, verifier, ¶ms.allowance) + emit::verifier_balance(rt, verifier, ¶ms.allowance, None) } pub fn remove_verifier( @@ -146,7 +146,7 @@ impl Actor { st.remove_verifier(rt.store(), &verifier_addr).context("failed to remove verifier") })?; - emit::verifier_balance(rt, verifier, &DataCap::zero()) + emit::verifier_balance(rt, verifier, &DataCap::zero(), None) } pub fn add_verified_client( @@ -165,8 +165,8 @@ impl Actor { )); } - let client = resolve_to_actor_id(rt, ¶ms.address, true)?; - let client = Address::new_id(client); + let client_id = resolve_to_actor_id(rt, ¶ms.address, true)?; + let client = Address::new_id(client_id); rt.transaction(|st: &mut State, rt| { if client == st.root_key { @@ -204,7 +204,12 @@ impl Actor { st.put_verifier(rt.store(), &verifier_addr, &new_verifier_cap) .context("failed to update verifier allowance")?; - emit::verifier_balance(rt, verifier_addr.id().unwrap(), &new_verifier_cap) + emit::verifier_balance( + rt, + verifier_addr.id().unwrap(), + &new_verifier_cap, + Some(client.id().unwrap()), + ) })?; // Credit client token allowance. @@ -345,7 +350,7 @@ impl Actor { )? .unwrap(); // Unwrapping here as both paths to here should ensure the allocation exists. - emit::allocation_removed(rt, *id, existing.client, existing.provider)?; + emit::allocation_removed(rt, *id, &existing)?; // Unwrapping here as both paths to here should ensure the allocation exists. recovered_datacap += existing.size.0; @@ -448,7 +453,8 @@ impl Actor { return Err(actor_error!(illegal_argument, "claim {} already exists", id)); } - emit::claim(rt, id, new_claim.client, new_claim.provider)?; + // Emit a claim event below + emit::claim(rt, id, &new_claim)?; allocs.remove(new_claim.client, id).context_code( ExitCode::USR_ILLEGAL_STATE, @@ -565,7 +571,7 @@ impl Actor { "HAMT put failure storing new claims", )?; batch_gen.add_success(); - emit::claim_updated(rt, term.claim_id, new_claim.client, new_claim.provider)?; + emit::claim_updated(rt, term.claim_id, &new_claim)?; } else { batch_gen.add_fail(ExitCode::USR_NOT_FOUND); info!("no claim {} for provider {}", term.claim_id, term.provider); @@ -617,7 +623,7 @@ impl Actor { )? .unwrap(); - emit::claim_removed(rt, *id, removed.client, removed.provider)?; + emit::claim_removed(rt, *id, &removed)?; } st.save_claims(&mut claims)?; @@ -717,13 +723,13 @@ impl Actor { let ids = st.insert_allocations(rt.store(), client, new_allocs.clone())?; for (id, alloc) in ids.iter().zip(new_allocs.iter()) { - emit::allocation(rt, *id, alloc.client, alloc.provider)?; + emit::allocation(rt, *id, alloc)?; } st.put_claims(rt.store(), updated_claims.clone())?; for (id, claim) in updated_claims { - emit::claim_updated(rt, id, claim.client, claim.provider)?; + emit::claim_updated(rt, id, &claim)?; } Ok(ids) diff --git a/actors/verifreg/tests/harness/mod.rs b/actors/verifreg/tests/harness/mod.rs index 5df23f5ef..d33a6a057 100644 --- a/actors/verifreg/tests/harness/mod.rs +++ b/actors/verifreg/tests/harness/mod.rs @@ -1,6 +1,8 @@ use std::cell::RefCell; use std::collections::HashMap; +use cid::Cid; + use frc46_token::receiver::{FRC46TokenReceived, FRC46_TOKEN_TYPE}; use frc46_token::token::types::{BurnParams, BurnReturn, TransferParams}; use frc46_token::token::TOKEN_PRECISION; @@ -231,13 +233,17 @@ impl Harness { ); let params = AddVerifiedClientParams { address: *client, allowance: allowance.clone() }; - rt.expect_emitted_event( - EventBuilder::new() - .typ("verifier-balance") - .field_indexed("verifier", &verifier.id().unwrap()) - .field("balance", &BigIntSer(&(verifier_balance - allowance))) - .build()?, - ); + if client_resolved.id().is_ok() { + // if the client isn't resolved, we don't expect an event because the call should abort + rt.expect_emitted_event( + EventBuilder::new() + .typ("verifier-balance") + .field_indexed("verifier", &verifier.id().unwrap()) + .field("balance", &BigIntSer(&(verifier_balance - allowance))) + .field_indexed("client", &client_resolved.id().unwrap()) + .build()?, + ); + } let ret = rt.call::( Method::AddVerifiedClient as MethodNum, IpldBlock::serialize_cbor(¶ms).unwrap(), @@ -290,13 +296,25 @@ impl Harness { claim_allocs: Vec, datacap_burnt: u64, all_or_nothing: bool, - expect_claimed: Vec<(AllocationID, Allocation)>, + expect_claimed: Vec<(AllocationID, Allocation, SectorNumber)>, ) -> Result { rt.expect_validate_caller_type(vec![Type::Miner]); rt.set_caller(*MINER_ACTOR_CODE_ID, Address::new_id(provider)); - for (id, alloc) in expect_claimed.iter() { - expect_emitted(rt, "claim", id, alloc.client, alloc.provider); + for (id, alloc, sector) in expect_claimed.iter() { + expect_claim_emitted( + rt, + "claim", + *id, + alloc.client, + alloc.provider, + &alloc.data, + alloc.size.0, + *sector, + alloc.term_min, + alloc.term_max, + 0, + ) } if datacap_burnt > 0 { @@ -339,8 +357,18 @@ impl Harness { let mut expected_datacap = 0u64; for (id, alloc) in expect_removed { expected_datacap += alloc.size.0; - - expect_emitted(rt, "allocation-removed", &id, alloc.client, alloc.provider); + expect_allocation_emitted( + rt, + "allocation-removed", + id, + alloc.client, + alloc.provider, + &alloc.data, + alloc.size.0, + alloc.term_min, + alloc.term_max, + alloc.expiration, + ) } rt.expect_send_simple( DATACAP_TOKEN_ACTOR_ADDR, @@ -380,8 +408,21 @@ impl Harness { rt.expect_validate_caller_any(); for (id, claim) in expect_removed { - expect_emitted(rt, "claim-removed", &id, claim.client, claim.provider); + expect_claim_emitted( + rt, + "claim-removed", + id, + claim.client, + claim.provider, + &claim.data, + claim.size.0, + claim.sector, + claim.term_min, + claim.term_max, + claim.term_start, + ) } + let params = RemoveExpiredClaimsParams { provider, claim_ids }; let ret = rt .call::( @@ -432,12 +473,36 @@ impl Harness { let allocs_req: AllocationRequests = payload.operator_data.deserialize().unwrap(); for (alloc, id) in allocs_req.allocations.iter().zip(expected_alloc_ids.iter()) { - expect_emitted(rt, "allocation", id, payload.from, alloc.provider); + expect_allocation_emitted( + rt, + "allocation", + *id, + payload.from, + alloc.provider, + &alloc.data, + alloc.size.0, + alloc.term_min, + alloc.term_max, + alloc.expiration, + ) } for ext in allocs_req.extensions { - let claim = self.load_claim(rt, ext.provider, ext.claim).unwrap(); - expect_emitted(rt, "claim-updated", &ext.claim, claim.client, claim.provider); + let mut claim = self.load_claim(rt, ext.provider, ext.claim).unwrap(); + claim.term_max = ext.term_max; + expect_claim_emitted( + rt, + "claim-updated", + ext.claim, + claim.client, + claim.provider, + &claim.data, + claim.size.0, + claim.sector, + claim.term_min, + claim.term_max, + claim.term_start, + ) } rt.expect_validate_caller_addr(vec![DATACAP_TOKEN_ACTOR_ADDR]); @@ -497,8 +562,22 @@ impl Harness { params: &ExtendClaimTermsParams, expected: Vec<(ClaimID, Claim)>, ) -> Result { - for (id, new_claim) in expected.iter() { - expect_emitted(rt, "claim-updated", id, new_claim.client, new_claim.provider); + for (id, mut new_claim) in expected { + let ext = params.terms.iter().find(|c| c.claim_id == id).unwrap(); + new_claim.term_max = ext.term_max; + expect_claim_emitted( + rt, + "claim-updated", + id, + new_claim.client, + new_claim.provider, + &new_claim.data, + new_claim.size.0, + new_claim.sector, + new_claim.term_min, + new_claim.term_max, + new_claim.term_start, + ) } rt.expect_validate_caller_any(); @@ -515,6 +594,66 @@ impl Harness { } } +#[allow(clippy::too_many_arguments)] +pub fn expect_allocation_emitted( + rt: &MockRuntime, + typ: &str, + id: u64, + client: ActorID, + provider: ActorID, + piece_cid: &Cid, + piece_size: u64, + term_min: ChainEpoch, + term_max: ChainEpoch, + expiration: ChainEpoch, +) { + rt.expect_emitted_event( + EventBuilder::new() + .typ(typ) + .field_indexed("id", &id) + .field_indexed("client", &client) + .field_indexed("provider", &provider) + .field_indexed("piece-cid", piece_cid) + .field("piece-size", &piece_size) + .field("term-min", &term_min) + .field("term-max", &term_max) + .field("expiration", &expiration) + .build() + .unwrap(), + ); +} + +#[allow(clippy::too_many_arguments)] +pub fn expect_claim_emitted( + rt: &MockRuntime, + typ: &str, + id: u64, + client: ActorID, + provider: ActorID, + piece_cid: &Cid, + piece_size: u64, + sector: SectorNumber, + term_min: ChainEpoch, + term_max: ChainEpoch, + term_start: ChainEpoch, +) { + rt.expect_emitted_event( + EventBuilder::new() + .typ(typ) + .field_indexed("id", &id) + .field_indexed("client", &client) + .field_indexed("provider", &provider) + .field_indexed("piece-cid", piece_cid) + .field("piece-size", &piece_size) + .field("term-min", &term_min) + .field("term-max", &term_max) + .field("term-start", &term_start) + .field_indexed("sector", §or) + .build() + .unwrap(), + ); +} + pub fn make_alloc(data_id: &str, client: ActorID, provider: ActorID, size: u64) -> Allocation { Allocation { client, @@ -539,18 +678,6 @@ pub fn make_alloc_req(rt: &MockRuntime, provider: ActorID, size: u64) -> Allocat } } -pub fn expect_emitted(rt: &MockRuntime, typ: &str, id: &u64, client: ActorID, provider: ActorID) { - rt.expect_emitted_event( - EventBuilder::new() - .typ(typ) - .field_indexed("id", &id) - .field_indexed("client", &client) - .field_indexed("provider", &provider) - .build() - .unwrap(), - ); -} - pub fn make_extension_req( provider: ActorID, claim: ClaimID, diff --git a/actors/verifreg/tests/verifreg_actor_test.rs b/actors/verifreg/tests/verifreg_actor_test.rs index 3759d6a24..d50c88dbc 100644 --- a/actors/verifreg/tests/verifreg_actor_test.rs +++ b/actors/verifreg/tests/verifreg_actor_test.rs @@ -449,6 +449,7 @@ mod clients { .typ("verifier-balance") .field_indexed("verifier", &VERIFIER.id().unwrap()) .field("balance", &BigIntSer(&(allowance_verifier - allowance_client))) + .field_indexed("client", &CLIENT.id().unwrap()) .build() .unwrap(), ); @@ -680,7 +681,7 @@ mod allocs_claims { reqs, size * 2, false, - vec![(id1, alloc1.clone()), (id2, alloc2.clone())], + vec![(id1, alloc1.clone(), sector), (id2, alloc2.clone(), sector)], ) .unwrap(); @@ -700,7 +701,14 @@ mod allocs_claims { ]; reqs[1].claims[0].client = CLIENT1; let ret = h - .claim_allocations(&rt, PROVIDER1, reqs, size, false, vec![(id1, alloc1.clone())]) + .claim_allocations( + &rt, + PROVIDER1, + reqs, + size, + false, + vec![(id1, alloc1.clone(), sector)], + ) .unwrap(); assert_eq!(ret.sector_results.codes(), vec![ExitCode::OK, ExitCode::USR_NOT_FOUND]); assert_eq!(ret.sector_claims[0].claimed_space, BigInt::from(size)); @@ -726,7 +734,14 @@ mod allocs_claims { let reqs = vec![make_claim_reqs(sector, expiry, &[(id1, &alloc1), (id1, &alloc1)])]; expect_abort( ExitCode::USR_ILLEGAL_ARGUMENT, - h.claim_allocations(&rt, PROVIDER1, reqs, size, false, vec![(id1, alloc1.clone())]), + h.claim_allocations( + &rt, + PROVIDER1, + reqs, + size, + false, + vec![(id1, alloc1.clone(), sector)], + ), ); rt.reset(); @@ -736,7 +751,14 @@ mod allocs_claims { make_claim_reqs(sector, expiry, &[(id1, &alloc1)]), ]; let ret = h - .claim_allocations(&rt, PROVIDER1, reqs, size, false, vec![(id1, alloc1.clone())]) + .claim_allocations( + &rt, + PROVIDER1, + reqs, + size, + false, + vec![(id1, alloc1.clone(), sector)], + ) .unwrap(); assert_eq!(ret.sector_results.codes(), vec![ExitCode::OK, ExitCode::USR_NOT_FOUND]); assert_eq!(ret.sector_claims[0].claimed_space, BigInt::from(size)); @@ -797,7 +819,14 @@ mod allocs_claims { ]; reqs[0].claims[1].size = PaddedPieceSize(0); let ret = h - .claim_allocations(&rt, PROVIDER1, reqs, size, false, vec![(id3, alloc3.clone())]) + .claim_allocations( + &rt, + PROVIDER1, + reqs, + size, + false, + vec![(id3, alloc3.clone(), sector)], + ) .unwrap(); assert_eq!(ret.sector_results.codes(), vec![ExitCode::USR_FORBIDDEN, ExitCode::OK]); assert_eq!(ret.sector_claims[0].claimed_space, BigInt::from(size)); @@ -831,7 +860,7 @@ mod allocs_claims { reqs[0].claims[1].size = PaddedPieceSize(0); expect_abort( ExitCode::USR_ILLEGAL_ARGUMENT, - h.claim_allocations(&rt, PROVIDER1, reqs, 0, true, vec![(id3, alloc3)]), + h.claim_allocations(&rt, PROVIDER1, reqs, 0, true, vec![(id3, alloc3, sector)]), ); rt.reset(); } @@ -1567,3 +1596,71 @@ mod datacap { } } } + +// Tests to match with Go github.com/filecoin-project/go-state-types/builtin/*/verifreg +mod serialization { + use std::str::FromStr; + + use cid::Cid; + use fil_actor_verifreg::{AllocationClaim, ClaimAllocationsParams, SectorAllocationClaims}; + use fvm_ipld_encoding::ipld_block::IpldBlock; + use fvm_shared::piece::PaddedPieceSize; + + #[test] + fn claim_allocations_params() { + let test_cases = vec![ + ( + ClaimAllocationsParams { sectors: vec![], all_or_nothing: false }, + // [[],false] + "8280f4", + ), + ( + ClaimAllocationsParams { + sectors: vec![SectorAllocationClaims { + sector: 101, + expiry: 202, + claims: vec![], + }], + all_or_nothing: true, + }, + // [[[101,202,[]]],true] + "828183186518ca80f5", + ), + ( + ClaimAllocationsParams { + sectors: vec![ + SectorAllocationClaims { + sector: 101, + expiry: 202, + claims: vec![ + AllocationClaim { + client: 303, + allocation_id: 404, + data: Cid::from_str("baga6ea4seaaqa").unwrap(), + size: PaddedPieceSize(505), + }, + AllocationClaim { + client: 606, + allocation_id: 707, + data: Cid::from_str("baga6ea4seaaqc").unwrap(), + size: PaddedPieceSize(808), + }, + ], + }, + SectorAllocationClaims { sector: 303, expiry: 404, claims: vec![] }, + ], + all_or_nothing: true, + }, + // [[[101,202,[[303,404,baga6ea4seaaqa,505],[606,707,baga6ea4seaaqc,808]]],[303,404,[]]],true] + "828283186518ca828419012f190194d82a49000181e203922001001901f98419025e1902c3d82a49000181e203922001011903288319012f19019480f5", + ), + ]; + + for (params, expected_hex) in test_cases { + let encoded = IpldBlock::serialize_cbor(¶ms).unwrap().unwrap(); + assert_eq!(const_hex::encode(&encoded.data), expected_hex); + let decoded: ClaimAllocationsParams = IpldBlock::deserialize(&encoded).unwrap(); + assert_eq!(params, decoded); + } + } +} diff --git a/integration_tests/src/expects.rs b/integration_tests/src/expects.rs index 907d85b08..08fbc08c4 100644 --- a/integration_tests/src/expects.rs +++ b/integration_tests/src/expects.rs @@ -74,7 +74,7 @@ impl Expect { params: Some(params), value: Some(TokenAmount::zero()), subinvocs: Some(vec![]), - events, + events: Some(events), ..Default::default() } } @@ -103,7 +103,7 @@ impl Expect { params: Some(params), value: Some(TokenAmount::zero()), subinvocs: Some(vec![Expect::burn(STORAGE_MARKET_ACTOR_ID, None)]), - events, + events: Some(events), ..Default::default() } } @@ -167,17 +167,6 @@ impl Expect { ..Default::default() } } - pub fn power_submit_porep(from: ActorID) -> ExpectInvocation { - // Note: params are unchecked. - ExpectInvocation { - from, - to: STORAGE_POWER_ACTOR_ADDR, - method: fil_actor_power::Method::SubmitPoRepForBulkVerify as u64, - value: Some(TokenAmount::zero()), - subinvocs: Some(vec![]), - ..Default::default() - } - } pub fn power_update_claim(from: ActorID, delta: PowerPair) -> ExpectInvocation { let params = IpldBlock::serialize_cbor(&UpdateClaimedPowerParams { raw_byte_delta: delta.raw, @@ -267,7 +256,7 @@ impl Expect { .unwrap(), ), subinvocs: Some(burn_invocs), - events: claim_events, + events: Some(claim_events), ..Default::default() }]), ..Default::default() @@ -368,11 +357,17 @@ impl Expect { } } - pub fn build_verifreg_event( + #[allow(clippy::too_many_arguments)] + pub fn build_verifreg_allocation_event( typ: &str, id: u64, client: ActorID, provider: ActorID, + piece_cid: &Cid, + piece_size: u64, + term_min: ChainEpoch, + term_max: ChainEpoch, + expiration: ChainEpoch, ) -> EmittedEvent { EmittedEvent { emitter: VERIFIED_REGISTRY_ACTOR_ID, @@ -381,11 +376,47 @@ impl Expect { .field_indexed("id", &id) .field_indexed("client", &client) .field_indexed("provider", &provider) + .field_indexed("piece-cid", piece_cid) + .field("piece-size", &piece_size) + .field("term-min", &term_min) + .field("term-max", &term_max) + .field("expiration", &expiration) .build() .unwrap(), } } + #[allow(clippy::too_many_arguments)] + pub fn build_verifreg_claim_event( + typ: &str, + id: u64, + client: ActorID, + provider: ActorID, + piece_cid: &Cid, + piece_size: u64, + term_min: ChainEpoch, + term_max: ChainEpoch, + term_start: ChainEpoch, + sector: SectorNumber, + ) -> EmittedEvent { + EmittedEvent { + emitter: VERIFIED_REGISTRY_ACTOR_ID, + event: EventBuilder::new() + .typ(typ) + .field_indexed("id", &id) + .field_indexed("client", &client) + .field_indexed("provider", &provider) + .field_indexed("piece-cid", piece_cid) + .field("piece-size", &piece_size) + .field("term-min", &term_min) + .field("term-max", &term_max) + .field("term-start", &term_start) + .field_indexed("sector", §or) + .build() + .unwrap(), + } + } + #[allow(clippy::too_many_arguments)] pub fn build_market_event( typ: &str, deal_id: DealID, diff --git a/integration_tests/src/tests/batch_onboarding_deals_test.rs b/integration_tests/src/tests/batch_onboarding_deals_test.rs index 79f986125..6aa256e7e 100644 --- a/integration_tests/src/tests/batch_onboarding_deals_test.rs +++ b/integration_tests/src/tests/batch_onboarding_deals_test.rs @@ -144,7 +144,7 @@ pub fn batch_onboarding_deals_test(v: &dyn VM) { // Associate deals with sectors. let sector_precommit_data = deals .into_iter() - .map(|(id, _)| precommit_meta_data_from_deals(v, &[id], SEAL_PROOF)) + .map(|(id, _)| precommit_meta_data_from_deals(v, &[id], SEAL_PROOF, true)) .collect(); // Pre-commit as single batch. diff --git a/integration_tests/src/tests/commit_post_test.rs b/integration_tests/src/tests/commit_post_test.rs index a315b5344..95f200f29 100644 --- a/integration_tests/src/tests/commit_post_test.rs +++ b/integration_tests/src/tests/commit_post_test.rs @@ -14,15 +14,14 @@ use crate::expects::Expect; use crate::util::{ advance_by_deadline_to_epoch, advance_to_proving_deadline, assert_invariants, create_accounts, create_miner, cron_tick, expect_invariants, get_network_stats, invariant_failure_patterns, - miner_balance, precommit_sectors_v2, submit_windowed_post, + miner_balance, miner_prove_sector, precommit_sectors_v2, submit_windowed_post, }; use crate::TEST_VM_RAND_ARRAY; use fil_actor_cron::Method as CronMethod; use fil_actor_market::Method as MarketMethod; use fil_actor_miner::{ max_prove_commit_duration, power_for_sector, DeadlineInfo, Method as MinerMethod, - PoStPartition, ProveCommitAggregateParams, ProveCommitSectorParams, State as MinerState, - SubmitWindowedPoStParams, + PoStPartition, ProveCommitAggregateParams, State as MinerState, SubmitWindowedPoStParams, }; use fil_actor_power::{Method as PowerMethod, State as PowerState}; use fil_actors_runtime::runtime::Policy; @@ -52,7 +51,6 @@ fn setup(v: &dyn VM) -> (MinerInfo, SectorInfo) { let addrs = create_accounts(v, 1, &TokenAmount::from_whole(10_000)); let seal_proof = RegisteredSealProof::StackedDRG32GiBV1P1; let (owner, worker) = (addrs[0], addrs[0]); - let worker_id = worker.id().unwrap(); let (id_addr, robust_addr) = create_miner( v, &owner, @@ -64,7 +62,7 @@ fn setup(v: &dyn VM) -> (MinerInfo, SectorInfo) { // precommit and advance to prove commit time let sector_number: SectorNumber = 100; - let infos = precommit_sectors_v2( + let _ = precommit_sectors_v2( v, 1, 1, @@ -76,7 +74,6 @@ fn setup(v: &dyn VM) -> (MinerInfo, SectorInfo) { true, None, ); - let pc = &infos[0]; let balances = miner_balance(v, &id_addr); assert!(balances.pre_commit_deposit.is_positive()); @@ -84,31 +81,10 @@ fn setup(v: &dyn VM) -> (MinerInfo, SectorInfo) { let prove_time = v.epoch() + Policy::default().pre_commit_challenge_delay + 1; advance_by_deadline_to_epoch(v, &id_addr, prove_time); - let unsealed_cid = pc.info.unsealed_cid.0; // prove commit, cron, advance to post time - let prove_params = ProveCommitSectorParams { sector_number, proof: vec![].into() }; - let prove_params_ser = IpldBlock::serialize_cbor(&prove_params).unwrap(); - apply_ok( - v, - &worker, - &robust_addr, - &TokenAmount::zero(), - MinerMethod::ProveCommitSector as u64, - Some(prove_params), - ); - ExpectInvocation { - from: worker_id, - to: id_addr, - method: MinerMethod::ProveCommitSector as u64, - params: Some(prove_params_ser), - subinvocs: Some(vec![Expect::power_submit_porep(id_addr.id().unwrap())]), - ..Default::default() - } - .matches(v.take_invocations().last().unwrap()); - + miner_prove_sector(v, &worker, &id_addr, sector_number, vec![]); cron_tick(v); - let pieces: Vec<(Cid, u64)> = vec![]; ExpectInvocation { to: CRON_ACTOR_ADDR, method: CronMethod::EpochTick as u64, @@ -119,31 +95,16 @@ fn setup(v: &dyn VM) -> (MinerInfo, SectorInfo) { method: PowerMethod::OnEpochTickEnd as u64, subinvocs: Some(vec![ Expect::reward_this_epoch(STORAGE_POWER_ACTOR_ID), - ExpectInvocation { - from: STORAGE_POWER_ACTOR_ID, - to: id_addr, - method: MinerMethod::ConfirmSectorProofsValid as u64, - subinvocs: Some(vec![Expect::power_update_pledge( - id_addr.id().unwrap(), - None, - )]), - events: vec![Expect::build_sector_activation_event( - "sector-activated", - id_addr.id().unwrap(), - sector_number, - unsealed_cid, - &pieces, - )], - ..Default::default() - }, Expect::reward_update_kpi(), ]), + events: Some(vec![]), ..Default::default() }, ExpectInvocation { from: CRON_ACTOR_ID, to: STORAGE_MARKET_ACTOR_ADDR, method: MarketMethod::CronTick as u64, + events: Some(vec![]), ..Default::default() }, ]), @@ -775,7 +736,7 @@ pub fn aggregate_one_precommit_expires_test(v: &dyn VM) { Expect::power_update_pledge(miner_id, None), Expect::burn(miner_id, None), ]), - events, + events: Some(events), ..Default::default() } .matches(v.take_invocations().last().unwrap()); diff --git a/integration_tests/src/tests/extend_sectors_test.rs b/integration_tests/src/tests/extend_sectors_test.rs index 92871a9b0..1663120cf 100644 --- a/integration_tests/src/tests/extend_sectors_test.rs +++ b/integration_tests/src/tests/extend_sectors_test.rs @@ -18,6 +18,7 @@ use fil_actor_miner::{ ProveReplicaUpdatesParams, ReplicaUpdate, SectorClaim, SectorOnChainInfoFlags, Sectors, State as MinerState, }; +use fil_actors_runtime::runtime::policy_constants::MARKET_DEFAULT_ALLOCATION_TERM_BUFFER; use vm_api::trace::ExpectInvocation; use vm_api::util::{apply_ok, get_state, mutate_state, DynBlockstore}; use vm_api::VM; @@ -26,11 +27,11 @@ use crate::expects::Expect; use crate::util::{ advance_by_deadline_to_epoch, advance_by_deadline_to_epoch_while_proving, advance_by_deadline_to_index, advance_to_proving_deadline, bf_all, create_accounts, - create_miner, cron_tick, expect_invariants, invariant_failure_patterns, market_add_balance, - market_pending_deal_allocations, market_publish_deal, miner_precommit_one_sector_v2, - miner_prove_sector, override_compute_unsealed_sector_cid, precommit_meta_data_from_deals, - sector_deadline, submit_windowed_post, verifreg_add_client, verifreg_add_verifier, - PrecommitMetadata, + create_miner, cron_tick, expect_invariants, invariant_failure_patterns, + make_piece_manifests_from_deal_ids, market_add_balance, market_pending_deal_allocations, + market_publish_deal, miner_precommit_one_sector_v2, miner_prove_sector, + override_compute_unsealed_sector_cid, precommit_meta_data_from_deals, sector_deadline, + submit_windowed_post, verifreg_add_client, verifreg_add_verifier, PrecommitMetadata, }; #[allow(clippy::too_many_arguments)] @@ -165,14 +166,20 @@ pub fn extend_legacy_sector_with_deals_test(v: &dyn VM, do_extend2: bool) { &miner_id, seal_proof, sector_number, - precommit_meta_data_from_deals(v, &deals, seal_proof), + precommit_meta_data_from_deals(v, &deals, seal_proof, false), true, deal_start + 180 * EPOCHS_IN_DAY, ); // advance time to max seal duration and prove the sector advance_by_deadline_to_epoch(v, &miner_id, deal_start); - miner_prove_sector(v, &worker, &miner_id, sector_number); + miner_prove_sector( + v, + &worker, + &miner_id, + sector_number, + make_piece_manifests_from_deal_ids(v, deals), + ); // trigger cron to validate the prove commit cron_tick(v); @@ -393,14 +400,20 @@ pub fn commit_sector_with_max_duration_deal_test(v: &dyn VM) { &miner_id, seal_proof, sector_number, - precommit_meta_data_from_deals(v, &deals, seal_proof), + precommit_meta_data_from_deals(v, &deals, seal_proof, false), true, deal_start + deal_lifetime, ); // advance time to max seal duration and prove the sector advance_by_deadline_to_epoch(v, &miner_id, deal_start); - miner_prove_sector(v, &worker, &miner_id, sector_number); + miner_prove_sector( + v, + &worker, + &miner_id, + sector_number, + make_piece_manifests_from_deal_ids(v, deals), + ); // trigger cron to validate the prove commit cron_tick(v); @@ -465,7 +478,7 @@ pub fn extend_sector_up_to_max_relative_extension_test(v: &dyn VM) { // advance time to max seal duration and prove the sector advance_by_deadline_to_epoch(v, &miner_id, sector_start); - miner_prove_sector(v, &worker, &miner_id, sector_number); + miner_prove_sector(v, &worker, &miner_id, sector_number, vec![]); // trigger cron to validate the prove commit cron_tick(v); @@ -566,7 +579,7 @@ pub fn extend_updated_sector_with_claims_test(v: &dyn VM) { // advance time by a day and prove the sector let prove_epoch = v.epoch() + EPOCHS_IN_DAY; advance_by_deadline_to_epoch(v, &miner_addr, prove_epoch); - miner_prove_sector(v, &worker, &miner_addr, sector_number); + miner_prove_sector(v, &worker, &miner_addr, sector_number, vec![]); // trigger cron to validate the prove commit cron_tick(v); @@ -617,6 +630,7 @@ pub fn extend_updated_sector_with_claims_test(v: &dyn VM) { // create 1 verified deal for total sector capacity let deal_start = v.epoch() + EPOCHS_IN_DAY; + let deal_lifetime = 340 * EPOCHS_IN_DAY; let deal_ids = market_publish_deal( v, &worker, @@ -626,7 +640,7 @@ pub fn extend_updated_sector_with_claims_test(v: &dyn VM) { piece_size, true, deal_start, - 340 * EPOCHS_IN_DAY, + deal_lifetime, ) .ids; @@ -663,6 +677,10 @@ pub fn extend_updated_sector_with_claims_test(v: &dyn VM) { let pis: Vec = vec![PieceInfo { cid: piece_cid, size: piece_size }]; let unsealed_cid = v.primitives().compute_unsealed_sector_cid(seal_proof, &pis).unwrap(); + let start_epoch = deal_start; + let end_epoch = deal_start + deal_lifetime; + let claim_term = end_epoch - start_epoch; + // check for the expected subcalls ExpectInvocation { from: worker_id, @@ -682,12 +700,18 @@ pub fn extend_updated_sector_with_claims_test(v: &dyn VM) { from: miner_id, to: VERIFIED_REGISTRY_ACTOR_ADDR, method: VerifregMethod::ClaimAllocations as u64, - events: vec![Expect::build_verifreg_event( + events: Some(vec![Expect::build_verifreg_claim_event( "claim", claim_id, verified_client.id().unwrap(), miner_id, - )], + &piece_cid, + piece_size.0, + claim_term, + claim_term + MARKET_DEFAULT_ALLOCATION_TERM_BUFFER, + v.epoch(), + sector_number, + )]), ..Default::default() }, Expect::reward_this_epoch(miner_id), @@ -698,13 +722,13 @@ pub fn extend_updated_sector_with_claims_test(v: &dyn VM) { PowerPair { raw: StoragePower::zero(), qa: 9 * old_power.qa }, ), ]), - events: vec![Expect::build_sector_activation_event( + events: Some(vec![Expect::build_sector_activation_event( "sector-updated", miner_id, sector_number, Some(unsealed_cid), &pieces, - )], + )]), ..Default::default() } .matches(v.take_invocations().last().unwrap()); diff --git a/integration_tests/src/tests/prove_commit3_test.rs b/integration_tests/src/tests/prove_commit3_test.rs index ab94e0b89..94746eed9 100644 --- a/integration_tests/src/tests/prove_commit3_test.rs +++ b/integration_tests/src/tests/prove_commit3_test.rs @@ -239,6 +239,45 @@ pub fn prove_commit_sectors2_test(v: &dyn VM) { }) .collect(); + let claim_event_1 = Expect::build_verifreg_claim_event( + "claim", + alloc_ids_s2[0], + client_id, + miner_id, + &allocs[0].data, + allocs[0].size.0, + claim_term_min, + claim_term_max, + v.epoch(), + first_sector_number + 2, + ); + + let claim_event_2 = Expect::build_verifreg_claim_event( + "claim", + alloc_ids_s2[1], + client_id, + miner_id, + &allocs[1].data, + allocs[1].size.0, + claim_term_min, + claim_term_max, + v.epoch(), + first_sector_number + 2, + ); + + let claim_event_3 = Expect::build_verifreg_claim_event( + "claim", + alloc_ids_s4[0], + client_id, + miner_id, + &manifests[4].pieces[0].cid, + manifests[4].pieces[0].size.0, + claim_term_min, + claim_term_max, + v.epoch(), + first_sector_number + 4, + ); + ExpectInvocation { from: worker_id, to: maddr, @@ -289,11 +328,7 @@ pub fn prove_commit_sectors2_test(v: &dyn VM) { }) .unwrap(), ), - events: vec![ - Expect::build_verifreg_event("claim", alloc_ids_s2[0], client_id, miner_id), - Expect::build_verifreg_event("claim", alloc_ids_s2[1], client_id, miner_id), - Expect::build_verifreg_event("claim", alloc_ids_s4[0], client_id, miner_id), - ], + events: Some(vec![claim_event_1, claim_event_2, claim_event_3]), ..Default::default() }, Expect::reward_this_epoch(miner_id), @@ -323,17 +358,24 @@ pub fn prove_commit_sectors2_test(v: &dyn VM) { ), value: Some(TokenAmount::zero()), subinvocs: Some(vec![]), - events: deal_ids_s3 - .iter() - .chain(deal_ids_s4.iter()) - .map(|deal_id| { - Expect::build_market_event("deal-activated", *deal_id, client_id, miner_id) - }) - .collect::>(), + events: Some( + deal_ids_s3 + .iter() + .chain(deal_ids_s4.iter()) + .map(|deal_id| { + Expect::build_market_event( + "deal-activated", + *deal_id, + client_id, + miner_id, + ) + }) + .collect::>(), + ), ..Default::default() }, ]), - events, + events: Some(events), ..Default::default() } .matches(v.take_invocations().last().unwrap()); diff --git a/integration_tests/src/tests/replica_update3_test.rs b/integration_tests/src/tests/replica_update3_test.rs index de31f6e2a..fe7936dec 100644 --- a/integration_tests/src/tests/replica_update3_test.rs +++ b/integration_tests/src/tests/replica_update3_test.rs @@ -250,6 +250,43 @@ pub fn prove_replica_update2_test(v: &dyn VM) { }, ]; + let claim_event_1 = Expect::build_verifreg_claim_event( + "claim", + alloc_ids_s2[0], + client_id, + miner_id, + &allocs[0].data, + allocs[0].size.0, + claim_term_min, + claim_term_max, + v.epoch(), + first_sector_number + 2, + ); + let claim_event_2 = Expect::build_verifreg_claim_event( + "claim", + alloc_ids_s2[1], + client_id, + miner_id, + &allocs[1].data, + allocs[1].size.0, + claim_term_min, + claim_term_max, + v.epoch(), + first_sector_number + 2, + ); + let claim_event_3 = Expect::build_verifreg_claim_event( + "claim", + alloc_ids_s4[0], + client_id, + miner_id, + &manifests[4].pieces[0].cid, + manifests[4].pieces[0].size.0, + claim_term_min, + claim_term_max, + v.epoch(), + first_sector_number + 4, + ); + // Replica update let update_proof = seal_proof.registered_update_proof().unwrap(); let proofs = vec![RawBytes::new(vec![1, 2, 3, 4]); manifests.len()]; @@ -352,11 +389,7 @@ pub fn prove_replica_update2_test(v: &dyn VM) { }) .unwrap(), ), - events: vec![ - Expect::build_verifreg_event("claim", alloc_ids_s2[0], client_id, miner_id), - Expect::build_verifreg_event("claim", alloc_ids_s2[1], client_id, miner_id), - Expect::build_verifreg_event("claim", alloc_ids_s4[0], client_id, miner_id), - ], + events: Some(vec![claim_event_1, claim_event_2, claim_event_3]), ..Default::default() }, Expect::reward_this_epoch(miner_id), @@ -387,18 +420,25 @@ pub fn prove_replica_update2_test(v: &dyn VM) { ), value: Some(TokenAmount::zero()), subinvocs: Some(vec![]), - events: deal_ids_s3 - .iter() - .chain(deal_ids_s4.iter()) - .map(|deal_id| { - Expect::build_market_event("deal-activated", *deal_id, client_id, miner_id) - }) - .collect::>(), + events: Some( + deal_ids_s3 + .iter() + .chain(deal_ids_s4.iter()) + .map(|deal_id| { + Expect::build_market_event( + "deal-activated", + *deal_id, + client_id, + miner_id, + ) + }) + .collect::>(), + ), ..Default::default() }, ]), - events, + events: Some(events), ..Default::default() } .matches(v.take_invocations().last().unwrap()); diff --git a/integration_tests/src/tests/replica_update_test.rs b/integration_tests/src/tests/replica_update_test.rs index 000430091..09ed7afdb 100644 --- a/integration_tests/src/tests/replica_update_test.rs +++ b/integration_tests/src/tests/replica_update_test.rs @@ -16,11 +16,12 @@ use fil_actor_market::Method as MarketMethod; use fil_actor_market::State as MarketState; use fil_actor_miner::{ power_for_sector, DisputeWindowedPoStParams, ExpirationExtension, ExtendSectorExpirationParams, - Method as MinerMethod, PowerPair, ProveCommitSectorParams, ProveReplicaUpdatesParams, - ReplicaUpdate, SectorOnChainInfo, SectorOnChainInfoFlags, Sectors, State as MinerState, - TerminateSectorsParams, TerminationDeclaration, SECTORS_AMT_BITWIDTH, + Method as MinerMethod, PowerPair, ProveReplicaUpdatesParams, ReplicaUpdate, SectorOnChainInfo, + SectorOnChainInfoFlags, Sectors, State as MinerState, TerminateSectorsParams, + TerminationDeclaration, SECTORS_AMT_BITWIDTH, }; use fil_actor_verifreg::Method as VerifregMethod; +use fil_actors_runtime::runtime::policy_constants::MARKET_DEFAULT_ALLOCATION_TERM_BUFFER; use fil_actors_runtime::runtime::Policy; use fil_actors_runtime::test_utils::make_sealed_cid; use fil_actors_runtime::VERIFIED_REGISTRY_ACTOR_ADDR; @@ -36,9 +37,9 @@ use crate::util::{ assert_invariants, bf_all, check_sector_active, check_sector_faulty, create_accounts, create_miner, cron_tick, deadline_state, declare_recovery, expect_invariants, get_deal_weights, get_network_stats, invariant_failure_patterns, make_bitfield, market_publish_deal, - miner_balance, miner_power, override_compute_unsealed_sector_cid, precommit_sectors_v2, - prove_commit_sectors, sector_info, submit_invalid_post, submit_windowed_post, - verifreg_add_client, verifreg_add_verifier, + miner_balance, miner_power, miner_prove_sector, override_compute_unsealed_sector_cid, + precommit_sectors_v2, prove_commit_sectors, sector_info, submit_invalid_post, + submit_windowed_post, verifreg_add_client, verifreg_add_verifier, }; #[vm_test] @@ -1032,8 +1033,20 @@ pub fn replica_update_verified_deal_test(v: &dyn VM) { assert_eq!(vec![100], bf_all(updated_sectors)); let claim_id = 1_u64; - let claim_event = - Expect::build_verifreg_event("claim", claim_id, client.id().unwrap(), maddr.id().unwrap()); + let deal_term = proposal.end_epoch - proposal.start_epoch; + let term_max = deal_term + MARKET_DEFAULT_ALLOCATION_TERM_BUFFER; + let claim_event = Expect::build_verifreg_claim_event( + "claim", + claim_id, + client.id().unwrap(), + maddr.id().unwrap(), + &proposal.piece_cid, + proposal.piece_size.0, + deal_term, + term_max, + v.epoch(), + sector_number, + ); let old_power = power_for_sector(seal_proof.sector_size().unwrap(), &old_sector_info); let pieces: Vec<(Cid, u64)> = vec![(proposal.piece_cid, proposal.piece_size.0)]; @@ -1060,7 +1073,7 @@ pub fn replica_update_verified_deal_test(v: &dyn VM) { from: miner_id, to: VERIFIED_REGISTRY_ACTOR_ADDR, method: VerifregMethod::ClaimAllocations as u64, - events: vec![claim_event], + events: Some(vec![claim_event]), ..Default::default() }, Expect::reward_this_epoch(miner_id), @@ -1072,13 +1085,13 @@ pub fn replica_update_verified_deal_test(v: &dyn VM) { PowerPair { raw: StoragePower::zero(), qa: 9 * old_power.qa }, ), ]), - events: vec![Expect::build_sector_activation_event( + events: Some(vec![Expect::build_sector_activation_event( "sector-updated", miner_id, sector_number, Some(unsealed_cid), &pieces, - )], + )]), ..Default::default() } .matches(v.take_invocations().last().unwrap()); @@ -1187,15 +1200,7 @@ pub fn create_sector( // prove commit let prove_time = v.epoch() + Policy::default().pre_commit_challenge_delay + 1; advance_by_deadline_to_epoch(v, &maddr, prove_time); - let prove_commit_params = ProveCommitSectorParams { sector_number, proof: vec![].into() }; - apply_ok( - v, - &worker, - &maddr, - &TokenAmount::zero(), - MinerMethod::ProveCommitSector as u64, - Some(prove_commit_params), - ); + miner_prove_sector(v, &worker, &maddr, sector_number, vec![]); cron_tick(v); diff --git a/integration_tests/src/tests/terminate_test.rs b/integration_tests/src/tests/terminate_test.rs index f4eb9e086..caf6e7668 100644 --- a/integration_tests/src/tests/terminate_test.rs +++ b/integration_tests/src/tests/terminate_test.rs @@ -11,8 +11,8 @@ use fil_actor_market::{ DealMetaArray, Method as MarketMethod, State as MarketState, WithdrawBalanceParams, }; use fil_actor_miner::{ - power_for_sector, Method as MinerMethod, ProveCommitSectorParams, State as MinerState, - TerminateSectorsParams, TerminationDeclaration, + power_for_sector, Method as MinerMethod, State as MinerState, TerminateSectorsParams, + TerminationDeclaration, }; use fil_actor_power::State as PowerState; use fil_actor_verifreg::{Method as VerifregMethod, VerifierParams}; @@ -32,9 +32,9 @@ use crate::expects::Expect; use crate::util::{ advance_by_deadline_to_epoch, advance_by_deadline_to_epoch_while_proving, advance_to_proving_deadline, assert_invariants, create_accounts, create_miner, cron_tick, - deal_cid_for_testing, make_bitfield, market_publish_deal, miner_balance, - miner_precommit_one_sector_v2, precommit_meta_data_from_deals, submit_windowed_post, - verifreg_add_verifier, + deal_cid_for_testing, make_bitfield, make_piece_manifests_from_deal_ids, market_publish_deal, + miner_balance, miner_precommit_one_sector_v2, miner_prove_sector, + precommit_meta_data_from_deals, submit_windowed_post, verifreg_add_verifier, }; #[vm_test] @@ -167,26 +167,20 @@ pub fn terminate_sectors_test(v: &dyn VM) { &miner_robust_addr, seal_proof, sector_number, - precommit_meta_data_from_deals(v, &deal_ids, seal_proof), + precommit_meta_data_from_deals(v, &deal_ids, seal_proof, false), true, v.epoch() + 220 * EPOCHS_IN_DAY, ); let prove_time = v.epoch() + Policy::default().pre_commit_challenge_delay + 1; advance_by_deadline_to_epoch(v, &miner_id_addr, prove_time); - - // prove commit, cron, advance to post time - let prove_params = ProveCommitSectorParams { sector_number, proof: vec![].into() }; - apply_ok( + miner_prove_sector( v, &worker, - &miner_robust_addr, - &TokenAmount::zero(), - MinerMethod::ProveCommitSector as u64, - Some(prove_params), + &miner_id_addr, + sector_number, + make_piece_manifests_from_deal_ids(v, deal_ids.clone()), ); - cron_tick(v); - let (dline_info, p_idx) = advance_to_proving_deadline(v, &miner_id_addr, sector_number); let d_idx = dline_info.index; let st: MinerState = get_state(v, &miner_id_addr).unwrap(); @@ -259,7 +253,7 @@ pub fn terminate_sectors_test(v: &dyn VM) { ), Expect::power_update_claim(miner_id, sector_power.neg()), ]), - events: vec![expect_event], + events: Some(vec![expect_event]), ..Default::default() } .matches(v.take_invocations().last().unwrap()); diff --git a/integration_tests/src/tests/verified_claim_test.rs b/integration_tests/src/tests/verified_claim_test.rs index e72ed2662..256c32341 100644 --- a/integration_tests/src/tests/verified_claim_test.rs +++ b/integration_tests/src/tests/verified_claim_test.rs @@ -1,8 +1,10 @@ use std::ops::Neg; use export_macro::vm_test; +use fvm_ipld_encoding::RawBytes; use fvm_shared::bigint::Zero; use fvm_shared::econ::TokenAmount; +use fvm_shared::error::ExitCode; use fvm_shared::piece::PaddedPieceSize; use fvm_shared::sector::{RegisteredSealProof, SectorNumber, StoragePower}; @@ -11,7 +13,10 @@ use fil_actor_market::{DealArray, DealMetaArray, DealSettlementSummary}; use fil_actor_market::{ PendingDealAllocationsMap, State as MarketState, PENDING_ALLOCATIONS_CONFIG, }; -use fil_actor_miner::{max_prove_commit_duration, PowerPair, SectorClaim, State as MinerState}; +use fil_actor_miner::{ + max_prove_commit_duration, PowerPair, ProveCommitSectors3Params, SectorActivationManifest, + SectorClaim, State as MinerState, +}; use fil_actor_power::State as PowerState; use fil_actor_verifreg::{ Claim, Method as VerifregMethod, RemoveExpiredClaimsParams, RemoveExpiredClaimsReturn, @@ -27,18 +32,19 @@ use fil_actors_runtime::{ DealWeight, DATACAP_TOKEN_ACTOR_ADDR, EPOCHS_IN_DAY, STORAGE_MARKET_ACTOR_ADDR, STORAGE_POWER_ACTOR_ADDR, VERIFIED_REGISTRY_ACTOR_ADDR, }; -use vm_api::util::{apply_ok, get_state, DynBlockstore}; +use vm_api::trace::ExpectInvocation; +use vm_api::util::{apply_code, apply_ok, get_state, DynBlockstore}; use vm_api::VM; use crate::util::{ advance_by_deadline_to_epoch, advance_by_deadline_to_epoch_while_proving, advance_by_deadline_to_index, advance_to_proving_deadline, assert_invariants, create_accounts, create_miner, cron_tick, datacap_extend_claim, datacap_get_balance, expect_invariants, - invariant_failure_patterns, market_add_balance, market_pending_deal_allocations, - market_publish_deal, miner_extend_sector_expiration2, miner_precommit_one_sector_v2, - miner_prove_sector, precommit_meta_data_from_deals, provider_settle_deal_payments, - sector_deadline, submit_windowed_post, verifreg_add_client, verifreg_add_verifier, - verifreg_extend_claim_terms, verifreg_remove_expired_allocations, + invariant_failure_patterns, make_piece_manifests_from_deal_ids, market_add_balance, + market_pending_deal_allocations, market_publish_deal, miner_extend_sector_expiration2, + miner_precommit_one_sector_v2, miner_prove_sector, precommit_meta_data_from_deals, + provider_settle_deal_payments, sector_deadline, submit_windowed_post, verifreg_add_client, + verifreg_add_verifier, verifreg_extend_claim_terms, verifreg_remove_expired_allocations, }; /// Tests a scenario involving a verified deal from the built-in market, with associated @@ -102,14 +108,20 @@ pub fn verified_claim_scenario_test(v: &dyn VM) { &miner_id, seal_proof, sector_number, - precommit_meta_data_from_deals(v, &deals, seal_proof), + precommit_meta_data_from_deals(v, &deals, seal_proof, false), true, deal_start + sector_term, ); // Advance time to max seal duration and prove the sector advance_by_deadline_to_epoch(v, &miner_id, deal_start); - miner_prove_sector(v, &worker, &miner_id, sector_number); + miner_prove_sector( + v, + &worker, + &miner_id, + sector_number, + make_piece_manifests_from_deal_ids(v, deals.clone()), + ); // Trigger cron to validate the prove commit cron_tick(v); @@ -246,15 +258,7 @@ pub fn verified_claim_scenario_test(v: &dyn VM) { let new_max_term = new_claim_expiry_epoch - claim.term_start; assert!(new_max_term > original_max_term); - datacap_extend_claim( - v, - &verified_client2, - &miner_id, - claim_id, - deal_size, - new_max_term, - verified_client.id().unwrap(), - ); + datacap_extend_claim(v, &verified_client2, &miner_id, claim_id, deal_size, new_max_term); // The miner extends the sector into the second year. let extended_expiration_2 = extended_expiration_1 + 60 * EPOCHS_IN_DAY; @@ -562,7 +566,7 @@ pub fn deal_passes_claim_fails_test(v: &dyn VM) { &miner_id, seal_proof, sector_number_a, - precommit_meta_data_from_deals(v, &[deal], seal_proof), + precommit_meta_data_from_deals(v, &[deal], seal_proof, false), true, sector_start + sector_term, ); @@ -573,15 +577,50 @@ pub fn deal_passes_claim_fails_test(v: &dyn VM) { &miner_id, seal_proof, sector_number_b, - precommit_meta_data_from_deals(v, &[bad_deal], seal_proof), + precommit_meta_data_from_deals(v, &[bad_deal], seal_proof, false), false, sector_start + sector_term, ); // Advance time and prove the sector advance_by_deadline_to_epoch(v, &miner_id, sector_start); - miner_prove_sector(v, &worker, &miner_id, sector_number_a); - miner_prove_sector(v, &worker, &miner_id, sector_number_b); + // ProveCommit3 fails on sector b because allocation is expired + let failing_prove_commit_params = ProveCommitSectors3Params { + sector_activations: vec![ + SectorActivationManifest { + sector_number: sector_number_b, + pieces: make_piece_manifests_from_deal_ids(v, vec![bad_deal]), + }, + SectorActivationManifest { + sector_number: sector_number_a, + pieces: make_piece_manifests_from_deal_ids(v, vec![deal]), + }, + ], + sector_proofs: vec![vec![].into(), vec![].into()], + aggregate_proof: RawBytes::default(), + aggregate_proof_type: None, + require_activation_success: true, // + require_notification_success: true, + }; + apply_code( + v, + &worker, + &miner_id, + &TokenAmount::zero(), + fil_actor_miner::Method::ProveCommitSectors3 as u64, + Some(failing_prove_commit_params), + ExitCode::USR_ILLEGAL_ARGUMENT, + ); + let worker_id = v.resolve_id_address(&worker).unwrap().id().unwrap(); + ExpectInvocation { + from: worker_id, + to: miner_id, + method: fil_actor_miner::Method::ProveCommitSectors3 as u64, + exit_code: ExitCode::USR_ILLEGAL_ARGUMENT, + ..Default::default() + } + .matches(v.take_invocations().last().unwrap()); + cron_tick(v); v.set_epoch(v.epoch() + 1); diff --git a/integration_tests/src/tests/verifreg_remove_datacap_test.rs b/integration_tests/src/tests/verifreg_remove_datacap_test.rs index 599d8d4d6..a9b0ce730 100644 --- a/integration_tests/src/tests/verifreg_remove_datacap_test.rs +++ b/integration_tests/src/tests/verifreg_remove_datacap_test.rs @@ -32,7 +32,7 @@ use vm_api::VM; use crate::expects::Expect; use crate::util::{ - assert_invariants, create_accounts, verifier_balance_event, verifreg_add_verifier, + assert_invariants, create_accounts, verifier_balance_event_with_client, verifreg_add_verifier, }; use crate::{TEST_VERIFREG_ROOT_ADDR, TEST_VERIFREG_ROOT_ID}; @@ -84,7 +84,11 @@ pub fn remove_datacap_simple_successful_path_test(v: &dyn VM) { subinvocs: None, ..Default::default() }]), - events: vec![verifier_balance_event(verifier1.id().unwrap(), verifier_datacap)], + events: Some(vec![verifier_balance_event_with_client( + verifier1.id().unwrap(), + verifier_datacap, + verified_client.id().unwrap(), + )]), ..Default::default() } .matches(v.take_invocations().last().unwrap()); diff --git a/integration_tests/src/util/mod.rs b/integration_tests/src/util/mod.rs index 5f0ecc1d5..487c48544 100644 --- a/integration_tests/src/util/mod.rs +++ b/integration_tests/src/util/mod.rs @@ -12,6 +12,7 @@ use fil_actor_reward::State as RewardState; use fil_actor_verifreg::{Claim, ClaimID, State as VerifregState}; use fil_actors_runtime::cbor::serialize; use fil_actors_runtime::test_utils::make_piece_cid; +use fil_actors_runtime::ActorError; use fil_actors_runtime::{ parse_uint_key, runtime::Policy, MessageAccumulator, REWARD_ACTOR_ADDR, STORAGE_MARKET_ACTOR_ADDR, STORAGE_POWER_ACTOR_ADDR, VERIFIED_REGISTRY_ACTOR_ADDR, @@ -168,7 +169,20 @@ pub fn get_beneficiary(v: &dyn VM, from: &Address, m_addr: &Address) -> GetBenef .unwrap() } +pub fn market_pending_deal_allocations_raw( + v: &dyn VM, + deals: &[DealID], +) -> Result, ActorError> { + let mut st: MarketState = get_state(v, &STORAGE_MARKET_ACTOR_ADDR).unwrap(); + let bs = &DynBlockstore::wrap(v.blockstore()); + st.get_pending_deal_allocation_ids(bs, deals) +} + pub fn market_pending_deal_allocations(v: &dyn VM, deals: &[DealID]) -> Vec { + market_pending_deal_allocations_raw(v, deals).unwrap() +} + +pub fn market_maybe_pending_deal_allocations(v: &dyn VM, deals: &[DealID]) -> Vec { let mut st: MarketState = get_state(v, &STORAGE_MARKET_ACTOR_ADDR).unwrap(); let bs = &DynBlockstore::wrap(v.blockstore()); st.get_pending_deal_allocation_ids(bs, deals).unwrap() diff --git a/integration_tests/src/util/workflows.rs b/integration_tests/src/util/workflows.rs index 19ac93596..2ff417c3c 100644 --- a/integration_tests/src/util/workflows.rs +++ b/integration_tests/src/util/workflows.rs @@ -39,19 +39,20 @@ use fil_actor_market::{ }; use fil_actor_miner::{ aggregate_pre_commit_network_fee, aggregate_prove_commit_network_fee, - max_prove_commit_duration, ChangeBeneficiaryParams, CompactCommD, DeadlineInfo, - DeclareFaultsRecoveredParams, ExpirationExtension2, ExtendSectorExpiration2Params, - Method as MinerMethod, PoStPartition, PowerPair, PreCommitSectorBatchParams2, - ProveCommitAggregateParams, ProveCommitSectorParams, RecoveryDeclaration, SectorClaim, - SectorPreCommitInfo, SectorPreCommitOnChainInfo, State as MinerState, SubmitWindowedPoStParams, - WithdrawBalanceParams, WithdrawBalanceReturn, + max_prove_commit_duration, ChangeBeneficiaryParams, CompactCommD, DataActivationNotification, + DeadlineInfo, DeclareFaultsRecoveredParams, ExpirationExtension2, + ExtendSectorExpiration2Params, Method as MinerMethod, PieceActivationManifest, PoStPartition, + PowerPair, PreCommitSectorBatchParams2, ProveCommitAggregateParams, ProveCommitSectors3Params, + RecoveryDeclaration, SectorActivationManifest, SectorClaim, SectorPreCommitInfo, + SectorPreCommitOnChainInfo, State as MinerState, SubmitWindowedPoStParams, + VerifiedAllocationKey, WithdrawBalanceParams, WithdrawBalanceReturn, }; use fil_actor_multisig::Method as MultisigMethod; use fil_actor_multisig::ProposeParams; use fil_actor_power::{CreateMinerParams, CreateMinerReturn, Method as PowerMethod}; use fil_actor_verifreg::ext::datacap::MintParams; -use fil_actor_verifreg::AllocationRequests; use fil_actor_verifreg::ClaimExtensionRequest; +use fil_actor_verifreg::{state, AllocationRequests}; use fil_actor_verifreg::{ AddVerifiedClientParams, AllocationID, ClaimID, ClaimTerm, ExtendClaimTermsParams, Method as VerifregMethod, RemoveExpiredAllocationsParams, State as VerifregState, @@ -86,6 +87,7 @@ use crate::expects::Expect; use crate::*; use super::make_bitfield; +use super::market_pending_deal_allocations_raw; use super::miner_dline_info; use super::sector_deadline; @@ -165,14 +167,22 @@ pub fn miner_prove_sector( worker: &Address, miner_id: &Address, sector_number: SectorNumber, + manifests: Vec, ) { - let prove_commit_params = ProveCommitSectorParams { sector_number, proof: vec![].into() }; + let prove_commit_params = ProveCommitSectors3Params { + sector_activations: vec![SectorActivationManifest { sector_number, pieces: manifests }], + sector_proofs: vec![vec![].into()], + aggregate_proof: RawBytes::default(), + aggregate_proof_type: None, + require_activation_success: true, + require_notification_success: true, + }; apply_ok( v, worker, miner_id, &TokenAmount::zero(), - MinerMethod::ProveCommitSector as u64, + MinerMethod::ProveCommitSectors3 as u64, Some(prove_commit_params), ); @@ -181,13 +191,7 @@ pub fn miner_prove_sector( ExpectInvocation { from: worker_id, to: *miner_id, - method: MinerMethod::ProveCommitSector as u64, - subinvocs: Some(vec![ExpectInvocation { - from: miner_id.id().unwrap(), - to: STORAGE_POWER_ACTOR_ADDR, - method: PowerMethod::SubmitPoRepForBulkVerify as u64, - ..Default::default() - }]), + method: MinerMethod::ProveCommitSectors3 as u64, ..Default::default() } .matches(v.take_invocations().last().unwrap()); @@ -297,7 +301,7 @@ pub fn precommit_sectors_v2_expect_code( .unwrap(), ), subinvocs: Some(invocs), - events, + events: Some(events), ..Default::default() }; expect.matches(v.take_invocations().last().unwrap()); @@ -352,6 +356,7 @@ pub fn precommit_meta_data_from_deals( v: &dyn VM, deal_ids: &[u64], seal_proof: RegisteredSealProof, + include_ids: bool, ) -> PrecommitMetadata { let state: MarketState = get_state(v, &STORAGE_MARKET_ACTOR_ADDR).unwrap(); let pieces: Vec = deal_ids @@ -362,8 +367,9 @@ pub fn precommit_meta_data_from_deals( }) .collect(); + let ids = if include_ids { deal_ids.to_vec() } else { vec![] }; PrecommitMetadata { - deals: deal_ids.to_vec(), + deals: ids, commd: CompactCommD::of( v.primitives().compute_unsealed_sector_cid(seal_proof, &pieces).unwrap(), ), @@ -437,7 +443,7 @@ pub fn prove_commit_sectors( Expect::power_update_pledge(miner_id, None), Expect::burn(miner_id, Some(expected_fee)), ]), - events, + events: Some(events), ..Default::default() } .matches(v.take_invocations().last().unwrap()); @@ -771,6 +777,23 @@ pub fn verifier_balance_event(verifier: ActorID, data_cap: DataCap) -> EmittedEv } } +pub fn verifier_balance_event_with_client( + verifier: ActorID, + data_cap: DataCap, + client: ActorID, +) -> EmittedEvent { + EmittedEvent { + emitter: VERIFIED_REGISTRY_ACTOR_ID, + event: EventBuilder::new() + .typ("verifier-balance") + .field_indexed("verifier", &verifier) + .field("balance", &BigIntSer(&data_cap)) + .field_indexed("client", &client) + .build() + .unwrap(), + } +} + pub fn verifreg_add_verifier(v: &dyn VM, verifier: &Address, data_cap: StoragePower) { let add_verifier_params = VerifierParams { address: *verifier, allowance: data_cap.clone() }; // root address is msig, send proposal from root key @@ -803,7 +826,7 @@ pub fn verifreg_add_verifier(v: &dyn VM, verifier: &Address, data_cap: StoragePo DATACAP_TOKEN_ACTOR_ADDR, *verifier, )]), - events: vec![verifier_balance_event(verifier.id().unwrap(), data_cap)], + events: Some(vec![verifier_balance_event(verifier.id().unwrap(), data_cap)]), ..Default::default() }]), ..Default::default() @@ -863,7 +886,11 @@ pub fn verifreg_add_client( )]), ..Default::default() }]), - events: vec![verifier_balance_event(verifier.id().unwrap(), updated_verifier_balance)], + events: Some(vec![verifier_balance_event_with_client( + verifier.id().unwrap(), + updated_verifier_balance, + client.id().unwrap(), + )]), ..Default::default() } .matches(v.take_invocations().last().unwrap()); @@ -908,11 +935,16 @@ pub fn verifreg_remove_expired_allocations( .iter() .map(|id| { let alloc = allocs.get(client.id().unwrap(), *id).unwrap().unwrap(); - Expect::build_verifreg_event( + Expect::build_verifreg_allocation_event( "allocation-removed", *id, client.id().unwrap(), alloc.provider, + &alloc.data, + alloc.size.0, + alloc.term_min, + alloc.term_max, + alloc.expiration, ) }) .collect(); @@ -955,7 +987,7 @@ pub fn verifreg_remove_expired_allocations( )]), ..Default::default() }]), - events: expected_events, + events: Some(expected_events), ..Default::default() } .matches(v.take_invocations().last().unwrap()); @@ -1005,7 +1037,17 @@ pub fn datacap_create_allocations( .iter() .enumerate() .map(|(i, alloc_id)| { - Expect::build_verifreg_event("allocation", *alloc_id, client_id, reqs[i].provider) + Expect::build_verifreg_allocation_event( + "allocation", + *alloc_id, + client.id().unwrap(), + reqs[i].provider, + &reqs[i].data, + reqs[i].size.0, + reqs[i].term_min, + reqs[i].term_max, + reqs[i].expiration, + ) }) .collect::>(); @@ -1028,8 +1070,15 @@ pub fn datacap_extend_claim( claim: ClaimID, size: u64, new_term: ChainEpoch, - claim_client: ActorID, ) { + // read existing claim with claim id from VerifReg state + let v_st: fil_actor_verifreg::State = get_state(v, &VERIFIED_REGISTRY_ACTOR_ADDR).unwrap(); + let store = DynBlockstore::wrap(v.blockstore()); + let mut claims = v_st.load_claims(&store).unwrap(); + let mut existing_claim = + state::get_claim(&mut claims, provider.id().unwrap(), claim).unwrap().unwrap().clone(); + existing_claim.term_max = new_term; + let payload = AllocationRequests { allocations: vec![], extensions: vec![ClaimExtensionRequest { @@ -1056,17 +1105,25 @@ pub fn datacap_extend_claim( ); let client_id = v.resolve_id_address(client).unwrap().id().unwrap(); + let claim_updated_event = Expect::build_verifreg_claim_event( + "claim-updated", + claim, + existing_claim.client, + provider.id().unwrap(), + &existing_claim.data, + existing_claim.size.0, + existing_claim.term_min, + existing_claim.term_max, + existing_claim.term_start, + existing_claim.sector, + ); + Expect::datacap_transfer_to_verifreg( client_id, token_amount, operator_data, true, // Burn - vec![Expect::build_verifreg_event( - "claim-updated", - claim, - claim_client, - provider.id().unwrap(), - )], + vec![claim_updated_event], ) .matches(v.take_invocations().last().unwrap()); } @@ -1181,6 +1238,18 @@ pub fn market_publish_deal( let v_st: fil_actor_verifreg::State = get_state(v, &VERIFIED_REGISTRY_ACTOR_ADDR).unwrap(); let alloc_id = v_st.next_allocation_id - 1; + let alloc_req = alloc_reqs.allocations[0].clone(); + let alloc_event = Expect::build_verifreg_allocation_event( + "allocation", + alloc_id, + deal_client.id().unwrap(), + miner_id.id().unwrap(), + &proposal.piece_cid, + proposal.piece_size.0, + alloc_req.term_min, + alloc_req.term_max, + alloc_req.expiration, + ); expect_publish_invocs.push(ExpectInvocation { from: STORAGE_MARKET_ACTOR_ID, @@ -1217,12 +1286,7 @@ pub fn market_publish_deal( }) .unwrap(), ), - events: vec![Expect::build_verifreg_event( - "allocation", - alloc_id, - deal_client.id().unwrap(), - miner_id.id().unwrap(), - )], + events: Some(vec![alloc_event]), ..Default::default() }]), ..Default::default() @@ -1239,12 +1303,12 @@ pub fn market_publish_deal( to: STORAGE_MARKET_ACTOR_ADDR, method: MarketMethod::PublishStorageDeals as u64, subinvocs: Some(expect_publish_invocs), - events: vec![Expect::build_market_event( + events: Some(vec![Expect::build_market_event( "deal-published", ret.ids[0], deal_client.id().unwrap(), miner_id.id().unwrap(), - )], + )]), ..Default::default() } .matches(v.take_invocations().last().unwrap()); @@ -1298,3 +1362,31 @@ pub fn get_deal_weights( } (DealWeight::from(deal.piece_size.0 * duration as u64), DealWeight::zero()) } + +pub fn make_piece_manifests_from_deal_ids( + v: &dyn VM, + deal_ids: Vec, +) -> Vec { + let mut piece_manifests = vec![]; + for deal_id in deal_ids { + let deal = get_deal(v, deal_id); + let alloc_key = match market_pending_deal_allocations_raw(v, &[deal_id]) { + Ok(alloc_ids) => Some(VerifiedAllocationKey { + id: *alloc_ids.first().unwrap(), + client: deal.client.id().unwrap(), + }), + Err(_) => None, + }; + + piece_manifests.push(PieceActivationManifest { + cid: deal.piece_cid, + size: deal.piece_size, + verified_allocation_key: alloc_key, + notify: vec![DataActivationNotification { + address: STORAGE_MARKET_ACTOR_ADDR, + payload: serialize(&deal_id, "dealid").unwrap(), + }], + }); + } + piece_manifests +} diff --git a/vm_api/src/trace.rs b/vm_api/src/trace.rs index 34ecd39e7..87395ee9e 100644 --- a/vm_api/src/trace.rs +++ b/vm_api/src/trace.rs @@ -52,7 +52,7 @@ pub struct ExpectInvocation { pub exit_code: ExitCode, pub return_value: Option, pub subinvocs: Option>, - pub events: Vec, + pub events: Option>, } impl ExpectInvocation { @@ -116,25 +116,26 @@ impl ExpectInvocation { } // match emitted events - let emitted_events = &invoc.events; - let expected_events = &self.events; - assert_eq!( - emitted_events.len(), - expected_events.len(), - "{} {} emitted={}, expected={}, {:?}, {:?}", - id, - "length of expected and emitted events do not match", - emitted_events.len(), - expected_events.len(), - emitted_events, - expected_events - ); + if let Some(expected_events) = &self.events { + let emitted_events = &invoc.events; + assert_eq!( + emitted_events.len(), + expected_events.len(), + "{} {} emitted={}, expected={}, {:?}, {:?}", + id, + "length of expected and emitted events do not match", + emitted_events.len(), + expected_events.len(), + emitted_events, + expected_events + ); - // use the zip method to iterate over the emitted events and expected_events - // vectors at the same time - for (emitted, expected) in emitted_events.iter().zip(expected_events.iter()) { - // only try to match if required fields match - assert_eq!(*emitted, *expected); + // use the zip method to iterate over the emitted events and expected_events + // vectors at the same time + for (emitted, expected) in emitted_events.iter().zip(expected_events.iter()) { + // only try to match if required fields match + assert_eq!(*emitted, *expected); + } } if let Some(expect_subinvocs) = &self.subinvocs { @@ -207,7 +208,7 @@ impl Default for ExpectInvocation { exit_code: ExitCode::OK, return_value: None, subinvocs: None, - events: vec![], + events: None, } } }