Files
pezkuwi-sdk/bizinikiwi/pezframe/revive/src/precompiles/builtin/system.rs
T
pezkuwichain 3139ffa25e fix: Complete snowbridge pezpallet rebrand and critical bug fixes
- snowbridge-pezpallet-* → pezsnowbridge-pezpallet-* (201 refs)
- pallet/ directories → pezpallet/ (4 locations)
- Fixed pezpallet.rs self-include recursion bug
- Fixed sc-chain-spec hardcoded crate name in derive macro
- Reverted .pezpallet_by_name() to .pallet_by_name() (subxt API)
- Added BizinikiwiConfig type alias for zombienet tests
- Deleted obsolete session state files

Verified: pezsnowbridge-pezpallet-*, pezpallet-staking,
pezpallet-staking-async, pezframe-benchmarking-cli all pass cargo check
2025-12-16 09:57:23 +03:00

191 lines
6.4 KiB
Rust

// This file is part of Bizinikiwi.
// Copyright (C) Parity Technologies (UK) Ltd.
// SPDX-License-Identifier: Apache-2.0
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
use crate::{
address::AddressMapper,
precompiles::{BuiltinAddressMatcher, BuiltinPrecompile, Error, Ext},
vm::RuntimeCosts,
Config, H160,
};
use alloc::vec::Vec;
use alloy_core::sol_types::SolValue;
use codec::Encode;
use core::{marker::PhantomData, num::NonZero};
use pezpallet_revive_uapi::precompiles::system::ISystem;
use pezsp_core::hexdisplay::AsBytesRef;
pub struct System<T>(PhantomData<T>);
impl<T: Config> BuiltinPrecompile for System<T> {
type T = T;
type Interface = ISystem::ISystemCalls;
const MATCHER: BuiltinAddressMatcher =
BuiltinAddressMatcher::Fixed(NonZero::new(0x900).unwrap());
const HAS_CONTRACT_INFO: bool = false;
fn call(
_address: &[u8; 20],
input: &Self::Interface,
env: &mut impl Ext<T = Self::T>,
) -> Result<Vec<u8>, Error> {
use ISystem::ISystemCalls;
match input {
ISystemCalls::terminate(_) if env.is_read_only() =>
Err(crate::Error::<T>::StateChangeDenied.into()),
ISystemCalls::hashBlake256(ISystem::hashBlake256Call { input }) => {
env.gas_meter_mut().charge(RuntimeCosts::HashBlake256(input.len() as u32))?;
let output = pezsp_io::hashing::blake2_256(input.as_bytes_ref());
Ok(output.abi_encode())
},
ISystemCalls::hashBlake128(ISystem::hashBlake128Call { input }) => {
env.gas_meter_mut().charge(RuntimeCosts::HashBlake128(input.len() as u32))?;
let output = pezsp_io::hashing::blake2_128(input.as_bytes_ref());
Ok(output.abi_encode())
},
ISystemCalls::toAccountId(ISystem::toAccountIdCall { input }) => {
env.gas_meter_mut().charge(RuntimeCosts::ToAccountId)?;
let account_id = env.to_account_id(&H160::from_slice(input.as_slice()));
Ok(account_id.encode().abi_encode())
},
ISystemCalls::callerIsOrigin(ISystem::callerIsOriginCall {}) => {
env.gas_meter_mut().charge(RuntimeCosts::CallerIsOrigin)?;
let is_origin = env.caller_is_origin(true);
Ok(is_origin.abi_encode())
},
ISystemCalls::callerIsRoot(ISystem::callerIsRootCall {}) => {
env.gas_meter_mut().charge(RuntimeCosts::CallerIsRoot)?;
let is_root = env.caller_is_root(true);
Ok(is_root.abi_encode())
},
ISystemCalls::ownCodeHash(ISystem::ownCodeHashCall {}) => {
env.gas_meter_mut().charge(RuntimeCosts::OwnCodeHash)?;
let caller = env.caller();
let addr = T::AddressMapper::to_address(caller.account_id()?);
let output = env.code_hash(&addr.into()).0.abi_encode();
Ok(output)
},
ISystemCalls::minimumBalance(ISystem::minimumBalanceCall {}) => {
env.gas_meter_mut().charge(RuntimeCosts::MinimumBalance)?;
let minimum_balance = env.minimum_balance();
Ok(minimum_balance.to_big_endian().abi_encode())
},
ISystemCalls::weightLeft(ISystem::weightLeftCall {}) => {
env.gas_meter_mut().charge(RuntimeCosts::WeightLeft)?;
let ref_time = env.gas_meter().gas_left().ref_time();
let proof_size = env.gas_meter().gas_left().proof_size();
let res = (ref_time, proof_size);
Ok(res.abi_encode())
},
ISystemCalls::terminate(ISystem::terminateCall { beneficiary }) => {
// no need to adjust gas because this always deletes code
env.gas_meter_mut().charge(RuntimeCosts::Terminate { code_removed: true })?;
let h160 = H160::from_slice(beneficiary.as_slice());
env.terminate_caller(&h160).map_err(Error::try_to_revert::<T>)?;
Ok(Vec::new())
},
}
}
}
#[cfg(test)]
mod tests {
use super::*;
use crate::{
address::AddressMapper,
call_builder::{caller_funding, CallSetup},
pezpallet,
precompiles::{
alloy::sol_types::{sol_data::Bytes, SolType},
tests::run_test_vectors,
BuiltinPrecompile,
},
tests::{ExtBuilder, Test},
};
use codec::Decode;
use pezframe_support::traits::fungible::Mutate;
#[test]
fn test_system_precompile() {
run_test_vectors::<System<Test>>(include_str!("testdata/900-blake2_256.json"));
run_test_vectors::<System<Test>>(include_str!("testdata/900-blake2_128.json"));
run_test_vectors::<System<Test>>(include_str!("testdata/900-to_account_id.json"));
}
#[test]
fn test_system_precompile_unmapped_account() {
ExtBuilder::default().build().execute_with(|| {
// given
let mut call_setup = CallSetup::<Test>::default();
let (mut ext, _) = call_setup.ext();
let unmapped_address = H160::zero();
// when
let input = ISystem::ISystemCalls::toAccountId(ISystem::toAccountIdCall {
input: unmapped_address.0.into(),
});
let raw_data =
<System<Test>>::call(&<System<Test>>::MATCHER.base_address(), &input, &mut ext)
.unwrap();
// then
let expected_fallback_account_id =
Bytes::abi_decode(&raw_data).expect("decoding failed");
assert_eq!(
expected_fallback_account_id.0.as_ref()[20..32],
[0xEE; 12],
"no fallback suffix found where one should be"
);
})
}
#[test]
fn test_system_precompile_mapped_account() {
use crate::test_utils::EVE;
ExtBuilder::default().build().execute_with(|| {
// given
let mapped_address = {
<Test as pezpallet::Config>::Currency::set_balance(&EVE, caller_funding::<Test>());
let _ = <Test as pezpallet::Config>::AddressMapper::map(&EVE);
<Test as pezpallet::Config>::AddressMapper::to_address(&EVE)
};
let mut call_setup = CallSetup::<Test>::default();
let (mut ext, _) = call_setup.ext();
// when
let input = ISystem::ISystemCalls::toAccountId(ISystem::toAccountIdCall {
input: mapped_address.0.into(),
});
let raw_data =
<System<Test>>::call(&<System<Test>>::MATCHER.base_address(), &input, &mut ext)
.unwrap();
// then
let data = Bytes::abi_decode(&raw_data).expect("decoding failed");
assert_ne!(
data.0.as_ref()[20..32],
[0xEE; 12],
"fallback suffix found where none should be"
);
assert_eq!(
<Test as pezframe_system::Config>::AccountId::decode(&mut data.as_ref()),
Ok(EVE),
);
})
}
}