Golang implemented sidechain for Bytom
Révision | be99aff7b59cb6bd843cd9a120b4fbf76fde2419 (tree) |
---|---|
l'heure | 2019-08-12 13:48:11 |
Auteur | Yahtoo Ma <yahtoo.ma@gmai...> |
Commiter | Yahtoo Ma |
Add protocol status test case
@@ -2,9 +2,14 @@ package state | ||
2 | 2 | |
3 | 3 | import ( |
4 | 4 | "encoding/hex" |
5 | + "math" | |
6 | + "reflect" | |
5 | 7 | "testing" |
6 | 8 | |
9 | + "github.com/davecgh/go-spew/spew" | |
10 | + | |
7 | 11 | "github.com/vapor/consensus" |
12 | + "github.com/vapor/crypto/ed25519/chainkd" | |
8 | 13 | "github.com/vapor/errors" |
9 | 14 | "github.com/vapor/math/checked" |
10 | 15 | "github.com/vapor/protocol/bc" |
@@ -12,6 +17,178 @@ import ( | ||
12 | 17 | "github.com/vapor/testutil" |
13 | 18 | ) |
14 | 19 | |
20 | +func TestApplyTransaction(t *testing.T) { | |
21 | + testXpub, _ := hex.DecodeString("a8018a1ba4d85fc7118bbd065612da78b2c503e61a1a093d9c659567c5d3a591b3752569fbcafa951b2304b8f576f3f220e03b957ca819840e7c29e4b7fb2c4d") | |
22 | + | |
23 | + cases := []struct { | |
24 | + desc string | |
25 | + tx *types.Tx | |
26 | + prevConsensusResult *ConsensusResult | |
27 | + postConsensusResult *ConsensusResult | |
28 | + wantErr error | |
29 | + }{ | |
30 | + { | |
31 | + desc: "test num Of vote overflow", | |
32 | + tx: &types.Tx{ | |
33 | + TxData: types.TxData{ | |
34 | + Inputs: []*types.TxInput{types.NewSpendInput(nil, bc.NewHash([32]byte{0xff}), *consensus.BTMAssetID, 600000000, 0, nil)}, | |
35 | + Outputs: []*types.TxOutput{types.NewVoteOutput(*consensus.BTMAssetID, math.MaxUint64-1000, []byte{0x51}, testXpub)}, | |
36 | + }, | |
37 | + }, | |
38 | + prevConsensusResult: &ConsensusResult{ | |
39 | + NumOfVote: map[string]uint64{ | |
40 | + hex.EncodeToString(testXpub): 1000000, | |
41 | + }, | |
42 | + }, | |
43 | + postConsensusResult: &ConsensusResult{ | |
44 | + NumOfVote: map[string]uint64{}, | |
45 | + }, | |
46 | + wantErr: checked.ErrOverflow, | |
47 | + }, | |
48 | + { | |
49 | + desc: "test num Of veto overflow", | |
50 | + tx: &types.Tx{ | |
51 | + TxData: types.TxData{ | |
52 | + Inputs: []*types.TxInput{types.NewVetoInput(nil, bc.NewHash([32]byte{0xff}), *consensus.BTMAssetID, 100000000, 0, []byte{0x51}, testXpub)}, | |
53 | + Outputs: []*types.TxOutput{types.NewIntraChainOutput(*consensus.BTMAssetID, 100000000, []byte{0x51})}, | |
54 | + }, | |
55 | + }, | |
56 | + prevConsensusResult: &ConsensusResult{ | |
57 | + NumOfVote: map[string]uint64{ | |
58 | + hex.EncodeToString(testXpub): 1000000, | |
59 | + }, | |
60 | + }, | |
61 | + postConsensusResult: &ConsensusResult{ | |
62 | + NumOfVote: map[string]uint64{}, | |
63 | + }, | |
64 | + wantErr: checked.ErrOverflow, | |
65 | + }, | |
66 | + { | |
67 | + desc: "test del pubkey from NumOfVote", | |
68 | + tx: &types.Tx{ | |
69 | + TxData: types.TxData{ | |
70 | + Inputs: []*types.TxInput{types.NewVetoInput(nil, bc.NewHash([32]byte{0xff}), *consensus.BTMAssetID, 1000000, 0, []byte{0x51}, testXpub)}, | |
71 | + Outputs: []*types.TxOutput{types.NewIntraChainOutput(*consensus.BTMAssetID, 100000000, []byte{0x51})}, | |
72 | + }, | |
73 | + }, | |
74 | + prevConsensusResult: &ConsensusResult{ | |
75 | + NumOfVote: map[string]uint64{ | |
76 | + hex.EncodeToString(testXpub): 1000000, | |
77 | + }, | |
78 | + }, | |
79 | + postConsensusResult: &ConsensusResult{ | |
80 | + NumOfVote: map[string]uint64{}, | |
81 | + }, | |
82 | + wantErr: nil, | |
83 | + }, | |
84 | + } | |
85 | + | |
86 | + for i, c := range cases { | |
87 | + if err := c.prevConsensusResult.ApplyTransaction(c.tx); err != nil { | |
88 | + if err != c.wantErr { | |
89 | + t.Errorf("test case #%d want err = %v, got err = %v", i, c.wantErr, err) | |
90 | + } | |
91 | + continue | |
92 | + } | |
93 | + | |
94 | + if !testutil.DeepEqual(c.prevConsensusResult, c.postConsensusResult) { | |
95 | + t.Errorf("test case #%d, want %v, got %v", i, c.postConsensusResult, c.prevConsensusResult) | |
96 | + } | |
97 | + } | |
98 | +} | |
99 | + | |
100 | +func TestAttachCoinbaseReward(t *testing.T) { | |
101 | + cases := []struct { | |
102 | + desc string | |
103 | + block *types.Block | |
104 | + prevConsensusResult *ConsensusResult | |
105 | + postConsensusResult *ConsensusResult | |
106 | + wantErr error | |
107 | + }{ | |
108 | + { | |
109 | + desc: "normal test with block contain coinbase tx and other tx", | |
110 | + block: &types.Block{ | |
111 | + BlockHeader: types.BlockHeader{ | |
112 | + Height: 1, | |
113 | + }, | |
114 | + Transactions: []*types.Tx{ | |
115 | + { | |
116 | + TxData: types.TxData{ | |
117 | + Inputs: []*types.TxInput{types.NewCoinbaseInput([]byte{0x01})}, | |
118 | + Outputs: []*types.TxOutput{types.NewIntraChainOutput(bc.AssetID{}, 0, []byte{0x51})}, | |
119 | + }, | |
120 | + }, | |
121 | + { | |
122 | + TxData: types.TxData{ | |
123 | + Inputs: []*types.TxInput{types.NewSpendInput(nil, bc.NewHash([32]byte{0xff}), *consensus.BTMAssetID, 300000000, 0, nil)}, | |
124 | + Outputs: []*types.TxOutput{types.NewIntraChainOutput(*consensus.BTMAssetID, 250000000, []byte{0x51})}, | |
125 | + }, | |
126 | + }, | |
127 | + }, | |
128 | + }, | |
129 | + prevConsensusResult: &ConsensusResult{ | |
130 | + CoinbaseReward: map[string]uint64{ | |
131 | + hex.EncodeToString([]byte{0x51}): 50000000, | |
132 | + hex.EncodeToString([]byte{0x52}): 80000000, | |
133 | + }, | |
134 | + }, | |
135 | + postConsensusResult: &ConsensusResult{ | |
136 | + CoinbaseReward: map[string]uint64{ | |
137 | + hex.EncodeToString([]byte{0x51}): consensus.BlockSubsidy(1) + 50000000, | |
138 | + }, | |
139 | + }, | |
140 | + wantErr: nil, | |
141 | + }, | |
142 | + { | |
143 | + desc: "test coinbase reward overflow", | |
144 | + block: &types.Block{ | |
145 | + BlockHeader: types.BlockHeader{ | |
146 | + Height: 100, | |
147 | + }, | |
148 | + Transactions: []*types.Tx{ | |
149 | + { | |
150 | + TxData: types.TxData{ | |
151 | + Inputs: []*types.TxInput{types.NewCoinbaseInput([]byte{0x01})}, | |
152 | + Outputs: []*types.TxOutput{types.NewIntraChainOutput(bc.AssetID{}, 0, []byte{0x51})}, | |
153 | + }, | |
154 | + }, | |
155 | + { | |
156 | + TxData: types.TxData{ | |
157 | + Inputs: []*types.TxInput{types.NewSpendInput(nil, bc.NewHash([32]byte{0xff}), *consensus.BTMAssetID, math.MaxUint64-80000000, 0, nil)}, | |
158 | + Outputs: []*types.TxOutput{types.NewIntraChainOutput(*consensus.BTMAssetID, 0, []byte{0x52})}, | |
159 | + }, | |
160 | + }, | |
161 | + }, | |
162 | + }, | |
163 | + prevConsensusResult: &ConsensusResult{ | |
164 | + CoinbaseReward: map[string]uint64{ | |
165 | + hex.EncodeToString([]byte{0x51}): 80000000, | |
166 | + hex.EncodeToString([]byte{0x52}): 50000000, | |
167 | + }, | |
168 | + }, | |
169 | + postConsensusResult: &ConsensusResult{ | |
170 | + CoinbaseReward: map[string]uint64{ | |
171 | + hex.EncodeToString([]byte{0x51}): consensus.BlockSubsidy(1) + 50000000, | |
172 | + }, | |
173 | + }, | |
174 | + wantErr: checked.ErrOverflow, | |
175 | + }, | |
176 | + } | |
177 | + | |
178 | + for i, c := range cases { | |
179 | + if err := c.prevConsensusResult.AttachCoinbaseReward(c.block); err != nil { | |
180 | + if err != c.wantErr { | |
181 | + t.Errorf("test case #%d want err = %v, got err = %v", i, c.wantErr, err) | |
182 | + } | |
183 | + continue | |
184 | + } | |
185 | + | |
186 | + if !testutil.DeepEqual(c.prevConsensusResult, c.postConsensusResult) { | |
187 | + t.Errorf("test case #%d, want %v, got %v", i, c.postConsensusResult, c.prevConsensusResult) | |
188 | + } | |
189 | + } | |
190 | +} | |
191 | + | |
15 | 192 | func TestCalCoinbaseReward(t *testing.T) { |
16 | 193 | cases := []struct { |
17 | 194 | desc string |
@@ -658,8 +835,100 @@ func TestConsensusDetachBlock(t *testing.T) { | ||
658 | 835 | }, |
659 | 836 | wantErr: errors.New("not found coinbase receiver"), |
660 | 837 | }, |
838 | + { | |
839 | + desc: "test number of vote overflow", | |
840 | + block: &types.Block{ | |
841 | + BlockHeader: types.BlockHeader{ | |
842 | + Height: consensus.MainNetParams.RoundVoteBlockNums - 1, | |
843 | + PreviousBlockHash: bc.Hash{V0: 1}, | |
844 | + }, | |
845 | + Transactions: []*types.Tx{ | |
846 | + &types.Tx{ | |
847 | + TxData: types.TxData{ | |
848 | + Inputs: []*types.TxInput{types.NewCoinbaseInput([]byte{0x01})}, | |
849 | + Outputs: []*types.TxOutput{types.NewIntraChainOutput(bc.AssetID{}, 0, []byte{0x51})}, | |
850 | + }, | |
851 | + }, | |
852 | + &types.Tx{ | |
853 | + TxData: types.TxData{ | |
854 | + Inputs: []*types.TxInput{types.NewSpendInput(nil, bc.NewHash([32]byte{0xff}), *consensus.BTMAssetID, 600000000, 0, nil)}, | |
855 | + Outputs: []*types.TxOutput{types.NewVoteOutput(*consensus.BTMAssetID, 600000000, []byte{0x51}, testXpub)}, | |
856 | + }, | |
857 | + }, | |
858 | + }, | |
859 | + }, | |
860 | + consensusResult: &ConsensusResult{ | |
861 | + BlockHash: testutil.MustDecodeHash("4ebd9e7c00d3e0370931689c6eb9e2131c6700fe66e6b9718028dd75d7a4e329"), | |
862 | + CoinbaseReward: map[string]uint64{ | |
863 | + "51": 100000000, | |
864 | + }, | |
865 | + NumOfVote: map[string]uint64{}, | |
866 | + }, | |
867 | + wantErr: checked.ErrOverflow, | |
868 | + }, | |
869 | + { | |
870 | + desc: "test number of veto overflow", | |
871 | + block: &types.Block{ | |
872 | + BlockHeader: types.BlockHeader{ | |
873 | + Height: consensus.MainNetParams.RoundVoteBlockNums - 1, | |
874 | + PreviousBlockHash: bc.Hash{V0: 1}, | |
875 | + }, | |
876 | + Transactions: []*types.Tx{ | |
877 | + &types.Tx{ | |
878 | + TxData: types.TxData{ | |
879 | + Inputs: []*types.TxInput{types.NewCoinbaseInput([]byte{0x01})}, | |
880 | + Outputs: []*types.TxOutput{types.NewIntraChainOutput(bc.AssetID{}, 0, []byte{0x51})}, | |
881 | + }, | |
882 | + }, | |
883 | + &types.Tx{ | |
884 | + TxData: types.TxData{ | |
885 | + Inputs: []*types.TxInput{types.NewVetoInput(nil, bc.NewHash([32]byte{0xff}), *consensus.BTMAssetID, math.MaxUint64, 0, []byte{0x51}, testXpub)}, | |
886 | + Outputs: []*types.TxOutput{types.NewIntraChainOutput(*consensus.BTMAssetID, math.MaxUint64, []byte{0x51})}, | |
887 | + }, | |
888 | + }, | |
889 | + }, | |
890 | + }, | |
891 | + consensusResult: &ConsensusResult{ | |
892 | + BlockHash: testutil.MustDecodeHash("4ebd9e7c00d3e0370931689c6eb9e2131c6700fe66e6b9718028dd75d7a4e329"), | |
893 | + CoinbaseReward: map[string]uint64{ | |
894 | + "51": 100000000, | |
895 | + }, | |
896 | + NumOfVote: map[string]uint64{ | |
897 | + "a8018a1ba4d85fc7118bbd065612da78b2c503e61a1a093d9c659567c5d3a591b3752569fbcafa951b2304b8f576f3f220e03b957ca819840e7c29e4b7fb2c4d": 100, | |
898 | + }, | |
899 | + }, | |
900 | + wantErr: checked.ErrOverflow, | |
901 | + }, | |
902 | + { | |
903 | + desc: "test detch coinbase overflow", | |
904 | + block: &types.Block{ | |
905 | + BlockHeader: types.BlockHeader{ | |
906 | + Height: consensus.MainNetParams.RoundVoteBlockNums - 1, | |
907 | + PreviousBlockHash: bc.Hash{V0: 1}, | |
908 | + }, | |
909 | + Transactions: []*types.Tx{ | |
910 | + &types.Tx{ | |
911 | + TxData: types.TxData{ | |
912 | + Inputs: []*types.TxInput{types.NewCoinbaseInput([]byte{0x01})}, | |
913 | + Outputs: []*types.TxOutput{types.NewIntraChainOutput(bc.AssetID{}, 0, []byte{0x51})}, | |
914 | + }, | |
915 | + }, | |
916 | + &types.Tx{ | |
917 | + TxData: types.TxData{ | |
918 | + Inputs: []*types.TxInput{types.NewVetoInput(nil, bc.NewHash([32]byte{0xff}), *consensus.BTMAssetID, math.MaxUint64, 0, []byte{0x51}, testXpub)}, | |
919 | + Outputs: []*types.TxOutput{types.NewIntraChainOutput(*consensus.BTMAssetID, math.MaxUint64, []byte{0x51})}, | |
920 | + }, | |
921 | + }, | |
922 | + }, | |
923 | + }, | |
924 | + consensusResult: &ConsensusResult{ | |
925 | + BlockHash: testutil.MustDecodeHash("4ebd9e7c00d3e0370931689c6eb9e2131c6700fe66e6b9718028dd75d7a4e329"), | |
926 | + CoinbaseReward: map[string]uint64{}, | |
927 | + NumOfVote: map[string]uint64{}, | |
928 | + }, | |
929 | + wantErr: checked.ErrOverflow, | |
930 | + }, | |
661 | 931 | } |
662 | - | |
663 | 932 | for i, c := range cases { |
664 | 933 | if err := c.consensusResult.DetachBlock(c.block); err != nil { |
665 | 934 | if err.Error() != c.wantErr.Error() { |
@@ -772,3 +1041,86 @@ func TestGetCoinbaseRewards(t *testing.T) { | ||
772 | 1041 | } |
773 | 1042 | } |
774 | 1043 | } |
1044 | + | |
1045 | +func TestConsensusNodes(t *testing.T) { | |
1046 | + var xpub1, xpub2, xpub3, xpub4, xpub5, xpub6, xpub7 chainkd.XPub | |
1047 | + strPub1 := "0f8669abbd3cc0a167156188e428f940088d5b2f36bb3449df71d2bdc5e077814ea3f68628eef279ed435f51ee26cff00f8bd28fabfd500bedb2a9e369f5c825" | |
1048 | + strPub2 := "e7f458ee8d2ba19b0fdc7410d1fd57e9c2e1a79377c661d66c55effe49d7ffc920e40510442d4a10b7bea06c09fb0b41f52601135adaaa7136204db36106c093" | |
1049 | + strPub3 := "1bec3a35da038ec7a76c40986e80b5af2dcef60341970e3fc58b4db0797bd4ca9b2cbf3d7ab820832e22a80b5b86ae1427f7f706a7780089958b2862e7bc0842" | |
1050 | + strPub4 := "b7f463446a31b3792cd168d52b7a89b3657bca3e25d6854db1488c389ab6fc8d538155c25c1ee6975cc7def19710908c7d9b7463ca34a22058b456b45e498db9" | |
1051 | + strPub5 := "b928e46bb01e834fdf167185e31b15de7cc257af8bbdf17f9c7fefd5bb97b306d048b6bc0da2097152c1c2ff38333c756a543adbba7030a447dcc776b8ac64ef" | |
1052 | + strPub6 := "36695997983028c279c3360ca345a90e3af1f9e3df2506119fca31cdc844be31630f9a421f4d1658e15d67a15ce29c36332dd45020d2a0147fcce4949ccd9a67" | |
1053 | + strPub7 := "123" | |
1054 | + | |
1055 | + xpub1.UnmarshalText([]byte(strPub1)) | |
1056 | + xpub2.UnmarshalText([]byte(strPub2)) | |
1057 | + xpub3.UnmarshalText([]byte(strPub3)) | |
1058 | + xpub4.UnmarshalText([]byte(strPub4)) | |
1059 | + xpub5.UnmarshalText([]byte(strPub5)) | |
1060 | + xpub6.UnmarshalText([]byte(strPub6)) | |
1061 | + xpub7.UnmarshalText([]byte(strPub7)) | |
1062 | + | |
1063 | + cases := []struct { | |
1064 | + consensusResult *ConsensusResult | |
1065 | + consensusNode map[string]*ConsensusNode | |
1066 | + wantErr error | |
1067 | + }{ | |
1068 | + { | |
1069 | + consensusResult: &ConsensusResult{ | |
1070 | + NumOfVote: map[string]uint64{ | |
1071 | + strPub1: 838063475500000, //1 | |
1072 | + strPub2: 474794800000000, //3 | |
1073 | + strPub3: 833812985000000, //2 | |
1074 | + strPub4: 285918061999999, //4 | |
1075 | + strPub5: 1228455289930297, //0 | |
1076 | + strPub6: 274387690000000, //5 | |
1077 | + strPub7: 1028455289930297, | |
1078 | + }, | |
1079 | + }, | |
1080 | + consensusNode: map[string]*ConsensusNode{ | |
1081 | + strPub1: &ConsensusNode{XPub: xpub1, VoteNum: 838063475500000, Order: 1}, | |
1082 | + strPub2: &ConsensusNode{XPub: xpub2, VoteNum: 474794800000000, Order: 3}, | |
1083 | + strPub3: &ConsensusNode{XPub: xpub3, VoteNum: 833812985000000, Order: 2}, | |
1084 | + strPub4: &ConsensusNode{XPub: xpub4, VoteNum: 285918061999999, Order: 4}, | |
1085 | + strPub5: &ConsensusNode{XPub: xpub5, VoteNum: 1228455289930297, Order: 0}, | |
1086 | + strPub6: &ConsensusNode{XPub: xpub6, VoteNum: 274387690000000, Order: 5}, | |
1087 | + }, | |
1088 | + wantErr: chainkd.ErrBadKeyStr, | |
1089 | + }, | |
1090 | + } | |
1091 | + | |
1092 | + for i, c := range cases { | |
1093 | + consensusNode, err := c.consensusResult.ConsensusNodes() | |
1094 | + if err != nil { | |
1095 | + if err != c.wantErr { | |
1096 | + t.Errorf("test case #%d want err = %v, got err = %v", i, c.wantErr, err) | |
1097 | + } | |
1098 | + continue | |
1099 | + } | |
1100 | + | |
1101 | + if !testutil.DeepEqual(consensusNode, c.consensusNode) { | |
1102 | + t.Errorf("test case #%d, want %v, got %v", i, c.consensusNode, consensusNode) | |
1103 | + } | |
1104 | + } | |
1105 | +} | |
1106 | + | |
1107 | +func TestFork(t *testing.T) { | |
1108 | + consensusResult := &ConsensusResult{ | |
1109 | + Seq: 100, | |
1110 | + NumOfVote: map[string]uint64{ | |
1111 | + "a": 100, | |
1112 | + "b": 200, | |
1113 | + }, | |
1114 | + CoinbaseReward: map[string]uint64{ | |
1115 | + "c": 300, | |
1116 | + "d": 400, | |
1117 | + }, | |
1118 | + BlockHash: bc.NewHash([32]byte{0x1, 0x2}), | |
1119 | + BlockHeight: 1024, | |
1120 | + } | |
1121 | + copy := consensusResult.Fork() | |
1122 | + | |
1123 | + if !reflect.DeepEqual(consensusResult, copy) { | |
1124 | + t.Fatalf("failed on test consensusResult got %s want %s", spew.Sdump(copy), spew.Sdump(consensusResult)) | |
1125 | + } | |
1126 | +} |
@@ -3,8 +3,11 @@ package state | ||
3 | 3 | import ( |
4 | 4 | "testing" |
5 | 5 | |
6 | + "github.com/davecgh/go-spew/spew" | |
7 | + | |
6 | 8 | "github.com/vapor/consensus" |
7 | 9 | "github.com/vapor/database/storage" |
10 | + "github.com/vapor/errors" | |
8 | 11 | "github.com/vapor/protocol/bc" |
9 | 12 | "github.com/vapor/testutil" |
10 | 13 | ) |
@@ -595,3 +598,832 @@ func TestDetachBlock(t *testing.T) { | ||
595 | 598 | } |
596 | 599 | } |
597 | 600 | } |
601 | + | |
602 | +func TestApplyCrossChainUTXO(t *testing.T) { | |
603 | + cases := []struct { | |
604 | + desc string | |
605 | + block *bc.Block | |
606 | + tx *bc.Tx | |
607 | + prevUTXOView *UtxoViewpoint | |
608 | + postUTXOView *UtxoViewpoint | |
609 | + err error | |
610 | + }{ | |
611 | + { | |
612 | + desc: "normal test", | |
613 | + block: &bc.Block{ | |
614 | + BlockHeader: &bc.BlockHeader{ | |
615 | + Height: 100, | |
616 | + }, | |
617 | + }, | |
618 | + tx: &bc.Tx{ | |
619 | + TxHeader: &bc.TxHeader{ | |
620 | + ResultIds: []*bc.Hash{}, | |
621 | + }, | |
622 | + MainchainOutputIDs: []bc.Hash{ | |
623 | + bc.Hash{V0: 0}, | |
624 | + }, | |
625 | + Entries: voteEntry, | |
626 | + }, | |
627 | + prevUTXOView: &UtxoViewpoint{ | |
628 | + Entries: map[bc.Hash]*storage.UtxoEntry{ | |
629 | + bc.Hash{V0: 0}: storage.NewUtxoEntry(storage.CrosschainUTXOType, 0, false), | |
630 | + }, | |
631 | + }, | |
632 | + postUTXOView: &UtxoViewpoint{ | |
633 | + Entries: map[bc.Hash]*storage.UtxoEntry{ | |
634 | + bc.Hash{V0: 0}: storage.NewUtxoEntry(storage.CrosschainUTXOType, 100, true), | |
635 | + }, | |
636 | + }, | |
637 | + err: nil, | |
638 | + }, | |
639 | + { | |
640 | + desc: "test failed to find mainchain output entry", | |
641 | + block: &bc.Block{ | |
642 | + BlockHeader: &bc.BlockHeader{}, | |
643 | + }, | |
644 | + tx: &bc.Tx{ | |
645 | + TxHeader: &bc.TxHeader{ | |
646 | + ResultIds: []*bc.Hash{}, | |
647 | + }, | |
648 | + MainchainOutputIDs: []bc.Hash{ | |
649 | + bc.Hash{V0: 0}, | |
650 | + }, | |
651 | + Entries: voteEntry, | |
652 | + }, | |
653 | + prevUTXOView: &UtxoViewpoint{ | |
654 | + Entries: map[bc.Hash]*storage.UtxoEntry{}, | |
655 | + }, | |
656 | + postUTXOView: &UtxoViewpoint{ | |
657 | + Entries: map[bc.Hash]*storage.UtxoEntry{}, | |
658 | + }, | |
659 | + err: errors.New("fail to find mainchain output entry"), | |
660 | + }, | |
661 | + { | |
662 | + desc: "test mainchain output has been spent", | |
663 | + block: &bc.Block{ | |
664 | + BlockHeader: &bc.BlockHeader{}, | |
665 | + }, | |
666 | + tx: &bc.Tx{ | |
667 | + TxHeader: &bc.TxHeader{ | |
668 | + ResultIds: []*bc.Hash{}, | |
669 | + }, | |
670 | + MainchainOutputIDs: []bc.Hash{ | |
671 | + bc.Hash{V0: 0}, | |
672 | + }, | |
673 | + Entries: voteEntry, | |
674 | + }, | |
675 | + prevUTXOView: &UtxoViewpoint{ | |
676 | + Entries: map[bc.Hash]*storage.UtxoEntry{ | |
677 | + bc.Hash{V0: 0}: storage.NewUtxoEntry(storage.CrosschainUTXOType, 0, true), | |
678 | + }, | |
679 | + }, | |
680 | + postUTXOView: &UtxoViewpoint{ | |
681 | + Entries: map[bc.Hash]*storage.UtxoEntry{}, | |
682 | + }, | |
683 | + err: errors.New("mainchain output has been spent"), | |
684 | + }, | |
685 | + } | |
686 | + | |
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) | |
691 | + } | |
692 | + continue | |
693 | + } | |
694 | + | |
695 | + if !testutil.DeepEqual(c.prevUTXOView, c.postUTXOView) { | |
696 | + t.Errorf("test case #%d, want %v, got %v", i, c.postUTXOView, c.prevUTXOView) | |
697 | + } | |
698 | + } | |
699 | +} | |
700 | + | |
701 | +func TestApplyOutputUTXO(t *testing.T) { | |
702 | + cases := []struct { | |
703 | + desc string | |
704 | + block *bc.Block | |
705 | + tx *bc.Tx | |
706 | + statusFail bool | |
707 | + prevUTXOView *UtxoViewpoint | |
708 | + postUTXOView *UtxoViewpoint | |
709 | + err error | |
710 | + }{ | |
711 | + { | |
712 | + desc: "normal test IntraChainOutput,VoteOutput,Retirement", | |
713 | + block: &bc.Block{ | |
714 | + BlockHeader: &bc.BlockHeader{}, | |
715 | + }, | |
716 | + tx: &bc.Tx{ | |
717 | + TxHeader: &bc.TxHeader{ | |
718 | + ResultIds: []*bc.Hash{&bc.Hash{V0: 0}, &bc.Hash{V0: 1}, &bc.Hash{V0: 2}}, | |
719 | + }, | |
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}, | |
725 | + Amount: 100, | |
726 | + }, | |
727 | + }, | |
728 | + }, | |
729 | + bc.Hash{V0: 1}: &bc.VoteOutput{ | |
730 | + Source: &bc.ValueSource{ | |
731 | + Value: &bc.AssetAmount{ | |
732 | + AssetId: &bc.AssetID{V0: 1}, | |
733 | + }, | |
734 | + }, | |
735 | + }, | |
736 | + bc.Hash{V0: 2}: &bc.Retirement{ | |
737 | + Source: &bc.ValueSource{ | |
738 | + Value: &bc.AssetAmount{ | |
739 | + AssetId: &bc.AssetID{V0: 1}, | |
740 | + }, | |
741 | + }, | |
742 | + }, | |
743 | + }, | |
744 | + }, | |
745 | + prevUTXOView: &UtxoViewpoint{ | |
746 | + Entries: map[bc.Hash]*storage.UtxoEntry{}, | |
747 | + }, | |
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), | |
752 | + }, | |
753 | + }, | |
754 | + err: nil, | |
755 | + }, | |
756 | + { | |
757 | + desc: "test statusFail", | |
758 | + block: &bc.Block{ | |
759 | + BlockHeader: &bc.BlockHeader{}, | |
760 | + }, | |
761 | + tx: &bc.Tx{ | |
762 | + TxHeader: &bc.TxHeader{ | |
763 | + ResultIds: []*bc.Hash{&bc.Hash{V0: 0}, &bc.Hash{V0: 1}, &bc.Hash{V0: 2}}, | |
764 | + }, | |
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}, | |
770 | + Amount: 100, | |
771 | + }, | |
772 | + }, | |
773 | + }, | |
774 | + bc.Hash{V0: 1}: &bc.VoteOutput{ | |
775 | + Source: &bc.ValueSource{ | |
776 | + Value: &bc.AssetAmount{ | |
777 | + AssetId: consensus.BTMAssetID, | |
778 | + }, | |
779 | + }, | |
780 | + }, | |
781 | + bc.Hash{V0: 2}: &bc.Retirement{ | |
782 | + Source: &bc.ValueSource{ | |
783 | + Value: &bc.AssetAmount{ | |
784 | + AssetId: &bc.AssetID{V0: 1}, | |
785 | + }, | |
786 | + }, | |
787 | + }, | |
788 | + }, | |
789 | + }, | |
790 | + statusFail: true, | |
791 | + prevUTXOView: &UtxoViewpoint{ | |
792 | + Entries: map[bc.Hash]*storage.UtxoEntry{}, | |
793 | + }, | |
794 | + postUTXOView: &UtxoViewpoint{ | |
795 | + Entries: map[bc.Hash]*storage.UtxoEntry{ | |
796 | + bc.Hash{V0: 1}: storage.NewUtxoEntry(storage.VoteUTXOType, 0, false), | |
797 | + }, | |
798 | + }, | |
799 | + err: nil, | |
800 | + }, | |
801 | + { | |
802 | + desc: "test failed on found id from tx entry", | |
803 | + block: &bc.Block{ | |
804 | + BlockHeader: &bc.BlockHeader{}, | |
805 | + }, | |
806 | + tx: &bc.Tx{ | |
807 | + TxHeader: &bc.TxHeader{ | |
808 | + ResultIds: []*bc.Hash{&bc.Hash{V0: 0}, &bc.Hash{V0: 1}, &bc.Hash{V0: 2}}, | |
809 | + }, | |
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, | |
815 | + }, | |
816 | + }, | |
817 | + }, | |
818 | + bc.Hash{V0: 2}: &bc.Retirement{ | |
819 | + Source: &bc.ValueSource{ | |
820 | + Value: &bc.AssetAmount{ | |
821 | + AssetId: &bc.AssetID{V0: 1}, | |
822 | + }, | |
823 | + }, | |
824 | + }, | |
825 | + }, | |
826 | + }, | |
827 | + statusFail: false, | |
828 | + prevUTXOView: &UtxoViewpoint{ | |
829 | + Entries: map[bc.Hash]*storage.UtxoEntry{}, | |
830 | + }, | |
831 | + postUTXOView: &UtxoViewpoint{ | |
832 | + Entries: map[bc.Hash]*storage.UtxoEntry{}, | |
833 | + }, | |
834 | + err: bc.ErrMissingEntry, | |
835 | + }, | |
836 | + } | |
837 | + | |
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()) | |
842 | + } | |
843 | + continue | |
844 | + } | |
845 | + | |
846 | + if !testutil.DeepEqual(c.prevUTXOView, c.postUTXOView) { | |
847 | + t.Errorf("test case #%d, want %v, got %v", i, c.postUTXOView, c.prevUTXOView) | |
848 | + } | |
849 | + } | |
850 | +} | |
851 | + | |
852 | +func TestApplySpendUTXO(t *testing.T) { | |
853 | + cases := []struct { | |
854 | + desc string | |
855 | + block *bc.Block | |
856 | + tx *bc.Tx | |
857 | + statusFail bool | |
858 | + prevUTXOView *UtxoViewpoint | |
859 | + postUTXOView *UtxoViewpoint | |
860 | + err error | |
861 | + }{ | |
862 | + { | |
863 | + desc: "normal test", | |
864 | + block: &bc.Block{ | |
865 | + BlockHeader: &bc.BlockHeader{ | |
866 | + Height: consensus.ActiveNetParams.VotePendingBlockNumber, | |
867 | + }, | |
868 | + }, | |
869 | + tx: &bc.Tx{ | |
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}, | |
877 | + Amount: 100, | |
878 | + }, | |
879 | + }, | |
880 | + }, | |
881 | + bc.Hash{V0: 1}: &bc.VoteOutput{ | |
882 | + Source: &bc.ValueSource{ | |
883 | + Value: &bc.AssetAmount{ | |
884 | + AssetId: &bc.AssetID{V0: 1}, | |
885 | + }, | |
886 | + }, | |
887 | + }, | |
888 | + bc.Hash{V0: 2}: &bc.IntraChainOutput{ | |
889 | + Source: &bc.ValueSource{ | |
890 | + Value: &bc.AssetAmount{ | |
891 | + AssetId: consensus.BTMAssetID, | |
892 | + Amount: 100, | |
893 | + }, | |
894 | + }, | |
895 | + }, | |
896 | + }, | |
897 | + }, | |
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), | |
903 | + }, | |
904 | + }, | |
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), | |
910 | + }, | |
911 | + }, | |
912 | + err: nil, | |
913 | + }, | |
914 | + { | |
915 | + desc: "test coinbase is not ready for use", | |
916 | + block: &bc.Block{ | |
917 | + BlockHeader: &bc.BlockHeader{ | |
918 | + Height: consensus.ActiveNetParams.CoinbasePendingBlockNumber - 1, | |
919 | + }, | |
920 | + }, | |
921 | + tx: &bc.Tx{ | |
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}, | |
929 | + }, | |
930 | + }, | |
931 | + }, | |
932 | + bc.Hash{V0: 2}: &bc.IntraChainOutput{ | |
933 | + Source: &bc.ValueSource{ | |
934 | + Value: &bc.AssetAmount{ | |
935 | + AssetId: consensus.BTMAssetID, | |
936 | + Amount: 100, | |
937 | + }, | |
938 | + }, | |
939 | + }, | |
940 | + }, | |
941 | + }, | |
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), | |
946 | + }, | |
947 | + }, | |
948 | + postUTXOView: &UtxoViewpoint{ | |
949 | + Entries: map[bc.Hash]*storage.UtxoEntry{}, | |
950 | + }, | |
951 | + err: errors.New("coinbase utxo is not ready for use"), | |
952 | + }, | |
953 | + { | |
954 | + desc: "test Coin is within the voting lock time", | |
955 | + block: &bc.Block{ | |
956 | + BlockHeader: &bc.BlockHeader{ | |
957 | + Height: consensus.ActiveNetParams.VotePendingBlockNumber - 1, | |
958 | + }, | |
959 | + }, | |
960 | + tx: &bc.Tx{ | |
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}, | |
968 | + }, | |
969 | + }, | |
970 | + }, | |
971 | + bc.Hash{V0: 2}: &bc.IntraChainOutput{ | |
972 | + Source: &bc.ValueSource{ | |
973 | + Value: &bc.AssetAmount{ | |
974 | + AssetId: consensus.BTMAssetID, | |
975 | + Amount: 100, | |
976 | + }, | |
977 | + }, | |
978 | + }, | |
979 | + }, | |
980 | + }, | |
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), | |
985 | + }, | |
986 | + }, | |
987 | + postUTXOView: &UtxoViewpoint{ | |
988 | + Entries: map[bc.Hash]*storage.UtxoEntry{}, | |
989 | + }, | |
990 | + err: errors.New("Coin is within the voting lock time"), | |
991 | + }, | |
992 | + { | |
993 | + desc: "test utxo has been spent", | |
994 | + block: &bc.Block{ | |
995 | + BlockHeader: &bc.BlockHeader{ | |
996 | + Height: 0, | |
997 | + }, | |
998 | + }, | |
999 | + tx: &bc.Tx{ | |
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}, | |
1007 | + Amount: 100, | |
1008 | + }, | |
1009 | + }, | |
1010 | + }, | |
1011 | + bc.Hash{V0: 1}: &bc.VoteOutput{ | |
1012 | + Source: &bc.ValueSource{ | |
1013 | + Value: &bc.AssetAmount{ | |
1014 | + AssetId: &bc.AssetID{V0: 1}, | |
1015 | + }, | |
1016 | + }, | |
1017 | + }, | |
1018 | + bc.Hash{V0: 2}: &bc.IntraChainOutput{ | |
1019 | + Source: &bc.ValueSource{ | |
1020 | + Value: &bc.AssetAmount{ | |
1021 | + AssetId: consensus.BTMAssetID, | |
1022 | + Amount: 100, | |
1023 | + }, | |
1024 | + }, | |
1025 | + }, | |
1026 | + }, | |
1027 | + }, | |
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), | |
1033 | + }, | |
1034 | + }, | |
1035 | + postUTXOView: &UtxoViewpoint{ | |
1036 | + Entries: map[bc.Hash]*storage.UtxoEntry{}, | |
1037 | + }, | |
1038 | + err: errors.New("utxo has been spent"), | |
1039 | + }, | |
1040 | + { | |
1041 | + desc: "test faild to find utxo entry", | |
1042 | + block: &bc.Block{ | |
1043 | + BlockHeader: &bc.BlockHeader{ | |
1044 | + Height: 0, | |
1045 | + }, | |
1046 | + }, | |
1047 | + tx: &bc.Tx{ | |
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}, | |
1055 | + Amount: 100, | |
1056 | + }, | |
1057 | + }, | |
1058 | + }, | |
1059 | + bc.Hash{V0: 1}: &bc.VoteOutput{ | |
1060 | + Source: &bc.ValueSource{ | |
1061 | + Value: &bc.AssetAmount{ | |
1062 | + AssetId: &bc.AssetID{V0: 1}, | |
1063 | + }, | |
1064 | + }, | |
1065 | + }, | |
1066 | + bc.Hash{V0: 2}: &bc.IntraChainOutput{ | |
1067 | + Source: &bc.ValueSource{ | |
1068 | + Value: &bc.AssetAmount{ | |
1069 | + AssetId: consensus.BTMAssetID, | |
1070 | + Amount: 100, | |
1071 | + }, | |
1072 | + }, | |
1073 | + }, | |
1074 | + }, | |
1075 | + }, | |
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), | |
1080 | + }, | |
1081 | + }, | |
1082 | + postUTXOView: &UtxoViewpoint{ | |
1083 | + Entries: map[bc.Hash]*storage.UtxoEntry{}, | |
1084 | + }, | |
1085 | + err: errors.New("fail to find utxo entry"), | |
1086 | + }, | |
1087 | + } | |
1088 | + | |
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()) | |
1093 | + } | |
1094 | + continue | |
1095 | + } | |
1096 | + | |
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)) | |
1099 | + } | |
1100 | + } | |
1101 | +} | |
1102 | + | |
1103 | +func TestDetachCrossChainUTXO(t *testing.T) { | |
1104 | + cases := []struct { | |
1105 | + desc string | |
1106 | + tx *bc.Tx | |
1107 | + prevUTXOView *UtxoViewpoint | |
1108 | + postUTXOView *UtxoViewpoint | |
1109 | + err error | |
1110 | + }{ | |
1111 | + { | |
1112 | + desc: "normal test", | |
1113 | + tx: &bc.Tx{ | |
1114 | + TxHeader: &bc.TxHeader{ | |
1115 | + ResultIds: []*bc.Hash{}, | |
1116 | + }, | |
1117 | + MainchainOutputIDs: []bc.Hash{ | |
1118 | + bc.Hash{V0: 0}, | |
1119 | + }, | |
1120 | + Entries: voteEntry, | |
1121 | + }, | |
1122 | + prevUTXOView: &UtxoViewpoint{ | |
1123 | + Entries: map[bc.Hash]*storage.UtxoEntry{ | |
1124 | + bc.Hash{V0: 0}: storage.NewUtxoEntry(storage.CrosschainUTXOType, 0, true), | |
1125 | + }, | |
1126 | + }, | |
1127 | + postUTXOView: &UtxoViewpoint{ | |
1128 | + Entries: map[bc.Hash]*storage.UtxoEntry{ | |
1129 | + bc.Hash{V0: 0}: storage.NewUtxoEntry(storage.CrosschainUTXOType, 0, false), | |
1130 | + }, | |
1131 | + }, | |
1132 | + err: nil, | |
1133 | + }, | |
1134 | + { | |
1135 | + desc: "test failed to find mainchain output entry", | |
1136 | + tx: &bc.Tx{ | |
1137 | + TxHeader: &bc.TxHeader{ | |
1138 | + ResultIds: []*bc.Hash{}, | |
1139 | + }, | |
1140 | + MainchainOutputIDs: []bc.Hash{ | |
1141 | + bc.Hash{V0: 0}, | |
1142 | + }, | |
1143 | + Entries: voteEntry, | |
1144 | + }, | |
1145 | + prevUTXOView: &UtxoViewpoint{ | |
1146 | + Entries: map[bc.Hash]*storage.UtxoEntry{}, | |
1147 | + }, | |
1148 | + postUTXOView: &UtxoViewpoint{ | |
1149 | + Entries: map[bc.Hash]*storage.UtxoEntry{}, | |
1150 | + }, | |
1151 | + err: errors.New("fail to find mainchain output entry"), | |
1152 | + }, | |
1153 | + { | |
1154 | + desc: "test revert output is unspent", | |
1155 | + tx: &bc.Tx{ | |
1156 | + TxHeader: &bc.TxHeader{ | |
1157 | + ResultIds: []*bc.Hash{}, | |
1158 | + }, | |
1159 | + MainchainOutputIDs: []bc.Hash{ | |
1160 | + bc.Hash{V0: 0}, | |
1161 | + }, | |
1162 | + Entries: voteEntry, | |
1163 | + }, | |
1164 | + prevUTXOView: &UtxoViewpoint{ | |
1165 | + Entries: map[bc.Hash]*storage.UtxoEntry{ | |
1166 | + bc.Hash{V0: 0}: storage.NewUtxoEntry(storage.CrosschainUTXOType, 0, false), | |
1167 | + }, | |
1168 | + }, | |
1169 | + postUTXOView: &UtxoViewpoint{ | |
1170 | + Entries: map[bc.Hash]*storage.UtxoEntry{}, | |
1171 | + }, | |
1172 | + err: errors.New("mainchain output is unspent"), | |
1173 | + }, | |
1174 | + } | |
1175 | + | |
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) | |
1180 | + } | |
1181 | + continue | |
1182 | + } | |
1183 | + | |
1184 | + if !testutil.DeepEqual(c.prevUTXOView, c.postUTXOView) { | |
1185 | + t.Errorf("test case #%d, want %v, got %v", i, c.postUTXOView, c.prevUTXOView) | |
1186 | + } | |
1187 | + } | |
1188 | +} | |
1189 | + | |
1190 | +func TestDetachOutputUTXO(t *testing.T) { | |
1191 | + cases := []struct { | |
1192 | + desc string | |
1193 | + tx *bc.Tx | |
1194 | + statusFail bool | |
1195 | + prevUTXOView *UtxoViewpoint | |
1196 | + postUTXOView *UtxoViewpoint | |
1197 | + err error | |
1198 | + }{ | |
1199 | + { | |
1200 | + desc: "normal test IntraChainOutput,VoteOutput", | |
1201 | + tx: &bc.Tx{ | |
1202 | + TxHeader: &bc.TxHeader{ | |
1203 | + ResultIds: []*bc.Hash{&bc.Hash{V0: 0}, &bc.Hash{V0: 1}, &bc.Hash{V0: 2}}, | |
1204 | + }, | |
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}, | |
1210 | + Amount: 100, | |
1211 | + }, | |
1212 | + }, | |
1213 | + }, | |
1214 | + bc.Hash{V0: 1}: &bc.VoteOutput{ | |
1215 | + Source: &bc.ValueSource{ | |
1216 | + Value: &bc.AssetAmount{ | |
1217 | + AssetId: &bc.AssetID{V0: 1}, | |
1218 | + }, | |
1219 | + }, | |
1220 | + }, | |
1221 | + bc.Hash{V0: 2}: &bc.Retirement{ | |
1222 | + Source: &bc.ValueSource{ | |
1223 | + Value: &bc.AssetAmount{ | |
1224 | + AssetId: &bc.AssetID{V0: 1}, | |
1225 | + }, | |
1226 | + }, | |
1227 | + }, | |
1228 | + }, | |
1229 | + }, | |
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), | |
1234 | + }, | |
1235 | + }, | |
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), | |
1240 | + }, | |
1241 | + }, | |
1242 | + err: nil, | |
1243 | + }, | |
1244 | + { | |
1245 | + desc: "test statusFail", | |
1246 | + tx: &bc.Tx{ | |
1247 | + TxHeader: &bc.TxHeader{ | |
1248 | + ResultIds: []*bc.Hash{&bc.Hash{V0: 0}, &bc.Hash{V0: 1}}, | |
1249 | + }, | |
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}, | |
1255 | + Amount: 100, | |
1256 | + }, | |
1257 | + }, | |
1258 | + }, | |
1259 | + bc.Hash{V0: 1}: &bc.VoteOutput{ | |
1260 | + Source: &bc.ValueSource{ | |
1261 | + Value: &bc.AssetAmount{ | |
1262 | + AssetId: consensus.BTMAssetID, | |
1263 | + }, | |
1264 | + }, | |
1265 | + }, | |
1266 | + }, | |
1267 | + }, | |
1268 | + statusFail: true, | |
1269 | + prevUTXOView: &UtxoViewpoint{ | |
1270 | + Entries: map[bc.Hash]*storage.UtxoEntry{}, | |
1271 | + }, | |
1272 | + postUTXOView: &UtxoViewpoint{ | |
1273 | + Entries: map[bc.Hash]*storage.UtxoEntry{ | |
1274 | + bc.Hash{V0: 1}: storage.NewUtxoEntry(storage.VoteUTXOType, 0, true), | |
1275 | + }, | |
1276 | + }, | |
1277 | + err: nil, | |
1278 | + }, | |
1279 | + { | |
1280 | + desc: "test failed on found id from tx entry", | |
1281 | + tx: &bc.Tx{ | |
1282 | + TxHeader: &bc.TxHeader{ | |
1283 | + ResultIds: []*bc.Hash{&bc.Hash{V0: 0}, &bc.Hash{V0: 1}, &bc.Hash{V0: 2}}, | |
1284 | + }, | |
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, | |
1290 | + }, | |
1291 | + }, | |
1292 | + }, | |
1293 | + bc.Hash{V0: 2}: &bc.Retirement{ | |
1294 | + Source: &bc.ValueSource{ | |
1295 | + Value: &bc.AssetAmount{ | |
1296 | + AssetId: &bc.AssetID{V0: 1}, | |
1297 | + }, | |
1298 | + }, | |
1299 | + }, | |
1300 | + }, | |
1301 | + }, | |
1302 | + statusFail: false, | |
1303 | + prevUTXOView: &UtxoViewpoint{ | |
1304 | + Entries: map[bc.Hash]*storage.UtxoEntry{}, | |
1305 | + }, | |
1306 | + postUTXOView: &UtxoViewpoint{ | |
1307 | + Entries: map[bc.Hash]*storage.UtxoEntry{}, | |
1308 | + }, | |
1309 | + err: bc.ErrMissingEntry, | |
1310 | + }, | |
1311 | + } | |
1312 | + | |
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()) | |
1317 | + } | |
1318 | + continue | |
1319 | + } | |
1320 | + | |
1321 | + if !testutil.DeepEqual(c.prevUTXOView, c.postUTXOView) { | |
1322 | + t.Errorf("test case #%d, want %v, got %v", i, c.postUTXOView, c.prevUTXOView) | |
1323 | + } | |
1324 | + } | |
1325 | +} | |
1326 | + | |
1327 | +func TestDetachSpendUTXO(t *testing.T) { | |
1328 | + cases := []struct { | |
1329 | + desc string | |
1330 | + tx *bc.Tx | |
1331 | + statusFail bool | |
1332 | + prevUTXOView *UtxoViewpoint | |
1333 | + postUTXOView *UtxoViewpoint | |
1334 | + err error | |
1335 | + }{ | |
1336 | + { | |
1337 | + desc: "normal test", | |
1338 | + tx: &bc.Tx{ | |
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}, | |
1346 | + Amount: 100, | |
1347 | + }, | |
1348 | + }, | |
1349 | + }, | |
1350 | + bc.Hash{V0: 1}: &bc.VoteOutput{ | |
1351 | + Source: &bc.ValueSource{ | |
1352 | + Value: &bc.AssetAmount{ | |
1353 | + AssetId: &bc.AssetID{V0: 1}, | |
1354 | + }, | |
1355 | + }, | |
1356 | + }, | |
1357 | + }, | |
1358 | + }, | |
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), | |
1363 | + }, | |
1364 | + }, | |
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), | |
1369 | + }, | |
1370 | + }, | |
1371 | + err: nil, | |
1372 | + }, | |
1373 | + { | |
1374 | + desc: "test utxo has been spent", | |
1375 | + tx: &bc.Tx{ | |
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, | |
1383 | + Amount: 100, | |
1384 | + }, | |
1385 | + }, | |
1386 | + }, | |
1387 | + bc.Hash{V0: 1}: &bc.VoteOutput{ | |
1388 | + Source: &bc.ValueSource{ | |
1389 | + Value: &bc.AssetAmount{ | |
1390 | + AssetId: &bc.AssetID{V0: 1}, | |
1391 | + }, | |
1392 | + }, | |
1393 | + }, | |
1394 | + bc.Hash{V0: 2}: &bc.IntraChainOutput{ | |
1395 | + Source: &bc.ValueSource{ | |
1396 | + Value: &bc.AssetAmount{ | |
1397 | + AssetId: consensus.BTMAssetID, | |
1398 | + Amount: 100, | |
1399 | + }, | |
1400 | + }, | |
1401 | + }, | |
1402 | + }, | |
1403 | + }, | |
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), | |
1408 | + }, | |
1409 | + }, | |
1410 | + postUTXOView: &UtxoViewpoint{ | |
1411 | + Entries: map[bc.Hash]*storage.UtxoEntry{}, | |
1412 | + }, | |
1413 | + err: errors.New("try to revert an unspent utxo"), | |
1414 | + }, | |
1415 | + } | |
1416 | + | |
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()) | |
1421 | + } | |
1422 | + continue | |
1423 | + } | |
1424 | + | |
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)) | |
1427 | + } | |
1428 | + } | |
1429 | +} |