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

Problem: e2ee module not up to date #1610

Merged
merged 17 commits into from
Sep 27, 2024
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@
* [#1592](https://github.com/crypto-org-chain/cronos/pull/1592) Change the default parallelism of the block-stm to minimum between GOMAXPROCS and NumCPU
* [#1600](https://github.com/crypto-org-chain/cronos/pull/1600) Update ethermint to avoid unnecessary block result in header related api call.
* [#1606](https://github.com/crypto-org-chain/cronos/pull/1606) Fix pebbledb support.
* [#1610](https://github.com/crypto-org-chain/cronos/pull/1610) Sync e2ee module with v1.3.x branch.

### Bug Fixes

Expand Down
106 changes: 88 additions & 18 deletions app/app.go
Original file line number Diff line number Diff line change
Expand Up @@ -15,8 +15,11 @@ import (
stdruntime "runtime"
"sort"

"filippo.io/age"

abci "github.com/cometbft/cometbft/abci/types"
tmos "github.com/cometbft/cometbft/libs/os"
cmtproto "github.com/cometbft/cometbft/proto/tendermint/types"
dbm "github.com/cosmos/cosmos-db"
"github.com/cosmos/gogoproto/proto"
"github.com/gorilla/mux"
Expand Down Expand Up @@ -159,6 +162,7 @@ import (
cronosprecompiles "github.com/crypto-org-chain/cronos/v2/x/cronos/keeper/precompiles"
"github.com/crypto-org-chain/cronos/v2/x/cronos/middleware"
cronostypes "github.com/crypto-org-chain/cronos/v2/x/cronos/types"
e2eekeyring "github.com/crypto-org-chain/cronos/v2/x/e2ee/keyring"

e2ee "github.com/crypto-org-chain/cronos/v2/x/e2ee"
e2eekeeper "github.com/crypto-org-chain/cronos/v2/x/e2ee/keeper"
Expand All @@ -179,7 +183,8 @@ const (
// NOTE: In the SDK, the default value is 255.
AddrLen = 20

FlagBlockedAddresses = "blocked-addresses"
FlagBlockedAddresses = "blocked-addresses"
FlagUnsafeIgnoreBlockListFailure = "unsafe-ignore-block-list-failure"
yihuang marked this conversation as resolved.
Show resolved Hide resolved
)

var Forks = []Fork{}
Expand Down Expand Up @@ -342,6 +347,8 @@ type App struct {
configurator module.Configurator

qms storetypes.RootMultiStore

blockProposalHandler *ProposalHandler
}

// New returns a reference to an initialized chain.
Expand All @@ -360,23 +367,67 @@ func New(
cdc := encodingConfig.Amino
txConfig := encodingConfig.TxConfig
interfaceRegistry := encodingConfig.InterfaceRegistry

txDecoder := txConfig.TxDecoder()
eip712.SetEncodingConfig(encodingConfig)

homePath := cast.ToString(appOpts.Get(flags.FlagHome))
var identity age.Identity
{
if cast.ToString(appOpts.Get("mode")) == "validator" {
krBackend := cast.ToString(appOpts.Get(flags.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)
identity = noneIdentity{}
} else {
identity, err = age.ParseX25519Identity(string(bz))
if err != nil {
logger.Error("e2ee identity for validator is invalid", "error", err)
identity = noneIdentity{}
}
}
}
}

addressCodec := authcodec.NewBech32Codec(sdk.GetConfig().GetBech32AccountAddrPrefix())

var mpool mempool.Mempool
if maxTxs := cast.ToInt(appOpts.Get(server.FlagMempoolMaxTxs)); maxTxs >= 0 {
// NOTE we use custom transaction decoder that supports the sdk.Tx interface instead of sdk.StdTx
// Setup Mempool and Proposal Handlers
mempool := mempool.NewPriorityMempool(mempool.PriorityNonceMempoolConfig[int64]{
mpool = mempool.NewPriorityMempool(mempool.PriorityNonceMempoolConfig[int64]{
TxPriority: mempool.NewDefaultTxPriority(),
SignerExtractor: evmapp.NewEthSignerExtractionAdapter(mempool.NewDefaultSignerExtractionAdapter()),
MaxTx: maxTxs,
})
baseAppOptions = append(baseAppOptions, baseapp.SetMempool(mempool))
} else {
mpool = mempool.NoOpMempool{}
}
blockProposalHandler := NewProposalHandler(txDecoder, identity, addressCodec)
baseAppOptions = append(baseAppOptions, func(app *baseapp.BaseApp) {
app.SetMempool(mpool)

// Re-use the default prepare proposal handler, extend the transaction validation logic
defaultProposalHandler := baseapp.NewDefaultProposalHandler(mpool, app)
defaultProposalHandler.SetTxSelector(NewExtTxSelector(
baseapp.NewDefaultTxSelector(),
txDecoder,
blockProposalHandler.ValidateTransaction,
))

app.SetPrepareProposal(defaultProposalHandler.PrepareProposalHandler())

// The default process proposal handler do nothing when the mempool is noop,
// so we just implement a new one.
app.SetProcessProposal(blockProposalHandler.ProcessProposalHandler())
})

blockSTMEnabled := cast.ToString(appOpts.Get(srvflags.EVMBlockExecutor)) == "block-stm"

homePath := cast.ToString(appOpts.Get(flags.FlagHome))
var cacheSize int
if !blockSTMEnabled {
// only enable memiavl cache if block-stm is not enabled, because it's not concurrency-safe.
Expand All @@ -399,16 +450,17 @@ func New(

invCheckPeriod := cast.ToUint(appOpts.Get(server.FlagInvCheckPeriod))
app := &App{
BaseApp: bApp,
cdc: cdc,
txConfig: txConfig,
appCodec: appCodec,
interfaceRegistry: interfaceRegistry,
invCheckPeriod: invCheckPeriod,
keys: keys,
tkeys: tkeys,
okeys: okeys,
memKeys: memKeys,
BaseApp: bApp,
cdc: cdc,
txConfig: txConfig,
appCodec: appCodec,
interfaceRegistry: interfaceRegistry,
invCheckPeriod: invCheckPeriod,
keys: keys,
tkeys: tkeys,
okeys: okeys,
memKeys: memKeys,
blockProposalHandler: blockProposalHandler,
}

app.SetDisableBlockGasMeter(true)
Expand Down Expand Up @@ -449,7 +501,7 @@ func New(
runtime.NewKVStoreService(keys[authtypes.StoreKey]),
ethermint.ProtoAccount,
maccPerms,
authcodec.NewBech32Codec(sdk.GetConfig().GetBech32AccountAddrPrefix()),
addressCodec,
sdk.GetConfig().GetBech32AccountAddrPrefix(),
authAddr,
)
Expand Down Expand Up @@ -976,6 +1028,15 @@ func New(
tmos.Exit(fmt.Sprintf("versiondb version %d lag behind iavl version %d", v1, v2))
}
}

if err := app.RefreshBlockList(app.NewUncachedContext(false, cmtproto.Header{})); err != nil {
if !cast.ToBool(appOpts.Get(FlagUnsafeIgnoreBlockListFailure)) {
panic(err)
}

// otherwise, just emit error log
app.Logger().Error("failed to update blocklist", "error", err)
}
}

app.ScopedIBCKeeper = scopedIBCKeeper
Expand Down Expand Up @@ -1025,7 +1086,7 @@ func (app *App) setAnteHandler(txConfig client.TxConfig, maxGasWanted uint64, bl
return fmt.Errorf("invalid bech32 address: %s, err: %w", str, err)
}

blockedMap[string(addr)] = struct{}{}
blockedMap[addr.String()] = struct{}{}
}
blockAddressDecorator := NewBlockAddressesDecorator(blockedMap)
options := evmante.HandlerOptions{
Expand Down Expand Up @@ -1085,7 +1146,16 @@ func (app *App) BeginBlocker(ctx sdk.Context) (sdk.BeginBlock, error) {

// EndBlocker application updates every end block
func (app *App) EndBlocker(ctx sdk.Context) (sdk.EndBlock, error) {
return app.ModuleManager.EndBlock(ctx)
rsp, err := app.ModuleManager.EndBlock(ctx)
if err := app.RefreshBlockList(ctx); err != nil {
app.Logger().Error("failed to update blocklist", "error", err)
}
return rsp, err
}

func (app *App) RefreshBlockList(ctx sdk.Context) error {
// refresh blocklist
return app.blockProposalHandler.SetBlockList(app.CronosKeeper.GetBlockList(ctx))
}
yihuang marked this conversation as resolved.
Show resolved Hide resolved

// InitChainer application update at chain initialization
Expand Down
2 changes: 1 addition & 1 deletion app/block_address.go
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,7 @@
return ctx, err
}
for _, signer := range signers {
if _, ok := bad.blockedMap[string(signer)]; ok {
if _, ok := bad.blockedMap[sdk.AccAddress(signer).String()]; ok {

Check warning on line 29 in app/block_address.go

View check run for this annotation

Codecov / codecov/patch

app/block_address.go#L29

Added line #L29 was not covered by tests
return ctx, fmt.Errorf("signer is blocked: %s", sdk.AccAddress(signer).String())
}
}
Expand Down
172 changes: 172 additions & 0 deletions app/proposal.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,172 @@
package app

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

"filippo.io/age"

"cosmossdk.io/core/address"
abci "github.com/cometbft/cometbft/abci/types"
"github.com/cosmos/cosmos-sdk/baseapp"
sdk "github.com/cosmos/cosmos-sdk/types"
"github.com/cosmos/cosmos-sdk/x/auth/signing"
)

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

var _ baseapp.TxSelector = &ExtTxSelector{}

// ExtTxSelector extends a baseapp.TxSelector with extra tx validation method
type ExtTxSelector struct {
baseapp.TxSelector
TxDecoder sdk.TxDecoder
ValidateTx func(sdk.Tx) error
}

func NewExtTxSelector(parent baseapp.TxSelector, txDecoder sdk.TxDecoder, validateTx func(sdk.Tx) error) *ExtTxSelector {
return &ExtTxSelector{
TxSelector: parent,
TxDecoder: txDecoder,
ValidateTx: validateTx,
}
}

func (ts *ExtTxSelector) SelectTxForProposal(ctx context.Context, maxTxBytes, maxBlockGas uint64, memTx sdk.Tx, txBz []byte, gasWanted uint64) bool {
var err error
if memTx == nil {
memTx, err = ts.TxDecoder(txBz)
if err != nil {
return false

Check warning on line 45 in app/proposal.go

View check run for this annotation

Codecov / codecov/patch

app/proposal.go#L40-L45

Added lines #L40 - L45 were not covered by tests
}
}

if err := ts.ValidateTx(memTx); err != nil {
return false

Check warning on line 50 in app/proposal.go

View check run for this annotation

Codecov / codecov/patch

app/proposal.go#L49-L50

Added lines #L49 - L50 were not covered by tests
}

// don't pass `memTx` to parent selector so it don't check tx gas wanted against block gas limit,
// it conflicts with the max-tx-gas-wanted logic.
return ts.TxSelector.SelectTxForProposal(ctx, maxTxBytes, maxBlockGas, nil, txBz, gasWanted)

Check warning on line 55 in app/proposal.go

View check run for this annotation

Codecov / codecov/patch

app/proposal.go#L55

Added line #L55 was not covered by tests
}

type ProposalHandler struct {
TxDecoder sdk.TxDecoder
// Identity is nil if it's not a validator node
Identity age.Identity
blocklist map[string]struct{}
lastBlockList []byte
addressCodec address.Codec
}

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

// SetBlockList don't fail if the identity is not set or the block list is empty.
func (h *ProposalHandler) SetBlockList(blob []byte) error {
if h.Identity == nil {
return nil
}

if bytes.Equal(h.lastBlockList, blob) {
return nil
}
h.lastBlockList = make([]byte, len(blob))
copy(h.lastBlockList, blob)

Check warning on line 86 in app/proposal.go

View check run for this annotation

Codecov / codecov/patch

app/proposal.go#L85-L86

Added lines #L85 - L86 were not covered by tests

if len(blob) == 0 {
h.blocklist = make(map[string]struct{})
return nil

Check warning on line 90 in app/proposal.go

View check run for this annotation

Codecov / codecov/patch

app/proposal.go#L88-L90

Added lines #L88 - L90 were not covered by tests
}

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

Check warning on line 95 in app/proposal.go

View check run for this annotation

Codecov / codecov/patch

app/proposal.go#L93-L95

Added lines #L93 - L95 were not covered by tests
}

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

Check warning on line 100 in app/proposal.go

View check run for this annotation

Codecov / codecov/patch

app/proposal.go#L98-L100

Added lines #L98 - L100 were not covered by tests
}

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

Check warning on line 105 in app/proposal.go

View check run for this annotation

Codecov / codecov/patch

app/proposal.go#L103-L105

Added lines #L103 - L105 were not covered by tests
}

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

Check warning on line 113 in app/proposal.go

View check run for this annotation

Codecov / codecov/patch

app/proposal.go#L109-L113

Added lines #L109 - L113 were not covered by tests
}
encoded, err := h.addressCodec.BytesToString(addr)
if err != nil {
return fmt.Errorf("invalid bech32 address: %s, err: %w", s, err)

Check warning on line 117 in app/proposal.go

View check run for this annotation

Codecov / codecov/patch

app/proposal.go#L115-L117

Added lines #L115 - L117 were not covered by tests
}
m[encoded] = struct{}{}

Check warning on line 119 in app/proposal.go

View check run for this annotation

Codecov / codecov/patch

app/proposal.go#L119

Added line #L119 was not covered by tests
}

h.blocklist = m
return nil

Check warning on line 123 in app/proposal.go

View check run for this annotation

Codecov / codecov/patch

app/proposal.go#L122-L123

Added lines #L122 - L123 were not covered by tests
}

func (h *ProposalHandler) ValidateTransaction(tx sdk.Tx) error {
sigTx, ok := tx.(signing.SigVerifiableTx)
if !ok {
return fmt.Errorf("tx of type %T does not implement SigVerifiableTx", tx)

Check warning on line 129 in app/proposal.go

View check run for this annotation

Codecov / codecov/patch

app/proposal.go#L126-L129

Added lines #L126 - L129 were not covered by tests
}

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

Check warning on line 134 in app/proposal.go

View check run for this annotation

Codecov / codecov/patch

app/proposal.go#L132-L134

Added lines #L132 - L134 were not covered by tests
}
for _, signer := range signers {
encoded, err := h.addressCodec.BytesToString(signer)
if err != nil {
return fmt.Errorf("invalid bech32 address: %s, err: %w", signer, err)

Check warning on line 139 in app/proposal.go

View check run for this annotation

Codecov / codecov/patch

app/proposal.go#L136-L139

Added lines #L136 - L139 were not covered by tests
yihuang marked this conversation as resolved.
Show resolved Hide resolved
}
if _, ok := h.blocklist[encoded]; ok {
return fmt.Errorf("signer is blocked: %s", encoded)

Check warning on line 142 in app/proposal.go

View check run for this annotation

Codecov / codecov/patch

app/proposal.go#L141-L142

Added lines #L141 - L142 were not covered by tests
}
}
return nil

Check warning on line 145 in app/proposal.go

View check run for this annotation

Codecov / codecov/patch

app/proposal.go#L145

Added line #L145 was not covered by tests
}

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

Check warning on line 153 in app/proposal.go

View check run for this annotation

Codecov / codecov/patch

app/proposal.go#L150-L153

Added lines #L150 - L153 were not covered by tests
}

if err := h.ValidateTransaction(memTx); err != nil {
return &abci.ResponseProcessProposal{Status: abci.ResponseProcessProposal_REJECT}, nil

Check warning on line 157 in app/proposal.go

View check run for this annotation

Codecov / codecov/patch

app/proposal.go#L156-L157

Added lines #L156 - L157 were not covered by tests
}
}

return &abci.ResponseProcessProposal{Status: abci.ResponseProcessProposal_ACCEPT}, nil

Check warning on line 161 in app/proposal.go

View check run for this annotation

Codecov / codecov/patch

app/proposal.go#L161

Added line #L161 was not covered by tests
}
}

// noneIdentity is a dummy identity which postpone the failure to the decryption time
type noneIdentity struct{}

var _ age.Identity = noneIdentity{}

func (noneIdentity) Unwrap([]*age.Stanza) ([]byte, error) {
return nil, age.ErrIncorrectIdentity

Check warning on line 171 in app/proposal.go

View check run for this annotation

Codecov / codecov/patch

app/proposal.go#L170-L171

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