diff --git a/CHANGELOG.md b/CHANGELOG.md index 97fff86f534e..1719f009c10c 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -41,7 +41,6 @@ - [#6014](https://github.com/ChainSafe/forest/pull/6014) Removed `unordered-graph-traversal` from `forest-tool benchmark`. - ### Fixed ## Forest v0.29.0 "Fëanor" diff --git a/src/lotus_json/actor_states/methods/mod.rs b/src/lotus_json/actor_states/methods/mod.rs index 0e66dd969862..43f5957b5e8b 100644 --- a/src/lotus_json/actor_states/methods/mod.rs +++ b/src/lotus_json/actor_states/methods/mod.rs @@ -12,6 +12,7 @@ mod init_exec4_params; mod init_exec_params; mod miner_actor_params; mod multisig_actor; +mod paych_params; mod power_actor; mod reward_methods; pub mod verified_reg_actor; diff --git a/src/lotus_json/actor_states/methods/paych_params.rs b/src/lotus_json/actor_states/methods/paych_params.rs new file mode 100644 index 000000000000..42901f7dc381 --- /dev/null +++ b/src/lotus_json/actor_states/methods/paych_params.rs @@ -0,0 +1,546 @@ +// Copyright 2019-2025 ChainSafe Systems +// SPDX-License-Identifier: Apache-2.0, MIT + +use super::*; +use crate::shim::address::Address; +use crate::shim::clock::ChainEpoch; +use crate::shim::econ::TokenAmount; +use fvm_ipld_encoding::RawBytes; +use paste::paste; +use schemars::JsonSchema; +use serde::{Deserialize, Serialize}; + +#[derive(Serialize, Deserialize, JsonSchema, Debug, Clone, PartialEq)] +#[serde(rename_all = "PascalCase")] +pub struct ConstructorParamsLotusJson { + #[schemars(with = "LotusJson
")] + #[serde(with = "crate::lotus_json")] + pub from: Address, + #[schemars(with = "LotusJson
")] + #[serde(with = "crate::lotus_json")] + pub to: Address, +} + +#[derive(Serialize, Deserialize, JsonSchema, Debug, Clone, PartialEq)] +#[serde(rename_all = "PascalCase")] +pub struct ModVerifyParamsLotusJson { + #[schemars(with = "LotusJson
")] + #[serde(with = "crate::lotus_json")] + pub actor: Address, + pub method: u64, + #[schemars(with = "LotusJson")] + #[serde(with = "crate::lotus_json")] + pub data: RawBytes, +} + +#[derive(Serialize, Deserialize, JsonSchema, Debug, Clone, PartialEq)] +#[serde(rename_all = "PascalCase")] +pub struct MergeLotusJson { + pub lane: u64, + pub nonce: u64, +} + +// Version-specific structs for different FVM versions to avoid conversion issues +#[derive(Serialize, Deserialize, JsonSchema, Debug, Clone, PartialEq)] +#[serde(rename_all = "PascalCase")] +pub struct SignedVoucherV2LotusJson { + #[schemars(with = "LotusJson
")] + #[serde(with = "crate::lotus_json")] + pub channel_addr: Address, + #[schemars(with = "LotusJson")] + #[serde(with = "crate::lotus_json")] + pub time_lock_min: ChainEpoch, + #[schemars(with = "LotusJson")] + #[serde(with = "crate::lotus_json")] + pub time_lock_max: ChainEpoch, + #[schemars(with = "LotusJson>")] + #[serde(with = "crate::lotus_json", rename = "SecretHash")] + pub secret_pre_image: Vec, + pub extra: Option, + pub lane: u64, + pub nonce: u64, + #[schemars(with = "LotusJson")] + #[serde(with = "crate::lotus_json")] + pub amount: TokenAmount, + #[schemars(with = "LotusJson")] + #[serde(with = "crate::lotus_json")] + pub min_settle_height: ChainEpoch, + // Lotus returns null (not []) when there are no merges; model as Option, so None means empty. + pub merges: Option>, + #[schemars(with = "LotusJson>")] + #[serde(with = "crate::lotus_json")] + pub signature: Option, +} + +#[derive(Serialize, Deserialize, JsonSchema, Debug, Clone, PartialEq)] +#[serde(rename_all = "PascalCase")] +pub struct SignedVoucherV3LotusJson { + #[schemars(with = "LotusJson
")] + #[serde(with = "crate::lotus_json")] + pub channel_addr: Address, + #[schemars(with = "LotusJson")] + #[serde(with = "crate::lotus_json")] + pub time_lock_min: ChainEpoch, + #[schemars(with = "LotusJson")] + #[serde(with = "crate::lotus_json")] + pub time_lock_max: ChainEpoch, + #[schemars(with = "LotusJson>")] + #[serde(with = "crate::lotus_json", rename = "SecretHash")] + pub secret_pre_image: Vec, + pub extra: Option, + pub lane: u64, + pub nonce: u64, + #[schemars(with = "LotusJson")] + #[serde(with = "crate::lotus_json")] + pub amount: TokenAmount, + #[schemars(with = "LotusJson")] + #[serde(with = "crate::lotus_json")] + pub min_settle_height: ChainEpoch, + // Lotus returns null (not []) when there are no merges; model as Option, so None means empty. + pub merges: Option>, + #[schemars(with = "LotusJson>")] + #[serde(with = "crate::lotus_json")] + pub signature: Option, +} + +#[derive(Serialize, Deserialize, JsonSchema, Debug, Clone, PartialEq)] +#[serde(rename_all = "PascalCase")] +pub struct SignedVoucherV4LotusJson { + #[schemars(with = "LotusJson
")] + #[serde(with = "crate::lotus_json")] + pub channel_addr: Address, + #[schemars(with = "LotusJson")] + #[serde(with = "crate::lotus_json")] + pub time_lock_min: ChainEpoch, + #[schemars(with = "LotusJson")] + #[serde(with = "crate::lotus_json")] + pub time_lock_max: ChainEpoch, + #[schemars(with = "LotusJson>")] + #[serde(with = "crate::lotus_json", rename = "SecretHash")] + pub secret_pre_image: Vec, + pub extra: Option, + pub lane: u64, + pub nonce: u64, + #[schemars(with = "LotusJson")] + #[serde(with = "crate::lotus_json")] + pub amount: TokenAmount, + #[schemars(with = "LotusJson")] + #[serde(with = "crate::lotus_json")] + pub min_settle_height: ChainEpoch, + // Lotus returns null (not []) when there are no merges; model as Option, so None means empty. + pub merges: Option>, + #[schemars(with = "LotusJson>")] + #[serde(with = "crate::lotus_json")] + pub signature: Option, +} + +#[derive(Serialize, Deserialize, Debug, Clone, PartialEq)] +#[serde(rename_all = "PascalCase")] +pub struct UpdateChannelStateParamsV2LotusJson { + pub sv: SignedVoucherV2LotusJson, + #[serde(with = "crate::lotus_json")] + pub secret: Vec, +} + +#[derive(Serialize, Deserialize, Debug, Clone, PartialEq)] +#[serde(rename_all = "PascalCase")] +pub struct UpdateChannelStateParamsV3LotusJson { + pub sv: SignedVoucherV3LotusJson, + #[serde(with = "crate::lotus_json")] + pub secret: Vec, +} + +#[derive(Serialize, Deserialize, JsonSchema, Debug, Clone, PartialEq)] +#[serde(rename_all = "PascalCase")] +pub struct UpdateChannelStateParamsV4LotusJson { + pub sv: SignedVoucherV4LotusJson, + #[schemars(with = "LotusJson>")] + #[serde(with = "crate::lotus_json")] + pub secret: Vec, +} + +// Implementation for ConstructorParams +macro_rules! impl_paych_constructor_params { + ($($version:literal),+) => { + $( + paste! { + impl HasLotusJson for fil_actor_paych_state::[]::ConstructorParams { + type LotusJson = ConstructorParamsLotusJson; + + #[cfg(test)] + fn snapshots() -> Vec<(serde_json::Value, Self)> { + vec![ + ( + json!({ + "From": "f01234", + "To": "f01235" + }), + Self { + from: Address::new_id(1234).into(), + to: Address::new_id(1235).into(), + }, + ), + ] + } + + fn into_lotus_json(self) -> Self::LotusJson { + ConstructorParamsLotusJson { + from: self.from.into(), + to: self.to.into(), + } + } + + fn from_lotus_json(lotus_json: Self::LotusJson) -> Self { + Self { + from: lotus_json.from.into(), + to: lotus_json.to.into(), + } + } + } + } + )+ + }; +} + +// Implementation for UpdateChannelStateParams with version-specific types +macro_rules! impl_paych_update_channel_state_params_v2 { + ($($version:literal),+) => { + $( + paste! { + impl HasLotusJson for fil_actor_paych_state::[]::UpdateChannelStateParams { + type LotusJson = UpdateChannelStateParamsV2LotusJson; + + #[cfg(test)] + fn snapshots() -> Vec<(serde_json::Value, Self)> { + vec![ + ( + json!({ + "Sv": { + "ChannelAddr": "f01234", + "TimeLockMin": 0, + "TimeLockMax": 0, + "SecretPreImage": "", + "Extra": null, + "Lane": 0, + "Nonce": 1, + "Amount": "1000", + "MinSettleHeight": 0, + "Merges": [], + "Signature": null + }, + "Secret": "" + }), + Self { + sv: fil_actor_paych_state::[]::SignedVoucher { + channel_addr: Address::new_id(1234).into(), + time_lock_min: 0, + time_lock_max: 0, + secret_pre_image: vec![], + extra: None, + lane: 0, + nonce: 1, + amount: TokenAmount::from_atto(1000).into(), + min_settle_height: 0, + merges: vec![], + signature: None, + }, + secret: vec![], + }, + ), + ] + } + + fn into_lotus_json(self) -> Self::LotusJson { + UpdateChannelStateParamsV2LotusJson { + sv: SignedVoucherV2LotusJson { + channel_addr: self.sv.channel_addr.into(), + time_lock_min: self.sv.time_lock_min, + time_lock_max: self.sv.time_lock_max, + secret_pre_image: self.sv.secret_pre_image, + extra: self.sv.extra.map(|e| ModVerifyParamsLotusJson { + actor: e.actor.into(), + method: e.method, + data: e.data, + }), + lane: self.sv.lane, + nonce: self.sv.nonce, + amount: self.sv.amount.into(), + min_settle_height: self.sv.min_settle_height, + merges: if self.sv.merges.is_empty() { + None + } else { + Some(self.sv.merges.into_iter().map(|m| MergeLotusJson { + lane: m.lane, + nonce: m.nonce, + }).collect()) + }, + signature: self.sv.signature, + }, + secret: self.secret, + } + } + + fn from_lotus_json(lotus_json: Self::LotusJson) -> Self { + Self { + sv: fil_actor_paych_state::[]::SignedVoucher { + channel_addr: lotus_json.sv.channel_addr.into(), + time_lock_min: lotus_json.sv.time_lock_min, + time_lock_max: lotus_json.sv.time_lock_max, + secret_pre_image: lotus_json.sv.secret_pre_image, + extra: lotus_json.sv.extra.map(|e| fil_actor_paych_state::[]::ModVerifyParams { + actor: e.actor.into(), + method: e.method, + data: e.data, + }), + lane: lotus_json.sv.lane, + nonce: lotus_json.sv.nonce, + amount: lotus_json.sv.amount.into(), + min_settle_height: lotus_json.sv.min_settle_height, + merges: if lotus_json.sv.merges.is_none() { + vec![] + } else { + lotus_json.sv.merges.unwrap().into_iter().map(|m| fil_actor_paych_state::[]::Merge { + lane: m.lane, + nonce: m.nonce, + }).collect() + }, + signature: lotus_json.sv.signature, + }, + secret: lotus_json.secret, + } + } + } + } + )+ + }; +} + +macro_rules! impl_paych_update_channel_state_params_v3 { + ($($version:literal),+) => { + $( + paste! { + impl HasLotusJson for fil_actor_paych_state::[]::UpdateChannelStateParams { + type LotusJson = UpdateChannelStateParamsV3LotusJson; + + #[cfg(test)] + fn snapshots() -> Vec<(serde_json::Value, Self)> { + vec![ + ( + json!({ + "Sv": { + "ChannelAddr": "f01234", + "TimeLockMin": 0, + "TimeLockMax": 0, + "SecretPreImage": "", + "Extra": null, + "Lane": 0, + "Nonce": 1, + "Amount": "1000", + "MinSettleHeight": 0, + "Merges": [], + "Signature": null + }, + "Secret": "" + }), + Self { + sv: fil_actor_paych_state::[]::SignedVoucher { + channel_addr: Address::new_id(1234).into(), + time_lock_min: 0, + time_lock_max: 0, + secret_pre_image: vec![], + extra: None, + lane: 0, + nonce: 1, + amount: TokenAmount::from_atto(1000).into(), + min_settle_height: 0, + merges: vec![], + signature: None, + }, + secret: vec![], + }, + ), + ] + } + + fn into_lotus_json(self) -> Self::LotusJson { + UpdateChannelStateParamsV3LotusJson { + sv: SignedVoucherV3LotusJson { + channel_addr: self.sv.channel_addr.into(), + time_lock_min: self.sv.time_lock_min, + time_lock_max: self.sv.time_lock_max, + secret_pre_image: self.sv.secret_pre_image, + extra: self.sv.extra.map(|e| ModVerifyParamsLotusJson { + actor: e.actor.into(), + method: e.method, + data: e.data, + }), + lane: self.sv.lane, + nonce: self.sv.nonce, + amount: self.sv.amount.into(), + min_settle_height: self.sv.min_settle_height, + merges: if self.sv.merges.is_empty() { + None + } else { + Some(self.sv.merges.into_iter().map(|m| MergeLotusJson { + lane: m.lane, + nonce: m.nonce, + }).collect()) + }, + signature: self.sv.signature, + }, + secret: self.secret, + } + } + + fn from_lotus_json(lotus_json: Self::LotusJson) -> Self { + Self { + sv: fil_actor_paych_state::[]::SignedVoucher { + channel_addr: lotus_json.sv.channel_addr.into(), + time_lock_min: lotus_json.sv.time_lock_min, + time_lock_max: lotus_json.sv.time_lock_max, + secret_pre_image: lotus_json.sv.secret_pre_image, + extra: lotus_json.sv.extra.map(|e| fil_actor_paych_state::[]::ModVerifyParams { + actor: e.actor.into(), + method: e.method, + data: e.data, + }), + lane: lotus_json.sv.lane, + nonce: lotus_json.sv.nonce, + amount: lotus_json.sv.amount.into(), + min_settle_height: lotus_json.sv.min_settle_height, + merges: if lotus_json.sv.merges.is_none() { + vec![] + } else { + lotus_json.sv.merges.unwrap().into_iter().map(|m| fil_actor_paych_state::[]::Merge { + lane: m.lane, + nonce: m.nonce, + }).collect() + }, + signature: lotus_json.sv.signature, + }, + secret: lotus_json.secret, + } + } + } + } + )+ + }; +} + +macro_rules! impl_paych_update_channel_state_params_v4 { + ($($version:literal),+) => { + $( + paste! { + impl HasLotusJson for fil_actor_paych_state::[]::UpdateChannelStateParams { + type LotusJson = UpdateChannelStateParamsV4LotusJson; + + #[cfg(test)] + fn snapshots() -> Vec<(serde_json::Value, Self)> { + vec![ + ( + json!({ + "Sv": { + "ChannelAddr": "f01234", + "TimeLockMin": 0, + "TimeLockMax": 0, + "SecretPreImage": "", + "Extra": null, + "Lane": 0, + "Nonce": 1, + "Amount": "1000", + "MinSettleHeight": 0, + "Merges": [], + "Signature": null + }, + "Secret": "" + }), + Self { + sv: fil_actor_paych_state::[]::SignedVoucher { + channel_addr: Address::new_id(1234).into(), + time_lock_min: 0, + time_lock_max: 0, + secret_pre_image: vec![], + extra: None, + lane: 0, + nonce: 1, + amount: TokenAmount::from_atto(1000).into(), + min_settle_height: 0, + merges: vec![], + signature: None, + }, + secret: vec![], + }, + ), + ] + } + + fn into_lotus_json(self) -> Self::LotusJson { + UpdateChannelStateParamsV4LotusJson { + sv: SignedVoucherV4LotusJson { + channel_addr: self.sv.channel_addr.into(), + time_lock_min: self.sv.time_lock_min, + time_lock_max: self.sv.time_lock_max, + secret_pre_image: self.sv.secret_pre_image, + extra: self.sv.extra.map(|e| ModVerifyParamsLotusJson { + actor: e.actor.into(), + method: e.method, + data: e.data, + }), + lane: self.sv.lane, + nonce: self.sv.nonce, + amount: self.sv.amount.into(), + min_settle_height: self.sv.min_settle_height, + merges: if self.sv.merges.is_empty() { + None + } else { + Some(self.sv.merges.into_iter().map(|m| MergeLotusJson { + lane: m.lane, + nonce: m.nonce, + }).collect()) + }, + signature: self.sv.signature, + }, + secret: self.secret, + } + } + + fn from_lotus_json(lotus_json: Self::LotusJson) -> Self { + Self { + sv: fil_actor_paych_state::[]::SignedVoucher { + channel_addr: lotus_json.sv.channel_addr.into(), + time_lock_min: lotus_json.sv.time_lock_min, + time_lock_max: lotus_json.sv.time_lock_max, + secret_pre_image: lotus_json.sv.secret_pre_image, + extra: lotus_json.sv.extra.map(|e| fil_actor_paych_state::[]::ModVerifyParams { + actor: e.actor.into(), + method: e.method, + data: e.data, + }), + lane: lotus_json.sv.lane, + nonce: lotus_json.sv.nonce, + amount: lotus_json.sv.amount.into(), + min_settle_height: lotus_json.sv.min_settle_height, + merges: if lotus_json.sv.merges.is_none() { + vec![] + } else { + lotus_json.sv.merges.unwrap().into_iter().map(|m| fil_actor_paych_state::[]::Merge { + lane: m.lane, + nonce: m.nonce, + }).collect() + }, + signature: lotus_json.sv.signature, + }, + secret: lotus_json.secret, + } + } + } + } + )+ + }; +} + +// Apply implementations with correct fvm_shared versions +impl_paych_constructor_params!(8, 9, 10, 11, 12, 13, 14, 15, 16); +impl_paych_update_channel_state_params_v2!(8, 9); +impl_paych_update_channel_state_params_v3!(10, 11); +impl_paych_update_channel_state_params_v4!(12, 13, 14, 15, 16); diff --git a/src/rpc/registry/actors/mod.rs b/src/rpc/registry/actors/mod.rs index 74b9506ee84a..ba401be54969 100644 --- a/src/rpc/registry/actors/mod.rs +++ b/src/rpc/registry/actors/mod.rs @@ -9,6 +9,7 @@ pub(crate) mod evm; pub(crate) mod init; pub(crate) mod miner; pub(crate) mod multisig; +pub(crate) mod payment_channel; pub(crate) mod power; pub(crate) mod reward; pub(crate) mod system; diff --git a/src/rpc/registry/actors/payment_channel.rs b/src/rpc/registry/actors/payment_channel.rs new file mode 100644 index 000000000000..7176c4484d60 --- /dev/null +++ b/src/rpc/registry/actors/payment_channel.rs @@ -0,0 +1,45 @@ +// Copyright 2019-2025 ChainSafe Systems +// SPDX-License-Identifier: Apache-2.0, MIT + +use crate::rpc::registry::methods_reg::{MethodRegistry, register_actor_methods}; +use crate::shim::message::MethodNum; +use cid::Cid; + +macro_rules! register_payment_channel_reg_versions { + ($registry:expr, $code_cid:expr, $version:literal) => {{ + paste::paste!{ + use fil_actor_paych_state::[]::{ConstructorParams, Method, UpdateChannelStateParams}; + } + + // Register methods with parameters + register_actor_methods!( + $registry, + $code_cid, + [ + (Method::Constructor, ConstructorParams), + (Method::UpdateChannelState, UpdateChannelStateParams), + ] + ); + + // Register methods without parameters + register_actor_methods!( + $registry, + $code_cid, + [(Method::Settle, empty), (Method::Collect, empty),] + ); + }}; +} + +pub(crate) fn register_actor_methods(registry: &mut MethodRegistry, cid: Cid, version: u64) { + macro_rules! register_versions { + ($($version:literal),+) => {{ + match version { + $( + $version => register_payment_channel_reg_versions!(registry, cid, $version), + )+ + _ => {} + } + }}; + } + register_versions!(8, 9, 10, 11, 12, 13, 14, 15, 16) +} diff --git a/src/rpc/registry/methods_reg.rs b/src/rpc/registry/methods_reg.rs index ffe2a41f5349..f75f982e323b 100644 --- a/src/rpc/registry/methods_reg.rs +++ b/src/rpc/registry/methods_reg.rs @@ -74,8 +74,8 @@ impl MethodRegistry { fn register_known_methods(&mut self) { use crate::rpc::registry::actors::{ - account, cron, datacap, eth_account, evm, init, miner, multisig, power, reward, system, - verified_reg, + account, cron, datacap, eth_account, evm, init, miner, multisig, payment_channel, + power, reward, system, verified_reg, }; for (&cid, &(actor_type, version)) in ACTOR_REGISTRY.iter() { @@ -98,6 +98,9 @@ impl MethodRegistry { verified_reg::register_actor_methods(self, cid, version) } BuiltinActor::EthAccount => eth_account::register_actor_methods(self, cid, version), + BuiltinActor::PaymentChannel => { + payment_channel::register_actor_methods(self, cid, version) + } _ => {} } } diff --git a/src/tool/subcommands/api_cmd/api_compare_tests.rs b/src/tool/subcommands/api_cmd/api_compare_tests.rs index 8b6abd43a994..509a325a6ab0 100644 --- a/src/tool/subcommands/api_cmd/api_compare_tests.rs +++ b/src/tool/subcommands/api_cmd/api_compare_tests.rs @@ -1902,10 +1902,70 @@ fn state_decode_params_api_tests(tipset: &Tipset) -> anyhow::Result tests.extend(datacap_actor_state_decode_params_tests(tipset)?); tests.extend(multisig_actor_state_decode_params_tests(tipset)?); tests.extend(verified_reg_actor_state_decode_params_tests(tipset)?); + tests.extend(paych_actor_state_decode_params_tests(tipset)?); Ok(tests) } +fn paych_actor_state_decode_params_tests(tipset: &Tipset) -> anyhow::Result> { + // payment channel actor address `t066116` + // https://calibration.filscan.io/en/address/t066116/ + let paych_address = Address::new_id(66116); + + let constructor_params = fil_actor_paych_state::v16::ConstructorParams { + from: Address::new_id(1234).into(), + to: Address::new_id(8457).into(), + }; + + let update_channel_state = fil_actor_paych_state::v16::UpdateChannelStateParams { + sv: fil_actor_paych_state::v16::SignedVoucher { + channel_addr: Address::new_id(1000).into(), + time_lock_min: 21, + time_lock_max: 234, + secret_pre_image: vec![], + extra: Some(fil_actor_paych_state::v16::ModVerifyParams { + actor: Address::new_id(1234).into(), + method: 223, + data: Default::default(), + }), + lane: 234, + nonce: 231, + amount: Default::default(), + min_settle_height: 0, + merges: vec![], + signature: None, + }, + secret: vec![0x11, 0x22, 0x33, 0x44, 0x55], // dummy data + }; + + Ok(vec![ + RpcTest::identity(StateDecodeParams::request(( + paych_address, + fil_actor_paych_state::v16::Method::Constructor as u64, + to_vec(&constructor_params).unwrap(), + tipset.key().into(), + ))?), + RpcTest::identity(StateDecodeParams::request(( + paych_address, + fil_actor_paych_state::v16::Method::UpdateChannelState as u64, + to_vec(&update_channel_state).unwrap(), + tipset.key().into(), + ))?), + RpcTest::identity(StateDecodeParams::request(( + paych_address, + fil_actor_paych_state::v16::Method::Settle as u64, + vec![], + tipset.key().into(), + ))?), + RpcTest::identity(StateDecodeParams::request(( + paych_address, + fil_actor_paych_state::v16::Method::Collect as u64, + vec![], + tipset.key().into(), + ))?), + ]) +} + fn evm_actor_state_decode_params_tests(tipset: &Tipset) -> anyhow::Result> { let evm_constructor_params = fil_actor_evm_state::v16::ConstructorParams { creator: fil_actor_evm_state::evm_shared::v16::address::EthAddress([0; 20]), diff --git a/src/tool/subcommands/api_cmd/test_snapshots.txt b/src/tool/subcommands/api_cmd/test_snapshots.txt index 28c16f60d4d1..ec8d9e169818 100644 --- a/src/tool/subcommands/api_cmd/test_snapshots.txt +++ b/src/tool/subcommands/api_cmd/test_snapshots.txt @@ -251,6 +251,10 @@ filecoin_miner_statedecodeparams_1755027105573353.rpcsnap.json.zst filecoin_miner_statedecodeparams_1755027105571760.rpcsnap.json.zst filecoin_miner_statedecodeparams_1755027105573989.rpcsnap.json.zst filecoin_ethaccount_statedecodeparams_1756186350854913.rpcsnap.json.zst +filecoin_payment_channel_statedecodeparams_1756194613312797.rpcsnap.json.zst +filecoin_payment_channel_statedecodeparams_1756194613312868.rpcsnap.json.zst +filecoin_payment_channel_statedecodeparams_1756194613312941.rpcsnap.json.zst +filecoin_payment_channel_statedecodeparams_1756194613313007.rpcsnap.json.zst filecoin_statereplay_1743504051038215.rpcsnap.json.zst filecoin_statesearchmsg_1741784596636715.rpcsnap.json.zst filecoin_statesearchmsglimited_1741784596704876.rpcsnap.json.zst