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

WIP: feat(evm): support readonly precompiles contract #38

Draft
wants to merge 10 commits into
base: main-dym
Choose a base branch
from
4 changes: 2 additions & 2 deletions go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -225,8 +225,8 @@ replace (
github.com/99designs/keyring => github.com/cosmos/keyring v1.2.0
// use Cosmos-SDK fork to enable Ledger functionality
github.com/cosmos/cosmos-sdk => github.com/evmos/cosmos-sdk v0.46.13-ledger.3
// use Evmos geth fork
github.com/ethereum/go-ethereum => github.com/evmos/go-ethereum v1.10.26
// go-ethereum fork with custom-precompiled-contract support
github.com/ethereum/go-ethereum => github.com/EscanBE/go-ethereum-for-evermint v1.10.28
// Security Advisory https://github.com/advisories/GHSA-h395-qcrw-5vmq
github.com/gin-gonic/gin => github.com/gin-gonic/gin v1.7.7
// use cosmos flavored protobufs
Expand Down
4 changes: 2 additions & 2 deletions go.sum
Original file line number Diff line number Diff line change
Expand Up @@ -216,6 +216,8 @@ github.com/ChainSafe/go-schnorrkel v1.0.0/go.mod h1:dpzHYVxLZcp8pjlV+O+UR8K0Hp/z
github.com/DATA-DOG/go-sqlmock v1.3.3/go.mod h1:f/Ixk793poVmq4qj/V1dPUg2JEAKC73Q5eFN3EC/SaM=
github.com/DataDog/datadog-go v3.2.0+incompatible/go.mod h1:LButxg5PwREeZtORoXG3tL4fMGNddJ+vMq1mwgfaqoQ=
github.com/DataDog/zstd v1.5.0/go.mod h1:g4AWEaM3yOg3HYfnJ3YIawPnVdXJh9QME85blwSAmyw=
github.com/EscanBE/go-ethereum-for-evermint v1.10.28 h1:+Iid0JWaULgPbGAB8lGEn1xqsr+GjeGlFzzTMcjgIIE=
github.com/EscanBE/go-ethereum-for-evermint v1.10.28/go.mod h1:/6CsT5Ceen2WPLI/oCA3xMcZ5sWMF/D46SjM/ayY0Oo=
github.com/Knetic/govaluate v3.0.1-0.20171022003610-9aa49832a739+incompatible/go.mod h1:r7JcOSlj0wfOMncg0iLm8Leh48TZaKVeNIfJntJ2wa0=
github.com/Microsoft/go-winio v0.6.0 h1:slsWYD/zyx7lCXoZVlvQrj0hPTM1HI4+v1sIda2yDvg=
github.com/Microsoft/go-winio v0.6.0/go.mod h1:cTAf44im0RAYeL23bpB+fzCyDH2MJiz2BO69KH/soAE=
Expand Down Expand Up @@ -492,8 +494,6 @@ github.com/evmos/cosmos-sdk v0.46.13-ledger.3 h1:GYoD+tM3lpn6TTRra6YCcfrxCXO39AT
github.com/evmos/cosmos-sdk v0.46.13-ledger.3/go.mod h1:EfY521ATNEla8eJ6oJuZBdgP5+p360s7InnRqX+TWdM=
github.com/evmos/evmos-ledger-go v0.3.0-rc0 h1:QbfTCOxAxvaHbdwmkEPewr0BwWy9hnQEc6kXZ6gij/I=
github.com/evmos/evmos-ledger-go v0.3.0-rc0/go.mod h1:w2llvjRGkc7u/S1FQfznebxAwrc+wCOIqXcDFUWVkKQ=
github.com/evmos/go-ethereum v1.10.26 h1:7wlczxUWTwhzJJUyh3Kkqt3/5fdSJzh8c42boc9GuII=
github.com/evmos/go-ethereum v1.10.26/go.mod h1:EYFyF19u3ezGLD4RqOkLq+ZCXzYbLoNDdZlMt7kyKFg=
github.com/facebookgo/ensure v0.0.0-20200202191622-63f1cf65ac4c h1:8ISkoahWXwZR41ois5lSJBSVw4D0OV19Ht/JSTzvSv0=
github.com/facebookgo/stack v0.0.0-20160209184415-751773369052 h1:JWuenKqqX8nojtoVVWjGfOF9635RETekkoH6Cc9SX0A=
github.com/facebookgo/subset v0.0.0-20200203212716-c811ad88dec4 h1:7HZCaLC5+BZpmbhCOZJ293Lz68O7PYrF2EzeiFMwCLk=
Expand Down
6 changes: 5 additions & 1 deletion local_node.sh
Original file line number Diff line number Diff line change
Expand Up @@ -69,6 +69,9 @@ if [[ $overwrite == "y" || $overwrite == "Y" ]]; then
jq '.app_state["evm"]["params"]["evm_denom"]="aevmos"' "$GENESIS" >"$TMP_GENESIS" && mv "$TMP_GENESIS" "$GENESIS"
jq '.app_state["inflation"]["params"]["mint_denom"]="aevmos"' "$GENESIS" >"$TMP_GENESIS" && mv "$TMP_GENESIS" "$GENESIS"

# Workaround feemarket params (somehow it is 20b aevmos)
jq '.app_state["feemarket"]["params"]["min_gas_price"]="0"' "$GENESIS" >"$TMP_GENESIS" && mv "$TMP_GENESIS" "$GENESIS"

# Set gas limit in genesis
jq '.consensus_params["block"]["max_gas"]="10000000"' "$GENESIS" >"$TMP_GENESIS" && mv "$TMP_GENESIS" "$GENESIS"

Expand Down Expand Up @@ -142,7 +145,8 @@ if [[ $overwrite == "y" || $overwrite == "Y" ]]; then
jq -r --arg total_supply "$total_supply" '.app_state["bank"]["supply"][0]["amount"]=$total_supply' "$GENESIS" >"$TMP_GENESIS" && mv "$TMP_GENESIS" "$GENESIS"

# Sign genesis transaction
evmosd gentx "${KEYS[0]}" 1000000000000000000000aevmos --keyring-backend $KEYRING --chain-id $CHAINID --home "$HOMEDIR"
BASE_FEE="$(cat "$HOMEDIR/config/genesis.json" | jq -r .app_state.feemarket.params.base_fee)"
evmosd gentx "${KEYS[0]}" 1000000000000000000000aevmos --gas-prices "$BASE_FEE"aevmos --keyring-backend $KEYRING --chain-id $CHAINID --home "$HOMEDIR"
## In case you want to create multiple validators at genesis
## 1. Back to `evmosd keys add` step, init more keys
## 2. Back to `evmosd add-genesis-account` step, add balance for those
Expand Down
2 changes: 2 additions & 0 deletions proto/ethermint/evm/v1/evm.proto
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,8 @@ message Params {
// allow_unprotected_txs defines if replay-protected (i.e non EIP155
// signed) transactions can be executed on the state machine.
bool allow_unprotected_txs = 6;
// precompiles_version is used to determine precompiles to enable. Default is zero, which enable precompiles of version 0.
uint32 precompiles_version = 7;
}

// ChainConfig defines the Ethereum ChainConfig parameters using *sdk.Int values
Expand Down
196 changes: 196 additions & 0 deletions x/evm/abi/bech32.abi.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,196 @@
[
{
"inputs": [],
"name": "bech32AccountAddrPrefix",
"outputs": [
{
"internalType": "string",
"name": "",
"type": "string"
}
],
"stateMutability": "view",
"type": "function"
},
{
"inputs": [],
"name": "bech32AccountPubPrefix",
"outputs": [
{
"internalType": "string",
"name": "",
"type": "string"
}
],
"stateMutability": "view",
"type": "function"
},
{
"inputs": [],
"name": "bech32ConsensusAddrPrefix",
"outputs": [
{
"internalType": "string",
"name": "",
"type": "string"
}
],
"stateMutability": "view",
"type": "function"
},
{
"inputs": [],
"name": "bech32ConsensusPubPrefix",
"outputs": [
{
"internalType": "string",
"name": "",
"type": "string"
}
],
"stateMutability": "view",
"type": "function"
},
{
"inputs": [
{
"internalType": "string",
"name": "bech32",
"type": "string"
}
],
"name": "bech32Decode",
"outputs": [
{
"internalType": "string",
"name": "",
"type": "string"
},
{
"internalType": "bytes",
"name": "",
"type": "bytes"
},
{
"internalType": "bool",
"name": "",
"type": "bool"
}
],
"stateMutability": "view",
"type": "function"
},
{
"inputs": [
{
"internalType": "string",
"name": "hrp",
"type": "string"
},
{
"internalType": "bytes32",
"name": "addr",
"type": "bytes32"
}
],
"name": "bech32Encode32BytesAddress",
"outputs": [
{
"internalType": "string",
"name": "",
"type": "string"
},
{
"internalType": "bool",
"name": "",
"type": "bool"
}
],
"stateMutability": "view",
"type": "function"
},
{
"inputs": [
{
"internalType": "string",
"name": "hrp",
"type": "string"
},
{
"internalType": "address",
"name": "addr",
"type": "address"
}
],
"name": "bech32EncodeAddress",
"outputs": [
{
"internalType": "string",
"name": "",
"type": "string"
},
{
"internalType": "bool",
"name": "",
"type": "bool"
}
],
"stateMutability": "view",
"type": "function"
},
{
"inputs": [
{
"internalType": "string",
"name": "hrp",
"type": "string"
},
{
"internalType": "bytes",
"name": "buffer",
"type": "bytes"
}
],
"name": "bech32EncodeBytes",
"outputs": [
{
"internalType": "string",
"name": "",
"type": "string"
},
{
"internalType": "bool",
"name": "",
"type": "bool"
}
],
"stateMutability": "view",
"type": "function"
},
{
"inputs": [],
"name": "bech32ValidatorAddrPrefix",
"outputs": [
{
"internalType": "string",
"name": "",
"type": "string"
}
],
"stateMutability": "view",
"type": "function"
},
{
"inputs": [],
"name": "bech32ValidatorPubPrefix",
"outputs": [
{
"internalType": "string",
"name": "",
"type": "string"
}
],
"stateMutability": "view",
"type": "function"
}
]
66 changes: 66 additions & 0 deletions x/evm/abi/bech32.sol
Original file line number Diff line number Diff line change
@@ -0,0 +1,66 @@
// SPDX-License-Identifier: MIT

pragma solidity >=0.7.0 <0.9.0;

interface IBech32CPC {
/**
* @dev Returns bech32-encoded value of the given 20 bytes address, using given HRP.
* The second return value indicating whether the operation succeeded.
*/
function bech32EncodeAddress(string memory hrp, address addr) external view returns (string memory, bool);

/**
* @dev Returns bech32-encoded value of the given 32 bytes address (ICA,...), using given HRP.
* The second return value indicating whether the operation succeeded.
*/
function bech32Encode32BytesAddress(string memory hrp, bytes32 addr) external view returns (string memory, bool);

/**
* @dev Returns bech32-encoded value of the given buffer, using given HRP.
* Maximum allowed buffer size is 256 bytes.
*
* The second return value indicating whether the operation succeeded.
*/
function bech32EncodeBytes(string memory hrp, bytes memory buffer) external view returns (string memory, bool);

/**
* @dev Decode given input bech32.
* Maximum allowed input is 1023 characters.
*
* Returns:
* - The first return value is the HRP.
* - The second return value is the decoded buffer.
* - The third return value indicating whether the operation succeeded.
*/
function bech32Decode(string memory bech32) external view returns (string memory, bytes memory, bool);

/**
* @dev Returns the Bech32 prefix for account address.
*/
function bech32AccountAddrPrefix() external view returns (string memory);

/**
* @dev Returns the Bech32 prefix for validator address.
*/
function bech32ValidatorAddrPrefix() external view returns (string memory);

/**
* @dev Returns the Bech32 prefix for consensus node address.
*/
function bech32ConsensusAddrPrefix() external view returns (string memory);

/**
* @dev Returns the Bech32 prefix for account public key.
*/
function bech32AccountPubPrefix() external view returns (string memory);

/**
* @dev Returns the Bech32 prefix for validator public key.
*/
function bech32ValidatorPubPrefix() external view returns (string memory);

/**
* @dev Returns the Bech32 prefix for consensus node public key.
*/
function bech32ConsensusPubPrefix() external view returns (string memory);
}
67 changes: 67 additions & 0 deletions x/evm/abi/precompiled_info.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,67 @@
package abi

import (
"bytes"
_ "embed"
"encoding/hex"
"encoding/json"
"fmt"

"github.com/ethereum/go-ethereum/accounts/abi"
)

type CustomPrecompiledContractInfo struct {
Name string
ABI abi.ABI
}

func (s *CustomPrecompiledContractInfo) UnmarshalJSON(data []byte) error {
if err := json.Unmarshal(data, &s.ABI); err != nil {
return fmt.Errorf("failed to unmarshal ABI: %w", err)
}
return nil
}

func (s CustomPrecompiledContractInfo) UnpackMethodInput(methodName string, fullInput []byte) ([]interface{}, error) {
return s.findMethodWithSignatureCheck(methodName, fullInput).Inputs.Unpack(fullInput[4:])
}

func (s CustomPrecompiledContractInfo) PackMethodOutput(methodName string, args ...any) ([]byte, error) {
return s.findMethod(methodName).Outputs.Pack(args...)
}

// findMethodWithSignatureCheck finds a method by name, panic if not exists, panic if the input signature does not match the method signature
func (s CustomPrecompiledContractInfo) findMethodWithSignatureCheck(methodName string, fullInput []byte) abi.Method {
method := s.findMethod(methodName)
inputSig := fullInput[:4]
if !bytes.Equal(method.ID, inputSig) {
panic(fmt.Sprintf("signature not match for %s: 0x%s != 0x%s", method.Sig, hex.EncodeToString(method.ID), hex.EncodeToString(inputSig)))
}
return method
}

// findMethod finds a method by name and panics if it does not exist
func (s CustomPrecompiledContractInfo) findMethod(methodName string) abi.Method {
method, found := s.ABI.Methods[methodName]
if !found {
panic(fmt.Sprintf("method could not be found in %s: %s", s.Name, methodName))
}
return method
}

var (
//go:embed bech32.abi.json
bech32Json []byte

Bech32CpcInfo CustomPrecompiledContractInfo
)

func init() {
var err error

err = json.Unmarshal(bech32Json, &Bech32CpcInfo)
if err != nil {
panic(err)
}
Bech32CpcInfo.Name = "Bech32"
}
Loading