Skip to content

Commit b8a72f8

Browse files
committed
v10: backport two integration tests (#1204)
1 parent c84dbf0 commit b8a72f8

File tree

6 files changed

+313
-59
lines changed

6 files changed

+313
-59
lines changed

Cargo.lock

Lines changed: 42 additions & 8 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

test_vm/Cargo.toml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -51,6 +51,7 @@ rand_chacha = "0.3.1"
5151
regex = "1"
5252
serde = { version = "1.0.136", features = ["derive"] }
5353
thiserror = "1.0.30"
54+
libsecp256k1 = { version = "0.7.1"}
5455
fil_actors_evm_shared = { version = "10.0.0-alpha.1", path = "../actors/evm/shared" }
5556

5657
[dev-dependencies]

test_vm/src/lib.rs

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -434,6 +434,10 @@ impl<'bs> VM<'bs> {
434434
let mut a = self.get_actor(from_id).unwrap();
435435
let call_seq = a.call_seq_num;
436436
a.call_seq_num = call_seq + 1;
437+
// EthAccount abstractions turns Placeholders into EthAccounts
438+
if a.code == *PLACEHOLDER_ACTOR_CODE_ID {
439+
a.code = *ETHACCOUNT_ACTOR_CODE_ID;
440+
}
437441
self.set_actor(from_id, a);
438442

439443
let prior_root = self.checkpoint();

test_vm/tests/account_authenticate_message_test.rs

Lines changed: 0 additions & 51 deletions
This file was deleted.
Lines changed: 171 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,171 @@
1+
use fil_actor_account::types::AuthenticateMessageParams;
2+
use fil_actor_account::Method::AuthenticateMessageExported;
3+
use fil_actors_runtime::test_utils::hash;
4+
use fil_actors_runtime::EAM_ACTOR_ID;
5+
use fvm_ipld_blockstore::MemoryBlockstore;
6+
use fvm_ipld_encoding::RawBytes;
7+
use fvm_shared::address::Address;
8+
use fvm_shared::bigint::Zero;
9+
use fvm_shared::crypto::hash::SupportedHashes::Keccak256;
10+
use fvm_shared::econ::TokenAmount;
11+
use fvm_shared::error::ExitCode;
12+
use fvm_shared::METHOD_SEND;
13+
use rand::SeedableRng;
14+
use rand_chacha::ChaCha8Rng;
15+
use test_vm::util::{apply_code, apply_ok, create_accounts, generate_deal_proposal};
16+
use test_vm::VM;
17+
18+
// Using a deal proposal as a serialized message, we confirm that:
19+
// - calls to Account::authenticate_message with valid signatures succeed
20+
// - calls to Account::authenticate_message with invalid signatures fail
21+
#[test]
22+
fn account_authenticate_message() {
23+
let store = MemoryBlockstore::new();
24+
let v = VM::new_with_singletons(&store);
25+
let addr = create_accounts(&v, 1, TokenAmount::from_whole(10_000))[0];
26+
27+
let proposal =
28+
generate_deal_proposal(addr, addr, TokenAmount::zero(), TokenAmount::zero(), 0, 0);
29+
let proposal_ser =
30+
RawBytes::serialize(proposal).expect("failed to marshal deal proposal").to_vec();
31+
32+
// With a good sig, message succeeds
33+
let authenticate_message_params = AuthenticateMessageParams {
34+
signature: proposal_ser.clone(),
35+
message: proposal_ser.clone(),
36+
};
37+
apply_ok(
38+
&v,
39+
addr,
40+
addr,
41+
TokenAmount::zero(),
42+
AuthenticateMessageExported as u64,
43+
Some(authenticate_message_params),
44+
);
45+
46+
// Bad, bad sig! message fails
47+
let authenticate_message_params =
48+
AuthenticateMessageParams { signature: vec![], message: proposal_ser };
49+
apply_code(
50+
&v,
51+
addr,
52+
addr,
53+
TokenAmount::zero(),
54+
AuthenticateMessageExported as u64,
55+
Some(authenticate_message_params),
56+
ExitCode::USR_ILLEGAL_ARGUMENT,
57+
);
58+
}
59+
60+
// Using a deal proposal as a serialized message, we confirm that:
61+
// - calls to EthAccount::authenticate_message with valid signatures succeed
62+
#[test]
63+
fn ethaccount_authenticate_message_success() {
64+
let store = MemoryBlockstore::new();
65+
let v = VM::new_with_singletons(&store);
66+
let addr = create_accounts(&v, 1, TokenAmount::from_whole(10_000))[0];
67+
let rng = &mut ChaCha8Rng::seed_from_u64(0);
68+
let secret_key = libsecp256k1::SecretKey::random(rng);
69+
70+
let proposal =
71+
generate_deal_proposal(addr, addr, TokenAmount::zero(), TokenAmount::zero(), 0, 0);
72+
let proposal_ser =
73+
RawBytes::serialize(proposal).expect("failed to marshal deal proposal").to_vec();
74+
75+
let msg_hash = get_hash_for_signature(&proposal_ser);
76+
let (good_sig, recovery_id) = libsecp256k1::sign(&msg_hash, &secret_key);
77+
78+
let pub_key = libsecp256k1::recover(&msg_hash, &good_sig, &recovery_id).unwrap();
79+
let pub_key_ser = pub_key.serialize();
80+
let pub_key_hash = hash(Keccak256, &pub_key_ser[1..]).0;
81+
82+
let eth_addr = Address::new_delegated(EAM_ACTOR_ID, &pub_key_hash[12..32]).unwrap();
83+
84+
// Create a Placeholder by sending to it
85+
apply_ok(&v, addr, eth_addr, TokenAmount::from_whole(2), METHOD_SEND, None::<RawBytes>);
86+
87+
// Create the EthAccount by sending from the Placeholder
88+
apply_ok(&v, eth_addr, addr, TokenAmount::from_whole(1), METHOD_SEND, None::<RawBytes>);
89+
90+
let mut good_sig_ser = [0; 65];
91+
good_sig_ser[..64].copy_from_slice(&good_sig.serialize());
92+
good_sig_ser[64] = recovery_id.serialize();
93+
94+
// With a good sig, message succeeds
95+
let authenticate_message_params =
96+
AuthenticateMessageParams { signature: good_sig_ser.to_vec(), message: proposal_ser };
97+
apply_ok(
98+
&v,
99+
addr,
100+
eth_addr,
101+
TokenAmount::zero(),
102+
AuthenticateMessageExported as u64,
103+
Some(authenticate_message_params),
104+
);
105+
}
106+
107+
// Using a deal proposal as a serialized message, we confirm that
108+
// calls to EthAccount::authenticate_message with invalid signatures fail
109+
#[test]
110+
fn ethaccount_authenticate_message_failure() {
111+
let store = MemoryBlockstore::new();
112+
let v = VM::new_with_singletons(&store);
113+
let addr = create_accounts(&v, 1, TokenAmount::from_whole(10_000))[0];
114+
let rng = &mut ChaCha8Rng::seed_from_u64(0);
115+
let secret_key = libsecp256k1::SecretKey::random(rng);
116+
117+
let proposal =
118+
generate_deal_proposal(addr, addr, TokenAmount::zero(), TokenAmount::zero(), 0, 0);
119+
let proposal_ser =
120+
RawBytes::serialize(proposal).expect("failed to marshal deal proposal").to_vec();
121+
122+
let msg_hash = get_hash_for_signature(&proposal_ser);
123+
let (good_sig, recovery_id) = libsecp256k1::sign(&msg_hash, &secret_key);
124+
125+
let pub_key = libsecp256k1::recover(&msg_hash, &good_sig, &recovery_id).unwrap();
126+
let pub_key_ser = pub_key.serialize();
127+
let pub_key_hash = hash(Keccak256, &pub_key_ser[1..]).0;
128+
129+
let eth_addr = Address::new_delegated(EAM_ACTOR_ID, &pub_key_hash[12..32]).unwrap();
130+
131+
// Create a Placeholder by sending to it
132+
apply_ok(&v, addr, eth_addr, TokenAmount::from_whole(2), METHOD_SEND, None::<RawBytes>);
133+
134+
// Create the EthAccount by sending from the Placeholder
135+
apply_ok(&v, eth_addr, addr, TokenAmount::from_whole(1), METHOD_SEND, None::<RawBytes>);
136+
137+
// To test a bad sig, we sign the correct payload with a different key (this is a bit more comprehensive than simply flipping a bit)
138+
139+
let other_key = libsecp256k1::SecretKey::random(rng);
140+
assert_ne!(secret_key, other_key);
141+
142+
let (bad_sig, bad_recovery_id) = libsecp256k1::sign(&msg_hash, &other_key);
143+
let mut bad_sig_ser = [0; 65];
144+
bad_sig_ser[..64].copy_from_slice(&bad_sig.serialize());
145+
bad_sig_ser[64] = bad_recovery_id.serialize();
146+
147+
let authenticate_message_params =
148+
AuthenticateMessageParams { signature: bad_sig_ser.to_vec(), message: proposal_ser };
149+
apply_code(
150+
&v,
151+
addr,
152+
addr,
153+
TokenAmount::zero(),
154+
AuthenticateMessageExported as u64,
155+
Some(authenticate_message_params),
156+
ExitCode::USR_ILLEGAL_ARGUMENT,
157+
);
158+
}
159+
160+
fn get_hash_for_signature(bytes: &[u8]) -> libsecp256k1::Message {
161+
let hash: [u8; 32] = blake2b_simd::Params::new()
162+
.hash_length(32)
163+
.to_state()
164+
.update(bytes)
165+
.finalize()
166+
.as_bytes()
167+
.try_into()
168+
.expect("fixed array size");
169+
170+
libsecp256k1::Message::parse(&hash)
171+
}

0 commit comments

Comments
 (0)