From 1cc8c5c37e1930dd8d43c7e63faeb60091c1d1fc Mon Sep 17 00:00:00 2001 From: n3wbie Date: Thu, 9 May 2024 14:53:50 +0900 Subject: [PATCH 1/6] feat: add msg idx in event --- gnovm/stdlibs/std/emit_event.go | 9 ++++++++- tm2/pkg/bft/abci/types/types.go | 7 +++++++ tm2/pkg/sdk/baseapp.go | 25 +++++++++++++++++-------- 3 files changed, 32 insertions(+), 9 deletions(-) diff --git a/gnovm/stdlibs/std/emit_event.go b/gnovm/stdlibs/std/emit_event.go index 46fea79d43c..52f90a672a1 100644 --- a/gnovm/stdlibs/std/emit_event.go +++ b/gnovm/stdlibs/std/emit_event.go @@ -21,6 +21,7 @@ func X_emit(m *gno.Machine, typ string, attrs []string) { fnIdent := getPrevFunctionNameFromTarget(m, "Emit") evt := gnoEvent{ + MsgIdx: 0, Type: typ, PkgPath: pkgPath, Func: fnIdent, @@ -46,14 +47,20 @@ func attrKeysAndValues(attrs []string) ([]gnoEventAttribute, error) { } type gnoEvent struct { - Type string `json:"type"` + MsgIdx int `json:"msg_idx"` PkgPath string `json:"pkg_path"` Func string `json:"func"` + Type string `json:"type"` Attributes []gnoEventAttribute `json:"attrs"` } func (e gnoEvent) AssertABCIEvent() {} +func (e gnoEvent) SetMsgIdx(msgIdx int) interface{} { + e.MsgIdx = msgIdx + return e +} + type gnoEventAttribute struct { Key string `json:"key"` Value string `json:"value"` diff --git a/tm2/pkg/bft/abci/types/types.go b/tm2/pkg/bft/abci/types/types.go index 8c2764cb1bd..21926cad537 100644 --- a/tm2/pkg/bft/abci/types/types.go +++ b/tm2/pkg/bft/abci/types/types.go @@ -206,6 +206,7 @@ type Error interface { type Event interface { AssertABCIEvent() + SetMsgIdx(int) interface{} } type Header interface { @@ -221,6 +222,9 @@ type Header interface { type StringError string func (StringError) AssertABCIError() {} +func (StringError) SetMsgIdx(i int) interface{} { + return nil +} func (err StringError) Error() string { return string(err) @@ -232,6 +236,9 @@ func (err StringError) Error() string { type EventString string func (EventString) AssertABCIEvent() {} +func (EventString) SetMsgIdx(i int) interface{} { + return nil +} func (err EventString) Event() string { return string(err) diff --git a/tm2/pkg/sdk/baseapp.go b/tm2/pkg/sdk/baseapp.go index 1801a0af35f..a0640d13aca 100644 --- a/tm2/pkg/sdk/baseapp.go +++ b/tm2/pkg/sdk/baseapp.go @@ -652,25 +652,34 @@ func (app *BaseApp) runMsgs(ctx Context, msgs []Msg, mode RunTxMode) (result Res // Each message result's Data must be length prefixed in order to separate // each result. data = append(data, msgResult.Data...) - events = append(events, msgResult.Events...) - defer func() { - events = append(events, ctx.EventLogger().Events()...) - result.Events = events - }() - // TODO append msgevent from ctx. XXX XXX + + // each msgs' event + var msgEvent []abci.Event + + // handle each msg's ctx event + msgCtxEvents := ctx.EventLogger().Events() + for _, msgCtxEvent := range msgCtxEvents { + overwriteInterface := msgCtxEvent.SetMsgIdx(i) + overwrwriteEvent := overwriteInterface.(abci.Event) + + msgEvent = append(msgEvent, overwrwriteEvent) + } + msgEvent = append(msgEvent, msgResult.Events...) + + events = append(events, msgEvent...) // stop execution and return on first failed message if !msgResult.IsOK() { msgLogs = append(msgLogs, fmt.Sprintf("msg:%d,success:%v,log:%s,events:%v", - i, false, msgResult.Log, events)) + i, false, msgResult.Log, msgEvent)) err = msgResult.Error break } msgLogs = append(msgLogs, fmt.Sprintf("msg:%d,success:%v,log:%s,events:%v", - i, true, msgResult.Log, events)) + i, true, msgResult.Log, msgEvent)) } result.Error = ABCIError(err) From bd6b483ef0a6a45ef76f9474ffed838252836cf8 Mon Sep 17 00:00:00 2001 From: n3wbie Date: Thu, 9 May 2024 15:19:37 +0900 Subject: [PATCH 2/6] fix: test cases --- gno.land/cmd/gnoland/testdata/event_defer_callback_loop.txtar | 2 +- gnovm/stdlibs/std/emit_event_test.go | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/gno.land/cmd/gnoland/testdata/event_defer_callback_loop.txtar b/gno.land/cmd/gnoland/testdata/event_defer_callback_loop.txtar index 9e7fac9abfe..6a7ffdf0f39 100644 --- a/gno.land/cmd/gnoland/testdata/event_defer_callback_loop.txtar +++ b/gno.land/cmd/gnoland/testdata/event_defer_callback_loop.txtar @@ -9,7 +9,7 @@ stdout OK! stdout 'GAS WANTED: 2000000' stdout 'GAS USED: [0-9]+' stdout 'HEIGHT: [0-9]+' -stdout 'EVENTS: \[{\"type\":\"ForLoopEvent\",\"pkg_path\":\"gno.land\/r\/demo\/edcl\",\"func\":\"\",\"attrs\":\[{\"key\":\"iteration\",\"value\":\"0\"},{\"key\":\"key\",\"value\":\"value\"}\]},{\"type\":\"ForLoopEvent\",\"pkg_path\":\"gno.land\/r\/demo\/edcl\",\"func\":\"\",\"attrs\":\[{\"key\":\"iteration\",\"value\":\"1\"},{\"key\":\"key\",\"value\":\"value\"}\]},{\"type\":\"ForLoopEvent\",\"pkg_path\":\"gno.land\/r\/demo\/edcl\",\"func\":\"\",\"attrs\":\[{\"key\":\"iteration\",\"value\":\"2\"},{\"key\":\"key\",\"value\":\"value\"}\]},{\"type\":\"ForLoopCompletionEvent\",\"pkg_path\":\"gno.land\/r\/demo\/edcl\",\"func\":\"forLoopEmitExample\",\"attrs\":\[{\"key\":\"count\",\"value\":\"3\"}\]},{\"type\":\"CallbackEvent\",\"pkg_path\":\"gno.land\/r\/demo\/edcl\",\"func\":\"\",\"attrs\":\[{\"key\":\"key1\",\"value\":\"value1\"},{\"key\":\"key2\",\"value\":\"value2\"}\]},{\"type\":\"CallbackCompletionEvent\",\"pkg_path\":\"gno.land\/r\/demo\/edcl\",\"func\":\"callbackEmitExample\",\"attrs\":\[{\"key\":\"key\",\"value\":\"value\"}\]},{\"type\":\"DeferEvent\",\"pkg_path\":\"gno.land\/r\/demo\/edcl\",\"func\":\"deferEmitExample\",\"attrs\":\[{\"key\":\"key1\",\"value\":\"value1\"},{\"key\":\"key2\",\"value\":\"value2\"}\]}\]' +stdout 'EVENTS: \[{\"msg_idx\":0,\"pkg_path\":\"gno.land/r/demo/edcl\",\"func\":\"\",\"type\":\"ForLoopEvent\",\"attrs\":\[{\"key\":\"iteration\",\"value\":\"0\"},{\"key\":\"key\",\"value\":\"value\"}]},{\"msg_idx\":0,\"pkg_path\":\"gno.land/r/demo/edcl\",\"func\":\"\",\"type\":\"ForLoopEvent\",\"attrs\":\[{\"key\":\"iteration\",\"value\":\"1\"},{\"key\":\"key\",\"value\":\"value\"}]},{\"msg_idx\":0,\"pkg_path\":\"gno.land/r/demo/edcl\",\"func\":\"\",\"type\":\"ForLoopEvent\",\"attrs\":\[{\"key\":\"iteration\",\"value\":\"2\"},{\"key\":\"key\",\"value\":\"value\"}]},{\"msg_idx\":0,\"pkg_path\":\"gno.land/r/demo/edcl\",\"func\":\"forLoopEmitExample\",\"type\":\"ForLoopCompletionEvent\",\"attrs\":\[{\"key\":\"count\",\"value\":\"3\"}]},{\"msg_idx\":0,\"pkg_path\":\"gno.land/r/demo/edcl\",\"func\":\"\",\"type\":\"CallbackEvent\",\"attrs\":\[{\"key\":\"key1\",\"value\":\"value1\"},{\"key\":\"key2\",\"value\":\"value2\"}]},{\"msg_idx\":0,\"pkg_path\":\"gno.land/r/demo/edcl\",\"func\":\"callbackEmitExample\",\"type\":\"CallbackCompletionEvent\",\"attrs\":\[{\"key\":\"key\",\"value\":\"value\"}]},{\"msg_idx\":0,\"pkg_path\":\"gno.land/r/demo/edcl\",\"func\":\"deferEmitExample\",\"type\":\"DeferEvent\",\"attrs\":\[{\"key\":\"key1\",\"value\":\"value1\"},{\"key\":\"key2\",\"value\":\"value2\"}\]}\]' -- edcl.gno -- diff --git a/gnovm/stdlibs/std/emit_event_test.go b/gnovm/stdlibs/std/emit_event_test.go index 10bd8ecacd9..f3b5107b30e 100644 --- a/gnovm/stdlibs/std/emit_event_test.go +++ b/gnovm/stdlibs/std/emit_event_test.go @@ -308,7 +308,7 @@ func TestEmit_ComplexInteraction(t *testing.T) { t.Fatal(err) } - expected := `[{"type":"ForLoopEvent","pkg_path":"","func":"","attrs":[{"key":"iteration","value":"0"},{"key":"key","value":"value"}]},{"type":"ForLoopEvent","pkg_path":"","func":"","attrs":[{"key":"iteration","value":"1"},{"key":"key","value":"value"}]},{"type":"ForLoopEvent","pkg_path":"","func":"","attrs":[{"key":"iteration","value":"2"},{"key":"key","value":"value"}]},{"type":"ForLoopCompletionEvent","pkg_path":"","func":"","attrs":[{"key":"count","value":"3"}]},{"type":"CallbackEvent","pkg_path":"","func":"","attrs":[{"key":"key1","value":"value1"},{"key":"key2","value":"value2"}]},{"type":"CallbackCompletionEvent","pkg_path":"","func":"","attrs":[{"key":"key","value":"value"}]},{"type":"DeferEvent","pkg_path":"","func":"","attrs":[{"key":"key1","value":"value1"},{"key":"key2","value":"value2"}]}]` + expected := `[{"msg_idx":0,"pkg_path":"","func":"","type":"ForLoopEvent","attrs":[{"key":"iteration","value":"0"},{"key":"key","value":"value"}]},{"msg_idx":0,"pkg_path":"","func":"","type":"ForLoopEvent","attrs":[{"key":"iteration","value":"1"},{"key":"key","value":"value"}]},{"msg_idx":0,"pkg_path":"","func":"","type":"ForLoopEvent","attrs":[{"key":"iteration","value":"2"},{"key":"key","value":"value"}]},{"msg_idx":0,"pkg_path":"","func":"","type":"ForLoopCompletionEvent","attrs":[{"key":"count","value":"3"}]},{"msg_idx":0,"pkg_path":"","func":"","type":"CallbackEvent","attrs":[{"key":"key1","value":"value1"},{"key":"key2","value":"value2"}]},{"msg_idx":0,"pkg_path":"","func":"","type":"CallbackCompletionEvent","attrs":[{"key":"key","value":"value"}]},{"msg_idx":0,"pkg_path":"","func":"","type":"DeferEvent","attrs":[{"key":"key1","value":"value1"},{"key":"key2","value":"value2"}]}]` assert.Equal(t, expected, string(res)) } From 03447f28206f740a1a6eb127afa268c39b96cd02 Mon Sep 17 00:00:00 2001 From: n3wbie Date: Fri, 10 May 2024 13:59:31 +0900 Subject: [PATCH 3/6] fix: txtar test --- gno.land/cmd/gnoland/testdata/event.txtar | 4 ++-- gno.land/cmd/gnoland/testdata/event_callback.txtar | 2 +- gno.land/cmd/gnoland/testdata/event_for_statement.txtar | 4 ++-- 3 files changed, 5 insertions(+), 5 deletions(-) diff --git a/gno.land/cmd/gnoland/testdata/event.txtar b/gno.land/cmd/gnoland/testdata/event.txtar index 45f2ceaf772..95c4e7d429a 100644 --- a/gno.land/cmd/gnoland/testdata/event.txtar +++ b/gno.land/cmd/gnoland/testdata/event.txtar @@ -9,14 +9,14 @@ stdout OK! stdout 'GAS WANTED: 2000000' stdout 'GAS USED: \d+' stdout 'HEIGHT: \d+' -stdout 'EVENTS: \[{\"type\":\"foo\",\"pkg_path\":\"gno.land\/r\/demo\/ee\",\"func\":\"SubFoo\",\"attrs\":\[{\"key\":\"key1\",\"value\":\"value1\"},{\"key\":\"key2\",\"value\":\"value2\"},{\"key\":\"key3\",\"value\":\"value3\"}\]},{\"type\":\"bar\",\"pkg_path\":\"gno.land\/r\/demo\/ee\",\"func\":\"SubBar\",\"attrs\":\[{\"key\":\"bar\",\"value\":\"baz\"}\]}\]' +stdout 'EVENTS: \[{\"msg_idx\":0,\"pkg_path\":\"gno.land\/r\/demo\/ee\",\"func\":\"SubFoo\",\"type\":\"foo\",\"attrs\":\[{\"key\":\"key1\",\"value\":\"value1\"},{\"key\":\"key2\",\"value\":\"value2\"},{\"key\":\"key3\",\"value\":\"value3\"}]},{\"msg_idx\":0,\"pkg_path\":\"gno.land\/r\/demo\/ee\",\"func\":\"SubBar\",\"type\":\"bar\",\"attrs\":\[{\"key\":\"bar\",\"value\":\"baz\"}\]}\]' gnokey maketx call -pkgpath gno.land/r/demo/ee -func Bar -gas-fee 1000000ugnot -gas-wanted 2000000 -broadcast -chainid=tendermint_test test1 stdout OK! stdout 'GAS WANTED: 2000000' stdout 'GAS USED: \d+' stdout 'HEIGHT: \d+' -stdout 'EVENTS: \[{\"type\":\"bar\",\"pkg_path\":\"gno.land\/r\/demo\/ee\",\"func\":\"Bar\",\"attrs\":\[{\"key\":\"foo\",\"value\":\"bar\"}\]}\]' +stdout 'EVENTS: \[{\"msg_idx\":0,\"pkg_path\":\"gno.land\/r\/demo\/ee\",\"func\":\"Bar\",\"type\":\"bar\",\"attrs\":\[{\"key\":\"foo\",\"value\":\"bar\"}\]}\]' -- ee.gno -- package ee diff --git a/gno.land/cmd/gnoland/testdata/event_callback.txtar b/gno.land/cmd/gnoland/testdata/event_callback.txtar index a0366df1346..18392ef70df 100644 --- a/gno.land/cmd/gnoland/testdata/event_callback.txtar +++ b/gno.land/cmd/gnoland/testdata/event_callback.txtar @@ -9,7 +9,7 @@ stdout OK! stdout 'GAS WANTED: 2000000' stdout 'GAS USED: [0-9]+' stdout 'HEIGHT: [0-9]+' -stdout 'EVENTS: \[{\"type\":\"foo\",\"pkg_path\":\"gno\.land\/r\/demo\/cbee\",\"func\":\"subFoo\",\"attrs\":\[{\"key\":\"k1\",\"value\":\"v1\"},{\"key\":\"k2\",\"value\":\"v2\"}\]},{\"type\":\"bar\",\"pkg_path\":\"gno\.land\/r\/demo\/cbee\",\"func\":\"subBar\",\"attrs\":\[{\"key\":\"bar\",\"value\":\"baz\"}\]}\]' +stdout 'EVENTS: \[{\"msg_idx\":0,\"pkg_path\":\"gno.land\/r\/demo\/cbee\",\"func\":\"subFoo\",\"type\":\"foo\",\"attrs\":\[{\"key\":\"k1\",\"value\":\"v1\"},{\"key\":\"k2\",\"value\":\"v2\"}]},{\"msg_idx\":0,\"pkg_path\":\"gno.land\/r\/demo\/cbee\",\"func\":\"subBar\",\"type\":\"bar\",\"attrs\":\[{\"key\":\"bar\",\"value\":\"baz\"}\]}\]' -- cbee.gno -- diff --git a/gno.land/cmd/gnoland/testdata/event_for_statement.txtar b/gno.land/cmd/gnoland/testdata/event_for_statement.txtar index a05a614f985..fae53841caa 100644 --- a/gno.land/cmd/gnoland/testdata/event_for_statement.txtar +++ b/gno.land/cmd/gnoland/testdata/event_for_statement.txtar @@ -9,14 +9,14 @@ stdout OK! stdout 'GAS WANTED: 2000000' stdout 'GAS USED: [0-9]+' stdout 'HEIGHT: [0-9]+' -stdout 'EVENTS: \[{"type":"testing","pkg_path":"gno.land\/r\/demo\/foree","func":"Foo","attrs":\[{"key":"foo","value":"bar"}\]},{"type":"testing","pkg_path":"gno.land\/r\/demo\/foree","func":"Foo","attrs":\[{"key":"foo","value":"bar"}\]},{"type":"testing","pkg_path":"gno.land\/r\/demo\/foree","func":"Foo","attrs":\[{"key":"foo","value":"bar"}\]},{"type":"testing","pkg_path":"gno.land\/r\/demo\/foree","func":"Foo","attrs":\[{"key":"foo","value":"bar"}\]},{"type":"testing","pkg_path":"gno.land\/r\/demo\/foree","func":"Foo","attrs":\[{"key":"foo","value":"bar"}\]},{"type":"testing","pkg_path":"gno.land\/r\/demo\/foree","func":"Foo","attrs":\[{"key":"foo","value":"bar"}\]},{"type":"testing","pkg_path":"gno.land\/r\/demo\/foree","func":"Foo","attrs":\[{"key":"foo","value":"bar"}\]},{"type":"testing","pkg_path":"gno.land\/r\/demo\/foree","func":"Foo","attrs":\[{"key":"foo","value":"bar"}\]},{"type":"testing","pkg_path":"gno.land\/r\/demo\/foree","func":"Foo","attrs":\[{"key":"foo","value":"bar"}\]},{"type":"testing","pkg_path":"gno.land\/r\/demo\/foree","func":"Foo","attrs":\[{"key":"foo","value":"bar"}\]}\]' +stdout 'EVENTS: \[{\"msg_idx\":0,\"pkg_path\":\"gno.land\/r\/demo\/foree\",\"func\":\"Foo\",\"type\":\"testing\",\"attrs\":\[{\"key\":\"foo\",\"value\":\"bar\"}]},{\"msg_idx\":0,\"pkg_path\":\"gno.land\/r\/demo\/foree\",\"func\":\"Foo\",\"type\":\"testing\",\"attrs\":\[{\"key\":\"foo\",\"value\":\"bar\"}]},{\"msg_idx\":0,\"pkg_path\":\"gno.land\/r\/demo\/foree\",\"func\":\"Foo\",\"type\":\"testing\",\"attrs\":\[{\"key\":\"foo\",\"value\":\"bar\"}]},{\"msg_idx\":0,\"pkg_path\":\"gno.land\/r\/demo\/foree\",\"func\":\"Foo\",\"type\":\"testing\",\"attrs\":\[{\"key\":\"foo\",\"value\":\"bar\"}]},{\"msg_idx\":0,\"pkg_path\":\"gno.land\/r\/demo\/foree\",\"func\":\"Foo\",\"type\":\"testing\",\"attrs\":\[{\"key\":\"foo\",\"value\":\"bar\"}]},{\"msg_idx\":0,\"pkg_path\":\"gno.land\/r\/demo\/foree\",\"func\":\"Foo\",\"type\":\"testing\",\"attrs\":\[{\"key\":\"foo\",\"value\":\"bar\"}]},{\"msg_idx\":0,\"pkg_path\":\"gno.land\/r\/demo\/foree\",\"func\":\"Foo\",\"type\":\"testing\",\"attrs\":\[{\"key\":\"foo\",\"value\":\"bar\"}]},{\"msg_idx\":0,\"pkg_path\":\"gno.land\/r\/demo\/foree\",\"func\":\"Foo\",\"type\":\"testing\",\"attrs\":\[{\"key\":\"foo\",\"value\":\"bar\"}]},{\"msg_idx\":0,\"pkg_path\":\"gno.land\/r\/demo\/foree\",\"func\":\"Foo\",\"type\":\"testing\",\"attrs\":\[{\"key\":\"foo\",\"value\":\"bar\"}]},{\"msg_idx\":0,\"pkg_path\":\"gno.land\/r\/demo\/foree\",\"func\":\"Foo\",\"type\":\"testing\",\"attrs\":\[{\"key\":\"foo\",\"value\":\"bar\"}\]}\]' gnokey maketx call -pkgpath gno.land/r/demo/foree -func Bar -gas-fee 1000000ugnot -gas-wanted 2000000 -broadcast -chainid=tendermint_test test1 stdout OK! stdout 'GAS WANTED: 2000000' stdout 'GAS USED: [0-9]+' stdout 'HEIGHT: [0-9]+' -stdout 'EVENTS: \[{"type":"Foo","pkg_path":"gno.land\/r\/demo\/foree","func":"subFoo","attrs":\[{"key":"k1","value":"v1"},{"key":"k2","value":"v2"}\]},{"type":"Bar","pkg_path":"gno.land\/r\/demo\/foree","func":"subBar","attrs":\[{"key":"bar","value":"baz"}\]},{"type":"Foo","pkg_path":"gno.land\/r\/demo\/foree","func":"subFoo","attrs":\[{"key":"k1","value":"v1"},{"key":"k2","value":"v2"}\]},{"type":"Bar","pkg_path":"gno.land\/r\/demo\/foree","func":"subBar","attrs":\[{"key":"bar","value":"baz"}\]}\]' +stdout 'EVENTS: \[{\"msg_idx\":0,\"pkg_path\":\"gno.land\/r\/demo\/foree\",\"func\":\"subFoo\",\"type\":\"Foo\",\"attrs\":\[{\"key\":\"k1\",\"value\":\"v1\"},{\"key\":\"k2\",\"value\":\"v2\"}]},{\"msg_idx\":0,\"pkg_path\":\"gno.land\/r\/demo\/foree\",\"func\":\"subBar\",\"type\":\"Bar\",\"attrs\":\[{\"key\":\"bar\",\"value\":\"baz\"}]},{\"msg_idx\":0,\"pkg_path\":\"gno.land\/r\/demo\/foree\",\"func\":\"subFoo\",\"type\":\"Foo\",\"attrs\":\[{\"key\":\"k1\",\"value\":\"v1\"},{\"key\":\"k2\",\"value\":\"v2\"}]},{\"msg_idx\":0,\"pkg_path\":\"gno.land\/r\/demo\/foree\",\"func\":\"subBar\",\"type\":\"Bar\",\"attrs\":\[{\"key\":\"bar\",\"value\":\"baz\"}\]}\]' -- foree.gno -- From 3002936883a10a4812b15a176057473feeaf0dff Mon Sep 17 00:00:00 2001 From: n3wbie Date: Mon, 13 May 2024 12:32:06 +0900 Subject: [PATCH 4/6] test: add multi-msg event test --- examples/gno.land/r/demo/event/event.gno | 9 ++++ examples/gno.land/r/demo/event/gno.mod | 1 + gno.land/pkg/gnoclient/integration_test.go | 59 ++++++++++++++++++++++ 3 files changed, 69 insertions(+) create mode 100644 examples/gno.land/r/demo/event/event.gno create mode 100644 examples/gno.land/r/demo/event/gno.mod diff --git a/examples/gno.land/r/demo/event/event.gno b/examples/gno.land/r/demo/event/event.gno new file mode 100644 index 00000000000..9e5de540734 --- /dev/null +++ b/examples/gno.land/r/demo/event/event.gno @@ -0,0 +1,9 @@ +package event + +import ( + "std" +) + +func Emit(value string) { + std.Emit("TAG", "key", value) +} diff --git a/examples/gno.land/r/demo/event/gno.mod b/examples/gno.land/r/demo/event/gno.mod new file mode 100644 index 00000000000..f740de2ec6a --- /dev/null +++ b/examples/gno.land/r/demo/event/gno.mod @@ -0,0 +1 @@ +module gno.land/r/demo/event \ No newline at end of file diff --git a/gno.land/pkg/gnoclient/integration_test.go b/gno.land/pkg/gnoclient/integration_test.go index ace9022e35d..9bcb944e21f 100644 --- a/gno.land/pkg/gnoclient/integration_test.go +++ b/gno.land/pkg/gnoclient/integration_test.go @@ -1,6 +1,7 @@ package gnoclient import ( + "fmt" "testing" "github.com/gnolang/gno/gnovm/pkg/gnolang" @@ -113,6 +114,64 @@ func TestCallMultiple_Integration(t *testing.T) { assert.Equal(t, expected, got) } +func TestCallMultipleWithEvent_Integration(t *testing.T) { + // Set up in-memory node + config, _ := integration.TestingNodeConfig(t, gnoenv.RootDir()) + node, remoteAddr := integration.TestingInMemoryNode(t, log.NewNoopLogger(), config) + defer node.Stop() + + // Init Signer & RPCClient + signer := newInMemorySigner(t, "tendermint_test") + rpcClient, err := rpcclient.NewHTTPClient(remoteAddr) + require.NoError(t, err) + + // Setup Client + client := Client{ + Signer: signer, + RPCClient: rpcClient, + } + + // Make Tx config + baseCfg := BaseTxCfg{ + GasFee: "10000ugnot", + GasWanted: 8000000, + AccountNumber: 0, + SequenceNumber: 0, + Memo: "", + } + + // Make Msg configs + msg1 := MsgCall{ + PkgPath: "gno.land/r/demo/event", + FuncName: "Emit", + Args: []string{"first_value"}, + Send: "", + } + + // Same call, different argument + msg2 := MsgCall{ + PkgPath: "gno.land/r/demo/event", + FuncName: "Emit", + Args: []string{"second_value"}, + Send: "", + } + + // Execute call + res, err := client.Call(baseCfg, msg1, msg2) + assert.Nil(t, err) + + // check response from block_results + blockRes, err := client.BlockResult(res.Height) + assert.Nil(t, err) + + // XXX: better comparison ? + event0 := fmt.Sprintf("%v", blockRes.Results.DeliverTxs[0].Events[0]) + assert.Equal(t, event0, "{0 gno.land/r/demo/event Emit TAG [{key first_value}]}") + + event1 := fmt.Sprintf("%v", blockRes.Results.DeliverTxs[0].Events[1]) + assert.Equal(t, event1, "{1 gno.land/r/demo/event Emit TAG [{key second_value}]}") +} + func TestSendSingle_Integration(t *testing.T) { // Set up in-memory node config, _ := integration.TestingNodeConfig(t, gnoenv.RootDir()) From cae1fee0a6f4691c3811f0d959bbafd22960c0bd Mon Sep 17 00:00:00 2001 From: n3wbie Date: Tue, 14 May 2024 14:31:41 +0900 Subject: [PATCH 5/6] feat: client TxSync --- gno.land/pkg/gnoclient/client_txs.go | 97 +++++++++++++++++++++++++++- 1 file changed, 96 insertions(+), 1 deletion(-) diff --git a/gno.land/pkg/gnoclient/client_txs.go b/gno.land/pkg/gnoclient/client_txs.go index a61fa9a892d..32e0cecc2df 100644 --- a/gno.land/pkg/gnoclient/client_txs.go +++ b/gno.land/pkg/gnoclient/client_txs.go @@ -114,6 +114,62 @@ func (c *Client) Call(cfg BaseTxCfg, msgs ...MsgCall) (*ctypes.ResultBroadcastTx return c.signAndBroadcastTxCommit(tx, cfg.AccountNumber, cfg.SequenceNumber) } +// CallTxSync executes one or more MsgCall calls on the blockchain synchronously +func (c *Client) CallTxSync(cfg BaseTxCfg, msgs ...MsgCall) (*ctypes.ResultBroadcastTx, error) { + // Validate required client fields. + if err := c.validateSigner(); err != nil { + return nil, err + } + if err := c.validateRPCClient(); err != nil { + return nil, err + } + + // Validate base transaction config + if err := cfg.validateBaseTxConfig(); err != nil { + return nil, err + } + + // Parse MsgCall slice + vmMsgs := make([]std.Msg, 0, len(msgs)) + for _, msg := range msgs { + // Validate MsgCall fields + if err := msg.validateMsgCall(); err != nil { + return nil, err + } + + // Parse send coins + send, err := std.ParseCoins(msg.Send) + if err != nil { + return nil, err + } + + // Unwrap syntax sugar to vm.MsgCall slice + vmMsgs = append(vmMsgs, std.Msg(vm.MsgCall{ + Caller: c.Signer.Info().GetAddress(), + PkgPath: msg.PkgPath, + Func: msg.FuncName, + Args: msg.Args, + Send: send, + })) + } + + // Parse gas fee + gasFeeCoins, err := std.ParseCoin(cfg.GasFee) + if err != nil { + return nil, err + } + + // Pack transaction + tx := std.Tx{ + Msgs: vmMsgs, + Fee: std.NewFee(cfg.GasWanted, gasFeeCoins), + Signatures: nil, + Memo: cfg.Memo, + } + + return c.signAndBroadcastTxSync(tx, cfg.AccountNumber, cfg.SequenceNumber) +} + // Run executes one or more MsgRun calls on the blockchain func (c *Client) Run(cfg BaseTxCfg, msgs ...MsgRun) (*ctypes.ResultBroadcastTxCommit, error) { // Validate required client fields. @@ -297,7 +353,7 @@ func (c *Client) AddPackage(cfg BaseTxCfg, msgs ...MsgAddPackage) (*ctypes.Resul func (c *Client) signAndBroadcastTxCommit(tx std.Tx, accountNumber, sequenceNumber uint64) (*ctypes.ResultBroadcastTxCommit, error) { caller := c.Signer.Info().GetAddress() - if sequenceNumber == 0 || accountNumber == 0 { + if sequenceNumber == 0 && accountNumber == 0 { // needs to be AND condition, if OR condition ≈ one of value will ignored account, _, err := c.QueryAccount(caller) if err != nil { return nil, errors.Wrap(err, "query account") @@ -336,4 +392,43 @@ func (c *Client) signAndBroadcastTxCommit(tx std.Tx, accountNumber, sequenceNumb return bres, nil } +func (c *Client) signAndBroadcastTxSync(tx std.Tx, accountNumber, sequenceNumber uint64) (*ctypes.ResultBroadcastTx, error) { + caller := c.Signer.Info().GetAddress() + + if sequenceNumber == 0 && accountNumber == 0 { + account, _, err := c.QueryAccount(caller) + if err != nil { + return nil, errors.Wrap(err, "query account") + } + accountNumber = account.AccountNumber + sequenceNumber = account.Sequence + } + + signCfg := SignCfg{ + UnsignedTX: tx, + SequenceNumber: sequenceNumber, + AccountNumber: accountNumber, + } + signedTx, err := c.Signer.Sign(signCfg) + if err != nil { + return nil, errors.Wrap(err, "sign") + } + + bz, err := amino.Marshal(signedTx) + if err != nil { + return nil, errors.Wrap(err, "marshaling tx binary bytes") + } + + bres, err := c.RPCClient.BroadcastTxSync(bz) + if err != nil { + return nil, errors.Wrap(err, "broadcasting bytes") + } + + if bres.Error != nil { + return bres, errors.Wrap(bres.Error, "broadcast transaction failed: log:%s", bres.Log) + } + + return bres, nil +} + // TODO: Add more functionality, examples, and unit tests. From dabf13c705b4ac13ffd25d55a9a4a2107e335555 Mon Sep 17 00:00:00 2001 From: n3wbie Date: Tue, 14 May 2024 14:34:25 +0900 Subject: [PATCH 6/6] test: multiple txs, multiple msgs, multiple events --- gno.land/pkg/gnoclient/integration_test.go | 125 ++++++++++++++++++++- 1 file changed, 124 insertions(+), 1 deletion(-) diff --git a/gno.land/pkg/gnoclient/integration_test.go b/gno.land/pkg/gnoclient/integration_test.go index 9bcb944e21f..e602713aba8 100644 --- a/gno.land/pkg/gnoclient/integration_test.go +++ b/gno.land/pkg/gnoclient/integration_test.go @@ -3,6 +3,7 @@ package gnoclient import ( "fmt" "testing" + "time" "github.com/gnolang/gno/gnovm/pkg/gnolang" @@ -114,7 +115,7 @@ func TestCallMultiple_Integration(t *testing.T) { assert.Equal(t, expected, got) } -func TestCallMultipleWithEvent_Integration(t *testing.T) { +func TestCall_SingleTx_MultipleMsg_MultipleEvent_Integration(t *testing.T) { // Set up in-memory node config, _ := integration.TestingNodeConfig(t, gnoenv.RootDir()) node, remoteAddr := integration.TestingInMemoryNode(t, log.NewNoopLogger(), config) @@ -172,6 +173,123 @@ func TestCallMultipleWithEvent_Integration(t *testing.T) { assert.Equal(t, event1, "{1 gno.land/r/demo/event Emit TAG [{key second_value}]}") } +func TestCall_MultipleTx_MultipleMsg_MultipleEvent_Integration(t *testing.T) { + // Set up in-memory node + config, _ := integration.TestingNodeConfig(t, gnoenv.RootDir()) + + // make node slower (same as current master branch) + config.TMConfig.Consensus.TimeoutCommit = 5 * time.Second + config.TMConfig.Consensus.SkipTimeoutCommit = false + config.TMConfig.Consensus.CreateEmptyBlocks = true + config.TMConfig.Consensus.CreateEmptyBlocksInterval = 0 * time.Second + + node, remoteAddr := integration.TestingInMemoryNode(t, log.NewNoopLogger(), config) + defer node.Stop() + + // Init Signer & RPCClient + signer := newInMemorySigner(t, "tendermint_test") + assert.Equal(t, signer.Account, "test1") + + rpcClient, err := rpcclient.NewHTTPClient(remoteAddr) + require.NoError(t, err) + + // Setup Client + client := Client{ + Signer: signer, + RPCClient: rpcClient, + } + assert.Equal(t, int64(1), client.latestHeight()) + + // Make Tx config + baseCfg := BaseTxCfg{ + GasFee: "10000ugnot", + GasWanted: 8000000, + AccountNumber: 0, + SequenceNumber: 0, + Memo: "", + } + + msg1 := MsgCall{ + PkgPath: "gno.land/r/demo/event", + FuncName: "Emit", + Args: []string{"test1_1stTx_1stEvent"}, + Send: "", + } + + msg2 := MsgCall{ + PkgPath: "gno.land/r/demo/event", + FuncName: "Emit", + Args: []string{"test1_1stTx_2ndEvent"}, + Send: "", + } + _, err = client.CallTxSync(baseCfg, msg1, msg2) + assert.Nil(t, err) + assert.Equal(t, int64(1), client.latestHeight()) + + msg3 := MsgCall{ + PkgPath: "gno.land/r/demo/event", + FuncName: "Emit", + Args: []string{"test1_2ndTx_1stEvent"}, + Send: "", + } + + msg4 := MsgCall{ + PkgPath: "gno.land/r/demo/event", + FuncName: "Emit", + Args: []string{"test1_2ndTx_2ndEvent"}, + Send: "", + } + + baseCfg.SequenceNumber += 1 + _, err = client.CallTxSync(baseCfg, msg3, msg4) + assert.Nil(t, err) + assert.Equal(t, int64(1), client.latestHeight()) + + // need this dummy ?? + toAddres, _ := crypto.AddressFromBech32("g14a0y9a64dugh3l7hneshdxr4w0rfkkww9ls35p") + amount := 10 + msg5 := MsgSend{ + ToAddress: toAddres, + Send: std.Coin{"ugnot", int64(amount)}.String(), + } + baseCfg.SequenceNumber += 1 + res, err := client.Send(baseCfg, msg5) + assert.Nil(t, err) + + assert.Equal(t, int64(2), res.Height) + assert.Equal(t, int64(2), client.latestHeight()) + + latestRes, _ := client.BlockResult(res.Height) + assert.Equal(t, int(3), len(latestRes.Results.DeliverTxs)) + + beforeRes, _ := client.BlockResult(res.Height - 1) + assert.Equal(t, int(0), len(beforeRes.Results.DeliverTxs)) + + // 1st TX + tx0 := latestRes.Results.DeliverTxs[0] + assert.Equal(t, int(2), len(tx0.Events)) + + tx0evt0 := fmt.Sprint(tx0.Events[0]) + assert.Equal(t, "{0 gno.land/r/demo/event Emit TAG [{key test1_1stTx_1stEvent}]}", tx0evt0) + + tx0evt1 := fmt.Sprint(tx0.Events[1]) + assert.Equal(t, "{1 gno.land/r/demo/event Emit TAG [{key test1_1stTx_2ndEvent}]}", tx0evt1) + + // 2nd TX + tx1 := latestRes.Results.DeliverTxs[1] + assert.Equal(t, int(2), len(tx1.Events)) + + tx1evt0 := fmt.Sprint(tx1.Events[0]) + assert.Equal(t, "{0 gno.land/r/demo/event Emit TAG [{key test1_2ndTx_1stEvent}]}", tx1evt0) + + tx1evt1 := fmt.Sprint(tx1.Events[1]) + assert.Equal(t, "{1 gno.land/r/demo/event Emit TAG [{key test1_2ndTx_2ndEvent}]}", tx1evt1) + + // 3rd TX == no event + tx2 := latestRes.Results.DeliverTxs[2] + assert.Equal(t, int(0), len(tx2.Events)) +} + func TestSendSingle_Integration(t *testing.T) { // Set up in-memory node config, _ := integration.TestingNodeConfig(t, gnoenv.RootDir()) @@ -614,3 +732,8 @@ func newInMemorySigner(t *testing.T, chainid string) *SignerFromKeybase { ChainID: chainid, // Chain ID for transaction signing } } + +func (c *Client) latestHeight() int64 { + height, _ := c.LatestBlockHeight() + return height +}