1use std::sync::Arc;
8
9use crate::networks::NetworkChain;
10use crate::shim::{address::Address, piece::PieceInfo};
11use crate::utils::db::CborStoreExt;
12use crate::{make_calibnet_policy, make_mainnet_policy};
13use ahash::HashMap;
14use anyhow::Context as _;
15use cid::{Cid, multibase::Base};
16use fil_actor_miner_state::{
17 v8::State as MinerStateOld,
18 v9::{State as MinerStateNew, util::sector_key},
19};
20use fil_actors_shared::abi::commp::compute_unsealed_sector_cid_v2;
21use fil_actors_shared::fvm_ipld_amt;
22use fvm_ipld_blockstore::Blockstore;
23
24use super::super::common::{
25 ActorMigration, ActorMigrationInput, ActorMigrationOutput, TypeMigration, TypeMigrator,
26};
27
28pub struct MinerMigrator {
29 chain: NetworkChain,
30 out_code: Cid,
31 market_proposals: Cid,
32 empty_deadline_v8_cid: Cid,
33 empty_deadlines_v8_cid: Cid,
34 empty_deadline_v9_cid: Cid,
35 empty_deadlines_v9_cid: Cid,
36}
37
38pub(super) fn miner_migrator<BS>(
39 out_code: Cid,
40 store: &Arc<BS>,
41 market_proposals: Cid,
42 chain: NetworkChain,
43) -> anyhow::Result<Arc<dyn ActorMigration<BS> + Send + Sync>>
44where
45 BS: Blockstore + Send + Sync,
46{
47 let empty_deadline_v8: fil_actor_miner_state::v8::Deadline =
48 fil_actor_miner_state::v8::Deadline::new(store)?;
49 let empty_deadline_v8_cid = store.put_cbor_default(&empty_deadline_v8)?;
50
51 let policy = match chain {
52 NetworkChain::Mainnet => make_mainnet_policy!(v8),
53 NetworkChain::Calibnet => make_calibnet_policy!(v8),
54 NetworkChain::Devnet(_) => unimplemented!("Policy::devnet"),
55 NetworkChain::Butterflynet => unimplemented!("Policy::butterflynet"),
56 };
57 let empty_deadlines_v8 =
58 fil_actor_miner_state::v8::Deadlines::new(&policy, empty_deadline_v8_cid);
59 let empty_deadlines_v8_cid = store.put_cbor_default(&empty_deadlines_v8)?;
60
61 let empty_deadline_v9 = fil_actor_miner_state::v9::Deadline::new(store)?;
62 let empty_deadline_v9_cid = store.put_cbor_default(&empty_deadline_v9)?;
63
64 let policy = match chain {
65 NetworkChain::Mainnet => make_mainnet_policy!(v9),
66 NetworkChain::Calibnet => make_calibnet_policy!(v9),
67 NetworkChain::Devnet(_) => unimplemented!("Policy::devnet"),
68 NetworkChain::Butterflynet => unimplemented!("Policy::butterflynet"),
69 };
70 let empty_deadlines_v9 =
71 fil_actor_miner_state::v9::Deadlines::new(&policy, empty_deadline_v9_cid);
72 let empty_deadlines_v9_cid = store.put_cbor_default(&empty_deadlines_v9)?;
73
74 Ok(Arc::new(MinerMigrator {
75 chain,
76 out_code,
77 market_proposals,
78 empty_deadline_v8_cid,
79 empty_deadlines_v8_cid,
80 empty_deadline_v9_cid,
81 empty_deadlines_v9_cid,
82 }))
83}
84
85impl<BS> ActorMigration<BS> for MinerMigrator
86where
87 BS: Blockstore + Send + Sync,
88{
89 fn migrate_state(
90 &self,
91 store: &BS,
92 input: ActorMigrationInput,
93 ) -> anyhow::Result<Option<ActorMigrationOutput>> {
94 let mut cache: HashMap<String, Cid> = Default::default();
95
96 let in_state: MinerStateOld = store.get_cbor_required(&input.head)?;
97 let new_pre_committed_sectors =
98 self.migrate_pre_committed_sectors(&store, &in_state.pre_committed_sectors)?;
99 let new_sectors =
100 self.migrate_sectors_with_cache(&mut cache, &store, &input.address, &in_state.sectors)?;
101 let new_deadlines = self.migrate_deadlines(&mut cache, &store, &in_state.deadlines)?;
102
103 let mut out_state: MinerStateNew = TypeMigrator::migrate_type(in_state, &store)?;
104 out_state.pre_committed_sectors = new_pre_committed_sectors;
105 out_state.sectors = new_sectors;
106 out_state.deadlines = new_deadlines;
107
108 let new_head = store.put_cbor_default(&out_state)?;
109
110 Ok(Some(ActorMigrationOutput {
111 new_code_cid: self.out_code,
112 new_head,
113 }))
114 }
115}
116
117impl MinerMigrator {
118 fn migrate_pre_committed_sectors(
119 &self,
120 store: &impl Blockstore,
121 old_pre_committed_sectors: &Cid,
122 ) -> anyhow::Result<Cid> {
123 use fil_actors_shared::v9::builtin::HAMT_BIT_WIDTH;
124
125 let market_proposals = fil_actors_shared::v8::Array::<
127 fil_actor_market_state::v8::DealProposal,
128 _,
129 >::load(&self.market_proposals, store)?;
130
131 let old_precommit_on_chain_infos =
132 fil_actors_shared::v8::make_map_with_root_and_bitwidth::<
133 _,
134 fil_actor_miner_state::v8::SectorPreCommitOnChainInfo,
135 >(old_pre_committed_sectors, store, HAMT_BIT_WIDTH)?;
136
137 let mut new_precommit_on_chain_infos = fil_actors_shared::v9::make_empty_map::<
138 _,
139 fil_actor_miner_state::v9::SectorPreCommitOnChainInfo,
140 >(store, HAMT_BIT_WIDTH);
141
142 old_precommit_on_chain_infos.for_each(|_key, value| {
143 let mut pieces = vec![];
144 for &deal_id in &value.info.deal_ids {
145 let deal = market_proposals.get(deal_id)?;
146 if let Some(deal) = deal {
151 pieces.push(PieceInfo::new(deal.piece_cid,deal.piece_size.into()).into());
152 }
153 }
154
155 let unsealed_cid = if !pieces.is_empty() {
156 Some(compute_unsealed_sector_cid_v2(
157 value.info.seal_proof,
158 pieces.as_slice(),
159 )?)
160 } else{
161 None
162 };
163
164 let mut sector_precommit_onchain_info:fil_actor_miner_state::v9::SectorPreCommitOnChainInfo = TypeMigrator::migrate_type(value.clone(), store)?;
165 sector_precommit_onchain_info.info.unsealed_cid = fil_actor_miner_state::v9::CompactCommD(unsealed_cid);
166 new_precommit_on_chain_infos.set(sector_key(value.info.sector_number)?, sector_precommit_onchain_info)?;
167 Ok(())
168 })?;
169
170 Ok(new_precommit_on_chain_infos.flush()?)
171 }
172
173 fn migrate_sectors_with_cache(
174 &self,
175 cache: &mut HashMap<String, Cid>,
176 store: &impl Blockstore,
177 miner_address: &Address,
178 in_root: &Cid,
179 ) -> anyhow::Result<Cid> {
180 let key = sectors_amt_key(in_root)?;
181
182 if let Some(v) = cache.get(&key) {
183 Ok(*v)
184 } else {
185 let in_array = fil_actors_shared::v8::Array::<
186 fil_actor_miner_state::v8::SectorOnChainInfo,
187 _,
188 >::load(in_root, store)?;
189
190 let prev_in_root = cache.get(&miner_prev_sectors_in_key(miner_address));
191 let prev_out_root = cache.get(&miner_prev_sectors_out_key(miner_address));
192
193 let mut out_array = if let Some(prev_in_root) = prev_in_root {
194 if let Some(prev_out_root) = prev_out_root {
195 let prev_in_sectors = fvm_ipld_amt::Amt::<
197 fil_actor_miner_state::v8::SectorOnChainInfo,
198 _,
199 >::load(prev_in_root, store)?;
200 let in_sectors = fvm_ipld_amt::Amt::<
201 fil_actor_miner_state::v8::SectorOnChainInfo,
202 _,
203 >::load(in_root, store)?;
204 let changes = fvm_ipld_amt::diff(&prev_in_sectors, &in_sectors)?;
205 let mut prev_out_sectors = fil_actors_shared::v9::Array::<
206 fil_actor_miner_state::v9::SectorOnChainInfo,
207 _,
208 >::load(prev_out_root, store)?;
209 for change in changes {
210 use fvm_ipld_amt::ChangeType;
211 match &change.change_type() {
212 ChangeType::Remove => {
213 prev_out_sectors.delete(change.key)?;
214 }
215 ChangeType::Modify | ChangeType::Add => {
216 let info_v8 = in_sectors
217 .get(change.key)?
218 .context("Failed to get info from in_sectors")?;
219 prev_out_sectors.set(
220 change.key,
221 TypeMigrator::migrate_type(info_v8.clone(), store)?,
222 )?;
223 }
224 };
225 }
226 prev_out_sectors
227 } else {
228 migrate_from_scratch(store, &in_array)?
229 }
230 } else {
231 migrate_from_scratch(store, &in_array)?
232 };
233
234 let out_root = out_array.flush()?;
235 cache.insert(miner_prev_sectors_in_key(miner_address), *in_root);
236 cache.insert(miner_prev_sectors_out_key(miner_address), out_root);
237
238 cache.insert(key, out_root);
239
240 Ok(out_root)
241 }
242 }
243
244 fn migrate_deadlines(
245 &self,
246 cache: &mut HashMap<String, Cid>,
247 store: &impl Blockstore,
248 deadlines: &Cid,
249 ) -> anyhow::Result<Cid> {
250 if deadlines == &self.empty_deadlines_v8_cid {
251 Ok(self.empty_deadlines_v9_cid)
252 } else {
253 let in_deadlines: fil_actor_miner_state::v8::Deadlines =
254 store.get_cbor_required(deadlines)?;
255
256 let policy = match &self.chain {
257 NetworkChain::Mainnet => make_mainnet_policy!(v9),
258 NetworkChain::Calibnet => make_calibnet_policy!(v9),
259 NetworkChain::Devnet(_) => unimplemented!("Policy::devnet"),
260 NetworkChain::Butterflynet => unimplemented!("Policy::butterflynet"),
261 };
262 let mut out_deadlines =
263 fil_actor_miner_state::v9::Deadlines::new(&policy, self.empty_deadline_v9_cid);
264 for (i, c) in in_deadlines.due.iter().enumerate() {
265 if c == &self.empty_deadline_v8_cid {
266 if let Some(due_i) = out_deadlines.due.get_mut(i) {
267 *due_i = *c;
268 } else {
269 out_deadlines.due.push(*c);
270 }
271 } else {
272 let in_deadline: fil_actor_miner_state::v8::Deadline =
273 store.get_cbor_required(c)?;
274
275 let out_sectors_snapshot_cid_cache_key =
276 sectors_amt_key(&in_deadline.sectors_snapshot)?;
277 let out_sectors_snapshot_cid =
278 match cache.get(&out_sectors_snapshot_cid_cache_key) {
279 Some(v) => *v,
280 None => {
281 let in_sectors_snapshot = fil_actors_shared::v8::Array::load(
282 &in_deadline.sectors_snapshot,
283 store,
284 )?;
285 let mut out_sectors_snapshot =
286 migrate_from_scratch(store, &in_sectors_snapshot)?;
287 let out_sectors_snapshot_cid = out_sectors_snapshot.flush()?;
288 cache.insert(
289 out_sectors_snapshot_cid_cache_key,
290 out_sectors_snapshot_cid,
291 );
292 out_sectors_snapshot_cid
293 }
294 };
295
296 let out_deadline = fil_actor_miner_state::v9::Deadline {
297 partitions: in_deadline.partitions,
298 expirations_epochs: in_deadline.expirations_epochs,
299 partitions_posted: in_deadline.partitions_posted,
300 early_terminations: in_deadline.early_terminations,
301 live_sectors: in_deadline.live_sectors,
302 total_sectors: in_deadline.total_sectors,
303 faulty_power: TypeMigrator::migrate_type(in_deadline.faulty_power, store)?,
304 optimistic_post_submissions: in_deadline.optimistic_post_submissions,
305 sectors_snapshot: out_sectors_snapshot_cid,
306 partitions_snapshot: in_deadline.partitions_snapshot,
307 optimistic_post_submissions_snapshot: in_deadline
308 .optimistic_post_submissions_snapshot,
309 };
310
311 let out_deadline_cid = store.put_cbor_default(&out_deadline)?;
312
313 if let Some(due_i) = out_deadlines.due.get_mut(i) {
314 *due_i = out_deadline_cid;
315 } else {
316 out_deadlines.due.push(out_deadline_cid);
317 }
318 }
319 }
320
321 store.put_cbor_default(&out_deadlines)
322 }
323 }
324}
325
326fn migrate_from_scratch<'bs, BS: Blockstore>(
327 store: &'bs BS,
328 in_array: &fil_actors_shared::v8::Array<fil_actor_miner_state::v8::SectorOnChainInfo, BS>,
329) -> anyhow::Result<
330 fil_actors_shared::v9::Array<'bs, fil_actor_miner_state::v9::SectorOnChainInfo, BS>,
331> {
332 use fil_actor_miner_state::v9::SECTORS_AMT_BITWIDTH;
333
334 let mut out_array = fil_actors_shared::v9::Array::<
335 fil_actor_miner_state::v9::SectorOnChainInfo,
336 _,
337 >::new_with_bit_width(store, SECTORS_AMT_BITWIDTH);
338
339 in_array.for_each(|key, info_v8| {
340 out_array.set(key, TypeMigrator::migrate_type(info_v8.clone(), store)?)?;
341 Ok(())
342 })?;
343
344 Ok(out_array)
345}
346
347fn miner_prev_sectors_in_key(addr: &Address) -> String {
348 format!("prev_sectors_in_{addr}")
349}
350
351fn miner_prev_sectors_out_key(addr: &Address) -> String {
352 format!("prev_sectors_out_{addr}")
353}
354
355fn sectors_amt_key(cid: &Cid) -> anyhow::Result<String> {
356 Ok(format!(
357 "sectors_amt_{}",
358 cid.to_string_of_base(Base::Base32Lower)?,
359 ))
360}
361
362#[cfg(test)]
363mod tests {
364 use super::*;
365 use crate::networks::{ChainConfig, Height};
366 use crate::shim::actors::BURNT_FUNDS_ACTOR_ADDR;
367 use crate::shim::actors::*;
368 use crate::shim::bigint::BigInt;
369 use crate::shim::{
370 econ::TokenAmount,
371 machine::{BuiltinActor, BuiltinActorManifest},
372 state_tree::{ActorState, StateRoot, StateTree, StateTreeVersion},
373 };
374 use crate::utils::multihash::prelude::*;
375 use fil_actors_shared::fvm_ipld_hamt::BytesKey;
376 use fvm_ipld_encoding::IPLD_RAW;
377 use fvm_shared2::{
378 bigint::Zero,
379 commcid::{
380 FIL_COMMITMENT_SEALED, FIL_COMMITMENT_UNSEALED, POSEIDON_BLS12_381_A1_FC1,
381 SHA2_256_TRUNC254_PADDED,
382 },
383 piece::PaddedPieceSize,
384 };
385 use multihash_codetable::Multihash;
386
387 #[test]
388 fn test_nv17_miner_migration() {
389 let store = Arc::new(crate::db::MemoryDB::default());
390 let (mut state_tree_old, manifest_old) = make_input_tree(&store);
391 let system_actor_old = state_tree_old
392 .get_actor(&system::ADDRESS.into())
393 .unwrap()
394 .unwrap();
395 let system_state_old: fil_actor_system_state::v9::State =
396 store.get_cbor_required(&system_actor_old.state).unwrap();
397 let manifest_data_cid_old = system_state_old.builtin_actors;
398 assert_eq!(manifest_data_cid_old, manifest_old.source_cid());
399 assert_eq!(
400 manifest_data_cid_old.to_string(),
401 "bafy2bzaceb7wfqkjc5c3ccjyhaf7zuhkvbzpvhnb35feaettztoharc7zdndc"
402 );
403
404 let base_addr_id = 10000;
405 let base_addr = Address::new_id(base_addr_id);
406 let base_worker_addr = Address::new_id(base_addr_id + 100);
407
408 let mut market_actor_old = state_tree_old
410 .get_actor(&market::ADDRESS.into())
411 .unwrap()
412 .unwrap();
413 let mut market_state_old: fil_actor_market_state::v8::State =
414 store.get_cbor_required(&market_actor_old.state).unwrap();
415 let mut proposals = fil_actors_shared::v8::Array::<
416 fil_actor_market_state::v8::DealProposal,
417 _,
418 >::load(&market_state_old.proposals, &store)
419 .unwrap();
420 let base_deal = fil_actor_market_state::v8::DealProposal {
421 piece_cid: Default::default(),
422 piece_size: PaddedPieceSize(512),
423 verified_deal: true,
424 client: base_addr.into(),
425 provider: base_addr.into(),
426 label: fil_actor_market_state::v8::Label::String("".into()),
427 start_epoch: 0,
428 end_epoch: 0,
429 storage_price_per_epoch: Zero::zero(),
430 provider_collateral: Zero::zero(),
431 client_collateral: Zero::zero(),
432 };
433 let deal0 = {
434 let mut deal = base_deal.clone();
435 deal.piece_cid = make_piece_cid("0".as_bytes());
436 assert_eq!(
437 deal.piece_cid.to_string(),
438 "baga6ea4seaqf73hlm374q3zy3fjhq3dnnfwhtqw3yi452turwrtstvz2e75vp2i"
439 );
440 deal
441 };
442 let deal1 = {
443 let mut deal = base_deal.clone();
444 deal.piece_cid = make_piece_cid("1".as_bytes());
445 assert_eq!(
446 deal.piece_cid.to_string(),
447 "baga6ea4seaqgxbvsop7tj7hbtvvyatx7li7vor5nutvkely5jhab4uw5w6dvwsy"
448 );
449 deal
450 };
451 let deal2 = {
452 let mut deal = base_deal;
453 deal.piece_cid = make_piece_cid("2".as_bytes());
454 assert_eq!(
455 deal.piece_cid.to_string(),
456 "baga6ea4seaqni426hitf4fxo4a7vs4mltnoqgam4a7mlnri7sdnduzto5qj2wni"
457 );
458 deal
459 };
460
461 let mut pending_proposals =
462 fil_actors_shared::v8::Set::from_root(&store, &market_state_old.pending_proposals)
463 .unwrap();
464
465 proposals.set(0, deal0).unwrap();
466 pending_proposals
467 .put(BytesKey(deal1.cid().unwrap().to_bytes()))
468 .unwrap();
469 proposals.set(1, deal1).unwrap();
470 pending_proposals
471 .put(BytesKey(deal2.cid().unwrap().to_bytes()))
472 .unwrap();
473 proposals.set(2, deal2).unwrap();
474
475 market_state_old.proposals = proposals.flush().unwrap();
476 assert_eq!(
477 market_state_old.proposals.to_string(),
478 "bafy2bzacecskt5brcfawiowjlv5lwnskkks2xzsmsnhkmjixndqlxuyb3abxs"
479 );
480 market_state_old.pending_proposals = pending_proposals.root().unwrap();
481
482 let market_state_cid_old = store.put_cbor_default(&market_state_old).unwrap();
483 market_actor_old.state = market_state_cid_old;
484 state_tree_old
485 .set_actor(&market::ADDRESS.into(), market_actor_old)
486 .unwrap();
487
488 let miner_cid_old = manifest_old.get(BuiltinActor::Miner).unwrap();
490 assert_eq!(
491 miner_cid_old.to_string(),
492 "bafkqaetgnfwc6obpon2g64tbm5sw22lomvza"
493 );
494 let base_miner_state = make_base_miner_state(&store, &base_addr, &base_worker_addr);
495
496 let base_precommit = fil_actor_miner_state::v8::SectorPreCommitOnChainInfo {
497 pre_commit_deposit: Zero::zero(),
498 pre_commit_epoch: 0,
499 deal_weight: Zero::zero(),
500 verified_deal_weight: Zero::zero(),
501 info: fil_actor_miner_state::v8::SectorPreCommitInfo {
502 seal_proof: fvm_shared2::sector::RegisteredSealProof::StackedDRG32GiBV1P1,
503 sealed_cid: make_sealed_cid("100".as_bytes()),
504 ..Default::default()
505 },
506 };
507 assert_eq!(
508 base_precommit.info.sealed_cid.to_string(),
509 "bagboea4b5abcblkxgzugketokvsj5szdvyourcdvislw57venjeowxmfu3xljuyg"
510 );
511
512 let miner1_state_cid = store.put_cbor_default(&base_miner_state).unwrap();
519 assert_eq!(
520 miner1_state_cid.to_string(),
521 "bafy2bzaceaqtktd7f5b2gutreh3b2czp2mkqu4ilyuu7mjcpwrk75g5nl6w6k"
522 );
523
524 let miner1 = ActorState::new(miner_cid_old, miner1_state_cid, Zero::zero(), 0, None);
525 let addr1 = Address::new_id(base_addr_id + 1);
526 state_tree_old.set_actor(&addr1, miner1).unwrap();
527
528 let mut precommits2 = fil_actors_shared::v8::make_map_with_root::<
530 _,
531 fil_actor_miner_state::v8::SectorPreCommitOnChainInfo,
532 >(&base_miner_state.pre_committed_sectors, &store)
533 .unwrap();
534 precommits2
535 .set(sector_key(0).unwrap(), base_precommit.clone())
536 .unwrap();
537 precommits2
538 .set(sector_key(1).unwrap(), base_precommit.clone())
539 .unwrap();
540 precommits2
541 .set(sector_key(2).unwrap(), base_precommit.clone())
542 .unwrap();
543 precommits2
544 .set(sector_key(3).unwrap(), base_precommit.clone())
545 .unwrap();
546
547 let precommit2_cid = precommits2.flush().unwrap();
548 assert_eq!(
549 precommit2_cid.to_string(),
550 "bafy2bzacedogkdulyeaujgdsiqzo323s5dpz44efwihxsuekkkpo4znpl3g2s"
551 );
552
553 let mut miner2_state = base_miner_state.clone();
554 miner2_state.pre_committed_sectors = precommit2_cid;
555 let miner2_state_cid = store.put_cbor_default(&miner2_state).unwrap();
556 assert_eq!(
557 miner2_state_cid.to_string(),
558 "bafy2bzacedad6xkymehkuoij4rhg2inzqnfin3er52znw53lddn5364usp2bi"
559 );
560
561 let miner2 = ActorState::new(miner_cid_old, miner2_state_cid, Zero::zero(), 0, None);
562 let addr2 = Address::new_id(base_addr_id + 2);
563 state_tree_old.set_actor(&addr2, miner2).unwrap();
564
565 let mut precommits3 = fil_actors_shared::v8::make_map_with_root::<
567 _,
568 fil_actor_miner_state::v8::SectorPreCommitOnChainInfo,
569 >(&base_miner_state.pre_committed_sectors, &store)
570 .unwrap();
571 let mut precommits3dot0 = base_precommit.clone();
572 precommits3dot0.info.deal_ids = vec![0];
573 precommits3dot0.info.sector_number = 0;
574
575 let mut precommits3dot1 = base_precommit.clone();
576 precommits3dot1.info.deal_ids = vec![1, 2];
577 precommits3dot1.info.sector_number = 1;
578
579 let mut precommits3dot2 = base_precommit;
580 precommits3dot2.info.sector_number = 2;
581
582 precommits3
583 .set(sector_key(0).unwrap(), precommits3dot0)
584 .unwrap();
585 precommits3
586 .set(sector_key(1).unwrap(), precommits3dot1)
587 .unwrap();
588 precommits3
589 .set(sector_key(2).unwrap(), precommits3dot2)
590 .unwrap();
591
592 let precommits3_cid = precommits3.flush().unwrap();
593 assert_eq!(
594 precommits3_cid.to_string(),
595 "bafy2bzacecdpddgu5sxniq5iez3xapyxvi3dg7pc5oxthywuclvxyj4h2vweo"
596 );
597
598 let mut miner3_state = base_miner_state.clone();
599 miner3_state.pre_committed_sectors = precommits3_cid;
600 let miner3_state_cid = store.put_cbor_default(&miner3_state).unwrap();
601 assert_eq!(
602 miner3_state_cid.to_string(),
603 "bafy2bzaceb7ojujla7jb6iaxeuk4etg2kui4gtjujwqadqkc7lkp4ugoqrh2m"
604 );
605
606 let miner3 = ActorState::new(miner_cid_old, miner3_state_cid, Zero::zero(), 0, None);
607 let addr3 = Address::new_id(base_addr_id + 3);
608 state_tree_old.set_actor(&addr3, miner3).unwrap();
609
610 let tree_root = state_tree_old.flush().unwrap();
611
612 let (new_manifest_cid, _new_manifest) = make_test_manifest(&store, "fil/9/");
613
614 let mut chain_config = ChainConfig::calibnet();
615 if let Some(entry) = chain_config.height_infos.get_mut(&Height::Shark) {
616 entry.bundle = Some(new_manifest_cid);
617 }
618 let new_state_cid =
619 super::super::run_migration(&chain_config, &store, &tree_root, 200).unwrap();
620 let actors_out_state_root: StateRoot = store.get_cbor_required(&new_state_cid).unwrap();
621 assert_eq!(
622 actors_out_state_root.actors.to_string(),
623 "bafy2bzacedgtk3lnnyfxnzc32etqaj3zvi7ar7nxq2jtxd2qr36ftbsjoycqu"
624 );
625 let new_state_cid2 =
626 super::super::run_migration(&chain_config, &store, &tree_root, 200).unwrap();
627 assert_eq!(new_state_cid, new_state_cid2);
628 }
629
630 #[test]
631 fn test_fip0029_miner_migration() {
632 let store = Arc::new(crate::db::MemoryDB::default());
633 let (mut state_tree_old, manifest_old) = make_input_tree(&store);
634 let addr = Address::new_id(10000);
635 let worker_addr = Address::new_id(20000);
636 let miner_cid_old = manifest_old.get(BuiltinActor::Miner).unwrap();
637 let miner_state = make_base_miner_state(&store, &addr, &worker_addr);
638 let miner_state_cid = store.put_cbor_default(&miner_state).unwrap();
639 assert_eq!(
640 miner_state_cid.to_string(),
641 "bafy2bzaceacitm72b4zks7ivplygpmyqa6aas2pxkv4rkiknluxiko5mn4ng6"
642 );
643 let miner_actor = ActorState::new(miner_cid_old, miner_state_cid, Zero::zero(), 0, None);
644 state_tree_old.set_actor(&addr, miner_actor).unwrap();
645 let state_tree_old_root = state_tree_old.flush().unwrap();
646 let (new_manifest_cid, _new_manifest) = make_test_manifest(&store, "fil/9/");
647 let mut chain_config = ChainConfig::calibnet();
648 if let Some(entry) = chain_config.height_infos.get_mut(&Height::Shark) {
649 entry.bundle = Some(new_manifest_cid);
650 }
651 let new_state_cid =
652 super::super::run_migration(&chain_config, &store, &state_tree_old_root, 200).unwrap();
653 let actors_out_state_root: StateRoot = store.get_cbor_required(&new_state_cid).unwrap();
654 assert_eq!(
655 actors_out_state_root.actors.to_string(),
656 "bafy2bzacebdpnjjyspbyj7al7d6234kdhkmdygkfdkp6zyao5o3egsfmribty"
657 );
658 }
659
660 fn make_input_tree<BS: Blockstore>(store: &Arc<BS>) -> (StateTree<BS>, BuiltinActorManifest) {
661 let mut tree = StateTree::new(store.clone(), StateTreeVersion::V4).unwrap();
662
663 let (_manifest_cid, manifest) = make_test_manifest(&store, "fil/8/");
664 let account_cid = manifest.get(BuiltinActor::Account).unwrap();
665 assert_eq!(account_cid.to_string(), "bafkqadlgnfwc6obpmfrwg33vnz2a");
667 let system_cid = manifest.get_system();
668 assert_eq!(system_cid.to_string(), "bafkqaddgnfwc6obpon4xg5dfnu");
670 let system_state = fil_actor_system_state::v9::State {
671 builtin_actors: manifest.source_cid(),
672 };
673 let system_state_cid = store.put_cbor_default(&system_state).unwrap();
674 assert_eq!(
675 system_state_cid.to_string(),
676 "bafy2bzacebrujchvrqxwiml3aaud4ts7kgj74kkf7qewwmrsj5tvhneeamtlq"
677 );
678 init_actor(
679 &mut tree,
680 system_state_cid,
681 system_cid,
682 &system::ADDRESS.into(),
683 Zero::zero(),
684 );
685
686 let init_cid = manifest.get_init();
687 assert_eq!(init_cid.to_string(), "bafkqactgnfwc6obpnfxgs5a");
689 let init_state =
690 fil_actor_init_state::v8::State::new(&store, "migrationtest".into()).unwrap();
691 let init_state_cid = store.put_cbor_default(&init_state).unwrap();
692 assert_eq!(
693 init_state_cid.to_string(),
694 "bafy2bzacednf3o3eyjwkm2isixe5lezt6klncgz5axriewegbkw34r6pqszbe"
695 );
696 init_actor(
697 &mut tree,
698 init_state_cid,
699 init_cid,
700 &init::ADDRESS.into(),
701 Zero::zero(),
702 );
703
704 let reward_cid = manifest.get(BuiltinActor::Reward).unwrap();
705 assert_eq!(reward_cid.to_string(), "bafkqaddgnfwc6obpojsxoylsmq");
706 let reward_state = fil_actor_reward_state::v8::State::new(Default::default());
707 let reward_state_cid = store.put_cbor_default(&reward_state).unwrap();
708 assert_eq!(
709 reward_state_cid.to_string(),
710 "bafy2bzaceaslbmsgmgmfi6pn2osvqcfuqinauuyt67zifnefurhpk4zxd2fos"
711 );
712 init_actor(
713 &mut tree,
714 reward_state_cid,
715 reward_cid,
716 &reward::ADDRESS.into(),
717 TokenAmount::from_whole(1_100_000_000),
718 );
719
720 let cron_cid = manifest.get(BuiltinActor::Cron).unwrap();
721 assert_eq!(cron_cid.to_string(), "bafkqactgnfwc6obpmnzg63q");
722 let cron_state = fil_actor_cron_state::v8::State {
723 entries: vec![
724 fil_actor_cron_state::v8::Entry {
725 receiver: crate::shim::actors::power::ADDRESS,
726 method_num: crate::shim::actors::power::Method::OnEpochTickEnd as u64,
727 },
728 fil_actor_cron_state::v8::Entry {
729 receiver: crate::shim::actors::market::ADDRESS,
730 method_num: crate::shim::actors::market::Method::CronTick as u64,
731 },
732 ],
733 };
734 let cron_state_cid = store.put_cbor_default(&cron_state).unwrap();
735 assert_eq!(
736 cron_state_cid.to_string(),
737 "bafy2bzacebs5dwwxmsjmzvoqcamx3qtl2x5qpqgpqxgnzl7scccmbvd37ulvs"
738 );
739 init_actor(
740 &mut tree,
741 cron_state_cid,
742 cron_cid,
743 &cron::ADDRESS.into(),
744 Zero::zero(),
745 );
746
747 let power_cid = manifest.get(BuiltinActor::Power).unwrap();
748 assert_eq!(
749 power_cid.to_string(),
750 "bafkqaetgnfwc6obpon2g64tbm5sxa33xmvza"
751 );
752 let power_state = fil_actor_power_state::v8::State::new(&store).unwrap();
753 let power_state_cid = store.put_cbor_default(&power_state).unwrap();
754 assert_eq!(
755 power_state_cid.to_string(),
756 "bafy2bzacebx3h3ib435qrzwb7zj7enrgepqeiyyeqpq6zwygasoag4m3mhy3w"
757 );
758 init_actor(
759 &mut tree,
760 power_state_cid,
761 power_cid,
762 &power::ADDRESS.into(),
763 Zero::zero(),
764 );
765
766 let market_cid = manifest.get(BuiltinActor::Market).unwrap();
767 assert_eq!(
768 market_cid.to_string(),
769 "bafkqae3gnfwc6obpon2g64tbm5sw2ylsnnsxi"
770 );
771 let market_state = fil_actor_market_state::v8::State::new(&store).unwrap();
772 let market_state_cid = store.put_cbor_default(&market_state).unwrap();
773 assert_eq!(
774 market_state_cid.to_string(),
775 "bafy2bzacea5udmevoj4io3yqy7ku7aitblugdvirbirg7wstzstb5xub5empc"
776 );
777 init_actor(
778 &mut tree,
779 market_state_cid,
780 market_cid,
781 &market::ADDRESS.into(),
782 Zero::zero(),
783 );
784
785 let verifreg_root = Address::new_id(80);
787 let account_state = fil_actor_account_state::v8::State {
788 address: verifreg_root.into(),
789 };
790 let account_state_cid = store.put_cbor_default(&account_state).unwrap();
791 assert_eq!(
792 account_state_cid.to_string(),
793 "bafy2bzaceajm42pledpxusdh4owdrdfvv463dthqg24npeeaz4jlbgzdcgkve"
794 );
795 init_actor(
796 &mut tree,
797 account_state_cid,
798 account_cid,
799 &account_state.address.into(),
800 Zero::zero(),
801 );
802
803 let verifreg_cid = manifest.get(BuiltinActor::VerifiedRegistry).unwrap();
804 assert_eq!(
805 verifreg_cid.to_string(),
806 "bafkqaftgnfwc6obpozsxe2lgnfswi4tfm5uxg5dspe"
807 );
808 let mut verifreg_state =
809 fil_actor_verifreg_state::v8::State::new(&store, verifreg_root.into()).unwrap();
810 let mut verified_clients = fil_actors_shared::v8::make_empty_map::<BS, BigInt>(
811 store,
812 fil_actors_shared::v8::builtin::HAMT_BIT_WIDTH,
813 );
814 {
829 verified_clients
830 .set(
831 BytesKey(Address::new_id(1001).to_bytes()),
832 num_bigint::BigInt::from(1).into(),
833 )
834 .unwrap();
835 verified_clients
836 .set(
837 BytesKey(Address::new_id(1002).to_bytes()),
838 num_bigint::BigInt::from(2).into(),
839 )
840 .unwrap();
841 verifreg_state.verified_clients = verified_clients.flush().unwrap();
842 }
843 let verifreg_state_cid = store.put_cbor_default(&verifreg_state).unwrap();
844 init_actor(
845 &mut tree,
846 verifreg_state_cid,
847 verifreg_cid,
848 &fil_actors_shared::v8::builtin::VERIFIED_REGISTRY_ACTOR_ADDR.into(),
849 Zero::zero(),
850 );
851
852 let account_state = fil_actor_account_state::v8::State {
854 address: BURNT_FUNDS_ACTOR_ADDR,
855 };
856 let account_state_cid = store.put_cbor_default(&account_state).unwrap();
857 assert_eq!(
858 account_state_cid.to_string(),
859 "bafy2bzacedpuk5ggwoq3s2wixsyjjnexpsjstdlyntio76vs2lt2jvy3o6mau"
860 );
861 init_actor(
862 &mut tree,
863 account_state_cid,
864 account_cid,
865 &account_state.address.into(),
866 Zero::zero(),
867 );
868
869 tree.flush().unwrap();
870
871 (tree, manifest)
872 }
873
874 fn init_actor<BS: Blockstore>(
875 tree: &mut StateTree<BS>,
876 state: Cid,
877 code: Cid,
878 addr: &Address,
879 balance: TokenAmount,
880 ) {
881 let actor = ActorState::new(code, state, balance, 0, None);
882 tree.set_actor(addr, actor).unwrap();
883 }
884
885 fn make_test_manifest<BS: Blockstore>(store: &BS, prefix: &str) -> (Cid, BuiltinActorManifest) {
886 let mut manifest_data = vec![];
887 for name in [
888 "account",
889 "cron",
890 "init",
891 "storagemarket",
892 "storageminer",
893 "multisig",
894 "paymentchannel",
895 "storagepower",
896 "reward",
897 "system",
898 "verifiedregistry",
899 "datacap",
900 ] {
901 let hash = MultihashCode::Identity.digest(format!("{prefix}{name}").as_bytes());
902 let code_cid = Cid::new_v1(IPLD_RAW, hash);
903 manifest_data.push((name, code_cid));
904 }
905
906 let manifest_cid = store
907 .put_cbor_default(&(1, store.put_cbor_default(&manifest_data).unwrap()))
908 .unwrap();
909 let manifest = BuiltinActorManifest::load_manifest(store, &manifest_cid).unwrap();
910
911 (manifest_cid, manifest)
912 }
913
914 fn make_base_miner_state<BS: Blockstore>(
915 store: &BS,
916 base_addr: &Address,
917 base_worker_addr: &Address,
918 ) -> fil_actor_miner_state::v8::State {
919 let empty_miner_info = fil_actor_miner_state::v8::MinerInfo {
920 owner: base_addr.into(),
921 worker: base_worker_addr.into(),
922 control_addresses: vec![],
923 pending_worker_key: None,
924 peer_id: vec![],
925 multi_address: vec![],
926 window_post_proof_type: fvm_shared2::sector::RegisteredPoStProof::Invalid(0),
927 sector_size: fvm_shared2::sector::SectorSize::_2KiB, window_post_partition_sectors: 0,
929 consensus_fault_elapsed: 0,
930 pending_owner_address: None,
931 };
932
933 let empty_miner_info_cid = store.put_cbor_default(&empty_miner_info).unwrap();
934
935 fil_actor_miner_state::v8::State::new(
936 &make_calibnet_policy!(v8),
937 store,
938 empty_miner_info_cid,
939 0,
940 0,
941 )
942 .unwrap()
943 }
944
945 fn make_piece_cid(data: &[u8]) -> Cid {
946 let hash = MultihashCode::Sha2_256.digest(data);
947 let hash = Multihash::wrap(SHA2_256_TRUNC254_PADDED, hash.digest()).unwrap();
948 Cid::new_v1(FIL_COMMITMENT_UNSEALED, hash)
949 }
950
951 fn make_sealed_cid(data: &[u8]) -> Cid {
952 let hash = MultihashCode::Sha2_256.digest(data);
953 let hash = Multihash::wrap(POSEIDON_BLS12_381_A1_FC1, hash.digest()).unwrap();
954 Cid::new_v1(FIL_COMMITMENT_SEALED, hash)
955 }
956}