Skip to content

Commit 651f5aa

Browse files
authored
chore: In gnoclient, separate out SignTx and BroadcastTxCommit (#2641)
We can use `gnokey maketx call`, `gnokey sign` and `gnokey broadcast` to make a transaction and sign it separately before broadcast. We want to support the same thing in the `gnoclient` API. (And we want to expose this API in Gno Native Kit.) * Split out new API function `NewCallTx` from `Call` * Split out new API function `NewRunTx` from `Run` * Split out new API function `NewSendTx` from `Send` * Split out new API function `NewAddPackageTx` from `AddPackage` * Split out new API functions `SignTx` and `BroadcastTxCommit` from `signAndBroadcastTxCommit` * In client_test.go and integration_test.go, add code to also test signing separately <details><summary>Contributors' checklist...</summary> - [x] Added new tests, or not needed, or not feasible - [x] Provided an example (e.g. screenshot) to aid review or the PR is self-explanatory - [x] Updated the official documentation or not needed - [x] No breaking changes were made, or a `BREAKING CHANGE: xxx` message was included in the description </details> --------- Signed-off-by: Jeff Thompson <[email protected]>
1 parent b7dbed9 commit 651f5aa

File tree

3 files changed

+230
-19
lines changed

3 files changed

+230
-19
lines changed

gno.land/pkg/gnoclient/client_test.go

Lines changed: 85 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -115,7 +115,13 @@ func TestCallSingle(t *testing.T) {
115115
res, err := client.Call(cfg, msg...)
116116
assert.NoError(t, err)
117117
require.NotNil(t, res)
118-
assert.Equal(t, string(res.DeliverTx.Data), "it works!")
118+
expected := "it works!"
119+
assert.Equal(t, string(res.DeliverTx.Data), expected)
120+
121+
res, err = callSigningSeparately(t, client, cfg, msg...)
122+
assert.NoError(t, err)
123+
require.NotNil(t, res)
124+
assert.Equal(t, string(res.DeliverTx.Data), expected)
119125
}
120126

121127
func TestCallMultiple(t *testing.T) {
@@ -192,6 +198,10 @@ func TestCallMultiple(t *testing.T) {
192198
res, err := client.Call(cfg, msg...)
193199
assert.NoError(t, err)
194200
assert.NotNil(t, res)
201+
202+
res, err = callSigningSeparately(t, client, cfg, msg...)
203+
assert.NoError(t, err)
204+
assert.NotNil(t, res)
195205
}
196206

197207
func TestCallErrors(t *testing.T) {
@@ -656,7 +666,13 @@ func main() {
656666
res, err := client.Run(cfg, msg)
657667
assert.NoError(t, err)
658668
require.NotNil(t, res)
659-
assert.Equal(t, "hi gnoclient!\n", string(res.DeliverTx.Data))
669+
expected := "hi gnoclient!\n"
670+
assert.Equal(t, expected, string(res.DeliverTx.Data))
671+
672+
res, err = runSigningSeparately(t, client, cfg, msg)
673+
assert.NoError(t, err)
674+
require.NotNil(t, res)
675+
assert.Equal(t, expected, string(res.DeliverTx.Data))
660676
}
661677

662678
func TestRunMultiple(t *testing.T) {
@@ -740,7 +756,13 @@ func main() {
740756
res, err := client.Run(cfg, msg1, msg2)
741757
assert.NoError(t, err)
742758
require.NotNil(t, res)
743-
assert.Equal(t, "hi gnoclient!\nhi gnoclient!\n", string(res.DeliverTx.Data))
759+
expected := "hi gnoclient!\nhi gnoclient!\n"
760+
assert.Equal(t, expected, string(res.DeliverTx.Data))
761+
762+
res, err = runSigningSeparately(t, client, cfg, msg1, msg2)
763+
assert.NoError(t, err)
764+
require.NotNil(t, res)
765+
assert.Equal(t, expected, string(res.DeliverTx.Data))
744766
}
745767

746768
func TestRunErrors(t *testing.T) {
@@ -1326,3 +1348,63 @@ func TestLatestBlockHeightErrors(t *testing.T) {
13261348
})
13271349
}
13281350
}
1351+
1352+
// The same as client.Call, but test signing separately
1353+
func callSigningSeparately(t *testing.T, client Client, cfg BaseTxCfg, msgs ...vm.MsgCall) (*ctypes.ResultBroadcastTxCommit, error) {
1354+
t.Helper()
1355+
tx, err := NewCallTx(cfg, msgs...)
1356+
assert.NoError(t, err)
1357+
require.NotNil(t, tx)
1358+
signedTx, err := client.SignTx(*tx, cfg.AccountNumber, cfg.SequenceNumber)
1359+
assert.NoError(t, err)
1360+
require.NotNil(t, signedTx)
1361+
res, err := client.BroadcastTxCommit(signedTx)
1362+
assert.NoError(t, err)
1363+
require.NotNil(t, res)
1364+
return res, nil
1365+
}
1366+
1367+
// The same as client.Run, but test signing separately
1368+
func runSigningSeparately(t *testing.T, client Client, cfg BaseTxCfg, msgs ...vm.MsgRun) (*ctypes.ResultBroadcastTxCommit, error) {
1369+
t.Helper()
1370+
tx, err := NewRunTx(cfg, msgs...)
1371+
assert.NoError(t, err)
1372+
require.NotNil(t, tx)
1373+
signedTx, err := client.SignTx(*tx, cfg.AccountNumber, cfg.SequenceNumber)
1374+
assert.NoError(t, err)
1375+
require.NotNil(t, signedTx)
1376+
res, err := client.BroadcastTxCommit(signedTx)
1377+
assert.NoError(t, err)
1378+
require.NotNil(t, res)
1379+
return res, nil
1380+
}
1381+
1382+
// The same as client.Send, but test signing separately
1383+
func sendSigningSeparately(t *testing.T, client Client, cfg BaseTxCfg, msgs ...bank.MsgSend) (*ctypes.ResultBroadcastTxCommit, error) {
1384+
t.Helper()
1385+
tx, err := NewSendTx(cfg, msgs...)
1386+
assert.NoError(t, err)
1387+
require.NotNil(t, tx)
1388+
signedTx, err := client.SignTx(*tx, cfg.AccountNumber, cfg.SequenceNumber)
1389+
assert.NoError(t, err)
1390+
require.NotNil(t, signedTx)
1391+
res, err := client.BroadcastTxCommit(signedTx)
1392+
assert.NoError(t, err)
1393+
require.NotNil(t, res)
1394+
return res, nil
1395+
}
1396+
1397+
// The same as client.AddPackage, but test signing separately
1398+
func addPackageSigningSeparately(t *testing.T, client Client, cfg BaseTxCfg, msgs ...vm.MsgAddPackage) (*ctypes.ResultBroadcastTxCommit, error) {
1399+
t.Helper()
1400+
tx, err := NewAddPackageTx(cfg, msgs...)
1401+
assert.NoError(t, err)
1402+
require.NotNil(t, tx)
1403+
signedTx, err := client.SignTx(*tx, cfg.AccountNumber, cfg.SequenceNumber)
1404+
assert.NoError(t, err)
1405+
require.NotNil(t, signedTx)
1406+
res, err := client.BroadcastTxCommit(signedTx)
1407+
assert.NoError(t, err)
1408+
require.NotNil(t, res)
1409+
return res, nil
1410+
}

gno.land/pkg/gnoclient/client_txs.go

Lines changed: 69 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -35,6 +35,16 @@ func (c *Client) Call(cfg BaseTxCfg, msgs ...vm.MsgCall) (*ctypes.ResultBroadcas
3535
return nil, err
3636
}
3737

38+
tx, err := NewCallTx(cfg, msgs...)
39+
if err != nil {
40+
return nil, err
41+
}
42+
return c.signAndBroadcastTxCommit(*tx, cfg.AccountNumber, cfg.SequenceNumber)
43+
}
44+
45+
// NewCallTx makes an unsigned transaction from one or more MsgCall.
46+
// The Caller field must be set.
47+
func NewCallTx(cfg BaseTxCfg, msgs ...vm.MsgCall) (*std.Tx, error) {
3848
// Validate base transaction config
3949
if err := cfg.validateBaseTxConfig(); err != nil {
4050
return nil, err
@@ -57,14 +67,12 @@ func (c *Client) Call(cfg BaseTxCfg, msgs ...vm.MsgCall) (*ctypes.ResultBroadcas
5767
}
5868

5969
// Pack transaction
60-
tx := std.Tx{
70+
return &std.Tx{
6171
Msgs: vmMsgs,
6272
Fee: std.NewFee(cfg.GasWanted, gasFeeCoins),
6373
Signatures: nil,
6474
Memo: cfg.Memo,
65-
}
66-
67-
return c.signAndBroadcastTxCommit(tx, cfg.AccountNumber, cfg.SequenceNumber)
75+
}, nil
6876
}
6977

7078
// Run executes one or more MsgRun calls on the blockchain
@@ -77,6 +85,16 @@ func (c *Client) Run(cfg BaseTxCfg, msgs ...vm.MsgRun) (*ctypes.ResultBroadcastT
7785
return nil, err
7886
}
7987

88+
tx, err := NewRunTx(cfg, msgs...)
89+
if err != nil {
90+
return nil, err
91+
}
92+
return c.signAndBroadcastTxCommit(*tx, cfg.AccountNumber, cfg.SequenceNumber)
93+
}
94+
95+
// NewRunTx makes an unsigned transaction from one or more MsgRun.
96+
// The Caller field must be set.
97+
func NewRunTx(cfg BaseTxCfg, msgs ...vm.MsgRun) (*std.Tx, error) {
8098
// Validate base transaction config
8199
if err := cfg.validateBaseTxConfig(); err != nil {
82100
return nil, err
@@ -99,14 +117,12 @@ func (c *Client) Run(cfg BaseTxCfg, msgs ...vm.MsgRun) (*ctypes.ResultBroadcastT
99117
}
100118

101119
// Pack transaction
102-
tx := std.Tx{
120+
return &std.Tx{
103121
Msgs: vmMsgs,
104122
Fee: std.NewFee(cfg.GasWanted, gasFeeCoins),
105123
Signatures: nil,
106124
Memo: cfg.Memo,
107-
}
108-
109-
return c.signAndBroadcastTxCommit(tx, cfg.AccountNumber, cfg.SequenceNumber)
125+
}, nil
110126
}
111127

112128
// Send executes one or more MsgSend calls on the blockchain
@@ -119,6 +135,16 @@ func (c *Client) Send(cfg BaseTxCfg, msgs ...bank.MsgSend) (*ctypes.ResultBroadc
119135
return nil, err
120136
}
121137

138+
tx, err := NewSendTx(cfg, msgs...)
139+
if err != nil {
140+
return nil, err
141+
}
142+
return c.signAndBroadcastTxCommit(*tx, cfg.AccountNumber, cfg.SequenceNumber)
143+
}
144+
145+
// NewSendTx makes an unsigned transaction from one or more MsgSend.
146+
// The FromAddress field must be set.
147+
func NewSendTx(cfg BaseTxCfg, msgs ...bank.MsgSend) (*std.Tx, error) {
122148
// Validate base transaction config
123149
if err := cfg.validateBaseTxConfig(); err != nil {
124150
return nil, err
@@ -141,14 +167,12 @@ func (c *Client) Send(cfg BaseTxCfg, msgs ...bank.MsgSend) (*ctypes.ResultBroadc
141167
}
142168

143169
// Pack transaction
144-
tx := std.Tx{
170+
return &std.Tx{
145171
Msgs: vmMsgs,
146172
Fee: std.NewFee(cfg.GasWanted, gasFeeCoins),
147173
Signatures: nil,
148174
Memo: cfg.Memo,
149-
}
150-
151-
return c.signAndBroadcastTxCommit(tx, cfg.AccountNumber, cfg.SequenceNumber)
175+
}, nil
152176
}
153177

154178
// AddPackage executes one or more AddPackage calls on the blockchain
@@ -161,6 +185,16 @@ func (c *Client) AddPackage(cfg BaseTxCfg, msgs ...vm.MsgAddPackage) (*ctypes.Re
161185
return nil, err
162186
}
163187

188+
tx, err := NewAddPackageTx(cfg, msgs...)
189+
if err != nil {
190+
return nil, err
191+
}
192+
return c.signAndBroadcastTxCommit(*tx, cfg.AccountNumber, cfg.SequenceNumber)
193+
}
194+
195+
// NewAddPackageTx makes an unsigned transaction from one or more MsgAddPackage.
196+
// The Creator field must be set.
197+
func NewAddPackageTx(cfg BaseTxCfg, msgs ...vm.MsgAddPackage) (*std.Tx, error) {
164198
// Validate base transaction config
165199
if err := cfg.validateBaseTxConfig(); err != nil {
166200
return nil, err
@@ -183,18 +217,29 @@ func (c *Client) AddPackage(cfg BaseTxCfg, msgs ...vm.MsgAddPackage) (*ctypes.Re
183217
}
184218

185219
// Pack transaction
186-
tx := std.Tx{
220+
return &std.Tx{
187221
Msgs: vmMsgs,
188222
Fee: std.NewFee(cfg.GasWanted, gasFeeCoins),
189223
Signatures: nil,
190224
Memo: cfg.Memo,
191-
}
192-
193-
return c.signAndBroadcastTxCommit(tx, cfg.AccountNumber, cfg.SequenceNumber)
225+
}, nil
194226
}
195227

196228
// signAndBroadcastTxCommit signs a transaction and broadcasts it, returning the result
197229
func (c *Client) signAndBroadcastTxCommit(tx std.Tx, accountNumber, sequenceNumber uint64) (*ctypes.ResultBroadcastTxCommit, error) {
230+
signedTx, err := c.SignTx(tx, accountNumber, sequenceNumber)
231+
if err != nil {
232+
return nil, err
233+
}
234+
return c.BroadcastTxCommit(signedTx)
235+
}
236+
237+
// SignTx signs a transaction and returns a signed tx ready for broadcasting.
238+
// If accountNumber or sequenceNumber is 0 then query the blockchain for the value.
239+
func (c *Client) SignTx(tx std.Tx, accountNumber, sequenceNumber uint64) (*std.Tx, error) {
240+
if err := c.validateSigner(); err != nil {
241+
return nil, err
242+
}
198243
caller, err := c.Signer.Info()
199244
if err != nil {
200245
return nil, err
@@ -218,7 +263,15 @@ func (c *Client) signAndBroadcastTxCommit(tx std.Tx, accountNumber, sequenceNumb
218263
if err != nil {
219264
return nil, errors.Wrap(err, "sign")
220265
}
266+
return signedTx, nil
267+
}
221268

269+
// BroadcastTxCommit marshals and broadcasts the signed transaction, returning the result.
270+
// If the result has a delivery error, then return a wrapped error.
271+
func (c *Client) BroadcastTxCommit(signedTx *std.Tx) (*ctypes.ResultBroadcastTxCommit, error) {
272+
if err := c.validateRPCClient(); err != nil {
273+
return nil, err
274+
}
222275
bz, err := amino.Marshal(signedTx)
223276
if err != nil {
224277
return nil, errors.Wrap(err, "marshaling tx binary bytes")

0 commit comments

Comments
 (0)