actor: fix event-based tx awaiting
If VUB-th block is received, we still can't guaranty that transaction wasn't accepted to chain. Back this situation by rolling back to a poll-based waiter.
This commit is contained in:
parent
6dbae7edc4
commit
95e23c8e46
3 changed files with 62 additions and 2 deletions
|
@ -304,13 +304,17 @@ func (w *EventWaiter) WaitAny(ctx context.Context, vub uint32, hashes ...util.Ui
|
||||||
}
|
}
|
||||||
|
|
||||||
select {
|
select {
|
||||||
case _, ok := <-bRcvr:
|
case b, ok := <-bRcvr:
|
||||||
if !ok {
|
if !ok {
|
||||||
// We're toast, retry with non-ws client.
|
// We're toast, retry with non-ws client.
|
||||||
wsWaitErr = ErrMissedEvent
|
wsWaitErr = ErrMissedEvent
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
waitErr = ErrTxNotAccepted
|
// We can easily end up in a situation when subscription was performed too late and
|
||||||
|
// the desired transaction and VUB-th block have already got accepted before the
|
||||||
|
// subscription happened. Thus, always retry with non-ws client, it will perform
|
||||||
|
// AER requests and make sure.
|
||||||
|
wsWaitErr = fmt.Errorf("block #%d was received by EventWaiter", b.Index)
|
||||||
case aer, ok := <-aerRcvr:
|
case aer, ok := <-aerRcvr:
|
||||||
if !ok {
|
if !ok {
|
||||||
// We're toast, retry with non-ws client.
|
// We're toast, retry with non-ws client.
|
||||||
|
|
|
@ -166,6 +166,7 @@ func TestWSWaiter_Wait(t *testing.T) {
|
||||||
})
|
})
|
||||||
|
|
||||||
// Missing AER after VUB.
|
// Missing AER after VUB.
|
||||||
|
c.RPCClient.appLog = nil
|
||||||
go func() {
|
go func() {
|
||||||
_, err = w.Wait(h, bCount-2, nil)
|
_, err = w.Wait(h, bCount-2, nil)
|
||||||
require.ErrorIs(t, err, ErrTxNotAccepted)
|
require.ErrorIs(t, err, ErrTxNotAccepted)
|
||||||
|
|
|
@ -2073,3 +2073,58 @@ func TestWSClient_Wait(t *testing.T) {
|
||||||
}
|
}
|
||||||
require.True(t, faultedChecked, "FAULTed transaction wasn't checked")
|
require.True(t, faultedChecked, "FAULTed transaction wasn't checked")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func TestWSClient_WaitWithLateSubscription(t *testing.T) {
|
||||||
|
chain, rpcSrv, httpSrv := initClearServerWithServices(t, false, false, true)
|
||||||
|
defer chain.Close()
|
||||||
|
defer rpcSrv.Shutdown()
|
||||||
|
|
||||||
|
url := "ws" + strings.TrimPrefix(httpSrv.URL, "http") + "/ws"
|
||||||
|
c, err := rpcclient.NewWS(context.Background(), url, rpcclient.Options{})
|
||||||
|
require.NoError(t, err)
|
||||||
|
require.NoError(t, c.Init())
|
||||||
|
acc, err := wallet.NewAccount()
|
||||||
|
require.NoError(t, err)
|
||||||
|
act, err := actor.New(c, []actor.SignerAccount{
|
||||||
|
{
|
||||||
|
Signer: transaction.Signer{
|
||||||
|
Account: acc.ScriptHash(),
|
||||||
|
},
|
||||||
|
Account: acc,
|
||||||
|
},
|
||||||
|
})
|
||||||
|
require.NoError(t, err)
|
||||||
|
|
||||||
|
// Firstly, accept the block.
|
||||||
|
blocks := getTestBlocks(t)
|
||||||
|
b1 := blocks[0]
|
||||||
|
b2 := blocks[1]
|
||||||
|
tx := b1.Transactions[0]
|
||||||
|
require.NoError(t, chain.AddBlock(b1))
|
||||||
|
|
||||||
|
// After that, subscribe for AERs/blocks and wait.
|
||||||
|
rcvr := make(chan *state.AppExecResult)
|
||||||
|
go func() {
|
||||||
|
aer, err := act.Wait(tx.Hash(), tx.ValidUntilBlock, nil)
|
||||||
|
require.NoError(t, err)
|
||||||
|
rcvr <- aer
|
||||||
|
}()
|
||||||
|
|
||||||
|
// Accept the next block to trigger event-based waiter loop exit and rollback to
|
||||||
|
// poll-based waiter.
|
||||||
|
require.NoError(t, chain.AddBlock(b2))
|
||||||
|
|
||||||
|
// Wait for the result.
|
||||||
|
waitloop:
|
||||||
|
for {
|
||||||
|
select {
|
||||||
|
case aer := <-rcvr:
|
||||||
|
require.Equal(t, tx.Hash(), aer.Container)
|
||||||
|
require.Equal(t, trigger.Application, aer.Trigger)
|
||||||
|
require.Equal(t, vmstate.Halt, aer.VMState)
|
||||||
|
break waitloop
|
||||||
|
case <-time.NewTimer(time.Duration(chain.GetConfig().SecondsPerBlock) * time.Second).C:
|
||||||
|
t.Fatal("transaction failed to be awaited")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
Loading…
Reference in a new issue