Add EIP-712 encoding support type for any array (#1430)
* Add EIP-712 encoding support type for any array * Refactor implementation + add tests * Refactor unpacking implementation; refactor test case * Fix lint issue * Add MsgExec test case * Update comment for clarity * Add changelog entry * Refactor `sdkerrors` to `errorsmod` Co-authored-by: Freddy Caceres <facs95@gmail.com>
This commit is contained in:
parent
71e51aabf6
commit
5f418c74ef
@ -45,6 +45,7 @@ Ref: https://keepachangelog.com/en/1.0.0/
|
||||
* (deps) [#1168](https://github.com/evmos/ethermint/pull/1168) Upgrade Cosmos SDK to `v0.46`.
|
||||
* (feemarket) [#1194](https://github.com/evmos/ethermint/pull/1194) Apply feemarket to native cosmos tx.
|
||||
* (eth) [#1346](https://github.com/evmos/ethermint/pull/1346) Added support for `sdk.Dec` and `ed25519` type on eip712.
|
||||
* (eth) [#1430](https://github.com/evmos/ethermint/pull/1430) Added support for array of type `Any` on eip712.
|
||||
* (ante) [1460](https://github.com/evmos/ethermint/pull/1460) Add KV Gas config on ethereum Txs.
|
||||
* (geth) [#1413](https://github.com/evmos/ethermint/pull/1413) Update geth version to v1.10.25.
|
||||
|
||||
|
@ -409,7 +409,29 @@ func (suite AnteTestSuite) TestAnteHandler() {
|
||||
coinAmount := sdk.NewCoin(evmtypes.DefaultEVMDenom, sdk.NewInt(20))
|
||||
amount := sdk.NewCoins(coinAmount)
|
||||
gas := uint64(200000)
|
||||
txBuilder := suite.CreateTestEIP712MsgEditValidator(from, privKey, "ethermint_9000-1", gas, amount)
|
||||
txBuilder := suite.CreateTestEIP712MsgSubmitEvidence(from, privKey, "ethermint_9000-1", gas, amount)
|
||||
return txBuilder.GetTx()
|
||||
}, false, false, true,
|
||||
},
|
||||
{
|
||||
"success- DeliverTx EIP712 submit proposal v1",
|
||||
func() sdk.Tx {
|
||||
from := acc.GetAddress()
|
||||
coinAmount := sdk.NewCoin(evmtypes.DefaultEVMDenom, sdk.NewInt(20))
|
||||
amount := sdk.NewCoins(coinAmount)
|
||||
gas := uint64(200000)
|
||||
txBuilder := suite.CreateTestEIP712SubmitProposalV1(from, privKey, "ethermint_9000-1", gas, amount)
|
||||
return txBuilder.GetTx()
|
||||
}, false, false, true,
|
||||
},
|
||||
{
|
||||
"success- DeliverTx EIP712 MsgExec",
|
||||
func() sdk.Tx {
|
||||
from := acc.GetAddress()
|
||||
coinAmount := sdk.NewCoin(evmtypes.DefaultEVMDenom, sdk.NewInt(20))
|
||||
amount := sdk.NewCoins(coinAmount)
|
||||
gas := uint64(200000)
|
||||
txBuilder := suite.CreateTestEIP712MsgExec(from, privKey, "ethermint_9000-1", gas, amount)
|
||||
return txBuilder.GetTx()
|
||||
}, false, false, true,
|
||||
},
|
||||
|
@ -38,12 +38,14 @@ import (
|
||||
authsigning "github.com/cosmos/cosmos-sdk/x/auth/signing"
|
||||
authtx "github.com/cosmos/cosmos-sdk/x/auth/tx"
|
||||
authtypes "github.com/cosmos/cosmos-sdk/x/auth/types"
|
||||
authz "github.com/cosmos/cosmos-sdk/x/authz"
|
||||
cryptocodec "github.com/evmos/ethermint/crypto/codec"
|
||||
"github.com/evmos/ethermint/crypto/ethsecp256k1"
|
||||
|
||||
"github.com/cosmos/cosmos-sdk/crypto/keys/ed25519"
|
||||
evtypes "github.com/cosmos/cosmos-sdk/x/evidence/types"
|
||||
"github.com/cosmos/cosmos-sdk/x/feegrant"
|
||||
govtypes "github.com/cosmos/cosmos-sdk/x/gov/types/v1"
|
||||
types5 "github.com/cosmos/cosmos-sdk/x/gov/types/v1beta1"
|
||||
"github.com/evmos/ethermint/app"
|
||||
ante "github.com/evmos/ethermint/app/ante"
|
||||
@ -344,6 +346,52 @@ func (suite *AnteTestSuite) CreateTestEIP712MsgSubmitEvidence(from sdk.AccAddres
|
||||
return suite.CreateTestEIP712CosmosTxBuilder(from, priv, chainId, gas, gasAmount, msgEvidence)
|
||||
}
|
||||
|
||||
func (suite *AnteTestSuite) CreateTestEIP712SubmitProposalV1(from sdk.AccAddress, priv cryptotypes.PrivKey, chainId string, gas uint64, gasAmount sdk.Coins) client.TxBuilder {
|
||||
// Build V1 proposal messages. Must all be same-type, since EIP-712
|
||||
// does not support arrays of variable type.
|
||||
authAcc := suite.app.GovKeeper.GetGovernanceAccount(suite.ctx)
|
||||
|
||||
proposal1, ok := types5.ContentFromProposalType("My proposal 1", "My description 1", types5.ProposalTypeText)
|
||||
suite.Require().True(ok)
|
||||
content1, err := govtypes.NewLegacyContent(
|
||||
proposal1,
|
||||
sdk.MustBech32ifyAddressBytes(sdk.GetConfig().GetBech32AccountAddrPrefix(), authAcc.GetAddress().Bytes()),
|
||||
)
|
||||
suite.Require().NoError(err)
|
||||
|
||||
proposal2, ok := types5.ContentFromProposalType("My proposal 2", "My description 2", types5.ProposalTypeText)
|
||||
suite.Require().True(ok)
|
||||
content2, err := govtypes.NewLegacyContent(
|
||||
proposal2,
|
||||
sdk.MustBech32ifyAddressBytes(sdk.GetConfig().GetBech32AccountAddrPrefix(), authAcc.GetAddress().Bytes()),
|
||||
)
|
||||
suite.Require().NoError(err)
|
||||
|
||||
proposalMsgs := []sdk.Msg{
|
||||
content1,
|
||||
content2,
|
||||
}
|
||||
|
||||
// Build V1 proposal
|
||||
msgProposal, err := govtypes.NewMsgSubmitProposal(
|
||||
proposalMsgs,
|
||||
sdk.NewCoins(sdk.NewCoin(evmtypes.DefaultEVMDenom, sdkmath.NewInt(100))),
|
||||
sdk.MustBech32ifyAddressBytes(sdk.GetConfig().GetBech32AccountAddrPrefix(), from.Bytes()),
|
||||
"Metadata",
|
||||
)
|
||||
|
||||
suite.Require().NoError(err)
|
||||
|
||||
return suite.CreateTestEIP712CosmosTxBuilder(from, priv, chainId, gas, gasAmount, msgProposal)
|
||||
}
|
||||
|
||||
func (suite *AnteTestSuite) CreateTestEIP712MsgExec(from sdk.AccAddress, priv cryptotypes.PrivKey, chainId string, gas uint64, gasAmount sdk.Coins) client.TxBuilder {
|
||||
recipient := sdk.AccAddress(common.Address{}.Bytes())
|
||||
msgSend := types2.NewMsgSend(from, recipient, sdk.NewCoins(sdk.NewCoin(evmtypes.DefaultEVMDenom, sdkmath.NewInt(1))))
|
||||
msgExec := authz.NewMsgExec(from, []sdk.Msg{msgSend})
|
||||
return suite.CreateTestEIP712CosmosTxBuilder(from, priv, chainId, gas, gasAmount, &msgExec)
|
||||
}
|
||||
|
||||
// StdSignBytes returns the bytes to sign for a transaction.
|
||||
func StdSignBytes(cdc *codec.LegacyAmino, chainID string, accnum uint64, sequence uint64, timeout uint64, fee legacytx.StdFee, msgs []sdk.Msg, memo string, tip *txtypes.Tip) []byte {
|
||||
msgsBytes := make([]json.RawMessage, 0, len(msgs))
|
||||
|
@ -188,7 +188,11 @@ func traverseFields(
|
||||
}
|
||||
|
||||
for i := 0; i < n; i++ {
|
||||
var field reflect.Value
|
||||
var (
|
||||
field reflect.Value
|
||||
err error
|
||||
)
|
||||
|
||||
if v.IsValid() {
|
||||
field = v.Field(i)
|
||||
}
|
||||
@ -197,23 +201,10 @@ func traverseFields(
|
||||
fieldName := jsonNameFromTag(t.Field(i).Tag)
|
||||
|
||||
if fieldType == cosmosAnyType {
|
||||
any, ok := field.Interface().(*codectypes.Any)
|
||||
if !ok {
|
||||
return errorsmod.Wrapf(errortypes.ErrPackAny, "%T", field.Interface())
|
||||
// Unpack field, value as Any
|
||||
if fieldType, field, err = unpackAny(cdc, field); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
anyWrapper := &cosmosAnyWrapper{
|
||||
Type: any.TypeUrl,
|
||||
}
|
||||
|
||||
if err := cdc.UnpackAny(any, &anyWrapper.Value); err != nil {
|
||||
return errorsmod.Wrap(err, "failed to unpack Any in msg struct")
|
||||
}
|
||||
|
||||
fieldType = reflect.TypeOf(anyWrapper)
|
||||
field = reflect.ValueOf(anyWrapper)
|
||||
|
||||
// then continue as normal
|
||||
}
|
||||
|
||||
// If its a nil pointer, do not include in types
|
||||
@ -255,6 +246,12 @@ func traverseFields(
|
||||
fieldType = fieldType.Elem()
|
||||
field = field.Index(0)
|
||||
isCollection = true
|
||||
|
||||
if fieldType == cosmosAnyType {
|
||||
if fieldType, field, err = unpackAny(cdc, field); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
for {
|
||||
@ -345,6 +342,27 @@ func jsonNameFromTag(tag reflect.StructTag) string {
|
||||
return parts[0]
|
||||
}
|
||||
|
||||
// Unpack the given Any value with Type/Value deconstruction
|
||||
func unpackAny(cdc codectypes.AnyUnpacker, field reflect.Value) (reflect.Type, reflect.Value, error) {
|
||||
any, ok := field.Interface().(*codectypes.Any)
|
||||
if !ok {
|
||||
return nil, reflect.Value{}, errorsmod.Wrapf(errortypes.ErrPackAny, "%T", field.Interface())
|
||||
}
|
||||
|
||||
anyWrapper := &cosmosAnyWrapper{
|
||||
Type: any.TypeUrl,
|
||||
}
|
||||
|
||||
if err := cdc.UnpackAny(any, &anyWrapper.Value); err != nil {
|
||||
return nil, reflect.Value{}, errorsmod.Wrap(err, "failed to unpack Any in msg struct")
|
||||
}
|
||||
|
||||
fieldType := reflect.TypeOf(anyWrapper)
|
||||
field = reflect.ValueOf(anyWrapper)
|
||||
|
||||
return fieldType, field, nil
|
||||
}
|
||||
|
||||
// _.foo_bar.baz -> TypeFooBarBaz
|
||||
//
|
||||
// this is needed for Geth's own signing code which doesn't
|
||||
|
Loading…
Reference in New Issue
Block a user