Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
10 changes: 10 additions & 0 deletions prdoc/pr_10861.prdoc
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
title: '[pallet-revive] weight charge in `sr25519_verify` and `ecdsa_to_eth_address`
precompiles'
doc:
- audience: Runtime Dev
description: I couldn't see where the weight is charged in those builtin pre-compiles
and a quick test indicated that there's no charges implemented. Assuming those
are compute-heavy functions, the missing weight charges seem like a DoS vector.
crates:
- name: pallet-revive
bump: patch
111 changes: 111 additions & 0 deletions substrate/frame/revive/src/precompiles/builtin/system.rs
Original file line number Diff line number Diff line change
Expand Up @@ -100,6 +100,22 @@ impl<T: Config> BuiltinPrecompile for System<T> {
env.terminate_caller(&h160).map_err(Error::try_to_revert::<T>)?;
Ok(Vec::new())
},
ISystemCalls::sr25519Verify(ISystem::sr25519VerifyCall {
signature,
message,
publicKey,
}) => {
env.frame_meter_mut()
.charge_weight_token(RuntimeCosts::Sr25519Verify(message.len() as _))?;
let ok = env.sr25519_verify(signature, message, publicKey);
Ok(ok.abi_encode())
},
ISystemCalls::ecdsaToEthAddress(ISystem::ecdsaToEthAddressCall { publicKey }) => {
env.frame_meter_mut().charge_weight_token(RuntimeCosts::EcdsaToEthAddress)?;
let address =
env.ecdsa_to_eth_address(publicKey).map_err(Error::try_to_revert::<T>)?;
Ok(address.abi_encode())
},
}
}
}
Expand All @@ -110,14 +126,19 @@ mod tests {
use crate::{
address::AddressMapper,
call_builder::{caller_funding, CallSetup},
metering::Token,
pallet,
precompiles::{
alloy::sol_types::{sol_data::Bytes, SolType},
tests::run_test_vectors,
BuiltinPrecompile,
},
test_utils::ALICE,
tests::{ExtBuilder, Test},
vm::RuntimeCosts,
};

use alloy_core::primitives::FixedBytes;
use codec::Decode;
use frame_support::traits::fungible::Mutate;

Expand Down Expand Up @@ -190,4 +211,94 @@ mod tests {
);
})
}

#[test]
fn sr25519_verify() {
use crate::precompiles::alloy::sol_types::sol_data::Bool;
ExtBuilder::default().build().execute_with(|| {
let _ = <Test as Config>::Currency::set_balance(&ALICE, 100_000_000_000);

let mut call_setup = CallSetup::<Test>::default();
let (mut ext, _) = call_setup.ext();

let mut call_with = |message: &[u8; 11]| {
// Alice's signature for "hello world"
#[rustfmt::skip]
let signature: [u8; 64] = [
184, 49, 74, 238, 78, 165, 102, 252, 22, 92, 156, 176, 124, 118, 168, 116, 247,
99, 0, 94, 2, 45, 9, 170, 73, 222, 182, 74, 60, 32, 75, 64, 98, 174, 69, 55, 83,
85, 180, 98, 208, 75, 231, 57, 205, 62, 4, 105, 26, 136, 172, 17, 123, 99, 90, 255,
228, 54, 115, 63, 30, 207, 205, 131,
];

// Alice's public key
#[rustfmt::skip]
let public_key: [u8; 32] = [
212, 53, 147, 199, 21, 253, 211, 28, 97, 20, 26, 189, 4, 169, 159, 214, 130, 44,
133, 88, 133, 76, 205, 227, 154, 86, 132, 231, 165, 109, 162, 125,
];

let weight_before = ext.frame_meter().weight_consumed();

let input = ISystem::ISystemCalls::sr25519Verify(ISystem::sr25519VerifyCall {
signature,
message: (*message).into(),
publicKey: public_key.into(),
});
let result =
<System<Test>>::call(&<System<Test>>::MATCHER.base_address(), &input, &mut ext)
.unwrap();

let weight_used = ext.frame_meter().weight_consumed() - weight_before;
assert!(weight_used.ref_time() > 0, "sr25519_verify should charge weight");
assert_eq!(
weight_used,
Token::<Test>::weight(&RuntimeCosts::Sr25519Verify(message.len() as u32)),
"sr25519_verify should charge the expected weight"
);
result
};
let result = Bool::abi_decode(&call_with(&b"hello world")).expect("decoding failed");
assert!(result);
let result = Bool::abi_decode(&call_with(&b"hello worlD")).expect("decoding failed");
assert!(!result);
});
}

#[test]
fn ecdsa_to_eth_address() {
ExtBuilder::default().build().execute_with(|| {
let _ = <Test as Config>::Currency::set_balance(&ALICE, 100_000_000_000);

let mut call_setup = CallSetup::<Test>::default();
let (mut ext, _) = call_setup.ext();

let pubkey_compressed = array_bytes::hex2array_unchecked(
"028db55b05db86c0b1786ca49f095d76344c9e6056b2f02701a7e7f3c20aabfd91",
);

let weight_before = ext.frame_meter().weight_consumed();

let input = ISystem::ISystemCalls::ecdsaToEthAddress(ISystem::ecdsaToEthAddressCall {
publicKey: pubkey_compressed,
});
let result =
<System<Test>>::call(&<System<Test>>::MATCHER.base_address(), &input, &mut ext)
.unwrap();

let expected: FixedBytes<20> = array_bytes::hex2array_unchecked::<_, 20>(
"09231da7b19A016f9e576d23B16277062F4d46A8",
)
.into();
assert_eq!(result, expected.abi_encode());

let weight_used = ext.frame_meter().weight_consumed() - weight_before;
assert!(weight_used.ref_time() > 0, "ecdsa_to_eth_address should charge weight");
assert_eq!(
weight_used,
Token::<Test>::weight(&RuntimeCosts::EcdsaToEthAddress),
"ecdsa_to_eth_address should charge the expected weight"
);
});
}
}
Loading