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

     1  package utxo_view
     2  
     3  import (
     4  	"os"
     5  	"testing"
     6  
     7  	"github.com/bytom/bytom/testutil"
     8  
     9  	"github.com/golang/protobuf/proto"
    10  
    11  	"github.com/bytom/bytom/database"
    12  	"github.com/bytom/bytom/database/storage"
    13  	"github.com/bytom/bytom/protocol/bc"
    14  	"github.com/bytom/bytom/protocol/bc/types"
    15  	"github.com/bytom/bytom/protocol/state"
    16  	dbm "github.com/bytom/bytom/database/leveldb"
    17  )
    18  
    19  func TestAttachOrDetachBlocks(t *testing.T) {
    20  	cases := []struct {
    21  		desc           string
    22  		before         map[bc.Hash]*storage.UtxoEntry
    23  		want           map[bc.Hash]*storage.UtxoEntry
    24  		attachBlock    []*bc.Block
    25  		detachBlock    []*bc.Block
    26  		attachTxStatus []*bc.TransactionStatus
    27  		detachTxStatus []*bc.TransactionStatus
    28  	}{
    29  		{
    30  			desc:   "coinbase tx",
    31  			before: make(map[bc.Hash]*storage.UtxoEntry),
    32  			want:   map[bc.Hash]*storage.UtxoEntry{*newTx(mockBlocks[0].Transactions[0]).OutputHash(0): storage.NewUtxoEntry(true, mockBlocks[0].Block.Height, false)},
    33  			attachBlock: []*bc.Block{
    34  				types.MapBlock(&mockBlocks[0].Block),
    35  			},
    36  			attachTxStatus: []*bc.TransactionStatus{
    37  				&bc.TransactionStatus{VerifyStatus: []*bc.TxVerifyResult{
    38  					&bc.TxVerifyResult{StatusFail: false},
    39  				}},
    40  			},
    41  		},
    42  		{
    43  			desc: "Chain trading 3",
    44  			before: map[bc.Hash]*storage.UtxoEntry{
    45  				newTx(mockBlocks[1].Transactions[1]).getSpentOutputID(0): storage.NewUtxoEntry(false, mockBlocks[1].Height-1, false),
    46  			},
    47  			want: map[bc.Hash]*storage.UtxoEntry{
    48  				*newTx(mockBlocks[1].Transactions[0]).OutputHash(0): storage.NewUtxoEntry(true, mockBlocks[1].Height, false),
    49  				*newTx(mockBlocks[1].Transactions[1]).OutputHash(0): storage.NewUtxoEntry(false, mockBlocks[1].Height, false),
    50  				*newTx(mockBlocks[1].Transactions[2]).OutputHash(0): storage.NewUtxoEntry(false, mockBlocks[1].Height, false),
    51  				*newTx(mockBlocks[1].Transactions[3]).OutputHash(0): storage.NewUtxoEntry(false, mockBlocks[1].Height, false),
    52  				*newTx(mockBlocks[1].Transactions[3]).OutputHash(1): storage.NewUtxoEntry(false, mockBlocks[1].Height, false),
    53  			},
    54  			attachBlock: []*bc.Block{
    55  				types.MapBlock(&mockBlocks[1].Block),
    56  			},
    57  			attachTxStatus: []*bc.TransactionStatus{
    58  				&bc.TransactionStatus{VerifyStatus: []*bc.TxVerifyResult{
    59  					&bc.TxVerifyResult{StatusFail: false},
    60  					&bc.TxVerifyResult{StatusFail: false},
    61  					&bc.TxVerifyResult{StatusFail: false},
    62  					&bc.TxVerifyResult{StatusFail: false},
    63  				}},
    64  			},
    65  		},
    66  		{
    67  			desc: "detach 1 block, attach 2 block",
    68  			before: map[bc.Hash]*storage.UtxoEntry{
    69  				*newTx(mockBlocks[2].Transactions[0]).OutputHash(0): storage.NewUtxoEntry(true, mockBlocks[2].Height, false),
    70  				*newTx(mockBlocks[2].Transactions[1]).OutputHash(0): storage.NewUtxoEntry(false, mockBlocks[2].Height, false),
    71  				*newTx(mockBlocks[2].Transactions[1]).OutputHash(1): storage.NewUtxoEntry(false, mockBlocks[2].Height, false),
    72  			},
    73  			want: map[bc.Hash]*storage.UtxoEntry{
    74  				*newTx(mockBlocks[3].Transactions[0]).OutputHash(0): storage.NewUtxoEntry(true, mockBlocks[3].Height, false),
    75  				*newTx(mockBlocks[3].Transactions[1]).OutputHash(0): storage.NewUtxoEntry(false, mockBlocks[3].Height, false),
    76  
    77  				*newTx(mockBlocks[4].Transactions[0]).OutputHash(0): storage.NewUtxoEntry(true, mockBlocks[4].Height, false),
    78  				*newTx(mockBlocks[4].Transactions[1]).OutputHash(0): storage.NewUtxoEntry(false, mockBlocks[4].Height, false),
    79  				*newTx(mockBlocks[4].Transactions[1]).OutputHash(1): storage.NewUtxoEntry(false, mockBlocks[4].Height, false),
    80  			},
    81  			attachBlock: []*bc.Block{
    82  				types.MapBlock(&mockBlocks[3].Block),
    83  				types.MapBlock(&mockBlocks[4].Block),
    84  			},
    85  			detachBlock: []*bc.Block{
    86  				types.MapBlock(&mockBlocks[2].Block),
    87  			},
    88  			attachTxStatus: []*bc.TransactionStatus{
    89  				&bc.TransactionStatus{VerifyStatus: []*bc.TxVerifyResult{
    90  					&bc.TxVerifyResult{StatusFail: false},
    91  					&bc.TxVerifyResult{StatusFail: false},
    92  				}},
    93  				&bc.TransactionStatus{VerifyStatus: []*bc.TxVerifyResult{
    94  					&bc.TxVerifyResult{StatusFail: false},
    95  					&bc.TxVerifyResult{StatusFail: false},
    96  				}},
    97  			},
    98  			detachTxStatus: []*bc.TransactionStatus{
    99  				&bc.TransactionStatus{VerifyStatus: []*bc.TxVerifyResult{
   100  					&bc.TxVerifyResult{StatusFail: false},
   101  					&bc.TxVerifyResult{StatusFail: false},
   102  				}},
   103  			},
   104  		},
   105  		{
   106  			desc: "detach block 5, attach block 2",
   107  			before: map[bc.Hash]*storage.UtxoEntry{
   108  				*newTx(mockBlocks[5].Transactions[0]).OutputHash(0): storage.NewUtxoEntry(true, mockBlocks[5].Height, false),
   109  				*newTx(mockBlocks[5].Transactions[1]).OutputHash(0): storage.NewUtxoEntry(false, mockBlocks[5].Height, false),
   110  				*newTx(mockBlocks[5].Transactions[1]).OutputHash(1): storage.NewUtxoEntry(false, mockBlocks[5].Height, false),
   111  
   112  				*newTx(mockBlocks[6].Transactions[0]).OutputHash(0): storage.NewUtxoEntry(true, mockBlocks[6].Height, false),
   113  				*newTx(mockBlocks[6].Transactions[1]).OutputHash(0): storage.NewUtxoEntry(false, mockBlocks[6].Height, false),
   114  				*newTx(mockBlocks[6].Transactions[1]).OutputHash(1): storage.NewUtxoEntry(false, mockBlocks[6].Height, false),
   115  				*newTx(mockBlocks[6].Transactions[1]).OutputHash(2): storage.NewUtxoEntry(false, mockBlocks[6].Height, false),
   116  				*newTx(mockBlocks[6].Transactions[1]).OutputHash(3): storage.NewUtxoEntry(false, mockBlocks[6].Height, false),
   117  				*newTx(mockBlocks[6].Transactions[2]).OutputHash(0): storage.NewUtxoEntry(false, mockBlocks[6].Height, false),
   118  				*newTx(mockBlocks[6].Transactions[2]).OutputHash(1): storage.NewUtxoEntry(false, mockBlocks[6].Height, false),
   119  				*newTx(mockBlocks[6].Transactions[2]).OutputHash(2): storage.NewUtxoEntry(false, mockBlocks[6].Height, false),
   120  				*newTx(mockBlocks[6].Transactions[2]).OutputHash(3): storage.NewUtxoEntry(false, mockBlocks[6].Height, false),
   121  
   122  				*newTx(mockBlocks[7].Transactions[0]).OutputHash(0): storage.NewUtxoEntry(true, mockBlocks[7].Height, false),
   123  				*newTx(mockBlocks[7].Transactions[1]).OutputHash(0): storage.NewUtxoEntry(false, mockBlocks[7].Height, false),
   124  				*newTx(mockBlocks[7].Transactions[1]).OutputHash(1): storage.NewUtxoEntry(false, mockBlocks[7].Height, false),
   125  				*newTx(mockBlocks[7].Transactions[1]).OutputHash(2): storage.NewUtxoEntry(false, mockBlocks[7].Height, false),
   126  				*newTx(mockBlocks[7].Transactions[1]).OutputHash(3): storage.NewUtxoEntry(false, mockBlocks[7].Height, false),
   127  
   128  				*newTx(mockBlocks[8].Transactions[0]).OutputHash(0): storage.NewUtxoEntry(true, mockBlocks[8].Height, false),
   129  				*newTx(mockBlocks[8].Transactions[1]).OutputHash(0): storage.NewUtxoEntry(false, mockBlocks[8].Height, false),
   130  				*newTx(mockBlocks[8].Transactions[1]).OutputHash(1): storage.NewUtxoEntry(false, mockBlocks[8].Height, false),
   131  				*newTx(mockBlocks[8].Transactions[1]).OutputHash(2): storage.NewUtxoEntry(false, mockBlocks[8].Height, false),
   132  				*newTx(mockBlocks[8].Transactions[1]).OutputHash(3): storage.NewUtxoEntry(false, mockBlocks[8].Height, false),
   133  				*newTx(mockBlocks[8].Transactions[2]).OutputHash(0): storage.NewUtxoEntry(false, mockBlocks[8].Height, false),
   134  				*newTx(mockBlocks[8].Transactions[2]).OutputHash(1): storage.NewUtxoEntry(false, mockBlocks[8].Height, false),
   135  				*newTx(mockBlocks[8].Transactions[3]).OutputHash(0): storage.NewUtxoEntry(false, mockBlocks[8].Height, false),
   136  				*newTx(mockBlocks[8].Transactions[3]).OutputHash(1): storage.NewUtxoEntry(false, mockBlocks[8].Height, false),
   137  
   138  				*newTx(mockBlocks[9].Transactions[0]).OutputHash(0): storage.NewUtxoEntry(true, mockBlocks[9].Height, false),
   139  				*newTx(mockBlocks[9].Transactions[1]).OutputHash(0): storage.NewUtxoEntry(false, mockBlocks[9].Height, false),
   140  				*newTx(mockBlocks[9].Transactions[1]).OutputHash(1): storage.NewUtxoEntry(false, mockBlocks[9].Height, false),
   141  			},
   142  			want: map[bc.Hash]*storage.UtxoEntry{
   143  				*newTx(mockBlocks[10].Transactions[0]).OutputHash(0): storage.NewUtxoEntry(true, mockBlocks[10].Height, false),
   144  				*newTx(mockBlocks[10].Transactions[1]).OutputHash(0): storage.NewUtxoEntry(false, mockBlocks[10].Height, false),
   145  				*newTx(mockBlocks[10].Transactions[1]).OutputHash(1): storage.NewUtxoEntry(false, mockBlocks[10].Height, false),
   146  				*newTx(mockBlocks[10].Transactions[2]).OutputHash(0): storage.NewUtxoEntry(false, mockBlocks[10].Height, false),
   147  				*newTx(mockBlocks[10].Transactions[2]).OutputHash(1): storage.NewUtxoEntry(false, mockBlocks[10].Height, false),
   148  				*newTx(mockBlocks[10].Transactions[2]).OutputHash(2): storage.NewUtxoEntry(false, mockBlocks[10].Height, false),
   149  				*newTx(mockBlocks[10].Transactions[2]).OutputHash(3): storage.NewUtxoEntry(false, mockBlocks[10].Height, false),
   150  				*newTx(mockBlocks[10].Transactions[3]).OutputHash(0): storage.NewUtxoEntry(false, mockBlocks[10].Height, false),
   151  				*newTx(mockBlocks[10].Transactions[3]).OutputHash(1): storage.NewUtxoEntry(false, mockBlocks[10].Height, false),
   152  				*newTx(mockBlocks[10].Transactions[3]).OutputHash(2): storage.NewUtxoEntry(false, mockBlocks[10].Height, false),
   153  				*newTx(mockBlocks[10].Transactions[3]).OutputHash(3): storage.NewUtxoEntry(false, mockBlocks[10].Height, false),
   154  				*newTx(mockBlocks[10].Transactions[4]).OutputHash(0): storage.NewUtxoEntry(false, mockBlocks[10].Height, false),
   155  				*newTx(mockBlocks[10].Transactions[4]).OutputHash(1): storage.NewUtxoEntry(false, mockBlocks[10].Height, false),
   156  				*newTx(mockBlocks[10].Transactions[4]).OutputHash(2): storage.NewUtxoEntry(false, mockBlocks[10].Height, false),
   157  				*newTx(mockBlocks[10].Transactions[4]).OutputHash(3): storage.NewUtxoEntry(false, mockBlocks[10].Height, false),
   158  				*newTx(mockBlocks[10].Transactions[5]).OutputHash(0): storage.NewUtxoEntry(false, mockBlocks[10].Height, false),
   159  				*newTx(mockBlocks[10].Transactions[5]).OutputHash(1): storage.NewUtxoEntry(false, mockBlocks[10].Height, false),
   160  				*newTx(mockBlocks[10].Transactions[5]).OutputHash(2): storage.NewUtxoEntry(false, mockBlocks[10].Height, false),
   161  				*newTx(mockBlocks[10].Transactions[5]).OutputHash(3): storage.NewUtxoEntry(false, mockBlocks[10].Height, false),
   162  
   163  				*newTx(mockBlocks[11].Transactions[0]).OutputHash(0): storage.NewUtxoEntry(true, mockBlocks[11].Height, false),
   164  				*newTx(mockBlocks[11].Transactions[1]).OutputHash(0): storage.NewUtxoEntry(false, mockBlocks[11].Height, false),
   165  				*newTx(mockBlocks[11].Transactions[1]).OutputHash(1): storage.NewUtxoEntry(false, mockBlocks[11].Height, false),
   166  				*newTx(mockBlocks[11].Transactions[2]).OutputHash(0): storage.NewUtxoEntry(false, mockBlocks[11].Height, false),
   167  				*newTx(mockBlocks[11].Transactions[2]).OutputHash(1): storage.NewUtxoEntry(false, mockBlocks[11].Height, false),
   168  				*newTx(mockBlocks[11].Transactions[3]).OutputHash(0): storage.NewUtxoEntry(false, mockBlocks[11].Height, false),
   169  				*newTx(mockBlocks[11].Transactions[3]).OutputHash(1): storage.NewUtxoEntry(false, mockBlocks[11].Height, false),
   170  			},
   171  			attachBlock: []*bc.Block{
   172  				types.MapBlock(&mockBlocks[10].Block),
   173  				types.MapBlock(&mockBlocks[11].Block),
   174  			},
   175  			detachBlock: []*bc.Block{
   176  				types.MapBlock(&mockBlocks[9].Block),
   177  				types.MapBlock(&mockBlocks[8].Block),
   178  				types.MapBlock(&mockBlocks[7].Block),
   179  				types.MapBlock(&mockBlocks[6].Block),
   180  				types.MapBlock(&mockBlocks[5].Block),
   181  			},
   182  			attachTxStatus: []*bc.TransactionStatus{
   183  				&bc.TransactionStatus{VerifyStatus: []*bc.TxVerifyResult{
   184  					&bc.TxVerifyResult{StatusFail: false},
   185  					&bc.TxVerifyResult{StatusFail: false},
   186  					&bc.TxVerifyResult{StatusFail: false},
   187  					&bc.TxVerifyResult{StatusFail: false},
   188  					&bc.TxVerifyResult{StatusFail: false},
   189  					&bc.TxVerifyResult{StatusFail: false},
   190  				}},
   191  				&bc.TransactionStatus{VerifyStatus: []*bc.TxVerifyResult{
   192  					&bc.TxVerifyResult{StatusFail: false},
   193  					&bc.TxVerifyResult{StatusFail: false},
   194  					&bc.TxVerifyResult{StatusFail: false},
   195  					&bc.TxVerifyResult{StatusFail: false},
   196  					&bc.TxVerifyResult{StatusFail: false},
   197  				}},
   198  			},
   199  			detachTxStatus: []*bc.TransactionStatus{
   200  
   201  				&bc.TransactionStatus{VerifyStatus: []*bc.TxVerifyResult{
   202  					&bc.TxVerifyResult{StatusFail: false},
   203  					&bc.TxVerifyResult{StatusFail: false},
   204  				}},
   205  				&bc.TransactionStatus{VerifyStatus: []*bc.TxVerifyResult{
   206  					&bc.TxVerifyResult{StatusFail: false},
   207  					&bc.TxVerifyResult{StatusFail: false},
   208  					&bc.TxVerifyResult{StatusFail: false},
   209  					&bc.TxVerifyResult{StatusFail: false},
   210  				}},
   211  				&bc.TransactionStatus{VerifyStatus: []*bc.TxVerifyResult{
   212  					&bc.TxVerifyResult{StatusFail: false},
   213  					&bc.TxVerifyResult{StatusFail: false},
   214  				}},
   215  				&bc.TransactionStatus{VerifyStatus: []*bc.TxVerifyResult{
   216  					&bc.TxVerifyResult{StatusFail: false},
   217  					&bc.TxVerifyResult{StatusFail: false},
   218  					&bc.TxVerifyResult{StatusFail: false},
   219  				}},
   220  				&bc.TransactionStatus{VerifyStatus: []*bc.TxVerifyResult{
   221  					&bc.TxVerifyResult{StatusFail: false},
   222  					&bc.TxVerifyResult{StatusFail: false},
   223  				}},
   224  			},
   225  		},
   226  		{
   227  			desc: "detach block 5, attach block 2. Other asset deals failed.",
   228  			before: map[bc.Hash]*storage.UtxoEntry{
   229  				*newTx(mockBlocks[5].Transactions[0]).OutputHash(0): storage.NewUtxoEntry(true, mockBlocks[5].Height, false),
   230  				*newTx(mockBlocks[5].Transactions[1]).OutputHash(0): storage.NewUtxoEntry(false, mockBlocks[5].Height, false),
   231  				*newTx(mockBlocks[5].Transactions[1]).OutputHash(1): storage.NewUtxoEntry(false, mockBlocks[5].Height, false),
   232  
   233  				*newTx(mockBlocks[6].Transactions[0]).OutputHash(0):      storage.NewUtxoEntry(true, mockBlocks[6].Height, false),
   234  				*newTx(mockBlocks[6].Transactions[1]).OutputHash(0):      storage.NewUtxoEntry(false, mockBlocks[6].Height, false),
   235  				*newTx(mockBlocks[6].Transactions[1]).OutputHash(1):      storage.NewUtxoEntry(false, mockBlocks[6].Height, false),
   236  				newTx(mockBlocks[6].Transactions[1]).getSpentOutputID(1): storage.NewUtxoEntry(false, mockBlocks[6].Height-1, false),
   237  
   238  				*newTx(mockBlocks[6].Transactions[2]).OutputHash(0):      storage.NewUtxoEntry(false, mockBlocks[6].Height, false),
   239  				*newTx(mockBlocks[6].Transactions[2]).OutputHash(1):      storage.NewUtxoEntry(false, mockBlocks[6].Height, false),
   240  				newTx(mockBlocks[6].Transactions[2]).getSpentOutputID(1): storage.NewUtxoEntry(false, mockBlocks[6].Height-1, false),
   241  
   242  				*newTx(mockBlocks[7].Transactions[0]).OutputHash(0):      storage.NewUtxoEntry(true, mockBlocks[7].Height, false),
   243  				*newTx(mockBlocks[7].Transactions[1]).OutputHash(0):      storage.NewUtxoEntry(false, mockBlocks[7].Height, false),
   244  				*newTx(mockBlocks[7].Transactions[1]).OutputHash(1):      storage.NewUtxoEntry(false, mockBlocks[7].Height, false),
   245  				newTx(mockBlocks[7].Transactions[1]).getSpentOutputID(1): storage.NewUtxoEntry(false, mockBlocks[7].Height-1, false),
   246  
   247  				*newTx(mockBlocks[8].Transactions[0]).OutputHash(0):      storage.NewUtxoEntry(true, mockBlocks[8].Height, false),
   248  				*newTx(mockBlocks[8].Transactions[1]).OutputHash(0):      storage.NewUtxoEntry(false, mockBlocks[8].Height, false),
   249  				*newTx(mockBlocks[8].Transactions[1]).OutputHash(1):      storage.NewUtxoEntry(false, mockBlocks[8].Height, false),
   250  				newTx(mockBlocks[8].Transactions[1]).getSpentOutputID(1): storage.NewUtxoEntry(false, mockBlocks[8].Height-1, false),
   251  
   252  				*newTx(mockBlocks[8].Transactions[2]).OutputHash(0): storage.NewUtxoEntry(false, mockBlocks[8].Height, false),
   253  				*newTx(mockBlocks[8].Transactions[2]).OutputHash(1): storage.NewUtxoEntry(false, mockBlocks[8].Height, false),
   254  				*newTx(mockBlocks[8].Transactions[3]).OutputHash(0): storage.NewUtxoEntry(false, mockBlocks[8].Height, false),
   255  				*newTx(mockBlocks[8].Transactions[3]).OutputHash(1): storage.NewUtxoEntry(false, mockBlocks[8].Height, false),
   256  
   257  				*newTx(mockBlocks[9].Transactions[0]).OutputHash(0): storage.NewUtxoEntry(true, mockBlocks[9].Height, false),
   258  				*newTx(mockBlocks[9].Transactions[1]).OutputHash(0): storage.NewUtxoEntry(false, mockBlocks[9].Height, false),
   259  				*newTx(mockBlocks[9].Transactions[1]).OutputHash(1): storage.NewUtxoEntry(false, mockBlocks[9].Height, false),
   260  			},
   261  			want: map[bc.Hash]*storage.UtxoEntry{
   262  
   263  				*newTx(mockBlocks[10].Transactions[0]).OutputHash(0): storage.NewUtxoEntry(true, mockBlocks[10].Height, false),
   264  				*newTx(mockBlocks[10].Transactions[1]).OutputHash(0): storage.NewUtxoEntry(false, mockBlocks[10].Height, false),
   265  				*newTx(mockBlocks[10].Transactions[1]).OutputHash(1): storage.NewUtxoEntry(false, mockBlocks[10].Height, false),
   266  
   267  				*newTx(mockBlocks[10].Transactions[2]).OutputHash(0): storage.NewUtxoEntry(false, mockBlocks[10].Height, false),
   268  				*newTx(mockBlocks[10].Transactions[2]).OutputHash(1): storage.NewUtxoEntry(false, mockBlocks[10].Height, false),
   269  				*newTx(mockBlocks[10].Transactions[2]).OutputHash(2): storage.NewUtxoEntry(false, mockBlocks[10].Height, false),
   270  				*newTx(mockBlocks[10].Transactions[2]).OutputHash(3): storage.NewUtxoEntry(false, mockBlocks[10].Height, false),
   271  
   272  				*newTx(mockBlocks[10].Transactions[3]).OutputHash(0): storage.NewUtxoEntry(false, mockBlocks[10].Height, false),
   273  				*newTx(mockBlocks[10].Transactions[3]).OutputHash(1): storage.NewUtxoEntry(false, mockBlocks[10].Height, false),
   274  				*newTx(mockBlocks[10].Transactions[3]).OutputHash(2): storage.NewUtxoEntry(false, mockBlocks[10].Height, false),
   275  				*newTx(mockBlocks[10].Transactions[3]).OutputHash(3): storage.NewUtxoEntry(false, mockBlocks[10].Height, false),
   276  
   277  				*newTx(mockBlocks[10].Transactions[4]).OutputHash(0): storage.NewUtxoEntry(false, mockBlocks[10].Height, false),
   278  				*newTx(mockBlocks[10].Transactions[4]).OutputHash(1): storage.NewUtxoEntry(false, mockBlocks[10].Height, false),
   279  				*newTx(mockBlocks[10].Transactions[4]).OutputHash(2): storage.NewUtxoEntry(false, mockBlocks[10].Height, false),
   280  				*newTx(mockBlocks[10].Transactions[4]).OutputHash(3): storage.NewUtxoEntry(false, mockBlocks[10].Height, false),
   281  				*newTx(mockBlocks[10].Transactions[5]).OutputHash(0): storage.NewUtxoEntry(false, mockBlocks[10].Height, false),
   282  				*newTx(mockBlocks[10].Transactions[5]).OutputHash(1): storage.NewUtxoEntry(false, mockBlocks[10].Height, false),
   283  				*newTx(mockBlocks[10].Transactions[5]).OutputHash(2): storage.NewUtxoEntry(false, mockBlocks[10].Height, false),
   284  				*newTx(mockBlocks[10].Transactions[5]).OutputHash(3): storage.NewUtxoEntry(false, mockBlocks[10].Height, false),
   285  
   286  				*newTx(mockBlocks[11].Transactions[0]).OutputHash(0): storage.NewUtxoEntry(true, mockBlocks[11].Height, false),
   287  				*newTx(mockBlocks[11].Transactions[1]).OutputHash(0): storage.NewUtxoEntry(false, mockBlocks[11].Height, false),
   288  				*newTx(mockBlocks[11].Transactions[1]).OutputHash(1): storage.NewUtxoEntry(false, mockBlocks[11].Height, false),
   289  				*newTx(mockBlocks[11].Transactions[2]).OutputHash(0): storage.NewUtxoEntry(false, mockBlocks[11].Height, false),
   290  				*newTx(mockBlocks[11].Transactions[2]).OutputHash(1): storage.NewUtxoEntry(false, mockBlocks[11].Height, false),
   291  				*newTx(mockBlocks[11].Transactions[3]).OutputHash(0): storage.NewUtxoEntry(false, mockBlocks[11].Height, false),
   292  				*newTx(mockBlocks[11].Transactions[3]).OutputHash(1): storage.NewUtxoEntry(false, mockBlocks[11].Height, false),
   293  			},
   294  			attachBlock: []*bc.Block{
   295  				types.MapBlock(&mockBlocks[10].Block),
   296  				types.MapBlock(&mockBlocks[11].Block),
   297  			},
   298  			detachBlock: []*bc.Block{
   299  				types.MapBlock(&mockBlocks[9].Block),
   300  				types.MapBlock(&mockBlocks[8].Block),
   301  				types.MapBlock(&mockBlocks[7].Block),
   302  				types.MapBlock(&mockBlocks[6].Block),
   303  				types.MapBlock(&mockBlocks[5].Block),
   304  			},
   305  			attachTxStatus: []*bc.TransactionStatus{
   306  				&bc.TransactionStatus{VerifyStatus: []*bc.TxVerifyResult{
   307  					&bc.TxVerifyResult{StatusFail: false},
   308  					&bc.TxVerifyResult{StatusFail: false},
   309  					&bc.TxVerifyResult{StatusFail: false},
   310  					&bc.TxVerifyResult{StatusFail: false},
   311  					&bc.TxVerifyResult{StatusFail: false},
   312  					&bc.TxVerifyResult{StatusFail: false},
   313  				}},
   314  				&bc.TransactionStatus{VerifyStatus: []*bc.TxVerifyResult{
   315  					&bc.TxVerifyResult{StatusFail: false},
   316  					&bc.TxVerifyResult{StatusFail: false},
   317  					&bc.TxVerifyResult{StatusFail: false},
   318  					&bc.TxVerifyResult{StatusFail: false},
   319  					&bc.TxVerifyResult{StatusFail: false},
   320  				}},
   321  			},
   322  			detachTxStatus: []*bc.TransactionStatus{
   323  				&bc.TransactionStatus{VerifyStatus: []*bc.TxVerifyResult{
   324  					&bc.TxVerifyResult{StatusFail: false},
   325  					&bc.TxVerifyResult{StatusFail: false},
   326  				}},
   327  				&bc.TransactionStatus{VerifyStatus: []*bc.TxVerifyResult{
   328  					&bc.TxVerifyResult{StatusFail: false},
   329  					&bc.TxVerifyResult{StatusFail: true},
   330  					&bc.TxVerifyResult{StatusFail: false},
   331  					&bc.TxVerifyResult{StatusFail: false},
   332  				}},
   333  				&bc.TransactionStatus{VerifyStatus: []*bc.TxVerifyResult{
   334  					&bc.TxVerifyResult{StatusFail: false},
   335  					&bc.TxVerifyResult{StatusFail: true},
   336  				}},
   337  				&bc.TransactionStatus{VerifyStatus: []*bc.TxVerifyResult{
   338  					&bc.TxVerifyResult{StatusFail: false},
   339  					&bc.TxVerifyResult{StatusFail: true},
   340  					&bc.TxVerifyResult{StatusFail: true},
   341  				}},
   342  				&bc.TransactionStatus{VerifyStatus: []*bc.TxVerifyResult{
   343  					&bc.TxVerifyResult{StatusFail: false},
   344  					&bc.TxVerifyResult{StatusFail: false},
   345  				}},
   346  			},
   347  		},
   348  		{
   349  			desc: "detach block 2, attach block 1. Chain trading",
   350  			before: map[bc.Hash]*storage.UtxoEntry{
   351  				// coinbase tx
   352  				*newTx(mockBlocks[12].Transactions[0]).OutputHash(0): storage.NewUtxoEntry(true, mockBlocks[12].Height, false),
   353  				*newTx(mockBlocks[12].Transactions[1]).OutputHash(1): storage.NewUtxoEntry(false, mockBlocks[12].Height, false),
   354  				*newTx(mockBlocks[12].Transactions[2]).OutputHash(1): storage.NewUtxoEntry(false, mockBlocks[12].Height, false),
   355  				*newTx(mockBlocks[12].Transactions[3]).OutputHash(1): storage.NewUtxoEntry(false, mockBlocks[12].Height, false),
   356  				*newTx(mockBlocks[12].Transactions[4]).OutputHash(1): storage.NewUtxoEntry(false, mockBlocks[12].Height, false),
   357  
   358  				*newTx(mockBlocks[13].Transactions[0]).OutputHash(0): storage.NewUtxoEntry(true, mockBlocks[13].Height, false),
   359  				*newTx(mockBlocks[13].Transactions[1]).OutputHash(1): storage.NewUtxoEntry(false, mockBlocks[13].Height, false),
   360  				*newTx(mockBlocks[13].Transactions[2]).OutputHash(0): storage.NewUtxoEntry(false, mockBlocks[13].Height, false),
   361  				*newTx(mockBlocks[13].Transactions[2]).OutputHash(1): storage.NewUtxoEntry(false, mockBlocks[13].Height, false),
   362  			},
   363  			want: map[bc.Hash]*storage.UtxoEntry{
   364  				newTx(mockBlocks[12].Transactions[1]).getSpentOutputID(0): storage.NewUtxoEntry(false, 0, false),
   365  				*newTx(mockBlocks[14].Transactions[0]).OutputHash(0):      storage.NewUtxoEntry(true, mockBlocks[14].Height, false),
   366  			},
   367  			attachBlock: []*bc.Block{
   368  				types.MapBlock(&mockBlocks[14].Block),
   369  			},
   370  			detachBlock: []*bc.Block{
   371  				types.MapBlock(&mockBlocks[13].Block),
   372  				types.MapBlock(&mockBlocks[12].Block),
   373  			},
   374  			attachTxStatus: []*bc.TransactionStatus{
   375  				&bc.TransactionStatus{VerifyStatus: []*bc.TxVerifyResult{
   376  					&bc.TxVerifyResult{StatusFail: false},
   377  					&bc.TxVerifyResult{StatusFail: false},
   378  					&bc.TxVerifyResult{StatusFail: false},
   379  					&bc.TxVerifyResult{StatusFail: false},
   380  				}},
   381  				&bc.TransactionStatus{VerifyStatus: []*bc.TxVerifyResult{
   382  					&bc.TxVerifyResult{StatusFail: false},
   383  					&bc.TxVerifyResult{StatusFail: false},
   384  				}},
   385  				&bc.TransactionStatus{VerifyStatus: []*bc.TxVerifyResult{
   386  					&bc.TxVerifyResult{StatusFail: false},
   387  					&bc.TxVerifyResult{StatusFail: false},
   388  					&bc.TxVerifyResult{StatusFail: false},
   389  				}},
   390  			},
   391  			detachTxStatus: []*bc.TransactionStatus{
   392  				&bc.TransactionStatus{VerifyStatus: []*bc.TxVerifyResult{
   393  					&bc.TxVerifyResult{StatusFail: false},
   394  					&bc.TxVerifyResult{StatusFail: false},
   395  					&bc.TxVerifyResult{StatusFail: false},
   396  				}},
   397  				&bc.TransactionStatus{VerifyStatus: []*bc.TxVerifyResult{
   398  					&bc.TxVerifyResult{StatusFail: false},
   399  					&bc.TxVerifyResult{StatusFail: false},
   400  					&bc.TxVerifyResult{StatusFail: false},
   401  					&bc.TxVerifyResult{StatusFail: false},
   402  					&bc.TxVerifyResult{StatusFail: false},
   403  				}},
   404  			},
   405  		},
   406  	}
   407  	node := blockNode(types.MapBlock(&mockBlocks[0].Block).BlockHeader)
   408  	defer os.RemoveAll("temp")
   409  	for index, c := range cases {
   410  		testDB := dbm.NewDB("testdb", "leveldb", "temp")
   411  		store := database.NewStore(testDB)
   412  
   413  		utxoViewpoint := state.NewUtxoViewpoint()
   414  		for k, v := range c.before {
   415  			utxoViewpoint.Entries[k] = v
   416  		}
   417  		if err := store.SaveChainStatus(node, utxoViewpoint); err != nil {
   418  			t.Error(err)
   419  		}
   420  
   421  		utxoViewpoint = state.NewUtxoViewpoint()
   422  		for index, block := range c.detachBlock {
   423  			if err := store.GetTransactionsUtxo(utxoViewpoint, block.Transactions); err != nil {
   424  				t.Error(err)
   425  			}
   426  			if err := utxoViewpoint.DetachBlock(block, c.detachTxStatus[index]); err != nil {
   427  				t.Error(err)
   428  			}
   429  		}
   430  
   431  		for index, block := range c.attachBlock {
   432  			if err := store.GetTransactionsUtxo(utxoViewpoint, block.Transactions); err != nil {
   433  				t.Error(err)
   434  			}
   435  			if err := utxoViewpoint.ApplyBlock(block, c.attachTxStatus[index]); err != nil {
   436  				t.Error(err)
   437  			}
   438  		}
   439  		if err := store.SaveChainStatus(node, utxoViewpoint); err != nil {
   440  			t.Error(err)
   441  		}
   442  
   443  		want := map[string]*storage.UtxoEntry{}
   444  		result := make(map[string]*storage.UtxoEntry)
   445  
   446  		for k, v := range c.want {
   447  			want[string(calcUtxoKey(&k))] = v
   448  		}
   449  
   450  		iter := testDB.IteratorPrefix([]byte(utxoPreFix))
   451  		defer iter.Release()
   452  
   453  		for iter.Next() {
   454  			utxoEntry := &storage.UtxoEntry{}
   455  			if err := proto.Unmarshal(iter.Value(), utxoEntry); err != nil {
   456  				t.Error(err)
   457  			}
   458  			key := string(iter.Key())
   459  			result[key] = utxoEntry
   460  		}
   461  
   462  		if !testutil.DeepEqual(want, result) {
   463  			t.Errorf("case [%d] fail. want: %v, result: %v", index, want, result)
   464  		}
   465  		testDB.Close()
   466  		os.RemoveAll("temp")
   467  	}
   468  }