github.com/bytom/bytom@v1.1.2-0.20221014091027-bbcba3df6075/account/utxo_keeper_test.go (about) 1 package account 2 3 import ( 4 "encoding/json" 5 "os" 6 "testing" 7 "time" 8 9 dbm "github.com/bytom/bytom/database/leveldb" 10 "github.com/bytom/bytom/protocol/bc" 11 "github.com/bytom/bytom/testutil" 12 ) 13 14 func TestAddUnconfirmedUtxo(t *testing.T) { 15 cases := []struct { 16 before utxoKeeper 17 after utxoKeeper 18 addUtxos []*UTXO 19 }{ 20 { 21 before: utxoKeeper{ 22 unconfirmed: map[bc.Hash]*UTXO{}, 23 }, 24 after: utxoKeeper{ 25 unconfirmed: map[bc.Hash]*UTXO{}, 26 }, 27 addUtxos: []*UTXO{}, 28 }, 29 { 30 before: utxoKeeper{ 31 unconfirmed: map[bc.Hash]*UTXO{}, 32 }, 33 after: utxoKeeper{ 34 unconfirmed: map[bc.Hash]*UTXO{ 35 bc.NewHash([32]byte{0x01}): &UTXO{OutputID: bc.NewHash([32]byte{0x01})}, 36 }, 37 }, 38 addUtxos: []*UTXO{ 39 &UTXO{OutputID: bc.NewHash([32]byte{0x01})}, 40 }, 41 }, 42 { 43 before: utxoKeeper{ 44 unconfirmed: map[bc.Hash]*UTXO{ 45 bc.NewHash([32]byte{0x01}): &UTXO{OutputID: bc.NewHash([32]byte{0x01})}, 46 }, 47 }, 48 after: utxoKeeper{ 49 unconfirmed: map[bc.Hash]*UTXO{ 50 bc.NewHash([32]byte{0x01}): &UTXO{OutputID: bc.NewHash([32]byte{0x01})}, 51 }, 52 }, 53 addUtxos: []*UTXO{ 54 &UTXO{OutputID: bc.NewHash([32]byte{0x01})}, 55 }, 56 }, 57 { 58 before: utxoKeeper{ 59 unconfirmed: map[bc.Hash]*UTXO{ 60 bc.NewHash([32]byte{0x01}): &UTXO{OutputID: bc.NewHash([32]byte{0x01})}, 61 }, 62 }, 63 after: utxoKeeper{ 64 unconfirmed: map[bc.Hash]*UTXO{ 65 bc.NewHash([32]byte{0x01}): &UTXO{OutputID: bc.NewHash([32]byte{0x01})}, 66 bc.NewHash([32]byte{0x02}): &UTXO{OutputID: bc.NewHash([32]byte{0x02})}, 67 bc.NewHash([32]byte{0x03}): &UTXO{OutputID: bc.NewHash([32]byte{0x03})}, 68 }, 69 }, 70 addUtxos: []*UTXO{ 71 &UTXO{OutputID: bc.NewHash([32]byte{0x02})}, 72 &UTXO{OutputID: bc.NewHash([32]byte{0x03})}, 73 }, 74 }, 75 } 76 77 for i, c := range cases { 78 c.before.AddUnconfirmedUtxo(c.addUtxos) 79 if !testutil.DeepEqual(c.before, c.after) { 80 t.Errorf("case %d: got %v want %v", i, c.before, c.after) 81 } 82 } 83 } 84 85 func TestCancel(t *testing.T) { 86 cases := []struct { 87 before utxoKeeper 88 after utxoKeeper 89 cancelRid uint64 90 }{ 91 { 92 before: utxoKeeper{ 93 reserved: map[bc.Hash]uint64{}, 94 reservations: map[uint64]*reservation{}, 95 }, 96 after: utxoKeeper{ 97 reserved: map[bc.Hash]uint64{}, 98 reservations: map[uint64]*reservation{}, 99 }, 100 cancelRid: 0, 101 }, 102 { 103 before: utxoKeeper{ 104 reserved: map[bc.Hash]uint64{ 105 bc.NewHash([32]byte{0x01}): 1, 106 }, 107 reservations: map[uint64]*reservation{ 108 1: &reservation{ 109 id: 1, 110 utxos: []*UTXO{ 111 &UTXO{OutputID: bc.NewHash([32]byte{0x01})}, 112 }, 113 change: 9527, 114 expiry: time.Date(2016, 8, 10, 0, 0, 0, 0, time.UTC), 115 }, 116 }, 117 }, 118 after: utxoKeeper{ 119 reserved: map[bc.Hash]uint64{}, 120 reservations: map[uint64]*reservation{}, 121 }, 122 cancelRid: 1, 123 }, 124 { 125 before: utxoKeeper{ 126 reserved: map[bc.Hash]uint64{ 127 bc.NewHash([32]byte{0x01}): 1, 128 }, 129 reservations: map[uint64]*reservation{ 130 1: &reservation{ 131 id: 1, 132 utxos: []*UTXO{ 133 &UTXO{OutputID: bc.NewHash([32]byte{0x01})}, 134 }, 135 change: 9527, 136 expiry: time.Date(2016, 8, 10, 0, 0, 0, 0, time.UTC), 137 }, 138 }, 139 }, 140 after: utxoKeeper{ 141 reserved: map[bc.Hash]uint64{ 142 bc.NewHash([32]byte{0x01}): 1, 143 }, 144 reservations: map[uint64]*reservation{ 145 1: &reservation{ 146 id: 1, 147 utxos: []*UTXO{ 148 &UTXO{OutputID: bc.NewHash([32]byte{0x01})}, 149 }, 150 change: 9527, 151 expiry: time.Date(2016, 8, 10, 0, 0, 0, 0, time.UTC), 152 }, 153 }, 154 }, 155 cancelRid: 2, 156 }, 157 { 158 before: utxoKeeper{ 159 reserved: map[bc.Hash]uint64{ 160 bc.NewHash([32]byte{0x01}): 1, 161 bc.NewHash([32]byte{0x02}): 3, 162 bc.NewHash([32]byte{0x03}): 3, 163 bc.NewHash([32]byte{0x04}): 3, 164 }, 165 reservations: map[uint64]*reservation{ 166 1: &reservation{ 167 id: 1, 168 utxos: []*UTXO{ 169 &UTXO{OutputID: bc.NewHash([32]byte{0x01})}, 170 }, 171 change: 9527, 172 expiry: time.Date(2016, 8, 10, 0, 0, 0, 0, time.UTC), 173 }, 174 3: &reservation{ 175 id: 3, 176 utxos: []*UTXO{ 177 &UTXO{OutputID: bc.NewHash([32]byte{0x02})}, 178 &UTXO{OutputID: bc.NewHash([32]byte{0x03})}, 179 &UTXO{OutputID: bc.NewHash([32]byte{0x04})}, 180 }, 181 change: 9528, 182 expiry: time.Date(2016, 8, 10, 0, 0, 0, 0, time.UTC), 183 }, 184 }, 185 }, 186 after: utxoKeeper{ 187 reserved: map[bc.Hash]uint64{ 188 bc.NewHash([32]byte{0x01}): 1, 189 }, 190 reservations: map[uint64]*reservation{ 191 1: &reservation{ 192 id: 1, 193 utxos: []*UTXO{ 194 &UTXO{OutputID: bc.NewHash([32]byte{0x01})}, 195 }, 196 change: 9527, 197 expiry: time.Date(2016, 8, 10, 0, 0, 0, 0, time.UTC), 198 }, 199 }, 200 }, 201 cancelRid: 3, 202 }, 203 } 204 205 for i, c := range cases { 206 c.before.cancel(c.cancelRid) 207 if !testutil.DeepEqual(c.before, c.after) { 208 t.Errorf("case %d: got %v want %v", i, c.before, c.after) 209 } 210 } 211 } 212 213 func TestRemoveUnconfirmedUtxo(t *testing.T) { 214 cases := []struct { 215 before utxoKeeper 216 after utxoKeeper 217 removeUtxos []*bc.Hash 218 }{ 219 { 220 before: utxoKeeper{ 221 unconfirmed: map[bc.Hash]*UTXO{}, 222 }, 223 after: utxoKeeper{ 224 unconfirmed: map[bc.Hash]*UTXO{}, 225 }, 226 removeUtxos: []*bc.Hash{}, 227 }, 228 { 229 before: utxoKeeper{ 230 unconfirmed: map[bc.Hash]*UTXO{ 231 bc.Hash{V0: 1}: &UTXO{OutputID: bc.NewHash([32]byte{0x01})}, 232 }, 233 }, 234 after: utxoKeeper{ 235 unconfirmed: map[bc.Hash]*UTXO{}, 236 }, 237 removeUtxos: []*bc.Hash{ 238 &bc.Hash{V0: 1}, 239 }, 240 }, 241 { 242 before: utxoKeeper{ 243 unconfirmed: map[bc.Hash]*UTXO{ 244 bc.Hash{V0: 1}: &UTXO{OutputID: bc.NewHash([32]byte{0x01})}, 245 bc.Hash{V0: 2}: &UTXO{OutputID: bc.NewHash([32]byte{0x02})}, 246 bc.Hash{V0: 3}: &UTXO{OutputID: bc.NewHash([32]byte{0x03})}, 247 bc.Hash{V0: 4}: &UTXO{OutputID: bc.NewHash([32]byte{0x04})}, 248 bc.Hash{V0: 5}: &UTXO{OutputID: bc.NewHash([32]byte{0x05})}, 249 }, 250 }, 251 after: utxoKeeper{ 252 unconfirmed: map[bc.Hash]*UTXO{ 253 bc.Hash{V0: 2}: &UTXO{OutputID: bc.NewHash([32]byte{0x02})}, 254 bc.Hash{V0: 4}: &UTXO{OutputID: bc.NewHash([32]byte{0x04})}, 255 }, 256 }, 257 removeUtxos: []*bc.Hash{ 258 &bc.Hash{V0: 1}, 259 &bc.Hash{V0: 3}, 260 &bc.Hash{V0: 5}, 261 }, 262 }, 263 } 264 265 for i, c := range cases { 266 c.before.RemoveUnconfirmedUtxo(c.removeUtxos) 267 if !testutil.DeepEqual(c.before, c.after) { 268 t.Errorf("case %d: got %v want %v", i, c.before, c.after) 269 } 270 } 271 } 272 273 func TestReserve(t *testing.T) { 274 currentHeight := func() uint64 { return 9527 } 275 testDB := dbm.NewDB("testdb", "leveldb", "temp") 276 defer os.RemoveAll("temp") 277 278 cases := []struct { 279 before utxoKeeper 280 after utxoKeeper 281 err error 282 reserveAmount uint64 283 exp time.Time 284 }{ 285 { 286 before: utxoKeeper{ 287 db: testDB, 288 currentHeight: currentHeight, 289 reserved: map[bc.Hash]uint64{}, 290 reservations: map[uint64]*reservation{}, 291 }, 292 after: utxoKeeper{ 293 db: testDB, 294 currentHeight: currentHeight, 295 reserved: map[bc.Hash]uint64{}, 296 reservations: map[uint64]*reservation{}, 297 }, 298 reserveAmount: 1, 299 err: ErrInsufficient, 300 }, 301 { 302 before: utxoKeeper{ 303 db: testDB, 304 currentHeight: currentHeight, 305 unconfirmed: map[bc.Hash]*UTXO{ 306 bc.NewHash([32]byte{0x01}): &UTXO{ 307 OutputID: bc.NewHash([32]byte{0x01}), 308 AccountID: "testAccount", 309 Amount: 3, 310 }, 311 }, 312 reserved: map[bc.Hash]uint64{}, 313 reservations: map[uint64]*reservation{}, 314 }, 315 after: utxoKeeper{ 316 db: testDB, 317 currentHeight: currentHeight, 318 unconfirmed: map[bc.Hash]*UTXO{ 319 bc.NewHash([32]byte{0x01}): &UTXO{ 320 OutputID: bc.NewHash([32]byte{0x01}), 321 AccountID: "testAccount", 322 Amount: 3, 323 }, 324 }, 325 reserved: map[bc.Hash]uint64{}, 326 reservations: map[uint64]*reservation{}, 327 }, 328 reserveAmount: 4, 329 err: ErrInsufficient, 330 }, 331 { 332 before: utxoKeeper{ 333 db: testDB, 334 currentHeight: currentHeight, 335 unconfirmed: map[bc.Hash]*UTXO{ 336 bc.NewHash([32]byte{0x01}): &UTXO{ 337 OutputID: bc.NewHash([32]byte{0x01}), 338 AccountID: "testAccount", 339 Amount: 3, 340 ValidHeight: 9528, 341 }, 342 }, 343 reserved: map[bc.Hash]uint64{}, 344 reservations: map[uint64]*reservation{}, 345 }, 346 after: utxoKeeper{ 347 db: testDB, 348 currentHeight: currentHeight, 349 unconfirmed: map[bc.Hash]*UTXO{ 350 bc.NewHash([32]byte{0x01}): &UTXO{ 351 OutputID: bc.NewHash([32]byte{0x01}), 352 AccountID: "testAccount", 353 Amount: 3, 354 ValidHeight: 9528, 355 }, 356 }, 357 reserved: map[bc.Hash]uint64{}, 358 reservations: map[uint64]*reservation{}, 359 }, 360 reserveAmount: 3, 361 err: ErrImmature, 362 }, 363 { 364 before: utxoKeeper{ 365 db: testDB, 366 currentHeight: currentHeight, 367 unconfirmed: map[bc.Hash]*UTXO{ 368 bc.NewHash([32]byte{0x01}): &UTXO{ 369 OutputID: bc.NewHash([32]byte{0x01}), 370 AccountID: "testAccount", 371 Amount: 3, 372 }, 373 }, 374 reserved: map[bc.Hash]uint64{ 375 bc.NewHash([32]byte{0x01}): 0, 376 }, 377 reservations: map[uint64]*reservation{}, 378 }, 379 after: utxoKeeper{ 380 db: testDB, 381 currentHeight: currentHeight, 382 unconfirmed: map[bc.Hash]*UTXO{ 383 bc.NewHash([32]byte{0x01}): &UTXO{ 384 OutputID: bc.NewHash([32]byte{0x01}), 385 AccountID: "testAccount", 386 Amount: 3, 387 }, 388 }, 389 reserved: map[bc.Hash]uint64{ 390 bc.NewHash([32]byte{0x01}): 0, 391 }, 392 reservations: map[uint64]*reservation{}, 393 }, 394 reserveAmount: 3, 395 err: ErrReserved, 396 }, 397 { 398 before: utxoKeeper{ 399 db: testDB, 400 currentHeight: currentHeight, 401 unconfirmed: map[bc.Hash]*UTXO{ 402 bc.NewHash([32]byte{0x01}): &UTXO{ 403 OutputID: bc.NewHash([32]byte{0x01}), 404 AccountID: "testAccount", 405 Amount: 3, 406 }, 407 }, 408 reserved: map[bc.Hash]uint64{}, 409 reservations: map[uint64]*reservation{}, 410 }, 411 after: utxoKeeper{ 412 db: testDB, 413 currentHeight: currentHeight, 414 unconfirmed: map[bc.Hash]*UTXO{ 415 bc.NewHash([32]byte{0x01}): &UTXO{ 416 OutputID: bc.NewHash([32]byte{0x01}), 417 AccountID: "testAccount", 418 Amount: 3, 419 }, 420 }, 421 reserved: map[bc.Hash]uint64{ 422 bc.NewHash([32]byte{0x01}): 1, 423 }, 424 reservations: map[uint64]*reservation{ 425 1: &reservation{ 426 id: 1, 427 utxos: []*UTXO{ 428 &UTXO{ 429 OutputID: bc.NewHash([32]byte{0x01}), 430 AccountID: "testAccount", 431 Amount: 3, 432 }, 433 }, 434 change: 1, 435 expiry: time.Date(2016, 8, 10, 0, 0, 0, 0, time.UTC), 436 }, 437 }, 438 }, 439 reserveAmount: 2, 440 err: nil, 441 exp: time.Date(2016, 8, 10, 0, 0, 0, 0, time.UTC), 442 }, 443 { 444 before: utxoKeeper{ 445 db: testDB, 446 currentHeight: currentHeight, 447 nextIndex: 1, 448 unconfirmed: map[bc.Hash]*UTXO{ 449 bc.NewHash([32]byte{0x01}): &UTXO{ 450 OutputID: bc.NewHash([32]byte{0x01}), 451 AccountID: "testAccount", 452 Amount: 3, 453 }, 454 bc.NewHash([32]byte{0x02}): &UTXO{ 455 OutputID: bc.NewHash([32]byte{0x02}), 456 AccountID: "testAccount", 457 Amount: 5, 458 }, 459 bc.NewHash([32]byte{0x03}): &UTXO{ 460 OutputID: bc.NewHash([32]byte{0x03}), 461 AccountID: "testAccount", 462 Amount: 7, 463 }, 464 }, 465 reserved: map[bc.Hash]uint64{ 466 bc.NewHash([32]byte{0x01}): 1, 467 }, 468 reservations: map[uint64]*reservation{}, 469 }, 470 after: utxoKeeper{ 471 db: testDB, 472 currentHeight: currentHeight, 473 unconfirmed: map[bc.Hash]*UTXO{ 474 bc.NewHash([32]byte{0x01}): &UTXO{ 475 OutputID: bc.NewHash([32]byte{0x01}), 476 AccountID: "testAccount", 477 Amount: 3, 478 }, 479 bc.NewHash([32]byte{0x02}): &UTXO{ 480 OutputID: bc.NewHash([32]byte{0x02}), 481 AccountID: "testAccount", 482 Amount: 5, 483 }, 484 bc.NewHash([32]byte{0x03}): &UTXO{ 485 OutputID: bc.NewHash([32]byte{0x03}), 486 AccountID: "testAccount", 487 Amount: 7, 488 }, 489 }, 490 reserved: map[bc.Hash]uint64{ 491 bc.NewHash([32]byte{0x01}): 1, 492 bc.NewHash([32]byte{0x02}): 2, 493 bc.NewHash([32]byte{0x03}): 2, 494 }, 495 reservations: map[uint64]*reservation{ 496 2: &reservation{ 497 id: 2, 498 utxos: []*UTXO{ 499 &UTXO{ 500 OutputID: bc.NewHash([32]byte{0x03}), 501 AccountID: "testAccount", 502 Amount: 7, 503 }, 504 &UTXO{ 505 OutputID: bc.NewHash([32]byte{0x02}), 506 AccountID: "testAccount", 507 Amount: 5, 508 }, 509 }, 510 change: 4, 511 expiry: time.Date(2016, 8, 10, 0, 0, 0, 0, time.UTC), 512 }, 513 }, 514 }, 515 reserveAmount: 8, 516 err: nil, 517 exp: time.Date(2016, 8, 10, 0, 0, 0, 0, time.UTC), 518 }, 519 } 520 521 for i, c := range cases { 522 if _, err := c.before.Reserve("testAccount", &bc.AssetID{}, c.reserveAmount, true, nil, c.exp); err != c.err { 523 t.Errorf("case %d: got error %v want error %v", i, err, c.err) 524 } 525 checkUtxoKeeperEqual(t, i, &c.before, &c.after) 526 } 527 } 528 529 func TestReserveParticular(t *testing.T) { 530 currentHeight := func() uint64 { return 9527 } 531 testDB := dbm.NewDB("testdb", "leveldb", "temp") 532 defer os.RemoveAll("temp") 533 534 cases := []struct { 535 before utxoKeeper 536 after utxoKeeper 537 err error 538 reserveHash bc.Hash 539 exp time.Time 540 }{ 541 { 542 before: utxoKeeper{ 543 db: testDB, 544 currentHeight: currentHeight, 545 unconfirmed: map[bc.Hash]*UTXO{ 546 bc.NewHash([32]byte{0x01}): &UTXO{ 547 OutputID: bc.NewHash([32]byte{0x01}), 548 AccountID: "testAccount", 549 Amount: 3, 550 }, 551 }, 552 reserved: map[bc.Hash]uint64{ 553 bc.NewHash([32]byte{0x01}): 0, 554 }, 555 reservations: map[uint64]*reservation{}, 556 }, 557 after: utxoKeeper{ 558 db: testDB, 559 currentHeight: currentHeight, 560 unconfirmed: map[bc.Hash]*UTXO{ 561 bc.NewHash([32]byte{0x01}): &UTXO{ 562 OutputID: bc.NewHash([32]byte{0x01}), 563 AccountID: "testAccount", 564 Amount: 3, 565 }, 566 }, 567 reserved: map[bc.Hash]uint64{ 568 bc.NewHash([32]byte{0x01}): 0, 569 }, 570 reservations: map[uint64]*reservation{}, 571 }, 572 reserveHash: bc.NewHash([32]byte{0x01}), 573 err: ErrReserved, 574 }, 575 { 576 before: utxoKeeper{ 577 db: testDB, 578 currentHeight: currentHeight, 579 unconfirmed: map[bc.Hash]*UTXO{ 580 bc.NewHash([32]byte{0x01}): &UTXO{ 581 OutputID: bc.NewHash([32]byte{0x01}), 582 AccountID: "testAccount", 583 Amount: 3, 584 ValidHeight: 9528, 585 }, 586 }, 587 reserved: map[bc.Hash]uint64{}, 588 reservations: map[uint64]*reservation{}, 589 }, 590 after: utxoKeeper{ 591 db: testDB, 592 currentHeight: currentHeight, 593 unconfirmed: map[bc.Hash]*UTXO{ 594 bc.NewHash([32]byte{0x01}): &UTXO{ 595 OutputID: bc.NewHash([32]byte{0x01}), 596 AccountID: "testAccount", 597 Amount: 3, 598 ValidHeight: 9528, 599 }, 600 }, 601 reserved: map[bc.Hash]uint64{}, 602 reservations: map[uint64]*reservation{}, 603 }, 604 reserveHash: bc.NewHash([32]byte{0x01}), 605 err: ErrImmature, 606 }, 607 { 608 before: utxoKeeper{ 609 db: testDB, 610 currentHeight: currentHeight, 611 unconfirmed: map[bc.Hash]*UTXO{ 612 bc.NewHash([32]byte{0x01}): &UTXO{ 613 OutputID: bc.NewHash([32]byte{0x01}), 614 AccountID: "testAccount", 615 Amount: 3, 616 }, 617 }, 618 reserved: map[bc.Hash]uint64{}, 619 reservations: map[uint64]*reservation{}, 620 }, 621 after: utxoKeeper{ 622 db: testDB, 623 currentHeight: currentHeight, 624 unconfirmed: map[bc.Hash]*UTXO{ 625 bc.NewHash([32]byte{0x01}): &UTXO{ 626 OutputID: bc.NewHash([32]byte{0x01}), 627 AccountID: "testAccount", 628 Amount: 3, 629 }, 630 }, 631 reserved: map[bc.Hash]uint64{ 632 bc.NewHash([32]byte{0x01}): 1, 633 }, 634 reservations: map[uint64]*reservation{ 635 1: &reservation{ 636 id: 1, 637 utxos: []*UTXO{ 638 &UTXO{ 639 OutputID: bc.NewHash([32]byte{0x01}), 640 AccountID: "testAccount", 641 Amount: 3, 642 }, 643 }, 644 change: 0, 645 expiry: time.Date(2016, 8, 10, 0, 0, 0, 0, time.UTC), 646 }, 647 }, 648 }, 649 reserveHash: bc.NewHash([32]byte{0x01}), 650 err: nil, 651 exp: time.Date(2016, 8, 10, 0, 0, 0, 0, time.UTC), 652 }, 653 } 654 655 for i, c := range cases { 656 if _, err := c.before.ReserveParticular(c.reserveHash, true, c.exp); err != c.err { 657 t.Errorf("case %d: got error %v want error %v", i, err, c.err) 658 } 659 checkUtxoKeeperEqual(t, i, &c.before, &c.after) 660 } 661 } 662 663 func TestExpireReservation(t *testing.T) { 664 before := &utxoKeeper{ 665 reservations: map[uint64]*reservation{ 666 1: &reservation{expiry: time.Date(2016, 8, 10, 0, 0, 0, 0, time.UTC)}, 667 2: &reservation{expiry: time.Date(3016, 8, 10, 0, 0, 0, 0, time.UTC)}, 668 3: &reservation{expiry: time.Date(2016, 8, 10, 0, 0, 0, 0, time.UTC)}, 669 4: &reservation{expiry: time.Date(3016, 8, 10, 0, 0, 0, 0, time.UTC)}, 670 5: &reservation{expiry: time.Date(3016, 8, 10, 0, 0, 0, 0, time.UTC)}, 671 }, 672 } 673 after := &utxoKeeper{ 674 reservations: map[uint64]*reservation{ 675 2: &reservation{expiry: time.Date(3016, 8, 10, 0, 0, 0, 0, time.UTC)}, 676 4: &reservation{expiry: time.Date(3016, 8, 10, 0, 0, 0, 0, time.UTC)}, 677 5: &reservation{expiry: time.Date(3016, 8, 10, 0, 0, 0, 0, time.UTC)}, 678 }, 679 } 680 before.expireReservation(time.Date(2017, 8, 10, 0, 0, 0, 0, time.UTC)) 681 checkUtxoKeeperEqual(t, 0, before, after) 682 } 683 684 func TestFindUtxos(t *testing.T) { 685 currentHeight := func() uint64 { return 9527 } 686 testDB := dbm.NewDB("testdb", "leveldb", "temp") 687 defer os.RemoveAll("temp") 688 689 cases := []struct { 690 uk utxoKeeper 691 dbUtxos []*UTXO 692 useUnconfirmed bool 693 wantUtxos []*UTXO 694 immatureAmount uint64 695 }{ 696 { 697 uk: utxoKeeper{ 698 db: testDB, 699 currentHeight: currentHeight, 700 unconfirmed: map[bc.Hash]*UTXO{}, 701 }, 702 dbUtxos: []*UTXO{}, 703 useUnconfirmed: true, 704 wantUtxos: []*UTXO{}, 705 immatureAmount: 0, 706 }, 707 { 708 uk: utxoKeeper{ 709 db: testDB, 710 currentHeight: currentHeight, 711 unconfirmed: map[bc.Hash]*UTXO{}, 712 }, 713 dbUtxos: []*UTXO{ 714 &UTXO{ 715 OutputID: bc.NewHash([32]byte{0x01}), 716 AccountID: "testAccount", 717 Amount: 3, 718 }, 719 &UTXO{ 720 OutputID: bc.NewHash([32]byte{0x02}), 721 AccountID: "testAccount", 722 AssetID: bc.AssetID{V0: 6}, 723 Amount: 3, 724 }, 725 }, 726 useUnconfirmed: false, 727 wantUtxos: []*UTXO{ 728 &UTXO{ 729 OutputID: bc.NewHash([32]byte{0x01}), 730 AccountID: "testAccount", 731 Amount: 3, 732 }, 733 }, 734 immatureAmount: 0, 735 }, 736 { 737 uk: utxoKeeper{ 738 db: testDB, 739 currentHeight: currentHeight, 740 unconfirmed: map[bc.Hash]*UTXO{}, 741 }, 742 dbUtxos: []*UTXO{ 743 &UTXO{ 744 OutputID: bc.NewHash([32]byte{0x02}), 745 AccountID: "testAccount", 746 Amount: 3, 747 ValidHeight: 9528, 748 }, 749 }, 750 useUnconfirmed: false, 751 wantUtxos: []*UTXO{}, 752 immatureAmount: 3, 753 }, 754 { 755 uk: utxoKeeper{ 756 db: testDB, 757 currentHeight: currentHeight, 758 unconfirmed: map[bc.Hash]*UTXO{ 759 bc.NewHash([32]byte{0x01}): &UTXO{ 760 OutputID: bc.NewHash([32]byte{0x01}), 761 AccountID: "testAccount", 762 Amount: 3, 763 }, 764 }, 765 }, 766 dbUtxos: []*UTXO{ 767 &UTXO{ 768 OutputID: bc.NewHash([32]byte{0x02}), 769 AccountID: "testAccount", 770 Amount: 3, 771 }, 772 }, 773 useUnconfirmed: false, 774 wantUtxos: []*UTXO{ 775 &UTXO{ 776 OutputID: bc.NewHash([32]byte{0x02}), 777 AccountID: "testAccount", 778 Amount: 3, 779 }, 780 }, 781 immatureAmount: 0, 782 }, 783 { 784 uk: utxoKeeper{ 785 db: testDB, 786 currentHeight: currentHeight, 787 unconfirmed: map[bc.Hash]*UTXO{ 788 bc.NewHash([32]byte{0x11}): &UTXO{ 789 OutputID: bc.NewHash([32]byte{0x01}), 790 AccountID: "testAccount", 791 Amount: 3, 792 }, 793 }, 794 }, 795 dbUtxos: []*UTXO{ 796 &UTXO{ 797 OutputID: bc.NewHash([32]byte{0x02}), 798 AccountID: "testAccount", 799 Amount: 3, 800 }, 801 }, 802 useUnconfirmed: true, 803 wantUtxos: []*UTXO{ 804 &UTXO{ 805 OutputID: bc.NewHash([32]byte{0x02}), 806 AccountID: "testAccount", 807 Amount: 3, 808 }, 809 &UTXO{ 810 OutputID: bc.NewHash([32]byte{0x01}), 811 AccountID: "testAccount", 812 Amount: 3, 813 }, 814 }, 815 immatureAmount: 0, 816 }, 817 { 818 uk: utxoKeeper{ 819 db: testDB, 820 currentHeight: currentHeight, 821 unconfirmed: map[bc.Hash]*UTXO{ 822 bc.NewHash([32]byte{0x01}): &UTXO{ 823 OutputID: bc.NewHash([32]byte{0x01}), 824 AccountID: "testAccount", 825 Amount: 1, 826 }, 827 bc.NewHash([32]byte{0x02}): &UTXO{ 828 OutputID: bc.NewHash([32]byte{0x02}), 829 AccountID: "notMe", 830 Amount: 2, 831 }, 832 }, 833 }, 834 dbUtxos: []*UTXO{ 835 &UTXO{ 836 OutputID: bc.NewHash([32]byte{0x03}), 837 AccountID: "testAccount", 838 Amount: 3, 839 }, 840 &UTXO{ 841 OutputID: bc.NewHash([32]byte{0x04}), 842 AccountID: "notMe", 843 Amount: 4, 844 }, 845 }, 846 useUnconfirmed: true, 847 wantUtxos: []*UTXO{ 848 &UTXO{ 849 OutputID: bc.NewHash([32]byte{0x03}), 850 AccountID: "testAccount", 851 Amount: 3, 852 }, 853 &UTXO{ 854 OutputID: bc.NewHash([32]byte{0x01}), 855 AccountID: "testAccount", 856 Amount: 1, 857 }, 858 }, 859 immatureAmount: 0, 860 }, 861 } 862 863 for i, c := range cases { 864 for _, u := range c.dbUtxos { 865 data, err := json.Marshal(u) 866 if err != nil { 867 t.Error(err) 868 } 869 testDB.Set(StandardUTXOKey(u.OutputID), data) 870 } 871 872 gotUtxos, immatureAmount := c.uk.findUtxos("testAccount", &bc.AssetID{}, c.useUnconfirmed, nil) 873 if !testutil.DeepEqual(gotUtxos, c.wantUtxos) { 874 t.Errorf("case %d: got %v want %v", i, gotUtxos, c.wantUtxos) 875 } 876 if immatureAmount != c.immatureAmount { 877 t.Errorf("case %d: got %v want %v", i, immatureAmount, c.immatureAmount) 878 } 879 880 for _, u := range c.dbUtxos { 881 testDB.Delete(StandardUTXOKey(u.OutputID)) 882 } 883 } 884 } 885 886 func TestFindUtxo(t *testing.T) { 887 currentHeight := func() uint64 { return 9527 } 888 testDB := dbm.NewDB("testdb", "leveldb", "temp") 889 defer os.RemoveAll("temp") 890 891 cases := []struct { 892 uk utxoKeeper 893 dbUtxos map[string]*UTXO 894 outHash bc.Hash 895 useUnconfirmed bool 896 wantUtxo *UTXO 897 err error 898 }{ 899 { 900 uk: utxoKeeper{ 901 db: testDB, 902 currentHeight: currentHeight, 903 unconfirmed: map[bc.Hash]*UTXO{}, 904 }, 905 dbUtxos: map[string]*UTXO{}, 906 outHash: bc.NewHash([32]byte{0x01}), 907 wantUtxo: nil, 908 err: ErrMatchUTXO, 909 }, 910 { 911 uk: utxoKeeper{ 912 db: testDB, 913 currentHeight: currentHeight, 914 unconfirmed: map[bc.Hash]*UTXO{ 915 bc.NewHash([32]byte{0x01}): &UTXO{OutputID: bc.NewHash([32]byte{0x01})}, 916 }, 917 }, 918 dbUtxos: map[string]*UTXO{}, 919 outHash: bc.NewHash([32]byte{0x01}), 920 wantUtxo: nil, 921 useUnconfirmed: false, 922 err: ErrMatchUTXO, 923 }, 924 { 925 uk: utxoKeeper{ 926 db: testDB, 927 currentHeight: currentHeight, 928 unconfirmed: map[bc.Hash]*UTXO{ 929 bc.NewHash([32]byte{0x01}): &UTXO{OutputID: bc.NewHash([32]byte{0x01})}, 930 }, 931 }, 932 dbUtxos: map[string]*UTXO{}, 933 outHash: bc.NewHash([32]byte{0x01}), 934 wantUtxo: &UTXO{OutputID: bc.NewHash([32]byte{0x01})}, 935 useUnconfirmed: true, 936 err: nil, 937 }, 938 { 939 uk: utxoKeeper{ 940 db: testDB, 941 currentHeight: currentHeight, 942 unconfirmed: map[bc.Hash]*UTXO{}, 943 }, 944 dbUtxos: map[string]*UTXO{ 945 string(StandardUTXOKey(bc.NewHash([32]byte{0x01}))): &UTXO{OutputID: bc.NewHash([32]byte{0x01})}, 946 }, 947 outHash: bc.NewHash([32]byte{0x01}), 948 wantUtxo: &UTXO{OutputID: bc.NewHash([32]byte{0x01})}, 949 useUnconfirmed: false, 950 err: nil, 951 }, 952 { 953 uk: utxoKeeper{ 954 db: testDB, 955 currentHeight: currentHeight, 956 unconfirmed: map[bc.Hash]*UTXO{}, 957 }, 958 dbUtxos: map[string]*UTXO{ 959 string(ContractUTXOKey(bc.NewHash([32]byte{0x01}))): &UTXO{OutputID: bc.NewHash([32]byte{0x01})}, 960 }, 961 outHash: bc.NewHash([32]byte{0x01}), 962 wantUtxo: &UTXO{OutputID: bc.NewHash([32]byte{0x01})}, 963 useUnconfirmed: false, 964 err: nil, 965 }, 966 } 967 968 for i, c := range cases { 969 for k, u := range c.dbUtxos { 970 data, err := json.Marshal(u) 971 if err != nil { 972 t.Error(err) 973 } 974 testDB.Set([]byte(k), data) 975 } 976 977 gotUtxo, err := c.uk.findUtxo(c.outHash, c.useUnconfirmed) 978 if !testutil.DeepEqual(gotUtxo, c.wantUtxo) { 979 t.Errorf("case %d: got %v want %v", i, gotUtxo, c.wantUtxo) 980 } 981 if err != c.err { 982 t.Errorf("case %d: got %v want %v", i, err, c.err) 983 } 984 985 for _, u := range c.dbUtxos { 986 testDB.Delete(StandardUTXOKey(u.OutputID)) 987 } 988 } 989 } 990 991 func TestOptUTXOs(t *testing.T) { 992 cases := []struct { 993 uk utxoKeeper 994 input []*UTXO 995 inputAmount uint64 996 wantUtxos []*UTXO 997 optAmount uint64 998 reservedAmount uint64 999 }{ 1000 { 1001 uk: utxoKeeper{ 1002 reserved: map[bc.Hash]uint64{ 1003 bc.NewHash([32]byte{0x01}): 1, 1004 }, 1005 }, 1006 input: []*UTXO{}, 1007 inputAmount: 13, 1008 wantUtxos: []*UTXO{}, 1009 optAmount: 0, 1010 reservedAmount: 0, 1011 }, 1012 { 1013 uk: utxoKeeper{ 1014 reserved: map[bc.Hash]uint64{ 1015 bc.NewHash([32]byte{0x01}): 1, 1016 }, 1017 }, 1018 input: []*UTXO{ 1019 &UTXO{OutputID: bc.NewHash([32]byte{0x01}), Amount: 1}, 1020 }, 1021 inputAmount: 13, 1022 wantUtxos: []*UTXO{}, 1023 optAmount: 0, 1024 reservedAmount: 1, 1025 }, 1026 { 1027 uk: utxoKeeper{ 1028 reserved: map[bc.Hash]uint64{ 1029 bc.NewHash([32]byte{0x01}): 1, 1030 }, 1031 }, 1032 input: []*UTXO{ 1033 &UTXO{OutputID: bc.NewHash([32]byte{0x01}), Amount: 1}, 1034 &UTXO{OutputID: bc.NewHash([32]byte{0x02}), Amount: 3}, 1035 &UTXO{OutputID: bc.NewHash([32]byte{0x03}), Amount: 5}, 1036 }, 1037 inputAmount: 13, 1038 wantUtxos: []*UTXO{ 1039 &UTXO{OutputID: bc.NewHash([32]byte{0x03}), Amount: 5}, 1040 &UTXO{OutputID: bc.NewHash([32]byte{0x02}), Amount: 3}, 1041 }, 1042 optAmount: 8, 1043 reservedAmount: 1, 1044 }, 1045 { 1046 uk: utxoKeeper{ 1047 reserved: map[bc.Hash]uint64{ 1048 bc.NewHash([32]byte{0x01}): 1, 1049 bc.NewHash([32]byte{0x02}): 2, 1050 bc.NewHash([32]byte{0x03}): 3, 1051 }, 1052 }, 1053 input: []*UTXO{ 1054 &UTXO{OutputID: bc.NewHash([32]byte{0x01}), Amount: 1}, 1055 &UTXO{OutputID: bc.NewHash([32]byte{0x02}), Amount: 3}, 1056 &UTXO{OutputID: bc.NewHash([32]byte{0x03}), Amount: 5}, 1057 }, 1058 inputAmount: 1, 1059 wantUtxos: []*UTXO{}, 1060 optAmount: 0, 1061 reservedAmount: 9, 1062 }, 1063 { 1064 uk: utxoKeeper{}, 1065 input: []*UTXO{ 1066 &UTXO{OutputID: bc.NewHash([32]byte{0x01}), Amount: 1}, 1067 &UTXO{OutputID: bc.NewHash([32]byte{0x02}), Amount: 3}, 1068 &UTXO{OutputID: bc.NewHash([32]byte{0x03}), Amount: 5}, 1069 }, 1070 inputAmount: 1, 1071 wantUtxos: []*UTXO{ 1072 &UTXO{OutputID: bc.NewHash([32]byte{0x01}), Amount: 1}, 1073 }, 1074 optAmount: 1, 1075 reservedAmount: 0, 1076 }, 1077 { 1078 uk: utxoKeeper{}, 1079 input: []*UTXO{ 1080 &UTXO{OutputID: bc.NewHash([32]byte{0x02}), Amount: 2}, 1081 &UTXO{OutputID: bc.NewHash([32]byte{0x03}), Amount: 3}, 1082 &UTXO{OutputID: bc.NewHash([32]byte{0x05}), Amount: 5}, 1083 }, 1084 inputAmount: 5, 1085 wantUtxos: []*UTXO{ 1086 &UTXO{OutputID: bc.NewHash([32]byte{0x03}), Amount: 3}, 1087 &UTXO{OutputID: bc.NewHash([32]byte{0x02}), Amount: 2}, 1088 }, 1089 optAmount: 5, 1090 reservedAmount: 0, 1091 }, 1092 { 1093 uk: utxoKeeper{}, 1094 input: []*UTXO{ 1095 &UTXO{OutputID: bc.NewHash([32]byte{0x01}), Amount: 1}, 1096 &UTXO{OutputID: bc.NewHash([32]byte{0x02}), Amount: 1}, 1097 &UTXO{OutputID: bc.NewHash([32]byte{0x03}), Amount: 1}, 1098 &UTXO{OutputID: bc.NewHash([32]byte{0x04}), Amount: 1}, 1099 &UTXO{OutputID: bc.NewHash([32]byte{0x05}), Amount: 1}, 1100 &UTXO{OutputID: bc.NewHash([32]byte{0x06}), Amount: 1}, 1101 &UTXO{OutputID: bc.NewHash([32]byte{0x08}), Amount: 6}, 1102 }, 1103 inputAmount: 6, 1104 wantUtxos: []*UTXO{ 1105 &UTXO{OutputID: bc.NewHash([32]byte{0x08}), Amount: 6}, 1106 }, 1107 optAmount: 6, 1108 reservedAmount: 0, 1109 }, 1110 { 1111 uk: utxoKeeper{}, 1112 input: []*UTXO{ 1113 &UTXO{OutputID: bc.NewHash([32]byte{0x01}), Amount: 1}, 1114 &UTXO{OutputID: bc.NewHash([32]byte{0x02}), Amount: 1}, 1115 &UTXO{OutputID: bc.NewHash([32]byte{0x03}), Amount: 1}, 1116 &UTXO{OutputID: bc.NewHash([32]byte{0x04}), Amount: 1}, 1117 &UTXO{OutputID: bc.NewHash([32]byte{0x05}), Amount: 1}, 1118 &UTXO{OutputID: bc.NewHash([32]byte{0x06}), Amount: 1}, 1119 &UTXO{OutputID: bc.NewHash([32]byte{0x08}), Amount: 6}, 1120 }, 1121 inputAmount: 5, 1122 wantUtxos: []*UTXO{ 1123 &UTXO{OutputID: bc.NewHash([32]byte{0x03}), Amount: 1}, 1124 &UTXO{OutputID: bc.NewHash([32]byte{0x04}), Amount: 1}, 1125 &UTXO{OutputID: bc.NewHash([32]byte{0x05}), Amount: 1}, 1126 &UTXO{OutputID: bc.NewHash([32]byte{0x06}), Amount: 1}, 1127 &UTXO{OutputID: bc.NewHash([32]byte{0x01}), Amount: 1}, 1128 }, 1129 optAmount: 5, 1130 reservedAmount: 0, 1131 }, 1132 { 1133 uk: utxoKeeper{}, 1134 input: []*UTXO{ 1135 &UTXO{OutputID: bc.NewHash([32]byte{0x01}), Amount: 1}, 1136 &UTXO{OutputID: bc.NewHash([32]byte{0x03}), Amount: 3}, 1137 &UTXO{OutputID: bc.NewHash([32]byte{0x05}), Amount: 5}, 1138 &UTXO{OutputID: bc.NewHash([32]byte{0x07}), Amount: 7}, 1139 &UTXO{OutputID: bc.NewHash([32]byte{0x11}), Amount: 11}, 1140 &UTXO{OutputID: bc.NewHash([32]byte{0x13}), Amount: 13}, 1141 &UTXO{OutputID: bc.NewHash([32]byte{0x23}), Amount: 23}, 1142 &UTXO{OutputID: bc.NewHash([32]byte{0x31}), Amount: 31}, 1143 }, 1144 inputAmount: 13, 1145 wantUtxos: []*UTXO{ 1146 &UTXO{OutputID: bc.NewHash([32]byte{0x07}), Amount: 7}, 1147 &UTXO{OutputID: bc.NewHash([32]byte{0x05}), Amount: 5}, 1148 &UTXO{OutputID: bc.NewHash([32]byte{0x03}), Amount: 3}, 1149 }, 1150 optAmount: 15, 1151 reservedAmount: 0, 1152 }, 1153 { 1154 uk: utxoKeeper{}, 1155 input: []*UTXO{ 1156 &UTXO{OutputID: bc.NewHash([32]byte{0x01}), Amount: 1}, 1157 }, 1158 inputAmount: 1, 1159 wantUtxos: []*UTXO{ 1160 &UTXO{OutputID: bc.NewHash([32]byte{0x01}), Amount: 1}, 1161 }, 1162 optAmount: 1, 1163 reservedAmount: 0, 1164 }, 1165 { 1166 uk: utxoKeeper{}, 1167 input: []*UTXO{ 1168 &UTXO{OutputID: bc.NewHash([32]byte{0x01}), Amount: 1}, 1169 &UTXO{OutputID: bc.NewHash([32]byte{0x02}), Amount: 2}, 1170 &UTXO{OutputID: bc.NewHash([32]byte{0x03}), Amount: 3}, 1171 &UTXO{OutputID: bc.NewHash([32]byte{0x04}), Amount: 4}, 1172 &UTXO{OutputID: bc.NewHash([32]byte{0x05}), Amount: 5}, 1173 &UTXO{OutputID: bc.NewHash([32]byte{0x06}), Amount: 6}, 1174 &UTXO{OutputID: bc.NewHash([32]byte{0x07}), Amount: 7}, 1175 &UTXO{OutputID: bc.NewHash([32]byte{0x08}), Amount: 8}, 1176 &UTXO{OutputID: bc.NewHash([32]byte{0x09}), Amount: 9}, 1177 &UTXO{OutputID: bc.NewHash([32]byte{0x10}), Amount: 10}, 1178 &UTXO{OutputID: bc.NewHash([32]byte{0x11}), Amount: 11}, 1179 &UTXO{OutputID: bc.NewHash([32]byte{0x12}), Amount: 12}, 1180 }, 1181 inputAmount: 15, 1182 wantUtxos: []*UTXO{ 1183 &UTXO{OutputID: bc.NewHash([32]byte{0x05}), Amount: 5}, 1184 &UTXO{OutputID: bc.NewHash([32]byte{0x04}), Amount: 4}, 1185 &UTXO{OutputID: bc.NewHash([32]byte{0x03}), Amount: 3}, 1186 &UTXO{OutputID: bc.NewHash([32]byte{0x02}), Amount: 2}, 1187 &UTXO{OutputID: bc.NewHash([32]byte{0x01}), Amount: 1}, 1188 }, 1189 optAmount: 15, 1190 reservedAmount: 0, 1191 }, 1192 } 1193 1194 for i, c := range cases { 1195 got, optAmount, reservedAmount := c.uk.optUTXOs(c.input, c.inputAmount) 1196 if !testutil.DeepEqual(got, c.wantUtxos) { 1197 t.Errorf("case %d: utxos got %v want %v", i, got, c.wantUtxos) 1198 } 1199 if optAmount != c.optAmount { 1200 t.Errorf("case %d: utxos got %v want %v", i, optAmount, c.optAmount) 1201 } 1202 if reservedAmount != c.reservedAmount { 1203 t.Errorf("case %d: reservedAmount got %v want %v", i, reservedAmount, c.reservedAmount) 1204 } 1205 } 1206 } 1207 1208 func checkUtxoKeeperEqual(t *testing.T, i int, a, b *utxoKeeper) { 1209 if !testutil.DeepEqual(a.unconfirmed, b.unconfirmed) { 1210 t.Errorf("case %d: unconfirmed got %v want %v", i, a.unconfirmed, b.unconfirmed) 1211 } 1212 if !testutil.DeepEqual(a.reserved, b.reserved) { 1213 t.Errorf("case %d: reserved got %v want %v", i, a.reserved, b.reserved) 1214 } 1215 if !testutil.DeepEqual(a.reservations, b.reservations) { 1216 t.Errorf("case %d: reservations got %v want %v", i, a.reservations, b.reservations) 1217 } 1218 }