Skip to content

Commit

Permalink
Add OpenGov precompile logs (moonbeam-foundation#2071)
Browse files Browse the repository at this point in the history
* Add vote_yes/no logs

* Comment

* Wip more conviction voting logs

* wip convition voting

* wip preimage

* conviction voting record costs

* Add tests preimage

* cleanup

* Use Hashing assoc type instead Blake explicitly

* Add referenda logs

* Wip referenda log tests

* referenda log tests

* past tense convention for naming events

* updated test

* record log costs first

* fmt

* Merge branch 'master' into tgm-opengov-precompile-logs

# Conflicts:
#	precompiles/preimage/src/lib.rs
#	precompiles/preimage/src/mock.rs
#	precompiles/preimage/src/tests.rs

* Fix version

* Cleanup after rebase
  • Loading branch information
tgmichel authored and imstar15 committed May 16, 2023
1 parent b7036fd commit a2c2a46
Show file tree
Hide file tree
Showing 12 changed files with 925 additions and 29 deletions.
70 changes: 70 additions & 0 deletions precompiles/conviction-voting/ConvictionVoting.sol
Original file line number Diff line number Diff line change
Expand Up @@ -94,4 +94,74 @@ interface ConvictionVoting {
/// @param trackId The trackId
/// @param target The target address
function unlock(uint16 trackId, address target) external;

/// @dev An account made a vote in a poll.
/// @custom:selector 3839f7832b2a6263aa1fd5040f37d10fd4f9e9c4a9ef07ec384cb1cef9fb4c0e
/// @param pollIndex uint32 Index of the poll.
/// @param voter address Address of the voter.
/// @param aye bool Is it a vote for or against the poll.
/// @param voteAmount uint256 Amount used to vote.
/// @param conviction uint8 Conviction of the vote.
event Voted(
uint32 indexed pollIndex,
address voter,
bool aye,
uint256 voteAmount,
uint8 conviction
);

/// @dev An account removed its vote from an ongoing poll.
/// @custom:selector 49fc1dd929f126e1d88cbb9c135625e30c2deba291adeea4740e446098b9957b
/// @param pollIndex uint32 Index of the poll.
/// @param voter address Address of the voter.
event VoteRemoved(
uint32 indexed pollIndex,
address voter
);

/// @dev An account removed a vote from a poll.
/// @custom:selector c1d068675720ab00d0c8792a0cbc7e198c0d2202111f0280f039f2c09c50491b
/// @param pollIndex uint32 Index of the poll.
/// @param caller address Address of the origin caller.
/// @param target address Address of the address which's vote is being removed.
/// @param trackId uint16 The trackId.
event VoteRemovedOther(
uint32 indexed pollIndex,
address caller,
address target,
uint16 trackId
);

/// @dev An account delegated for the given trackId.
/// @custom:selector 6cc151d547592e227b1e85a264ac3699c6f1014112b08bb3832de1f23b9c66db
/// @param trackId uint16 The trackId.
/// @param from address Address of the caller.
/// @param to address Address of the representative.
/// @param delegatedAmount uint256 Amount being delegated.
/// @param conviction uint8 Conviction being delegated.
event Delegated(
uint16 indexed trackId,
address from,
address to,
uint256 delegatedAmount,
uint8 conviction
);

/// @dev An account undelegated for the given trackId.
/// @custom:selector 1053303328f6db14014ccced6297bcad2b3897157ce46070711ab995a05dfa14
/// @param trackId uint16 The trackId.
/// @param caller address Address of the caller.
event Undelegated(
uint16 indexed trackId,
address caller
);

/// @dev An account called to unlock tokens for the given trackId.
/// @custom:selector dcf72fa65ca7fb720b9ccc8ee28e0188edc3d943115124cdd4086c49f836a128
/// @param trackId uint16 The trackId.
/// @param caller address Address of the caller.
event Unlocked(
uint16 indexed trackId,
address caller
);
}
129 changes: 118 additions & 11 deletions precompiles/conviction-voting/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,7 @@ use pallet_conviction_voting::Call as ConvictionVotingCall;
use pallet_conviction_voting::{AccountVote, Conviction, Tally, Vote};
use pallet_evm::AddressMapping;
use precompile_utils::prelude::*;
use sp_core::{H160, U256};
use sp_core::{H160, H256, U256};
use sp_runtime::traits::StaticLookup;
use sp_std::marker::PhantomData;

Expand Down Expand Up @@ -53,8 +53,29 @@ type ClassOf<Runtime> = <<Runtime as pallet_conviction_voting::Config>::Polls as
>,
>>::Class;

/// Solidity selector of the Vote log, which is the Keccak of the Log signature.
pub(crate) const SELECTOR_LOG_VOTED: [u8; 32] =
keccak256!("Voted(uint32,address,bool,uint256,uint8)");

/// Solidity selector of the VoteRemove log, which is the Keccak of the Log signature.
pub(crate) const SELECTOR_LOG_VOTE_REMOVED: [u8; 32] = keccak256!("VoteRemoved(uint32,address)");

/// Solidity selector of the VoteRemoveOther log, which is the Keccak of the Log signature.
pub(crate) const SELECTOR_LOG_VOTE_REMOVED_OTHER: [u8; 32] =
keccak256!("VoteRemovedOther(uint32,address,address,uint16)");

/// Solidity selector of the Delegate log, which is the Keccak of the Log signature.
pub(crate) const SELECTOR_LOG_DELEGATED: [u8; 32] =
keccak256!("Delegated(uint16,address,address,uint256,uint8)");

/// Solidity selector of the Undelegate log, which is the Keccak of the Log signature.
pub(crate) const SELECTOR_LOG_UNDELEGATED: [u8; 32] = keccak256!("Undelegated(uint16,address)");

/// Solidity selector of the Unlock log, which is the Keccak of the Log signature.
pub(crate) const SELECTOR_LOG_UNLOCKED: [u8; 32] = keccak256!("Unlocked(uint16,address)");

/// Direction of vote
enum VoteDirection {
pub(crate) enum VoteDirection {
Yes,
No,
#[allow(unused)]
Expand Down Expand Up @@ -85,15 +106,28 @@ where
vote_amount: U256,
conviction: u8,
) -> EvmResult {
let poll_index = Self::u32_to_index(poll_index).in_field("pollIndex")?;
let vote_amount = Self::u256_to_amount(vote_amount).in_field("voteAmount")?;
let conviction = Self::u8_to_conviction(conviction).in_field("conviction")?;

let caller = handle.context().caller;
let aye = match vote {
VoteDirection::Yes => true,
VoteDirection::No => false,
_ => return Err(RevertReason::custom("Abstain not supported").into()),
};
let event = log2(
handle.context().address,
SELECTOR_LOG_VOTED,
H256::from_low_u64_be(poll_index as u64), // poll index,
EvmDataWriter::new()
.write::<Address>(Address(caller))
.write::<bool>(aye)
.write::<U256>(vote_amount)
.write::<u8>(conviction)
.build(),
);
handle.record_log_costs(&[&event])?;

let poll_index = Self::u32_to_index(poll_index).in_field("pollIndex")?;
let vote_amount = Self::u256_to_amount(vote_amount).in_field("voteAmount")?;
let conviction = Self::u8_to_conviction(conviction).in_field("conviction")?;

let vote = AccountVote::Standard {
vote: Vote { aye, conviction },
Expand All @@ -105,11 +139,13 @@ where
aye, poll_index, conviction
);

let origin = Runtime::AddressMapping::into_account_id(handle.context().caller);
let origin = Runtime::AddressMapping::into_account_id(caller);
let call = ConvictionVotingCall::<Runtime>::vote { poll_index, vote }.into();

<RuntimeHelper<Runtime>>::try_dispatch(handle, Some(origin).into(), call)?;

event.record(handle)?;

Ok(())
}

Expand Down Expand Up @@ -159,6 +195,17 @@ where

#[precompile::public("removeVote(uint32)")]
fn remove_vote(handle: &mut impl PrecompileHandle, poll_index: u32) -> EvmResult {
let caller = handle.context().caller;
let event = log2(
handle.context().address,
SELECTOR_LOG_VOTE_REMOVED,
H256::from_low_u64_be(poll_index as u64), // poll index,
EvmDataWriter::new()
.write::<Address>(Address(caller))
.build(),
);
handle.record_log_costs(&[&event])?;

let index = Self::u32_to_index(poll_index).in_field("pollIndex")?;

log::trace!(
Expand All @@ -167,11 +214,13 @@ where
index
);

let origin = Runtime::AddressMapping::into_account_id(handle.context().caller);
let origin = Runtime::AddressMapping::into_account_id(caller);
let call = ConvictionVotingCall::<Runtime>::remove_vote { class: None, index };

RuntimeHelper::<Runtime>::try_dispatch(handle, Some(origin).into(), call)?;

event.record(handle)?;

Ok(())
}

Expand All @@ -182,6 +231,20 @@ where
track_id: u16,
poll_index: u32,
) -> EvmResult {
let caller = handle.context().caller;

let event = log2(
handle.context().address,
SELECTOR_LOG_VOTE_REMOVED_OTHER,
H256::from_low_u64_be(poll_index as u64), // poll index,
EvmDataWriter::new()
.write::<Address>(Address(caller))
.write::<Address>(target)
.write::<u16>(track_id)
.build(),
);
handle.record_log_costs(&[&event])?;

let class = Self::u16_to_track_id(track_id).in_field("trackId")?;
let index = Self::u32_to_index(poll_index).in_field("pollIndex")?;

Expand All @@ -195,7 +258,7 @@ where
index
);

let origin = Runtime::AddressMapping::into_account_id(handle.context().caller);
let origin = Runtime::AddressMapping::into_account_id(caller);
let call = ConvictionVotingCall::<Runtime>::remove_other_vote {
target,
class,
Expand All @@ -204,6 +267,8 @@ where

RuntimeHelper::<Runtime>::try_dispatch(handle, Some(origin).into(), call)?;

event.record(handle)?;

Ok(())
}

Expand All @@ -215,6 +280,21 @@ where
conviction: u8,
amount: U256,
) -> EvmResult {
let caller = handle.context().caller;

let event = log2(
handle.context().address,
SELECTOR_LOG_DELEGATED,
H256::from_low_u64_be(track_id as u64), // track id,
EvmDataWriter::new()
.write::<Address>(Address(caller))
.write::<Address>(representative)
.write::<U256>(amount)
.write::<u8>(conviction)
.build(),
);
handle.record_log_costs(&[&event])?;

let class = Self::u16_to_track_id(track_id).in_field("trackId")?;
let amount = Self::u256_to_amount(amount).in_field("amount")?;
let conviction = Self::u8_to_conviction(conviction).in_field("conviction")?;
Expand All @@ -227,7 +307,7 @@ where
let representative = Runtime::AddressMapping::into_account_id(representative.into());
let to: <Runtime::Lookup as StaticLookup>::Source =
Runtime::Lookup::unlookup(representative.clone());
let origin = Runtime::AddressMapping::into_account_id(handle.context().caller);
let origin = Runtime::AddressMapping::into_account_id(caller);
let call = ConvictionVotingCall::<Runtime>::delegate {
class,
to,
Expand All @@ -237,21 +317,46 @@ where

RuntimeHelper::<Runtime>::try_dispatch(handle, Some(origin).into(), call)?;

event.record(handle)?;

Ok(())
}
#[precompile::public("undelegate(uint16)")]
fn undelegate(handle: &mut impl PrecompileHandle, track_id: u16) -> EvmResult {
let caller = handle.context().caller;

let event = log2(
handle.context().address,
SELECTOR_LOG_UNDELEGATED,
H256::from_low_u64_be(track_id as u64), // track id,
EvmDataWriter::new()
.write::<Address>(Address(caller))
.build(),
);
handle.record_log_costs(&[&event])?;

let class = Self::u16_to_track_id(track_id).in_field("trackId")?;
let origin = Runtime::AddressMapping::into_account_id(handle.context().caller);
let origin = Runtime::AddressMapping::into_account_id(caller);
let call = ConvictionVotingCall::<Runtime>::undelegate { class };

RuntimeHelper::<Runtime>::try_dispatch(handle, Some(origin).into(), call)?;

event.record(handle)?;

Ok(())
}
#[precompile::public("unlock(uint16,address)")]
fn unlock(handle: &mut impl PrecompileHandle, track_id: u16, target: Address) -> EvmResult {
let class = Self::u16_to_track_id(track_id).in_field("trackId")?;

let event = log2(
handle.context().address,
SELECTOR_LOG_UNLOCKED,
H256::from_low_u64_be(track_id as u64), // track id,
EvmDataWriter::new().write::<Address>(target).build(),
);
handle.record_log_costs(&[&event])?;

let target: H160 = target.into();
let target = Runtime::AddressMapping::into_account_id(target);
let target: <Runtime::Lookup as StaticLookup>::Source =
Expand All @@ -267,6 +372,8 @@ where

RuntimeHelper::<Runtime>::try_dispatch(handle, Some(origin).into(), call)?;

event.record(handle)?;

Ok(())
}
fn u8_to_conviction(conviction: u8) -> MayRevert<Conviction> {
Expand Down
45 changes: 44 additions & 1 deletion precompiles/conviction-voting/src/mock.rs
Original file line number Diff line number Diff line change
Expand Up @@ -246,4 +246,47 @@ impl pallet_conviction_voting::Config for Runtime {
type Polls = TestPolls;
}

// genesis builder TODO
pub(crate) struct ExtBuilder {
/// Endowed accounts with balances
balances: Vec<(AccountId, Balance)>,
}

impl Default for ExtBuilder {
fn default() -> ExtBuilder {
ExtBuilder { balances: vec![] }
}
}

impl ExtBuilder {
/// Fund some accounts before starting the test
pub(crate) fn with_balances(mut self, balances: Vec<(AccountId, Balance)>) -> Self {
self.balances = balances;
self
}

/// Build the test externalities for use in tests
pub(crate) fn build(self) -> sp_io::TestExternalities {
let mut t = frame_system::GenesisConfig::default()
.build_storage::<Runtime>()
.expect("Frame system builds valid default genesis config");

pallet_balances::GenesisConfig::<Runtime> {
balances: self.balances.clone(),
}
.assimilate_storage(&mut t)
.expect("Pallet balances storage can be assimilated");

let mut ext = sp_io::TestExternalities::new(t);
ext.execute_with(|| {
System::set_block_number(1);
});
ext
}
}

pub(crate) fn events() -> Vec<RuntimeEvent> {
System::events()
.into_iter()
.map(|r| r.event)
.collect::<Vec<_>>()
}
Loading

0 comments on commit a2c2a46

Please sign in to comment.