10000 feat(gov): Add VoteWeighted transaction, unit and integration tests. (backport #2922) by mergify[bot] · Pull Request #2940 · evmos/evmos · GitHub
[go: up one dir, main page]
More Web Proxy on the site http://driver.im/
Skip to content

feat(gov): Add VoteWeighted transaction, unit and integration tests. (backport #2922) #2940

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 4 commits into from
Oct 14, 2024
Merged
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
6 changes: 6 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -37,8 +37,14 @@ Ref: https://keepachangelog.com/en/1.0.0/

## Unreleased

### State Machine Breaking

- (upgrade) [#2933](https://github.com/evmos/evmos/pull/2933) Update upgrade handler logic for `v20` release.

### Improvements

- (precompiles) [#2922](https://github.com/evmos/evmos/pull/2922) Add 'VoteWeighted' transaction to gov precompile.

## [v20.0.0-rc3](https://github.com/evmos/evmos/releases/tag/v20.0.0-rc3) - 2024-10-08

### State Machine Breaking
Expand Down
19 changes: 19 additions & 0 deletions precompiles/gov/IGov.sol
Original file line number Diff line number Diff line change
Expand Up @@ -48,6 +48,12 @@ interface IGov {
/// @param option the option for voter
event Vote(address indexed voter, uint64 proposalId, uint8 option);

/// @dev VoteWeighted defines an Event emitted when a proposal voted.
/// @param voter the address of the voter
/// @param proposalId the proposal of id
/// @param options the options for voter
event VoteWeighted(address indexed voter, uint64 proposalId, WeightedVoteOption[] options);

/// TRANSACTIONS

/// @dev vote defines a method to add a vote on a specific proposal.
Expand All @@ -63,6 +69,19 @@ interface IGov {
string memory metadata
) external returns (bool success);

/// @dev voteWeighted defines a method to add a vote on a specific proposal.
/// @param voter The address of the voter
/// @param proposalId The proposal id
/// @param options The options for voter
/// @param metadata The metadata for voter send
/// @return success Whether the transaction was successful or not
function voteWeighted(
address voter,
uint64 proposalId,
WeightedVoteOption[] calldata options,
string memory metadata
) external returns (bool success);

/// QUERIES

/// @dev getVote returns the vote of a single voter for a
Expand Down
83 changes: 83 additions & 0 deletions precompiles/gov/abi.json
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,43 @@
"name": "Vote",
"type": "event"
},
{
"anonymous": false,
"inputs": [
{
"indexed": true,
"internalType": "address",
"name": "voter",
"type": "address"
},
{
"indexed": false,
"internalType": "uint64",
"name": "proposalId",
"type": "uint64"
},
{
"components": [
{
"internalType": "enum VoteOption",
"name": "option",
"type": "uint8"
},
{
"internalType": "string",
"name": "weight",
"type": "string"
}
],
"indexed": false,
"internalType": "struct WeightedVoteOption[]",
"name": "options",
"type": "tuple[]"
}
],
"name": "VoteWeighted",
"type": "event"
},
{
"inputs": [
{
Expand Down Expand Up @@ -221,6 +258,52 @@
],
"stateMutability": "nonpayable",
"type": "function"
},
{
"inputs": [
{
"internalType": "address",
"name": "voter",
"type": "address"
},
{
"internalType": "uint64",
"name": "proposalId",
"type": "uint64"
},
{
"components": [
{
"internalType": "enum VoteOption",
"name": "option",
"type": "uint8"
},
{
"internalType": "string",
"name": "weight",
"type": "string"
}
],
"internalType": "struct WeightedVoteOption[]",
"name": "options",
"type": "tuple[]"
},
{
"internalType": "string",
"name": "metadata",
"type": "string"
}
],
"name": "voteWeighted",
"outputs": [
{
"internalType": "bool",
"name": "success",
"type": "bool"
}
],
"stateMutability": "nonpayable",
"type": "function"
}
],
"bytecode": "0x",
Expand Down
8 changes: 8 additions & 0 deletions precompiles/gov/errors.go
Original file line number Diff line number Diff line change
Expand Up @@ -15,4 +15,12 @@ const (
ErrInvalidOption = "invalid option %s "
// ErrInvalidMetadata invalid metadata.
ErrInvalidMetadata = "invalid metadata %s "
// ErrInvalidWeightedVoteOptions invalid weighted vote options.
ErrInvalidWeightedVoteOptions = "invalid weighted vote options %s "
// ErrInvalidWeightedVoteOption invalid weighted vote option.
ErrInvalidWeightedVoteOption = "invalid weighted vote option %s "
// ErrInvalidWeightedVoteOptionType invalid weighted vote option type.
ErrInvalidWeightedVoteOptionType = "invalid weighted vote option type %s "
// ErrInvalidWeightedVoteOptionWeight invalid weighted vote option weight.
ErrInvalidWeightedVoteOptionWeight = "invalid weighted vote option weight %s "
)
35 changes: 34 additions & 1 deletion precompiles/gov/events.go
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,6 @@ package gov

import (
sdk "github.com/cosmos/cosmos-sdk/types"

"github.com/ethereum/go-ethereum/accounts/abi"
"github.com/ethereum/go-ethereum/common"
ethtypes "github.com/ethereum/go-ethereum/core/types"
Expand All @@ -17,6 +16,8 @@ import (
const (
// EventTypeVote defines the event type for the gov VoteMethod transaction.
EventTypeVote = "Vote"
// EventTypeVoteWeighted defines the event type for the gov VoteWeightedMethod transaction.
EventTypeVoteWeighted = "VoteWeighted"
)

// EmitVoteEvent creates a new event emitted on a Vote transaction.
Expand Down Expand Up @@ -50,3 +51,35 @@ func (p Precompile) EmitVoteEvent(ctx sdk.Context, stateDB vm.StateDB, voterAddr

return nil
}

// EmitVoteWeightedEvent creates a new event emitted on a VoteWeighted transaction.
func (p Precompile) EmitVoteWeightedEvent(ctx sdk.Context, stateDB vm.StateDB, voterAddress common.Address, proposalID uint64, options WeightedVoteOptions) error {
// Prepare the event topics
event := p.ABI.Events[EventTypeVoteWeighted]
topics := make([]common.Hash, 2)

// The first topic is always the signature of the event.
topics[0] = event.ID

var err error
topics[1], err = cmn.MakeTopic(voterAddress)
if err != nil {
return err
}

// Prepare the event data
arguments := abi.Arguments{event.Inputs[1], event.Inputs[2]}
packed, err := arguments.Pack(proposalID, options)
if err != nil {
return err
}

stateDB.AddLog(&ethtypes.Log{
Address: p.Address(),
Topics: topics,
Data: packed,
BlockNumber: uint64(ctx.BlockHeight()), //nolint:gosec // G115
})

return nil
}
81 changes: 81 additions & 0 deletions precompiles/gov/events_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -84,3 +84,84 @@ func (s *PrecompileTestSuite) TestVoteEvent() {
}
}
}

func (s *PrecompileTestSuite) TestVoteWeightedEvent() {
var (
stDB *statedb.StateDB
ctx sdk.Context
method = s.precompile.Methods[gov.VoteWeightedMethod]
)

testCases := []struct {
name string
malleate func(voter common.Address, proposalId uint64, options gov.WeightedVoteOptions) []interface{}
postCheck func()
gas uint64
expError bool
errContains string
}{
{
"success - the correct VoteWeighted event is emitted",
func(voter common.Address, proposalId uint64, options gov.WeightedVoteOptions) []interface{} {
return []interface{}{
voter,
proposalId,
options,
"",
}
},
func() {
log := stDB.Logs()[0]
s.Require().Equal(log.Address, s.precompile.Address())

// Check event signature matches the one emitted
event := s.precompile.ABI.Events[gov.EventTypeVoteWeighted]
s.Require().Equal(crypto.Keccak256Hash([]byte(event.Sig)), common.HexToHash(log.Topics[0].Hex()))
s.Require().Equal(log.BlockNumber, uint64(ctx.BlockHeight())) //nolint:gosec // G115

// Check the fully unpacked event matches the one emitted
var voteWeightedEvent gov.EventVoteWeighted
err := cmn.UnpackLog(s.precompile.ABI, &voteWeightedEvent, gov.EventTypeVoteWeighted, *log)
s.Require().NoError(err)
s.Require().Equal(s.keyring.GetAddr(0), voteWeightedEvent.Voter)
s.Require().Equal(uint64(1), voteWeightedEvent.ProposalId)
s.Require().Equal(2, len(voteWeightedEvent.Options))
s.Require().Equal(uint8(1), voteWeightedEvent.Options[0].Option)
s.Require().Equal("0.70", voteWeightedEvent.Options[0].Weight)
s.Require().Equal(uint8(2), voteWeightedEvent.Options[1].Option)
s.Require().Equal("0.30", voteWeightedEvent.Options[1].Weight)
},
20000,
false,
"",
},
}

for _, tc := range testCases {
s.Run(tc.name, func() {
s.SetupTest()
stDB = s.network.GetStateDB()
ctx = s.network.GetContext()

contract := vm.NewContract(vm.AccountRef(s.keyring.GetAddr(0)), s.precompile, big.NewInt(0), tc.gas)
ctx = ctx.WithGasMeter(storetypes.NewInfiniteGasMeter())
initialGas := ctx.GasMeter().GasConsumed()
s.Require().Zero(initialGas)

options := gov.WeightedVoteOptions{
{Option: 1, Weight: "0.70"},
{Option: 2, Weight: "0.30"},
}

_, err := s.precompile.VoteWeighted(ctx, s.keyring.GetAddr(0), contract, stDB, &method, tc.malleate(s.keyring.GetAddr(0), 1, options))

if tc.expError {
s.Require().Error(err)
s.Require().Contains(err.Error(), tc.errContains)
} else {
s.Require().NoError(err)
tc.postCheck()
}
})
}
}
5 changes: 4 additions & 1 deletion precompiles/gov/gov.go
Original file line number Diff line number Diff line change
Expand Up @@ -104,6 +104,8 @@ func (p Precompile) Run(evm *vm.EVM, contract *vm.Contract, readOnly bool) (bz [
// gov transactions
case VoteMethod:
bz, err = p.Vote(ctx, evm.Origin, contract, stateDB, method, args)
case VoteWeightedMethod:
bz, err = p.VoteWeighted(ctx, evm.Origin, contract, stateDB, method, args)
// gov queries
case GetVoteMethod:
bz, err = p.GetVote(ctx, method, contract, args)
Expand Down Expand Up @@ -134,9 +136,10 @@ func (p Precompile) Run(evm *vm.EVM, contract *vm.Contract, readOnly bool) (bz [
//
// Available gov transactions are:
// - Vote
// - VoteWeighted
5EF6 func (Precompile) IsTransaction(methodName string) bool {
switch methodName {
case VoteMethod:
case VoteMethod, VoteWeightedMethod:
return true
default:
return false
Expand Down
Loading
Loading
0