Skip to content

Commit

Permalink
Runtime: Don't convert syscall errors
Browse files Browse the repository at this point in the history
  • Loading branch information
arajasek committed Jan 12, 2023
1 parent 610f399 commit 3c41f6d
Show file tree
Hide file tree
Showing 8 changed files with 151 additions and 31 deletions.
1 change: 1 addition & 0 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

14 changes: 12 additions & 2 deletions actors/evm/src/interpreter/system.rs
Original file line number Diff line number Diff line change
Expand Up @@ -222,11 +222,21 @@ impl<'r, RT: Runtime> System<'r, RT> {
send_flags: SendFlags,
) -> Result<Option<IpldBlock>, ActorError> {
self.flush()?;
let result = self.rt.send_generalized(to, method, params, value, gas_limit, send_flags)?;
let result = self
.rt
.send_generalized(to, method, params, value, gas_limit, send_flags)
.map_err(|err| actor_error!(unspecified; "send syscall failed: {}", err))?;
if !send_flags.read_only() {
self.reload()?;
}
Ok(result)
match result.exit_code {
ExitCode::OK => Ok(result.return_data),
e => Err(ActorError::unchecked_with_data(
e,
"send failed".to_string(),
result.return_data,
)),
}
}

/// Flush the actor state (bytecode, nonce, and slots).
Expand Down
6 changes: 2 additions & 4 deletions runtime/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ repository = "https://github.com/filecoin-project/builtin-actors"
fvm_ipld_hamt = "0.6.1"
fvm_ipld_amt = { version = "0.5.0", features = ["go-interop"] }
fvm_shared = { version = "3.0.0-alpha.15", default-features = false }
fvm_sdk = { version = "3.0.0-alpha.21"}
num = { version = "0.4", features = ["serde"] }
num-traits = "0.2.14"
num-derive = "0.3.3"
Expand All @@ -36,9 +37,6 @@ castaway = "0.2.2"
# build.rs.
sha2 = "0.10"

# fil-actor
fvm_sdk = { version = "3.0.0-alpha.21", optional = true }

# test_util
rand = { version = "0.8.5", default-features = false, optional = true }
hex = { version = "0.4.3", optional = true }
Expand All @@ -58,7 +56,7 @@ rand = { version = "0.8.5" }

[features]
default = []
fil-actor = ["fvm_sdk"]
fil-actor = []
m2-native = ["fvm_sdk/m2-native"]

# Enable 2k sectors
Expand Down
29 changes: 20 additions & 9 deletions runtime/src/runtime/fvm.rs
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,8 @@ use fvm_ipld_blockstore::Blockstore;
use fvm_ipld_encoding::ipld_block::IpldBlock;
use fvm_ipld_encoding::CborStore;
use fvm_sdk as fvm;
use fvm_sdk::NO_DATA_BLOCK_ID;
use fvm_sdk::send::Response;
use fvm_sdk::{SyscallResult, NO_DATA_BLOCK_ID};
use fvm_shared::address::{Address, Payload};
use fvm_shared::chainid::ChainID;
use fvm_shared::clock::ChainEpoch;
Expand Down Expand Up @@ -310,20 +311,14 @@ where
&self.blockstore
}

