7 "github.com/golang/protobuf/proto"
9 "github.com/bytom/bytom/database"
10 dbm "github.com/bytom/bytom/database/leveldb"
11 "github.com/bytom/bytom/database/storage"
12 "github.com/bytom/bytom/protocol/bc"
13 "github.com/bytom/bytom/protocol/bc/types"
14 "github.com/bytom/bytom/protocol/state"
15 "github.com/bytom/bytom/testutil"
18 func TestAttachOrDetachBlocks(t *testing.T) {
21 before map[bc.Hash]*storage.UtxoEntry
22 want map[bc.Hash]*storage.UtxoEntry
23 attachBlock []*bc.Block
24 detachBlock []*bc.Block
25 attachTxStatus []*bc.TransactionStatus
26 detachTxStatus []*bc.TransactionStatus
30 before: make(map[bc.Hash]*storage.UtxoEntry),
31 want: map[bc.Hash]*storage.UtxoEntry{*newTx(mockBlocks[0].Transactions[0]).OutputHash(0): storage.NewUtxoEntry(true, mockBlocks[0].Block.Height, false)},
32 attachBlock: []*bc.Block{
33 types.MapBlock(&mockBlocks[0].Block),
35 attachTxStatus: []*bc.TransactionStatus{
36 &bc.TransactionStatus{VerifyStatus: []*bc.TxVerifyResult{
37 &bc.TxVerifyResult{StatusFail: false},
42 desc: "Chain trading 3",
43 before: map[bc.Hash]*storage.UtxoEntry{
44 newTx(mockBlocks[1].Transactions[1]).getSpentOutputID(0): storage.NewUtxoEntry(false, mockBlocks[1].Height-1, false),
46 want: map[bc.Hash]*storage.UtxoEntry{
47 *newTx(mockBlocks[1].Transactions[0]).OutputHash(0): storage.NewUtxoEntry(true, mockBlocks[1].Height, false),
48 *newTx(mockBlocks[1].Transactions[1]).OutputHash(0): storage.NewUtxoEntry(false, mockBlocks[1].Height, false),
49 *newTx(mockBlocks[1].Transactions[2]).OutputHash(0): storage.NewUtxoEntry(false, mockBlocks[1].Height, false),
50 *newTx(mockBlocks[1].Transactions[3]).OutputHash(0): storage.NewUtxoEntry(false, mockBlocks[1].Height, false),
51 *newTx(mockBlocks[1].Transactions[3]).OutputHash(1): storage.NewUtxoEntry(false, mockBlocks[1].Height, false),
53 attachBlock: []*bc.Block{
54 types.MapBlock(&mockBlocks[1].Block),
56 attachTxStatus: []*bc.TransactionStatus{
57 &bc.TransactionStatus{VerifyStatus: []*bc.TxVerifyResult{
58 &bc.TxVerifyResult{StatusFail: false},
59 &bc.TxVerifyResult{StatusFail: false},
60 &bc.TxVerifyResult{StatusFail: false},
61 &bc.TxVerifyResult{StatusFail: false},
66 desc: "detach 1 block, attach 2 block",
67 before: map[bc.Hash]*storage.UtxoEntry{
68 *newTx(mockBlocks[2].Transactions[0]).OutputHash(0): storage.NewUtxoEntry(true, mockBlocks[2].Height, false),
69 *newTx(mockBlocks[2].Transactions[1]).OutputHash(0): storage.NewUtxoEntry(false, mockBlocks[2].Height, false),
70 *newTx(mockBlocks[2].Transactions[1]).OutputHash(1): storage.NewUtxoEntry(false, mockBlocks[2].Height, false),
72 want: map[bc.Hash]*storage.UtxoEntry{
73 *newTx(mockBlocks[3].Transactions[0]).OutputHash(0): storage.NewUtxoEntry(true, mockBlocks[3].Height, false),
74 *newTx(mockBlocks[3].Transactions[1]).OutputHash(0): storage.NewUtxoEntry(false, mockBlocks[3].Height, false),
76 *newTx(mockBlocks[4].Transactions[0]).OutputHash(0): storage.NewUtxoEntry(true, mockBlocks[4].Height, false),
77 *newTx(mockBlocks[4].Transactions[1]).OutputHash(0): storage.NewUtxoEntry(false, mockBlocks[4].Height, false),
78 *newTx(mockBlocks[4].Transactions[1]).OutputHash(1): storage.NewUtxoEntry(false, mockBlocks[4].Height, false),
80 attachBlock: []*bc.Block{
81 types.MapBlock(&mockBlocks[3].Block),
82 types.MapBlock(&mockBlocks[4].Block),
84 detachBlock: []*bc.Block{
85 types.MapBlock(&mockBlocks[2].Block),
87 attachTxStatus: []*bc.TransactionStatus{
88 &bc.TransactionStatus{VerifyStatus: []*bc.TxVerifyResult{
89 &bc.TxVerifyResult{StatusFail: false},
90 &bc.TxVerifyResult{StatusFail: false},
92 &bc.TransactionStatus{VerifyStatus: []*bc.TxVerifyResult{
93 &bc.TxVerifyResult{StatusFail: false},
94 &bc.TxVerifyResult{StatusFail: false},
97 detachTxStatus: []*bc.TransactionStatus{
98 &bc.TransactionStatus{VerifyStatus: []*bc.TxVerifyResult{
99 &bc.TxVerifyResult{StatusFail: false},
100 &bc.TxVerifyResult{StatusFail: false},
105 desc: "detach block 5, attach block 2",
106 before: map[bc.Hash]*storage.UtxoEntry{
107 *newTx(mockBlocks[5].Transactions[0]).OutputHash(0): storage.NewUtxoEntry(true, mockBlocks[5].Height, false),
108 *newTx(mockBlocks[5].Transactions[1]).OutputHash(0): storage.NewUtxoEntry(false, mockBlocks[5].Height, false),
109 *newTx(mockBlocks[5].Transactions[1]).OutputHash(1): storage.NewUtxoEntry(false, mockBlocks[5].Height, false),
111 *newTx(mockBlocks[6].Transactions[0]).OutputHash(0): storage.NewUtxoEntry(true, mockBlocks[6].Height, false),
112 *newTx(mockBlocks[6].Transactions[1]).OutputHash(0): storage.NewUtxoEntry(false, mockBlocks[6].Height, false),
113 *newTx(mockBlocks[6].Transactions[1]).OutputHash(1): storage.NewUtxoEntry(false, mockBlocks[6].Height, false),
114 *newTx(mockBlocks[6].Transactions[1]).OutputHash(2): storage.NewUtxoEntry(false, mockBlocks[6].Height, false),
115 *newTx(mockBlocks[6].Transactions[1]).OutputHash(3): storage.NewUtxoEntry(false, mockBlocks[6].Height, false),
116 *newTx(mockBlocks[6].Transactions[2]).OutputHash(0): storage.NewUtxoEntry(false, mockBlocks[6].Height, false),
117 *newTx(mockBlocks[6].Transactions[2]).OutputHash(1): storage.NewUtxoEntry(false, mockBlocks[6].Height, false),
118 *newTx(mockBlocks[6].Transactions[2]).OutputHash(2): storage.NewUtxoEntry(false, mockBlocks[6].Height, false),
119 *newTx(mockBlocks[6].Transactions[2]).OutputHash(3): storage.NewUtxoEntry(false, mockBlocks[6].Height, false),
121 *newTx(mockBlocks[7].Transactions[0]).OutputHash(0): storage.NewUtxoEntry(true, mockBlocks[7].Height, false),
122 *newTx(mockBlocks[7].Transactions[1]).OutputHash(0): storage.NewUtxoEntry(false, mockBlocks[7].Height, false),
123 *newTx(mockBlocks[7].Transactions[1]).OutputHash(1): storage.NewUtxoEntry(false, mockBlocks[7].Height, false),
124 *newTx(mockBlocks[7].Transactions[1]).OutputHash(2): storage.NewUtxoEntry(false, mockBlocks[7].Height, false),
125 *newTx(mockBlocks[7].Transactions[1]).OutputHash(3): storage.NewUtxoEntry(false, mockBlocks[7].Height, false),
127 *newTx(mockBlocks[8].Transactions[0]).OutputHash(0): storage.NewUtxoEntry(true, mockBlocks[8].Height, false),
128 *newTx(mockBlocks[8].Transactions[1]).OutputHash(0): storage.NewUtxoEntry(false, mockBlocks[8].Height, false),
129 *newTx(mockBlocks[8].Transactions[1]).OutputHash(1): storage.NewUtxoEntry(false, mockBlocks[8].Height, false),
130 *newTx(mockBlocks[8].Transactions[1]).OutputHash(2): storage.NewUtxoEntry(false, mockBlocks[8].Height, false),
131 *newTx(mockBlocks[8].Transactions[1]).OutputHash(3): storage.NewUtxoEntry(false, mockBlocks[8].Height, false),
132 *newTx(mockBlocks[8].Transactions[2]).OutputHash(0): storage.NewUtxoEntry(false, mockBlocks[8].Height, false),
133 *newTx(mockBlocks[8].Transactions[2]).OutputHash(1): storage.NewUtxoEntry(false, mockBlocks[8].Height, false),
134 *newTx(mockBlocks[8].Transactions[3]).OutputHash(0): storage.NewUtxoEntry(false, mockBlocks[8].Height, false),
135 *newTx(mockBlocks[8].Transactions[3]).OutputHash(1): storage.NewUtxoEntry(false, mockBlocks[8].Height, false),
137 *newTx(mockBlocks[9].Transactions[0]).OutputHash(0): storage.NewUtxoEntry(true, mockBlocks[9].Height, false),
138 *newTx(mockBlocks[9].Transactions[1]).OutputHash(0): storage.NewUtxoEntry(false, mockBlocks[9].Height, false),
139 *newTx(mockBlocks[9].Transactions[1]).OutputHash(1): storage.NewUtxoEntry(false, mockBlocks[9].Height, false),
141 want: map[bc.Hash]*storage.UtxoEntry{
142 *newTx(mockBlocks[10].Transactions[0]).OutputHash(0): storage.NewUtxoEntry(true, mockBlocks[10].Height, false),
143 *newTx(mockBlocks[10].Transactions[1]).OutputHash(0): storage.NewUtxoEntry(false, mockBlocks[10].Height, false),
144 *newTx(mockBlocks[10].Transactions[1]).OutputHash(1): storage.NewUtxoEntry(false, mockBlocks[10].Height, false),
145 *newTx(mockBlocks[10].Transactions[2]).OutputHash(0): storage.NewUtxoEntry(false, mockBlocks[10].Height, false),
146 *newTx(mockBlocks[10].Transactions[2]).OutputHash(1): storage.NewUtxoEntry(false, mockBlocks[10].Height, false),
147 *newTx(mockBlocks[10].Transactions[2]).OutputHash(2): storage.NewUtxoEntry(false, mockBlocks[10].Height, false),
148 *newTx(mockBlocks[10].Transactions[2]).OutputHash(3): storage.NewUtxoEntry(false, mockBlocks[10].Height, false),
149 *newTx(mockBlocks[10].Transactions[3]).OutputHash(0): storage.NewUtxoEntry(false, mockBlocks[10].Height, false),
150 *newTx(mockBlocks[10].Transactions[3]).OutputHash(1): storage.NewUtxoEntry(false, mockBlocks[10].Height, false),
151 *newTx(mockBlocks[10].Transactions[3]).OutputHash(2): storage.NewUtxoEntry(false, mockBlocks[10].Height, false),
152 *newTx(mockBlocks[10].Transactions[3]).OutputHash(3): storage.NewUtxoEntry(false, mockBlocks[10].Height, false),
153 *newTx(mockBlocks[10].Transactions[4]).OutputHash(0): storage.NewUtxoEntry(false, mockBlocks[10].Height, false),
154 *newTx(mockBlocks[10].Transactions[4]).OutputHash(1): storage.NewUtxoEntry(false, mockBlocks[10].Height, false),
155 *newTx(mockBlocks[10].Transactions[4]).OutputHash(2): storage.NewUtxoEntry(false, mockBlocks[10].Height, false),
156 *newTx(mockBlocks[10].Transactions[4]).OutputHash(3): storage.NewUtxoEntry(false, mockBlocks[10].Height, false),
157 *newTx(mockBlocks[10].Transactions[5]).OutputHash(0): storage.NewUtxoEntry(false, mockBlocks[10].Height, false),
158 *newTx(mockBlocks[10].Transactions[5]).OutputHash(1): storage.NewUtxoEntry(false, mockBlocks[10].Height, false),
159 *newTx(mockBlocks[10].Transactions[5]).OutputHash(2): storage.NewUtxoEntry(false, mockBlocks[10].Height, false),
160 *newTx(mockBlocks[10].Transactions[5]).OutputHash(3): storage.NewUtxoEntry(false, mockBlocks[10].Height, false),
162 *newTx(mockBlocks[11].Transactions[0]).OutputHash(0): storage.NewUtxoEntry(true, mockBlocks[11].Height, false),
163 *newTx(mockBlocks[11].Transactions[1]).OutputHash(0): storage.NewUtxoEntry(false, mockBlocks[11].Height, false),
164 *newTx(mockBlocks[11].Transactions[1]).OutputHash(1): storage.NewUtxoEntry(false, mockBlocks[11].Height, false),
165 *newTx(mockBlocks[11].Transactions[2]).OutputHash(0): storage.NewUtxoEntry(false, mockBlocks[11].Height, false),
166 *newTx(mockBlocks[11].Transactions[2]).OutputHash(1): storage.NewUtxoEntry(false, mockBlocks[11].Height, false),
167 *newTx(mockBlocks[11].Transactions[3]).OutputHash(0): storage.NewUtxoEntry(false, mockBlocks[11].Height, false),
168 *newTx(mockBlocks[11].Transactions[3]).OutputHash(1): storage.NewUtxoEntry(false, mockBlocks[11].Height, false),
170 attachBlock: []*bc.Block{
171 types.MapBlock(&mockBlocks[10].Block),
172 types.MapBlock(&mockBlocks[11].Block),
174 detachBlock: []*bc.Block{
175 types.MapBlock(&mockBlocks[9].Block),
176 types.MapBlock(&mockBlocks[8].Block),
177 types.MapBlock(&mockBlocks[7].Block),
178 types.MapBlock(&mockBlocks[6].Block),
179 types.MapBlock(&mockBlocks[5].Block),
181 attachTxStatus: []*bc.TransactionStatus{
182 &bc.TransactionStatus{VerifyStatus: []*bc.TxVerifyResult{
183 &bc.TxVerifyResult{StatusFail: false},
184 &bc.TxVerifyResult{StatusFail: false},
185 &bc.TxVerifyResult{StatusFail: false},
186 &bc.TxVerifyResult{StatusFail: false},
187 &bc.TxVerifyResult{StatusFail: false},
188 &bc.TxVerifyResult{StatusFail: false},
190 &bc.TransactionStatus{VerifyStatus: []*bc.TxVerifyResult{
191 &bc.TxVerifyResult{StatusFail: false},
192 &bc.TxVerifyResult{StatusFail: false},
193 &bc.TxVerifyResult{StatusFail: false},
194 &bc.TxVerifyResult{StatusFail: false},
195 &bc.TxVerifyResult{StatusFail: false},
198 detachTxStatus: []*bc.TransactionStatus{
200 &bc.TransactionStatus{VerifyStatus: []*bc.TxVerifyResult{
201 &bc.TxVerifyResult{StatusFail: false},
202 &bc.TxVerifyResult{StatusFail: false},
204 &bc.TransactionStatus{VerifyStatus: []*bc.TxVerifyResult{
205 &bc.TxVerifyResult{StatusFail: false},
206 &bc.TxVerifyResult{StatusFail: false},
207 &bc.TxVerifyResult{StatusFail: false},
208 &bc.TxVerifyResult{StatusFail: false},
210 &bc.TransactionStatus{VerifyStatus: []*bc.TxVerifyResult{
211 &bc.TxVerifyResult{StatusFail: false},
212 &bc.TxVerifyResult{StatusFail: false},
214 &bc.TransactionStatus{VerifyStatus: []*bc.TxVerifyResult{
215 &bc.TxVerifyResult{StatusFail: false},
216 &bc.TxVerifyResult{StatusFail: false},
217 &bc.TxVerifyResult{StatusFail: false},
219 &bc.TransactionStatus{VerifyStatus: []*bc.TxVerifyResult{
220 &bc.TxVerifyResult{StatusFail: false},
221 &bc.TxVerifyResult{StatusFail: false},
226 desc: "detach block 2, attach block 1. Chain trading",
227 before: map[bc.Hash]*storage.UtxoEntry{
229 *newTx(mockBlocks[12].Transactions[0]).OutputHash(0): storage.NewUtxoEntry(true, mockBlocks[12].Height, false),
230 *newTx(mockBlocks[12].Transactions[1]).OutputHash(1): storage.NewUtxoEntry(false, mockBlocks[12].Height, false),
231 *newTx(mockBlocks[12].Transactions[2]).OutputHash(1): storage.NewUtxoEntry(false, mockBlocks[12].Height, false),
232 *newTx(mockBlocks[12].Transactions[3]).OutputHash(1): storage.NewUtxoEntry(false, mockBlocks[12].Height, false),
233 *newTx(mockBlocks[12].Transactions[4]).OutputHash(1): storage.NewUtxoEntry(false, mockBlocks[12].Height, false),
235 *newTx(mockBlocks[13].Transactions[0]).OutputHash(0): storage.NewUtxoEntry(true, mockBlocks[13].Height, false),
236 *newTx(mockBlocks[13].Transactions[1]).OutputHash(1): storage.NewUtxoEntry(false, mockBlocks[13].Height, false),
237 *newTx(mockBlocks[13].Transactions[2]).OutputHash(0): storage.NewUtxoEntry(false, mockBlocks[13].Height, false),
238 *newTx(mockBlocks[13].Transactions[2]).OutputHash(1): storage.NewUtxoEntry(false, mockBlocks[13].Height, false),
240 want: map[bc.Hash]*storage.UtxoEntry{
241 newTx(mockBlocks[12].Transactions[1]).getSpentOutputID(0): storage.NewUtxoEntry(false, 0, false),
242 *newTx(mockBlocks[14].Transactions[0]).OutputHash(0): storage.NewUtxoEntry(true, mockBlocks[14].Height, false),
244 attachBlock: []*bc.Block{
245 types.MapBlock(&mockBlocks[14].Block),
247 detachBlock: []*bc.Block{
248 types.MapBlock(&mockBlocks[13].Block),
249 types.MapBlock(&mockBlocks[12].Block),
251 attachTxStatus: []*bc.TransactionStatus{
252 &bc.TransactionStatus{VerifyStatus: []*bc.TxVerifyResult{
253 &bc.TxVerifyResult{StatusFail: false},
254 &bc.TxVerifyResult{StatusFail: false},
255 &bc.TxVerifyResult{StatusFail: false},
256 &bc.TxVerifyResult{StatusFail: false},
258 &bc.TransactionStatus{VerifyStatus: []*bc.TxVerifyResult{
259 &bc.TxVerifyResult{StatusFail: false},
260 &bc.TxVerifyResult{StatusFail: false},
262 &bc.TransactionStatus{VerifyStatus: []*bc.TxVerifyResult{
263 &bc.TxVerifyResult{StatusFail: false},
264 &bc.TxVerifyResult{StatusFail: false},
265 &bc.TxVerifyResult{StatusFail: false},
268 detachTxStatus: []*bc.TransactionStatus{
269 &bc.TransactionStatus{VerifyStatus: []*bc.TxVerifyResult{
270 &bc.TxVerifyResult{StatusFail: false},
271 &bc.TxVerifyResult{StatusFail: false},
272 &bc.TxVerifyResult{StatusFail: false},
274 &bc.TransactionStatus{VerifyStatus: []*bc.TxVerifyResult{
275 &bc.TxVerifyResult{StatusFail: false},
276 &bc.TxVerifyResult{StatusFail: false},
277 &bc.TxVerifyResult{StatusFail: false},
278 &bc.TxVerifyResult{StatusFail: false},
279 &bc.TxVerifyResult{StatusFail: false},
284 node := blockNode(types.MapBlock(&mockBlocks[0].Block).BlockHeader)
285 defer os.RemoveAll("temp")
287 for index, c := range cases {
288 testDB := dbm.NewDB("testdb", "leveldb", "temp")
289 store := database.NewStore(testDB)
291 utxoViewpoint0 := state.NewUtxoViewpoint()
292 for k, v := range c.before {
293 utxoViewpoint0.Entries[k] = v
295 contractView := state.NewContractViewpoint()
296 if err := store.SaveChainStatus(node, utxoViewpoint0, contractView, 0, &bc.Hash{}); err != nil {
300 utxoViewpoint := state.NewUtxoViewpoint()
301 for _, block := range c.detachBlock {
302 if err := store.GetTransactionsUtxo(utxoViewpoint, block.Transactions); err != nil {
305 if err := utxoViewpoint.DetachBlock(block); err != nil {
310 for _, block := range c.attachBlock {
311 if err := store.GetTransactionsUtxo(utxoViewpoint, block.Transactions); err != nil {
314 if err := utxoViewpoint.ApplyBlock(block); err != nil {
318 if err := store.SaveChainStatus(node, utxoViewpoint, contractView, 0, &bc.Hash{}); err != nil {
322 want := map[string]*storage.UtxoEntry{}
323 result := make(map[string]*storage.UtxoEntry)
325 for k, v := range c.want {
326 want[string(calcUtxoKey(&k))] = v
329 iter := testDB.IteratorPrefix([]byte(utxoPreFix))
333 utxoEntry := &storage.UtxoEntry{}
334 if err := proto.Unmarshal(iter.Value(), utxoEntry); err != nil {
337 key := string(iter.Key())
338 result[key] = utxoEntry
341 if !testutil.DeepEqual(want, result) {
342 t.Errorf("case [%d] fail. want: %v, result: %v", index, want, result)