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

feat: json rpc #22

Merged
merged 19 commits into from
Jul 12, 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: 5 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
@@ -1,7 +1,8 @@
# MiniEVM

MiniEVM is an optimistic rollup consumer chain powered by EVM, designed to simplify the process of bootstrapping an L2 network. The main advantage of using MiniEVM is that the users can leverage the OPinit stack for enhanced security and utilize all the Initia ecosystem tooling from day one, without the need to prepare a validator group or build the users' own ecosystem tools.
- https://github.com/initia-labs/evm

- [go-ethereum](https://github.com/initia-labs/evm)

## Prerequisites

Expand All @@ -19,6 +20,9 @@ To get started with L2, please visit the [documentation](https://initia.gitbook.
- Integrates seamlessly with the OPinit stack, enhancing security.
- Provides immediate access to the full suite of Initia ecosystem tools right from the start.

## JSON-RPC

For information of supported JSON-RPC methods, please refer to the [JSON-RPC documentation](jsonrpc/README.md).

## Contributing

Expand Down
20 changes: 15 additions & 5 deletions app/ante/ante.go
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,9 @@

opchildante "github.com/initia-labs/OPinit/x/opchild/ante"
opchildtypes "github.com/initia-labs/OPinit/x/opchild/types"
"github.com/initia-labs/initia/app/ante/accnum"
"github.com/initia-labs/initia/app/ante/sigverify"
evmkeeper "github.com/initia-labs/minievm/x/evm/keeper"

"github.com/skip-mev/block-sdk/v2/block"
auctionante "github.com/skip-mev/block-sdk/v2/x/auction/ante"
Expand All @@ -25,9 +28,11 @@
IBCkeeper *ibckeeper.Keeper
OPChildKeeper opchildtypes.AnteKeeper
AuctionKeeper auctionkeeper.Keeper
TxEncoder sdk.TxEncoder
MevLane auctionante.MEVLane
FreeLane block.Lane
EVMKeeper *evmkeeper.Keeper

TxEncoder sdk.TxEncoder
MevLane auctionante.MEVLane
FreeLane block.Lane
}

// NewAnteHandler returns an AnteHandler that checks and increments sequence
Expand All @@ -46,9 +51,13 @@
return nil, errorsmod.Wrap(sdkerrors.ErrLogic, "sign mode handler is required for ante builder")
}

if options.EVMKeeper == nil {
return nil, errorsmod.Wrap(sdkerrors.ErrLogic, "EVM keeper is required for ante builder")
}

Check warning on line 56 in app/ante/ante.go

View check run for this annotation

Codecov / codecov/patch

app/ante/ante.go#L55-L56

Added lines #L55 - L56 were not covered by tests

sigGasConsumer := options.SigGasConsumer
if sigGasConsumer == nil {
sigGasConsumer = ante.DefaultSigVerificationGasConsumer
sigGasConsumer = sigverify.DefaultSigVerificationGasConsumer
}

txFeeChecker := options.TxFeeChecker
Expand All @@ -72,6 +81,7 @@
}

