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

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