diff --git a/pkg/rpcclient/actor/actor.go b/pkg/rpcclient/actor/actor.go index bf3ec334e..e81a581da 100644 --- a/pkg/rpcclient/actor/actor.go +++ b/pkg/rpcclient/actor/actor.go @@ -17,6 +17,7 @@ import ( "github.com/nspcc-dev/neo-go/pkg/core/transaction" "github.com/nspcc-dev/neo-go/pkg/neorpc/result" "github.com/nspcc-dev/neo-go/pkg/rpcclient/invoker" + "github.com/nspcc-dev/neo-go/pkg/rpcclient/waiter" "github.com/nspcc-dev/neo-go/pkg/util" "github.com/nspcc-dev/neo-go/pkg/wallet" ) @@ -72,7 +73,7 @@ type SignerAccount struct { // and ErrTxNotAccepted is returned if transaction wasn't accepted by this moment. type Actor struct { invoker.Invoker - Waiter + waiter.Waiter client RPCActor opts Options @@ -126,7 +127,7 @@ func New(ra RPCActor, signers []SignerAccount) (*Actor, error) { } return &Actor{ Invoker: *inv, - Waiter: NewWaiter(ra, version), + Waiter: waiter.New(ra, version), client: ra, opts: NewDefaultOptions(), signers: signers, diff --git a/pkg/rpcclient/actor/compat_test.go b/pkg/rpcclient/actor/compat_test.go index b8e356898..874025d14 100644 --- a/pkg/rpcclient/actor/compat_test.go +++ b/pkg/rpcclient/actor/compat_test.go @@ -11,9 +11,3 @@ func TestRPCActorRPCClientCompat(t *testing.T) { _ = actor.RPCActor(&rpcclient.WSClient{}) _ = actor.RPCActor(&rpcclient.Client{}) } - -func TestRPCWaiterRPCClientCompat(t *testing.T) { - _ = actor.RPCPollingWaiter(&rpcclient.Client{}) - _ = actor.RPCPollingWaiter(&rpcclient.WSClient{}) - _ = actor.RPCEventWaiter(&rpcclient.WSClient{}) -} diff --git a/pkg/rpcclient/notary/actor_test.go b/pkg/rpcclient/notary/actor_test.go index 16fc7ce4c..ccda87c5b 100644 --- a/pkg/rpcclient/notary/actor_test.go +++ b/pkg/rpcclient/notary/actor_test.go @@ -15,6 +15,7 @@ import ( "github.com/nspcc-dev/neo-go/pkg/network/payload" "github.com/nspcc-dev/neo-go/pkg/rpcclient/actor" "github.com/nspcc-dev/neo-go/pkg/rpcclient/invoker" + "github.com/nspcc-dev/neo-go/pkg/rpcclient/waiter" "github.com/nspcc-dev/neo-go/pkg/smartcontract" "github.com/nspcc-dev/neo-go/pkg/smartcontract/trigger" "github.com/nspcc-dev/neo-go/pkg/util" @@ -78,7 +79,7 @@ func (r *RPCClient) GetApplicationLog(hash util.Uint256, trig *trigger.Type) (*r return r.applog, nil } -var _ = actor.RPCPollingWaiter(&RPCClient{}) +var _ = waiter.RPCPollingWaiter(&RPCClient{}) func TestNewActor(t *testing.T) { rc := &RPCClient{ diff --git a/pkg/rpcclient/actor/waiter.go b/pkg/rpcclient/waiter/waiter.go similarity index 98% rename from pkg/rpcclient/actor/waiter.go rename to pkg/rpcclient/waiter/waiter.go index 183660846..dd17e2a19 100644 --- a/pkg/rpcclient/actor/waiter.go +++ b/pkg/rpcclient/waiter/waiter.go @@ -1,4 +1,4 @@ -package actor +package waiter import ( "context" @@ -100,12 +100,12 @@ func errIsAlreadyExists(err error) bool { return strings.Contains(strings.ToLower(err.Error()), "already exists") } -// NewWaiter creates Waiter instance. It can be either websocket-based or +// New creates Waiter instance. It can be either websocket-based or // polling-base, otherwise Waiter stub is returned. As a first argument // it accepts RPCEventWaiter implementation, RPCPollingWaiter implementation // or not an implementation of these two interfaces. It returns websocket-based // waiter, polling-based waiter or a stub correspondingly. -func NewWaiter(base any, v *result.Version) Waiter { +func New(base any, v *result.Version) Waiter { if eventW, ok := base.(RPCEventWaiter); ok { return &EventWaiter{ ws: eventW, diff --git a/pkg/rpcclient/actor/waiter_test.go b/pkg/rpcclient/waiter/waiter_test.go similarity index 55% rename from pkg/rpcclient/actor/waiter_test.go rename to pkg/rpcclient/waiter/waiter_test.go index 495e62815..1eaff101a 100644 --- a/pkg/rpcclient/actor/waiter_test.go +++ b/pkg/rpcclient/waiter/waiter_test.go @@ -1,20 +1,82 @@ -package actor +package waiter_test import ( "context" "errors" "sync" + "sync/atomic" "testing" "time" + "github.com/google/uuid" "github.com/nspcc-dev/neo-go/pkg/core/block" "github.com/nspcc-dev/neo-go/pkg/core/state" + "github.com/nspcc-dev/neo-go/pkg/core/transaction" "github.com/nspcc-dev/neo-go/pkg/neorpc" "github.com/nspcc-dev/neo-go/pkg/neorpc/result" + "github.com/nspcc-dev/neo-go/pkg/rpcclient" + "github.com/nspcc-dev/neo-go/pkg/rpcclient/actor" + "github.com/nspcc-dev/neo-go/pkg/rpcclient/waiter" + "github.com/nspcc-dev/neo-go/pkg/smartcontract" + "github.com/nspcc-dev/neo-go/pkg/smartcontract/trigger" "github.com/nspcc-dev/neo-go/pkg/util" + "github.com/nspcc-dev/neo-go/pkg/vm/stackitem" "github.com/stretchr/testify/require" ) +type RPCClient struct { + err error + invRes *result.Invoke + netFee int64 + bCount atomic.Uint32 + version *result.Version + hash util.Uint256 + appLog *result.ApplicationLog + context context.Context +} + +func (r *RPCClient) InvokeContractVerify(contract util.Uint160, params []smartcontract.Parameter, signers []transaction.Signer, witnesses ...transaction.Witness) (*result.Invoke, error) { + return r.invRes, r.err +} +func (r *RPCClient) InvokeFunction(contract util.Uint160, operation string, params []smartcontract.Parameter, signers []transaction.Signer) (*result.Invoke, error) { + return r.invRes, r.err +} +func (r *RPCClient) InvokeScript(script []byte, signers []transaction.Signer) (*result.Invoke, error) { + return r.invRes, r.err +} +func (r *RPCClient) CalculateNetworkFee(tx *transaction.Transaction) (int64, error) { + return r.netFee, r.err +} +func (r *RPCClient) GetBlockCount() (uint32, error) { + return r.bCount.Load(), r.err +} +func (r *RPCClient) GetVersion() (*result.Version, error) { + verCopy := *r.version + return &verCopy, r.err +} +func (r *RPCClient) SendRawTransaction(tx *transaction.Transaction) (util.Uint256, error) { + return r.hash, r.err +} +func (r *RPCClient) TerminateSession(sessionID uuid.UUID) (bool, error) { + return false, nil // Just a stub, unused by actor. +} +func (r *RPCClient) TraverseIterator(sessionID, iteratorID uuid.UUID, maxItemsCount int) ([]stackitem.Item, error) { + return nil, nil // Just a stub, unused by actor. +} +func (r *RPCClient) Context() context.Context { + if r.context == nil { + return context.Background() + } + return r.context +} + +func (r *RPCClient) GetApplicationLog(hash util.Uint256, trig *trigger.Type) (*result.ApplicationLog, error) { + if r.appLog != nil { + return r.appLog, nil + } + return nil, errors.New("not found") +} + type AwaitableRPCClient struct { RPCClient @@ -38,16 +100,16 @@ func (c *AwaitableRPCClient) ReceiveExecutions(flt *neorpc.ExecutionFilter, rcvr func (c *AwaitableRPCClient) Unsubscribe(id string) error { return nil } func TestNewWaiter(t *testing.T) { - w := NewWaiter((RPCActor)(nil), nil) - _, ok := w.(NullWaiter) + w := waiter.New((actor.RPCActor)(nil), nil) + _, ok := w.(waiter.NullWaiter) require.True(t, ok) - w = NewWaiter(&RPCClient{}, &result.Version{}) - _, ok = w.(*PollingWaiter) + w = waiter.New(&RPCClient{}, &result.Version{}) + _, ok = w.(*waiter.PollingWaiter) require.True(t, ok) - w = NewWaiter(&AwaitableRPCClient{RPCClient: RPCClient{}}, &result.Version{}) - _, ok = w.(*EventWaiter) + w = waiter.New(&AwaitableRPCClient{RPCClient: RPCClient{}}, &result.Version{}) + _, ok = w.(*waiter.EventWaiter) require.True(t, ok) } @@ -58,8 +120,8 @@ func TestPollingWaiter_Wait(t *testing.T) { expected := &state.AppExecResult{Container: h, Execution: state.Execution{}} c := &RPCClient{appLog: appLog} c.bCount.Store(bCount) - w := NewWaiter(c, &result.Version{Protocol: result.Protocol{MillisecondsPerBlock: 1}}) // reduce testing time. - _, ok := w.(*PollingWaiter) + w := waiter.New(c, &result.Version{Protocol: result.Protocol{MillisecondsPerBlock: 1}}) // reduce testing time. + _, ok := w.(*waiter.PollingWaiter) require.True(t, ok) // Wait with error. @@ -75,7 +137,7 @@ func TestPollingWaiter_Wait(t *testing.T) { // Missing AER after VUB. c.appLog = nil _, err = w.Wait(h, bCount-2, nil) - require.ErrorIs(t, ErrTxNotAccepted, err) + require.ErrorIs(t, waiter.ErrTxNotAccepted, err) checkErr := func(t *testing.T, trigger func(), target error) { errCh := make(chan error) @@ -106,14 +168,14 @@ func TestPollingWaiter_Wait(t *testing.T) { // Tx is accepted before VUB. c.appLog = nil c.bCount.Store(bCount) - checkErr(t, func() { c.bCount.Store(bCount + 1) }, ErrTxNotAccepted) + checkErr(t, func() { c.bCount.Store(bCount + 1) }, waiter.ErrTxNotAccepted) // Context is cancelled. c.appLog = nil c.bCount.Store(bCount) ctx, cancel := context.WithCancel(context.Background()) c.context = ctx - checkErr(t, cancel, ErrContextDone) + checkErr(t, cancel, waiter.ErrContextDone) } func TestWSWaiter_Wait(t *testing.T) { @@ -123,8 +185,8 @@ func TestWSWaiter_Wait(t *testing.T) { expected := &state.AppExecResult{Container: h, Execution: state.Execution{}} c := &AwaitableRPCClient{RPCClient: RPCClient{appLog: appLog}} c.bCount.Store(bCount) - w := NewWaiter(c, &result.Version{Protocol: result.Protocol{MillisecondsPerBlock: 1}}) // reduce testing time. - _, ok := w.(*EventWaiter) + w := waiter.New(c, &result.Version{Protocol: result.Protocol{MillisecondsPerBlock: 1}}) // reduce testing time. + _, ok := w.(*waiter.EventWaiter) require.True(t, ok) // Wait with error. @@ -176,7 +238,7 @@ func TestWSWaiter_Wait(t *testing.T) { // Missing AER after VUB. go func() { _, err = w.Wait(h, bCount-2, nil) - require.ErrorIs(t, err, ErrTxNotAccepted) + require.ErrorIs(t, err, waiter.ErrTxNotAccepted) doneCh <- struct{}{} }() check(t, func() { @@ -185,3 +247,9 @@ func TestWSWaiter_Wait(t *testing.T) { c.subBlockCh <- &block.Block{} }) } + +func TestRPCWaiterRPCClientCompat(t *testing.T) { + _ = waiter.RPCPollingWaiter(&rpcclient.Client{}) + _ = waiter.RPCPollingWaiter(&rpcclient.WSClient{}) + _ = waiter.RPCEventWaiter(&rpcclient.WSClient{}) +}