From 8336b1b518d9b9253f1f828784365b5d63c172cf Mon Sep 17 00:00:00 2001 From: Roman Khimov Date: Thu, 20 Jun 2024 17:12:35 +0300 Subject: [PATCH 1/2] invoker: add Signers() API Signers are very important for notary checks and keeping/passing an additional copy of them is very inconvenient. Exposing them from invoker makes them available in actors too. Signed-off-by: Roman Khimov --- pkg/rpcclient/invoker/invoker.go | 14 ++++++++++++++ pkg/rpcclient/invoker/invoker_test.go | 16 ++++++++++++++++ 2 files changed, 30 insertions(+) diff --git a/pkg/rpcclient/invoker/invoker.go b/pkg/rpcclient/invoker/invoker.go index a56be5942..a40a0c2dd 100644 --- a/pkg/rpcclient/invoker/invoker.go +++ b/pkg/rpcclient/invoker/invoker.go @@ -137,6 +137,20 @@ func (h *historicConverter) TraverseIterator(sessionID, iteratorID uuid.UUID, ma return h.client.TraverseIterator(sessionID, iteratorID, maxItemsCount) } +// Signers returns the set of current invoker signers which is mostly useful +// when working with upper-layer actors. Returned slice is a newly allocated +// one (if this invoker has them), so it's safe to modify. +func (v *Invoker) Signers() []transaction.Signer { + if v.signers == nil { + return nil + } + var res = make([]transaction.Signer, len(v.signers)) + for i := range v.signers { + res[i] = *v.signers[i].Copy() + } + return res +} + // Call invokes a method of the contract with the given parameters (and // Invoker-specific list of signers) and returns the result as is. func (v *Invoker) Call(contract util.Uint160, operation string, params ...any) (*result.Invoke, error) { diff --git a/pkg/rpcclient/invoker/invoker_test.go b/pkg/rpcclient/invoker/invoker_test.go index 5d5a6159f..39b21bcaf 100644 --- a/pkg/rpcclient/invoker/invoker_test.go +++ b/pkg/rpcclient/invoker/invoker_test.go @@ -158,3 +158,19 @@ func TestInvoker(t *testing.T) { } }) } + +func TestInvokerSigners(t *testing.T) { + resExp := &result.Invoke{State: "HALT"} + ri := &rpcInv{resExp, true, nil, nil} + inv := New(ri, nil) + + require.Nil(t, inv.Signers()) + + s := []transaction.Signer{} + inv = New(ri, s) + require.Equal(t, s, inv.Signers()) + + s = append(s, transaction.Signer{Account: util.Uint160{1, 2, 3}, Scopes: transaction.CalledByEntry}) + inv = New(ri, s) + require.Equal(t, s, inv.Signers()) +} From cc3f528eb66ed50818d1ac3e0c1c68ad321d3b31 Mon Sep 17 00:00:00 2001 From: Roman Khimov Date: Fri, 21 Jun 2024 09:48:15 +0300 Subject: [PATCH 2/2] actor: add SignerAccounts() API Allow to retrieve the list easily. Signed-off-by: Roman Khimov --- pkg/rpcclient/actor/actor.go | 13 +++++++++++++ pkg/rpcclient/actor/actor_test.go | 11 ++++++++--- 2 files changed, 21 insertions(+), 3 deletions(-) diff --git a/pkg/rpcclient/actor/actor.go b/pkg/rpcclient/actor/actor.go index 2884c3cd2..89b9a1d2a 100644 --- a/pkg/rpcclient/actor/actor.go +++ b/pkg/rpcclient/actor/actor.go @@ -280,6 +280,19 @@ func (a *Actor) SendUncheckedRun(script []byte, sysfee int64, attrs []transactio return a.sendWrapper(a.MakeUncheckedRun(script, sysfee, attrs, txHook)) } +// SignerAccounts returns the array of actor's signers/accounts. It's useful in +// case you need it elsewhere like for notary-related processing. Returned slice +// is a newly allocated one with signers deeply copied, accounts however are not +// so changing received account internals is an error. +func (a *Actor) SignerAccounts() []SignerAccount { + var res = make([]SignerAccount, len(a.signers)) + for i := range a.signers { + res[i].Signer = *a.signers[i].Signer.Copy() + res[i].Account = a.signers[i].Account + } + return res +} + // Sender return the sender address that will be used in transactions created // by Actor. func (a *Actor) Sender() util.Uint160 { diff --git a/pkg/rpcclient/actor/actor_test.go b/pkg/rpcclient/actor/actor_test.go index 4bd1b98a8..1dc120129 100644 --- a/pkg/rpcclient/actor/actor_test.go +++ b/pkg/rpcclient/actor/actor_test.go @@ -101,9 +101,14 @@ func TestNew(t *testing.T) { // Good simple. a, err := NewSimple(client, acc) require.NoError(t, err) - require.Equal(t, 1, len(a.signers)) + require.Equal(t, []SignerAccount{{ + Signer: transaction.Signer{ + Account: acc.ScriptHash(), + Scopes: transaction.CalledByEntry, + }, + Account: acc, + }}, a.SignerAccounts()) require.Equal(t, 1, len(a.txSigners)) - require.Equal(t, transaction.CalledByEntry, a.signers[0].Signer.Scopes) require.Equal(t, transaction.CalledByEntry, a.txSigners[0].Scopes) // Contractless account. @@ -158,7 +163,7 @@ func TestNew(t *testing.T) { signers[0].Signer.Account = acc.Contract.ScriptHash() a, err = New(client, signers) require.NoError(t, err) - require.Equal(t, 2, len(a.signers)) + require.Equal(t, signers, a.SignerAccounts()) require.Equal(t, 2, len(a.txSigners)) // Good tuned