Skip to content

Commit

Permalink
merge daan/api
Browse files Browse the repository at this point in the history
  • Loading branch information
Daanvdplas committed Sep 13, 2024
2 parents 497b2f7 + 4b9da05 commit 4e7fbaa
Show file tree
Hide file tree
Showing 25 changed files with 1,041 additions and 818 deletions.
21 changes: 21 additions & 0 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

11 changes: 7 additions & 4 deletions extension/src/functions.rs
Original file line number Diff line number Diff line change
Expand Up @@ -149,7 +149,7 @@ pub trait Readable {
/// Trait for fallible conversion of a value based on additional information available from the
/// environment.
pub trait Converter {
/// The type returned in the event of a conversion error.
/// The error type returned when conversion fails.
type Error;
/// The type of value to be converted.
type Source;
Expand All @@ -173,7 +173,7 @@ pub trait Converter {
/// A default converter, for converting (encoding) from some type into a byte array.
pub struct DefaultConverter<T>(PhantomData<T>);
impl<T: Into<Vec<u8>>> Converter for DefaultConverter<T> {
/// The type returned in the event of a conversion error.
/// The error type returned when conversion fails.
type Error = DispatchError;
/// The type of value to be converted.
type Source = T;
Expand Down Expand Up @@ -476,7 +476,7 @@ mod tests {
Ok(Converging(0))
));
// Check if the contract environment buffer is written correctly.
assert_eq!(env.buffer, UppercaseConverter::try_convert(expected, &env).unwrap());
assert_eq!(Ok(&env.buffer), UppercaseConverter::try_convert(expected, &env).as_ref());
}

#[test]
Expand Down Expand Up @@ -552,6 +552,9 @@ mod tests {
fn default_conversion_works() {
let env = MockEnvironment::default();
let source = "pop".to_string();
assert_eq!(DefaultConverter::try_convert(source.clone(), &env).unwrap(), source.as_bytes());
assert_eq!(
DefaultConverter::try_convert(source.clone(), &env),
Ok(source.as_bytes().into())
);
}
}
107 changes: 65 additions & 42 deletions pallets/api/src/extension.rs
Original file line number Diff line number Diff line change
Expand Up @@ -112,7 +112,7 @@ impl<Source: Debug, Target: TryFrom<(Source, u8), Error = DispatchError> + Debug
/// - `value` - The value to be converted.
/// - `env` - The current execution environment.
fn try_convert(value: Self::Source, env: &impl Environment) -> Result<Self::Target> {
// Defer to supplied versioned result conversion type
// Defer to supplied versioned result conversion type.
let version = version(env);
log::debug!(target: Self::LOG_TARGET, "versioned result converter: result={value:?}, version={version}");
let converted: Target = (value, version).try_into()?;
Expand Down Expand Up @@ -163,12 +163,16 @@ mod tests {

#[test]
fn prepender_works() {
let func = 0;
let version = 1;
let module = 2;
let index = 3;
let env = MockEnvironment {
func_id: u16::from_le_bytes([1, 2]),
ext_id: u16::from_le_bytes([3, 4]),
func_id: u16::from_le_bytes([func, version]),
ext_id: u16::from_le_bytes([module, index]),
};
assert_eq!(Prepender::process(vec![0u8], &env), vec![2, 3, 4, 0]);
assert_eq!(Prepender::process(vec![0u8, 5, 10], &env), vec![2, 3, 4, 0, 5, 10]);
let data = 42;
assert_eq!(Prepender::process(vec![data], &env), vec![version, module, index, data]);
}

#[test]
Expand Down Expand Up @@ -199,9 +203,8 @@ mod tests {
));
}

#[test]
fn versioned_error_converter_works() {
use super::RetVal::Converging;
mod versioned_error {
use super::{RetVal::Converging, *};

// Mock versioned error.
#[derive(Debug)]
Expand Down Expand Up @@ -239,36 +242,41 @@ mod tests {
}
}

// Because `Retval` does not implement the `Debug` trait the success and error test cases
// are separated.
for (version, error, expected_result) in vec![
(0, BadOrigin, 1),
(0, CannotLookup, 100),
(1, BadOrigin, 2),
(1, CannotLookup, 200),
] {
let env = MockEnvironment { func_id: u16::from_le_bytes([0, version]), ext_id: 0u16 };
// Again, due to missing `Debug` trait the result has to be unwrapped.
let Ok(Converging(result)) =
VersionedErrorConverter::<VersionedError>::convert(error, &env)
else {
panic!("should not happen")
};
assert_eq!(result, expected_result);
#[test]
fn versioned_error_converter_works() {
for (version, error, expected_result) in vec![
(0, BadOrigin, 1),
(0, Other("test"), 100),
(1, BadOrigin, 2),
(1, Other("test"), 200),
] {
let env =
MockEnvironment { func_id: u16::from_le_bytes([0, version]), ext_id: 0u16 };
// Because `Retval` does not implement the `Debug` trait the result has to be
// unwrapped.
let Ok(Converging(result)) =
VersionedErrorConverter::<VersionedError>::convert(error, &env)
else {
panic!("should not happen")
};
assert_eq!(result, expected_result);
}
}

// Error case.
let env = MockEnvironment { func_id: u16::from_le_bytes([0, 2]), ext_id: 0u16 };
let result = VersionedErrorConverter::<VersionedError>::convert(BadOrigin, &env)
.err()
.unwrap(); // Again, can't use `unwrap_err()` due to missing `Debug` trait.
assert_eq!(result, Other("DecodingFailed"));
#[test]
fn versioned_error_converter_fails_when_invalid_version() {
let version = 2;
let env = MockEnvironment { func_id: u16::from_le_bytes([0, version]), ext_id: 0u16 };
let result = VersionedErrorConverter::<VersionedError>::convert(BadOrigin, &env).err();
assert_eq!(result, Some(Other("DecodingFailed")));
}
}

#[test]
fn versioned_result_converter_works() {
mod versioned_result {
use VersionedRuntimeResult::{V0, V1};

use super::*;

// Mock versioned runtime result.
#[derive(Debug, PartialEq)]
pub enum VersionedRuntimeResult {
Expand All @@ -282,6 +290,7 @@ mod tests {
// Mock conversion based on result and version.
fn try_from(value: (u8, u8)) -> Result<Self> {
let (result, version) = value;
// Per version there is a specific upper bound allowed.
match version {
0 if result <= 50 => Ok(V0(result)),
0 if result > 50 => Ok(V0(50)),
Expand All @@ -292,17 +301,31 @@ mod tests {
}
}

for (version, value, expected_result) in vec![
(0, 10, Ok(V0(10))),
(0, 100, Ok(V0(50))),
(1, 10, Ok(V1(10))),
(1, 100, Ok(V1(100))),
(2, 10, Err(Other("DecodingFailed"))),
] {
let env = MockEnvironment { func_id: u16::from_le_bytes([0, version]), ext_id: 0u16 };
#[test]
fn versioned_result_converter_works() {
for (version, value, expected_result) in vec![
(0, 10, Ok(V0(10))),
// `V0` has 50 as upper bound and therefore caps the value.
(0, 100, Ok(V0(50))),
(1, 10, Ok(V1(10))),
// Different upper bound for `V1`.
(1, 100, Ok(V1(100))),
] {
let env =
MockEnvironment { func_id: u16::from_le_bytes([0, version]), ext_id: 0u16 };
let result = VersionedResultConverter::<u8, VersionedRuntimeResult>::try_convert(
value, &env,
);
assert_eq!(result, expected_result);
}
}

#[test]
fn versioned_result_converter_fails_when_invalid_version() {
let env = MockEnvironment { func_id: u16::from_le_bytes([0, 2]), ext_id: 0u16 };
let result =
VersionedResultConverter::<u8, VersionedRuntimeResult>::try_convert(value, &env);
assert_eq!(result, expected_result);
VersionedResultConverter::<u8, VersionedRuntimeResult>::try_convert(10, &env).err();
assert_eq!(result, Some(Other("DecodingFailed")));
}
}

Expand Down
73 changes: 72 additions & 1 deletion pallets/api/src/fungibles/benchmarking.rs
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,10 @@ use frame_support::{
use frame_system::RawOrigin;
use sp_runtime::traits::Zero;

use super::{AccountIdOf, AssetsInstanceOf, AssetsOf, BalanceOf, Call, Config, Pallet, TokenIdOf};
use super::{
AccountIdOf, AssetsInstanceOf, AssetsOf, BalanceOf, Call, Config, Pallet, Read, TokenIdOf,
};
use crate::Read as _;

const SEED: u32 = 1;

Expand Down Expand Up @@ -103,5 +106,73 @@ mod benchmarks {
Ok(())
}

#[benchmark]
// Storage: `Assets`
fn total_supply() {
#[block]
{
Pallet::<T>::read(Read::TotalSupply(TokenIdOf::<T>::zero()));
}
}
#[benchmark]
// Storage: `AssetAccount`
fn balance_of() {
#[block]
{
Pallet::<T>::read(Read::BalanceOf {
token: TokenIdOf::<T>::zero(),
owner: account("Alice", 0, SEED),
});
}
}
#[benchmark]
// Storage: `Approval`
fn allowance() {
#[block]
{
Pallet::<T>::read(Read::Allowance {
token: TokenIdOf::<T>::zero(),
owner: account("Alice", 0, SEED),
spender: account("Bob", 0, SEED),
});
}
}

#[benchmark]
// Storage: `AssetMetadata`
fn token_name() {
#[block]
{
Pallet::<T>::read(Read::TokenName(TokenIdOf::<T>::zero()));
}
}

#[benchmark]
// Storage: `AssetMetadata`
fn token_symbol() {
#[block]
{
Pallet::<T>::read(Read::TokenSymbol(TokenIdOf::<T>::zero()));
}
}

#[benchmark]
// Storage: `AssetMetadata`
fn token_decimals() {
#[block]
{
Pallet::<T>::read(Read::TokenDecimals(TokenIdOf::<T>::zero()));
}
}

#[benchmark]
// Storage: `Assets`
fn token_exists() {
#[block]
{
Pallet::<T>::read(Read::TokenExists(TokenIdOf::<T>::zero()));
}
}

impl_benchmark_test_suite!(Pallet, crate::mock::new_test_ext(), crate::mock::Test);
}
20 changes: 15 additions & 5 deletions pallets/api/src/fungibles/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -41,7 +41,8 @@ pub mod pallet {
use super::*;

/// State reads for the fungibles API with required input.
#[derive(Encode, Decode, Debug, MaxEncodedLen, PartialEq, Clone)]
#[derive(Encode, Decode, Debug, MaxEncodedLen)]
#[cfg_attr(feature = "std", derive(PartialEq, Clone))]
#[repr(u8)]
#[allow(clippy::unnecessary_cast)]
pub enum Read<T: Config> {
Expand Down Expand Up @@ -81,7 +82,8 @@ pub mod pallet {
}

/// Results of state reads for the fungibles API.
#[derive(Debug, PartialEq, Clone)]
#[derive(Debug)]
#[cfg_attr(feature = "std", derive(PartialEq, Clone))]
pub enum ReadResult<T: Config> {
/// Total token supply for a specified token.
TotalSupply(BalanceOf<T>),
Expand Down Expand Up @@ -485,9 +487,17 @@ pub mod pallet {
///
/// # Parameters
/// - `request` - The read request.
fn weight(_request: &Self::Read) -> Weight {
// TODO: match on request and return benchmarked weight
T::DbWeight::get().reads(1_u64)
fn weight(request: &Self::Read) -> Weight {
use Read::*;
match request {
TotalSupply(_) => <T as Config>::WeightInfo::total_supply(),
BalanceOf { .. } => <T as Config>::WeightInfo::balance_of(),
Allowance { .. } => <T as Config>::WeightInfo::allowance(),
TokenName(_) => <T as Config>::WeightInfo::token_name(),
TokenSymbol(_) => <T as Config>::WeightInfo::token_symbol(),
TokenDecimals(_) => <T as Config>::WeightInfo::token_decimals(),
TokenExists(_) => <T as Config>::WeightInfo::token_exists(),
}
}

/// Performs the requested read and returns the result.
Expand Down
Loading

0 comments on commit 4e7fbaa

Please sign in to comment.