-
Notifications
You must be signed in to change notification settings - Fork 38
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
* wip * wip2 * feat: json-rpc signing * direction * add indexer * enable jsonrpc * add precision checking logic * fix test * reterive value from the msg * fix: handle unit conversion in cosmos to ethereum tx (#24) whenever ethereum tx is converted into cosmos tx by ConvertEthereumTxToCosmosTx, the value is converted to cosmos fee unit from wei. so when convert the cosmos tx to back the original ethereum tx, we should convert the value back to wei to get original ethereum tx. * fix pubkey recover * fix test * feat: implement new apis and refactoring (#28) * feat: new eth apis, refactor: code structures new eth apis - GetStorageAt - GetCode refactor - Restricted the scope of access for each namespace API (instead of accessing the backend directly, now access is through a scoped wrapper) - Also renamed files and repositioned some methods within the backend directory to better reflect their purpose * fix: not implemented txpool api temp disable txpool api because we don't have any implementation * fix: change event type for extract logs * add cap for filters * add filter system and apis * fix comment Co-authored-by: zsystm <[email protected]> * delete unused interfaces and comments * fix varible and function naming * add TODO comments * delete unused functions * add error handling * Set websocket params to prevent timeout * fix: change GetLogsByHeight interface * chore: change variable names from tm to comet * docs: add comments about websocket client params * fix: go.mod and go.work.sum ran the followings for this commit: - go mod tidy - go work sync * update: cometbft dep current version of cometbft which minievm uses have a bug(cometbft/cometbft#3264 (comment)) which makes transaction broadcasting unavailable. --------- Co-authored-by: jason song <[email protected]> Co-authored-by: jasonsong0 <[email protected]> * feat: directly subscribe logs from indexer (#34) * change filter system to directly subscribe from indexer * use mutex and pass logs in bulk * fix dependency problems * add readme * update readme --------- Co-authored-by: suha jin <[email protected]> Co-authored-by: zsystm <[email protected]> Co-authored-by: jason song <[email protected]> Co-authored-by: jasonsong0 <[email protected]>
- Loading branch information
1 parent
a59fe85
commit cbf3be3
Showing
84 changed files
with
6,173 additions
and
342 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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") | ||
} | ||
|
||
// 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 | ||
} | ||
|
||
signers, err := sigTx.GetSigners() | ||
if err != nil { | ||
return ctx, err | ||
} | ||
|
||
// 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)) | ||
} | ||
|
||
for i, sig := range sigs { | ||
acc, err := authante.GetSignerAcc(ctx, svd.ak, signers[i]) | ||
if err != nil { | ||
return ctx, err | ||
} | ||
|
||
// retrieve pubkey | ||
pubKey := acc.GetPubKey() | ||
if !simulate && pubKey == nil { | ||
return ctx, errorsmod.Wrap(sdkerrors.ErrInvalidPubKey, "pubkey on account is not set") | ||
} | ||
|
||
// 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, | ||
) | ||
} | ||
|
||
// retrieve signer data | ||
genesis := ctx.BlockHeight() == 0 | ||
chainID := ctx.ChainID() | ||
var accNum uint64 | ||
if !genesis { | ||
accNum = acc.GetAccountNumber() | ||
} | ||
|
||
// 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) | ||
|
||
} | ||
} | ||
} | ||
|
||
return next(ctx, tx, simulate) | ||
} | ||
|
||
// 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") | ||
|
||
case *secp256k1.PubKey, *ethsecp256k1.PubKey: | ||
meter.ConsumeGas(params.SigVerifyCostSecp256k1, "ante verify: secp256k1") | ||
return nil | ||
|
||
case *secp256r1.PubKey: | ||
meter.ConsumeGas(params.SigVerifyCostSecp256r1(), "ante verify: secp256r1") | ||
return nil | ||
|
||
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 | ||
|
||
default: | ||
return errorsmod.Wrapf(sdkerrors.ErrInvalidPubKey, "unrecognized public key type: %T", pubkey) | ||
} | ||
} | ||
|
||
// 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 | ||
} | ||
sigV2 := signing.SignatureV2{ | ||
PubKey: pubkey.GetPubKeys()[i], | ||
Data: sig.Signatures[sigIndex], | ||
Sequence: accSeq, | ||
} | ||
err := DefaultSigVerificationGasConsumer(meter, sigV2, params) | ||
if err != nil { | ||
return err | ||
} | ||
sigIndex++ | ||
} | ||
|
||
return nil | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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) | ||
} | ||
} | ||
|
||
// 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") | ||
} | ||
|
||
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 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) | ||
} | ||
|
||
return nil | ||
} | ||
|
||
signMode, err := internalSignModeToAPI(data.SignMode) | ||
if err != nil { | ||
return err | ||
} | ||
signBytes, err := handler.GetSignBytes(ctx, signMode, signerData, txData) | ||
if err != nil { | ||
return err | ||
} | ||
|
||
if !pubKey.VerifySignature(signBytes, data.Signature) { | ||
return fmt.Errorf("unable to verify single signer signature") | ||
} | ||
|
||
return nil | ||
|
||
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) | ||
}, data) | ||
if err != nil { | ||
return err | ||
} | ||
return nil | ||
default: | ||
return fmt.Errorf("unexpected SignatureData %T", signatureData) | ||
} | ||
} |
Oops, something went wrong.