diff --git a/.spelling b/.spelling index 533d210b07..774f3fadab 100644 --- a/.spelling +++ b/.spelling @@ -23,6 +23,7 @@ cleanup Cleanup clef codegen +cometbft config cyclomatic dApp diff --git a/CHANGELOG.md b/CHANGELOG.md index 3e6adfd9fc..4b7eaddfe4 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -44,6 +44,7 @@ ### 🛠Improvements +- [8051](https://github.com/vegaprotocol/vega/issues/8051) - Upgrade to comet `0.38.0` - [9484](https://github.com/vegaprotocol/vega/issues/9484) - Remove network parameters that only provide defaults for market liquidity settings. - [8718](https://github.com/vegaprotocol/vega/issues/8718) - Emit market data event after setting mark price prior to final settlement. - [8590](https://github.com/vegaprotocol/vega/issues/8590) - Improved Ethereum oracle support. diff --git a/blockexplorer/entities/transaction.go b/blockexplorer/entities/transaction.go index 89e63b8faf..c39f850d80 100644 --- a/blockexplorer/entities/transaction.go +++ b/blockexplorer/entities/transaction.go @@ -26,7 +26,7 @@ import ( pb "code.vegaprotocol.io/vega/protos/blockexplorer/api/v1" commandspb "code.vegaprotocol.io/vega/protos/vega/commands/v1" - tmTypes "github.com/tendermint/tendermint/abci/types" + tmTypes "github.com/cometbft/cometbft/abci/types" "google.golang.org/protobuf/proto" ) @@ -92,8 +92,8 @@ func extractAttribute(r *tmTypes.TxResult, eType, key string) string { for _, e := range r.Result.Events { if e.Type == eType { for _, a := range e.Attributes { - if string(a.Key) == key { - return string(a.Value) + if a.Key == key { + return a.Value } } } diff --git a/blockexplorer/store/transactions_test.go b/blockexplorer/store/transactions_test.go index fc1a581111..0b402adab5 100644 --- a/blockexplorer/store/transactions_test.go +++ b/blockexplorer/store/transactions_test.go @@ -33,10 +33,10 @@ import ( pb "code.vegaprotocol.io/vega/protos/blockexplorer/api/v1" "github.com/cenkalti/backoff" + tmTypes "github.com/cometbft/cometbft/abci/types" "github.com/jackc/pgx/v4" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" - tmTypes "github.com/tendermint/tendermint/abci/types" ) var ( diff --git a/cmd/vega/commands/genesis/generate.go b/cmd/vega/commands/genesis/generate.go index 1418ea8cc6..6b9f45488e 100644 --- a/cmd/vega/commands/genesis/generate.go +++ b/cmd/vega/commands/genesis/generate.go @@ -28,8 +28,8 @@ import ( "code.vegaprotocol.io/vega/logging" "code.vegaprotocol.io/vega/paths" + tmtypes "github.com/cometbft/cometbft/types" "github.com/jessevdk/go-flags" - tmtypes "github.com/tendermint/tendermint/types" ) type generateCmd struct { diff --git a/cmd/vega/commands/genesis/load_checkpoint.go b/cmd/vega/commands/genesis/load_checkpoint.go index d8642d3512..cf92d54ea3 100644 --- a/cmd/vega/commands/genesis/load_checkpoint.go +++ b/cmd/vega/commands/genesis/load_checkpoint.go @@ -31,9 +31,9 @@ import ( vgfs "code.vegaprotocol.io/vega/libs/fs" "code.vegaprotocol.io/vega/logging" + tmjson "github.com/cometbft/cometbft/libs/json" + tmtypes "github.com/cometbft/cometbft/types" "github.com/jessevdk/go-flags" - tmjson "github.com/tendermint/tendermint/libs/json" - tmtypes "github.com/tendermint/tendermint/types" ) type loadCheckpointCmd struct { diff --git a/cmd/vega/commands/genesis/new_validator.go b/cmd/vega/commands/genesis/new_validator.go index 6d9079063f..01c7418261 100644 --- a/cmd/vega/commands/genesis/new_validator.go +++ b/cmd/vega/commands/genesis/new_validator.go @@ -27,9 +27,9 @@ import ( "code.vegaprotocol.io/vega/logging" "code.vegaprotocol.io/vega/paths" + tmjson "github.com/cometbft/cometbft/libs/json" + tmtypes "github.com/cometbft/cometbft/types" "github.com/jessevdk/go-flags" - tmjson "github.com/tendermint/tendermint/libs/json" - tmtypes "github.com/tendermint/tendermint/types" ) var ErrAppendAndReplaceAreMutuallyExclusive = errors.New("--append and --replace and mutually exclusive") diff --git a/cmd/vega/commands/init.go b/cmd/vega/commands/init.go index af038b9c8d..1e9537ad75 100644 --- a/cmd/vega/commands/init.go +++ b/cmd/vega/commands/init.go @@ -29,13 +29,13 @@ import ( "code.vegaprotocol.io/vega/logging" "code.vegaprotocol.io/vega/paths" + tmcfg "github.com/cometbft/cometbft/config" + tmos "github.com/cometbft/cometbft/libs/os" + tmrand "github.com/cometbft/cometbft/libs/rand" + "github.com/cometbft/cometbft/p2p" + "github.com/cometbft/cometbft/privval" + "github.com/cometbft/cometbft/types" "github.com/jessevdk/go-flags" - tmcfg "github.com/tendermint/tendermint/config" - tmos "github.com/tendermint/tendermint/libs/os" - tmrand "github.com/tendermint/tendermint/libs/rand" - "github.com/tendermint/tendermint/p2p" - "github.com/tendermint/tendermint/privval" - "github.com/tendermint/tendermint/types" ) type InitCmd struct { diff --git a/cmd/vega/commands/node/app_wrapper.go b/cmd/vega/commands/node/app_wrapper.go index aa3d9caee0..8b9af75730 100644 --- a/cmd/vega/commands/node/app_wrapper.go +++ b/cmd/vega/commands/node/app_wrapper.go @@ -15,7 +15,11 @@ package node -import "github.com/tendermint/tendermint/abci/types" +import ( + "context" + + "github.com/cometbft/cometbft/abci/types" +) type appW struct { // this is the application currently in use @@ -32,71 +36,65 @@ func newAppW(app types.Application) *appW { } } -func (app *appW) Info(req types.RequestInfo) types.ResponseInfo { - return app.impl.Info(req) -} - -func (app *appW) DeliverTx(req types.RequestDeliverTx) types.ResponseDeliverTx { - return app.impl.DeliverTx(req) +func (app *appW) Info(ctx context.Context, req *types.RequestInfo) (*types.ResponseInfo, error) { + return app.impl.Info(ctx, req) } -func (app *appW) CheckTx(req types.RequestCheckTx) types.ResponseCheckTx { - return app.impl.CheckTx(req) +func (app *appW) CheckTx(ctx context.Context, req *types.RequestCheckTx) (*types.ResponseCheckTx, error) { + return app.impl.CheckTx(ctx, req) } -func (app *appW) Commit() types.ResponseCommit { - resp := app.impl.Commit() +func (app *appW) Commit(ctx context.Context, req *types.RequestCommit) (*types.ResponseCommit, error) { + resp, err := app.impl.Commit(ctx, req) // if we are scheduled for an upgrade of the protocol // let's do it now. if app.update != nil { app.impl = app.update app.update = nil } - return resp + return resp, err +} + +func (app *appW) Query(ctx context.Context, req *types.RequestQuery) (*types.ResponseQuery, error) { + return app.impl.Query(ctx, req) +} + +func (app *appW) InitChain(ctx context.Context, req *types.RequestInitChain) (*types.ResponseInitChain, error) { + return app.impl.InitChain(ctx, req) } -func (app *appW) Query(req types.RequestQuery) types.ResponseQuery { - return app.impl.Query(req) +func (app *appW) ListSnapshots(ctx context.Context, req *types.RequestListSnapshots) (*types.ResponseListSnapshots, error) { + return app.impl.ListSnapshots(ctx, req) } -func (app *appW) InitChain(req types.RequestInitChain) types.ResponseInitChain { - return app.impl.InitChain(req) +func (app *appW) OfferSnapshot(ctx context.Context, req *types.RequestOfferSnapshot) (*types.ResponseOfferSnapshot, error) { + return app.impl.OfferSnapshot(ctx, req) } -func (app *appW) BeginBlock(req types.RequestBeginBlock) types.ResponseBeginBlock { - return app.impl.BeginBlock(req) +func (app *appW) LoadSnapshotChunk(ctx context.Context, req *types.RequestLoadSnapshotChunk) (*types.ResponseLoadSnapshotChunk, error) { + return app.impl.LoadSnapshotChunk(ctx, req) } -func (app *appW) EndBlock(req types.RequestEndBlock) types.ResponseEndBlock { - return app.impl.EndBlock(req) +func (app *appW) ApplySnapshotChunk(ctx context.Context, req *types.RequestApplySnapshotChunk) (*types.ResponseApplySnapshotChunk, error) { + return app.impl.ApplySnapshotChunk(ctx, req) } -func (app *appW) ListSnapshots( - req types.RequestListSnapshots, -) types.ResponseListSnapshots { - return app.impl.ListSnapshots(req) +func (app *appW) PrepareProposal(ctx context.Context, proposal *types.RequestPrepareProposal) (*types.ResponsePrepareProposal, error) { + return app.impl.PrepareProposal(ctx, proposal) } -func (app *appW) OfferSnapshot( - req types.RequestOfferSnapshot, -) types.ResponseOfferSnapshot { - return app.impl.OfferSnapshot(req) +func (app *appW) ProcessProposal(ctx context.Context, proposal *types.RequestProcessProposal) (*types.ResponseProcessProposal, error) { + return app.impl.ProcessProposal(ctx, proposal) } -func (app *appW) LoadSnapshotChunk( - req types.RequestLoadSnapshotChunk, -) types.ResponseLoadSnapshotChunk { - return app.impl.LoadSnapshotChunk(req) +func (app *appW) FinalizeBlock(ctx context.Context, req *types.RequestFinalizeBlock) (*types.ResponseFinalizeBlock, error) { + return app.impl.FinalizeBlock(ctx, req) } -func (app *appW) ApplySnapshotChunk( - req types.RequestApplySnapshotChunk, -) types.ResponseApplySnapshotChunk { - return app.impl.ApplySnapshotChunk(req) +func (app *appW) ExtendVote(ctx context.Context, req *types.RequestExtendVote) (*types.ResponseExtendVote, error) { + return app.impl.ExtendVote(ctx, req) } -func (app *appW) SetOption( - req types.RequestSetOption, -) types.ResponseSetOption { - return app.impl.SetOption(req) +func (app *appW) VerifyVoteExtension(ctx context.Context, req *types.RequestVerifyVoteExtension) (*types.ResponseVerifyVoteExtension, error) { + return app.impl.VerifyVoteExtension(ctx, req) } diff --git a/cmd/vega/commands/node/fetch_genesis.go b/cmd/vega/commands/node/fetch_genesis.go index c029613970..b186e35040 100644 --- a/cmd/vega/commands/node/fetch_genesis.go +++ b/cmd/vega/commands/node/fetch_genesis.go @@ -24,7 +24,7 @@ import ( "code.vegaprotocol.io/vega/core/genesis" - tmtypes "github.com/tendermint/tendermint/types" + tmtypes "github.com/cometbft/cometbft/types" ) func genesisDocHTTPFromURL(genesisFilePath string) (*tmtypes.GenesisDoc, error) { diff --git a/cmd/vega/commands/node/node.go b/cmd/vega/commands/node/node.go index aedfcb11db..e490d5e3bd 100644 --- a/cmd/vega/commands/node/node.go +++ b/cmd/vega/commands/node/node.go @@ -42,8 +42,8 @@ import ( apipb "code.vegaprotocol.io/vega/protos/vega/api/v1" "code.vegaprotocol.io/vega/version" - "github.com/tendermint/tendermint/abci/types" - tmtypes "github.com/tendermint/tendermint/types" + "github.com/cometbft/cometbft/abci/types" + tmtypes "github.com/cometbft/cometbft/types" "google.golang.org/grpc" ) @@ -323,8 +323,7 @@ func (n *Command) startBlockchain(log *logging.Logger, tmHome, network, networkU if err != nil { return err } - // n.blockchainClient = blockchain.NewClient(client) - n.blockchainClient.Set(client) + n.blockchainClient.Set(client, n.tmNode.MempoolSize) case blockchain.ProviderNullChain: // nullchain acts as both the client and the server because its does everything n.nullBlockchain = nullchain.NewClient( @@ -335,7 +334,7 @@ func (n *Command) startBlockchain(log *logging.Logger, tmHome, network, networkU n.nullBlockchain.SetABCIApp(n.abciApp) n.blockchainServer = blockchain.NewServer(n.Log, n.nullBlockchain) // n.blockchainClient = blockchain.NewClient(n.nullBlockchain) - n.blockchainClient.Set(n.nullBlockchain) + n.blockchainClient.Set(n.nullBlockchain, 100*1024*1024) default: return ErrUnknownChainProvider diff --git a/cmd/vega/commands/nodewallet/import.go b/cmd/vega/commands/nodewallet/import.go index b9da4add8a..11d9a74e9a 100644 --- a/cmd/vega/commands/nodewallet/import.go +++ b/cmd/vega/commands/nodewallet/import.go @@ -28,8 +28,8 @@ import ( "code.vegaprotocol.io/vega/logging" "code.vegaprotocol.io/vega/paths" + tmconfig "github.com/cometbft/cometbft/config" "github.com/jessevdk/go-flags" - tmconfig "github.com/tendermint/tendermint/config" ) var ( diff --git a/cmd/vega/commands/tm.go b/cmd/vega/commands/tm.go index 97104a7e80..09af8abb89 100644 --- a/cmd/vega/commands/tm.go +++ b/cmd/vega/commands/tm.go @@ -20,11 +20,11 @@ import ( "os" "path/filepath" + tmcmd "github.com/cometbft/cometbft/cmd/cometbft/commands" + tmdebug "github.com/cometbft/cometbft/cmd/cometbft/commands/debug" + tmcfg "github.com/cometbft/cometbft/config" + tmcli "github.com/cometbft/cometbft/libs/cli" "github.com/jessevdk/go-flags" - tmcmd "github.com/tendermint/tendermint/cmd/cometbft/commands" - tmdebug "github.com/tendermint/tendermint/cmd/cometbft/commands/debug" - tmcfg "github.com/tendermint/tendermint/config" - tmcli "github.com/tendermint/tendermint/libs/cli" ) func Tm(_ context.Context, parser *flags.Parser) error { @@ -57,7 +57,6 @@ func (opts *tmCmd) Execute(_ []string) error { rootCmd.AddCommand( tmcmd.GenValidatorCmd, tmcmd.InitFilesCmd, - tmcmd.ProbeUpnpCmd, tmcmd.LightCmd, tmcmd.ReplayCmd, tmcmd.ReplayConsoleCmd, diff --git a/cmd/vega/commands/watch.go b/cmd/vega/commands/watch.go index 29b3e1f1be..9727ff07af 100644 --- a/cmd/vega/commands/watch.go +++ b/cmd/vega/commands/watch.go @@ -23,8 +23,8 @@ import ( "code.vegaprotocol.io/vega/core/blockchain/abci" + tmctypes "github.com/cometbft/cometbft/rpc/core/types" "github.com/jessevdk/go-flags" - tmctypes "github.com/tendermint/tendermint/rpc/core/types" ) type watch struct { diff --git a/cmd/vegatools/snapshot.go b/cmd/vegatools/snapshot.go index 0181d5aa79..be7a9ccbb7 100644 --- a/cmd/vegatools/snapshot.go +++ b/cmd/vegatools/snapshot.go @@ -24,10 +24,9 @@ import ( "code.vegaprotocol.io/vega/paths" "code.vegaprotocol.io/vega/vegatools/snapshotdb" + tmconfig "github.com/cometbft/cometbft/config" + "github.com/cometbft/cometbft/store" "github.com/spf13/viper" - tmconfig "github.com/tendermint/tendermint/config" - "github.com/tendermint/tendermint/node" - "github.com/tendermint/tendermint/store" ) type snapshotCmd struct { @@ -46,7 +45,7 @@ func getLastProcessedBlock(homeDir string) (int64, error) { conf.SetRoot(homeDir) // lets get the last processed block from tendermint - blockStoreDB, err := node.DefaultDBProvider(&node.DBContext{ID: "blockstore", Config: conf}) + blockStoreDB, err := tmconfig.DefaultDBProvider(&tmconfig.DBContext{ID: "blockstore", Config: conf}) if err != nil { return 0, err } diff --git a/core/api/core.go b/core/api/core.go index e1333cb7ef..c2e9aba9fc 100644 --- a/core/api/core.go +++ b/core/api/core.go @@ -40,9 +40,9 @@ import ( eventspb "code.vegaprotocol.io/vega/protos/vega/events/v1" "code.vegaprotocol.io/vega/wallet/crypto" + "github.com/cometbft/cometbft/libs/bytes" + tmctypes "github.com/cometbft/cometbft/rpc/core/types" "github.com/pkg/errors" - "github.com/tendermint/tendermint/libs/bytes" - tmctypes "github.com/tendermint/tendermint/rpc/core/types" "google.golang.org/grpc/codes" ) @@ -659,14 +659,14 @@ func (s *coreService) SubmitRawTransaction(ctx context.Context, req *protoapi.Su if txResult != nil { return &protoapi.SubmitRawTransactionResponse{ Success: false, - Code: txResult.DeliverTx.Code, - Data: string(txResult.DeliverTx.Data), - Log: txResult.DeliverTx.Log, + Code: txResult.TxResult.Code, + Data: string(txResult.TxResult.Data), + Log: txResult.TxResult.Log, }, s.handleSubmitRawTxTMError(err) } return nil, s.handleSubmitRawTxTMError(err) } - setResponseBasisContent(successResponse, txResult.DeliverTx.Code, txResult.DeliverTx.Log, txResult.DeliverTx.Data, txResult.Hash) + setResponseBasisContent(successResponse, txResult.TxResult.Code, txResult.TxResult.Log, txResult.TxResult.Data, txResult.Hash) successResponse.Height = txResult.Height default: diff --git a/core/api/grpc.go b/core/api/grpc.go index 4e60cc7dde..f4021ecc3b 100644 --- a/core/api/grpc.go +++ b/core/api/grpc.go @@ -31,7 +31,7 @@ import ( commandspb "code.vegaprotocol.io/vega/protos/vega/commands/v1" eventspb "code.vegaprotocol.io/vega/protos/vega/events/v1" - tmctypes "github.com/tendermint/tendermint/rpc/core/types" + tmctypes "github.com/cometbft/cometbft/rpc/core/types" "google.golang.org/grpc" "google.golang.org/grpc/metadata" "google.golang.org/grpc/peer" diff --git a/core/api/mocks/blockchain_mock.go b/core/api/mocks/blockchain_mock.go index 92b0e0daaf..e2119096ed 100644 --- a/core/api/mocks/blockchain_mock.go +++ b/core/api/mocks/blockchain_mock.go @@ -10,8 +10,8 @@ import ( time "time" v1 "code.vegaprotocol.io/vega/protos/vega/commands/v1" + coretypes "github.com/cometbft/cometbft/rpc/core/types" gomock "github.com/golang/mock/gomock" - coretypes "github.com/tendermint/tendermint/rpc/core/types" ) // MockBlockchain is a mock of Blockchain interface. diff --git a/core/blockchain/abci/abci.go b/core/blockchain/abci/abci.go index a8a4095d7f..56e7b55f86 100644 --- a/core/blockchain/abci/abci.go +++ b/core/blockchain/abci/abci.go @@ -16,23 +16,24 @@ package abci import ( + "context" "encoding/hex" - "errors" + "strconv" "code.vegaprotocol.io/vega/core/blockchain" vgcontext "code.vegaprotocol.io/vega/libs/context" - "github.com/tendermint/tendermint/abci/types" + "github.com/cometbft/cometbft/abci/types" ) -func (app *App) Info(req types.RequestInfo) types.ResponseInfo { +func (app *App) Info(ctx context.Context, req *types.RequestInfo) (*types.ResponseInfo, error) { if fn := app.OnInfo; fn != nil { - return fn(req) + return fn(ctx, req) } - return app.BaseApplication.Info(req) + return app.BaseApplication.Info(ctx, req) } -func (app *App) InitChain(req types.RequestInitChain) (resp types.ResponseInitChain) { +func (app *App) InitChain(_ context.Context, req *types.RequestInitChain) (*types.ResponseInitChain, error) { _, err := LoadGenesisState(req.AppStateBytes) if err != nil { panic(err) @@ -41,42 +42,81 @@ func (app *App) InitChain(req types.RequestInitChain) (resp types.ResponseInitCh if fn := app.OnInitChain; fn != nil { return fn(req) } - return + return &types.ResponseInitChain{}, nil } -func (app *App) BeginBlock(req types.RequestBeginBlock) (resp types.ResponseBeginBlock) { - if fn := app.OnBeginBlock; fn != nil { - app.ctx, resp = fn(req) +// PrepareProposal will take the given transactions from the mempool and attempts to prepare a +// proposal from them when it's our turn to do so while keeping the size, gas, pow, and spam constraints. +func (app *App) PrepareProposal(_ context.Context, req *types.RequestPrepareProposal) (*types.ResponsePrepareProposal, error) { + txs := make([]Tx, 0, len(req.Txs)) + rawTxs := make([][]byte, 0, len(req.Txs)) + for _, v := range req.Txs { + tx, _, err := app.getTx(v) + // ignore transactions we can't verify + if err != nil { + continue + } + // ignore transactions we don't know to handle + if _, ok := app.deliverTxs[tx.Command()]; !ok { + continue + } + txs = append(txs, tx) + rawTxs = append(rawTxs, v) } - return + + // let the application decide on the order and the number of transactions it wants to pick up for this block + res := &types.ResponsePrepareProposal{Txs: app.OnPrepareProposal(txs, rawTxs)} + return res, nil } -func (app *App) EndBlock(req types.RequestEndBlock) (resp types.ResponseEndBlock) { - if fn := app.OnEndBlock; fn != nil { - app.ctx, resp = fn(req) +// ProcessProposal implements part of the Application interface. +// It accepts any proposal that does not contain a malformed transaction. +// NB: processProposal will not be called if the node is fast-sync-ing so no state change is allowed here!!!. +func (app *App) ProcessProposal(_ context.Context, req *types.RequestProcessProposal) (*types.ResponseProcessProposal, error) { + // check transaction signatures if any is wrong, reject the block + txs := make([]Tx, 0, len(req.Txs)) + for _, v := range req.Txs { + tx, _, err := app.getTx(v) + if err != nil { + // if there's a transaction we can't decode or verify, reject it + return &types.ResponseProcessProposal{Status: types.ResponseProcessProposal_REJECT}, err + } + // if there's no handler for a transaction, reject it + if _, ok := app.deliverTxs[tx.Command()]; !ok { + return &types.ResponseProcessProposal{Status: types.ResponseProcessProposal_REJECT}, nil + } + txs = append(txs, tx) + } + // let the application verify the block + if !app.OnProcessProposal(txs) { + return &types.ResponseProcessProposal{Status: types.ResponseProcessProposal_REJECT}, nil } - return + return &types.ResponseProcessProposal{Status: types.ResponseProcessProposal_ACCEPT}, nil } -func (app *App) Commit() (resp types.ResponseCommit) { +func (app *App) Commit(_ context.Context, req *types.RequestCommit) (*types.ResponseCommit, error) { if fn := app.OnCommit; fn != nil { return fn() } - return + return &types.ResponseCommit{}, nil } -func (app *App) CheckTx(req types.RequestCheckTx) (resp types.ResponseCheckTx) { +func (app *App) CheckTx(_ context.Context, req *types.RequestCheckTx) (*types.ResponseCheckTx, error) { // first, only decode the transaction but don't validate tx, code, err := app.getTx(req.GetTx()) + + var resp *types.ResponseCheckTx if err != nil { - return blockchain.NewResponseCheckTxError(code, err) + // TODO I think we need to return error in this case as now the API allows for it + // return blockchain.NewResponseCheckTxError(code, err), err + return blockchain.NewResponseCheckTxError(code, err), nil } // check for spam and replay if fn := app.OnCheckTxSpam; fn != nil { - resp = fn(tx) + resp := fn(tx) if resp.IsErr() { - return AddCommonCheckTxEvents(resp, tx) + return AddCommonCheckTxEvents(&resp, tx), nil } } @@ -84,14 +124,14 @@ func (app *App) CheckTx(req types.RequestCheckTx) (resp types.ResponseCheckTx) { if fn := app.OnCheckTx; fn != nil { ctx, resp = fn(ctx, req, tx) if resp.IsErr() { - return AddCommonCheckTxEvents(resp, tx) + return AddCommonCheckTxEvents(resp, tx), nil } } // Lookup for check tx, skip if not found if fn, ok := app.checkTxs[tx.Command()]; ok { if err := fn(ctx, tx); err != nil { - return AddCommonCheckTxEvents(blockchain.NewResponseCheckTxError(blockchain.AbciTxnInternalError, err), tx) + return AddCommonCheckTxEvents(blockchain.NewResponseCheckTxError(blockchain.AbciTxnInternalError, err), tx), nil } } @@ -100,99 +140,102 @@ func (app *App) CheckTx(req types.RequestCheckTx) (resp types.ResponseCheckTx) { if resp.IsOK() { app.cacheTx(req.Tx, tx) } - - return AddCommonCheckTxEvents(resp, tx) + return AddCommonCheckTxEvents(resp, tx), nil } -func (app *App) DeliverTx(req types.RequestDeliverTx) (resp types.ResponseDeliverTx) { - // first, only decode the transaction but don't validate - tx, code, err := app.getTx(req.GetTx()) - if err != nil { - return blockchain.NewResponseDeliverTxError(code, err) - } - app.removeTxFromCache(req.GetTx()) - - // check for spam and replay - if fn := app.OnDeliverTxSpam; fn != nil { - resp = fn(app.ctx, tx) - if resp.IsErr() { - return AddCommonDeliverTxEvents(resp, tx) - } - } - - // It's been validated by CheckTx so we can skip the validation here - ctx := app.ctx - if fn := app.OnDeliverTx; fn != nil { - ctx, resp = fn(ctx, req, tx) - if resp.IsErr() { - return AddCommonDeliverTxEvents(resp, tx) +// FinalizeBlock lets the application process a whole block end to end. +func (app *App) FinalizeBlock(_ context.Context, req *types.RequestFinalizeBlock) (*types.ResponseFinalizeBlock, error) { + blockHeight := uint64(req.Height) + blockTime := req.Time + + txs := make([]Tx, 0, len(req.Txs)) + for _, rtx := range req.Txs { + // getTx can't fail at this point as we've verified on processProposal, however as it can fail in nullblockchain, handle it here + tx, _, err := app.getTx(rtx) + if err != nil { + continue } + app.removeTxFromCache(rtx) + txs = append(txs, tx) } - // Lookup for deliver tx, fail if not found - fn := app.deliverTxs[tx.Command()] - if fn == nil { - return AddCommonDeliverTxEvents( - blockchain.NewResponseDeliverTxError(blockchain.AbciUnknownCommandError, errors.New("invalid vega command")), tx, - ) - } + app.ctx = app.OnBeginBlock(blockHeight, hex.EncodeToString(req.Hash), blockTime, hex.EncodeToString(req.ProposerAddress), txs) + results := make([]*types.ExecTxResult, 0, len(req.Txs)) + events := []types.Event{} - txHash := hex.EncodeToString(tx.Hash()) - ctx = vgcontext.WithTxHash(ctx, txHash) - - if err := fn(ctx, tx); err != nil { - if perr, ok := err.(MaybePartialError); ok { - if perr.IsPartial() { - return AddCommonDeliverTxEvents( - blockchain.NewResponseDeliverTxError(blockchain.AbciTxnPartialProcessingError, err), tx, - ) + for _, tx := range txs { + // there must be a handling function at this point + fn := app.deliverTxs[tx.Command()] + txHash := hex.EncodeToString(tx.Hash()) + ctx := vgcontext.WithTxHash(app.ctx, txHash) + // process the transaction and handle errors + if err := fn(ctx, tx); err != nil { + if perr, ok := err.(MaybePartialError); ok && perr.IsPartial() { + results = append(results, blockchain.NewResponseDeliverTxError(blockchain.AbciTxnPartialProcessingError, err)) + } else { + results = append(results, blockchain.NewResponseDeliverTxError(blockchain.AbciTxnInternalError, err)) } + } else { + results = append(results, blockchain.NewResponseDeliverTx(types.CodeTypeOK, "")) } - - return AddCommonDeliverTxEvents( - blockchain.NewResponseDeliverTxError(blockchain.AbciTxnInternalError, err), tx, - ) - } - - return AddCommonDeliverTxEvents( - blockchain.NewResponseDeliverTx(types.CodeTypeOK, ""), tx, + events = append(events, getBaseTxEvents(tx)...) + } + valUpdates, consensusUpdates := app.OnEndBlock(blockHeight) + events = append(events, types.Event{ + Type: "val_updates", + Attributes: []types.EventAttribute{ + { + Key: "size", + Value: strconv.Itoa(valUpdates.Len()), + }, + { + Key: "height", + Value: strconv.Itoa(int(req.Height)), + }, + }, + }, ) + + hash := app.OnFinalize() + println("finished processing block", blockHeight, "with block hash", hex.EncodeToString(hash), "with", len(txs), "transactions") + return &types.ResponseFinalizeBlock{ + TxResults: results, + ValidatorUpdates: valUpdates, + ConsensusParamUpdates: &consensusUpdates, + AppHash: hash, + Events: events, + }, nil } -func (app *App) ListSnapshots(req types.RequestListSnapshots) (resp types.ResponseListSnapshots) { +func (app *App) ListSnapshots(ctx context.Context, req *types.RequestListSnapshots) (*types.ResponseListSnapshots, error) { if app.OnListSnapshots != nil { - resp = app.OnListSnapshots(req) + return app.OnListSnapshots(ctx, req) } - return + return &types.ResponseListSnapshots{}, nil } -func (app *App) OfferSnapshot(req types.RequestOfferSnapshot) (resp types.ResponseOfferSnapshot) { +func (app *App) OfferSnapshot(ctx context.Context, req *types.RequestOfferSnapshot) (*types.ResponseOfferSnapshot, error) { if app.OnOfferSnapshot != nil { - resp = app.OnOfferSnapshot(req) + return app.OnOfferSnapshot(ctx, req) } - return + return &types.ResponseOfferSnapshot{}, nil } -func (app *App) LoadSnapshotChunk(req types.RequestLoadSnapshotChunk) (resp types.ResponseLoadSnapshotChunk) { +func (app *App) LoadSnapshotChunk(ctx context.Context, req *types.RequestLoadSnapshotChunk) (*types.ResponseLoadSnapshotChunk, error) { if app.OnLoadSnapshotChunk != nil { - resp = app.OnLoadSnapshotChunk(req) + return app.OnLoadSnapshotChunk(ctx, req) } - return + return &types.ResponseLoadSnapshotChunk{}, nil } -func (app *App) ApplySnapshotChunk(req types.RequestApplySnapshotChunk) (resp types.ResponseApplySnapshotChunk) { +func (app *App) ApplySnapshotChunk(_ context.Context, req *types.RequestApplySnapshotChunk) (*types.ResponseApplySnapshotChunk, error) { if app.OnApplySnapshotChunk != nil { - resp = app.OnApplySnapshotChunk(app.ctx, req) + return app.OnApplySnapshotChunk(app.ctx, req) } - return -} - -func AddCommonCheckTxEvents(resp types.ResponseCheckTx, tx Tx) types.ResponseCheckTx { - resp.Events = getBaseTxEvents(tx) - return resp + return &types.ResponseApplySnapshotChunk{}, nil } -func AddCommonDeliverTxEvents(resp types.ResponseDeliverTx, tx Tx) types.ResponseDeliverTx { +func AddCommonCheckTxEvents(resp *types.ResponseCheckTx, tx Tx) *types.ResponseCheckTx { resp.Events = getBaseTxEvents(tx) return resp } @@ -203,8 +246,8 @@ func getBaseTxEvents(tx Tx) []types.Event { Type: "tx", Attributes: []types.EventAttribute{ { - Key: []byte("submitter"), - Value: []byte(tx.PubKeyHex()), + Key: "submitter", + Value: tx.PubKeyHex(), Index: true, }, }, @@ -213,8 +256,8 @@ func getBaseTxEvents(tx Tx) []types.Event { Type: "command", Attributes: []types.EventAttribute{ { - Key: []byte("type"), - Value: []byte(tx.Command().String()), + Key: "type", + Value: tx.Command().String(), Index: true, }, }, @@ -237,8 +280,8 @@ func getBaseTxEvents(tx Tx) []types.Event { } if len(market) > 0 { commandAttributes = append(commandAttributes, types.EventAttribute{ - Key: []byte("market"), - Value: []byte(market), + Key: "market", + Value: market, Index: true, }) } @@ -252,8 +295,8 @@ func getBaseTxEvents(tx Tx) []types.Event { } if len(asset) > 0 { commandAttributes = append(commandAttributes, types.EventAttribute{ - Key: []byte("asset"), - Value: []byte(asset), + Key: "asset", + Value: asset, Index: true, }) } @@ -264,8 +307,8 @@ func getBaseTxEvents(tx Tx) []types.Event { } if len(reference) > 0 { commandAttributes = append(commandAttributes, types.EventAttribute{ - Key: []byte("reference"), - Value: []byte(reference), + Key: "reference", + Value: reference, Index: true, }) } @@ -276,8 +319,8 @@ func getBaseTxEvents(tx Tx) []types.Event { } if len(proposal) > 0 { commandAttributes = append(commandAttributes, types.EventAttribute{ - Key: []byte("proposal"), - Value: []byte(proposal), + Key: "proposal", + Value: proposal, Index: true, }) } diff --git a/core/blockchain/abci/abci_test.go b/core/blockchain/abci/abci_test.go index 976ce9fd45..a2e5f0e6ca 100644 --- a/core/blockchain/abci/abci_test.go +++ b/core/blockchain/abci/abci_test.go @@ -25,8 +25,8 @@ import ( "code.vegaprotocol.io/vega/core/blockchain/abci" "code.vegaprotocol.io/vega/core/txn" + "github.com/cometbft/cometbft/abci/types" "github.com/stretchr/testify/require" - "github.com/tendermint/tendermint/abci/types" ) type testTx struct { @@ -40,6 +40,7 @@ type testTx struct { powTxID string } +func (tx *testTx) GetLength() int { return 0 } func (tx *testTx) Unmarshal(interface{}) error { return nil } func (tx *testTx) GetPoWTID() string { return tx.powTxID } func (tx *testTx) GetVersion() uint32 { return 2 } @@ -99,9 +100,8 @@ func TestABCICheckTx(t *testing.T) { return errors.New("boom") }) - app.OnCheckTx = func(ctx context.Context, req types.RequestCheckTx, _ abci.Tx) (context.Context, types.ResponseCheckTx) { - resp := types.ResponseCheckTx{} - return context.WithValue(ctx, testKey, "val"), resp + app.OnCheckTx = func(ctx context.Context, _ *types.RequestCheckTx, _ abci.Tx) (context.Context, *types.ResponseCheckTx) { + return context.WithValue(ctx, testKey, "val"), &types.ResponseCheckTx{} } t.Run("CommandWithNoError", func(t *testing.T) { @@ -111,7 +111,7 @@ func TestABCICheckTx(t *testing.T) { }) req := types.RequestCheckTx{Tx: tx} - resp := app.CheckTx(req) + resp, _ := app.CheckTx(context.Background(), &req) require.True(t, resp.IsOK()) }) @@ -122,7 +122,7 @@ func TestABCICheckTx(t *testing.T) { }) req := types.RequestCheckTx{Tx: tx} - resp := app.CheckTx(req) + resp, _ := app.CheckTx(context.Background(), &req) require.True(t, resp.IsErr()) require.Equal(t, blockchain.AbciTxnInternalError, resp.Code) }) @@ -131,7 +131,7 @@ func TestABCICheckTx(t *testing.T) { tx := []byte("tx-not-registered-on-the-codec") req := types.RequestCheckTx{Tx: tx} - resp := app.CheckTx(req) + resp, _ := app.CheckTx(context.Background(), &req) require.True(t, resp.IsErr()) require.Equal(t, blockchain.AbciTxnDecodingFailure, resp.Code) }) diff --git a/core/blockchain/abci/app.go b/core/blockchain/abci/app.go index efa61a7aab..06a13f78a7 100644 --- a/core/blockchain/abci/app.go +++ b/core/blockchain/abci/app.go @@ -22,8 +22,8 @@ import ( "code.vegaprotocol.io/vega/core/txn" "code.vegaprotocol.io/vega/core/types" + abci "github.com/cometbft/cometbft/abci/types" lru "github.com/hashicorp/golang-lru" - abci "github.com/tendermint/tendermint/abci/types" ) type ( @@ -40,16 +40,17 @@ type App struct { codec Codec // handlers - OnInitChain OnInitChainHandler - OnBeginBlock OnBeginBlockHandler - OnEndBlock OnEndBlockHandler - OnCheckTx OnCheckTxHandler - OnDeliverTx OnDeliverTxHandler - OnCommit OnCommitHandler + OnPrepareProposal PrepareProposalHandler + OnProcessProposal ProcessProposalHandler + OnInitChain OnInitChainHandler + OnCheckTx OnCheckTxHandler + OnCommit OnCommitHandler + OnBeginBlock OnBeginBlockHandler + OnEndBlock OnEndBlockHandler + OnFinalize FinalizeHandler // spam check - OnCheckTxSpam OnCheckTxSpamHandler - OnDeliverTxSpam OnDeliverTxSpamHandler + OnCheckTxSpam OnCheckTxSpamHandler // snapshot stuff diff --git a/core/blockchain/abci/client.go b/core/blockchain/abci/client.go index e06ab4c7ef..f7854c78a7 100644 --- a/core/blockchain/abci/client.go +++ b/core/blockchain/abci/client.go @@ -23,13 +23,13 @@ import ( "sync" "time" - cmtjson "github.com/tendermint/tendermint/libs/json" - tmlog "github.com/tendermint/tendermint/libs/log" - tmquery "github.com/tendermint/tendermint/libs/pubsub/query" - tmclihttp "github.com/tendermint/tendermint/rpc/client/http" - tmctypes "github.com/tendermint/tendermint/rpc/core/types" - "github.com/tendermint/tendermint/types" - tmtypes "github.com/tendermint/tendermint/types" + cmtjson "github.com/cometbft/cometbft/libs/json" + tmlog "github.com/cometbft/cometbft/libs/log" + tmquery "github.com/cometbft/cometbft/libs/pubsub/query" + tmclihttp "github.com/cometbft/cometbft/rpc/client/http" + tmctypes "github.com/cometbft/cometbft/rpc/core/types" + "github.com/cometbft/cometbft/types" + tmtypes "github.com/cometbft/cometbft/types" ) var ErrEmptyClientAddr = errors.New("abci client addr is empty in config") @@ -156,7 +156,7 @@ func (c *Client) GenesisValidators(ctx context.Context) ([]*tmtypes.Validator, e return validators, nil } -// Subscribe subscribes to any event matching query (https://godoc.org/github.com/tendermint/tendermint/types#pkg-constants). +// Subscribe subscribes to any event matching query (https://godoc.org/github.com/cometbft/cometbft/types#pkg-constants). // Subscribe will call fn each time it receives an event from the node. // The function returns nil when the context is canceled or when fn returns an error. func (c *Client) Subscribe(ctx context.Context, fn func(tmctypes.ResultEvent) error, queries ...string) error { diff --git a/core/blockchain/abci/local_client.go b/core/blockchain/abci/local_client.go index 20eb09d097..461cee6af3 100644 --- a/core/blockchain/abci/local_client.go +++ b/core/blockchain/abci/local_client.go @@ -19,12 +19,12 @@ import ( "context" "time" - tmquery "github.com/tendermint/tendermint/libs/pubsub/query" - "github.com/tendermint/tendermint/libs/service" - nm "github.com/tendermint/tendermint/node" - "github.com/tendermint/tendermint/rpc/client/local" - tmctypes "github.com/tendermint/tendermint/rpc/core/types" - tmtypes "github.com/tendermint/tendermint/types" + tmquery "github.com/cometbft/cometbft/libs/pubsub/query" + "github.com/cometbft/cometbft/libs/service" + nm "github.com/cometbft/cometbft/node" + "github.com/cometbft/cometbft/rpc/client/local" + tmctypes "github.com/cometbft/cometbft/rpc/core/types" + tmtypes "github.com/cometbft/cometbft/types" ) type LocalClient struct { @@ -139,7 +139,7 @@ func (c *LocalClient) GenesisValidators(ctx context.Context) ([]*tmtypes.Validat return validators, nil } -// Subscribe subscribes to any event matching query (https://godoc.org/github.com/tendermint/tendermint/types#pkg-constants). +// Subscribe subscribes to any event matching query (https://godoc.org/github.com/cometbft/cometbft/types#pkg-constants). // Subscribe will call fn each time it receives an event from the node. // The function returns nil when the context is canceled or when fn returns an error. func (c *LocalClient) Subscribe(ctx context.Context, fn func(tmctypes.ResultEvent) error, queries ...string) error { diff --git a/core/blockchain/abci/tm_logger.go b/core/blockchain/abci/tm_logger.go index c0045ca29b..b3c10de410 100644 --- a/core/blockchain/abci/tm_logger.go +++ b/core/blockchain/abci/tm_logger.go @@ -16,7 +16,7 @@ package abci import ( - tmlog "github.com/tendermint/tendermint/libs/log" + tmlog "github.com/cometbft/cometbft/libs/log" "go.uber.org/zap" ) diff --git a/core/blockchain/abci/tm_node.go b/core/blockchain/abci/tm_node.go index db8a2d9a57..b26e986776 100644 --- a/core/blockchain/abci/tm_node.go +++ b/core/blockchain/abci/tm_node.go @@ -21,20 +21,22 @@ import ( "code.vegaprotocol.io/vega/core/blockchain" "code.vegaprotocol.io/vega/logging" + "github.com/cometbft/cometbft/abci/types" + "github.com/cometbft/cometbft/config" + bftconfig "github.com/cometbft/cometbft/config" + "github.com/cometbft/cometbft/libs/service" + nm "github.com/cometbft/cometbft/node" + "github.com/cometbft/cometbft/p2p" + "github.com/cometbft/cometbft/privval" + "github.com/cometbft/cometbft/proxy" + tmtypes "github.com/cometbft/cometbft/types" "github.com/spf13/viper" - "github.com/tendermint/tendermint/abci/types" - "github.com/tendermint/tendermint/config" - "github.com/tendermint/tendermint/libs/service" - nm "github.com/tendermint/tendermint/node" - "github.com/tendermint/tendermint/p2p" - "github.com/tendermint/tendermint/privval" - "github.com/tendermint/tendermint/proxy" - tmtypes "github.com/tendermint/tendermint/types" ) type TmNode struct { - conf blockchain.Config - node service.Service + conf blockchain.Config + node service.Service + MempoolSize int64 } const namedLogger = "tendermint" @@ -101,7 +103,7 @@ func NewTmNode( nodeKey, proxy.NewLocalClientCreator(app), genesisDocProvider, - nm.DefaultDBProvider, + bftconfig.DefaultDBProvider, nm.DefaultMetricsProvider(config.Instrumentation), logger) if err != nil { @@ -114,7 +116,7 @@ func NewTmNode( // return nil, fmt.Errorf("creating tendermint node: %v", err) // } - return &TmNode{conf, node}, nil + return &TmNode{conf, node, config.Mempool.MaxTxsBytes}, nil } func (*TmNode) ReloadConf(cfg blockchain.Config) { @@ -156,9 +158,7 @@ func loadConfig(homeDir string) (*config.Config, error) { func overwriteConfig(config *config.Config) { config.Consensus.TimeoutCommit = 0 config.Consensus.CreateEmptyBlocks = true - // enforce using priority mempool - config.Mempool.Version = "v1" - // ensure transactions are continuously checked + // ensure rechecking tx is enabled config.Mempool.Recheck = true // enforce compatibility config.P2P.MaxPacketMsgPayloadSize = 16384 diff --git a/core/blockchain/abci/types.go b/core/blockchain/abci/types.go index adf2248877..80e7ae718e 100644 --- a/core/blockchain/abci/types.go +++ b/core/blockchain/abci/types.go @@ -17,10 +17,12 @@ package abci import ( "context" + "time" "code.vegaprotocol.io/vega/core/txn" - "github.com/tendermint/tendermint/abci/types" + "github.com/cometbft/cometbft/abci/types" + types1 "github.com/cometbft/cometbft/proto/tendermint/types" ) //nolint:interfacebloat @@ -37,6 +39,7 @@ type Tx interface { GetPoWNonce() uint64 GetPoWTID() string GetVersion() uint32 + GetLength() int GetNonce() uint64 } @@ -46,17 +49,19 @@ type Codec interface { // ABCI hooks. type ( - OnInitChainHandler func(types.RequestInitChain) types.ResponseInitChain - OnBeginBlockHandler func(types.RequestBeginBlock) (context.Context, types.ResponseBeginBlock) - OnEndBlockHandler func(types.RequestEndBlock) (context.Context, types.ResponseEndBlock) - OnCheckTxHandler func(context.Context, types.RequestCheckTx, Tx) (context.Context, types.ResponseCheckTx) - OnDeliverTxHandler func(context.Context, types.RequestDeliverTx, Tx) (context.Context, types.ResponseDeliverTx) - OnCommitHandler func() types.ResponseCommit - ListSnapshotsHandler func(types.RequestListSnapshots) types.ResponseListSnapshots - OfferSnapshotHandler func(types.RequestOfferSnapshot) types.ResponseOfferSnapshot - LoadSnapshotChunkHandler func(types.RequestLoadSnapshotChunk) types.ResponseLoadSnapshotChunk - ApplySnapshotChunkHandler func(context.Context, types.RequestApplySnapshotChunk) types.ResponseApplySnapshotChunk - InfoHandler func(types.RequestInfo) types.ResponseInfo + PrepareProposalHandler func(txs []Tx, raWtxs [][]byte) [][]byte + ProcessProposalHandler func(txs []Tx) bool + OnInitChainHandler func(*types.RequestInitChain) (*types.ResponseInitChain, error) + OnBeginBlockHandler func(uint64, string, time.Time, string, []Tx) context.Context + OnEndBlockHandler func(blockHeight uint64) (types.ValidatorUpdates, types1.ConsensusParams) + OnCheckTxHandler func(context.Context, *types.RequestCheckTx, Tx) (context.Context, *types.ResponseCheckTx) + OnDeliverTxHandler func(context.Context, Tx) + OnCommitHandler func() (*types.ResponseCommit, error) + ListSnapshotsHandler func(context.Context, *types.RequestListSnapshots) (*types.ResponseListSnapshots, error) + OfferSnapshotHandler func(context.Context, *types.RequestOfferSnapshot) (*types.ResponseOfferSnapshot, error) + LoadSnapshotChunkHandler func(context.Context, *types.RequestLoadSnapshotChunk) (*types.ResponseLoadSnapshotChunk, error) + ApplySnapshotChunkHandler func(context.Context, *types.RequestApplySnapshotChunk) (*types.ResponseApplySnapshotChunk, error) + InfoHandler func(context.Context, *types.RequestInfo) (*types.ResponseInfo, error) OnCheckTxSpamHandler func(Tx) types.ResponseCheckTx - OnDeliverTxSpamHandler func(context.Context, Tx) types.ResponseDeliverTx + FinalizeHandler func() []byte ) diff --git a/core/blockchain/client.go b/core/blockchain/client.go index 5f27a59b42..786d573286 100644 --- a/core/blockchain/client.go +++ b/core/blockchain/client.go @@ -25,9 +25,9 @@ import ( "code.vegaprotocol.io/vega/libs/proto" commandspb "code.vegaprotocol.io/vega/protos/vega/commands/v1" - "github.com/tendermint/tendermint/libs/bytes" - tmctypes "github.com/tendermint/tendermint/rpc/core/types" - tmtypes "github.com/tendermint/tendermint/types" + "github.com/cometbft/cometbft/libs/bytes" + tmctypes "github.com/cometbft/cometbft/rpc/core/types" + tmtypes "github.com/cometbft/cometbft/types" ) var ErrClientNotReady = errors.New("tendermint client is not ready") @@ -53,8 +53,9 @@ type ChainClientImpl interface { // Client abstract all communication to the blockchain. type Client struct { *Config - clt ChainClientImpl - mu sync.RWMutex + clt ChainClientImpl + mempoolSize int64 + mu sync.RWMutex } // NewClient instantiate a new blockchain client. @@ -70,10 +71,11 @@ func NewClientWithImpl(clt ChainClientImpl) *Client { } } -func (c *Client) Set(clt ChainClientImpl) { +func (c *Client) Set(clt ChainClientImpl, mempoolSize int64) { c.mu.Lock() defer c.mu.Unlock() c.clt = clt + c.mempoolSize = mempoolSize } func (c *Client) isReady() bool { @@ -104,7 +106,7 @@ func (c *Client) CheckTransaction(ctx context.Context, tx *commandspb.Transactio if _, err := commands.CheckTransaction(tx, chainID); err != nil { return &tmctypes.ResultCheckTx{ - ResponseCheckTx: NewResponseCheckTxError(AbciTxnDecodingFailure, err), + ResponseCheckTx: *NewResponseCheckTxError(AbciTxnDecodingFailure, err), }, nil } @@ -149,7 +151,7 @@ func (c *Client) SubmitTransactionCommit(ctx context.Context, tx *commandspb.Tra if _, err := commands.CheckTransaction(tx, chainID); err != nil { return &tmctypes.ResultBroadcastTxCommit{ - CheckTx: NewResponseCheckTxError(AbciTxnDecodingFailure, err), + CheckTx: *NewResponseCheckTxError(AbciTxnDecodingFailure, err), }, nil } @@ -301,6 +303,10 @@ func (c *Client) GenesisValidators() ([]*tmtypes.Validator, error) { return c.clt.GenesisValidators(ctx) } +func (c *Client) MaxMempoolSize() int64 { + return c.mempoolSize +} + func (c *Client) Validators(height *int64) ([]*tmtypes.Validator, error) { if !c.isReady() { return nil, ErrClientNotReady diff --git a/core/blockchain/nullchain/mocks/mocks.go b/core/blockchain/nullchain/mocks/mocks.go index 0532c7ed69..17b4a0999c 100644 --- a/core/blockchain/nullchain/mocks/mocks.go +++ b/core/blockchain/nullchain/mocks/mocks.go @@ -5,11 +5,12 @@ package mocks import ( + context "context" reflect "reflect" time "time" + types "github.com/cometbft/cometbft/abci/types" gomock "github.com/golang/mock/gomock" - types "github.com/tendermint/tendermint/abci/types" ) // MockTimeService is a mock of TimeService interface. @@ -72,86 +73,62 @@ func (m *MockApplicationService) EXPECT() *MockApplicationServiceMockRecorder { return m.recorder } -// BeginBlock mocks base method. -func (m *MockApplicationService) BeginBlock(arg0 types.RequestBeginBlock) types.ResponseBeginBlock { - m.ctrl.T.Helper() - ret := m.ctrl.Call(m, "BeginBlock", arg0) - ret0, _ := ret[0].(types.ResponseBeginBlock) - return ret0 -} - -// BeginBlock indicates an expected call of BeginBlock. -func (mr *MockApplicationServiceMockRecorder) BeginBlock(arg0 interface{}) *gomock.Call { - mr.mock.ctrl.T.Helper() - return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "BeginBlock", reflect.TypeOf((*MockApplicationService)(nil).BeginBlock), arg0) -} - // Commit mocks base method. -func (m *MockApplicationService) Commit() types.ResponseCommit { +func (m *MockApplicationService) Commit(arg0 context.Context, arg1 *types.RequestCommit) (*types.ResponseCommit, error) { m.ctrl.T.Helper() - ret := m.ctrl.Call(m, "Commit") - ret0, _ := ret[0].(types.ResponseCommit) - return ret0 + ret := m.ctrl.Call(m, "Commit", arg0, arg1) + ret0, _ := ret[0].(*types.ResponseCommit) + ret1, _ := ret[1].(error) + return ret0, ret1 } // Commit indicates an expected call of Commit. -func (mr *MockApplicationServiceMockRecorder) Commit() *gomock.Call { - mr.mock.ctrl.T.Helper() - return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "Commit", reflect.TypeOf((*MockApplicationService)(nil).Commit)) -} - -// DeliverTx mocks base method. -func (m *MockApplicationService) DeliverTx(arg0 types.RequestDeliverTx) types.ResponseDeliverTx { - m.ctrl.T.Helper() - ret := m.ctrl.Call(m, "DeliverTx", arg0) - ret0, _ := ret[0].(types.ResponseDeliverTx) - return ret0 -} - -// DeliverTx indicates an expected call of DeliverTx. -func (mr *MockApplicationServiceMockRecorder) DeliverTx(arg0 interface{}) *gomock.Call { +func (mr *MockApplicationServiceMockRecorder) Commit(arg0, arg1 interface{}) *gomock.Call { mr.mock.ctrl.T.Helper() - return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "DeliverTx", reflect.TypeOf((*MockApplicationService)(nil).DeliverTx), arg0) + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "Commit", reflect.TypeOf((*MockApplicationService)(nil).Commit), arg0, arg1) } -// EndBlock mocks base method. -func (m *MockApplicationService) EndBlock(arg0 types.RequestEndBlock) types.ResponseEndBlock { +// FinalizeBlock mocks base method. +func (m *MockApplicationService) FinalizeBlock(arg0 context.Context, arg1 *types.RequestFinalizeBlock) (*types.ResponseFinalizeBlock, error) { m.ctrl.T.Helper() - ret := m.ctrl.Call(m, "EndBlock", arg0) - ret0, _ := ret[0].(types.ResponseEndBlock) - return ret0 + ret := m.ctrl.Call(m, "FinalizeBlock", arg0, arg1) + ret0, _ := ret[0].(*types.ResponseFinalizeBlock) + ret1, _ := ret[1].(error) + return ret0, ret1 } -// EndBlock indicates an expected call of EndBlock. -func (mr *MockApplicationServiceMockRecorder) EndBlock(arg0 interface{}) *gomock.Call { +// FinalizeBlock indicates an expected call of FinalizeBlock. +func (mr *MockApplicationServiceMockRecorder) FinalizeBlock(arg0, arg1 interface{}) *gomock.Call { mr.mock.ctrl.T.Helper() - return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "EndBlock", reflect.TypeOf((*MockApplicationService)(nil).EndBlock), arg0) + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "FinalizeBlock", reflect.TypeOf((*MockApplicationService)(nil).FinalizeBlock), arg0, arg1) } // Info mocks base method. -func (m *MockApplicationService) Info(arg0 types.RequestInfo) types.ResponseInfo { +func (m *MockApplicationService) Info(arg0 context.Context, arg1 *types.RequestInfo) (*types.ResponseInfo, error) { m.ctrl.T.Helper() - ret := m.ctrl.Call(m, "Info", arg0) - ret0, _ := ret[0].(types.ResponseInfo) - return ret0 + ret := m.ctrl.Call(m, "Info", arg0, arg1) + ret0, _ := ret[0].(*types.ResponseInfo) + ret1, _ := ret[1].(error) + return ret0, ret1 } // Info indicates an expected call of Info. -func (mr *MockApplicationServiceMockRecorder) Info(arg0 interface{}) *gomock.Call { +func (mr *MockApplicationServiceMockRecorder) Info(arg0, arg1 interface{}) *gomock.Call { mr.mock.ctrl.T.Helper() - return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "Info", reflect.TypeOf((*MockApplicationService)(nil).Info), arg0) + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "Info", reflect.TypeOf((*MockApplicationService)(nil).Info), arg0, arg1) } // InitChain mocks base method. -func (m *MockApplicationService) InitChain(arg0 types.RequestInitChain) types.ResponseInitChain { +func (m *MockApplicationService) InitChain(arg0 context.Context, arg1 *types.RequestInitChain) (*types.ResponseInitChain, error) { m.ctrl.T.Helper() - ret := m.ctrl.Call(m, "InitChain", arg0) - ret0, _ := ret[0].(types.ResponseInitChain) - return ret0 + ret := m.ctrl.Call(m, "InitChain", arg0, arg1) + ret0, _ := ret[0].(*types.ResponseInitChain) + ret1, _ := ret[1].(error) + return ret0, ret1 } // InitChain indicates an expected call of InitChain. -func (mr *MockApplicationServiceMockRecorder) InitChain(arg0 interface{}) *gomock.Call { +func (mr *MockApplicationServiceMockRecorder) InitChain(arg0, arg1 interface{}) *gomock.Call { mr.mock.ctrl.T.Helper() - return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "InitChain", reflect.TypeOf((*MockApplicationService)(nil).InitChain), arg0) + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "InitChain", reflect.TypeOf((*MockApplicationService)(nil).InitChain), arg0, arg1) } diff --git a/core/blockchain/nullchain/nullchain.go b/core/blockchain/nullchain/nullchain.go index 5c1f1dd464..9dda90a4d1 100644 --- a/core/blockchain/nullchain/nullchain.go +++ b/core/blockchain/nullchain/nullchain.go @@ -32,13 +32,12 @@ import ( vgrand "code.vegaprotocol.io/vega/libs/rand" "code.vegaprotocol.io/vega/logging" - abci "github.com/tendermint/tendermint/abci/types" - "github.com/tendermint/tendermint/crypto/tmhash" - "github.com/tendermint/tendermint/p2p" - "github.com/tendermint/tendermint/proto/tendermint/crypto" - "github.com/tendermint/tendermint/proto/tendermint/types" - tmctypes "github.com/tendermint/tendermint/rpc/core/types" - tmtypes "github.com/tendermint/tendermint/types" + abci "github.com/cometbft/cometbft/abci/types" + "github.com/cometbft/cometbft/crypto/tmhash" + "github.com/cometbft/cometbft/p2p" + "github.com/cometbft/cometbft/proto/tendermint/crypto" + tmctypes "github.com/cometbft/cometbft/rpc/core/types" + tmtypes "github.com/cometbft/cometbft/types" ) const namedLogger = "nullchain" @@ -55,12 +54,10 @@ type TimeService interface { } type ApplicationService interface { - InitChain(res abci.RequestInitChain) (resp abci.ResponseInitChain) - BeginBlock(req abci.RequestBeginBlock) (resp abci.ResponseBeginBlock) - EndBlock(req abci.RequestEndBlock) (resp abci.ResponseEndBlock) - Commit() (resp abci.ResponseCommit) - DeliverTx(req abci.RequestDeliverTx) (resp abci.ResponseDeliverTx) - Info(req abci.RequestInfo) (resp abci.ResponseInfo) + InitChain(context.Context, *abci.RequestInitChain) (*abci.ResponseInitChain, error) + FinalizeBlock(context.Context, *abci.RequestFinalizeBlock) (*abci.ResponseFinalizeBlock, error) + Commit(context.Context, *abci.RequestCommit) (*abci.ResponseCommit, error) + Info(context.Context, *abci.RequestInfo) (*abci.ResponseInfo, error) } // nullGenesis is a subset of a tendermint genesis file, just the bits we need to run the nullblockchain. @@ -82,7 +79,7 @@ type NullBlockchain struct { now time.Time blockHeight int64 - pending []*abci.RequestDeliverTx + pending [][]byte mu sync.Mutex replaying atomic.Bool @@ -105,7 +102,7 @@ func NewClient( transactionsPerBlock: cfg.TransactionsPerBlock, blockDuration: cfg.BlockDuration.Duration, blockHeight: 1, - pending: make([]*abci.RequestDeliverTx, 0), + pending: make([][]byte, 0), } return n @@ -138,7 +135,7 @@ func (n *NullBlockchain) StartChain() error { return err } - if r := n.app.Info(abci.RequestInfo{}); r.LastBlockHeight > 0 { + if r, _ := n.app.Info(context.Background(), &abci.RequestInfo{}); r.LastBlockHeight > 0 { n.log.Info("protocol loaded from snapshot", logging.Int64("height", r.LastBlockHeight)) n.blockHeight = r.LastBlockHeight + 1 n.now = n.timeService.GetTimeNow().Add(n.blockDuration) @@ -164,7 +161,7 @@ func (n *NullBlockchain) StartChain() error { if n.cfg.Replay.Replay { n.log.Info("nullchain is replaying chain", logging.String("replay-file", n.cfg.Replay.ReplayFile)) n.replaying.Store(true) - blockHeight, blockTime, err := r.replayChain(n.blockHeight, n.genesis.ChainID) + blockHeight, blockTime, err := r.replayChain(n.blockHeight) if err != nil { return err } @@ -190,20 +187,22 @@ func (n *NullBlockchain) processBlock() { n.log.Debugf("processing block %d with %d transactions", n.blockHeight, len(n.pending)) } - resp := abci.ResponseCommit{} + resp := &abci.ResponseFinalizeBlock{} if n.replayer != nil && n.cfg.Replay.Record { n.replayer.startBlock(n.blockHeight, n.now.UnixNano(), n.pending) - defer func() { n.replayer.saveBlock(resp.Data) }() + defer func() { + n.replayer.saveBlock(resp.AppHash) + }() } - n.BeginBlock() - for _, tx := range n.pending { - n.app.DeliverTx(*tx) - } + resp, _ = n.app.FinalizeBlock(context.Background(), &abci.RequestFinalizeBlock{ + Height: n.blockHeight, + Time: n.now, + Hash: vgcrypto.Hash([]byte(strconv.FormatInt(n.blockHeight+n.now.UnixNano(), 10))), + Txs: n.pending, + }) n.pending = n.pending[:0] - - n.EndBlock() - resp = n.app.Commit() + n.app.Commit(context.Background(), &abci.RequestCommit{}) // Increment time, blockheight, ready to start a new block n.blockHeight++ @@ -214,7 +213,7 @@ func (n *NullBlockchain) handleTransaction(tx []byte) { n.mu.Lock() defer n.mu.Unlock() - n.pending = append(n.pending, &abci.RequestDeliverTx{Tx: tx}) + n.pending = append(n.pending, tx) if n.log.GetLevel() <= logging.DebugLevel { n.log.Debugf("transaction added to block: %d of %d", len(n.pending), n.transactionsPerBlock) } @@ -309,8 +308,8 @@ func (n *NullBlockchain) InitChain() error { logging.String("time", n.now.String()), logging.Int("n_validators", len(validators)), ) - n.app.InitChain( - abci.RequestInitChain{ + n.app.InitChain(context.Background(), + &abci.RequestInitChain{ Time: n.now, ChainId: n.genesis.ChainID, InitialHeight: n.blockHeight, @@ -321,38 +320,6 @@ func (n *NullBlockchain) InitChain() error { return nil } -func (n *NullBlockchain) BeginBlock() *NullBlockchain { - if n.log.GetLevel() <= logging.DebugLevel { - n.log.Debug("sending BeginBlock", - logging.Int64("height", n.blockHeight), - logging.String("time", n.now.String()), - ) - } - - r := abci.RequestBeginBlock{ - Header: types.Header{ - Time: n.now, - Height: n.blockHeight, - ChainID: n.genesis.ChainID, - }, - Hash: vgcrypto.Hash([]byte(strconv.FormatInt(n.blockHeight+n.now.UnixNano(), 10))), - } - n.app.BeginBlock(r) - return n -} - -func (n *NullBlockchain) EndBlock() *NullBlockchain { - if n.log.GetLevel() <= logging.DebugLevel { - n.log.Debug("sending EndBlock", logging.Int64("blockHeight", n.blockHeight)) - } - n.app.EndBlock( - abci.RequestEndBlock{ - Height: n.blockHeight, - }, - ) - return n -} - func (n *NullBlockchain) GetGenesisTime(context.Context) (time.Time, error) { return *n.genesis.GenesisTime, nil } @@ -364,7 +331,7 @@ func (n *NullBlockchain) GetChainID(context.Context) (string, error) { func (n *NullBlockchain) GetStatus(context.Context) (*tmctypes.ResultStatus, error) { return &tmctypes.ResultStatus{ NodeInfo: p2p.DefaultNodeInfo{ - Version: "0.34.20", + Version: "0.38.0", }, SyncInfo: tmctypes.SyncInfo{ CatchingUp: n.replaying.Load(), diff --git a/core/blockchain/nullchain/nullchain_test.go b/core/blockchain/nullchain/nullchain_test.go index 10c4c95c6b..9588b309b8 100644 --- a/core/blockchain/nullchain/nullchain_test.go +++ b/core/blockchain/nullchain/nullchain_test.go @@ -31,11 +31,10 @@ import ( vgrand "code.vegaprotocol.io/vega/libs/rand" "code.vegaprotocol.io/vega/logging" + abci "github.com/cometbft/cometbft/abci/types" "github.com/golang/mock/gomock" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" - abci "github.com/tendermint/tendermint/abci/types" - "github.com/tendermint/tendermint/proto/tendermint/types" ) const ( @@ -78,18 +77,13 @@ func testTransactionsCreateBlock(t *testing.T) { // Expected BeginBlock to be called with time shuffled forward by a block now, _ := testChain.chain.GetGenesisTime(ctx) - r := abci.RequestBeginBlock{Header: types.Header{Time: now, ChainID: chainID, Height: 1}} // One round of block processing calls - testChain.app.EXPECT().BeginBlock(gomock.Any()).Do(func(rr abci.RequestBeginBlock) { - require.Equal(t, rr.Header, r.Header) + testChain.app.EXPECT().FinalizeBlock(gomock.Any(), gomock.Any()).Do(func(_ context.Context, rr *abci.RequestFinalizeBlock) { + require.Equal(t, now, rr.Time) + require.Equal(t, int64(1), rr.Height) }).Times(1) - testChain.app.EXPECT().EndBlock(gomock.Any()).Times(1) - testChain.app.EXPECT().Commit().Times(1) - - // Expect only two of the three transactions to be delivered - testChain.app.EXPECT().DeliverTx(gomock.Any()).Times(2) - + testChain.app.EXPECT().Commit(gomock.Any(), gomock.Any()).Times(1) // Send in three transactions, two gets delivered in the block, one left over testChain.chain.SendTransactionSync(ctx, []byte(vgrand.RandomStr(5))) testChain.chain.SendTransactionSync(ctx, []byte(vgrand.RandomStr(5))) @@ -117,14 +111,12 @@ func testTimeForwardingCreatesBlocks(t *testing.T) { testChain.chain.SendTransactionSync(ctx, []byte(vgrand.RandomStr(5))) // One round of block processing calls - testChain.app.EXPECT().BeginBlock(gomock.Any()).Times(10).Do(func(r abci.RequestBeginBlock) { - beginBlockTime = r.Header.Time - }) - testChain.app.EXPECT().EndBlock(gomock.Any()).Times(10).Do(func(r abci.RequestEndBlock) { + + testChain.app.EXPECT().FinalizeBlock(gomock.Any(), gomock.Any()).Times(10).Do(func(_ context.Context, r *abci.RequestFinalizeBlock) { + beginBlockTime = r.Time height = int(r.Height) }) - testChain.app.EXPECT().Commit().Times(10) - testChain.app.EXPECT().DeliverTx(gomock.Any()).Times(3) + testChain.app.EXPECT().Commit(gomock.Any(), gomock.Any()).Times(10) testChain.chain.ForwardTime(step) assert.True(t, beginBlockTime.Equal(now.Add(18*time.Second))) // the start of the next block will take us to +20 seconds @@ -194,17 +186,15 @@ func testReplayWithSnapshotRestore(t *testing.T) { // pretend the protocol restores to block height 10 restoredBlockTime := time.Unix(10000, 15) restoreBlockHeight := int64(10) - testChain.app.EXPECT().Info(gomock.Any()).Times(1).Return( - abci.ResponseInfo{ + testChain.app.EXPECT().Info(gomock.Any(), gomock.Any()).Times(1).Return( + &abci.ResponseInfo{ LastBlockHeight: restoreBlockHeight, - }, + }, nil, ) // we'll replay 5 blocks - testChain.app.EXPECT().BeginBlock(gomock.Any()).Times(5) - testChain.app.EXPECT().DeliverTx(gomock.Any()).Times(10) - testChain.app.EXPECT().EndBlock(gomock.Any()).Times(5) - testChain.app.EXPECT().Commit().Times(5) + testChain.app.EXPECT().FinalizeBlock(gomock.Any(), gomock.Any()).Times(5) + testChain.app.EXPECT().Commit(gomock.Any(), gomock.Any()).Times(5) testChain.ts.EXPECT().GetTimeNow().Times(1).Return(restoredBlockTime) // start the nullchain from a snapshot @@ -212,15 +202,13 @@ func testReplayWithSnapshotRestore(t *testing.T) { require.NoError(t, err) // continue the chain and check we're at the right block height and stuff - testChain.app.EXPECT().DeliverTx(gomock.Any()).Times(2) - testChain.app.EXPECT().EndBlock(gomock.Any()).Times(1) - testChain.app.EXPECT().Commit().Times(1) - // the next begin block should be at block height 16 (restored to 10, replayed 5, starting the next) - req := abci.RequestBeginBlock{} - testChain.app.EXPECT().BeginBlock(gomock.Any()).Times(1).Do(func(r abci.RequestBeginBlock) { + req := &abci.RequestFinalizeBlock{} + testChain.app.EXPECT().FinalizeBlock(gomock.Any(), gomock.Any()).DoAndReturn(func(_ context.Context, r *abci.RequestFinalizeBlock) (*abci.ResponseFinalizeBlock, error) { req = r - }) + return &abci.ResponseFinalizeBlock{}, nil + }).AnyTimes() + testChain.app.EXPECT().Commit(gomock.Any(), gomock.Any()).Times(1) // fill the block testChain.chain.SendTransactionSync(ctx, []byte(vgrand.RandomStr(5))) @@ -228,9 +216,8 @@ func testReplayWithSnapshotRestore(t *testing.T) { genesis, err := testChain.chain.GetGenesisTime(ctx) require.NoError(t, err) - require.Equal(t, int64(16), req.Header.Height) - require.Equal(t, genesis.Add(15*time.Second).UnixNano(), req.Header.Time.UnixNano()) - require.Equal(t, chainID, req.Header.ChainID) + require.Equal(t, int64(16), req.Height) + require.Equal(t, genesis.Add(15*time.Second).UnixNano(), req.Time.UnixNano()) } func testReplayFromGenesis(t *testing.T) { @@ -246,18 +233,16 @@ func testReplayFromGenesis(t *testing.T) { defer newChain.ctrl.Finish() // protocol is starting from 0 - newChain.app.EXPECT().Info(gomock.Any()).Times(1).Return( - abci.ResponseInfo{ + newChain.app.EXPECT().Info(gomock.Any(), gomock.Any()).Times(1).Return( + &abci.ResponseInfo{ LastBlockHeight: 0, - }, + }, nil, ) // we'll replay 15 blocks - newChain.app.EXPECT().InitChain(gomock.Any()).Times(1) - newChain.app.EXPECT().BeginBlock(gomock.Any()).Times(15) - newChain.app.EXPECT().DeliverTx(gomock.Any()).Times(30) - newChain.app.EXPECT().EndBlock(gomock.Any()).Times(15) - newChain.app.EXPECT().Commit().Times(15) + newChain.app.EXPECT().InitChain(gomock.Any(), gomock.Any()).Times(1) + newChain.app.EXPECT().FinalizeBlock(gomock.Any(), gomock.Any()).Times(15).Return(&abci.ResponseFinalizeBlock{}, nil) + newChain.app.EXPECT().Commit(gomock.Any(), gomock.Any()).Times(15) // start the nullchain from genesis err := newChain.chain.StartChain() @@ -274,14 +259,11 @@ func testReplayPanicBlock(t *testing.T) { generateChain(t, testChain, 5) // send in a single transaction that works - testChain.app.EXPECT().BeginBlock(gomock.Any()).Times(1) - testChain.app.EXPECT().DeliverTx(gomock.Any()).Times(1) - testChain.chain.SendTransactionSync(ctx, []byte(vgrand.RandomStr(5))) - // the next transaction will panic - testChain.app.EXPECT().DeliverTx(gomock.Any()).Do(func(rr abci.RequestDeliverTx) { + testChain.app.EXPECT().FinalizeBlock(gomock.Any(), gomock.Any()).Do(func(_ context.Context, rr *abci.RequestFinalizeBlock) { panic("ah panic processing transaction") }).Times(1) + testChain.chain.SendTransactionSync(ctx, []byte(vgrand.RandomStr(5))) require.Panics(t, func() { testChain.chain.SendTransactionSync(ctx, []byte(vgrand.RandomStr(5))) @@ -295,18 +277,16 @@ func testReplayPanicBlock(t *testing.T) { defer newChain.ctrl.Finish() // protocol is starting from 0 - newChain.app.EXPECT().Info(gomock.Any()).Times(1).Return( - abci.ResponseInfo{ + newChain.app.EXPECT().Info(gomock.Any(), gomock.Any()).Times(1).Return( + &abci.ResponseInfo{ LastBlockHeight: 0, - }, + }, nil, ) // we'll replay 5 full blocks, and process the 6th "panic" block ready to start the 7th - newChain.app.EXPECT().InitChain(gomock.Any()).Times(1) - newChain.app.EXPECT().BeginBlock(gomock.Any()).Times(6) - newChain.app.EXPECT().DeliverTx(gomock.Any()).Times(12) - newChain.app.EXPECT().EndBlock(gomock.Any()).Times(6) - newChain.app.EXPECT().Commit().Times(6) + newChain.app.EXPECT().InitChain(gomock.Any(), gomock.Any()).Times(1) + newChain.app.EXPECT().FinalizeBlock(gomock.Any(), gomock.Any()).Times(6) + newChain.app.EXPECT().Commit(gomock.Any(), gomock.Any()).Times(6) // start the nullchain from genesis err := newChain.chain.StartChain() @@ -355,8 +335,8 @@ func getTestNullChain(t *testing.T, txnPerBlock uint64, d time.Duration) *testNu t.Helper() nc := getTestUnstartedNullChain(t, txnPerBlock, d, nil) - nc.app.EXPECT().Info(gomock.Any()).Times(1) - nc.app.EXPECT().InitChain(gomock.Any()).Times(1) + nc.app.EXPECT().Info(gomock.Any(), gomock.Any()).Times(1).Return(&abci.ResponseInfo{}, nil) + nc.app.EXPECT().InitChain(gomock.Any(), gomock.Any()).Times(1) err := nc.chain.StartChain() require.NoError(t, err) @@ -382,15 +362,13 @@ func generateChain(t *testing.T, nc *testNullBlockChain, height int) { nTxns := int(nc.cfg.TransactionsPerBlock) * height ctx := context.Background() - nc.app.EXPECT().InitChain(gomock.Any()).Times(1) - nc.app.EXPECT().BeginBlock(gomock.Any()).Times(height) - nc.app.EXPECT().DeliverTx(gomock.Any()).Times(nTxns) - nc.app.EXPECT().EndBlock(gomock.Any()).Times(height) - nc.app.EXPECT().Commit().Times(height) - nc.app.EXPECT().Info(gomock.Any()).Times(1).Return( - abci.ResponseInfo{ + nc.app.EXPECT().InitChain(gomock.Any(), gomock.Any()).Times(1) + nc.app.EXPECT().FinalizeBlock(gomock.Any(), gomock.Any()).Times(height).Return(&abci.ResponseFinalizeBlock{}, nil) + nc.app.EXPECT().Commit(gomock.Any(), gomock.Any()).Times(height) + nc.app.EXPECT().Info(gomock.Any(), gomock.Any()).Times(1).Return( + &abci.ResponseInfo{ LastBlockHeight: 0, - }, + }, nil, ) // start the nullchain diff --git a/core/blockchain/nullchain/replay.go b/core/blockchain/nullchain/replay.go index 4b0dbf7564..a0396cf46b 100644 --- a/core/blockchain/nullchain/replay.go +++ b/core/blockchain/nullchain/replay.go @@ -18,6 +18,7 @@ package nullchain import ( "bufio" "bytes" + "context" "encoding/hex" "encoding/json" "errors" @@ -31,8 +32,7 @@ import ( vgcrypto "code.vegaprotocol.io/vega/libs/crypto" "code.vegaprotocol.io/vega/logging" - abci "github.com/tendermint/tendermint/abci/types" - "github.com/tendermint/tendermint/proto/tendermint/types" + abci "github.com/cometbft/cometbft/abci/types" ) var ErrReplayFileIsRequired = errors.New("replay-file is required when replay/record is enabled") @@ -75,8 +75,8 @@ func NewNullChainReplayer(app ApplicationService, cfg blockchain.ReplayConfig, l }, nil } -func (r *Replayer) InitChain(req abci.RequestInitChain) (resp abci.ResponseInitChain) { - return r.app.InitChain(req) +func (r *Replayer) InitChain(req abci.RequestInitChain) (*abci.ResponseInitChain, error) { + return r.app.InitChain(context.Background(), &req) } func (r *Replayer) Stop() error { @@ -87,14 +87,12 @@ func (r *Replayer) Stop() error { // startBlock saves in memory all the transactions in the block, we do not write until saveBlock us called // with a potential appHash. -func (r *Replayer) startBlock(height, now int64, txs []*abci.RequestDeliverTx) { +func (r *Replayer) startBlock(height, now int64, txs [][]byte) { r.current = &blockData{ Height: height, Time: now, } - for _, tx := range txs { - r.current.Txs = append(r.current.Txs, tx.Tx) - } + r.current.Txs = append(r.current.Txs, txs...) } // saveBlock writes to the replay file the details of the current block adding the appHash to it. @@ -124,7 +122,7 @@ func readLine(r *bufio.Reader) ([]byte, error) { // replayChain sends all the recorded per-block transactions into the protocol returning the block-height and block-time it reached // appHeight is the block-height the application will process next, any blocks less than this will not be replayed. -func (r *Replayer) replayChain(appHeight int64, chainID string) (int64, time.Time, error) { +func (r *Replayer) replayChain(appHeight int64) (int64, time.Time, error) { var replayedHeight int64 var replayedTime time.Time @@ -159,28 +157,14 @@ func (r *Replayer) replayChain(appHeight int64, chainID string) (int64, time.Tim } r.log.Info("replaying block", logging.Int64("height", data.Height), logging.Int("ntxns", len(data.Txs))) - r.app.BeginBlock( - abci.RequestBeginBlock{ - Header: types.Header{ - Time: time.Unix(0, data.Time), - Height: data.Height, - ChainID: chainID, - }, - Hash: vgcrypto.Hash([]byte(strconv.FormatInt(data.Height+data.Time, 10))), - }, - ) - - // deliever all the txns in that block - for _, tx := range data.Txs { - r.app.DeliverTx(abci.RequestDeliverTx{Tx: tx}) - } + resp, _ := r.app.FinalizeBlock(context.Background(), &abci.RequestFinalizeBlock{ + Height: data.Height, + Time: time.Unix(0, data.Time), + Hash: vgcrypto.Hash([]byte(strconv.FormatInt(data.Height+data.Time, 10))), + Txs: data.Txs, + }) - r.app.EndBlock( - abci.RequestEndBlock{ - Height: data.Height, - }, - ) - resp := r.app.Commit() + r.app.Commit(context.Background(), &abci.RequestCommit{}) if len(data.AppHash) == 0 { // we've replayed a block which when recorded must have panicked so we do not have a apphash @@ -189,8 +173,8 @@ func (r *Replayer) replayChain(appHeight int64, chainID string) (int64, time.Tim continue } - if !bytes.Equal(data.AppHash, resp.Data) { - return replayedHeight, replayedTime, fmt.Errorf("appHash mismatch on replay, expected %s got %s", hex.EncodeToString(data.AppHash), hex.EncodeToString(resp.Data)) + if !bytes.Equal(data.AppHash, resp.AppHash) { + return replayedHeight, replayedTime, fmt.Errorf("appHash mismatch on replay, expected %s got %s", hex.EncodeToString(data.AppHash), hex.EncodeToString(resp.AppHash)) } } diff --git a/core/blockchain/response.go b/core/blockchain/response.go index 4d57d1164d..44caa7b2ec 100644 --- a/core/blockchain/response.go +++ b/core/blockchain/response.go @@ -15,7 +15,7 @@ package blockchain -import "github.com/tendermint/tendermint/abci/types" +import "github.com/cometbft/cometbft/abci/types" const ( // AbciTxnValidationFailure ... @@ -37,30 +37,30 @@ const ( AbciSpamError uint32 = 89 ) -func NewResponseCheckTx(code uint32, info string) types.ResponseCheckTx { - return types.ResponseCheckTx{ +func NewResponseCheckTx(code uint32, info string) *types.ResponseCheckTx { + return &types.ResponseCheckTx{ Code: code, Info: info, } } -func NewResponseCheckTxError(code uint32, err error) types.ResponseCheckTx { - return types.ResponseCheckTx{ +func NewResponseCheckTxError(code uint32, err error) *types.ResponseCheckTx { + return &types.ResponseCheckTx{ Code: code, Info: err.Error(), Data: []byte(err.Error()), } } -func NewResponseDeliverTx(code uint32, info string) types.ResponseDeliverTx { - return types.ResponseDeliverTx{ +func NewResponseDeliverTx(code uint32, info string) *types.ExecTxResult { + return &types.ExecTxResult{ Code: code, Info: info, } } -func NewResponseDeliverTxError(code uint32, err error) types.ResponseDeliverTx { - return types.ResponseDeliverTx{ +func NewResponseDeliverTxError(code uint32, err error) *types.ExecTxResult { + return &types.ExecTxResult{ Code: code, Info: err.Error(), Data: []byte(err.Error()), diff --git a/core/checkpoint/engine.go b/core/checkpoint/engine.go index 8fd5790108..cf5110a7b2 100644 --- a/core/checkpoint/engine.go +++ b/core/checkpoint/engine.go @@ -254,7 +254,7 @@ func (e *Engine) makeCheckpoint(ctx context.Context) *types.CheckpointState { } // add block height to checkpoint h, _ := vegactx.BlockHeightFromContext(ctx) - if err := cp.SetBlockHeight(h); err != nil { + if err := cp.SetBlockHeight(int64(h)); err != nil { e.log.Panic("could not set block height", logging.Error(err)) } cpState := &types.CheckpointState{} @@ -263,7 +263,7 @@ func (e *Engine) makeCheckpoint(ctx context.Context) *types.CheckpointState { panic(fmt.Errorf("checkpoint could not be created: %w", err)) } - e.log.Debug("checkpoint taken", logging.Int64("block-height", h)) + e.log.Debug("checkpoint taken", logging.Uint64("block-height", h)) return cpState } diff --git a/core/docs/chain-replay.md b/core/docs/chain-replay.md index bba529d610..25e24eae5d 100644 --- a/core/docs/chain-replay.md +++ b/core/docs/chain-replay.md @@ -62,11 +62,11 @@ Instead of a backup, which effectively replays the full chain from genesis, you ## References -- https://github.com/tendermint/tendermint/blob/master/docs/introduction/quick-start.md +- https://github.com/cometbft/cometbft/blob/master/docs/introduction/quick-start.md - https://docs.tendermint.com/master/spec/abci/apps.html - https://github.com/tendermint/spec/blob/master/spec/abci/README.md - https://docs.tendermint.com/master/spec/abci/apps.html#state-sync [wallet]: https://github.com/vegaprotocol/vega#configuration [gcloud]: https://cloud.google.com/sdk/docs/install -[tendermint]: https://github.com/tendermint/tendermint/blob/master/docs/introduction/install.md \ No newline at end of file +[tendermint]: https://github.com/cometbft/cometbft/blob/master/docs/introduction/install.md \ No newline at end of file diff --git a/core/events/bus.go b/core/events/bus.go index 93811a48b5..600bebe1ee 100644 --- a/core/events/bus.go +++ b/core/events/bus.go @@ -446,7 +446,7 @@ func newBase(ctx context.Context, t Type) *Base { traceID: tID, chainID: cID, txHash: txHash, - blockNr: h, + blockNr: int64(h), et: t, } } diff --git a/core/events/checkpoint.go b/core/events/checkpoint.go index fad7de425e..6daf6bc1ed 100644 --- a/core/events/checkpoint.go +++ b/core/events/checkpoint.go @@ -37,7 +37,7 @@ func NewCheckpointEvent(ctx context.Context, snap *types.CheckpointState) *Check data: eventspb.CheckpointEvent{ Hash: hex.EncodeToString(snap.Hash), BlockHash: block, - BlockHeight: uint64(height), + BlockHeight: height, }, } } diff --git a/core/execution/common/market_activity_tracker_internal_test.go b/core/execution/common/market_activity_tracker_internal_test.go index e34b2678b3..93872067ac 100644 --- a/core/execution/common/market_activity_tracker_internal_test.go +++ b/core/execution/common/market_activity_tracker_internal_test.go @@ -201,7 +201,6 @@ func TestPositions(t *testing.T) { tracker.recordPosition("p1", 30, num.DecimalOne(), time.Unix(45, 0), time.Unix(0, 0)) // 155555544 * ( 10000000 - 2500000 ) + ( 300000000 * 2500000 ) / 10000000 = 191666658 tracker.processPositionEndOfEpoch(time.Unix(0, 0), time.Unix(60, 0)) - println(tracker.getPositionMetricTotal("p1", 1)) require.Equal(t, uint64(191666658), tracker.getPositionMetricTotal("p1", 1)) // epoch 2 diff --git a/core/genesis/sign.go b/core/genesis/sign.go index aa79599c85..b6d2813b23 100644 --- a/core/genesis/sign.go +++ b/core/genesis/sign.go @@ -18,7 +18,7 @@ package genesis import ( "encoding/json" - tmtypes "github.com/tendermint/tendermint/types" + tmtypes "github.com/cometbft/cometbft/types" ) func FromJSON(rawGenesisDoc []byte) (*tmtypes.GenesisDoc, *State, error) { diff --git a/core/nodewallets/commander.go b/core/nodewallets/commander.go index 495b75e5da..b11059bc6d 100644 --- a/core/nodewallets/commander.go +++ b/core/nodewallets/commander.go @@ -28,8 +28,8 @@ import ( commandspb "code.vegaprotocol.io/vega/protos/vega/commands/v1" "github.com/cenkalti/backoff" + tmctypes "github.com/cometbft/cometbft/rpc/core/types" "github.com/golang/protobuf/proto" - tmctypes "github.com/tendermint/tendermint/rpc/core/types" ) const ( diff --git a/core/nodewallets/commander_test.go b/core/nodewallets/commander_test.go index 8c9b879198..86f589a142 100644 --- a/core/nodewallets/commander_test.go +++ b/core/nodewallets/commander_test.go @@ -28,10 +28,10 @@ import ( "code.vegaprotocol.io/vega/logging" commandspb "code.vegaprotocol.io/vega/protos/vega/commands/v1" + tmctypes "github.com/cometbft/cometbft/rpc/core/types" "github.com/golang/mock/gomock" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" - tmctypes "github.com/tendermint/tendermint/rpc/core/types" ) type testCommander struct { diff --git a/core/nodewallets/mocks/chain_mock.go b/core/nodewallets/mocks/chain_mock.go index 73f6e23041..8369da1e97 100644 --- a/core/nodewallets/mocks/chain_mock.go +++ b/core/nodewallets/mocks/chain_mock.go @@ -9,8 +9,8 @@ import ( reflect "reflect" v1 "code.vegaprotocol.io/vega/protos/vega/commands/v1" + coretypes "github.com/cometbft/cometbft/rpc/core/types" gomock "github.com/golang/mock/gomock" - coretypes "github.com/tendermint/tendermint/rpc/core/types" ) // MockChain is a mock of Chain interface. diff --git a/core/pow/engine.go b/core/pow/engine.go index 519922abda..592a8a37f3 100644 --- a/core/pow/engine.go +++ b/core/pow/engine.go @@ -19,9 +19,7 @@ import ( "context" "encoding/hex" "errors" - "strconv" "sync" - "time" "code.vegaprotocol.io/vega/core/blockchain/abci" "code.vegaprotocol.io/vega/core/types" @@ -33,17 +31,25 @@ import ( ) const ( - ringSize = 500 - minBanDuration = time.Second * 30 // minimum ban duration + ringSize = 500 ) +type ValidationEntry struct { + ValResult ValidationResult + Difficulty *uint + Tx abci.Tx +} + var ErrNonceAlreadyUsedByParty = errors.New("nonce already used by party") -var banDurationAsEpochFraction = num.DecimalOne().Div(num.DecimalFromInt64(48)) // 1/48 of an epoch will be the default 30 minutes ban +type ValidationResult int64 -type EpochEngine interface { - NotifyOnEpoch(f func(context.Context, types.Epoch), r func(context.Context, types.Epoch)) -} +const ( + ValidationResultVerificationPowError ValidationResult = iota + ValidationResultValidatorCommand + ValidationResultTooManyTx + ValidationResultSuccess +) // params defines the modifiable set of parameters to be applied at the from block and valid for transactions generated for the untilBlock. type params struct { @@ -78,17 +84,9 @@ type partyStateForBlock struct { type state struct { blockToPartyState map[uint64]map[string]*partyStateForBlock } - -//go:generate go run github.com/golang/mock/mockgen -destination mocks/time_service_mock.go -package mocks code.vegaprotocol.io/vega/core/pow TimeService -type TimeService interface { - GetTimeNow() time.Time -} - type Engine struct { - timeService TimeService - activeParams []*params // active sets of parameters - activeStates []*state // active states corresponding to the sets of parameters - bannedParties map[string]time.Time // banned party -> release time + activeParams []*params // active sets of parameters + activeStates []*state // active states corresponding to the sets of parameters currentBlock uint64 // the current block height blockHeight [ringSize]uint64 // block heights in scope ring buffer - this has a fixed size which is equal to the maximum value of the network parameter @@ -108,18 +106,16 @@ type Engine struct { noVerify bool // disables verification of PoW in scenario, where we use the null chain and we do not want to send transaction w/o verification // snapshot key - hashKeys []string - log *logging.Logger - lock sync.RWMutex - banDuration time.Duration + hashKeys []string + log *logging.Logger + lock sync.RWMutex } // New instantiates the proof of work engine. -func New(log *logging.Logger, config Config, timeService TimeService) *Engine { +func New(log *logging.Logger, config Config) *Engine { log = log.Named(namedLogger) log.SetLevel(config.Level.Get()) e := &Engine{ - bannedParties: map[string]time.Time{}, log: log, hashKeys: []string{(&types.PayloadProofOfWork{}).Key()}, activeParams: []*params{}, @@ -131,54 +127,62 @@ func New(log *logging.Logger, config Config, timeService TimeService) *Engine { seenNonceRef: map[nonceRef]struct{}{}, mempoolSeenTid: map[string]struct{}{}, heightToTid: map[uint64][]string{}, - timeService: timeService, } e.log.Info("PoW spam protection started") return e } -// OnEpochDurationChanged updates the ban duration as a fraction of the epoch duration. -func (e *Engine) OnEpochDurationChanged(_ context.Context, duration time.Duration) error { - epochImpliedDurationNano, _ := num.UintFromDecimal(num.DecimalFromInt64(duration.Nanoseconds()).Mul(banDurationAsEpochFraction)) - epochImpliedDurationDuration := time.Duration(epochImpliedDurationNano.Uint64()) - if epochImpliedDurationDuration < minBanDuration { - e.banDuration = minBanDuration - } else { - e.banDuration = epochImpliedDurationDuration - } - return nil -} - // OnBeginBlock updates the block height and block hash and clears any out of scope parameters set and states. -func (e *Engine) BeginBlock(blockHeight uint64, blockHash string) { +// It also records all of the block's transactions. +func (e *Engine) BeginBlock(blockHeight uint64, blockHash string, txs []abci.Tx) { e.lock.Lock() defer e.lock.Unlock() - e.currentBlock = blockHeight idx := blockHeight % ringSize e.blockHeight[idx] = blockHeight e.blockHash[idx] = blockHash + e.updatePowState(txs) +} - tm := e.timeService.GetTimeNow() - - // check if there are banned parties who can be released - for k, v := range e.bannedParties { - if !tm.Before(v) { - delete(e.bannedParties, k) - e.log.Info("released proof of work spam ban from", logging.String("party", k)) +// CheckTx is called by checkTx in the abci and verifies the proof of work, it doesn't update any state. +func (e *Engine) CheckTx(tx abci.Tx) error { + if e.log.IsDebug() { + e.lock.RLock() + e.log.Debug("checktx got tx", logging.String("command", tx.Command().String()), logging.Uint64("height", tx.BlockHeight()), logging.String("tid", tx.GetPoWTID()), logging.Uint64("current-block", e.currentBlock)) + e.lock.RUnlock() + } + if !tx.Command().IsValidatorCommand() { + e.lock.Lock() + if _, ok := e.mempoolSeenTid[tx.GetPoWTID()]; ok { + e.log.Error("tid already seen", logging.String("tid", tx.GetPoWTID()), logging.String("party", tx.Party())) + e.lock.Unlock() + return errors.New("proof of work tid already seen by the node") } + e.mempoolSeenTid[tx.GetPoWTID()] = struct{}{} + e.lock.Unlock() } + + _, err := e.verify(tx) + if err != nil { + e.log.Debug("checktx error", logging.String("command", tx.Command().String()), logging.Uint64("height", tx.BlockHeight()), logging.String("tid", tx.GetPoWTID()), logging.Uint64("current-block", e.currentBlock)) + } + return err } -// EndOfBlock clears up block data structures at the end of the block. -func (e *Engine) EndOfBlock() { - e.lock.Lock() - defer e.lock.Unlock() +// EndPrepareProposal is a callback called at the end of prepareBlock to revert to the state +// before prepare block. +func (e *Engine) EndPrepareProposal(txs []ValidationEntry) { + e.log.Debug("EndPrepareBlock called with", logging.Int("txs", len(txs))) + e.rollback(txs) +} +// updatePowState updates the pow state given the block transaction and cleans up out of scope states and param sets. +func (e *Engine) updatePowState(txs []abci.Tx) { + e.mempoolSeenTid = map[string]struct{}{} // run this once for migration cleanup // this is going to clean up blocks that belong to inactive states which are unreachable by the latter loop. if e.lastPruningBlock == 0 { - if e.activeParams[0].fromBlock > 0 { + if len(e.activeParams) > 0 && e.activeParams[0].fromBlock > 0 { end := e.activeParams[0].fromBlock for block := uint64(0); block <= end; block++ { if b, ok := e.heightToTx[block]; ok { @@ -199,6 +203,43 @@ func (e *Engine) EndOfBlock() { } } + for _, tx := range txs { + d, _ := e.verifyWithLock(tx) + dUint := uint(d) + txHash := hex.EncodeToString(tx.Hash()) + txBlock := tx.BlockHeight() + stateInd := 0 + for i, p := range e.activeParams { + if txBlock >= p.fromBlock && (p.untilBlock == nil || *p.untilBlock >= txBlock) { + stateInd = i + break + } + } + state := e.activeStates[stateInd] + e.seenTx[txHash] = struct{}{} + e.heightToTx[tx.BlockHeight()] = append(e.heightToTx[tx.BlockHeight()], txHash) + if tx.Command().IsValidatorCommand() { + continue + } + + e.heightToTid[tx.BlockHeight()] = append(e.heightToTid[tx.BlockHeight()], tx.GetPoWTID()) + e.heightToNonceRef[tx.BlockHeight()] = append(e.heightToNonceRef[tx.BlockHeight()], nonceRef{tx.Party(), tx.GetNonce()}) + e.seenTid[tx.GetPoWTID()] = struct{}{} + e.seenNonceRef[nonceRef{tx.Party(), tx.GetNonce()}] = struct{}{} + if _, ok := state.blockToPartyState[txBlock]; !ok { + state.blockToPartyState[txBlock] = map[string]*partyStateForBlock{tx.Party(): {observedDifficulty: dUint, seenCount: uint(1)}} + continue + } + if _, ok := state.blockToPartyState[txBlock][tx.Party()]; !ok { + state.blockToPartyState[txBlock][tx.Party()] = &partyStateForBlock{observedDifficulty: dUint, seenCount: uint(1)} + continue + } + partyState := state.blockToPartyState[txBlock][tx.Party()] + partyState.observedDifficulty += dUint + partyState.seenCount++ + } + + // update out of scope states/params toDelete := []int{} // iterate over parameters set and clear them out if they're not relevant anymore. for i, p := range e.activeParams { @@ -248,10 +289,10 @@ func (e *Engine) EndOfBlock() { } } -func (e *Engine) Commit() { - e.lock.Lock() - e.mempoolSeenTid = map[string]struct{}{} - e.lock.Unlock() +// OnFinalize is called when the finalizeBlock is completed to clenup the mempool cache. +func (e *Engine) OnFinalize() { + e.log.Info("mempool seen cleared") + e.log.Debug("OnFinalize") } func (e *Engine) DisableVerification() { @@ -259,39 +300,92 @@ func (e *Engine) DisableVerification() { e.noVerify = true } -// CheckTx is called by checkTx in the abci and verifies the proof of work, it doesn't update any state. -func (e *Engine) CheckTx(tx abci.Tx) error { - if e.log.IsDebug() { - e.lock.RLock() - e.log.Debug("checktx got tx", logging.String("command", tx.Command().String()), logging.Uint64("height", tx.BlockHeight()), logging.String("tid", tx.GetPoWTID()), logging.Uint64("current-block", e.currentBlock)) - e.lock.RUnlock() - } - if !tx.Command().IsValidatorCommand() { - e.lock.Lock() - if _, ok := e.mempoolSeenTid[tx.GetPoWTID()]; ok { - e.log.Error("tid already seen", logging.String("tid", tx.GetPoWTID()), logging.String("party", tx.Party())) - e.lock.Unlock() - return errors.New("proof of work tid already seen") +// rollback is called without the lock. For each input validation entry depending on its status it reverts any changes made to the interim block state. +func (e *Engine) rollback(txs []ValidationEntry) { + e.lock.Lock() + defer e.lock.Unlock() + for _, ve := range txs { + e.log.Debug("rollback", logging.String("party", ve.Tx.Party()), logging.String("tx-hash", hex.EncodeToString(ve.Tx.Hash())), logging.Int64("ve-result", int64(ve.ValResult))) + // pow error does not change state, we can skip + if ve.ValResult == ValidationResultVerificationPowError { + continue + } + txHash := hex.EncodeToString(ve.Tx.Hash()) + // remove the transaction from seenTx - need to acquire lock! + + delete(e.seenTx, txHash) + + // if it's a validator command, we're done + if ve.ValResult == ValidationResultValidatorCommand { + continue + } + + // otherwise need to remove the seenTid from the block state - need to acquire lock! + delete(e.seenTid, ve.Tx.GetPoWTID()) + delete(e.seenNonceRef, nonceRef{ve.Tx.Party(), ve.Tx.GetNonce()}) + + // if the validation result is too many transactions or the difficulty is nil, nothing to revert + if ve.ValResult == ValidationResultTooManyTx || ve.Difficulty == nil { + continue + } + stateInd := 0 + txBlock := ve.Tx.BlockHeight() + for i, p := range e.activeParams { + if txBlock >= p.fromBlock && (p.untilBlock == nil || *p.untilBlock >= txBlock) { + stateInd = i + break + } + } + state := e.activeStates[stateInd] + if _, ok := state.blockToPartyState[txBlock]; !ok { + e.log.Error("cannot find state of the block - that should be impossible") + } else if _, ok := state.blockToPartyState[txBlock][ve.Tx.Party()]; !ok { + e.log.Error("cannot find the party in the block state - that should be impossible") + } + + partyState := state.blockToPartyState[txBlock][ve.Tx.Party()] + e.log.Debug("found party state for party", logging.Bool("found", partyState != nil), logging.String("party", ve.Tx.Party())) + partyState.seenCount-- + partyState.observedDifficulty -= *ve.Difficulty + if partyState.seenCount == 0 { + e.log.Debug("seen count for party is zero, removing party from block state", logging.String("party", ve.Tx.Party())) + delete(state.blockToPartyState[txBlock], ve.Tx.Party()) + } + if len(state.blockToPartyState[txBlock]) == 0 { + e.log.Debug("no more transactions for block, removing block height", logging.Uint64("height", txBlock)) + delete(state.blockToPartyState, txBlock) } - e.mempoolSeenTid[tx.GetPoWTID()] = struct{}{} - e.lock.Unlock() } +} - _, err := e.verify(tx) - return err +func (e *Engine) ProcessProposal(txs []abci.Tx) bool { + ves := []ValidationEntry{} + success := true + for _, tx := range txs { + vr, d := e.CheckBlockTx(tx) + ves = append(ves, ValidationEntry{Tx: tx, Difficulty: d, ValResult: vr}) + if vr == ValidationResultVerificationPowError || vr == ValidationResultTooManyTx { + success = false + break + } + } + e.rollback(ves) + return success } -// DeliverTx is called by deliverTx in the abci and verifies the proof of work, takes a not of the transaction id and counts the number of transactions of the party in the block. -func (e *Engine) DeliverTx(tx abci.Tx) error { +// CheckBlockTx verifies if a transaction can be included a prepared/verified block. +func (e *Engine) CheckBlockTx(tx abci.Tx) (ValidationResult, *uint) { if e.log.IsDebug() { e.lock.RLock() - e.log.Debug("delivertx got tx", logging.String("command", tx.Command().String()), logging.Uint64("height", tx.BlockHeight()), logging.String("tid", tx.GetPoWTID()), logging.Uint64("current-block", e.currentBlock)) + e.log.Debug("CheckBlockTx got tx", logging.String("command", tx.Command().String()), logging.Uint64("height", tx.BlockHeight()), logging.String("tid", tx.GetPoWTID()), logging.Uint64("current-block", e.currentBlock)) e.lock.RUnlock() } d, err := e.verify(tx) + dUint := uint(d) if err != nil { - return err + e.log.Error("pow error", logging.Error(err)) + return ValidationResultVerificationPowError, nil } e.lock.Lock() @@ -311,67 +405,63 @@ func (e *Engine) DeliverTx(tx abci.Tx) error { params := e.activeParams[stateInd] e.seenTx[txHash] = struct{}{} - e.heightToTx[tx.BlockHeight()] = append(e.heightToTx[tx.BlockHeight()], txHash) if tx.Command().IsValidatorCommand() { - return nil + return ValidationResultValidatorCommand, nil } // if version supports pow, save the pow result and the tid - e.heightToTid[tx.BlockHeight()] = append(e.heightToTid[tx.BlockHeight()], tx.GetPoWTID()) - e.heightToNonceRef[tx.BlockHeight()] = append(e.heightToNonceRef[tx.BlockHeight()], nonceRef{tx.Party(), tx.GetNonce()}) e.seenTid[tx.GetPoWTID()] = struct{}{} e.seenNonceRef[nonceRef{tx.Party(), tx.GetNonce()}] = struct{}{} // if it's the first transaction we're seeing from any party for this block height, initialise the state if _, ok := state.blockToPartyState[txBlock]; !ok { - state.blockToPartyState[txBlock] = map[string]*partyStateForBlock{tx.Party(): {observedDifficulty: uint(d), seenCount: uint(1)}} + state.blockToPartyState[txBlock] = map[string]*partyStateForBlock{tx.Party(): {observedDifficulty: dUint, seenCount: uint(1)}} if e.log.IsDebug() { e.log.Debug("transaction accepted", logging.String("tid", tx.GetPoWTID())) } - return nil + e.log.Debug("updated party block state", logging.Uint64("height", txBlock), logging.String("party", tx.Party()), logging.String("tx-hash", txHash)) + return ValidationResultSuccess, &dUint } // if it's the first transaction for the party for this block height if _, ok := state.blockToPartyState[txBlock][tx.Party()]; !ok { - state.blockToPartyState[txBlock] = map[string]*partyStateForBlock{tx.Party(): {observedDifficulty: uint(d), seenCount: uint(1)}} - return nil + state.blockToPartyState[txBlock][tx.Party()] = &partyStateForBlock{observedDifficulty: dUint, seenCount: uint(1)} + e.log.Debug("updated party block state", logging.Uint64("height", txBlock), logging.String("party", tx.Party()), logging.String("tx-hash", txHash)) + return ValidationResultSuccess, &dUint } // it's not the first transaction for the party for the given block height // if we've seen less than the allowed number of transactions per block, take a note and let it pass partyState := state.blockToPartyState[txBlock][tx.Party()] if partyState.seenCount < uint(params.spamPoWNumberOfTxPerBlock) { - partyState.observedDifficulty += uint(d) + partyState.observedDifficulty += dUint partyState.seenCount++ if e.log.IsDebug() { e.log.Debug("transaction accepted", logging.String("tid", tx.GetPoWTID())) } - return nil + e.log.Debug("updated party block state", logging.Uint64("height", txBlock), logging.String("party", tx.Party()), logging.String("tx-hash", txHash)) + return ValidationResultSuccess, &dUint } - // if we've seen already enough transactions and `spamPoWIncreasingDifficulty` is not enabled then fail the transaction and ban the party + // if we've seen already enough transactions and `spamPoWIncreasingDifficulty` is not enabled then fail the transaction if !params.spamPoWIncreasingDifficulty { - e.bannedParties[tx.Party()] = e.timeService.GetTimeNow().Add(e.banDuration) - return errors.New("too many transactions per block") + return ValidationResultTooManyTx, nil } // calculate the expected difficulty - allow spamPoWNumberOfTxPerBlock for every level of increased difficulty totalExpectedDifficulty, _ := calculateExpectedDifficulty(params.spamPoWDifficulty, uint(params.spamPoWNumberOfTxPerBlock), partyState.seenCount+1) - // if the observed difficulty sum is less than the expected difficulty, ban the party and reject the tx - if partyState.observedDifficulty+uint(d) < totalExpectedDifficulty { - banTime := e.timeService.GetTimeNow().Add(e.banDuration) - e.bannedParties[tx.Party()] = banTime - e.log.Info("banning party for not respecting required difficulty rules", logging.String("party", tx.Party()), logging.Time("until", banTime)) - return errors.New("too many transactions per block") + // if the observed difficulty sum is less than the expected difficulty, reject the tx + if partyState.observedDifficulty+dUint < totalExpectedDifficulty { + return ValidationResultTooManyTx, nil } - partyState.observedDifficulty += +uint(d) + partyState.observedDifficulty += dUint partyState.seenCount++ - - return nil + e.log.Debug("updated party block state", logging.Uint64("height", txBlock), logging.String("party", tx.Party()), logging.String("tx-hash", txHash)) + return ValidationResultSuccess, &dUint } // calculateExpectedDifficulty calculates the expected total difficulty given the default difficulty, the max batch size and the number of seen transactions @@ -421,30 +511,14 @@ func (e *Engine) findParamsForBlockHeight(height uint64) int { return paramIndex } -// verify the proof of work -// 1. check that the party is not banned -// 2. check that the block height is already known to the engine - this is rejected if it's too old or not yet seen as we need to know the block hash -// 3. check that we've not seen this transaction ID before (in the previous `spamPoWNumberOfPastBlocks` blocks) -// 4. check that the proof of work can be verified with the required difficulty. -func (e *Engine) verify(tx abci.Tx) (byte, error) { - e.lock.RLock() - defer e.lock.RUnlock() +func (e *Engine) verifyWithLock(tx abci.Tx) (byte, error) { var h byte - if e.noVerify { return h, nil } - // check if the party is banned for the epoch - if _, ok := e.bannedParties[tx.Party()]; ok { - e.log.Error("party is banned", logging.String("tid", tx.GetPoWTID()), logging.String("party", tx.Party())) - return h, errors.New("party is banned from sending transactions") - } - // check if the transaction was seen in scope txHash := hex.EncodeToString(tx.Hash()) - - // check for replay attacks if _, ok := e.seenTx[txHash]; ok { e.log.Error("replay attack: txHash already used", logging.String("tx-hash", txHash), logging.String("tid", tx.GetPoWTID()), logging.String("party", tx.Party()), logging.String("command", tx.Command().String())) return h, errors.New("transaction hash already used") @@ -505,6 +579,16 @@ func (e *Engine) verify(tx abci.Tx) (byte, error) { return diff, nil } +// verify the proof of work +// 1. check that the block height is already known to the engine - this is rejected if it's too old or not yet seen as we need to know the block hash +// 2. check that we've not seen this transaction ID before (in the previous `spamPoWNumberOfPastBlocks` blocks) +// 3. check that the proof of work can be verified with the required difficulty. +func (e *Engine) verify(tx abci.Tx) (byte, error) { + e.lock.RLock() + defer e.lock.RUnlock() + return e.verifyWithLock(tx) +} + func (e *Engine) updateParam(netParamName, netParamValue string, p *params) { switch netParamName { case "spamPoWNumberOfPastBlocks": @@ -718,18 +802,8 @@ func (e *Engine) GetSpamStatistics(partyID string) *protoapi.PoWStatistic { }) } - until := e.bannedParties[partyID].UnixNano() - - var bannedUntil *string - - if until > 0 { - untilStr := strconv.FormatInt(until, 10) - bannedUntil = &untilStr - } - return &protoapi.PoWStatistic{ BlockStates: stats, - BannedUntil: bannedUntil, NumberOfPastBlocks: e.getActiveParams().spamPoWNumberOfPastBlocks, } } diff --git a/core/pow/engine_test.go b/core/pow/engine_test.go index a210569dd7..f0f7476716 100644 --- a/core/pow/engine_test.go +++ b/core/pow/engine_test.go @@ -17,13 +17,12 @@ package pow import ( "context" - "encoding/hex" "errors" "math/rand" "testing" - "time" - "code.vegaprotocol.io/vega/core/delegation/mocks" + "code.vegaprotocol.io/vega/core/blockchain/abci" + "code.vegaprotocol.io/vega/core/pow/mocks" "code.vegaprotocol.io/vega/core/txn" "code.vegaprotocol.io/vega/libs/crypto" "code.vegaprotocol.io/vega/libs/num" @@ -34,53 +33,44 @@ import ( "github.com/stretchr/testify/require" ) -func TestUpdateBanDuration(t *testing.T) { - e := New(logging.NewTestLogger(), NewDefaultConfig(), mocks.NewMockTimeService(gomock.NewController(t))) - e.OnEpochDurationChanged(context.Background(), time.Hour*10) - require.Equal(t, float64(750), e.banDuration.Round(time.Second).Seconds()) // 10h/48 = 10 * 60 * 60 / 48 = 750s - - e.OnEpochDurationChanged(context.Background(), time.Second*10) - require.Equal(t, float64(30), e.banDuration.Round(time.Second).Seconds()) // minimum of 30s applies -} - func TestSpamPoWNumberOfPastBlocks(t *testing.T) { - e := New(logging.NewTestLogger(), NewDefaultConfig(), mocks.NewMockTimeService(gomock.NewController(t))) + e := New(logging.NewTestLogger(), NewDefaultConfig()) e.UpdateSpamPoWNumberOfPastBlocks(context.Background(), num.NewUint(200)) require.Equal(t, uint32(200), e.SpamPoWNumberOfPastBlocks()) } func TestSpamPoWDifficulty(t *testing.T) { - e := New(logging.NewTestLogger(), NewDefaultConfig(), mocks.NewMockTimeService(gomock.NewController(t))) + e := New(logging.NewTestLogger(), NewDefaultConfig()) e.UpdateSpamPoWDifficulty(context.Background(), num.NewUint(20)) require.Equal(t, uint32(20), e.SpamPoWDifficulty()) } func TestSpamPoWHashFunction(t *testing.T) { - e := New(logging.NewTestLogger(), NewDefaultConfig(), mocks.NewMockTimeService(gomock.NewController(t))) + e := New(logging.NewTestLogger(), NewDefaultConfig()) e.UpdateSpamPoWHashFunction(context.Background(), "hash4") require.Equal(t, "hash4", e.SpamPoWHashFunction()) } func TestSpamPoWNumberOfTxPerBlock(t *testing.T) { - e := New(logging.NewTestLogger(), NewDefaultConfig(), mocks.NewMockTimeService(gomock.NewController(t))) + e := New(logging.NewTestLogger(), NewDefaultConfig()) e.UpdateSpamPoWNumberOfPastBlocks(context.Background(), num.NewUint(2)) require.Equal(t, uint32(2), e.SpamPoWNumberOfPastBlocks()) } func TestSpamPoWIncreasingDifficulty(t *testing.T) { - e := New(logging.NewTestLogger(), NewDefaultConfig(), mocks.NewMockTimeService(gomock.NewController(t))) + e := New(logging.NewTestLogger(), NewDefaultConfig()) e.UpdateSpamPoWIncreasingDifficulty(context.Background(), num.NewUint(1)) require.Equal(t, true, e.SpamPoWIncreasingDifficulty()) } func TestUpdateNumberOfBlocks(t *testing.T) { - e := New(logging.NewTestLogger(), NewDefaultConfig(), mocks.NewMockTimeService(gomock.NewController(t))) + e := New(logging.NewTestLogger(), NewDefaultConfig()) e.UpdateSpamPoWNumberOfPastBlocks(context.Background(), num.NewUint(5)) require.Equal(t, uint32(5), e.SpamPoWNumberOfPastBlocks()) } func TestCheckTx(t *testing.T) { - e := New(logging.NewTestLogger(), NewDefaultConfig(), mocks.NewMockTimeService(gomock.NewController(t))) + e := New(logging.NewTestLogger(), NewDefaultConfig()) e.UpdateSpamPoWNumberOfPastBlocks(context.Background(), num.NewUint(5)) e.UpdateSpamPoWDifficulty(context.Background(), num.NewUint(20)) e.UpdateSpamPoWHashFunction(context.Background(), crypto.Sha3) @@ -95,10 +85,6 @@ func TestCheckTx(t *testing.T) { // seen transction require.Equal(t, errors.New("proof of work tid already used"), e.CheckTx(&testTx{blockHeight: 100, powTxID: "49B0DF0954A8C048554B1C65F4F5883C38640D101A11959EB651AE2065A80BBB"})) - // party is banned - e.bannedParties["C692100485479CE9E1815B9E0A66D3596295A04DB42170CB4B61CFAE7332ADD8"] = time.Time{} - require.Equal(t, errors.New("party is banned from sending transactions"), e.CheckTx(&testTx{party: "C692100485479CE9E1815B9E0A66D3596295A04DB42170CB4B61CFAE7332ADD8", blockHeight: 100, powTxID: "A204DF39B63100C76EC831A843BF3C538FF54217DBA4B1409A3773507053EBB5"})) - // incorrect pow require.Equal(t, errors.New("failed to verify proof of work"), e.CheckTx(&testTx{party: crypto.RandomHash(), blockHeight: 100, powTxID: "077723AB0705677EAA704130D403C21352F87A9AF0E9C4C8F85CC13245FEFED7", powNonce: 1})) @@ -106,8 +92,8 @@ func TestCheckTx(t *testing.T) { require.NoError(t, e.CheckTx(&testTx{party: crypto.RandomHash(), blockHeight: 100, powTxID: "2E7A16D9EF690F0D2BEED115FBA13BA2AAA16C8F971910AD88C72B9DB010C7D4", powNonce: 596})) } -func TestCheckTxValidator(t *testing.T) { - e := New(logging.NewTestLogger(), NewDefaultConfig(), mocks.NewMockTimeService(gomock.NewController(t))) +func TestCheckBlockTx(t *testing.T) { + e := New(logging.NewTestLogger(), NewDefaultConfig()) e.UpdateSpamPoWNumberOfPastBlocks(context.Background(), num.NewUint(5)) e.UpdateSpamPoWDifficulty(context.Background(), num.NewUint(20)) e.UpdateSpamPoWHashFunction(context.Background(), crypto.Sha3) @@ -115,52 +101,60 @@ func TestCheckTxValidator(t *testing.T) { e.currentBlock = 100 e.blockHeight[100] = 100 - e.blockHash[100] = "113EB390CBEB921433BDBA832CCDFD81AC4C77C3748A41B1AF08C96BC6C7BCD9" - e.seenTid["49B0DF0954A8C048554B1C65F4F5883C38640D101A11959EB651AE2065A80BBB"] = struct{}{} - e.heightToTid[96] = []string{"49B0DF0954A8C048554B1C65F4F5883C38640D101A11959EB651AE2065A80BBB"} - - // seen transction - require.Equal(t, errors.New("proof of work tid already used"), e.CheckTx(&testTx{blockHeight: 100, powTxID: "49B0DF0954A8C048554B1C65F4F5883C38640D101A11959EB651AE2065A80BBB"})) + e.blockHash[100] = "2E7A16D9EF690F0D2BEED115FBA13BA2AAA16C8F971910AD88C72B9DB010C7D4" - // party is banned - e.bannedParties["C692100485479CE9E1815B9E0A66D3596295A04DB42170CB4B61CFAE7332ADD8"] = time.Time{} + require.Equal(t, 0, len(e.seenTid)) + require.Equal(t, 0, len(e.heightToTid)) + party := crypto.RandomHash() + tx1 := &testTx{party: party, blockHeight: 100, txID: "1", powTxID: "DFE522E234D67E6AE3F017859F898E576B3928EA57310B765398615A0D3FDE2F", powNonce: 424517} // 00000e31f8ac983354f5885d46b7631bc75f69ec82e8f6178bae53db0ab7e054 - 20 + res1, d1 := e.CheckBlockTx(tx1) + require.Equal(t, ValidationResultSuccess, res1) + require.Equal(t, 1, len(e.seenTid)) - // transaction too old: height 10, number of past blocks 5, current block 100 - oldTx := &testTx{ - party: "f8480da06c54a04a363c0563f207c0336a2bf80bf6864d560bf9d90653769f83", - blockHeight: 10, - powTxID: "2E7A16D9EF690F0D2BEED115FBA13BA2AAA16C8F971910AD88C72B9DB010C7D4", - powNonce: 596, + // same transaction within the same proposal should fail verification + res2, d2 := e.CheckBlockTx(tx1) + require.Equal(t, ValidationResultVerificationPowError, res2) + + // another transaction with invalid nonce should fail verification + tx2 := &testTx{party: party, blockHeight: 100, txID: "2", powTxID: "DFE522E234D67E6AE3F017859F898E576B3928EA57310B765398615A0D3FDE2F", powNonce: 1} + res3, d3 := e.CheckBlockTx(tx2) + require.Equal(t, ValidationResultVerificationPowError, res3) + + // old transaction should fail verification + tx3 := &testTx{party: party, blockHeight: 50, txID: "3", powTxID: "5B0E1EB96CCAC120E6D824A5F4C4007EABC59573B861BD84B1EF09DFB376DC84", powNonce: 4031737} + res4, d4 := e.CheckBlockTx(tx3) + require.Equal(t, ValidationResultVerificationPowError, res4) + + // add another transaction not increasing difficulty + tx4 := &testTx{party: party, blockHeight: 100, txID: "4", powTxID: "2A1319636230740888C968E4E7610D6DE820E644EEC3C08AA5322A0A022014BD", powNonce: 1421231} // 000009c5043c4e1dd7fe190ece8d3fd83d94c4e2a2b7800456ce5f5a653c9f75 - 20 + res5, d5 := e.CheckBlockTx(tx4) + require.Equal(t, ValidationResultTooManyTx, res5) + + entries := []ValidationEntry{ + {ValResult: res1, Difficulty: d1, Tx: tx1}, + {ValResult: res2, Difficulty: d2, Tx: tx1}, + {ValResult: res3, Difficulty: d3, Tx: tx2}, + {ValResult: res4, Difficulty: d4, Tx: tx3}, + {ValResult: res5, Difficulty: d5, Tx: tx4}, } - txHash := hex.EncodeToString(oldTx.Hash()) - expErr := errors.New("unknown block height for tx:" + txHash + ", command:" + oldTx.Command().String() + ", party:" + oldTx.Party()) - require.Equal(t, expErr, e.CheckTx(oldTx)) - // old tx, validator command is no good anymore! - require.Equal(t, "unknown block height for tx:, command:Node Signature, party:f8480da06c54a04a363c0563f207c0336a2bf80bf6864d560bf9d90653769f83", e.CheckTx(&testValidatorTx{testTx: *oldTx}).Error()) -} - -func TestDeliverTx(t *testing.T) { - e := New(logging.NewTestLogger(), NewDefaultConfig(), mocks.NewMockTimeService(gomock.NewController(t))) - e.UpdateSpamPoWNumberOfPastBlocks(context.Background(), num.NewUint(5)) - e.UpdateSpamPoWDifficulty(context.Background(), num.NewUint(20)) - e.UpdateSpamPoWHashFunction(context.Background(), crypto.Sha3) - e.UpdateSpamPoWNumberOfTxPerBlock(context.Background(), num.NewUint(1)) - - e.currentBlock = 100 - e.blockHeight[100] = 100 - e.blockHash[100] = "113EB390CBEB921433BDBA832CCDFD81AC4C77C3748A41B1AF08C96BC6C7BCD9" - + e.rollback(entries) require.Equal(t, 0, len(e.seenTid)) require.Equal(t, 0, len(e.heightToTid)) - party := crypto.RandomHash() - require.NoError(t, e.DeliverTx(&testTx{party: party, blockHeight: 100, powTxID: "2E7A16D9EF690F0D2BEED115FBA13BA2AAA16C8F971910AD88C72B9DB010C7D4", powNonce: 596})) + + res, d := e.CheckBlockTx(tx1) + require.Equal(t, ValidationResultSuccess, res) require.Equal(t, 1, len(e.seenTid)) + + valEntry := ValidationEntry{ValResult: res, Difficulty: d, Tx: tx1} + e.rollback([]ValidationEntry{valEntry}) + e.BeginBlock(101, crypto.RandomHash(), []abci.Tx{tx1}) require.Equal(t, 1, len(e.heightToTid)) - require.Equal(t, "2E7A16D9EF690F0D2BEED115FBA13BA2AAA16C8F971910AD88C72B9DB010C7D4", e.heightToTid[100][0]) + require.Equal(t, 1, len(e.seenTid)) + require.Equal(t, "DFE522E234D67E6AE3F017859F898E576B3928EA57310B765398615A0D3FDE2F", e.heightToTid[100][0]) } func TestMempoolTidRejection(t *testing.T) { - e := New(logging.NewTestLogger(), NewDefaultConfig(), mocks.NewMockTimeService(gomock.NewController(t))) + e := New(logging.NewTestLogger(), NewDefaultConfig()) e.UpdateSpamPoWNumberOfPastBlocks(context.Background(), num.NewUint(5)) e.UpdateSpamPoWDifficulty(context.Background(), num.NewUint(20)) e.UpdateSpamPoWHashFunction(context.Background(), crypto.Sha3) @@ -176,21 +170,19 @@ func TestMempoolTidRejection(t *testing.T) { require.Equal(t, 1, len(e.mempoolSeenTid)) require.Error(t, e.CheckTx(tx1)) - e.DeliverTx(tx1) - + res, d := e.CheckBlockTx(tx1) + e.rollback([]ValidationEntry{{Tx: tx1, Difficulty: d, ValResult: res}}) + e.BeginBlock(101, crypto.RandomHash(), []abci.Tx{tx1}) require.Equal(t, 1, len(e.seenTid)) _, ok := e.seenTid["2E7A16D9EF690F0D2BEED115FBA13BA2AAA16C8F971910AD88C72B9DB010C7D4"] require.True(t, ok) - e.Commit() require.Equal(t, 0, len(e.mempoolSeenTid)) - require.Error(t, e.CheckTx(tx1)) } func TestDeliverTxDuplciateNonce(t *testing.T) { - ts := mocks.NewMockTimeService(gomock.NewController(t)) - e := New(logging.NewTestLogger(), NewDefaultConfig(), ts) + e := New(logging.NewTestLogger(), NewDefaultConfig()) e.UpdateSpamPoWNumberOfPastBlocks(context.Background(), num.NewUint(5)) e.UpdateSpamPoWDifficulty(context.Background(), num.NewUint(20)) e.UpdateSpamPoWHashFunction(context.Background(), crypto.Sha3) @@ -213,7 +205,9 @@ func TestDeliverTxDuplciateNonce(t *testing.T) { nonce: 12, } - require.NoError(t, e.DeliverTx(tx)) + require.Equal(t, true, e.ProcessProposal([]abci.Tx{tx})) + e.BeginBlock(101, crypto.RandomHash(), []abci.Tx{tx}) + require.Equal(t, 1, len(e.seenTid)) require.Equal(t, 1, len(e.heightToTid)) require.Equal(t, 1, len(e.heightToNonceRef)) @@ -223,20 +217,21 @@ func TestDeliverTxDuplciateNonce(t *testing.T) { tx.powNonce = 100 tx.powTxID = "113EB390CBEB921433BDBA832CCDFD81AC4C77C3748A41B1AF08C96BC6C7BCD9" tx.txID = crypto.RandomHash() - require.ErrorIs(t, ErrNonceAlreadyUsedByParty, e.DeliverTx(tx)) + + require.Equal(t, false, e.ProcessProposal([]abci.Tx{tx})) // but a different party can used that nonce at that height tx.powTxID = "DC911C0EA95545441F3E1182DD25D973764395A7E75CBDBC086F1C6F7075AED6" tx.powNonce = 523162 tx.party = crypto.RandomHash() - require.NoError(t, e.DeliverTx(tx)) + + require.Equal(t, true, e.ProcessProposal([]abci.Tx{tx})) + e.BeginBlock(101, crypto.RandomHash(), []abci.Tx{tx}) require.Equal(t, 1, len(e.heightToNonceRef)) require.Equal(t, 2, len(e.heightToNonceRef[100])) // check the maps are purged when we leave scope - ts.EXPECT().GetTimeNow().AnyTimes().Return(time.Unix(1000, 12)) - e.BeginBlock(104, "2D2E4EC3DA3584F3FD4AD1BD1C0700E3C8DFB7BB1C307312AB35F18940836FC4") - e.EndOfBlock() + e.BeginBlock(104, crypto.RandomHash(), []abci.Tx{}) require.Equal(t, 0, len(e.seenTid)) require.Equal(t, 0, len(e.heightToTid)) require.Equal(t, 0, len(e.heightToNonceRef)) @@ -338,89 +333,61 @@ func TestExpectedDifficulty(t *testing.T) { } func TestBeginBlock(t *testing.T) { - ts := mocks.NewMockTimeService(gomock.NewController(t)) - ts.EXPECT().GetTimeNow().AnyTimes().Return(time.Now()) - e := New(logging.NewTestLogger(), NewDefaultConfig(), ts) + e := New(logging.NewTestLogger(), NewDefaultConfig()) e.UpdateSpamPoWNumberOfPastBlocks(context.Background(), num.NewUint(3)) e.UpdateSpamPoWDifficulty(context.Background(), num.NewUint(20)) e.UpdateSpamPoWHashFunction(context.Background(), crypto.Sha3) e.UpdateSpamPoWNumberOfTxPerBlock(context.Background(), num.NewUint(1)) - e.BeginBlock(100, "2E7A16D9EF690F0D2BEED115FBA13BA2AAA16C8F971910AD88C72B9DB010C7D4") - e.BeginBlock(101, "113EB390CBEB921433BDBA832CCDFD81AC4C77C3748A41B1AF08C96BC6C7BCD9") - e.BeginBlock(102, "C692100485479CE9E1815B9E0A66D3596295A04DB42170CB4B61CFAE7332ADD8") + e.BeginBlock(100, "113EB390CBEB921433BDBA832CCDFD81AC4C77C3748A41B1AF08C96BC6C7BCD9", []abci.Tx{}) + e.BeginBlock(101, "C692100485479CE9E1815B9E0A66D3596295A04DB42170CB4B61CFAE7332ADD8", []abci.Tx{}) + e.BeginBlock(102, "2E7A16D9EF690F0D2BEED115FBA13BA2AAA16C8F971910AD88C72B9DB010C7D4", []abci.Tx{}) require.Equal(t, uint64(102), e.currentBlock) require.Equal(t, uint64(100), e.blockHeight[100]) require.Equal(t, uint64(101), e.blockHeight[101]) require.Equal(t, uint64(102), e.blockHeight[102]) - require.Equal(t, "2E7A16D9EF690F0D2BEED115FBA13BA2AAA16C8F971910AD88C72B9DB010C7D4", e.blockHash[100]) - require.Equal(t, "113EB390CBEB921433BDBA832CCDFD81AC4C77C3748A41B1AF08C96BC6C7BCD9", e.blockHash[101]) - require.Equal(t, "C692100485479CE9E1815B9E0A66D3596295A04DB42170CB4B61CFAE7332ADD8", e.blockHash[102]) - - // now add some transactions for block 100 before it goes off - e.DeliverTx(&testTx{txID: "1", party: crypto.RandomHash(), blockHeight: 100, powTxID: "94A9CB1532011081B013CCD8E6AAA832CAB1CBA603F0C5A093B14C4961E5E7F0", powNonce: 431336}) - e.DeliverTx(&testTx{txID: "2", party: crypto.RandomHash(), blockHeight: 100, powTxID: "DC911C0EA95545441F3E1182DD25D973764395A7E75CBDBC086F1C6F7075AED6", powNonce: 523162}) - - require.Equal(t, 2, len(e.seenTid)) - require.Equal(t, 2, len(e.heightToTid[100])) + require.Equal(t, "113EB390CBEB921433BDBA832CCDFD81AC4C77C3748A41B1AF08C96BC6C7BCD9", e.blockHash[100]) + require.Equal(t, "C692100485479CE9E1815B9E0A66D3596295A04DB42170CB4B61CFAE7332ADD8", e.blockHash[101]) + require.Equal(t, "2E7A16D9EF690F0D2BEED115FBA13BA2AAA16C8F971910AD88C72B9DB010C7D4", e.blockHash[102]) + + // now add some transactions for block 102 before it goes off + tx1 := &testTx{txID: "1", party: crypto.RandomHash(), blockHeight: 102, powTxID: "94A9CB1532011081B013CCD8E6AAA832CAB1CBA603F0C5A093B14C4961E5E7F0", powNonce: 431336} + tx2 := &testTx{txID: "2", party: crypto.RandomHash(), blockHeight: 102, powTxID: "DC911C0EA95545441F3E1182DD25D973764395A7E75CBDBC086F1C6F7075AED6", powNonce: 523162} + + res1, d1 := e.CheckBlockTx(tx1) + res2, d2 := e.CheckBlockTx(tx2) + require.Equal(t, ValidationResultSuccess, res1) + require.Equal(t, ValidationResultSuccess, res2) + e.rollback([]ValidationEntry{{Tx: tx1, ValResult: res1, Difficulty: d1}, {Tx: tx2, ValResult: res2, Difficulty: d2}}) + require.Equal(t, 0, len(e.seenTid)) + require.Equal(t, 0, len(e.heightToTid[100])) - e.BeginBlock(103, "2E289FB9CEF7234E2C08F34CCD66B330229067CE47E22F76EF0595B3ABA9968F") + e.BeginBlock(103, "2E289FB9CEF7234E2C08F34CCD66B330229067CE47E22F76EF0595B3ABA9968F", []abci.Tx{tx1, tx2}) require.Equal(t, uint64(103), e.currentBlock) require.Equal(t, uint64(103), e.blockHeight[103]) require.Equal(t, uint64(101), e.blockHeight[101]) require.Equal(t, uint64(102), e.blockHeight[102]) + require.Equal(t, "C692100485479CE9E1815B9E0A66D3596295A04DB42170CB4B61CFAE7332ADD8", e.blockHash[101]) + require.Equal(t, "2E7A16D9EF690F0D2BEED115FBA13BA2AAA16C8F971910AD88C72B9DB010C7D4", e.blockHash[102]) require.Equal(t, "2E289FB9CEF7234E2C08F34CCD66B330229067CE47E22F76EF0595B3ABA9968F", e.blockHash[103]) - require.Equal(t, "113EB390CBEB921433BDBA832CCDFD81AC4C77C3748A41B1AF08C96BC6C7BCD9", e.blockHash[101]) - require.Equal(t, "C692100485479CE9E1815B9E0A66D3596295A04DB42170CB4B61CFAE7332ADD8", e.blockHash[102]) -} - -func TestBan(t *testing.T) { - now := time.Now() - ts := mocks.NewMockTimeService(gomock.NewController(t)) - ts.EXPECT().GetTimeNow().Times(72).Return(now) - e := New(logging.NewTestLogger(), NewDefaultConfig(), ts) - e.UpdateSpamPoWNumberOfPastBlocks(context.Background(), num.NewUint(1)) - e.UpdateSpamPoWDifficulty(context.Background(), num.NewUint(20)) - e.UpdateSpamPoWHashFunction(context.Background(), crypto.Sha3) - e.UpdateSpamPoWNumberOfTxPerBlock(context.Background(), num.NewUint(1)) - e.UpdateSpamPoWIncreasingDifficulty(context.Background(), num.NewUint(1)) - e.OnEpochDurationChanged(context.Background(), 24*time.Hour) - - // test happy days first - 4 transactions with increasing difficulty results in no ban - regardless of the order they come in - party := crypto.RandomHash() - txs := []*testTx{ - {txID: "4", party: party, powTxID: "DFE522E234D67E6AE3F017859F898E576B3928EA57310B765398615A0D3FDE2F", powNonce: 424517}, // 00000e31f8ac983354f5885d46b7631bc75f69ec82e8f6178bae53db0ab7e054 - 20 - {txID: "5", party: party, powTxID: "5B87F9DFA41DABE84A11CA78D9FE11DA8FC2AA926004CA66454A7AF0A206480D", powNonce: 4095356}, // 0000077b7d66117b57e45ccba0c31554e61c9853cc1cd9a2cf09c41b0aa9c22e - 21 - {txID: "6", party: party, powTxID: "B14DD602ED48C9F7B5367105A4A97FFC9199EA0C9E1490B786534768DD1538EF", powNonce: 1751582}, // 000003bbf0cde49e3899ad23282b18defbc12a65f07c95d768464b87024df368 - 22 - {txID: "7", party: party, powTxID: "94A9CB1532011081B013CCD8E6AAA832CAB1CBA603F0C5A093B14C4961E5E7F0", powNonce: 431336}, // 000001c297318619efd60b9197f89e36fea83ca8d7461cf7b7c78af84e0a3b51 - 23 - } - testBanWithTxPermutations(t, e, txs, false, 102, party, now) - - txs = []*testTx{ - {txID: "8", party: party, powTxID: "2A1319636230740888C968E4E7610D6DE820E644EEC3C08AA5322A0A022014BD", powNonce: 1421231}, // 000009c5043c4e1dd7fe190ece8d3fd83d94c4e2a2b7800456ce5f5a653c9f75 - 20 - {txID: "9", party: party, powTxID: "DFE522E234D67E6AE3F017859F898E576B3928EA57310B765398615A0D3FDE2F", powNonce: 424517}, // 00000e31f8ac983354f5885d46b7631bc75f69ec82e8f6178bae53db0ab7e054 - 20 - {txID: "10", party: party, powTxID: "5B0E1EB96CCAC120E6D824A5F4C4007EABC59573B861BD84B1EF09DFB376DC84", powNonce: 4031737}, // 000002a98320df372412d7179ca2645b13ff3ecbe660e4a9a743fb423d8aec1f - 22 - {txID: "11", party: party, powTxID: "94A9CB1532011081B013CCD8E6AAA832CAB1CBA603F0C5A093B14C4961E5E7F0", powNonce: 431336}, // 000001c297318619efd60b9197f89e36fea83ca8d7461cf7b7c78af84e0a3b51 - 23 - } - testBanWithTxPermutations(t, e, txs, true, 126, party, now) - now = now.Add(e.banDuration) - ts.EXPECT().GetTimeNow().Times(1).Return(now) - e.BeginBlock(129, crypto.RandomHash()) - require.Equal(t, 0, len(e.bannedParties)) + require.Equal(t, 2, len(e.seenTid)) + require.Equal(t, 2, len(e.seenTx)) + require.Equal(t, 2, len(e.heightToTid[102])) + require.Equal(t, *d1, e.activeStates[0].blockToPartyState[102][tx1.party].observedDifficulty) + require.Equal(t, *d2, e.activeStates[0].blockToPartyState[102][tx2.party].observedDifficulty) + require.Equal(t, uint(1), e.activeStates[0].blockToPartyState[102][tx1.party].seenCount) + require.Equal(t, uint(1), e.activeStates[0].blockToPartyState[102][tx2.party].seenCount) } func TestAllowTransactionsAcrossMultipleBlocks(t *testing.T) { - now := time.Now() - ts := mocks.NewMockTimeService(gomock.NewController(t)) - ts.EXPECT().GetTimeNow().AnyTimes().Return(now) - e := New(logging.NewTestLogger(), NewDefaultConfig(), ts) + e := New(logging.NewTestLogger(), NewDefaultConfig()) e.UpdateSpamPoWNumberOfPastBlocks(context.Background(), num.NewUint(10)) e.UpdateSpamPoWDifficulty(context.Background(), num.NewUint(20)) e.UpdateSpamPoWHashFunction(context.Background(), crypto.Sha3) e.UpdateSpamPoWNumberOfTxPerBlock(context.Background(), num.NewUint(1)) e.UpdateSpamPoWIncreasingDifficulty(context.Background(), num.NewUint(1)) - e.BeginBlock(100, "2E7A16D9EF690F0D2BEED115FBA13BA2AAA16C8F971910AD88C72B9DB010C7D4") + e.BeginBlock(100, "2E7A16D9EF690F0D2BEED115FBA13BA2AAA16C8F971910AD88C72B9DB010C7D4", []abci.Tx{}) // test happy days first - 4 transactions with increasing difficulty results in no ban - regardless of the order they come in party := crypto.RandomHash() @@ -432,120 +399,55 @@ func TestAllowTransactionsAcrossMultipleBlocks(t *testing.T) { } // process the first transaction on block 101 - e.BeginBlock(101, crypto.RandomHash()) - require.NoError(t, e.DeliverTx(txs[0])) + e.BeginBlock(101, crypto.RandomHash(), []abci.Tx{}) + res, d := e.CheckBlockTx(txs[0]) + require.Equal(t, ValidationResultSuccess, res) + e.rollback([]ValidationEntry{{ValResult: res, Difficulty: d, Tx: txs[0]}}) // process the second transaction on block 102 - e.BeginBlock(102, crypto.RandomHash()) - require.NoError(t, e.DeliverTx(txs[1])) + e.BeginBlock(102, crypto.RandomHash(), []abci.Tx{txs[0]}) + res, d = e.CheckBlockTx(txs[1]) + require.Equal(t, ValidationResultSuccess, res) + e.rollback([]ValidationEntry{{ValResult: res, Difficulty: d, Tx: txs[1]}}) // process the third transaction on block 103 - e.BeginBlock(103, crypto.RandomHash()) - require.NoError(t, e.DeliverTx(txs[2])) - - // process the last transaction on block 104 - this should get us banned - e.BeginBlock(104, crypto.RandomHash()) - require.Equal(t, "too many transactions per block", e.DeliverTx(txs[3]).Error()) - - require.Equal(t, 1, len(e.bannedParties)) + e.BeginBlock(103, crypto.RandomHash(), []abci.Tx{txs[1]}) + res, d = e.CheckBlockTx(txs[2]) + require.Equal(t, ValidationResultSuccess, res) + e.rollback([]ValidationEntry{{ValResult: res, Difficulty: d, Tx: txs[2]}}) + + // process the last transaction on block 104 + e.BeginBlock(104, crypto.RandomHash(), []abci.Tx{txs[2]}) + res, d = e.CheckBlockTx(txs[3]) + require.Equal(t, ValidationResultTooManyTx, res) + e.rollback([]ValidationEntry{{ValResult: res, Difficulty: d, Tx: txs[3]}}) } func TestEdgeCase1(t *testing.T) { ts := mocks.NewMockTimeService(gomock.NewController(t)) - e := New(logging.NewTestLogger(), NewDefaultConfig(), ts) + e := New(logging.NewTestLogger(), NewDefaultConfig()) e.UpdateSpamPoWDifficulty(context.Background(), num.NewUint(20)) e.UpdateSpamPoWNumberOfPastBlocks(context.Background(), num.NewUint(100)) e.UpdateSpamPoWHashFunction(context.Background(), crypto.Sha3) ts.EXPECT().GetTimeNow().AnyTimes() - e.BeginBlock(1, "9DF61AC8AD2178E2E2FD2D94E0F07A4B8AA141213179B03C184F8EAD898A9336") - e.EndOfBlock() - e.BeginBlock(50, "1D5839A6F7BF1CDB681590890E9D50ECFA222C41F57D1F05229ED3DED533F59A") + e.BeginBlock(1, "9DF61AC8AD2178E2E2FD2D94E0F07A4B8AA141213179B03C184F8EAD898A9336", []abci.Tx{}) nonce, _, _ := crypto.PoW("9DF61AC8AD2178E2E2FD2D94E0F07A4B8AA141213179B03C184F8EAD898A9336", "2E7A16D9EF690F0D2BEED115FBA13BA2AAA16C8F971910AD88C72B9DB010C7D4", 20, "sha3_24_rounds") - // a transaction signed with block 1 is executed in block 50 - require.NoError(t, e.DeliverTx(&testTx{txID: "5CCCE01E56B9666F39F007BF577F10BB46987CFE1B1BE80AAC1DBBF51F9C45FE", party: "zohar", blockHeight: 1, powTxID: "2E7A16D9EF690F0D2BEED115FBA13BA2AAA16C8F971910AD88C72B9DB010C7D4", powNonce: nonce})) - e.EndOfBlock() + + e.BeginBlock(50, "1D5839A6F7BF1CDB681590890E9D50ECFA222C41F57D1F05229ED3DED533F59A", []abci.Tx{&testTx{txID: "5CCCE01E56B9666F39F007BF577F10BB46987CFE1B1BE80AAC1DBBF51F9C45FE", party: "zohar", blockHeight: 1, powTxID: "2E7A16D9EF690F0D2BEED115FBA13BA2AAA16C8F971910AD88C72B9DB010C7D4", powNonce: nonce}}) // come block 100 - e.BeginBlock(100, "2D2E4EC3DA3584F3FD4AD1BD1C0700E3C8DFB7BB1C307312AB35F18940836FC4") - e.EndOfBlock() + e.BeginBlock(100, "2D2E4EC3DA3584F3FD4AD1BD1C0700E3C8DFB7BB1C307312AB35F18940836FC4", []abci.Tx{}) // block 100 ended, block 101 is being prepared, at this point transactions from block 1 are not valid anymore. // we've cleared the state of the 100th oldest block seen tx (aka block 1) - now with the modified check for distance in verify - checktx should not allow the transaction in require.Error(t, e.CheckTx(&testTx{txID: "5CCCE01E56B9666F39F007BF577F10BB46987CFE1B1BE80AAC1DBBF51F9C45FE", party: "zohar", blockHeight: 2261296, powTxID: "2E7A16D9EF690F0D2BEED115FBA13BA2AAA16C8F971910AD88C72B9DB010C7D4", powNonce: nonce})) - e.BeginBlock(101, "2D2E4EC3DA3584F3FD4AD1BD1C0700E3C8DFB7BB1C307312AB35F18940836FC4") - e.EndOfBlock() + e.BeginBlock(101, "2D2E4EC3DA3584F3FD4AD1BD1C0700E3C8DFB7BB1C307312AB35F18940836FC4", []abci.Tx{}) // verify for fun that we can't get the transaction at this point either. require.Error(t, e.CheckTx(&testTx{txID: "5CCCE01E56B9666F39F007BF577F10BB46987CFE1B1BE80AAC1DBBF51F9C45FE", party: "zohar", blockHeight: 2261296, powTxID: "2E7A16D9EF690F0D2BEED115FBA13BA2AAA16C8F971910AD88C72B9DB010C7D4", powNonce: nonce})) } -func TestEndBlock(t *testing.T) { - e := New(logging.NewTestLogger(), NewDefaultConfig(), mocks.NewMockTimeService(gomock.NewController(t))) - e.UpdateSpamPoWNumberOfPastBlocks(context.Background(), num.NewUint(1)) - e.UpdateSpamPoWDifficulty(context.Background(), num.NewUint(20)) - e.UpdateSpamPoWHashFunction(context.Background(), crypto.Sha3) - e.UpdateSpamPoWNumberOfTxPerBlock(context.Background(), num.NewUint(1)) -} - -func testBanWithTxPermutations(t *testing.T, e *Engine, txs []*testTx, expectedBan bool, blockHeight uint64, party string, now time.Time) { - t.Helper() - txsPerm := permutation(txs) - for i, perm := range txsPerm { - // clear any bans - e.bannedParties = map[string]time.Time{} - - // begin a new block - e.BeginBlock(blockHeight+uint64(i), "2E7A16D9EF690F0D2BEED115FBA13BA2AAA16C8F971910AD88C72B9DB010C7D4") - - // send the transactions with the given permutation - errors := []error{} - for _, p := range perm { - p.blockHeight = blockHeight + uint64(i) - err := e.DeliverTx(p) - if err != nil { - errors = append(errors, err) - } - } - - if expectedBan { - require.True(t, len(errors) > 0) - require.Equal(t, "too many transactions per block", errors[0].Error()) - } else { - require.Equal(t, 0, len(errors)) - } - - // end the block to check if the party was playing nice - e.EndOfBlock() - - // verify expected ban - if expectedBan { - require.Equal(t, 1, len(e.bannedParties)) - require.Equal(t, now.Add(e.banDuration), e.bannedParties[party]) - } else { - require.Equal(t, 0, len(e.bannedParties)) - } - } -} - -func permutation(xs []*testTx) (permuts [][]*testTx) { - var rc func([]*testTx, int) - rc = func(a []*testTx, k int) { - if k == len(a) { - permuts = append(permuts, append([]*testTx{}, a...)) - } else { - for i := k; i < len(xs); i++ { - a[k], a[i] = a[i], a[k] - rc(a, k+1) - a[k], a[i] = a[i], a[k] - } - } - } - rc(xs, 0) - - return permuts -} - type testTx struct { party string blockHeight uint64 @@ -555,10 +457,8 @@ type testTx struct { nonce uint64 } -type testValidatorTx struct { - testTx -} - +func (tx *testTx) TTL() uint64 { return 100 } +func (tx *testTx) GetLength() int { return 0 } func (tx *testTx) Unmarshal(interface{}) error { return nil } func (tx *testTx) GetPoWTID() string { return tx.powTxID } func (tx *testTx) GetVersion() uint32 { return 2 } @@ -581,10 +481,6 @@ func (tx *testTx) GetNonce() uint64 { return rand.Uint64() } -func (tx *testValidatorTx) Command() txn.Command { - return txn.NodeSignatureCommand -} - func Test_ExpectedSpamDifficulty(t *testing.T) { type args struct { spamPowDifficulty uint @@ -714,36 +610,3 @@ func Test_ExpectedSpamDifficulty(t *testing.T) { }) } } - -func TestPruning(t *testing.T) { - ts := mocks.NewMockTimeService(gomock.NewController(t)) - ts.EXPECT().GetTimeNow().AnyTimes().Return(time.Now()) - e := New(logging.NewTestLogger(), NewDefaultConfig(), ts) - e.UpdateSpamPoWNumberOfPastBlocks(context.Background(), num.NewUint(5)) - e.UpdateSpamPoWDifficulty(context.Background(), num.NewUint(20)) - e.UpdateSpamPoWHashFunction(context.Background(), crypto.Sha3) - e.UpdateSpamPoWNumberOfTxPerBlock(context.Background(), num.NewUint(1)) - - e.currentBlock = 100 - e.blockHeight[100] = 100 - e.blockHash[100] = "113EB390CBEB921433BDBA832CCDFD81AC4C77C3748A41B1AF08C96BC6C7BCD9" - - require.Equal(t, 0, len(e.seenTid)) - require.Equal(t, 0, len(e.heightToTid)) - party := crypto.RandomHash() - require.NoError(t, e.DeliverTx(&testTx{party: party, blockHeight: 100, powTxID: "2E7A16D9EF690F0D2BEED115FBA13BA2AAA16C8F971910AD88C72B9DB010C7D4", powNonce: 596})) - require.Equal(t, 1, len(e.seenTid)) - require.Equal(t, 1, len(e.heightToTid)) - require.Equal(t, "2E7A16D9EF690F0D2BEED115FBA13BA2AAA16C8F971910AD88C72B9DB010C7D4", e.heightToTid[100][0]) - - e.BeginBlock(999, crypto.RandomHash()) - e.EndOfBlock() - require.Equal(t, 1, len(e.seenTid)) - require.Equal(t, 1, len(e.heightToTid)) - require.Equal(t, "2E7A16D9EF690F0D2BEED115FBA13BA2AAA16C8F971910AD88C72B9DB010C7D4", e.heightToTid[100][0]) - - e.BeginBlock(1000, crypto.RandomHash()) - e.EndOfBlock() - require.Equal(t, 0, len(e.heightToTid)) - require.Equal(t, 0, len(e.seenTid)) -} diff --git a/core/pow/multiple_config_test.go b/core/pow/multiple_config_test.go index 604cf93d68..aa608fe3da 100644 --- a/core/pow/multiple_config_test.go +++ b/core/pow/multiple_config_test.go @@ -18,23 +18,19 @@ package pow import ( "context" "testing" - "time" - "code.vegaprotocol.io/vega/core/pow/mocks" + "code.vegaprotocol.io/vega/core/blockchain/abci" "code.vegaprotocol.io/vega/libs/crypto" "code.vegaprotocol.io/vega/libs/num" "code.vegaprotocol.io/vega/logging" - "github.com/golang/mock/gomock" "github.com/stretchr/testify/require" ) func TestConfigurationHistory(t *testing.T) { - ts := mocks.NewMockTimeService(gomock.NewController(t)) - ts.EXPECT().GetTimeNow().AnyTimes().Return(time.Now()) - e := New(logging.NewTestLogger(), NewDefaultConfig(), ts) + e := New(logging.NewTestLogger(), NewDefaultConfig()) - e.BeginBlock(1, crypto.RandomHash()) + e.BeginBlock(1, crypto.RandomHash(), []abci.Tx{}) require.Equal(t, 0, len(e.activeParams)) require.Equal(t, 0, len(e.activeStates)) e.UpdateSpamPoWDifficulty(context.Background(), num.NewUint(1)) @@ -43,8 +39,7 @@ func TestConfigurationHistory(t *testing.T) { require.Equal(t, uint64(1), e.activeParams[0].fromBlock) require.Nil(t, e.activeParams[0].untilBlock) - e.EndOfBlock() - e.BeginBlock(2, crypto.RandomHash()) + e.BeginBlock(2, crypto.RandomHash(), []abci.Tx{}) e.UpdateSpamPoWDifficulty(context.Background(), num.NewUint(5)) require.Equal(t, 2, len(e.activeParams)) require.Equal(t, 2, len(e.activeStates)) @@ -55,151 +50,121 @@ func TestConfigurationHistory(t *testing.T) { // we're in block 2, we expect difficulty to change in block 3 require.Equal(t, uint32(1), e.SpamPoWDifficulty()) - e.EndOfBlock() - e.BeginBlock(3, crypto.RandomHash()) + e.BeginBlock(3, crypto.RandomHash(), []abci.Tx{}) require.Equal(t, uint32(5), e.SpamPoWDifficulty()) } func TestSpamPoWNumberOfPastBlocksChange(t *testing.T) { - ts := mocks.NewMockTimeService(gomock.NewController(t)) - ts.EXPECT().GetTimeNow().AnyTimes().Return(time.Now()) - - e := New(logging.NewTestLogger(), NewDefaultConfig(), ts) - e.BeginBlock(1, crypto.RandomHash()) + e := New(logging.NewTestLogger(), NewDefaultConfig()) + e.BeginBlock(1, crypto.RandomHash(), []abci.Tx{}) e.UpdateSpamPoWNumberOfPastBlocks(context.Background(), num.NewUint(10)) // it's the first configuration so it's starting from this block rather than next require.Equal(t, uint32(10), e.SpamPoWNumberOfPastBlocks()) - e.EndOfBlock() - e.BeginBlock(2, crypto.RandomHash()) + e.BeginBlock(2, crypto.RandomHash(), []abci.Tx{}) e.UpdateSpamPoWNumberOfPastBlocks(context.Background(), num.NewUint(100)) require.Equal(t, uint32(10), e.SpamPoWNumberOfPastBlocks()) e.UpdateSpamPoWNumberOfPastBlocks(context.Background(), num.NewUint(110)) require.Equal(t, uint32(10), e.SpamPoWNumberOfPastBlocks()) - e.EndOfBlock() - e.BeginBlock(3, crypto.RandomHash()) + e.BeginBlock(3, crypto.RandomHash(), []abci.Tx{}) require.Equal(t, uint32(110), e.SpamPoWNumberOfPastBlocks()) } func TestSpamPoWDifficultyChange(t *testing.T) { - ts := mocks.NewMockTimeService(gomock.NewController(t)) - ts.EXPECT().GetTimeNow().AnyTimes().Return(time.Now()) - e := New(logging.NewTestLogger(), NewDefaultConfig(), ts) - e.BeginBlock(1, crypto.RandomHash()) + e := New(logging.NewTestLogger(), NewDefaultConfig()) + e.BeginBlock(1, crypto.RandomHash(), []abci.Tx{}) e.UpdateSpamPoWDifficulty(context.Background(), num.NewUint(10)) // it's the first configuration so it's starting from this block rather than next require.Equal(t, uint32(10), e.SpamPoWDifficulty()) - e.EndOfBlock() - e.BeginBlock(2, crypto.RandomHash()) + e.BeginBlock(2, crypto.RandomHash(), []abci.Tx{}) e.UpdateSpamPoWDifficulty(context.Background(), num.NewUint(100)) require.Equal(t, uint32(10), e.SpamPoWDifficulty()) e.UpdateSpamPoWDifficulty(context.Background(), num.NewUint(110)) require.Equal(t, uint32(10), e.SpamPoWDifficulty()) - e.EndOfBlock() - e.BeginBlock(3, crypto.RandomHash()) + e.BeginBlock(3, crypto.RandomHash(), []abci.Tx{}) require.Equal(t, uint32(110), e.SpamPoWDifficulty()) } func TestSpamPoWHashChange(t *testing.T) { - ts := mocks.NewMockTimeService(gomock.NewController(t)) - ts.EXPECT().GetTimeNow().AnyTimes().Return(time.Now()) - e := New(logging.NewTestLogger(), NewDefaultConfig(), ts) - e.BeginBlock(1, crypto.RandomHash()) + e := New(logging.NewTestLogger(), NewDefaultConfig()) + e.BeginBlock(1, crypto.RandomHash(), []abci.Tx{}) e.UpdateSpamPoWHashFunction(context.Background(), "f1") // it's the first configuration so it's starting from this block rather than next require.Equal(t, "f1", e.SpamPoWHashFunction()) - e.EndOfBlock() - e.BeginBlock(2, crypto.RandomHash()) + e.BeginBlock(2, crypto.RandomHash(), []abci.Tx{}) e.UpdateSpamPoWHashFunction(context.Background(), "f2") require.Equal(t, "f1", e.SpamPoWHashFunction()) e.UpdateSpamPoWHashFunction(context.Background(), "f3") require.Equal(t, "f1", e.SpamPoWHashFunction()) - e.EndOfBlock() - e.BeginBlock(3, crypto.RandomHash()) + e.BeginBlock(3, crypto.RandomHash(), []abci.Tx{}) require.Equal(t, "f3", e.SpamPoWHashFunction()) } func TestSpamPoWNumberOfTxPerBlockChange(t *testing.T) { - ts := mocks.NewMockTimeService(gomock.NewController(t)) - ts.EXPECT().GetTimeNow().AnyTimes().Return(time.Now()) - e := New(logging.NewTestLogger(), NewDefaultConfig(), ts) - e.BeginBlock(1, crypto.RandomHash()) + e := New(logging.NewTestLogger(), NewDefaultConfig()) + e.BeginBlock(1, crypto.RandomHash(), []abci.Tx{}) e.UpdateSpamPoWNumberOfTxPerBlock(context.Background(), num.NewUint(10)) // it's the first configuration so it's starting from this block rather than next require.Equal(t, uint32(10), e.SpamPoWNumberOfTxPerBlock()) - e.EndOfBlock() - e.BeginBlock(2, crypto.RandomHash()) + e.BeginBlock(2, crypto.RandomHash(), []abci.Tx{}) e.UpdateSpamPoWNumberOfTxPerBlock(context.Background(), num.NewUint(100)) require.Equal(t, uint32(10), e.SpamPoWNumberOfTxPerBlock()) e.UpdateSpamPoWNumberOfTxPerBlock(context.Background(), num.NewUint(110)) require.Equal(t, uint32(10), e.SpamPoWNumberOfTxPerBlock()) - e.EndOfBlock() - e.BeginBlock(3, crypto.RandomHash()) + e.BeginBlock(3, crypto.RandomHash(), []abci.Tx{}) require.Equal(t, uint32(110), e.SpamPoWNumberOfTxPerBlock()) } func TestSpamPoWIncreasingDifficultyChange(t *testing.T) { - ts := mocks.NewMockTimeService(gomock.NewController(t)) - ts.EXPECT().GetTimeNow().AnyTimes().Return(time.Now()) - e := New(logging.NewTestLogger(), NewDefaultConfig(), ts) - e.BeginBlock(1, crypto.RandomHash()) + e := New(logging.NewTestLogger(), NewDefaultConfig()) + e.BeginBlock(1, crypto.RandomHash(), []abci.Tx{}) e.UpdateSpamPoWIncreasingDifficulty(context.Background(), num.NewUint(1)) // it's the first configuration so it's starting from this block rather than next require.Equal(t, true, e.SpamPoWIncreasingDifficulty()) - e.EndOfBlock() - e.BeginBlock(2, crypto.RandomHash()) + e.BeginBlock(2, crypto.RandomHash(), []abci.Tx{}) e.UpdateSpamPoWIncreasingDifficulty(context.Background(), num.NewUint(1)) require.Equal(t, true, e.SpamPoWIncreasingDifficulty()) e.UpdateSpamPoWIncreasingDifficulty(context.Background(), num.NewUint(0)) require.Equal(t, true, e.SpamPoWIncreasingDifficulty()) - e.EndOfBlock() - e.BeginBlock(3, crypto.RandomHash()) + e.BeginBlock(3, crypto.RandomHash(), []abci.Tx{}) require.Equal(t, false, e.SpamPoWIncreasingDifficulty()) } func TestBlockData(t *testing.T) { - ts := mocks.NewMockTimeService(gomock.NewController(t)) - ts.EXPECT().GetTimeNow().AnyTimes().Return(time.Now()) - e := New(logging.NewTestLogger(), NewDefaultConfig(), ts) + e := New(logging.NewTestLogger(), NewDefaultConfig()) blockHash := crypto.RandomHash() e.UpdateSpamPoWDifficulty(context.Background(), num.NewUint(5)) - e.BeginBlock(1, blockHash) + e.BeginBlock(1, blockHash, []abci.Tx{}) height, hash := e.BlockData() require.Equal(t, uint64(1), height) require.Equal(t, blockHash, hash) - e.EndOfBlock() blockHash = crypto.RandomHash() - e.BeginBlock(2, blockHash) + e.BeginBlock(2, blockHash, []abci.Tx{}) height, hash = e.BlockData() require.Equal(t, uint64(2), height) require.Equal(t, blockHash, hash) } func TestFindParamsForBlockHeight(t *testing.T) { - ts := mocks.NewMockTimeService(gomock.NewController(t)) - ts.EXPECT().GetTimeNow().AnyTimes().Return(time.Now()) - e := New(logging.NewTestLogger(), NewDefaultConfig(), ts) + e := New(logging.NewTestLogger(), NewDefaultConfig()) e.UpdateSpamPoWNumberOfPastBlocks(context.Background(), num.NewUint(100)) e.UpdateSpamPoWDifficulty(context.Background(), num.NewUint(20)) e.UpdateSpamPoWHashFunction(context.Background(), "sha3") e.UpdateSpamPoWNumberOfTxPerBlock(context.Background(), num.NewUint(1)) e.UpdateSpamPoWIncreasingDifficulty(context.Background(), num.NewUint(1)) - e.BeginBlock(9, crypto.RandomHash()) + e.BeginBlock(9, crypto.RandomHash(), []abci.Tx{}) e.UpdateSpamPoWDifficulty(context.Background(), num.NewUint(21)) - e.EndOfBlock() - e.BeginBlock(19, crypto.RandomHash()) + e.BeginBlock(19, crypto.RandomHash(), []abci.Tx{}) e.UpdateSpamPoWDifficulty(context.Background(), num.NewUint(22)) - e.EndOfBlock() - e.BeginBlock(29, crypto.RandomHash()) + e.BeginBlock(29, crypto.RandomHash(), []abci.Tx{}) e.UpdateSpamPoWDifficulty(context.Background(), num.NewUint(23)) - e.EndOfBlock() require.Equal(t, uint(20), e.activeParams[e.findParamsForBlockHeight(1)].spamPoWDifficulty) require.Equal(t, uint(20), e.activeParams[e.findParamsForBlockHeight(9)].spamPoWDifficulty) @@ -211,88 +176,83 @@ func TestFindParamsForBlockHeight(t *testing.T) { require.Equal(t, uint(23), e.activeParams[e.findParamsForBlockHeight(100)].spamPoWDifficulty) } -func TestVerifyWithMultipleConfigs(t *testing.T) { - ts := mocks.NewMockTimeService(gomock.NewController(t)) - ts.EXPECT().GetTimeNow().AnyTimes().Return(time.Now()) - e := New(logging.NewTestLogger(), NewDefaultConfig(), ts) - e.UpdateSpamPoWNumberOfPastBlocks(context.Background(), num.NewUint(100)) - e.UpdateSpamPoWDifficulty(context.Background(), num.NewUint(20)) - e.UpdateSpamPoWHashFunction(context.Background(), "sha3_24_rounds") - e.UpdateSpamPoWNumberOfTxPerBlock(context.Background(), num.NewUint(1)) - e.UpdateSpamPoWIncreasingDifficulty(context.Background(), num.NewUint(0)) - e.OnEpochDurationChanged(context.Background(), 24*time.Hour) - - block9Hash := "2E7A16D9EF690F0D2BEED115FBA13BA2AAA16C8F971910AD88C72B9DB010C7D4" - e.BeginBlock(9, block9Hash) - e.UpdateSpamPoWDifficulty(context.Background(), num.NewUint(21)) - e.UpdateSpamPoWNumberOfPastBlocks(context.Background(), num.NewUint(50)) - e.UpdateSpamPoWNumberOfTxPerBlock(context.Background(), num.NewUint(5)) - e.UpdateSpamPoWIncreasingDifficulty(context.Background(), num.NewUint(1)) - - e.EndOfBlock() - e.BeginBlock(19, crypto.RandomHash()) - e.UpdateSpamPoWDifficulty(context.Background(), num.NewUint(22)) - e.UpdateSpamPoWNumberOfPastBlocks(context.Background(), num.NewUint(80)) - e.UpdateSpamPoWNumberOfTxPerBlock(context.Background(), num.NewUint(1)) - e.UpdateSpamPoWIncreasingDifficulty(context.Background(), num.NewUint(1)) - - e.EndOfBlock() - block29Hash := "8890702af457ddcda01fba579a126adcecae954781500acb546fef9c8087a239" - e.BeginBlock(29, block29Hash) - e.UpdateSpamPoWDifficulty(context.Background(), num.NewUint(1)) - e.UpdateSpamPoWNumberOfPastBlocks(context.Background(), num.NewUint(70)) - e.UpdateSpamPoWNumberOfTxPerBlock(context.Background(), num.NewUint(2)) - e.UpdateSpamPoWIncreasingDifficulty(context.Background(), num.NewUint(0)) - e.EndOfBlock() - - block30Hash := "377EEAC9847D751A4FAFD3F2896E99C1A03363EBDA3036C33940CFE578E196D1" - e.BeginBlock(30, block30Hash) - - // now we're in block 90 - e.BeginBlock(90, "792ca202b84226c739f9923046a0f4e7b5ff9e6f1b5636d8e26a8e2c5dec70ac") - - // transactions sent from block height < 10 have past blocks of 100, difficulty of 20 and allow 1 transaction per block with no increased difficulty - tx9_1 := &testTx{txID: "1", blockHeight: 9, party: "party", powTxID: "DFE522E234D67E6AE3F017859F898E576B3928EA57310B765398615A0D3FDE2F", powNonce: 424517} - err := e.DeliverTx(tx9_1) - require.NoError(t, err) - - // doesn't really matter what the pow data is because in block 19 the parameters allowed only 50 blocks behind meaning in block 90 the transaction should be rejected as too old - tx19 := &testTx{txID: "2", blockHeight: 19, party: "party", powTxID: "5B87F9DFA41DABE84A11CA78D9FE11DA8FC2AA926004CA66454A7AF0A206480D", powNonce: 4095356} - err = e.DeliverTx(tx19) - require.Equal(t, "unknown block height for tx:32, command:Amend Order, party:party", err.Error()) - - // in block 29 we're allowed to submit 1 transactions with difficulty starting at 22 and increased difficulty - tx29_1 := &testTx{txID: "3", blockHeight: 29, party: "party", powTxID: "74030ee7dc931be9d9cc5f2c9d44ac174b4144b377ef07a7bb1781856921dd43", powNonce: 1903233} - tx29_2 := &testTx{txID: "4", blockHeight: 29, party: "party", powTxID: "94A9CB1532011081B013CCD8E6AAA832CAB1CBA603F0C5A093B14C4961E5E7F0", powNonce: 7914217} - err = e.DeliverTx(tx29_1) - require.NoError(t, err) - err = e.DeliverTx(tx29_2) - require.NoError(t, err) - - // finally we have a transaction sent in block 30 which allows for 2 transactions with no increased difficulty - tx30_1 := &testTx{txID: "5", blockHeight: 30, party: "party", powTxID: "2A1319636230740888C968E4E7610D6DE820E644EEC3C08AA5322A0A022014BD", powNonce: 380742} - err = e.DeliverTx(tx30_1) - require.NoError(t, err) - - tx30_2 := &testTx{txID: "6", blockHeight: 30, party: "party", powTxID: "2E7A16D9EF690F0D2BEED115FBA13BA2AAA16C8F971910AD88C72B9DB010C7D4", powNonce: 1296835} - err = e.DeliverTx(tx30_2) - require.NoError(t, err) - tx30_3 := &testTx{txID: "7", blockHeight: 30, party: "party", powTxID: "5B0E1EB96CCAC120E6D824A5F4C4007EABC59573B861BD84B1EF09DFB376DC84", powNonce: 388948} - err = e.DeliverTx(tx30_3) - // the third transaction would be rejected and ban the party - require.Equal(t, "too many transactions per block", err.Error()) - - // now move on to the next block and the party should be banned - e.BeginBlock(91, crypto.RandomHash()) - tx90 := &testTx{txID: "7", blockHeight: 90, party: "party", powTxID: "3b8399cdffee2686d75d1a96d22cd49cd11f62c93da20e72239895bfdaf4b772", powNonce: 0} - err = e.DeliverTx(tx90) - require.Equal(t, "party is banned from sending transactions", err.Error()) -} +// func TestVerifyWithMultipleConfigs(t *testing.T) { +// e := New(logging.NewTestLogger(), NewDefaultConfig()) +// e.UpdateSpamPoWNumberOfPastBlocks(context.Background(), num.NewUint(100)) +// e.UpdateSpamPoWDifficulty(context.Background(), num.NewUint(20)) +// e.UpdateSpamPoWHashFunction(context.Background(), "sha3_24_rounds") +// e.UpdateSpamPoWNumberOfTxPerBlock(context.Background(), num.NewUint(1)) +// e.UpdateSpamPoWIncreasingDifficulty(context.Background(), num.NewUint(0)) + +// block9Hash := "2E7A16D9EF690F0D2BEED115FBA13BA2AAA16C8F971910AD88C72B9DB010C7D4" +// e.BeginBlock(9, block9Hash) +// e.UpdateSpamPoWDifficulty(context.Background(), num.NewUint(21)) +// e.UpdateSpamPoWNumberOfPastBlocks(context.Background(), num.NewUint(50)) +// e.UpdateSpamPoWNumberOfTxPerBlock(context.Background(), num.NewUint(5)) +// e.UpdateSpamPoWIncreasingDifficulty(context.Background(), num.NewUint(1)) + +// e.EndOfBlock() +// e.BeginBlock(19, crypto.RandomHash()) +// e.UpdateSpamPoWDifficulty(context.Background(), num.NewUint(22)) +// e.UpdateSpamPoWNumberOfPastBlocks(context.Background(), num.NewUint(80)) +// e.UpdateSpamPoWNumberOfTxPerBlock(context.Background(), num.NewUint(1)) +// e.UpdateSpamPoWIncreasingDifficulty(context.Background(), num.NewUint(1)) + +// e.EndOfBlock() +// block29Hash := "8890702af457ddcda01fba579a126adcecae954781500acb546fef9c8087a239" +// e.BeginBlock(29, block29Hash) +// e.UpdateSpamPoWDifficulty(context.Background(), num.NewUint(1)) +// e.UpdateSpamPoWNumberOfPastBlocks(context.Background(), num.NewUint(70)) +// e.UpdateSpamPoWNumberOfTxPerBlock(context.Background(), num.NewUint(2)) +// e.UpdateSpamPoWIncreasingDifficulty(context.Background(), num.NewUint(0)) +// e.EndOfBlock() + +// block30Hash := "377EEAC9847D751A4FAFD3F2896E99C1A03363EBDA3036C33940CFE578E196D1" +// e.BeginBlock(30, block30Hash) + +// // now we're in block 90 +// e.BeginBlock(90, "792ca202b84226c739f9923046a0f4e7b5ff9e6f1b5636d8e26a8e2c5dec70ac") + +// // transactions sent from block height < 10 have past blocks of 100, difficulty of 20 and allow 1 transaction per block with no increased difficulty +// tx9_1 := &testTx{txID: "1", blockHeight: 9, party: "party", powTxID: "DFE522E234D67E6AE3F017859F898E576B3928EA57310B765398615A0D3FDE2F", powNonce: 424517} +// err := e.DeliverTx(tx9_1) +// require.NoError(t, err) + +// // doesn't really matter what the pow data is because in block 19 the parameters allowed only 50 blocks behind meaning in block 90 the transaction should be rejected as too old +// tx19 := &testTx{txID: "2", blockHeight: 19, party: "party", powTxID: "5B87F9DFA41DABE84A11CA78D9FE11DA8FC2AA926004CA66454A7AF0A206480D", powNonce: 4095356} +// err = e.DeliverTx(tx19) +// require.Equal(t, "unknown block height for tx:32, command:Amend Order, party:party", err.Error()) + +// // in block 29 we're allowed to submit 1 transactions with difficulty starting at 22 and increased difficulty +// tx29_1 := &testTx{txID: "3", blockHeight: 29, party: "party", powTxID: "74030ee7dc931be9d9cc5f2c9d44ac174b4144b377ef07a7bb1781856921dd43", powNonce: 1903233} +// tx29_2 := &testTx{txID: "4", blockHeight: 29, party: "party", powTxID: "94A9CB1532011081B013CCD8E6AAA832CAB1CBA603F0C5A093B14C4961E5E7F0", powNonce: 7914217} +// err = e.DeliverTx(tx29_1) +// require.NoError(t, err) +// err = e.DeliverTx(tx29_2) +// require.NoError(t, err) + +// // finally we have a transaction sent in block 30 which allows for 2 transactions with no increased difficulty +// tx30_1 := &testTx{txID: "5", blockHeight: 30, party: "party", powTxID: "2A1319636230740888C968E4E7610D6DE820E644EEC3C08AA5322A0A022014BD", powNonce: 380742} +// err = e.DeliverTx(tx30_1) +// require.NoError(t, err) + +// tx30_2 := &testTx{txID: "6", blockHeight: 30, party: "party", powTxID: "2E7A16D9EF690F0D2BEED115FBA13BA2AAA16C8F971910AD88C72B9DB010C7D4", powNonce: 1296835} +// err = e.DeliverTx(tx30_2) +// require.NoError(t, err) +// tx30_3 := &testTx{txID: "7", blockHeight: 30, party: "party", powTxID: "5B0E1EB96CCAC120E6D824A5F4C4007EABC59573B861BD84B1EF09DFB376DC84", powNonce: 388948} +// err = e.DeliverTx(tx30_3) +// // the third transaction would be rejected and ban the party +// require.Equal(t, "too many transactions per block", err.Error()) + +// // now move on to the next block and the party should be banned +// e.BeginBlock(91, crypto.RandomHash()) +// tx90 := &testTx{txID: "7", blockHeight: 90, party: "party", powTxID: "3b8399cdffee2686d75d1a96d22cd49cd11f62c93da20e72239895bfdaf4b772", powNonce: 0} +// err = e.DeliverTx(tx90) +// require.Equal(t, "party is banned from sending transactions", err.Error()) +// } func TestEndOfBlockCleanup(t *testing.T) { - ts := mocks.NewMockTimeService(gomock.NewController(t)) - ts.EXPECT().GetTimeNow().AnyTimes().Return(time.Now()) - e := New(logging.NewTestLogger(), NewDefaultConfig(), ts) + e := New(logging.NewTestLogger(), NewDefaultConfig()) e.UpdateSpamPoWNumberOfPastBlocks(context.Background(), num.NewUint(100)) e.UpdateSpamPoWDifficulty(context.Background(), num.NewUint(20)) e.UpdateSpamPoWHashFunction(context.Background(), "sha3_24_rounds") @@ -302,7 +262,7 @@ func TestEndOfBlockCleanup(t *testing.T) { // the setting above is good for transactions from blocks 0 - 9+100 // that means at the end of block 109 it can be removed - e.BeginBlock(9, crypto.RandomHash()) + e.BeginBlock(9, crypto.RandomHash(), []abci.Tx{}) e.UpdateSpamPoWDifficulty(context.Background(), num.NewUint(21)) e.UpdateSpamPoWNumberOfPastBlocks(context.Background(), num.NewUint(50)) e.UpdateSpamPoWNumberOfTxPerBlock(context.Background(), num.NewUint(5)) @@ -311,8 +271,7 @@ func TestEndOfBlockCleanup(t *testing.T) { // the setting above is good for transactions from blocks 10 - 19+50 // that means at the end of block 69 it can be removed - e.EndOfBlock() - e.BeginBlock(19, crypto.RandomHash()) + e.BeginBlock(19, crypto.RandomHash(), []abci.Tx{}) e.UpdateSpamPoWDifficulty(context.Background(), num.NewUint(22)) e.UpdateSpamPoWNumberOfPastBlocks(context.Background(), num.NewUint(80)) e.UpdateSpamPoWNumberOfTxPerBlock(context.Background(), num.NewUint(1)) @@ -321,30 +280,25 @@ func TestEndOfBlockCleanup(t *testing.T) { // the setting above is good for transactions from blocks 20 - 29+80 // that means at the end of block 109 it can be removed - e.EndOfBlock() - e.BeginBlock(29, crypto.RandomHash()) + e.BeginBlock(29, crypto.RandomHash(), []abci.Tx{}) e.UpdateSpamPoWDifficulty(context.Background(), num.NewUint(1)) e.UpdateSpamPoWNumberOfPastBlocks(context.Background(), num.NewUint(70)) e.UpdateSpamPoWNumberOfTxPerBlock(context.Background(), num.NewUint(2)) e.UpdateSpamPoWIncreasingDifficulty(context.Background(), num.NewUint(0)) - e.EndOfBlock() // the setting above is good for transactions from blocks 30 - - e.BeginBlock(30, crypto.RandomHash()) - e.EndOfBlock() + e.BeginBlock(30, crypto.RandomHash(), []abci.Tx{}) require.Equal(t, 4, len(e.activeParams)) require.Equal(t, 4, len(e.activeStates)) - e.BeginBlock(69, crypto.RandomHash()) - e.EndOfBlock() + e.BeginBlock(69, crypto.RandomHash(), []abci.Tx{}) require.Equal(t, 3, len(e.activeParams)) require.Equal(t, 3, len(e.activeStates)) - e.BeginBlock(109, crypto.RandomHash()) - e.EndOfBlock() + e.BeginBlock(109, crypto.RandomHash(), []abci.Tx{}) require.Equal(t, 1, len(e.activeParams)) require.Equal(t, 1, len(e.activeStates)) diff --git a/core/pow/noop_engine.go b/core/pow/noop_engine.go index 752f4dc7a4..f3383a0fe7 100644 --- a/core/pow/noop_engine.go +++ b/core/pow/noop_engine.go @@ -32,27 +32,29 @@ func NewNoop() *NoopEngine { return &NoopEngine{} } -func (e *NoopEngine) BeginBlock(blockHeight uint64, blockHash string) { +func (e *NoopEngine) BeginBlock(blockHeight uint64, blockHash string, txs []abci.Tx) { e.blockHeight = blockHeight e.blockHash = blockHash } +func (e *NoopEngine) OnFinalize() {} func (e *NoopEngine) EndOfBlock() {} func (e *NoopEngine) Commit() {} func (e *NoopEngine) CheckTx(tx abci.Tx) error { return nil } -func (e *NoopEngine) DeliverTx(tx abci.Tx) error { - return nil +func (e *NoopEngine) ProcessProposal([]abci.Tx) bool { return false } +func (e *NoopEngine) CheckBlockTx(tx abci.Tx) (ValidationResult, *uint) { + return ValidationResultSuccess, nil } - -func (e *NoopEngine) IsReady() bool { return true } -func (e *NoopEngine) SpamPoWNumberOfPastBlocks() uint32 { return uint32(0) } -func (e *NoopEngine) SpamPoWDifficulty() uint32 { return uint32(0) } -func (e *NoopEngine) SpamPoWHashFunction() string { return "" } -func (e *NoopEngine) SpamPoWNumberOfTxPerBlock() uint32 { return uint32(0) } -func (e *NoopEngine) SpamPoWIncreasingDifficulty() bool { return false } +func (e *NoopEngine) EndPrepareProposal([]ValidationEntry) {} +func (e *NoopEngine) IsReady() bool { return true } +func (e *NoopEngine) SpamPoWNumberOfPastBlocks() uint32 { return uint32(0) } +func (e *NoopEngine) SpamPoWDifficulty() uint32 { return uint32(0) } +func (e *NoopEngine) SpamPoWHashFunction() string { return "" } +func (e *NoopEngine) SpamPoWNumberOfTxPerBlock() uint32 { return uint32(0) } +func (e *NoopEngine) SpamPoWIncreasingDifficulty() bool { return false } func (e *NoopEngine) BlockData() (uint64, string) { return e.blockHeight, e.blockHash diff --git a/core/pow/snapshot.go b/core/pow/snapshot.go index c7cb48a2bc..924d38a354 100644 --- a/core/pow/snapshot.go +++ b/core/pow/snapshot.go @@ -18,7 +18,6 @@ package pow import ( "context" "sort" - "time" "code.vegaprotocol.io/vega/core/types" snapshot "code.vegaprotocol.io/vega/protos/vega/snapshot/v1" @@ -40,11 +39,6 @@ func (e *Engine) Stopped() bool { // get the serialised form and hash of the given key. func (e *Engine) serialise() ([]byte, error) { - bannedParties := map[string]int64{} - for k, t := range e.bannedParties { - bannedParties[k] = t.UnixNano() - } - nonceHeights := map[uint64][]*snapshot.NonceRef{} for k, v := range e.heightToNonceRef { @@ -61,7 +55,6 @@ func (e *Engine) serialise() ([]byte, error) { HeightToTx: e.heightToTx, HeightToTid: e.heightToTid, HeightToNonceRef: nonceHeights, - BannedParties: bannedParties, ActiveParams: e.paramsToSnapshotParams(), ActiveStates: e.statesToSnapshotStates(), LastPruningBlock: e.lastPruningBlock, @@ -180,10 +173,6 @@ func (e *Engine) LoadState(ctx context.Context, p *types.Payload) ([]types.State return nil, types.ErrInvalidSnapshotNamespace } pl := p.Data.(*types.PayloadProofOfWork) - e.bannedParties = make(map[string]time.Time, len(pl.BannedParties)) - for k, v := range pl.BannedParties { - e.bannedParties[k] = time.Unix(0, v) - } copy(e.blockHash[:], pl.BlockHash[:ringSize]) copy(e.blockHeight[:], pl.BlockHeight[:ringSize]) e.heightToTx = pl.HeightToTx diff --git a/core/pow/snapshot_test.go b/core/pow/snapshot_test.go index 413e034268..00bbed65f1 100644 --- a/core/pow/snapshot_test.go +++ b/core/pow/snapshot_test.go @@ -21,31 +21,31 @@ import ( "testing" "time" - "code.vegaprotocol.io/vega/core/api/mocks" + "code.vegaprotocol.io/vega/core/blockchain/abci" "code.vegaprotocol.io/vega/core/integration/stubs" + "code.vegaprotocol.io/vega/core/pow/mocks" "code.vegaprotocol.io/vega/core/snapshot" "code.vegaprotocol.io/vega/core/stats" "code.vegaprotocol.io/vega/core/types" + vgcontext "code.vegaprotocol.io/vega/libs/context" "code.vegaprotocol.io/vega/libs/crypto" "code.vegaprotocol.io/vega/libs/num" + "code.vegaprotocol.io/vega/libs/proto" vgtest "code.vegaprotocol.io/vega/libs/test" "code.vegaprotocol.io/vega/logging" "code.vegaprotocol.io/vega/paths" snapshotpb "code.vegaprotocol.io/vega/protos/vega/snapshot/v1" "github.com/golang/mock/gomock" - "github.com/golang/protobuf/proto" - "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" ) func TestConversions(t *testing.T) { p := &types.PayloadProofOfWork{ - BlockHeight: []uint64{100, 101, 102}, - BlockHash: []string{"94A9CB1532011081B013CCD8E6AAA832CAB1CBA603F0C5A093B14C4961E5E7F0", "DC911C0EA95545441F3E1182DD25D973764395A7E75CBDBC086F1C6F7075AED6", "2E4F2967AA904F9A952BB4813EC6BBB3730B9FFFEC44106B89F0A1958547733C"}, - HeightToTx: map[uint64][]string{100: {"1", "2"}, 101: {"3"}}, - HeightToTid: map[uint64][]string{100: {"100", "200"}, 101: {"300"}}, - BannedParties: map[string]int64{"party1": 105, "party2": 104}, + BlockHeight: []uint64{100, 101, 102}, + BlockHash: []string{"94A9CB1532011081B013CCD8E6AAA832CAB1CBA603F0C5A093B14C4961E5E7F0", "DC911C0EA95545441F3E1182DD25D973764395A7E75CBDBC086F1C6F7075AED6", "2E4F2967AA904F9A952BB4813EC6BBB3730B9FFFEC44106B89F0A1958547733C"}, + HeightToTx: map[uint64][]string{100: {"1", "2"}, 101: {"3"}}, + HeightToTid: map[uint64][]string{100: {"100", "200"}, 101: {"300"}}, } pp := p.IntoProto() @@ -71,10 +71,6 @@ func TestConversions(t *testing.T) { require.Equal(t, "100", pp.ProofOfWork.TidAtHeight[0].Transactions[0]) require.Equal(t, "200", pp.ProofOfWork.TidAtHeight[0].Transactions[1]) require.Equal(t, "300", pp.ProofOfWork.TidAtHeight[1].Transactions[0]) - require.Equal(t, "party1", pp.ProofOfWork.Banned[0].Party) - require.Equal(t, int64(105), pp.ProofOfWork.Banned[0].Until) - require.Equal(t, "party2", pp.ProofOfWork.Banned[1].Party) - require.Equal(t, int64(104), pp.ProofOfWork.Banned[1].Until) ppp := types.PayloadProofOfWorkFromProto(pp) @@ -98,24 +94,22 @@ func TestConversions(t *testing.T) { require.Equal(t, 1, len(ppp.HeightToTid[101])) require.Equal(t, "3", ppp.HeightToTx[101][0]) require.Equal(t, "300", ppp.HeightToTid[101][0]) - require.Equal(t, int64(105), ppp.BannedParties["party1"]) - require.Equal(t, int64(104), ppp.BannedParties["party2"]) } func TestSnapshot(t *testing.T) { ts := mocks.NewMockTimeService(gomock.NewController(t)) ts.EXPECT().GetTimeNow().AnyTimes().Return(time.Now()) - e := New(logging.NewTestLogger(), NewDefaultConfig(), ts) - e.UpdateSpamPoWNumberOfPastBlocks(context.Background(), num.NewUint(1)) + e := New(logging.NewTestLogger(), NewDefaultConfig()) + e.UpdateSpamPoWNumberOfPastBlocks(context.Background(), num.NewUint(100)) e.UpdateSpamPoWDifficulty(context.Background(), num.NewUint(20)) e.UpdateSpamPoWHashFunction(context.Background(), crypto.Sha3) e.UpdateSpamPoWNumberOfTxPerBlock(context.Background(), num.NewUint(1)) e.UpdateSpamPoWIncreasingDifficulty(context.Background(), num.NewUint(1)) - e.BeginBlock(100, "2E7A16D9EF690F0D2BEED115FBA13BA2AAA16C8F971910AD88C72B9DB010C7D4") + e.BeginBlock(100, "2E7A16D9EF690F0D2BEED115FBA13BA2AAA16C8F971910AD88C72B9DB010C7D4", []abci.Tx{}) - // add a new set of configuration which becomes active at block 101 - e.UpdateSpamPoWNumberOfPastBlocks(context.Background(), num.NewUint(5)) + // add a new set of configuration which becomes active at block 100 + e.UpdateSpamPoWNumberOfPastBlocks(context.Background(), num.NewUint(200)) e.UpdateSpamPoWDifficulty(context.Background(), num.NewUint(25)) e.UpdateSpamPoWHashFunction(context.Background(), crypto.Sha3) e.UpdateSpamPoWNumberOfTxPerBlock(context.Background(), num.NewUint(2)) @@ -123,18 +117,20 @@ func TestSnapshot(t *testing.T) { party := crypto.RandomHash() - require.NoError(t, e.DeliverTx(&testTx{txID: "1", party: party, blockHeight: 100, powTxID: "DFE522E234D67E6AE3F017859F898E576B3928EA57310B765398615A0D3FDE2F", powNonce: 424517})) - require.NoError(t, e.DeliverTx(&testTx{txID: "2", party: party, blockHeight: 100, powTxID: "5B0E1EB96CCAC120E6D824A5F4C4007EABC59573B861BD84B1EF09DFB376DC84", powNonce: 4031737})) - require.NoError(t, e.DeliverTx(&testTx{txID: "3", party: party, blockHeight: 100, powTxID: "94A9CB1532011081B013CCD8E6AAA832CAB1CBA603F0C5A093B14C4961E5E7F0", powNonce: 431336})) + txs := []abci.Tx{ + &testTx{txID: "1", party: party, blockHeight: 100, powTxID: "DFE522E234D67E6AE3F017859F898E576B3928EA57310B765398615A0D3FDE2F", powNonce: 424517}, + &testTx{txID: "2", party: party, blockHeight: 100, powTxID: "5B0E1EB96CCAC120E6D824A5F4C4007EABC59573B861BD84B1EF09DFB376DC84", powNonce: 4031737}, + &testTx{txID: "3", party: party, blockHeight: 100, powTxID: "94A9CB1532011081B013CCD8E6AAA832CAB1CBA603F0C5A093B14C4961E5E7F0", powNonce: 431336}, + } - e.BeginBlock(101, "2E289FB9CEF7234E2C08F34CCD66B330229067CE47E22F76EF0595B3ABA9968F") - e.BeginBlock(102, "2E289FB9CEF7234E2C08F34CCD66B330229067CE47E22F76EF0595B3ABA9968F") + e.BeginBlock(101, "2E289FB9CEF7234E2C08F34CCD66B330229067CE47E22F76EF0595B3ABA9968F", txs) + e.BeginBlock(102, "2E289FB9CEF7234E2C08F34CCD66B330229067CE47E22F76EF0595B3ABA9968F", []abci.Tx{}) key := (&types.PayloadProofOfWork{}).Key() state1, _, err := e.GetState(key) require.NoError(t, err) - eLoaded := New(logging.NewTestLogger(), NewDefaultConfig(), mocks.NewMockTimeService(gomock.NewController(t))) + eLoaded := New(logging.NewTestLogger(), NewDefaultConfig()) eLoaded.UpdateSpamPoWNumberOfPastBlocks(context.Background(), num.NewUint(1)) eLoaded.UpdateSpamPoWDifficulty(context.Background(), num.NewUint(20)) eLoaded.UpdateSpamPoWHashFunction(context.Background(), crypto.Sha3) @@ -155,7 +151,7 @@ func TestSnapshotViaEngine(t *testing.T) { ctx := vgtest.VegaContext("chainid", 100) ts := mocks.NewMockTimeService(gomock.NewController(t)) ts.EXPECT().GetTimeNow().AnyTimes().Return(time.Now()) - powEngine1 := New(logging.NewTestLogger(), NewDefaultConfig(), ts) + powEngine1 := New(logging.NewTestLogger(), NewDefaultConfig()) now := time.Now() log := logging.NewTestLogger() timeService := stubs.NewTimeStub() @@ -171,27 +167,27 @@ func TestSnapshotViaEngine(t *testing.T) { snapshotEngine1.AddProviders(powEngine1) require.NoError(t, snapshotEngine1.Start(ctx)) - require.NoError(t, powEngine1.UpdateSpamPoWNumberOfPastBlocks(context.Background(), num.NewUint(2))) require.NoError(t, powEngine1.UpdateSpamPoWDifficulty(context.Background(), num.NewUint(20))) require.NoError(t, powEngine1.UpdateSpamPoWHashFunction(context.Background(), crypto.Sha3)) require.NoError(t, powEngine1.UpdateSpamPoWNumberOfTxPerBlock(context.Background(), num.NewUint(1))) require.NoError(t, powEngine1.UpdateSpamPoWIncreasingDifficulty(context.Background(), num.NewUint(1))) - powEngine1.BeginBlock(99, "377EEAC9847D751A4FAFD3F2896E99C1A03363EBDA3036C33940CFE578E196D1") - powEngine1.BeginBlock(100, "2E7A16D9EF690F0D2BEED115FBA13BA2AAA16C8F971910AD88C72B9DB010C7D4") + powEngine1.BeginBlock(99, "377EEAC9847D751A4FAFD3F2896E99C1A03363EBDA3036C33940CFE578E196D1", []abci.Tx{}) + powEngine1.BeginBlock(100, "2E7A16D9EF690F0D2BEED115FBA13BA2AAA16C8F971910AD88C72B9DB010C7D4", []abci.Tx{}) party := crypto.RandomHash() - require.NoError(t, powEngine1.DeliverTx(&testTx{txID: "1", party: party, blockHeight: 100, powTxID: "DFE522E234D67E6AE3F017859F898E576B3928EA57310B765398615A0D3FDE2F", powNonce: 424517})) - require.NoError(t, powEngine1.DeliverTx(&testTx{txID: "2", party: party, blockHeight: 100, powTxID: "5B0E1EB96CCAC120E6D824A5F4C4007EABC59573B861BD84B1EF09DFB376DC84", powNonce: 4031737})) - require.NoError(t, powEngine1.DeliverTx(&testTx{txID: "3", party: party, blockHeight: 100, powTxID: "94A9CB1532011081B013CCD8E6AAA832CAB1CBA603F0C5A093B14C4961E5E7F0", powNonce: 431336})) - - // add another transaction from the same party with reduced difficulty but from another block - require.NoError(t, powEngine1.DeliverTx(&testTx{txID: "4", party: party, blockHeight: 99, powTxID: "4633a4d29f543cdd9afe7555c352179063d1ead0c778d246fabfc4c6f8adf031", powNonce: 2646611})) + txs := []abci.Tx{ + &testTx{txID: "1", party: party, blockHeight: 100, powTxID: "DFE522E234D67E6AE3F017859F898E576B3928EA57310B765398615A0D3FDE2F", powNonce: 424517}, + &testTx{txID: "2", party: party, blockHeight: 100, powTxID: "5B0E1EB96CCAC120E6D824A5F4C4007EABC59573B861BD84B1EF09DFB376DC84", powNonce: 4031737}, + &testTx{txID: "3", party: party, blockHeight: 100, powTxID: "94A9CB1532011081B013CCD8E6AAA832CAB1CBA603F0C5A093B14C4961E5E7F0", powNonce: 431336}, + // add another transaction from the same party with reduced difficulty but from another block + &testTx{txID: "4", party: party, blockHeight: 99, powTxID: "4633a4d29f543cdd9afe7555c352179063d1ead0c778d246fabfc4c6f8adf031", powNonce: 2646611}, + } - powEngine1.BeginBlock(101, "2E289FB9CEF7234E2C08F34CCD66B330229067CE47E22F76EF0595B3ABA9968F") - powEngine1.BeginBlock(102, "2E289FB9CEF7234E2C08F34CCD66B330229067CE47E22F76EF0595B3ABA9968F") + powEngine1.BeginBlock(101, "2E289FB9CEF7234E2C08F34CCD66B330229067CE47E22F76EF0595B3ABA9968F", txs) + powEngine1.BeginBlock(102, "2E289FB9CEF7234E2C08F34CCD66B330229067CE47E22F76EF0595B3ABA9968F", []abci.Tx{}) require.NoError(t, powEngine1.UpdateSpamPoWNumberOfPastBlocks(context.Background(), num.NewUint(2))) require.NoError(t, powEngine1.UpdateSpamPoWDifficulty(context.Background(), num.NewUint(25))) @@ -199,14 +195,15 @@ func TestSnapshotViaEngine(t *testing.T) { require.NoError(t, powEngine1.UpdateSpamPoWNumberOfTxPerBlock(context.Background(), num.NewUint(5))) require.NoError(t, powEngine1.UpdateSpamPoWIncreasingDifficulty(context.Background(), num.NewUint(0))) + ctx = vgcontext.WithTraceID(vgcontext.WithBlockHeight(context.Background(), 102), "0xDEADBEEF") + ctx = vgcontext.WithChainID(ctx, "chainid") hash1, err := snapshotEngine1.SnapshotNow(ctx) require.NoError(t, err) - state1 := map[string][]byte{} for _, key := range powEngine1.Keys() { state, additionalProvider, err := powEngine1.GetState(key) require.NoError(t, err) - assert.Empty(t, additionalProvider) + require.Empty(t, additionalProvider) state1[key] = state } @@ -214,7 +211,7 @@ func TestSnapshotViaEngine(t *testing.T) { tsLoaded := mocks.NewMockTimeService(gomock.NewController(t)) tsLoaded.EXPECT().GetTimeNow().AnyTimes().Return(time.Now()) - powEngine2 := New(logging.NewTestLogger(), NewDefaultConfig(), tsLoaded) + powEngine2 := New(logging.NewTestLogger(), NewDefaultConfig()) timeServiceLoaded := stubs.NewTimeStub() timeServiceLoaded.SetTime(now) snapshotEngine2, err := snapshot.NewEngine(vegaPath, config, log, timeServiceLoaded, statsData.Blockchain) @@ -234,11 +231,11 @@ func TestSnapshotViaEngine(t *testing.T) { for _, key := range powEngine2.Keys() { state, additionalProvider, err := powEngine2.GetState(key) require.NoError(t, err) - assert.Empty(t, additionalProvider) + require.Empty(t, additionalProvider) state2[key] = state } for key := range state1 { - assert.Equalf(t, state1[key], state2[key], "Key %q does not have the same data", key) + require.Equalf(t, state1[key], state2[key], "Key %q does not have the same data", key) } } diff --git a/core/processor/abci.go b/core/processor/abci.go index 7b73930452..983b3ca0fc 100644 --- a/core/processor/abci.go +++ b/core/processor/abci.go @@ -25,6 +25,7 @@ import ( "os" "path/filepath" "reflect" + "sort" "strconv" "strings" "sync/atomic" @@ -38,6 +39,7 @@ import ( "code.vegaprotocol.io/vega/core/genesis" "code.vegaprotocol.io/vega/core/idgeneration" "code.vegaprotocol.io/vega/core/netparams" + "code.vegaprotocol.io/vega/core/pow" "code.vegaprotocol.io/vega/core/processor/ratelimit" "code.vegaprotocol.io/vega/core/referral" "code.vegaprotocol.io/vega/core/snapshot" @@ -57,14 +59,23 @@ import ( commandspb "code.vegaprotocol.io/vega/protos/vega/commands/v1" eventspb "code.vegaprotocol.io/vega/protos/vega/events/v1" - tmtypes "github.com/tendermint/tendermint/abci/types" - tmtypes1 "github.com/tendermint/tendermint/proto/tendermint/types" - tmtypesint "github.com/tendermint/tendermint/types" + tmtypes "github.com/cometbft/cometbft/abci/types" + tmtypes1 "github.com/cometbft/cometbft/proto/tendermint/types" + types1 "github.com/cometbft/cometbft/proto/tendermint/types" + tmtypesint "github.com/cometbft/cometbft/types" "go.uber.org/zap" ) const AppVersion = 1 +type TxWrapper struct { + tx abci.Tx + timeIndex int // this is an indicator of insertion order + raw []byte + priority uint64 + gasWanted uint64 +} + var ( ErrUnexpectedTxPubKey = errors.New("no one listens to the public keys that signed this oracle data") ErrTradingDisabled = errors.New("trading disabled") @@ -85,19 +96,22 @@ type Checkpoint interface { } type SpamEngine interface { - EndOfBlock(blockHeight uint64, now time.Time) - PreBlockAccept(tx abci.Tx) (bool, error) - PostBlockAccept(tx abci.Tx) (bool, error) + BeginBlock(txs []abci.Tx) + EndPrepareProposal() + PreBlockAccept(tx abci.Tx) error + ProcessProposal(txs []abci.Tx) bool + CheckBlockTx(tx abci.Tx) error } type PoWEngine interface { api.ProofOfWorkParams - BeginBlock(blockHeight uint64, blockHash string) - EndOfBlock() + BeginBlock(blockHeight uint64, blockHash string, txs []abci.Tx) + CheckBlockTx(tx abci.Tx) (pow.ValidationResult, *uint) + ProcessProposal(txs []abci.Tx) bool + EndPrepareProposal([]pow.ValidationEntry) CheckTx(tx abci.Tx) error - DeliverTx(tx abci.Tx) error - Commit() GetSpamStatistics(partyID string) *protoapi.PoWStatistic + OnFinalize() } //nolint:interfacebloat @@ -143,6 +157,7 @@ type VolumeDiscountProgram interface { type BlockchainClient interface { Validators(height *int64) ([]*tmtypesint.Validator, error) + MaxMempoolSize() int64 } type ProtocolUpgradeService interface { @@ -320,15 +335,16 @@ func NewApp( } // setup handlers + app.abci.OnPrepareProposal = app.prepareProposal + app.abci.OnProcessProposal = app.processProposal app.abci.OnInitChain = app.OnInitChain app.abci.OnBeginBlock = app.OnBeginBlock app.abci.OnEndBlock = app.OnEndBlock app.abci.OnCommit = app.OnCommit app.abci.OnCheckTx = app.OnCheckTx app.abci.OnCheckTxSpam = app.OnCheckTxSpam - app.abci.OnDeliverTx = app.OnDeliverTx - app.abci.OnDeliverTxSpam = app.OnDeliverTXSpam app.abci.OnInfo = app.Info + app.abci.OnFinalize = app.Finalize // snapshot specific handlers. app.abci.OnListSnapshots = app.ListSnapshots app.abci.OnOfferSnapshot = app.OfferSnapshot @@ -591,20 +607,20 @@ func (app *App) cancel() { } } -func (app *App) Info(_ tmtypes.RequestInfo) tmtypes.ResponseInfo { +func (app *App) Info(_ context.Context, _ *tmtypes.RequestInfo) (*tmtypes.ResponseInfo, error) { if len(app.lastBlockAppHash) != 0 { // we must've lost connection to tendermint for a bit, tell it where we got up to height, _ := vgcontext.BlockHeightFromContext(app.blockCtx) app.log.Info("ABCI service INFO requested after reconnect", - logging.Int64("height", height), + logging.Uint64("height", height), logging.String("hash", hex.EncodeToString(app.lastBlockAppHash)), ) - return tmtypes.ResponseInfo{ + return &tmtypes.ResponseInfo{ AppVersion: AppVersion, Version: app.version, - LastBlockHeight: height, + LastBlockHeight: int64(height), LastBlockAppHash: app.lastBlockAppHash, - } + }, nil } // returns whether or not we have loaded from a snapshot (and may even do the loading) @@ -638,39 +654,36 @@ func (app *App) Info(_ tmtypes.RequestInfo) tmtypes.ResponseInfo { logging.Int64("height", resp.LastBlockHeight), logging.String("hash", hex.EncodeToString(resp.LastBlockAppHash)), ) - return resp + return &resp, nil } -func (app *App) ListSnapshots(_ tmtypes.RequestListSnapshots) tmtypes.ResponseListSnapshots { +func (app *App) ListSnapshots(_ context.Context, _ *tmtypes.RequestListSnapshots) (*tmtypes.ResponseListSnapshots, error) { app.log.Debug("ABCI service ListSnapshots requested") - latestSnapshots, err := app.snapshotEngine.ListLatestSnapshots() if err != nil { app.log.Error("Could not list latest snapshots", logging.Error(err)) - return tmtypes.ResponseListSnapshots{} + return &tmtypes.ResponseListSnapshots{}, err } - - return tmtypes.ResponseListSnapshots{ + return &tmtypes.ResponseListSnapshots{ Snapshots: latestSnapshots, - } + }, nil } -func (app *App) OfferSnapshot(req tmtypes.RequestOfferSnapshot) tmtypes.ResponseOfferSnapshot { +func (app *App) OfferSnapshot(_ context.Context, req *tmtypes.RequestOfferSnapshot) (*tmtypes.ResponseOfferSnapshot, error) { app.log.Debug("ABCI service OfferSnapshot start") - if app.snapshotEngine.HasRestoredStateAlready() { app.log.Warn("The snapshot engine aborted the snapshot offer from state-sync since the state has already been restored") - return tmtypes.ResponseOfferSnapshot{ + return &tmtypes.ResponseOfferSnapshot{ Result: tmtypes.ResponseOfferSnapshot_ABORT, - } + }, nil } deserializedSnapshot, err := types.SnapshotFromTM(req.Snapshot) if err != nil { app.log.Error("Could not deserialize snapshot", logging.Error(err)) - return tmtypes.ResponseOfferSnapshot{ + return &tmtypes.ResponseOfferSnapshot{ Result: tmtypes.ResponseOfferSnapshot_REJECT_SENDER, - } + }, err } // check that our unpacked snapshot's hash matches that which tendermint thinks it sent @@ -678,58 +691,56 @@ func (app *App) OfferSnapshot(req tmtypes.RequestOfferSnapshot) tmtypes.Response app.log.Error("The hashes from the request and the deserialized snapshot mismatch", logging.String("deserialized-hash", hex.EncodeToString(deserializedSnapshot.Hash)), logging.String("request-hash", hex.EncodeToString(req.AppHash))) - return tmtypes.ResponseOfferSnapshot{ + return &tmtypes.ResponseOfferSnapshot{ Result: tmtypes.ResponseOfferSnapshot_REJECT, - } + }, fmt.Errorf("hash mismatch") } - return app.snapshotEngine.ReceiveSnapshot(deserializedSnapshot) + res := app.snapshotEngine.ReceiveSnapshot(deserializedSnapshot) + return &res, nil } -func (app *App) ApplySnapshotChunk(ctx context.Context, req tmtypes.RequestApplySnapshotChunk) tmtypes.ResponseApplySnapshotChunk { +func (app *App) ApplySnapshotChunk(ctx context.Context, req *tmtypes.RequestApplySnapshotChunk) (*tmtypes.ResponseApplySnapshotChunk, error) { app.log.Debug("ABCI service ApplySnapshotChunk start") if app.snapshotEngine.HasRestoredStateAlready() { app.log.Warn("The snapshot engine aborted the snapshot chunk from state-sync since the state has already been restored") - return tmtypes.ResponseApplySnapshotChunk{ + return &tmtypes.ResponseApplySnapshotChunk{ Result: tmtypes.ResponseApplySnapshotChunk_ABORT, - } + }, nil // ??? } - chunk := &types.RawChunk{ Nr: req.Index, Data: req.Chunk, } - return app.snapshotEngine.ReceiveSnapshotChunk(ctx, chunk, req.Sender) + res := app.snapshotEngine.ReceiveSnapshotChunk(ctx, chunk, req.Sender) + return &res, nil } -func (app *App) LoadSnapshotChunk(req tmtypes.RequestLoadSnapshotChunk) tmtypes.ResponseLoadSnapshotChunk { +func (app *App) LoadSnapshotChunk(_ context.Context, req *tmtypes.RequestLoadSnapshotChunk) (*tmtypes.ResponseLoadSnapshotChunk, error) { app.log.Debug("ABCI service LoadSnapshotChunk start") - - rawChunk, err := app.snapshotEngine.RetrieveSnapshotChunk(req.Height, req.Format, req.Chunk) + raw, err := app.snapshotEngine.RetrieveSnapshotChunk(req.Height, req.Format, req.Chunk) if err != nil { - app.log.Error("Could not load a snapshot chunk from snapshot engine", - logging.Uint64("height", req.Height), - logging.Error(err), - ) - return tmtypes.ResponseLoadSnapshotChunk{} - } - - return tmtypes.ResponseLoadSnapshotChunk{ - Chunk: rawChunk.Data, + app.log.Error("failed to load snapshot chunk", logging.Error(err), logging.Uint64("height", req.Height)) + return &tmtypes.ResponseLoadSnapshotChunk{}, err } + return &tmtypes.ResponseLoadSnapshotChunk{ + Chunk: raw.Data, + }, nil } -func (app *App) OnInitChain(req tmtypes.RequestInitChain) tmtypes.ResponseInitChain { +func (app *App) OnInitChain(req *tmtypes.RequestInitChain) (*tmtypes.ResponseInitChain, error) { app.log.Debug("ABCI service InitChain start") hash := hex.EncodeToString(vgcrypto.Hash([]byte(req.ChainId))) app.abci.SetChainID(req.ChainId) app.chainCtx = vgcontext.WithChainID(context.Background(), req.ChainId) - ctx := vgcontext.WithBlockHeight(app.chainCtx, req.InitialHeight) + ctx := vgcontext.WithBlockHeight(app.chainCtx, uint64(req.InitialHeight)) ctx = vgcontext.WithTraceID(ctx, hash) app.blockCtx = ctx + app.log.Debug("OnInitChain-NewBeginBlock", logging.Uint64("height", uint64(req.InitialHeight)), logging.Time("blockTime", req.Time), logging.String("blockHash", hash)) + app.broker.Send( events.NewBeginBlock(ctx, eventspb.BeginBlock{ Height: uint64(req.InitialHeight), @@ -751,12 +762,131 @@ func (app *App) OnInitChain(req tmtypes.RequestInitChain) tmtypes.ResponseInitCh app.ethCallEngine.Start() - return tmtypes.ResponseInitChain{ + return &tmtypes.ResponseInitChain{ Validators: app.top.GetValidatorPowerUpdates(), + }, nil +} + +// prepareProposal takes an ordered slice of transactions and decides which of them go into the next block. +// The logic for selection is as follows: +// 1. mempool transactions are sorted by priority then insertion order (aka time) +// 2. we add *valid* transaction to the block so long as gas and maxBytes limits are not violated +// 3. we never add transactions failing pow checks +// 4. we never add transactions failing spam checks +// therefore a block generated with this method will never contain any transactions that would violate spam/pow constraints that would have previously +// caused the party to get blocked. +func (app *App) prepareProposal(txs []abci.Tx, rawTxs [][]byte) [][]byte { + var totalBytes int64 + + // internally we use this as max bytes, externally to consensus params we return max ints. This is done so that cometbft always returns to us the full mempool + // and we can first sort it by priority and then reap by size. + maxBytes := tmtypesint.DefaultBlockParams().MaxBytes * 4 + app.log.Debug("prepareProposal called with", logging.Int("txs", len(rawTxs)), logging.Int64("max-bytes", maxBytes)) + + // wrap the transaction with information about gas wanted and priority + wrappedTxs := make([]*TxWrapper, 0, len(txs)) + for i, v := range txs { + wtx, error := app.wrapTx(v, rawTxs[i], i) + if error != nil { + continue + } + wrappedTxs = append(wrappedTxs, wtx) } + + // sort by priority descending. If priority is equal use the order in the mempol ascending + sort.Slice(wrappedTxs, func(i, j int) bool { + if wrappedTxs[i].priority == wrappedTxs[j].priority { + return wrappedTxs[i].timeIndex < wrappedTxs[j].timeIndex + } + return wrappedTxs[i].priority > wrappedTxs[j].priority + }) + + // add transactions to the block as long as we can without breaking size and gas limits in order of priority + validationResults := []pow.ValidationEntry{} + maxGas := app.getMaxGas() + totalGasWanted := uint64(0) + blockTxs := [][]byte{} + + for _, tx := range wrappedTxs { + totalBytes += int64(len(tx.raw)) + if totalBytes > maxBytes { + break + } + totalGasWanted += tx.gasWanted + if totalGasWanted > maxGas { + break + } + + if !app.nilPow { + vr, d := app.pow.CheckBlockTx(tx.tx) + validationResults = append(validationResults, pow.ValidationEntry{Tx: tx.tx, Difficulty: d, ValResult: vr}) + if vr != pow.ValidationResultSuccess && vr != pow.ValidationResultValidatorCommand { + app.log.Debug("pow failure", logging.Int64("validation-result", int64(vr))) + continue + } + } + + if !app.nilSpam { + err := app.spam.CheckBlockTx(tx.tx) + if err != nil { + app.log.Debug("spam error", logging.Error(err)) + continue + } + } + + if err := app.canSubmitTx(tx.tx); err != nil { + continue + } + app.log.Debug("adding tx to blockProposal", logging.String("tx-hash", hex.EncodeToString(tx.tx.Hash())), logging.String("tid", tx.tx.GetPoWTID())) + blockTxs = append(blockTxs, tx.raw) + } + app.log.Debug("prepareProposal returned with", logging.Int("blockTxs", len(blockTxs))) + if !app.nilPow { + app.pow.EndPrepareProposal(validationResults) + } + if !app.nilSpam { + app.spam.EndPrepareProposal() + } + return blockTxs +} + +// processProposal takes a block proposal and verifies that it has no malformed or offending transactions which should never be if the validator is using the prepareProposal +// to generate a block. +// The verifications include: +// 1. no violations of pow and spam +// 2. max gas limit is not exceeded +// 3. (soft) max bytes is not exceeded. +func (app *App) processProposal(txs []abci.Tx) bool { + totalGasWanted := 0 + maxGas := app.gastimator.GetMaxGas() + maxBytes := tmtypesint.DefaultBlockParams().MaxBytes * 4 + size := int64(0) + for _, tx := range txs { + size += int64(tx.GetLength()) + if size > maxBytes { + return false + } + gw, err := app.getGasWanted(tx) + if err != nil { + return false + } + totalGasWanted += int(gw) + if totalGasWanted > int(maxGas) { + return false + } + } + + if !app.nilPow && !app.pow.ProcessProposal(txs) { + return false + } + + if !app.nilSpam && !app.spam.ProcessProposal(txs) { + return false + } + return true } -func (app *App) OnEndBlock(req tmtypes.RequestEndBlock) (ctx context.Context, resp tmtypes.ResponseEndBlock) { +func (app *App) OnEndBlock(blockHeight uint64) (tmtypes.ValidatorUpdates, types1.ConsensusParams) { app.log.Debug("entering end block", logging.Time("at", time.Now())) defer func() { app.log.Debug("leaving end block", logging.Time("at", time.Now())) }() @@ -768,91 +898,79 @@ func (app *App) OnEndBlock(req tmtypes.RequestEndBlock) (ctx context.Context, re ) app.epoch.OnBlockEnd(app.blockCtx) - if !app.nilPow { - app.pow.EndOfBlock() - } - - if !app.nilSpam { - app.spam.EndOfBlock(uint64(req.Height), app.time.GetTimeNow()) - } - app.stateVar.OnBlockEnd(app.blockCtx) powerUpdates := app.top.GetValidatorPowerUpdates() - resp = tmtypes.ResponseEndBlock{} - if len(powerUpdates) > 0 { - resp.ValidatorUpdates = powerUpdates + if len(powerUpdates) == 0 { + powerUpdates = tmtypes.ValidatorUpdates{} } // update max gas based on the network parameter - resp.ConsensusParamUpdates = &tmtypes.ConsensusParams{ - Block: &tmtypes.BlockParams{ + consensusParamUpdates := types1.ConsensusParams{ + Block: &types1.BlockParams{ MaxGas: int64(app.gastimator.OnBlockEnd()), - MaxBytes: tmtypesint.DefaultBlockParams().MaxBytes, + MaxBytes: -1, // we tell comet that we always want to get the full mempool }, Version: &tmtypes1.VersionParams{ - AppVersion: AppVersion, + App: AppVersion, }, } app.exec.BlockEnd(app.blockCtx) - return ctx, resp + return powerUpdates, consensusParamUpdates } // OnBeginBlock updates the internal lastBlockTime value with each new block. -func (app *App) OnBeginBlock( - req tmtypes.RequestBeginBlock, -) (ctx context.Context, resp tmtypes.ResponseBeginBlock) { - app.log.Debug("entering begin block", logging.Time("at", time.Now()), logging.Uint64("height", uint64(req.Header.Height))) +func (app *App) OnBeginBlock(blockHeight uint64, blockHash string, blockTime time.Time, proposer string, txs []abci.Tx) context.Context { + app.log.Debug("entering begin block", logging.Time("at", time.Now()), logging.Uint64("height", blockHeight), logging.Time("time", blockTime), logging.String("blockHash", blockHash)) defer func() { app.log.Debug("leaving begin block", logging.Time("at", time.Now())) }() - hash := hex.EncodeToString(req.Hash) - ctx = vgcontext.WithBlockHeight(vgcontext.WithTraceID(app.chainCtx, hash), req.Header.Height) - + ctx := vgcontext.WithBlockHeight(vgcontext.WithTraceID(app.chainCtx, blockHash), blockHeight) if app.protocolUpgradeService.CoreReadyForUpgrade() { app.startProtocolUpgrade(ctx) } - app.broker.Send( - events.NewBeginBlock(ctx, eventspb.BeginBlock{ - Height: uint64(req.Header.Height), - Timestamp: req.Header.Time.UnixNano(), - Hash: hash, - }), - ) + app.broker.Send(events.NewBeginBlock(ctx, eventspb.BeginBlock{ + Height: blockHeight, + Timestamp: blockTime.UnixNano(), + Hash: blockHash, + })) + app.cBlock = blockHash - app.cBlock = hash + for _, tx := range txs { + app.setTxStats(tx.GetLength()) + } // update pow engine on a new block if !app.nilPow { - app.pow.BeginBlock(uint64(req.Header.Height), hash) + app.pow.BeginBlock(blockHeight, blockHash, txs) } - app.stats.SetHash(hash) - app.stats.SetHeight(uint64(req.Header.Height)) - app.blockCtx = ctx - - now := req.Header.Time + if !app.nilSpam { + app.spam.BeginBlock(txs) + } + app.stats.SetHash(blockHash) + app.stats.SetHeight(blockHeight) + app.blockCtx = ctx + now := blockTime app.time.SetTimeNow(ctx, now) app.rates.NextBlock() app.currentTimestamp = app.time.GetTimeNow() app.previousTimestamp = app.time.GetTimeLastBatch() - app.log.Debug("ABCI service BEGIN completed", logging.Int64("current-timestamp", app.currentTimestamp.UnixNano()), logging.Int64("previous-timestamp", app.previousTimestamp.UnixNano()), logging.String("current-datetime", vegatime.Format(app.currentTimestamp)), logging.String("previous-datetime", vegatime.Format(app.previousTimestamp)), - logging.Int64("height", req.Header.GetHeight()), + logging.Uint64("height", blockHeight), ) - app.protocolUpgradeService.BeginBlock(ctx, uint64(req.Header.Height)) - app.top.BeginBlock(ctx, req) + app.protocolUpgradeService.BeginBlock(ctx, blockHeight) + app.top.BeginBlock(ctx, blockHeight, proposer) app.balanceChecker.BeginBlock(ctx) app.exec.BeginBlock(ctx) - - return ctx, resp + return ctx } func (app *App) startProtocolUpgrade(ctx context.Context) { @@ -908,14 +1026,8 @@ func (app *App) startProtocolUpgrade(ctx context.Context) { } } -func (app *App) OnCommit() (resp tmtypes.ResponseCommit) { - app.log.Debug("entering commit", logging.Time("at", time.Now())) - defer func() { app.log.Debug("leaving commit", logging.Time("at", time.Now())) }() - - if !app.nilPow { - app.pow.Commit() - } - +// Finalize calculates the app hash for the block ending. +func (app *App) Finalize() []byte { // call checkpoint _first_ so the snapshot contains the correct checkpoint state. cpt, _ := app.checkpoint.Checkpoint(app.blockCtx, app.currentTimestamp) @@ -943,21 +1055,21 @@ func (app *App) OnCommit() (resp tmtypes.ResponseCommit) { if len(snapHash) > 0 { app.log.Info("State has been snapshotted", logging.Float64("duration", t1.Sub(t0).Seconds())) } - resp.Data = snapHash + appHash := snapHash if len(snapHash) == 0 { - resp.Data = vgcrypto.Hash([]byte(app.version)) - resp.Data = append(resp.Data, app.exec.Hash()...) - resp.Data = append(resp.Data, app.delegation.Hash()...) - resp.Data = append(resp.Data, app.gov.Hash()...) - resp.Data = append(resp.Data, app.stakingAccounts.Hash()...) + appHash = vgcrypto.Hash([]byte(app.version)) + appHash = append(appHash, app.exec.Hash()...) + appHash = append(appHash, app.delegation.Hash()...) + appHash = append(appHash, app.gov.Hash()...) + appHash = append(appHash, app.stakingAccounts.Hash()...) } if cpt != nil { if len(snapHash) == 0 { // only append to commit hash if we aren't using the snapshot hash // otherwise restoring a checkpoint would restore an incomplete/wrong hash - resp.Data = append(resp.Data, cpt.Hash...) + appHash = append(appHash, cpt.Hash...) app.log.Debug("checkpoint hash", logging.String("response-data", hex.EncodeToString(cpt.Hash))) } _ = app.handleCheckpoint(cpt) @@ -969,25 +1081,32 @@ func (app *App) OnCommit() (resp tmtypes.ResponseCommit) { // so we just re-hash to have an output which is actually an // hash and is consistent over all calls to Commit if len(snapHash) <= 0 { - resp.Data = vgcrypto.Hash(resp.Data) + appHash = vgcrypto.Hash(appHash) } else { app.broker.Send(events.NewSnapshotEventEvent(app.blockCtx, app.stats.Height(), app.cBlock, app.protocolUpgradeService.TimeForUpgrade())) } // Update response and save the apphash incase we lose connection with tendermint and need to verify our // current state - app.lastBlockAppHash = resp.Data - app.log.Debug("apphash calculated", logging.String("response-data", hex.EncodeToString(resp.Data))) + app.log.Debug("apphash calculated", logging.String("response-data", hex.EncodeToString(appHash))) + if !app.nilPow { + app.pow.OnFinalize() + } + return appHash +} + +func (app *App) OnCommit() (*tmtypes.ResponseCommit, error) { + app.log.Debug("entering commit", logging.Time("at", time.Now()), logging.Uint64("height", app.stats.Height())) + defer func() { app.log.Debug("leaving commit", logging.Time("at", time.Now())) }() app.updateStats() app.setBatchStats() - app.broker.Send( events.NewEndBlock(app.blockCtx, eventspb.EndBlock{ Height: app.stats.Height(), }), ) - return resp + return &tmtypes.ResponseCommit{}, nil } func (app *App) handleCheckpoint(cpt *types.CheckpointState) error { @@ -1085,7 +1204,7 @@ func (app *App) OnCheckTxSpam(tx abci.Tx) tmtypes.ResponseCheckTx { } // additional spam checks if !app.nilSpam { - if _, err := app.spam.PreBlockAccept(tx); err != nil { + if err := app.spam.PreBlockAccept(tx); err != nil { app.log.Error(err.Error()) resp.Code = blockchain.AbciSpamError resp.Data = []byte(err.Error()) @@ -1096,7 +1215,7 @@ func (app *App) OnCheckTxSpam(tx abci.Tx) tmtypes.ResponseCheckTx { } // OnCheckTx performs soft validations. -func (app *App) OnCheckTx(ctx context.Context, _ tmtypes.RequestCheckTx, tx abci.Tx) (context.Context, tmtypes.ResponseCheckTx) { +func (app *App) OnCheckTx(ctx context.Context, _ *tmtypes.RequestCheckTx, tx abci.Tx) (context.Context, *tmtypes.ResponseCheckTx) { resp := tmtypes.ResponseCheckTx{} if app.log.IsDebug() { @@ -1106,7 +1225,7 @@ func (app *App) OnCheckTx(ctx context.Context, _ tmtypes.RequestCheckTx, tx abci if err := app.canSubmitTx(tx); err != nil { resp.Code = blockchain.AbciTxnValidationFailure resp.Data = []byte(err.Error()) - return ctx, resp + return ctx, &resp } // Check ratelimits @@ -1118,20 +1237,19 @@ func (app *App) OnCheckTx(ctx context.Context, _ tmtypes.RequestCheckTx, tx abci app.log.Error("error getting gas estimate", logging.Error(err)) resp.Code = blockchain.AbciTxnValidationFailure resp.Data = []byte(err.Error()) - return ctx, resp + return ctx, &resp } resp.GasWanted = int64(gasWanted) - resp.Priority = int64(app.gastimator.GetPriority(tx)) if app.log.IsDebug() { - app.log.Debug("transaction passed checkTx", logging.String("tid", tx.GetPoWTID()), logging.String("command", tx.Command().String()), logging.Int64("priority", resp.Priority), logging.Int64("gas-wanted", resp.GasWanted), logging.Int64("max-gas", int64(app.gastimator.GetMaxGas()))) + app.log.Debug("transaction passed checkTx", logging.String("tid", tx.GetPoWTID()), logging.String("command", tx.Command().String())) } if isval { - return ctx, resp + return ctx, &resp } - return ctx, resp + return ctx, &resp } // limitPubkey returns whether a request should be rate limited or not. @@ -1270,48 +1388,6 @@ func validateUseOfEthOracles(terms *types.ProposalTerms, netp NetworkParameters) return nil } -// OnDeliverTXSpam checks spam and replay. -func (app *App) OnDeliverTXSpam(ctx context.Context, tx abci.Tx) tmtypes.ResponseDeliverTx { - var resp tmtypes.ResponseDeliverTx - ctxWithHash := vgcontext.WithTxHash(ctx, hex.EncodeToString(tx.Hash())) - - // verify proof of work - if !app.nilPow { - if err := app.pow.DeliverTx(tx); err != nil { - app.log.Error(err.Error()) - resp.Code = blockchain.AbciSpamError - resp.Data = []byte(err.Error()) - app.broker.Send(events.NewTxErrEvent(ctxWithHash, err, tx.Party(), tx.GetCmd(), tx.Command().String())) - return resp - } - } - if !app.nilSpam { - if _, err := app.spam.PostBlockAccept(tx); err != nil { - app.log.Error(err.Error()) - resp.Code = blockchain.AbciSpamError - resp.Data = []byte(err.Error()) - evt := events.NewTxErrEvent(ctxWithHash, err, tx.Party(), tx.GetCmd(), tx.Command().String()) - app.broker.Send(evt) - return resp - } - } - return resp -} - -// OnDeliverTx increments the internal tx counter and decorates the context with tracing information. -func (app *App) OnDeliverTx(ctx context.Context, req tmtypes.RequestDeliverTx, tx abci.Tx) (context.Context, tmtypes.ResponseDeliverTx) { - app.setTxStats(len(req.Tx)) - var resp tmtypes.ResponseDeliverTx - if err := app.canSubmitTx(tx); err != nil { - resp.Code = blockchain.AbciTxnValidationFailure - resp.Data = []byte(err.Error()) - } - - // we don't need to set trace ID on context, it's been handled with OnBeginBlock - - return ctx, resp -} - func (app *App) CheckProtocolUpgradeProposal(ctx context.Context, tx abci.Tx) error { if err := app.RequireValidatorPubKey(ctx, tx); err != nil { return err @@ -1843,7 +1919,6 @@ func (app *App) DeliverChainEvent(ctx context.Context, tx abci.Tx, id string) er if err := tx.Unmarshal(ce); err != nil { return err } - return app.processChainEvent(ctx, ce, tx.PubKeyHex(), id) } @@ -2175,7 +2250,7 @@ func (app *App) DeliverKeyRotateSubmission(ctx context.Context, tx abci.Tx) erro return app.top.AddKeyRotate( ctx, tx.PubKeyHex(), - uint64(currentBlockHeight), + currentBlockHeight, kr, ) } @@ -2234,6 +2309,34 @@ func (app *App) DeliverEthereumKeyRotateSubmission(ctx context.Context, tx abci. ) } +func (app *App) wrapTx(tx abci.Tx, rawTx []byte, insertionOrder int) (*TxWrapper, error) { + priority := app.getPriority(tx) + gasWanted, err := app.getGasWanted(tx) + if err != nil { + return nil, err + } + + return &TxWrapper{ + tx: tx, + timeIndex: insertionOrder, + raw: rawTx, + priority: priority, + gasWanted: gasWanted, + }, nil +} + +func (app *App) getPriority(tx abci.Tx) uint64 { + return app.gastimator.GetPriority(tx) +} + +func (app *App) getGasWanted(tx abci.Tx) (uint64, error) { + return app.gastimator.CalcGasWantedForTx(tx) +} + +func (app *App) getMaxGas() uint64 { + return app.gastimator.maxGas +} + func (app *App) CreateReferralSet(ctx context.Context, tx abci.Tx, deterministicID string) error { params := &commandspb.CreateReferralSet{} if err := tx.Unmarshal(params); err != nil { diff --git a/core/processor/gastimator_test.go b/core/processor/gastimator_test.go index fd471bb2e9..5f676bda0a 100644 --- a/core/processor/gastimator_test.go +++ b/core/processor/gastimator_test.go @@ -299,6 +299,7 @@ type testTx struct { unmarshaller func(interface{}) error } +func (tx *testTx) GetLength() int { return 0 } func (tx *testTx) Unmarshal(i interface{}) error { return tx.unmarshaller(i) } func (tx *testTx) GetPoWTID() string { return "" } func (tx *testTx) GetVersion() uint32 { return 2 } diff --git a/core/processor/mocks/mocks.go b/core/processor/mocks/mocks.go index 0490d91fa3..ffc8e01096 100644 --- a/core/processor/mocks/mocks.go +++ b/core/processor/mocks/mocks.go @@ -18,8 +18,8 @@ import ( num "code.vegaprotocol.io/vega/libs/num" vega "code.vegaprotocol.io/vega/protos/vega" v1 "code.vegaprotocol.io/vega/protos/vega/commands/v1" + types0 "github.com/cometbft/cometbft/abci/types" gomock "github.com/golang/mock/gomock" - types0 "github.com/tendermint/tendermint/abci/types" ) // MockTimeService is a mock of TimeService interface. @@ -1209,15 +1209,15 @@ func (mr *MockValidatorTopologyMockRecorder) AllVegaPubKeys() *gomock.Call { } // BeginBlock mocks base method. -func (m *MockValidatorTopology) BeginBlock(arg0 context.Context, arg1 types0.RequestBeginBlock) { +func (m *MockValidatorTopology) BeginBlock(arg0 context.Context, arg1 uint64, arg2 string) { m.ctrl.T.Helper() - m.ctrl.Call(m, "BeginBlock", arg0, arg1) + m.ctrl.Call(m, "BeginBlock", arg0, arg1, arg2) } // BeginBlock indicates an expected call of BeginBlock. -func (mr *MockValidatorTopologyMockRecorder) BeginBlock(arg0, arg1 interface{}) *gomock.Call { +func (mr *MockValidatorTopologyMockRecorder) BeginBlock(arg0, arg1, arg2 interface{}) *gomock.Call { mr.mock.ctrl.T.Helper() - return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "BeginBlock", reflect.TypeOf((*MockValidatorTopology)(nil).BeginBlock), arg0, arg1) + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "BeginBlock", reflect.TypeOf((*MockValidatorTopology)(nil).BeginBlock), arg0, arg1, arg2) } // GetValidatorPowerUpdates mocks base method. diff --git a/core/processor/processor.go b/core/processor/processor.go index 338c549b36..fcb2629921 100644 --- a/core/processor/processor.go +++ b/core/processor/processor.go @@ -32,8 +32,8 @@ import ( "code.vegaprotocol.io/vega/libs/num" commandspb "code.vegaprotocol.io/vega/protos/vega/commands/v1" + abcitypes "github.com/cometbft/cometbft/abci/types" "github.com/pkg/errors" - abcitypes "github.com/tendermint/tendermint/abci/types" ) //go:generate go run github.com/golang/mock/mockgen -destination mocks/mocks.go -package mocks code.vegaprotocol.io/vega/core/processor TimeService,EpochService,DelegationEngine,ExecutionEngine,GovernanceEngine,Stats,Assets,ValidatorTopology,Notary,EvtForwarder,Witness,Banking,NetworkParameters,OraclesEngine,OracleAdaptors,Limits,StakeVerifier,StakingAccounts,ERC20MultiSigTopology,Checkpoint @@ -167,7 +167,7 @@ type ValidatorTopology interface { IsValidator() bool AddKeyRotate(ctx context.Context, nodeID string, currentBlockHeight uint64, kr *commandspb.KeyRotateSubmission) error ProcessEthereumKeyRotation(ctx context.Context, nodeID string, kr *commandspb.EthereumKeyRotateSubmission, verify func(message, signature []byte, hexAddress string) error) error - BeginBlock(ctx context.Context, req abcitypes.RequestBeginBlock) + BeginBlock(ctx context.Context, blockHeight uint64, proposer string) GetValidatorPowerUpdates() []abcitypes.ValidatorUpdate ProcessAnnounceNode(ctx context.Context, nr *commandspb.AnnounceNode) error ProcessValidatorHeartbeat(context.Context, *commandspb.ValidatorHeartbeat, func(message, signature, pubkey []byte) error, func(message, signature []byte, hexAddress string) error) error diff --git a/core/processor/tx.go b/core/processor/tx.go index 867a4b65f2..5fa162b43d 100644 --- a/core/processor/tx.go +++ b/core/processor/tx.go @@ -25,7 +25,7 @@ import ( "code.vegaprotocol.io/vega/libs/proto" commandspb "code.vegaprotocol.io/vega/protos/vega/commands/v1" - "github.com/tendermint/tendermint/crypto/tmhash" + "github.com/cometbft/cometbft/crypto/tmhash" ) type Tx struct { @@ -143,6 +143,10 @@ func (t Tx) Command() txn.Command { } } +func (t Tx) GetLength() int { + return len(t.originalTx) +} + func (t Tx) GetNonce() uint64 { return t.inputData.Nonce } diff --git a/core/protocol/all_services.go b/core/protocol/all_services.go index 6b8067571f..36f73b1626 100644 --- a/core/protocol/all_services.go +++ b/core/protocol/all_services.go @@ -378,11 +378,10 @@ func newServices( svcs.snapshotEngine.AddProviders(svcs.checkpoint, svcs.collateral, svcs.governance, svcs.delegation, svcs.netParams, svcs.epochService, svcs.assets, svcs.banking, svcs.witness, svcs.notary, svcs.stakingAccounts, svcs.stakeVerifier, svcs.limits, svcs.topology, svcs.eventForwarder, svcs.executionEngine, svcs.marketActivityTracker, svcs.statevar, svcs.erc20MultiSigTopology, svcs.protocolUpgradeEngine, svcs.ethereumOraclesVerifier, svcs.vesting, svcs.activityStreak, svcs.referralProgram, svcs.volumeDiscount, - svcs.teamsEngine) + svcs.teamsEngine, svcs.spam) - svcs.snapshotEngine.AddProviders(svcs.spam) + pow := pow.New(svcs.log, svcs.conf.PoW) - pow := pow.New(svcs.log, svcs.conf.PoW, svcs.timeService) if svcs.conf.Blockchain.ChainProvider == blockchain.ProviderNullChain { pow.DisableVerification() } @@ -409,10 +408,6 @@ func newServices( Param: netparams.SpamPoWNumberOfTxPerBlock, Watcher: pow.UpdateSpamPoWNumberOfTxPerBlock, }, - { - Param: netparams.ValidatorsEpochLength, - Watcher: pow.OnEpochDurationChanged, - }, } // The team engine is used to know the team a party belongs to. The computation @@ -497,10 +492,6 @@ func (svcs *allServices) setupNetParameters(powWatchers []netparams.WatchParam) spamWatchers := []netparams.WatchParam{} if svcs.spam != nil { spamWatchers = []netparams.WatchParam{ - { - Param: netparams.ValidatorsEpochLength, - Watcher: svcs.spam.OnEpochDurationChanged, - }, { Param: netparams.SpamProtectionMaxVotes, Watcher: svcs.spam.OnMaxVotesChanged, diff --git a/core/snapshot/databases/metadata/in_memory.go b/core/snapshot/databases/metadata/in_memory.go index 2ef7b0a92c..10f0a9078c 100644 --- a/core/snapshot/databases/metadata/in_memory.go +++ b/core/snapshot/databases/metadata/in_memory.go @@ -18,7 +18,7 @@ package metadata import ( "sort" - tmtypes "github.com/tendermint/tendermint/abci/types" + tmtypes "github.com/cometbft/cometbft/abci/types" ) type InMemoryDatabase struct { diff --git a/core/snapshot/databases/metadata/in_memory_test.go b/core/snapshot/databases/metadata/in_memory_test.go index 9cb46a3421..c6f44a909c 100644 --- a/core/snapshot/databases/metadata/in_memory_test.go +++ b/core/snapshot/databases/metadata/in_memory_test.go @@ -20,9 +20,9 @@ import ( "code.vegaprotocol.io/vega/core/snapshot/databases/metadata" + tmtypes "github.com/cometbft/cometbft/abci/types" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" - tmtypes "github.com/tendermint/tendermint/abci/types" ) func TestInMemoryDatabase(t *testing.T) { diff --git a/core/snapshot/databases/metadata/level_db.go b/core/snapshot/databases/metadata/level_db.go index f555edf552..8b66a58133 100644 --- a/core/snapshot/databases/metadata/level_db.go +++ b/core/snapshot/databases/metadata/level_db.go @@ -24,8 +24,8 @@ import ( "code.vegaprotocol.io/vega/paths" cometbftdb "github.com/cometbft/cometbft-db" + tmtypes "github.com/cometbft/cometbft/abci/types" "github.com/syndtr/goleveldb/leveldb/opt" - tmtypes "github.com/tendermint/tendermint/abci/types" ) const metaDBName = "snapshot_meta" diff --git a/core/snapshot/databases/metadata/level_db_test.go b/core/snapshot/databases/metadata/level_db_test.go index a8135f9494..39149eb413 100644 --- a/core/snapshot/databases/metadata/level_db_test.go +++ b/core/snapshot/databases/metadata/level_db_test.go @@ -21,9 +21,9 @@ import ( "code.vegaprotocol.io/vega/core/snapshot/databases/metadata" "code.vegaprotocol.io/vega/paths" + tmtypes "github.com/cometbft/cometbft/abci/types" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" - tmtypes "github.com/tendermint/tendermint/abci/types" ) func TestLevelDBDatabase(t *testing.T) { diff --git a/core/snapshot/engine.go b/core/snapshot/engine.go index 6de18d1126..3266ffee97 100644 --- a/core/snapshot/engine.go +++ b/core/snapshot/engine.go @@ -36,7 +36,7 @@ import ( "code.vegaprotocol.io/vega/paths" "code.vegaprotocol.io/vega/version" - tmtypes "github.com/tendermint/tendermint/abci/types" + tmtypes "github.com/cometbft/cometbft/abci/types" "go.uber.org/zap" "golang.org/x/exp/slices" ) @@ -550,7 +550,7 @@ func (e *Engine) snapshotNow(ctx context.Context, saveAsync bool) ([]byte, DoneC snapMetricsRecord := newSnapMetricsState() defer func() { blockHeight, _ := vgcontext.BlockHeightFromContext(ctx) - snapMetricsRecord.Report(uint64(blockHeight)) + snapMetricsRecord.Report(blockHeight) }() // Start the gathering of providers state asynchronously. @@ -661,7 +661,7 @@ func (e *Engine) snapshotNow(ctx context.Context, saveAsync bool) ([]byte, DoneC e.snapshotTreeLock.Unlock() return nil, nil, err } - e.appState.Height = uint64(height) + e.appState.Height = height _, block := vegactx.TraceIDFromContext(ctx) e.appState.Block = block @@ -722,7 +722,7 @@ func (e *Engine) snapshotNow(ctx context.Context, saveAsync bool) ([]byte, DoneC } e.log.Info("Snapshot taken", - logging.Int64("height", height), + logging.Uint64("height", height), logging.ByteString("hash", hash), logging.String("protocol-version", e.appState.ProtocolVersion), logging.Bool("protocol-upgrade", e.appState.ProtocolUpdgade), @@ -815,7 +815,7 @@ func (e *Engine) restoreStateFromSnapshot(ctx context.Context, payloads []*types e.appState = payloadsPerNamespace[types.AppSnapshot][0].GetAppState().AppState // These values are needed in the context by providers, to send events. - ctx = vegactx.WithTraceID(vegactx.WithBlockHeight(ctx, int64(e.appState.Height)), e.appState.Block) + ctx = vegactx.WithTraceID(vegactx.WithBlockHeight(ctx, e.appState.Height), e.appState.Block) ctx = vegactx.WithChainID(ctx, e.appState.ChainID) ctx = vegactx.WithSnapshotInfo(ctx, e.appState.ProtocolVersion, e.appState.ProtocolUpdgade) diff --git a/core/snapshot/engine_test.go b/core/snapshot/engine_test.go index 9c1de64a2f..9ec77d910b 100644 --- a/core/snapshot/engine_test.go +++ b/core/snapshot/engine_test.go @@ -34,10 +34,10 @@ import ( "code.vegaprotocol.io/vega/paths" "code.vegaprotocol.io/vega/version" + tmtypes "github.com/cometbft/cometbft/abci/types" "github.com/golang/mock/gomock" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" - tmtypes "github.com/tendermint/tendermint/abci/types" ) func TestEngine(t *testing.T) { @@ -288,7 +288,7 @@ func TestTakingSnapshotSucceeds(t *testing.T) { vegaPaths := paths.New(t.TempDir()) log := logging.NewTestLogger() ctx := vegactx.WithChainID(vegactx.WithTraceID(vegactx.WithBlockHeight(context.Background(), - int64(testSnapshot.appState.Height)), testSnapshot.appState.Block), testSnapshot.appState.ChainID, + testSnapshot.appState.Height), testSnapshot.appState.Block), testSnapshot.appState.ChainID, ) // Some providers matching the snapshot payloads. diff --git a/core/snapshot/tree/databases.go b/core/snapshot/tree/databases.go index 2385c8f110..8e6898b1a6 100644 --- a/core/snapshot/tree/databases.go +++ b/core/snapshot/tree/databases.go @@ -17,7 +17,7 @@ package tree import ( cometbftdb "github.com/cometbft/cometbft-db" - tmtypes "github.com/tendermint/tendermint/abci/types" + tmtypes "github.com/cometbft/cometbft/abci/types" ) type MetadataDatabase interface { diff --git a/core/snapshot/tree/tree.go b/core/snapshot/tree/tree.go index f3fa60f02e..697dba06ac 100644 --- a/core/snapshot/tree/tree.go +++ b/core/snapshot/tree/tree.go @@ -26,8 +26,8 @@ import ( "code.vegaprotocol.io/vega/logging" snapshotpb "code.vegaprotocol.io/vega/protos/vega/snapshot/v1" + tmtypes "github.com/cometbft/cometbft/abci/types" "github.com/cosmos/iavl" - tmtypes "github.com/tendermint/tendermint/abci/types" ) // Tree is a high-level structure that abstract the management of the AVL away diff --git a/core/spam/engine.go b/core/spam/engine.go index 0a6ab13425..d53b668ef8 100644 --- a/core/spam/engine.go +++ b/core/spam/engine.go @@ -18,9 +18,7 @@ package spam import ( "context" "encoding/hex" - "strconv" "sync" - "time" "code.vegaprotocol.io/vega/core/blockchain/abci" "code.vegaprotocol.io/vega/core/netparams" @@ -31,18 +29,6 @@ import ( protoapi "code.vegaprotocol.io/vega/protos/vega/api/v1" ) -var ( - increaseFactor = num.NewUint(2) - banDurationAsEpochFraction = num.DecimalOne().Div(num.DecimalFromInt64(48)) // 1/48 of an epoch will be the default 30 minutes ban - banFactor = num.DecimalFromFloat(0.5) - rejectRatioForIncrease = num.DecimalFromFloat(0.3) -) - -const ( - numberOfBlocksForIncreaseCheck uint64 = 10 - minBanDuration = time.Second * 30 // minimum ban duration -) - type StakingAccounts interface { GetAvailableBalance(party string) (*num.Uint, error) } @@ -61,16 +47,15 @@ type Engine struct { currentEpoch *types.Epoch policyNameToPolicy map[string]Policy hashKeys []string - banDuration time.Duration - - noSpamProtection bool // flag that disables chesk for the spam policies, that is useful for the nullchain + noSpamProtection bool // flag that disables chesk for the spam policies, that is useful for the nullchain } type Policy interface { Reset(epoch types.Epoch) - EndOfBlock(blockHeight uint64, now time.Time, banDuration time.Duration) - PreBlockAccept(tx abci.Tx) (bool, error) - PostBlockAccept(tx abci.Tx) (bool, error) + UpdateTx(tx abci.Tx) + RollbackProposal() + CheckBlockTx(abci.Tx) error + PreBlockAccept(tx abci.Tx) error UpdateUintParam(name string, value *num.Uint) error UpdateIntParam(name string, value int64) error Serialise() ([]byte, error) @@ -127,10 +112,10 @@ func New(log *logging.Logger, config Config, epochEngine EpochEngine, accounting delegationPolicy.policyName: delegationPolicy, transferPolicy.policyName: transferPolicy, issuesSignaturesPolicy.policyName: issuesSignaturesPolicy, + voteKey: votePolicy, createReferralSetPolicy.policyName: createReferralSetPolicy, updateReferralSetPolicy.policyName: updateReferralSetPolicy, applyReferralCodePolicy.policyName: applyReferralCodePolicy, - voteKey: votePolicy, } e.hashKeys = []string{ proposalPolicy.policyName, @@ -168,18 +153,6 @@ func (e *Engine) DisableSpamProtection() { e.noSpamProtection = true } -// OnEpochDurationChanged updates the ban duration as a fraction of the epoch duration. -func (e *Engine) OnEpochDurationChanged(_ context.Context, duration time.Duration) error { - epochImpliedDurationNano, _ := num.UintFromDecimal(num.DecimalFromInt64(duration.Nanoseconds()).Mul(banDurationAsEpochFraction)) - epochImpliedDurationDuration := time.Duration(epochImpliedDurationNano.Uint64()) - if epochImpliedDurationDuration < minBanDuration { - e.banDuration = minBanDuration - } else { - e.banDuration = epochImpliedDurationDuration - } - return nil -} - // OnCreateReferralSet is called when the net param for max create referral set per epoch has changed. func (e *Engine) OnMaxCreateReferralSet(ctx context.Context, max int64) error { return e.transactionTypeToPolicy[txn.CreateReferralSetCommand].UpdateIntParam(netparams.SpamProtectionMaxCreateReferralSet, max) @@ -275,66 +248,76 @@ func (e *Engine) OnEpochEvent(ctx context.Context, epoch types.Epoch) { } } -// EndOfBlock is called when the block is finished. -func (e *Engine) EndOfBlock(blockHeight uint64, now time.Time) { - if e.log.GetLevel() <= logging.DebugLevel { - e.log.Debug("Spam protection EndOfBlock called", logging.Uint64("blockHeight", blockHeight)) - } - - if e.noSpamProtection { - e.log.Info("Spam protection EndOfBlock disabled", logging.Uint64("blockHeight", blockHeight)) - return +func (e *Engine) BeginBlock(txs []abci.Tx) { + for _, tx := range txs { + if _, ok := e.transactionTypeToPolicy[tx.Command()]; !ok { + continue + } + e.transactionTypeToPolicy[tx.Command()].UpdateTx(tx) } +} +func (e *Engine) EndPrepareProposal() { for _, policy := range e.transactionTypeToPolicy { - policy.EndOfBlock(blockHeight, now, e.banDuration) + policy.RollbackProposal() } } // PreBlockAccept is called from onCheckTx before a tx is added to mempool // returns false is rejected by spam engine with a corresponding error. -func (e *Engine) PreBlockAccept(tx abci.Tx) (bool, error) { +func (e *Engine) PreBlockAccept(tx abci.Tx) error { command := tx.Command() if _, ok := e.transactionTypeToPolicy[command]; !ok { - return true, nil + return nil } if e.log.GetLevel() <= logging.DebugLevel { e.log.Debug("Spam protection PreBlockAccept called for policy", logging.String("txHash", hex.EncodeToString(tx.Hash())), logging.String("command", command.String())) } - if e.noSpamProtection { e.log.Debug("Spam protection PreBlockAccept disabled for policy", logging.String("txHash", hex.EncodeToString(tx.Hash())), logging.String("command", command.String())) - return true, nil + return nil } - return e.transactionTypeToPolicy[command].PreBlockAccept(tx) } +func (e *Engine) ProcessProposal(txs []abci.Tx) bool { + success := true + for _, tx := range txs { + command := tx.Command() + if _, ok := e.transactionTypeToPolicy[command]; !ok { + continue + } + if e.noSpamProtection { + e.log.Debug("Spam protection PreBlockAccept disabled for policy", logging.String("txHash", hex.EncodeToString(tx.Hash())), logging.String("command", command.String())) + continue + } + + if err := e.transactionTypeToPolicy[command].CheckBlockTx(tx); err != nil { + success = false + } + } + for _, p := range e.transactionTypeToPolicy { + p.RollbackProposal() + } + return success +} + // PostBlockAccept is called from onDeliverTx before the block is processed // returns false is rejected by spam engine with a corresponding error. -func (e *Engine) PostBlockAccept(tx abci.Tx) (bool, error) { +func (e *Engine) CheckBlockTx(tx abci.Tx) error { command := tx.Command() if _, ok := e.transactionTypeToPolicy[command]; !ok { - return true, nil + return nil } if e.log.GetLevel() <= logging.DebugLevel { e.log.Debug("Spam protection PostBlockAccept called for policy", logging.String("txHash", hex.EncodeToString(tx.Hash())), logging.String("command", command.String())) } if e.noSpamProtection { - e.log.Debug("Spam protection PostBlockAccept disabled for policy", logging.String("txHash", hex.EncodeToString(tx.Hash())), logging.String("command", command.String())) - return true, nil - } - - return e.transactionTypeToPolicy[command].PostBlockAccept(tx) -} - -func parseBannedUntil(until int64) *string { - if until == 0 { + e.log.Debug("Spam protection PreBlockAccept disabled for policy", logging.String("txHash", hex.EncodeToString(tx.Hash())), logging.String("command", command.String())) return nil } - t := strconv.FormatInt(until, 10) - return &t + return e.transactionTypeToPolicy[command].CheckBlockTx(tx) } func (e *Engine) GetSpamStatistics(partyID string) *protoapi.SpamStatistics { diff --git a/core/spam/engine_test.go b/core/spam/engine_test.go index 18a6d3bef8..9d7b630e0c 100644 --- a/core/spam/engine_test.go +++ b/core/spam/engine_test.go @@ -1,17 +1,14 @@ -// Copyright (C) 2023 Gobalsky Labs Limited +// Copyright (c) 2022 Gobalsky Labs Limited // -// This program is free software: you can redistribute it and/or modify -// it under the terms of the GNU Affero General Public License as -// published by the Free Software Foundation, either version 3 of the -// License, or (at your option) any later version. +// Use of this software is governed by the Business Source License included +// in the LICENSE.VEGA file and at https://www.mariadb.com/bsl11. // -// This program is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU Affero General Public License for more details. +// Change Date: 18 months from the later of the date of the first publicly +// available Distribution of this version of the repository, and 25 June 2022. // -// You should have received a copy of the GNU Affero General Public License -// along with this program. If not, see <http://www.gnu.org/licenses/>. +// On the date above, in accordance with the Business Source License, use +// of this software will be governed by version 3 or later of the GNU General +// Public License. package spam_test @@ -20,8 +17,8 @@ import ( "context" "errors" "testing" - "time" + "code.vegaprotocol.io/vega/core/blockchain/abci" "code.vegaprotocol.io/vega/core/spam" "code.vegaprotocol.io/vega/core/txn" "code.vegaprotocol.io/vega/core/types" @@ -78,7 +75,7 @@ func (t *testTx) GetCmd() interface{} { func TestEngine(t *testing.T) { t.Run("pre block goes is handled by the appropriate spam policy", testPreBlockAccept) t.Run("post block goes is handled by the appropriate spam policy", testPostBlockAccept) - t.Run("end of block is applied to all policies", testEndOfBlock) + t.Run("end prepare and end process is applied to all policies", testEndOfBlock) t.Run("reset is applied to all policies", testEngineReset) } @@ -92,24 +89,21 @@ func testEngineReset(t *testing.T) { // pre accept for i := 0; i < 3; i++ { - accept, _ := engine.PreBlockAccept(tx1) - require.Equal(t, true, accept) - - accept, _ = engine.PreBlockAccept(tx2) - require.Equal(t, true, accept) + require.NoError(t, engine.PreBlockAccept(tx1)) + require.NoError(t, engine.PreBlockAccept(tx2)) } // post accept for i := 0; i < 3; i++ { - accept, _ := engine.PostBlockAccept(tx1) - require.Equal(t, true, accept) - accept, _ = engine.PostBlockAccept(tx2) - require.Equal(t, true, accept) + err := engine.CheckBlockTx(tx1) + require.NoError(t, err) + err = engine.CheckBlockTx(tx2) + require.NoError(t, err) } - // move to next block, we've voted/proposed everything already so shouldn't be allowed to make more - tm := time.Now() - engine.EndOfBlock(1, tm) + engine.EndPrepareProposal() + engine.ProcessProposal([]abci.Tx{tx1, tx1, tx1, tx2, tx2, tx2}) + engine.BeginBlock([]abci.Tx{tx1, tx1, tx1, tx2, tx2, tx2}) proposalState, _, err := engine.GetState("proposal") require.Nil(t, err) @@ -143,13 +137,8 @@ func testEngineReset(t *testing.T) { require.Nil(t, err) require.True(t, bytes.Equal(voteState, voteState2)) - accept, err := snapEngine.engine.PreBlockAccept(tx1) - require.Equal(t, false, accept) - require.Equal(t, errors.New("party has already submitted the maximum number of proposal requests per epoch"), err) - - accept, err = snapEngine.engine.PreBlockAccept(tx2) - require.Equal(t, false, accept) - require.Equal(t, spam.ErrTooManyVotes, err) + require.Error(t, errors.New("party has already submitted the maximum number of proposal requests per epoch"), snapEngine.engine.PreBlockAccept(tx1)) + require.Equal(t, spam.ErrTooManyVotes, snapEngine.engine.PreBlockAccept(tx2)) // Notify an epoch event for the *same* epoch and a reset should not happen snapEngine.engine.OnEpochEvent(context.Background(), types.Epoch{Seq: 0}) @@ -162,11 +151,8 @@ func testEngineReset(t *testing.T) { // expect to be able to submit 3 more votes/proposals successfully for i := 0; i < 3; i++ { - accept, _ := snapEngine.engine.PreBlockAccept(tx1) - require.Equal(t, true, accept) - - accept, _ = snapEngine.engine.PreBlockAccept(tx2) - require.Equal(t, true, accept) + require.NoError(t, snapEngine.engine.PreBlockAccept(tx1)) + require.NoError(t, snapEngine.engine.PreBlockAccept(tx2)) } proposalState3, _, err := snapEngine.engine.GetState("proposal") @@ -184,20 +170,16 @@ func testPreBlockAccept(t *testing.T) { engine.OnEpochEvent(context.Background(), types.Epoch{Seq: 0}) tx1 := &testTx{party: "party1", proposal: "proposal1", command: txn.ProposeCommand} - accept, _ := engine.PreBlockAccept(tx1) - require.Equal(t, true, accept) + require.NoError(t, engine.PreBlockAccept(tx1)) tx2 := &testTx{party: "party1", proposal: "proposal1", command: txn.VoteCommand} - accept, _ = engine.PreBlockAccept(tx2) - require.Equal(t, true, accept) + require.NoError(t, engine.PreBlockAccept(tx2)) tx1 = &testTx{party: "party2", proposal: "proposal1", command: txn.ProposeCommand} - _, err := engine.PreBlockAccept(tx1) - require.Equal(t, errors.New("party has insufficient associated governance tokens in their staking account to submit proposal request"), err) + require.Equal(t, errors.New("party has insufficient associated governance tokens in their staking account to submit proposal request"), engine.PreBlockAccept(tx1)) tx2 = &testTx{party: "party2", proposal: "proposal1", command: txn.VoteCommand} - _, err = engine.PreBlockAccept(tx2) - require.Equal(t, spam.ErrInsufficientTokensForVoting, err) + require.Equal(t, spam.ErrInsufficientTokensForVoting, engine.PreBlockAccept(tx2)) } func testPostBlockAccept(t *testing.T) { @@ -206,23 +188,24 @@ func testPostBlockAccept(t *testing.T) { engine.OnEpochEvent(context.Background(), types.Epoch{Seq: 0}) + tx1 := &testTx{party: "party1", proposal: "proposal1", command: txn.ProposeCommand} + tx2 := &testTx{party: "party1", proposal: "proposal1", command: txn.VoteCommand} for i := 0; i < 3; i++ { - tx1 := &testTx{party: "party1", proposal: "proposal1", command: txn.ProposeCommand} - accept, _ := engine.PostBlockAccept(tx1) - require.Equal(t, true, accept) + err := engine.CheckBlockTx(tx1) + require.NoError(t, err) - tx2 := &testTx{party: "party1", proposal: "proposal1", command: txn.VoteCommand} - accept, _ = engine.PostBlockAccept(tx2) - require.Equal(t, true, accept) + err = engine.CheckBlockTx(tx2) + require.NoError(t, err) } + engine.EndPrepareProposal() + engine.ProcessProposal([]abci.Tx{tx1, tx1, tx1, tx2, tx2, tx2}) + engine.BeginBlock([]abci.Tx{tx1, tx1, tx1, tx2, tx2, tx2}) - tx1 := &testTx{party: "party1", proposal: "proposal1", command: txn.ProposeCommand} - _, err := engine.PostBlockAccept(tx1) - require.Equal(t, errors.New("party has already submitted the maximum number of proposal requests per epoch"), err) + tx1 = &testTx{party: "party1", proposal: "proposal1", command: txn.ProposeCommand} + require.Error(t, errors.New("party has already submitted the maximum number of proposal requests per epoch"), engine.CheckBlockTx(tx1)) - tx2 := &testTx{party: "party1", proposal: "proposal1", command: txn.VoteCommand} - _, err = engine.PostBlockAccept(tx2) - require.Equal(t, spam.ErrTooManyVotes, err) + tx2 = &testTx{party: "party1", proposal: "proposal1", command: txn.VoteCommand} + require.Error(t, spam.ErrTooManyVotes, engine.CheckBlockTx(tx2)) } func testEndOfBlock(t *testing.T) { @@ -231,23 +214,29 @@ func testEndOfBlock(t *testing.T) { engine.OnEpochEvent(context.Background(), types.Epoch{Seq: 0}) + tx1 := &testTx{party: "party1", proposal: "proposal1", command: txn.ProposeCommand} + tx2 := &testTx{party: "party1", proposal: "proposal1", command: txn.VoteCommand} + + for i := 0; i < 3; i++ { + require.NoError(t, engine.CheckBlockTx(tx1)) + require.NoError(t, engine.CheckBlockTx(tx2)) + } + engine.EndPrepareProposal() + engine.ProcessProposal([]abci.Tx{tx1, tx1, tx1, tx2, tx2, tx2}) + engine.BeginBlock([]abci.Tx{tx1, tx1, tx1, tx2, tx2, tx2}) + for i := 0; i < 3; i++ { tx1 := &testTx{party: "party1", proposal: "proposal1", command: txn.ProposeCommand} - accept, _ := engine.PostBlockAccept(tx1) - require.Equal(t, true, accept) + require.Error(t, engine.CheckBlockTx(tx1)) tx2 := &testTx{party: "party1", proposal: "proposal1", command: txn.VoteCommand} - accept, _ = engine.PostBlockAccept(tx2) - require.Equal(t, true, accept) + require.Error(t, engine.CheckBlockTx(tx2)) } - engine.EndOfBlock(1, time.Now()) - tx1 := &testTx{party: "party1", proposal: "proposal1", command: txn.ProposeCommand} - _, err := engine.PreBlockAccept(tx1) - require.Equal(t, errors.New("party has already submitted the maximum number of proposal requests per epoch"), err) + // proposal is rejected + engine.EndPrepareProposal() - tx2 := &testTx{party: "party1", proposal: "proposal1", command: txn.VoteCommand} - _, err = engine.PreBlockAccept(tx2) - require.Equal(t, spam.ErrTooManyVotes, err) + require.Error(t, errors.New("party has already submitted the maximum number of proposal requests per epoch"), engine.PreBlockAccept(tx1)) + require.Equal(t, spam.ErrTooManyVotes, engine.PreBlockAccept(tx2)) } type testEngine struct { diff --git a/core/spam/simple_spam_policy.go b/core/spam/simple_spam_policy.go index 93b5e69a68..ab7ac84fc9 100644 --- a/core/spam/simple_spam_policy.go +++ b/core/spam/simple_spam_policy.go @@ -20,7 +20,6 @@ import ( "errors" "sort" "sync" - "time" "code.vegaprotocol.io/vega/core/blockchain/abci" "code.vegaprotocol.io/vega/core/types" @@ -42,13 +41,10 @@ type SimpleSpamPolicy struct { minTokensParamName string maxAllowedParamName string - partyToCount map[string]uint64 // commands that are already on blockchain - blockPartyToCount map[string]uint64 // commands in the current block - bannedParties map[string]int64 // parties banned -> ban end time - partyBlockRejects map[string]*blockRejectInfo // total vs rejection in the current block - currentEpochSeq uint64 // current epoch sequence - lock sync.RWMutex // global lock to sync calls from multiple tendermint threads - banErr func(until time.Time) error + partyToCount map[string]uint64 // commands that are already on blockchain + blockPartyToCount map[string]uint64 // commands in the current block + currentEpochSeq uint64 // current epoch sequence + lock sync.RWMutex // global lock to sync calls from multiple tendermint threads insufficientTokensErr error tooManyCommands error } @@ -56,21 +52,16 @@ type SimpleSpamPolicy struct { // NewSimpleSpamPolicy instantiates the simple spam policy. func NewSimpleSpamPolicy(policyName string, minTokensParamName string, maxAllowedParamName string, log *logging.Logger, accounts StakingAccounts) *SimpleSpamPolicy { return &SimpleSpamPolicy{ - log: log, - accounts: accounts, - policyName: policyName, - partyToCount: map[string]uint64{}, - blockPartyToCount: map[string]uint64{}, - bannedParties: map[string]int64{}, - partyBlockRejects: map[string]*blockRejectInfo{}, - lock: sync.RWMutex{}, - minTokensParamName: minTokensParamName, - maxAllowedParamName: maxAllowedParamName, - minTokensRequired: num.UintZero(), - maxAllowedCommands: 1, // default is allow one per epoch - banErr: func(until time.Time) error { - return errors.New("party is banned from submitting " + policyName + " until the earlier between " + until.String() + " and the beginning of the next epoch") - }, + log: log, + accounts: accounts, + policyName: policyName, + partyToCount: map[string]uint64{}, + blockPartyToCount: map[string]uint64{}, + lock: sync.RWMutex{}, + minTokensParamName: minTokensParamName, + maxAllowedParamName: maxAllowedParamName, + minTokensRequired: num.UintZero(), + maxAllowedCommands: 1, // default is allow one per epoch insufficientTokensErr: errors.New("party has insufficient associated governance tokens in their staking account to submit " + policyName + " request"), tooManyCommands: errors.New("party has already submitted the maximum number of " + policyName + " requests per epoch"), } @@ -87,22 +78,11 @@ func (ssp *SimpleSpamPolicy) Serialise() ([]byte, error) { sort.SliceStable(partyToCount, func(i, j int) bool { return partyToCount[i].Party < partyToCount[j].Party }) - bannedParties := make([]*types.BannedParty, 0, len(ssp.bannedParties)) - for party, until := range ssp.bannedParties { - bannedParties = append(bannedParties, &types.BannedParty{ - Party: party, - Until: until, - }) - } - - sort.SliceStable(bannedParties, func(i, j int) bool { return bannedParties[i].Party < bannedParties[j].Party }) - payload := types.Payload{ Data: &types.PayloadSimpleSpamPolicy{ SimpleSpamPolicy: &types.SimpleSpamPolicy{ PolicyName: ssp.policyName, PartyToCount: partyToCount, - BannedParty: bannedParties, CurrentEpochSeq: ssp.currentEpochSeq, }, }, @@ -118,11 +98,6 @@ func (ssp *SimpleSpamPolicy) Deserialise(p *types.Payload) error { for _, ptc := range pl.PartyToCount { ssp.partyToCount[ptc.Party] = ptc.Count } - ssp.bannedParties = make(map[string]int64, len(pl.BannedParty)) - for _, bp := range pl.BannedParty { - ssp.bannedParties[bp.Party] = bp.Until - } - ssp.currentEpochSeq = pl.CurrentEpochSeq return nil @@ -158,49 +133,20 @@ func (ssp *SimpleSpamPolicy) Reset(epoch types.Epoch) { // reset counts ssp.partyToCount = map[string]uint64{} - - // clear banned on new epoch - ssp.bannedParties = map[string]int64{} - ssp.blockPartyToCount = map[string]uint64{} - ssp.partyBlockRejects = map[string]*blockRejectInfo{} } -// EndOfBlock is called at the end of the processing of the block to carry over state and trigger bans if necessary. -func (ssp *SimpleSpamPolicy) EndOfBlock(blockHeight uint64, now time.Time, banDuration time.Duration) { +func (ssp *SimpleSpamPolicy) UpdateTx(tx abci.Tx) { ssp.lock.Lock() defer ssp.lock.Unlock() - // add the block's counters to the epoch's - for party, count := range ssp.blockPartyToCount { - if _, ok := ssp.partyToCount[party]; !ok { - ssp.partyToCount[party] = 0 - } - ssp.partyToCount[party] += count - } - - ssp.blockPartyToCount = map[string]uint64{} - - // release bans - nowNano := now.UnixNano() - for k, v := range ssp.bannedParties { - if nowNano >= v { - delete(ssp.bannedParties, k) - } - } - - endBanTime := now.Add(banDuration).UnixNano() - - // ban parties with more than <banFactor> rejection rate in the block - for p, bStats := range ssp.partyBlockRejects { - if num.DecimalFromInt64(int64(bStats.rejected)).Div(num.DecimalFromInt64(int64(bStats.total))).GreaterThanOrEqual(banFactor) { - ssp.bannedParties[p] = endBanTime - } + if _, ok := ssp.partyToCount[tx.Party()]; !ok { + ssp.partyToCount[tx.Party()] = 0 } - ssp.partyBlockRejects = map[string]*blockRejectInfo{} + ssp.partyToCount[tx.Party()]++ } -// PostBlockAccept is called to verify a transaction from the block before passed to the application layer. -func (ssp *SimpleSpamPolicy) PostBlockAccept(tx abci.Tx) (bool, error) { +// CheckBlockTx is called to verify a transaction from the block before passed to the application layer. +func (ssp *SimpleSpamPolicy) CheckBlockTx(tx abci.Tx) error { party := tx.Party() ssp.lock.Lock() @@ -218,18 +164,9 @@ func (ssp *SimpleSpamPolicy) PostBlockAccept(tx abci.Tx) (bool, error) { blockCommands += count } - // if too many votes in total - reject and update counters + // if too many votes in total - reject if epochCommands+blockCommands >= ssp.maxAllowedCommands { - // update vote stats for the epoch - if partyRejectStats, ok := ssp.partyBlockRejects[party]; ok { - partyRejectStats.add(true) - } else { - ssp.partyBlockRejects[party] = &blockRejectInfo{total: 1, rejected: 1} - } - if ssp.log.GetLevel() <= logging.DebugLevel { - ssp.log.Debug("Spam post: party has already submitted the max amount of commands for "+ssp.policyName, logging.String("txHash", hex.EncodeToString(tx.Hash())), logging.String("party", party)) - } - return false, ssp.tooManyCommands + return ssp.tooManyCommands } // update block counters @@ -238,38 +175,27 @@ func (ssp *SimpleSpamPolicy) PostBlockAccept(tx abci.Tx) (bool, error) { } ssp.blockPartyToCount[party]++ - // update party and block stats - if partyRejectStats, ok := ssp.partyBlockRejects[party]; ok { - partyRejectStats.add(false) - } else { - ssp.partyBlockRejects[party] = &blockRejectInfo{total: 1, rejected: 0} - } - return true, nil + return nil +} + +func (ssp *SimpleSpamPolicy) RollbackProposal() { + ssp.blockPartyToCount = map[string]uint64{} } // PreBlockAccept checks if the commands violates spam rules based on the information we had about the number of existing commands preceding the current block. -func (ssp *SimpleSpamPolicy) PreBlockAccept(tx abci.Tx) (bool, error) { +func (ssp *SimpleSpamPolicy) PreBlockAccept(tx abci.Tx) error { party := tx.Party() ssp.lock.RLock() defer ssp.lock.RUnlock() - // check if the party is banned - until, ok := ssp.bannedParties[party] - if ok { - if ssp.log.GetLevel() <= logging.DebugLevel { - ssp.log.Debug("Spam pre: party is banned from "+ssp.policyName, logging.String("txHash", hex.EncodeToString(tx.Hash())), logging.String("party", party)) - } - return false, ssp.banErr(time.Unix(0, until).UTC()) - } - // check if the party has enough balance to submit commands balance, err := ssp.accounts.GetAvailableBalance(party) if !ssp.minTokensRequired.IsZero() && (err != nil || balance.LT(ssp.minTokensRequired)) { if ssp.log.GetLevel() <= logging.DebugLevel { ssp.log.Debug("Spam pre: party has insufficient balance for "+ssp.policyName, logging.String("txHash", hex.EncodeToString(tx.Hash())), logging.String("party", party), logging.String("balance", num.UintToString(balance))) } - return false, ssp.insufficientTokensErr + return ssp.insufficientTokensErr } // Check we have not exceeded our command limit for this given party in this epoch @@ -277,10 +203,10 @@ func (ssp *SimpleSpamPolicy) PreBlockAccept(tx abci.Tx) (bool, error) { if ssp.log.GetLevel() <= logging.DebugLevel { ssp.log.Debug("Spam pre: party has already submitted the max amount of commands for "+ssp.policyName, logging.String("txHash", hex.EncodeToString(tx.Hash())), logging.String("party", party), logging.Uint64("count", commandCount), logging.Uint64("maxAllowed", ssp.maxAllowedCommands)) } - return false, ssp.tooManyCommands + return ssp.tooManyCommands } - return true, nil + return nil } func (ssp *SimpleSpamPolicy) GetSpamStats(party string) *protoapi.SpamStatistic { @@ -289,7 +215,6 @@ func (ssp *SimpleSpamPolicy) GetSpamStats(party string) *protoapi.SpamStatistic return &protoapi.SpamStatistic{ CountForEpoch: ssp.partyToCount[party], MaxForEpoch: ssp.maxAllowedCommands, - BannedUntil: parseBannedUntil(ssp.bannedParties[party]), MinTokensRequired: ssp.minTokensRequired.String(), } } diff --git a/core/spam/simple_spam_policy_test.go b/core/spam/simple_spam_policy_test.go index 6f9f8d547a..b54eb21876 100644 --- a/core/spam/simple_spam_policy_test.go +++ b/core/spam/simple_spam_policy_test.go @@ -16,19 +16,14 @@ package spam_test import ( - "bytes" - "errors" "strconv" "testing" - "time" "code.vegaprotocol.io/vega/core/netparams" "code.vegaprotocol.io/vega/core/spam" "code.vegaprotocol.io/vega/core/types" "code.vegaprotocol.io/vega/libs/num" - "code.vegaprotocol.io/vega/libs/proto" "code.vegaprotocol.io/vega/logging" - snapshot "code.vegaprotocol.io/vega/protos/vega/snapshot/v1" "github.com/stretchr/testify/require" ) @@ -37,18 +32,6 @@ var insufficientPropTokens, _ = num.UintFromString("50000000000000000000000", 10 var sufficientPropTokens, _ = num.UintFromString("100000000000000000000000", 10) -func TestSimpleSpamProtection(t *testing.T) { - t.Run("Pre reject command from party with insufficient balance at the beginning of the epoch", testCommandPreRejectInsufficientBalance) - t.Run("Pre reject command from party that is banned for the epochs", testCommandPreRejectBannedParty) - t.Run("Pre reject command from party that already had more than 3 proposal for the epoch", testCommandPreRejectTooManyProposals) - t.Run("Pre accept command success", testCommandPreAccept) - t.Run("Post accept command success", testCommandPostAccept) - t.Run("Post reject command from party with too many proposals in total all from current block", testCommandPostRejectTooManyProposals) - t.Run("command counts from the block successfully applied on state", testCommandCountersUpdated) - t.Run("Start of epoch resets counters", testCommandReset) - t.Run("On end of block, block proposal counters are reset and take a snapshot roundtrip", testProposalEndBlockReset) -} - func getCommandSpamPolicy(accounts map[string]*num.Uint) *spam.SimpleSpamPolicy { testAccounts := testAccounts{balances: accounts} logger := logging.NewTestLogger() @@ -59,142 +42,16 @@ func getCommandSpamPolicy(accounts map[string]*num.Uint) *spam.SimpleSpamPolicy return policy } -func testProposalEndBlockReset(t *testing.T) { - tokenMap := make(map[string]*num.Uint, 1) - tokenMap["party1"] = sufficientPropTokens - // set state - policy := getCommandSpamPolicy(tokenMap) - - policy.Reset(types.Epoch{Seq: 0}) - - // in each block we vote once - var i uint64 - for ; i < 3; i++ { - tx := &testTx{party: "party1", proposal: "proposal1"} - accept, err := policy.PreBlockAccept(tx) - require.Equal(t, true, accept) - require.Nil(t, err) - - accept, err = policy.PostBlockAccept(tx) - require.Equal(t, true, accept) - require.Nil(t, err) - policy.EndOfBlock(i, time.Now(), time.Minute*30) - } - - tx := &testTx{party: "party1", proposal: "proposal1"} - accept, err := policy.PreBlockAccept(tx) - require.Equal(t, false, accept) - require.Equal(t, errors.New("party has already submitted the maximum number of simple requests per epoch"), err) - - bytes1, err := policy.Serialise() - require.Nil(t, err) - var proposalPayload snapshot.Payload - proto.Unmarshal(bytes1, &proposalPayload) - payload := types.PayloadFromProto(&proposalPayload) - policy.Deserialise(payload) - bytes2, err := policy.Serialise() - require.Nil(t, err) - require.True(t, bytes.Equal(bytes1, bytes2)) - - policy.Reset(types.Epoch{Seq: 1}) - - bytes3, err := policy.Serialise() - require.Nil(t, err) - require.False(t, bytes.Equal(bytes3, bytes2)) -} - -// reject proposal when the proposer doesn't have sufficient balance at the beginning of the epoch. -func testCommandPreRejectInsufficientBalance(t *testing.T) { +func TestInsufficientPropTokens(t *testing.T) { policy := getCommandSpamPolicy(map[string]*num.Uint{"party1": insufficientPropTokens}) - tx := &testTx{party: "party1", proposal: "proposal1"} - accept, err := policy.PreBlockAccept(tx) - require.Equal(t, false, accept) - require.Equal(t, errors.New("party has insufficient associated governance tokens in their staking account to submit simple request"), err) -} - -// reject proposal requests from banned parties for as long as they are banned. -func testCommandPreRejectBannedParty(t *testing.T) { - policy := getCommandSpamPolicy(map[string]*num.Uint{"party1": sufficientPropTokens}) - - // epoch 0 started party1 has enough balance - policy.Reset(types.Epoch{Seq: 0}) - - // trigger banning of party1 by causing it to post reject 3/6 of the proposal - tx := &testTx{party: "party1", proposal: "proposal1"} - for i := 0; i < 6; i++ { - accept, err := policy.PreBlockAccept(tx) - require.Equal(t, true, accept) - require.Nil(t, err) - } - for i := 0; i < 3; i++ { - accept, err := policy.PostBlockAccept(tx) - require.Equal(t, true, accept) - require.Nil(t, err) - } - for i := 0; i < 3; i++ { - accept, err := policy.PostBlockAccept(tx) - require.Equal(t, false, accept) - require.Equal(t, errors.New("party has already submitted the maximum number of simple requests per epoch"), err) - } - - // end the block for banning to take place - it will be unblocked with the new epoch so it doesn't matter - tm, _ := time.Parse("2006-01-02 15:04", "2022-12-12 04:35") - policy.EndOfBlock(1, tm, time.Minute*30) - - accept, err := policy.PreBlockAccept(tx) - require.Equal(t, false, accept) - require.Equal(t, errors.New("party is banned from submitting simple until the earlier between 2022-12-12 05:05:00 +0000 UTC and the beginning of the next epoch"), err) - - // advance epochs - verify still banned until epoch 4 (including) - policy.Reset(types.Epoch{Seq: uint64(2)}) - - // should be released from ban on epoch 5 - policy.Reset(types.Epoch{Seq: 5}) - accept, err = policy.PreBlockAccept(tx) - require.Equal(t, true, accept) - require.Nil(t, err) -} - -func testCommandPreRejectTooManyProposals(t *testing.T) { - policy := getCommandSpamPolicy(map[string]*num.Uint{"party1": sufficientPropTokens}) // epoch 0 block 0 policy.Reset(types.Epoch{Seq: 0}) - - // propose 4 proposals, all preaccepted 3 post accepted tx := &testTx{party: "party1", proposal: "proposal1"} - // pre accepted - for i := 0; i < 4; i++ { - accept, err := policy.PreBlockAccept(tx) - require.Equal(t, true, accept) - require.Nil(t, err) - } - - // 3 post accepted - for i := 0; i < 3; i++ { - accept, err := policy.PostBlockAccept(tx) - require.Equal(t, true, accept) - require.Nil(t, err) - } - - // end block 0 - policy.EndOfBlock(1, time.Now(), time.Minute*30) - - // try to submit proposal - pre rejected because it already have 3 proposals - accept, err := policy.PreBlockAccept(tx) - require.Equal(t, false, accept) - require.Equal(t, errors.New("party has already submitted the maximum number of simple requests per epoch"), err) - - // advance to next epoch to reset limits - policy.Reset(types.Epoch{Seq: 1}) - for i := 0; i < 3; i++ { - tx := &testTx{party: "party1", proposal: "proposal1"} - accept, err := policy.PreBlockAccept(tx) - require.Equal(t, true, accept) - require.Nil(t, err) - } + err := policy.PreBlockAccept(tx) + require.Equal(t, "party has insufficient associated governance tokens in their staking account to submit simple request", err.Error()) } -func testCommandPreAccept(t *testing.T) { +func TestCommandPreAccept(t *testing.T) { policy := getCommandSpamPolicy(map[string]*num.Uint{"party1": sufficientPropTokens}) // epoch 0 block 0 policy.Reset(types.Epoch{Seq: 0}) @@ -204,134 +61,80 @@ func testCommandPreAccept(t *testing.T) { tx := &testTx{party: "party1", proposal: "proposal" + strconv.Itoa(i+1)} // pre accepted for i := 0; i < 5; i++ { - accept, err := policy.PreBlockAccept(tx) - require.Equal(t, true, accept) - require.Nil(t, err) + err := policy.PreBlockAccept(tx) + require.NoError(t, err) } } } -func testCommandPostAccept(t *testing.T) { - policy := getCommandSpamPolicy(map[string]*num.Uint{"party1": sufficientPropTokens}) - policy.Reset(types.Epoch{Seq: 0}) - tx := &testTx{party: "party1", proposal: "proposal1"} - // pre accepted - for i := 0; i < 3; i++ { - accept, err := policy.PreBlockAccept(tx) - require.Equal(t, true, accept) - require.Nil(t, err) - } - - // post accepted - for i := 0; i < 3; i++ { - accept, err := policy.PostBlockAccept(tx) - require.Equal(t, true, accept) - require.Nil(t, err) - } -} - -func testCommandPostRejectTooManyProposals(t *testing.T) { +func TestEndPrepareBlock(t *testing.T) { policy := getCommandSpamPolicy(map[string]*num.Uint{"party1": sufficientPropTokens}) policy.Reset(types.Epoch{Seq: 0}) - tx := &testTx{party: "party1", proposal: "proposal1"} - // pre accepted - for i := 0; i < 5; i++ { - accept, err := policy.PreBlockAccept(tx) - require.Equal(t, true, accept) - require.Nil(t, err) - } - // post accepted - for i := 0; i < 3; i++ { - accept, err := policy.PostBlockAccept(tx) - require.Equal(t, true, accept) - require.Nil(t, err) - } + tx1 := &testTx{party: "party1", proposal: "proposal1"} + tx2 := &testTx{party: "party1", proposal: "proposal2"} + tx3 := &testTx{party: "party1", proposal: "proposal3"} - // post rejected - for i := 0; i < 2; i++ { - accept, err := policy.PostBlockAccept(tx) - require.Equal(t, false, accept) - require.Equal(t, errors.New("party has already submitted the maximum number of simple requests per epoch"), err) - } -} + // prepare a block + require.NoError(t, policy.CheckBlockTx(tx1)) + require.NoError(t, policy.CheckBlockTx(tx2)) + require.NoError(t, policy.CheckBlockTx(tx3)) -func testCommandCountersUpdated(t *testing.T) { - policy := getCommandSpamPolicy(map[string]*num.Uint{"party1": sufficientPropTokens}) - policy.Reset(types.Epoch{Seq: 0}) + // end the proposal preparation to rollback any block changes + policy.RollbackProposal() - tx := &testTx{party: "party1", proposal: "proposal"} - // pre accepted - for i := 0; i < 3; i++ { - accept, err := policy.PreBlockAccept(tx) - require.Equal(t, true, accept) - require.Nil(t, err) - } + s := policy.GetSpamStats(tx1.party) + require.Equal(t, uint64(0), s.CountForEpoch) - // post accepted - for i := 0; i < 3; i++ { - accept, err := policy.PostBlockAccept(tx) - require.Equal(t, true, accept) - require.Nil(t, err) - } + // assume block was proposed, now check from process proposal + policy.UpdateTx(tx1) + policy.UpdateTx(tx2) + policy.UpdateTx(tx3) - policy.EndOfBlock(1, time.Now(), time.Minute*30) - accept, err := policy.PreBlockAccept(tx) - require.Equal(t, false, accept) - require.Equal(t, errors.New("party has already submitted the maximum number of simple requests per epoch"), err) + s = policy.GetSpamStats(tx1.party) + require.Equal(t, uint64(3), s.CountForEpoch) } -func testCommandReset(t *testing.T) { - // set state +func TestCheckBlockTx(t *testing.T) { policy := getCommandSpamPolicy(map[string]*num.Uint{"party1": sufficientPropTokens}) policy.Reset(types.Epoch{Seq: 0}) - tx := &testTx{party: "party1", proposal: "proposal1"} - // pre accepted - for i := 0; i < 6; i++ { - accept, err := policy.PreBlockAccept(tx) - require.Equal(t, true, accept) - require.Nil(t, err) - } - // post accepted - for i := 0; i < 3; i++ { - accept, err := policy.PostBlockAccept(tx) - require.Equal(t, true, accept) - require.Nil(t, err) - } - for i := 0; i < 3; i++ { - accept, err := policy.PostBlockAccept(tx) - require.Equal(t, false, accept) - require.Equal(t, errors.New("party has already submitted the maximum number of simple requests per epoch"), err) - } + tx1 := &testTx{party: "party1", proposal: "proposal1"} + tx2 := &testTx{party: "party1", proposal: "proposal2"} + tx3 := &testTx{party: "party1", proposal: "proposal3"} + tx4 := &testTx{party: "party1", proposal: "proposal4"} + + require.NoError(t, policy.CheckBlockTx(tx1)) + require.NoError(t, policy.CheckBlockTx(tx2)) + require.NoError(t, policy.CheckBlockTx(tx3)) + require.Error(t, policy.CheckBlockTx(tx4)) - // trigger ban of party1 for 30 minutes - tm, _ := time.Parse("2006-01-02 15:04", "2022-12-12 04:35") - policy.EndOfBlock(1, tm, time.Minute*30) + // rollback the proposal + policy.RollbackProposal() - policy.EndOfBlock(1, tm.Add(10*time.Minute), time.Minute*30) - accept, err := policy.PreBlockAccept(tx) - require.Equal(t, false, accept) - require.Equal(t, errors.New("party is banned from submitting simple until the earlier between 2022-12-12 05:05:00 +0000 UTC and the beginning of the next epoch"), err) + // as the state has nothing expect pre block accept of all 4 txs + require.NoError(t, policy.PreBlockAccept(tx1)) + require.NoError(t, policy.PreBlockAccept(tx2)) + require.NoError(t, policy.PreBlockAccept(tx3)) + require.NoError(t, policy.PreBlockAccept(tx4)) - policy.EndOfBlock(1, tm.Add(20*time.Minute), time.Minute*30) - accept, err = policy.PreBlockAccept(tx) - require.Equal(t, false, accept) - require.Equal(t, errors.New("party is banned from submitting simple until the earlier between 2022-12-12 05:05:00 +0000 UTC and the beginning of the next epoch"), err) + // now a block is made with the first 3 txs + policy.UpdateTx(tx1) + policy.UpdateTx(tx2) + policy.UpdateTx(tx3) - // advance time until the ban is lifted fro party1 - policy.EndOfBlock(1, tm.Add(30*time.Minute), time.Minute*30) + stats := policy.GetSpamStats(tx1.party) + require.Equal(t, uint64(3), stats.CountForEpoch) - // ban is finished, but still not eligible to submit another command - accept, err = policy.PreBlockAccept(tx) - require.Equal(t, false, accept) - require.Equal(t, errors.New("party has already submitted the maximum number of simple requests per epoch"), err) + // now that there's been 3 proposals already, the 4th should be pre-rejected + require.Error(t, policy.PreBlockAccept(tx4)) + + // start a new epoch to reset counters + policy.Reset(types.Epoch{Seq: 0}) - // end the epoch - policy.Reset(types.Epoch{Seq: 2}) + // check that the new proposal is pre-block accepted + require.NoError(t, policy.PreBlockAccept(tx4)) - // new epoch new allowance - accept, err = policy.PreBlockAccept(tx) - require.Equal(t, true, accept) - require.NoError(t, err) + stats = policy.GetSpamStats(tx1.party) + require.Equal(t, uint64(0), stats.CountForEpoch) } diff --git a/core/spam/vote_spam_policy.go b/core/spam/vote_spam_policy.go index 0846afe1c8..4c0be169f1 100644 --- a/core/spam/vote_spam_policy.go +++ b/core/spam/vote_spam_policy.go @@ -21,7 +21,6 @@ import ( "sort" "strings" "sync" - "time" "code.vegaprotocol.io/vega/core/blockchain/abci" "code.vegaprotocol.io/vega/core/types" @@ -32,19 +31,6 @@ import ( commandspb "code.vegaprotocol.io/vega/protos/vega/commands/v1" ) -type blockRejectInfo struct { - rejected uint64 - total uint64 -} - -func (b *blockRejectInfo) add(rejected bool) { - b.total++ - if rejected { - b.rejected++ - } -} - -var maxMinVotingTokens, _ = num.UintFromString("1600000000000000000000", 10) var ( // ErrInsufficientTokensForVoting is returned when the party has insufficient tokens for voting. ErrInsufficientTokensForVoting = errors.New("party has insufficient associated governance tokens in their staking account to submit votes") @@ -60,36 +46,20 @@ type VoteSpamPolicy struct { minTokensParamName string maxAllowedParamName string - - minVotingTokensFactor *num.Uint // a factor applied on the min voting tokens - effectiveMinTokens *num.Uint // minVotingFactor * minVotingTokens - partyToVote map[string]map[string]uint64 // those are votes that are already on blockchain - blockPartyToVote map[string]map[string]uint64 // votes in the current block - bannedParties map[string]int64 // parties banned -> ban end time - recentBlocksRejectStats [numberOfBlocksForIncreaseCheck]*blockRejectInfo // recent blocks post rejection stats - blockPostRejects *blockRejectInfo // this blocks post reject stats - partyBlockRejects map[string]*blockRejectInfo // total vs rejection in the current block - currentBlockIndex uint64 // the index of the current block in the circular buffer <recentBlocksRejectStats> - lastIncreaseBlock uint64 // the last block we've increased the number of <minVotingTokens> - currentEpochSeq uint64 // the sequence id of the current epoch - lock sync.RWMutex // global lock to sync calls from multiple tendermint threads + partyToVote map[string]map[string]uint64 // those are votes that are already on blockchain + blockPartyToVote map[string]map[string]uint64 // votes in the current block + currentEpochSeq uint64 // the sequence id of the current epoch + lock sync.RWMutex // global lock to sync calls from multiple tendermint threads } // NewVoteSpamPolicy instantiates vote spam policy. func NewVoteSpamPolicy(minTokensParamName string, maxAllowedParamName string, log *logging.Logger, accounts StakingAccounts) *VoteSpamPolicy { return &VoteSpamPolicy{ - log: log, - accounts: accounts, - minVotingTokensFactor: num.NewUint(1), - minVotingTokens: num.NewUint(1), - + log: log, + accounts: accounts, + minVotingTokens: num.NewUint(1), partyToVote: map[string]map[string]uint64{}, blockPartyToVote: map[string]map[string]uint64{}, - bannedParties: map[string]int64{}, - blockPostRejects: &blockRejectInfo{total: 0, rejected: 0}, - partyBlockRejects: map[string]*blockRejectInfo{}, - currentBlockIndex: 0, - lastIncreaseBlock: 0, lock: sync.RWMutex{}, minTokensParamName: minTokensParamName, maxAllowedParamName: maxAllowedParamName, @@ -118,36 +88,11 @@ func (vsp *VoteSpamPolicy) Serialise() ([]byte, error) { return partyProposalVoteCount[i].Proposal < partyProposalVoteCount[j].Proposal }) - bannedParties := make([]*types.BannedParty, 0, len(vsp.bannedParties)) - for party, until := range vsp.bannedParties { - bannedParties = append(bannedParties, &types.BannedParty{ - Party: party, - Until: until, - }) - } - - sort.SliceStable(bannedParties, func(i, j int) bool { return bannedParties[i].Party < bannedParties[j].Party }) - - recentRejects := make([]*types.BlockRejectStats, 0, len(vsp.recentBlocksRejectStats)) - for _, brs := range vsp.recentBlocksRejectStats { - if brs != nil { - recentRejects = append(recentRejects, &types.BlockRejectStats{ - Total: brs.total, - Rejected: brs.rejected, - }) - } - } - payload := types.Payload{ Data: &types.PayloadVoteSpamPolicy{ VoteSpamPolicy: &types.VoteSpamPolicy{ - PartyProposalVoteCount: partyProposalVoteCount, - BannedParty: bannedParties, - RecentBlocksRejectStats: recentRejects, - CurrentBlockIndex: vsp.currentBlockIndex, - LastIncreaseBlock: vsp.lastIncreaseBlock, - CurrentEpochSeq: vsp.currentEpochSeq, - MinVotingTokensFactor: vsp.minVotingTokensFactor, + PartyProposalVoteCount: partyProposalVoteCount, + CurrentEpochSeq: vsp.currentEpochSeq, }, }, } @@ -157,18 +102,6 @@ func (vsp *VoteSpamPolicy) Serialise() ([]byte, error) { func (vsp *VoteSpamPolicy) Deserialise(p *types.Payload) error { pl := p.Data.(*types.PayloadVoteSpamPolicy).VoteSpamPolicy - - var i uint64 - for ; i < numberOfBlocksForIncreaseCheck; i++ { - vsp.recentBlocksRejectStats[i] = nil - } - for j, bl := range pl.RecentBlocksRejectStats { - vsp.recentBlocksRejectStats[j] = &blockRejectInfo{ - total: bl.Total, - rejected: bl.Rejected, - } - } - vsp.partyToVote = map[string]map[string]uint64{} for _, ptv := range pl.PartyProposalVoteCount { if _, ok := vsp.partyToVote[ptv.Party]; !ok { @@ -176,17 +109,7 @@ func (vsp *VoteSpamPolicy) Deserialise(p *types.Payload) error { } vsp.partyToVote[ptv.Party][ptv.Proposal] = ptv.Count } - vsp.bannedParties = make(map[string]int64, len(pl.BannedParty)) - for _, bp := range pl.BannedParty { - vsp.bannedParties[bp.Party] = bp.Until - } - vsp.currentEpochSeq = pl.CurrentEpochSeq - vsp.lastIncreaseBlock = pl.LastIncreaseBlock - vsp.currentBlockIndex = pl.CurrentBlockIndex - vsp.minVotingTokensFactor = pl.MinVotingTokensFactor - vsp.effectiveMinTokens = num.UintZero().Mul(vsp.minVotingTokens, vsp.minVotingTokensFactor) - return nil } @@ -195,9 +118,6 @@ func (vsp *VoteSpamPolicy) Deserialise(p *types.Payload) error { func (vsp *VoteSpamPolicy) UpdateUintParam(name string, value *num.Uint) error { if name == vsp.minTokensParamName { vsp.minVotingTokens = value.Clone() - // NB: this means that if during the epoch the min tokens changes externally - // and we already have a factor on it, the factor will be applied on the new value for the duration of the epoch - vsp.effectiveMinTokens = num.UintZero().Mul(vsp.minVotingTokens, vsp.minVotingTokensFactor) } else { return errors.New("unknown parameter for vote spam policy") } @@ -220,119 +140,34 @@ func (vsp *VoteSpamPolicy) Reset(epoch types.Epoch) { vsp.lock.Lock() defer vsp.lock.Unlock() // reset the token count factor to 1 - vsp.minVotingTokensFactor = num.NewUint(1) - vsp.effectiveMinTokens = vsp.minVotingTokens vsp.currentEpochSeq = epoch.Seq - // set last increase to 0 so we'd check right away on the next block - vsp.lastIncreaseBlock = 0 - // reset vote counts vsp.partyToVote = map[string]map[string]uint64{} // reset current block vote counts vsp.blockPartyToVote = map[string]map[string]uint64{} - - // reset block stats - vsp.currentBlockIndex = 0 - var i uint64 - for ; i < numberOfBlocksForIncreaseCheck; i++ { - vsp.recentBlocksRejectStats[i] = nil - } - - // clear banned - vsp.bannedParties = map[string]int64{} - - // reset block rejects - this is not essential here as it's cleared at the end of every block anyways - // but just for consistency - vsp.partyBlockRejects = map[string]*blockRejectInfo{} - vsp.blockPostRejects = &blockRejectInfo{ - total: 0, - rejected: 0, - } } -// EndOfBlock is called at the end of the block to allow updating of the state for the next block. -func (vsp *VoteSpamPolicy) EndOfBlock(blockHeight uint64, now time.Time, banDuration time.Duration) { +func (vsp *VoteSpamPolicy) UpdateTx(tx abci.Tx) { vsp.lock.Lock() defer vsp.lock.Unlock() - // add the block's vote counters to the epoch's - for p, v := range vsp.blockPartyToVote { - if _, ok := vsp.partyToVote[p]; !ok { - vsp.partyToVote[p] = map[string]uint64{} - } - - for proposalID, votes := range v { - if _, ok := vsp.partyToVote[p][proposalID]; !ok { - vsp.partyToVote[p][proposalID] = 0 - } - vsp.partyToVote[p][proposalID] = vsp.partyToVote[p][proposalID] + votes - } + if _, ok := vsp.partyToVote[tx.Party()]; !ok { + vsp.partyToVote[tx.Party()] = map[string]uint64{} } - - vsp.blockPartyToVote = map[string]map[string]uint64{} - - // release bans - nowNano := now.UnixNano() - for k, v := range vsp.bannedParties { - if nowNano >= v { - delete(vsp.bannedParties, k) - } - } - - endBanTime := now.Add(banDuration).UnixNano() - - // ban parties with more than <banFactor> rejection rate in the block - for p, bStats := range vsp.partyBlockRejects { - if num.DecimalFromInt64(int64(bStats.rejected)).Div(num.DecimalFromInt64(int64(bStats.total))).GreaterThanOrEqual(banFactor) { - vsp.bannedParties[p] = endBanTime - } - } - vsp.partyBlockRejects = map[string]*blockRejectInfo{} - - // add the block rejects to the last 10 blocks - vsp.recentBlocksRejectStats[vsp.currentBlockIndex] = &blockRejectInfo{ - rejected: vsp.blockPostRejects.rejected, - total: vsp.blockPostRejects.total, - } - vsp.currentBlockIndex++ - vsp.currentBlockIndex %= numberOfBlocksForIncreaseCheck - vsp.blockPostRejects = &blockRejectInfo{ - rejected: 0, - total: 0, - } - - // check if we need to increase the limits, i.e. if we're below the max and we've not increased in the last n blocks - if (vsp.lastIncreaseBlock == 0 || blockHeight > vsp.lastIncreaseBlock+numberOfBlocksForIncreaseCheck) && num.UintZero().Mul(vsp.minVotingTokens, vsp.minVotingTokensFactor).LT(maxMinVotingTokens) { - average := vsp.calcRejectAverage() - if average.GreaterThan(rejectRatioForIncrease) { - vsp.lastIncreaseBlock = blockHeight - vsp.minVotingTokensFactor = num.UintZero().Mul(vsp.minVotingTokensFactor, increaseFactor) - vsp.effectiveMinTokens = num.UintZero().Mul(vsp.minVotingTokensFactor, vsp.minVotingTokens) - } + vote := &commandspb.VoteSubmission{} + tx.Unmarshal(vote) + if _, ok := vsp.partyToVote[tx.Party()][vote.ProposalId]; !ok { + vsp.partyToVote[tx.Party()][vote.ProposalId] = 0 } + vsp.partyToVote[tx.Party()][vote.ProposalId] = vsp.partyToVote[tx.Party()][vote.ProposalId] + 1 } -// calculate the mean rejection rate in the last <numberOfBlocksForIncreaseCheck>. -func (vsp *VoteSpamPolicy) calcRejectAverage() num.Decimal { - var total uint64 - var rejected uint64 - var i uint64 - for ; i < numberOfBlocksForIncreaseCheck; i++ { - if vsp.recentBlocksRejectStats[i] != nil { - total += vsp.recentBlocksRejectStats[i].total - rejected += vsp.recentBlocksRejectStats[i].rejected - } - } - if total == 0 { - return num.DecimalZero() - } - return num.DecimalFromInt64(int64(rejected)).Div(num.DecimalFromInt64(int64((total)))) +func (vsp *VoteSpamPolicy) RollbackProposal() { + vsp.blockPartyToVote = map[string]map[string]uint64{} } -// PostBlockAccept checks if votes that made it to the block should be rejected based on the number of votes preceding the block + votes seen in the block -// NB: this is called as part of the processing of the block. -func (vsp *VoteSpamPolicy) PostBlockAccept(tx abci.Tx) (bool, error) { +func (vsp *VoteSpamPolicy) CheckBlockTx(tx abci.Tx) error { party := tx.Party() vsp.lock.Lock() @@ -340,8 +175,7 @@ func (vsp *VoteSpamPolicy) PostBlockAccept(tx abci.Tx) (bool, error) { vote := &commandspb.VoteSubmission{} if err := tx.Unmarshal(vote); err != nil { - vsp.blockPostRejects.add(true) - return false, err + return err } // get number of votes preceding the block in this epoch @@ -362,19 +196,7 @@ func (vsp *VoteSpamPolicy) PostBlockAccept(tx abci.Tx) (bool, error) { // if too many votes in total - reject and update counters if epochVotes+blockVotes >= vsp.numVotes { - // update party/proposal vote stats for the epoch - vsp.blockPostRejects.add(true) - // update vote stats for the epoch - if partyRejectStats, ok := vsp.partyBlockRejects[party]; ok { - partyRejectStats.add(true) - } else { - vsp.partyBlockRejects[party] = &blockRejectInfo{total: 1, rejected: 1} - } - if vsp.log.GetLevel() <= logging.DebugLevel { - vsp.log.Debug("Spam post: party has already voted for proposal the max amount of votes", logging.String("txHash", hex.EncodeToString(tx.Hash())), logging.String("party", party), logging.String("proposal", vote.ProposalId), logging.Uint64("voteCount", epochVotes+blockVotes), logging.Uint64("maxAllowed", vsp.numVotes)) - } - - return false, ErrTooManyVotes + return ErrTooManyVotes } // update vote counters for party/proposal votes @@ -386,47 +208,31 @@ func (vsp *VoteSpamPolicy) PostBlockAccept(tx abci.Tx) (bool, error) { } else { vsp.blockPartyToVote[party][vote.ProposalId] = votes + 1 } - - // update party and block stats - if partyRejectStats, ok := vsp.partyBlockRejects[party]; ok { - partyRejectStats.add(false) - } else { - vsp.partyBlockRejects[party] = &blockRejectInfo{total: 1, rejected: 0} - } - vsp.blockPostRejects.add(false) - return true, nil + return nil } // PreBlockAccept checks if the vote should be rejected as spam or not based on the number of votes in current epoch's preceding blocks and the number of tokens // held by the party. // NB: this is done at mempool before adding to block. -func (vsp *VoteSpamPolicy) PreBlockAccept(tx abci.Tx) (bool, error) { +func (vsp *VoteSpamPolicy) PreBlockAccept(tx abci.Tx) error { party := tx.Party() vsp.lock.RLock() defer vsp.lock.RUnlock() - until, ok := vsp.bannedParties[party] - if ok { - if vsp.log.GetLevel() <= logging.DebugLevel { - vsp.log.Debug("Spam pre: party is banned from voting", logging.String("txHash", hex.EncodeToString(tx.Hash())), logging.String("party", party)) - } - return false, errors.New("party is banned from submitting votes until the earlier between " + time.Unix(0, until).UTC().String() + " and the beginning of the next epoch") - } - // check if the party has enough balance to submit votes balance, err := vsp.accounts.GetAvailableBalance(party) - if err != nil || balance.LT(vsp.effectiveMinTokens) { + if err != nil || balance.LT(vsp.minVotingTokens) { if vsp.log.GetLevel() <= logging.DebugLevel { vsp.log.Debug("Spam pre: party has insufficient balance for voting", logging.String("txHash", hex.EncodeToString(tx.Hash())), logging.String("party", party), logging.String("balance", num.UintToString(balance))) } - return false, ErrInsufficientTokensForVoting + return ErrInsufficientTokensForVoting } vote := &commandspb.VoteSubmission{} if err := tx.Unmarshal(vote); err != nil { - return false, err + return err } // Check we have not exceeded our vote limit for this given proposal in this epoch @@ -435,11 +241,11 @@ func (vsp *VoteSpamPolicy) PreBlockAccept(tx abci.Tx) (bool, error) { if vsp.log.GetLevel() <= logging.DebugLevel { vsp.log.Debug("Spam pre: party has already voted for proposal the max amount of votes", logging.String("txHash", hex.EncodeToString(tx.Hash())), logging.String("party", party), logging.String("proposal", vote.ProposalId), logging.Uint64("voteCount", voteCount), logging.Uint64("maxAllowed", vsp.numVotes)) } - return false, ErrTooManyVotes + return ErrTooManyVotes } } - return true, nil + return nil } func (vsp *VoteSpamPolicy) GetSpamStats(_ string) *protoapi.SpamStatistic { @@ -453,7 +259,6 @@ func (vsp *VoteSpamPolicy) GetVoteSpamStats(partyID string) *protoapi.VoteSpamSt partyStats := vsp.partyToVote[partyID] stats := make([]*protoapi.VoteSpamStatistic, 0, len(partyStats)) - bannedUntil := vsp.bannedParties[partyID] for proposal, votes := range partyStats { stats = append(stats, &protoapi.VoteSpamStatistic{ @@ -462,10 +267,8 @@ func (vsp *VoteSpamPolicy) GetVoteSpamStats(partyID string) *protoapi.VoteSpamSt MinTokensRequired: vsp.minVotingTokens.String(), }) } - return &protoapi.VoteSpamStatistics{ Statistics: stats, MaxForEpoch: vsp.numVotes, - BannedUntil: parseBannedUntil(bannedUntil), } } diff --git a/core/spam/vote_spam_policy_test.go b/core/spam/vote_spam_policy_test.go index 77bef75bc2..cc7fc940af 100644 --- a/core/spam/vote_spam_policy_test.go +++ b/core/spam/vote_spam_policy_test.go @@ -19,7 +19,6 @@ import ( "bytes" "strconv" "testing" - "time" "code.vegaprotocol.io/vega/core/netparams" "code.vegaprotocol.io/vega/core/spam" @@ -39,28 +38,19 @@ type testTx struct { command txn.Command } +func (*testTx) GetLength() int { return 0 } func (*testTx) GetPoWNonce() uint64 { return 0 } func (*testTx) GetNonce() uint64 { return 0 } func (*testTx) GetPoWTID() string { return "" } func (*testTx) GetVersion() uint32 { return 2 } -var ( - sufficientTokensForVoting, _ = num.UintFromString("100000000000000000000", 10) - sufficientTokens2ForVoting, _ = num.UintFromString("200000000000000000000", 10) - sufficientTokens4ForVoting, _ = num.UintFromString("400000000000000000000", 10) - sufficientTokens8ForVoting, _ = num.UintFromString("800000000000000000000", 10) - maxSufficientTokensForVoting, _ = num.UintFromString("1600000000000000000000", 10) -) +var sufficientTokensForVoting, _ = num.UintFromString("100000000000000000000", 10) func TestVotingSpamProtection(t *testing.T) { t.Run("Pre reject vote from party with insufficient balance at the beginning of the epoch", testPreRejectInsufficientBalance) - t.Run("Pre reject vote from party with insufficient balance at the beginning of the epoch vs factored min tokens", testPreRejectInsufficientBalanceWithFactor) - t.Run("Double min tokens until the max", testFactoringOfMinTokens) - t.Run("Pre reject vote from party that is banned for the epochs", testPreRejectBannedParty) t.Run("Pre reject vote from party that already had more than 3 votes for the epoch", testPreRejectTooManyVotesPerProposal) t.Run("Pre accept vote success", testPreAccept) t.Run("Post accept vote success", testPostAccept) - t.Run("Post reject vote from party with too many votes in total all from current block", testPostRejectTooManyVotes) t.Run("Vote counts from the block carried over to next block", testCountersUpdated) t.Run("On epoch start voting counters are reset", testReset) t.Run("On end of block, block voting counters are reset and take a snapshot roundtrip", testVoteEndBlockReset) @@ -81,222 +71,7 @@ func testPreRejectInsufficientBalance(t *testing.T) { policy := getVotingSpamPolicy(map[string]*num.Uint{"party1": num.NewUint(50)}) policy.Reset(types.Epoch{Seq: 0}) tx := &testTx{party: "party1", proposal: "proposal1"} - accept, err := policy.PreBlockAccept(tx) - require.Equal(t, false, accept) - require.Equal(t, spam.ErrInsufficientTokensForVoting, err) -} - -// reject votes requests when the voter doesn't have sufficient balance with a factored min tokens. -func testPreRejectInsufficientBalanceWithFactor(t *testing.T) { - // epoch 0 started party1 has enough balance without doubling, party2 has enough balance with doubling - tokenMap := make(map[string]*num.Uint, 2) - tokenMap["party1"] = sufficientTokensForVoting - tokenMap["party2"] = sufficientTokens2ForVoting - policy := getVotingSpamPolicy(tokenMap) - - policy.Reset(types.Epoch{Seq: 0}) - - // make 30% of transactions post fail - tx1 := &testTx{party: "party1", proposal: "proposal1"} - tx2 := &testTx{party: "party2", proposal: "proposal2"} - - // party1 submits 5 votes for proposal 1 (with nothing earlier in the epoch) - for i := 0; i < 5; i++ { - accept, err := policy.PreBlockAccept(tx1) - require.Equal(t, true, accept) - require.Nil(t, err) - } - - // party2 submits 4 votes for proposal 2 (with nothing earlier in the epoch) - for i := 0; i < 5; i++ { - accept, err := policy.PreBlockAccept(tx2) - require.Equal(t, true, accept) - require.Nil(t, err) - } - - // party1 gets 3 post accepted and 2 post rejected - for i := 0; i < 3; i++ { - accept, err := policy.PostBlockAccept(tx1) - require.Equal(t, true, accept) - require.Nil(t, err) - } - for i := 0; i < 2; i++ { - accept, err := policy.PostBlockAccept(tx1) - require.Equal(t, false, accept) - require.Equal(t, spam.ErrTooManyVotes, err) - } - - // party2 gets 3 post accepted and 1 post rejected - for i := 0; i < 3; i++ { - accept, err := policy.PostBlockAccept(tx2) - require.Equal(t, true, accept) - require.Nil(t, err) - } - - accept, err := policy.PostBlockAccept(tx2) - require.Equal(t, false, accept) - require.Equal(t, spam.ErrTooManyVotes, err) - - // end the block for doubling of min amount to take place - policy.EndOfBlock(1, time.Now(), time.Minute*30) - - // in the next block party1 should not have enough balance to vote while party2 still has, but has no more votes - accept, err = policy.PreBlockAccept(tx1) - require.Equal(t, false, accept) - require.Equal(t, spam.ErrInsufficientTokensForVoting, err) - - accept, err = policy.PreBlockAccept(tx2) - require.Equal(t, false, accept) - require.Equal(t, spam.ErrTooManyVotes, err) -} - -// attack for a number of blocks until the min tokens reach 1600. -func testFactoringOfMinTokens(t *testing.T) { - // epoch 0 started party1 has enough balance without doubling, party2 has enough balance with doubling - tokenMap := make(map[string]*num.Uint, 2) - tokenMap["party1"] = sufficientTokensForVoting - tokenMap["party2"] = sufficientTokens2ForVoting - tokenMap["party3"] = sufficientTokens4ForVoting - tokenMap["party4"] = sufficientTokens8ForVoting - tokenMap["party5"] = maxSufficientTokensForVoting - policy := getVotingSpamPolicy(tokenMap) - - policy.Reset(types.Epoch{Seq: 0}) - - // party x submits 5 votes for proposal 1 (with nothing earlier in the epoch) - for i := 0; i < 4; i++ { - tx := &testTx{party: "party" + strconv.Itoa(i+1), proposal: "proposal" + strconv.Itoa(i+1)} - // pre accepted - for i := 0; i < 5; i++ { - accept, err := policy.PreBlockAccept(tx) - require.Equal(t, true, accept) - require.Nil(t, err) - } - - // post 3 accepted 2 rejected - for i := 0; i < 3; i++ { - accept, err := policy.PostBlockAccept(tx) - require.Equal(t, true, accept) - require.Nil(t, err) - } - for i := 0; i < 2; i++ { - accept, err := policy.PostBlockAccept(tx) - require.Equal(t, false, accept) - require.Equal(t, spam.ErrTooManyVotes, err) - } - - for j := 0; j < 11; j++ { - // the first end of block will double the amount, the following 10 will have no impact on doubling - policy.EndOfBlock(uint64(i*10+j)+1, time.Now(), time.Minute*30) - } - } - - // at this point we expect the min tokens to be the max so all but party5 shall be pre rejected - for i := 1; i < 5; i++ { - tx := &testTx{party: "party" + strconv.Itoa(i), proposal: "proposal" + strconv.Itoa(i)} - // pre rejected - for i := 0; i < 5; i++ { - accept, err := policy.PreBlockAccept(tx) - require.Equal(t, false, accept) - require.Equal(t, spam.ErrInsufficientTokensForVoting, err) - } - } - - tx := &testTx{party: "party5", proposal: "proposal5"} - for i := 0; i < 5; i++ { - accept, err := policy.PreBlockAccept(tx) - require.Equal(t, true, accept) - require.Nil(t, err) - } - - for i := 0; i < 3; i++ { - accept, err := policy.PostBlockAccept(tx) - require.Equal(t, true, accept) - require.Nil(t, err) - } - for i := 0; i < 2; i++ { - accept, err := policy.PostBlockAccept(tx) - require.Equal(t, false, accept) - require.Equal(t, spam.ErrTooManyVotes, err) - } - - // advance to the next epoch so we reset the balances and all should be able to succeed with their token balances - policy.Reset(types.Epoch{Seq: 0}) - - for i := 0; i < 4; i++ { - tx := &testTx{party: "party" + strconv.Itoa(i+1), proposal: "proposal" + strconv.Itoa(i+1)} - // pre accepted - for i := 0; i < 5; i++ { - accept, err := policy.PreBlockAccept(tx) - require.Equal(t, true, accept) - require.Nil(t, err) - } - - // post 3 accepted 2 rejected - for i := 0; i < 3; i++ { - accept, err := policy.PostBlockAccept(tx) - require.Equal(t, true, accept) - require.Nil(t, err) - } - for i := 0; i < 2; i++ { - accept, err := policy.PostBlockAccept(tx) - require.Equal(t, false, accept) - require.Equal(t, spam.ErrTooManyVotes, err) - } - - for j := 0; j < 11; j++ { - // the first end of block will double the amount, the following 10 will have no impact on doubling - policy.EndOfBlock(uint64(i*10+j)+1, time.Now(), time.Minute*30) - } - } -} - -// reject vote requests from banned parties for as long as they are banned. -func testPreRejectBannedParty(t *testing.T) { - policy := getVotingSpamPolicy(map[string]*num.Uint{"party1": sufficientTokens2ForVoting}) - - // epoch 0 started party1 has enough balance - policy.Reset(types.Epoch{Seq: 0}) - - // trigger banning of party1 by causing it to post reject 3/6 of the requests to vote - tx := &testTx{party: "party1", proposal: "proposal1"} - for i := 0; i < 6; i++ { - accept, err := policy.PreBlockAccept(tx) - require.Equal(t, true, accept) - require.Nil(t, err) - } - for i := 0; i < 3; i++ { - accept, err := policy.PostBlockAccept(tx) - require.Equal(t, true, accept) - require.Nil(t, err) - } - for i := 0; i < 3; i++ { - accept, err := policy.PostBlockAccept(tx) - require.Equal(t, false, accept) - require.Equal(t, spam.ErrTooManyVotes, err) - } - - // end the block for banning to take place - tm, _ := time.Parse("2006-01-02 15:04", "2022-12-12 04:35") - policy.EndOfBlock(1, tm, time.Minute*30) - - accept, err := policy.PreBlockAccept(tx) - require.Equal(t, false, accept) - print(tm.String()) - require.Equal(t, "party is banned from submitting votes until the earlier between 2022-12-12 05:05:00 +0000 UTC and the beginning of the next epoch", err.Error()) - - // advance 30 minutes - verify still banned until 30 minutes pass - for i := 0; i < 3; i++ { - accept, err := policy.PreBlockAccept(tx) - require.Equal(t, false, accept) - require.Equal(t, "party is banned from submitting votes until the earlier between 2022-12-12 05:05:00 +0000 UTC and the beginning of the next epoch", err.Error()) - adjustment := 10 * time.Minute * time.Duration(i+1) - policy.EndOfBlock(1, tm.Add(adjustment), time.Minute*30) - } - // should be released from ban now but should still fail as they have already voted 3 times - accept, err = policy.PreBlockAccept(tx) - require.Equal(t, "party has already voted the maximum number of times per proposal per epoch", err.Error()) - require.Equal(t, false, accept) + require.Equal(t, spam.ErrInsufficientTokensForVoting, policy.PreBlockAccept(tx)) } func testPreRejectTooManyVotesPerProposal(t *testing.T) { @@ -309,45 +84,40 @@ func testPreRejectTooManyVotesPerProposal(t *testing.T) { tx := &testTx{party: "party1", proposal: "proposal" + strconv.Itoa(i+1)} // pre accepted for i := 0; i < 5; i++ { - accept, err := policy.PreBlockAccept(tx) - require.Equal(t, true, accept) - require.Nil(t, err) + require.NoError(t, policy.PreBlockAccept(tx)) } - // post 3 accepted 1 rejected + // prepare block check + for i := 0; i < 5; i++ { + if i < 3 { + require.NoError(t, policy.CheckBlockTx(tx)) + } else { + require.Error(t, policy.CheckBlockTx(tx)) + } + } + + policy.RollbackProposal() + for i := 0; i < 3; i++ { - accept, err := policy.PostBlockAccept(tx) - require.Equal(t, true, accept) - require.Nil(t, err) + policy.UpdateTx(tx) } } - // end block 0 - policy.EndOfBlock(1, time.Now(), time.Minute*30) - // try to submit for i := 0; i < 2; i++ { tx := &testTx{party: "party1", proposal: "proposal" + strconv.Itoa(i+1)} - // pre rejected - accept, err := policy.PreBlockAccept(tx) - require.Equal(t, false, accept) - require.Equal(t, spam.ErrTooManyVotes, err) + require.Equal(t, spam.ErrTooManyVotes.Error(), policy.PreBlockAccept(tx).Error()) } tx := &testTx{party: "party1", proposal: "proposal3"} // pre accepted - accept, err := policy.PreBlockAccept(tx) - require.Equal(t, true, accept) - require.Nil(t, err) + require.NoError(t, policy.PreBlockAccept(tx)) // advance to next epoch to reset limits policy.Reset(types.Epoch{Seq: 0}) for i := 0; i < 3; i++ { tx := &testTx{party: "party1", proposal: "proposal" + strconv.Itoa(i+1)} - // pre rejected - accept, err := policy.PreBlockAccept(tx) - require.Equal(t, true, accept) - require.Nil(t, err) + require.NoError(t, policy.PreBlockAccept(tx)) } } @@ -361,9 +131,7 @@ func testPreAccept(t *testing.T) { tx := &testTx{party: "party1", proposal: "proposal" + strconv.Itoa(i+1)} // pre accepted for i := 0; i < 5; i++ { - accept, err := policy.PreBlockAccept(tx) - require.Equal(t, true, accept) - require.Nil(t, err) + require.Nil(t, policy.PreBlockAccept(tx)) } } } @@ -371,102 +139,87 @@ func testPreAccept(t *testing.T) { func testPostAccept(t *testing.T) { policy := getVotingSpamPolicy(map[string]*num.Uint{"party1": sufficientTokensForVoting}) policy.Reset(types.Epoch{Seq: 0}) - for i := 0; i < 2; i++ { - tx := &testTx{party: "party1", proposal: "proposal" + strconv.Itoa(i+1)} - // pre accepted - for i := 0; i < 3; i++ { - accept, err := policy.PreBlockAccept(tx) - require.Equal(t, true, accept) - require.Nil(t, err) - } - } - for i := 0; i < 2; i++ { - tx := &testTx{party: "party1", proposal: "proposal" + strconv.Itoa(i+1)} - // post accepted - for i := 0; i < 3; i++ { - accept, err := policy.PostBlockAccept(tx) - require.Equal(t, true, accept) - require.Nil(t, err) - } - } -} + policy.Reset(types.Epoch{Seq: 0}) -func testPostRejectTooManyVotes(t *testing.T) { - policy := getVotingSpamPolicy(map[string]*num.Uint{"party1": sufficientTokensForVoting}) + tx1 := &testTx{party: "party1", proposal: "proposal1"} + tx2 := &testTx{party: "party1", proposal: "proposal1"} + tx3 := &testTx{party: "party1", proposal: "proposal1"} + tx4 := &testTx{party: "party1", proposal: "proposal1"} + + require.NoError(t, policy.CheckBlockTx(tx1)) + require.NoError(t, policy.CheckBlockTx(tx2)) + require.NoError(t, policy.CheckBlockTx(tx3)) + require.Error(t, policy.CheckBlockTx(tx4)) + + policy.RollbackProposal() + + // as the state has nothing, expect pre block accept of all 4 txs + require.NoError(t, policy.PreBlockAccept(tx1)) + require.NoError(t, policy.PreBlockAccept(tx2)) + require.NoError(t, policy.PreBlockAccept(tx3)) + require.NoError(t, policy.PreBlockAccept(tx4)) + + // now a block is made with the first 3 txs + require.NoError(t, policy.CheckBlockTx(tx1)) + require.NoError(t, policy.CheckBlockTx(tx2)) + require.NoError(t, policy.CheckBlockTx(tx3)) + + // and the block is confirmed + policy.RollbackProposal() + policy.UpdateTx(tx1) + policy.UpdateTx(tx2) + policy.UpdateTx(tx3) + + stats := policy.GetVoteSpamStats(tx1.party).GetStatistics()[0] + require.Equal(t, uint64(3), stats.CountForEpoch) + + // now that there's been 3 proposals already, the 4th should be pre-rejected + require.Error(t, policy.PreBlockAccept(tx4)) + + // start a new epoch to reset counters policy.Reset(types.Epoch{Seq: 0}) - for i := 0; i < 2; i++ { - tx := &testTx{party: "party1", proposal: "proposal" + strconv.Itoa(i+1)} - // pre accepted - for i := 0; i < 5; i++ { - accept, err := policy.PreBlockAccept(tx) - require.Equal(t, true, accept) - require.Nil(t, err) - } - } - for i := 0; i < 2; i++ { - tx := &testTx{party: "party1", proposal: "proposal" + strconv.Itoa(i+1)} - // post accepted - for i := 0; i < 3; i++ { - accept, err := policy.PostBlockAccept(tx) - require.Equal(t, true, accept) - require.Nil(t, err) - } + // check that the new proposal is pre-block accepted + require.NoError(t, policy.PreBlockAccept(tx4)) - // post rejected - for i := 0; i < 2; i++ { - accept, err := policy.PostBlockAccept(tx) - require.Equal(t, false, accept) - require.Equal(t, spam.ErrTooManyVotes, err) - } - } + require.Equal(t, 0, len(policy.GetVoteSpamStats(tx1.party).GetStatistics())) } func testCountersUpdated(t *testing.T) { policy := getVotingSpamPolicy(map[string]*num.Uint{"party1": sufficientTokensForVoting}) policy.Reset(types.Epoch{Seq: 0}) + for i := 0; i < 2; i++ { tx := &testTx{party: "party1", proposal: "proposal" + strconv.Itoa(i+1)} - // pre accepted + // post accepted for i := 0; i < 2; i++ { - accept, err := policy.PreBlockAccept(tx) - require.Equal(t, true, accept) - require.Nil(t, err) + require.NoError(t, policy.CheckBlockTx(tx)) } } - + policy.RollbackProposal() for i := 0; i < 2; i++ { tx := &testTx{party: "party1", proposal: "proposal" + strconv.Itoa(i+1)} // post accepted for i := 0; i < 2; i++ { - accept, err := policy.PostBlockAccept(tx) - require.Equal(t, true, accept) - require.Nil(t, err) + policy.UpdateTx(tx) } } - policy.EndOfBlock(1, time.Now(), time.Minute*30) for i := 0; i < 2; i++ { tx := &testTx{party: "party1", proposal: "proposal" + strconv.Itoa(i+1)} // pre accepted for i := 0; i < 2; i++ { - accept, err := policy.PreBlockAccept(tx) - require.Equal(t, true, accept) - require.Nil(t, err) + require.NoError(t, policy.PreBlockAccept(tx)) } } for i := 0; i < 2; i++ { tx := &testTx{party: "party1", proposal: "proposal" + strconv.Itoa(i+1)} // post accepted - accept, err := policy.PostBlockAccept(tx) - require.Equal(t, true, accept) - require.Nil(t, err) + require.NoError(t, policy.CheckBlockTx(tx)) // post rejected - accept, err = policy.PostBlockAccept(tx) - require.Equal(t, false, accept) - require.Equal(t, spam.ErrTooManyVotes, err) + require.Error(t, spam.ErrTooManyVotes, policy.CheckBlockTx(tx)) } } @@ -478,9 +231,7 @@ func testReset(t *testing.T) { tx := &testTx{party: "party1", proposal: "proposal" + strconv.Itoa(i+1)} // pre accepted for i := 0; i < 6; i++ { - accept, err := policy.PreBlockAccept(tx) - require.Equal(t, true, accept) - require.Nil(t, err) + require.NoError(t, policy.PreBlockAccept(tx)) } } @@ -488,37 +239,27 @@ func testReset(t *testing.T) { tx := &testTx{party: "party1", proposal: "proposal" + strconv.Itoa(i+1)} // post accepted for i := 0; i < 3; i++ { - accept, err := policy.PostBlockAccept(tx) - require.Equal(t, true, accept) - require.Nil(t, err) + require.NoError(t, policy.CheckBlockTx(tx)) } for i := 0; i < 3; i++ { - accept, err := policy.PostBlockAccept(tx) - require.Equal(t, false, accept) - require.Equal(t, spam.ErrTooManyVotes, err) + require.Equal(t, spam.ErrTooManyVotes, policy.CheckBlockTx(tx)) + } + } + policy.RollbackProposal() + for i := 0; i < 2; i++ { + tx := &testTx{party: "party1", proposal: "proposal" + strconv.Itoa(i+1)} + // post accepted + for i := 0; i < 3; i++ { + policy.UpdateTx(tx) } } - // trigger ban of party1 for 30 minutes - tm, _ := time.Parse("2006-01-02 15:04", "2022-12-12 04:35") - policy.EndOfBlock(1, tm, time.Minute*30) - - policy.EndOfBlock(1, tm.Add(10*time.Minute), time.Minute*30) tx := &testTx{party: "party1", proposal: "proposal1"} - accept, err := policy.PreBlockAccept(tx) - require.Equal(t, false, accept) - require.Equal(t, "party is banned from submitting votes until the earlier between 2022-12-12 05:05:00 +0000 UTC and the beginning of the next epoch", err.Error()) - - policy.EndOfBlock(1, tm.Add(20*time.Minute), time.Minute*30) - accept, err = policy.PreBlockAccept(tx) - require.Equal(t, false, accept) - require.Equal(t, "party is banned from submitting votes until the earlier between 2022-12-12 05:05:00 +0000 UTC and the beginning of the next epoch", err.Error()) - - policy.EndOfBlock(1, tm.Add(30*time.Minute), time.Minute*30) - accept, err = policy.PostBlockAccept(tx) - require.Equal(t, false, accept) - require.Equal(t, "party has already voted the maximum number of times per proposal per epoch", err.Error()) + require.Error(t, policy.PreBlockAccept(tx)) + + policy.Reset(types.Epoch{Seq: 1}) + require.NoError(t, policy.PreBlockAccept(tx)) } func testVoteEndBlockReset(t *testing.T) { @@ -530,20 +271,14 @@ func testVoteEndBlockReset(t *testing.T) { var i uint64 for ; i < 3; i++ { tx := &testTx{party: "party1", proposal: "proposal1"} - accept, err := policy.PreBlockAccept(tx) - require.Equal(t, true, accept) - require.Nil(t, err) - - accept, err = policy.PostBlockAccept(tx) - require.Equal(t, true, accept) - require.Nil(t, err) - policy.EndOfBlock(i, time.Now(), time.Minute*30) + require.NoError(t, policy.PreBlockAccept(tx)) + require.NoError(t, policy.CheckBlockTx(tx)) + policy.RollbackProposal() + policy.UpdateTx(tx) } tx := &testTx{party: "party1", proposal: "proposal1"} - accept, err := policy.PreBlockAccept(tx) - require.Equal(t, false, accept) - require.Equal(t, spam.ErrTooManyVotes, err) + require.Error(t, spam.ErrTooManyVotes, policy.PreBlockAccept(tx)) bytes1, err := policy.Serialise() require.Nil(t, err) @@ -554,9 +289,19 @@ func testVoteEndBlockReset(t *testing.T) { bytes2, err := policy.Serialise() require.Nil(t, err) require.True(t, bytes.Equal(bytes1, bytes2)) - policy.EndOfBlock(3, time.Now(), time.Minute*30) + tx2 := &testTx{party: "party1", proposal: "proposal2"} + require.NoError(t, policy.CheckBlockTx(tx2)) + policy.RollbackProposal() + + // verify that changes made during prepare proposal are properly rolled back and not affecting the state bytes3, err := policy.Serialise() - require.Nil(t, err) - require.False(t, bytes.Equal(bytes3, bytes2)) + require.NoError(t, err) + require.True(t, bytes.Equal(bytes3, bytes2)) + + // now the block has been processed, verify that the state has changed + policy.UpdateTx(tx2) + bytes4, err := policy.Serialise() + require.NoError(t, err) + require.False(t, bytes.Equal(bytes4, bytes3)) } diff --git a/core/stats/stats.go b/core/stats/stats.go index a0714ebcbe..b0bac0045f 100644 --- a/core/stats/stats.go +++ b/core/stats/stats.go @@ -24,7 +24,7 @@ import ( proto "code.vegaprotocol.io/vega/protos/vega" "code.vegaprotocol.io/vega/version" - tmversion "github.com/tendermint/tendermint/version" + tmversion "github.com/cometbft/cometbft/version" ) // Stats ties together all other package level application stats types. diff --git a/core/tendermint/config.go b/core/tendermint/config.go index 0d2e19b974..308e4b1482 100644 --- a/core/tendermint/config.go +++ b/core/tendermint/config.go @@ -23,12 +23,12 @@ import ( "code.vegaprotocol.io/vega/core/genesis" vgfs "code.vegaprotocol.io/vega/libs/fs" - tmconfig "github.com/tendermint/tendermint/config" - tmcrypto "github.com/tendermint/tendermint/crypto" - tmjson "github.com/tendermint/tendermint/libs/json" - tmos "github.com/tendermint/tendermint/libs/os" - "github.com/tendermint/tendermint/privval" - tmtypes "github.com/tendermint/tendermint/types" + tmconfig "github.com/cometbft/cometbft/config" + tmcrypto "github.com/cometbft/cometbft/crypto" + tmjson "github.com/cometbft/cometbft/libs/json" + tmos "github.com/cometbft/cometbft/libs/os" + "github.com/cometbft/cometbft/privval" + tmtypes "github.com/cometbft/cometbft/types" ) type Config struct { diff --git a/core/tendermint/print.go b/core/tendermint/print.go index 67dee7e094..99d6d66d4f 100644 --- a/core/tendermint/print.go +++ b/core/tendermint/print.go @@ -18,7 +18,7 @@ package tendermint import ( "fmt" - tmjson "github.com/tendermint/tendermint/libs/json" + tmjson "github.com/cometbft/cometbft/libs/json" ) func Prettify(v interface{}) (string, error) { diff --git a/core/types/snapshot.go b/core/types/snapshot.go index 85ecf2ab73..87f52ad3a6 100644 --- a/core/types/snapshot.go +++ b/core/types/snapshot.go @@ -25,8 +25,8 @@ import ( "code.vegaprotocol.io/vega/libs/proto" snapshot "code.vegaprotocol.io/vega/protos/vega/snapshot/v1" + tmtypes "github.com/cometbft/cometbft/abci/types" "github.com/cosmos/iavl" - tmtypes "github.com/tendermint/tendermint/abci/types" ) // StateProvider - not a huge fan of this interface being here, but it ensures that the state providers diff --git a/core/types/snapshot_nodes.go b/core/types/snapshot_nodes.go index 0ee7383f64..0f86101da0 100644 --- a/core/types/snapshot_nodes.go +++ b/core/types/snapshot_nodes.go @@ -88,7 +88,6 @@ type PayloadProofOfWork struct { HeightToTx map[uint64][]string HeightToTid map[uint64][]string HeightToNonceRef map[uint64][]*snapshot.NonceRef - BannedParties map[string]int64 ActiveParams []*snapshot.ProofOfWorkParams ActiveStates []*snapshot.ProofOfWorkState LastPruningBlock uint64 @@ -3790,11 +3789,6 @@ type PartyCount struct { Count uint64 } -type BannedParty struct { - Party string - Until int64 -} - type BlockRejectStats struct { Total uint64 Rejected uint64 @@ -3811,18 +3805,15 @@ type PayloadSimpleSpamPolicy struct { type SimpleSpamPolicy struct { PolicyName string PartyToCount []*PartyCount - BannedParty []*BannedParty CurrentEpochSeq uint64 } type VoteSpamPolicy struct { PartyProposalVoteCount []*PartyProposalVoteCount - BannedParty []*BannedParty RecentBlocksRejectStats []*BlockRejectStats CurrentBlockIndex uint64 LastIncreaseBlock uint64 CurrentEpochSeq uint64 - MinVotingTokensFactor *num.Uint } func PayloadSimpleSpamPolicyFromProto(ssp *snapshot.Payload_SimpleSpamPolicy) *PayloadSimpleSpamPolicy { @@ -3843,15 +3834,9 @@ func SimpleSpamPolicyFromProto(ssp *snapshot.SimpleSpamPolicy) *SimpleSpamPolicy partyCount = append(partyCount, PartyCountFromProto(ptv)) } - bannedParties := make([]*BannedParty, 0, len(ssp.BannedParties)) - for _, ban := range ssp.BannedParties { - bannedParties = append(bannedParties, BannedPartyFromProto(ban)) - } - return &SimpleSpamPolicy{ PolicyName: ssp.PolicyName, PartyToCount: partyCount, - BannedParty: bannedParties, CurrentEpochSeq: ssp.CurrentEpochSeq, } } @@ -3862,26 +3847,17 @@ func VoteSpamPolicyFromProto(vsp *snapshot.VoteSpamPolicy) *VoteSpamPolicy { partyProposalVoteCount = append(partyProposalVoteCount, PartyProposalVoteCountFromProto(ptv)) } - bannedParties := make([]*BannedParty, 0, len(vsp.BannedParties)) - for _, ban := range vsp.BannedParties { - bannedParties = append(bannedParties, BannedPartyFromProto(ban)) - } - recentBlocksRejectStats := make([]*BlockRejectStats, 0, len(vsp.RecentBlocksRejectStats)) for _, rejects := range vsp.RecentBlocksRejectStats { recentBlocksRejectStats = append(recentBlocksRejectStats, BlockRejectStatsFromProto(rejects)) } - minTokensFactor, _ := num.UintFromString(vsp.MinVotingTokensFactor, 10) - return &VoteSpamPolicy{ PartyProposalVoteCount: partyProposalVoteCount, - BannedParty: bannedParties, RecentBlocksRejectStats: recentBlocksRejectStats, LastIncreaseBlock: vsp.LastIncreaseBlock, CurrentBlockIndex: vsp.CurrentBlockIndex, CurrentEpochSeq: vsp.CurrentEpochSeq, - MinVotingTokensFactor: minTokensFactor, } } @@ -3907,13 +3883,6 @@ func PartyTokenBalanceFromProto(balance *snapshot.PartyTokenBalance) *PartyToken } } -func BannedPartyFromProto(ban *snapshot.BannedParty) *BannedParty { - return &BannedParty{ - Party: ban.Party, - Until: ban.Until, - } -} - func PartyProposalVoteCountFromProto(ppvc *snapshot.PartyProposalVoteCount) *PartyProposalVoteCount { return &PartyProposalVoteCount{ Party: ppvc.Party, @@ -3937,13 +3906,6 @@ func (p *PartyProposalVoteCount) IntoProto() *snapshot.PartyProposalVoteCount { } } -func (b *BannedParty) IntoProto() *snapshot.BannedParty { - return &snapshot.BannedParty{ - Party: b.Party, - Until: b.Until, - } -} - func (ptc *PartyTokenBalance) IntoProto() *snapshot.PartyTokenBalance { return &snapshot.PartyTokenBalance{ Party: ptc.Party, @@ -3957,15 +3919,9 @@ func (ssp *SimpleSpamPolicy) IntoProto() *snapshot.SimpleSpamPolicy { partyToCount = append(partyToCount, &snapshot.SpamPartyTransactionCount{Party: pc.Party, Count: pc.Count}) } - bannedParties := make([]*snapshot.BannedParty, 0, len(ssp.BannedParty)) - for _, ban := range ssp.BannedParty { - bannedParties = append(bannedParties, ban.IntoProto()) - } - return &snapshot.SimpleSpamPolicy{ PolicyName: ssp.PolicyName, PartyToCount: partyToCount, - BannedParties: bannedParties, CurrentEpochSeq: ssp.CurrentEpochSeq, } } @@ -3976,23 +3932,16 @@ func (vsp *VoteSpamPolicy) IntoProto() *snapshot.VoteSpamPolicy { partyProposalVoteCount = append(partyProposalVoteCount, ptv.IntoProto()) } - bannedParties := make([]*snapshot.BannedParty, 0, len(vsp.BannedParty)) - for _, ban := range vsp.BannedParty { - bannedParties = append(bannedParties, ban.IntoProto()) - } - recentBlocksRejectStats := make([]*snapshot.BlockRejectStats, 0, len(vsp.RecentBlocksRejectStats)) for _, rejects := range vsp.RecentBlocksRejectStats { recentBlocksRejectStats = append(recentBlocksRejectStats, rejects.IntoProto()) } return &snapshot.VoteSpamPolicy{ PartyToVote: partyProposalVoteCount, - BannedParties: bannedParties, RecentBlocksRejectStats: recentBlocksRejectStats, LastIncreaseBlock: vsp.LastIncreaseBlock, CurrentBlockIndex: vsp.CurrentBlockIndex, CurrentEpochSeq: vsp.CurrentEpochSeq, - MinVotingTokensFactor: vsp.MinVotingTokensFactor.String(), } } @@ -4694,7 +4643,6 @@ func PayloadProofOfWorkFromProto(s *snapshot.Payload_ProofOfWork) *PayloadProofO pow := &PayloadProofOfWork{ BlockHeight: s.ProofOfWork.BlockHeight, BlockHash: s.ProofOfWork.BlockHash, - BannedParties: make(map[string]int64, len(s.ProofOfWork.Banned)), HeightToTx: make(map[uint64][]string, len(s.ProofOfWork.TxAtHeight)), HeightToTid: make(map[uint64][]string, len(s.ProofOfWork.TidAtHeight)), HeightToNonceRef: make(map[uint64][]*snapshot.NonceRef, len(s.ProofOfWork.NonceRefsAtHeight)), @@ -4703,9 +4651,6 @@ func PayloadProofOfWorkFromProto(s *snapshot.Payload_ProofOfWork) *PayloadProofO LastPruningBlock: s.ProofOfWork.LastPruningBlock, } - for _, bp := range s.ProofOfWork.Banned { - pow.BannedParties[bp.Party] = bp.Until - } for _, tah := range s.ProofOfWork.TxAtHeight { pow.HeightToTx[tah.Height] = tah.Transactions } @@ -4719,12 +4664,6 @@ func PayloadProofOfWorkFromProto(s *snapshot.Payload_ProofOfWork) *PayloadProofO } func (p *PayloadProofOfWork) IntoProto() *snapshot.Payload_ProofOfWork { - banned := make([]*snapshot.BannedParty, 0, len(p.BannedParties)) - for k, v := range p.BannedParties { - banned = append(banned, &snapshot.BannedParty{Party: k, Until: v}) - } - sort.Slice(banned, func(i, j int) bool { return banned[i].Party < banned[j].Party }) - txAtHeight := make([]*snapshot.TransactionsAtHeight, 0, len(p.HeightToTx)) for k, v := range p.HeightToTx { txAtHeight = append(txAtHeight, &snapshot.TransactionsAtHeight{Height: k, Transactions: v}) @@ -4746,7 +4685,6 @@ func (p *PayloadProofOfWork) IntoProto() *snapshot.Payload_ProofOfWork { ProofOfWork: &snapshot.ProofOfWork{ BlockHeight: p.BlockHeight, BlockHash: p.BlockHash, - Banned: banned, TxAtHeight: txAtHeight, TidAtHeight: tidAtHeight, PowParams: p.ActiveParams, diff --git a/core/types/snapshot_nodes_test.go b/core/types/snapshot_nodes_test.go index 8a355d90bd..b202aaae8a 100644 --- a/core/types/snapshot_nodes_test.go +++ b/core/types/snapshot_nodes_test.go @@ -542,9 +542,7 @@ func getDummyData() *types.Chunk { }, }, &types.Payload{ Data: &types.PayloadVoteSpamPolicy{ - VoteSpamPolicy: &types.VoteSpamPolicy{ - MinVotingTokensFactor: num.UintZero(), - }, + VoteSpamPolicy: &types.VoteSpamPolicy{}, }, }, &types.Payload{ Data: &types.PayloadSimpleSpamPolicy{ @@ -717,9 +715,7 @@ func TestPayloadConversion(t *testing.T) { }, }, &types.Payload{ Data: &types.PayloadVoteSpamPolicy{ - VoteSpamPolicy: &types.VoteSpamPolicy{ - MinVotingTokensFactor: num.UintZero(), - }, + VoteSpamPolicy: &types.VoteSpamPolicy{}, }, }, &types.Payload{ Data: &types.PayloadSimpleSpamPolicy{ diff --git a/core/validators/topology.go b/core/validators/topology.go index 42de3eb0ad..6474885fc9 100644 --- a/core/validators/topology.go +++ b/core/validators/topology.go @@ -36,8 +36,8 @@ import ( commandspb "code.vegaprotocol.io/vega/protos/vega/commands/v1" v1 "code.vegaprotocol.io/vega/protos/vega/snapshot/v1" + abcitypes "github.com/cometbft/cometbft/abci/types" "github.com/ethereum/go-ethereum/common" - abcitypes "github.com/tendermint/tendermint/abci/types" "golang.org/x/exp/maps" ) @@ -449,7 +449,7 @@ func (t *Topology) NumberOfTendermintValidators() uint { return count } -func (t *Topology) BeginBlock(ctx context.Context, req abcitypes.RequestBeginBlock) { +func (t *Topology) BeginBlock(ctx context.Context, blockHeight uint64, proposer string) { // we're not adding or removing nodes only potentially changing their state so should be safe t.mu.RLock() defer t.mu.RUnlock() @@ -460,8 +460,8 @@ func (t *Topology) BeginBlock(ctx context.Context, req abcitypes.RequestBeginBlo t.rng = rand.New(rand.NewSource(currentTime.Unix())) t.checkHeartbeat(ctx) - t.validatorPerformance.BeginBlock(ctx, hex.EncodeToString(req.Header.ProposerAddress)) - t.currentBlockHeight = uint64(req.Header.Height) + t.validatorPerformance.BeginBlock(ctx, proposer) + t.currentBlockHeight = blockHeight t.signatures.SetNonce(currentTime) t.signatures.ClearStaleSignatures() diff --git a/core/validators/topology_checkpoint.go b/core/validators/topology_checkpoint.go index cbb2d87074..344546fa20 100644 --- a/core/validators/topology_checkpoint.go +++ b/core/validators/topology_checkpoint.go @@ -26,7 +26,7 @@ import ( checkpoint "code.vegaprotocol.io/vega/protos/vega/checkpoint/v1" eventspb "code.vegaprotocol.io/vega/protos/vega/events/v1" - tmtypes "github.com/tendermint/tendermint/abci/types" + tmtypes "github.com/cometbft/cometbft/abci/types" ) func (t *Topology) Name() types.CheckpointName { diff --git a/core/validators/topology_checkpoint_test.go b/core/validators/topology_checkpoint_test.go index 877497551c..4b58df9c2a 100644 --- a/core/validators/topology_checkpoint_test.go +++ b/core/validators/topology_checkpoint_test.go @@ -29,8 +29,6 @@ import ( "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" - abcitypes "github.com/tendermint/tendermint/abci/types" - types1 "github.com/tendermint/tendermint/proto/tendermint/types" ) func addTwoNodes(top *testTop) { @@ -183,7 +181,7 @@ func testTopologyCheckpointUsesRelativeBlockHeight(t *testing.T) { var newNetworkBlockHeight uint64 = 100 // set current block height to newNetworkBlockHeight - newTop.BeginBlock(ctx, abcitypes.RequestBeginBlock{Header: types1.Header{Height: int64(newNetworkBlockHeight)}}) + newTop.BeginBlock(ctx, newNetworkBlockHeight, "") newTop.Load(ctx, ckp) diff --git a/core/validators/topology_eth_key_rotate_test.go b/core/validators/topology_eth_key_rotate_test.go index c073b468ec..2eb35254c9 100644 --- a/core/validators/topology_eth_key_rotate_test.go +++ b/core/validators/topology_eth_key_rotate_test.go @@ -28,8 +28,6 @@ import ( "github.com/golang/mock/gomock" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" - abcitypes "github.com/tendermint/tendermint/abci/types" - types1 "github.com/tendermint/tendermint/proto/tendermint/types" ) func TestTopologyEthereumKeyRotate(t *testing.T) { @@ -246,7 +244,7 @@ func testEthereumKeyRotationBeginBlock(t *testing.T) { require.NoError(t, err) // when - top.BeginBlock(ctx, abcitypes.RequestBeginBlock{Header: types1.Header{Height: 11}}) + top.BeginBlock(ctx, 11, "") // then data1 := top.Get("vega-master-pubkey-1") require.NotNil(t, data1) @@ -262,7 +260,7 @@ func testEthereumKeyRotationBeginBlock(t *testing.T) { assert.Equal(t, "eth-address-4", data4.EthereumAddress) // when - top.BeginBlock(ctx, abcitypes.RequestBeginBlock{Header: types1.Header{Height: 13}}) + top.BeginBlock(ctx, 13, "") // then data3 = top.Get("vega-master-pubkey-3") require.NotNil(t, data3) @@ -309,7 +307,7 @@ func TestEthereumKeyRotationBeginBlockWithSubmitter(t *testing.T) { now := time.Unix(666, 666) top.signatures.EXPECT().SetNonce(now).Times(1) top.timeService.EXPECT().GetTimeNow().Times(5).Return(now) - top.BeginBlock(ctx, abcitypes.RequestBeginBlock{Header: types1.Header{Height: 11}}) + top.BeginBlock(ctx, 11, "") // then data1 := top.Get("vega-master-pubkey-1") @@ -327,7 +325,7 @@ func TestEthereumKeyRotationBeginBlockWithSubmitter(t *testing.T) { now = now.Add(time.Second) top.signatures.EXPECT().SetNonce(now).Times(1) top.timeService.EXPECT().GetTimeNow().Times(5).Return(now) - top.BeginBlock(ctx, abcitypes.RequestBeginBlock{Header: types1.Header{Height: 140}}) + top.BeginBlock(ctx, 140, "") // try to submit again err = top.ProcessEthereumKeyRotation(ctx, "vega-key-1", newEthereumKeyRotationSubmission("new-eth-address-1", "new-eth-address-2", 150, submitter), MockVerify) @@ -391,7 +389,7 @@ func getTestTopWithMockedSignatures(t *testing.T) *testTopWithSignatures { signatures.EXPECT().ClearStaleSignatures().Times(1) signatures.EXPECT().SetNonce(gomock.Any()).Times(1) signatures.EXPECT().OfferSignatures().AnyTimes() - top.BeginBlock(context.Background(), abcitypes.RequestBeginBlock{Header: types1.Header{Height: 10}}) + top.BeginBlock(context.Background(), 10, "") return &testTopWithSignatures{ testTop: top, diff --git a/core/validators/topology_snapshot.go b/core/validators/topology_snapshot.go index 370902dc30..812be593e4 100644 --- a/core/validators/topology_snapshot.go +++ b/core/validators/topology_snapshot.go @@ -31,7 +31,7 @@ import ( eventspb "code.vegaprotocol.io/vega/protos/vega/events/v1" snapshot "code.vegaprotocol.io/vega/protos/vega/snapshot/v1" - tmtypes "github.com/tendermint/tendermint/abci/types" + tmtypes "github.com/cometbft/cometbft/abci/types" ) var ( @@ -320,7 +320,7 @@ func (t *Topology) restore(ctx context.Context, topology *types.Topology, p *typ t.log.Panic("failed to restore current block-height from context", logging.Error(err)) } - t.currentBlockHeight = uint64(bh) + t.currentBlockHeight = bh t.validatorPowerUpdates = vUpdates t.chainValidators = topology.ChainValidators[:] t.restorePendingKeyRotations(topology.PendingPubKeyRotations) diff --git a/core/validators/topology_snapshot_test.go b/core/validators/topology_snapshot_test.go index cfe5c00d44..52018f141b 100644 --- a/core/validators/topology_snapshot_test.go +++ b/core/validators/topology_snapshot_test.go @@ -18,6 +18,7 @@ package validators_test import ( "bytes" "context" + "encoding/hex" "testing" "code.vegaprotocol.io/vega/core/types" @@ -30,8 +31,6 @@ import ( "github.com/golang/mock/gomock" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" - abcitypes "github.com/tendermint/tendermint/abci/types" - types1 "github.com/tendermint/tendermint/proto/tendermint/types" ) var topKey = (&types.PayloadTopology{}).Key() @@ -164,10 +163,8 @@ func TestTopologySnapshot(t *testing.T) { func updateValidatorPerformanceToNonDefaultState(t *testing.T, top *validators.Topology) { t.Helper() - req1 := abcitypes.RequestBeginBlock{Header: types1.Header{ProposerAddress: address1, Height: int64(1)}} - top.BeginBlock(context.Background(), req1) + top.BeginBlock(context.Background(), 1, hex.EncodeToString(address1)) // expecting address1 to propose but got address3 - req2 := abcitypes.RequestBeginBlock{Header: types1.Header{ProposerAddress: address3, Height: int64(1)}} - top.BeginBlock(context.Background(), req2) + top.BeginBlock(context.Background(), 1, hex.EncodeToString(address3)) } diff --git a/core/validators/topology_test.go b/core/validators/topology_test.go index 4cb87080e8..5d18e1ad89 100644 --- a/core/validators/topology_test.go +++ b/core/validators/topology_test.go @@ -38,8 +38,6 @@ import ( "github.com/stretchr/testify/assert" "github.com/stretchr/testify/mock" "github.com/stretchr/testify/require" - abcitypes "github.com/tendermint/tendermint/abci/types" - types1 "github.com/tendermint/tendermint/proto/tendermint/types" ) var tmPubKey = "tm-pub-key" @@ -700,7 +698,7 @@ func testBeginBlockSuccess(t *testing.T) { assert.NoError(t, err) // when - top.BeginBlock(ctx, abcitypes.RequestBeginBlock{Header: types1.Header{Height: 11}}) + top.BeginBlock(ctx, 11, "") // then data1 := top.Get("vega-master-pubkey-1") assert.NotNil(t, data1) @@ -716,7 +714,7 @@ func testBeginBlockSuccess(t *testing.T) { assert.Equal(t, hex.EncodeToString([]byte("vega-key-4")), data4.VegaPubKey) // when - top.BeginBlock(ctx, abcitypes.RequestBeginBlock{Header: types1.Header{Height: 13}}) + top.BeginBlock(ctx, 13, "") // then data3 = top.Get("vega-master-pubkey-3") assert.NotNil(t, data3) @@ -774,7 +772,7 @@ func testBeginBlockNotifyKeyChange(t *testing.T) { top.NotifyOnKeyChange(c1.Call, c2.Call) // when - top.BeginBlock(ctx, abcitypes.RequestBeginBlock{Header: types1.Header{Height: 11}}) + top.BeginBlock(ctx, 11, "") // then c1.AssertExpectations(t) diff --git a/core/validators/validator_performance.go b/core/validators/validator_performance.go index a9861d837c..cf3cd7ddd8 100644 --- a/core/validators/validator_performance.go +++ b/core/validators/validator_performance.go @@ -24,7 +24,7 @@ import ( "code.vegaprotocol.io/vega/libs/num" "code.vegaprotocol.io/vega/logging" - "github.com/tendermint/tendermint/crypto/sr25519" + "github.com/cometbft/cometbft/crypto/sr25519" ) var ( diff --git a/core/validators/validator_set.go b/core/validators/validator_set.go index f0b86bc13f..54b885c3cf 100644 --- a/core/validators/validator_set.go +++ b/core/validators/validator_set.go @@ -28,8 +28,8 @@ import ( "code.vegaprotocol.io/vega/logging" proto "code.vegaprotocol.io/vega/protos/vega" - tmtypes "github.com/tendermint/tendermint/abci/types" - "github.com/tendermint/tendermint/crypto/encoding" + tmtypes "github.com/cometbft/cometbft/abci/types" + "github.com/cometbft/cometbft/crypto/encoding" ) var ( diff --git a/datanode/broker/sqlstore_broker_test.go b/datanode/broker/sqlstore_broker_test.go index 933de426b6..fe69dc7c8e 100644 --- a/datanode/broker/sqlstore_broker_test.go +++ b/datanode/broker/sqlstore_broker_test.go @@ -594,7 +594,7 @@ func (t *testSQLBrokerSubscriber) Types() []events.Type { type blockEventSource struct { vegaTime time.Time - blockHeight int64 + blockHeight uint64 } func newBlockEventSource() *blockEventSource { @@ -609,7 +609,7 @@ func (s *blockEventSource) NextBeginBlockEvent() *events.BeginBlock { ctx = vgcontext.WithBlockHeight(ctx, s.blockHeight) event := events.NewBeginBlock(ctx, eventsv1.BeginBlock{ - Height: uint64(s.blockHeight), + Height: s.blockHeight, Timestamp: s.vegaTime.UnixNano(), }) @@ -621,7 +621,7 @@ func (s *blockEventSource) NextEndBlockEvent() *events.EndBlock { ctx = vgcontext.WithBlockHeight(ctx, s.blockHeight) event := events.NewEndBlock(ctx, eventsv1.EndBlock{ - Height: uint64(s.blockHeight), + Height: s.blockHeight, }) s.vegaTime = s.vegaTime.Add(1 * time.Second) diff --git a/go.mod b/go.mod index 269143e00e..4fcea83f5f 100644 --- a/go.mod +++ b/go.mod @@ -9,7 +9,7 @@ require ( github.com/cosmos/iavl v0.20.0 github.com/cucumber/godog v0.12.5 github.com/ethereum/go-ethereum v1.11.6 - github.com/fatih/color v1.13.0 + github.com/fatih/color v1.15.0 github.com/fsnotify/fsnotify v1.6.0 github.com/golang/mock v1.6.1-0.20220512030613-73266f9366fc github.com/golang/protobuf v1.5.3 @@ -18,15 +18,15 @@ require ( github.com/holiman/uint256 v1.2.2-0.20230321075855-87b91420868c github.com/imdario/mergo v0.3.13 github.com/jessevdk/go-flags v1.4.0 - github.com/jinzhu/copier v0.2.8 + github.com/jinzhu/copier v0.3.5 github.com/julienschmidt/httprouter v1.3.0 github.com/mattn/go-isatty v0.0.18 github.com/pkg/errors v0.9.1 github.com/prometheus/client_golang v1.14.0 - github.com/rs/cors v1.8.2 + github.com/rs/cors v1.8.3 github.com/satori/go.uuid v1.2.0 github.com/shopspring/decimal v1.3.1 - github.com/spf13/afero v1.8.2 // indirect + github.com/spf13/afero v1.9.3 // indirect github.com/spf13/cobra v1.6.1 github.com/spf13/pflag v1.0.5 // indirect github.com/stretchr/testify v1.8.2 @@ -47,6 +47,7 @@ require ( github.com/adrg/xdg v0.4.0 github.com/blang/semver/v4 v4.0.0 github.com/cenkalti/backoff/v4 v4.2.0 + github.com/cometbft/cometbft v0.38.0 github.com/cometbft/cometbft-db v0.7.0 github.com/cucumber/messages-go/v16 v16.0.1 github.com/dgraph-io/badger/v2 v2.2007.4 @@ -78,12 +79,11 @@ require ( github.com/muesli/cancelreader v0.2.2 github.com/muesli/termenv v0.11.0 github.com/multiformats/go-multiaddr v0.9.0 - github.com/oasisprotocol/curve25519-voi v0.0.0-20220317090546-adb2f9614b17 + github.com/oasisprotocol/curve25519-voi v0.0.0-20220708102147-0a8a51822cae github.com/pbnjay/memory v0.0.0-20210728143218-7b4eea64cf58 github.com/pressly/goose/v3 v3.6.1 github.com/sirupsen/logrus v1.9.0 github.com/soheilhy/cmux v0.1.4 - github.com/tendermint/tendermint v0.35.9 github.com/tmc/grpc-websocket-proxy v0.0.0-20220101234140-673ab2c3ae75 github.com/tyler-smith/go-bip39 v1.1.0 github.com/urfave/cli/v2 v2.17.2-0.20221006022127-8f469abc00aa @@ -100,10 +100,8 @@ require ( bazil.org/fuse v0.0.0-20200117225306-7b5117fecadc // indirect contrib.go.opencensus.io/exporter/prometheus v0.4.2 // indirect github.com/AndreasBriese/bbloom v0.0.0-20190825152654-46b345b51c96 // indirect - github.com/ChainSafe/go-schnorrkel v1.0.0 // indirect github.com/DataDog/zstd v1.5.2 // indirect github.com/VictoriaMetrics/fastcache v1.6.0 // indirect - github.com/Workiva/go-datastructures v1.0.53 // indirect github.com/alecthomas/units v0.0.0-20211218093645-b94a6e3cc137 // indirect github.com/alexbrainman/goissue34681 v0.0.0-20191006012335-3fc7a47baff5 // indirect github.com/bahlo/generic-list-go v0.2.0 // indirect @@ -115,10 +113,9 @@ require ( github.com/cockroachdb/redact v1.1.3 // indirect github.com/containerd/cgroups v1.1.0 // indirect github.com/coreos/go-systemd/v22 v22.5.0 // indirect - github.com/cosmos/go-bip39 v0.0.0-20180819234021-555e2067c45d // indirect + github.com/cosmos/gogoproto v1.4.6 // indirect github.com/cpuguy83/go-md2man/v2 v2.0.2 // indirect github.com/crackcomm/go-gitignore v0.0.0-20170627025303-887ab5e44cc3 // indirect - github.com/creachadair/taskgroup v0.3.2 // indirect github.com/cskr/pubsub v1.0.2 // indirect github.com/davidlazar/go-crypto v0.0.0-20200604182044-b73af7476f6c // indirect github.com/deckarep/golang-set/v2 v2.1.0 // indirect @@ -135,19 +132,18 @@ require ( github.com/gballet/go-libpcsclite v0.0.0-20190607065134-2772fd86a8ff // indirect github.com/getsentry/sentry-go v0.18.0 // indirect github.com/go-kit/log v0.2.1 // indirect - github.com/go-logfmt/logfmt v0.5.1 // indirect + github.com/go-logfmt/logfmt v0.6.0 // indirect github.com/go-logr/logr v1.2.3 // indirect github.com/go-logr/stdr v1.2.2 // indirect github.com/go-pkgz/expirable-cache v0.1.0 // indirect github.com/go-task/slim-sprig v0.0.0-20230315185526-52ccab3ef572 // indirect github.com/godbus/dbus/v5 v5.1.0 // indirect github.com/gofrs/flock v0.8.1 // indirect + github.com/golang/glog v1.1.0 // indirect github.com/golang/groupcache v0.0.0-20210331224755-41bb18bfe9da // indirect github.com/google/go-querystring v1.1.0 // indirect github.com/google/gopacket v1.1.19 // indirect github.com/google/pprof v0.0.0-20230405160723-4a4c7d95572b // indirect - github.com/gtank/merlin v0.1.1 // indirect - github.com/gtank/ristretto255 v0.1.2 // indirect github.com/hannahhoward/go-pubsub v0.0.0-20200423002714-8d62886cc36e // indirect github.com/hashicorp/errwrap v1.1.0 // indirect github.com/hashicorp/go-multierror v1.1.1 // indirect @@ -219,7 +215,6 @@ require ( github.com/miekg/dns v1.1.53 // indirect github.com/mikioh/tcpinfo v0.0.0-20190314235526-30a79bb1804b // indirect github.com/mikioh/tcpopt v0.0.0-20190314235656-172688c1accc // indirect - github.com/mimoo/StrobeGo v0.0.0-20210601165009-122bf33a46e0 // indirect github.com/minio/sha256-simd v1.0.0 // indirect github.com/mitchellh/go-homedir v1.1.0 // indirect github.com/mr-tron/base58 v1.2.0 // indirect @@ -291,15 +286,15 @@ require ( github.com/armon/go-radix v1.0.0 // indirect github.com/benbjohnson/clock v1.3.0 // indirect github.com/beorn7/perks v1.0.1 // indirect - github.com/btcsuite/btcd/btcec/v2 v2.2.1 // indirect + github.com/btcsuite/btcd/btcec/v2 v2.3.2 // indirect github.com/cespare/xxhash v1.1.0 // indirect github.com/cespare/xxhash/v2 v2.2.0 // indirect github.com/confio/ics23/go v0.9.0 // indirect github.com/cucumber/gherkin-go/v19 v19.0.3 // indirect github.com/davecgh/go-spew v1.1.1 // indirect github.com/decred/dcrd/dcrec/secp256k1/v4 v4.1.0 // indirect - github.com/dgraph-io/ristretto v0.0.3-0.20200630154024-f66de99634de // indirect - github.com/dgryski/go-farm v0.0.0-20190423205320-6a90982ecee2 // indirect + github.com/dgraph-io/ristretto v0.1.1 // indirect + github.com/dgryski/go-farm v0.0.0-20200201041132-a6ae2369ad13 // indirect github.com/dustin/go-humanize v1.0.1 github.com/elastic/go-licenser v0.3.1 // indirect github.com/elastic/go-sysinfo v1.1.1 // indirect @@ -308,7 +303,7 @@ require ( github.com/go-kit/kit v0.12.0 // indirect github.com/go-ole/go-ole v1.2.6 // indirect github.com/go-stack/stack v1.8.1 // indirect - github.com/gofrs/uuid v4.3.0+incompatible // indirect + github.com/gofrs/uuid v4.4.0+incompatible // indirect github.com/gogo/protobuf v1.3.2 github.com/golang/snappy v0.0.5-0.20220116011046-fa5810519dcb // indirect github.com/google/orderedcode v0.0.1 // indirect @@ -318,7 +313,7 @@ require ( github.com/hashicorp/go-immutable-radix v1.3.1 // indirect github.com/hashicorp/go-memdb v1.3.0 // indirect github.com/hashicorp/hcl v1.0.0 // indirect - github.com/inconshreveable/mousetrap v1.0.1 // indirect + github.com/inconshreveable/mousetrap v1.1.0 // indirect github.com/jackc/chunkreader/v2 v2.0.1 // indirect github.com/jackc/pgio v1.0.0 // indirect github.com/jackc/pgpassfile v1.0.0 // indirect @@ -328,16 +323,15 @@ require ( github.com/jhump/protoreflect v1.12.1-0.20220721211354-060cc04fc18b // indirect github.com/jmhodges/levigo v1.0.0 // indirect github.com/joeshaw/multierror v0.0.0-20140124173710-69b34d4ec901 // indirect - github.com/lib/pq v1.10.6 // indirect + github.com/lib/pq v1.10.7 // indirect github.com/libp2p/go-buffer-pool v0.1.0 // indirect github.com/lucasb-eyer/go-colorful v1.2.0 // indirect - github.com/magiconair/properties v1.8.6 // indirect + github.com/magiconair/properties v1.8.7 // indirect github.com/mattn/go-colorable v0.1.13 // indirect github.com/mattn/go-runewidth v0.0.13 // indirect github.com/matttproud/golang_protobuf_extensions v1.0.4 // indirect github.com/minio/highwayhash v1.0.2 // indirect - github.com/pelletier/go-toml v1.9.5 // indirect - github.com/pelletier/go-toml/v2 v2.0.5 // indirect + github.com/pelletier/go-toml/v2 v2.0.6 // indirect github.com/petermattis/goid v0.0.0-20180202154549-b0b1615b78e5 // indirect github.com/pmezard/go-difflib v1.0.0 // indirect github.com/prometheus/client_model v0.3.0 // indirect @@ -350,9 +344,9 @@ require ( github.com/shirou/gopsutil v3.21.4-0.20210419000835-c7a38de76ee5+incompatible // indirect github.com/spf13/cast v1.5.0 // indirect github.com/spf13/jwalterweatherman v1.1.0 // indirect - github.com/spf13/viper v1.13.0 + github.com/spf13/viper v1.15.0 github.com/stretchr/objx v0.5.0 // indirect - github.com/subosito/gotenv v1.4.1 // indirect + github.com/subosito/gotenv v1.4.2 // indirect github.com/tklauser/go-sysconf v0.3.10 // indirect github.com/tklauser/numcpus v0.4.0 // indirect github.com/xi2/xz v0.0.0-20171230120015-48954b6210f8 // indirect @@ -381,6 +375,4 @@ replace ( github.com/fergusstrange/embedded-postgres => github.com/vegaprotocol/embedded-postgres v1.13.1-0.20221123183204-2e7a2feee5bb github.com/muesli/cancelreader => github.com/vegaprotocol/cancelreader v0.0.0-20230724130739-6f2217a69449 github.com/shopspring/decimal => github.com/vegaprotocol/decimal v1.3.1-uint256 - github.com/tendermint/tendermint => github.com/vegaprotocol/cometbft v0.34.29-patch.1 - github.com/tendermint/tm-db => github.com/cometbft/cometbft-db v0.6.7 ) diff --git a/go.sum b/go.sum index d1152e8aa6..d1da7d96c5 100644 --- a/go.sum +++ b/go.sum @@ -56,14 +56,12 @@ github.com/99designs/gqlgen v0.17.20/go.mod h1:Mja2HI23kWT1VRH09hvWshFgOzKswpO20 github.com/AndreasBriese/bbloom v0.0.0-20190306092124-e2d15f34fcf9/go.mod h1:bOvUY6CB00SOBii9/FifXqc0awNKxLFCL/+pkDPuyl8= github.com/AndreasBriese/bbloom v0.0.0-20190825152654-46b345b51c96 h1:cTp8I5+VIoKjsnZuH8vjyaysT/ses3EvZeaV/1UkF2M= github.com/AndreasBriese/bbloom v0.0.0-20190825152654-46b345b51c96/go.mod h1:bOvUY6CB00SOBii9/FifXqc0awNKxLFCL/+pkDPuyl8= -github.com/Azure/go-ansiterm v0.0.0-20210617225240-d185dfc1b5a1 h1:UQHMgLO+TxOElx5B5HZ4hJQsoJ/PvUvKRhJHDQXO8P8= +github.com/Azure/go-ansiterm v0.0.0-20230124172434-306776ec8161 h1:L/gRVlceqvL25UVaW/CKtUDjefjrs0SPonmDGUVOYP0= github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU= github.com/BurntSushi/toml v1.1.0/go.mod h1:CxXYINrC8qIiEnFrOxCa7Jy5BFHlXnUU2pbicEuybxQ= github.com/BurntSushi/toml v1.2.1 h1:9F2/+DoOYIOksmaJFPw1tGFy1eDnIJXg+UHjuD8lTak= github.com/BurntSushi/toml v1.2.1/go.mod h1:CxXYINrC8qIiEnFrOxCa7Jy5BFHlXnUU2pbicEuybxQ= github.com/BurntSushi/xgb v0.0.0-20160522181843-27f122750802/go.mod h1:IVnqGOEym/WlBOVXweHU+Q+/VP0lqqI8lqeDx9IjBqo= -github.com/ChainSafe/go-schnorrkel v1.0.0 h1:3aDA67lAykLaG1y3AOjs88dMxC88PgUuHRrLeDnvGIM= -github.com/ChainSafe/go-schnorrkel v1.0.0/go.mod h1:dpzHYVxLZcp8pjlV+O+UR8K0Hp/z7vcchBSbMBEhCw4= github.com/CloudyKit/fastprinter v0.0.0-20200109182630-33d98a066a53/go.mod h1:+3IMCy2vIlbG1XG/0ggNQv0SvxCAIpPM5b1nCz56Xno= github.com/CloudyKit/jet/v3 v3.0.0/go.mod h1:HKQPgSJmdK8hdoAbKUUWajkHyHo4RaU5rMdUywE7VMo= github.com/DataDog/zstd v1.5.2 h1:vUG4lAyuPCXO0TLbXvPv7EB7cNK1QV/luu55UHLrrn8= @@ -88,8 +86,6 @@ github.com/StackExchange/wmi v1.2.1/go.mod h1:rcmrprowKIVzvc+NUiLncP2uuArMWLCbu9 github.com/VictoriaMetrics/fastcache v1.6.0 h1:C/3Oi3EiBCqufydp1neRZkqcwmEiuRT9c3fqvvgKm5o= github.com/VictoriaMetrics/fastcache v1.6.0/go.mod h1:0qHz5QP0GMX4pfmMA/zt5RgfNuXJrTP0zS7DqpHGGTw= github.com/VividCortex/gohistogram v1.0.0 h1:6+hBz+qvs0JOrrNhhmR7lFxo5sINxBCGXrdtl/UvroE= -github.com/Workiva/go-datastructures v1.0.53 h1:J6Y/52yX10Xc5JjXmGtWoSSxs3mZnGSaq37xZZh7Yig= -github.com/Workiva/go-datastructures v1.0.53/go.mod h1:1yZL+zfsztete+ePzZz/Zb1/t5BnDuE2Ya2MMGhzP6A= github.com/adlio/schema v1.3.3 h1:oBJn8I02PyTB466pZO1UZEn1TV5XLlifBSyMrmHl/1I= github.com/adrg/xdg v0.4.0 h1:RzRqFcjH4nE5C6oTAxhBtoE2IRyjBSa62SCbyPidvls= github.com/adrg/xdg v0.4.0/go.mod h1:N6ag73EX4wyxeaoeHctc1mas01KZgsj5tYiAIwqJE/E= @@ -144,10 +140,10 @@ github.com/btcsuite/btcd v0.23.3 h1:4KH/JKy9WiCd+iUS9Mu0Zp7Dnj17TGdKrg9xc/FGj24= github.com/btcsuite/btcd v0.23.3/go.mod h1:0QJIIN1wwIXF/3G/m87gIwGniDMDQqjVn4SZgnFpsYY= github.com/btcsuite/btcd/btcec/v2 v2.1.0/go.mod h1:2VzYrv4Gm4apmbVVsSq5bqf1Ec8v56E48Vt0Y/umPgA= github.com/btcsuite/btcd/btcec/v2 v2.1.3/go.mod h1:ctjw4H1kknNJmRN4iP1R7bTQ+v3GJkZBd6mui8ZsAZE= -github.com/btcsuite/btcd/btcec/v2 v2.2.1 h1:xP60mv8fvp+0khmrN0zTdPC3cNm24rfeE6lh2R/Yv3E= -github.com/btcsuite/btcd/btcec/v2 v2.2.1/go.mod h1:9/CSmJxmuvqzX9Wh2fXMWToLOHhPd11lSPuIupwTkI8= +github.com/btcsuite/btcd/btcec/v2 v2.3.2 h1:5n0X6hX0Zk+6omWcihdYvdAlGf2DfasC0GMf7DClJ3U= +github.com/btcsuite/btcd/btcec/v2 v2.3.2/go.mod h1:zYzJ8etWJQIv1Ogk7OzpWjowwOdXY1W/17j2MW85J04= github.com/btcsuite/btcd/btcutil v1.1.0/go.mod h1:5OapHB7A2hBBWLm48mmw4MOHNJCcUBTwmWH/0Jn8VHE= -github.com/btcsuite/btcd/btcutil v1.1.2 h1:XLMbX8JQEiwMcYft2EGi8zPUkoa0abKIU6/BJSRsjzQ= +github.com/btcsuite/btcd/btcutil v1.1.3 h1:xfbtw8lwpp0G6NwSHb+UE67ryTFHJAiNuipusjXSohQ= github.com/btcsuite/btcd/chaincfg/chainhash v1.0.0/go.mod h1:7SFka0XMvUgj3hfZtydOrQY2mwhPclbT2snogU7SQQc= github.com/btcsuite/btcd/chaincfg/chainhash v1.0.1 h1:q0rUy8C/TYNBQS1+CGKw68tLOFYSNEs0TFnxxnS9+4U= github.com/btcsuite/btcd/chaincfg/chainhash v1.0.1/go.mod h1:7SFka0XMvUgj3hfZtydOrQY2mwhPclbT2snogU7SQQc= @@ -202,6 +198,8 @@ github.com/cockroachdb/pebble v0.0.0-20230209160836-829675f94811/go.mod h1:Nb5lg github.com/cockroachdb/redact v1.1.3 h1:AKZds10rFSIj7qADf0g46UixK8NNLwWTNdCIGS5wfSQ= github.com/cockroachdb/redact v1.1.3/go.mod h1:BVNblN9mBWFyMyqK1k3AAiSxhvhfK2oOZZ2lK+dpvRg= github.com/codegangsta/inject v0.0.0-20150114235600-33e0aa1cb7c0/go.mod h1:4Zcjuz89kmFXt9morQgcfYZAYZ5n8WHjt81YYWIwtTM= +github.com/cometbft/cometbft v0.38.0 h1:ogKnpiPX7gxCvqTEF4ly25/wAxUqf181t30P3vqdpdc= +github.com/cometbft/cometbft v0.38.0/go.mod h1:5Jz0Z8YsHSf0ZaAqGvi/ifioSdVFPtEGrm8Y9T/993k= github.com/cometbft/cometbft-db v0.7.0 h1:uBjbrBx4QzU0zOEnU8KxoDl18dMNgDh+zZRUE0ucsbo= github.com/cometbft/cometbft-db v0.7.0/go.mod h1:yiKJIm2WKrt6x8Cyxtq9YTEcIMPcEe4XPxhgX59Fzf0= github.com/confio/ics23/go v0.9.0 h1:cWs+wdbS2KRPZezoaaj+qBleXgUk5WOQFMP3CQFGTr4= @@ -223,8 +221,8 @@ github.com/coreos/go-systemd/v22 v22.1.0/go.mod h1:xO0FLkIi5MaZafQlIrOotqXZ90ih+ github.com/coreos/go-systemd/v22 v22.5.0 h1:RrqgGjYQKalulkV8NGVIfkXQf6YYmOyiJKk8iXXhfZs= github.com/coreos/go-systemd/v22 v22.5.0/go.mod h1:Y58oyj3AT4RCenI/lSvhwexgC+NSVTIJ3seZv2GcEnc= github.com/coreos/pkg v0.0.0-20180928190104-399ea9e2e55f/go.mod h1:E3G3o1h8I7cfcXa63jLwjI0eiQQMgzzUDFVpN/nH/eA= -github.com/cosmos/go-bip39 v0.0.0-20180819234021-555e2067c45d h1:49RLWk1j44Xu4fjHb6JFYmeUnDORVwHNkDxaQ0ctCVU= -github.com/cosmos/go-bip39 v0.0.0-20180819234021-555e2067c45d/go.mod h1:tSxLoYXyBmiFeKpvmq4dzayMdCjCnu8uqmCysIGBT2Y= +github.com/cosmos/gogoproto v1.4.6 h1:Ee7z15dWJaGlgM2rWrK8N2IX7PQcuccu8oG68jp5RL4= +github.com/cosmos/gogoproto v1.4.6/go.mod h1:VS/ASYmPgv6zkPKLjR9EB91lwbLHOzaGCirmKKhncfI= github.com/cosmos/iavl v0.20.0 h1:fTVznVlepH0KK8NyKq8w+U7c2L6jofa27aFX6YGlm38= github.com/cosmos/iavl v0.20.0/go.mod h1:WO7FyvaZJoH65+HFOsDir7xU9FWk2w9cHXNW1XHcl7A= github.com/cpuguy83/go-md2man v1.0.10/go.mod h1:SmD6nW6nTyfqj6ABTjUi3V3JVMnlJmwcJI5acqYI6dE= @@ -235,8 +233,6 @@ github.com/cpuguy83/go-md2man/v2 v2.0.2 h1:p1EgwI/C7NhT0JmVkwCD2ZBK8j4aeHQX2pMHH github.com/cpuguy83/go-md2man/v2 v2.0.2/go.mod h1:tgQtvFlXSQOSOSIRvRPT7W67SCa46tRHOmNcaadrF8o= github.com/crackcomm/go-gitignore v0.0.0-20170627025303-887ab5e44cc3 h1:HVTnpeuvF6Owjd5mniCL8DEXo7uYXdQEmOP4FJbV5tg= github.com/crackcomm/go-gitignore v0.0.0-20170627025303-887ab5e44cc3/go.mod h1:p1d6YEZWvFzEh4KLyvBcVSnrfNDDvK2zfK/4x2v/4pE= -github.com/creachadair/taskgroup v0.3.2 h1:zlfutDS+5XG40AOxcHDSThxKzns8Tnr9jnr6VqkYlkM= -github.com/creachadair/taskgroup v0.3.2/go.mod h1:wieWwecHVzsidg2CsUnFinW1faVN4+kq+TDlRJQ0Wbk= github.com/creack/pty v1.1.7/go.mod h1:lj5s0c3V2DBrqTV7llrYr5NG6My20zk30Fl46Y7DoTY= github.com/creack/pty v1.1.9/go.mod h1:oKZEueFk5CKHvIhNR5MUki03XCEU+Q6VDXinZuGJ33E= github.com/cskr/pubsub v1.0.2 h1:vlOzMhl6PFn60gRlTQQsIfVwaPB/B/8MziK8FhEPt/0= @@ -268,13 +264,15 @@ github.com/dgraph-io/badger v1.6.2/go.mod h1:JW2yswe3V058sS0kZ2h/AXeDSqFjxnZcRrV github.com/dgraph-io/badger/v2 v2.2007.4 h1:TRWBQg8UrlUhaFdco01nO2uXwzKS7zd+HVdwV/GHc4o= github.com/dgraph-io/badger/v2 v2.2007.4/go.mod h1:vSw/ax2qojzbN6eXHIx6KPKtCSHJN/Uz0X0VPruTIhk= github.com/dgraph-io/ristretto v0.0.2/go.mod h1:KPxhHT9ZxKefz+PCeOGsrHpl1qZ7i70dGTu2u+Ahh6E= -github.com/dgraph-io/ristretto v0.0.3-0.20200630154024-f66de99634de h1:t0UHb5vdojIDUqktM6+xJAfScFBsVpXZmqC9dsgJmeA= github.com/dgraph-io/ristretto v0.0.3-0.20200630154024-f66de99634de/go.mod h1:KPxhHT9ZxKefz+PCeOGsrHpl1qZ7i70dGTu2u+Ahh6E= +github.com/dgraph-io/ristretto v0.1.1 h1:6CWw5tJNgpegArSHpNHJKldNeq03FQCwYvfMVWajOK8= +github.com/dgraph-io/ristretto v0.1.1/go.mod h1:S1GPSBCYCIhmVNfcth17y2zZtQT6wzkzgwUve0VDWWA= github.com/dgrijalva/jwt-go v3.2.0+incompatible/go.mod h1:E3ru+11k8xSBh+hMPgOLZmtrrCbhqsmaPHjLKYnJCaQ= github.com/dgrijalva/jwt-go/v4 v4.0.0-preview1 h1:CaO/zOnF8VvUfEbhRatPcwKVWamvbYd8tQGRWacE9kU= github.com/dgrijalva/jwt-go/v4 v4.0.0-preview1/go.mod h1:+hnT3ywWDTAFrW5aE+u2Sa/wT555ZqwoCS+pk3p6ry4= -github.com/dgryski/go-farm v0.0.0-20190423205320-6a90982ecee2 h1:tdlZCpZ/P9DhczCTSixgIKmwPv6+wP5DGjqLYw5SUiA= github.com/dgryski/go-farm v0.0.0-20190423205320-6a90982ecee2/go.mod h1:SqUrOPUnsFjfmXRMNPybcSiG0BgUW2AuFH8PAnS2iTw= +github.com/dgryski/go-farm v0.0.0-20200201041132-a6ae2369ad13 h1:fAjc9m62+UWV/WAFKLNi6ZS0675eEUC9y3AlwSbQu1Y= +github.com/dgryski/go-farm v0.0.0-20200201041132-a6ae2369ad13/go.mod h1:SqUrOPUnsFjfmXRMNPybcSiG0BgUW2AuFH8PAnS2iTw= github.com/dgryski/go-sip13 v0.0.0-20181026042036-e10d5fee7954/go.mod h1:vAd38F8PWV+bWy6jNmig1y/TA+kYO4g3RSRF0IAv0no= github.com/dgryski/trifles v0.0.0-20200323201526-dd97f9abfb48 h1:fRzb/w+pyskVMQ+UbP35JkH8yB7MYb4q/qhBarqZE6g= github.com/dgryski/trifles v0.0.0-20200323201526-dd97f9abfb48/go.mod h1:if7Fbed8SFyPtHLHbg49SI7NAdJiC5WIA09pe59rfAA= @@ -323,8 +321,8 @@ github.com/facebookgo/subset v0.0.0-20200203212716-c811ad88dec4 h1:7HZCaLC5+BZpm github.com/fasthttp-contrib/websocket v0.0.0-20160511215533-1f3b11f56072/go.mod h1:duJ4Jxv5lDcvg4QuQr0oowTf7dz4/CR8NtyCooz9HL8= github.com/fatih/color v1.7.0/go.mod h1:Zm6kSWBoL9eyXnKyktHP6abPY2pDugNf5KwzbycvMj4= github.com/fatih/color v1.9.0/go.mod h1:eQcE1qtQxscV5RaZvpXrrb8Drkc3/DdQ+uUYCNjL+zU= -github.com/fatih/color v1.13.0 h1:8LOYc1KYPPmyKMuN8QV2DNRWNbLo6LZ0iLs8+mlH53w= -github.com/fatih/color v1.13.0/go.mod h1:kLAiJbzzSOZDVNGyDpeOxJ47H46qBXwg5ILebYFFOfk= +github.com/fatih/color v1.15.0 h1:kOqh6YHBtK8aywxGerMG2Eq3H6Qgoqeo13Bk2Mv/nBs= +github.com/fatih/color v1.15.0/go.mod h1:0h5ZqXfHYED7Bhv2ZJamyIOUej9KtShiJESRwBDUSsw= github.com/fatih/structs v1.1.0/go.mod h1:9NiDSp5zOcgEDl+j00MP/WkGVPOlPRLejGD8Ga6PJ7M= github.com/felixge/fgprof v0.9.3 h1:VvyZxILNuCiUCSXtPtYmmtGvb65nqXh2QFWc0Wpf2/g= github.com/felixge/fgprof v0.9.3/go.mod h1:RdbpDgzqYVh/T9fPELJyV7EYJuHB55UTEULNun8eiPw= @@ -392,8 +390,9 @@ github.com/go-latex/latex v0.0.0-20210118124228-b3d85cf34e07/go.mod h1:CO1AlKB2C github.com/go-logfmt/logfmt v0.3.0/go.mod h1:Qt1PoO58o5twSAckw1HlFXLmHsOX5/0LbT9GBnD5lWE= github.com/go-logfmt/logfmt v0.4.0/go.mod h1:3RMwSq7FuexP4Kalkev3ejPJsZTpXXBr9+V4qmtdjCk= github.com/go-logfmt/logfmt v0.5.0/go.mod h1:wCYkCAKZfumFQihp8CzCvQ3paCTfi41vtzG1KdI/P7A= -github.com/go-logfmt/logfmt v0.5.1 h1:otpy5pqBCBZ1ng9RQ0dPu4PN7ba75Y/aA+UpowDyNVA= github.com/go-logfmt/logfmt v0.5.1/go.mod h1:WYhtIu8zTZfxdn5+rREduYbwxfcBr/Vr6KEVveWlfTs= +github.com/go-logfmt/logfmt v0.6.0 h1:wGYYu3uicYdqXVgoYbvnkrPVXkuLM1p1ifugDMEdRi4= +github.com/go-logfmt/logfmt v0.6.0/go.mod h1:WYhtIu8zTZfxdn5+rREduYbwxfcBr/Vr6KEVveWlfTs= github.com/go-logr/logr v1.2.2/go.mod h1:jdQByPbusPIv2/zmleS9BjJVeZ6kBagPoEUsqbVz/1A= github.com/go-logr/logr v1.2.3 h1:2DntVwHkVopvECVRSlL5PSo9eG+cAkDCuckLubN+rq0= github.com/go-logr/logr v1.2.3/go.mod h1:jdQByPbusPIv2/zmleS9BjJVeZ6kBagPoEUsqbVz/1A= @@ -435,8 +434,8 @@ github.com/gofrs/flock v0.8.1 h1:+gYjHKf32LDeiEEFhQaotPbLuUXjY5ZqxKgXy7n59aw= github.com/gofrs/flock v0.8.1/go.mod h1:F1TvTiK9OcQqauNUHlbJvyl9Qa1QvF/gOUDKA14jxHU= github.com/gofrs/uuid v3.2.0+incompatible/go.mod h1:b2aQJv3Z4Fp6yNu3cdSllBxTCLRxnplIgP/c0N/04lM= github.com/gofrs/uuid v4.0.0+incompatible/go.mod h1:b2aQJv3Z4Fp6yNu3cdSllBxTCLRxnplIgP/c0N/04lM= -github.com/gofrs/uuid v4.3.0+incompatible h1:CaSVZxm5B+7o45rtab4jC2G37WGYX1zQfuU2i6DSvnc= -github.com/gofrs/uuid v4.3.0+incompatible/go.mod h1:b2aQJv3Z4Fp6yNu3cdSllBxTCLRxnplIgP/c0N/04lM= +github.com/gofrs/uuid v4.4.0+incompatible h1:3qXRTX8/NbyulANqlc0lchS1gqAVxRgsuW1YrTJupqA= +github.com/gofrs/uuid v4.4.0+incompatible/go.mod h1:b2aQJv3Z4Fp6yNu3cdSllBxTCLRxnplIgP/c0N/04lM= github.com/gogo/googleapis v0.0.0-20180223154316-0cd9801be74a/go.mod h1:gf4bu3Q80BeJ6H1S1vYPm8/ELATdvryBaNFGgqEef3s= github.com/gogo/googleapis v1.4.1/go.mod h1:2lpHqI5OcWCtVElxXnPt+s8oJvMpySlOyM6xDCrzib4= github.com/gogo/protobuf v1.1.1/go.mod h1:r8qH/GZQm5c6nD/R0oafs1akxWv10x8SbQlK7atdtwQ= @@ -454,6 +453,7 @@ github.com/golang/freetype v0.0.0-20170609003504-e2365dfdc4a0/go.mod h1:E/TSTwGw github.com/golang/glog v0.0.0-20160126235308-23def4e6c14b/go.mod h1:SBH7ygxi8pfUlaOkMMuAQtPIUF8ecWP5IEl/CR7VP2Q= github.com/golang/glog v1.0.0/go.mod h1:EWib/APOK0SL3dFbYqvxE3UYd8E6s1ouQ7iEp/0LWV4= github.com/golang/glog v1.1.0 h1:/d3pCKDPWNnvIWe0vVUpNP32qc8U3PDVxySP/y360qE= +github.com/golang/glog v1.1.0/go.mod h1:pfYeQZ3JWZoXTV5sFc986z3HTpwQs9At6P4ImfuP3NQ= github.com/golang/groupcache v0.0.0-20190129154638-5b532d6fd5ef/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc= github.com/golang/groupcache v0.0.0-20190702054246-869f871628b6/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc= github.com/golang/groupcache v0.0.0-20191227052852-215e87163ea7/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc= @@ -572,11 +572,6 @@ github.com/grpc-ecosystem/grpc-gateway v1.16.0/go.mod h1:BDjrQk3hbvj6Nolgz8mAMFb github.com/grpc-ecosystem/grpc-gateway/v2 v2.7.0/go.mod h1:hgWBS7lorOAVIJEQMi4ZsPv9hVvWI6+ch50m39Pf2Ks= github.com/grpc-ecosystem/grpc-gateway/v2 v2.9.0 h1:SLkFeyLhrg86Ny5Wme4MGGace7EHfgsb07uWX/QUGEQ= github.com/grpc-ecosystem/grpc-gateway/v2 v2.9.0/go.mod h1:z5aB5opCfWSoAzCrC18hMgjy4oWJ2dPXkn+f3kqTHxI= -github.com/gtank/merlin v0.1.1-0.20191105220539-8318aed1a79f/go.mod h1:T86dnYJhcGOh5BjZFCJWTDeTK7XW8uE+E21Cy/bIQ+s= -github.com/gtank/merlin v0.1.1 h1:eQ90iG7K9pOhtereWsmyRJ6RAwcP4tHTDBHXNg+u5is= -github.com/gtank/merlin v0.1.1/go.mod h1:T86dnYJhcGOh5BjZFCJWTDeTK7XW8uE+E21Cy/bIQ+s= -github.com/gtank/ristretto255 v0.1.2 h1:JEqUCPA1NvLq5DwYtuzigd7ss8fwbYay9fi4/5uMzcc= -github.com/gtank/ristretto255 v0.1.2/go.mod h1:Ph5OpO6c7xKUGROZfWVLiJf9icMDwUeIvY4OmlYW69o= github.com/gxed/hashland/keccakpg v0.0.1/go.mod h1:kRzw3HkwxFU1mpmPP8v1WyQzwdGfmKFJ6tItnhQ67kU= github.com/gxed/hashland/murmur3 v0.0.1/go.mod h1:KjXop02n4/ckmZSnY2+HKcLud/tcmvhST0bie/0lS48= github.com/hannahhoward/go-pubsub v0.0.0-20200423002714-8d62886cc36e h1:3YKHER4nmd7b5qy5t0GWDTwSn4OyRgfAXSmo6VnryBY= @@ -638,8 +633,9 @@ github.com/imdario/mergo v0.3.13 h1:lFzP57bqS/wsqKssCGmtLAb8A0wKjLGrve2q3PPVcBk= github.com/imdario/mergo v0.3.13/go.mod h1:4lJ1jqUDcsbIECGy0RUJAXNIhg+6ocWgb1ALK2O4oXg= github.com/imkira/go-interpol v1.1.0/go.mod h1:z0h2/2T3XF8kyEPpRgJ3kmNv+C43p+I/CoI+jC3w2iA= github.com/inconshreveable/mousetrap v1.0.0/go.mod h1:PxqpIevigyE2G7u3NXJIT2ANytuPF1OarO4DADm73n8= -github.com/inconshreveable/mousetrap v1.0.1 h1:U3uMjPSQEBMNp1lFxmllqCPM6P5u/Xq7Pgzkat/bFNc= github.com/inconshreveable/mousetrap v1.0.1/go.mod h1:vpF70FUmC8bwa3OWnCshd2FqLfsEA9PFc4w1p2J65bw= +github.com/inconshreveable/mousetrap v1.1.0 h1:wN+x4NVGpMsO7ErUn/mUI3vEoE6Jt13X2s0bqwp9tc8= +github.com/inconshreveable/mousetrap v1.1.0/go.mod h1:vpF70FUmC8bwa3OWnCshd2FqLfsEA9PFc4w1p2J65bw= github.com/inhies/go-bytesize v0.0.0-20220417184213-4913239db9cf h1:FtEj8sfIcaaBfAKrE1Cwb61YDtYq9JxChK1c7AKce7s= github.com/inhies/go-bytesize v0.0.0-20220417184213-4913239db9cf/go.mod h1:yrqSXGoD/4EKfF26AOGzscPOgTTJcyAwM2rpixWT+t4= github.com/ipfs/bbloom v0.0.4 h1:Gi+8EGJ2y5qiD5FbsbpX/TMNcJw8gSqr7eyjHa4Fhvs= @@ -849,8 +845,8 @@ github.com/jhump/protoreflect v1.11.0/go.mod h1:U7aMIjN0NWq9swDP7xDdoMfRHb35uiuT github.com/jhump/protoreflect v1.11.1-0.20220215191356-c1d18a52a21d/go.mod h1:JytZfP5d0r8pVNLZvai7U/MCuTWITgrI4tTg7puQFKI= github.com/jhump/protoreflect v1.12.1-0.20220721211354-060cc04fc18b h1:izTof8BKh/nE1wrKOrloNA5q4odOarjf+Xpe+4qow98= github.com/jhump/protoreflect v1.12.1-0.20220721211354-060cc04fc18b/go.mod h1:JytZfP5d0r8pVNLZvai7U/MCuTWITgrI4tTg7puQFKI= -github.com/jinzhu/copier v0.2.8 h1:N8MbL5niMwE3P4dOwurJixz5rMkKfujmMRFmAanSzWE= -github.com/jinzhu/copier v0.2.8/go.mod h1:24xnZezI2Yqac9J61UC6/dG/k76ttpq0DdJI3QmUvro= +github.com/jinzhu/copier v0.3.5 h1:GlvfUwHk62RokgqVNvYsku0TATCF7bAHVwEXoBh3iJg= +github.com/jinzhu/copier v0.3.5/go.mod h1:DfbEm0FYsaqBcKcFuvmOZb218JkPGtvSHsKg8S8hyyg= github.com/jinzhu/inflection v1.0.0/go.mod h1:h+uFLlag+Qp1Va5pdKtLDYj+kHp5pxUVkryuEj+Srlc= github.com/jinzhu/now v1.1.1/go.mod h1:d3SSVoowX0Lcu0IBviAWJpolVfI5UJVZZ7cO71lE/z8= github.com/jmhodges/levigo v1.0.0 h1:q5EC36kV79HWeTBWsod3mG11EgStG3qArTKcvlksN1U= @@ -934,8 +930,8 @@ github.com/lib/pq v1.3.0/go.mod h1:5WUZQaWbwv1U+lTReE5YruASi9Al49XbQIvNi/34Woo= github.com/lib/pq v1.8.0/go.mod h1:AlVN5x4E4T544tWzH6hKfbfQvm3HdbOxrmggDNAPY9o= github.com/lib/pq v1.10.0/go.mod h1:AlVN5x4E4T544tWzH6hKfbfQvm3HdbOxrmggDNAPY9o= github.com/lib/pq v1.10.2/go.mod h1:AlVN5x4E4T544tWzH6hKfbfQvm3HdbOxrmggDNAPY9o= -github.com/lib/pq v1.10.6 h1:jbk+ZieJ0D7EVGJYpL9QTz7/YW6UHbmdnZWYyK5cdBs= -github.com/lib/pq v1.10.6/go.mod h1:AlVN5x4E4T544tWzH6hKfbfQvm3HdbOxrmggDNAPY9o= +github.com/lib/pq v1.10.7 h1:p7ZhMD+KsSRozJr34udlUrhboJwWAgCg34+/ZZNvZZw= +github.com/lib/pq v1.10.7/go.mod h1:AlVN5x4E4T544tWzH6hKfbfQvm3HdbOxrmggDNAPY9o= github.com/libp2p/go-buffer-pool v0.0.1/go.mod h1:xtyIz9PMobb13WaxR6Zo1Pd1zXJKYg0a8KiIvDp3TzQ= github.com/libp2p/go-buffer-pool v0.0.2/go.mod h1:MvaB6xw5vOrDl8rYZGLFdKAuk/hRoRZd1Vi32+RXyFM= github.com/libp2p/go-buffer-pool v0.1.0 h1:oK4mSFcQz7cTQIfqbe4MIj9gLW+mnanjyFtc6cdF0Y8= @@ -1002,8 +998,8 @@ github.com/machinebox/graphql v0.2.2 h1:dWKpJligYKhYKO5A2gvNhkJdQMNZeChZYyBbrZkB github.com/machinebox/graphql v0.2.2/go.mod h1:F+kbVMHuwrQ5tYgU9JXlnskM8nOaFxCAEolaQybkjWA= github.com/magiconair/properties v1.8.0/go.mod h1:PppfXfuXeibc/6YijjN8zIbojt8czPbwD3XqdrwzmxQ= github.com/magiconair/properties v1.8.1/go.mod h1:PppfXfuXeibc/6YijjN8zIbojt8czPbwD3XqdrwzmxQ= -github.com/magiconair/properties v1.8.6 h1:5ibWZ6iY0NctNGWo87LalDlEZ6R41TqbbDamhfG/Qzo= -github.com/magiconair/properties v1.8.6/go.mod h1:y3VJvCyxH9uVvJTWEGAELF3aiYNyPKd5NZ3oSwXrF60= +github.com/magiconair/properties v1.8.7 h1:IeQXZAiQcpL9mgcAe1Nu6cX9LLw6ExEHKjN0VQdvPDY= +github.com/magiconair/properties v1.8.7/go.mod h1:Dhd985XPs7jluiymwWYZ0G4Z61jb3vdS329zhj2hYo0= github.com/mailru/easyjson v0.0.0-20180823135443-60711f1a8329/go.mod h1:C1wdFJiN94OJF2b5HbByQZoLdCWB1Yqtg26g4irojpc= github.com/mailru/easyjson v0.0.0-20190312143242-1de009706dbe/go.mod h1:C1wdFJiN94OJF2b5HbByQZoLdCWB1Yqtg26g4irojpc= github.com/marten-seemann/tcp v0.0.0-20210406111302-dfbc87cc63fd h1:br0buuQ854V8u83wA0rVZ8ttrq5CpaPZdvrK0LP2lOk= @@ -1017,7 +1013,6 @@ github.com/mattn/go-colorable v0.1.2/go.mod h1:U0ppj6V5qS13XJ6of8GYAs25YV2eR4EVc github.com/mattn/go-colorable v0.1.4/go.mod h1:U0ppj6V5qS13XJ6of8GYAs25YV2eR4EVcfRqFIhoBtE= github.com/mattn/go-colorable v0.1.6/go.mod h1:u6P/XSegPjTcexA+o6vUJrdnUu04hMope9wVRipJSqc= github.com/mattn/go-colorable v0.1.8/go.mod h1:u6P/XSegPjTcexA+o6vUJrdnUu04hMope9wVRipJSqc= -github.com/mattn/go-colorable v0.1.9/go.mod h1:u6P/XSegPjTcexA+o6vUJrdnUu04hMope9wVRipJSqc= github.com/mattn/go-colorable v0.1.11/go.mod h1:u5H1YNBxpqRaxsYJYSkiCWKzEfiAb1Gb520KVy5xxl4= github.com/mattn/go-colorable v0.1.13 h1:fFA4WZxdEF4tXPZVKMLwD8oUnCTTo08duU7wxecdEvA= github.com/mattn/go-colorable v0.1.13/go.mod h1:7S9/ev0klgBDR4GtXTXX8a3vIGJpMovkB8vQcUbaXHg= @@ -1059,9 +1054,6 @@ github.com/mikioh/tcpinfo v0.0.0-20190314235526-30a79bb1804b h1:z78hV3sbSMAUoyUM github.com/mikioh/tcpinfo v0.0.0-20190314235526-30a79bb1804b/go.mod h1:lxPUiZwKoFL8DUUmalo2yJJUCxbPKtm8OKfqr2/FTNU= github.com/mikioh/tcpopt v0.0.0-20190314235656-172688c1accc h1:PTfri+PuQmWDqERdnNMiD9ZejrlswWrCpBEZgWOiTrc= github.com/mikioh/tcpopt v0.0.0-20190314235656-172688c1accc/go.mod h1:cGKTAVKx4SxOuR/czcZ/E2RSJ3sfHs8FpHhQ5CWMf9s= -github.com/mimoo/StrobeGo v0.0.0-20181016162300-f8f6d4d2b643/go.mod h1:43+3pMjjKimDBf5Kr4ZFNGbLql1zKkbImw+fZbw3geM= -github.com/mimoo/StrobeGo v0.0.0-20210601165009-122bf33a46e0 h1:QRUSJEgZn2Snx0EmT/QLXibWjSUDjKWvXIT19NBVp94= -github.com/mimoo/StrobeGo v0.0.0-20210601165009-122bf33a46e0/go.mod h1:43+3pMjjKimDBf5Kr4ZFNGbLql1zKkbImw+fZbw3geM= github.com/minio/blake2b-simd v0.0.0-20160723061019-3f5f724cb5b1/go.mod h1:pD8RvIylQ358TN4wwqatJ8rNavkEINozVn9DtGI3dfQ= github.com/minio/highwayhash v1.0.2 h1:Aak5U0nElisjDCfPSG79Tgzkn2gl66NxOMspRrKnA/g= github.com/minio/highwayhash v1.0.2/go.mod h1:BQskDq+xkJ12lmlUUi7U0M5Swg3EWR+dLTk+kldvVxY= @@ -1150,8 +1142,8 @@ github.com/nishanths/predeclared v0.0.0-20200524104333-86fad755b4d3/go.mod h1:nt github.com/nxadm/tail v1.4.4/go.mod h1:kenIhsEOeOJmVchQTgglprH7qJGnHDVpk1VPCcaMI8A= github.com/nxadm/tail v1.4.8 h1:nPr65rt6Y5JFSKQO7qToXr7pePgD6Gwiw05lkbyAQTE= github.com/nxadm/tail v1.4.8/go.mod h1:+ncqLTQzXmGhMZNUePPaPqPvBxHAIsmXswZKocGu+AU= -github.com/oasisprotocol/curve25519-voi v0.0.0-20220317090546-adb2f9614b17 h1:pxR+aWfo+famermIZvD+SiDQ3qmF7Iy2VPZuEsKTMtA= -github.com/oasisprotocol/curve25519-voi v0.0.0-20220317090546-adb2f9614b17/go.mod h1:WUcXjUd98qaCVFb6j8Xc87MsKeMCXDu9Nk8JRJ9SeC8= +github.com/oasisprotocol/curve25519-voi v0.0.0-20220708102147-0a8a51822cae h1:FatpGJD2jmJfhZiFDElaC0QhZUDQnxUeAwTGkfAHN3I= +github.com/oasisprotocol/curve25519-voi v0.0.0-20220708102147-0a8a51822cae/go.mod h1:hVoHR2EVESiICEMbg137etN/Lx+lSrHPTD39Z/uE+2s= github.com/oklog/ulid v1.3.1/go.mod h1:CirwcVhetQ6Lv90oh/F+FBtV6XMibvdAFo93nm5qn4U= github.com/olekukonko/tablewriter v0.0.5 h1:P2Ga83D34wi1o9J6Wh1mRuqd4mF/x/lgBS7N7AbDhec= github.com/olekukonko/tablewriter v0.0.5/go.mod h1:hPp6KlRPjbx+hW8ykQs1w3UBbZlj6HuIJcUGPhkA7kY= @@ -1190,14 +1182,11 @@ github.com/pascaldekloe/goe v0.0.0-20180627143212-57f6aae5913c/go.mod h1:lzWF7FI github.com/pbnjay/memory v0.0.0-20210728143218-7b4eea64cf58 h1:onHthvaw9LFnH4t2DcNVpwGmV9E1BkGknEliJkfwQj0= github.com/pbnjay/memory v0.0.0-20210728143218-7b4eea64cf58/go.mod h1:DXv8WO4yhMYhSNPKjeNKa5WY9YCIEBRbNzFFPJbWO6Y= github.com/pelletier/go-toml v1.2.0/go.mod h1:5z9KED0ma1S8pY6P1sdut58dfprrGBbd/94hg7ilaic= -github.com/pelletier/go-toml v1.9.5 h1:4yBQzkHv+7BHq2PQUZF3Mx0IYxG7LsP222s7Agd3ve8= -github.com/pelletier/go-toml v1.9.5/go.mod h1:u1nR/EPcESfeI/szUZKdtJ0xRNbUoANCkoOuaOx1Y+c= -github.com/pelletier/go-toml/v2 v2.0.5 h1:ipoSadvV8oGUjnUbMub59IDPPwfxF694nG/jwbMiyQg= -github.com/pelletier/go-toml/v2 v2.0.5/go.mod h1:OMHamSCAODeSsVrwwvcJOaoN0LIUIaFVNZzmWyNfXas= +github.com/pelletier/go-toml/v2 v2.0.6 h1:nrzqCb7j9cDFj2coyLNLaZuJTLjWjlaz6nvTvIwycIU= +github.com/pelletier/go-toml/v2 v2.0.6/go.mod h1:eumQOmlWiOPt5WriQQqoM5y18pDHwha2N+QD+EUNTek= github.com/petar/GoLLRB v0.0.0-20210522233825-ae3b015fd3e9 h1:1/WtZae0yGtPq+TI6+Tv1WTxkukpXeMlviSxvL7SRgk= github.com/petermattis/goid v0.0.0-20180202154549-b0b1615b78e5 h1:q2e307iGHPdTGp0hoxKjt1H5pDo6utceo3dQVK3I5XQ= github.com/petermattis/goid v0.0.0-20180202154549-b0b1615b78e5/go.mod h1:jvVRKCrJTQWu0XVbaOlby/2lO20uSCHEMzzplHXte1o= -github.com/philhofer/fwd v1.1.1/go.mod h1:gk3iGcWd9+svBvR0sR+KPcfE+RNWozjowpeBVG3ZVNU= github.com/phpdave11/gofpdf v1.4.2/go.mod h1:zpO6xFn9yxo3YLyMvW8HcKWVdbNqgIfOOp2dXMnm1mY= github.com/phpdave11/gofpdi v1.0.12/go.mod h1:vBmVV0Do6hSBHC8uKUQ71JGW+ZGQq74llk/7bXwjDoI= github.com/pingcap/errors v0.11.4 h1:lFuQV/oaUMGcD2tqt+01ROSmJs75VG1ToEOkZIZ4nE4= @@ -1286,8 +1275,8 @@ github.com/rogpeppe/go-internal v1.6.1/go.mod h1:xXDCJY+GAPziupqXw64V24skbSoqbTE github.com/rogpeppe/go-internal v1.8.1/go.mod h1:JeRgkft04UBgHMgCIwADu4Pn6Mtm5d4nPKWu0nJ5d+o= github.com/rogpeppe/go-internal v1.9.0 h1:73kH8U+JUqXU8lRuOHeVHaa/SZPifC7BkcraZVejAe8= github.com/rogpeppe/go-internal v1.9.0/go.mod h1:WtVeX8xhTBvf0smdhujwtBcq4Qrzq/fJaraNFVN+nFs= -github.com/rs/cors v1.8.2 h1:KCooALfAYGs415Cwu5ABvv9n9509fSiG5SQJn/AQo4U= -github.com/rs/cors v1.8.2/go.mod h1:XyqrcTp5zjWr1wsJ8PIRZssZ8b/WMcMf71DJnit4EMU= +github.com/rs/cors v1.8.3 h1:O+qNyWn7Z+F9M0ILBHgMVPuB1xTOucVd5gtaYyXBpRo= +github.com/rs/cors v1.8.3/go.mod h1:XyqrcTp5zjWr1wsJ8PIRZssZ8b/WMcMf71DJnit4EMU= github.com/rs/xid v1.2.1/go.mod h1:+uKXf+4Djp6Md1KODXJxgGQPKngRmWyn10oCKFzNHOQ= github.com/rs/zerolog v1.13.0/go.mod h1:YbFCdg8HfsridGWAh22vktObvhZbQsZXe4/zB0OKkWU= github.com/rs/zerolog v1.15.0/go.mod h1:xYTKnLHcpfU2225ny5qZjxnj9NvkumZYjJHlAThCjNc= @@ -1362,8 +1351,8 @@ github.com/spaolacci/murmur3 v0.0.0-20180118202830-f09979ecbc72/go.mod h1:JwIasO github.com/spaolacci/murmur3 v1.1.0 h1:7c1g84S4BPRrfL5Xrdp6fOJ206sU9y293DDHaoy0bLI= github.com/spaolacci/murmur3 v1.1.0/go.mod h1:JwIasOWyU6f++ZhiEuf87xNszmSA2myDM2Kzu9HwQUA= github.com/spf13/afero v1.1.2/go.mod h1:j4pytiNVoe2o6bmDsKpLACNPDBIoEAkihy7loJ1B0CQ= -github.com/spf13/afero v1.8.2 h1:xehSyVa0YnHWsJ49JFljMpg1HX19V6NDZ1fkm1Xznbo= -github.com/spf13/afero v1.8.2/go.mod h1:CtAatgMJh6bJEIs48Ay/FOnkljP3WeGUG0MC1RfAqwo= +github.com/spf13/afero v1.9.3 h1:41FoI0fD7OR7mGcKE/aOiLkGreyf8ifIOQmJANWogMk= +github.com/spf13/afero v1.9.3/go.mod h1:iUV7ddyEEZPO5gA3zD4fJt6iStLlL+Lg4m2cihcDf8Y= github.com/spf13/cast v1.3.0/go.mod h1:Qx5cxh0v+4UWYiBimWS+eyWzqEqokIECu5etghLkUJE= github.com/spf13/cast v1.5.0 h1:rj3WzYc11XZaIZMPKmwP96zkFEnnAmV8s6XbB2aY32w= github.com/spf13/cast v1.5.0/go.mod h1:SpXXQ5YoyJw6s3/6cMTQuxvgRl3PCJiyaX9p6b155UU= @@ -1379,8 +1368,8 @@ github.com/spf13/pflag v1.0.5 h1:iy+VFUOCP1a+8yFto/drg2CJ5u0yRoB7fZw3DKv/JXA= github.com/spf13/pflag v1.0.5/go.mod h1:McXfInJRrz4CZXVZOBLb0bTZqETkiAhM9Iw0y3An2Bg= github.com/spf13/viper v1.3.2/go.mod h1:ZiWeW+zYFKm7srdB9IoDzzZXaJaI5eL9QjNiN/DMA2s= github.com/spf13/viper v1.7.0/go.mod h1:8WkrPz2fc9jxqZNCJI/76HCieCp4Q8HaLFoCha5qpdg= -github.com/spf13/viper v1.13.0 h1:BWSJ/M+f+3nmdz9bxB+bWX28kkALN2ok11D0rSo8EJU= -github.com/spf13/viper v1.13.0/go.mod h1:Icm2xNL3/8uyh/wFuB1jI7TiTNKp8632Nwegu+zgdYw= +github.com/spf13/viper v1.15.0 h1:js3yy885G8xwJa6iOISGFwd+qlUo5AvyXb7CiihdtiU= +github.com/spf13/viper v1.15.0/go.mod h1:fFcTBJxvhhzSJiZy8n+PeW6t8l+KeT/uTARa0jHOQLA= github.com/src-d/envconfig v1.0.0/go.mod h1:Q9YQZ7BKITldTBnoxsE5gOeB5y66RyPXeue/R4aaNBc= github.com/status-im/keycard-go v0.2.0 h1:QDLFswOQu1r5jsycloeQh3bVU8n/NatHHaZobtDnDzA= github.com/status-im/keycard-go v0.2.0/go.mod h1:wlp8ZLbsmrF6g6WjugPAx+IzoLrkdf9+mHxBEeo3Hbg= @@ -1404,8 +1393,8 @@ github.com/stretchr/testify v1.8.2 h1:+h33VjcLVPDHtOdpUCuF+7gSuG3yGIftsP1YvFihtJ github.com/stretchr/testify v1.8.2/go.mod h1:w2LPCIKwWwSfY2zedu0+kehJoqGctiVI29o6fzry7u4= github.com/stvp/go-udp-testing v0.0.0-20201019212854-469649b16807/go.mod h1:7jxmlfBCDBXRzr0eAQJ48XC1hBu1np4CS5+cHEYfwpc= github.com/subosito/gotenv v1.2.0/go.mod h1:N0PQaV/YGNqwC0u51sEeR/aUtSLEXKX9iv69rRypqCw= -github.com/subosito/gotenv v1.4.1 h1:jyEFiXpy21Wm81FBN71l9VoMMV8H8jG+qIK3GCpY6Qs= -github.com/subosito/gotenv v1.4.1/go.mod h1:ayKnFf/c6rvx/2iiLrJUk1e6plDbT3edrFNGqEflhK0= +github.com/subosito/gotenv v1.4.2 h1:X1TuBLAMDFbaTAChgCBLu3DU3UPyELpnF2jjJ2cz/S8= +github.com/subosito/gotenv v1.4.2/go.mod h1:ayKnFf/c6rvx/2iiLrJUk1e6plDbT3edrFNGqEflhK0= github.com/syndtr/goleveldb v1.0.0/go.mod h1:ZVVdQEZoIme9iO1Ch2Jdy24qqXrMMOU6lpPAyBWyWuQ= github.com/syndtr/goleveldb v1.0.1-0.20210819022825-2ae1ddf74ef7/go.mod h1:q4W45IWZaF22tdD+VEXcAWRA037jwmWEB5VWYORlTpc= github.com/syndtr/goleveldb v1.0.1-0.20220614013038-64ee5596c38a h1:1ur3QoCqvE5fl+nylMaIr9PVV1w343YRDtsy+Rwu7XI= @@ -1414,7 +1403,6 @@ github.com/tarm/serial v0.0.0-20180830185346-98f6abe2eb07/go.mod h1:kDXzergiv9cb github.com/tecbot/gorocksdb v0.0.0-20191217155057-f0fad39f321c h1:g+WoO5jjkqGAzHWCjJB1zZfXPIAaDpzXIEJ0eS6B5Ok= github.com/tecbot/gorocksdb v0.0.0-20191217155057-f0fad39f321c/go.mod h1:ahpPrc7HpcfEWDQRZEmnXMzHY03mLDYMCxeDzy46i+8= github.com/thoas/go-funk v0.9.1 h1:O549iLZqPpTUQ10ykd26sZhzD+rmR5pWhuElrhbC20M= -github.com/tinylib/msgp v1.1.5/go.mod h1:eQsjooMTnV42mHu917E26IogZ2930nFyBQdofk10Udg= github.com/tj/assert v0.0.3 h1:Df/BlaZ20mq6kuai7f5z2TvPFiwC3xaWJSDQNiIS3Rk= github.com/tklauser/go-sysconf v0.3.10 h1:IJ1AZGZRWbY8T5Vfk04D9WOA5WSejdflXxP03OUqALw= github.com/tklauser/go-sysconf v0.3.10/go.mod h1:C8XykCvCb+Gn0oNCWPIlcb0RuglQTYaQ2hGm7jmxEFk= @@ -1423,7 +1411,6 @@ github.com/tklauser/numcpus v0.4.0/go.mod h1:1+UI3pD8NW14VMwdgJNJ1ESk2UnwhAnz5hM github.com/tmc/grpc-websocket-proxy v0.0.0-20190109142713-0ad062ec5ee5/go.mod h1:ncp9v5uamzpCO7NfCPTXjqaC+bZgJeR0sMTm6dMHP7U= github.com/tmc/grpc-websocket-proxy v0.0.0-20220101234140-673ab2c3ae75 h1:6fotK7otjonDflCTK0BCfls4SPy3NcCVb5dqqmbRknE= github.com/tmc/grpc-websocket-proxy v0.0.0-20220101234140-673ab2c3ae75/go.mod h1:KO6IkyS8Y3j8OdNO85qEYBsRPuteD+YciPomcXdrMnk= -github.com/ttacon/chalk v0.0.0-20160626202418-22c06c80ed31/go.mod h1:onvgF043R+lC5RZ8IT9rBXDaEDnpnw/Cl+HFiw+v/7Q= github.com/tv42/httpunix v0.0.0-20191220191345-2ba4b9c3382c h1:u6SKchux2yDvFQnDHS3lPnIRmfVJ5Sxy3ao2SIdysLQ= github.com/tv42/httpunix v0.0.0-20191220191345-2ba4b9c3382c/go.mod h1:hzIxponao9Kjc7aWznkXaL4U4TWaDSs8zcsY4Ka08nM= github.com/tyler-smith/go-bip39 v1.1.0 h1:5eUemwrMargf3BSLRRCalXT93Ns6pQJIjYQN2nyfOP8= @@ -1449,8 +1436,6 @@ github.com/valyala/fasttemplate v1.2.1/go.mod h1:KHLXt3tVN2HBp8eijSv/kGJopbvo7S+ github.com/valyala/tcplisten v0.0.0-20161114210144-ceec8f93295a/go.mod h1:v3UYOV9WzVtRmSR+PDvWpU/qWl4Wa5LApYYX4ZtKbio= github.com/vegaprotocol/cancelreader v0.0.0-20230724130739-6f2217a69449 h1:X2/RVmrBNProT5+53SnPJvCAicmHmxrTGwtbnercH3Q= github.com/vegaprotocol/cancelreader v0.0.0-20230724130739-6f2217a69449/go.mod h1:3XuTXfFS2VjM+HTLZY9Ak0l6eUKfijIfMUZ4EgX0QYo= -github.com/vegaprotocol/cometbft v0.34.29-patch.1 h1:cagbEi+E+0qObyYyI3XcmHfQD4S6qlwKAxK6PDtNEpc= -github.com/vegaprotocol/cometbft v0.34.29-patch.1/go.mod h1:L9shMfbkZ8B+7JlwANEr+NZbBcn+hBpwdbeYvA5rLCw= github.com/vegaprotocol/decimal v1.3.1-uint256 h1:Aj//9joGGuz+dAKo6W/r9Rt1HUXYrjH7oerdCg1q/So= github.com/vegaprotocol/decimal v1.3.1-uint256/go.mod h1:+mRbjtsnpvm5Qw6aiLEf3I6SHICNB4nhMTmH9y8hMtg= github.com/vegaprotocol/embedded-postgres v1.13.1-0.20221123183204-2e7a2feee5bb h1:c7l0ESzXbIbr7ykEjWki6+aG+77gAJua3ETrAxd50HI= @@ -1607,7 +1592,6 @@ golang.org/x/crypto v0.0.0-20190701094942-4def268fd1a4/go.mod h1:yigFU9vqHzYiE8U golang.org/x/crypto v0.0.0-20190820162420-60c769a6c586/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= golang.org/x/crypto v0.0.0-20190911031432-227b76d455e7/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= -golang.org/x/crypto v0.0.0-20191206172530-e9b2fee46413/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= golang.org/x/crypto v0.0.0-20191227163750-53104e6ec876/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= golang.org/x/crypto v0.0.0-20200323165209-0ec3e9974c59/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= golang.org/x/crypto v0.0.0-20200602180216-279210d13fed/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= @@ -1618,7 +1602,6 @@ golang.org/x/crypto v0.0.0-20210322153248-0c34fe9e7dc2/go.mod h1:T9bdIzuCu7OtxOm golang.org/x/crypto v0.0.0-20210421170649-83a5a9bb288b/go.mod h1:T9bdIzuCu7OtxOm1hfPfRQxPLYneinmdGuTeoZ9dtd4= golang.org/x/crypto v0.0.0-20210616213533-5ff15b29337e/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc= golang.org/x/crypto v0.0.0-20210711020723-a769d52b0f97/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc= -golang.org/x/crypto v0.0.0-20210813211128-0a44fdfbc16e/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc= golang.org/x/crypto v0.0.0-20210921155107-089bfa567519/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc= golang.org/x/crypto v0.0.0-20211108221036-ceb1ce70b4fa/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc= golang.org/x/crypto v0.0.0-20220722155217-630584e8d5aa/go.mod h1:IxCIyHEi3zRg3s0A5j5BB6A9Jmi73HwBIUl50j+osU4= @@ -1877,6 +1860,7 @@ golang.org/x/sys v0.0.0-20220715151400-c0bba94af5f8/go.mod h1:oPkhp1MJrh7nUepCBc golang.org/x/sys v0.0.0-20220722155257-8c9f86f7a55f/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20220811171246-fbc7d0a398ab/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20220908164124-27713097b956/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20221010170243-090e33056c14/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.5.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.13.0 h1:Af8nKPmuFypiUBjVoU9V20FiaFXOcuZI21p0ycVYYGE= @@ -1904,7 +1888,7 @@ golang.org/x/time v0.0.0-20181108054448-85acf8d2951c/go.mod h1:tRJNPiyCQ0inRvYxb golang.org/x/time v0.0.0-20190308202827-9d24e82272b4/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= golang.org/x/time v0.0.0-20191024005414-555d28b269f0/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= golang.org/x/time v0.0.0-20201208040808-7e3f01d25324/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= -golang.org/x/time v0.0.0-20220922220347-f3bd1da661af h1:Yx9k8YCG3dvF87UAn2tu2HQLf2dt/eR1bXxpLMWeH+Y= +golang.org/x/time v0.1.0 h1:xYY+Bajn2a7VBmTM5GikTmnK8ZuX8YgnQCqZpbBNtmA= golang.org/x/tools v0.0.0-20180221164845-07fd8470d635/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= golang.org/x/tools v0.0.0-20180525024113-a5b4c53f6e8b/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= golang.org/x/tools v0.0.0-20180828015842-6cd1fcedba52/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= @@ -1967,7 +1951,6 @@ golang.org/x/tools v0.0.0-20200729194436-6467de6f59a7/go.mod h1:njjCfa9FT2d7l9Bc golang.org/x/tools v0.0.0-20200804011535-6c149bb5ef0d/go.mod h1:njjCfa9FT2d7l9Bc6FUM5FLjQPp3cFF28FI3qnDFljA= golang.org/x/tools v0.0.0-20200825202427-b303f430e36d/go.mod h1:njjCfa9FT2d7l9Bc6FUM5FLjQPp3cFF28FI3qnDFljA= golang.org/x/tools v0.0.0-20200904185747-39188db58858/go.mod h1:Cj7w3i3Rnn0Xh82ur9kSqwfTHTeVxaDqrfMjpcNT6bE= -golang.org/x/tools v0.0.0-20201022035929-9cf592e881e9/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA= golang.org/x/tools v0.0.0-20201110124207-079ba7bd75cd/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA= golang.org/x/tools v0.0.0-20201201161351-ac6f37ff4c2a/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA= golang.org/x/tools v0.0.0-20201208233053-a543418bbed2/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA= diff --git a/libs/context/context.go b/libs/context/context.go index 6915ed5991..98cd9d6eb3 100644 --- a/libs/context/context.go +++ b/libs/context/context.go @@ -77,12 +77,12 @@ func TraceIDFromContext(ctx context.Context) (context.Context, string) { return ctx, stID } -func BlockHeightFromContext(ctx context.Context) (int64, error) { +func BlockHeightFromContext(ctx context.Context) (uint64, error) { hv := ctx.Value(blockHeightKey) if hv == nil { return 0, ErrBlockHeightMissing } - h, ok := hv.(int64) + h, ok := hv.(uint64) if !ok { return 0, ErrBlockHeightMissing } @@ -123,7 +123,7 @@ func WithTraceID(ctx context.Context, tID string) context.Context { return context.WithValue(ctx, traceIDKey, tID) } -func WithBlockHeight(ctx context.Context, h int64) context.Context { +func WithBlockHeight(ctx context.Context, h uint64) context.Context { return context.WithValue(ctx, blockHeightKey, h) } diff --git a/libs/test/wrapper.go b/libs/test/wrapper.go index bf5b9d2c9d..40b5bdc3e2 100644 --- a/libs/test/wrapper.go +++ b/libs/test/wrapper.go @@ -25,7 +25,7 @@ import ( func VegaContext(chainId string, blockHeight int64) context.Context { return vgcontext.WithChainID( vgcontext.WithTraceID( - vgcontext.WithBlockHeight(context.Background(), blockHeight), + vgcontext.WithBlockHeight(context.Background(), uint64(blockHeight)), vgcrypto.RandomHash(), ), chainId) diff --git a/libs/tm/keys.go b/libs/tm/keys.go index 4070fbba25..9618f56efe 100644 --- a/libs/tm/keys.go +++ b/libs/tm/keys.go @@ -18,7 +18,7 @@ package tm import ( "encoding/base64" - tmcrypto "github.com/tendermint/tendermint/proto/tendermint/crypto" + tmcrypto "github.com/cometbft/cometbft/proto/tendermint/crypto" ) func PubKeyToString(pubKey tmcrypto.PublicKey) string {