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 }