Skip to content
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

Problem: relayer doesn't make use of binding contract #1193

Closed
wants to merge 4 commits into from
Closed
Show file tree
Hide file tree
Changes from 2 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
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -86,6 +86,7 @@
- [#1179](https://github.com/crypto-org-chain/cronos/pull/1179) Support blocking addresses in mempool.
- [#1182](https://github.com/crypto-org-chain/cronos/pull/1182) Bump librocksdb to 8.5.3.
- [#1183](https://github.com/crypto-org-chain/cronos/pull/1183) Avoid redundant logs added from relayer.
- [#](https://github.com/crypto-org-chain/cronos/pull/) Make use of binding contract in relayer.
mmsqe marked this conversation as resolved.
Show resolved Hide resolved

*April 13, 2023*

Expand Down
2 changes: 1 addition & 1 deletion nix/default.nix
Original file line number Diff line number Diff line change
Expand Up @@ -56,7 +56,7 @@ import sources.nixpkgs {
name = "rly";
src = sources.relayer;
subPackages = [ "." ];
vendorSha256 = "sha256-IoaGLD3XKRmD61qcr/sPn3aWaa7zYAO9EbMiJFnF5BY=";
vendorSha256 = "sha256-5s5URiAZk59mOfZdUcqYAB/IvzFuBiQH5jDBuh6huTE=";
doCheck = false;
GOWORK = "off";
postInstall = ''
Expand Down
6 changes: 3 additions & 3 deletions nix/sources.json
Original file line number Diff line number Diff line change
Expand Up @@ -126,10 +126,10 @@
"homepage": "https://github.com/crypto-org-chain/relayer",
"owner": "crypto-org-chain",
"repo": "relayer",
"rev": "f202a264463e9d5829398f6be50bff990421b483",
"sha256": "08x4bhwglx12rp78gs4hzgp2cywzqwr7gghk1kxasmvy9z0qxp92",
"rev": "efc56cdee7e8148e8c70945e974da12060f110f0",
"sha256": "0dm5vrkdq9q0qysykxw407r3w8gbpzhf9yhh92l68vcqs1y3qp11",
"type": "tarball",
"url": "https://github.com/crypto-org-chain/relayer/archive/f202a264463e9d5829398f6be50bff990421b483.tar.gz",
"url": "https://github.com/mmsqe/relayer/archive/efc56cdee7e8148e8c70945e974da12060f110f0.tar.gz",
"url_template": "https://github.com/<owner>/<repo>/archive/<rev>.tar.gz"
}
}
2 changes: 2 additions & 0 deletions scripts/gen-bindings-contracts
Original file line number Diff line number Diff line change
Expand Up @@ -2,13 +2,15 @@

solc08 --abi --bin x/cronos/events/bindings/src/CosmosTypes.sol -o build --overwrite
solc08 --abi --bin x/cronos/events/bindings/src/Relayer.sol -o build --overwrite
solc08 --abi --bin x/cronos/events/bindings/src/RelayerFunctions.sol -o build --overwrite
solc08 --abi --bin x/cronos/events/bindings/src/Bank.sol -o build --overwrite
solc08 --abi --bin x/cronos/events/bindings/src/ICA.sol -o build --overwrite
solc08 --abi --bin x/cronos/events/bindings/src/ICACallback.sol -o build --overwrite


abigen --pkg lib --abi build/CosmosTypes.abi --bin build/CosmosTypes.bin --out x/cronos/events/bindings/cosmos/lib/cosmos_types.abigen.go --type CosmosTypes
abigen --pkg relayer --abi build/IRelayerModule.abi --bin build/IRelayerModule.bin --out x/cronos/events/bindings/cosmos/precompile/relayer/i_relayer_module.abigen.go --type RelayerModule
abigen --pkg relayer --abi build/IRelayerFunctions.abi --bin build/IRelayerFunctions.bin --out x/cronos/events/bindings/cosmos/precompile/relayer/i_relayer_functions.abigen.go --type RelayerFunctions
abigen --pkg bank --abi build/IBankModule.abi --bin build/IBankModule.bin --out x/cronos/events/bindings/cosmos/precompile/bank/i_bank_module.abigen.go --type BankModule
abigen --pkg ica --abi build/IICAModule.abi --bin build/IICAModule.bin --out x/cronos/events/bindings/cosmos/precompile/ica/i_ica_module.abigen.go --type ICAModule
abigen --pkg icacallback --abi build/IICACallback.abi --bin build/IICACallback.bin --out x/cronos/events/bindings/cosmos/precompile/icacallback/i_ica_callback.abigen.go --type ICACallback

Large diffs are not rendered by default.

21 changes: 21 additions & 0 deletions x/cronos/events/bindings/src/RelayerFunctions.sol
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.4;

interface IRelayerFunctions {
function createClient(bytes calldata data) external payable returns (bytes calldata);
function updateClient(bytes calldata data) external payable returns (bytes calldata);
function upgradeClient(bytes calldata data) external payable returns (bytes calldata);
function submitMisbehaviour(bytes calldata data) external payable returns (bytes calldata);
function connectionOpenInit(bytes calldata data) external payable returns (bytes calldata);
function connectionOpenTry(bytes calldata data) external payable returns (bytes calldata);
function connectionOpenAck(bytes calldata data) external payable returns (bytes calldata);
function connectionOpenConfirm(bytes calldata data) external payable returns (bytes calldata);
function channelOpenInit(bytes calldata data) external payable returns (bytes calldata);
function channelOpenTry(bytes calldata data) external payable returns (bytes calldata);
function channelOpenAck(bytes calldata data) external payable returns (bytes calldata);
function channelOpenConfirm(bytes calldata data) external payable returns (bytes calldata);
function recvPacket(bytes calldata data) external payable returns (bytes calldata);
function acknowledgement(bytes calldata data) external payable returns (bytes calldata);
function timeout(bytes calldata data) external payable returns (bytes calldata);
function timeoutOnClose(bytes calldata data) external payable returns (bytes calldata);
}
179 changes: 89 additions & 90 deletions x/cronos/keeper/precompiles/relayer.go
Original file line number Diff line number Diff line change
@@ -1,41 +1,63 @@
package precompiles

import (
"encoding/binary"
"errors"

storetypes "github.com/cosmos/cosmos-sdk/store/types"

"github.com/cosmos/cosmos-sdk/codec"
"github.com/ethereum/go-ethereum/accounts/abi"
"github.com/ethereum/go-ethereum/common"
"github.com/ethereum/go-ethereum/core/vm"

ibckeeper "github.com/cosmos/ibc-go/v7/modules/core/keeper"
cronosevents "github.com/crypto-org-chain/cronos/v2/x/cronos/events"
"github.com/crypto-org-chain/cronos/v2/x/cronos/events/bindings/cosmos/precompile/relayer"
)

var (
irelayerABI abi.ABI
relayerContractAddress = common.BytesToAddress([]byte{101})
relayerGasRequiredByMethod = map[int]uint64{}
relayerGasRequiredByMethod = map[[4]byte]uint64{}
)

const (
CreateClient = "createClient"
UpdateClient = "updateClient"
UpgradeClient = "upgradeClient"
SubmitMisbehaviour = "submitMisbehaviour"
ConnectionOpenInit = "connectionOpenInit"
ConnectionOpenTry = "connectionOpenTry"
ConnectionOpenAck = "connectionOpenAck"
ConnectionOpenConfirm = "connectionOpenConfirm"
ChannelOpenInit = "channelOpenInit"
ChannelOpenTry = "channelOpenTry"
ChannelOpenAck = "channelOpenAck"
ChannelOpenConfirm = "channelOpenConfirm"
RecvPacket = "recvPacket"
Acknowledgement = "acknowledgement"
Timeout = "timeout"
TimeoutOnClose = "timeoutOnClose"
)

func init() {
relayerGasRequiredByMethod[prefixCreateClient] = 200000
relayerGasRequiredByMethod[prefixUpdateClient] = 400000
relayerGasRequiredByMethod[prefixUpgradeClient] = 400000
relayerGasRequiredByMethod[prefixSubmitMisbehaviour] = 100000
relayerGasRequiredByMethod[prefixConnectionOpenInit] = 100000
relayerGasRequiredByMethod[prefixConnectionOpenTry] = 100000
relayerGasRequiredByMethod[prefixConnectionOpenAck] = 100000
relayerGasRequiredByMethod[prefixConnectionOpenConfirm] = 100000
relayerGasRequiredByMethod[prefixChannelOpenInit] = 100000
relayerGasRequiredByMethod[prefixChannelOpenTry] = 100000
relayerGasRequiredByMethod[prefixChannelOpenAck] = 100000
relayerGasRequiredByMethod[prefixChannelOpenConfirm] = 100000
relayerGasRequiredByMethod[prefixRecvPacket] = 250000
relayerGasRequiredByMethod[prefixAcknowledgement] = 250000
relayerGasRequiredByMethod[prefixTimeout] = 100000
relayerGasRequiredByMethod[prefixTimeoutOnClose] = 100000
if err := irelayerABI.UnmarshalJSON([]byte(relayer.RelayerFunctionsMetaData.ABI)); err != nil {
panic(err)
}
for methodName := range irelayerABI.Methods {
var methodID [4]byte
copy(methodID[:], irelayerABI.Methods[methodName].ID[:4])
switch methodName {
case CreateClient:
relayerGasRequiredByMethod[methodID] = 200000
case RecvPacket, Acknowledgement:
relayerGasRequiredByMethod[methodID] = 250000
case UpdateClient, UpgradeClient:
relayerGasRequiredByMethod[methodID] = 400000
default:
relayerGasRequiredByMethod[methodID] = 100000
}
}
Fixed Show fixed Hide fixed
}

type RelayerContract struct {
Expand Down Expand Up @@ -63,11 +85,9 @@ func (bc *RelayerContract) Address() common.Address {
func (bc *RelayerContract) RequiredGas(input []byte) uint64 {
// base cost to prevent large input size
baseCost := uint64(len(input)) * bc.kvGasConfig.WriteCostPerByte
if len(input) < prefixSize4Bytes {
return 0
}
prefix := int(binary.LittleEndian.Uint32(input[:prefixSize4Bytes]))
requiredGas, ok := relayerGasRequiredByMethod[prefix]
var methodID [4]byte
copy(methodID[:], input[:4])
requiredGas, ok := relayerGasRequiredByMethod[methodID]
if ok {
return requiredGas + baseCost
}
Expand All @@ -78,83 +98,62 @@ func (bc *RelayerContract) IsStateful() bool {
return true
}

// prefix bytes for the relayer msg type
const (
prefixSize4Bytes = 4
// Client
prefixCreateClient = iota + 1
prefixUpdateClient
prefixUpgradeClient
prefixSubmitMisbehaviour
// Connection
prefixConnectionOpenInit
prefixConnectionOpenTry
prefixConnectionOpenAck
prefixConnectionOpenConfirm
// Channel
prefixChannelOpenInit
prefixChannelOpenTry
prefixChannelOpenAck
prefixChannelOpenConfirm
prefixChannelCloseInit
prefixChannelCloseConfirm
prefixRecvPacket
prefixAcknowledgement
prefixTimeout
prefixTimeoutOnClose
)

func (bc *RelayerContract) Run(evm *vm.EVM, contract *vm.Contract, readonly bool) ([]byte, error) {
if readonly {
return nil, errors.New("the method is not readonly")
}
// parse input
if len(contract.Input) < int(prefixSize4Bytes) {
return nil, errors.New("data too short to contain prefix")
methodID := contract.Input[:4]
method, err := irelayerABI.MethodById(methodID)
if err != nil {
return nil, err
}
prefix := int(binary.LittleEndian.Uint32(contract.Input[:prefixSize4Bytes]))
input := contract.Input[prefixSize4Bytes:]
stateDB := evm.StateDB.(ExtStateDB)

var (
err error
res []byte
)
var res []byte
precompileAddr := bc.Address()
args, err := method.Inputs.Unpack(contract.Input[4:])
if err != nil {
return nil, errors.New("fail to unpack input arguments")
}
input := args[0].([]byte)
converter := cronosevents.RelayerConvertEvent
switch prefix {
case prefixCreateClient:
res, err = exec(bc.cdc, stateDB, contract.CallerAddress, precompileAddr, input, bc.ibcKeeper.CreateClient, converter)
case prefixUpdateClient:
res, err = exec(bc.cdc, stateDB, contract.CallerAddress, precompileAddr, input, bc.ibcKeeper.UpdateClient, converter)
case prefixUpgradeClient:
res, err = exec(bc.cdc, stateDB, contract.CallerAddress, precompileAddr, input, bc.ibcKeeper.UpgradeClient, converter)
case prefixSubmitMisbehaviour:
res, err = exec(bc.cdc, stateDB, contract.CallerAddress, precompileAddr, input, bc.ibcKeeper.SubmitMisbehaviour, converter)
case prefixConnectionOpenInit:
res, err = exec(bc.cdc, stateDB, contract.CallerAddress, precompileAddr, input, bc.ibcKeeper.ConnectionOpenInit, converter)
case prefixConnectionOpenTry:
res, err = exec(bc.cdc, stateDB, contract.CallerAddress, precompileAddr, input, bc.ibcKeeper.ConnectionOpenTry, converter)
case prefixConnectionOpenAck:
res, err = exec(bc.cdc, stateDB, contract.CallerAddress, precompileAddr, input, bc.ibcKeeper.ConnectionOpenAck, converter)
case prefixConnectionOpenConfirm:
res, err = exec(bc.cdc, stateDB, contract.CallerAddress, precompileAddr, input, bc.ibcKeeper.ConnectionOpenConfirm, converter)
case prefixChannelOpenInit:
res, err = exec(bc.cdc, stateDB, contract.CallerAddress, precompileAddr, input, bc.ibcKeeper.ChannelOpenInit, converter)
case prefixChannelOpenTry:
res, err = exec(bc.cdc, stateDB, contract.CallerAddress, precompileAddr, input, bc.ibcKeeper.ChannelOpenTry, converter)
case prefixChannelOpenAck:
res, err = exec(bc.cdc, stateDB, contract.CallerAddress, precompileAddr, input, bc.ibcKeeper.ChannelOpenAck, converter)
case prefixChannelOpenConfirm:
res, err = exec(bc.cdc, stateDB, contract.CallerAddress, precompileAddr, input, bc.ibcKeeper.ChannelOpenConfirm, converter)
case prefixRecvPacket:
res, err = exec(bc.cdc, stateDB, contract.CallerAddress, precompileAddr, input, bc.ibcKeeper.RecvPacket, converter)
case prefixAcknowledgement:
res, err = exec(bc.cdc, stateDB, contract.CallerAddress, precompileAddr, input, bc.ibcKeeper.Acknowledgement, converter)
case prefixTimeout:
res, err = exec(bc.cdc, stateDB, contract.CallerAddress, precompileAddr, input, bc.ibcKeeper.Timeout, converter)
case prefixTimeoutOnClose:
res, err = exec(bc.cdc, stateDB, contract.CallerAddress, precompileAddr, input, bc.ibcKeeper.TimeoutOnClose, converter)
e := &Executor{
bc.cdc, stateDB, contract.CallerAddress, precompileAddr, input, converter,
}
switch method.Name {
case CreateClient:
res, err = exec(e, bc.ibcKeeper.CreateClient)
case UpdateClient:
res, err = exec(e, bc.ibcKeeper.UpdateClient)
case UpgradeClient:
res, err = exec(e, bc.ibcKeeper.UpgradeClient)
case SubmitMisbehaviour:
res, err = exec(e, bc.ibcKeeper.SubmitMisbehaviour)
case ConnectionOpenInit:
res, err = exec(e, bc.ibcKeeper.ConnectionOpenInit)
case ConnectionOpenTry:
res, err = exec(e, bc.ibcKeeper.ConnectionOpenTry)
case ConnectionOpenAck:
res, err = exec(e, bc.ibcKeeper.ConnectionOpenAck)
case ConnectionOpenConfirm:
res, err = exec(e, bc.ibcKeeper.ConnectionOpenConfirm)
case ChannelOpenInit:
res, err = exec(e, bc.ibcKeeper.ChannelOpenInit)
case ChannelOpenTry:
res, err = exec(e, bc.ibcKeeper.ChannelOpenTry)
case ChannelOpenAck:
res, err = exec(e, bc.ibcKeeper.ChannelOpenAck)
case ChannelOpenConfirm:
res, err = exec(e, bc.ibcKeeper.ChannelOpenConfirm)
case RecvPacket:
res, err = exec(e, bc.ibcKeeper.RecvPacket)
case Acknowledgement:
res, err = exec(e, bc.ibcKeeper.Acknowledgement)
case Timeout:
res, err = exec(e, bc.ibcKeeper.Timeout)
case TimeoutOnClose:
res, err = exec(e, bc.ibcKeeper.TimeoutOnClose)
default:
return nil, errors.New("unknown method")
}
Expand Down
24 changes: 14 additions & 10 deletions x/cronos/keeper/precompiles/utils.go
Original file line number Diff line number Diff line change
Expand Up @@ -16,40 +16,44 @@ type NativeMessage interface {
GetSigners() []sdk.AccAddress
}

type Executor struct {
cdc codec.Codec
stateDB ExtStateDB
caller common.Address
contract common.Address
input []byte
converter statedb.EventConverter
}

// exec is a generic function that executes the given action in statedb, and marshal/unmarshal the input/output
func exec[Req any, PReq interface {
*Req
NativeMessage
}, Resp codec.ProtoMarshaler](
cdc codec.Codec,
stateDB ExtStateDB,
caller common.Address,
contract common.Address,
input []byte,
e *Executor,
action func(context.Context, PReq) (Resp, error),
converter statedb.EventConverter,
) ([]byte, error) {
msg := PReq(new(Req))
if err := cdc.Unmarshal(input, msg); err != nil {
if err := e.cdc.Unmarshal(e.input, msg); err != nil {
return nil, fmt.Errorf("fail to Unmarshal %T %w", msg, err)
}

signers := msg.GetSigners()
if len(signers) != 1 {
return nil, errors.New("don't support multi-signers message")
}
if common.BytesToAddress(signers[0].Bytes()) != caller {
if common.BytesToAddress(signers[0].Bytes()) != e.caller {
return nil, errors.New("caller is not authenticated")
}

var res Resp
if err := stateDB.ExecuteNativeAction(contract, converter, func(ctx sdk.Context) error {
if err := e.stateDB.ExecuteNativeAction(e.contract, e.converter, func(ctx sdk.Context) error {
var err error
res, err = action(ctx, msg)
return err
}); err != nil {
return nil, err
}

return cdc.Marshal(res)
return e.cdc.Marshal(res)
}