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

     1  package state
     2  
     3  import (
     4  	"fmt"
     5  	"testing"
     6  
     7  	"github.com/bytom/bytom/consensus"
     8  	"github.com/bytom/bytom/database/storage"
     9  	"github.com/bytom/bytom/protocol/bc"
    10  	"github.com/bytom/bytom/testutil"
    11  )
    12  
    13  var defaultEntry = map[bc.Hash]bc.Entry{
    14  	bc.Hash{V0: 0}: &bc.OriginalOutput{
    15  		Source: &bc.ValueSource{
    16  			Value: &bc.AssetAmount{
    17  				AssetId: &bc.AssetID{V0: 0},
    18  				Amount:  1,
    19  			},
    20  		},
    21  	},
    22  }
    23  
    24  var gasOnlyTxEntry = map[bc.Hash]bc.Entry{
    25  	bc.Hash{V1: 0}: &bc.OriginalOutput{
    26  		Source: &bc.ValueSource{
    27  			Value: &bc.AssetAmount{
    28  				AssetId: consensus.BTMAssetID,
    29  				Amount:  1,
    30  			},
    31  		},
    32  	},
    33  	bc.Hash{V1: 1}: &bc.OriginalOutput{
    34  		Source: &bc.ValueSource{
    35  			Value: &bc.AssetAmount{
    36  				AssetId: &bc.AssetID{V0: 999},
    37  				Amount:  1,
    38  			},
    39  		},
    40  	},
    41  }
    42  
    43  func TestApplyBlock(t *testing.T) {
    44  	cases := []struct {
    45  		block     *bc.Block
    46  		inputView *UtxoViewpoint
    47  		fetchView *UtxoViewpoint
    48  		gasOnlyTx bool
    49  		err       bool
    50  	}{
    51  		{
    52  			// can't find prevout in tx entries
    53  			block: &bc.Block{
    54  				BlockHeader: &bc.BlockHeader{},
    55  				Transactions: []*bc.Tx{
    56  					&bc.Tx{
    57  						SpentOutputIDs: []bc.Hash{
    58  							bc.Hash{V0: 1},
    59  						},
    60  						Entries: defaultEntry,
    61  					},
    62  				},
    63  			},
    64  			inputView: &UtxoViewpoint{
    65  				Entries: map[bc.Hash]*storage.UtxoEntry{
    66  					bc.Hash{V0: 0}: storage.NewUtxoEntry(storage.NormalUTXOType, 0, false),
    67  				},
    68  			},
    69  			fetchView: NewUtxoViewpoint(),
    70  			err:       true,
    71  		},
    72  		{
    73  			block: &bc.Block{
    74  				BlockHeader: &bc.BlockHeader{},
    75  				Transactions: []*bc.Tx{
    76  					&bc.Tx{
    77  						SpentOutputIDs: []bc.Hash{
    78  							bc.Hash{V0: 0},
    79  						},
    80  						Entries: defaultEntry,
    81  					},
    82  				},
    83  			},
    84  			inputView: NewUtxoViewpoint(),
    85  			fetchView: NewUtxoViewpoint(),
    86  			err:       true,
    87  		},
    88  		{
    89  			block: &bc.Block{
    90  				BlockHeader: &bc.BlockHeader{},
    91  				Transactions: []*bc.Tx{
    92  					&bc.Tx{
    93  						SpentOutputIDs: []bc.Hash{
    94  							bc.Hash{V0: 0},
    95  						},
    96  						Entries: defaultEntry,
    97  					},
    98  				},
    99  			},
   100  			inputView: &UtxoViewpoint{
   101  				Entries: map[bc.Hash]*storage.UtxoEntry{
   102  					bc.Hash{V0: 0}: storage.NewUtxoEntry(storage.NormalUTXOType, 0, true),
   103  				},
   104  			},
   105  			err: true,
   106  		},
   107  		{
   108  			block: &bc.Block{
   109  				BlockHeader: &bc.BlockHeader{},
   110  				Transactions: []*bc.Tx{
   111  					&bc.Tx{
   112  						TxHeader: &bc.TxHeader{
   113  							ResultIds: []*bc.Hash{},
   114  						},
   115  						SpentOutputIDs: []bc.Hash{
   116  							bc.Hash{V0: 0},
   117  						},
   118  						Entries: defaultEntry,
   119  					},
   120  				},
   121  			},
   122  			inputView: &UtxoViewpoint{
   123  				Entries: map[bc.Hash]*storage.UtxoEntry{
   124  					bc.Hash{V0: 0}: storage.NewUtxoEntry(storage.NormalUTXOType, 0, false),
   125  				},
   126  			},
   127  			fetchView: &UtxoViewpoint{
   128  				Entries: map[bc.Hash]*storage.UtxoEntry{
   129  					bc.Hash{V0: 0}: storage.NewUtxoEntry(storage.NormalUTXOType, 0, true),
   130  				},
   131  			},
   132  			err: false,
   133  		},
   134  		{
   135  			block: &bc.Block{
   136  				BlockHeader: &bc.BlockHeader{
   137  					Height: 101,
   138  				},
   139  				Transactions: []*bc.Tx{
   140  					&bc.Tx{
   141  						TxHeader: &bc.TxHeader{
   142  							ResultIds: []*bc.Hash{},
   143  						},
   144  						SpentOutputIDs: []bc.Hash{
   145  							bc.Hash{V0: 0},
   146  						},
   147  						Entries: defaultEntry,
   148  					},
   149  				},
   150  			},
   151  			inputView: &UtxoViewpoint{
   152  				Entries: map[bc.Hash]*storage.UtxoEntry{
   153  					bc.Hash{V0: 0}: storage.NewUtxoEntry(storage.CoinbaseUTXOType, 0, false),
   154  				},
   155  			},
   156  			fetchView: &UtxoViewpoint{
   157  				Entries: map[bc.Hash]*storage.UtxoEntry{
   158  					bc.Hash{V0: 0}: storage.NewUtxoEntry(storage.CoinbaseUTXOType, 0, true),
   159  				},
   160  			},
   161  			err: false,
   162  		},
   163  		{
   164  			block: &bc.Block{
   165  				BlockHeader: &bc.BlockHeader{
   166  					Height: 0,
   167  				},
   168  				Transactions: []*bc.Tx{
   169  					&bc.Tx{
   170  						TxHeader: &bc.TxHeader{
   171  							ResultIds: []*bc.Hash{},
   172  						},
   173  						SpentOutputIDs: []bc.Hash{
   174  							bc.Hash{V0: 0},
   175  						},
   176  						Entries: defaultEntry,
   177  					},
   178  				},
   179  			},
   180  			inputView: &UtxoViewpoint{
   181  				Entries: map[bc.Hash]*storage.UtxoEntry{
   182  					bc.Hash{V0: 0}: storage.NewUtxoEntry(storage.CoinbaseUTXOType, 0, false),
   183  				},
   184  			},
   185  			fetchView: &UtxoViewpoint{
   186  				Entries: map[bc.Hash]*storage.UtxoEntry{
   187  					bc.Hash{V0: 0}: storage.NewUtxoEntry(storage.CoinbaseUTXOType, 0, true),
   188  				},
   189  			},
   190  			err: true,
   191  		},
   192  		{
   193  			// output will be store
   194  			block: &bc.Block{
   195  				BlockHeader: &bc.BlockHeader{},
   196  				Transactions: []*bc.Tx{
   197  					&bc.Tx{
   198  						TxHeader: &bc.TxHeader{
   199  							ResultIds: []*bc.Hash{
   200  								&bc.Hash{V0: 0},
   201  							},
   202  						},
   203  						SpentOutputIDs: []bc.Hash{},
   204  						Entries:        defaultEntry,
   205  					},
   206  				},
   207  			},
   208  			inputView: NewUtxoViewpoint(),
   209  			fetchView: &UtxoViewpoint{
   210  				Entries: map[bc.Hash]*storage.UtxoEntry{
   211  					bc.Hash{V0: 0}: storage.NewUtxoEntry(storage.CoinbaseUTXOType, 0, false),
   212  				},
   213  			},
   214  			err: false,
   215  		},
   216  		{
   217  			// non-btm asset spent input will be spent
   218  			block: &bc.Block{
   219  				BlockHeader: &bc.BlockHeader{},
   220  				Transactions: []*bc.Tx{
   221  					&bc.Tx{
   222  						TxHeader: &bc.TxHeader{
   223  							ResultIds: []*bc.Hash{},
   224  						},
   225  						SpentOutputIDs: []bc.Hash{
   226  							bc.Hash{V1: 0},
   227  							bc.Hash{V1: 1},
   228  						},
   229  						Entries: gasOnlyTxEntry,
   230  					},
   231  				},
   232  			},
   233  			inputView: &UtxoViewpoint{
   234  				Entries: map[bc.Hash]*storage.UtxoEntry{
   235  					bc.Hash{V1: 0}: storage.NewUtxoEntry(storage.NormalUTXOType, 0, false),
   236  					bc.Hash{V1: 1}: storage.NewUtxoEntry(storage.NormalUTXOType, 0, false),
   237  				},
   238  			},
   239  			fetchView: &UtxoViewpoint{
   240  				Entries: map[bc.Hash]*storage.UtxoEntry{
   241  					bc.Hash{V1: 0}: storage.NewUtxoEntry(storage.NormalUTXOType, 0, true),
   242  					bc.Hash{V1: 1}: storage.NewUtxoEntry(storage.NormalUTXOType, 0, true),
   243  				},
   244  			},
   245  			err: false,
   246  		},
   247  		{
   248  			// apply gas only tx, non-btm asset spent output will not be store
   249  			block: &bc.Block{
   250  				BlockHeader: &bc.BlockHeader{},
   251  				Transactions: []*bc.Tx{
   252  					&bc.Tx{
   253  						TxHeader: &bc.TxHeader{
   254  							ResultIds: []*bc.Hash{
   255  								&bc.Hash{V1: 0},
   256  								&bc.Hash{V1: 1},
   257  							},
   258  						},
   259  						SpentOutputIDs: []bc.Hash{},
   260  						Entries:        gasOnlyTxEntry,
   261  					},
   262  				},
   263  			},
   264  			inputView: NewUtxoViewpoint(),
   265  			fetchView: &UtxoViewpoint{
   266  				Entries: map[bc.Hash]*storage.UtxoEntry{
   267  					bc.Hash{V1: 0}: storage.NewUtxoEntry(storage.CoinbaseUTXOType, 0, false),
   268  					bc.Hash{V1: 1}: storage.NewUtxoEntry(storage.CoinbaseUTXOType, 0, false),
   269  				},
   270  			},
   271  			err: false,
   272  		},
   273  	}
   274  
   275  	for i, c := range cases {
   276  		if err := c.inputView.ApplyBlock(c.block); c.err != (err != nil) {
   277  			t.Errorf("case #%d want err = %v, get err = %v", i, c.err, err)
   278  		}
   279  		if c.err {
   280  			continue
   281  		}
   282  		if !testutil.DeepEqual(c.inputView, c.fetchView) {
   283  			t.Errorf("test case %d, want %v, get %v", i, c.fetchView, c.inputView)
   284  		}
   285  	}
   286  }
   287  
   288  func TestDetachBlock(t *testing.T) {
   289  	cases := []struct {
   290  		block     *bc.Block
   291  		inputView *UtxoViewpoint
   292  		fetchView *UtxoViewpoint
   293  		gasOnlyTx bool
   294  		err       bool
   295  	}{
   296  		{
   297  			block: &bc.Block{
   298  				BlockHeader: &bc.BlockHeader{},
   299  				Transactions: []*bc.Tx{
   300  					&bc.Tx{
   301  						TxHeader: &bc.TxHeader{
   302  							ResultIds: []*bc.Hash{},
   303  						},
   304  						SpentOutputIDs: []bc.Hash{
   305  							bc.Hash{V0: 0},
   306  						},
   307  						Entries: defaultEntry,
   308  					},
   309  				},
   310  			},
   311  			inputView: NewUtxoViewpoint(),
   312  			fetchView: &UtxoViewpoint{
   313  				Entries: map[bc.Hash]*storage.UtxoEntry{
   314  					bc.Hash{V0: 0}: storage.NewUtxoEntry(storage.NormalUTXOType, 0, false),
   315  				},
   316  			},
   317  			err: false,
   318  		},
   319  		{
   320  			block: &bc.Block{
   321  				BlockHeader: &bc.BlockHeader{},
   322  				Transactions: []*bc.Tx{
   323  					&bc.Tx{
   324  						TxHeader: &bc.TxHeader{
   325  							ResultIds: []*bc.Hash{
   326  								&bc.Hash{V0: 0},
   327  							},
   328  						},
   329  						SpentOutputIDs: []bc.Hash{},
   330  						Entries:        defaultEntry,
   331  					},
   332  				},
   333  			},
   334  			inputView: NewUtxoViewpoint(),
   335  			fetchView: &UtxoViewpoint{
   336  				Entries: map[bc.Hash]*storage.UtxoEntry{
   337  					bc.Hash{V0: 0}: storage.NewUtxoEntry(storage.NormalUTXOType, 0, true),
   338  				},
   339  			},
   340  			err: false,
   341  		},
   342  		{
   343  			block: &bc.Block{
   344  				BlockHeader: &bc.BlockHeader{},
   345  				Transactions: []*bc.Tx{
   346  					&bc.Tx{
   347  						TxHeader: &bc.TxHeader{
   348  							ResultIds: []*bc.Hash{},
   349  						},
   350  						SpentOutputIDs: []bc.Hash{
   351  							bc.Hash{V0: 0},
   352  						},
   353  						Entries: defaultEntry,
   354  					},
   355  				},
   356  			},
   357  			inputView: &UtxoViewpoint{
   358  				Entries: map[bc.Hash]*storage.UtxoEntry{
   359  					bc.Hash{V0: 0}: storage.NewUtxoEntry(storage.NormalUTXOType, 0, false),
   360  				},
   361  			},
   362  			err: true,
   363  		},
   364  		{
   365  			block: &bc.Block{
   366  				BlockHeader: &bc.BlockHeader{},
   367  				Transactions: []*bc.Tx{
   368  					&bc.Tx{
   369  						TxHeader: &bc.TxHeader{
   370  							ResultIds: []*bc.Hash{},
   371  						},
   372  						SpentOutputIDs: []bc.Hash{
   373  							bc.Hash{V0: 0},
   374  						},
   375  						Entries: defaultEntry,
   376  					},
   377  				},
   378  			},
   379  			inputView: &UtxoViewpoint{
   380  				Entries: map[bc.Hash]*storage.UtxoEntry{
   381  					bc.Hash{V0: 0}: storage.NewUtxoEntry(storage.NormalUTXOType, 0, true),
   382  				},
   383  			},
   384  			fetchView: &UtxoViewpoint{
   385  				Entries: map[bc.Hash]*storage.UtxoEntry{
   386  					bc.Hash{V0: 0}: storage.NewUtxoEntry(storage.NormalUTXOType, 0, false),
   387  				},
   388  			},
   389  			err: false,
   390  		},
   391  	}
   392  
   393  	for i, c := range cases {
   394  		if err := c.inputView.DetachBlock(c.block); c.err != (err != nil) {
   395  			t.Errorf("case %d want err = %v, get err = %v", i, c.err, err)
   396  		}
   397  		if c.err {
   398  			continue
   399  		}
   400  		if !testutil.DeepEqual(c.inputView, c.fetchView) {
   401  			for hash, entry := range c.inputView.Entries {
   402  				fmt.Println(hash.String(), ":", entry.String())
   403  			}
   404  
   405  			for hash, entry := range c.fetchView.Entries {
   406  				fmt.Println(hash.String(), ":", entry.String())
   407  			}
   408  
   409  			t.Errorf("test case %d, want %v, get %v", i, c.fetchView, c.inputView)
   410  		}
   411  	}
   412  }