From 3cde9a0bbc04683aedb96871b0b45f8e2e650101 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Hern=C3=A1n=20Vanzetto?= Date: Tue, 5 Jul 2022 16:08:58 +0300 Subject: [PATCH] abci-cli: Add `process_proposal` command to abci-cli (#8901) * Add `process_proposal` command to abci-cli * Added process proposal to the 'tutorial' examples * Added entry in CHANGELOG_PENDING.md * Allow empty blocks in PrepareProposal, ProcessProposal, and FinalizeBlock * Fix minimum arguments * Add tests for empty block * Updated abci-cli doc Co-authored-by: Sergio Mena Co-authored-by: Jasmina Malicevic --- CHANGELOG_PENDING.md | 1 + abci/cmd/abci-cli/abci-cli.go | 74 ++++++++++++++++++++++---------- abci/example/kvstore/kvstore.go | 2 +- abci/tests/server/client.go | 13 ++++++ abci/tests/test_cli/ex1.abci | 9 +++- abci/tests/test_cli/ex1.abci.out | 25 +++++++++++ docs/app-dev/abci-cli.md | 27 ++++++++++++ 7 files changed, 127 insertions(+), 24 deletions(-) diff --git a/CHANGELOG_PENDING.md b/CHANGELOG_PENDING.md index 07e755501..13eeaef16 100644 --- a/CHANGELOG_PENDING.md +++ b/CHANGELOG_PENDING.md @@ -33,6 +33,7 @@ Special thanks to external contributors on this release: - [abci] \#8664 Move `app_hash` parameter from `Commit` to `FinalizeBlock`. (@sergio-mena) - [abci] \#8656 Added cli command for `PrepareProposal`. (@jmalicevic) - [sink/psql] \#8637 tx_results emitted from psql sink are now json encoded, previously they were protobuf encoded + - [abci] \#8901 Added cli command for `ProcessProposal`. (@hvanz) - P2P Protocol diff --git a/abci/cmd/abci-cli/abci-cli.go b/abci/cmd/abci-cli/abci-cli.go index 237493e0e..824bbb360 100644 --- a/abci/cmd/abci-cli/abci-cli.go +++ b/abci/cmd/abci-cli/abci-cli.go @@ -79,10 +79,11 @@ func RootCmmand(logger log.Logger) *cobra.Command { // Structure for data passed to print response. type response struct { // generic abci response - Data []byte - Code uint32 - Info string - Log string + Data []byte + Code uint32 + Info string + Log string + Status int32 Query *queryResponse } @@ -132,6 +133,7 @@ func addCommands(cmd *cobra.Command, logger log.Logger) { cmd.AddCommand(versionCmd) cmd.AddCommand(testCmd) cmd.AddCommand(prepareProposalCmd) + cmd.AddCommand(processProposalCmd) cmd.AddCommand(getQueryCmd()) // examples @@ -172,7 +174,7 @@ This command opens an interactive console for running any of the other commands without opening a new connection each time `, Args: cobra.ExactArgs(0), - ValidArgs: []string{"echo", "info", "query", "check_tx", "prepare_proposal", "finalize_block", "commit"}, + ValidArgs: []string{"echo", "info", "query", "check_tx", "prepare_proposal", "process_proposal", "finalize_block", "commit"}, RunE: cmdConsole, } @@ -195,7 +197,7 @@ var finalizeBlockCmd = &cobra.Command{ Use: "finalize_block", Short: "deliver a block of transactions to the application", Long: "deliver a block of transactions to the application", - Args: cobra.MinimumNArgs(1), + Args: cobra.MinimumNArgs(0), RunE: cmdFinalizeBlock, } @@ -230,10 +232,18 @@ var prepareProposalCmd = &cobra.Command{ Use: "prepare_proposal", Short: "prepare proposal", Long: "prepare proposal", - Args: cobra.MinimumNArgs(1), + Args: cobra.MinimumNArgs(0), RunE: cmdPrepareProposal, } +var processProposalCmd = &cobra.Command{ + Use: "process_proposal", + Short: "process proposal", + Long: "process proposal", + Args: cobra.MinimumNArgs(0), + RunE: cmdProcessProposal, +} + func getQueryCmd() *cobra.Command { cmd := &cobra.Command{ Use: "query", @@ -352,6 +362,11 @@ func cmdTest(cmd *cobra.Command, args []string) error { types.TxRecord_UNMODIFIED, }, nil) }, + func() error { + return servertest.ProcessProposal(ctx, client, [][]byte{ + {0x01}, + }, types.ResponseProcessProposal_ACCEPT) + }, }) } @@ -454,6 +469,8 @@ func muxOnCommands(cmd *cobra.Command, pArgs []string) error { return cmdQuery(cmd, actualArgs) case "prepare_proposal": return cmdPrepareProposal(cmd, actualArgs) + case "process_proposal": + return cmdProcessProposal(cmd, actualArgs) default: return cmdUnimplemented(cmd, pArgs) } @@ -517,13 +534,6 @@ const codeBad uint32 = 10 // Append new txs to application func cmdFinalizeBlock(cmd *cobra.Command, args []string) error { - if len(args) == 0 { - printResponse(cmd, args, response{ - Code: codeBad, - Log: "Must provide at least one transaction", - }) - return nil - } txs := make([][]byte, len(args)) for i, arg := range args { txBytes, err := stringOrHexToBytes(arg) @@ -633,15 +643,8 @@ func inTxArray(txByteArray [][]byte, tx []byte) bool { } return false } + func cmdPrepareProposal(cmd *cobra.Command, args []string) error { - if len(args) == 0 { - printResponse(cmd, args, response{ - Code: codeBad, - Info: "Must provide at least one transaction", - Log: "Must provide at least one transaction", - }) - return nil - } txsBytesArray := make([][]byte, len(args)) for i, arg := range args { @@ -682,6 +685,30 @@ func cmdPrepareProposal(cmd *cobra.Command, args []string) error { return nil } +func cmdProcessProposal(cmd *cobra.Command, args []string) error { + txsBytesArray := make([][]byte, len(args)) + + for i, arg := range args { + txBytes, err := stringOrHexToBytes(arg) + if err != nil { + return err + } + txsBytesArray[i] = txBytes + } + + res, err := client.ProcessProposal(cmd.Context(), &types.RequestProcessProposal{ + Txs: txsBytesArray, + }) + if err != nil { + return err + } + + printResponse(cmd, args, response{ + Status: int32(res.Status), + }) + return nil +} + func makeKVStoreCmd(logger log.Logger) func(*cobra.Command, []string) error { return func(cmd *cobra.Command, args []string) error { // Create the application - in memory or persisted to disk @@ -739,6 +766,9 @@ func printResponse(cmd *cobra.Command, args []string, rsps ...response) { if rsp.Log != "" { fmt.Printf("-> log: %s\n", rsp.Log) } + if cmd.Use == "process_proposal" { + fmt.Printf("-> status: %s\n", types.ResponseProcessProposal_ProposalStatus_name[rsp.Status]) + } if rsp.Query != nil { fmt.Printf("-> height: %d\n", rsp.Query.Height) diff --git a/abci/example/kvstore/kvstore.go b/abci/example/kvstore/kvstore.go index c9a2a148c..c1005eb86 100644 --- a/abci/example/kvstore/kvstore.go +++ b/abci/example/kvstore/kvstore.go @@ -293,7 +293,7 @@ func (app *Application) PrepareProposal(_ context.Context, req *types.RequestPre func (*Application) ProcessProposal(_ context.Context, req *types.RequestProcessProposal) (*types.ResponseProcessProposal, error) { for _, tx := range req.Txs { - if len(tx) == 0 { + if len(tx) == 0 || isPrepareTx(tx) { return &types.ResponseProcessProposal{Status: types.ResponseProcessProposal_REJECT}, nil } } diff --git a/abci/tests/server/client.go b/abci/tests/server/client.go index 7762c8d03..eb5649d9e 100644 --- a/abci/tests/server/client.go +++ b/abci/tests/server/client.go @@ -83,6 +83,19 @@ func PrepareProposal(ctx context.Context, client abciclient.Client, txBytes [][] fmt.Println("Passed test: PrepareProposal") return nil } + +func ProcessProposal(ctx context.Context, client abciclient.Client, txBytes [][]byte, statusExp types.ResponseProcessProposal_ProposalStatus) error { + res, _ := client.ProcessProposal(ctx, &types.RequestProcessProposal{Txs: txBytes}) + if res.Status != statusExp { + fmt.Println("Failed test: ProcessProposal") + fmt.Printf("ProcessProposal response status was unexpected. Got %v expected %v.", + res.Status, statusExp) + return errors.New("ProcessProposal error") + } + fmt.Println("Passed test: ProcessProposal") + return nil +} + func CheckTx(ctx context.Context, client abciclient.Client, txBytes []byte, codeExp uint32, dataExp []byte) error { res, _ := client.CheckTx(ctx, &types.RequestCheckTx{Tx: txBytes}) code, data := res.Code, res.Data diff --git a/abci/tests/test_cli/ex1.abci b/abci/tests/test_cli/ex1.abci index dc9e213ec..eba06028a 100644 --- a/abci/tests/test_cli/ex1.abci +++ b/abci/tests/test_cli/ex1.abci @@ -1,6 +1,7 @@ echo hello info prepare_proposal "abc" +process_proposal "abc" finalize_block "abc" commit info @@ -8,4 +9,10 @@ query "abc" finalize_block "def=xyz" "ghi=123" commit query "def" -prepare_proposal "preparedef" \ No newline at end of file +prepare_proposal "preparedef" +process_proposal "def" +process_proposal "preparedef" +prepare_proposal +process_proposal +finalize_block +commit \ No newline at end of file diff --git a/abci/tests/test_cli/ex1.abci.out b/abci/tests/test_cli/ex1.abci.out index f4f342dfb..fb3ababfa 100644 --- a/abci/tests/test_cli/ex1.abci.out +++ b/abci/tests/test_cli/ex1.abci.out @@ -12,6 +12,10 @@ -> code: OK -> log: Succeeded. Tx: abc action: UNMODIFIED +> process_proposal "abc" +-> code: OK +-> status: ACCEPT + > finalize_block "abc" -> code: OK -> code: OK @@ -58,3 +62,24 @@ -> code: OK -> log: Succeeded. Tx: preparedef action: REMOVED +> process_proposal "def" +-> code: OK +-> status: ACCEPT + +> process_proposal "preparedef" +-> code: OK +-> status: REJECT + +> prepare_proposal + +> process_proposal +-> code: OK +-> status: ACCEPT + +> finalize_block +-> code: OK +-> data.hex: 0x0600000000000000 + +> commit +-> code: OK + diff --git a/docs/app-dev/abci-cli.md b/docs/app-dev/abci-cli.md index 109e3b9fb..bb94a36ca 100644 --- a/docs/app-dev/abci-cli.md +++ b/docs/app-dev/abci-cli.md @@ -208,6 +208,33 @@ Try running these commands: -> key.hex: 646566 -> value: xyz -> value.hex: 78797A + +> prepare_proposal "preparedef" +-> code: OK +-> log: Succeeded. Tx: def action: ADDED +-> code: OK +-> log: Succeeded. Tx: preparedef action: REMOVED + +> process_proposal "def" +-> code: OK +-> status: ACCEPT + +> process_proposal "preparedef" +-> code: OK +-> status: REJECT + +> prepare_proposal + +> process_proposal +-> code: OK +-> status: ACCEPT + +> finalize_block +-> code: OK +-> data.hex: 0x0600000000000000 + +> commit +-> code: OK ``` Note that if we do `finalize_block "abc" ...` it will store `(abc, abc)`, but if