Skip to content

Commit 2ac6b9e

Browse files
committed
Proof of concept exported API for Account actor
1 parent fdcf50b commit 2ac6b9e

File tree

5 files changed

+108
-50
lines changed

5 files changed

+108
-50
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: 36 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,38 @@ 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<BS, RT>(rt: &mut RT, method: MethodNum) -> Result<(), ActorError>
50+
where
51+
BS: Blockstore,
52+
RT: Runtime<BS>,
53+
{
54+
if method >= FIRST_EXPORTED_METHOD_NUMBER {
55+
return Ok(());
56+
}
57+
let caller = rt.message().caller();
58+
let code_cid = rt.get_actor_code_cid(&caller.id().unwrap());
59+
match code_cid {
60+
None => {
61+
return Err(
62+
actor_error!(forbidden; "no code for caller {} of method {}", caller, method),
63+
)
64+
}
65+
Some(code_cid) => {
66+
let builtin_type = rt.resolve_builtin_actor_type(&code_cid);
67+
if builtin_type.is_none() {
68+
return Err(
69+
actor_error!(forbidden; "caller {} of method {} must be built-in", caller, method),
70+
);
71+
}
72+
}
73+
}
74+
Ok(())
75+
}

runtime/src/test_utils.rs

Lines changed: 13 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -42,18 +42,18 @@ use crate::runtime::{
4242
use crate::{actor_error, ActorError};
4343

4444
lazy_static::lazy_static! {
45-
pub static ref SYSTEM_ACTOR_CODE_ID: Cid = make_builtin(b"fil/test/system");
46-
pub static ref INIT_ACTOR_CODE_ID: Cid = make_builtin(b"fil/test/init");
47-
pub static ref CRON_ACTOR_CODE_ID: Cid = make_builtin(b"fil/test/cron");
48-
pub static ref ACCOUNT_ACTOR_CODE_ID: Cid = make_builtin(b"fil/test/account");
49-
pub static ref POWER_ACTOR_CODE_ID: Cid = make_builtin(b"fil/test/storagepower");
50-
pub static ref MINER_ACTOR_CODE_ID: Cid = make_builtin(b"fil/test/storageminer");
51-
pub static ref MARKET_ACTOR_CODE_ID: Cid = make_builtin(b"fil/test/storagemarket");
52-
pub static ref PAYCH_ACTOR_CODE_ID: Cid = make_builtin(b"fil/test/paymentchannel");
53-
pub static ref MULTISIG_ACTOR_CODE_ID: Cid = make_builtin(b"fil/test/multisig");
54-
pub static ref REWARD_ACTOR_CODE_ID: Cid = make_builtin(b"fil/test/reward");
55-
pub static ref VERIFREG_ACTOR_CODE_ID: Cid = make_builtin(b"fil/test/verifiedregistry");
56-
pub static ref DATACAP_TOKEN_ACTOR_CODE_ID: Cid = make_builtin(b"fil/test/datacap");
45+
pub static ref SYSTEM_ACTOR_CODE_ID: Cid = make_identity_cid(b"fil/test/system");
46+
pub static ref INIT_ACTOR_CODE_ID: Cid = make_identity_cid(b"fil/test/init");
47+
pub static ref CRON_ACTOR_CODE_ID: Cid = make_identity_cid(b"fil/test/cron");
48+
pub static ref ACCOUNT_ACTOR_CODE_ID: Cid = make_identity_cid(b"fil/test/account");
49+
pub static ref POWER_ACTOR_CODE_ID: Cid = make_identity_cid(b"fil/test/storagepower");
50+
pub static ref MINER_ACTOR_CODE_ID: Cid = make_identity_cid(b"fil/test/storageminer");
51+
pub static ref MARKET_ACTOR_CODE_ID: Cid = make_identity_cid(b"fil/test/storagemarket");
52+
pub static ref PAYCH_ACTOR_CODE_ID: Cid = make_identity_cid(b"fil/test/paymentchannel");
53+
pub static ref MULTISIG_ACTOR_CODE_ID: Cid = make_identity_cid(b"fil/test/multisig");
54+
pub static ref REWARD_ACTOR_CODE_ID: Cid = make_identity_cid(b"fil/test/reward");
55+
pub static ref VERIFREG_ACTOR_CODE_ID: Cid = make_identity_cid(b"fil/test/verifiedregistry");
56+
pub static ref DATACAP_TOKEN_ACTOR_CODE_ID: Cid = make_identity_cid(b"fil/test/datacap");
5757
pub static ref ACTOR_TYPES: BTreeMap<Cid, Type> = {
5858
let mut map = BTreeMap::new();
5959
map.insert(*SYSTEM_ACTOR_CODE_ID, Type::System);
@@ -99,7 +99,7 @@ lazy_static::lazy_static! {
9999
const IPLD_RAW: u64 = 0x55;
100100

101101
/// Returns an identity CID for bz.
102-
pub fn make_builtin(bz: &[u8]) -> Cid {
102+
pub fn make_identity_cid(bz: &[u8]) -> Cid {
103103
Cid::new_v1(IPLD_RAW, OtherMultihash::wrap(0, bz).expect("name too long"))
104104
}
105105

test_vm/tests/test_vm_test.rs

Lines changed: 11 additions & 4 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;
@@ -18,14 +20,19 @@ fn state_control() {
1820
let addr2 = Address::new_id(2222);
1921

2022
// set actor
21-
let a1 =
22-
actor(*ACCOUNT_ACTOR_CODE_ID, make_builtin(b"a1-head"), 42, TokenAmount::from_atto(10u8));
23+
let a1 = actor(
24+
*ACCOUNT_ACTOR_CODE_ID,
25+
make_identity_cid(b"a1-head"),
26+
42,
27+
TokenAmount::from_atto(10u8),
28+
);
2329
v.set_actor(addr1, a1.clone());
2430
let out = v.get_actor(addr1).unwrap();
2531
assert_eq!(out, a1);
2632
let check = v.checkpoint();
2733

28-
let a2 = actor(*PAYCH_ACTOR_CODE_ID, make_builtin(b"a2-head"), 88, TokenAmount::from_atto(1u8));
34+
let a2 =
35+
actor(*PAYCH_ACTOR_CODE_ID, make_identity_cid(b"a2-head"), 88, TokenAmount::from_atto(1u8));
2936
v.set_actor(addr2, a2.clone());
3037
assert_eq!(v.get_actor(addr2).unwrap(), a2);
3138
// rollback removes a2 but not a1

0 commit comments

Comments
 (0)