anteDecorators := []sdk.AnteDecorator{
accnum.NewAccountNumberDecorator(options.AccountKeeper),
ante.NewSetUpContextDecorator(), // outermost AnteDecorator. SetUpContext must be called first
ante.NewExtensionOptionsDecorator(options.ExtensionOptionChecker),
ante.NewValidateBasicDecorator(),
Expand All @@ -83,7 +93,7 @@
ante.NewSetPubKeyDecorator(options.AccountKeeper),
ante.NewValidateSigCountDecorator(options.AccountKeeper),
ante.NewSigGasConsumeDecorator(options.AccountKeeper, sigGasConsumer),
ante.NewSigVerificationDecorator(options.AccountKeeper, options.SignModeHandler),
NewSigVerificationDecorator(options.AccountKeeper, options.EVMKeeper, options.SignModeHandler),
ante.NewIncrementSequenceDecorator(options.AccountKeeper),
ibcante.NewRedundantRelayDecorator(options.IBCkeeper),
auctionante.NewAuctionDecorator(options.AuctionKeeper, options.TxEncoder, options.MevLane),
Expand Down
200 changes: 200 additions & 0 deletions app/ante/sigverify.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,200 @@
package ante

import (
"fmt"

"google.golang.org/protobuf/types/known/anypb"

errorsmod "cosmossdk.io/errors"
storetypes "cosmossdk.io/store/types"
txsigning "cosmossdk.io/x/tx/signing"

codectypes "github.com/cosmos/cosmos-sdk/codec/types"
"github.com/cosmos/cosmos-sdk/crypto/keys/ed25519"
"github.com/cosmos/cosmos-sdk/crypto/keys/secp256k1"
"github.com/cosmos/cosmos-sdk/crypto/keys/secp256r1"
"github.com/cosmos/cosmos-sdk/crypto/types/multisig"
sdk "github.com/cosmos/cosmos-sdk/types"
sdkerrors "github.com/cosmos/cosmos-sdk/types/errors"
"github.com/cosmos/cosmos-sdk/types/tx/signing"
authante "github.com/cosmos/cosmos-sdk/x/auth/ante"
authsigning "github.com/cosmos/cosmos-sdk/x/auth/signing"
"github.com/cosmos/cosmos-sdk/x/auth/types"

"github.com/initia-labs/initia/crypto/ethsecp256k1"
evmkeeper "github.com/initia-labs/minievm/x/evm/keeper"
)

// SigVerificationDecorator verifies all signatures for a tx and return an error if any are invalid. Note,
// the SigVerificationDecorator will not check signatures on ReCheck.
//
// CONTRACT: Pubkeys are set in context for all signers before this decorator runs
// CONTRACT: Tx must implement SigVerifiableTx interface
type SigVerificationDecorator struct {
ak authante.AccountKeeper
ek *evmkeeper.Keeper
signModeHandler *txsigning.HandlerMap
}

func NewSigVerificationDecorator(
ak authante.AccountKeeper,
ek *evmkeeper.Keeper,
signModeHandler *txsigning.HandlerMap) SigVerificationDecorator {
return SigVerificationDecorator{
ak: ak,
ek: ek,
signModeHandler: signModeHandler,
}
}

func (svd SigVerificationDecorator) AnteHandle(ctx sdk.Context, tx sdk.Tx, simulate bool, next sdk.AnteHandler) (newCtx sdk.Context, err error) {
sigTx, ok := tx.(authsigning.Tx)
if !ok {
return ctx, errorsmod.Wrap(sdkerrors.ErrTxDecode, "invalid transaction type")
}

Check warning on line 54 in app/ante/sigverify.go

View check run for this annotation

Codecov / codecov/patch

app/ante/sigverify.go#L50-L54

Added lines #L50 - L54 were not covered by tests

// stdSigs contains the sequence number, account number, and signatures.
// When simulating, this would just be a 0-length slice.
sigs, err := sigTx.GetSignaturesV2()
if err != nil {
return ctx, err
}

Check warning on line 61 in app/ante/sigverify.go

View check run for this annotation

Codecov / codecov/patch

app/ante/sigverify.go#L58-L61

Added lines #L58 - L61 were not covered by tests

signers, err := sigTx.GetSigners()
if err != nil {
return ctx, err
}

Check warning on line 66 in app/ante/sigverify.go

View check run for this annotation

Codecov / codecov/patch

app/ante/sigverify.go#L63-L66

Added lines #L63 - L66 were not covered by tests

// check that signer length and signature length are the same
if len(sigs) != len(signers) {
return ctx, errorsmod.Wrapf(sdkerrors.ErrUnauthorized, "invalid number of signer; expected: %d, got %d", len(signers), len(sigs))
}

Check warning on line 71 in app/ante/sigverify.go

View check run for this annotation

Codecov / codecov/patch

app/ante/sigverify.go#L69-L71

Added lines #L69 - L71 were not covered by tests

for i, sig := range sigs {
acc, err := authante.GetSignerAcc(ctx, svd.ak, signers[i])
if err != nil {
return ctx, err
}

Check warning on line 77 in app/ante/sigverify.go

View check run for this annotation

Codecov / codecov/patch

app/ante/sigverify.go#L73-L77

Added lines #L73 - L77 were not covered by tests

// retrieve pubkey
pubKey := acc.GetPubKey()
if !simulate && pubKey == nil {
return ctx, errorsmod.Wrap(sdkerrors.ErrInvalidPubKey, "pubkey on account is not set")
}

Check warning on line 83 in app/ante/sigverify.go

View check run for this annotation

Codecov / codecov/patch

app/ante/sigverify.go#L80-L83

Added lines #L80 - L83 were not covered by tests

// Check account sequence number.
if sig.Sequence != acc.GetSequence() {
return ctx, errorsmod.Wrapf(
sdkerrors.ErrWrongSequence,
"account sequence mismatch, expected %d, got %d", acc.GetSequence(), sig.Sequence,
)
}

Check warning on line 91 in app/ante/sigverify.go

View check run for this annotation

Codecov / codecov/patch

app/ante/sigverify.go#L86-L91

Added lines #L86 - L91 were not covered by tests

// retrieve signer data
genesis := ctx.BlockHeight() == 0
chainID := ctx.ChainID()
var accNum uint64
if !genesis {
accNum = acc.GetAccountNumber()
}

Check warning on line 99 in app/ante/sigverify.go

View check run for this annotation

Codecov / codecov/patch

app/ante/sigverify.go#L94-L99

Added lines #L94 - L99 were not covered by tests

// no need to verify signatures on recheck tx
if !simulate && !ctx.IsReCheckTx() {
anyPk, _ := codectypes.NewAnyWithValue(pubKey)

signerData := txsigning.SignerData{
Address: acc.GetAddress().String(),
ChainID: chainID,
AccountNumber: accNum,
Sequence: acc.GetSequence(),
PubKey: &anypb.Any{
TypeUrl: anyPk.TypeUrl,
Value: anyPk.Value,
},
}
adaptableTx, ok := tx.(authsigning.V2AdaptableTx)
if !ok {
return ctx, fmt.Errorf("expected tx to implement V2AdaptableTx, got %T", tx)
}
txData := adaptableTx.GetSigningTxData()
err = verifySignature(ctx, pubKey, signerData, sig.Data, svd.signModeHandler, txData, svd.ek, tx)
if err != nil {
var errMsg string
if authante.OnlyLegacyAminoSigners(sig.Data) {
// If all signers are using SIGN_MODE_LEGACY_AMINO, we rely on VerifySignature to check account sequence number,
// and therefore communicate sequence number as a potential cause of error.
errMsg = fmt.Sprintf("signature verification failed; please verify account number (%d), sequence (%d) and chain-id (%s)", accNum, acc.GetSequence(), chainID)
} else {
errMsg = fmt.Sprintf("signature verification failed; please verify account number (%d) and chain-id (%s): (%s)", accNum, chainID, err.Error())
}
return ctx, errorsmod.Wrap(sdkerrors.ErrUnauthorized, errMsg)

Check warning on line 130 in app/ante/sigverify.go

View check run for this annotation

Codecov / codecov/patch

app/ante/sigverify.go#L102-L130

Added lines #L102 - L130 were not covered by tests

}
}
}

return next(ctx, tx, simulate)

Check warning on line 136 in app/ante/sigverify.go

View check run for this annotation

Codecov / codecov/patch

app/ante/sigverify.go#L136

Added line #L136 was not covered by tests
}

// defaultSigVerificationGasConsumer is the default implementation of SignatureVerificationGasConsumer. It consumes gas
// for signature verification based upon the public key type. The cost is fetched from the given params and is matched
// by the concrete type.
func DefaultSigVerificationGasConsumer(
meter storetypes.GasMeter, sig signing.SignatureV2, params types.Params,
) error {
pubkey := sig.PubKey
switch pubkey := pubkey.(type) {
case *ed25519.PubKey:
meter.ConsumeGas(params.SigVerifyCostED25519, "ante verify: ed25519")
return errorsmod.Wrap(sdkerrors.ErrInvalidPubKey, "ED25519 public keys are unsupported")

Check warning on line 149 in app/ante/sigverify.go

View check run for this annotation

Codecov / codecov/patch

app/ante/sigverify.go#L144-L149

Added lines #L144 - L149 were not covered by tests

case *secp256k1.PubKey, *ethsecp256k1.PubKey:
meter.ConsumeGas(params.SigVerifyCostSecp256k1, "ante verify: secp256k1")
return nil

Check warning on line 153 in app/ante/sigverify.go

View check run for this annotation

Codecov / codecov/patch

app/ante/sigverify.go#L151-L153

Added lines #L151 - L153 were not covered by tests

case *secp256r1.PubKey:
meter.ConsumeGas(params.SigVerifyCostSecp256r1(), "ante verify: secp256r1")
return nil

Check warning on line 157 in app/ante/sigverify.go

View check run for this annotation

Codecov / codecov/patch

app/ante/sigverify.go#L155-L157

Added lines #L155 - L157 were not covered by tests

case multisig.PubKey:
multisignature, ok := sig.Data.(*signing.MultiSignatureData)
if !ok {
return fmt.Errorf("expected %T, got, %T", &signing.MultiSignatureData{}, sig.Data)
}
err := consumeMultisignatureVerificationGas(meter, multisignature, pubkey, params, sig.Sequence)
if err != nil {
return err
}
return nil

Check warning on line 168 in app/ante/sigverify.go

View check run for this annotation

Codecov / codecov/patch

app/ante/sigverify.go#L159-L168

Added lines #L159 - L168 were not covered by tests

default:
return errorsmod.Wrapf(sdkerrors.ErrInvalidPubKey, "unrecognized public key type: %T", pubkey)

Check warning on line 171 in app/ante/sigverify.go

View check run for this annotation

Codecov / codecov/patch

app/ante/sigverify.go#L170-L171

Added lines #L170 - L171 were not covered by tests
}
}

// consumeMultisignatureVerificationGas consumes gas from a GasMeter for verifying a multisig pubkey signature
func consumeMultisignatureVerificationGas(
meter storetypes.GasMeter, sig *signing.MultiSignatureData, pubkey multisig.PubKey,
params types.Params, accSeq uint64,
) error {
size := sig.BitArray.Count()
sigIndex := 0

for i := 0; i < size; i++ {
if !sig.BitArray.GetIndex(i) {
continue

Check warning on line 185 in app/ante/sigverify.go

View check run for this annotation

Codecov / codecov/patch

app/ante/sigverify.go#L179-L185

Added lines #L179 - L185 were not covered by tests
}
sigV2 := signing.SignatureV2{
PubKey: pubkey.GetPubKeys()[i],
Data: sig.Signatures[sigIndex],
Sequence: accSeq,
}
err := DefaultSigVerificationGasConsumer(meter, sigV2, params)
if err != nil {
return err
}
sigIndex++

Check warning on line 196 in app/ante/sigverify.go

View check run for this annotation

Codecov / codecov/patch

app/ante/sigverify.go#L187-L196

Added lines #L187 - L196 were not covered by tests
}

return nil

Check warning on line 199 in app/ante/sigverify.go

View check run for this annotation

Codecov / codecov/patch

app/ante/sigverify.go#L199

Added line #L199 was not covered by tests
}
116 changes: 116 additions & 0 deletions app/ante/verify.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,116 @@
package ante

import (
"context"
"fmt"

signingv1beta1 "cosmossdk.io/api/cosmos/tx/signing/v1beta1"
errorsmod "cosmossdk.io/errors"
txsigning "cosmossdk.io/x/tx/signing"

cryptotypes "github.com/cosmos/cosmos-sdk/crypto/types"
"github.com/cosmos/cosmos-sdk/crypto/types/multisig"
sdk "github.com/cosmos/cosmos-sdk/types"
sdkerrors "github.com/cosmos/cosmos-sdk/types/errors"
"github.com/cosmos/cosmos-sdk/types/tx/signing"

evmkeeper "github.com/initia-labs/minievm/x/evm/keeper"
evmtypes "github.com/initia-labs/minievm/x/evm/types"

coretypes "github.com/ethereum/go-ethereum/core/types"
)

// internalSignModeToAPI converts a signing.SignMode to a protobuf SignMode.
func internalSignModeToAPI(mode signing.SignMode) (signingv1beta1.SignMode, error) {
switch mode {
case signing.SignMode_SIGN_MODE_DIRECT:
return signingv1beta1.SignMode_SIGN_MODE_DIRECT, nil
case signing.SignMode_SIGN_MODE_LEGACY_AMINO_JSON:
return signingv1beta1.SignMode_SIGN_MODE_LEGACY_AMINO_JSON, nil
case signing.SignMode_SIGN_MODE_TEXTUAL:
return signingv1beta1.SignMode_SIGN_MODE_TEXTUAL, nil
case signing.SignMode_SIGN_MODE_DIRECT_AUX:
return signingv1beta1.SignMode_SIGN_MODE_DIRECT_AUX, nil
case signing.SignMode_SIGN_MODE_EIP_191:
return signingv1beta1.SignMode_SIGN_MODE_EIP_191, nil
default:
return signingv1beta1.SignMode_SIGN_MODE_UNSPECIFIED, fmt.Errorf("unsupported sign mode %s", mode)

Check warning on line 37 in app/ante/verify.go

View check run for this annotation

Codecov / codecov/patch

app/ante/verify.go#L24-L37

Added lines #L24 - L37 were not covered by tests
}
}

// verifySignature verifies a transaction signature contained in SignatureData abstracting over different signing
// modes. It differs from verifySignature in that it uses the new txsigning.TxData interface in x/tx.
func verifySignature(
ctx context.Context,
pubKey cryptotypes.PubKey,
signerData txsigning.SignerData,
signatureData signing.SignatureData,
handler *txsigning.HandlerMap,
txData txsigning.TxData,
// required to verify EVM signatures
ek *evmkeeper.Keeper,
tx sdk.Tx,
) error {
switch data := signatureData.(type) {
case *signing.SingleSignatureData:
if data.SignMode == evmkeeper.SignMode_SIGN_MODE_ETHEREUM {
// eth sign mode
ethTx, expectedSender, err := evmkeeper.NewTxUtils(ek).ConvertCosmosTxToEthereumTx(ctx, tx)
if err != nil {
return err
}
if ethTx == nil {
return fmt.Errorf("failed to convert tx to ethereum tx")
}

Check warning on line 64 in app/ante/verify.go

View check run for this annotation

Codecov / codecov/patch

app/ante/verify.go#L53-L64

Added lines #L53 - L64 were not covered by tests

sdkCtx := sdk.UnwrapSDKContext(ctx)
ethChainID := evmtypes.ConvertCosmosChainIDToEthereumChainID(sdkCtx.ChainID())
signer := coretypes.LatestSignerForChainID(ethChainID)
sender, err := signer.Sender(ethTx)
if err != nil {
return errorsmod.Wrapf(sdkerrors.ErrorInvalidSigner, "failed to recover sender address: %v", err)
}

Check warning on line 72 in app/ante/verify.go

View check run for this annotation

Codecov / codecov/patch

app/ante/verify.go#L66-L72

Added lines #L66 - L72 were not covered by tests

// check if the recovered sender matches the expected sender
if expectedSender == nil || *expectedSender != sender {
return errorsmod.Wrapf(sdkerrors.ErrorInvalidSigner, "expected sender %s, got %s", expectedSender, sender)
}

Check warning on line 77 in app/ante/verify.go

View check run for this annotation

Codecov / codecov/patch

app/ante/verify.go#L75-L77

Added lines #L75 - L77 were not covered by tests

return nil

Check warning on line 79 in app/ante/verify.go

View check run for this annotation

Codecov / codecov/patch

app/ante/verify.go#L79

Added line #L79 was not covered by tests
}

signMode, err := internalSignModeToAPI(data.SignMode)
if err != nil {
return err
}
signBytes, err := handler.GetSignBytes(ctx, signMode, signerData, txData)
if err != nil {
return err
}

Check warning on line 89 in app/ante/verify.go

View check run for this annotation

Codecov / codecov/patch

app/ante/verify.go#L82-L89

Added lines #L82 - L89 were not covered by tests

if !pubKey.VerifySignature(signBytes, data.Signature) {
return fmt.Errorf("unable to verify single signer signature")
}

Check warning on line 93 in app/ante/verify.go

View check run for this annotation

Codecov / codecov/patch

app/ante/verify.go#L91-L93

Added lines #L91 - L93 were not covered by tests

return nil

Check warning on line 95 in app/ante/verify.go

View check run for this annotation

Codecov / codecov/patch

app/ante/verify.go#L95

Added line #L95 was not covered by tests

case *signing.MultiSignatureData:
multiPK, ok := pubKey.(multisig.PubKey)
if !ok {
return fmt.Errorf("expected %T, got %T", (multisig.PubKey)(nil), pubKey)
}
err := multiPK.VerifyMultisignature(func(mode signing.SignMode) ([]byte, error) {
signMode, err := internalSignModeToAPI(mode)
if err != nil {
return nil, err
}
return handler.GetSignBytes(ctx, signMode, signerData, txData)

Check warning on line 107 in app/ante/verify.go

View check run for this annotation

Codecov / codecov/patch

app/ante/verify.go#L97-L107

Added lines #L97 - L107 were not covered by tests
}, data)
if err != nil {
return err
}
return nil
default:
return fmt.Errorf("unexpected SignatureData %T", signatureData)

Check warning on line 114 in app/ante/verify.go

View check run for this annotation

Codecov / codecov/patch

app/ante/verify.go#L109-L114

Added lines #L109 - L114 were not covered by tests
}
}
Loading
Loading