Skip to content

Commit

Permalink
Fix precompile tuple encoding in return position (#2068)
Browse files Browse the repository at this point in the history
* fix returns tuple encoding

* use struct in Referanda precompile to keep same encoding

* fix typos
  • Loading branch information
nanocryk authored Feb 8, 2023
1 parent 19dcb00 commit e0f31c8
Show file tree
Hide file tree
Showing 13 changed files with 435 additions and 133 deletions.
27 changes: 13 additions & 14 deletions precompiles/referenda/Referenda.sol
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,18 @@ Referenda constant REFERENDA_CONTRACT = Referenda(REFERENDA_ADDRESS);
/// @title The interface through which solidity contracts will interact with the Referenda pallet
/// @custom:address 0x0000000000000000000000000000000000000811
interface Referenda {
struct TrackInfo {
string name;
uint256 maxDeciding;
uint256 decisionDeposit;
uint256 preparePeriod;
uint256 decisionPeriod;
uint256 confirmPeriod;
uint256 minEnactmentPeriod;
bytes minApproval;
bytes minSupport;
}

/// Return the total referendum count
/// @custom:selector 3a42ee31
function referendumCount() external view returns (uint256);
Expand All @@ -33,20 +45,7 @@ interface Referenda {
/// Return the governance parameters configured for the input TrackId
/// @param trackId The track identifier
/// @custom:selector 34038146
function trackInfo(uint16 trackId)
external
view
returns (
string memory,
uint256,
uint256,
uint256,
uint256,
uint256,
uint256,
bytes memory,
bytes memory
);
function trackInfo(uint16 trackId) external view returns (TrackInfo memory);

/// @dev Submit a referenda
/// @custom:selector 95f9ed68
Expand Down
123 changes: 97 additions & 26 deletions precompiles/referenda/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,7 @@ use frame_support::traits::{
use pallet_evm::AddressMapping;
use pallet_referenda::{Call as ReferendaCall, DecidingCount, ReferendumCount, TracksInfo};
use parity_scale_codec::Encode;
use precompile_utils::prelude::*;
use precompile_utils::{data::String, prelude::*};
use sp_core::U256;
use sp_std::{boxed::Box, marker::PhantomData, vec::Vec};

Expand All @@ -49,6 +49,90 @@ type BoundedCallOf<Runtime> = Bounded<<Runtime as pallet_referenda::Config>::Run
type OriginOf<Runtime> =
<<Runtime as frame_system::Config>::RuntimeOrigin as OriginTrait>::PalletsOrigin;

pub struct TrackInfo {
name: UnboundedBytes,
max_deciding: U256,
decision_deposit: U256,
prepare_period: U256,
decision_period: U256,
confirm_period: U256,
min_enactment_period: U256,
min_approval: UnboundedBytes,
min_support: UnboundedBytes,
}

impl EvmData for TrackInfo {
fn read(reader: &mut EvmDataReader) -> MayRevert<Self> {
precompile_utils::read_struct!(reader, {
name: UnboundedBytes,
max_deciding: U256,
decision_deposit: U256,
prepare_period: U256,
decision_period: U256,
confirm_period: U256,
min_enactment_period: U256,
min_approval: UnboundedBytes,
min_support: UnboundedBytes
});
Ok(TrackInfo {
name,
max_deciding,
decision_deposit,
prepare_period,
decision_period,
confirm_period,
min_enactment_period,
min_approval,
min_support,
})
}

fn write(writer: &mut EvmDataWriter, value: Self) {
EvmData::write(
writer,
(
value.name,
value.max_deciding,
value.decision_deposit,
value.prepare_period,
value.decision_period,
value.confirm_period,
value.min_enactment_period,
value.min_approval,
value.min_support,
),
);
}

fn has_static_size() -> bool {
<(
UnboundedBytes,
U256,
U256,
U256,
U256,
U256,
U256,
UnboundedBytes,
UnboundedBytes,
)>::has_static_size()
}

fn solidity_type() -> String {
<(
UnboundedBytes,
U256,
U256,
U256,
U256,
U256,
U256,
UnboundedBytes,
UnboundedBytes,
)>::solidity_type()
}
}

/// A precompile to wrap the functionality from pallet-referenda.
pub struct ReferendaPrecompile<Runtime, GovOrigin: TryFrom<u16>>(PhantomData<(Runtime, GovOrigin)>);

Expand Down Expand Up @@ -130,20 +214,7 @@ where

#[precompile::public("trackInfo(uint16)")]
#[precompile::view]
fn track_info(
handle: &mut impl PrecompileHandle,
track_id: u16,
) -> EvmResult<(
UnboundedBytes,
U256,
U256,
U256,
U256,
U256,
U256,
UnboundedBytes,
UnboundedBytes,
)> {
fn track_info(handle: &mut impl PrecompileHandle, track_id: u16) -> EvmResult<TrackInfo> {
// Fetch data from runtime
handle.record_cost(RuntimeHelper::<Runtime>::db_read_gas_cost())?;
let track_id: TrackIdOf<Runtime> = track_id
Expand All @@ -156,17 +227,17 @@ where
.unwrap_or_else(|x| x);
let track_info = &tracks[index].1;

Ok((
track_info.name.as_bytes().into(),
track_info.max_deciding.into(),
track_info.decision_deposit.into(),
track_info.prepare_period.into(),
track_info.decision_period.into(),
track_info.confirm_period.into(),
track_info.min_enactment_period.into(),
track_info.min_approval.encode().into(),
track_info.min_support.encode().into(),
))
Ok(TrackInfo {
name: track_info.name.into(),
max_deciding: track_info.max_deciding.into(),
decision_deposit: track_info.decision_deposit.into(),
prepare_period: track_info.prepare_period.into(),
decision_period: track_info.decision_period.into(),
confirm_period: track_info.confirm_period.into(),
min_enactment_period: track_info.min_enactment_period.into(),
min_approval: track_info.min_approval.encode().into(),
min_support: track_info.min_support.encode().into(),
})
}

/// Propose a referendum on a privileged action.
Expand Down
5 changes: 3 additions & 2 deletions precompiles/utils/macro/src/precompile/expand.rs
Original file line number Diff line number Diff line change
Expand Up @@ -270,8 +270,9 @@ impl Precompile {
.as_ref()
.map(|_| quote!(discriminant,));

let write_output =
quote_spanned!(output_span=> EvmDataWriter::new().write(output?).build());
let write_output = quote_spanned!(output_span=>
::precompile_utils::data::encode_as_function_return_value(output?)
);

quote!(
use ::precompile_utils::EvmDataWriter;
Expand Down
1 change: 1 addition & 0 deletions precompiles/utils/macro/tests/precompile.rs
Original file line number Diff line number Diff line change
Expand Up @@ -23,5 +23,6 @@ fn ui() {

#[test]
fn expand() {
// use `expand` to refresh the output.
macrotest::expand_without_refresh("tests/precompile/expand/**/*.rs");
}
Original file line number Diff line number Diff line change
@@ -1,46 +1,46 @@
error[E0277]: the trait bound `String: EvmData` is not satisfied
--> tests/precompile/compile-fail/evm-data/arg-dont-impl-evmdata.rs:26:43
|
26 | fn foo(test: &mut impl PrecompileHandle, arg: String) -> EvmResult {
| ^^^ the trait `EvmData` is not implemented for `String`
|
= help: the following other types implement trait `EvmData`:
()
(TupleElement0, TupleElement1)
(TupleElement0, TupleElement1, TupleElement2)
(TupleElement0, TupleElement1, TupleElement2, TupleElement3)
(TupleElement0, TupleElement1, TupleElement2, TupleElement3, TupleElement4)
(TupleElement0, TupleElement1, TupleElement2, TupleElement3, TupleElement4, TupleElement5)
(TupleElement0, TupleElement1, TupleElement2, TupleElement3, TupleElement4, TupleElement5, TupleElement6)
(TupleElement0, TupleElement1, TupleElement2, TupleElement3, TupleElement4, TupleElement5, TupleElement6, TupleElement7)
and 27 others
--> tests/precompile/compile-fail/evm-data/arg-dont-impl-evmdata.rs:26:43
|
26 | fn foo(test: &mut impl PrecompileHandle, arg: String) -> EvmResult {
| ^^^ the trait `EvmData` is not implemented for `String`
|
= help: the following other types implement trait `EvmData`:
()
(TupleElement0, TupleElement1)
(TupleElement0, TupleElement1, TupleElement2)
(TupleElement0, TupleElement1, TupleElement2, TupleElement3)
(TupleElement0, TupleElement1, TupleElement2, TupleElement3, TupleElement4)
(TupleElement0, TupleElement1, TupleElement2, TupleElement3, TupleElement4, TupleElement5)
(TupleElement0, TupleElement1, TupleElement2, TupleElement3, TupleElement4, TupleElement5, TupleElement6)
(TupleElement0, TupleElement1, TupleElement2, TupleElement3, TupleElement4, TupleElement5, TupleElement6, TupleElement7)
and $N others
note: required by a bound in `EvmDataReader::<'a>::read`
--> $WORKSPACE/precompiles/utils/src/data/mod.rs
|
| pub fn read<T: EvmData>(&mut self) -> MayRevert<T> {
| ^^^^^^^ required by this bound in `EvmDataReader::<'a>::read`
--> $WORKSPACE/precompiles/utils/src/data/mod.rs
|
| pub fn read<T: EvmData>(&mut self) -> MayRevert<T> {
| ^^^^^^^ required by this bound in `EvmDataReader::<'a>::read`

error[E0277]: the trait bound `String: EvmData` is not satisfied
--> tests/precompile/compile-fail/evm-data/arg-dont-impl-evmdata.rs:26:43
|
26 | fn foo(test: &mut impl PrecompileHandle, arg: String) -> EvmResult {
| ^^^ the trait `EvmData` is not implemented for `String`
|
= help: the following other types implement trait `EvmData`:
()
(TupleElement0, TupleElement1)
(TupleElement0, TupleElement1, TupleElement2)
(TupleElement0, TupleElement1, TupleElement2, TupleElement3)
(TupleElement0, TupleElement1, TupleElement2, TupleElement3, TupleElement4)
(TupleElement0, TupleElement1, TupleElement2, TupleElement3, TupleElement4, TupleElement5)
(TupleElement0, TupleElement1, TupleElement2, TupleElement3, TupleElement4, TupleElement5, TupleElement6)
(TupleElement0, TupleElement1, TupleElement2, TupleElement3, TupleElement4, TupleElement5, TupleElement6, TupleElement7)
and 27 others
--> tests/precompile/compile-fail/evm-data/arg-dont-impl-evmdata.rs:26:43
|
26 | fn foo(test: &mut impl PrecompileHandle, arg: String) -> EvmResult {
| ^^^ the trait `EvmData` is not implemented for `String`
|
= help: the following other types implement trait `EvmData`:
()
(TupleElement0, TupleElement1)
(TupleElement0, TupleElement1, TupleElement2)
(TupleElement0, TupleElement1, TupleElement2, TupleElement3)
(TupleElement0, TupleElement1, TupleElement2, TupleElement3, TupleElement4)
(TupleElement0, TupleElement1, TupleElement2, TupleElement3, TupleElement4, TupleElement5)
(TupleElement0, TupleElement1, TupleElement2, TupleElement3, TupleElement4, TupleElement5, TupleElement6)
(TupleElement0, TupleElement1, TupleElement2, TupleElement3, TupleElement4, TupleElement5, TupleElement6, TupleElement7)
and $N others
note: required by a bound in `EvmDataWriter::write`
--> $WORKSPACE/precompiles/utils/src/data/mod.rs
|
| pub fn write<T: EvmData>(mut self, value: T) -> Self {
| ^^^^^^^ required by this bound in `EvmDataWriter::write`
--> $WORKSPACE/precompiles/utils/src/data/mod.rs
|
| pub fn write<T: EvmData>(mut self, value: T) -> Self {
| ^^^^^^^ required by this bound in `EvmDataWriter::write`

error[E0277]: the trait bound `String: EvmData` is not satisfied
--> tests/precompile/compile-fail/evm-data/arg-dont-impl-evmdata.rs:26:5
Expand All @@ -57,5 +57,5 @@ error[E0277]: the trait bound `String: EvmData` is not satisfied
(TupleElement0, TupleElement1, TupleElement2, TupleElement3, TupleElement4, TupleElement5)
(TupleElement0, TupleElement1, TupleElement2, TupleElement3, TupleElement4, TupleElement5, TupleElement6)
(TupleElement0, TupleElement1, TupleElement2, TupleElement3, TupleElement4, TupleElement5, TupleElement6, TupleElement7)
and 27 others
and $N others
= note: required for `(String,)` to implement `EvmData`
Original file line number Diff line number Diff line change
@@ -1,21 +1,21 @@
error[E0277]: the trait bound `String: EvmData` is not satisfied
--> tests/precompile/compile-fail/evm-data/output-dont-impl-evmdata.rs:26:46
|
26 | fn foo(test: &mut impl PrecompileHandle) -> EvmResult<String> {
| ^^^^^^^^^^^^^^^^^ the trait `EvmData` is not implemented for `String`
|
= help: the following other types implement trait `EvmData`:
()
(TupleElement0, TupleElement1)
(TupleElement0, TupleElement1, TupleElement2)
(TupleElement0, TupleElement1, TupleElement2, TupleElement3)
(TupleElement0, TupleElement1, TupleElement2, TupleElement3, TupleElement4)
(TupleElement0, TupleElement1, TupleElement2, TupleElement3, TupleElement4, TupleElement5)
(TupleElement0, TupleElement1, TupleElement2, TupleElement3, TupleElement4, TupleElement5, TupleElement6)
(TupleElement0, TupleElement1, TupleElement2, TupleElement3, TupleElement4, TupleElement5, TupleElement6, TupleElement7)
and 27 others
note: required by a bound in `EvmDataWriter::write`
--> $WORKSPACE/precompiles/utils/src/data/mod.rs
|
| pub fn write<T: EvmData>(mut self, value: T) -> Self {
| ^^^^^^^ required by this bound in `EvmDataWriter::write`
--> tests/precompile/compile-fail/evm-data/output-dont-impl-evmdata.rs:26:46
|
26 | fn foo(test: &mut impl PrecompileHandle) -> EvmResult<String> {
| ^^^^^^^^^^^^^^^^^ the trait `EvmData` is not implemented for `String`
|
= help: the following other types implement trait `EvmData`:
()
(TupleElement0, TupleElement1)
(TupleElement0, TupleElement1, TupleElement2)
(TupleElement0, TupleElement1, TupleElement2, TupleElement3)
(TupleElement0, TupleElement1, TupleElement2, TupleElement3, TupleElement4)
(TupleElement0, TupleElement1, TupleElement2, TupleElement3, TupleElement4, TupleElement5)
(TupleElement0, TupleElement1, TupleElement2, TupleElement3, TupleElement4, TupleElement5, TupleElement6)
(TupleElement0, TupleElement1, TupleElement2, TupleElement3, TupleElement4, TupleElement5, TupleElement6, TupleElement7)
and $N others
note: required by a bound in `encode_as_function_return_value`
--> $WORKSPACE/precompiles/utils/src/data/mod.rs
|
| pub fn encode_as_function_return_value<T: EvmData>(value: T) -> Vec<u8> {
| ^^^^^^^ required by this bound in `encode_as_function_return_value`
Original file line number Diff line number Diff line change
Expand Up @@ -211,26 +211,26 @@ where
let output = <BatchPrecompile<
Runtime,
>>::batch_all(handle, to, value, call_data, gas_limit);
EvmDataWriter::new().write(output?).build()
::precompile_utils::data::encode_as_function_return_value(output?)
}
Self::batch_some { to, value, call_data, gas_limit } => {
use ::precompile_utils::EvmDataWriter;
let output = <BatchPrecompile<
Runtime,
>>::batch_some(handle, to, value, call_data, gas_limit);
EvmDataWriter::new().write(output?).build()
::precompile_utils::data::encode_as_function_return_value(output?)
}
Self::batch_some_until_failure { to, value, call_data, gas_limit } => {
use ::precompile_utils::EvmDataWriter;
let output = <BatchPrecompile<
Runtime,
>>::batch_some_until_failure(handle, to, value, call_data, gas_limit);
EvmDataWriter::new().write(output?).build()
::precompile_utils::data::encode_as_function_return_value(output?)
}
Self::fallback {} => {
use ::precompile_utils::EvmDataWriter;
let output = <BatchPrecompile<Runtime>>::fallback(handle);
EvmDataWriter::new().write(output?).build()
::precompile_utils::data::encode_as_function_return_value(output?)
}
Self::__phantom(_, _) => {
::core::panicking::panic_fmt(
Expand Down
Loading

0 comments on commit e0f31c8

Please sign in to comment.