github.com/ethersphere/bee/v2@v2.2.0/pkg/transaction/monitor_test.go (about)

     1  // Copyright 2021 The Swarm Authors. All rights reserved.
     2  // Use of this source code is governed by a BSD-style
     3  // license that can be found in the LICENSE file.
     4  
     5  package transaction_test
     6  
     7  import (
     8  	"errors"
     9  	"testing"
    10  	"time"
    11  
    12  	"github.com/ethereum/go-ethereum/common"
    13  	"github.com/ethereum/go-ethereum/core/types"
    14  	"github.com/ethersphere/bee/v2/pkg/log"
    15  	"github.com/ethersphere/bee/v2/pkg/transaction"
    16  	"github.com/ethersphere/bee/v2/pkg/transaction/backendsimulation"
    17  )
    18  
    19  func TestMonitorWatchTransaction(t *testing.T) {
    20  	t.Parallel()
    21  
    22  	logger := log.Noop
    23  	txHash := common.HexToHash("0xabcd")
    24  	nonce := uint64(10)
    25  	sender := common.HexToAddress("0xffee")
    26  	pollingInterval := 1 * time.Millisecond
    27  	cancellationDepth := uint64(5)
    28  
    29  	testTimeout := 5 * time.Second
    30  
    31  	t.Run("single transaction confirmed", func(t *testing.T) {
    32  		t.Parallel()
    33  
    34  		monitor := transaction.NewMonitor(
    35  			logger,
    36  			backendsimulation.New(
    37  				backendsimulation.WithBlocks(
    38  					backendsimulation.Block{
    39  						Number: 0,
    40  					},
    41  					backendsimulation.Block{
    42  						Number: 1,
    43  						Receipts: map[common.Hash]*types.Receipt{
    44  							txHash: {TxHash: txHash},
    45  						},
    46  						NoncesAt: map[backendsimulation.AccountAtKey]uint64{
    47  							{
    48  								BlockNumber: 1,
    49  								Account:     sender,
    50  							}: nonce + 1,
    51  						},
    52  					},
    53  				),
    54  			),
    55  			sender,
    56  			pollingInterval,
    57  			cancellationDepth,
    58  		)
    59  
    60  		receiptC, errC, err := monitor.WatchTransaction(txHash, nonce)
    61  		if err != nil {
    62  			t.Fatal(err)
    63  		}
    64  
    65  		select {
    66  		case receipt := <-receiptC:
    67  			if receipt.TxHash != txHash {
    68  				t.Fatal("got wrong receipt")
    69  			}
    70  		case err := <-errC:
    71  			t.Fatal(err)
    72  		case <-time.After(testTimeout):
    73  			t.Fatal("timed out")
    74  		}
    75  
    76  		err = monitor.Close()
    77  		if err != nil {
    78  			t.Fatal(err)
    79  		}
    80  	})
    81  
    82  	t.Run("single transaction cancelled", func(t *testing.T) {
    83  		t.Parallel()
    84  
    85  		monitor := transaction.NewMonitor(
    86  			logger,
    87  			backendsimulation.New(
    88  				backendsimulation.WithBlocks(
    89  					backendsimulation.Block{
    90  						Number: 0,
    91  					},
    92  					backendsimulation.Block{
    93  						Number: 1,
    94  						NoncesAt: map[backendsimulation.AccountAtKey]uint64{
    95  							{
    96  								BlockNumber: 1,
    97  								Account:     sender,
    98  							}: nonce + 1,
    99  						},
   100  					},
   101  					backendsimulation.Block{
   102  						Number: 1 + cancellationDepth,
   103  						NoncesAt: map[backendsimulation.AccountAtKey]uint64{
   104  							{
   105  								BlockNumber: 1 + cancellationDepth,
   106  								Account:     sender,
   107  							}: nonce + 1,
   108  						},
   109  					},
   110  				),
   111  			),
   112  			sender,
   113  			pollingInterval,
   114  			cancellationDepth,
   115  		)
   116  
   117  		receiptC, errC, err := monitor.WatchTransaction(txHash, nonce)
   118  		if err != nil {
   119  			t.Fatal(err)
   120  		}
   121  
   122  		select {
   123  		case <-receiptC:
   124  			t.Fatal("got receipt")
   125  		case err := <-errC:
   126  			if !errors.Is(err, transaction.ErrTransactionCancelled) {
   127  				t.Fatalf("got wrong error. wanted %v, got %v", transaction.ErrTransactionCancelled, err)
   128  			}
   129  		case <-time.After(testTimeout):
   130  			t.Fatal("timed out")
   131  		}
   132  
   133  		err = monitor.Close()
   134  		if err != nil {
   135  			t.Fatal(err)
   136  		}
   137  	})
   138  
   139  	t.Run("multiple transactions mixed", func(t *testing.T) {
   140  		t.Parallel()
   141  
   142  		txHash2 := common.HexToHash("bbbb")
   143  		txHash3 := common.HexToHash("cccc")
   144  
   145  		monitor := transaction.NewMonitor(
   146  			logger,
   147  			backendsimulation.New(
   148  				backendsimulation.WithBlocks(
   149  					backendsimulation.Block{
   150  						Number: 0,
   151  					},
   152  					backendsimulation.Block{
   153  						Number: 1,
   154  						Receipts: map[common.Hash]*types.Receipt{
   155  							txHash: {TxHash: txHash},
   156  						},
   157  						NoncesAt: map[backendsimulation.AccountAtKey]uint64{
   158  							{
   159  								BlockNumber: 1,
   160  								Account:     sender,
   161  							}: nonce + 1,
   162  						},
   163  					},
   164  					backendsimulation.Block{
   165  						Number: 2,
   166  						Receipts: map[common.Hash]*types.Receipt{
   167  							txHash: {TxHash: txHash},
   168  						},
   169  						NoncesAt: map[backendsimulation.AccountAtKey]uint64{
   170  							{
   171  								BlockNumber: 2,
   172  								Account:     sender,
   173  							}: nonce + 2,
   174  						},
   175  					},
   176  					backendsimulation.Block{
   177  						Number: 3,
   178  						Receipts: map[common.Hash]*types.Receipt{
   179  							txHash:  {TxHash: txHash},
   180  							txHash3: {TxHash: txHash3},
   181  						},
   182  						NoncesAt: map[backendsimulation.AccountAtKey]uint64{
   183  							{
   184  								BlockNumber: 3,
   185  								Account:     sender,
   186  							}: nonce + 4,
   187  						},
   188  					},
   189  					backendsimulation.Block{
   190  						Number: 3 + cancellationDepth,
   191  						Receipts: map[common.Hash]*types.Receipt{
   192  							txHash:  {TxHash: txHash},
   193  							txHash3: {TxHash: txHash3},
   194  						},
   195  						NoncesAt: map[backendsimulation.AccountAtKey]uint64{
   196  							{
   197  								BlockNumber: 3 + cancellationDepth,
   198  								Account:     sender,
   199  							}: nonce + 4,
   200  						},
   201  					},
   202  				),
   203  			),
   204  			sender,
   205  			pollingInterval,
   206  			cancellationDepth,
   207  		)
   208  
   209  		receiptC, errC, err := monitor.WatchTransaction(txHash, nonce)
   210  		if err != nil {
   211  			t.Fatal(err)
   212  		}
   213  
   214  		receiptC2, errC2, err := monitor.WatchTransaction(txHash2, nonce)
   215  		if err != nil {
   216  			t.Fatal(err)
   217  		}
   218  
   219  		receiptC3, errC3, err := monitor.WatchTransaction(txHash3, nonce+1)
   220  		if err != nil {
   221  			t.Fatal(err)
   222  		}
   223  
   224  		select {
   225  		case receipt := <-receiptC:
   226  			if receipt.TxHash != txHash {
   227  				t.Fatal("got wrong receipt")
   228  			}
   229  		case err := <-errC:
   230  			t.Fatalf("got wrong error. wanted %v, got %v", transaction.ErrTransactionCancelled, err)
   231  		case <-time.After(testTimeout):
   232  			t.Fatal("timed out")
   233  		}
   234  
   235  		select {
   236  		case <-receiptC2:
   237  			t.Fatal("got receipt")
   238  		case err := <-errC2:
   239  			if !errors.Is(err, transaction.ErrTransactionCancelled) {
   240  				t.Fatalf("got wrong error. wanted %v, got %v", transaction.ErrTransactionCancelled, err)
   241  			}
   242  		case <-time.After(testTimeout):
   243  			t.Fatal("timed out")
   244  		}
   245  
   246  		select {
   247  		case receipt := <-receiptC3:
   248  			if receipt.TxHash != txHash3 {
   249  				t.Fatal("got wrong receipt")
   250  			}
   251  		case err := <-errC3:
   252  			t.Fatal(err)
   253  		case <-time.After(testTimeout):
   254  			t.Fatal("timed out")
   255  		}
   256  
   257  		err = monitor.Close()
   258  		if err != nil {
   259  			t.Fatal(err)
   260  		}
   261  	})
   262  
   263  	t.Run("single transaction no confirm", func(t *testing.T) {
   264  		t.Parallel()
   265  
   266  		txHash2 := common.HexToHash("bbbb")
   267  		monitor := transaction.NewMonitor(
   268  			logger,
   269  			backendsimulation.New(
   270  				backendsimulation.WithBlocks(
   271  					backendsimulation.Block{
   272  						Number: 0,
   273  					},
   274  					backendsimulation.Block{
   275  						Number: 1,
   276  						NoncesAt: map[backendsimulation.AccountAtKey]uint64{
   277  							{
   278  								BlockNumber: 1,
   279  								Account:     sender,
   280  							}: nonce,
   281  						},
   282  					},
   283  					backendsimulation.Block{
   284  						Number: 1 + cancellationDepth,
   285  						NoncesAt: map[backendsimulation.AccountAtKey]uint64{
   286  							{
   287  								BlockNumber: 1,
   288  								Account:     sender,
   289  							}: nonce,
   290  							{
   291  								BlockNumber: 1 + cancellationDepth,
   292  								Account:     sender,
   293  							}: nonce + 1,
   294  						},
   295  					},
   296  					backendsimulation.Block{
   297  						Number: 1 + cancellationDepth + 1,
   298  						Receipts: map[common.Hash]*types.Receipt{
   299  							txHash2: {TxHash: txHash2},
   300  						},
   301  						NoncesAt: map[backendsimulation.AccountAtKey]uint64{
   302  							{
   303  								BlockNumber: 1 + cancellationDepth + 1,
   304  								Account:     sender,
   305  							}: nonce + 2,
   306  						},
   307  					},
   308  				),
   309  			),
   310  			sender,
   311  			pollingInterval,
   312  			cancellationDepth,
   313  		)
   314  
   315  		receiptC, errC, err := monitor.WatchTransaction(txHash, nonce)
   316  		if err != nil {
   317  			t.Fatal(err)
   318  		}
   319  
   320  		receiptC2, errC2, err := monitor.WatchTransaction(txHash2, nonce+1)
   321  		if err != nil {
   322  			t.Fatal(err)
   323  		}
   324  
   325  		select {
   326  		case <-receiptC:
   327  			t.Fatal("got receipt")
   328  		case err := <-errC:
   329  			t.Fatal(err)
   330  		case <-receiptC2:
   331  		case err := <-errC2:
   332  			t.Fatal(err)
   333  		case <-time.After(1 * time.Second):
   334  			t.Fatal("timeout")
   335  		}
   336  
   337  		err = monitor.Close()
   338  		if err != nil {
   339  			t.Fatal(err)
   340  		}
   341  	})
   342  
   343  	t.Run("shutdown while waiting", func(t *testing.T) {
   344  		t.Parallel()
   345  
   346  		monitor := transaction.NewMonitor(
   347  			logger,
   348  			backendsimulation.New(
   349  				backendsimulation.WithBlocks(
   350  					backendsimulation.Block{
   351  						Number: 0,
   352  					},
   353  					backendsimulation.Block{
   354  						Number: 1,
   355  						NoncesAt: map[backendsimulation.AccountAtKey]uint64{
   356  							{
   357  								BlockNumber: 1,
   358  								Account:     sender,
   359  							}: nonce + 1,
   360  						},
   361  					},
   362  				),
   363  			),
   364  			sender,
   365  			pollingInterval,
   366  			cancellationDepth,
   367  		)
   368  
   369  		receiptC, errC, err := monitor.WatchTransaction(txHash, nonce)
   370  		if err != nil {
   371  			t.Fatal(err)
   372  		}
   373  
   374  		err = monitor.Close()
   375  		if err != nil {
   376  			t.Fatal(err)
   377  		}
   378  
   379  		select {
   380  		case <-receiptC:
   381  			t.Fatal("got receipt")
   382  		case err := <-errC:
   383  			if !errors.Is(err, transaction.ErrMonitorClosed) {
   384  				t.Fatalf("got wrong error. wanted %v, got %v", transaction.ErrMonitorClosed, err)
   385  			}
   386  		case <-time.After(testTimeout):
   387  			t.Fatal("timed out")
   388  		}
   389  	})
   390  
   391  }