• R/O
  • HTTP
  • SSH
  • HTTPS

vapor: Commit

Golang implemented sidechain for Bytom


Commit MetaInfo

Revisionbe99aff7b59cb6bd843cd9a120b4fbf76fde2419 (tree)
Time2019-08-12 13:48:11
AuthorYahtoo Ma <yahtoo.ma@gmai...>
CommiterYahtoo Ma

Log Message

Add protocol status test case

Change Summary

Incremental Difference

--- a/protocol/state/consensus_result_test.go
+++ b/protocol/state/consensus_result_test.go
@@ -2,9 +2,14 @@ package state
22
33 import (
44 "encoding/hex"
5+ "math"
6+ "reflect"
57 "testing"
68
9+ "github.com/davecgh/go-spew/spew"
10+
711 "github.com/vapor/consensus"
12+ "github.com/vapor/crypto/ed25519/chainkd"
813 "github.com/vapor/errors"
914 "github.com/vapor/math/checked"
1015 "github.com/vapor/protocol/bc"
@@ -12,6 +17,178 @@ import (
1217 "github.com/vapor/testutil"
1318 )
1419
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+
15192 func TestCalCoinbaseReward(t *testing.T) {
16193 cases := []struct {
17194 desc string
@@ -658,8 +835,100 @@ func TestConsensusDetachBlock(t *testing.T) {
658835 },
659836 wantErr: errors.New("not found coinbase receiver"),
660837 },
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+ },
661931 }
662-
663932 for i, c := range cases {
664933 if err := c.consensusResult.DetachBlock(c.block); err != nil {
665934 if err.Error() != c.wantErr.Error() {
@@ -772,3 +1041,86 @@ func TestGetCoinbaseRewards(t *testing.T) {
7721041 }
7731042 }
7741043 }
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+}
--- a/protocol/state/utxo_view_test.go
+++ b/protocol/state/utxo_view_test.go
@@ -3,8 +3,11 @@ package state
33 import (
44 "testing"
55
6+ "github.com/davecgh/go-spew/spew"
7+
68 "github.com/vapor/consensus"
79 "github.com/vapor/database/storage"
10+ "github.com/vapor/errors"
811 "github.com/vapor/protocol/bc"
912 "github.com/vapor/testutil"
1013 )
@@ -595,3 +598,832 @@ func TestDetachBlock(t *testing.T) {
595598 }
596599 }
597600 }
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+}
Show on old repository browser