forest/message/
chain_message.rs

1// Copyright 2019-2025 ChainSafe Systems
2// SPDX-License-Identifier: Apache-2.0, MIT
3
4use super::Message as MessageTrait;
5use crate::message::signed_message::SignedMessage;
6use crate::shim::message::MethodNum;
7use crate::shim::{address::Address, econ::TokenAmount, message::Message};
8use fvm_ipld_encoding::RawBytes;
9use get_size2::GetSize;
10use serde::{Deserialize, Serialize};
11
12/// `Enum` to encapsulate signed and unsigned messages. Useful when working with
13/// both types
14#[derive(Clone, Debug, Serialize, Deserialize, Hash, Eq, PartialEq, GetSize)]
15#[serde(untagged)]
16pub enum ChainMessage {
17    Unsigned(Message),
18    Signed(SignedMessage),
19}
20
21impl ChainMessage {
22    pub fn message(&self) -> &Message {
23        match self {
24            Self::Unsigned(m) => m,
25            Self::Signed(sm) => sm.message(),
26        }
27    }
28
29    pub fn cid(&self) -> cid::Cid {
30        match self {
31            ChainMessage::Unsigned(msg) => msg.cid(),
32            ChainMessage::Signed(msg) => msg.cid(),
33        }
34    }
35
36    /// Tests if a message is equivalent to another replacing message.
37    /// A replacing message is a message with a different CID,
38    /// any of Gas values, and different signature, but with all
39    /// other parameters matching (source/destination, nonce, parameters, etc.)
40    /// See <https://github.com/filecoin-project/lotus/blob/813d133c24295629ef442fc3aa60e6e6b2101226/chain/types/message.go#L138>
41    pub fn equal_call(&self, other: &Self) -> bool {
42        self.message().equal_call(other.message())
43    }
44}
45
46impl MessageTrait for ChainMessage {
47    fn from(&self) -> Address {
48        match self {
49            Self::Signed(t) => t.from(),
50            Self::Unsigned(t) => t.from,
51        }
52    }
53    fn to(&self) -> Address {
54        match self {
55            Self::Signed(t) => t.to(),
56            Self::Unsigned(t) => t.to,
57        }
58    }
59    fn sequence(&self) -> u64 {
60        match self {
61            Self::Signed(t) => t.sequence(),
62            Self::Unsigned(t) => t.sequence,
63        }
64    }
65    fn value(&self) -> TokenAmount {
66        match self {
67            Self::Signed(t) => t.value(),
68            Self::Unsigned(t) => t.value.clone(),
69        }
70    }
71    fn method_num(&self) -> MethodNum {
72        match self {
73            Self::Signed(t) => t.method_num(),
74            Self::Unsigned(t) => t.method_num,
75        }
76    }
77    fn params(&self) -> &RawBytes {
78        match self {
79            Self::Signed(t) => t.params(),
80            Self::Unsigned(t) => t.params(),
81        }
82    }
83    fn gas_limit(&self) -> u64 {
84        match self {
85            Self::Signed(t) => t.gas_limit(),
86            Self::Unsigned(t) => t.gas_limit(),
87        }
88    }
89    fn set_gas_limit(&mut self, token_amount: u64) {
90        match self {
91            Self::Signed(t) => t.set_gas_limit(token_amount),
92            Self::Unsigned(t) => t.set_gas_limit(token_amount),
93        }
94    }
95    fn set_sequence(&mut self, new_sequence: u64) {
96        match self {
97            Self::Signed(t) => t.set_sequence(new_sequence),
98            Self::Unsigned(t) => t.set_sequence(new_sequence),
99        }
100    }
101    fn required_funds(&self) -> TokenAmount {
102        match self {
103            Self::Signed(t) => t.required_funds(),
104            Self::Unsigned(t) => &t.gas_fee_cap * t.gas_limit + &t.value,
105        }
106    }
107    fn gas_fee_cap(&self) -> TokenAmount {
108        match self {
109            Self::Signed(t) => t.gas_fee_cap(),
110            Self::Unsigned(t) => t.gas_fee_cap.clone(),
111        }
112    }
113    fn gas_premium(&self) -> TokenAmount {
114        match self {
115            Self::Signed(t) => t.gas_premium(),
116            Self::Unsigned(t) => t.gas_premium.clone(),
117        }
118    }
119
120    fn set_gas_fee_cap(&mut self, cap: TokenAmount) {
121        match self {
122            Self::Signed(t) => t.set_gas_fee_cap(cap),
123            Self::Unsigned(t) => t.set_gas_fee_cap(cap),
124        }
125    }
126
127    fn set_gas_premium(&mut self, prem: TokenAmount) {
128        match self {
129            Self::Signed(t) => t.set_gas_premium(prem),
130            Self::Unsigned(t) => t.set_gas_premium(prem),
131        }
132    }
133}
134
135impl From<Message> for ChainMessage {
136    fn from(value: Message) -> Self {
137        Self::Unsigned(value)
138    }
139}
140
141impl From<SignedMessage> for ChainMessage {
142    fn from(value: SignedMessage) -> Self {
143        Self::Signed(value)
144    }
145}