mirror of
https://github.com/pezkuwichain/pezkuwi-subxt.git
synced 2026-06-17 14:51:07 +00:00
pallet-evm: add builtin support for the four basic Ethereum precompiles (#6743)
* pallet-evm: add builtin support for the four basic Ethereum precompiles * linear_cost -> ensure_linear_cost to directly return OutOfGas error
This commit is contained in:
Generated
+12
@@ -4391,6 +4391,7 @@ dependencies = [
|
|||||||
"pallet-timestamp",
|
"pallet-timestamp",
|
||||||
"parity-scale-codec",
|
"parity-scale-codec",
|
||||||
"primitive-types",
|
"primitive-types",
|
||||||
|
"ripemd160",
|
||||||
"rlp",
|
"rlp",
|
||||||
"serde",
|
"serde",
|
||||||
"sha3",
|
"sha3",
|
||||||
@@ -5954,6 +5955,17 @@ dependencies = [
|
|||||||
"winapi 0.3.8",
|
"winapi 0.3.8",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "ripemd160"
|
||||||
|
version = "0.9.1"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "2eca4ecc81b7f313189bf73ce724400a07da2a6dac19588b03c8bd76a2dcc251"
|
||||||
|
dependencies = [
|
||||||
|
"block-buffer 0.9.0",
|
||||||
|
"digest 0.9.0",
|
||||||
|
"opaque-debug 0.3.0",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "rle-decode-fast"
|
name = "rle-decode-fast"
|
||||||
version = "1.0.1"
|
version = "1.0.1"
|
||||||
|
|||||||
@@ -27,6 +27,7 @@ rlp = { version = "0.4", default-features = false }
|
|||||||
evm = { version = "0.17", default-features = false }
|
evm = { version = "0.17", default-features = false }
|
||||||
sha3 = { version = "0.8", default-features = false }
|
sha3 = { version = "0.8", default-features = false }
|
||||||
impl-trait-for-tuples = "0.1"
|
impl-trait-for-tuples = "0.1"
|
||||||
|
ripemd160 = { version = "0.9", default-features = false }
|
||||||
|
|
||||||
[features]
|
[features]
|
||||||
default = ["std"]
|
default = ["std"]
|
||||||
@@ -45,4 +46,5 @@ std = [
|
|||||||
"primitive-types/std",
|
"primitive-types/std",
|
||||||
"evm/std",
|
"evm/std",
|
||||||
"pallet-timestamp/std",
|
"pallet-timestamp/std",
|
||||||
|
"ripemd160/std",
|
||||||
]
|
]
|
||||||
|
|||||||
@@ -21,8 +21,8 @@
|
|||||||
#![cfg_attr(not(feature = "std"), no_std)]
|
#![cfg_attr(not(feature = "std"), no_std)]
|
||||||
|
|
||||||
mod backend;
|
mod backend;
|
||||||
mod precompiles;
|
|
||||||
mod tests;
|
mod tests;
|
||||||
|
pub mod precompiles;
|
||||||
|
|
||||||
pub use crate::precompiles::{Precompile, Precompiles};
|
pub use crate::precompiles::{Precompile, Precompiles};
|
||||||
pub use crate::backend::{Account, Log, Vicinity, Backend};
|
pub use crate::backend::{Account, Log, Vicinity, Backend};
|
||||||
|
|||||||
@@ -15,9 +15,12 @@
|
|||||||
// See the License for the specific language governing permissions and
|
// See the License for the specific language governing permissions and
|
||||||
// limitations under the License.
|
// limitations under the License.
|
||||||
|
|
||||||
use sp_std::vec::Vec;
|
//! Builtin precompiles.
|
||||||
|
|
||||||
|
use sp_std::{cmp::min, vec::Vec};
|
||||||
use sp_core::H160;
|
use sp_core::H160;
|
||||||
use evm::{ExitError, ExitSucceed};
|
use evm::{ExitError, ExitSucceed};
|
||||||
|
use ripemd160::Digest;
|
||||||
use impl_trait_for_tuples::impl_for_tuples;
|
use impl_trait_for_tuples::impl_for_tuples;
|
||||||
|
|
||||||
/// Custom precompiles to be used by EVM engine.
|
/// Custom precompiles to be used by EVM engine.
|
||||||
@@ -67,3 +70,97 @@ impl Precompiles for Tuple {
|
|||||||
None
|
None
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Linear gas cost
|
||||||
|
fn ensure_linear_cost(
|
||||||
|
target_gas: Option<usize>,
|
||||||
|
len: usize,
|
||||||
|
base: usize,
|
||||||
|
word: usize
|
||||||
|
) -> Result<usize, ExitError> {
|
||||||
|
let cost = base.checked_add(
|
||||||
|
word.checked_mul(len.saturating_add(31) / 32).ok_or(ExitError::OutOfGas)?
|
||||||
|
).ok_or(ExitError::OutOfGas)?;
|
||||||
|
|
||||||
|
if let Some(target_gas) = target_gas {
|
||||||
|
if cost > target_gas {
|
||||||
|
return Err(ExitError::OutOfGas)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Ok(cost)
|
||||||
|
}
|
||||||
|
|
||||||
|
/// The identity precompile.
|
||||||
|
pub struct Identity;
|
||||||
|
|
||||||
|
impl Precompile for Identity {
|
||||||
|
fn execute(
|
||||||
|
input: &[u8],
|
||||||
|
target_gas: Option<usize>,
|
||||||
|
) -> core::result::Result<(ExitSucceed, Vec<u8>, usize), ExitError> {
|
||||||
|
let cost = ensure_linear_cost(target_gas, input.len(), 15, 3)?;
|
||||||
|
|
||||||
|
Ok((ExitSucceed::Returned, input.to_vec(), cost))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// The ecrecover precompile.
|
||||||
|
pub struct ECRecover;
|
||||||
|
|
||||||
|
impl Precompile for ECRecover {
|
||||||
|
fn execute(
|
||||||
|
i: &[u8],
|
||||||
|
target_gas: Option<usize>,
|
||||||
|
) -> core::result::Result<(ExitSucceed, Vec<u8>, usize), ExitError> {
|
||||||
|
let cost = ensure_linear_cost(target_gas, i.len(), 3000, 0)?;
|
||||||
|
|
||||||
|
let mut input = [0u8; 128];
|
||||||
|
input[..min(i.len(), 128)].copy_from_slice(&i[..min(i.len(), 128)]);
|
||||||
|
|
||||||
|
let mut msg = [0u8; 32];
|
||||||
|
let mut sig = [0u8; 65];
|
||||||
|
|
||||||
|
msg[0..32].copy_from_slice(&input[0..32]);
|
||||||
|
sig[0..32].copy_from_slice(&input[64..96]);
|
||||||
|
sig[32..64].copy_from_slice(&input[96..128]);
|
||||||
|
sig[64] = input[63];
|
||||||
|
|
||||||
|
let pubkey = sp_io::crypto::secp256k1_ecdsa_recover(&sig, &msg)
|
||||||
|
.map_err(|_| ExitError::Other("Public key recover failed"))?;
|
||||||
|
let mut address = sp_io::hashing::keccak_256(&pubkey);
|
||||||
|
address[0..12].copy_from_slice(&[0u8; 12]);
|
||||||
|
|
||||||
|
Ok((ExitSucceed::Returned, address.to_vec(), cost))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// The ripemd precompile.
|
||||||
|
pub struct Ripemd160;
|
||||||
|
|
||||||
|
impl Precompile for Ripemd160 {
|
||||||
|
fn execute(
|
||||||
|
input: &[u8],
|
||||||
|
target_gas: Option<usize>,
|
||||||
|
) -> core::result::Result<(ExitSucceed, Vec<u8>, usize), ExitError> {
|
||||||
|
let cost = ensure_linear_cost(target_gas, input.len(), 600, 120)?;
|
||||||
|
|
||||||
|
let ret = ripemd160::Ripemd160::digest(input).to_vec();
|
||||||
|
Ok((ExitSucceed::Returned, ret, cost))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// The sha256 precompile.
|
||||||
|
pub struct Sha256;
|
||||||
|
|
||||||
|
impl Precompile for Sha256 {
|
||||||
|
fn execute(
|
||||||
|
input: &[u8],
|
||||||
|
target_gas: Option<usize>,
|
||||||
|
) -> core::result::Result<(ExitSucceed, Vec<u8>, usize), ExitError> {
|
||||||
|
let cost = ensure_linear_cost(target_gas, input.len(), 60, 12)?;
|
||||||
|
|
||||||
|
let ret = sp_io::hashing::sha2_256(input);
|
||||||
|
Ok((ExitSucceed::Returned, ret.to_vec(), cost))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user