OSDN Git Service

61c3f305054106b80fc9d22337ff96d277cfb6a5
[bytom/bytom.git] / test / integration / block_integration_test.go
1 package integration
2
3 import (
4         "testing"
5
6         "time"
7
8         "github.com/bytom/config"
9         "github.com/bytom/consensus"
10         "github.com/bytom/database"
11         "github.com/bytom/database/storage"
12         "github.com/bytom/protocol"
13         "github.com/bytom/protocol/bc"
14         "github.com/bytom/protocol/bc/types"
15         "github.com/bytom/protocol/state"
16         "github.com/bytom/testutil"
17 )
18
19 var blockMap map[int][]*attachBlock
20
21 type attachBlock struct {
22         block        *types.Block
23         verifyResult []*bc.TxVerifyResult
24 }
25
26 func init() {
27         consensus.ActiveNetParams = consensus.SoloNetParams
28
29         blockMap = map[int][]*attachBlock{
30                 0: {
31                         {
32                                 block:        config.GenesisBlock(),
33                                 verifyResult: []*bc.TxVerifyResult{{StatusFail: false}},
34                         },
35                 },
36                 1: {
37                         {
38                                 block: &types.Block{
39                                         BlockHeader: types.BlockHeader{
40                                                 Height:            1,
41                                                 Version:           1,
42                                                 Timestamp:         1556431597,
43                                                 Nonce:             5,
44                                                 Bits:              2305843009214532812,
45                                                 PreviousBlockHash: testutil.MustDecodeHash("ce4fe9431cd0225b3a811f8f8ec922f2b07a921bb12a8dddae9a85540072c770"),
46                                         },
47                                         Transactions: []*types.Tx{
48                                                 types.NewTx(types.TxData{
49                                                         Version:        1,
50                                                         SerializedSize: 77,
51                                                         TimeRange:      0,
52                                                         Inputs: []*types.TxInput{
53                                                                 types.NewCoinbaseInput(testutil.MustDecodeHexString("0031")),
54                                                         },
55                                                         Outputs: []*types.TxOutput{
56                                                                 types.NewTxOutput(*consensus.BTMAssetID, 41250000000, testutil.MustDecodeHexString("0014024bb9bfc639bdac292ff9ceb41b5c6f5a970eab")),
57                                                         },
58                                                 }),
59                                         },
60                                 },
61                                 verifyResult: []*bc.TxVerifyResult{{StatusFail: false}},
62                         },
63                         {
64                                 block: &types.Block{
65                                         BlockHeader: types.BlockHeader{
66                                                 Height:            1,
67                                                 Version:           1,
68                                                 Timestamp:         1556431697,
69                                                 Nonce:             36,
70                                                 Bits:              2305843009214532812,
71                                                 PreviousBlockHash: testutil.MustDecodeHash("ce4fe9431cd0225b3a811f8f8ec922f2b07a921bb12a8dddae9a85540072c770"),
72                                         },
73                                         Transactions: []*types.Tx{
74                                                 types.NewTx(types.TxData{
75                                                         Version:        1,
76                                                         SerializedSize: 77,
77                                                         TimeRange:      0,
78                                                         Inputs: []*types.TxInput{
79                                                                 types.NewCoinbaseInput(testutil.MustDecodeHexString("0031")),
80                                                         },
81                                                         Outputs: []*types.TxOutput{
82                                                                 types.NewTxOutput(*consensus.BTMAssetID, 41250000000, testutil.MustDecodeHexString("00143d05e891b165b165afefa2e861e83a9745f80d8c")),
83                                                         },
84                                                 }),
85                                         },
86                                 },
87                                 verifyResult: []*bc.TxVerifyResult{{StatusFail: false}},
88                         },
89                 },
90                 2: {
91                         // only has coinbase transaction
92                         {
93                                 block: &types.Block{
94                                         BlockHeader: types.BlockHeader{
95                                                 Height:            2,
96                                                 Version:           1,
97                                                 Timestamp:         1556431604,
98                                                 Nonce:             0,
99                                                 Bits:              2305843009214532812,
100                                                 PreviousBlockHash: testutil.MustDecodeHash("2eaf7f40b0a0d4a5025f3d5d9b8589d3db1634f7b55089ca59253a9c587266b2"),
101                                         },
102                                         Transactions: []*types.Tx{
103                                                 types.NewTx(types.TxData{
104                                                         Version:        1,
105                                                         SerializedSize: 77,
106                                                         TimeRange:      0,
107                                                         Inputs: []*types.TxInput{
108                                                                 types.NewCoinbaseInput(testutil.MustDecodeHexString("0032")),
109                                                         },
110                                                         Outputs: []*types.TxOutput{
111                                                                 types.NewTxOutput(*consensus.BTMAssetID, 41250000000, testutil.MustDecodeHexString("0014024bb9bfc639bdac292ff9ceb41b5c6f5a970eab")),
112                                                         },
113                                                 }),
114                                         },
115                                 },
116                                 verifyResult: []*bc.TxVerifyResult{{StatusFail: false}},
117                         },
118                         // with spend btm transaction
119                         {
120                                 block: &types.Block{
121                                         BlockHeader: types.BlockHeader{
122                                                 Height:            2,
123                                                 Version:           1,
124                                                 Timestamp:         1556431604,
125                                                 Nonce:             12,
126                                                 Bits:              2305843009214532812,
127                                                 PreviousBlockHash: testutil.MustDecodeHash("2eaf7f40b0a0d4a5025f3d5d9b8589d3db1634f7b55089ca59253a9c587266b2"),
128                                         },
129                                         Transactions: []*types.Tx{
130                                                 types.NewTx(types.TxData{
131                                                         Version:        1,
132                                                         SerializedSize: 77,
133                                                         TimeRange:      0,
134                                                         Inputs: []*types.TxInput{
135                                                                 types.NewCoinbaseInput(testutil.MustDecodeHexString("0032")),
136                                                         },
137                                                         Outputs: []*types.TxOutput{
138                                                                 types.NewTxOutput(*consensus.BTMAssetID, 41350000000, testutil.MustDecodeHexString("0014024bb9bfc639bdac292ff9ceb41b5c6f5a970eab")),
139                                                         },
140                                                 }),
141                                                 types.NewTx(types.TxData{
142                                                         Version:   1,
143                                                         TimeRange: 0,
144                                                         Inputs: []*types.TxInput{
145                                                                 types.NewSpendInput(
146                                                                         [][]byte{
147                                                                                 testutil.MustDecodeHexString("7b4082c9d745c3f07dd07afb1f987960d2ef3ea2486741c3f3184751485f77d046df6670eba21020fcf9c7987c0c938384320dc21b0e116c62ae2597cb1fe109"),
148                                                                                 testutil.MustDecodeHexString("33b05e00e19cb2bdbc8a6a67b4f1e03fc265534bcfc7641b305c8204fb486f79"),
149                                                                         },
150                                                                         testutil.MustDecodeHash("28b7b53d8dc90006bf97e0a4eaae2a72ec3d869873188698b694beaf20789f21"),
151                                                                         *consensus.BTMAssetID, 10000000000, 0,
152                                                                         testutil.MustDecodeHexString("0014cade6dd7cbe2ea2b8ab90dfb8756dda4ba1624bc"),
153                                                                 ),
154                                                         },
155                                                         Outputs: []*types.TxOutput{
156                                                                 types.NewTxOutput(*consensus.BTMAssetID, 9900000000, testutil.MustDecodeHexString("00143d05e891b165b165afefa2e861e83a9745f80d8c")),
157                                                         },
158                                                 }),
159                                         },
160                                 },
161                                 verifyResult: []*bc.TxVerifyResult{{StatusFail: false}, {StatusFail: false}},
162                         },
163                         // with btm retire transaction
164                         {
165                                 block: &types.Block{
166                                         BlockHeader: types.BlockHeader{
167                                                 Height:            2,
168                                                 Version:           1,
169                                                 Timestamp:         1556431607,
170                                                 Nonce:             4,
171                                                 Bits:              2305843009214532812,
172                                                 PreviousBlockHash: testutil.MustDecodeHash("2eaf7f40b0a0d4a5025f3d5d9b8589d3db1634f7b55089ca59253a9c587266b2"),
173                                         },
174                                         Transactions: []*types.Tx{
175                                                 types.NewTx(types.TxData{
176                                                         Version:        1,
177                                                         SerializedSize: 77,
178                                                         TimeRange:      0,
179                                                         Inputs: []*types.TxInput{
180                                                                 types.NewCoinbaseInput(testutil.MustDecodeHexString("0032")),
181                                                         },
182                                                         Outputs: []*types.TxOutput{
183                                                                 types.NewTxOutput(*consensus.BTMAssetID, 41350000000, testutil.MustDecodeHexString("0014024bb9bfc639bdac292ff9ceb41b5c6f5a970eab")),
184                                                         },
185                                                 }),
186                                                 types.NewTx(types.TxData{
187                                                         Version:   1,
188                                                         TimeRange: 0,
189                                                         Inputs: []*types.TxInput{
190                                                                 types.NewSpendInput(
191                                                                         [][]byte{
192                                                                                 testutil.MustDecodeHexString("302035b362d80419cfed12cfc7d33d2ff7638c589ee2cf6573eb14b4d8cb4a63d7d1302589666dd6d1cd08185dbb2842407f3980bc2564705eda15680c984c05"),
193                                                                                 testutil.MustDecodeHexString("33b05e00e19cb2bdbc8a6a67b4f1e03fc265534bcfc7641b305c8204fb486f79"),
194                                                                         },
195                                                                         testutil.MustDecodeHash("28b7b53d8dc90006bf97e0a4eaae2a72ec3d869873188698b694beaf20789f21"),
196                                                                         *consensus.BTMAssetID, 10000000000, 0,
197                                                                         testutil.MustDecodeHexString("0014cade6dd7cbe2ea2b8ab90dfb8756dda4ba1624bc"),
198                                                                 ),
199                                                         },
200                                                         Outputs: []*types.TxOutput{
201                                                                 types.NewTxOutput(*consensus.BTMAssetID, 9900000000, testutil.MustDecodeHexString("6a")), // retire
202                                                         },
203                                                 }),
204                                         },
205                                 },
206                                 verifyResult: []*bc.TxVerifyResult{{StatusFail: false}, {StatusFail: false}},
207                         },
208                         // with issuance transaction
209                         {
210                                 block: &types.Block{
211                                         BlockHeader: types.BlockHeader{
212                                                 Height:            2,
213                                                 Version:           1,
214                                                 Timestamp:         1556431607,
215                                                 Nonce:             17,
216                                                 Bits:              2305843009214532812,
217                                                 PreviousBlockHash: testutil.MustDecodeHash("2eaf7f40b0a0d4a5025f3d5d9b8589d3db1634f7b55089ca59253a9c587266b2"),
218                                         },
219                                         Transactions: []*types.Tx{
220                                                 types.NewTx(types.TxData{
221                                                         Version:        1,
222                                                         SerializedSize: 77,
223                                                         TimeRange:      0,
224                                                         Inputs: []*types.TxInput{
225                                                                 types.NewCoinbaseInput(testutil.MustDecodeHexString("0032")),
226                                                         },
227                                                         Outputs: []*types.TxOutput{
228                                                                 types.NewTxOutput(*consensus.BTMAssetID, 41350000000, testutil.MustDecodeHexString("0014024bb9bfc639bdac292ff9ceb41b5c6f5a970eab")),
229                                                         },
230                                                 }),
231                                                 types.NewTx(types.TxData{
232                                                         Version:   1,
233                                                         TimeRange: 0,
234                                                         Inputs: []*types.TxInput{
235                                                                 types.NewSpendInput(
236                                                                         [][]byte{
237                                                                                 testutil.MustDecodeHexString("46cbb829b6a5bb9fc436c8e51bcbd9f0b3ed99ce97b2e0fac28879b4202c5a9eccaae39a4d18584f789a9427af3a2f09ff0360fb187e46ef172146a9b957ef0c"),
238                                                                                 testutil.MustDecodeHexString("33b05e00e19cb2bdbc8a6a67b4f1e03fc265534bcfc7641b305c8204fb486f79"),
239                                                                         },
240                                                                         testutil.MustDecodeHash("28b7b53d8dc90006bf97e0a4eaae2a72ec3d869873188698b694beaf20789f21"),
241                                                                         *consensus.BTMAssetID, 10000000000, 0,
242                                                                         testutil.MustDecodeHexString("0014cade6dd7cbe2ea2b8ab90dfb8756dda4ba1624bc"),
243                                                                 ),
244                                                                 types.NewIssuanceInput(
245                                                                         testutil.MustDecodeHexString("fd0aec4229deb281"),
246                                                                         10000000000,
247                                                                         testutil.MustDecodeHexString("ae20f25e8b73ffbc3a42300a43279fdf612d79e1936a6c614fc05a5adec9bba42dcd5151ad"),
248                                                                         [][]byte{testutil.MustDecodeHexString("df9fabf4636904e017eefb7cdf2b4f08e29efbd4cfc41fe5b01a453191f0913489b19ad74272145824e92bd4843e91140cc5d1a6256f84981d1437ed4566a60b")},
249                                                                         testutil.MustDecodeHexString("7b0a202022646563696d616c73223a20382c0a2020226465736372697074696f6e223a207b7d2c0a2020226e616d65223a2022222c0a20202273796d626f6c223a2022220a7d"),
250                                                                 ),
251                                                         },
252                                                         Outputs: []*types.TxOutput{
253                                                                 types.NewTxOutput(*consensus.BTMAssetID, 9900000000, testutil.MustDecodeHexString("0014024bb9bfc639bdac292ff9ceb41b5c6f5a970eab")),
254                                                                 types.NewTxOutput(testutil.MustDecodeAsset("641ccb49dd38df9921a55e020d40a2323589c36ab5557f8a249ee01cc09d1836"), 10000000000, testutil.MustDecodeHexString("0014024bb9bfc639bdac292ff9ceb41b5c6f5a970eab")),
255                                                         },
256                                                 }),
257                                         },
258                                 },
259                                 verifyResult: []*bc.TxVerifyResult{{StatusFail: false}, {StatusFail: false}},
260                         },
261                         // with issuance transaction but status fail is true
262                         {
263                                 block: &types.Block{
264                                         BlockHeader: types.BlockHeader{
265                                                 Height:            2,
266                                                 Version:           1,
267                                                 Timestamp:         1556431607,
268                                                 Nonce:             4,
269                                                 Bits:              2305843009214532812,
270                                                 PreviousBlockHash: testutil.MustDecodeHash("2eaf7f40b0a0d4a5025f3d5d9b8589d3db1634f7b55089ca59253a9c587266b2"),
271                                         },
272                                         Transactions: []*types.Tx{
273                                                 types.NewTx(types.TxData{
274                                                         Version:        1,
275                                                         SerializedSize: 77,
276                                                         TimeRange:      0,
277                                                         Inputs: []*types.TxInput{
278                                                                 types.NewCoinbaseInput(testutil.MustDecodeHexString("0032")),
279                                                         },
280                                                         Outputs: []*types.TxOutput{
281                                                                 types.NewTxOutput(*consensus.BTMAssetID, 41350000000, testutil.MustDecodeHexString("0014024bb9bfc639bdac292ff9ceb41b5c6f5a970eab")),
282                                                         },
283                                                 }),
284                                                 types.NewTx(types.TxData{
285                                                         Version:   1,
286                                                         TimeRange: 0,
287                                                         Inputs: []*types.TxInput{
288                                                                 types.NewSpendInput(
289                                                                         [][]byte{
290                                                                                 testutil.MustDecodeHexString("46cbb829b6a5bb9fc436c8e51bcbd9f0b3ed99ce97b2e0fac28879b4202c5a9eccaae39a4d18584f789a9427af3a2f09ff0360fb187e46ef172146a9b957ef0c"),
291                                                                                 testutil.MustDecodeHexString("33b05e00e19cb2bdbc8a6a67b4f1e03fc265534bcfc7641b305c8204fb486f79"),
292                                                                         },
293                                                                         testutil.MustDecodeHash("28b7b53d8dc90006bf97e0a4eaae2a72ec3d869873188698b694beaf20789f21"),
294                                                                         *consensus.BTMAssetID, 10000000000, 0,
295                                                                         testutil.MustDecodeHexString("0014cade6dd7cbe2ea2b8ab90dfb8756dda4ba1624bc"),
296                                                                 ),
297                                                                 types.NewIssuanceInput(
298                                                                         testutil.MustDecodeHexString("fd0aec4229deb281"),
299                                                                         10000000000,
300                                                                         testutil.MustDecodeHexString("ae20f25e8b73ffbc3a42300a43279fdf612d79e1936a6c614fc05a5adec9bba42dcd5151ad"),
301                                                                         // invalid signature
302                                                                         [][]byte{testutil.MustDecodeHexString("df9fabf4636904e017eefb7cdf2b4f08e29efbd4cfc41fe5b01a453191f0913489b19ad74272145824e92bd4843e91140cc5d1a6256f84981d1437ed4566a60c")},
303                                                                         testutil.MustDecodeHexString("7b0a202022646563696d616c73223a20382c0a2020226465736372697074696f6e223a207b7d2c0a2020226e616d65223a2022222c0a20202273796d626f6c223a2022220a7d"),
304                                                                 ),
305                                                         },
306                                                         Outputs: []*types.TxOutput{
307                                                                 types.NewTxOutput(*consensus.BTMAssetID, 9900000000, testutil.MustDecodeHexString("0014024bb9bfc639bdac292ff9ceb41b5c6f5a970eab")),
308                                                                 types.NewTxOutput(testutil.MustDecodeAsset("641ccb49dd38df9921a55e020d40a2323589c36ab5557f8a249ee01cc09d1836"), 10000000000, testutil.MustDecodeHexString("0014024bb9bfc639bdac292ff9ceb41b5c6f5a970eab")),
309                                                         },
310                                                 }),
311                                         },
312                                 },
313                                 verifyResult: []*bc.TxVerifyResult{{StatusFail: false}, {StatusFail: true}},
314                         },
315                         // with non btm transaction
316                         {
317                                 block: &types.Block{
318                                         BlockHeader: types.BlockHeader{
319                                                 Height:            2,
320                                                 Version:           1,
321                                                 Timestamp:         1556431607,
322                                                 Nonce:             4,
323                                                 Bits:              2305843009214532812,
324                                                 PreviousBlockHash: testutil.MustDecodeHash("2eaf7f40b0a0d4a5025f3d5d9b8589d3db1634f7b55089ca59253a9c587266b2"),
325                                         },
326                                         Transactions: []*types.Tx{
327                                                 types.NewTx(types.TxData{
328                                                         Version:        1,
329                                                         SerializedSize: 77,
330                                                         TimeRange:      0,
331                                                         Inputs: []*types.TxInput{
332                                                                 types.NewCoinbaseInput(testutil.MustDecodeHexString("0032")),
333                                                         },
334                                                         Outputs: []*types.TxOutput{
335                                                                 types.NewTxOutput(*consensus.BTMAssetID, 41350000000, testutil.MustDecodeHexString("0014024bb9bfc639bdac292ff9ceb41b5c6f5a970eab")),
336                                                         },
337                                                 }),
338                                                 types.NewTx(types.TxData{
339                                                         Version:   1,
340                                                         TimeRange: 0,
341                                                         Inputs: []*types.TxInput{
342                                                                 types.NewSpendInput(
343                                                                         [][]byte{
344                                                                                 testutil.MustDecodeHexString("afc4e24f0e0383e3fd78af3de189be3913faddbbd8cac8a8c9316bf9eb0866e83df3618cf4c7b4d091a79968a16377d422cbd8011f1f5e75ba201e173b68ad02"),
345                                                                                 testutil.MustDecodeHexString("33b05e00e19cb2bdbc8a6a67b4f1e03fc265534bcfc7641b305c8204fb486f79"),
346                                                                         },
347                                                                         testutil.MustDecodeHash("28b7b53d8dc90006bf97e0a4eaae2a72ec3d869873188698b694beaf20789f21"),
348                                                                         *consensus.BTMAssetID, 10000000000, 0,
349                                                                         testutil.MustDecodeHexString("0014cade6dd7cbe2ea2b8ab90dfb8756dda4ba1624bc"),
350                                                                 ),
351                                                                 types.NewSpendInput(
352                                                                         [][]byte{
353                                                                                 testutil.MustDecodeHexString("cd6fb451102db667341438f20dbeabd30b343ed08d89625a8e27e82478e89ddea9e7d51f8a4036e0cc2602ac5fae0bdbfda025a0e2c12e3ddc8100b62461670b"),
354                                                                                 testutil.MustDecodeHexString("33b05e00e19cb2bdbc8a6a67b4f1e03fc265534bcfc7641b305c8204fb486f79"),
355                                                                         },
356                                                                         testutil.MustDecodeHash("28b7b53d8dc90006bf97e0a4eaae2a72ec3d869873188698b694beaf20789f22"),
357                                                                         testutil.MustDecodeAsset("641ccb49dd38df9921a55e020d40a2323589c36ab5557f8a249ee01cc09d1836"), 10000000000, 1,
358                                                                         testutil.MustDecodeHexString("0014cade6dd7cbe2ea2b8ab90dfb8756dda4ba1624bc"),
359                                                                 ),
360                                                         },
361                                                         Outputs: []*types.TxOutput{
362                                                                 types.NewTxOutput(*consensus.BTMAssetID, 9900000000, testutil.MustDecodeHexString("0014024bb9bfc639bdac292ff9ceb41b5c6f5a970eab")),
363                                                                 types.NewTxOutput(testutil.MustDecodeAsset("641ccb49dd38df9921a55e020d40a2323589c36ab5557f8a249ee01cc09d1836"), 10000000000, testutil.MustDecodeHexString("0014024bb9bfc639bdac292ff9ceb41b5c6f5a970eab")),
364                                                         },
365                                                 }),
366                                         },
367                                 },
368                                 verifyResult: []*bc.TxVerifyResult{{StatusFail: false}, {StatusFail: false}},
369                         },
370                         // with non btm transaction but status fail is true
371                         {
372                                 block: &types.Block{
373                                         BlockHeader: types.BlockHeader{
374                                                 Height:            2,
375                                                 Version:           1,
376                                                 Timestamp:         1556431607,
377                                                 Nonce:             12,
378                                                 Bits:              2305843009214532812,
379                                                 PreviousBlockHash: testutil.MustDecodeHash("2eaf7f40b0a0d4a5025f3d5d9b8589d3db1634f7b55089ca59253a9c587266b2"),
380                                         },
381                                         Transactions: []*types.Tx{
382                                                 types.NewTx(types.TxData{
383                                                         Version:        1,
384                                                         SerializedSize: 77,
385                                                         TimeRange:      0,
386                                                         Inputs: []*types.TxInput{
387                                                                 types.NewCoinbaseInput(testutil.MustDecodeHexString("0032")),
388                                                         },
389                                                         Outputs: []*types.TxOutput{
390                                                                 types.NewTxOutput(*consensus.BTMAssetID, 41350000000, testutil.MustDecodeHexString("0014024bb9bfc639bdac292ff9ceb41b5c6f5a970eab")),
391                                                         },
392                                                 }),
393                                                 types.NewTx(types.TxData{
394                                                         Version:   1,
395                                                         TimeRange: 0,
396                                                         Inputs: []*types.TxInput{
397                                                                 types.NewSpendInput(
398                                                                         [][]byte{
399                                                                                 testutil.MustDecodeHexString("afc4e24f0e0383e3fd78af3de189be3913faddbbd8cac8a8c9316bf9eb0866e83df3618cf4c7b4d091a79968a16377d422cbd8011f1f5e75ba201e173b68ad02"),
400                                                                                 testutil.MustDecodeHexString("33b05e00e19cb2bdbc8a6a67b4f1e03fc265534bcfc7641b305c8204fb486f79"),
401                                                                         },
402                                                                         testutil.MustDecodeHash("28b7b53d8dc90006bf97e0a4eaae2a72ec3d869873188698b694beaf20789f21"),
403                                                                         *consensus.BTMAssetID, 10000000000, 0,
404                                                                         testutil.MustDecodeHexString("0014cade6dd7cbe2ea2b8ab90dfb8756dda4ba1624bc"),
405                                                                 ),
406                                                                 types.NewSpendInput(
407                                                                         // invalid signature
408                                                                         [][]byte{
409                                                                                 testutil.MustDecodeHexString("cd6fb451102db667341438f20dbeabd30b343ed08d89625a8e27e82478e89ddea9e7d51f8a4036e0cc2602ac5fae0bdbfda025a0e2c12e3ddc8100b62461670c"),
410                                                                                 testutil.MustDecodeHexString("33b05e00e19cb2bdbc8a6a67b4f1e03fc265534bcfc7641b305c8204fb486f79"),
411                                                                         },
412                                                                         testutil.MustDecodeHash("28b7b53d8dc90006bf97e0a4eaae2a72ec3d869873188698b694beaf20789f22"),
413                                                                         testutil.MustDecodeAsset("641ccb49dd38df9921a55e020d40a2323589c36ab5557f8a249ee01cc09d1836"), 10000000000, 1,
414                                                                         testutil.MustDecodeHexString("0014cade6dd7cbe2ea2b8ab90dfb8756dda4ba1624bc"),
415                                                                 ),
416                                                         },
417                                                         Outputs: []*types.TxOutput{
418                                                                 types.NewTxOutput(*consensus.BTMAssetID, 9900000000, testutil.MustDecodeHexString("0014024bb9bfc639bdac292ff9ceb41b5c6f5a970eab")),
419                                                                 types.NewTxOutput(testutil.MustDecodeAsset("641ccb49dd38df9921a55e020d40a2323589c36ab5557f8a249ee01cc09d1836"), 10000000000, testutil.MustDecodeHexString("0014024bb9bfc639bdac292ff9ceb41b5c6f5a970eab")),
420                                                         },
421                                                 }),
422                                         },
423                                 },
424                                 verifyResult: []*bc.TxVerifyResult{{StatusFail: false}, {StatusFail: true}},
425                         },
426                 },
427                 3: {
428                         // the previous block is blockMap[2][0]
429                         {
430                                 block: &types.Block{
431                                         BlockHeader: types.BlockHeader{
432                                                 Height:            3,
433                                                 Version:           1,
434                                                 Timestamp:         1556431640,
435                                                 Nonce:             0,
436                                                 Bits:              2305843009214532812,
437                                                 PreviousBlockHash: testutil.MustDecodeHash("09c6064f4f1e7325440c45df03e97f97dbfbb66033315a384308256038af6c30"),
438                                         },
439                                         Transactions: []*types.Tx{
440                                                 types.NewTx(types.TxData{
441                                                         Version:        1,
442                                                         SerializedSize: 77,
443                                                         TimeRange:      0,
444                                                         Inputs: []*types.TxInput{
445                                                                 types.NewCoinbaseInput(testutil.MustDecodeHexString("0033")),
446                                                         },
447                                                         Outputs: []*types.TxOutput{
448                                                                 types.NewTxOutput(*consensus.BTMAssetID, 41250000000, testutil.MustDecodeHexString("0014024bb9bfc639bdac292ff9ceb41b5c6f5a970eab")),
449                                                         },
450                                                 }),
451                                         },
452                                 },
453                                 verifyResult: []*bc.TxVerifyResult{{StatusFail: false}},
454                         },
455                         // the previous block is blockMap[2][2]
456                         {
457                                 block: &types.Block{
458                                         BlockHeader: types.BlockHeader{
459                                                 Height:            3,
460                                                 Version:           1,
461                                                 Timestamp:         1556431640,
462                                                 Nonce:             5,
463                                                 Bits:              2305843009214532812,
464                                                 PreviousBlockHash: testutil.MustDecodeHash("33f56264283cc12e3b232068caa13c1fd052c21b231a94e8c0a40bac25629f88"),
465                                         },
466                                         Transactions: []*types.Tx{
467                                                 types.NewTx(types.TxData{
468                                                         Version:        1,
469                                                         SerializedSize: 77,
470                                                         TimeRange:      0,
471                                                         Inputs: []*types.TxInput{
472                                                                 types.NewCoinbaseInput(testutil.MustDecodeHexString("0033")),
473                                                         },
474                                                         Outputs: []*types.TxOutput{
475                                                                 types.NewTxOutput(*consensus.BTMAssetID, 41250000000, testutil.MustDecodeHexString("0014024bb9bfc639bdac292ff9ceb41b5c6f5a970eab")),
476                                                         },
477                                                 }),
478                                         },
479                                 },
480                                 verifyResult: []*bc.TxVerifyResult{{StatusFail: false}},
481                         },
482                 },
483         }
484
485         mustPostProcessBlock()
486 }
487
488 func TestProcessBlock(t *testing.T) {
489         cases := []*processBlockTestCase{
490                 {
491                         desc: "process a invalid block",
492                         newBlock: &types.Block{
493                                 BlockHeader: types.BlockHeader{
494                                         Height:            1,
495                                         Version:           1,
496                                         Bits:              2305843009214532812,
497                                         PreviousBlockHash: blockMap[0][0].block.Hash(),
498                                 },
499                         },
500                         wantStore: createStoreItems([]int{0}, []*attachBlock{blockMap[0][0]}),
501                         wantBlockIndex: state.NewBlockIndexWithData(
502                                 map[bc.Hash]*state.BlockNode{
503                                         blockMap[0][0].block.Hash(): mustCreateBlockNode(&blockMap[0][0].block.BlockHeader),
504                                 },
505                                 []*state.BlockNode{
506                                         mustNewBlockNode(&blockMap[0][0].block.BlockHeader, nil),
507                                 },
508                         ),
509                         wantOrphanManage: protocol.NewOrphanManage(),
510                         wantError:        true,
511                 },
512                 {
513                         desc:      "process a orphan block normally",
514                         newBlock:  blockMap[2][0].block,
515                         wantStore: createStoreItems([]int{0}, []*attachBlock{blockMap[0][0]}),
516                         wantBlockIndex: state.NewBlockIndexWithData(
517                                 map[bc.Hash]*state.BlockNode{
518                                         blockMap[0][0].block.Hash(): mustNewBlockNode(&blockMap[0][0].block.BlockHeader, nil),
519                                 },
520                                 []*state.BlockNode{
521                                         mustNewBlockNode(&blockMap[0][0].block.BlockHeader, nil),
522                                 },
523                         ),
524                         wantOrphanManage: protocol.NewOrphanManageWithData(
525                                 map[bc.Hash]*protocol.OrphanBlock{blockMap[2][0].block.Hash(): {Block: blockMap[2][0].block}},
526                                 map[bc.Hash][]*bc.Hash{blockMap[2][0].block.PreviousBlockHash: {hashPtr(blockMap[2][0].block.Hash())}},
527                         ),
528                         wantIsOrphan: true,
529                         wantError:    false,
530                 },
531                 {
532                         desc:      "attach a block normally",
533                         newBlock:  blockMap[1][0].block,
534                         wantStore: createStoreItems([]int{0, 1}, []*attachBlock{blockMap[0][0], blockMap[1][0]}),
535                         wantBlockIndex: state.NewBlockIndexWithData(
536                                 map[bc.Hash]*state.BlockNode{
537                                         blockMap[0][0].block.Hash(): mustCreateBlockNode(&blockMap[0][0].block.BlockHeader),
538                                         blockMap[1][0].block.Hash(): mustCreateBlockNode(&blockMap[1][0].block.BlockHeader, &blockMap[0][0].block.BlockHeader),
539                                 },
540                                 []*state.BlockNode{
541                                         mustNewBlockNode(&blockMap[0][0].block.BlockHeader, nil),
542                                         mustNewBlockNode(&blockMap[1][0].block.BlockHeader, mustNewBlockNode(&blockMap[0][0].block.BlockHeader, nil)),
543                                 },
544                         ),
545                         wantOrphanManage: protocol.NewOrphanManage(),
546                         wantIsOrphan:     false,
547                         wantError:        false,
548                 },
549                 {
550                         desc:      "init genesis block from db",
551                         newBlock:  blockMap[1][0].block,
552                         initStore: createStoreItems([]int{0}, []*attachBlock{blockMap[0][0]}),
553                         wantStore: createStoreItems([]int{0, 1}, []*attachBlock{blockMap[0][0], blockMap[1][0]}),
554                         wantBlockIndex: state.NewBlockIndexWithData(
555                                 map[bc.Hash]*state.BlockNode{
556                                         blockMap[0][0].block.Hash(): mustCreateBlockNode(&blockMap[0][0].block.BlockHeader),
557                                         blockMap[1][0].block.Hash(): mustCreateBlockNode(&blockMap[1][0].block.BlockHeader, &blockMap[0][0].block.BlockHeader),
558                                 },
559                                 []*state.BlockNode{
560                                         mustNewBlockNode(&blockMap[0][0].block.BlockHeader, nil),
561                                         mustNewBlockNode(&blockMap[1][0].block.BlockHeader, mustNewBlockNode(&blockMap[0][0].block.BlockHeader, nil)),
562                                 },
563                         ),
564                         wantOrphanManage: protocol.NewOrphanManage(),
565                         wantIsOrphan:     false,
566                         wantError:        false,
567                 },
568                 {
569                         desc:      "attach a block to fork chain normally, not rollback",
570                         newBlock:  blockMap[2][0].block,
571                         initStore: createStoreItems([]int{0, 1}, []*attachBlock{blockMap[0][0], blockMap[1][0], blockMap[1][1]}),
572                         wantStore: createStoreItems([]int{0, 1, 3}, []*attachBlock{blockMap[0][0], blockMap[1][0], blockMap[1][1], blockMap[2][0]}),
573                         wantBlockIndex: state.NewBlockIndexWithData(
574                                 map[bc.Hash]*state.BlockNode{
575                                         blockMap[0][0].block.Hash(): mustCreateBlockNode(&blockMap[0][0].block.BlockHeader),
576                                         blockMap[1][0].block.Hash(): mustCreateBlockNode(&blockMap[1][0].block.BlockHeader, &blockMap[0][0].block.BlockHeader),
577                                         blockMap[1][1].block.Hash(): mustCreateBlockNode(&blockMap[1][1].block.BlockHeader, &blockMap[0][0].block.BlockHeader),
578                                         blockMap[2][0].block.Hash(): mustCreateBlockNode(&blockMap[2][0].block.BlockHeader, &blockMap[1][0].block.BlockHeader, &blockMap[0][0].block.BlockHeader),
579                                 },
580                                 []*state.BlockNode{
581                                         mustCreateBlockNode(&blockMap[0][0].block.BlockHeader),
582                                         mustCreateBlockNode(&blockMap[1][0].block.BlockHeader, &blockMap[0][0].block.BlockHeader),
583                                         mustCreateBlockNode(&blockMap[2][0].block.BlockHeader, &blockMap[1][0].block.BlockHeader, &blockMap[0][0].block.BlockHeader),
584                                 },
585                         ),
586                         wantOrphanManage: protocol.NewOrphanManage(),
587                         wantIsOrphan:     false,
588                         wantError:        false,
589                 },
590                 {
591                         desc:     "attach a block with btm transaction normally",
592                         newBlock: blockMap[2][1].block,
593                         initStore: createStoreItems([]int{0, 1}, []*attachBlock{blockMap[0][0], blockMap[1][0]}, &storeItem{
594                                 key: database.CalcUtxoKey(hashPtr(testutil.MustDecodeHash("c93b687f98d039046cd2afd514c62f5d1c2c3b0804e4845b00a33e736ef48a33"))),
595                                 val: &storage.UtxoEntry{IsCoinBase: false, BlockHeight: 1, Spent: false},
596                         }),
597                         wantStore: createStoreItems([]int{0, 1, 2}, []*attachBlock{blockMap[0][0], blockMap[1][0], blockMap[2][1]}, &storeItem{
598                                 key: database.CalcUtxoKey(hashPtr(testutil.MustDecodeHash("c93b687f98d039046cd2afd514c62f5d1c2c3b0804e4845b00a33e736ef48a33"))),
599                                 val: &storage.UtxoEntry{IsCoinBase: false, BlockHeight: 1, Spent: false},
600                         }),
601                         wantBlockIndex: state.NewBlockIndexWithData(
602                                 map[bc.Hash]*state.BlockNode{
603                                         blockMap[0][0].block.Hash(): mustCreateBlockNode(&blockMap[0][0].block.BlockHeader),
604                                         blockMap[1][0].block.Hash(): mustCreateBlockNode(&blockMap[1][0].block.BlockHeader, &blockMap[0][0].block.BlockHeader),
605                                         blockMap[2][1].block.Hash(): mustCreateBlockNode(&blockMap[2][1].block.BlockHeader, &blockMap[1][0].block.BlockHeader, &blockMap[0][0].block.BlockHeader),
606                                 },
607                                 []*state.BlockNode{
608                                         mustCreateBlockNode(&blockMap[0][0].block.BlockHeader),
609                                         mustCreateBlockNode(&blockMap[1][0].block.BlockHeader, &blockMap[0][0].block.BlockHeader),
610                                         mustCreateBlockNode(&blockMap[2][1].block.BlockHeader, &blockMap[1][0].block.BlockHeader, &blockMap[0][0].block.BlockHeader),
611                                 },
612                         ),
613                         wantOrphanManage: protocol.NewOrphanManage(),
614                         wantIsOrphan:     false,
615                         wantError:        false,
616                 },
617                 {
618                         desc:     "attach a block with retire transaction normally",
619                         newBlock: blockMap[2][2].block,
620                         initStore: createStoreItems([]int{0, 1}, []*attachBlock{blockMap[0][0], blockMap[1][0]}, &storeItem{
621                                 key: database.CalcUtxoKey(hashPtr(testutil.MustDecodeHash("c93b687f98d039046cd2afd514c62f5d1c2c3b0804e4845b00a33e736ef48a33"))),
622                                 val: &storage.UtxoEntry{IsCoinBase: false, BlockHeight: 1, Spent: false},
623                         }),
624                         wantStore: createStoreItems([]int{0, 1, 2}, []*attachBlock{blockMap[0][0], blockMap[1][0], blockMap[2][2]}, &storeItem{
625                                 key: database.CalcUtxoKey(hashPtr(testutil.MustDecodeHash("c93b687f98d039046cd2afd514c62f5d1c2c3b0804e4845b00a33e736ef48a33"))),
626                                 val: &storage.UtxoEntry{IsCoinBase: false, BlockHeight: 1, Spent: false},
627                         }),
628                         wantBlockIndex: state.NewBlockIndexWithData(
629                                 map[bc.Hash]*state.BlockNode{
630                                         blockMap[0][0].block.Hash(): mustCreateBlockNode(&blockMap[0][0].block.BlockHeader),
631                                         blockMap[1][0].block.Hash(): mustCreateBlockNode(&blockMap[1][0].block.BlockHeader, &blockMap[0][0].block.BlockHeader),
632                                         blockMap[2][2].block.Hash(): mustCreateBlockNode(&blockMap[2][2].block.BlockHeader, &blockMap[1][0].block.BlockHeader, &blockMap[0][0].block.BlockHeader),
633                                 },
634                                 []*state.BlockNode{
635                                         mustCreateBlockNode(&blockMap[0][0].block.BlockHeader),
636                                         mustCreateBlockNode(&blockMap[1][0].block.BlockHeader, &blockMap[0][0].block.BlockHeader),
637                                         mustCreateBlockNode(&blockMap[2][2].block.BlockHeader, &blockMap[1][0].block.BlockHeader, &blockMap[0][0].block.BlockHeader),
638                                 },
639                         ),
640                         wantOrphanManage: protocol.NewOrphanManage(),
641                         wantIsOrphan:     false,
642                         wantError:        false,
643                 },
644                 {
645                         desc:     "attach a block with issuance transaction normally",
646                         newBlock: blockMap[2][3].block,
647                         initStore: createStoreItems([]int{0, 1}, []*attachBlock{blockMap[0][0], blockMap[1][0]}, &storeItem{
648                                 key: database.CalcUtxoKey(hashPtr(testutil.MustDecodeHash("c93b687f98d039046cd2afd514c62f5d1c2c3b0804e4845b00a33e736ef48a33"))),
649                                 val: &storage.UtxoEntry{IsCoinBase: false, BlockHeight: 1, Spent: false},
650                         }),
651                         wantStore: createStoreItems([]int{0, 1, 2}, []*attachBlock{blockMap[0][0], blockMap[1][0], blockMap[2][3]}, &storeItem{
652                                 key: database.CalcUtxoKey(hashPtr(testutil.MustDecodeHash("c93b687f98d039046cd2afd514c62f5d1c2c3b0804e4845b00a33e736ef48a33"))),
653                                 val: &storage.UtxoEntry{IsCoinBase: false, BlockHeight: 1, Spent: false},
654                         }),
655                         wantBlockIndex: state.NewBlockIndexWithData(
656                                 map[bc.Hash]*state.BlockNode{
657                                         blockMap[0][0].block.Hash(): mustCreateBlockNode(&blockMap[0][0].block.BlockHeader),
658                                         blockMap[1][0].block.Hash(): mustCreateBlockNode(&blockMap[1][0].block.BlockHeader, &blockMap[0][0].block.BlockHeader),
659                                         blockMap[2][3].block.Hash(): mustCreateBlockNode(&blockMap[2][3].block.BlockHeader, &blockMap[1][0].block.BlockHeader, &blockMap[0][0].block.BlockHeader),
660                                 },
661                                 []*state.BlockNode{
662                                         mustCreateBlockNode(&blockMap[0][0].block.BlockHeader),
663                                         mustCreateBlockNode(&blockMap[1][0].block.BlockHeader, &blockMap[0][0].block.BlockHeader),
664                                         mustCreateBlockNode(&blockMap[2][3].block.BlockHeader, &blockMap[1][0].block.BlockHeader, &blockMap[0][0].block.BlockHeader),
665                                 },
666                         ),
667                         wantOrphanManage: protocol.NewOrphanManage(),
668                         wantIsOrphan:     false,
669                         wantError:        false,
670                 },
671                 {
672                         desc:     "attach a block with issuance transaction but status fail is true",
673                         newBlock: blockMap[2][4].block,
674                         initStore: createStoreItems([]int{0, 1}, []*attachBlock{blockMap[0][0], blockMap[1][0]}, &storeItem{
675                                 key: database.CalcUtxoKey(hashPtr(testutil.MustDecodeHash("c93b687f98d039046cd2afd514c62f5d1c2c3b0804e4845b00a33e736ef48a33"))),
676                                 val: &storage.UtxoEntry{IsCoinBase: false, BlockHeight: 1, Spent: false},
677                         }),
678                         wantStore: createStoreItems([]int{0, 1, 2}, []*attachBlock{blockMap[0][0], blockMap[1][0], blockMap[2][4]}, &storeItem{
679                                 key: database.CalcUtxoKey(hashPtr(testutil.MustDecodeHash("c93b687f98d039046cd2afd514c62f5d1c2c3b0804e4845b00a33e736ef48a33"))),
680                                 val: &storage.UtxoEntry{IsCoinBase: false, BlockHeight: 1, Spent: false},
681                         }),
682                         wantBlockIndex: state.NewBlockIndexWithData(
683                                 map[bc.Hash]*state.BlockNode{
684                                         blockMap[0][0].block.Hash(): mustCreateBlockNode(&blockMap[0][0].block.BlockHeader),
685                                         blockMap[1][0].block.Hash(): mustCreateBlockNode(&blockMap[1][0].block.BlockHeader, &blockMap[0][0].block.BlockHeader),
686                                         blockMap[2][4].block.Hash(): mustCreateBlockNode(&blockMap[2][4].block.BlockHeader, &blockMap[1][0].block.BlockHeader, &blockMap[0][0].block.BlockHeader),
687                                 },
688                                 []*state.BlockNode{
689                                         mustCreateBlockNode(&blockMap[0][0].block.BlockHeader),
690                                         mustCreateBlockNode(&blockMap[1][0].block.BlockHeader, &blockMap[0][0].block.BlockHeader),
691                                         mustCreateBlockNode(&blockMap[2][4].block.BlockHeader, &blockMap[1][0].block.BlockHeader, &blockMap[0][0].block.BlockHeader),
692                                 },
693                         ),
694                         wantOrphanManage: protocol.NewOrphanManage(),
695                         wantIsOrphan:     false,
696                         wantError:        false,
697                 },
698                 {
699                         desc:     "attach a block with non btm transaction",
700                         newBlock: blockMap[2][5].block,
701                         initStore: createStoreItems([]int{0, 1}, []*attachBlock{blockMap[0][0], blockMap[1][0]}, &storeItem{
702                                 key: database.CalcUtxoKey(hashPtr(testutil.MustDecodeHash("be164edbce8bcd1d890c1164541b8418fdcb257499757d3b88561bca06e97e29"))),
703                                 val: &storage.UtxoEntry{IsCoinBase: false, BlockHeight: 1, Spent: false},
704                         }, &storeItem{
705                                 key: database.CalcUtxoKey(hashPtr(testutil.MustDecodeHash("c93b687f98d039046cd2afd514c62f5d1c2c3b0804e4845b00a33e736ef48a33"))),
706                                 val: &storage.UtxoEntry{IsCoinBase: false, BlockHeight: 1, Spent: false},
707                         }),
708                         wantStore: createStoreItems([]int{0, 1, 2}, []*attachBlock{blockMap[0][0], blockMap[1][0], blockMap[2][5]}, &storeItem{
709                                 key: database.CalcUtxoKey(hashPtr(testutil.MustDecodeHash("be164edbce8bcd1d890c1164541b8418fdcb257499757d3b88561bca06e97e29"))),
710                                 val: &storage.UtxoEntry{IsCoinBase: false, BlockHeight: 1, Spent: false},
711                         }, &storeItem{
712                                 key: database.CalcUtxoKey(hashPtr(testutil.MustDecodeHash("c93b687f98d039046cd2afd514c62f5d1c2c3b0804e4845b00a33e736ef48a33"))),
713                                 val: &storage.UtxoEntry{IsCoinBase: false, BlockHeight: 1, Spent: false},
714                         }),
715                         wantBlockIndex: state.NewBlockIndexWithData(
716                                 map[bc.Hash]*state.BlockNode{
717                                         blockMap[0][0].block.Hash(): mustCreateBlockNode(&blockMap[0][0].block.BlockHeader),
718                                         blockMap[1][0].block.Hash(): mustCreateBlockNode(&blockMap[1][0].block.BlockHeader, &blockMap[0][0].block.BlockHeader),
719                                         blockMap[2][5].block.Hash(): mustCreateBlockNode(&blockMap[2][5].block.BlockHeader, &blockMap[1][0].block.BlockHeader, &blockMap[0][0].block.BlockHeader),
720                                 },
721                                 []*state.BlockNode{
722                                         mustCreateBlockNode(&blockMap[0][0].block.BlockHeader),
723                                         mustCreateBlockNode(&blockMap[1][0].block.BlockHeader, &blockMap[0][0].block.BlockHeader),
724                                         mustCreateBlockNode(&blockMap[2][5].block.BlockHeader, &blockMap[1][0].block.BlockHeader, &blockMap[0][0].block.BlockHeader),
725                                 },
726                         ),
727                         wantOrphanManage: protocol.NewOrphanManage(),
728                         wantIsOrphan:     false,
729                         wantError:        false,
730                 },
731                 {
732                         desc:     "attach a block with non btm transaction but status fail is true",
733                         newBlock: blockMap[2][6].block,
734                         initStore: createStoreItems([]int{0, 1}, []*attachBlock{blockMap[0][0], blockMap[1][0]}, &storeItem{
735                                 key: database.CalcUtxoKey(hashPtr(testutil.MustDecodeHash("be164edbce8bcd1d890c1164541b8418fdcb257499757d3b88561bca06e97e29"))),
736                                 val: &storage.UtxoEntry{IsCoinBase: false, BlockHeight: 1, Spent: false},
737                         }, &storeItem{
738                                 key: database.CalcUtxoKey(hashPtr(testutil.MustDecodeHash("c93b687f98d039046cd2afd514c62f5d1c2c3b0804e4845b00a33e736ef48a33"))),
739                                 val: &storage.UtxoEntry{IsCoinBase: false, BlockHeight: 1, Spent: false},
740                         }),
741                         wantStore: createStoreItems([]int{0, 1, 2}, []*attachBlock{blockMap[0][0], blockMap[1][0], blockMap[2][6]}, &storeItem{
742                                 key: database.CalcUtxoKey(hashPtr(testutil.MustDecodeHash("be164edbce8bcd1d890c1164541b8418fdcb257499757d3b88561bca06e97e29"))),
743                                 val: &storage.UtxoEntry{IsCoinBase: false, BlockHeight: 1, Spent: false},
744                         }, &storeItem{
745                                 key: database.CalcUtxoKey(hashPtr(testutil.MustDecodeHash("c93b687f98d039046cd2afd514c62f5d1c2c3b0804e4845b00a33e736ef48a33"))),
746                                 val: &storage.UtxoEntry{IsCoinBase: false, BlockHeight: 1, Spent: false},
747                         }),
748                         wantBlockIndex: state.NewBlockIndexWithData(
749                                 map[bc.Hash]*state.BlockNode{
750                                         blockMap[0][0].block.Hash(): mustCreateBlockNode(&blockMap[0][0].block.BlockHeader),
751                                         blockMap[1][0].block.Hash(): mustCreateBlockNode(&blockMap[1][0].block.BlockHeader, &blockMap[0][0].block.BlockHeader),
752                                         blockMap[2][6].block.Hash(): mustCreateBlockNode(&blockMap[2][6].block.BlockHeader, &blockMap[1][0].block.BlockHeader, &blockMap[0][0].block.BlockHeader),
753                                 },
754                                 []*state.BlockNode{
755                                         mustCreateBlockNode(&blockMap[0][0].block.BlockHeader),
756                                         mustCreateBlockNode(&blockMap[1][0].block.BlockHeader, &blockMap[0][0].block.BlockHeader),
757                                         mustCreateBlockNode(&blockMap[2][6].block.BlockHeader, &blockMap[1][0].block.BlockHeader, &blockMap[0][0].block.BlockHeader),
758                                 },
759                         ),
760                         wantOrphanManage: protocol.NewOrphanManage(),
761                         wantIsOrphan:     false,
762                         wantError:        false,
763                 },
764                 {
765                         desc:      "rollback a block only has coinbase transaction",
766                         newBlock:  blockMap[2][0].block,
767                         initStore: createStoreItems([]int{0, 2}, []*attachBlock{blockMap[0][0], blockMap[1][0], blockMap[1][1]}),
768                         wantStore: createStoreItems([]int{0, 1, 3}, []*attachBlock{blockMap[0][0], blockMap[1][0], blockMap[1][1], blockMap[2][0]}),
769                         wantBlockIndex: state.NewBlockIndexWithData(
770                                 map[bc.Hash]*state.BlockNode{
771                                         blockMap[0][0].block.Hash(): mustCreateBlockNode(&blockMap[0][0].block.BlockHeader),
772                                         blockMap[1][0].block.Hash(): mustCreateBlockNode(&blockMap[1][0].block.BlockHeader, &blockMap[0][0].block.BlockHeader),
773                                         blockMap[1][1].block.Hash(): mustCreateBlockNode(&blockMap[1][1].block.BlockHeader, &blockMap[0][0].block.BlockHeader),
774                                         blockMap[2][0].block.Hash(): mustCreateBlockNode(&blockMap[2][0].block.BlockHeader, &blockMap[1][0].block.BlockHeader, &blockMap[0][0].block.BlockHeader),
775                                 },
776                                 []*state.BlockNode{
777                                         mustCreateBlockNode(&blockMap[0][0].block.BlockHeader),
778                                         mustCreateBlockNode(&blockMap[1][0].block.BlockHeader, &blockMap[0][0].block.BlockHeader),
779                                         mustCreateBlockNode(&blockMap[2][0].block.BlockHeader, &blockMap[1][0].block.BlockHeader, &blockMap[0][0].block.BlockHeader),
780                                 },
781                         ),
782                         wantOrphanManage: protocol.NewOrphanManage(),
783                         wantIsOrphan:     false,
784                         wantError:        false,
785                 },
786                 {
787                         desc:     "rollback a block has spend btm transaction",
788                         newBlock: blockMap[3][0].block,
789                         initStore: createStoreItems([]int{0, 1, 3}, []*attachBlock{blockMap[0][0], blockMap[1][0], blockMap[2][0], blockMap[2][1]}, &storeItem{
790                                 key: database.CalcUtxoKey(hashPtr(testutil.MustDecodeHash("c93b687f98d039046cd2afd514c62f5d1c2c3b0804e4845b00a33e736ef48a33"))),
791                                 val: &storage.UtxoEntry{IsCoinBase: false, BlockHeight: 1, Spent: false},
792                         }),
793                         wantStore: createStoreItems([]int{0, 1, 2, 4}, []*attachBlock{blockMap[0][0], blockMap[1][0], blockMap[2][0], blockMap[2][1], blockMap[3][0]}, &storeItem{
794                                 key: database.CalcUtxoKey(hashPtr(testutil.MustDecodeHash("c93b687f98d039046cd2afd514c62f5d1c2c3b0804e4845b00a33e736ef48a33"))),
795                                 val: &storage.UtxoEntry{IsCoinBase: false, BlockHeight: 0, Spent: false},
796                         }),
797                         wantBlockIndex: state.NewBlockIndexWithData(
798                                 map[bc.Hash]*state.BlockNode{
799                                         blockMap[0][0].block.Hash(): mustCreateBlockNode(&blockMap[0][0].block.BlockHeader),
800                                         blockMap[1][0].block.Hash(): mustCreateBlockNode(&blockMap[1][0].block.BlockHeader, &blockMap[0][0].block.BlockHeader),
801                                         blockMap[2][0].block.Hash(): mustCreateBlockNode(&blockMap[2][0].block.BlockHeader, &blockMap[1][0].block.BlockHeader, &blockMap[0][0].block.BlockHeader),
802                                         blockMap[2][1].block.Hash(): mustCreateBlockNode(&blockMap[2][1].block.BlockHeader, &blockMap[1][0].block.BlockHeader, &blockMap[0][0].block.BlockHeader),
803                                         blockMap[3][0].block.Hash(): mustCreateBlockNode(&blockMap[3][0].block.BlockHeader, &blockMap[2][0].block.BlockHeader, &blockMap[1][0].block.BlockHeader, &blockMap[0][0].block.BlockHeader),
804                                 },
805                                 []*state.BlockNode{
806                                         mustCreateBlockNode(&blockMap[0][0].block.BlockHeader),
807                                         mustCreateBlockNode(&blockMap[1][0].block.BlockHeader, &blockMap[0][0].block.BlockHeader),
808                                         mustCreateBlockNode(&blockMap[2][0].block.BlockHeader, &blockMap[1][0].block.BlockHeader, &blockMap[0][0].block.BlockHeader),
809                                         mustCreateBlockNode(&blockMap[3][0].block.BlockHeader, &blockMap[2][0].block.BlockHeader, &blockMap[1][0].block.BlockHeader, &blockMap[0][0].block.BlockHeader),
810                                 },
811                         ),
812                         wantOrphanManage: protocol.NewOrphanManage(),
813                         wantIsOrphan:     false,
814                         wantError:        false,
815                 },
816                 {
817                         desc:     "rollback a block has issuance transaction",
818                         newBlock: blockMap[3][0].block,
819                         initStore: createStoreItems([]int{0, 1, 3}, []*attachBlock{blockMap[0][0], blockMap[1][0], blockMap[2][0], blockMap[2][3]}, &storeItem{
820                                 key: database.CalcUtxoKey(hashPtr(testutil.MustDecodeHash("c93b687f98d039046cd2afd514c62f5d1c2c3b0804e4845b00a33e736ef48a33"))),
821                                 val: &storage.UtxoEntry{IsCoinBase: false, BlockHeight: 1, Spent: false},
822                         }),
823                         wantStore: createStoreItems([]int{0, 1, 2, 4}, []*attachBlock{blockMap[0][0], blockMap[1][0], blockMap[2][0], blockMap[2][3], blockMap[3][0]}, &storeItem{
824                                 key: database.CalcUtxoKey(hashPtr(testutil.MustDecodeHash("c93b687f98d039046cd2afd514c62f5d1c2c3b0804e4845b00a33e736ef48a33"))),
825                                 val: &storage.UtxoEntry{IsCoinBase: false, BlockHeight: 0, Spent: false},
826                         }),
827                         wantBlockIndex: state.NewBlockIndexWithData(
828                                 map[bc.Hash]*state.BlockNode{
829                                         blockMap[0][0].block.Hash(): mustCreateBlockNode(&blockMap[0][0].block.BlockHeader),
830                                         blockMap[1][0].block.Hash(): mustCreateBlockNode(&blockMap[1][0].block.BlockHeader, &blockMap[0][0].block.BlockHeader),
831                                         blockMap[2][0].block.Hash(): mustCreateBlockNode(&blockMap[2][0].block.BlockHeader, &blockMap[1][0].block.BlockHeader, &blockMap[0][0].block.BlockHeader),
832                                         blockMap[2][3].block.Hash(): mustCreateBlockNode(&blockMap[2][3].block.BlockHeader, &blockMap[1][0].block.BlockHeader, &blockMap[0][0].block.BlockHeader),
833                                         blockMap[3][0].block.Hash(): mustCreateBlockNode(&blockMap[3][0].block.BlockHeader, &blockMap[2][0].block.BlockHeader, &blockMap[1][0].block.BlockHeader, &blockMap[0][0].block.BlockHeader),
834                                 },
835                                 []*state.BlockNode{
836                                         mustCreateBlockNode(&blockMap[0][0].block.BlockHeader),
837                                         mustCreateBlockNode(&blockMap[1][0].block.BlockHeader, &blockMap[0][0].block.BlockHeader),
838                                         mustCreateBlockNode(&blockMap[2][0].block.BlockHeader, &blockMap[1][0].block.BlockHeader, &blockMap[0][0].block.BlockHeader),
839                                         mustCreateBlockNode(&blockMap[3][0].block.BlockHeader, &blockMap[2][0].block.BlockHeader, &blockMap[1][0].block.BlockHeader, &blockMap[0][0].block.BlockHeader),
840                                 },
841                         ),
842                         wantOrphanManage: protocol.NewOrphanManage(),
843                         wantIsOrphan:     false,
844                         wantError:        false,
845                 },
846                 {
847                         desc:     "rollback a block has issuance transaction but status fail is true",
848                         newBlock: blockMap[3][0].block,
849                         initStore: createStoreItems([]int{0, 1, 3}, []*attachBlock{blockMap[0][0], blockMap[1][0], blockMap[2][0], blockMap[2][4]}, &storeItem{
850                                 key: database.CalcUtxoKey(hashPtr(testutil.MustDecodeHash("c93b687f98d039046cd2afd514c62f5d1c2c3b0804e4845b00a33e736ef48a33"))),
851                                 val: &storage.UtxoEntry{IsCoinBase: false, BlockHeight: 1, Spent: false},
852                         }),
853                         wantStore: createStoreItems([]int{0, 1, 2, 4}, []*attachBlock{blockMap[0][0], blockMap[1][0], blockMap[2][0], blockMap[2][4], blockMap[3][0]}, &storeItem{
854                                 key: database.CalcUtxoKey(hashPtr(testutil.MustDecodeHash("c93b687f98d039046cd2afd514c62f5d1c2c3b0804e4845b00a33e736ef48a33"))),
855                                 val: &storage.UtxoEntry{IsCoinBase: false, BlockHeight: 0, Spent: false},
856                         }),
857                         wantBlockIndex: state.NewBlockIndexWithData(
858                                 map[bc.Hash]*state.BlockNode{
859                                         blockMap[0][0].block.Hash(): mustCreateBlockNode(&blockMap[0][0].block.BlockHeader),
860                                         blockMap[1][0].block.Hash(): mustCreateBlockNode(&blockMap[1][0].block.BlockHeader, &blockMap[0][0].block.BlockHeader),
861                                         blockMap[2][0].block.Hash(): mustCreateBlockNode(&blockMap[2][0].block.BlockHeader, &blockMap[1][0].block.BlockHeader, &blockMap[0][0].block.BlockHeader),
862                                         blockMap[2][4].block.Hash(): mustCreateBlockNode(&blockMap[2][4].block.BlockHeader, &blockMap[1][0].block.BlockHeader, &blockMap[0][0].block.BlockHeader),
863                                         blockMap[3][0].block.Hash(): mustCreateBlockNode(&blockMap[3][0].block.BlockHeader, &blockMap[2][0].block.BlockHeader, &blockMap[1][0].block.BlockHeader, &blockMap[0][0].block.BlockHeader),
864                                 },
865                                 []*state.BlockNode{
866                                         mustCreateBlockNode(&blockMap[0][0].block.BlockHeader),
867                                         mustCreateBlockNode(&blockMap[1][0].block.BlockHeader, &blockMap[0][0].block.BlockHeader),
868                                         mustCreateBlockNode(&blockMap[2][0].block.BlockHeader, &blockMap[1][0].block.BlockHeader, &blockMap[0][0].block.BlockHeader),
869                                         mustCreateBlockNode(&blockMap[3][0].block.BlockHeader, &blockMap[2][0].block.BlockHeader, &blockMap[1][0].block.BlockHeader, &blockMap[0][0].block.BlockHeader),
870                                 },
871                         ),
872                         wantOrphanManage: protocol.NewOrphanManage(),
873                         wantIsOrphan:     false,
874                         wantError:        false,
875                 },
876                 {
877                         desc:     "rollback a block has spend non btm",
878                         newBlock: blockMap[3][0].block,
879                         initStore: createStoreItems([]int{0, 1, 3}, []*attachBlock{blockMap[0][0], blockMap[1][0], blockMap[2][0], blockMap[2][5]}, &storeItem{
880                                 key: database.CalcUtxoKey(hashPtr(testutil.MustDecodeHash("c93b687f98d039046cd2afd514c62f5d1c2c3b0804e4845b00a33e736ef48a33"))),
881                                 val: &storage.UtxoEntry{IsCoinBase: false, BlockHeight: 1, Spent: false},
882                         }, &storeItem{
883                                 key: database.CalcUtxoKey(hashPtr(testutil.MustDecodeHash("be164edbce8bcd1d890c1164541b8418fdcb257499757d3b88561bca06e97e29"))),
884                                 val: &storage.UtxoEntry{IsCoinBase: false, BlockHeight: 1, Spent: false},
885                         }),
886                         wantStore: createStoreItems([]int{0, 1, 2, 4}, []*attachBlock{blockMap[0][0], blockMap[1][0], blockMap[2][0], blockMap[2][5], blockMap[3][0]}, &storeItem{
887                                 key: database.CalcUtxoKey(hashPtr(testutil.MustDecodeHash("c93b687f98d039046cd2afd514c62f5d1c2c3b0804e4845b00a33e736ef48a33"))),
888                                 val: &storage.UtxoEntry{IsCoinBase: false, BlockHeight: 0, Spent: false},
889                         }, &storeItem{
890                                 key: database.CalcUtxoKey(hashPtr(testutil.MustDecodeHash("be164edbce8bcd1d890c1164541b8418fdcb257499757d3b88561bca06e97e29"))),
891                                 val: &storage.UtxoEntry{IsCoinBase: false, BlockHeight: 0, Spent: false},
892                         }),
893                         wantBlockIndex: state.NewBlockIndexWithData(
894                                 map[bc.Hash]*state.BlockNode{
895                                         blockMap[0][0].block.Hash(): mustCreateBlockNode(&blockMap[0][0].block.BlockHeader),
896                                         blockMap[1][0].block.Hash(): mustCreateBlockNode(&blockMap[1][0].block.BlockHeader, &blockMap[0][0].block.BlockHeader),
897                                         blockMap[2][0].block.Hash(): mustCreateBlockNode(&blockMap[2][0].block.BlockHeader, &blockMap[1][0].block.BlockHeader, &blockMap[0][0].block.BlockHeader),
898                                         blockMap[2][5].block.Hash(): mustCreateBlockNode(&blockMap[2][5].block.BlockHeader, &blockMap[1][0].block.BlockHeader, &blockMap[0][0].block.BlockHeader),
899                                         blockMap[3][0].block.Hash(): mustCreateBlockNode(&blockMap[3][0].block.BlockHeader, &blockMap[2][0].block.BlockHeader, &blockMap[1][0].block.BlockHeader, &blockMap[0][0].block.BlockHeader),
900                                 },
901                                 []*state.BlockNode{
902                                         mustCreateBlockNode(&blockMap[0][0].block.BlockHeader),
903                                         mustCreateBlockNode(&blockMap[1][0].block.BlockHeader, &blockMap[0][0].block.BlockHeader),
904                                         mustCreateBlockNode(&blockMap[2][0].block.BlockHeader, &blockMap[1][0].block.BlockHeader, &blockMap[0][0].block.BlockHeader),
905                                         mustCreateBlockNode(&blockMap[3][0].block.BlockHeader, &blockMap[2][0].block.BlockHeader, &blockMap[1][0].block.BlockHeader, &blockMap[0][0].block.BlockHeader),
906                                 },
907                         ),
908                         wantOrphanManage: protocol.NewOrphanManage(),
909                         wantIsOrphan:     false,
910                         wantError:        false,
911                 },
912                 {
913                         desc:     "rollback a block has spend non btm but status fail is true",
914                         newBlock: blockMap[3][0].block,
915                         initStore: createStoreItems([]int{0, 1, 3}, []*attachBlock{blockMap[0][0], blockMap[1][0], blockMap[2][0], blockMap[2][6]}, &storeItem{
916                                 key: database.CalcUtxoKey(hashPtr(testutil.MustDecodeHash("c93b687f98d039046cd2afd514c62f5d1c2c3b0804e4845b00a33e736ef48a33"))),
917                                 val: &storage.UtxoEntry{IsCoinBase: false, BlockHeight: 1, Spent: false},
918                         }, &storeItem{
919                                 key: database.CalcUtxoKey(hashPtr(testutil.MustDecodeHash("be164edbce8bcd1d890c1164541b8418fdcb257499757d3b88561bca06e97e29"))),
920                                 val: &storage.UtxoEntry{IsCoinBase: false, BlockHeight: 1, Spent: false},
921                         }),
922                         wantStore: createStoreItems([]int{0, 1, 2, 4}, []*attachBlock{blockMap[0][0], blockMap[1][0], blockMap[2][0], blockMap[2][6], blockMap[3][0]}, &storeItem{
923                                 key: database.CalcUtxoKey(hashPtr(testutil.MustDecodeHash("c93b687f98d039046cd2afd514c62f5d1c2c3b0804e4845b00a33e736ef48a33"))),
924                                 val: &storage.UtxoEntry{IsCoinBase: false, BlockHeight: 0, Spent: false},
925                         }, &storeItem{
926                                 key: database.CalcUtxoKey(hashPtr(testutil.MustDecodeHash("be164edbce8bcd1d890c1164541b8418fdcb257499757d3b88561bca06e97e29"))),
927                                 val: &storage.UtxoEntry{IsCoinBase: false, BlockHeight: 1, Spent: false},
928                         }),
929                         wantBlockIndex: state.NewBlockIndexWithData(
930                                 map[bc.Hash]*state.BlockNode{
931                                         blockMap[0][0].block.Hash(): mustCreateBlockNode(&blockMap[0][0].block.BlockHeader),
932                                         blockMap[1][0].block.Hash(): mustCreateBlockNode(&blockMap[1][0].block.BlockHeader, &blockMap[0][0].block.BlockHeader),
933                                         blockMap[2][0].block.Hash(): mustCreateBlockNode(&blockMap[2][0].block.BlockHeader, &blockMap[1][0].block.BlockHeader, &blockMap[0][0].block.BlockHeader),
934                                         blockMap[2][6].block.Hash(): mustCreateBlockNode(&blockMap[2][6].block.BlockHeader, &blockMap[1][0].block.BlockHeader, &blockMap[0][0].block.BlockHeader),
935                                         blockMap[3][0].block.Hash(): mustCreateBlockNode(&blockMap[3][0].block.BlockHeader, &blockMap[2][0].block.BlockHeader, &blockMap[1][0].block.BlockHeader, &blockMap[0][0].block.BlockHeader),
936                                 },
937                                 []*state.BlockNode{
938                                         mustCreateBlockNode(&blockMap[0][0].block.BlockHeader),
939                                         mustCreateBlockNode(&blockMap[1][0].block.BlockHeader, &blockMap[0][0].block.BlockHeader),
940                                         mustCreateBlockNode(&blockMap[2][0].block.BlockHeader, &blockMap[1][0].block.BlockHeader, &blockMap[0][0].block.BlockHeader),
941                                         mustCreateBlockNode(&blockMap[3][0].block.BlockHeader, &blockMap[2][0].block.BlockHeader, &blockMap[1][0].block.BlockHeader, &blockMap[0][0].block.BlockHeader),
942                                 },
943                         ),
944                         wantOrphanManage: protocol.NewOrphanManage(),
945                         wantIsOrphan:     false,
946                         wantError:        false,
947                 },
948                 {
949                         desc:      "rollback a block only has coinbase tx, and from orphan manage",
950                         newBlock:  blockMap[1][0].block,
951                         initStore: createStoreItems([]int{0, 1}, []*attachBlock{blockMap[0][0], blockMap[1][1]}),
952                         initOrphanManage: protocol.NewOrphanManageWithData(
953                                 map[bc.Hash]*protocol.OrphanBlock{
954                                         blockMap[2][0].block.Hash(): protocol.NewOrphanBlock(blockMap[2][0].block, time.Now().Add(time.Minute*60)),
955                                 },
956                                 map[bc.Hash][]*bc.Hash{blockMap[2][0].block.PreviousBlockHash: {hashPtr(blockMap[2][0].block.Hash())}},
957                         ),
958                         wantStore: createStoreItems([]int{0, 1, 3}, []*attachBlock{blockMap[0][0], blockMap[1][0], blockMap[1][1], blockMap[2][0]}),
959                         wantBlockIndex: state.NewBlockIndexWithData(
960                                 map[bc.Hash]*state.BlockNode{
961                                         blockMap[0][0].block.Hash(): mustCreateBlockNode(&blockMap[0][0].block.BlockHeader),
962                                         blockMap[1][0].block.Hash(): mustCreateBlockNode(&blockMap[1][0].block.BlockHeader, &blockMap[0][0].block.BlockHeader),
963                                         blockMap[1][1].block.Hash(): mustCreateBlockNode(&blockMap[1][1].block.BlockHeader, &blockMap[0][0].block.BlockHeader),
964                                         blockMap[2][0].block.Hash(): mustCreateBlockNode(&blockMap[2][0].block.BlockHeader, &blockMap[1][0].block.BlockHeader, &blockMap[0][0].block.BlockHeader),
965                                 },
966                                 []*state.BlockNode{
967                                         mustCreateBlockNode(&blockMap[0][0].block.BlockHeader),
968                                         mustCreateBlockNode(&blockMap[1][0].block.BlockHeader, &blockMap[0][0].block.BlockHeader),
969                                         mustCreateBlockNode(&blockMap[2][0].block.BlockHeader, &blockMap[1][0].block.BlockHeader, &blockMap[0][0].block.BlockHeader),
970                                 },
971                         ),
972                         wantOrphanManage: protocol.NewOrphanManage(),
973                         wantIsOrphan:     false,
974                         wantError:        false,
975                 },
976                 {
977                         desc:     "rollback a block has spend btm tx, and from orphan manage",
978                         newBlock: blockMap[2][0].block,
979                         initStore: createStoreItems([]int{0, 1, 2}, []*attachBlock{blockMap[0][0], blockMap[1][0], blockMap[2][1]}, &storeItem{
980                                 key: database.CalcUtxoKey(hashPtr(testutil.MustDecodeHash("c93b687f98d039046cd2afd514c62f5d1c2c3b0804e4845b00a33e736ef48a33"))),
981                                 val: &storage.UtxoEntry{IsCoinBase: false, BlockHeight: 1, Spent: false},
982                         }),
983                         initOrphanManage: protocol.NewOrphanManageWithData(
984                                 map[bc.Hash]*protocol.OrphanBlock{
985                                         blockMap[3][0].block.Hash(): protocol.NewOrphanBlock(blockMap[3][0].block, time.Now().Add(time.Minute*60)),
986                                 },
987                                 map[bc.Hash][]*bc.Hash{blockMap[3][0].block.PreviousBlockHash: {hashPtr(blockMap[3][0].block.Hash())}},
988                         ),
989                         wantStore: createStoreItems([]int{0, 1, 2, 4}, []*attachBlock{blockMap[0][0], blockMap[1][0], blockMap[2][0], blockMap[2][1], blockMap[3][0]}, &storeItem{
990                                 key: database.CalcUtxoKey(hashPtr(testutil.MustDecodeHash("c93b687f98d039046cd2afd514c62f5d1c2c3b0804e4845b00a33e736ef48a33"))),
991                                 val: &storage.UtxoEntry{IsCoinBase: false, BlockHeight: 0, Spent: false},
992                         }),
993                         wantBlockIndex: state.NewBlockIndexWithData(
994                                 map[bc.Hash]*state.BlockNode{
995                                         blockMap[0][0].block.Hash(): mustCreateBlockNode(&blockMap[0][0].block.BlockHeader),
996                                         blockMap[1][0].block.Hash(): mustCreateBlockNode(&blockMap[1][0].block.BlockHeader, &blockMap[0][0].block.BlockHeader),
997                                         blockMap[2][0].block.Hash(): mustCreateBlockNode(&blockMap[2][0].block.BlockHeader, &blockMap[1][0].block.BlockHeader, &blockMap[0][0].block.BlockHeader),
998                                         blockMap[2][1].block.Hash(): mustCreateBlockNode(&blockMap[2][1].block.BlockHeader, &blockMap[1][0].block.BlockHeader, &blockMap[0][0].block.BlockHeader),
999                                         blockMap[3][0].block.Hash(): mustCreateBlockNode(&blockMap[3][0].block.BlockHeader, &blockMap[2][0].block.BlockHeader, &blockMap[1][0].block.BlockHeader, &blockMap[0][0].block.BlockHeader),
1000                                 },
1001                                 []*state.BlockNode{
1002                                         mustCreateBlockNode(&blockMap[0][0].block.BlockHeader),
1003                                         mustCreateBlockNode(&blockMap[1][0].block.BlockHeader, &blockMap[0][0].block.BlockHeader),
1004                                         mustCreateBlockNode(&blockMap[2][0].block.BlockHeader, &blockMap[1][0].block.BlockHeader, &blockMap[0][0].block.BlockHeader),
1005                                         mustCreateBlockNode(&blockMap[3][0].block.BlockHeader, &blockMap[2][0].block.BlockHeader, &blockMap[1][0].block.BlockHeader, &blockMap[0][0].block.BlockHeader),
1006                                 },
1007                         ),
1008                         wantOrphanManage: protocol.NewOrphanManage(),
1009                         wantIsOrphan:     false,
1010                         wantError:        false,
1011                 },
1012                 {
1013                         desc:     "rollback a block has retire tx, and from orphan manage",
1014                         newBlock: blockMap[2][0].block,
1015                         initStore: createStoreItems([]int{0, 1, 2}, []*attachBlock{blockMap[0][0], blockMap[1][0], blockMap[2][2]}, &storeItem{
1016                                 key: database.CalcUtxoKey(hashPtr(testutil.MustDecodeHash("c93b687f98d039046cd2afd514c62f5d1c2c3b0804e4845b00a33e736ef48a33"))),
1017                                 val: &storage.UtxoEntry{IsCoinBase: false, BlockHeight: 1, Spent: false},
1018                         }),
1019                         initOrphanManage: protocol.NewOrphanManageWithData(
1020                                 map[bc.Hash]*protocol.OrphanBlock{
1021                                         blockMap[3][0].block.Hash(): protocol.NewOrphanBlock(blockMap[3][0].block, time.Now().Add(time.Minute*60)),
1022                                 },
1023                                 map[bc.Hash][]*bc.Hash{blockMap[3][0].block.PreviousBlockHash: {hashPtr(blockMap[3][0].block.Hash())}},
1024                         ),
1025                         wantStore: createStoreItems([]int{0, 1, 2, 4}, []*attachBlock{blockMap[0][0], blockMap[1][0], blockMap[2][0], blockMap[2][2], blockMap[3][0]}, &storeItem{
1026                                 key: database.CalcUtxoKey(hashPtr(testutil.MustDecodeHash("c93b687f98d039046cd2afd514c62f5d1c2c3b0804e4845b00a33e736ef48a33"))),
1027                                 val: &storage.UtxoEntry{IsCoinBase: false, BlockHeight: 0, Spent: false},
1028                         }),
1029                         wantBlockIndex: state.NewBlockIndexWithData(
1030                                 map[bc.Hash]*state.BlockNode{
1031                                         blockMap[0][0].block.Hash(): mustCreateBlockNode(&blockMap[0][0].block.BlockHeader),
1032                                         blockMap[1][0].block.Hash(): mustCreateBlockNode(&blockMap[1][0].block.BlockHeader, &blockMap[0][0].block.BlockHeader),
1033                                         blockMap[2][0].block.Hash(): mustCreateBlockNode(&blockMap[2][0].block.BlockHeader, &blockMap[1][0].block.BlockHeader, &blockMap[0][0].block.BlockHeader),
1034                                         blockMap[2][2].block.Hash(): mustCreateBlockNode(&blockMap[2][2].block.BlockHeader, &blockMap[1][0].block.BlockHeader, &blockMap[0][0].block.BlockHeader),
1035                                         blockMap[3][0].block.Hash(): mustCreateBlockNode(&blockMap[3][0].block.BlockHeader, &blockMap[2][0].block.BlockHeader, &blockMap[1][0].block.BlockHeader, &blockMap[0][0].block.BlockHeader),
1036                                 },
1037                                 []*state.BlockNode{
1038                                         mustCreateBlockNode(&blockMap[0][0].block.BlockHeader),
1039                                         mustCreateBlockNode(&blockMap[1][0].block.BlockHeader, &blockMap[0][0].block.BlockHeader),
1040                                         mustCreateBlockNode(&blockMap[2][0].block.BlockHeader, &blockMap[1][0].block.BlockHeader, &blockMap[0][0].block.BlockHeader),
1041                                         mustCreateBlockNode(&blockMap[3][0].block.BlockHeader, &blockMap[2][0].block.BlockHeader, &blockMap[1][0].block.BlockHeader, &blockMap[0][0].block.BlockHeader),
1042                                 },
1043                         ),
1044                         wantOrphanManage: protocol.NewOrphanManage(),
1045                         wantIsOrphan:     false,
1046                         wantError:        false,
1047                 },
1048                 {
1049                         desc:     "rollback a block has issuance tx, and from orphan manage",
1050                         newBlock: blockMap[2][0].block,
1051                         initStore: createStoreItems([]int{0, 1, 2}, []*attachBlock{blockMap[0][0], blockMap[1][0], blockMap[2][3]}, &storeItem{
1052                                 key: database.CalcUtxoKey(hashPtr(testutil.MustDecodeHash("c93b687f98d039046cd2afd514c62f5d1c2c3b0804e4845b00a33e736ef48a33"))),
1053                                 val: &storage.UtxoEntry{IsCoinBase: false, BlockHeight: 1, Spent: false},
1054                         }),
1055                         initOrphanManage: protocol.NewOrphanManageWithData(
1056                                 map[bc.Hash]*protocol.OrphanBlock{
1057                                         blockMap[3][0].block.Hash(): protocol.NewOrphanBlock(blockMap[3][0].block, time.Now().Add(time.Minute*60)),
1058                                 },
1059                                 map[bc.Hash][]*bc.Hash{blockMap[3][0].block.PreviousBlockHash: {hashPtr(blockMap[3][0].block.Hash())}},
1060                         ),
1061                         wantStore: createStoreItems([]int{0, 1, 2, 4}, []*attachBlock{blockMap[0][0], blockMap[1][0], blockMap[2][0], blockMap[2][3], blockMap[3][0]}, &storeItem{
1062                                 key: database.CalcUtxoKey(hashPtr(testutil.MustDecodeHash("c93b687f98d039046cd2afd514c62f5d1c2c3b0804e4845b00a33e736ef48a33"))),
1063                                 val: &storage.UtxoEntry{IsCoinBase: false, BlockHeight: 0, Spent: false},
1064                         }),
1065                         wantBlockIndex: state.NewBlockIndexWithData(
1066                                 map[bc.Hash]*state.BlockNode{
1067                                         blockMap[0][0].block.Hash(): mustCreateBlockNode(&blockMap[0][0].block.BlockHeader),
1068                                         blockMap[1][0].block.Hash(): mustCreateBlockNode(&blockMap[1][0].block.BlockHeader, &blockMap[0][0].block.BlockHeader),
1069                                         blockMap[2][0].block.Hash(): mustCreateBlockNode(&blockMap[2][0].block.BlockHeader, &blockMap[1][0].block.BlockHeader, &blockMap[0][0].block.BlockHeader),
1070                                         blockMap[2][3].block.Hash(): mustCreateBlockNode(&blockMap[2][3].block.BlockHeader, &blockMap[1][0].block.BlockHeader, &blockMap[0][0].block.BlockHeader),
1071                                         blockMap[3][0].block.Hash(): mustCreateBlockNode(&blockMap[3][0].block.BlockHeader, &blockMap[2][0].block.BlockHeader, &blockMap[1][0].block.BlockHeader, &blockMap[0][0].block.BlockHeader),
1072                                 },
1073                                 []*state.BlockNode{
1074                                         mustCreateBlockNode(&blockMap[0][0].block.BlockHeader),
1075                                         mustCreateBlockNode(&blockMap[1][0].block.BlockHeader, &blockMap[0][0].block.BlockHeader),
1076                                         mustCreateBlockNode(&blockMap[2][0].block.BlockHeader, &blockMap[1][0].block.BlockHeader, &blockMap[0][0].block.BlockHeader),
1077                                         mustCreateBlockNode(&blockMap[3][0].block.BlockHeader, &blockMap[2][0].block.BlockHeader, &blockMap[1][0].block.BlockHeader, &blockMap[0][0].block.BlockHeader),
1078                                 },
1079                         ),
1080                         wantOrphanManage: protocol.NewOrphanManage(),
1081                         wantIsOrphan:     false,
1082                         wantError:        false,
1083                 },
1084                 {
1085                         desc:     "rollback a block has non btm tx, and from orphan manage",
1086                         newBlock: blockMap[2][0].block,
1087                         initStore: createStoreItems([]int{0, 1, 2}, []*attachBlock{blockMap[0][0], blockMap[1][0], blockMap[2][5]}, &storeItem{
1088                                 key: database.CalcUtxoKey(hashPtr(testutil.MustDecodeHash("c93b687f98d039046cd2afd514c62f5d1c2c3b0804e4845b00a33e736ef48a33"))),
1089                                 val: &storage.UtxoEntry{IsCoinBase: false, BlockHeight: 1, Spent: false},
1090                         }, &storeItem{
1091                                 key: database.CalcUtxoKey(hashPtr(testutil.MustDecodeHash("be164edbce8bcd1d890c1164541b8418fdcb257499757d3b88561bca06e97e29"))),
1092                                 val: &storage.UtxoEntry{IsCoinBase: false, BlockHeight: 1, Spent: false},
1093                         }),
1094                         initOrphanManage: protocol.NewOrphanManageWithData(
1095                                 map[bc.Hash]*protocol.OrphanBlock{
1096                                         blockMap[3][0].block.Hash(): protocol.NewOrphanBlock(blockMap[3][0].block, time.Now().Add(time.Minute*60)),
1097                                 },
1098                                 map[bc.Hash][]*bc.Hash{blockMap[3][0].block.PreviousBlockHash: {hashPtr(blockMap[3][0].block.Hash())}},
1099                         ),
1100                         wantStore: createStoreItems([]int{0, 1, 2, 4}, []*attachBlock{blockMap[0][0], blockMap[1][0], blockMap[2][0], blockMap[2][5], blockMap[3][0]}, &storeItem{
1101                                 key: database.CalcUtxoKey(hashPtr(testutil.MustDecodeHash("c93b687f98d039046cd2afd514c62f5d1c2c3b0804e4845b00a33e736ef48a33"))),
1102                                 val: &storage.UtxoEntry{IsCoinBase: false, BlockHeight: 0, Spent: false},
1103                         }, &storeItem{
1104                                 key: database.CalcUtxoKey(hashPtr(testutil.MustDecodeHash("be164edbce8bcd1d890c1164541b8418fdcb257499757d3b88561bca06e97e29"))),
1105                                 val: &storage.UtxoEntry{IsCoinBase: false, BlockHeight: 0, Spent: false},
1106                         }),
1107                         wantBlockIndex: state.NewBlockIndexWithData(
1108                                 map[bc.Hash]*state.BlockNode{
1109                                         blockMap[0][0].block.Hash(): mustCreateBlockNode(&blockMap[0][0].block.BlockHeader),
1110                                         blockMap[1][0].block.Hash(): mustCreateBlockNode(&blockMap[1][0].block.BlockHeader, &blockMap[0][0].block.BlockHeader),
1111                                         blockMap[2][0].block.Hash(): mustCreateBlockNode(&blockMap[2][0].block.BlockHeader, &blockMap[1][0].block.BlockHeader, &blockMap[0][0].block.BlockHeader),
1112                                         blockMap[2][5].block.Hash(): mustCreateBlockNode(&blockMap[2][5].block.BlockHeader, &blockMap[1][0].block.BlockHeader, &blockMap[0][0].block.BlockHeader),
1113                                         blockMap[3][0].block.Hash(): mustCreateBlockNode(&blockMap[3][0].block.BlockHeader, &blockMap[2][0].block.BlockHeader, &blockMap[1][0].block.BlockHeader, &blockMap[0][0].block.BlockHeader),
1114                                 },
1115                                 []*state.BlockNode{
1116                                         mustCreateBlockNode(&blockMap[0][0].block.BlockHeader),
1117                                         mustCreateBlockNode(&blockMap[1][0].block.BlockHeader, &blockMap[0][0].block.BlockHeader),
1118                                         mustCreateBlockNode(&blockMap[2][0].block.BlockHeader, &blockMap[1][0].block.BlockHeader, &blockMap[0][0].block.BlockHeader),
1119                                         mustCreateBlockNode(&blockMap[3][0].block.BlockHeader, &blockMap[2][0].block.BlockHeader, &blockMap[1][0].block.BlockHeader, &blockMap[0][0].block.BlockHeader),
1120                                 },
1121                         ),
1122                         wantOrphanManage: protocol.NewOrphanManage(),
1123                         wantIsOrphan:     false,
1124                         wantError:        false,
1125                 },
1126         }
1127
1128         for _, c := range cases {
1129                 if err := c.Run(); err != nil {
1130                         panic(err)
1131                 }
1132         }
1133 }
1134
1135 func createStoreItems(mainChainIndexes []int, attachBlocks []*attachBlock, extralItem ...*storeItem) storeItems {
1136         var items storeItems
1137         for _, item := range extralItem {
1138                 items = append(items, item)
1139         }
1140
1141         mainChainIndexMap := make(map[int]interface{})
1142         for _, index := range mainChainIndexes {
1143                 mainChainIndexMap[index] = nil
1144         }
1145
1146         for i, attachBlock := range attachBlocks {
1147                 block := attachBlock.block
1148                 blockHash := block.Hash()
1149                 items = append(items, &storeItem{
1150                         key: database.CalcBlockKey(&blockHash),
1151                         val: block,
1152                 })
1153
1154                 items = append(items, &storeItem{
1155                         key: database.CalcTxStatusKey(&blockHash),
1156                         val: &bc.TransactionStatus{Version: 1, VerifyStatus: attachBlock.verifyResult},
1157                 })
1158                 items = append(items, &storeItem{
1159                         key: database.CalcBlockHeaderKey(block.Height, &blockHash),
1160                         val: block.BlockHeader,
1161                 })
1162
1163                 if _, ok := mainChainIndexMap[i]; !ok {
1164                         continue
1165                 }
1166
1167                 for i, tx := range block.Transactions {
1168                         statusFail := attachBlock.verifyResult[i].StatusFail
1169                         for _, input := range tx.Inputs {
1170                                 if statusFail && input.AssetID() != *consensus.BTMAssetID {
1171                                         continue
1172                                 }
1173
1174                                 if _, ok := input.TypedInput.(*types.SpendInput); !ok {
1175                                         continue
1176                                 }
1177                                 spendOutputID, err := input.SpentOutputID()
1178                                 if err != nil {
1179                                         panic(err)
1180                                 }
1181                                 index := spendUTXO(spendOutputID, items, block.Height)
1182                                 items = append(items[0:index], items[index+1:]...)
1183                         }
1184                         for j, output := range tx.Outputs {
1185                                 if statusFail && *tx.Outputs[j].AssetId != *consensus.BTMAssetID {
1186                                         continue
1187                                 }
1188                                 if output.ControlProgram[0] == 0x6a {
1189                                         continue
1190                                 }
1191                                 items = append(items, &storeItem{key: database.CalcUtxoKey(tx.Tx.ResultIds[j]),
1192                                         val: &storage.UtxoEntry{IsCoinBase: i == 0, BlockHeight: block.Height, Spent: false},
1193                                 })
1194                         }
1195                 }
1196         }
1197
1198         lastIndex := mainChainIndexes[len(mainChainIndexes)-1]
1199         betBlock := attachBlocks[lastIndex].block
1200         bestBlockHash := betBlock.Hash()
1201         items = append(items, &storeItem{
1202                 key: database.BlockStoreKey,
1203                 val: &protocol.BlockStoreState{Height: betBlock.Height, Hash: &bestBlockHash},
1204         })
1205         return items
1206 }
1207
1208 func hashPtr(hash bc.Hash) *bc.Hash {
1209         return &hash
1210 }
1211
1212 func mustCreateBlockNode(header *types.BlockHeader, parents ...*types.BlockHeader) *state.BlockNode {
1213         var parentNode *state.BlockNode
1214         for i := len(parents) - 1; i >= 0; i-- {
1215                 parentNode = mustNewBlockNode(parents[i], parentNode)
1216         }
1217         return mustNewBlockNode(header, parentNode)
1218 }
1219
1220 func mustPostProcessBlock() {
1221         for _, blocks := range blockMap {
1222                 for _, attachBlock := range blocks {
1223                         mustCalcMerkleRootHash(attachBlock)
1224                         mustFillTransactionSize(attachBlock.block)
1225                         sortSpendOutputID(attachBlock.block)
1226                 }
1227         }
1228 }
1229
1230 func mustCalcMerkleRootHash(attachBlock *attachBlock) {
1231         bcBlock := types.MapBlock(attachBlock.block)
1232         txStatusHash, err := types.TxStatusMerkleRoot(attachBlock.verifyResult)
1233         if err != nil {
1234                 panic("fail on calc genesis tx status merkle root")
1235         }
1236
1237         merkleRoot, err := types.TxMerkleRoot(bcBlock.Transactions)
1238         if err != nil {
1239                 panic("fail on calc genesis tx merkel root")
1240         }
1241
1242         attachBlock.block.TransactionStatusHash = txStatusHash
1243         attachBlock.block.TransactionsMerkleRoot = merkleRoot
1244 }
1245
1246 func mustFillTransactionSize(block *types.Block) {
1247         for _, tx := range block.Transactions {
1248                 bytes, err := tx.MarshalText()
1249                 if err != nil {
1250                         panic(err)
1251                 }
1252                 tx.TxData.SerializedSize = uint64(len(bytes) / 2)
1253                 tx.Tx.SerializedSize = uint64(len(bytes) / 2)
1254         }
1255 }
1256
1257 func mustNewBlockNode(h *types.BlockHeader, parent *state.BlockNode) *state.BlockNode {
1258         node, err := state.NewBlockNode(h, parent)
1259         if err != nil {
1260                 panic(err)
1261         }
1262         return node
1263 }
1264
1265 func spendUTXO(spendOutputID bc.Hash, items storeItems, blockHeight uint64) int {
1266         for i, item := range items {
1267                 utxo, ok := item.val.(*storage.UtxoEntry)
1268                 if !ok {
1269                         continue
1270                 }
1271                 if string(database.CalcUtxoKey(&spendOutputID)) != string(item.key) {
1272                         continue
1273                 }
1274                 if utxo.Spent || (utxo.IsCoinBase && utxo.BlockHeight+consensus.CoinbasePendingBlockNumber > blockHeight) {
1275                         panic("utxo can not be use")
1276                 }
1277                 utxo.Spent = true
1278                 return i
1279         }
1280         panic("can not find available utxo")
1281 }