1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99
// Copyright 2019-2022 PureStake Inc.
// This file is part of Moonbeam.
// Moonbeam is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
// Moonbeam is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
// You should have received a copy of the GNU General Public License
// along with Moonbeam. If not, see <http://www.gnu.org/licenses/>.
#![cfg_attr(not(feature = "std"), no_std)]
#[cfg(test)]
mod mock;
#[cfg(test)]
mod tests;
use core::marker::PhantomData;
use fp_evm::{ExitError, IsPrecompileResult, PrecompileFailure};
use precompile_utils::{
precompile_set::{is_precompile_or_fail, IsActivePrecompile},
prelude::*,
};
use sp_core::Get;
const DUMMY_CODE: [u8; 5] = [0x60, 0x00, 0x60, 0x00, 0xfd];
pub struct PrecompileRegistry<Runtime>(PhantomData<Runtime>);
#[precompile_utils::precompile]
impl<Runtime> PrecompileRegistry<Runtime>
where
Runtime: pallet_evm::Config,
Runtime::PrecompilesType: IsActivePrecompile,
{
#[precompile::public("isPrecompile(address)")]
#[precompile::view]
fn is_precompile(handle: &mut impl PrecompileHandle, address: Address) -> EvmResult<bool> {
// We consider the precompile set is optimized to do at most one storage read.
// In the case of moonbeam, the storage item that can be read is pallet_asset::Asset
// (TODO make it more generic, maybe add a const generic on PrecompileRegistry type)
// Storage item: Asset:
// Blake2_128(16) + AssetId(16) + AssetDetails((4 * AccountId(20)) + (3 * Balance(16)) + 15)
handle.record_db_read::<Runtime>(175)?;
is_precompile_or_fail::<Runtime>(address.0, handle.remaining_gas())
}
#[precompile::public("isActivePrecompile(address)")]
#[precompile::view]
fn is_active_precompile(
handle: &mut impl PrecompileHandle,
address: Address,
) -> EvmResult<bool> {
// We consider the precompile set is optimized to do at most one storage read.
// In the case of moonbeam, the storage item that can be read is pallet_asset::Asset
// (TODO make it more generic, maybe add a const generic on PrecompileRegistry type)
// Storage item: Asset:
// Blake2_128(16) + AssetId(16) + AssetDetails((4 * AccountId(20)) + (3 * Balance(16)) + 15)
handle.record_db_read::<Runtime>(175)?;
match <Runtime::PrecompilesValue>::get()
.is_active_precompile(address.0, handle.remaining_gas())
{
IsPrecompileResult::Answer { is_precompile, .. } => Ok(is_precompile),
IsPrecompileResult::OutOfGas => Err(PrecompileFailure::Error {
exit_status: ExitError::OutOfGas,
}),
}
}
#[precompile::public("updateAccountCode(address)")]
fn update_account_code(handle: &mut impl PrecompileHandle, address: Address) -> EvmResult<()> {
// Prevent touching addresses that are not precompiles.
//
// We consider the precompile set is optimized to do at most one storage read.
// In the case of moonbeam, the storage item that can be read is pallet_asset::Asset
// (TODO make it more generic, maybe add a const generic on PrecompileRegistry type)
// Storage item: Asset:
// Blake2_128(16) + AssetId(16) + AssetDetails((4 * AccountId(20)) + (3 * Balance(16)) + 15)
handle.record_db_read::<Runtime>(175)?;
if !is_precompile_or_fail::<Runtime>(address.0, handle.remaining_gas())? {
return Err(revert("provided address is not a precompile"));
}
// pallet_evm::create_account read storage item pallet_evm::AccountCodes
//
// AccountCodes: Blake2128(16) + H160(20) + Vec(5)
// We asume an existing precompile can hold at most 5 bytes worth of dummy code.
handle.record_db_read::<Runtime>(41)?;
pallet_evm::Pallet::<Runtime>::create_account(address.0, DUMMY_CODE.to_vec());
Ok(())
}
}