diff --git a/Cargo.lock b/Cargo.lock index 0402d439..b8f170a3 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -764,6 +764,7 @@ dependencies = [ "fvm_shared 2.6.0", "fvm_shared 3.6.0", "fvm_shared 4.0.0", + "integer-encoding", "lazy_static", "multihash", "num", diff --git a/actors/multisig/src/v12/state.rs b/actors/multisig/src/v12/state.rs index f5d38a77..4421eaf9 100644 --- a/actors/multisig/src/v12/state.rs +++ b/actors/multisig/src/v12/state.rs @@ -5,11 +5,11 @@ use cid::Cid; use fil_actors_shared::v12::{ActorError, Config, Map2, DEFAULT_HAMT_CONFIG}; use fvm_ipld_blockstore::Blockstore; use fvm_ipld_encoding::tuple::*; -use fvm_shared::address::Address; -use fvm_shared::bigint::BigInt; -use fvm_shared::bigint::Integer; -use fvm_shared::clock::ChainEpoch; -use fvm_shared::econ::TokenAmount; +use fvm_shared4::address::Address; +use fvm_shared4::bigint::BigInt; +use fvm_shared4::bigint::Integer; +use fvm_shared4::clock::ChainEpoch; +use fvm_shared4::econ::TokenAmount; use indexmap::IndexMap; use num_traits::Zero; diff --git a/actors/multisig/src/v12/types.rs b/actors/multisig/src/v12/types.rs index 151dbbeb..c3689902 100644 --- a/actors/multisig/src/v12/types.rs +++ b/actors/multisig/src/v12/types.rs @@ -5,11 +5,11 @@ use std::fmt::Display; use fvm_ipld_encoding::tuple::*; use fvm_ipld_encoding::{strict_bytes, RawBytes}; -use fvm_shared::address::Address; -use fvm_shared::clock::ChainEpoch; -use fvm_shared::econ::TokenAmount; -use fvm_shared::error::ExitCode; -use fvm_shared::MethodNum; +use fvm_shared4::address::Address; +use fvm_shared4::clock::ChainEpoch; +use fvm_shared4::econ::TokenAmount; +use fvm_shared4::error::ExitCode; +use fvm_shared4::MethodNum; use serde::{Deserialize, Serialize}; use fil_actors_shared::v12::MapKey; diff --git a/fil_actor_interface/Cargo.toml b/fil_actor_interface/Cargo.toml index 4d0fb071..82ed2a9b 100644 --- a/fil_actor_interface/Cargo.toml +++ b/fil_actor_interface/Cargo.toml @@ -30,6 +30,7 @@ fvm_ipld_encoding.workspace = true fvm_shared = { workspace = true } fvm_shared3 = { workspace = true } fvm_shared4 = { workspace = true } +integer-encoding.workspace = true lazy_static.workspace = true multihash = { workspace = true, features = ["identity"] } num.workspace = true diff --git a/fil_actor_interface/src/builtin/multisig/mod.rs b/fil_actor_interface/src/builtin/multisig/mod.rs index 6434fee2..f4372787 100644 --- a/fil_actor_interface/src/builtin/multisig/mod.rs +++ b/fil_actor_interface/src/builtin/multisig/mod.rs @@ -1,12 +1,15 @@ // Copyright 2019-2023 ChainSafe Systems // SPDX-License-Identifier: Apache-2.0, MIT -use crate::convert::from_token_v3_to_v2; +use crate::convert::{ + from_address_v3_to_v2, from_address_v4_to_v2, from_token_v3_to_v2, from_token_v4_to_v2, +}; use anyhow::Context; use cid::Cid; use fvm_ipld_blockstore::Blockstore; -use fvm_shared::{clock::ChainEpoch, econ::TokenAmount}; -use serde::Serialize; +use fvm_ipld_encoding::RawBytes; +use fvm_shared::{address::Address, clock::ChainEpoch, econ::TokenAmount, MethodNum}; +use serde::{Deserialize, Serialize}; use crate::io::get_obj; @@ -21,7 +24,18 @@ pub enum State { V9(fil_actor_multisig_state::v9::State), V10(fil_actor_multisig_state::v10::State), V11(fil_actor_multisig_state::v11::State), - V12(fil_actor_multisig_state::v11::State), + V12(fil_actor_multisig_state::v12::State), +} + +/// Transaction type used in multisig actor +#[derive(Serialize, Deserialize, Clone, PartialEq, Eq, Debug)] +pub struct Transaction { + pub id: i64, + pub to: Address, + pub value: TokenAmount, + pub method: MethodNum, + pub params: RawBytes, + pub approved: Vec
, } pub fn is_v8_multisig_cid(cid: &Cid) -> bool { @@ -84,7 +98,57 @@ impl State { State::V9(st) => st.amount_locked(height), State::V10(st) => from_token_v3_to_v2(st.amount_locked(height)), State::V11(st) => from_token_v3_to_v2(st.amount_locked(height)), - State::V12(st) => from_token_v3_to_v2(st.amount_locked(height)), + State::V12(st) => from_token_v4_to_v2(st.amount_locked(height)), }) } + + /// Returns pending transactions for the given multisig wallet + pub fn get_pending_txn(&self, store: &BS) -> anyhow::Result> { + let mut res = Vec::new(); + match self { + State::V8(st) => { + let txns = fil_actors_shared::v8::make_map_with_root::< + BS, + fil_actor_multisig_state::v8::Transaction, + >(&st.pending_txs, store)?; + crate::parse_pending_transactions!(res, txns); + Ok(res) + } + State::V9(st) => { + let txns = fil_actors_shared::v9::make_map_with_root::< + BS, + fil_actor_multisig_state::v9::Transaction, + >(&st.pending_txs, store)?; + crate::parse_pending_transactions!(res, txns); + Ok(res) + } + State::V10(st) => { + let txns = fil_actors_shared::v10::make_map_with_root::< + BS, + fil_actor_multisig_state::v10::Transaction, + >(&st.pending_txs, store)?; + crate::parse_pending_transactions_v3!(res, txns); + Ok(res) + } + State::V11(st) => { + let txns = fil_actors_shared::v11::make_map_with_root::< + BS, + fil_actor_multisig_state::v11::Transaction, + >(&st.pending_txs, store)?; + crate::parse_pending_transactions_v3!(res, txns); + Ok(res) + } + State::V12(st) => { + let txns = fil_actor_multisig_state::v12::PendingTxnMap::load( + store, + &st.pending_txs, + fil_actor_multisig_state::v12::PENDING_TXN_CONFIG, + "pending txns", + ) + .expect("Could not load pending transactions"); + crate::parse_pending_transactions_v4!(res, txns); + Ok(res) + } + } + } } diff --git a/fil_actor_interface/src/lib.rs b/fil_actor_interface/src/lib.rs index 3211df19..136b742f 100644 --- a/fil_actor_interface/src/lib.rs +++ b/fil_actor_interface/src/lib.rs @@ -4,6 +4,7 @@ mod builtin; mod convert; mod io; +mod macros; mod r#mod; pub use self::builtin::*; diff --git a/fil_actor_interface/src/macros.rs b/fil_actor_interface/src/macros.rs new file mode 100644 index 00000000..628dc4d9 --- /dev/null +++ b/fil_actor_interface/src/macros.rs @@ -0,0 +1,90 @@ +// Copyright 2019-2022 ChainSafe Systems +// SPDX-License-Identifier: Apache-2.0, MIT + +/// This macro iterates over each transaction, decodes the transaction key using variable-length integer encoding, +/// and constructs a Transaction object with the decoded data. +/// +/// Parameters: +/// - `$res`: A mutable reference to a collection where the parsed transactions will be stored. +/// - `$txns`: A collection of transaction data to be parsed. +#[macro_export] +macro_rules! parse_pending_transactions { + ($res:ident, $txns:expr) => { + $txns.for_each(|tx_key, txn| { + match integer_encoding::VarInt::decode_var(&tx_key) { + Some((tx_id, _)) => { + $res.push(Transaction { + id: tx_id, + to: txn.to, + value: txn.value.clone(), + method: txn.method, + params: txn.params.clone(), + approved: txn.approved.clone(), + }); + } + None => anyhow::bail!("Error decoding varint"), + } + Ok(()) + })?; + }; +} + +/// This macro iterates over each transaction, decodes the transaction key, and constructs a Transaction object +/// with additional processing for address and token formats using `from_address_v3_to_v2` and `from_token_v3_to_v2`. +/// +/// Parameters: +/// - `$res`: A mutable reference to a collection where the parsed transactions will be stored. +/// - `$txns`: A collection of transaction data to be parsed. +#[macro_export] +macro_rules! parse_pending_transactions_v3 { + ($res:ident, $txns:expr) => { + $txns.for_each(|tx_key, txn| { + match integer_encoding::VarInt::decode_var(&tx_key) { + Some((tx_id, _)) => { + $res.push(Transaction { + id: tx_id, + to: from_address_v3_to_v2(txn.to), + value: from_token_v3_to_v2(txn.value.clone()), + method: txn.method, + params: txn.params.clone(), + approved: txn + .approved + .iter() + .map(|&addr| from_address_v3_to_v2(addr)) + .collect(), + }); + } + None => anyhow::bail!("Error decoding varint"), + } + Ok(()) + })?; + }; +} + +/// This macro iterates over each transaction, assumes that transaction id's are directly available and not encoded. +/// It constructs Transaction objects with transformations for address and token data from version 4 to version 2 +/// using `from_address_v4_to_v2` and `from_token_v4_to_v2`. +/// +/// Parameters: +/// - `$res`: A mutable reference to a collection where the parsed transactions will be stored. +/// - `$txns`: A collection of transaction data to be parsed. +#[macro_export] +macro_rules! parse_pending_transactions_v4 { + ($res:ident, $txns:expr) => { + $txns.for_each(|tx_id, txn| { + $res.push(Transaction { + id: tx_id.0, + to: from_address_v4_to_v2(txn.to), + value: from_token_v4_to_v2(txn.value.clone()), + method: txn.method, + params: txn.params.clone(), + approved: txn + .approved + .iter() + .map(|&addr| from_address_v4_to_v2(addr)) + .collect(), + }); + Ok(()) + })?; + }; +}