Skip to content

Land Builtin actors API MVP into next #850

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 18 commits into from
Nov 30, 2022
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
18 commits
Select commit Hold shift + click to select a range
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 5 additions & 0 deletions Cargo.lock

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

10 changes: 7 additions & 3 deletions actors/account/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ use num_traits::FromPrimitive;

use fil_actors_runtime::builtin::singletons::SYSTEM_ACTOR_ADDR;
use fil_actors_runtime::runtime::{ActorCode, Runtime};
use fil_actors_runtime::{actor_error, ActorError};
use fil_actors_runtime::{actor_error, restrict_internal_api, ActorError};
use fil_actors_runtime::{cbor, ActorDowncast};

use crate::types::AuthenticateMessageParams;
Expand All @@ -32,7 +32,9 @@ fil_actors_runtime::wasm_trampoline!(Actor);
pub enum Method {
Constructor = METHOD_CONSTRUCTOR,
PubkeyAddress = 2,
AuthenticateMessage = 3,
// Deprecated in v10
// AuthenticateMessage = 3,
AuthenticateMessageExported = frc42_dispatch::method_hash!("AuthenticateMessage"),
UniversalReceiverHook = frc42_dispatch::method_hash!("Receive"),
}

Expand Down Expand Up @@ -109,6 +111,8 @@ impl ActorCode for Actor {
where
RT: Runtime,
{
restrict_internal_api(rt, method)?;

match FromPrimitive::from_u64(method) {
Some(Method::Constructor) => {
Self::constructor(rt, cbor::deserialize_params(params)?)?;
Expand All @@ -118,7 +122,7 @@ impl ActorCode for Actor {
let addr = Self::pubkey_address(rt)?;
Ok(RawBytes::serialize(addr)?)
}
Some(Method::AuthenticateMessage) => {
Some(Method::AuthenticateMessageExported) => {
Self::authenticate_message(rt, cbor::deserialize_params(params)?)?;
Ok(RawBytes::default())
}
Expand Down
65 changes: 35 additions & 30 deletions actors/account/tests/account_actor_test.rs
Original file line number Diff line number Diff line change
Expand Up @@ -16,12 +16,8 @@ use fil_actors_runtime::test_utils::*;
#[test]
fn construction() {
fn construct(addr: Address, exit_code: ExitCode) {
let mut rt = MockRuntime {
receiver: Address::new_id(100),
caller: SYSTEM_ACTOR_ADDR,
caller_type: *SYSTEM_ACTOR_CODE_ID,
..Default::default()
};
let mut rt = MockRuntime { receiver: Address::new_id(100), ..Default::default() };
rt.set_caller(*SYSTEM_ACTOR_CODE_ID, SYSTEM_ACTOR_ADDR);
rt.expect_validate_caller_addr(vec![SYSTEM_ACTOR_ADDR]);

if exit_code.is_success() {
Expand Down Expand Up @@ -59,12 +55,8 @@ fn construction() {

#[test]
fn token_receiver() {
let mut rt = MockRuntime {
receiver: Address::new_id(100),
caller: SYSTEM_ACTOR_ADDR,
caller_type: *SYSTEM_ACTOR_CODE_ID,
..Default::default()
};
let mut rt = MockRuntime { receiver: Address::new_id(100), ..Default::default() };
rt.set_caller(*SYSTEM_ACTOR_CODE_ID, SYSTEM_ACTOR_ADDR);
rt.expect_validate_caller_addr(vec![SYSTEM_ACTOR_ADDR]);

let param = Address::new_secp256k1(&[2; fvm_shared::address::SECP_PUB_LEN]).unwrap();
Expand All @@ -74,6 +66,7 @@ fn token_receiver() {
)
.unwrap();

rt.set_caller(make_identity_cid(b"1234"), Address::new_id(1000));
rt.expect_validate_caller_any();
let ret = rt.call::<AccountActor>(
Method::UniversalReceiverHook as MethodNum,
Expand All @@ -83,25 +76,15 @@ fn token_receiver() {
assert_eq!(RawBytes::default(), ret.unwrap());
}

fn check_state(rt: &MockRuntime) {
let test_address = Address::new_id(1000);
let (_, acc) = check_state_invariants(&rt.get_state(), &test_address);
acc.assert_empty();
}

#[test]
fn authenticate_message() {
let mut rt = MockRuntime {
receiver: Address::new_id(100),
caller: SYSTEM_ACTOR_ADDR,
caller_type: *SYSTEM_ACTOR_CODE_ID,
..Default::default()
};
let mut rt = MockRuntime { receiver: Address::new_id(100), ..Default::default() };
rt.set_caller(*SYSTEM_ACTOR_CODE_ID, SYSTEM_ACTOR_ADDR);

let addr = Address::new_secp256k1(&[2; fvm_shared::address::SECP_PUB_LEN]).unwrap();
rt.expect_validate_caller_addr(vec![SYSTEM_ACTOR_ADDR]);

rt.call::<AccountActor>(1, &RawBytes::serialize(addr).unwrap()).unwrap();
rt.call::<AccountActor>(Method::Constructor as MethodNum, &RawBytes::serialize(addr).unwrap())
.unwrap();

let state: State = rt.get_state();
assert_eq!(state.address, addr);
Expand All @@ -110,26 +93,48 @@ fn authenticate_message() {
RawBytes::serialize(AuthenticateMessageParams { signature: vec![], message: vec![] })
.unwrap();

// Valid signature
rt.expect_validate_caller_any();
rt.expect_verify_signature(ExpectedVerifySig {
sig: Signature::new_secp256k1(vec![]),
signer: addr,
plaintext: vec![],
result: Ok(()),
});
assert_eq!(RawBytes::default(), rt.call::<AccountActor>(3, &params).unwrap());
assert_eq!(
RawBytes::default(),
rt.call::<AccountActor>(Method::AuthenticateMessageExported as MethodNum, &params).unwrap()
);
rt.verify();

// Invalid signature
rt.expect_validate_caller_any();
rt.expect_verify_signature(ExpectedVerifySig {
sig: Signature::new_secp256k1(vec![]),
signer: addr,
plaintext: vec![],
result: Err(anyhow!("bad signature")),
});
assert_eq!(
expect_abort_contains_message(
ExitCode::USR_ILLEGAL_ARGUMENT,
rt.call::<AccountActor>(3, &params).unwrap_err().exit_code()
"bad signature",
rt.call::<AccountActor>(Method::AuthenticateMessageExported as MethodNum, &params),
);

rt.verify();

// Ok to call exported method number
rt.expect_validate_caller_any();
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This looks redundant with 113 and on now that we made that part of the test use the exported method

rt.expect_verify_signature(ExpectedVerifySig {
sig: Signature::new_secp256k1(vec![]),
signer: addr,
plaintext: vec![],
result: Ok(()),
});
rt.call::<AccountActor>(Method::AuthenticateMessageExported as MethodNum, &params).unwrap();
}

fn check_state(rt: &MockRuntime) {
let test_address = Address::new_id(1000);
let (_, acc) = check_state_invariants(&rt.get_state(), &test_address);
acc.assert_empty();
}
3 changes: 2 additions & 1 deletion actors/cron/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
// SPDX-License-Identifier: Apache-2.0, MIT

use fil_actors_runtime::runtime::{ActorCode, Runtime};
use fil_actors_runtime::{actor_error, cbor, ActorError, SYSTEM_ACTOR_ADDR};
use fil_actors_runtime::{actor_error, cbor, restrict_internal_api, ActorError, SYSTEM_ACTOR_ADDR};

use fvm_ipld_encoding::tuple::*;
use fvm_ipld_encoding::RawBytes;
Expand Down Expand Up @@ -83,6 +83,7 @@ impl ActorCode for Actor {
where
RT: Runtime,
{
restrict_internal_api(rt, method)?;
match FromPrimitive::from_u64(method) {
Some(Method::Constructor) => {
Self::constructor(rt, cbor::deserialize_params(params)?)?;
Expand Down
1 change: 1 addition & 0 deletions actors/cron/tests/cron_actor_test.rs
Original file line number Diff line number Diff line change
Expand Up @@ -114,6 +114,7 @@ fn epoch_tick_with_entries() {
}

fn construct_and_verify(rt: &mut MockRuntime, params: &ConstructorParams) {
rt.set_caller(*SYSTEM_ACTOR_CODE_ID, SYSTEM_ACTOR_ADDR);
rt.expect_validate_caller_addr(vec![SYSTEM_ACTOR_ADDR]);
let ret = rt.call::<CronActor>(1, &RawBytes::serialize(&params).unwrap()).unwrap();
assert_eq!(RawBytes::default(), ret);
Expand Down
48 changes: 32 additions & 16 deletions actors/datacap/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,8 @@ use num_traits::{FromPrimitive, Zero};
use fil_actors_runtime::cbor::serialize;
use fil_actors_runtime::runtime::{ActorCode, Runtime};
use fil_actors_runtime::{
actor_error, cbor, ActorContext, ActorError, AsActorError, SYSTEM_ACTOR_ADDR,
actor_error, cbor, restrict_internal_api, ActorContext, ActorError, AsActorError,
SYSTEM_ACTOR_ADDR,
};

pub use self::state::State;
Expand All @@ -42,9 +43,10 @@ lazy_static! {
* BigInt::from(1_000_000_000_000_000_000_000_i128)
);
}
/// Static method numbers for builtin-actor private dispatch.
/// The methods are also expected to be exposed via FRC-XXXX standard calling convention,
/// with numbers determined by name.

/// Datacap actor methods available
/// Some methods are available under 2 method nums -- a static number for "private" builtin actor usage,
/// and via FRC-0042 calling convention, with number determined by method name.
#[derive(FromPrimitive)]
#[repr(u64)]
pub enum Method {
Expand All @@ -65,6 +67,19 @@ pub enum Method {
Burn = 19,
BurnFrom = 20,
Allowance = 21,
// Method numbers derived from FRC-0042 standards
NameExported = frc42_dispatch::method_hash!("Name"),
SymbolExported = frc42_dispatch::method_hash!("Symbol"),
TotalSupplyExported = frc42_dispatch::method_hash!("TotalSupply"),
BalanceOfExported = frc42_dispatch::method_hash!("BalanceOf"),
TransferExported = frc42_dispatch::method_hash!("Transfer"),
TransferFromExported = frc42_dispatch::method_hash!("TransferFrom"),
IncreaseAllowanceExported = frc42_dispatch::method_hash!("IncreaseAllowance"),
DecreaseAllowanceExported = frc42_dispatch::method_hash!("DecreaseAllowance"),
RevokeAllowanceExported = frc42_dispatch::method_hash!("RevokeAllowance"),
BurnExported = frc42_dispatch::method_hash!("Burn"),
BurnFromExported = frc42_dispatch::method_hash!("BurnFrom"),
AllowanceExported = frc42_dispatch::method_hash!("Allowance"),
}

pub struct Actor;
Expand Down Expand Up @@ -452,6 +467,7 @@ impl ActorCode for Actor {
where
RT: Runtime,
{
restrict_internal_api(rt, method)?;
// I'm trying to find a fixed template for these blocks so we can macro it.
// Current blockers:
// - the serialize method maps () to CBOR null (we want no bytes instead)
Expand All @@ -469,51 +485,51 @@ impl ActorCode for Actor {
let ret = Self::destroy(rt, cbor::deserialize_params(params)?)?;
serialize(&ret, "destroy result")
}
Some(Method::Name) => {
Some(Method::Name) | Some(Method::NameExported) => {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why are we keeping the non-exported method numbers active?

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is it a policy decision that built-in actors only call other built-in actors through their internal method numbers? If that's the case, I think it makes sense for uniformity, as otherwise we would see calls to exported and internal method sprinkled over this codebase. However, it might be a usability nit for explorers and other tooling to have two method numbers associated with the same exact behaviour.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

let ret = Self::name(rt)?;
serialize(&ret, "name result")
}
Some(Method::Symbol) => {
Some(Method::Symbol) | Some(Method::SymbolExported) => {
let ret = Self::symbol(rt)?;
serialize(&ret, "symbol result")
}
Some(Method::TotalSupply) => {
Some(Method::TotalSupply) | Some(Method::TotalSupplyExported) => {
let ret = Self::total_supply(rt, cbor::deserialize_params(params)?)?;
serialize(&ret, "total_supply result")
}
Some(Method::BalanceOf) => {
Some(Method::BalanceOf) | Some(Method::BalanceOfExported) => {
let ret = Self::balance_of(rt, cbor::deserialize_params(params)?)?;
serialize(&ret, "balance_of result")
}
Some(Method::Transfer) => {
Some(Method::Transfer) | Some(Method::TransferExported) => {
let ret = Self::transfer(rt, cbor::deserialize_params(params)?)?;
serialize(&ret, "transfer result")
}
Some(Method::TransferFrom) => {
Some(Method::TransferFrom) | Some(Method::TransferFromExported) => {
let ret = Self::transfer_from(rt, cbor::deserialize_params(params)?)?;
serialize(&ret, "transfer_from result")
}
Some(Method::IncreaseAllowance) => {
Some(Method::IncreaseAllowance) | Some(Method::IncreaseAllowanceExported) => {
let ret = Self::increase_allowance(rt, cbor::deserialize_params(params)?)?;
serialize(&ret, "increase_allowance result")
}
Some(Method::DecreaseAllowance) => {
Some(Method::DecreaseAllowance) | Some(Method::DecreaseAllowanceExported) => {
let ret = Self::decrease_allowance(rt, cbor::deserialize_params(params)?)?;
serialize(&ret, "decrease_allowance result")
}
Some(Method::RevokeAllowance) => {
Some(Method::RevokeAllowance) | Some(Method::RevokeAllowanceExported) => {
Self::revoke_allowance(rt, cbor::deserialize_params(params)?)?;
Ok(RawBytes::default())
}
Some(Method::Burn) => {
Some(Method::Burn) | Some(Method::BurnExported) => {
let ret = Self::burn(rt, cbor::deserialize_params(params)?)?;
serialize(&ret, "burn result")
}
Some(Method::BurnFrom) => {
Some(Method::BurnFrom) | Some(Method::BurnFromExported) => {
let ret = Self::burn_from(rt, cbor::deserialize_params(params)?)?;
serialize(&ret, "burn_from result")
}
Some(Method::Allowance) => {
Some(Method::Allowance) | Some(Method::AllowanceExported) => {
let ret = Self::allowance(rt, cbor::deserialize_params(params)?)?;
serialize(&ret, "allowance result")
}
Expand Down
Loading