github.com/Bytom/bytom@v1.1.2-0.20210127130405-ae40204c0b09/test/integration/block_integration_test.go (about)

     1  package integration
     2  
     3  import (
     4  	"testing"
     5  
     6  	"time"
     7  
     8  	"github.com/bytom/bytom/config"
     9  	"github.com/bytom/bytom/consensus"
    10  	"github.com/bytom/bytom/database"
    11  	"github.com/bytom/bytom/database/storage"
    12  	"github.com/bytom/bytom/protocol"
    13  	"github.com/bytom/bytom/protocol/bc"
    14  	"github.com/bytom/bytom/protocol/bc/types"
    15  	"github.com/bytom/bytom/protocol/state"
    16  	"github.com/bytom/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  }