Skip to content

Commit 2e398d5

Browse files
cmichixermicusathei
authored andcommitted
[pallet-revive] Move to_account_id host function to System pre-compile (#9455)
Part of closing #8572. cc @athei @pgherveou --------- Co-authored-by: xermicus <[email protected]> Co-authored-by: Alexander Theißen <[email protected]> (cherry picked from commit 8744f5e)
1 parent b83468f commit 2e398d5

File tree

11 files changed

+135
-179
lines changed

11 files changed

+135
-179
lines changed

prdoc/pr_9455.prdoc

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
title: '[pallet-revive] Migrate `to_account_id` from host function to pre-compile'
2+
doc:
3+
- audience: Runtime Dev
4+
description: Moves the unstable host function `to_account_id` to the
5+
`System` pre-compile.
6+
crates:
7+
- name: pallet-revive
8+
bump: patch
9+
- name: pallet-revive-fixtures
10+
bump: patch
11+
- name: pallet-revive-uapi
12+
bump: major

substrate/frame/revive/fixtures/contracts/to_account_id.rs

Lines changed: 0 additions & 40 deletions
This file was deleted.

substrate/frame/revive/src/benchmarking.rs

Lines changed: 24 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -23,11 +23,14 @@ use crate::{
2323
evm::runtime::GAS_PRICE,
2424
exec::{Key, MomentOf, PrecompileExt},
2525
limits,
26-
precompiles::{self, run::builtin as run_builtin_precompile},
26+
precompiles::{
27+
self, run::builtin as run_builtin_precompile, BenchmarkSystem, BuiltinPrecompile, ISystem,
28+
},
2729
storage::WriteOutcome,
2830
Pallet as Contracts, *,
2931
};
3032
use alloc::{vec, vec::Vec};
33+
use alloy_core::sol_types::SolInterface;
3134
use codec::{Encode, MaxEncodedLen};
3235
use frame_benchmarking::v2::*;
3336
use frame_support::{
@@ -548,35 +551,40 @@ mod benchmarks {
548551
}
549552

550553
#[benchmark(pov_mode = Measured)]
551-
fn seal_to_account_id() {
554+
fn to_account_id() {
552555
// use a mapped address for the benchmark, to ensure that we bench the worst
553556
// case (and not the fallback case).
557+
let account_id = account("precompile_to_account_id", 0, 0);
554558
let address = {
555-
let caller = account("seal_to_account_id", 0, 0);
556-
T::Currency::set_balance(&caller, caller_funding::<T>());
557-
T::AddressMapper::map(&caller).unwrap();
558-
T::AddressMapper::to_address(&caller)
559+
T::Currency::set_balance(&account_id, caller_funding::<T>());
560+
T::AddressMapper::map(&account_id).unwrap();
561+
T::AddressMapper::to_address(&account_id)
559562
};
560563

561-
let len = <T::AccountId as MaxEncodedLen>::max_encoded_len();
562-
build_runtime!(runtime, memory: [vec![0u8; len], address.0, ]);
564+
let input_bytes = ISystem::ISystemCalls::toAccountId(ISystem::toAccountIdCall {
565+
input: address.0.into(),
566+
})
567+
.abi_encode();
568+
569+
let mut call_setup = CallSetup::<T>::default();
570+
let (mut ext, _) = call_setup.ext();
563571

564572
let result;
565573
#[block]
566574
{
567-
result = runtime.bench_to_account_id(memory.as_mut_slice(), len as u32, 0);
575+
result = run_builtin_precompile(
576+
&mut ext,
577+
H160(BenchmarkSystem::<T>::MATCHER.base_address()).as_fixed_bytes(),
578+
input_bytes,
579+
);
568580
}
569-
570-
assert_ok!(result);
581+
let data = result.unwrap().data;
571582
assert_ne!(
572-
memory.as_slice()[20..32],
583+
data.as_slice()[20..32],
573584
[0xEE; 12],
574585
"fallback suffix found where none should be"
575586
);
576-
assert_eq!(
577-
T::AccountId::decode(&mut memory.as_slice()),
578-
Ok(runtime.ext().to_account_id(&address))
579-
);
587+
assert_eq!(T::AccountId::decode(&mut data.as_slice()), Ok(account_id),);
580588
}
581589

582590
#[benchmark(pov_mode = Measured)]
@@ -1969,9 +1977,6 @@ mod benchmarks {
19691977
// `n`: Input to hash in bytes
19701978
#[benchmark(pov_mode = Measured)]
19711979
fn hash_blake2_256(n: Linear<0, { limits::code::BLOB_BYTES }>) {
1972-
use crate::precompiles::{BenchmarkSystem, BuiltinPrecompile, ISystem};
1973-
use alloy_core::sol_types::SolInterface;
1974-
19751980
let input = vec![0u8; n as usize];
19761981
let input_bytes = ISystem::ISystemCalls::hashBlake256(ISystem::hashBlake256Call {
19771982
input: input.clone().into(),

substrate/frame/revive/src/exec.rs

Lines changed: 0 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -324,9 +324,6 @@ pub trait PrecompileExt: sealing::Sealed {
324324
/// Return the origin of the whole call stack.
325325
fn origin(&self) -> &Origin<Self::T>;
326326

327-
/// Returns the account id for the given `address`.
328-
fn to_account_id(&self, address: &H160) -> AccountIdOf<Self::T>;
329-
330327
/// Returns the code hash of the contract for the given `address`.
331328
/// If not a contract but account exists then `keccak_256([])` is returned, otherwise `zero`.
332329
fn code_hash(&self, address: &H160) -> H256;
@@ -1939,10 +1936,6 @@ where
19391936
&self.origin
19401937
}
19411938

1942-
fn to_account_id(&self, address: &H160) -> T::AccountId {
1943-
T::AddressMapper::to_account_id(address)
1944-
}
1945-
19461939
fn code_hash(&self, address: &H160) -> H256 {
19471940
if let Some(code) = <AllPrecompiles<T>>::code(address.as_fixed_bytes()) {
19481941
return sp_io::hashing::keccak_256(code).into()

substrate/frame/revive/src/exec/tests.rs

Lines changed: 0 additions & 34 deletions
Original file line numberDiff line numberDiff line change
@@ -793,40 +793,6 @@ fn origin_returns_proper_values() {
793793
assert_eq!(WitnessedCallerCharlie::get(), Some(ALICE_ADDR));
794794
}
795795

796-
#[test]
797-
fn to_account_id_returns_proper_values() {
798-
let bob_code_hash = MockLoader::insert(Call, |ctx, _| {
799-
let alice_account_id = <Test as Config>::AddressMapper::to_account_id(&ALICE_ADDR);
800-
assert_eq!(ctx.ext.to_account_id(&ALICE_ADDR), alice_account_id);
801-
802-
const UNMAPPED_ADDR: H160 = H160([99u8; 20]);
803-
let mut unmapped_fallback_account_id = [0xEE; 32];
804-
unmapped_fallback_account_id[..20].copy_from_slice(UNMAPPED_ADDR.as_bytes());
805-
assert_eq!(
806-
ctx.ext.to_account_id(&UNMAPPED_ADDR),
807-
AccountId32::new(unmapped_fallback_account_id)
808-
);
809-
810-
exec_success()
811-
});
812-
813-
ExtBuilder::default().build().execute_with(|| {
814-
place_contract(&BOB, bob_code_hash);
815-
let origin = Origin::from_account_id(ALICE);
816-
let mut storage_meter = storage::meter::Meter::new(0);
817-
let result = MockStack::run_call(
818-
origin,
819-
BOB_ADDR,
820-
&mut GasMeter::<Test>::new(GAS_LIMIT),
821-
&mut storage_meter,
822-
U256::zero(),
823-
vec![0],
824-
false,
825-
);
826-
assert_matches!(result, Ok(_));
827-
});
828-
}
829-
830796
#[test]
831797
fn code_hash_returns_proper_values() {
832798
let bob_code_hash = MockLoader::insert(Call, |ctx, _| {

substrate/frame/revive/src/precompiles/builtin/system.rs

Lines changed: 90 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -31,6 +31,16 @@ sol! {
3131
interface ISystem {
3232
/// Computes the BLAKE2 256-bit hash on the given input.
3333
function hashBlake256(bytes memory input) external pure returns (bytes32 digest);
34+
/// Retrieve the account id for a specified `H160` address.
35+
///
36+
/// Calling this function on a native `H160` chain (`type AccountId = H160`)
37+
/// does not make sense, as it would just return the `address` that it was
38+
/// called with.
39+
///
40+
/// # Note
41+
///
42+
/// If no mapping exists for `addr`, the fallback account id will be returned.
43+
function toAccountId(address input) external view returns (bytes memory account_id);
3444
}
3545
}
3646

@@ -53,17 +63,95 @@ impl<T: Config> BuiltinPrecompile for System<T> {
5363
let output = sp_io::hashing::blake2_256(input.as_bytes_ref());
5464
Ok(output.to_vec())
5565
},
66+
ISystemCalls::toAccountId(ISystem::toAccountIdCall { input }) => {
67+
use crate::address::AddressMapper;
68+
use codec::Encode;
69+
env.gas_meter_mut().charge(RuntimeCosts::ToAccountId)?;
70+
let account_id =
71+
T::AddressMapper::to_account_id(&crate::H160::from_slice(input.as_slice()));
72+
Ok(account_id.encode())
73+
},
5674
}
5775
}
5876
}
5977

6078
#[cfg(test)]
6179
mod tests {
62-
use super::*;
63-
use crate::{precompiles::tests::run_test_vectors, tests::Test};
80+
use super::{ISystem, *};
81+
use crate::{
82+
address::AddressMapper,
83+
call_builder::{caller_funding, CallSetup},
84+
pallet,
85+
precompiles::{tests::run_test_vectors, BuiltinPrecompile},
86+
tests::{ExtBuilder, Test},
87+
H160,
88+
};
89+
use codec::Decode;
90+
use frame_support::traits::fungible::Mutate;
6491

6592
#[test]
6693
fn test_system_precompile() {
6794
run_test_vectors::<System<Test>>(include_str!("testdata/900-blake2_256.json"));
95+
run_test_vectors::<System<Test>>(include_str!("testdata/900-to_account_id.json"));
96+
}
97+
98+
#[test]
99+
fn test_system_precompile_unmapped_account() {
100+
ExtBuilder::default().build().execute_with(|| {
101+
// given
102+
let mut call_setup = CallSetup::<Test>::default();
103+
let (mut ext, _) = call_setup.ext();
104+
let unmapped_address = H160::zero();
105+
106+
// when
107+
let input = ISystem::ISystemCalls::toAccountId(ISystem::toAccountIdCall {
108+
input: unmapped_address.0.into(),
109+
});
110+
let expected_fallback_account_id =
111+
<System<Test>>::call(&<System<Test>>::MATCHER.base_address(), &input, &mut ext)
112+
.unwrap();
113+
114+
// then
115+
assert_eq!(
116+
expected_fallback_account_id[20..32],
117+
[0xEE; 12],
118+
"no fallback suffix found where one should be"
119+
);
120+
})
121+
}
122+
123+
#[test]
124+
fn test_system_precompile_mapped_account() {
125+
use crate::test_utils::EVE;
126+
ExtBuilder::default().build().execute_with(|| {
127+
// given
128+
let mapped_address = {
129+
<Test as pallet::Config>::Currency::set_balance(&EVE, caller_funding::<Test>());
130+
let _ = <Test as pallet::Config>::AddressMapper::map(&EVE);
131+
<Test as pallet::Config>::AddressMapper::to_address(&EVE)
132+
};
133+
134+
let mut call_setup = CallSetup::<Test>::default();
135+
let (mut ext, _) = call_setup.ext();
136+
137+
// when
138+
let input = ISystem::ISystemCalls::toAccountId(ISystem::toAccountIdCall {
139+
input: mapped_address.0.into(),
140+
});
141+
let data =
142+
<System<Test>>::call(&<System<Test>>::MATCHER.base_address(), &input, &mut ext)
143+
.unwrap();
144+
145+
// then
146+
assert_ne!(
147+
data.as_slice()[20..32],
148+
[0xEE; 12],
149+
"fallback suffix found where none should be"
150+
);
151+
assert_eq!(
152+
<Test as frame_system::Config>::AccountId::decode(&mut data.as_slice()),
153+
Ok(EVE),
154+
);
155+
})
68156
}
69157
}
Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
[
2+
{
3+
"Input": "cf5231cc00000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000001000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000000",
4+
"Expected": "0000000000000000000000000000000000000020eeeeeeeeeeeeeeeeeeeeeeee",
5+
"Name": "vector 1",
6+
"Gas": 8000000,
7+
"NoBenchmark": false
8+
}
9+
]

substrate/frame/revive/src/tests.rs

Lines changed: 0 additions & 37 deletions
Original file line numberDiff line numberDiff line change
@@ -3913,43 +3913,6 @@ fn origin_api_works() {
39133913
});
39143914
}
39153915

3916-
#[test]
3917-
fn to_account_id_works() {
3918-
let (code_hash_code, _) = compile_module("to_account_id").unwrap();
3919-
3920-
ExtBuilder::default().existential_deposit(1).build().execute_with(|| {
3921-
let _ = <Test as Config>::Currency::set_balance(&ALICE, 1_000_000);
3922-
let _ = <Test as Config>::Currency::set_balance(&EVE, 1_000_000);
3923-
3924-
let Contract { addr, .. } =
3925-
builder::bare_instantiate(Code::Upload(code_hash_code)).build_and_unwrap_contract();
3926-
3927-
// mapped account
3928-
<Pallet<Test>>::map_account(RuntimeOrigin::signed(EVE)).unwrap();
3929-
let expected_mapped_account_id = &<Test as Config>::AddressMapper::to_account_id(&EVE_ADDR);
3930-
assert_ne!(
3931-
expected_mapped_account_id.encode()[20..32],
3932-
[0xEE; 12],
3933-
"fallback suffix found where none should be"
3934-
);
3935-
assert_ok!(builder::call(addr)
3936-
.data((EVE_ADDR, expected_mapped_account_id).encode())
3937-
.build());
3938-
3939-
// fallback for unmapped accounts
3940-
let expected_fallback_account_id =
3941-
&<Test as Config>::AddressMapper::to_account_id(&BOB_ADDR);
3942-
assert_eq!(
3943-
expected_fallback_account_id.encode()[20..32],
3944-
[0xEE; 12],
3945-
"no fallback suffix found where one should be"
3946-
);
3947-
assert_ok!(builder::call(addr)
3948-
.data((BOB_ADDR, expected_fallback_account_id).encode())
3949-
.build());
3950-
});
3951-
}
3952-
39533916
#[test]
39543917
fn code_hash_works() {
39553918
use crate::precompiles::{Precompile, EVM_REVERT};

substrate/frame/revive/src/vm/runtime.rs

Lines changed: 0 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -2123,25 +2123,4 @@ pub mod env {
21232123
already_charged,
21242124
)?)
21252125
}
2126-
2127-
/// Retrieves the account id for a specified contract address.
2128-
///
2129-
/// See [`pallet_revive_uapi::HostFn::to_account_id`].
2130-
fn to_account_id(
2131-
&mut self,
2132-
memory: &mut M,
2133-
addr_ptr: u32,
2134-
out_ptr: u32,
2135-
) -> Result<(), TrapReason> {
2136-
self.charge_gas(RuntimeCosts::ToAccountId)?;
2137-
let address = memory.read_h160(addr_ptr)?;
2138-
let account_id = self.ext.to_account_id(&address);
2139-
Ok(self.write_fixed_sandbox_output(
2140-
memory,
2141-
out_ptr,
2142-
&account_id.encode(),
2143-
false,
2144-
already_charged,
2145-
)?)
2146-
}
21472126
}

0 commit comments

Comments
 (0)