diff --git a/CHANGELOG.md b/CHANGELOG.md index 8a121854096c..4ddf0b02d15b 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -40,6 +40,9 @@ `Filecoin.NetAgentVersion` and `--agent` flag to the `forest-cli net peers` subcommand, that will list the agent version of the connected peers. +- [#3995](https://github.com/ChainSafe/forest/pull/3955) Added support for the + NV22 _Dragon_ network upgrade, together with the required state migration. + ### Changed ### Removed diff --git a/Cargo.lock b/Cargo.lock index 67aec7663c27..f91fe0c0700d 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -2738,9 +2738,9 @@ checksum = "1676f435fc1dadde4d03e43f5d62b259e1ce5f40bd4ffb21db2b42ebe59c1382" [[package]] name = "fil_actor_account_state" -version = "9.4.0" +version = "10.0.0-dev.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0fbac6eee8519336b3d91c595d9779e59a9eb25498722df907732a451e537602" +checksum = "c94732b4360fa5796fe0f0524b62d4b7f9081c0001e45e44e1969511ad237a68" dependencies = [ "frc42_macros", "fvm_ipld_encoding", @@ -2754,9 +2754,9 @@ dependencies = [ [[package]] name = "fil_actor_cron_state" -version = "9.4.0" +version = "10.0.0-dev.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9d9f0a936390d99738a6f1d9745e33e714bc925e5d35847f46c540181019534c" +checksum = "29941aeb04a17810b8d2104e0f0e4fa10001393e7a1d3523631196d7922fbc2f" dependencies = [ "fvm_ipld_encoding", "fvm_shared 2.6.0", @@ -2769,12 +2769,14 @@ dependencies = [ [[package]] name = "fil_actor_datacap_state" -version = "9.4.0" +version = "10.0.0-dev.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b3ef0bdf23cfe3f7ef97653247b11153447d781ac1f17388f90892ffb60a4eeb" +checksum = "091aa98dfbb933274389c5be9348590e168548b15b886bd2eafbff7c13ecef23" dependencies = [ "fil_actors_shared", "frc42_macros", + "frc46_token", + "fvm_ipld_blockstore", "fvm_ipld_encoding", "fvm_shared 2.6.0", "fvm_shared 3.6.0", @@ -2787,9 +2789,9 @@ dependencies = [ [[package]] name = "fil_actor_evm_state" -version = "9.4.0" +version = "10.0.0-dev.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1bd7b2edf69071d56319ae7d19dd57165f64df3ac9a77e296727866219973878" +checksum = "539689549dd7c11fa9139a8adce2568fcbcab1383edf152e5cba45061df6d3d2" dependencies = [ "cid", "fil_actors_shared", @@ -2807,9 +2809,9 @@ dependencies = [ [[package]] name = "fil_actor_init_state" -version = "9.4.0" +version = "10.0.0-dev.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f6107f9cad8a978a15d62eacc9647ac10e52a91586fa877aa1d1cd12468b0681" +checksum = "ed980044e180910897862014dc237448f44c7f7600470a9357458b8c7d1ea0bc" dependencies = [ "anyhow", "cid", @@ -2828,9 +2830,9 @@ dependencies = [ [[package]] name = "fil_actor_interface" -version = "9.4.0" +version = "10.0.0-dev.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "186533fd65b63999b1738700b9bea5f7ea3ee61efc5ad0b8d2af08f35237314a" +checksum = "ab089bd0e43f98c8bdccdec814e14c74c631b73ee832f16d313bbb8ba9cecc1e" dependencies = [ "anyhow", "cid", @@ -2866,9 +2868,9 @@ dependencies = [ [[package]] name = "fil_actor_market_state" -version = "9.4.0" +version = "10.0.0-dev.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f0c906b7f9f6dbf931076466969d93e67bc33090b13e4fedf73aff5be4846f5e" +checksum = "f0c76cad842778e6aa42e9defdcdea0553072ff6f0c0aa41242fd00f265b8d9d" dependencies = [ "anyhow", "cid", @@ -2891,9 +2893,9 @@ dependencies = [ [[package]] name = "fil_actor_miner_state" -version = "9.4.0" +version = "10.0.0-dev.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4819dcd358141977de9d35830929dcde157ae240e291de40cf62ac336f92c6d7" +checksum = "7022542811937e9b5d722586f0b17037561ef7cd3f0c35ce4c849a20da7c744d" dependencies = [ "anyhow", "bitflags 2.4.2", @@ -2921,9 +2923,9 @@ dependencies = [ [[package]] name = "fil_actor_multisig_state" -version = "9.4.0" +version = "10.0.0-dev.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "204fe308f5d55ad834f57f36fdf0eba8703db92bf60dc24f1417dee1dda6b473" +checksum = "b8738df800e7cb4d350717ebc20d74fffaf26c9298108e03e5458a4690760797" dependencies = [ "anyhow", "cid", @@ -2944,9 +2946,9 @@ dependencies = [ [[package]] name = "fil_actor_power_state" -version = "9.4.0" +version = "10.0.0-dev.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2a8cdc9c1e3cec390d758bc81faeb3d9b0c4e7974ff9eb247ded8ba3401eea92" +checksum = "7a1996681dae26388ae9a30fb9fcefebda66e56b470b78a887b9b995cbb9a8f7" dependencies = [ "anyhow", "cid", @@ -2967,9 +2969,9 @@ dependencies = [ [[package]] name = "fil_actor_reward_state" -version = "9.4.0" +version = "10.0.0-dev.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f27b57db0a6f8777e373c1c8e1fcccdb5a50b7bc436095c1cbfa84cdbdb11d03" +checksum = "8dc9c0958524a3413cf72974b715fbae5bf57407f914ef1ca129624b4fcd7a58" dependencies = [ "fvm_ipld_encoding", "fvm_shared 2.6.0", @@ -2983,11 +2985,13 @@ dependencies = [ [[package]] name = "fil_actor_system_state" -version = "9.4.0" +version = "10.0.0-dev.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5266c8d23d81980dfcda733e2e8e32d87c51bb392714f58aa835e6bad82e8234" +checksum = "1b6cdcc5a6a21fb639853cb828fe2625aa1e792439db1161681f866ecbbc594e" dependencies = [ "cid", + "fil_actors_shared", + "fvm_ipld_blockstore", "fvm_ipld_encoding", "fvm_shared 2.6.0", "fvm_shared 4.1.2", @@ -2998,9 +3002,9 @@ dependencies = [ [[package]] name = "fil_actor_verifreg_state" -version = "9.4.0" +version = "10.0.0-dev.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0f205cc8195bd298016d995a560e636ebaf550c5d3239de189860bc6f9ab2014" +checksum = "62e9394839dd721f7cdbbafd82747ec9daa4b6229e1bc1c7f014366216fc3a60" dependencies = [ "anyhow", "cid", @@ -3018,13 +3022,14 @@ dependencies = [ [[package]] name = "fil_actors_shared" -version = "9.4.0" +version = "10.0.0-dev.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1c0151e5842dba148031583452e40be7d5738ac7182f08bce183b4f6844224d1" +checksum = "fa8b5e64f9b025625f7f667dc90e729d350fddae0f464c119b2d7436a79800f2" dependencies = [ "anyhow", "cid", "filecoin-proofs-api", + "frc46_token", "fvm_ipld_amt", "fvm_ipld_bitfield", "fvm_ipld_blockstore", @@ -3041,6 +3046,7 @@ dependencies = [ "num-derive", "num-traits", "paste", + "regex", "serde", "serde_repr", "sha2 0.10.8", @@ -3262,6 +3268,7 @@ dependencies = [ "fil_actors_shared", "filecoin-proofs-api", "flume 0.11.0", + "frc46_token", "fs_extra", "futures", "fvm 2.7.0", @@ -3419,20 +3426,35 @@ dependencies = [ "thiserror", ] +[[package]] +name = "frc42_dispatch" +version = "6.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1a1704e27193af21e58435974ff20f2be25cc59338afb89920abdb540ad3182b" +dependencies = [ + "frc42_hasher", + "frc42_macros", + "fvm_ipld_encoding", + "fvm_shared 4.1.2", + "thiserror", +] + [[package]] name = "frc42_hasher" -version = "3.0.0" +version = "4.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "08a35e7214108f81cefc17b0466be01279f384faf913918a12dbc8528bb758a4" +checksum = "63f58bb50d36d90f5d0fee8391d6e1ed1a2b15ab8da6417dc42d7c78b587479d" dependencies = [ + "fvm_sdk", + "fvm_shared 4.1.2", "thiserror", ] [[package]] name = "frc42_macros" -version = "3.0.0" +version = "4.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6f50cd62b077775194bde67eef8076b31f915b9c099f3a7fd1a760363d65f145" +checksum = "5a9ce38a981bab5e0d3c0835baa86f83066afe9afaf0aec23cee421f6d8c628e" dependencies = [ "blake2b_simd", "frc42_hasher", @@ -3441,6 +3463,27 @@ dependencies = [ "syn 1.0.109", ] +[[package]] +name = "frc46_token" +version = "10.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "24f4829f83aef107908f00e225027fb4d74c064b747e6f0c4dc5e77ad843cc86" +dependencies = [ + "cid", + "frc42_dispatch", + "fvm_actor_utils", + "fvm_ipld_blockstore", + "fvm_ipld_encoding", + "fvm_ipld_hamt 0.9.0", + "fvm_sdk", + "fvm_shared 4.1.2", + "integer-encoding", + "num-traits", + "serde", + "serde_tuple", + "thiserror", +] + [[package]] name = "fs2" version = "0.4.3" @@ -3756,6 +3799,25 @@ dependencies = [ "wasmprinter", ] +[[package]] +name = "fvm_actor_utils" +version = "10.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1786030c99fd87853ec122697a1bb227f6eac67a4d96a5c27335ecb9dc3c21ec" +dependencies = [ + "anyhow", + "cid", + "frc42_dispatch", + "fvm_ipld_blockstore", + "fvm_ipld_encoding", + "fvm_sdk", + "fvm_shared 4.1.2", + "num-traits", + "serde", + "serde_tuple", + "thiserror", +] + [[package]] name = "fvm_ipld_amt" version = "0.6.2" @@ -3852,6 +3914,22 @@ dependencies = [ "thiserror", ] +[[package]] +name = "fvm_sdk" +version = "4.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9e58331aefe4b5592c59abfd4d94c62b23ea61d1e121202fbc2fb6abd2fcb165" +dependencies = [ + "byteorder", + "cid", + "fvm_ipld_encoding", + "fvm_shared 4.1.2", + "lazy_static", + "log", + "num-traits", + "thiserror", +] + [[package]] name = "fvm_shared" version = "2.6.0" diff --git a/Cargo.toml b/Cargo.toml index 99d90b00ba9d..406c1caf0000 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -52,20 +52,21 @@ dialoguer = "0.11" digest = "0.10.5" directories = "5" ethereum-types = "0.14.1" -fil_actor_account_state = { version = "9.4.0" } -fil_actor_cron_state = { version = "9.4.0" } -fil_actor_datacap_state = { version = "9.4.0" } -fil_actor_init_state = { version = "9.4.0" } -fil_actor_interface = { version = "9.4.0" } -fil_actor_market_state = { version = "9.4.0" } -fil_actor_miner_state = { version = "9.4.0" } -fil_actor_power_state = { version = "9.4.0" } -fil_actor_reward_state = { version = "9.4.0" } -fil_actor_system_state = { version = "9.4.0" } -fil_actor_verifreg_state = { version = "9.4.0" } -fil_actors_shared = { version = "9.4.0", features = ["json"] } +fil_actor_account_state = { version = "10.0.0-dev.4" } +fil_actor_cron_state = { version = "10.0.0-dev.4" } +fil_actor_datacap_state = { version = "10.0.0-dev.4" } +fil_actor_init_state = { version = "10.0.0-dev.4" } +fil_actor_interface = { version = "10.0.0-dev.4" } +fil_actor_market_state = { version = "10.0.0-dev.4" } +fil_actor_miner_state = { version = "10.0.0-dev.4" } +fil_actor_power_state = { version = "10.0.0-dev.4" } +fil_actor_reward_state = { version = "10.0.0-dev.4" } +fil_actor_system_state = { version = "10.0.0-dev.4" } +fil_actor_verifreg_state = { version = "10.0.0-dev.4" } +fil_actors_shared = { version = "10.0.0-dev.4", features = ["json"] } filecoin-proofs-api = { version = "16.0", default-features = false } flume = "0.11" +frc46_token = "10.0.0" fs_extra = "1.2" futures = "0.3" fvm2 = { package = "fvm", version = "~2.7", default-features = false } diff --git a/build/bootstrap/butterflynet b/build/bootstrap/butterflynet index 0646d83fcecc..26378350f6cf 100644 --- a/build/bootstrap/butterflynet +++ b/build/bootstrap/butterflynet @@ -1,2 +1,2 @@ -/dns4/bootstrap-0.butterfly.fildev.network/tcp/1347/p2p/12D3KooWFbgk3NSUv7u3kYqLUfVi5ycmzkVoCMA6DFWNJScazsh1 -/dns4/bootstrap-1.butterfly.fildev.network/tcp/1347/p2p/12D3KooWLsnUi7HD2camXmvhmfHke53krsbFfFf5eHh6g2G3m2Nt +/dns4/bootstrap-0.butterfly.fildev.network/tcp/1347/p2p/12D3KooWQDmegAZg23vAgxoGzRsYb8Ma4oW2p759QrGyC9Y6Bszu +/dns4/bootstrap-1.butterfly.fildev.network/tcp/1347/p2p/12D3KooWNi7kCgFSNDKMuKu1ng8LCZtB1rWVy4yZG8UDWyUdLaDM diff --git a/scripts/devnet/.env b/scripts/devnet/.env index 290c497fb5d6..e4d2fc77dbbd 100644 --- a/scripts/devnet/.env +++ b/scripts/devnet/.env @@ -1,4 +1,4 @@ -LOTUS_IMAGE=ghcr.io/chainsafe/lotus-devnet:2024-02-29-a2919fe +LOTUS_IMAGE=ghcr.io/chainsafe/lotus-devnet:2024-03-07-b74be0f FOREST_DATA_DIR=/forest_data LOTUS_DATA_DIR=/lotus_data FIL_PROOFS_PARAMETER_CACHE=/var/tmp/filecoin-proof-parameters @@ -12,6 +12,6 @@ HYGGE_HEIGHT=-9 LIGHTNING_HEIGHT=3 THUNDER_HEIGHT=6 WATERMELON_HEIGHT=9 -DRAGON_HEIGHT=1000 -DRAND_QUICKNET_HEIGHT=12 -TARGET_HEIGHT=15 +DRAGON_HEIGHT=12 +DRAND_QUICKNET_HEIGHT=15 +TARGET_HEIGHT=20 diff --git a/scripts/devnet/lotus.dockerfile b/scripts/devnet/lotus.dockerfile index b4326c1f0d87..bf7f730533e8 100644 --- a/scripts/devnet/lotus.dockerfile +++ b/scripts/devnet/lotus.dockerfile @@ -5,7 +5,7 @@ RUN apt-get update && apt-get install -y ca-certificates build-essential clang o WORKDIR /lotus -RUN git clone --depth 1 --branch v1.25.2 https://github.com/filecoin-project/lotus.git . +RUN git clone --depth 1 --branch v1.26.0-rc2 https://github.com/filecoin-project/lotus.git . RUN CGO_CFLAGS_ALLOW="-D__BLST_PORTABLE__" \ CGO_CFLAGS="-D__BLST_PORTABLE__" \ diff --git a/src/networks/actors_bundle.rs b/src/networks/actors_bundle.rs index 2b707e0281aa..8cd2eb370f85 100644 --- a/src/networks/actors_bundle.rs +++ b/src/networks/actors_bundle.rs @@ -69,16 +69,19 @@ pub static ACTOR_BUNDLES: Lazy> = Lazy::new(|| { "bafy2bzacedrunxfqta5skb7q7x32lnp4efz2oq7fn226ffm7fu5iqs62jkmvs" @ "v12.0.0-rc.1" for "calibrationnet", "bafy2bzacebl4w5ptfvuw6746w7ev562idkbf5ppq72e6zub22435ws2rukzru" @ "v12.0.0-rc.2" for "calibrationnet", "bafy2bzacednzb3pkrfnbfhmoqtb3bc6dgvxszpqklf3qcc7qzcage4ewzxsca" @ "v12.0.0" for "calibrationnet", - "bafy2bzaceaiy4dsxxus5xp5n5i4tjzkb7sc54mjz7qnk2efhgmsrobjesxnza" @ "v11.0.0" for "butterflynet", + "bafy2bzacea4firkyvt2zzdwqjrws5pyeluaesh6uaid246tommayr4337xpmi" @ "v13.0.0-rc.3" for "calibrationnet", "bafy2bzacectxvbk77ntedhztd6sszp2btrtvsmy7lp2ypnrk6yl74zb34t2cq" @ "v12.0.0" for "butterflynet", + "bafy2bzaceaqx5xa4cwso24rjiu2ketjlztrqlac6dkyol7tlyuhzrle3zfbos" @ "v13.0.0-rc.3" for "butterflynet", "bafy2bzacedozk3jh2j4nobqotkbofodq4chbrabioxbfrygpldgoxs3zwgggk" @ "v9.0.3" for "devnet", "bafy2bzacebzz376j5kizfck56366kdz5aut6ktqrvqbi3efa2d4l2o2m653ts" @ "v10.0.0" for "devnet", "bafy2bzaceay35go4xbjb45km6o46e5bib3bi46panhovcbedrynzwmm3drr4i" @ "v11.0.0" for "devnet", "bafy2bzaceasjdukhhyjbegpli247vbf5h64f7uvxhhebdihuqsj2mwisdwa6o" @ "v12.0.0" for "devnet", + "bafy2bzaceap34qfq4emg4fp3xd7bxtzt7pvkaj37kunqm2ccvttchtlljw7d4" @ "v13.0.0-rc.3" for "devnet", "bafy2bzaceb6j6666h36xnhksu3ww4kxb6e25niayfgkdnifaqi6m6ooc66i6i" @ "v9.0.3" for "mainnet", "bafy2bzacecsuyf7mmvrhkx2evng5gnz5canlnz2fdlzu2lvcgptiq2pzuovos" @ "v10.0.0" for "mainnet", "bafy2bzacecnhaiwcrpyjvzl4uv4q3jzoif26okl3m66q3cijp3dfwlcxwztwo" @ "v11.0.0" for "mainnet", "bafy2bzaceapkgfggvxyllnmuogtwasmsv5qi2qzhc2aybockd6kag2g5lzaio" @ "v12.0.0" for "mainnet", + "bafy2bzacecoplaet2m4kzueqgutjxpl76bhmuiq5hmo3ueighbnxas3rj4dvy" @ "v13.0.0-rc.3" for "mainnet", ]) }); diff --git a/src/networks/butterflynet/mod.rs b/src/networks/butterflynet/mod.rs index ee5f7476ad36..3b08ca09048a 100644 --- a/src/networks/butterflynet/mod.rs +++ b/src/networks/butterflynet/mod.rs @@ -10,7 +10,10 @@ use url::Url; use crate::{db::SettingsStore, utils::net::http_get}; -use super::{drand::DRAND_MAINNET, parse_bootstrap_peers, DrandPoint, Height, HeightInfo}; +use super::{ + drand::{DRAND_MAINNET, DRAND_QUICKNET}, + get_upgrade_height_from_env, parse_bootstrap_peers, DrandPoint, Height, HeightInfo, +}; /// Fetches the genesis CAR from the local database or downloads it if it does not exist. /// The result bytes may be compressed. @@ -32,7 +35,7 @@ pub async fn fetch_genesis(db: &DB) -> anyhow::Result /// Genesis CID pub static GENESIS_CID: Lazy = Lazy::new(|| { - Cid::from_str("bafy2bzacecl7vdlut572ia64cskp3onngc5ii6co2vsdoshc6ehcx7bful5oo").unwrap() + Cid::from_str("bafy2bzacedz4owzn3irngak4cdv3xndfxyy4qi5hcv7p724anbnt27l7dctoq").unwrap() }); /// Compressed genesis file. It is compressed with zstd and cuts the download size by 80% (from 10 MB to 2 MB). @@ -47,7 +50,7 @@ static GENESIS_URL: Lazy = Lazy::new(|| { /// The genesis file does not live on the `master` branch, currently on a draft PR. /// `` static GENESIS_URL_ALT: Lazy = Lazy::new(|| { - "https://github.com/filecoin-project/lotus/raw/3e379c9997bf152639a593d3efee49b88fee27ec/build/genesis/butterflynet.car".parse().expect("hard-coded URL must parse") + "https://github.com/filecoin-project/lotus/raw/3331a7e52c97e5723fc0c613271a616bb3ccdb39/build/genesis/butterflynet.car".parse().expect("hard-coded URL must parse") }); pub(crate) const MINIMUM_CONSENSUS_POWER: i64 = 2 << 30; @@ -65,21 +68,21 @@ pub const ETH_CHAIN_ID: u64 = 3141592; pub static HEIGHT_INFOS: Lazy> = Lazy::new(|| { HashMap::from_iter([ ( - Height::Thunder, + Height::Watermelon, HeightInfo { epoch: -1, bundle: Some( - Cid::try_from("bafy2bzaceaiy4dsxxus5xp5n5i4tjzkb7sc54mjz7qnk2efhgmsrobjesxnza") + Cid::try_from("bafy2bzacectxvbk77ntedhztd6sszp2btrtvsmy7lp2ypnrk6yl74zb34t2cq") .unwrap(), ), }, ), ( - Height::Watermelon, + Height::Dragon, HeightInfo { - epoch: 400, + epoch: 2600, bundle: Some( - Cid::try_from("bafy2bzacectxvbk77ntedhztd6sszp2btrtvsmy7lp2ypnrk6yl74zb34t2cq") + Cid::try_from("bafy2bzaceaqx5xa4cwso24rjiu2ketjlztrqlac6dkyol7tlyuhzrle3zfbos") .unwrap(), ), }, @@ -87,11 +90,18 @@ pub static HEIGHT_INFOS: Lazy> = Lazy::new(|| { ]) }); -pub(super) static DRAND_SCHEDULE: Lazy<[DrandPoint<'static>; 1]> = Lazy::new(|| { - [DrandPoint { - height: 0, - config: &DRAND_MAINNET, - }] +pub(super) static DRAND_SCHEDULE: Lazy<[DrandPoint<'static>; 2]> = Lazy::new(|| { + [ + DrandPoint { + height: 0, + config: &DRAND_MAINNET, + }, + DrandPoint { + height: get_upgrade_height_from_env("FOREST_DRAND_QUICKNET_HEIGHT") + .unwrap_or(HEIGHT_INFOS.get(&Height::Dragon).unwrap().epoch + 120), + config: &DRAND_QUICKNET, + }, + ] }); /// Creates a new butterfly policy with the given version. @@ -161,10 +171,12 @@ mod tests { let v10 = make_butterfly_policy!(v10); let v11 = make_butterfly_policy!(v11); let v12 = make_butterfly_policy!(v12); + let v13 = make_butterfly_policy!(v13); // basic sanity checks assert_eq!(v10.minimum_consensus_power, MINIMUM_CONSENSUS_POWER.into()); assert_eq!(v11.minimum_consensus_power, MINIMUM_CONSENSUS_POWER.into()); assert_eq!(v12.minimum_consensus_power, MINIMUM_CONSENSUS_POWER.into()); + assert_eq!(v13.minimum_consensus_power, MINIMUM_CONSENSUS_POWER.into()); } } diff --git a/src/networks/calibnet/mod.rs b/src/networks/calibnet/mod.rs index be823f7c9050..723198849eed 100644 --- a/src/networks/calibnet/mod.rs +++ b/src/networks/calibnet/mod.rs @@ -7,7 +7,10 @@ use libp2p::Multiaddr; use once_cell::sync::Lazy; use std::str::FromStr; -use super::{drand::DRAND_MAINNET, parse_bootstrap_peers, DrandPoint, Height, HeightInfo}; +use super::{ + drand::{DRAND_MAINNET, DRAND_QUICKNET}, + get_upgrade_height_from_env, parse_bootstrap_peers, DrandPoint, Height, HeightInfo, +}; /// Default genesis car file bytes. pub const DEFAULT_GENESIS: &[u8] = include_bytes!("genesis.car"); @@ -191,14 +194,31 @@ pub static HEIGHT_INFOS: Lazy> = Lazy::new(|| { ), }, ), + ( + Height::Dragon, + HeightInfo { + epoch: 1_427_974, + bundle: Some( + Cid::try_from("bafy2bzacea4firkyvt2zzdwqjrws5pyeluaesh6uaid246tommayr4337xpmi") + .unwrap(), + ), + }, + ), ]) }); -pub(super) static DRAND_SCHEDULE: Lazy<[DrandPoint<'static>; 1]> = Lazy::new(|| { - [DrandPoint { - height: 0, - config: &DRAND_MAINNET, - }] +pub(super) static DRAND_SCHEDULE: Lazy<[DrandPoint<'static>; 2]> = Lazy::new(|| { + [ + DrandPoint { + height: 0, + config: &DRAND_MAINNET, + }, + DrandPoint { + height: get_upgrade_height_from_env("FOREST_DRAND_QUICKNET_HEIGHT") + .unwrap_or(HEIGHT_INFOS.get(&Height::Dragon).unwrap().epoch + 120), + config: &DRAND_QUICKNET, + }, + ] }); #[cfg(test)] diff --git a/src/networks/devnet/mod.rs b/src/networks/devnet/mod.rs index 24c4937a3131..beb222378231 100644 --- a/src/networks/devnet/mod.rs +++ b/src/networks/devnet/mod.rs @@ -51,20 +51,30 @@ pub static HEIGHT_INFOS: Lazy> = Lazy::new(|| { ( Height::Thunder, HeightInfo { - epoch: get_upgrade_height_from_env("FOREST_THUNDER_HEIGHT").unwrap_or(-1), + epoch: get_upgrade_height_from_env("FOREST_THUNDER_HEIGHT").unwrap_or(-23), bundle: None, }, ), ( Height::Watermelon, HeightInfo { - epoch: get_upgrade_height_from_env("FOREST_WATERMELON_HEIGHT").unwrap_or(200), + epoch: get_upgrade_height_from_env("FOREST_WATERMELON_HEIGHT").unwrap_or(-1), bundle: Some( Cid::try_from("bafy2bzaceasjdukhhyjbegpli247vbf5h64f7uvxhhebdihuqsj2mwisdwa6o") .unwrap(), ), }, ), + ( + Height::Dragon, + HeightInfo { + epoch: get_upgrade_height_from_env("FOREST_DRAGON_HEIGHT").unwrap_or(20), + bundle: Some( + Cid::try_from("bafy2bzaceap34qfq4emg4fp3xd7bxtzt7pvkaj37kunqm2ccvttchtlljw7d4") + .unwrap(), + ), + }, + ), ]) }); @@ -75,9 +85,6 @@ pub(super) static DRAND_SCHEDULE: Lazy<[DrandPoint<'static>; 2]> = Lazy::new(|| config: &DRAND_MAINNET, }, DrandPoint { - // height is TBD. - // likely to be `get_upgrade_epoch_by_height(HEIGHT_INFOS.iter(), Height::Pineapple).unwrap()`. - // remember to remove `#[allow(dead_code)]` from `get_upgrade_epoch_by_height` height: get_upgrade_height_from_env("FOREST_DRAND_QUICKNET_HEIGHT").unwrap_or(i64::MAX), config: &DRAND_QUICKNET, }, diff --git a/src/networks/mainnet/mod.rs b/src/networks/mainnet/mod.rs index 4c5443f0b5bb..169014a32bad 100644 --- a/src/networks/mainnet/mod.rs +++ b/src/networks/mainnet/mod.rs @@ -10,7 +10,7 @@ use std::str::FromStr; use super::{ drand::{DRAND_INCENTINET, DRAND_MAINNET, DRAND_QUICKNET}, - parse_bootstrap_peers, DrandPoint, Height, HeightInfo, + get_upgrade_height_from_env, parse_bootstrap_peers, DrandPoint, Height, HeightInfo, }; const SMOKE_HEIGHT: ChainEpoch = 51000; @@ -202,6 +202,17 @@ pub static HEIGHT_INFOS: Lazy> = Lazy::new(|| { ), }, ), + ( + Height::Dragon, + HeightInfo { + // 2024-04-02T14:00:00Z - Epoch will be updated in final release + epoch: i64::MAX, + bundle: Some( + Cid::try_from("bafy2bzacecoplaet2m4kzueqgutjxpl76bhmuiq5hmo3ueighbnxas3rj4dvy") + .unwrap(), + ), + }, + ), ]) }); @@ -216,8 +227,8 @@ pub(super) static DRAND_SCHEDULE: Lazy<[DrandPoint<'static>; 3]> = Lazy::new(|| config: &DRAND_MAINNET, }, DrandPoint { - // height is TBD - height: i64::MAX, + // 2024-04-02T14:00:00Z - Epoch will be updated in final release + height: get_upgrade_height_from_env("FOREST_DRAND_QUICKNET_HEIGHT").unwrap_or(i64::MAX), config: &DRAND_QUICKNET, }, ] diff --git a/src/networks/mod.rs b/src/networks/mod.rs index 2a5e859c2f0c..8719b592ccc0 100644 --- a/src/networks/mod.rs +++ b/src/networks/mod.rs @@ -64,7 +64,7 @@ impl Display for NetworkChain { match self { NetworkChain::Mainnet => write!(f, "mainnet"), NetworkChain::Calibnet => write!(f, "calibnet"), - NetworkChain::Butterflynet => write!(f, "Butterflynet"), + NetworkChain::Butterflynet => write!(f, "butterflynet"), NetworkChain::Devnet(name) => write!(f, "{name}"), } } @@ -126,6 +126,7 @@ pub enum Height { Watermelon, WatermelonFix, WatermelonFix2, + Dragon, } impl Default for Height { @@ -161,6 +162,7 @@ impl From for NetworkVersion { Height::Watermelon => NetworkVersion::V21, Height::WatermelonFix => NetworkVersion::V21, Height::WatermelonFix2 => NetworkVersion::V21, + Height::Dragon => NetworkVersion::V22, } } } diff --git a/src/rpc/state_api.rs b/src/rpc/state_api.rs index 1a2ce3abe48d..c02a8cd6b93a 100644 --- a/src/rpc/state_api.rs +++ b/src/rpc/state_api.rs @@ -217,11 +217,12 @@ pub async fn state_market_deals( sector_start_epoch: -1, last_updated_epoch: -1, slash_epoch: -1, + verified_claim: 0, }); out.insert( deal_id.to_string(), MarketDeal { - proposal: d, + proposal: d?, state: s, }, ); diff --git a/src/shim/version.rs b/src/shim/version.rs index 3fadee4faf32..2d2eed1f10e9 100644 --- a/src/shim/version.rs +++ b/src/shim/version.rs @@ -56,6 +56,7 @@ impl NetworkVersion { pub const V19: Self = Self(NetworkVersion_latest::new(19)); pub const V20: Self = Self(NetworkVersion_latest::new(20)); pub const V21: Self = Self(NetworkVersion_latest::new(21)); + pub const V22: Self = Self(NetworkVersion_latest::new(22)); } impl Deref for NetworkVersion { diff --git a/src/state_migration/common/mod.rs b/src/state_migration/common/mod.rs index 9fa23061c09b..d7240dbc3c89 100644 --- a/src/state_migration/common/mod.rs +++ b/src/state_migration/common/mod.rs @@ -85,6 +85,12 @@ pub(in crate::state_migration) trait ActorMigration { store: &BS, input: ActorMigrationInput, ) -> anyhow::Result>; + + /// Some migration jobs might need to be deferred to be executed after the regular state migration. + /// These may require some metadata collected during other migrations. + fn is_deferred(&self) -> bool { + false + } } /// Trait that defines the interface for actor migration job to be executed after the state migration. diff --git a/src/state_migration/common/state_migration.rs b/src/state_migration/common/state_migration.rs index 007014eeb908..38f5c8091a98 100644 --- a/src/state_migration/common/state_migration.rs +++ b/src/state_migration/common/state_migration.rs @@ -3,12 +3,14 @@ use std::num::NonZeroUsize; use std::sync::atomic::AtomicU64; +use std::sync::Arc; use crate::cid_collections::CidHashMap; use crate::shim::{clock::ChainEpoch, state_tree::StateTree}; use crate::state_migration::common::MigrationCache; use cid::Cid; use fvm_ipld_blockstore::Blockstore; +use parking_lot::Mutex; use super::PostMigrationCheckArc; use super::{verifier::MigrationVerifier, Migrator, PostMigratorArc}; @@ -78,18 +80,30 @@ impl StateMigration { } let cache = MigrationCache::new(NonZeroUsize::new(10_000).expect("infallible")); + let num_threads = std::env::var("FOREST_STATE_MIGRATION_THREADS") + .ok() + .and_then(|s| s.parse().ok()) + // Don't use all CPU, otherwise the migration will starve the rest of the system. + .unwrap_or_else(|| num_cpus::get() / 2) + // At least 3 are required to not deadlock the migration. + .max(3); + let pool = rayon::ThreadPoolBuilder::new() .thread_name(|id| format!("state migration thread: {id}")) - .num_threads(3) // minimum needed, more doesn't increase performance in any way + .num_threads(num_threads) .build()?; - let (state_tx, state_rx) = crossbeam_channel::bounded(1); - let (job_tx, job_rx) = crossbeam_channel::bounded(1); + let (state_tx, state_rx) = crossbeam_channel::bounded(30); + let (job_tx, job_rx) = crossbeam_channel::bounded(30); let job_counter = AtomicU64::new(0); + let cache_clone = cache.clone(); + + let actors_in = Arc::new(Mutex::new(actors_in)); + let actors_in_clone = actors_in.clone(); pool.scope(|s| { s.spawn(move |_| { - actors_in + actors_in.lock() .for_each(|addr, state| { state_tx .send((addr, state.clone())) @@ -103,7 +117,12 @@ impl StateMigration { while let Ok((address, state)) = state_rx.recv() { let job_tx = job_tx.clone(); let migrator = self.migrations.get(&state.code).cloned().unwrap_or_else(|| panic!("migration failed with state code: {}", state.code)); - let cache_clone = cache.clone(); + + // Deferred migrations should be done at a later time. + if migrator.is_deferred() { + continue; + } + let cache_clone = cache_clone.clone(); scope.spawn(move |_| { let job = MigrationJob { address, @@ -146,6 +165,47 @@ impl StateMigration { } }); + // This is okay to execute even if there are no deferred migrations, as the iteration is + // very cheap; ~200ms on mainnet. The alternative is to collect the deferred migrations + // into a separate collection, which would increase the memory footprint of the migration. + tracing::info!("Processing deferred migrations"); + let mut job_counter = 0; + actors_in_clone.lock().for_each(|address, state| { + job_counter += 1; + let migrator = self + .migrations + .get(&state.code) + .cloned() + .unwrap_or_else(|| panic!("migration failed with state code: {}", state.code)); + + if !migrator.is_deferred() { + return Ok(()); + } + + let job = MigrationJob { + address, + actor_state: state.clone(), + actor_migration: migrator, + }; + let job_output = job.run(store, prior_epoch, cache.clone())?; + if let Some(MigrationJobOutput { + address, + actor_state, + }) = job_output + { + actors_out + .set_actor(&address, actor_state) + .unwrap_or_else(|e| { + panic!( + "Failed setting new actor state at given address: {address}, Reason: {e}" + ) + }); + } + + Ok(()) + })?; + tracing::info!("Processed {job_counter} deferred migrations"); + // execute post migration actions, e.g., create new actors for post_migrator in self.post_migrators.iter() { post_migrator.post_migrate_state(store, &mut actors_out)?; diff --git a/src/state_migration/mod.rs b/src/state_migration/mod.rs index ca6141208d1e..363ec1b68fc9 100644 --- a/src/state_migration/mod.rs +++ b/src/state_migration/mod.rs @@ -21,6 +21,7 @@ mod nv19; mod nv21; mod nv21fix; mod nv21fix2; +mod nv22; mod type_migrations; type RunMigration = fn(&ChainConfig, &Arc, &Cid, ChainEpoch) -> anyhow::Result; @@ -42,6 +43,7 @@ where (Height::Hygge, nv18::run_migration::), (Height::Lightning, nv19::run_migration::), (Height::Watermelon, nv21::run_migration::), + (Height::Dragon, nv22::run_migration::), ] } NetworkChain::Calibnet => { @@ -52,10 +54,11 @@ where (Height::Watermelon, nv21::run_migration::), (Height::WatermelonFix, nv21fix::run_migration::), (Height::WatermelonFix2, nv21fix2::run_migration::), + (Height::Dragon, nv22::run_migration::), ] } NetworkChain::Butterflynet => { - vec![(Height::Watermelon, nv21::run_migration::)] + vec![(Height::Dragon, nv22::run_migration::)] } NetworkChain::Devnet(_) => { vec![ @@ -63,6 +66,7 @@ where (Height::Hygge, nv18::run_migration::), (Height::Lightning, nv19::run_migration::), (Height::Watermelon, nv21::run_migration::), + (Height::Dragon, nv22::run_migration::), ] } }; diff --git a/src/state_migration/nv17/datacap.rs b/src/state_migration/nv17/datacap.rs index 01f4ecf1dd92..cfeedd37b046 100644 --- a/src/state_migration/nv17/datacap.rs +++ b/src/state_migration/nv17/datacap.rs @@ -14,6 +14,7 @@ use crate::state_migration::common::PostMigrator; use crate::utils::db::CborStoreExt; use cid::Cid; use fil_actors_shared::fvm_ipld_hamt::BytesKey; +use frc46_token::token::state::TokenState; use fvm_ipld_blockstore::Blockstore; use num_traits::Zero; use once_cell::sync::Lazy; @@ -73,8 +74,7 @@ impl PostMigrator for DataCapPostMigrator { verifreg_balance.into(), )?; - let mut token = - fil_actors_shared::frc46_token::TokenState::new_with_bit_width(&store, HAMT_BIT_WIDTH)?; + let mut token = TokenState::new_with_bit_width(store, HAMT_BIT_WIDTH)?; token.supply = TokenAmount::from_atto(token_supply).into(); token.balances = balances_map.flush()?; token.allowances = allowances_map.flush()?; diff --git a/src/state_migration/nv22/market.rs b/src/state_migration/nv22/market.rs new file mode 100644 index 000000000000..ea3dcb80a0d7 --- /dev/null +++ b/src/state_migration/nv22/market.rs @@ -0,0 +1,184 @@ +// Copyright 2019-2024 ChainSafe Systems +// SPDX-License-Identifier: Apache-2.0, MIT + +//! This module contains the migration logic for the `NV22` upgrade for the +//! Market actor. +use std::sync::Arc; + +use crate::shim::econ::TokenAmount; +use crate::utils::db::CborStoreExt; +use anyhow::Context; +use cid::Cid; +use fil_actor_market_state::v12::{ + DealProposal, DealState as DealStateOld, State as MarketStateOld, +}; +use fil_actor_market_state::v13::{ + DealState as DealStateNew, ProviderSectorsMap as ProviderSectorsMapNew, SectorDealIDs, + SectorDealsMap, State as MarketStateNew, PROVIDER_SECTORS_CONFIG, SECTOR_DEALS_CONFIG, + STATES_AMT_BITWIDTH, +}; + +use fil_actors_shared::v12::Array as ArrayOld; +use fil_actors_shared::v13::Array as ArrayNew; +use fvm_ipld_blockstore::Blockstore; +use fvm_ipld_encoding::CborStore; +use fvm_shared4::clock::ChainEpoch; + +use crate::state_migration::common::{ActorMigration, ActorMigrationInput, ActorMigrationOutput}; + +use super::miner::ProviderSectors; + +pub struct MarketMigrator { + upgrade_epoch: ChainEpoch, + provider_sectors: Arc, + out_cid: Cid, +} +pub(in crate::state_migration) fn market_migrator( + upgrade_epoch: ChainEpoch, + provider_sectors: Arc, + out_cid: Cid, +) -> anyhow::Result + Send + Sync>> { + Ok(Arc::new(MarketMigrator { + upgrade_epoch, + provider_sectors, + out_cid, + })) +} + +impl ActorMigration for MarketMigrator { + fn migrate_state( + &self, + store: &BS, + input: ActorMigrationInput, + ) -> anyhow::Result> { + let in_state: MarketStateOld = store + .get_cbor(&input.head)? + .context("failed to load state")?; + + let (provider_sectors, new_states) = + self.migrate_provider_sectors_and_states(store, &in_state.states, &in_state.proposals)?; + + let out_state = MarketStateNew { + proposals: in_state.proposals, + states: new_states, + pending_proposals: in_state.pending_proposals, + escrow_table: in_state.escrow_table, + locked_table: in_state.locked_table, + next_id: in_state.next_id, + deal_ops_by_epoch: in_state.deal_ops_by_epoch, + last_cron: in_state.last_cron, + total_client_locked_collateral: TokenAmount::from( + in_state.total_client_locked_collateral, + ) + .into(), + total_provider_locked_collateral: TokenAmount::from( + in_state.total_provider_locked_collateral, + ) + .into(), + total_client_storage_fee: TokenAmount::from(in_state.total_client_storage_fee).into(), + pending_deal_allocation_ids: in_state.pending_deal_allocation_ids, + provider_sectors, + }; + + let new_head = store.put_cbor_default(&out_state)?; + + Ok(Some(ActorMigrationOutput { + new_code_cid: self.out_cid, + new_head, + })) + } + + fn is_deferred(&self) -> bool { + true + } +} + +impl MarketMigrator { + fn migrate_provider_sectors_and_states( + &self, + store: &impl Blockstore, + states: &Cid, + proposals: &Cid, + ) -> anyhow::Result<(Cid, Cid)> { + //dbg!("running market migration"); + let (provider_sectors_root, new_state_array_root) = + self.migrate_provider_sectors_and_states_with_scratch(store, states, proposals)?; + + Ok((provider_sectors_root, new_state_array_root)) + } + + /// This method implements the migration logic as outlined in the [FIP-0076](https://github.com/filecoin-project/FIPs/blob/master/FIPS/fip-0076.md#migration) + // > For each deal state object in the market actor state that has a terminated epoch set to -1: + // > * find the corresponding deal proposal object and extract the provider's actor ID; + // > * in the provider's miner state, find the ID of the sector with the corresponding deal ID in sector metadata; + // > * if such a sector cannot be found, assert that the deal's end epoch has passed and use sector ID 0 [1]; + // > * set the new deal state object's sector number to the sector ID found; + // > * add the deal ID to the ProviderSectors mapping for the provider's actor ID and sector number. + // > For each deal state object in the market actor state that has a terminated epoch set to any other value: + // > * set the deal state object's sector number to 0. + fn migrate_provider_sectors_and_states_with_scratch( + &self, + store: &impl Blockstore, + states: &Cid, + proposals: &Cid, + ) -> anyhow::Result<(Cid, Cid)> { + let old_state_array = ArrayOld::::load(states, store)?; + let mut new_state_array = + ArrayNew::::new_with_bit_width(store, STATES_AMT_BITWIDTH); + + let proposals_array = ArrayOld::::load(proposals, store)?; + + old_state_array.for_each(|deal_id, old_state| { + let proposal = proposals_array + .get(deal_id)? + .context("deal proposal not found")?; + + let sector_number = + if old_state.slash_epoch == -1 && proposal.end_epoch >= self.upgrade_epoch { + // find the corresponding deal proposal object and extract the provider's actor ID; + self.provider_sectors + .deal_to_sector + .read() + .get(&deal_id) + .map(|sector_id| sector_id.number) + .unwrap_or(0) + } else { + 0 + }; + + let new_state = DealStateNew { + sector_number, + last_updated_epoch: old_state.last_updated_epoch, + sector_start_epoch: old_state.sector_start_epoch, + slash_epoch: old_state.slash_epoch, + }; + new_state_array.set(deal_id, new_state)?; + + Ok(()) + })?; + + let new_state_array_root = new_state_array.flush()?; + let mut out_provider_sectors = + ProviderSectorsMapNew::empty(store, PROVIDER_SECTORS_CONFIG, "provider sectors"); + + for (miner, sectors) in self.provider_sectors.miner_to_sector_to_deals.read().iter() { + let mut actor_sectors = + SectorDealsMap::empty(store, SECTOR_DEALS_CONFIG, "sector deals"); + + for (sector, deals) in sectors.iter() { + actor_sectors.set( + sector, + SectorDealIDs { + deals: deals.clone(), + }, + )?; + } + + out_provider_sectors.set(miner, actor_sectors.flush()?)?; + } + + let out_provider_sectors_root = out_provider_sectors.flush()?; + + Ok((out_provider_sectors_root, new_state_array_root)) + } +} diff --git a/src/state_migration/nv22/migration.rs b/src/state_migration/nv22/migration.rs new file mode 100644 index 000000000000..7a6591336814 --- /dev/null +++ b/src/state_migration/nv22/migration.rs @@ -0,0 +1,120 @@ +// Copyright 2019-2024 ChainSafe Systems +// SPDX-License-Identifier: Apache-2.0, MIT +// +//! This module contains the migration logic for the `NV22` upgrade. State migration logic +//! comes from the +//! [FIP-0076](https://github.com/filecoin-project/FIPs/blob/master/FIPS/fip-0076.md#migration). + +use std::sync::Arc; + +use crate::networks::{ChainConfig, Height}; +use crate::shim::{ + address::Address, + clock::ChainEpoch, + machine::{BuiltinActor, BuiltinActorManifest}, + state_tree::{StateTree, StateTreeVersion}, +}; +use anyhow::Context; +use cid::Cid; + +use fvm_ipld_blockstore::Blockstore; +use fvm_ipld_encoding::CborStore; + +use super::{market, miner, system, verifier::Verifier, SystemStateOld}; +use crate::state_migration::common::{migrators::nil_migrator, StateMigration}; + +impl StateMigration { + pub fn add_nv22_migrations( + &mut self, + store: &Arc, + state: &Cid, + new_manifest: &BuiltinActorManifest, + chain_config: &ChainConfig, + ) -> anyhow::Result<()> { + let upgrade_epoch = chain_config + .height_infos + .get(&Height::Dragon) + .context("no height info for network version NV22")? + .epoch; + + let state_tree = StateTree::new_from_root(store.clone(), state)?; + let system_actor = state_tree + .get_actor(&Address::new_id(0))? + .context("failed to get system actor")?; + + let system_actor_state = store + .get_cbor::(&system_actor.state)? + .context("system actor state not found")?; + + let current_manifest_data = system_actor_state.builtin_actors; + + let current_manifest = + BuiltinActorManifest::load_v1_actor_list(store, ¤t_manifest_data)?; + + for (name, code) in current_manifest.builtin_actors() { + let new_code = new_manifest.get(name)?; + self.add_migrator(code, nil_migrator(new_code)) + } + + let miner_old_code = current_manifest.get(BuiltinActor::Miner)?; + let miner_new_code = new_manifest.get(BuiltinActor::Miner)?; + + let market_old_code = current_manifest.get(BuiltinActor::Market)?; + let market_new_code = new_manifest.get(BuiltinActor::Market)?; + + let provider_sectors = Arc::new(miner::ProviderSectors::default()); + + self.add_migrator( + miner_old_code, + miner::miner_migrator(upgrade_epoch, provider_sectors.clone(), miner_new_code)?, + ); + + self.add_migrator( + market_old_code, + market::market_migrator(upgrade_epoch, provider_sectors.clone(), market_new_code)?, + ); + + self.add_migrator( + current_manifest.get_system(), + system::system_migrator(new_manifest), + ); + + Ok(()) + } +} + +/// Runs the migration for `NV22`. Returns the new state root. +pub fn run_migration( + chain_config: &ChainConfig, + blockstore: &Arc, + state: &Cid, + epoch: ChainEpoch, +) -> anyhow::Result +where + DB: Blockstore + Send + Sync, +{ + let new_manifest_cid = chain_config + .height_infos + .get(&Height::Dragon) + .context("no height info for network version NV22")? + .bundle + .as_ref() + .context("no bundle for network version NV22")?; + + blockstore.get(new_manifest_cid)?.context(format!( + "manifest for network version NV22 not found in blockstore: {new_manifest_cid}" + ))?; + + // Add migration specification verification + let verifier = Arc::new(Verifier::default()); + + let new_manifest = BuiltinActorManifest::load_manifest(blockstore, new_manifest_cid)?; + let mut migration = StateMigration::::new(Some(verifier)); + migration.add_nv22_migrations(blockstore, state, &new_manifest, chain_config)?; + + let actors_in = StateTree::new_from_root(blockstore.clone(), state)?; + let actors_out = StateTree::new(blockstore.clone(), StateTreeVersion::V5)?; + let new_state = migration.migrate_state_tree(blockstore, epoch, actors_in, actors_out)?; + + Ok(new_state) +} diff --git a/src/state_migration/nv22/miner.rs b/src/state_migration/nv22/miner.rs new file mode 100644 index 000000000000..0214fc47c5e3 --- /dev/null +++ b/src/state_migration/nv22/miner.rs @@ -0,0 +1,100 @@ +// Copyright 2019-2024 ChainSafe Systems +// SPDX-License-Identifier: Apache-2.0, MIT + +//! This module contains the migration logic for the `NV22` upgrade for the +//! Miner actor. While the `NV22` upgrade does not change the state of the +//! Miner actor, it does change the state of the Market actor, which requires +//! metadata from the Miner actor. +//! +//! As per [FIP-0076](https://github.com/filecoin-project/FIPs/blob/master/FIPS/fip-0076.md#backwards-compatibility) +//! > This proposal requires a state migration to the market actor to add the new `ProviderSectors` mapping, +//! > and to add a sector number to and remove allocation ID from each `DealState`. Computing this mapping +//! > requires reading all sector metadata from the miner actor. + +use crate::state_migration::common::{ActorMigration, ActorMigrationInput, ActorMigrationOutput}; +use ahash::HashMap; +use anyhow::Context; +use cid::Cid; +use fil_actor_miner_state::v12::State as MinerStateOld; +use fil_actors_shared::v12::Array as ArrayOld; +use fvm_ipld_blockstore::Blockstore; +use fvm_ipld_encoding::CborStore; +use fvm_shared4::clock::ChainEpoch; +use fvm_shared4::deal::DealID; +use fvm_shared4::sector::{SectorID, SectorNumber}; +use fvm_shared4::ActorID; +use parking_lot::RwLock; +use std::sync::Arc; + +#[derive(Default)] +pub struct ProviderSectors { + pub deal_to_sector: RwLock>, + pub miner_to_sector_to_deals: RwLock>>>, +} + +pub struct MinerMigrator { + upgrade_epoch: ChainEpoch, + provider_sectors: Arc, + out_cid: Cid, +} + +pub(in crate::state_migration) fn miner_migrator( + upgrade_epoch: ChainEpoch, + provider_sectors: Arc, + out_cid: Cid, +) -> anyhow::Result + Send + Sync>> { + Ok(Arc::new(MinerMigrator { + upgrade_epoch, + provider_sectors, + out_cid, + })) +} + +impl ActorMigration for MinerMigrator { + fn migrate_state( + &self, + store: &BS, + input: ActorMigrationInput, + ) -> anyhow::Result> { + let miner_id = input.address.id()?; + let in_state: MinerStateOld = store + .get_cbor(&input.head)? + .context("Miner actor: could not read v12 state")?; + + let in_sectors = ArrayOld::::load( + &in_state.sectors, + store, + )?; + + in_sectors.for_each(|i, sector| { + if sector.deal_ids.is_empty() || sector.expiration < self.upgrade_epoch { + return Ok(()); + } + + let mut sectors = self.provider_sectors.deal_to_sector.write(); + for deal_id in sector.deal_ids.iter() { + sectors.insert( + *deal_id, + SectorID { + miner: miner_id, + number: i, + }, + ); + } + drop(sectors); + + let mut sector_deals = self.provider_sectors.miner_to_sector_to_deals.write(); + sector_deals + .entry(miner_id) + .or_default() + .insert(i, sector.deal_ids.clone()); + + Ok(()) + })?; + + Ok(Some(ActorMigrationOutput { + new_code_cid: self.out_cid, + new_head: input.head, + })) + } +} diff --git a/src/state_migration/nv22/mod.rs b/src/state_migration/nv22/mod.rs new file mode 100644 index 000000000000..2289a0659ce9 --- /dev/null +++ b/src/state_migration/nv22/mod.rs @@ -0,0 +1,24 @@ +// Copyright 2019-2024 ChainSafe Systems +// SPDX-License-Identifier: Apache-2.0, MIT + +//! This module contains the migration logic for the `NV22` upgrade. +//! The corresponding Go implementation can be found here: +//! + +mod market; +mod migration; +mod miner; + +/// Run migration for `NV22`. This should be the only exported method in this +/// module. +pub use migration::run_migration; + +use crate::{define_system_states, impl_system, impl_verifier}; + +define_system_states!( + fil_actor_system_state::v12::State, + fil_actor_system_state::v13::State +); + +impl_system!(); +impl_verifier!();