Skip to content

Commit

Permalink
Problem: no end-to-end encryption module
Browse files Browse the repository at this point in the history
add keeper

add grpc query

signer option

getter/setter

genesis init/export

fix lint
  • Loading branch information
yihuang committed Apr 26, 2024
1 parent 9001b48 commit 6603d85
Show file tree
Hide file tree
Showing 15 changed files with 2,287 additions and 0 deletions.
12 changes: 12 additions & 0 deletions app/app.go
Original file line number Diff line number Diff line change
Expand Up @@ -162,6 +162,10 @@ import (
icaauthkeeper "github.com/crypto-org-chain/cronos/v2/x/icaauth/keeper"
icaauthtypes "github.com/crypto-org-chain/cronos/v2/x/icaauth/types"

e2ee "github.com/crypto-org-chain/cronos/v2/x/e2ee"
e2eekeeper "github.com/crypto-org-chain/cronos/v2/x/e2ee/keeper"
e2eetypes "github.com/crypto-org-chain/cronos/v2/x/e2ee/types"

// force register the extension json-rpc.
_ "github.com/crypto-org-chain/cronos/v2/x/cronos/rpc"
_ "github.com/ethereum/go-ethereum/eth/tracers/js"
Expand Down Expand Up @@ -250,6 +254,8 @@ func StoreKeys() (
icahosttypes.StoreKey,
// ethermint keys
evmtypes.StoreKey, feemarkettypes.StoreKey,
// e2ee keys
e2eetypes.StoreKey,
// this line is used by starport scaffolding # stargate/app/storeKey
cronostypes.StoreKey,
}
Expand Down Expand Up @@ -320,6 +326,9 @@ type App struct {
EvmKeeper *evmkeeper.Keeper
FeeMarketKeeper feemarketkeeper.Keeper

// e2ee keeper
E2EEKeeper e2eekeeper.Keeper

// this line is used by starport scaffolding # stargate/app/keeperDeclaration

CronosKeeper cronoskeeper.Keeper
Expand Down Expand Up @@ -704,6 +713,8 @@ func New(
// If evidence needs to be handled for the app, set routes in router here and seal
app.EvidenceKeeper = *evidenceKeeper

app.E2EEKeeper = e2eekeeper.NewKeeper(keys[e2eetypes.StoreKey], app.AccountKeeper.AddressCodec())

/**** Module Options ****/

// NOTE: we may consider parsing `appOpts` inside module constructors. For the moment
Expand Down Expand Up @@ -754,6 +765,7 @@ func New(
// Ethermint app modules
feemarket.NewAppModule(app.FeeMarketKeeper, feeMarketS),
evm.NewAppModule(app.EvmKeeper, app.AccountKeeper, evmS),
e2ee.NewAppModule(app.E2EEKeeper),

// Cronos app modules
cronosModule,
Expand Down
2 changes: 2 additions & 0 deletions app/upgrades.go
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ import (
"github.com/cosmos/cosmos-sdk/types/module"
icahosttypes "github.com/cosmos/ibc-go/v8/modules/apps/27-interchain-accounts/host/types"
clientkeeper "github.com/cosmos/ibc-go/v8/modules/core/02-client/keeper"
e2eetypes "github.com/crypto-org-chain/cronos/v2/x/e2ee/types"
)

func (app *App) RegisterUpgradeHandlers(cdc codec.BinaryCodec, clientKeeper clientkeeper.Keeper) {
Expand Down Expand Up @@ -39,6 +40,7 @@ func (app *App) RegisterUpgradeHandlers(cdc codec.BinaryCodec, clientKeeper clie
app.SetStoreLoader(upgradetypes.UpgradeStoreLoader(upgradeInfo.Height, &storetypes.StoreUpgrades{
Added: []string{
icahosttypes.StoreKey,
e2eetypes.StoreKey,
},
}))
}
Expand Down
18 changes: 18 additions & 0 deletions proto/e2ee/genesis.proto
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
syntax = "proto3";
package e2ee;

import "gogoproto/gogo.proto";

option go_package = "github.com/crypto-org-chain/cronos/v2/x/e2ee/types";

// EncryptionKeyEntry is a type that contains the owner and the public key.
message EncryptionKeyEntry {
string address = 1;
bytes key = 2;
}

// GenesisState defines the e2ee module's genesis state.
message GenesisState {
// params defines all the paramaters of the module.
repeated EncryptionKeyEntry keys = 1 [(gogoproto.nullable) = false];
}
25 changes: 25 additions & 0 deletions proto/e2ee/query.proto
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
syntax = "proto3";
package e2ee;

import "gogoproto/gogo.proto";
import "google/api/annotations.proto";

option go_package = "github.com/crypto-org-chain/cronos/v2/x/e2ee/types";

// Query defines the gRPC querier service.
service Query {
// Key queries the encryption key of a given address
rpc Key(KeyRequest) returns (KeyResponse) {
option (google.api.http).get = "/e2ee/v1/key/{address}";
}
}

// KeyRequest is the request type for the Query/Key RPC method.
message KeyRequest {
string address = 1;
}

// KeyResponse is the response type for the Query/Key RPC method.
message KeyResponse {
bytes key = 1;
}
27 changes: 27 additions & 0 deletions proto/e2ee/tx.proto
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
syntax = "proto3";
package e2ee;

import "cosmos/msg/v1/msg.proto";
import "gogoproto/gogo.proto";

option go_package = "github.com/crypto-org-chain/cronos/v2/x/e2ee/types";

// Msg defines the e2ee Msg service
service Msg {
option (cosmos.msg.v1.service) = true;

// RegisterEncryptionKey registers a new encryption key to a specific account
rpc RegisterEncryptionKey(MsgRegisterEncryptionKey) returns (MsgRegisterEncryptionKeyResponse);
}

// MsgRegisterEncryptionKey defines the Msg/RegisterEncryptionKey request type
message MsgRegisterEncryptionKey {
option (cosmos.msg.v1.signer) = "address";

string address = 1;
bytes key = 2;
}

// MsgRegisterEncryptionKeyResponse defines the Msg/RegisterEncryptionKey response type
message MsgRegisterEncryptionKeyResponse {
}
2 changes: 2 additions & 0 deletions x/e2ee/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
e2ee a module for end-to-end encrypted messaging, user can register encryption keys on chain, and receive encrypted
messages on/off chain.
22 changes: 22 additions & 0 deletions x/e2ee/autocli.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
package e2ee

import (
autocliv1 "cosmossdk.io/api/cosmos/autocli/v1"
)

// AutoCLIOptions implements the autocli.HasAutoCLIConfig interface.
func (am AppModule) AutoCLIOptions() *autocliv1.ModuleOptions {
return &autocliv1.ModuleOptions{
Query: &autocliv1.ServiceCommandDescriptor{
Service: "e2ee.Query",
RpcCommandOptions: []*autocliv1.RpcCommandOptions{
{
RpcMethod: "Key",
Use: "key [address]",
Short: "Query an encryption key by address",
PositionalArgs: []*autocliv1.PositionalArgDescriptor{{ProtoField: "address"}},
},
},
},
}
}
87 changes: 87 additions & 0 deletions x/e2ee/keeper/keeper.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,87 @@
package keeper

import (
"context"

"cosmossdk.io/core/address"
"cosmossdk.io/store/prefix"
storetypes "cosmossdk.io/store/types"
sdk "github.com/cosmos/cosmos-sdk/types"

"github.com/crypto-org-chain/cronos/v2/x/e2ee/types"
)

type Keeper struct {
storeKey storetypes.StoreKey
addressCodec address.Codec
}

var (
_ types.MsgServer = Keeper{}
_ types.QueryServer = Keeper{}
)

func NewKeeper(storeKey storetypes.StoreKey, addressCodec address.Codec) Keeper {
return Keeper{
storeKey: storeKey,
addressCodec: addressCodec,
}
}

func (k Keeper) RegisterEncryptionKey(
ctx context.Context,
req *types.MsgRegisterEncryptionKey,
) (*types.MsgRegisterEncryptionKeyResponse, error) {
bz, err := k.addressCodec.StringToBytes(req.Address)
if err != nil {
return nil, err
}
sdkCtx := sdk.UnwrapSDKContext(ctx)
sdkCtx.KVStore(k.storeKey).Set(types.KeyPrefix(bz), req.Key)
return &types.MsgRegisterEncryptionKeyResponse{}, nil
}

func (k Keeper) InitGenesis(
ctx context.Context,
state *types.GenesisState,
) error {
for _, key := range state.Keys {
if _, err := k.RegisterEncryptionKey(ctx, &types.MsgRegisterEncryptionKey{
Address: key.Address,
Key: key.Key,
}); err != nil {
return err
}
}
return nil
}

func (k Keeper) ExportGenesis(ctx context.Context) (*types.GenesisState, error) {
sdkCtx := sdk.UnwrapSDKContext(ctx)
iter := prefix.NewStore(sdkCtx.KVStore(k.storeKey), types.KeyPrefixEncryptionKey).Iterator(nil, nil)
defer iter.Close()

var keys []types.EncryptionKeyEntry
for ; iter.Valid(); iter.Next() {
address, err := k.addressCodec.BytesToString(iter.Key())
if err != nil {
return nil, err
}
key := iter.Value()
keys = append(keys, types.EncryptionKeyEntry{
Address: address,
Key: key,
})
}
return &types.GenesisState{Keys: keys}, nil
}

func (k Keeper) Key(ctx context.Context, req *types.KeyRequest) (*types.KeyResponse, error) {
bz, err := k.addressCodec.StringToBytes(req.Address)
if err != nil {
return nil, err
}
sdkCtx := sdk.UnwrapSDKContext(ctx)
value := sdkCtx.KVStore(k.storeKey).Get(types.KeyPrefix(bz))
return &types.KeyResponse{Key: value}, nil
}
135 changes: 135 additions & 0 deletions x/e2ee/module.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,135 @@
package e2ee

import (
"encoding/json"
"fmt"

abci "github.com/cometbft/cometbft/abci/types"
"github.com/gorilla/mux"
"github.com/grpc-ecosystem/grpc-gateway/runtime"
"github.com/spf13/cobra"

"github.com/cosmos/cosmos-sdk/client"
"github.com/cosmos/cosmos-sdk/codec"
cdctypes "github.com/cosmos/cosmos-sdk/codec/types"
sdk "github.com/cosmos/cosmos-sdk/types"
"github.com/cosmos/cosmos-sdk/types/module"

"github.com/crypto-org-chain/cronos/v2/x/e2ee/keeper"
"github.com/crypto-org-chain/cronos/v2/x/e2ee/types"
)

var (
_ module.AppModule = AppModule{}
_ module.AppModuleBasic = AppModuleBasic{}
_ module.HasGenesisBasics = AppModuleBasic{}
// this line is used by starport scaffolding # ibc/module/interface
)

// ----------------------------------------------------------------------------
// AppModuleBasic
// ----------------------------------------------------------------------------

// AppModuleBasic implements the AppModuleBasic interface for the capability module.
type AppModuleBasic struct{}

func NewAppModuleBasic() AppModuleBasic {
return AppModuleBasic{}
}

// AddModuleInitFlags implements servertypes.ModuleInitFlags interface.
func AddModuleInitFlags(startCmd *cobra.Command) {
}

// Name returns the capability module's name.
func (AppModuleBasic) Name() string {
return types.ModuleName
}

func (AppModuleBasic) RegisterCodec(cdc *codec.LegacyAmino) {
}

func (AppModuleBasic) RegisterLegacyAminoCodec(cdc *codec.LegacyAmino) {
}

// RegisterInterfaces registers the module's interface types
func (a AppModuleBasic) RegisterInterfaces(reg cdctypes.InterfaceRegistry) {
}

// DefaultGenesis returns the capability module's default genesis state.
func (AppModuleBasic) DefaultGenesis(cdc codec.JSONCodec) json.RawMessage {
return cdc.MustMarshalJSON(types.DefaultGenesis())
}

// ValidateGenesis performs genesis state validation for the capability module.
func (AppModuleBasic) ValidateGenesis(cdc codec.JSONCodec, config client.TxEncodingConfig, bz json.RawMessage) error {
var genState types.GenesisState
if err := cdc.UnmarshalJSON(bz, &genState); err != nil {
return fmt.Errorf("failed to unmarshal %s genesis state: %w", types.ModuleName, err)
}
return genState.Validate()
}

// RegisterRESTRoutes registers the capability module's REST service handlers.
func (AppModuleBasic) RegisterRESTRoutes(clientCtx client.Context, rtr *mux.Router) {
}

// RegisterGRPCGatewayRoutes registers the gRPC Gateway routes for the module.
func (AppModuleBasic) RegisterGRPCGatewayRoutes(clientCtx client.Context, mux *runtime.ServeMux) {
}

// ----------------------------------------------------------------------------
// AppModule
// ----------------------------------------------------------------------------

// AppModule implements the AppModule interface for the capability module.
type AppModule struct {
AppModuleBasic

keeper keeper.Keeper
}

func NewAppModule(keeper keeper.Keeper) AppModule {
return AppModule{
AppModuleBasic: NewAppModuleBasic(),
keeper: keeper,
}
}

func (am AppModule) RegisterServices(cfg module.Configurator) {
types.RegisterQueryServer(cfg.QueryServer(), am.keeper)
types.RegisterMsgServer(cfg.MsgServer(), am.keeper)
}

func (am AppModule) InitGenesis(ctx sdk.Context, cdc codec.JSONCodec, gs json.RawMessage) []abci.ValidatorUpdate {
var genState types.GenesisState
// Initialize global index to index in genesis state
cdc.MustUnmarshalJSON(gs, &genState)
if err := am.keeper.InitGenesis(ctx, &genState); err != nil {
panic(err)
}
return []abci.ValidatorUpdate{}
}

// ExportGenesis returns the capability module's exported genesis state as raw JSON bytes.
func (am AppModule) ExportGenesis(ctx sdk.Context, cdc codec.JSONCodec) json.RawMessage {
genState, err := am.keeper.ExportGenesis(ctx)
if err != nil {
panic(err)
}
return cdc.MustMarshalJSON(genState)
}

// ConsensusVersion implements AppModule/ConsensusVersion.
func (AppModule) ConsensusVersion() uint64 { return 1 }

// Name returns the capability module's name.
func (am AppModule) Name() string {
return am.AppModuleBasic.Name()
}

// IsAppModule implements the appmodule.AppModule interface.
func (am AppModule) IsAppModule() {}

// IsOnePerModuleType implements the depinject.OnePerModuleType interface.
func (am AppModule) IsOnePerModuleType() {}
12 changes: 12 additions & 0 deletions x/e2ee/types/genesis.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
package types

// DefaultGenesis returns the default Capability genesis state
func DefaultGenesis() *GenesisState {
return &GenesisState{}
}

// Validate performs basic genesis state validation returning an error upon any
// failure.
func (gs GenesisState) Validate() error {
return nil
}
Loading

0 comments on commit 6603d85

Please sign in to comment.