github.com/bytom/bytom@v1.1.2-0.20221014091027-bbcba3df6075/test/utxo_view/utxo_view_test.go (about)

     1  package utxo_view
     2  
     3  import (
     4  	"os"
     5  	"testing"
     6  
     7  	"github.com/golang/protobuf/proto"
     8  
     9  	"github.com/bytom/bytom/database"
    10  	dbm "github.com/bytom/bytom/database/leveldb"
    11  	"github.com/bytom/bytom/database/storage"
    12  	"github.com/bytom/bytom/protocol/bc"
    13  	"github.com/bytom/bytom/protocol/bc/types"
    14  	"github.com/bytom/bytom/protocol/state"
    15  	"github.com/bytom/bytom/testutil"
    16  )
    17  
    18  func TestAttachOrDetachBlocks(t *testing.T) {
    19  	cases := []struct {
    20  		desc        string
    21  		before      map[bc.Hash]*storage.UtxoEntry
    22  		want        map[bc.Hash]*storage.UtxoEntry
    23  		attachBlock []*bc.Block
    24  		detachBlock []*bc.Block
    25  	}{
    26  		{
    27  			desc:   "coinbase tx",
    28  			before: make(map[bc.Hash]*storage.UtxoEntry),
    29  			want:   map[bc.Hash]*storage.UtxoEntry{*newTx(mockBlocks[0].Transactions[0]).OutputHash(0): storage.NewUtxoEntry(storage.CoinbaseUTXOType, mockBlocks[0].Block.Height, false)},
    30  			attachBlock: []*bc.Block{
    31  				types.MapBlock(&mockBlocks[0].Block),
    32  			},
    33  		},
    34  		{
    35  			desc: "Chain trading 3",
    36  			before: map[bc.Hash]*storage.UtxoEntry{
    37  				newTx(mockBlocks[1].Transactions[1]).getSpentOutputID(0): storage.NewUtxoEntry(storage.NormalUTXOType, mockBlocks[1].Height-1, false),
    38  			},
    39  			want: map[bc.Hash]*storage.UtxoEntry{
    40  				*newTx(mockBlocks[1].Transactions[0]).OutputHash(0): storage.NewUtxoEntry(storage.CoinbaseUTXOType, mockBlocks[1].Height, false),
    41  				*newTx(mockBlocks[1].Transactions[1]).OutputHash(0): storage.NewUtxoEntry(storage.NormalUTXOType, mockBlocks[1].Height, false),
    42  				*newTx(mockBlocks[1].Transactions[2]).OutputHash(0): storage.NewUtxoEntry(storage.NormalUTXOType, mockBlocks[1].Height, false),
    43  				*newTx(mockBlocks[1].Transactions[3]).OutputHash(0): storage.NewUtxoEntry(storage.NormalUTXOType, mockBlocks[1].Height, false),
    44  				*newTx(mockBlocks[1].Transactions[3]).OutputHash(1): storage.NewUtxoEntry(storage.NormalUTXOType, mockBlocks[1].Height, false),
    45  			},
    46  			attachBlock: []*bc.Block{
    47  				types.MapBlock(&mockBlocks[1].Block),
    48  			},
    49  		},
    50  		{
    51  			desc: "detach 1 block, attach 2 block",
    52  			before: map[bc.Hash]*storage.UtxoEntry{
    53  				*newTx(mockBlocks[2].Transactions[0]).OutputHash(0): storage.NewUtxoEntry(storage.CoinbaseUTXOType, mockBlocks[2].Height, false),
    54  				*newTx(mockBlocks[2].Transactions[1]).OutputHash(0): storage.NewUtxoEntry(storage.NormalUTXOType, mockBlocks[2].Height, false),
    55  				*newTx(mockBlocks[2].Transactions[1]).OutputHash(1): storage.NewUtxoEntry(storage.NormalUTXOType, mockBlocks[2].Height, false),
    56  			},
    57  			want: map[bc.Hash]*storage.UtxoEntry{
    58  				*newTx(mockBlocks[3].Transactions[0]).OutputHash(0): storage.NewUtxoEntry(storage.CoinbaseUTXOType, mockBlocks[3].Height, false),
    59  				*newTx(mockBlocks[3].Transactions[1]).OutputHash(0): storage.NewUtxoEntry(storage.NormalUTXOType, mockBlocks[3].Height, false),
    60  
    61  				*newTx(mockBlocks[4].Transactions[0]).OutputHash(0): storage.NewUtxoEntry(storage.CoinbaseUTXOType, mockBlocks[4].Height, false),
    62  				*newTx(mockBlocks[4].Transactions[1]).OutputHash(0): storage.NewUtxoEntry(storage.NormalUTXOType, mockBlocks[4].Height, false),
    63  				*newTx(mockBlocks[4].Transactions[1]).OutputHash(1): storage.NewUtxoEntry(storage.NormalUTXOType, mockBlocks[4].Height, false),
    64  			},
    65  			attachBlock: []*bc.Block{
    66  				types.MapBlock(&mockBlocks[3].Block),
    67  				types.MapBlock(&mockBlocks[4].Block),
    68  			},
    69  			detachBlock: []*bc.Block{
    70  				types.MapBlock(&mockBlocks[2].Block),
    71  			},
    72  		},
    73  		{
    74  			desc: "detach block 5, attach block 2",
    75  			before: map[bc.Hash]*storage.UtxoEntry{
    76  				*newTx(mockBlocks[5].Transactions[0]).OutputHash(0): storage.NewUtxoEntry(storage.CoinbaseUTXOType, mockBlocks[5].Height, false),
    77  				*newTx(mockBlocks[5].Transactions[1]).OutputHash(0): storage.NewUtxoEntry(storage.NormalUTXOType, mockBlocks[5].Height, false),
    78  				*newTx(mockBlocks[5].Transactions[1]).OutputHash(1): storage.NewUtxoEntry(storage.NormalUTXOType, mockBlocks[5].Height, false),
    79  
    80  				*newTx(mockBlocks[6].Transactions[0]).OutputHash(0): storage.NewUtxoEntry(storage.CoinbaseUTXOType, mockBlocks[6].Height, false),
    81  				*newTx(mockBlocks[6].Transactions[1]).OutputHash(0): storage.NewUtxoEntry(storage.NormalUTXOType, mockBlocks[6].Height, false),
    82  				*newTx(mockBlocks[6].Transactions[1]).OutputHash(1): storage.NewUtxoEntry(storage.NormalUTXOType, mockBlocks[6].Height, false),
    83  				*newTx(mockBlocks[6].Transactions[1]).OutputHash(2): storage.NewUtxoEntry(storage.NormalUTXOType, mockBlocks[6].Height, false),
    84  				*newTx(mockBlocks[6].Transactions[1]).OutputHash(3): storage.NewUtxoEntry(storage.NormalUTXOType, mockBlocks[6].Height, false),
    85  				*newTx(mockBlocks[6].Transactions[2]).OutputHash(0): storage.NewUtxoEntry(storage.NormalUTXOType, mockBlocks[6].Height, false),
    86  				*newTx(mockBlocks[6].Transactions[2]).OutputHash(1): storage.NewUtxoEntry(storage.NormalUTXOType, mockBlocks[6].Height, false),
    87  				*newTx(mockBlocks[6].Transactions[2]).OutputHash(2): storage.NewUtxoEntry(storage.NormalUTXOType, mockBlocks[6].Height, false),
    88  				*newTx(mockBlocks[6].Transactions[2]).OutputHash(3): storage.NewUtxoEntry(storage.NormalUTXOType, mockBlocks[6].Height, false),
    89  
    90  				*newTx(mockBlocks[7].Transactions[0]).OutputHash(0): storage.NewUtxoEntry(storage.CoinbaseUTXOType, mockBlocks[7].Height, false),
    91  				*newTx(mockBlocks[7].Transactions[1]).OutputHash(0): storage.NewUtxoEntry(storage.NormalUTXOType, mockBlocks[7].Height, false),
    92  				*newTx(mockBlocks[7].Transactions[1]).OutputHash(1): storage.NewUtxoEntry(storage.NormalUTXOType, mockBlocks[7].Height, false),
    93  				*newTx(mockBlocks[7].Transactions[1]).OutputHash(2): storage.NewUtxoEntry(storage.NormalUTXOType, mockBlocks[7].Height, false),
    94  				*newTx(mockBlocks[7].Transactions[1]).OutputHash(3): storage.NewUtxoEntry(storage.NormalUTXOType, mockBlocks[7].Height, false),
    95  
    96  				*newTx(mockBlocks[8].Transactions[0]).OutputHash(0): storage.NewUtxoEntry(storage.CoinbaseUTXOType, mockBlocks[8].Height, false),
    97  				*newTx(mockBlocks[8].Transactions[1]).OutputHash(0): storage.NewUtxoEntry(storage.NormalUTXOType, mockBlocks[8].Height, false),
    98  				*newTx(mockBlocks[8].Transactions[1]).OutputHash(1): storage.NewUtxoEntry(storage.NormalUTXOType, mockBlocks[8].Height, false),
    99  				*newTx(mockBlocks[8].Transactions[1]).OutputHash(2): storage.NewUtxoEntry(storage.NormalUTXOType, mockBlocks[8].Height, false),
   100  				*newTx(mockBlocks[8].Transactions[1]).OutputHash(3): storage.NewUtxoEntry(storage.NormalUTXOType, mockBlocks[8].Height, false),
   101  				*newTx(mockBlocks[8].Transactions[2]).OutputHash(0): storage.NewUtxoEntry(storage.NormalUTXOType, mockBlocks[8].Height, false),
   102  				*newTx(mockBlocks[8].Transactions[2]).OutputHash(1): storage.NewUtxoEntry(storage.NormalUTXOType, mockBlocks[8].Height, false),
   103  				*newTx(mockBlocks[8].Transactions[3]).OutputHash(0): storage.NewUtxoEntry(storage.NormalUTXOType, mockBlocks[8].Height, false),
   104  				*newTx(mockBlocks[8].Transactions[3]).OutputHash(1): storage.NewUtxoEntry(storage.NormalUTXOType, mockBlocks[8].Height, false),
   105  
   106  				*newTx(mockBlocks[9].Transactions[0]).OutputHash(0): storage.NewUtxoEntry(storage.CoinbaseUTXOType, mockBlocks[9].Height, false),
   107  				*newTx(mockBlocks[9].Transactions[1]).OutputHash(0): storage.NewUtxoEntry(storage.NormalUTXOType, mockBlocks[9].Height, false),
   108  				*newTx(mockBlocks[9].Transactions[1]).OutputHash(1): storage.NewUtxoEntry(storage.NormalUTXOType, mockBlocks[9].Height, false),
   109  			},
   110  			want: map[bc.Hash]*storage.UtxoEntry{
   111  				*newTx(mockBlocks[10].Transactions[0]).OutputHash(0): storage.NewUtxoEntry(storage.CoinbaseUTXOType, mockBlocks[10].Height, false),
   112  				*newTx(mockBlocks[10].Transactions[1]).OutputHash(0): storage.NewUtxoEntry(storage.NormalUTXOType, mockBlocks[10].Height, false),
   113  				*newTx(mockBlocks[10].Transactions[1]).OutputHash(1): storage.NewUtxoEntry(storage.NormalUTXOType, mockBlocks[10].Height, false),
   114  				*newTx(mockBlocks[10].Transactions[2]).OutputHash(0): storage.NewUtxoEntry(storage.NormalUTXOType, mockBlocks[10].Height, false),
   115  				*newTx(mockBlocks[10].Transactions[2]).OutputHash(1): storage.NewUtxoEntry(storage.NormalUTXOType, mockBlocks[10].Height, false),
   116  				*newTx(mockBlocks[10].Transactions[2]).OutputHash(2): storage.NewUtxoEntry(storage.NormalUTXOType, mockBlocks[10].Height, false),
   117  				*newTx(mockBlocks[10].Transactions[2]).OutputHash(3): storage.NewUtxoEntry(storage.NormalUTXOType, mockBlocks[10].Height, false),
   118  				*newTx(mockBlocks[10].Transactions[3]).OutputHash(0): storage.NewUtxoEntry(storage.NormalUTXOType, mockBlocks[10].Height, false),
   119  				*newTx(mockBlocks[10].Transactions[3]).OutputHash(1): storage.NewUtxoEntry(storage.NormalUTXOType, mockBlocks[10].Height, false),
   120  				*newTx(mockBlocks[10].Transactions[3]).OutputHash(2): storage.NewUtxoEntry(storage.NormalUTXOType, mockBlocks[10].Height, false),
   121  				*newTx(mockBlocks[10].Transactions[3]).OutputHash(3): storage.NewUtxoEntry(storage.NormalUTXOType, mockBlocks[10].Height, false),
   122  				*newTx(mockBlocks[10].Transactions[4]).OutputHash(0): storage.NewUtxoEntry(storage.NormalUTXOType, mockBlocks[10].Height, false),
   123  				*newTx(mockBlocks[10].Transactions[4]).OutputHash(1): storage.NewUtxoEntry(storage.NormalUTXOType, mockBlocks[10].Height, false),
   124  				*newTx(mockBlocks[10].Transactions[4]).OutputHash(2): storage.NewUtxoEntry(storage.NormalUTXOType, mockBlocks[10].Height, false),
   125  				*newTx(mockBlocks[10].Transactions[4]).OutputHash(3): storage.NewUtxoEntry(storage.NormalUTXOType, mockBlocks[10].Height, false),
   126  				*newTx(mockBlocks[10].Transactions[5]).OutputHash(0): storage.NewUtxoEntry(storage.NormalUTXOType, mockBlocks[10].Height, false),
   127  				*newTx(mockBlocks[10].Transactions[5]).OutputHash(1): storage.NewUtxoEntry(storage.NormalUTXOType, mockBlocks[10].Height, false),
   128  				*newTx(mockBlocks[10].Transactions[5]).OutputHash(2): storage.NewUtxoEntry(storage.NormalUTXOType, mockBlocks[10].Height, false),
   129  				*newTx(mockBlocks[10].Transactions[5]).OutputHash(3): storage.NewUtxoEntry(storage.NormalUTXOType, mockBlocks[10].Height, false),
   130  
   131  				*newTx(mockBlocks[11].Transactions[0]).OutputHash(0): storage.NewUtxoEntry(storage.CoinbaseUTXOType, mockBlocks[11].Height, false),
   132  				*newTx(mockBlocks[11].Transactions[1]).OutputHash(0): storage.NewUtxoEntry(storage.NormalUTXOType, mockBlocks[11].Height, false),
   133  				*newTx(mockBlocks[11].Transactions[1]).OutputHash(1): storage.NewUtxoEntry(storage.NormalUTXOType, mockBlocks[11].Height, false),
   134  				*newTx(mockBlocks[11].Transactions[2]).OutputHash(0): storage.NewUtxoEntry(storage.NormalUTXOType, mockBlocks[11].Height, false),
   135  				*newTx(mockBlocks[11].Transactions[2]).OutputHash(1): storage.NewUtxoEntry(storage.NormalUTXOType, mockBlocks[11].Height, false),
   136  				*newTx(mockBlocks[11].Transactions[3]).OutputHash(0): storage.NewUtxoEntry(storage.NormalUTXOType, mockBlocks[11].Height, false),
   137  				*newTx(mockBlocks[11].Transactions[3]).OutputHash(1): storage.NewUtxoEntry(storage.NormalUTXOType, mockBlocks[11].Height, false),
   138  			},
   139  			attachBlock: []*bc.Block{
   140  				types.MapBlock(&mockBlocks[10].Block),
   141  				types.MapBlock(&mockBlocks[11].Block),
   142  			},
   143  			detachBlock: []*bc.Block{
   144  				types.MapBlock(&mockBlocks[9].Block),
   145  				types.MapBlock(&mockBlocks[8].Block),
   146  				types.MapBlock(&mockBlocks[7].Block),
   147  				types.MapBlock(&mockBlocks[6].Block),
   148  				types.MapBlock(&mockBlocks[5].Block),
   149  			},
   150  		},
   151  		{
   152  			desc: "detach block 2, attach block 1. Chain trading",
   153  			before: map[bc.Hash]*storage.UtxoEntry{
   154  				// coinbase tx
   155  				*newTx(mockBlocks[12].Transactions[0]).OutputHash(0): storage.NewUtxoEntry(storage.CoinbaseUTXOType, mockBlocks[12].Height, false),
   156  				*newTx(mockBlocks[12].Transactions[1]).OutputHash(1): storage.NewUtxoEntry(storage.NormalUTXOType, mockBlocks[12].Height, false),
   157  				*newTx(mockBlocks[12].Transactions[2]).OutputHash(1): storage.NewUtxoEntry(storage.NormalUTXOType, mockBlocks[12].Height, false),
   158  				*newTx(mockBlocks[12].Transactions[3]).OutputHash(1): storage.NewUtxoEntry(storage.NormalUTXOType, mockBlocks[12].Height, false),
   159  				*newTx(mockBlocks[12].Transactions[4]).OutputHash(1): storage.NewUtxoEntry(storage.NormalUTXOType, mockBlocks[12].Height, false),
   160  
   161  				*newTx(mockBlocks[13].Transactions[0]).OutputHash(0): storage.NewUtxoEntry(storage.CoinbaseUTXOType, mockBlocks[13].Height, false),
   162  				*newTx(mockBlocks[13].Transactions[1]).OutputHash(1): storage.NewUtxoEntry(storage.NormalUTXOType, mockBlocks[13].Height, false),
   163  				*newTx(mockBlocks[13].Transactions[2]).OutputHash(0): storage.NewUtxoEntry(storage.NormalUTXOType, mockBlocks[13].Height, false),
   164  				*newTx(mockBlocks[13].Transactions[2]).OutputHash(1): storage.NewUtxoEntry(storage.NormalUTXOType, mockBlocks[13].Height, false),
   165  			},
   166  			want: map[bc.Hash]*storage.UtxoEntry{
   167  				newTx(mockBlocks[12].Transactions[1]).getSpentOutputID(0): storage.NewUtxoEntry(storage.NormalUTXOType, 0, false),
   168  				*newTx(mockBlocks[14].Transactions[0]).OutputHash(0):      storage.NewUtxoEntry(storage.CoinbaseUTXOType, mockBlocks[14].Height, false),
   169  			},
   170  			attachBlock: []*bc.Block{
   171  				types.MapBlock(&mockBlocks[14].Block),
   172  			},
   173  			detachBlock: []*bc.Block{
   174  				types.MapBlock(&mockBlocks[13].Block),
   175  				types.MapBlock(&mockBlocks[12].Block),
   176  			},
   177  		},
   178  	}
   179  	mockBlockHeader := &mockBlocks[0].Block.BlockHeader
   180  	defer os.RemoveAll("temp")
   181  
   182  	for index, c := range cases {
   183  		testDB := dbm.NewDB("testdb", "leveldb", "temp")
   184  		store := database.NewStore(testDB)
   185  
   186  		utxoViewpoint := state.NewUtxoViewpoint()
   187  		for k, v := range c.before {
   188  			utxoViewpoint.Entries[k] = v
   189  		}
   190  		contractView := state.NewContractViewpoint()
   191  		if err := store.SaveChainStatus(mockBlockHeader, []*types.BlockHeader{mockBlockHeader}, utxoViewpoint, contractView, 0, &bc.Hash{}); err != nil {
   192  			t.Error(err)
   193  		}
   194  
   195  		utxoViewpoint = state.NewUtxoViewpoint()
   196  		for _, block := range c.detachBlock {
   197  			if err := store.GetTransactionsUtxo(utxoViewpoint, block.Transactions); err != nil {
   198  				t.Error(err)
   199  			}
   200  			if err := utxoViewpoint.DetachBlock(block); err != nil {
   201  				t.Error(err)
   202  			}
   203  		}
   204  
   205  		for _, block := range c.attachBlock {
   206  			if err := store.GetTransactionsUtxo(utxoViewpoint, block.Transactions); err != nil {
   207  				t.Error(err)
   208  			}
   209  			if err := utxoViewpoint.ApplyBlock(block); err != nil {
   210  				t.Error(err)
   211  			}
   212  		}
   213  		if err := store.SaveChainStatus(mockBlockHeader, []*types.BlockHeader{mockBlockHeader}, utxoViewpoint, contractView, 0, &bc.Hash{}); err != nil {
   214  			t.Error(err)
   215  		}
   216  
   217  		want := map[string]*storage.UtxoEntry{}
   218  		result := make(map[string]*storage.UtxoEntry)
   219  
   220  		for k, v := range c.want {
   221  			want[string(database.CalcUtxoKey(&k))] = v
   222  		}
   223  
   224  		iter := testDB.IteratorPrefix([]byte(database.UtxoKeyPrefix))
   225  		defer iter.Release()
   226  
   227  		for iter.Next() {
   228  			utxoEntry := &storage.UtxoEntry{}
   229  			if err := proto.Unmarshal(iter.Value(), utxoEntry); err != nil {
   230  				t.Error(err)
   231  			}
   232  			key := string(iter.Key())
   233  			result[key] = utxoEntry
   234  		}
   235  
   236  		if !testutil.DeepEqual(want, result) {
   237  			t.Errorf("case [%d] fail. want: %v, result: %v", index, want, result)
   238  		}
   239  
   240  		testDB.Close()
   241  		os.RemoveAll("temp")
   242  	}
   243  }