cfx_parity_trace_types/
action_types.rs

1// Copyright 2020 Conflux Foundation. All rights reserved.
2// Conflux is free software and distributed under GNU General Public License.
3// See http://www.gnu.org/licenses/
4
5use cfx_bytes::Bytes;
6
7use crate::AddressPocket;
8use cfx_types::{Address, Bloom, BloomInput, Space, U256};
9use cfx_vm_types::{ActionParams, CallType, CreateType};
10use rlp::{Decodable, DecoderError, Encodable, Rlp, RlpStream};
11use rlp_derive::{RlpDecodable, RlpEncodable};
12use serde::{ser::SerializeStruct, Serialize, Serializer};
13use strum_macros::EnumDiscriminants;
14
15/// Description of a _call_ action, either a `CALL` operation or a message
16/// transaction.
17#[derive(Debug, Clone, PartialEq, RlpEncodable, Serialize)]
18#[serde(rename_all = "camelCase")]
19pub struct Call {
20    /// The space
21    pub space: Space,
22    /// The sending account.
23    pub from: Address,
24    /// The destination account.
25    pub to: Address,
26    /// The value transferred to the destination account.
27    pub value: U256,
28    /// The gas available for executing the call.
29    pub gas: U256,
30    /// The input data provided to the call.
31    pub input: Bytes,
32    /// The type of the call.
33    pub call_type: CallType,
34}
35
36impl Decodable for Call {
37    fn decode(rlp: &Rlp) -> Result<Self, DecoderError> {
38        match rlp.item_count()? {
39            6 => Ok(Call {
40                space: Space::Native,
41                from: rlp.val_at(0)?,
42                to: rlp.val_at(1)?,
43                value: rlp.val_at(2)?,
44                gas: rlp.val_at(3)?,
45                input: rlp.val_at(4)?,
46                call_type: rlp.val_at(5)?,
47            }),
48            7 => Ok(Call {
49                space: rlp.val_at(0)?,
50                from: rlp.val_at(1)?,
51                to: rlp.val_at(2)?,
52                value: rlp.val_at(3)?,
53                gas: rlp.val_at(4)?,
54                input: rlp.val_at(5)?,
55                call_type: rlp.val_at(6)?,
56            }),
57            _ => Err(DecoderError::RlpInvalidLength),
58        }
59    }
60}
61
62impl From<ActionParams> for Call {
63    fn from(p: ActionParams) -> Self {
64        match p.call_type {
65            CallType::DelegateCall | CallType::CallCode => Call {
66                space: p.space,
67                from: p.address,
68                to: p.code_address,
69                value: p.value.value(),
70                gas: p.gas,
71                input: p.data.unwrap_or_else(Vec::new),
72                call_type: p.call_type,
73            },
74            _ => Call {
75                space: p.space,
76                from: p.sender,
77                to: p.address,
78                value: p.value.value(),
79                gas: p.gas,
80                input: p.data.unwrap_or_else(Vec::new),
81                call_type: p.call_type,
82            },
83        }
84    }
85}
86
87impl Call {
88    /// Returns call action bloom.
89    /// The bloom contains from and to addresses.
90    pub fn bloom(&self) -> Bloom {
91        let mut bloom = Bloom::default();
92        bloom.accrue(BloomInput::Raw(self.from.as_bytes()));
93        bloom.accrue(BloomInput::Raw(self.to.as_bytes()));
94        bloom
95    }
96}
97
98/// The outcome of the action result.
99#[derive(Debug, PartialEq, Clone, Serialize)]
100#[serde(rename_all = "lowercase")]
101pub enum Outcome {
102    Success,
103    Reverted,
104    Fail,
105}
106
107impl Encodable for Outcome {
108    fn rlp_append(&self, s: &mut RlpStream) {
109        let v = match *self {
110            Outcome::Success => 0u32,
111            Outcome::Reverted => 1,
112            Outcome::Fail => 2,
113        };
114        Encodable::rlp_append(&v, s);
115    }
116}
117
118impl Decodable for Outcome {
119    fn decode(rlp: &Rlp) -> Result<Self, DecoderError> {
120        rlp.as_val().and_then(|v| {
121            Ok(match v {
122                0u32 => Outcome::Success,
123                1 => Outcome::Reverted,
124                2 => Outcome::Fail,
125                _ => {
126                    return Err(DecoderError::Custom(
127                        "Invalid value of Outcome item",
128                    ));
129                }
130            })
131        })
132    }
133}
134
135/// Description of the result of a _call_ action.
136#[derive(Debug, Clone, PartialEq, RlpEncodable, RlpDecodable, Serialize)]
137#[serde(rename_all = "camelCase")]
138pub struct CallResult {
139    /// The outcome of the result
140    pub outcome: Outcome,
141    /// The amount of gas left
142    pub gas_left: U256,
143    /// Output data
144    pub return_data: Bytes,
145}
146
147/// Description of a _create_ action, either a `CREATE` operation or a create
148/// transaction.
149#[derive(Debug, Clone, PartialEq, RlpEncodable, Serialize)]
150#[serde(rename_all = "camelCase")]
151pub struct Create {
152    /// Space
153    pub space: Space,
154    /// The address of the creator.
155    pub from: Address,
156    /// The value with which the new account is endowed.
157    pub value: U256,
158    /// The gas available for the creation init code.
159    pub gas: U256,
160    /// The init code.
161    pub init: Bytes,
162    /// The create type `CREATE` or `CREATE2`
163    pub create_type: CreateType,
164}
165
166impl Decodable for Create {
167    fn decode(rlp: &Rlp) -> Result<Self, DecoderError> {
168        match rlp.item_count()? {
169            5 => Ok(Create {
170                space: Space::Native,
171                from: rlp.val_at(0)?,
172                value: rlp.val_at(1)?,
173                gas: rlp.val_at(2)?,
174                init: rlp.val_at(3)?,
175                create_type: rlp.val_at(4)?,
176            }),
177            6 => Ok(Create {
178                space: rlp.val_at(0)?,
179                from: rlp.val_at(1)?,
180                value: rlp.val_at(2)?,
181                gas: rlp.val_at(3)?,
182                init: rlp.val_at(4)?,
183                create_type: rlp.val_at(5)?,
184            }),
185            _ => Err(DecoderError::RlpInvalidLength),
186        }
187    }
188}
189
190impl From<ActionParams> for Create {
191    fn from(p: ActionParams) -> Self {
192        Create {
193            space: p.space,
194            from: p.sender,
195            value: p.value.value(),
196            gas: p.gas,
197            init: p.code.map_or_else(Vec::new, |c| (*c).clone()),
198            create_type: p.create_type,
199        }
200    }
201}
202
203impl Create {
204    /// Returns bloom create action bloom.
205    /// The bloom contains only from address.
206    pub fn bloom(&self) -> Bloom {
207        BloomInput::Raw(self.from.as_bytes()).into()
208    }
209}
210
211/// Description of the result of a _create_ action.
212#[derive(Debug, Clone, PartialEq, RlpEncodable, RlpDecodable, Serialize)]
213#[serde(rename_all = "camelCase")]
214pub struct CreateResult {
215    /// The outcome of the create
216    pub outcome: Outcome,
217    /// The created contract address
218    pub addr: Address,
219    /// The amount of gas left
220    pub gas_left: U256,
221    /// Output data
222    pub return_data: Bytes,
223}
224
225impl CreateResult {
226    /// Returns create result bloom.
227    /// The bloom contains only created contract address.
228    pub fn bloom(&self) -> Bloom {
229        if self.outcome == Outcome::Success {
230            BloomInput::Raw(self.addr.as_bytes()).into()
231        } else {
232            Bloom::default()
233        }
234    }
235}
236
237/// Description of the result of an internal transfer action regarding about
238/// CFX.
239#[derive(Debug, Clone, PartialEq, RlpEncodable, RlpDecodable)]
240pub struct InternalTransferAction {
241    /// The source address. If it is zero, then it is an interest mint action.
242    pub from: AddressPocket,
243    /// The destination address. If it is zero, then it is a burnt action.
244    pub to: AddressPocket,
245    /// The amount of CFX
246    pub value: U256,
247}
248
249impl Serialize for InternalTransferAction {
250    fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
251    where S: Serializer {
252        let mut s = serializer.serialize_struct("InternalTransferAction", 5)?;
253        s.serialize_field("from", &self.from.inner_address_or_default())?;
254        s.serialize_field("fromPocket", &*self.from.pocket())?;
255        s.serialize_field("fromSpace", &*self.from.space())?;
256        s.serialize_field("to", &self.to.inner_address_or_default())?;
257        s.serialize_field("toPocket", &*self.to.pocket())?;
258        s.serialize_field("toSpace", &*self.to.space())?;
259        s.serialize_field("value", &self.value)?;
260        s.end()
261    }
262}
263
264impl InternalTransferAction {
265    pub fn bloom(&self) -> Bloom {
266        let mut bloom = Bloom::default();
267        bloom.accrue(BloomInput::Raw(
268            self.from.inner_address_or_default().as_ref(),
269        ));
270        bloom.accrue(BloomInput::Raw(
271            self.to.inner_address_or_default().as_ref(),
272        ));
273        bloom
274    }
275}
276
277#[derive(Debug, Clone, PartialEq, RlpEncodable, RlpDecodable, Serialize)]
278pub struct SetAuth {
279    pub space: Space,
280    /// The address of the impl.
281    pub address: Address,
282    pub chain_id: U256,
283    pub nonce: U256,
284    /// The outcome of the create
285    pub outcome: SetAuthOutcome,
286    /// The address of the author.
287    pub author: Option<Address>,
288}
289
290impl SetAuth {
291    /// The bloom contains only impl address.
292    pub fn bloom(&self) -> Bloom {
293        let mut bloom = Bloom::default();
294        bloom.accrue(BloomInput::Raw(self.address.as_bytes()));
295        if self.author.is_some() {
296            bloom.accrue(BloomInput::Raw(
297                self.author.as_ref().unwrap().as_bytes(),
298            ));
299        }
300        bloom
301    }
302}
303
304/// The outcome of the action result.
305#[derive(Debug, PartialEq, Copy, Clone, Serialize)]
306#[serde(rename_all = "snake_case")]
307pub enum SetAuthOutcome {
308    Success,
309    InvalidChainId,
310    NonceOverflow,
311    // Only account is empty or already delegated can set auth
312    AccountCanNotSetAuth,
313    InvalidNonce,
314    InvalidSignature,
315}
316
317impl Encodable for SetAuthOutcome {
318    fn rlp_append(&self, s: &mut RlpStream) {
319        let v = match *self {
320            SetAuthOutcome::Success => 0u32,
321            SetAuthOutcome::InvalidChainId => 1,
322            SetAuthOutcome::NonceOverflow => 2,
323            SetAuthOutcome::AccountCanNotSetAuth => 3,
324            SetAuthOutcome::InvalidNonce => 4,
325            SetAuthOutcome::InvalidSignature => 5,
326        };
327        Encodable::rlp_append(&v, s);
328    }
329}
330
331impl Decodable for SetAuthOutcome {
332    fn decode(rlp: &Rlp) -> Result<Self, DecoderError> {
333        rlp.as_val().and_then(|v| {
334            Ok(match v {
335                0u32 => SetAuthOutcome::Success,
336                1 => SetAuthOutcome::InvalidChainId,
337                2 => SetAuthOutcome::NonceOverflow,
338                3 => SetAuthOutcome::AccountCanNotSetAuth,
339                4 => SetAuthOutcome::InvalidNonce,
340                5 => SetAuthOutcome::InvalidSignature,
341                _ => {
342                    return Err(DecoderError::Custom(
343                        "Invalid value of SetAuthOutcome item",
344                    ));
345                }
346            })
347        })
348    }
349}
350
351/// Represents a _selfdestruct_ action fka `suicide`.
352#[derive(
353    Clone, Copy, Debug, PartialEq, Eq, Serialize, RlpEncodable, RlpDecodable,
354)]
355#[serde(rename_all = "camelCase")]
356pub struct SelfDestructAction {
357    // / The space of the contract.
358    pub space: Space,
359    /// destroyed/suicided address.
360    pub address: Address,
361    /// Balance of the contract just before it was destroyed.
362    pub balance: U256,
363    /// destroyed contract heir.
364    pub refund_address: Address,
365}
366
367impl SelfDestructAction {
368    /// Returns call action bloom.
369    /// The bloom contains contract address.
370    pub fn bloom(&self) -> Bloom {
371        let mut bloom = Bloom::default();
372        bloom.accrue(BloomInput::Raw(self.address.as_bytes()));
373        bloom
374    }
375}
376
377/// Description of an action that we trace; will be either a call or a create.
378#[derive(Debug, Clone, PartialEq, EnumDiscriminants)]
379#[strum_discriminants(name(ActionType))]
380pub enum Action {
381    /// It's a call action.
382    Call(Call),
383    /// It's a create action.
384    Create(Create),
385    /// It's the result of a call action
386    CallResult(CallResult),
387    /// It's the result of a create action
388    CreateResult(CreateResult),
389    /// It's an internal transfer action
390    InternalTransferAction(InternalTransferAction),
391    /// It's an 7702 set auth action
392    SetAuth(SetAuth),
393    /// It's a selfdestruct action
394    SelfDestruct(SelfDestructAction),
395}
396
397impl Encodable for Action {
398    fn rlp_append(&self, s: &mut RlpStream) {
399        s.begin_list(2);
400        match *self {
401            Action::Call(ref call) => {
402                s.append(&0u8);
403                s.append(call);
404            }
405            Action::Create(ref create) => {
406                s.append(&1u8);
407                s.append(create);
408            }
409            Action::CallResult(ref call_result) => {
410                s.append(&2u8);
411                s.append(call_result);
412            }
413            Action::CreateResult(ref create_result) => {
414                s.append(&3u8);
415                s.append(create_result);
416            }
417            Action::InternalTransferAction(ref internal_action) => {
418                s.append(&4u8);
419                s.append(internal_action);
420            }
421            Action::SetAuth(ref set_auth_action) => {
422                s.append(&5u8);
423                s.append(set_auth_action);
424            }
425            Action::SelfDestruct(ref selfdestruct_action) => {
426                s.append(&6u8);
427                s.append(selfdestruct_action);
428            }
429        }
430    }
431}
432
433impl Decodable for Action {
434    fn decode(rlp: &Rlp) -> Result<Self, DecoderError> {
435        let action_type: u8 = rlp.val_at(0)?;
436        match action_type {
437            0 => rlp.val_at(1).map(Action::Call),
438            1 => rlp.val_at(1).map(Action::Create),
439            2 => rlp.val_at(1).map(Action::CallResult),
440            3 => rlp.val_at(1).map(Action::CreateResult),
441            4 => rlp.val_at(1).map(Action::InternalTransferAction),
442            5 => rlp.val_at(1).map(Action::SetAuth),
443            6 => rlp.val_at(1).map(Action::SelfDestruct),
444            _ => Err(DecoderError::Custom("Invalid action type.")),
445        }
446    }
447}
448
449impl Action {
450    /// Returns action bloom.
451    pub fn bloom(&self) -> Bloom {
452        match *self {
453            Action::Call(ref call) => call.bloom(),
454            Action::Create(ref create) => create.bloom(),
455            Action::CallResult(_) => Bloom::default(),
456            Action::CreateResult(ref create_result) => create_result.bloom(),
457            Action::InternalTransferAction(ref internal_action) => {
458                internal_action.bloom()
459            }
460            Action::SetAuth(ref set_auth_action) => set_auth_action.bloom(),
461            Action::SelfDestruct(ref selfdestruct_action) => {
462                selfdestruct_action.bloom()
463            }
464        }
465    }
466}