6 "github.com/davecgh/go-spew/spew"
8 "github.com/vapor/consensus"
9 "github.com/vapor/database/storage"
10 "github.com/vapor/errors"
11 "github.com/vapor/protocol/bc"
12 "github.com/vapor/testutil"
15 var defaultEntry = map[bc.Hash]bc.Entry{
16 bc.Hash{V0: 0}: &bc.IntraChainOutput{
17 Source: &bc.ValueSource{
18 Value: &bc.AssetAmount{
19 AssetId: &bc.AssetID{V0: 0},
25 var coinbaseEntry = map[bc.Hash]bc.Entry{
26 bc.Hash{V0: 0}: &bc.IntraChainOutput{
27 Source: &bc.ValueSource{
28 Value: &bc.AssetAmount{
29 AssetId: consensus.BTMAssetID,
33 bc.Hash{V0: 1}: &bc.IntraChainOutput{
34 Source: &bc.ValueSource{
35 Value: &bc.AssetAmount{
36 AssetId: consensus.BTMAssetID,
43 var voteEntry = map[bc.Hash]bc.Entry{
44 bc.Hash{V0: 0}: &bc.VoteOutput{
45 Source: &bc.ValueSource{
46 Value: &bc.AssetAmount{
47 AssetId: &bc.AssetID{V0: 0},
53 var gasOnlyTxEntry = map[bc.Hash]bc.Entry{
54 bc.Hash{V1: 0}: &bc.IntraChainOutput{
55 Source: &bc.ValueSource{
56 Value: &bc.AssetAmount{
57 AssetId: consensus.BTMAssetID,
61 bc.Hash{V1: 1}: &bc.IntraChainOutput{
62 Source: &bc.ValueSource{
63 Value: &bc.AssetAmount{
64 AssetId: &bc.AssetID{V0: 999},
70 func TestApplyBlock(t *testing.T) {
73 inputView *UtxoViewpoint
74 fetchView *UtxoViewpoint
79 // can't find prevout in tx entries
81 BlockHeader: &bc.BlockHeader{
82 TransactionStatus: bc.NewTransactionStatus(),
84 Transactions: []*bc.Tx{
86 SpentOutputIDs: []bc.Hash{
89 Entries: defaultEntry,
93 inputView: &UtxoViewpoint{
94 Entries: map[bc.Hash]*storage.UtxoEntry{
95 bc.Hash{V0: 0}: storage.NewUtxoEntry(storage.NormalUTXOType, 0, false),
98 fetchView: NewUtxoViewpoint(),
103 BlockHeader: &bc.BlockHeader{
104 TransactionStatus: bc.NewTransactionStatus(),
106 Transactions: []*bc.Tx{
108 SpentOutputIDs: []bc.Hash{
111 Entries: defaultEntry,
115 inputView: NewUtxoViewpoint(),
116 fetchView: NewUtxoViewpoint(),
121 BlockHeader: &bc.BlockHeader{
122 TransactionStatus: bc.NewTransactionStatus(),
124 Transactions: []*bc.Tx{
126 SpentOutputIDs: []bc.Hash{
129 Entries: defaultEntry,
133 inputView: &UtxoViewpoint{
134 Entries: map[bc.Hash]*storage.UtxoEntry{
135 bc.Hash{V0: 0}: storage.NewUtxoEntry(storage.NormalUTXOType, 0, true),
142 BlockHeader: &bc.BlockHeader{
143 TransactionStatus: bc.NewTransactionStatus(),
145 Transactions: []*bc.Tx{
147 TxHeader: &bc.TxHeader{
148 ResultIds: []*bc.Hash{},
150 SpentOutputIDs: []bc.Hash{
153 Entries: defaultEntry,
157 inputView: &UtxoViewpoint{
158 Entries: map[bc.Hash]*storage.UtxoEntry{
159 bc.Hash{V0: 0}: storage.NewUtxoEntry(storage.NormalUTXOType, 0, false),
162 fetchView: &UtxoViewpoint{
163 Entries: map[bc.Hash]*storage.UtxoEntry{
164 bc.Hash{V0: 0}: storage.NewUtxoEntry(storage.NormalUTXOType, 0, true),
171 BlockHeader: &bc.BlockHeader{
172 Height: consensus.MainNetParams.CoinbasePendingBlockNumber + 1,
173 TransactionStatus: bc.NewTransactionStatus(),
175 Transactions: []*bc.Tx{
177 TxHeader: &bc.TxHeader{
178 ResultIds: []*bc.Hash{},
180 SpentOutputIDs: []bc.Hash{
183 Entries: defaultEntry,
187 inputView: &UtxoViewpoint{
188 Entries: map[bc.Hash]*storage.UtxoEntry{
189 bc.Hash{V0: 0}: storage.NewUtxoEntry(storage.CoinbaseUTXOType, 0, false),
192 fetchView: &UtxoViewpoint{
193 Entries: map[bc.Hash]*storage.UtxoEntry{
194 bc.Hash{V0: 0}: storage.NewUtxoEntry(storage.CoinbaseUTXOType, 0, true),
201 BlockHeader: &bc.BlockHeader{
203 TransactionStatus: bc.NewTransactionStatus(),
205 Transactions: []*bc.Tx{
207 TxHeader: &bc.TxHeader{
208 ResultIds: []*bc.Hash{},
210 SpentOutputIDs: []bc.Hash{
213 Entries: defaultEntry,
217 inputView: &UtxoViewpoint{
218 Entries: map[bc.Hash]*storage.UtxoEntry{
219 bc.Hash{V0: 0}: storage.NewUtxoEntry(storage.CoinbaseUTXOType, 0, false),
222 fetchView: &UtxoViewpoint{
223 Entries: map[bc.Hash]*storage.UtxoEntry{
224 bc.Hash{V0: 0}: storage.NewUtxoEntry(storage.CoinbaseUTXOType, 0, true),
230 // output will be store
232 BlockHeader: &bc.BlockHeader{
233 TransactionStatus: bc.NewTransactionStatus(),
235 Transactions: []*bc.Tx{
237 TxHeader: &bc.TxHeader{
238 ResultIds: []*bc.Hash{
243 SpentOutputIDs: []bc.Hash{},
244 Entries: coinbaseEntry,
248 inputView: NewUtxoViewpoint(),
249 fetchView: &UtxoViewpoint{
250 Entries: map[bc.Hash]*storage.UtxoEntry{
251 bc.Hash{V0: 1}: storage.NewUtxoEntry(storage.CoinbaseUTXOType, 0, false),
257 // apply gas only tx, non-btm asset spent input will not be spent
259 BlockHeader: &bc.BlockHeader{
260 TransactionStatus: bc.NewTransactionStatus(),
262 Transactions: []*bc.Tx{
264 TxHeader: &bc.TxHeader{
265 ResultIds: []*bc.Hash{},
267 SpentOutputIDs: []bc.Hash{
271 Entries: gasOnlyTxEntry,
275 inputView: &UtxoViewpoint{
276 Entries: map[bc.Hash]*storage.UtxoEntry{
277 bc.Hash{V1: 0}: storage.NewUtxoEntry(storage.NormalUTXOType, 0, false),
278 bc.Hash{V1: 1}: storage.NewUtxoEntry(storage.NormalUTXOType, 0, false),
281 fetchView: &UtxoViewpoint{
282 Entries: map[bc.Hash]*storage.UtxoEntry{
283 bc.Hash{V1: 0}: storage.NewUtxoEntry(storage.NormalUTXOType, 0, true),
284 bc.Hash{V1: 1}: storage.NewUtxoEntry(storage.NormalUTXOType, 0, false),
291 // apply gas only tx, non-btm asset spent output will not be store
293 BlockHeader: &bc.BlockHeader{
294 TransactionStatus: bc.NewTransactionStatus(),
296 Transactions: []*bc.Tx{
298 TxHeader: &bc.TxHeader{
299 ResultIds: []*bc.Hash{
304 SpentOutputIDs: []bc.Hash{},
305 Entries: gasOnlyTxEntry,
309 inputView: NewUtxoViewpoint(),
310 fetchView: NewUtxoViewpoint(),
316 BlockHeader: &bc.BlockHeader{
317 TransactionStatus: bc.NewTransactionStatus(),
319 Transactions: []*bc.Tx{
321 TxHeader: &bc.TxHeader{
322 ResultIds: []*bc.Hash{},
324 SpentOutputIDs: []bc.Hash{
331 inputView: &UtxoViewpoint{
332 Entries: map[bc.Hash]*storage.UtxoEntry{
333 bc.Hash{V0: 0}: storage.NewUtxoEntry(storage.VoteUTXOType, 0, false),
336 fetchView: &UtxoViewpoint{
337 Entries: map[bc.Hash]*storage.UtxoEntry{
338 bc.Hash{V0: 0}: storage.NewUtxoEntry(storage.VoteUTXOType, 0, true),
345 BlockHeader: &bc.BlockHeader{
346 Height: consensus.MainNetParams.VotePendingBlockNumber + 1,
347 TransactionStatus: bc.NewTransactionStatus(),
349 Transactions: []*bc.Tx{
351 TxHeader: &bc.TxHeader{
352 ResultIds: []*bc.Hash{},
354 SpentOutputIDs: []bc.Hash{
361 inputView: &UtxoViewpoint{
362 Entries: map[bc.Hash]*storage.UtxoEntry{
363 bc.Hash{V0: 0}: storage.NewUtxoEntry(storage.VoteUTXOType, 1, false),
366 fetchView: &UtxoViewpoint{
367 Entries: map[bc.Hash]*storage.UtxoEntry{
368 bc.Hash{V0: 0}: storage.NewUtxoEntry(storage.VoteUTXOType, 1, true),
375 for i, c := range cases {
376 c.block.TransactionStatus.SetStatus(0, c.gasOnlyTx)
377 if err := c.inputView.ApplyBlock(c.block, c.block.TransactionStatus); c.err != (err != nil) {
378 t.Errorf("case #%d want err = %v, get err = %v", i, c.err, err)
383 if !testutil.DeepEqual(c.inputView, c.fetchView) {
384 t.Errorf("test case %d, want %v, get %v", i, c.fetchView, c.inputView)
389 func TestDetachBlock(t *testing.T) {
392 inputView *UtxoViewpoint
393 fetchView *UtxoViewpoint
399 BlockHeader: &bc.BlockHeader{
400 TransactionStatus: bc.NewTransactionStatus(),
402 Transactions: []*bc.Tx{
404 TxHeader: &bc.TxHeader{
405 ResultIds: []*bc.Hash{},
407 SpentOutputIDs: []bc.Hash{
410 Entries: defaultEntry,
414 inputView: NewUtxoViewpoint(),
415 fetchView: &UtxoViewpoint{
416 Entries: map[bc.Hash]*storage.UtxoEntry{
417 bc.Hash{V0: 0}: storage.NewUtxoEntry(storage.NormalUTXOType, 0, false),
424 BlockHeader: &bc.BlockHeader{
425 TransactionStatus: bc.NewTransactionStatus(),
427 Transactions: []*bc.Tx{
429 TxHeader: &bc.TxHeader{
430 ResultIds: []*bc.Hash{
435 SpentOutputIDs: []bc.Hash{},
436 Entries: coinbaseEntry,
440 inputView: &UtxoViewpoint{
441 Entries: map[bc.Hash]*storage.UtxoEntry{
442 bc.Hash{V0: 1}: storage.NewUtxoEntry(storage.NormalUTXOType, 0, false),
445 fetchView: &UtxoViewpoint{
446 Entries: map[bc.Hash]*storage.UtxoEntry{
447 bc.Hash{V0: 1}: storage.NewUtxoEntry(storage.NormalUTXOType, 0, true),
454 BlockHeader: &bc.BlockHeader{
455 TransactionStatus: bc.NewTransactionStatus(),
457 Transactions: []*bc.Tx{
459 TxHeader: &bc.TxHeader{
460 ResultIds: []*bc.Hash{},
462 SpentOutputIDs: []bc.Hash{
465 Entries: defaultEntry,
469 inputView: &UtxoViewpoint{
470 Entries: map[bc.Hash]*storage.UtxoEntry{
471 bc.Hash{V0: 0}: storage.NewUtxoEntry(storage.NormalUTXOType, 0, false),
478 BlockHeader: &bc.BlockHeader{
479 TransactionStatus: bc.NewTransactionStatus(),
481 Transactions: []*bc.Tx{
483 TxHeader: &bc.TxHeader{
484 ResultIds: []*bc.Hash{},
486 SpentOutputIDs: []bc.Hash{
489 Entries: defaultEntry,
493 inputView: &UtxoViewpoint{
494 Entries: map[bc.Hash]*storage.UtxoEntry{
495 bc.Hash{V0: 0}: storage.NewUtxoEntry(storage.NormalUTXOType, 0, true),
498 fetchView: &UtxoViewpoint{
499 Entries: map[bc.Hash]*storage.UtxoEntry{
500 bc.Hash{V0: 0}: storage.NewUtxoEntry(storage.NormalUTXOType, 0, false),
507 BlockHeader: &bc.BlockHeader{
508 TransactionStatus: bc.NewTransactionStatus(),
510 Transactions: []*bc.Tx{
512 TxHeader: &bc.TxHeader{
513 ResultIds: []*bc.Hash{},
515 SpentOutputIDs: []bc.Hash{
519 Entries: gasOnlyTxEntry,
523 inputView: &UtxoViewpoint{
524 Entries: map[bc.Hash]*storage.UtxoEntry{
525 bc.Hash{V1: 0}: storage.NewUtxoEntry(storage.NormalUTXOType, 0, true),
526 bc.Hash{V1: 1}: storage.NewUtxoEntry(storage.NormalUTXOType, 0, true),
529 fetchView: &UtxoViewpoint{
530 Entries: map[bc.Hash]*storage.UtxoEntry{
531 bc.Hash{V1: 0}: storage.NewUtxoEntry(storage.NormalUTXOType, 0, false),
532 bc.Hash{V1: 1}: storage.NewUtxoEntry(storage.NormalUTXOType, 0, true),
540 BlockHeader: &bc.BlockHeader{
541 TransactionStatus: bc.NewTransactionStatus(),
543 Transactions: []*bc.Tx{
545 TxHeader: &bc.TxHeader{
546 ResultIds: []*bc.Hash{
551 SpentOutputIDs: []bc.Hash{},
552 Entries: gasOnlyTxEntry,
556 inputView: NewUtxoViewpoint(),
557 fetchView: NewUtxoViewpoint(),
563 BlockHeader: &bc.BlockHeader{
564 TransactionStatus: bc.NewTransactionStatus(),
566 Transactions: []*bc.Tx{
568 TxHeader: &bc.TxHeader{
569 ResultIds: []*bc.Hash{},
571 SpentOutputIDs: []bc.Hash{
578 inputView: NewUtxoViewpoint(),
579 fetchView: &UtxoViewpoint{
580 Entries: map[bc.Hash]*storage.UtxoEntry{
581 bc.Hash{V0: 0}: storage.NewUtxoEntry(storage.VoteUTXOType, 0, false),
588 for i, c := range cases {
589 c.block.TransactionStatus.SetStatus(0, c.gasOnlyTx)
590 if err := c.inputView.DetachBlock(c.block, c.block.TransactionStatus); c.err != (err != nil) {
591 t.Errorf("case %d want err = %v, get err = %v", i, c.err, err)
596 if !testutil.DeepEqual(c.inputView, c.fetchView) {
597 t.Errorf("test case %d, want %v, get %v", i, c.fetchView, c.inputView)
602 func TestApplyCrossChainUTXO(t *testing.T) {
607 prevUTXOView *UtxoViewpoint
608 postUTXOView *UtxoViewpoint
614 BlockHeader: &bc.BlockHeader{
619 TxHeader: &bc.TxHeader{
620 ResultIds: []*bc.Hash{},
622 MainchainOutputIDs: []bc.Hash{
627 prevUTXOView: &UtxoViewpoint{
628 Entries: map[bc.Hash]*storage.UtxoEntry{
629 bc.Hash{V0: 0}: storage.NewUtxoEntry(storage.CrosschainUTXOType, 0, false),
632 postUTXOView: &UtxoViewpoint{
633 Entries: map[bc.Hash]*storage.UtxoEntry{
634 bc.Hash{V0: 0}: storage.NewUtxoEntry(storage.CrosschainUTXOType, 100, true),
640 desc: "test failed to find mainchain output entry",
642 BlockHeader: &bc.BlockHeader{},
645 TxHeader: &bc.TxHeader{
646 ResultIds: []*bc.Hash{},
648 MainchainOutputIDs: []bc.Hash{
653 prevUTXOView: &UtxoViewpoint{
654 Entries: map[bc.Hash]*storage.UtxoEntry{},
656 postUTXOView: &UtxoViewpoint{
657 Entries: map[bc.Hash]*storage.UtxoEntry{},
659 err: errors.New("fail to find mainchain output entry"),
662 desc: "test mainchain output has been spent",
664 BlockHeader: &bc.BlockHeader{},
667 TxHeader: &bc.TxHeader{
668 ResultIds: []*bc.Hash{},
670 MainchainOutputIDs: []bc.Hash{
675 prevUTXOView: &UtxoViewpoint{
676 Entries: map[bc.Hash]*storage.UtxoEntry{
677 bc.Hash{V0: 0}: storage.NewUtxoEntry(storage.CrosschainUTXOType, 0, true),
680 postUTXOView: &UtxoViewpoint{
681 Entries: map[bc.Hash]*storage.UtxoEntry{},
683 err: errors.New("mainchain output has been spent"),
687 for i, c := range cases {
688 if err := c.prevUTXOView.applyCrossChainUtxo(c.block, c.tx); err != nil {
689 if err.Error() != c.err.Error() {
690 t.Errorf("test case #%d want err = %v, got err = %v", i, c.err, err)
695 if !testutil.DeepEqual(c.prevUTXOView, c.postUTXOView) {
696 t.Errorf("test case #%d, want %v, got %v", i, c.postUTXOView, c.prevUTXOView)
701 func TestApplyOutputUTXO(t *testing.T) {
707 prevUTXOView *UtxoViewpoint
708 postUTXOView *UtxoViewpoint
712 desc: "normal test IntraChainOutput,VoteOutput,Retirement",
714 BlockHeader: &bc.BlockHeader{},
717 TxHeader: &bc.TxHeader{
718 ResultIds: []*bc.Hash{&bc.Hash{V0: 0}, &bc.Hash{V0: 1}, &bc.Hash{V0: 2}},
720 Entries: map[bc.Hash]bc.Entry{
721 bc.Hash{V0: 0}: &bc.IntraChainOutput{
722 Source: &bc.ValueSource{
723 Value: &bc.AssetAmount{
724 AssetId: &bc.AssetID{V0: 0},
729 bc.Hash{V0: 1}: &bc.VoteOutput{
730 Source: &bc.ValueSource{
731 Value: &bc.AssetAmount{
732 AssetId: &bc.AssetID{V0: 1},
736 bc.Hash{V0: 2}: &bc.Retirement{
737 Source: &bc.ValueSource{
738 Value: &bc.AssetAmount{
739 AssetId: &bc.AssetID{V0: 1},
745 prevUTXOView: &UtxoViewpoint{
746 Entries: map[bc.Hash]*storage.UtxoEntry{},
748 postUTXOView: &UtxoViewpoint{
749 Entries: map[bc.Hash]*storage.UtxoEntry{
750 bc.Hash{V0: 0}: storage.NewUtxoEntry(storage.NormalUTXOType, 0, false),
751 bc.Hash{V0: 1}: storage.NewUtxoEntry(storage.VoteUTXOType, 0, false),
757 desc: "test statusFail",
759 BlockHeader: &bc.BlockHeader{},
762 TxHeader: &bc.TxHeader{
763 ResultIds: []*bc.Hash{&bc.Hash{V0: 0}, &bc.Hash{V0: 1}, &bc.Hash{V0: 2}},
765 Entries: map[bc.Hash]bc.Entry{
766 bc.Hash{V0: 0}: &bc.IntraChainOutput{
767 Source: &bc.ValueSource{
768 Value: &bc.AssetAmount{
769 AssetId: &bc.AssetID{V0: 0},
774 bc.Hash{V0: 1}: &bc.VoteOutput{
775 Source: &bc.ValueSource{
776 Value: &bc.AssetAmount{
777 AssetId: consensus.BTMAssetID,
781 bc.Hash{V0: 2}: &bc.Retirement{
782 Source: &bc.ValueSource{
783 Value: &bc.AssetAmount{
784 AssetId: &bc.AssetID{V0: 1},
791 prevUTXOView: &UtxoViewpoint{
792 Entries: map[bc.Hash]*storage.UtxoEntry{},
794 postUTXOView: &UtxoViewpoint{
795 Entries: map[bc.Hash]*storage.UtxoEntry{
796 bc.Hash{V0: 1}: storage.NewUtxoEntry(storage.VoteUTXOType, 0, false),
802 desc: "test failed on found id from tx entry",
804 BlockHeader: &bc.BlockHeader{},
807 TxHeader: &bc.TxHeader{
808 ResultIds: []*bc.Hash{&bc.Hash{V0: 0}, &bc.Hash{V0: 1}, &bc.Hash{V0: 2}},
810 Entries: map[bc.Hash]bc.Entry{
811 bc.Hash{V0: 1}: &bc.VoteOutput{
812 Source: &bc.ValueSource{
813 Value: &bc.AssetAmount{
814 AssetId: consensus.BTMAssetID,
818 bc.Hash{V0: 2}: &bc.Retirement{
819 Source: &bc.ValueSource{
820 Value: &bc.AssetAmount{
821 AssetId: &bc.AssetID{V0: 1},
828 prevUTXOView: &UtxoViewpoint{
829 Entries: map[bc.Hash]*storage.UtxoEntry{},
831 postUTXOView: &UtxoViewpoint{
832 Entries: map[bc.Hash]*storage.UtxoEntry{},
834 err: bc.ErrMissingEntry,
838 for i, c := range cases {
839 if err := c.prevUTXOView.applyOutputUtxo(c.block, c.tx, c.statusFail); err != nil {
840 if errors.Root(err) != errors.Root(c.err) {
841 t.Errorf("test case #%d want err = %v, got err = %v", i, c.err.Error(), err.Error())
846 if !testutil.DeepEqual(c.prevUTXOView, c.postUTXOView) {
847 t.Errorf("test case #%d, want %v, got %v", i, c.postUTXOView, c.prevUTXOView)
852 func TestApplySpendUTXO(t *testing.T) {
858 prevUTXOView *UtxoViewpoint
859 postUTXOView *UtxoViewpoint
865 BlockHeader: &bc.BlockHeader{
866 Height: consensus.ActiveNetParams.VotePendingBlockNumber,
870 TxHeader: &bc.TxHeader{},
871 SpentOutputIDs: []bc.Hash{{V0: 0}, {V0: 1}, {V0: 2}},
872 Entries: map[bc.Hash]bc.Entry{
873 bc.Hash{V0: 0}: &bc.IntraChainOutput{
874 Source: &bc.ValueSource{
875 Value: &bc.AssetAmount{
876 AssetId: &bc.AssetID{V0: 0},
881 bc.Hash{V0: 1}: &bc.VoteOutput{
882 Source: &bc.ValueSource{
883 Value: &bc.AssetAmount{
884 AssetId: &bc.AssetID{V0: 1},
888 bc.Hash{V0: 2}: &bc.IntraChainOutput{
889 Source: &bc.ValueSource{
890 Value: &bc.AssetAmount{
891 AssetId: consensus.BTMAssetID,
898 prevUTXOView: &UtxoViewpoint{
899 Entries: map[bc.Hash]*storage.UtxoEntry{
900 bc.Hash{V0: 0}: storage.NewUtxoEntry(storage.NormalUTXOType, 0, false),
901 bc.Hash{V0: 1}: storage.NewUtxoEntry(storage.VoteUTXOType, 0, false),
902 bc.Hash{V0: 2}: storage.NewUtxoEntry(storage.CoinbaseUTXOType, 0, false),
905 postUTXOView: &UtxoViewpoint{
906 Entries: map[bc.Hash]*storage.UtxoEntry{
907 bc.Hash{V0: 0}: storage.NewUtxoEntry(storage.NormalUTXOType, 0, true),
908 bc.Hash{V0: 1}: storage.NewUtxoEntry(storage.VoteUTXOType, 0, true),
909 bc.Hash{V0: 2}: storage.NewUtxoEntry(storage.CoinbaseUTXOType, 0, true),
915 desc: "test coinbase is not ready for use",
917 BlockHeader: &bc.BlockHeader{
918 Height: consensus.ActiveNetParams.CoinbasePendingBlockNumber - 1,
922 TxHeader: &bc.TxHeader{},
923 SpentOutputIDs: []bc.Hash{{V0: 1}, {V0: 2}},
924 Entries: map[bc.Hash]bc.Entry{
925 bc.Hash{V0: 1}: &bc.VoteOutput{
926 Source: &bc.ValueSource{
927 Value: &bc.AssetAmount{
928 AssetId: &bc.AssetID{V0: 1},
932 bc.Hash{V0: 2}: &bc.IntraChainOutput{
933 Source: &bc.ValueSource{
934 Value: &bc.AssetAmount{
935 AssetId: consensus.BTMAssetID,
942 prevUTXOView: &UtxoViewpoint{
943 Entries: map[bc.Hash]*storage.UtxoEntry{
944 bc.Hash{V0: 1}: storage.NewUtxoEntry(storage.NormalUTXOType, 0, false),
945 bc.Hash{V0: 2}: storage.NewUtxoEntry(storage.CoinbaseUTXOType, 0, false),
948 postUTXOView: &UtxoViewpoint{
949 Entries: map[bc.Hash]*storage.UtxoEntry{},
951 err: errors.New("coinbase utxo is not ready for use"),
954 desc: "test Coin is within the voting lock time",
956 BlockHeader: &bc.BlockHeader{
957 Height: consensus.ActiveNetParams.VotePendingBlockNumber - 1,
961 TxHeader: &bc.TxHeader{},
962 SpentOutputIDs: []bc.Hash{{V0: 1}, {V0: 2}},
963 Entries: map[bc.Hash]bc.Entry{
964 bc.Hash{V0: 1}: &bc.VoteOutput{
965 Source: &bc.ValueSource{
966 Value: &bc.AssetAmount{
967 AssetId: &bc.AssetID{V0: 1},
971 bc.Hash{V0: 2}: &bc.IntraChainOutput{
972 Source: &bc.ValueSource{
973 Value: &bc.AssetAmount{
974 AssetId: consensus.BTMAssetID,
981 prevUTXOView: &UtxoViewpoint{
982 Entries: map[bc.Hash]*storage.UtxoEntry{
983 bc.Hash{V0: 1}: storage.NewUtxoEntry(storage.NormalUTXOType, 0, false),
984 bc.Hash{V0: 2}: storage.NewUtxoEntry(storage.VoteUTXOType, 0, false),
987 postUTXOView: &UtxoViewpoint{
988 Entries: map[bc.Hash]*storage.UtxoEntry{},
990 err: errors.New("Coin is within the voting lock time"),
993 desc: "test utxo has been spent",
995 BlockHeader: &bc.BlockHeader{
1000 TxHeader: &bc.TxHeader{},
1001 SpentOutputIDs: []bc.Hash{{V0: 0}, {V0: 1}, {V0: 2}},
1002 Entries: map[bc.Hash]bc.Entry{
1003 bc.Hash{V0: 0}: &bc.IntraChainOutput{
1004 Source: &bc.ValueSource{
1005 Value: &bc.AssetAmount{
1006 AssetId: &bc.AssetID{V0: 0},
1011 bc.Hash{V0: 1}: &bc.VoteOutput{
1012 Source: &bc.ValueSource{
1013 Value: &bc.AssetAmount{
1014 AssetId: &bc.AssetID{V0: 1},
1018 bc.Hash{V0: 2}: &bc.IntraChainOutput{
1019 Source: &bc.ValueSource{
1020 Value: &bc.AssetAmount{
1021 AssetId: consensus.BTMAssetID,
1028 prevUTXOView: &UtxoViewpoint{
1029 Entries: map[bc.Hash]*storage.UtxoEntry{
1030 bc.Hash{V0: 0}: storage.NewUtxoEntry(storage.NormalUTXOType, 0, true),
1031 bc.Hash{V0: 1}: storage.NewUtxoEntry(storage.VoteUTXOType, 0, false),
1032 bc.Hash{V0: 2}: storage.NewUtxoEntry(storage.CoinbaseUTXOType, 0, false),
1035 postUTXOView: &UtxoViewpoint{
1036 Entries: map[bc.Hash]*storage.UtxoEntry{},
1038 err: errors.New("utxo has been spent"),
1041 desc: "test faild to find utxo entry",
1043 BlockHeader: &bc.BlockHeader{
1048 TxHeader: &bc.TxHeader{},
1049 SpentOutputIDs: []bc.Hash{{V0: 0}, {V0: 1}, {V0: 2}},
1050 Entries: map[bc.Hash]bc.Entry{
1051 bc.Hash{V0: 0}: &bc.IntraChainOutput{
1052 Source: &bc.ValueSource{
1053 Value: &bc.AssetAmount{
1054 AssetId: &bc.AssetID{V0: 0},
1059 bc.Hash{V0: 1}: &bc.VoteOutput{
1060 Source: &bc.ValueSource{
1061 Value: &bc.AssetAmount{
1062 AssetId: &bc.AssetID{V0: 1},
1066 bc.Hash{V0: 2}: &bc.IntraChainOutput{
1067 Source: &bc.ValueSource{
1068 Value: &bc.AssetAmount{
1069 AssetId: consensus.BTMAssetID,
1076 prevUTXOView: &UtxoViewpoint{
1077 Entries: map[bc.Hash]*storage.UtxoEntry{
1078 bc.Hash{V0: 1}: storage.NewUtxoEntry(storage.VoteUTXOType, 0, false),
1079 bc.Hash{V0: 2}: storage.NewUtxoEntry(storage.CoinbaseUTXOType, 0, false),
1082 postUTXOView: &UtxoViewpoint{
1083 Entries: map[bc.Hash]*storage.UtxoEntry{},
1085 err: errors.New("fail to find utxo entry"),
1089 for i, c := range cases {
1090 if err := c.prevUTXOView.applySpendUtxo(c.block, c.tx, c.statusFail); err != nil {
1091 if err.Error() != c.err.Error() {
1092 t.Errorf("test case #%d want err = %v, got err = %v", i, err.Error(), c.err.Error())
1097 if !testutil.DeepEqual(c.prevUTXOView, c.postUTXOView) {
1098 t.Errorf("test case #%d, want %v, got %v", i, spew.Sdump(c.postUTXOView), spew.Sdump(c.prevUTXOView))
1103 func TestDetachCrossChainUTXO(t *testing.T) {
1107 prevUTXOView *UtxoViewpoint
1108 postUTXOView *UtxoViewpoint
1112 desc: "normal test",
1114 TxHeader: &bc.TxHeader{
1115 ResultIds: []*bc.Hash{},
1117 MainchainOutputIDs: []bc.Hash{
1122 prevUTXOView: &UtxoViewpoint{
1123 Entries: map[bc.Hash]*storage.UtxoEntry{
1124 bc.Hash{V0: 0}: storage.NewUtxoEntry(storage.CrosschainUTXOType, 0, true),
1127 postUTXOView: &UtxoViewpoint{
1128 Entries: map[bc.Hash]*storage.UtxoEntry{
1129 bc.Hash{V0: 0}: storage.NewUtxoEntry(storage.CrosschainUTXOType, 0, false),
1135 desc: "test failed to find mainchain output entry",
1137 TxHeader: &bc.TxHeader{
1138 ResultIds: []*bc.Hash{},
1140 MainchainOutputIDs: []bc.Hash{
1145 prevUTXOView: &UtxoViewpoint{
1146 Entries: map[bc.Hash]*storage.UtxoEntry{},
1148 postUTXOView: &UtxoViewpoint{
1149 Entries: map[bc.Hash]*storage.UtxoEntry{},
1151 err: errors.New("fail to find mainchain output entry"),
1154 desc: "test revert output is unspent",
1156 TxHeader: &bc.TxHeader{
1157 ResultIds: []*bc.Hash{},
1159 MainchainOutputIDs: []bc.Hash{
1164 prevUTXOView: &UtxoViewpoint{
1165 Entries: map[bc.Hash]*storage.UtxoEntry{
1166 bc.Hash{V0: 0}: storage.NewUtxoEntry(storage.CrosschainUTXOType, 0, false),
1169 postUTXOView: &UtxoViewpoint{
1170 Entries: map[bc.Hash]*storage.UtxoEntry{},
1172 err: errors.New("mainchain output is unspent"),
1176 for i, c := range cases {
1177 if err := c.prevUTXOView.detachCrossChainUtxo(c.tx); err != nil {
1178 if err.Error() != c.err.Error() {
1179 t.Errorf("test case #%d want err = %v, got err = %v", i, c.err, err)
1184 if !testutil.DeepEqual(c.prevUTXOView, c.postUTXOView) {
1185 t.Errorf("test case #%d, want %v, got %v", i, c.postUTXOView, c.prevUTXOView)
1190 func TestDetachOutputUTXO(t *testing.T) {
1195 prevUTXOView *UtxoViewpoint
1196 postUTXOView *UtxoViewpoint
1200 desc: "normal test IntraChainOutput,VoteOutput",
1202 TxHeader: &bc.TxHeader{
1203 ResultIds: []*bc.Hash{&bc.Hash{V0: 0}, &bc.Hash{V0: 1}, &bc.Hash{V0: 2}},
1205 Entries: map[bc.Hash]bc.Entry{
1206 bc.Hash{V0: 0}: &bc.IntraChainOutput{
1207 Source: &bc.ValueSource{
1208 Value: &bc.AssetAmount{
1209 AssetId: &bc.AssetID{V0: 0},
1214 bc.Hash{V0: 1}: &bc.VoteOutput{
1215 Source: &bc.ValueSource{
1216 Value: &bc.AssetAmount{
1217 AssetId: &bc.AssetID{V0: 1},
1221 bc.Hash{V0: 2}: &bc.Retirement{
1222 Source: &bc.ValueSource{
1223 Value: &bc.AssetAmount{
1224 AssetId: &bc.AssetID{V0: 1},
1230 prevUTXOView: &UtxoViewpoint{
1231 Entries: map[bc.Hash]*storage.UtxoEntry{
1232 bc.Hash{V0: 0}: storage.NewUtxoEntry(storage.NormalUTXOType, 0, true),
1233 bc.Hash{V0: 1}: storage.NewUtxoEntry(storage.VoteUTXOType, 0, true),
1236 postUTXOView: &UtxoViewpoint{
1237 Entries: map[bc.Hash]*storage.UtxoEntry{
1238 bc.Hash{V0: 0}: storage.NewUtxoEntry(storage.NormalUTXOType, 0, true),
1239 bc.Hash{V0: 1}: storage.NewUtxoEntry(storage.VoteUTXOType, 0, true),
1245 desc: "test statusFail",
1247 TxHeader: &bc.TxHeader{
1248 ResultIds: []*bc.Hash{&bc.Hash{V0: 0}, &bc.Hash{V0: 1}},
1250 Entries: map[bc.Hash]bc.Entry{
1251 bc.Hash{V0: 0}: &bc.IntraChainOutput{
1252 Source: &bc.ValueSource{
1253 Value: &bc.AssetAmount{
1254 AssetId: &bc.AssetID{V0: 0},
1259 bc.Hash{V0: 1}: &bc.VoteOutput{
1260 Source: &bc.ValueSource{
1261 Value: &bc.AssetAmount{
1262 AssetId: consensus.BTMAssetID,
1269 prevUTXOView: &UtxoViewpoint{
1270 Entries: map[bc.Hash]*storage.UtxoEntry{},
1272 postUTXOView: &UtxoViewpoint{
1273 Entries: map[bc.Hash]*storage.UtxoEntry{
1274 bc.Hash{V0: 1}: storage.NewUtxoEntry(storage.VoteUTXOType, 0, true),
1280 desc: "test failed on found id from tx entry",
1282 TxHeader: &bc.TxHeader{
1283 ResultIds: []*bc.Hash{&bc.Hash{V0: 0}, &bc.Hash{V0: 1}, &bc.Hash{V0: 2}},
1285 Entries: map[bc.Hash]bc.Entry{
1286 bc.Hash{V0: 1}: &bc.VoteOutput{
1287 Source: &bc.ValueSource{
1288 Value: &bc.AssetAmount{
1289 AssetId: consensus.BTMAssetID,
1293 bc.Hash{V0: 2}: &bc.Retirement{
1294 Source: &bc.ValueSource{
1295 Value: &bc.AssetAmount{
1296 AssetId: &bc.AssetID{V0: 1},
1303 prevUTXOView: &UtxoViewpoint{
1304 Entries: map[bc.Hash]*storage.UtxoEntry{},
1306 postUTXOView: &UtxoViewpoint{
1307 Entries: map[bc.Hash]*storage.UtxoEntry{},
1309 err: bc.ErrMissingEntry,
1313 for i, c := range cases {
1314 if err := c.prevUTXOView.detachOutputUtxo(c.tx, c.statusFail); err != nil {
1315 if errors.Root(err) != errors.Root(c.err) {
1316 t.Errorf("test case #%d want err = %v, got err = %v", i, c.err.Error(), err.Error())
1321 if !testutil.DeepEqual(c.prevUTXOView, c.postUTXOView) {
1322 t.Errorf("test case #%d, want %v, got %v", i, c.postUTXOView, c.prevUTXOView)
1327 func TestDetachSpendUTXO(t *testing.T) {
1332 prevUTXOView *UtxoViewpoint
1333 postUTXOView *UtxoViewpoint
1337 desc: "normal test",
1339 TxHeader: &bc.TxHeader{},
1340 SpentOutputIDs: []bc.Hash{{V0: 0}, {V0: 1}},
1341 Entries: map[bc.Hash]bc.Entry{
1342 bc.Hash{V0: 0}: &bc.IntraChainOutput{
1343 Source: &bc.ValueSource{
1344 Value: &bc.AssetAmount{
1345 AssetId: &bc.AssetID{V0: 0},
1350 bc.Hash{V0: 1}: &bc.VoteOutput{
1351 Source: &bc.ValueSource{
1352 Value: &bc.AssetAmount{
1353 AssetId: &bc.AssetID{V0: 1},
1359 prevUTXOView: &UtxoViewpoint{
1360 Entries: map[bc.Hash]*storage.UtxoEntry{
1361 bc.Hash{V0: 0}: storage.NewUtxoEntry(storage.NormalUTXOType, 0, true),
1362 bc.Hash{V0: 1}: storage.NewUtxoEntry(storage.VoteUTXOType, 0, true),
1365 postUTXOView: &UtxoViewpoint{
1366 Entries: map[bc.Hash]*storage.UtxoEntry{
1367 bc.Hash{V0: 0}: storage.NewUtxoEntry(storage.NormalUTXOType, 0, false),
1368 bc.Hash{V0: 1}: storage.NewUtxoEntry(storage.VoteUTXOType, 0, false),
1374 desc: "test utxo has been spent",
1376 TxHeader: &bc.TxHeader{},
1377 SpentOutputIDs: []bc.Hash{{V0: 0}, {V0: 1}, {V0: 2}},
1378 Entries: map[bc.Hash]bc.Entry{
1379 bc.Hash{V0: 0}: &bc.IntraChainOutput{
1380 Source: &bc.ValueSource{
1381 Value: &bc.AssetAmount{
1382 AssetId: consensus.BTMAssetID,
1387 bc.Hash{V0: 1}: &bc.VoteOutput{
1388 Source: &bc.ValueSource{
1389 Value: &bc.AssetAmount{
1390 AssetId: &bc.AssetID{V0: 1},
1394 bc.Hash{V0: 2}: &bc.IntraChainOutput{
1395 Source: &bc.ValueSource{
1396 Value: &bc.AssetAmount{
1397 AssetId: consensus.BTMAssetID,
1404 prevUTXOView: &UtxoViewpoint{
1405 Entries: map[bc.Hash]*storage.UtxoEntry{
1406 bc.Hash{V0: 0}: storage.NewUtxoEntry(storage.NormalUTXOType, 0, false),
1407 bc.Hash{V0: 1}: storage.NewUtxoEntry(storage.VoteUTXOType, 0, true),
1410 postUTXOView: &UtxoViewpoint{
1411 Entries: map[bc.Hash]*storage.UtxoEntry{},
1413 err: errors.New("try to revert an unspent utxo"),
1417 for i, c := range cases {
1418 if err := c.prevUTXOView.detachSpendUtxo(c.tx, c.statusFail); err != nil {
1419 if err.Error() != c.err.Error() {
1420 t.Errorf("test case #%d want err = %v, got err = %v", i, err.Error(), c.err.Error())
1425 if !testutil.DeepEqual(c.prevUTXOView, c.postUTXOView) {
1426 t.Errorf("test case #%d, want %v, got %v", i, spew.Sdump(c.postUTXOView), spew.Sdump(c.prevUTXOView))