Skip to content

Commit

Permalink
Problem: e2ee module is not backported
Browse files Browse the repository at this point in the history
Problem: no end-to-end encryption module (crypto-org-chain#1407)

* Problem: no end-to-end encryption module

add keeper

add grpc query

signer option

getter/setter

genesis init/export

fix lint

* fix proto lint

* fix test

* register codec

* changelog

* fix build

* Update x/e2ee/types/keys.go

Co-authored-by: mmsqe <[email protected]>
Signed-off-by: yihuang <[email protected]>

* Update x/e2ee/types/codec.go

Co-authored-by: mmsqe <[email protected]>
Signed-off-by: yihuang <[email protected]>

---------

Signed-off-by: yihuang <[email protected]>
Co-authored-by: mmsqe <[email protected]>

Problem: encryption-key cmd is not supported (crypto-org-chain#1409)

* Problem: encryption-key cmd is not supported

* gen doc

* add validate

Problem: no keyring interface for e2ee to store arbitrary payload (crypto-org-chain#1413)

changelo

add age encrypt/decrypt in unit test

Update x/e2ee/keyring/keyring.go

Signed-off-by: yihuang <[email protected]>

fix lint

fix build

Problem: no encrypt and decrypt cmds for message (crypto-org-chain#1411)

* Problem: no encrypt and decrypt cmds for message

* fix doc

* add gen

* test

* cleanup

* move command to e2ee module

move encrypt cmd to e2ee module

move decrypt cmd to e2ee

update integration test

store key as string, to make autocli better

fix integration test

Update x/e2ee/client/cli/encrypt.go

Signed-off-by: yihuang <[email protected]>

fix lint

---------

Signed-off-by: yihuang <[email protected]>
Co-authored-by: yihuang <[email protected]>
Co-authored-by: yihuang <[email protected]>

Problem: no efficient batch query for encryption keys (crypto-org-chain#1415)

Update CHANGELOG.md

Signed-off-by: yihuang <[email protected]>

update swagger

typo

fix build

proposal handler

update version

check exist

Problem: proto-gen fails in CI (crypto-org-chain#1392)

* Problem: proto-gen fails in CI

* Apply suggestions from code review

add cronos msg

add store-block-list cmd

refresh block list

add handler

update deps

add handler

lint

fix cmd

test store list

set with ante

move to util

fix ibc

Revert "set with ante"

This reverts commit c2700f5.

reject on err

fix prepare proposal

fix proto lint
  • Loading branch information
yihuang committed May 3, 2024
1 parent 4584c0a commit 3258b5b
Show file tree
Hide file tree
Showing 57 changed files with 5,053 additions and 127 deletions.
4 changes: 2 additions & 2 deletions .github/workflows/proto.yml
Original file line number Diff line number Diff line change
Expand Up @@ -40,10 +40,10 @@ jobs:
with:
PATTERNS: |
**/**.proto
- name: proto-gen
- name: proto-gen-ci
if: env.GIT_DIFF
run: |
make proto-gen # proto-swagger-gen FIXME swagger-gen result is not reproducible in CI
make proto-gen-ci # proto-swagger-gen FIXME swagger-gen result is not reproducible in CI
git checkout -- go.mod go.sum docs/api/proto-docs.md # FIXME doc gen not reproducible in CI
- name: check working directory is clean
uses: numtide/clean-git-action@main
16 changes: 16 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,16 @@
# Changelog

## UNRELEASED

### State Machine Breaking

* [#1407](https://github.com/crypto-org-chain/cronos/pull/1407) Add end-to-end encryption module.

### Improvements

* [#1413](https://github.com/crypto-org-chain/cronos/pull/1413) Add custom keyring implementation for e2ee module.
* (e2ee)[#1415](https://github.com/crypto-org-chain/cronos/pull/1415) Add batch keys query for e2ee module.

*April 22, 2024*

## v1.2.1
Expand All @@ -13,6 +24,11 @@

* (rpc) [#1397](https://github.com/crypto-org-chain/cronos/pull/1397) Avoid panic on invalid elasticity_multiplier.

### Features

* [#1406](https://github.com/crypto-org-chain/cronos/pull/1406) Add set-encryption-key for encryption module.
* [#1411](https://github.com/crypto-org-chain/cronos/pull/1411) Add encrypt and decrypt cmds for message.

*April 8, 2024*

## v1.2.0
Expand Down
5 changes: 5 additions & 0 deletions Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -272,6 +272,7 @@ endif
HTTPS_GIT := https://github.com/crypto-org-chain/cronos.git
protoVer=0.11.6
protoImageName=ghcr.io/cosmos/proto-builder:$(protoVer)
protoImageCi=$(DOCKER) run --rm -v $(CURDIR):/workspace --workdir /workspace --user root $(protoImageName)
protoImage=$(DOCKER) run --rm -v $(CURDIR):/workspace --workdir /workspace $(protoImageName)

# ------
Expand All @@ -280,6 +281,10 @@ protoImage=$(DOCKER) run --rm -v $(CURDIR):/workspace --workdir /workspace $(pro
#
proto-all: proto-format proto-lint proto-gen

proto-gen-ci:
@echo "Generating Protobuf files"
$(protoImageCi) sh ./scripts/protocgen.sh

proto-gen:
@echo "Generating Protobuf files"
$(protoImage) sh ./scripts/protocgen.sh
Expand Down
90 changes: 78 additions & 12 deletions app/app.go
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@ import (

autocliv1 "cosmossdk.io/api/cosmos/autocli/v1"
reflectionv1 "cosmossdk.io/api/cosmos/reflection/v1"
"filippo.io/age"
runtimeservices "github.com/cosmos/cosmos-sdk/runtime/services"
"golang.org/x/exp/slices"

Expand All @@ -23,6 +24,7 @@ import (
tmjson "github.com/cometbft/cometbft/libs/json"
"github.com/cometbft/cometbft/libs/log"
tmos "github.com/cometbft/cometbft/libs/os"
tmproto "github.com/cometbft/cometbft/proto/tendermint/types"
"github.com/cosmos/cosmos-sdk/client"
"github.com/cosmos/cosmos-sdk/codec/types"
"github.com/gorilla/mux"
Expand Down Expand Up @@ -123,6 +125,7 @@ import (
icaauthkeeper "github.com/crypto-org-chain/cronos/v2/x/icaauth/keeper"
icaauthtypes "github.com/crypto-org-chain/cronos/v2/x/icaauth/types"

clientflags "github.com/cosmos/cosmos-sdk/client/flags"
evmante "github.com/evmos/ethermint/app/ante"
srvflags "github.com/evmos/ethermint/server/flags"
ethermint "github.com/evmos/ethermint/types"
Expand Down Expand Up @@ -159,6 +162,11 @@ import (
_ "github.com/ethereum/go-ethereum/eth/tracers/native"
ethparams "github.com/ethereum/go-ethereum/params"

e2ee "github.com/crypto-org-chain/cronos/v2/x/e2ee"
e2eekeeper "github.com/crypto-org-chain/cronos/v2/x/e2ee/keeper"
e2eekeyring "github.com/crypto-org-chain/cronos/v2/x/e2ee/keyring"
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"
)
Expand Down Expand Up @@ -260,6 +268,7 @@ func GenModuleBasics() module.BasicManager {
ibcfee.AppModuleBasic{},
evm.AppModuleBasic{},
feemarket.AppModuleBasic{},
e2ee.AppModuleBasic{},
// this line is used by starport scaffolding # stargate/app/moduleBasic
gravity.AppModuleBasic{},
cronos.AppModuleBasic{},
Expand All @@ -286,6 +295,8 @@ func StoreKeys(skipGravity bool) (
icaauthtypes.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 @@ -357,6 +368,9 @@ type App struct {
// Gravity module
GravityKeeper gravitykeeper.Keeper

// e2ee keeper
E2EEKeeper e2eekeeper.Keeper

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

CronosKeeper cronoskeeper.Keeper
Expand All @@ -371,6 +385,8 @@ type App struct {
configurator module.Configurator

qms storetypes.MultiStore

blockProposalHandler *ProposalHandler
}

// New returns a reference to an initialized chain.
Expand All @@ -385,15 +401,37 @@ func New(
cdc := encodingConfig.Amino
interfaceRegistry := encodingConfig.InterfaceRegistry

var identity age.Identity
{
if cast.ToString(appOpts.Get("mode")) == "validator" {
krBackend := cast.ToString(appOpts.Get(clientflags.FlagKeyringBackend))
kr, err := e2eekeyring.New("cronosd", krBackend, homePath, os.Stdin)
if err != nil {
panic(err)
}
bz, err := kr.Get(e2eetypes.DefaultKeyringName)
if err != nil {
logger.Error("e2ee identity for validator not found", "error", err)
} else {
identity, err = age.ParseX25519Identity(string(bz))
if err != nil {
panic(err)
}
}
}
}

baseAppOptions = memiavlstore.SetupMemIAVL(logger, homePath, appOpts, false, false, baseAppOptions)

blockProposalHandler := NewProposalHandler(encodingConfig.TxConfig.TxDecoder(), identity)

// NOTE we use custom transaction decoder that supports the sdk.Tx interface instead of sdk.StdTx
// Setup Mempool and Proposal Handlers
baseAppOptions = append(baseAppOptions, func(app *baseapp.BaseApp) {
mempool := mempool.NoOpMempool{}
app.SetMempool(mempool)
handler := baseapp.NewDefaultProposalHandler(mempool, app)
app.SetPrepareProposal(handler.PrepareProposalHandler())
app.SetProcessProposal(handler.ProcessProposalHandler())
app.SetPrepareProposal(blockProposalHandler.PrepareProposalHandler())
app.SetProcessProposal(blockProposalHandler.ProcessProposalHandler())
})
bApp := baseapp.NewBaseApp(Name, logger, db, encodingConfig.TxConfig.TxDecoder(), baseAppOptions...)

Expand All @@ -404,14 +442,15 @@ func New(
keys, memKeys, tkeys := StoreKeys(skipGravity)

app := &App{
BaseApp: bApp,
cdc: cdc,
appCodec: appCodec,
interfaceRegistry: interfaceRegistry,
invCheckPeriod: invCheckPeriod,
keys: keys,
tkeys: tkeys,
memKeys: memKeys,
BaseApp: bApp,
cdc: cdc,
appCodec: appCodec,
interfaceRegistry: interfaceRegistry,
invCheckPeriod: invCheckPeriod,
keys: keys,
tkeys: tkeys,
memKeys: memKeys,
blockProposalHandler: blockProposalHandler,
}

// init params keeper and subspaces
Expand Down Expand Up @@ -666,6 +705,8 @@ func New(
// this line is used by starport scaffolding # ibc/app/router
app.IBCKeeper.SetRouter(ibcRouter)

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

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

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

// Cronos app modules
cronosModule,
}

Expand Down Expand Up @@ -737,6 +781,7 @@ func New(
vestingtypes.ModuleName,
cronostypes.ModuleName,
consensusparamtypes.ModuleName,
e2eetypes.ModuleName,
}
endBlockersOrder := []string{
crisistypes.ModuleName, govtypes.ModuleName, stakingtypes.ModuleName,
Expand All @@ -760,6 +805,7 @@ func New(
vestingtypes.ModuleName,
cronostypes.ModuleName,
consensusparamtypes.ModuleName,
e2eetypes.ModuleName,
}
// NOTE: The genutils module must occur after staking so that pools are
// properly initialized with tokens from genesis accounts.
Expand Down Expand Up @@ -795,6 +841,7 @@ func New(
consensusparamtypes.ModuleName,
// NOTE: crisis module must go at the end to check for invariants on each module
crisistypes.ModuleName,
e2eetypes.ModuleName,
}

if !skipGravity {
Expand Down Expand Up @@ -908,6 +955,10 @@ func New(
tmos.Exit(fmt.Sprintf("versiondb version %d lag behind iavl version %d", v1, v2))
}
}

if err := app.RefreshBlockList(app.NewUncachedContext(false, tmproto.Header{})); err != nil {
panic(err)
}
}

app.ScopedIBCKeeper = scopedIBCKeeper
Expand Down Expand Up @@ -1002,7 +1053,22 @@ func (app *App) BeginBlocker(ctx sdk.Context, req abci.RequestBeginBlock) abci.R

// EndBlocker application updates every end block
func (app *App) EndBlocker(ctx sdk.Context, req abci.RequestEndBlock) abci.ResponseEndBlock {
return app.mm.EndBlock(ctx, req)
rsp := app.mm.EndBlock(ctx, req)

if err := app.RefreshBlockList(ctx); err != nil {
app.Logger().Error("failed to update blocklist", "error", err)
}

return rsp
}

func (app *App) RefreshBlockList(ctx sdk.Context) error {
if app.blockProposalHandler.Identity == nil {
return nil
}

// refresh blocklist
return app.blockProposalHandler.SetBlockList(app.CronosKeeper.GetBlockList(ctx))
}

// InitChainer application update at chain initialization
Expand Down
117 changes: 117 additions & 0 deletions app/proposal.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,117 @@
package app

import (
"bytes"
"encoding/json"
"fmt"
"io"

"filippo.io/age"

abci "github.com/cometbft/cometbft/abci/types"
sdk "github.com/cosmos/cosmos-sdk/types"
"github.com/cosmos/cosmos-sdk/x/auth/signing"
)

type BlockList struct {
Addresses []string `mapstructure:"addresses"`
}

type ProposalHandler struct {
TxDecoder sdk.TxDecoder
Identity age.Identity
Blocklist map[string]struct{}
LastBlockList []byte
}

func NewProposalHandler(txDecoder sdk.TxDecoder, identity age.Identity) *ProposalHandler {
return &ProposalHandler{
TxDecoder: txDecoder,
Identity: identity,
Blocklist: make(map[string]struct{}),
}
}

func (h *ProposalHandler) SetBlockList(blob []byte) error {
if h.Identity == nil {
return nil
}

if bytes.Equal(h.LastBlockList, blob) {
return nil
}
h.LastBlockList = blob

reader, err := age.Decrypt(bytes.NewBuffer(blob), h.Identity)
if err != nil {
return err
}

data, err := io.ReadAll(reader)
if err != nil {
return err
}

var blocklist BlockList
if err := json.Unmarshal(data, &blocklist); err != nil {
return err
}

// convert to map
m := make(map[string]struct{}, len(blocklist.Addresses))
for _, s := range blocklist.Addresses {
addr, err := sdk.AccAddressFromBech32(s)
if err != nil {
return fmt.Errorf("invalid bech32 address: %s, err: %w", s, err)
}
m[addr.String()] = struct{}{}
}

h.Blocklist = m
return nil
}

func (h *ProposalHandler) ValidateTransaction(txBz []byte) error {
tx, err := h.TxDecoder(txBz)
if err != nil {
return err
}

sigTx, ok := tx.(signing.SigVerifiableTx)
if !ok {
return fmt.Errorf("tx of type %T does not implement SigVerifiableTx", tx)
}

for _, signer := range sigTx.GetSigners() {
if _, ok := h.Blocklist[signer.String()]; ok {
return fmt.Errorf("signer is blocked: %s", signer.String())
}
}
return nil
}

func (h *ProposalHandler) PrepareProposalHandler() sdk.PrepareProposalHandler {
return func(ctx sdk.Context, req abci.RequestPrepareProposal) abci.ResponsePrepareProposal {
txs := make([][]byte, 0, len(req.Txs))
for _, txBz := range req.Txs {
if err := h.ValidateTransaction(txBz); err != nil {
continue
}
txs = append(txs, txBz)
}

return abci.ResponsePrepareProposal{Txs: txs}
}
}

func (h *ProposalHandler) ProcessProposalHandler() sdk.ProcessProposalHandler {
return func(ctx sdk.Context, req abci.RequestProcessProposal) abci.ResponseProcessProposal {
for _, txBz := range req.Txs {
if err := h.ValidateTransaction(txBz); err != nil {
return abci.ResponseProcessProposal{Status: abci.ResponseProcessProposal_REJECT}
}
}

return abci.ResponseProcessProposal{Status: abci.ResponseProcessProposal_ACCEPT}
}
}
Loading

0 comments on commit 3258b5b

Please sign in to comment.