fn send_generalized(
fn send(
&self,
to: &Address,
method: MethodNum,
params: Option<IpldBlock>,
value: TokenAmount,
gas_limit: Option<u64>,
flags: SendFlags,
) -> Result<Option<IpldBlock>, ActorError> {
if self.in_transaction {
return Err(actor_error!(assertion_failed; "send is not allowed during transaction"));
}

match fvm::send::send(to, method, params, value, gas_limit, flags) {
match self.send_generalized(to, method, params, value, None, SendFlags::empty()) {
Ok(ret) => {
if ret.exit_code.is_success() {
Ok(ret.return_data)
Expand Down Expand Up @@ -383,6 +378,22 @@ where
}
}

fn send_generalized(
&self,
to: &Address,
method: MethodNum,
params: Option<IpldBlock>,
value: TokenAmount,
gas_limit: Option<u64>,
flags: SendFlags,
) -> SyscallResult<Response> {
if self.in_transaction {
return Err(ErrorNumber::IllegalOperation);
}

fvm::send::send(to, method, params, value, gas_limit, flags)
}

fn new_actor_address(&mut self) -> Result<Address, ActorError> {
Ok(fvm::actor::next_actor_address())
}
Expand Down
8 changes: 4 additions & 4 deletions runtime/src/runtime/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -49,6 +49,8 @@ pub(crate) mod empty;

pub use empty::EMPTY_ARR_CID;
use fvm_ipld_encoding::ipld_block::IpldBlock;
use fvm_sdk::send::Response;
use fvm_sdk::SyscallResult;

/// Runtime is the VM's internal runtime object.
/// this is everything that is accessible to actors, beyond parameters.
Expand Down Expand Up @@ -195,9 +197,7 @@ pub trait Runtime: Primitives + Verifier + RuntimePolicy {
method: MethodNum,
params: Option<IpldBlock>,
value: TokenAmount,
) -> Result<Option<IpldBlock>, ActorError> {
self.send_generalized(to, method, params, value, None, SendFlags::empty())
}
) -> Result<Option<IpldBlock>, ActorError>;

/// Generalizes [`Runtime::send`] and [`Runtime::send_read_only`] to allow the caller to
/// specify a gas limit and send flags.
Expand All @@ -209,7 +209,7 @@ pub trait Runtime: Primitives + Verifier + RuntimePolicy {
value: TokenAmount,
gas_limit: Option<u64>,
flags: SendFlags,
) -> Result<Option<IpldBlock>, ActorError>;
) -> SyscallResult<Response>;

/// Computes an address for a new actor. The returned address is intended to uniquely refer to
/// the actor even in the event of a chain re-org (whereas an ID-address might refer to a
Expand Down
73 changes: 67 additions & 6 deletions runtime/src/test_utils.rs
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@ use fvm_shared::crypto::signature::{
Signature, SECP_PUB_LEN, SECP_SIG_LEN, SECP_SIG_MESSAGE_HASH_SIZE,
};
use fvm_shared::econ::TokenAmount;
use fvm_shared::error::ExitCode;
use fvm_shared::error::{ErrorNumber, ExitCode};
use fvm_shared::piece::PieceInfo;
use fvm_shared::randomness::RANDOMNESS_LENGTH;
use fvm_shared::sector::{
Expand All @@ -49,6 +49,7 @@ use fvm_shared::event::ActorEvent;
use libsecp256k1::{recover, Message, RecoveryId, Signature as EcsdaSignature};

use fvm_ipld_encoding::ipld_block::IpldBlock;
use fvm_sdk::send::Response;

lazy_static::lazy_static! {
pub static ref SYSTEM_ACTOR_CODE_ID: Cid = make_identity_cid(b"fil/test/system");
Expand Down Expand Up @@ -1122,14 +1123,12 @@ impl<BS: Blockstore> Runtime for MockRuntime<BS> {
&self.store
}

fn send_generalized(
fn send(
&self,
to: &Address,
method: MethodNum,
params: Option<IpldBlock>,
value: TokenAmount,
gas_limit: Option<u64>,
send_flags: SendFlags,
) -> Result<Option<IpldBlock>, ActorError> {
// TODO gas_limit is currently ignored, what should we do about it?
self.require_in_call();
Expand All @@ -1148,8 +1147,8 @@ impl<BS: Blockstore> Runtime for MockRuntime<BS> {

let expected_msg = self.expectations.borrow_mut().expect_sends.pop_front().unwrap();

assert_eq!(expected_msg.gas_limit, gas_limit, "gas limit did not match expectation");
assert_eq!(expected_msg.send_flags, send_flags, "send flags did not match expectation");
assert!(expected_msg.gas_limit.is_none(), "gas limit did not match expectation");
assert!(expected_msg.send_flags.is_empty(), "send flags did not match expectation");

assert!(
expected_msg.to == *to
Expand Down Expand Up @@ -1194,6 +1193,68 @@ impl<BS: Blockstore> Runtime for MockRuntime<BS> {
}
}

fn send_generalized(
&self,
to: &Address,
method: MethodNum,
params: Option<IpldBlock>,
value: TokenAmount,
gas_limit: Option<u64>,
send_flags: SendFlags,
) -> Result<Response, ErrorNumber> {
// TODO gas_limit is currently ignored, what should we do about it?
self.require_in_call();
if self.in_transaction {
return Ok(Response { exit_code: ExitCode::USR_ASSERTION_FAILED, return_data: None });
}

assert!(
!self.expectations.borrow_mut().expect_sends.is_empty(),
"unexpected message to: {:?} method: {:?}, value: {:?}, params: {:?}",
to,
method,
value,
params
);

let expected_msg = self.expectations.borrow_mut().expect_sends.pop_front().unwrap();

assert_eq!(expected_msg.gas_limit, gas_limit, "gas limit did not match expectation");
assert_eq!(expected_msg.send_flags, send_flags, "send flags did not match expectation");

assert!(
expected_msg.to == *to
&& expected_msg.method == method
&& expected_msg.params == params
&& expected_msg.value == value,
"message sent does not match expectation.\n\
message - to: {:?}, method: {:?}, value: {:?}, params: {:?}\n\
expected - to: {:?}, method: {:?}, value: {:?}, params: {:?}\n\
method match {}, params match {}, value match {}",
to,
method,
value,
params,
expected_msg.to,
expected_msg.method,
expected_msg.value,
expected_msg.params,
expected_msg.method == method,
expected_msg.params == params,
expected_msg.value == value,
);

{
let mut balance = self.balance.borrow_mut();
if value > *balance {
return Err(ErrorNumber::InsufficientFunds);
}
*balance -= value;
}

Ok(Response { exit_code: expected_msg.exit_code, return_data: expected_msg.send_return })
}

fn new_actor_address(&mut self) -> Result<Address, ActorError> {
self.require_in_call();
let ret = *self.new_actor_addr.as_ref().expect("unexpected call to new actor address");
Expand Down
1 change: 1 addition & 0 deletions test_vm/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,7 @@ fvm_ipld_blockstore = { version = "0.1.1", default-features = false }
fvm_ipld_encoding = { version = "0.3.2", default-features = false }
fvm_ipld_hamt = "0.6.1"
fvm_shared = { version = "3.0.0-alpha.15", default-features = false }
fvm_sdk = { version = "3.0.0-alpha.21"}
indexmap = { version = "1.8.0", features = ["serde-1"] }
integer-encoding = { version = "3.0.3", default-features = false }
lazy_static = "1.4.0"
Expand Down
50 changes: 44 additions & 6 deletions test_vm/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,8 @@ use fvm_ipld_encoding::ipld_block::IpldBlock;
use fvm_ipld_encoding::tuple::*;
use fvm_ipld_encoding::{CborStore, RawBytes};
use fvm_ipld_hamt::{BytesKey, Hamt, Sha256};
use fvm_sdk::send::Response;
use fvm_sdk::SyscallResult;
use fvm_shared::address::{Address, Payload};
use fvm_shared::bigint::Zero;
use fvm_shared::chainid::ChainID;
Expand Down Expand Up @@ -990,6 +992,42 @@ impl<'invocation, 'bs> Runtime for InvocationCtx<'invocation, 'bs> {
self.v.get_actor(Address::new_id(id)).and_then(|act| act.predictable_address)
}

fn send(
&self,
to: &Address,
method: MethodNum,
params: Option<IpldBlock>,
value: TokenAmount,
) -> Result<Option<IpldBlock>, ActorError> {
// TODO gas_limit is current ignored, what should we do about it?
if !self.allow_side_effects {
return Err(ActorError::unchecked(
ExitCode::SYS_ASSERTION_FAILED,
"Calling send is not allowed during side-effect lock".to_string(),
));
}

let new_actor_msg = InternalMessage { from: self.to(), to: *to, value, method, params };
let mut new_ctx = InvocationCtx {
v: self.v,
top: self.top.clone(),
msg: new_actor_msg,
allow_side_effects: true,
caller_validated: false,
policy: self.policy,
subinvocations: RefCell::new(vec![]),
actor_exit: RefCell::new(None),
read_only: false,
};
let res = new_ctx.invoke_actor();
let invoc = new_ctx.gather_trace(res.clone());
RefMut::map(self.subinvocations.borrow_mut(), |subinvocs| {
subinvocs.push(invoc);
subinvocs
});
res
}

fn send_generalized(
&self,
to: &Address,
Expand All @@ -998,18 +1036,15 @@ impl<'invocation, 'bs> Runtime for InvocationCtx<'invocation, 'bs> {
value: TokenAmount,
_gas_limit: Option<u64>,
mut send_flags: SendFlags,
) -> Result<Option<IpldBlock>, ActorError> {
) -> SyscallResult<Response> {
// replicate FVM by silently propagating read only flag to subcalls
if self.read_only() {
send_flags.set(SendFlags::READ_ONLY, true)
}

// TODO gas_limit is current ignored, what should we do about it?
if !self.allow_side_effects {
return Err(ActorError::unchecked(
ExitCode::SYS_ASSERTION_FAILED,
"Calling send is not allowed during side-effect lock".to_string(),
));
return Ok(Response { exit_code: ExitCode::SYS_ASSERTION_FAILED, return_data: None });
}

let new_actor_msg = InternalMessage { from: self.to(), to: *to, value, method, params };
Expand All @@ -1030,7 +1065,10 @@ impl<'invocation, 'bs> Runtime for InvocationCtx<'invocation, 'bs> {
subinvocs.push(invoc);
subinvocs
});
res
Ok(Response {
exit_code: res.clone().map_or_else(|e| e.exit_code(), |_| ExitCode::OK),
return_data: res.unwrap_or(None),
})
}

fn get_randomness_from_tickets(
Expand Down

0 comments on commit 3c41f6d

Please sign in to comment.