Skip to content

Commit a241f95

Browse files
anortharajasek
authored andcommitted
Proof of concept exported API for Account actor (#797)
1 parent 1b11df4 commit a241f95

File tree

5 files changed

+105
-52
lines changed

5 files changed

+105
-52
lines changed

actors/account/src/lib.rs

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,7 @@ use num_traits::FromPrimitive;
1212

1313
use fil_actors_runtime::builtin::singletons::SYSTEM_ACTOR_ADDR;
1414
use fil_actors_runtime::runtime::{ActorCode, Runtime};
15-
use fil_actors_runtime::{actor_error, ActorError};
15+
use fil_actors_runtime::{actor_error, restrict_internal_api, ActorError};
1616
use fil_actors_runtime::{cbor, ActorDowncast};
1717

1818
use crate::types::AuthenticateMessageParams;
@@ -33,6 +33,7 @@ pub enum Method {
3333
Constructor = METHOD_CONSTRUCTOR,
3434
PubkeyAddress = 2,
3535
AuthenticateMessage = 3,
36+
AuthenticateMessageExported = frc42_dispatch::method_hash!("AuthenticateMessage"),
3637
UniversalReceiverHook = frc42_dispatch::method_hash!("Receive"),
3738
}
3839

@@ -109,6 +110,8 @@ impl ActorCode for Actor {
109110
where
110111
RT: Runtime,
111112
{
113+
restrict_internal_api(rt, method)?;
114+
112115
match FromPrimitive::from_u64(method) {
113116
Some(Method::Constructor) => {
114117
Self::constructor(rt, cbor::deserialize_params(params)?)?;
@@ -118,7 +121,7 @@ impl ActorCode for Actor {
118121
let addr = Self::pubkey_address(rt)?;
119122
Ok(RawBytes::serialize(addr)?)
120123
}
121-
Some(Method::AuthenticateMessage) => {
124+
Some(Method::AuthenticateMessage) | Some(Method::AuthenticateMessageExported) => {
122125
Self::authenticate_message(rt, cbor::deserialize_params(params)?)?;
123126
Ok(RawBytes::default())
124127
}

actors/account/tests/account_actor_test.rs

Lines changed: 43 additions & 30 deletions
Original file line numberDiff line numberDiff line change
@@ -16,12 +16,8 @@ use fil_actors_runtime::test_utils::*;
1616
#[test]
1717
fn construction() {
1818
fn construct(addr: Address, exit_code: ExitCode) {
19-
let mut rt = MockRuntime {
20-
receiver: Address::new_id(100),
21-
caller: SYSTEM_ACTOR_ADDR,
22-
caller_type: *SYSTEM_ACTOR_CODE_ID,
23-
..Default::default()
24-
};
19+
let mut rt = MockRuntime { receiver: Address::new_id(100), ..Default::default() };
20+
rt.set_caller(*SYSTEM_ACTOR_CODE_ID, SYSTEM_ACTOR_ADDR);
2521
rt.expect_validate_caller_addr(vec![SYSTEM_ACTOR_ADDR]);
2622

2723
if exit_code.is_success() {
@@ -59,12 +55,8 @@ fn construction() {
5955

6056
#[test]
6157
fn token_receiver() {
62-
let mut rt = MockRuntime {
63-
receiver: Address::new_id(100),
64-
caller: SYSTEM_ACTOR_ADDR,
65-
caller_type: *SYSTEM_ACTOR_CODE_ID,
66-
..Default::default()
67-
};
58+
let mut rt = MockRuntime { receiver: Address::new_id(100), ..Default::default() };
59+
rt.set_caller(*SYSTEM_ACTOR_CODE_ID, SYSTEM_ACTOR_ADDR);
6860
rt.expect_validate_caller_addr(vec![SYSTEM_ACTOR_ADDR]);
6961

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

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

86-
fn check_state(rt: &MockRuntime) {
87-
let test_address = Address::new_id(1000);
88-
let (_, acc) = check_state_invariants(&rt.get_state(), &test_address);
89-
acc.assert_empty();
90-
}
91-
9279
#[test]
9380
fn authenticate_message() {
94-
let mut rt = MockRuntime {
95-
receiver: Address::new_id(100),
96-
caller: SYSTEM_ACTOR_ADDR,
97-
caller_type: *SYSTEM_ACTOR_CODE_ID,
98-
..Default::default()
99-
};
81+
let mut rt = MockRuntime { receiver: Address::new_id(100), ..Default::default() };
82+
rt.set_caller(*SYSTEM_ACTOR_CODE_ID, SYSTEM_ACTOR_ADDR);
10083

10184
let addr = Address::new_secp256k1(&[2; fvm_shared::address::SECP_PUB_LEN]).unwrap();
10285
rt.expect_validate_caller_addr(vec![SYSTEM_ACTOR_ADDR]);
103-
104-
rt.call::<AccountActor>(1, &RawBytes::serialize(addr).unwrap()).unwrap();
86+
rt.call::<AccountActor>(Method::Constructor as MethodNum, &RawBytes::serialize(addr).unwrap())
87+
.unwrap();
10588

10689
let state: State = rt.get_state();
10790
assert_eq!(state.address, addr);
@@ -110,26 +93,56 @@ fn authenticate_message() {
11093
RawBytes::serialize(AuthenticateMessageParams { signature: vec![], message: vec![] })
11194
.unwrap();
11295

96+
// Valid signature
11397
rt.expect_validate_caller_any();
11498
rt.expect_verify_signature(ExpectedVerifySig {
11599
sig: Signature::new_secp256k1(vec![]),
116100
signer: addr,
117101
plaintext: vec![],
118102
result: Ok(()),
119103
});
120-
assert_eq!(RawBytes::default(), rt.call::<AccountActor>(3, &params).unwrap());
104+
assert_eq!(
105+
RawBytes::default(),
106+
rt.call::<AccountActor>(Method::AuthenticateMessage as MethodNum, &params).unwrap()
107+
);
108+
rt.verify();
121109

110+
// Invalid signature
122111
rt.expect_validate_caller_any();
123112
rt.expect_verify_signature(ExpectedVerifySig {
124113
sig: Signature::new_secp256k1(vec![]),
125114
signer: addr,
126115
plaintext: vec![],
127116
result: Err(anyhow!("bad signature")),
128117
});
129-
assert_eq!(
118+
expect_abort_contains_message(
130119
ExitCode::USR_ILLEGAL_ARGUMENT,
131-
rt.call::<AccountActor>(3, &params).unwrap_err().exit_code()
120+
"bad signature",
121+
rt.call::<AccountActor>(Method::AuthenticateMessage as MethodNum, &params),
132122
);
133-
134123
rt.verify();
124+
125+
// Invalid caller of internal method number
126+
rt.set_caller(make_identity_cid(b"1234"), Address::new_id(1000));
127+
expect_abort_contains_message(
128+
ExitCode::USR_FORBIDDEN,
129+
"must be built-in",
130+
rt.call::<AccountActor>(Method::AuthenticateMessage as MethodNum, &params),
131+
);
132+
133+
// Ok to call exported method number
134+
rt.expect_validate_caller_any();
135+
rt.expect_verify_signature(ExpectedVerifySig {
136+
sig: Signature::new_secp256k1(vec![]),
137+
signer: addr,
138+
plaintext: vec![],
139+
result: Ok(()),
140+
});
141+
rt.call::<AccountActor>(Method::AuthenticateMessageExported as MethodNum, &params).unwrap();
142+
}
143+
144+
fn check_state(rt: &MockRuntime) {
145+
let test_address = Address::new_id(1000);
146+
let (_, acc) = check_state_invariants(&rt.get_state(), &test_address);
147+
acc.assert_empty();
135148
}

runtime/src/builtin/shared.rs

Lines changed: 35 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,8 +3,8 @@
33

44
use crate::{actor_error, ActorContext, ActorError};
55
use fvm_shared::address::Address;
6-
use fvm_shared::ActorID;
76
use fvm_shared::METHOD_SEND;
7+
use fvm_shared::{ActorID, MethodNum};
88

99
use crate::runtime::builtins::Type;
1010
use crate::runtime::Runtime;
@@ -38,3 +38,37 @@ pub fn resolve_to_actor_id(
3838

3939
Err(actor_error!(illegal_argument, "failed to resolve or initialize address {}", address))
4040
}
41+
42+
// The lowest FRC-42 method number.
43+
pub const FIRST_EXPORTED_METHOD_NUMBER: MethodNum = 1 << 24;
44+
45+
// Checks whether the caller is allowed to invoke some method number.
46+
// All method numbers below the FRC-42 range are restricted to built-in actors
47+
// (including the account and multisig actors).
48+
// Methods may subsequently enforce tighter restrictions.
49+
pub fn restrict_internal_api<RT>(rt: &mut RT, method: MethodNum) -> Result<(), ActorError>
50+
where
51+
RT: Runtime,
52+
{
53+
if method >= FIRST_EXPORTED_METHOD_NUMBER {
54+
return Ok(());
55+
}
56+
let caller = rt.message().caller();
57+
let code_cid = rt.get_actor_code_cid(&caller.id().unwrap());
58+
match code_cid {
59+
None => {
60+
return Err(
61+
actor_error!(forbidden; "no code for caller {} of method {}", caller, method),
62+
)
63+
}
64+
Some(code_cid) => {
65+
let builtin_type = rt.resolve_builtin_actor_type(&code_cid);
66+
if builtin_type.is_none() {
67+
return Err(
68+
actor_error!(forbidden; "caller {} of method {} must be built-in", caller, method),
69+
);
70+
}
71+
}
72+
}
73+
Ok(())
74+
}

runtime/src/test_utils.rs

Lines changed: 16 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -46,21 +46,21 @@ use fvm_shared::event::ActorEvent;
4646
use libsecp256k1::{recover, Message, RecoveryId, Signature as EcsdaSignature};
4747

4848
lazy_static::lazy_static! {
49-
pub static ref SYSTEM_ACTOR_CODE_ID: Cid = make_builtin(b"fil/test/system");
50-
pub static ref INIT_ACTOR_CODE_ID: Cid = make_builtin(b"fil/test/init");
51-
pub static ref CRON_ACTOR_CODE_ID: Cid = make_builtin(b"fil/test/cron");
52-
pub static ref ACCOUNT_ACTOR_CODE_ID: Cid = make_builtin(b"fil/test/account");
53-
pub static ref POWER_ACTOR_CODE_ID: Cid = make_builtin(b"fil/test/storagepower");
54-
pub static ref MINER_ACTOR_CODE_ID: Cid = make_builtin(b"fil/test/storageminer");
55-
pub static ref MARKET_ACTOR_CODE_ID: Cid = make_builtin(b"fil/test/storagemarket");
56-
pub static ref PAYCH_ACTOR_CODE_ID: Cid = make_builtin(b"fil/test/paymentchannel");
57-
pub static ref MULTISIG_ACTOR_CODE_ID: Cid = make_builtin(b"fil/test/multisig");
58-
pub static ref REWARD_ACTOR_CODE_ID: Cid = make_builtin(b"fil/test/reward");
59-
pub static ref VERIFREG_ACTOR_CODE_ID: Cid = make_builtin(b"fil/test/verifiedregistry");
60-
pub static ref DATACAP_TOKEN_ACTOR_CODE_ID: Cid = make_builtin(b"fil/test/datacap");
61-
pub static ref EMBRYO_ACTOR_CODE_ID: Cid = make_builtin(b"fil/test/embryo");
62-
pub static ref EVM_ACTOR_CODE_ID: Cid = make_builtin(b"fil/test/evm");
63-
pub static ref EAM_ACTOR_CODE_ID: Cid = make_builtin(b"fil/test/eam");
49+
pub static ref SYSTEM_ACTOR_CODE_ID: Cid = make_identity_cid(b"fil/test/system");
50+
pub static ref INIT_ACTOR_CODE_ID: Cid = make_identity_cid(b"fil/test/init");
51+
pub static ref CRON_ACTOR_CODE_ID: Cid = make_identity_cid(b"fil/test/cron");
52+
pub static ref ACCOUNT_ACTOR_CODE_ID: Cid = make_identity_cid(b"fil/test/account");
53+
pub static ref POWER_ACTOR_CODE_ID: Cid = make_identity_cid(b"fil/test/storagepower");
54+
pub static ref MINER_ACTOR_CODE_ID: Cid = make_identity_cid(b"fil/test/storageminer");
55+
pub static ref MARKET_ACTOR_CODE_ID: Cid = make_identity_cid(b"fil/test/storagemarket");
56+
pub static ref PAYCH_ACTOR_CODE_ID: Cid = make_identity_cid(b"fil/test/paymentchannel");
57+
pub static ref MULTISIG_ACTOR_CODE_ID: Cid = make_identity_cid(b"fil/test/multisig");
58+
pub static ref REWARD_ACTOR_CODE_ID: Cid = make_identity_cid(b"fil/test/reward");
59+
pub static ref VERIFREG_ACTOR_CODE_ID: Cid = make_identity_cid(b"fil/test/verifiedregistry");
60+
pub static ref DATACAP_TOKEN_ACTOR_CODE_ID: Cid = make_identity_cid(b"fil/test/datacap");
61+
pub static ref EMBRYO_ACTOR_CODE_ID: Cid = make_identity_cid(b"fil/test/embryo");
62+
pub static ref EVM_ACTOR_CODE_ID: Cid = make_identity_cid(b"fil/test/evm");
63+
pub static ref EAM_ACTOR_CODE_ID: Cid = make_identity_cid(b"fil/test/eam");
6464
pub static ref ACTOR_TYPES: BTreeMap<Cid, Type> = {
6565
let mut map = BTreeMap::new();
6666
map.insert(*SYSTEM_ACTOR_CODE_ID, Type::System);
@@ -114,7 +114,7 @@ lazy_static::lazy_static! {
114114
const IPLD_RAW: u64 = 0x55;
115115

116116
/// Returns an identity CID for bz.
117-
pub fn make_builtin(bz: &[u8]) -> Cid {
117+
pub fn make_identity_cid(bz: &[u8]) -> Cid {
118118
Cid::new_v1(IPLD_RAW, OtherMultihash::wrap(0, bz).expect("name too long"))
119119
}
120120

test_vm/tests/test_vm_test.rs

Lines changed: 6 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,7 @@
11
use fil_actor_account::State as AccountState;
2-
use fil_actors_runtime::test_utils::{make_builtin, ACCOUNT_ACTOR_CODE_ID, PAYCH_ACTOR_CODE_ID};
2+
use fil_actors_runtime::test_utils::{
3+
make_identity_cid, ACCOUNT_ACTOR_CODE_ID, PAYCH_ACTOR_CODE_ID,
4+
};
35
use fvm_ipld_blockstore::MemoryBlockstore;
46
use fvm_ipld_encoding::RawBytes;
57
use fvm_shared::address::Address;
@@ -20,7 +22,7 @@ fn state_control() {
2022
// set actor
2123
let a1 = actor(
2224
*ACCOUNT_ACTOR_CODE_ID,
23-
make_builtin(b"a1-head"),
25+
make_identity_cid(b"a1-head"),
2426
42,
2527
TokenAmount::from_atto(10u8),
2628
None,
@@ -32,11 +34,12 @@ fn state_control() {
3234

3335
let a2 = actor(
3436
*PAYCH_ACTOR_CODE_ID,
35-
make_builtin(b"a2-head"),
37+
make_identity_cid(b"a2-head"),
3638
88,
3739
TokenAmount::from_atto(1u8),
3840
None,
3941
);
42+
4043
v.set_actor(addr2, a2.clone());
4144
assert_eq!(v.get_actor(addr2).unwrap(), a2);
4245
// rollback removes a2 but not a1

0 commit comments

Comments
 (0)