From adebbc06efa4e3d162e763cca61e536bf4c1e677 Mon Sep 17 00:00:00 2001 From: Facundo Date: Mon, 9 Dec 2024 18:41:36 +0100 Subject: [PATCH 1/2] progress --- server/v2/cometbft/abci.go | 2 +- server/v2/cometbft/handlers/defaults.go | 2 +- server/v2/cometbft/handlers/handlers.go | 4 ++-- server/v2/cometbft/options.go | 2 +- 4 files changed, 5 insertions(+), 5 deletions(-) diff --git a/server/v2/cometbft/abci.go b/server/v2/cometbft/abci.go index c376f4ac2690..e8fd297b2f97 100644 --- a/server/v2/cometbft/abci.go +++ b/server/v2/cometbft/abci.go @@ -74,7 +74,7 @@ type consensus[T transaction.Tx] struct { prepareProposalHandler handlers.PrepareHandler[T] processProposalHandler handlers.ProcessHandler[T] - verifyVoteExt handlers.VerifyVoteExtensionhandler + verifyVoteExt handlers.VerifyVoteExtensionHandler extendVote handlers.ExtendVoteHandler checkTxHandler handlers.CheckTxHandler[T] diff --git a/server/v2/cometbft/handlers/defaults.go b/server/v2/cometbft/handlers/defaults.go index d8f43bb2fd25..e9f90eecb1ca 100644 --- a/server/v2/cometbft/handlers/defaults.go +++ b/server/v2/cometbft/handlers/defaults.go @@ -197,7 +197,7 @@ func NoOpExtendVote() ExtendVoteHandler { // NoOpVerifyVoteExtensionHandler defines a no-op VerifyVoteExtension handler. It // will always return an ACCEPT status with no error. -func NoOpVerifyVoteExtensionHandler() VerifyVoteExtensionhandler { +func NoOpVerifyVoteExtensionHandler() VerifyVoteExtensionHandler { return func(context.Context, store.ReaderMap, *abci.VerifyVoteExtensionRequest) (*abci.VerifyVoteExtensionResponse, error) { return &abci.VerifyVoteExtensionResponse{Status: abci.VERIFY_VOTE_EXTENSION_STATUS_ACCEPT}, nil } diff --git a/server/v2/cometbft/handlers/handlers.go b/server/v2/cometbft/handlers/handlers.go index 015594f469f7..aa420da63389 100644 --- a/server/v2/cometbft/handlers/handlers.go +++ b/server/v2/cometbft/handlers/handlers.go @@ -19,10 +19,10 @@ type ( // If the verification of a transaction fails, the boolean is false and the error is non-nil. ProcessHandler[T transaction.Tx] func(context.Context, AppManager[T], transaction.Codec[T], *abci.ProcessProposalRequest) error - // VerifyVoteExtensionhandler is a function type that handles the verification of a vote extension request. + // VerifyVoteExtensionHandler is a function type that handles the verification of a vote extension request. // It takes a context, a store reader map, and a request to verify a vote extension. // It returns a response to verify the vote extension and an error if any. - VerifyVoteExtensionhandler func(context.Context, store.ReaderMap, *abci.VerifyVoteExtensionRequest) (*abci.VerifyVoteExtensionResponse, error) + VerifyVoteExtensionHandler func(context.Context, store.ReaderMap, *abci.VerifyVoteExtensionRequest) (*abci.VerifyVoteExtensionResponse, error) // ExtendVoteHandler is a function type that handles the extension of a vote. // It takes a context, a store reader map, and a request to extend a vote. diff --git a/server/v2/cometbft/options.go b/server/v2/cometbft/options.go index b5936148b5a5..5016495461e3 100644 --- a/server/v2/cometbft/options.go +++ b/server/v2/cometbft/options.go @@ -20,7 +20,7 @@ type ServerOptions[T transaction.Tx] struct { PrepareProposalHandler handlers.PrepareHandler[T] ProcessProposalHandler handlers.ProcessHandler[T] CheckTxHandler handlers.CheckTxHandler[T] - VerifyVoteExtensionHandler handlers.VerifyVoteExtensionhandler + VerifyVoteExtensionHandler handlers.VerifyVoteExtensionHandler ExtendVoteHandler handlers.ExtendVoteHandler KeygenF keyGenF From 79efd34cf886bd24385b79852f0bcaba4216919a Mon Sep 17 00:00:00 2001 From: Facundo Date: Wed, 11 Dec 2024 14:29:42 +0100 Subject: [PATCH 2/2] kind of working --- runtime/v2/builder.go | 25 ++++++++++++++++++++- server/v2/cometbft/abci.go | 2 ++ server/v2/cometbft/utils.go | 31 +++++++++++++++++++++++++ simapp/v2/app_di.go | 8 ++++++- simapp/v2/go.mod | 2 ++ simapp/v2/simdv2/cmd/config.go | 41 ++++++++++++++++++++++++++++++++++ x/auth/tx/gogotx.go | 7 ++---- 7 files changed, 109 insertions(+), 7 deletions(-) diff --git a/runtime/v2/builder.go b/runtime/v2/builder.go index 631ac550c0c6..e04424a65c5f 100644 --- a/runtime/v2/builder.go +++ b/runtime/v2/builder.go @@ -30,6 +30,7 @@ type AppBuilder[T transaction.Tx] struct { branch func(state store.ReaderMap) store.WriterMap txValidator func(ctx context.Context, tx T) error postTxExec func(ctx context.Context, tx T, success bool) error + preblocker func(ctx context.Context, txs []T) error } // RegisterModules registers the provided modules with the module manager. @@ -95,11 +96,23 @@ func (a *AppBuilder[T]) Build(opts ...AppBuilderOption[T]) (*App[T], error) { endBlocker, valUpdate := a.app.moduleManager.EndBlock() + preblockerFn := func(ctx context.Context, txs []T) error { + if err := a.app.moduleManager.PreBlocker()(ctx, txs); err != nil { + return err + } + + if a.preblocker != nil { + return a.preblocker(ctx, txs) + } + + return nil + } + stf, err := stf.New[T]( a.app.logger.With("module", "stf"), a.app.msgRouterBuilder, a.app.queryRouterBuilder, - a.app.moduleManager.PreBlocker(), + preblockerFn, a.app.moduleManager.BeginBlock(), endBlocker, a.txValidator, @@ -219,3 +232,13 @@ func AppBuilderWithPostTxExec[T transaction.Tx]( a.postTxExec = postTxExec } } + +func AppBuilderWithPreblocker[T transaction.Tx]( + preblocker func( + ctx context.Context, txs []T, + ) error, +) AppBuilderOption[T] { + return func(a *AppBuilder[T]) { + a.preblocker = preblocker + } +} diff --git a/server/v2/cometbft/abci.go b/server/v2/cometbft/abci.go index 79eb8863d223..a87650843961 100644 --- a/server/v2/cometbft/abci.go +++ b/server/v2/cometbft/abci.go @@ -730,6 +730,8 @@ func decodeTxs[T transaction.Tx](logger log.Logger, rawTxs [][]byte, codec trans if err != nil { // do not return an error here, as we want to deliver the block even if some txs are invalid logger.Debug("failed to decode tx", "err", err) + txs[i] = RawTx(rawTx).(T) // allows getting the raw bytes down the line + continue } txs[i] = tx } diff --git a/server/v2/cometbft/utils.go b/server/v2/cometbft/utils.go index 81d47b7f8cb8..a06d97ba6cd9 100644 --- a/server/v2/cometbft/utils.go +++ b/server/v2/cometbft/utils.go @@ -2,6 +2,7 @@ package cometbft import ( "context" + "crypto/sha256" "errors" "fmt" "math" @@ -442,3 +443,33 @@ func uint64ToInt64(u uint64) int64 { } return int64(u) } + +// RawTx allows access to the raw bytes of a transaction even if it failed +// to decode. +func RawTx(tx []byte) transaction.Tx { + return InjectedTx(tx) +} + +type InjectedTx []byte + +var _ transaction.Tx = InjectedTx{} + +func (tx InjectedTx) Bytes() []byte { + return tx +} + +func (tx InjectedTx) Hash() [32]byte { + return sha256.Sum256(tx) +} + +func (tx InjectedTx) GetGasLimit() (uint64, error) { + return 0, nil +} + +func (tx InjectedTx) GetMessages() ([]transaction.Msg, error) { + return nil, nil +} + +func (tx InjectedTx) GetSenders() ([]transaction.Identity, error) { + return [][]byte{[]byte("cometbft")}, nil +} diff --git a/simapp/v2/app_di.go b/simapp/v2/app_di.go index bd0a39472a1c..b2566608ff4b 100644 --- a/simapp/v2/app_di.go +++ b/simapp/v2/app_di.go @@ -1,6 +1,7 @@ package simapp import ( + "context" _ "embed" "fmt" @@ -157,7 +158,12 @@ func NewSimApp[T transaction.Tx]( } var err error - app.App, err = appBuilder.Build() + app.App, err = appBuilder.Build(runtime.AppBuilderWithPreblocker( + func(ctx context.Context, txs []T) error { + fmt.Println("Preblocker!!!", txs) + return nil + }, + )) if err != nil { return nil, err } diff --git a/simapp/v2/go.mod b/simapp/v2/go.mod index d29decad721d..72a81daa94c8 100644 --- a/simapp/v2/go.mod +++ b/simapp/v2/go.mod @@ -279,6 +279,7 @@ replace ( cosmossdk.io/x/slashing => ../../x/slashing cosmossdk.io/x/staking => ../../x/staking cosmossdk.io/x/tx => ../../x/tx + cosmossdk.io/x/auth => ../../x/auth cosmossdk.io/x/upgrade => ../../x/upgrade ) @@ -299,6 +300,7 @@ replace ( replace ( cosmossdk.io/api => ../../api cosmossdk.io/core/testing => ../../core/testing + cosmossdk.io/core => ../../core cosmossdk.io/indexer/postgres => ../../indexer/postgres cosmossdk.io/runtime/v2 => ../../runtime/v2 cosmossdk.io/schema => ../../schema diff --git a/simapp/v2/simdv2/cmd/config.go b/simapp/v2/simdv2/cmd/config.go index 96325705b380..05cd7977a384 100644 --- a/simapp/v2/simdv2/cmd/config.go +++ b/simapp/v2/simdv2/cmd/config.go @@ -1,14 +1,19 @@ package cmd import ( + "context" + "fmt" "strings" "time" + v1 "github.com/cometbft/cometbft/api/cometbft/abci/v1" cmtcfg "github.com/cometbft/cometbft/config" + "cosmossdk.io/core/store" "cosmossdk.io/core/transaction" serverv2 "cosmossdk.io/server/v2" "cosmossdk.io/server/v2/cometbft" + "cosmossdk.io/server/v2/cometbft/handlers" clientconfig "github.com/cosmos/cosmos-sdk/client/config" "github.com/cosmos/cosmos-sdk/crypto/keyring" @@ -92,6 +97,8 @@ func initCometConfig() cometbft.CfgOption { func initCometOptions[T transaction.Tx]() cometbft.ServerOptions[T] { serverOptions := cometbft.DefaultServerOptions[T]() + serverOptions.PrepareProposalHandler = CustomPrepareProposal[T]() + serverOptions.ExtendVoteHandler = CustomExtendVoteHandler[T]() // overwrite app mempool, using max-txs option // serverOptions.Mempool = func(cfg map[string]any) mempool.Mempool[T] { @@ -106,3 +113,37 @@ func initCometOptions[T transaction.Tx]() cometbft.ServerOptions[T] { return serverOptions } + +func CustomExtendVoteHandler[T transaction.Tx]() handlers.ExtendVoteHandler { + return func(ctx context.Context, rm store.ReaderMap, evr *v1.ExtendVoteRequest) (*v1.ExtendVoteResponse, error) { + return &v1.ExtendVoteResponse{ + VoteExtension: []byte("BTC=1234567.89;height=" + fmt.Sprint(evr.Height)), + }, nil + } +} + +func CustomPrepareProposal[T transaction.Tx]() handlers.PrepareHandler[T] { + return func(ctx context.Context, app handlers.AppManager[T], codec transaction.Codec[T], req *v1.PrepareProposalRequest) ([]T, error) { + var txs []T + for _, tx := range req.Txs { + decTx, err := codec.Decode(tx) + if err != nil { + continue + } + + txs = append(txs, decTx) + } + + // Process vote extensions + injectedTx := []byte{} + for _, vote := range req.LocalLastCommit.Votes { + // TODO: add signature verification + injectedTx = append(injectedTx, vote.VoteExtension...) + } + + // put the injected tx into the first position + txs = append([]T{cometbft.RawTx(injectedTx).(T)}, txs...) + + return txs, nil + } +} diff --git a/x/auth/tx/gogotx.go b/x/auth/tx/gogotx.go index aa424f1c991f..1a386eb34ffd 100644 --- a/x/auth/tx/gogotx.go +++ b/x/auth/tx/gogotx.go @@ -32,7 +32,7 @@ func newWrapperFromDecodedTx( addrCodec address.Codec, cdc codec.BinaryCodec, decodedTx *decode.DecodedTx, ) (*gogoTxWrapper, error) { var ( - fees = make(sdk.Coins, len(decodedTx.Tx.AuthInfo.Fee.Amount)) + fees = sdk.Coins{} // decodedTx.Tx.AuthInfo.Fee.Amount might be nil err error ) for i, fee := range decodedTx.Tx.AuthInfo.Fee.Amount { @@ -43,10 +43,7 @@ func newWrapperFromDecodedTx( if err = sdk.ValidateDenom(fee.Denom); err != nil { return nil, fmt.Errorf("invalid fee coin denom at index %d: %w", i, err) } - fees[i] = sdk.Coin{ - Denom: fee.Denom, - Amount: amtInt, - } + fees.Add(sdk.NewCoin(fee.Denom, amtInt)) } if !fees.IsSorted() { return nil, fmt.Errorf("invalid not sorted tx fees: %s", fees.String())