actors_runtime/util/chaos/
mod.rs

1// Copyright 2019-2022 ChainSafe Systems
2// SPDX-License-Identifier: Apache-2.0, MIT
3
4use cid::Cid;
5use fvm_shared::actor::builtin::Type;
6use fvm_shared::address::Address;
7use fvm_shared::blockstore::Blockstore;
8use fvm_shared::encoding::RawBytes;
9use fvm_shared::error::ExitCode;
10use fvm_shared::{MethodNum, METHOD_CONSTRUCTOR};
11use num_derive::FromPrimitive;
12use num_traits::FromPrimitive;
13pub use state::*;
14pub use types::*;
15
16use crate::runtime::{ActorCode, Runtime};
17use crate::{actor_error, ActorError};
18
19mod state;
20mod types;
21
22// * Updated to test-vectors commit: 907892394dd83fe1f4bf1a82146bbbcc58963148
23
24// Caller Validation methods
25const CALLER_VALIDATION_BRANCH_NONE: i64 = 0;
26const CALLER_VALIDATION_BRANCH_TWICE: i64 = 1;
27const CALLER_VALIDATION_BRANCH_IS_ADDRESS: i64 = 2;
28const CALLER_VALIDATION_BRANCH_IS_TYPE: i64 = 3;
29
30// Mutate State Branch Methods
31const MUTATE_IN_TRANSACTION: i64 = 0;
32
33/// Chaos actor methods available
34#[derive(FromPrimitive)]
35#[repr(u64)]
36pub enum Method {
37    Constructor = METHOD_CONSTRUCTOR,
38    CallerValidation = 2,
39    CreateActor = 3,
40    ResolveAddress = 4,
41    DeleteActor = 5,
42    Send = 6,
43    MutateState = 7,
44    AbortWith = 8,
45    InspectRuntime = 9,
46}
47
48/// Chaos Actor
49pub struct Actor;
50
51impl Actor {
52    pub fn send<BS, RT>(rt: &mut RT, arg: SendArgs) -> Result<SendReturn, ActorError>
53    where
54        BS: Blockstore,
55        RT: Runtime<BS>,
56    {
57        rt.validate_immediate_caller_accept_any()?;
58
59        let result = rt.send(arg.to, arg.method, arg.params, arg.value);
60        if let Err(e) = result {
61            Ok(SendReturn {
62                return_value: RawBytes::default(),
63                code: e.exit_code(),
64            })
65        } else {
66            Ok(SendReturn {
67                return_value: result.unwrap(),
68                code: ExitCode::Ok,
69            })
70        }
71    }
72
73    /// Constructor for Account actor
74    pub fn constructor<BS, RT>(_rt: &mut RT)
75    where
76        BS: Blockstore,
77        RT: Runtime<BS>,
78    {
79        panic!("Constructor should not be called");
80    }
81
82    /// CallerValidation violates VM call validation constraints.
83    ///
84    ///  CALLER_VALIDATION_BRANCH_NONE performs no validation.
85    ///  CALLER_VALIDATION_BRANCH_TWICE validates twice.
86    ///  CALLER_VALIDATION_BRANCH_IS_ADDRESS validates against an empty caller
87    ///  address set.
88    ///  CALLER_VALIDATION_BRANCH_IS_TYPE validates against an empty caller type set.
89    pub fn caller_validation<BS, RT>(
90        rt: &mut RT,
91        args: CallerValidationArgs,
92    ) -> Result<(), ActorError>
93    where
94        BS: Blockstore,
95        RT: Runtime<BS>,
96    {
97        match args.branch {
98            x if x == CALLER_VALIDATION_BRANCH_NONE => {}
99            x if x == CALLER_VALIDATION_BRANCH_TWICE => {
100                rt.validate_immediate_caller_accept_any()?;
101                rt.validate_immediate_caller_accept_any()?;
102            }
103            x if x == CALLER_VALIDATION_BRANCH_IS_ADDRESS => {
104                rt.validate_immediate_caller_is(&args.addrs)?;
105            }
106            x if x == CALLER_VALIDATION_BRANCH_IS_TYPE => {
107                let types: Vec<Type> = args
108                    .types
109                    .iter()
110                    .map(|typ| rt.resolve_builtin_actor_type(typ).unwrap())
111                    .collect();
112                rt.validate_immediate_caller_type(&types)?;
113            }
114            _ => panic!("invalid branch passed to CallerValidation"),
115        }
116        Ok(())
117    }
118
119    // Creates an actor with the supplied CID and Address.
120    pub fn create_actor<BS, RT>(rt: &mut RT, arg: CreateActorArgs) -> Result<(), ActorError>
121    where
122        BS: Blockstore,
123        RT: Runtime<BS>,
124    {
125        rt.validate_immediate_caller_accept_any()?;
126        // TODO Temporarily fine to use default as Undefined Cid, but may need to change in the future
127        let actor_cid = if arg.undef_cid {
128            Cid::default()
129        } else {
130            arg.cid
131        };
132
133        let actor_address = arg.actor_id;
134
135        rt.create_actor(actor_cid, actor_address)
136    }
137
138    /// Resolves address, and returns the resolved address (defaulting to 0 ID) and success boolean.
139    pub fn resolve_address<BS, RT>(
140        rt: &mut RT,
141        args: Address,
142    ) -> Result<ResolveAddressResponse, ActorError>
143    where
144        BS: Blockstore,
145        RT: Runtime<BS>,
146    {
147        rt.validate_immediate_caller_accept_any()?;
148        let resolved = rt.resolve_address(&args);
149        Ok(ResolveAddressResponse {
150            address: resolved.unwrap_or_else(|| Address::new_id(0)),
151            success: resolved.is_some(),
152        })
153    }
154
155    pub fn delete_actor<BS, RT>(rt: &mut RT, beneficiary: Address) -> Result<(), ActorError>
156    where
157        BS: Blockstore,
158        RT: Runtime<BS>,
159    {
160        rt.validate_immediate_caller_accept_any()?;
161        rt.delete_actor(&beneficiary)
162    }
163
164    pub fn mutate_state<BS, RT>(rt: &mut RT, arg: MutateStateArgs) -> Result<(), ActorError>
165    where
166        BS: Blockstore,
167        RT: Runtime<BS>,
168    {
169        rt.validate_immediate_caller_accept_any()?;
170
171        match arg.branch {
172            x if x == MUTATE_IN_TRANSACTION => rt.transaction(|s: &mut State, _| {
173                s.value = arg.value;
174                Ok(())
175            }),
176
177            _ => Err(actor_error!(ErrIllegalArgument; "Invalid mutate state command given" )),
178        }
179    }
180
181    pub fn abort_with(arg: AbortWithArgs) -> Result<(), ActorError> {
182        if arg.uncontrolled {
183            panic!("Uncontrolled abort/error");
184        }
185        Err(ActorError::new(arg.code, arg.message))
186    }
187
188    pub fn inspect_runtime<BS, RT>(rt: &mut RT) -> Result<InspectRuntimeReturn, ActorError>
189    where
190        BS: Blockstore,
191        RT: Runtime<BS>,
192    {
193        rt.validate_immediate_caller_accept_any()?;
194        Ok(InspectRuntimeReturn {
195            caller: rt.message().caller(),
196            receiver: rt.message().receiver(),
197            value_received: rt.message().value_received(),
198            curr_epoch: rt.curr_epoch(),
199            current_balance: rt.current_balance(),
200            state: rt.state()?,
201        })
202    }
203}
204
205impl ActorCode for Actor {
206    fn invoke_method<BS, RT>(
207        rt: &mut RT,
208        method: MethodNum,
209        params: &RawBytes,
210    ) -> Result<RawBytes, ActorError>
211    where
212        BS: Blockstore,
213        RT: Runtime<BS>,
214    {
215        match FromPrimitive::from_u64(method) {
216            Some(Method::Constructor) => {
217                Self::constructor(rt);
218                Ok(RawBytes::default())
219            }
220            Some(Method::CallerValidation) => {
221                Self::caller_validation(rt, rt.deserialize_params(params)?)?;
222                Ok(RawBytes::default())
223            }
224
225            Some(Method::CreateActor) => {
226                Self::create_actor(rt, rt.deserialize_params(params)?)?;
227                Ok(RawBytes::default())
228            }
229            Some(Method::ResolveAddress) => {
230                let res = Self::resolve_address(rt, rt.deserialize_params(params)?)?;
231                Ok(RawBytes::serialize(res)?)
232            }
233
234            Some(Method::Send) => {
235                let res: SendReturn = Self::send(rt, rt.deserialize_params(params)?)?;
236                Ok(RawBytes::serialize(res)?)
237            }
238
239            Some(Method::DeleteActor) => {
240                Self::delete_actor(rt, rt.deserialize_params(params)?)?;
241                Ok(RawBytes::default())
242            }
243
244            Some(Method::MutateState) => {
245                Self::mutate_state(rt, rt.deserialize_params(params)?)?;
246                Ok(RawBytes::default())
247            }
248
249            Some(Method::AbortWith) => {
250                Self::abort_with(rt.deserialize_params(params)?)?;
251                Ok(RawBytes::default())
252            }
253
254            Some(Method::InspectRuntime) => {
255                let inspect = Self::inspect_runtime(rt)?;
256                Ok(RawBytes::serialize(inspect)?)
257            }
258
259            None => Err(actor_error!(SysErrInvalidMethod; "Invalid method")),
260        }
261    }
262}