10 "github.com/golang/groupcache/lru"
11 "github.com/vapor/blockchain/txbuilder"
12 "github.com/vapor/crypto/ed25519/chainkd"
13 dbm "github.com/vapor/database/leveldb"
14 "github.com/vapor/protocol/bc"
15 "github.com/vapor/testutil"
18 func TestAddUnconfirmedUtxo(t *testing.T) {
26 unconfirmed: map[bc.Hash]*UTXO{},
29 unconfirmed: map[bc.Hash]*UTXO{},
35 unconfirmed: map[bc.Hash]*UTXO{},
38 unconfirmed: map[bc.Hash]*UTXO{
39 bc.NewHash([32]byte{0x01}): &UTXO{OutputID: bc.NewHash([32]byte{0x01})},
43 &UTXO{OutputID: bc.NewHash([32]byte{0x01})},
48 unconfirmed: map[bc.Hash]*UTXO{
49 bc.NewHash([32]byte{0x01}): &UTXO{OutputID: bc.NewHash([32]byte{0x01})},
53 unconfirmed: map[bc.Hash]*UTXO{
54 bc.NewHash([32]byte{0x01}): &UTXO{OutputID: bc.NewHash([32]byte{0x01})},
58 &UTXO{OutputID: bc.NewHash([32]byte{0x01})},
63 unconfirmed: map[bc.Hash]*UTXO{
64 bc.NewHash([32]byte{0x01}): &UTXO{OutputID: bc.NewHash([32]byte{0x01})},
68 unconfirmed: map[bc.Hash]*UTXO{
69 bc.NewHash([32]byte{0x01}): &UTXO{OutputID: bc.NewHash([32]byte{0x01})},
70 bc.NewHash([32]byte{0x02}): &UTXO{OutputID: bc.NewHash([32]byte{0x02})},
71 bc.NewHash([32]byte{0x03}): &UTXO{OutputID: bc.NewHash([32]byte{0x03})},
75 &UTXO{OutputID: bc.NewHash([32]byte{0x02})},
76 &UTXO{OutputID: bc.NewHash([32]byte{0x03})},
81 for i, c := range cases {
82 c.before.AddUnconfirmedUtxo(c.addUtxos)
83 if !testutil.DeepEqual(c.before, c.after) {
84 t.Errorf("case %d: got %v want %v", i, c.before, c.after)
89 func TestCancel(t *testing.T) {
97 reserved: map[bc.Hash]uint64{},
98 reservations: map[uint64]*reservation{},
101 reserved: map[bc.Hash]uint64{},
102 reservations: map[uint64]*reservation{},
108 reserved: map[bc.Hash]uint64{
109 bc.NewHash([32]byte{0x01}): 1,
111 reservations: map[uint64]*reservation{
115 &UTXO{OutputID: bc.NewHash([32]byte{0x01})},
118 expiry: time.Date(2016, 8, 10, 0, 0, 0, 0, time.UTC),
123 reserved: map[bc.Hash]uint64{},
124 reservations: map[uint64]*reservation{},
130 reserved: map[bc.Hash]uint64{
131 bc.NewHash([32]byte{0x01}): 1,
133 reservations: map[uint64]*reservation{
137 &UTXO{OutputID: bc.NewHash([32]byte{0x01})},
140 expiry: time.Date(2016, 8, 10, 0, 0, 0, 0, time.UTC),
145 reserved: map[bc.Hash]uint64{
146 bc.NewHash([32]byte{0x01}): 1,
148 reservations: map[uint64]*reservation{
152 &UTXO{OutputID: bc.NewHash([32]byte{0x01})},
155 expiry: time.Date(2016, 8, 10, 0, 0, 0, 0, time.UTC),
163 reserved: map[bc.Hash]uint64{
164 bc.NewHash([32]byte{0x01}): 1,
165 bc.NewHash([32]byte{0x02}): 3,
166 bc.NewHash([32]byte{0x03}): 3,
167 bc.NewHash([32]byte{0x04}): 3,
169 reservations: map[uint64]*reservation{
173 &UTXO{OutputID: bc.NewHash([32]byte{0x01})},
176 expiry: time.Date(2016, 8, 10, 0, 0, 0, 0, time.UTC),
181 &UTXO{OutputID: bc.NewHash([32]byte{0x02})},
182 &UTXO{OutputID: bc.NewHash([32]byte{0x03})},
183 &UTXO{OutputID: bc.NewHash([32]byte{0x04})},
186 expiry: time.Date(2016, 8, 10, 0, 0, 0, 0, time.UTC),
191 reserved: map[bc.Hash]uint64{
192 bc.NewHash([32]byte{0x01}): 1,
194 reservations: map[uint64]*reservation{
198 &UTXO{OutputID: bc.NewHash([32]byte{0x01})},
201 expiry: time.Date(2016, 8, 10, 0, 0, 0, 0, time.UTC),
209 for i, c := range cases {
210 c.before.cancel(c.cancelRid)
211 if !testutil.DeepEqual(c.before, c.after) {
212 t.Errorf("case %d: got %v want %v", i, c.before, c.after)
217 func TestRemoveUnconfirmedUtxo(t *testing.T) {
221 removeUtxos []*bc.Hash
225 unconfirmed: map[bc.Hash]*UTXO{},
228 unconfirmed: map[bc.Hash]*UTXO{},
230 removeUtxos: []*bc.Hash{},
234 unconfirmed: map[bc.Hash]*UTXO{
235 bc.Hash{V0: 1}: &UTXO{OutputID: bc.NewHash([32]byte{0x01})},
239 unconfirmed: map[bc.Hash]*UTXO{},
241 removeUtxos: []*bc.Hash{
247 unconfirmed: map[bc.Hash]*UTXO{
248 bc.Hash{V0: 1}: &UTXO{OutputID: bc.NewHash([32]byte{0x01})},
249 bc.Hash{V0: 2}: &UTXO{OutputID: bc.NewHash([32]byte{0x02})},
250 bc.Hash{V0: 3}: &UTXO{OutputID: bc.NewHash([32]byte{0x03})},
251 bc.Hash{V0: 4}: &UTXO{OutputID: bc.NewHash([32]byte{0x04})},
252 bc.Hash{V0: 5}: &UTXO{OutputID: bc.NewHash([32]byte{0x05})},
256 unconfirmed: map[bc.Hash]*UTXO{
257 bc.Hash{V0: 2}: &UTXO{OutputID: bc.NewHash([32]byte{0x02})},
258 bc.Hash{V0: 4}: &UTXO{OutputID: bc.NewHash([32]byte{0x04})},
261 removeUtxos: []*bc.Hash{
269 for i, c := range cases {
270 c.before.RemoveUnconfirmedUtxo(c.removeUtxos)
271 if !testutil.DeepEqual(c.before, c.after) {
272 t.Errorf("case %d: got %v want %v", i, c.before, c.after)
277 func TestReserve(t *testing.T) {
278 currentHeight := func() uint64 { return 9527 }
279 testDB := dbm.NewDB("testdb", "leveldb", "temp")
285 accountStore := newMockAccountStore(testDB)
298 currentHeight: currentHeight,
299 reserved: map[bc.Hash]uint64{},
300 reservations: map[uint64]*reservation{},
304 currentHeight: currentHeight,
305 reserved: map[bc.Hash]uint64{},
306 reservations: map[uint64]*reservation{},
309 err: ErrInsufficient,
314 currentHeight: currentHeight,
315 unconfirmed: map[bc.Hash]*UTXO{
316 bc.NewHash([32]byte{0x01}): &UTXO{
317 OutputID: bc.NewHash([32]byte{0x01}),
318 AccountID: "testAccount",
322 reserved: map[bc.Hash]uint64{},
323 reservations: map[uint64]*reservation{},
327 currentHeight: currentHeight,
328 unconfirmed: map[bc.Hash]*UTXO{
329 bc.NewHash([32]byte{0x01}): &UTXO{
330 OutputID: bc.NewHash([32]byte{0x01}),
331 AccountID: "testAccount",
335 reserved: map[bc.Hash]uint64{},
336 reservations: map[uint64]*reservation{},
339 err: ErrInsufficient,
344 currentHeight: currentHeight,
345 unconfirmed: map[bc.Hash]*UTXO{
346 bc.NewHash([32]byte{0x01}): &UTXO{
347 OutputID: bc.NewHash([32]byte{0x01}),
348 AccountID: "testAccount",
353 reserved: map[bc.Hash]uint64{},
354 reservations: map[uint64]*reservation{},
358 currentHeight: currentHeight,
359 unconfirmed: map[bc.Hash]*UTXO{
360 bc.NewHash([32]byte{0x01}): &UTXO{
361 OutputID: bc.NewHash([32]byte{0x01}),
362 AccountID: "testAccount",
367 reserved: map[bc.Hash]uint64{},
368 reservations: map[uint64]*reservation{},
376 currentHeight: currentHeight,
377 unconfirmed: map[bc.Hash]*UTXO{
378 bc.NewHash([32]byte{0x01}): &UTXO{
379 OutputID: bc.NewHash([32]byte{0x01}),
380 AccountID: "testAccount",
384 reserved: map[bc.Hash]uint64{
385 bc.NewHash([32]byte{0x01}): 0,
387 reservations: map[uint64]*reservation{},
391 currentHeight: currentHeight,
392 unconfirmed: map[bc.Hash]*UTXO{
393 bc.NewHash([32]byte{0x01}): &UTXO{
394 OutputID: bc.NewHash([32]byte{0x01}),
395 AccountID: "testAccount",
399 reserved: map[bc.Hash]uint64{
400 bc.NewHash([32]byte{0x01}): 0,
402 reservations: map[uint64]*reservation{},
410 currentHeight: currentHeight,
411 unconfirmed: map[bc.Hash]*UTXO{
412 bc.NewHash([32]byte{0x01}): &UTXO{
413 OutputID: bc.NewHash([32]byte{0x01}),
414 AccountID: "testAccount",
418 reserved: map[bc.Hash]uint64{},
419 reservations: map[uint64]*reservation{},
423 currentHeight: currentHeight,
424 unconfirmed: map[bc.Hash]*UTXO{
425 bc.NewHash([32]byte{0x01}): &UTXO{
426 OutputID: bc.NewHash([32]byte{0x01}),
427 AccountID: "testAccount",
431 reserved: map[bc.Hash]uint64{
432 bc.NewHash([32]byte{0x01}): 1,
434 reservations: map[uint64]*reservation{
439 OutputID: bc.NewHash([32]byte{0x01}),
440 AccountID: "testAccount",
445 expiry: time.Date(2016, 8, 10, 0, 0, 0, 0, time.UTC),
451 exp: time.Date(2016, 8, 10, 0, 0, 0, 0, time.UTC),
456 currentHeight: currentHeight,
458 unconfirmed: map[bc.Hash]*UTXO{
459 bc.NewHash([32]byte{0x01}): &UTXO{
460 OutputID: bc.NewHash([32]byte{0x01}),
461 AccountID: "testAccount",
464 bc.NewHash([32]byte{0x02}): &UTXO{
465 OutputID: bc.NewHash([32]byte{0x02}),
466 AccountID: "testAccount",
469 bc.NewHash([32]byte{0x03}): &UTXO{
470 OutputID: bc.NewHash([32]byte{0x03}),
471 AccountID: "testAccount",
475 reserved: map[bc.Hash]uint64{
476 bc.NewHash([32]byte{0x01}): 1,
478 reservations: map[uint64]*reservation{},
482 currentHeight: currentHeight,
483 unconfirmed: map[bc.Hash]*UTXO{
484 bc.NewHash([32]byte{0x01}): &UTXO{
485 OutputID: bc.NewHash([32]byte{0x01}),
486 AccountID: "testAccount",
489 bc.NewHash([32]byte{0x02}): &UTXO{
490 OutputID: bc.NewHash([32]byte{0x02}),
491 AccountID: "testAccount",
494 bc.NewHash([32]byte{0x03}): &UTXO{
495 OutputID: bc.NewHash([32]byte{0x03}),
496 AccountID: "testAccount",
500 reserved: map[bc.Hash]uint64{
501 bc.NewHash([32]byte{0x01}): 1,
502 bc.NewHash([32]byte{0x02}): 2,
503 bc.NewHash([32]byte{0x03}): 2,
505 reservations: map[uint64]*reservation{
510 OutputID: bc.NewHash([32]byte{0x03}),
511 AccountID: "testAccount",
515 OutputID: bc.NewHash([32]byte{0x02}),
516 AccountID: "testAccount",
521 expiry: time.Date(2016, 8, 10, 0, 0, 0, 0, time.UTC),
527 exp: time.Date(2016, 8, 10, 0, 0, 0, 0, time.UTC),
532 currentHeight: currentHeight,
533 unconfirmed: map[bc.Hash]*UTXO{
534 bc.NewHash([32]byte{0x01}): &UTXO{
535 OutputID: bc.NewHash([32]byte{0x01}),
536 AccountID: "testAccount",
538 Vote: []byte("af594006a40837d9f028daabb6d589df0b9138daefad5683e5233c2646279217294a8d532e60863bcf196625a35fb8ceeffa3c09610eb92dcfb655a947f13269"),
541 reserved: map[bc.Hash]uint64{},
542 reservations: map[uint64]*reservation{},
546 currentHeight: currentHeight,
547 unconfirmed: map[bc.Hash]*UTXO{
548 bc.NewHash([32]byte{0x01}): &UTXO{
549 OutputID: bc.NewHash([32]byte{0x01}),
550 AccountID: "testAccount",
552 Vote: []byte("af594006a40837d9f028daabb6d589df0b9138daefad5683e5233c2646279217294a8d532e60863bcf196625a35fb8ceeffa3c09610eb92dcfb655a947f13269"),
555 reserved: map[bc.Hash]uint64{
556 bc.NewHash([32]byte{0x01}): 1,
558 reservations: map[uint64]*reservation{
563 OutputID: bc.NewHash([32]byte{0x01}),
564 AccountID: "testAccount",
566 Vote: []byte("af594006a40837d9f028daabb6d589df0b9138daefad5683e5233c2646279217294a8d532e60863bcf196625a35fb8ceeffa3c09610eb92dcfb655a947f13269"),
570 expiry: time.Date(2016, 8, 10, 0, 0, 0, 0, time.UTC),
576 exp: time.Date(2016, 8, 10, 0, 0, 0, 0, time.UTC),
577 vote: []byte("af594006a40837d9f028daabb6d589df0b9138daefad5683e5233c2646279217294a8d532e60863bcf196625a35fb8ceeffa3c09610eb92dcfb655a947f13269"),
581 for i, c := range cases {
582 if _, err := c.before.Reserve("testAccount", &bc.AssetID{}, c.reserveAmount, true, c.vote, c.exp); err != c.err {
583 t.Errorf("case %d: got error %v want error %v", i, err, c.err)
585 checkUtxoKeeperEqual(t, i, &c.before, &c.after)
589 func TestReserveParticular(t *testing.T) {
590 currentHeight := func() uint64 { return 9527 }
591 testDB := dbm.NewDB("testdb", "leveldb", "temp")
592 defer os.RemoveAll("temp")
594 accountStore := newMockAccountStore(testDB)
606 currentHeight: currentHeight,
607 unconfirmed: map[bc.Hash]*UTXO{
608 bc.NewHash([32]byte{0x01}): &UTXO{
609 OutputID: bc.NewHash([32]byte{0x01}),
610 AccountID: "testAccount",
614 reserved: map[bc.Hash]uint64{
615 bc.NewHash([32]byte{0x01}): 0,
617 reservations: map[uint64]*reservation{},
621 currentHeight: currentHeight,
622 unconfirmed: map[bc.Hash]*UTXO{
623 bc.NewHash([32]byte{0x01}): &UTXO{
624 OutputID: bc.NewHash([32]byte{0x01}),
625 AccountID: "testAccount",
629 reserved: map[bc.Hash]uint64{
630 bc.NewHash([32]byte{0x01}): 0,
632 reservations: map[uint64]*reservation{},
634 reserveHash: bc.NewHash([32]byte{0x01}),
640 currentHeight: currentHeight,
641 unconfirmed: map[bc.Hash]*UTXO{
642 bc.NewHash([32]byte{0x01}): &UTXO{
643 OutputID: bc.NewHash([32]byte{0x01}),
644 AccountID: "testAccount",
649 reserved: map[bc.Hash]uint64{},
650 reservations: map[uint64]*reservation{},
654 currentHeight: currentHeight,
655 unconfirmed: map[bc.Hash]*UTXO{
656 bc.NewHash([32]byte{0x01}): &UTXO{
657 OutputID: bc.NewHash([32]byte{0x01}),
658 AccountID: "testAccount",
663 reserved: map[bc.Hash]uint64{},
664 reservations: map[uint64]*reservation{},
666 reserveHash: bc.NewHash([32]byte{0x01}),
672 currentHeight: currentHeight,
673 unconfirmed: map[bc.Hash]*UTXO{
674 bc.NewHash([32]byte{0x01}): &UTXO{
675 OutputID: bc.NewHash([32]byte{0x01}),
676 AccountID: "testAccount",
680 reserved: map[bc.Hash]uint64{},
681 reservations: map[uint64]*reservation{},
685 currentHeight: currentHeight,
686 unconfirmed: map[bc.Hash]*UTXO{
687 bc.NewHash([32]byte{0x01}): &UTXO{
688 OutputID: bc.NewHash([32]byte{0x01}),
689 AccountID: "testAccount",
693 reserved: map[bc.Hash]uint64{
694 bc.NewHash([32]byte{0x01}): 1,
696 reservations: map[uint64]*reservation{
701 OutputID: bc.NewHash([32]byte{0x01}),
702 AccountID: "testAccount",
707 expiry: time.Date(2016, 8, 10, 0, 0, 0, 0, time.UTC),
711 reserveHash: bc.NewHash([32]byte{0x01}),
713 exp: time.Date(2016, 8, 10, 0, 0, 0, 0, time.UTC),
717 for i, c := range cases {
718 if _, err := c.before.ReserveParticular(c.reserveHash, true, c.exp); err != c.err {
719 t.Errorf("case %d: got error %v want error %v", i, err, c.err)
721 checkUtxoKeeperEqual(t, i, &c.before, &c.after)
725 func TestExpireReservation(t *testing.T) {
726 before := &utxoKeeper{
727 reservations: map[uint64]*reservation{
728 1: &reservation{expiry: time.Date(2016, 8, 10, 0, 0, 0, 0, time.UTC)},
729 2: &reservation{expiry: time.Date(3016, 8, 10, 0, 0, 0, 0, time.UTC)},
730 3: &reservation{expiry: time.Date(2016, 8, 10, 0, 0, 0, 0, time.UTC)},
731 4: &reservation{expiry: time.Date(3016, 8, 10, 0, 0, 0, 0, time.UTC)},
732 5: &reservation{expiry: time.Date(3016, 8, 10, 0, 0, 0, 0, time.UTC)},
735 after := &utxoKeeper{
736 reservations: map[uint64]*reservation{
737 2: &reservation{expiry: time.Date(3016, 8, 10, 0, 0, 0, 0, time.UTC)},
738 4: &reservation{expiry: time.Date(3016, 8, 10, 0, 0, 0, 0, time.UTC)},
739 5: &reservation{expiry: time.Date(3016, 8, 10, 0, 0, 0, 0, time.UTC)},
742 before.expireReservation(time.Date(2017, 8, 10, 0, 0, 0, 0, time.UTC))
743 checkUtxoKeeperEqual(t, 0, before, after)
746 func TestFindUtxos(t *testing.T) {
747 currentHeight := func() uint64 { return 9527 }
748 testDB := dbm.NewDB("testdb", "leveldb", "temp")
754 accountStore := newMockAccountStore(testDB)
761 immatureAmount uint64
767 currentHeight: currentHeight,
768 unconfirmed: map[bc.Hash]*UTXO{},
771 useUnconfirmed: true,
772 wantUtxos: []*UTXO{},
778 currentHeight: currentHeight,
779 unconfirmed: map[bc.Hash]*UTXO{},
783 OutputID: bc.NewHash([32]byte{0x01}),
784 AccountID: "testAccount",
788 OutputID: bc.NewHash([32]byte{0x02}),
789 AccountID: "testAccount",
790 AssetID: bc.AssetID{V0: 6},
794 useUnconfirmed: false,
797 OutputID: bc.NewHash([32]byte{0x01}),
798 AccountID: "testAccount",
807 currentHeight: currentHeight,
808 unconfirmed: map[bc.Hash]*UTXO{},
812 OutputID: bc.NewHash([32]byte{0x02}),
813 AccountID: "testAccount",
818 useUnconfirmed: false,
819 wantUtxos: []*UTXO{},
825 currentHeight: currentHeight,
826 unconfirmed: map[bc.Hash]*UTXO{
827 bc.NewHash([32]byte{0x01}): &UTXO{
828 OutputID: bc.NewHash([32]byte{0x01}),
829 AccountID: "testAccount",
836 OutputID: bc.NewHash([32]byte{0x02}),
837 AccountID: "testAccount",
841 useUnconfirmed: false,
844 OutputID: bc.NewHash([32]byte{0x02}),
845 AccountID: "testAccount",
854 currentHeight: currentHeight,
855 unconfirmed: map[bc.Hash]*UTXO{
856 bc.NewHash([32]byte{0x11}): &UTXO{
857 OutputID: bc.NewHash([32]byte{0x01}),
858 AccountID: "testAccount",
865 OutputID: bc.NewHash([32]byte{0x02}),
866 AccountID: "testAccount",
870 useUnconfirmed: true,
873 OutputID: bc.NewHash([32]byte{0x02}),
874 AccountID: "testAccount",
878 OutputID: bc.NewHash([32]byte{0x01}),
879 AccountID: "testAccount",
888 currentHeight: currentHeight,
889 unconfirmed: map[bc.Hash]*UTXO{
890 bc.NewHash([32]byte{0x01}): &UTXO{
891 OutputID: bc.NewHash([32]byte{0x01}),
892 AccountID: "testAccount",
895 bc.NewHash([32]byte{0x02}): &UTXO{
896 OutputID: bc.NewHash([32]byte{0x02}),
904 OutputID: bc.NewHash([32]byte{0x03}),
905 AccountID: "testAccount",
909 OutputID: bc.NewHash([32]byte{0x04}),
914 useUnconfirmed: true,
917 OutputID: bc.NewHash([32]byte{0x03}),
918 AccountID: "testAccount",
922 OutputID: bc.NewHash([32]byte{0x01}),
923 AccountID: "testAccount",
932 currentHeight: currentHeight,
933 unconfirmed: map[bc.Hash]*UTXO{},
937 OutputID: bc.NewHash([32]byte{0x01}),
938 AccountID: "testAccount",
940 Vote: []byte("af594006a40837d9f028daabb6d589df0b9138daefad5683e5233c2646279217294a8d532e60863bcf196625a35fb8ceeffa3c09610eb92dcfb655a947f13269"),
943 useUnconfirmed: false,
946 OutputID: bc.NewHash([32]byte{0x01}),
947 AccountID: "testAccount",
949 Vote: []byte("af594006a40837d9f028daabb6d589df0b9138daefad5683e5233c2646279217294a8d532e60863bcf196625a35fb8ceeffa3c09610eb92dcfb655a947f13269"),
953 vote: []byte("af594006a40837d9f028daabb6d589df0b9138daefad5683e5233c2646279217294a8d532e60863bcf196625a35fb8ceeffa3c09610eb92dcfb655a947f13269"),
957 for i, c := range cases {
958 for _, u := range c.dbUtxos {
959 if err := c.uk.store.SetStandardUTXO(u.OutputID, u); err != nil {
964 gotUtxos, immatureAmount := c.uk.findUtxos("testAccount", &bc.AssetID{}, c.useUnconfirmed, c.vote)
965 if !testutil.DeepEqual(gotUtxos, c.wantUtxos) {
966 t.Errorf("case %d: got %v want %v", i, gotUtxos, c.wantUtxos)
968 if immatureAmount != c.immatureAmount {
969 t.Errorf("case %d: got %v want %v", i, immatureAmount, c.immatureAmount)
972 for _, u := range c.dbUtxos {
973 c.uk.store.DeleteStandardUTXO(u.OutputID)
978 func TestFindUTXO(t *testing.T) {
979 currentHeight := func() uint64 { return 9527 }
980 testDB := dbm.NewDB("testdb", "leveldb", "temp")
981 defer os.RemoveAll("temp")
983 accountStore := newMockAccountStore(testDB)
987 dbUtxos map[string]*UTXO
996 currentHeight: currentHeight,
997 unconfirmed: map[bc.Hash]*UTXO{},
999 dbUtxos: map[string]*UTXO{},
1000 outHash: bc.NewHash([32]byte{0x01}),
1006 store: accountStore,
1007 currentHeight: currentHeight,
1008 unconfirmed: map[bc.Hash]*UTXO{
1009 bc.NewHash([32]byte{0x01}): &UTXO{OutputID: bc.NewHash([32]byte{0x01})},
1012 dbUtxos: map[string]*UTXO{},
1013 outHash: bc.NewHash([32]byte{0x01}),
1015 useUnconfirmed: false,
1020 store: accountStore,
1021 currentHeight: currentHeight,
1022 unconfirmed: map[bc.Hash]*UTXO{
1023 bc.NewHash([32]byte{0x01}): &UTXO{OutputID: bc.NewHash([32]byte{0x01})},
1026 dbUtxos: map[string]*UTXO{},
1027 outHash: bc.NewHash([32]byte{0x01}),
1028 wantUtxo: &UTXO{OutputID: bc.NewHash([32]byte{0x01})},
1029 useUnconfirmed: true,
1034 store: accountStore,
1035 currentHeight: currentHeight,
1036 unconfirmed: map[bc.Hash]*UTXO{},
1038 dbUtxos: map[string]*UTXO{
1039 string(StandardUTXOKey(bc.NewHash([32]byte{0x01}))): &UTXO{OutputID: bc.NewHash([32]byte{0x01})},
1041 outHash: bc.NewHash([32]byte{0x01}),
1042 wantUtxo: &UTXO{OutputID: bc.NewHash([32]byte{0x01})},
1043 useUnconfirmed: false,
1048 store: accountStore,
1049 currentHeight: currentHeight,
1050 unconfirmed: map[bc.Hash]*UTXO{},
1052 dbUtxos: map[string]*UTXO{
1053 string(ContractUTXOKey(bc.NewHash([32]byte{0x01}))): &UTXO{OutputID: bc.NewHash([32]byte{0x01})},
1055 outHash: bc.NewHash([32]byte{0x01}),
1056 wantUtxo: &UTXO{OutputID: bc.NewHash([32]byte{0x01})},
1057 useUnconfirmed: false,
1062 for i, c := range cases {
1063 for k, u := range c.dbUtxos {
1064 data, err := json.Marshal(u)
1068 testDB.Set([]byte(k), data)
1071 gotUtxo, err := c.uk.findUtxo(c.outHash, c.useUnconfirmed)
1072 if !testutil.DeepEqual(gotUtxo, c.wantUtxo) {
1073 t.Errorf("case %d: got %v want %v", i, gotUtxo, c.wantUtxo)
1076 t.Errorf("case %d: got %v want %v", i, err, c.err)
1079 for _, u := range c.dbUtxos {
1080 c.uk.store.DeleteStandardUTXO(u.OutputID)
1085 func TestOptUTXOs(t *testing.T) {
1092 reservedAmount uint64
1096 reserved: map[bc.Hash]uint64{
1097 bc.NewHash([32]byte{0x01}): 1,
1102 wantUtxos: []*UTXO{},
1108 reserved: map[bc.Hash]uint64{
1109 bc.NewHash([32]byte{0x01}): 1,
1113 &UTXO{OutputID: bc.NewHash([32]byte{0x01}), Amount: 1},
1116 wantUtxos: []*UTXO{},
1122 reserved: map[bc.Hash]uint64{
1123 bc.NewHash([32]byte{0x01}): 1,
1127 &UTXO{OutputID: bc.NewHash([32]byte{0x01}), Amount: 1},
1128 &UTXO{OutputID: bc.NewHash([32]byte{0x02}), Amount: 3},
1129 &UTXO{OutputID: bc.NewHash([32]byte{0x03}), Amount: 5},
1133 &UTXO{OutputID: bc.NewHash([32]byte{0x03}), Amount: 5},
1134 &UTXO{OutputID: bc.NewHash([32]byte{0x02}), Amount: 3},
1141 reserved: map[bc.Hash]uint64{
1142 bc.NewHash([32]byte{0x01}): 1,
1143 bc.NewHash([32]byte{0x02}): 2,
1144 bc.NewHash([32]byte{0x03}): 3,
1148 &UTXO{OutputID: bc.NewHash([32]byte{0x01}), Amount: 1},
1149 &UTXO{OutputID: bc.NewHash([32]byte{0x02}), Amount: 3},
1150 &UTXO{OutputID: bc.NewHash([32]byte{0x03}), Amount: 5},
1153 wantUtxos: []*UTXO{},
1160 &UTXO{OutputID: bc.NewHash([32]byte{0x01}), Amount: 1},
1161 &UTXO{OutputID: bc.NewHash([32]byte{0x02}), Amount: 3},
1162 &UTXO{OutputID: bc.NewHash([32]byte{0x03}), Amount: 5},
1166 &UTXO{OutputID: bc.NewHash([32]byte{0x01}), Amount: 1},
1174 &UTXO{OutputID: bc.NewHash([32]byte{0x02}), Amount: 2},
1175 &UTXO{OutputID: bc.NewHash([32]byte{0x03}), Amount: 3},
1176 &UTXO{OutputID: bc.NewHash([32]byte{0x05}), Amount: 5},
1180 &UTXO{OutputID: bc.NewHash([32]byte{0x03}), Amount: 3},
1181 &UTXO{OutputID: bc.NewHash([32]byte{0x02}), Amount: 2},
1189 &UTXO{OutputID: bc.NewHash([32]byte{0x01}), Amount: 1},
1190 &UTXO{OutputID: bc.NewHash([32]byte{0x02}), Amount: 1},
1191 &UTXO{OutputID: bc.NewHash([32]byte{0x03}), Amount: 1},
1192 &UTXO{OutputID: bc.NewHash([32]byte{0x04}), Amount: 1},
1193 &UTXO{OutputID: bc.NewHash([32]byte{0x05}), Amount: 1},
1194 &UTXO{OutputID: bc.NewHash([32]byte{0x06}), Amount: 1},
1195 &UTXO{OutputID: bc.NewHash([32]byte{0x08}), Amount: 6},
1199 &UTXO{OutputID: bc.NewHash([32]byte{0x08}), Amount: 6},
1207 &UTXO{OutputID: bc.NewHash([32]byte{0x01}), Amount: 1},
1208 &UTXO{OutputID: bc.NewHash([32]byte{0x02}), Amount: 1},
1209 &UTXO{OutputID: bc.NewHash([32]byte{0x03}), Amount: 1},
1210 &UTXO{OutputID: bc.NewHash([32]byte{0x04}), Amount: 1},
1211 &UTXO{OutputID: bc.NewHash([32]byte{0x05}), Amount: 1},
1212 &UTXO{OutputID: bc.NewHash([32]byte{0x06}), Amount: 1},
1213 &UTXO{OutputID: bc.NewHash([32]byte{0x08}), Amount: 6},
1217 &UTXO{OutputID: bc.NewHash([32]byte{0x03}), Amount: 1},
1218 &UTXO{OutputID: bc.NewHash([32]byte{0x04}), Amount: 1},
1219 &UTXO{OutputID: bc.NewHash([32]byte{0x05}), Amount: 1},
1220 &UTXO{OutputID: bc.NewHash([32]byte{0x06}), Amount: 1},
1221 &UTXO{OutputID: bc.NewHash([32]byte{0x01}), Amount: 1},
1229 &UTXO{OutputID: bc.NewHash([32]byte{0x01}), Amount: 1},
1230 &UTXO{OutputID: bc.NewHash([32]byte{0x03}), Amount: 3},
1231 &UTXO{OutputID: bc.NewHash([32]byte{0x05}), Amount: 5},
1232 &UTXO{OutputID: bc.NewHash([32]byte{0x07}), Amount: 7},
1233 &UTXO{OutputID: bc.NewHash([32]byte{0x11}), Amount: 11},
1234 &UTXO{OutputID: bc.NewHash([32]byte{0x13}), Amount: 13},
1235 &UTXO{OutputID: bc.NewHash([32]byte{0x23}), Amount: 23},
1236 &UTXO{OutputID: bc.NewHash([32]byte{0x31}), Amount: 31},
1240 &UTXO{OutputID: bc.NewHash([32]byte{0x07}), Amount: 7},
1241 &UTXO{OutputID: bc.NewHash([32]byte{0x05}), Amount: 5},
1242 &UTXO{OutputID: bc.NewHash([32]byte{0x03}), Amount: 3},
1250 &UTXO{OutputID: bc.NewHash([32]byte{0x01}), Amount: 1},
1254 &UTXO{OutputID: bc.NewHash([32]byte{0x01}), Amount: 1},
1262 &UTXO{OutputID: bc.NewHash([32]byte{0x01}), Amount: 1},
1263 &UTXO{OutputID: bc.NewHash([32]byte{0x02}), Amount: 2},
1264 &UTXO{OutputID: bc.NewHash([32]byte{0x03}), Amount: 3},
1265 &UTXO{OutputID: bc.NewHash([32]byte{0x04}), Amount: 4},
1266 &UTXO{OutputID: bc.NewHash([32]byte{0x05}), Amount: 5},
1267 &UTXO{OutputID: bc.NewHash([32]byte{0x06}), Amount: 6},
1268 &UTXO{OutputID: bc.NewHash([32]byte{0x07}), Amount: 7},
1269 &UTXO{OutputID: bc.NewHash([32]byte{0x08}), Amount: 8},
1270 &UTXO{OutputID: bc.NewHash([32]byte{0x09}), Amount: 9},
1271 &UTXO{OutputID: bc.NewHash([32]byte{0x10}), Amount: 10},
1272 &UTXO{OutputID: bc.NewHash([32]byte{0x11}), Amount: 11},
1273 &UTXO{OutputID: bc.NewHash([32]byte{0x12}), Amount: 12},
1277 &UTXO{OutputID: bc.NewHash([32]byte{0x05}), Amount: 5},
1278 &UTXO{OutputID: bc.NewHash([32]byte{0x04}), Amount: 4},
1279 &UTXO{OutputID: bc.NewHash([32]byte{0x03}), Amount: 3},
1280 &UTXO{OutputID: bc.NewHash([32]byte{0x02}), Amount: 2},
1281 &UTXO{OutputID: bc.NewHash([32]byte{0x01}), Amount: 1},
1288 for i, c := range cases {
1289 got, optAmount, reservedAmount := c.uk.optUTXOs(c.input, c.inputAmount)
1290 if !testutil.DeepEqual(got, c.wantUtxos) {
1291 t.Errorf("case %d: utxos got %v want %v", i, got, c.wantUtxos)
1293 if optAmount != c.optAmount {
1294 t.Errorf("case %d: utxos got %v want %v", i, optAmount, c.optAmount)
1296 if reservedAmount != c.reservedAmount {
1297 t.Errorf("case %d: reservedAmount got %v want %v", i, reservedAmount, c.reservedAmount)
1302 func checkUtxoKeeperEqual(t *testing.T, i int, a, b *utxoKeeper) {
1303 if !testutil.DeepEqual(a.unconfirmed, b.unconfirmed) {
1304 t.Errorf("case %d: unconfirmed got %v want %v", i, a.unconfirmed, b.unconfirmed)
1306 if !testutil.DeepEqual(a.reserved, b.reserved) {
1307 t.Errorf("case %d: reserved got %v want %v", i, a.reserved, b.reserved)
1309 if !testutil.DeepEqual(a.reservations, b.reservations) {
1310 t.Errorf("case %d: reservations got %v want %v", i, a.reservations, b.reservations)
1315 utxoPrefix byte = iota //UTXOPrefix is StandardUTXOKey prefix
1318 accountPrefix // AccountPrefix is account ID prefix
1322 // leveldb key prefix
1325 accountStore = []byte("AS:")
1326 UTXOPrefix = append(accountStore, utxoPrefix, colon)
1327 ContractPrefix = append(accountStore, contractPrefix, colon)
1328 ContractIndexPrefix = append(accountStore, contractIndexPrefix, colon)
1329 AccountPrefix = append(accountStore, accountPrefix, colon) // AccountPrefix is account ID prefix
1330 AccountIndexPrefix = append(accountStore, accountIndexPrefix, colon)
1334 sutxoPrefix byte = iota //SUTXOPrefix is ContractUTXOKey prefix
1336 txPrefix //TxPrefix is wallet database transactions prefix
1337 txIndexPrefix //TxIndexPrefix is wallet database tx index prefix
1338 unconfirmedTxPrefix //UnconfirmedTxPrefix is txpool unconfirmed transactions prefix
1339 globalTxIndexPrefix //GlobalTxIndexPrefix is wallet database global tx index prefix
1343 recoveryKey //recoveryKey key for db store recovery info.
1347 walletStore = []byte("WS:")
1348 SUTXOPrefix = append(walletStore, sutxoPrefix, colon)
1349 AccountAliasPrefix = append(walletStore, accountAliasPrefix, colon)
1350 TxPrefix = append(walletStore, txPrefix, colon) //TxPrefix is wallet database transactions prefix
1351 TxIndexPrefix = append(walletStore, txIndexPrefix, colon) //TxIndexPrefix is wallet database tx index prefix
1352 UnconfirmedTxPrefix = append(walletStore, unconfirmedTxPrefix, colon) //UnconfirmedTxPrefix is txpool unconfirmed transactions prefix
1353 GlobalTxIndexPrefix = append(walletStore, globalTxIndexPrefix, colon) //GlobalTxIndexPrefix is wallet database global tx index prefix
1354 WalletKey = append(walletStore, walletKey)
1355 MiningAddressKey = append(walletStore, miningAddressKey)
1356 CoinbaseAbKey = append(walletStore, coinbaseAbKey)
1357 RecoveryKey = append(walletStore, recoveryKey)
1360 type mockAccountStore struct {
1365 // NewAccountStore create new AccountStore.
1366 func newMockAccountStore(db dbm.DB) *mockAccountStore {
1367 return &mockAccountStore{
1373 // StandardUTXOKey makes an account unspent outputs key to store
1374 func StandardUTXOKey(id bc.Hash) []byte {
1375 return append(UTXOPrefix, id.Bytes()...)
1378 // ContractUTXOKey makes a smart contract unspent outputs key to store
1379 func ContractUTXOKey(id bc.Hash) []byte {
1380 return append(SUTXOPrefix, id.Bytes()...)
1383 func (store *mockAccountStore) InitBatch() AccountStore { return nil }
1384 func (store *mockAccountStore) CommitBatch() error { return nil }
1385 func (store *mockAccountStore) DeleteAccount(*Account) error { return nil }
1386 func (store *mockAccountStore) GetAccountByAlias(string) (*Account, error) { return nil, nil }
1387 func (store *mockAccountStore) GetAccountByID(string) (*Account, error) { return nil, nil }
1388 func (store *mockAccountStore) GetAccountIndex([]chainkd.XPub) uint64 { return 0 }
1389 func (store *mockAccountStore) GetBip44ContractIndex(string, bool) uint64 { return 0 }
1390 func (store *mockAccountStore) GetCoinbaseArbitrary() []byte { return nil }
1391 func (store *mockAccountStore) GetContractIndex(string) uint64 { return 0 }
1392 func (store *mockAccountStore) GetControlProgram(bc.Hash) (*CtrlProgram, error) { return nil, nil }
1393 func (store *mockAccountStore) GetMiningAddress() (*CtrlProgram, error) { return nil, nil }
1394 func (store *mockAccountStore) ListAccounts(string) ([]*Account, error) { return nil, nil }
1395 func (store *mockAccountStore) ListControlPrograms() ([]*CtrlProgram, error) { return nil, nil }
1396 func (store *mockAccountStore) SetAccount(*Account) error { return nil }
1397 func (store *mockAccountStore) SetAccountIndex(*Account) { return }
1398 func (store *mockAccountStore) SetBip44ContractIndex(string, bool, uint64) { return }
1399 func (store *mockAccountStore) SetCoinbaseArbitrary([]byte) { return }
1400 func (store *mockAccountStore) SetContractIndex(string, uint64) { return }
1401 func (store *mockAccountStore) SetControlProgram(bc.Hash, *CtrlProgram) error { return nil }
1402 func (store *mockAccountStore) SetMiningAddress(*CtrlProgram) error { return nil }
1404 // DeleteStandardUTXO delete utxo by outpu id
1405 func (store *mockAccountStore) DeleteStandardUTXO(outputID bc.Hash) {
1406 if store.batch == nil {
1407 store.db.Delete(StandardUTXOKey(outputID))
1409 store.batch.Delete(StandardUTXOKey(outputID))
1413 // GetUTXO get standard utxo by id
1414 func (store *mockAccountStore) GetUTXO(outid bc.Hash) (*UTXO, error) {
1416 if data := store.db.Get(StandardUTXOKey(outid)); data != nil {
1417 return u, json.Unmarshal(data, u)
1419 if data := store.db.Get(ContractUTXOKey(outid)); data != nil {
1420 return u, json.Unmarshal(data, u)
1422 return nil, ErrMatchUTXO
1425 // ListUTXOs get utxos by accountID
1426 func (store *mockAccountStore) ListUTXOs() ([]*UTXO, error) {
1427 utxoIter := store.db.IteratorPrefix([]byte(UTXOPrefix))
1428 defer utxoIter.Release()
1431 for utxoIter.Next() {
1433 if err := json.Unmarshal(utxoIter.Value(), utxo); err != nil {
1436 utxos = append(utxos, utxo)
1441 // SetStandardUTXO set standard utxo
1442 func (store *mockAccountStore) SetStandardUTXO(outputID bc.Hash, utxo *UTXO) error {
1443 data, err := json.Marshal(utxo)
1447 if store.batch == nil {
1448 store.db.Set(StandardUTXOKey(outputID), data)
1450 store.batch.Set(StandardUTXOKey(outputID), data)
1455 func mockAccountManager(t *testing.T) *Manager {
1456 dirPath, err := ioutil.TempDir(".", "")
1460 defer os.RemoveAll(dirPath)
1462 testDB := dbm.NewDB("testdb", "memdb", dirPath)
1463 accountStore := newMockAccountStore(testDB)
1464 bestBlockHeight := func() uint64 { return 9527 }
1467 store: accountStore,
1469 utxoKeeper: newUtxoKeeper(bestBlockHeight, accountStore),
1470 cache: lru.New(maxAccountCache),
1471 aliasCache: lru.New(maxAccountCache),
1472 delayedACPs: make(map[*txbuilder.TemplateBuilder][]*CtrlProgram),