Skip to content

Commit

Permalink
Test VM state mutation (#1356)
Browse files Browse the repository at this point in the history
* make power scenario test portable

* port extend sectors test to run on the dyn VM

* port evm tests

* port placeholder_deploy test

* cleanup and refactor replica update tests
  • Loading branch information
alexytsu authored Aug 8, 2023
1 parent 4d02c0c commit f9b5760
Show file tree
Hide file tree
Showing 19 changed files with 598 additions and 971 deletions.
3 changes: 0 additions & 3 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

1 change: 1 addition & 0 deletions integration_tests/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -45,6 +45,7 @@ fvm_ipld_encoding = { workspace = true }
fvm_ipld_hamt = { workspace = true }
fvm_shared = { workspace = true }
hex = { workspace = true }
hex-literal = { workspace = true }
indexmap = { workspace = true }
integer-encoding = { workspace = true }
lazy_static = { workspace = true }
Expand Down
72 changes: 67 additions & 5 deletions integration_tests/src/tests/evm_test.rs
Original file line number Diff line number Diff line change
@@ -1,19 +1,25 @@
use std::sync::Arc;

use ethers::prelude::abigen;
use ethers::providers::Provider;
use ethers::{core::types::Address as EthAddress, prelude::builders::ContractCall};
use fil_actors_evm_shared::uints::U256;
use fil_actors_runtime::{test_utils::EVM_ACTOR_CODE_ID, EAM_ACTOR_ADDR, EAM_ACTOR_ID};
use fil_actors_runtime::{
test_utils::ETHACCOUNT_ACTOR_CODE_ID, test_utils::EVM_ACTOR_CODE_ID, EAM_ACTOR_ADDR,
EAM_ACTOR_ID,
};
use fvm_ipld_encoding::ipld_block::IpldBlock;
use fvm_ipld_encoding::RawBytes;
use fvm_ipld_encoding::{strict_bytes, BytesDe};
use fvm_shared::ActorID;
use fvm_shared::METHOD_SEND;
use fvm_shared::{address::Address, econ::TokenAmount};
use num_traits::Zero;
use serde::{Deserialize, Serialize};
use vm_api::util::serialize_ok;
use std::sync::Arc;
use vm_api::util::{apply_ok, serialize_ok};
use vm_api::VM;

use crate::util::create_accounts;
use crate::TEST_FAUCET_ADDR;

// Generate a statically typed interface for the contracts.
abigen!(Recursive, "../actors/evm/tests/contracts/Recursive.abi");
Expand All @@ -29,7 +35,63 @@ pub fn id_to_eth(id: ActorID) -> EthAddress {

#[derive(Debug, Clone, Serialize, Deserialize)]
#[serde(transparent)]
struct ContractParams(#[serde(with = "strict_bytes")] pub Vec<u8>);
pub struct ContractParams(#[serde(with = "strict_bytes")] pub Vec<u8>);

pub fn evm_eth_create_external_test(v: &dyn VM) {
// create the EthAccount
let eth_bits = hex_literal::hex!("FEEDFACECAFEBEEF000000000000000000000000");
let eth_addr = Address::new_delegated(EAM_ACTOR_ID, &eth_bits).unwrap();
apply_ok(
v,
&TEST_FAUCET_ADDR,
&eth_addr,
&TokenAmount::from_whole(10_000),
METHOD_SEND,
None::<RawBytes>,
);

let account = v.resolve_id_address(&eth_addr).unwrap();

let mut actor = v.actor(&account).unwrap();
actor.code = *ETHACCOUNT_ACTOR_CODE_ID;
v.set_actor(&account, actor);

// now create an empty contract
let params = IpldBlock::serialize_cbor(&fil_actor_eam::CreateExternalParams(vec![])).unwrap();
let create_result = v
.execute_message(
&account,
&EAM_ACTOR_ADDR,
&TokenAmount::zero(),
fil_actor_eam::Method::CreateExternal as u64,
params,
)
.unwrap();

assert!(
create_result.code.is_success(),
"failed to create the new actor {}",
create_result.message
);

// and call it
let create_return: fil_actor_eam::CreateExternalReturn =
create_result.ret.unwrap().deserialize().expect("failed to decode results");

let robust_addr = create_return.robust_address.unwrap();

let params = IpldBlock::serialize_cbor(&ContractParams(vec![])).unwrap();
let call_result = v
.execute_message(
&account,
&robust_addr,
&TokenAmount::zero(),
fil_actor_evm::Method::InvokeContract as u64,
params,
)
.unwrap();
assert!(call_result.code.is_success(), "failed to call the new actor {}", call_result.message);
}

pub fn evm_call_test(v: &dyn VM) {
let account = create_accounts(v, 1, &TokenAmount::from_whole(10_000))[0];
Expand Down
227 changes: 221 additions & 6 deletions integration_tests/src/tests/extend_sectors_test.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ use fil_actor_market::{DealMetaArray, SectorDeals, State as MarketState};
use fil_actor_miner::{
max_prove_commit_duration, power_for_sector, ExpirationExtension, ExpirationExtension2,
ExtendSectorExpiration2Params, ExtendSectorExpirationParams, Method as MinerMethod, PowerPair,
ProveReplicaUpdatesParams2, ReplicaUpdate2, SectorClaim, State as MinerState,
ProveReplicaUpdatesParams2, ReplicaUpdate2, SectorClaim, Sectors, State as MinerState,
};
use fil_actor_verifreg::Method as VerifregMethod;
use fil_actors_runtime::runtime::Policy;
Expand All @@ -18,15 +18,16 @@ use fvm_shared::econ::TokenAmount;
use fvm_shared::piece::PaddedPieceSize;
use fvm_shared::sector::{RegisteredSealProof, SectorNumber, StoragePower};
use vm_api::trace::ExpectInvocation;
use vm_api::util::{apply_ok, get_state, DynBlockstore};
use vm_api::util::{apply_ok, get_state, mutate_state, DynBlockstore};
use vm_api::VM;

use crate::expects::Expect;
use crate::util::{
advance_by_deadline_to_epoch, advance_by_deadline_to_index, advance_to_proving_deadline,
bf_all, create_accounts, create_miner, cron_tick, market_add_balance, market_publish_deal,
miner_precommit_sector, miner_prove_sector, sector_deadline, submit_windowed_post,
verifreg_add_client, verifreg_add_verifier,
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_publish_deal, miner_precommit_sector, miner_prove_sector, sector_deadline,
submit_windowed_post, verifreg_add_client, verifreg_add_verifier,
};

#[allow(clippy::too_many_arguments)]
Expand Down Expand Up @@ -103,6 +104,220 @@ pub fn extend(
.matches(v.take_invocations().last().unwrap());
}

pub fn extend_legacy_sector_with_deals_test(v: &dyn VM, do_extend2: bool) {
let addrs = create_accounts(v, 3, &TokenAmount::from_whole(10_000));
let seal_proof = RegisteredSealProof::StackedDRG32GiBV1P1;
let (owner, worker, verifier, verified_client) = (addrs[0], addrs[0], addrs[1], addrs[2]);
let sector_number: SectorNumber = 100;
let policy = Policy::default();

// create miner
let miner_id = create_miner(
v,
&owner,
&worker,
seal_proof.registered_window_post_proof().unwrap(),
&TokenAmount::from_whole(1_000),
)
.0;
v.set_epoch(200);

//
// publish verified deals
//

// register verifier then verified client
let datacap = StoragePower::from(32_u128 << 40);
verifreg_add_verifier(v, &verifier, datacap.clone());
verifreg_add_client(v, &verifier, &verified_client, datacap);

// add market collateral for clients and miner
market_add_balance(v, &verified_client, &verified_client, &TokenAmount::from_whole(3));
market_add_balance(v, &worker, &miner_id, &TokenAmount::from_whole(64));

// create 1 verified deal for total sector capacity for 6 months
let deal_start = v.epoch() + max_prove_commit_duration(&Policy::default(), seal_proof).unwrap();
let deals = market_publish_deal(
v,
&worker,
&verified_client,
&miner_id,
"deal1".to_string(),
PaddedPieceSize(32u64 << 30),
true,
deal_start,
180 * EPOCHS_IN_DAY,
)
.ids;

//
// Precommit, prove and PoSt empty sector (more fully tested in TestCommitPoStFlow)
//

miner_precommit_sector(
v,
&worker,
&miner_id,
seal_proof,
sector_number,
deals,
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);
// trigger cron to validate the prove commit
cron_tick(v);

// inspect sector info

let miner_state: MinerState = get_state(v, &miner_id).unwrap();
let mut sector_info = miner_state
.get_sector(&DynBlockstore::wrap(v.blockstore()), sector_number)
.unwrap()
.unwrap();
assert_eq!(180 * EPOCHS_IN_DAY, sector_info.expiration - sector_info.activation);
assert_eq!(StoragePower::zero(), sector_info.deal_weight); // 0 space time
assert_eq!(
DealWeight::from(180 * EPOCHS_IN_DAY * (32i64 << 30)),
sector_info.verified_deal_weight
); // (180 days *2880 epochs per day) * 32 GiB

// Note: we don't need to explicitly set verified weight using the legacy method
// because legacy and simple qa power deal weight calculations line up for fully packed sectors
// We do need to set simple_qa_power to false
sector_info.simple_qa_power = false;

// Manually craft state to match legacy sectors
mutate_state(v, &miner_id, |st: &mut MinerState| {
let store = &DynBlockstore::wrap(v.blockstore());
let mut sectors = Sectors::load(store, &st.sectors).unwrap();
sectors.store(vec![sector_info.clone()]).unwrap();
st.sectors = sectors.amt.flush().unwrap();
});

let initial_verified_deal_weight = sector_info.verified_deal_weight;
let initial_deal_weight = sector_info.deal_weight;

// advance to proving period and submit post
let (deadline_info, partition_index) = advance_to_proving_deadline(v, &miner_id, sector_number);
let expected_power_delta = PowerPair {
raw: StoragePower::from(32u64 << 30),
qa: StoragePower::from(10 * (32u64 << 30)),
};
submit_windowed_post(
v,
&worker,
&miner_id,
deadline_info,
partition_index,
Some(expected_power_delta),
);

// move forward one deadline so advanceWhileProving doesn't fail double submitting posts
advance_by_deadline_to_index(
v,
&miner_id,
deadline_info.index + 1 % policy.wpost_period_deadlines,
);

// Advance halfway through life and extend another 6 months. We need to spread the remaining 90
// days of 10x power over 90 + 180 days
// subtract half the remaining deal weight:
// - verified deal weight /= 2
//
// normalize 90 days of 10x power plus 180 days of 1x power over 90+180 days:
// - multiplier = ((10 * 90) + (1 * 180)) / (90 + 180)
// - multiplier = 4
//
// delta from the previous 10x power multiplier:
// - power delta = (10-4)*32GiB = 6*32GiB
advance_by_deadline_to_epoch_while_proving(
v,
&miner_id,
&worker,
sector_number,
deal_start + 90 * EPOCHS_IN_DAY,
);

let new_expiration = deal_start + 2 * 180 * EPOCHS_IN_DAY;
let expected_power_delta =
PowerPair { raw: StoragePower::zero(), qa: StoragePower::from(-6 * (32i64 << 30)) };
extend(
v,
worker,
miner_id,
deadline_info.index,
partition_index,
sector_number,
new_expiration,
expected_power_delta,
do_extend2,
);

let miner_state: MinerState = get_state(v, &miner_id).unwrap();
sector_info = miner_state
.get_sector(&DynBlockstore::wrap(v.blockstore()), sector_number)
.unwrap()
.unwrap();
assert_eq!(180 * 2 * EPOCHS_IN_DAY, sector_info.expiration - sector_info.activation);
assert_eq!(initial_deal_weight, sector_info.deal_weight); // 0 space time, unchanged
assert_eq!(&initial_verified_deal_weight / 2, sector_info.verified_deal_weight);

// advance to 6 months (original expiration) and extend another 6 months
//
// We're 1/3rd of the way through the last extension, so keep 2/3 of the power.
// - verified deal weight *= 2/3
//
// normalize 180 days of 4x power plus 180 days of 1x power over 180+180 days:
// - multiplier = ((4 * 180) + (1 * 180)) / (90 + 180)
// - multiplier = 2.5
//
// delta from the previous 4x power multiplier:
// - power delta = (4-2.5)*32GiB = 1.5*32GiB

advance_by_deadline_to_epoch_while_proving(
v,
&miner_id,
&worker,
sector_number,
deal_start + 180 * EPOCHS_IN_DAY,
);

let new_expiration = deal_start + 3 * 180 * EPOCHS_IN_DAY;
let expected_power_delta =
PowerPair { raw: StoragePower::zero(), qa: StoragePower::from(-15 * (32i64 << 30) / 10) };
extend(
v,
worker,
miner_id,
deadline_info.index,
partition_index,
sector_number,
new_expiration,
expected_power_delta,
do_extend2,
);

let miner_state: MinerState = get_state(v, &miner_id).unwrap();
let sector_info = miner_state
.get_sector(&DynBlockstore::wrap(v.blockstore()), sector_number)
.unwrap()
.unwrap();
assert_eq!(180 * 3 * EPOCHS_IN_DAY, sector_info.expiration - sector_info.activation);
// 0 space time, unchanged
assert_eq!(initial_deal_weight, sector_info.deal_weight);
// 1/2 * 2/3 -> 1/3
assert_eq!(initial_verified_deal_weight / 3, sector_info.verified_deal_weight);

expect_invariants(
v,
&Policy::default(),
&[invariant_failure_patterns::REWARD_STATE_EPOCH_MISMATCH.to_owned()],
);
}

pub fn commit_sector_with_max_duration_deal_test(v: &dyn VM) {
let addrs = create_accounts(v, 3, &TokenAmount::from_whole(10_000));
let seal_proof = RegisteredSealProof::StackedDRG32GiBV1P1;
Expand Down
Loading

0 comments on commit f9b5760

Please sign in to comment.