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

     1  package validation
     2  
     3  import (
     4  	"math"
     5  	"testing"
     6  
     7  	"github.com/davecgh/go-spew/spew"
     8  
     9  	"github.com/bytom/bytom/consensus"
    10  	"github.com/bytom/bytom/crypto/sha3pool"
    11  	"github.com/bytom/bytom/errors"
    12  	"github.com/bytom/bytom/protocol/bc"
    13  	"github.com/bytom/bytom/protocol/bc/types"
    14  	"github.com/bytom/bytom/protocol/vm"
    15  	"github.com/bytom/bytom/protocol/vm/vmutil"
    16  	"github.com/bytom/bytom/testutil"
    17  )
    18  
    19  func init() {
    20  	spew.Config.DisableMethods = true
    21  }
    22  
    23  func TestGasStatus(t *testing.T) {
    24  	cases := []struct {
    25  		input  *GasState
    26  		output *GasState
    27  		f      func(*GasState) error
    28  		err    error
    29  	}{
    30  		{
    31  			input: &GasState{
    32  				GasLeft:  10000,
    33  				GasUsed:  0,
    34  				BTMValue: 0,
    35  			},
    36  			output: &GasState{
    37  				GasLeft:  10000 / consensus.VMGasRate,
    38  				GasUsed:  0,
    39  				BTMValue: 10000,
    40  			},
    41  			f: func(input *GasState) error {
    42  				return input.setGas(10000, 0)
    43  			},
    44  			err: nil,
    45  		},
    46  		{
    47  			input: &GasState{
    48  				GasLeft:  10000,
    49  				GasUsed:  0,
    50  				BTMValue: 0,
    51  			},
    52  			output: &GasState{
    53  				GasLeft:  10000,
    54  				GasUsed:  0,
    55  				BTMValue: 0,
    56  			},
    57  			f: func(input *GasState) error {
    58  				return input.setGas(-10000, 0)
    59  			},
    60  			err: ErrGasCalculate,
    61  		},
    62  		{
    63  			input: &GasState{
    64  				GasLeft:  30000,
    65  				GasUsed:  0,
    66  				BTMValue: 0,
    67  			},
    68  			output: &GasState{
    69  				GasLeft:  300000,
    70  				GasUsed:  0,
    71  				BTMValue: 80000000000,
    72  			},
    73  			f: func(input *GasState) error {
    74  				return input.setGas(80000000000, 0)
    75  			},
    76  			err: nil,
    77  		},
    78  		{
    79  			input: &GasState{
    80  				GasLeft:  30000,
    81  				GasUsed:  0,
    82  				BTMValue: 0,
    83  			},
    84  			output: &GasState{
    85  				GasLeft:  300000,
    86  				GasUsed:  0,
    87  				BTMValue: math.MaxInt64,
    88  			},
    89  			f: func(input *GasState) error {
    90  				return input.setGas(math.MaxInt64, 0)
    91  			},
    92  			err: nil,
    93  		},
    94  		{
    95  			input: &GasState{
    96  				GasLeft:  10000,
    97  				GasUsed:  0,
    98  				BTMValue: 0,
    99  			},
   100  			output: &GasState{
   101  				GasLeft:  10000,
   102  				GasUsed:  0,
   103  				BTMValue: 0,
   104  			},
   105  			f: func(input *GasState) error {
   106  				return input.updateUsage(-1)
   107  			},
   108  			err: ErrGasCalculate,
   109  		},
   110  		{
   111  			input: &GasState{
   112  				GasLeft:  10000,
   113  				GasUsed:  0,
   114  				BTMValue: 0,
   115  			},
   116  			output: &GasState{
   117  				GasLeft:  9999,
   118  				GasUsed:  1,
   119  				BTMValue: 0,
   120  			},
   121  			f: func(input *GasState) error {
   122  				return input.updateUsage(9999)
   123  			},
   124  			err: nil,
   125  		},
   126  		{
   127  			input: &GasState{
   128  				GasLeft:  -10000,
   129  				GasUsed:  0,
   130  				BTMValue: 0,
   131  			},
   132  			output: &GasState{
   133  				GasLeft:  -10000,
   134  				GasUsed:  0,
   135  				BTMValue: 0,
   136  			},
   137  			f: func(input *GasState) error {
   138  				return input.updateUsage(math.MaxInt64)
   139  			},
   140  			err: ErrGasCalculate,
   141  		},
   142  		{
   143  			input: &GasState{
   144  				GasLeft:    1000,
   145  				GasUsed:    10,
   146  				StorageGas: 1000,
   147  			},
   148  			output: &GasState{
   149  				GasLeft:    0,
   150  				GasUsed:    1010,
   151  				StorageGas: 1000,
   152  			},
   153  			f: func(input *GasState) error {
   154  				return input.chargeStorageGas()
   155  			},
   156  			err: nil,
   157  		},
   158  		{
   159  			input: &GasState{
   160  				GasLeft:    900,
   161  				GasUsed:    10,
   162  				StorageGas: 1000,
   163  			},
   164  			output: &GasState{
   165  				GasLeft:    -100,
   166  				GasUsed:    10,
   167  				StorageGas: 1000,
   168  			},
   169  			f: func(input *GasState) error {
   170  				return input.chargeStorageGas()
   171  			},
   172  			err: ErrGasCalculate,
   173  		},
   174  		{
   175  			input: &GasState{
   176  				GasLeft:    1000,
   177  				GasUsed:    math.MaxInt64,
   178  				StorageGas: 1000,
   179  			},
   180  			output: &GasState{
   181  				GasLeft:    0,
   182  				GasUsed:    0,
   183  				StorageGas: 1000,
   184  			},
   185  			f: func(input *GasState) error {
   186  				return input.chargeStorageGas()
   187  			},
   188  			err: ErrGasCalculate,
   189  		},
   190  		{
   191  			input: &GasState{
   192  				GasLeft:    math.MinInt64,
   193  				GasUsed:    0,
   194  				StorageGas: 1000,
   195  			},
   196  			output: &GasState{
   197  				GasLeft:    0,
   198  				GasUsed:    0,
   199  				StorageGas: 1000,
   200  			},
   201  			f: func(input *GasState) error {
   202  				return input.chargeStorageGas()
   203  			},
   204  			err: ErrGasCalculate,
   205  		},
   206  	}
   207  
   208  	for i, c := range cases {
   209  		err := c.f(c.input)
   210  
   211  		if rootErr(err) != c.err {
   212  			t.Errorf("case %d: got error %s, want %s", i, err, c.err)
   213  		} else if *c.input != *c.output {
   214  			t.Errorf("case %d: gasStatus %v, want %v;", i, c.input, c.output)
   215  		}
   216  	}
   217  }
   218  
   219  func TestOverflow(t *testing.T) {
   220  	sourceID := &bc.Hash{V0: 9999}
   221  	ctrlProgram := []byte{byte(vm.OP_TRUE)}
   222  	converter := func(prog []byte) ([]byte, error) { return nil, nil }
   223  	newTx := func(inputs []uint64, outputs []uint64) *bc.Tx {
   224  		txInputs := make([]*types.TxInput, 0, len(inputs))
   225  		txOutputs := make([]*types.TxOutput, 0, len(outputs))
   226  
   227  		for i, amount := range inputs {
   228  			txInput := types.NewSpendInput(nil, *sourceID, *consensus.BTMAssetID, amount, uint64(i), ctrlProgram, nil)
   229  			txInputs = append(txInputs, txInput)
   230  		}
   231  
   232  		for _, amount := range outputs {
   233  			txOutput := types.NewOriginalTxOutput(*consensus.BTMAssetID, amount, ctrlProgram, nil)
   234  			txOutputs = append(txOutputs, txOutput)
   235  		}
   236  
   237  		txData := &types.TxData{
   238  			Version:        1,
   239  			SerializedSize: 100,
   240  			TimeRange:      0,
   241  			Inputs:         txInputs,
   242  			Outputs:        txOutputs,
   243  		}
   244  		return types.MapTx(txData)
   245  	}
   246  
   247  	cases := []struct {
   248  		inputs  []uint64
   249  		outputs []uint64
   250  		err     error
   251  	}{
   252  		{
   253  			inputs:  []uint64{math.MaxUint64, 1},
   254  			outputs: []uint64{0},
   255  			err:     ErrOverflow,
   256  		},
   257  		{
   258  			inputs:  []uint64{math.MaxUint64, math.MaxUint64},
   259  			outputs: []uint64{0},
   260  			err:     ErrOverflow,
   261  		},
   262  		{
   263  			inputs:  []uint64{math.MaxUint64, math.MaxUint64 - 1},
   264  			outputs: []uint64{0},
   265  			err:     ErrOverflow,
   266  		},
   267  		{
   268  			inputs:  []uint64{math.MaxInt64, 1},
   269  			outputs: []uint64{0},
   270  			err:     ErrOverflow,
   271  		},
   272  		{
   273  			inputs:  []uint64{math.MaxInt64, math.MaxInt64},
   274  			outputs: []uint64{0},
   275  			err:     ErrOverflow,
   276  		},
   277  		{
   278  			inputs:  []uint64{math.MaxInt64, math.MaxInt64 - 1},
   279  			outputs: []uint64{0},
   280  			err:     ErrOverflow,
   281  		},
   282  		{
   283  			inputs:  []uint64{0},
   284  			outputs: []uint64{math.MaxUint64},
   285  			err:     ErrOverflow,
   286  		},
   287  		{
   288  			inputs:  []uint64{0},
   289  			outputs: []uint64{math.MaxInt64},
   290  			err:     ErrGasCalculate,
   291  		},
   292  		{
   293  			inputs:  []uint64{math.MaxInt64 - 1},
   294  			outputs: []uint64{math.MaxInt64},
   295  			err:     ErrGasCalculate,
   296  		},
   297  	}
   298  
   299  	for i, c := range cases {
   300  		tx := newTx(c.inputs, c.outputs)
   301  		if _, err := ValidateTx(tx, mockBlock(), converter); rootErr(err) != c.err {
   302  			t.Fatalf("case %d test failed, want %s, have %s", i, c.err, rootErr(err))
   303  		}
   304  	}
   305  }
   306  
   307  func TestTxValidation(t *testing.T) {
   308  	var (
   309  		tx      *bc.Tx
   310  		vs      *validationState
   311  		fixture *txFixture
   312  
   313  		// the mux from tx, pulled out for convenience
   314  		mux *bc.Mux
   315  	)
   316  
   317  	addCoinbase := func(assetID *bc.AssetID, amount uint64, arbitrary []byte) {
   318  		coinbase := bc.NewCoinbase(arbitrary)
   319  		txOutput := types.NewOriginalTxOutput(*assetID, amount, []byte{byte(vm.OP_TRUE)}, nil)
   320  		muxID := getMuxID(tx)
   321  		coinbase.SetDestination(muxID, &txOutput.AssetAmount, uint64(len(mux.Sources)))
   322  		coinbaseID := bc.EntryID(coinbase)
   323  		tx.Entries[coinbaseID] = coinbase
   324  
   325  		mux.Sources = append(mux.Sources, &bc.ValueSource{
   326  			Ref:   &coinbaseID,
   327  			Value: &txOutput.AssetAmount,
   328  		})
   329  
   330  		src := &bc.ValueSource{
   331  			Ref:      muxID,
   332  			Value:    &txOutput.AssetAmount,
   333  			Position: uint64(len(tx.ResultIds)),
   334  		}
   335  		prog := &bc.Program{txOutput.VMVersion, txOutput.ControlProgram}
   336  		output := bc.NewOriginalOutput(src, prog, nil, uint64(len(tx.ResultIds)))
   337  		outputID := bc.EntryID(output)
   338  		tx.Entries[outputID] = output
   339  
   340  		dest := &bc.ValueDestination{
   341  			Value:    src.Value,
   342  			Ref:      &outputID,
   343  			Position: 0,
   344  		}
   345  		mux.WitnessDestinations = append(mux.WitnessDestinations, dest)
   346  		tx.ResultIds = append(tx.ResultIds, &outputID)
   347  		vs.block.Transactions = append(vs.block.Transactions, vs.tx)
   348  	}
   349  
   350  	cases := []struct {
   351  		desc string // description of the test case
   352  		f    func() // function to adjust tx, vs, and/or mux
   353  		err  error  // expected error
   354  	}{
   355  		{
   356  			desc: "base case",
   357  		},
   358  		{
   359  			desc: "unbalanced mux amounts",
   360  			f: func() {
   361  				mux.Sources[0].Value.Amount++
   362  				iss := tx.Entries[*mux.Sources[0].Ref].(*bc.Issuance)
   363  				iss.WitnessDestination.Value.Amount++
   364  			},
   365  			err: ErrUnbalanced,
   366  		},
   367  		{
   368  			desc: "unbalanced mux amounts",
   369  			f: func() {
   370  				mux.WitnessDestinations[0].Value.Amount++
   371  			},
   372  			err: ErrUnbalanced,
   373  		},
   374  		{
   375  			desc: "balanced mux amounts",
   376  			f: func() {
   377  				mux.Sources[1].Value.Amount++
   378  				mux.WitnessDestinations[0].Value.Amount++
   379  			},
   380  			err: nil,
   381  		},
   382  		{
   383  			desc: "overflowing mux source amounts",
   384  			f: func() {
   385  				mux.Sources[0].Value.Amount = math.MaxInt64
   386  				iss := tx.Entries[*mux.Sources[0].Ref].(*bc.Issuance)
   387  				iss.WitnessDestination.Value.Amount = math.MaxInt64
   388  			},
   389  			err: ErrOverflow,
   390  		},
   391  		{
   392  			desc: "underflowing mux destination amounts",
   393  			f: func() {
   394  				mux.WitnessDestinations[0].Value.Amount = math.MaxInt64
   395  				out := tx.Entries[*mux.WitnessDestinations[0].Ref].(*bc.OriginalOutput)
   396  				out.Source.Value.Amount = math.MaxInt64
   397  				mux.WitnessDestinations[1].Value.Amount = math.MaxInt64
   398  				out = tx.Entries[*mux.WitnessDestinations[1].Ref].(*bc.OriginalOutput)
   399  				out.Source.Value.Amount = math.MaxInt64
   400  			},
   401  			err: ErrOverflow,
   402  		},
   403  		{
   404  			desc: "unbalanced mux assets",
   405  			f: func() {
   406  				mux.Sources[1].Value.AssetId = newAssetID(255)
   407  				sp := tx.Entries[*mux.Sources[1].Ref].(*bc.Spend)
   408  				sp.WitnessDestination.Value.AssetId = newAssetID(255)
   409  			},
   410  			err: ErrUnbalanced,
   411  		},
   412  		{
   413  			desc: "mismatched output source / mux dest position",
   414  			f: func() {
   415  				tx.Entries[*tx.ResultIds[0]].(*bc.OriginalOutput).Source.Position = 1
   416  			},
   417  			err: ErrMismatchedPosition,
   418  		},
   419  		{
   420  			desc: "mismatched input dest / mux source position",
   421  			f: func() {
   422  				mux.Sources[0].Position = 1
   423  			},
   424  			err: ErrMismatchedPosition,
   425  		},
   426  		{
   427  			desc: "mismatched output source and mux dest",
   428  			f: func() {
   429  				// For this test, it's necessary to construct a mostly
   430  				// identical second transaction in order to get a similar but
   431  				// not equal output entry for the mux to falsely point
   432  				// to. That entry must be added to the first tx's Entries map.
   433  				fixture2 := sample(t, fixture)
   434  				tx2 := types.NewTx(*fixture2.tx).Tx
   435  				out2ID := tx2.ResultIds[0]
   436  				out2 := tx2.Entries[*out2ID].(*bc.OriginalOutput)
   437  				tx.Entries[*out2ID] = out2
   438  				mux.WitnessDestinations[0].Ref = out2ID
   439  			},
   440  			err: ErrMismatchedReference,
   441  		},
   442  		{
   443  			desc: "mismatched input dest and mux source",
   444  			f: func() {
   445  				fixture2 := sample(t, fixture)
   446  				tx2 := types.NewTx(*fixture2.tx).Tx
   447  				input2ID := tx2.InputIDs[2]
   448  				input2 := tx2.Entries[input2ID].(*bc.Spend)
   449  				dest2Ref := input2.WitnessDestination.Ref
   450  				dest2 := tx2.Entries[*dest2Ref].(*bc.Mux)
   451  				tx.Entries[*dest2Ref] = dest2
   452  				tx.Entries[input2ID] = input2
   453  				mux.Sources[0].Ref = &input2ID
   454  			},
   455  			err: ErrMismatchedReference,
   456  		},
   457  		{
   458  			desc: "invalid mux destination position",
   459  			f: func() {
   460  				mux.WitnessDestinations[0].Position = 1
   461  			},
   462  			err: ErrPosition,
   463  		},
   464  		{
   465  			desc: "mismatched mux dest value / output source value",
   466  			f: func() {
   467  				outID := tx.ResultIds[0]
   468  				out := tx.Entries[*outID].(*bc.OriginalOutput)
   469  				mux.WitnessDestinations[0].Value = &bc.AssetAmount{
   470  					AssetId: out.Source.Value.AssetId,
   471  					Amount:  out.Source.Value.Amount + 1,
   472  				}
   473  				mux.Sources[0].Value.Amount++ // the mux must still balance
   474  			},
   475  			err: ErrMismatchedValue,
   476  		},
   477  		{
   478  			desc: "empty tx results",
   479  			f: func() {
   480  				tx.ResultIds = nil
   481  			},
   482  			err: ErrEmptyResults,
   483  		},
   484  		{
   485  			desc: "empty tx results, but that's OK",
   486  			f: func() {
   487  				tx.Version = 2
   488  				tx.ResultIds = nil
   489  			},
   490  		},
   491  		{
   492  			desc: "issuance program failure",
   493  			f: func() {
   494  				iss := txIssuance(t, tx, 0)
   495  				iss.WitnessArguments[0] = []byte{}
   496  			},
   497  			err: vm.ErrFalseVMResult,
   498  		},
   499  		{
   500  			desc: "spend control program failure",
   501  			f: func() {
   502  				spend := txSpend(t, tx, 1)
   503  				spend.WitnessArguments[0] = []byte{}
   504  			},
   505  			err: vm.ErrFalseVMResult,
   506  		},
   507  		{
   508  			desc: "mismatched spent source/witness value",
   509  			f: func() {
   510  				spend := txSpend(t, tx, 1)
   511  				spentOutput := tx.Entries[*spend.SpentOutputId].(*bc.OriginalOutput)
   512  				spentOutput.Source.Value = &bc.AssetAmount{
   513  					AssetId: spend.WitnessDestination.Value.AssetId,
   514  					Amount:  spend.WitnessDestination.Value.Amount + 1,
   515  				}
   516  			},
   517  			err: ErrMismatchedValue,
   518  		},
   519  		{
   520  			desc: "gas out of limit",
   521  			f: func() {
   522  				vs.tx.SerializedSize = 10000000
   523  			},
   524  			err: ErrOverGasCredit,
   525  		},
   526  		{
   527  			desc: "no gas spend input",
   528  			f: func() {
   529  				spendID := mux.Sources[len(mux.Sources)-1].Ref
   530  				delete(tx.Entries, *spendID)
   531  				mux.Sources = mux.Sources[:len(mux.Sources)-1]
   532  				vs.gasStatus.GasLeft = 0
   533  			},
   534  			err: vm.ErrRunLimitExceeded,
   535  		},
   536  		{
   537  			desc: "no gas spend input, but set gas left, so it's ok",
   538  			f: func() {
   539  				spendID := mux.Sources[len(mux.Sources)-1].Ref
   540  				delete(tx.Entries, *spendID)
   541  				mux.Sources = mux.Sources[:len(mux.Sources)-1]
   542  			},
   543  			err: nil,
   544  		},
   545  		{
   546  			desc: "mismatched gas spend input destination amount/prevout source amount",
   547  			f: func() {
   548  				spendID := mux.Sources[len(mux.Sources)-1].Ref
   549  				spend := tx.Entries[*spendID].(*bc.Spend)
   550  				spend.WitnessDestination.Value = &bc.AssetAmount{
   551  					AssetId: spend.WitnessDestination.Value.AssetId,
   552  					Amount:  spend.WitnessDestination.Value.Amount + 1,
   553  				}
   554  			},
   555  			err: ErrMismatchedValue,
   556  		},
   557  		{
   558  			desc: "mismatched witness asset destination",
   559  			f: func() {
   560  				issuanceID := mux.Sources[0].Ref
   561  				issuance := tx.Entries[*issuanceID].(*bc.Issuance)
   562  				issuance.WitnessAssetDefinition.Data = &bc.Hash{V0: 9999}
   563  			},
   564  			err: ErrMismatchedAssetID,
   565  		},
   566  		{
   567  			desc: "issuance witness position greater than length of mux sources",
   568  			f: func() {
   569  				issuanceID := mux.Sources[0].Ref
   570  				issuance := tx.Entries[*issuanceID].(*bc.Issuance)
   571  				issuance.WitnessDestination.Position = uint64(len(mux.Sources) + 1)
   572  			},
   573  			err: ErrPosition,
   574  		},
   575  		{
   576  			desc: "normal coinbase tx",
   577  			f: func() {
   578  				addCoinbase(consensus.BTMAssetID, 100000, nil)
   579  			},
   580  			err: nil,
   581  		},
   582  		{
   583  			desc: "invalid coinbase tx asset id",
   584  			f: func() {
   585  				addCoinbase(&bc.AssetID{V1: 100}, 100000, nil)
   586  			},
   587  			err: ErrWrongCoinbaseAsset,
   588  		},
   589  		{
   590  			desc: "coinbase tx is not first tx in block",
   591  			f: func() {
   592  				addCoinbase(consensus.BTMAssetID, 100000, nil)
   593  				vs.block.Transactions[0] = nil
   594  			},
   595  			err: ErrWrongCoinbaseTransaction,
   596  		},
   597  		{
   598  			desc: "coinbase arbitrary size out of limit",
   599  			f: func() {
   600  				arbitrary := make([]byte, consensus.CoinbaseArbitrarySizeLimit+1)
   601  				addCoinbase(consensus.BTMAssetID, 100000, arbitrary)
   602  			},
   603  			err: ErrCoinbaseArbitraryOversize,
   604  		},
   605  		{
   606  			desc: "normal retirement output",
   607  			f: func() {
   608  				outputID := tx.ResultIds[0]
   609  				output := tx.Entries[*outputID].(*bc.OriginalOutput)
   610  				retirement := bc.NewRetirement(output.Source, output.Ordinal)
   611  				retirementID := bc.EntryID(retirement)
   612  				tx.Entries[retirementID] = retirement
   613  				delete(tx.Entries, *outputID)
   614  				tx.ResultIds[0] = &retirementID
   615  				mux.WitnessDestinations[0].Ref = &retirementID
   616  			},
   617  			err: nil,
   618  		},
   619  		{
   620  			desc: "ordinal doesn't matter for prevouts",
   621  			f: func() {
   622  				spend := txSpend(t, tx, 1)
   623  				prevout := tx.Entries[*spend.SpentOutputId].(*bc.OriginalOutput)
   624  				newPrevout := bc.NewOriginalOutput(prevout.Source, prevout.ControlProgram, prevout.StateData, 10)
   625  				hash := bc.EntryID(newPrevout)
   626  				spend.SpentOutputId = &hash
   627  			},
   628  			err: nil,
   629  		},
   630  		{
   631  			desc: "mux witness destination have no source",
   632  			f: func() {
   633  				dest := &bc.ValueDestination{
   634  					Value: &bc.AssetAmount{
   635  						AssetId: &bc.AssetID{V2: 1000},
   636  						Amount:  100,
   637  					},
   638  					Ref:      mux.WitnessDestinations[0].Ref,
   639  					Position: 0,
   640  				}
   641  				mux.WitnessDestinations = append(mux.WitnessDestinations, dest)
   642  			},
   643  			err: ErrNoSource,
   644  		},
   645  	}
   646  
   647  	for i, c := range cases {
   648  		t.Run(c.desc, func(t *testing.T) {
   649  			fixture = sample(t, nil)
   650  			tx = types.NewTx(*fixture.tx).Tx
   651  			vs = &validationState{
   652  				block:   mockBlock(),
   653  				tx:      tx,
   654  				entryID: tx.ID,
   655  				gasStatus: &GasState{
   656  					GasLeft: int64(80000),
   657  					GasUsed: 0,
   658  				},
   659  				cache: make(map[bc.Hash]error),
   660  			}
   661  			muxID := getMuxID(tx)
   662  			mux = tx.Entries[*muxID].(*bc.Mux)
   663  
   664  			if c.f != nil {
   665  				c.f()
   666  			}
   667  			err := checkValid(vs, tx.TxHeader)
   668  
   669  			if rootErr(err) != c.err {
   670  				t.Errorf("case #%d (%s) got error %s, want %s; validationState is:\n%s", i, c.desc, err, c.err, spew.Sdump(vs))
   671  			}
   672  		})
   673  	}
   674  }
   675  
   676  // TestCoinbase test the coinbase transaction is valid (txtest#1016)
   677  func TestCoinbase(t *testing.T) {
   678  	cp, _ := vmutil.DefaultCoinbaseProgram()
   679  	retire, _ := vmutil.RetireProgram([]byte{})
   680  	converter := func(prog []byte) ([]byte, error) { return nil, nil }
   681  	CbTx := types.MapTx(&types.TxData{
   682  		SerializedSize: 1,
   683  		Inputs: []*types.TxInput{
   684  			types.NewCoinbaseInput(nil),
   685  		},
   686  		Outputs: []*types.TxOutput{
   687  			types.NewOriginalTxOutput(*consensus.BTMAssetID, 888, cp, nil),
   688  		},
   689  	})
   690  
   691  	cases := []struct {
   692  		block   *bc.Block
   693  		txIndex int
   694  		err     error
   695  	}{
   696  		{
   697  			block: &bc.Block{
   698  				BlockHeader:  &bc.BlockHeader{Height: 666},
   699  				Transactions: []*bc.Tx{CbTx},
   700  			},
   701  			txIndex: 0,
   702  			err:     nil,
   703  		},
   704  		{
   705  			block: &bc.Block{
   706  				BlockHeader: &bc.BlockHeader{Height: 666},
   707  				Transactions: []*bc.Tx{
   708  					CbTx,
   709  					types.MapTx(&types.TxData{
   710  						SerializedSize: 1,
   711  						Inputs: []*types.TxInput{
   712  							types.NewCoinbaseInput(nil),
   713  						},
   714  						Outputs: []*types.TxOutput{
   715  							types.NewOriginalTxOutput(*consensus.BTMAssetID, 888, cp, nil),
   716  						},
   717  					}),
   718  				},
   719  			},
   720  			txIndex: 1,
   721  			err:     ErrWrongCoinbaseTransaction,
   722  		},
   723  		{
   724  			block: &bc.Block{
   725  				BlockHeader: &bc.BlockHeader{Height: 666},
   726  				Transactions: []*bc.Tx{
   727  					CbTx,
   728  					types.MapTx(&types.TxData{
   729  						SerializedSize: 1,
   730  						Inputs: []*types.TxInput{
   731  							types.NewCoinbaseInput(nil),
   732  							types.NewSpendInput([][]byte{}, *newHash(8), *consensus.BTMAssetID, 100000000, 0, cp, nil),
   733  						},
   734  						Outputs: []*types.TxOutput{
   735  							types.NewOriginalTxOutput(*consensus.BTMAssetID, 888, cp, nil),
   736  							types.NewOriginalTxOutput(*consensus.BTMAssetID, 90000000, cp, nil),
   737  						},
   738  					}),
   739  				},
   740  			},
   741  			txIndex: 1,
   742  			err:     ErrWrongCoinbaseTransaction,
   743  		},
   744  		{
   745  			block: &bc.Block{
   746  				BlockHeader: &bc.BlockHeader{Height: 666},
   747  				Transactions: []*bc.Tx{
   748  					CbTx,
   749  					types.MapTx(&types.TxData{
   750  						SerializedSize: 1,
   751  						Inputs: []*types.TxInput{
   752  							types.NewSpendInput([][]byte{}, *newHash(8), *consensus.BTMAssetID, 100000000, 0, cp, nil),
   753  							types.NewCoinbaseInput(nil),
   754  						},
   755  						Outputs: []*types.TxOutput{
   756  							types.NewOriginalTxOutput(*consensus.BTMAssetID, 888, cp, nil),
   757  							types.NewOriginalTxOutput(*consensus.BTMAssetID, 90000000, cp, nil),
   758  						},
   759  					}),
   760  				},
   761  			},
   762  			txIndex: 1,
   763  			err:     ErrWrongCoinbaseTransaction,
   764  		},
   765  		{
   766  			block: &bc.Block{
   767  				BlockHeader: &bc.BlockHeader{Height: 666},
   768  				Transactions: []*bc.Tx{
   769  					types.MapTx(&types.TxData{
   770  						SerializedSize: 1,
   771  						Inputs: []*types.TxInput{
   772  							types.NewCoinbaseInput(nil),
   773  							types.NewSpendInput([][]byte{}, *newHash(8), *consensus.BTMAssetID, 100000000, 0, cp, nil),
   774  						},
   775  						Outputs: []*types.TxOutput{
   776  							types.NewOriginalTxOutput(*consensus.BTMAssetID, 888, cp, nil),
   777  							types.NewOriginalTxOutput(*consensus.BTMAssetID, 90000000, cp, nil),
   778  						},
   779  					}),
   780  				},
   781  			},
   782  			txIndex: 0,
   783  			err:     nil,
   784  		},
   785  		{
   786  			block: &bc.Block{
   787  				BlockHeader: &bc.BlockHeader{Height: 666},
   788  				Transactions: []*bc.Tx{
   789  					types.MapTx(&types.TxData{
   790  						SerializedSize: 1,
   791  						Inputs: []*types.TxInput{
   792  							types.NewCoinbaseInput(nil),
   793  							types.NewSpendInput([][]byte{}, *newHash(8), *consensus.BTMAssetID, 100000000, 0, retire, nil),
   794  						},
   795  						Outputs: []*types.TxOutput{
   796  							types.NewOriginalTxOutput(*consensus.BTMAssetID, 888, cp, nil),
   797  							types.NewOriginalTxOutput(*consensus.BTMAssetID, 90000000, cp, nil),
   798  						},
   799  					}),
   800  				},
   801  			},
   802  			txIndex: 0,
   803  			err:     vm.ErrReturn,
   804  		},
   805  	}
   806  
   807  	for i, c := range cases {
   808  		_, err := ValidateTx(c.block.Transactions[c.txIndex], c.block, converter)
   809  		if rootErr(err) != c.err {
   810  			t.Errorf("#%d got error %s, want %s", i, err, c.err)
   811  		}
   812  	}
   813  }
   814  
   815  func TestDoubleSpend(t *testing.T) {
   816  	testData := "07010004016201609bc47dda88eee18c7433340c16e054cabee4318a8d638e873be19e979df81dc7ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0e3f9f5c80e0101160014f233267911e94dc74df706fe3b697273e212d5450063024088b5e730136407312980d3b1446004a8c552111721a4ba48044365cf7f7785542f2d7799f73d7cba1be2301fdfb91ad6ea99559b1857a25336eaefd90675870f207642ba797fd89d1f98a8559b4ca74123697dd4dee882955acd0da9010a80d64e0161015fe334d4fe18398f0232d2aca7050388ce4ee5ae82c8148d7f0cea748438b65135ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff80ace684200101160014f233267911e94dc74df706fe3b697273e212d545006302404a17a5995b8163ee448719b462a5694b22a35522dd9883333fd462cc3d0aabf049445c5cbb911a40e1906a5bea99b23b1a79e215eeb1a818d8b1dd27e06f3004207642ba797fd89d1f98a8559b4ca74123697dd4dee882955acd0da9010a80d64e016201609bc47dda88eee18c7433340c16e054cabee4318a8d638e873be19e979df81dc7ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0e3f9f5c80e0101160014f233267911e94dc74df706fe3b697273e212d5450063024088b5e730136407312980d3b1446004a8c552111721a4ba48044365cf7f7785542f2d7799f73d7cba1be2301fdfb91ad6ea99559b1857a25336eaefd90675870f207642ba797fd89d1f98a8559b4ca74123697dd4dee882955acd0da9010a80d64e0161015fe334d4fe18398f0232d2aca7050388ce4ee5ae82c8148d7f0cea748438b65135ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff80ace684200101160014f233267911e94dc74df706fe3b697273e212d545006302409278702c74eb3ae7666f9da4841443a4b001d6c7d7de631faf9f26eb464f6cdd741dcd4c2f3a1eb47cbc345f56a16902380b8f74b7a559f9bec854bd0e955b0c207642ba797fd89d1f98a8559b4ca74123697dd4dee882955acd0da9010a80d64e0201003fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffa08ba3fae80e01160014aac0345165045e612b3d7363f39a372bead80ce7000001003fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe08fe0fae80e01160014aac0345165045e612b3d7363f39a372bead80ce70000"
   817  	/*
   818  		07  // serflags
   819  		01  // tx version
   820  		00  // time range
   821  		04  // input cnts
   822  
   823  		01  // input0: asset version
   824  		63  // input 0: input commitment length   +state length
   825  		01  // input 0: spend type flag
   826  		61 // input 0: spend commitment length  + state length
   827  		9bc47dda88eee18c7433340c16e054cabee4318a8d638e873be19e979df81dc7  // input 0: source id
   828  		ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff  // input 0: assetID
   829  		e0e3f9f5c80e  // amt
   830  		01  // source pos
   831  		01  // vm version
   832  		16  // spend program length
   833  		00147c7662d92bd5e77454736f94731c60a6e9cbc69f // spend program  + after state encode
   834  		00
   835  		63 // witness length
   836  		02 // arg array length
   837  		40 // 1 arg length
   838  		4a17a5995b8163ee448719b462a5694b22a35522dd9883333fd462cc3d0aabf049445c5cbb911a40e1906a5bea99b23b1a79e215eeb1a818d8b1dd27e06f3004 // 1 arg data
   839  		20 // 2 arg length
   840  		0530c4bc9dd3cbf679fec6d824ce5c37b0c8dab88b67bcae3b000924b7dce994 // 2 arg data
   841  		01 // input 1 ~ input 3,output 0 ~ output1 ...
   842  		61
   843  		01
   844  		5f
   845  		e334d4fe18398f0232d2aca7050388ce4ee5ae82c8148d7f0cea748438b65135
   846  		ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
   847  		80ace68420
   848  		01
   849  		01
   850  		16
   851  		00147c7662d92bd5e77454736f94731c60a6e9cbc69f
   852  		00
   853  		63
   854  		02
   855  		40
   856  		4a17a5995b8163ee448719b462a5694b22a35522dd9883333fd462cc3d0aabf049445c5cbb911a40e1906a5bea99b23b1a79e215eeb1a818d8b1dd27e06f3004
   857  		20
   858  		0530c4bc9dd3cbf679fec6d824ce5c37b0c8dab88b67bcae3b000924b7dce994
   859  		01  // input2
   860  		62
   861  		01
   862  		60
   863  		9bc47dda88eee18c7433340c16e054cabee4318a8d638e873be19e979df81dc7
   864  		ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
   865  		e0e3f9f5c80e
   866  		01
   867  		01
   868  		16
   869  		00147c7662d92bd5e77454736f94731c60a6e9cbc69f
   870  		00
   871  		63
   872  		02
   873  		40
   874  		62c29b20941e7f762c3afae232f61d8dac1c544825931e391408c6715c408ef69f494a1b3b61ce380ddee0c8b18ecac2b46ef96a62eebb6ec40f9f545410870a
   875  		20
   876  		0530c4bc9dd3cbf679fec6d824ce5c37b0c8dab88b67bcae3b000924b7dce994
   877  		01 // input3
   878  		61
   879  		01
   880  		5f
   881  		e334d4fe18398f0232d2aca7050388ce4ee5ae82c8148d7f0cea748438b65135
   882  		ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
   883  		80ace68420
   884  		01
   885  		01
   886  		16
   887  		00147c7662d92bd5e77454736f94731c60a6e9cbc69f
   888  		00
   889  		63
   890  		02
   891  		40
   892  		e443d66c75b4d5fa71676d60b0b067e6941f06349f31e5f73a7d51a73f5797632b2e01e8584cd1c8730dc16df075866b0c796bd7870182e2da4b37188208fe02
   893  		20
   894  		0530c4bc9dd3cbf679fec6d824ce5c37b0c8dab88b67bcae3b000924b7dce994
   895  		02  //output cnts
   896  		01
   897  		00
   898  		3f
   899  		ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
   900  		a08ba3fae80e
   901  		01
   902  		16
   903  		0014aac0345165045e612b3d7363f39a372bead80ce7
   904  		00
   905  		00
   906  		01003f
   907  		ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe08fe0fae80e01160014aac0345165045e612b3d7363f39a372bead80ce700
   908  		00
   909  	*/
   910  	converter := func(prog []byte) ([]byte, error) { return nil, nil }
   911  	tx := types.Tx{}
   912  	if err := tx.UnmarshalText([]byte(testData)); err != nil {
   913  		t.Errorf("fail on unmarshal txData: %s", err)
   914  	}
   915  	cases := []struct {
   916  		block    *bc.Block
   917  		GasValid bool
   918  		err      error
   919  	}{
   920  		{
   921  			block: &bc.Block{
   922  				BlockHeader: &bc.BlockHeader{
   923  					Height: 5000,
   924  				},
   925  			},
   926  			err: ErrInputDoubleSend,
   927  		},
   928  	}
   929  
   930  	for i, c := range cases {
   931  		_, err := ValidateTx(tx.Tx, c.block, converter)
   932  		if rootErr(err) != c.err {
   933  			t.Errorf("#%d got error %s, want %s", i, err, c.err)
   934  		}
   935  	}
   936  }
   937  
   938  // TestTimeRange test the checkTimeRange function (txtest#1004)
   939  func TestTimeRange(t *testing.T) {
   940  	converter := func(prog []byte) ([]byte, error) { return nil, nil }
   941  	cases := []struct {
   942  		timeRange uint64
   943  		err       bool
   944  	}{
   945  		{
   946  			timeRange: 0,
   947  			err:       false,
   948  		},
   949  		{
   950  			timeRange: 334,
   951  			err:       false,
   952  		},
   953  		{
   954  			timeRange: 332,
   955  			err:       true,
   956  		},
   957  		{
   958  			timeRange: 1521625824,
   959  			err:       false,
   960  		},
   961  	}
   962  
   963  	block := &bc.Block{
   964  		BlockHeader: &bc.BlockHeader{
   965  			Height:    333,
   966  			Timestamp: 1521625823,
   967  		},
   968  	}
   969  
   970  	tx := types.MapTx(&types.TxData{
   971  		SerializedSize: 1,
   972  		TimeRange:      0,
   973  		Inputs: []*types.TxInput{
   974  			mockGasTxInput(),
   975  		},
   976  		Outputs: []*types.TxOutput{
   977  			types.NewOriginalTxOutput(*consensus.BTMAssetID, 1, []byte{0x6a}, nil),
   978  		},
   979  	})
   980  
   981  	for i, c := range cases {
   982  		tx.TimeRange = c.timeRange
   983  		if _, err := ValidateTx(tx, block, converter); (err != nil) != c.err {
   984  			t.Errorf("#%d got error %t, want %t", i, !c.err, c.err)
   985  		}
   986  	}
   987  }
   988  
   989  func TestValidateTxVersion(t *testing.T) {
   990  	converter := func(prog []byte) ([]byte, error) { return nil, nil }
   991  	cases := []struct {
   992  		desc  string
   993  		block *bc.Block
   994  		err   error
   995  	}{
   996  		{
   997  			desc: "tx version greater than 1 (txtest#1001)",
   998  			block: &bc.Block{
   999  				BlockHeader: &bc.BlockHeader{Version: 1},
  1000  				Transactions: []*bc.Tx{
  1001  					{TxHeader: &bc.TxHeader{Version: 2}},
  1002  				},
  1003  			},
  1004  			err: ErrTxVersion,
  1005  		},
  1006  		{
  1007  			desc: "tx version equals 0 (txtest#1002)",
  1008  			block: &bc.Block{
  1009  				BlockHeader: &bc.BlockHeader{Version: 1},
  1010  				Transactions: []*bc.Tx{
  1011  					{TxHeader: &bc.TxHeader{Version: 0}},
  1012  				},
  1013  			},
  1014  			err: ErrTxVersion,
  1015  		},
  1016  		{
  1017  			desc: "tx version equals max uint64 (txtest#1003)",
  1018  			block: &bc.Block{
  1019  				BlockHeader: &bc.BlockHeader{Version: 1},
  1020  				Transactions: []*bc.Tx{
  1021  					{TxHeader: &bc.TxHeader{Version: math.MaxUint64}},
  1022  				},
  1023  			},
  1024  			err: ErrTxVersion,
  1025  		},
  1026  	}
  1027  
  1028  	for i, c := range cases {
  1029  		if _, err := ValidateTx(c.block.Transactions[0], c.block, converter); rootErr(err) != c.err {
  1030  			t.Errorf("case #%d (%s) got error %t, want %t", i, c.desc, err, c.err)
  1031  		}
  1032  	}
  1033  }
  1034  
  1035  // A txFixture is returned by sample (below) to produce a sample
  1036  // transaction, which takes a separate, optional _input_ txFixture to
  1037  // affect the transaction that's built. The components of the
  1038  // transaction are the fields of txFixture.
  1039  type txFixture struct {
  1040  	initialBlockID bc.Hash
  1041  	issuanceProg   bc.Program
  1042  	issuanceArgs   [][]byte
  1043  	assetDef       []byte
  1044  	assetID        bc.AssetID
  1045  	txVersion      uint64
  1046  	txInputs       []*types.TxInput
  1047  	txOutputs      []*types.TxOutput
  1048  	tx             *types.TxData
  1049  }
  1050  
  1051  // Produces a sample transaction in a txFixture object (see above). A
  1052  // separate input txFixture can be used to alter the transaction
  1053  // that's created.
  1054  //
  1055  // The output of this function can be used as the input to a
  1056  // subsequent call to make iterative refinements to a test object.
  1057  //
  1058  // The default transaction produced is valid and has three inputs:
  1059  //  - an issuance of 10 units
  1060  //  - a spend of 20 units
  1061  //  - a spend of 40 units
  1062  // and two outputs, one of 25 units and one of 45 units.
  1063  // All amounts are denominated in the same asset.
  1064  //
  1065  // The issuance program for the asset requires two numbers as
  1066  // arguments that add up to 5. The prevout control programs require
  1067  // two numbers each, adding to 9 and 13, respectively.
  1068  //
  1069  // The min and max times for the transaction are now +/- one minute.
  1070  func sample(tb testing.TB, in *txFixture) *txFixture {
  1071  	var result txFixture
  1072  	if in != nil {
  1073  		result = *in
  1074  	}
  1075  
  1076  	if result.initialBlockID.IsZero() {
  1077  		result.initialBlockID = *newHash(1)
  1078  	}
  1079  	if testutil.DeepEqual(result.issuanceProg, bc.Program{}) {
  1080  		prog, err := vm.Assemble("ADD 5 NUMEQUAL")
  1081  		if err != nil {
  1082  			tb.Fatal(err)
  1083  		}
  1084  		result.issuanceProg = bc.Program{VmVersion: 1, Code: prog}
  1085  	}
  1086  	if len(result.issuanceArgs) == 0 {
  1087  		result.issuanceArgs = [][]byte{{2}, {3}}
  1088  	}
  1089  	if len(result.assetDef) == 0 {
  1090  		result.assetDef = []byte{2}
  1091  	}
  1092  	if result.assetID.IsZero() {
  1093  		refdatahash := hashData(result.assetDef)
  1094  		result.assetID = bc.ComputeAssetID(result.issuanceProg.Code, result.issuanceProg.VmVersion, &refdatahash)
  1095  	}
  1096  
  1097  	if result.txVersion == 0 {
  1098  		result.txVersion = 1
  1099  	}
  1100  	if len(result.txInputs) == 0 {
  1101  		cp1, err := vm.Assemble("ADD 9 NUMEQUAL")
  1102  		if err != nil {
  1103  			tb.Fatal(err)
  1104  		}
  1105  		args1 := [][]byte{{4}, {5}}
  1106  
  1107  		cp2, err := vm.Assemble("ADD 13 NUMEQUAL")
  1108  		if err != nil {
  1109  			tb.Fatal(err)
  1110  		}
  1111  		args2 := [][]byte{{6}, {7}}
  1112  
  1113  		result.txInputs = []*types.TxInput{
  1114  			types.NewIssuanceInput([]byte{3}, 10, result.issuanceProg.Code, result.issuanceArgs, result.assetDef),
  1115  			types.NewSpendInput(args1, *newHash(5), result.assetID, 20, 0, cp1, nil),
  1116  			types.NewSpendInput(args2, *newHash(8), result.assetID, 40, 0, cp2, nil),
  1117  		}
  1118  	}
  1119  
  1120  	result.txInputs = append(result.txInputs, mockGasTxInput())
  1121  
  1122  	if len(result.txOutputs) == 0 {
  1123  		cp1, err := vm.Assemble("ADD 17 NUMEQUAL")
  1124  		if err != nil {
  1125  			tb.Fatal(err)
  1126  		}
  1127  		cp2, err := vm.Assemble("ADD 21 NUMEQUAL")
  1128  		if err != nil {
  1129  			tb.Fatal(err)
  1130  		}
  1131  
  1132  		result.txOutputs = []*types.TxOutput{
  1133  			types.NewOriginalTxOutput(result.assetID, 25, cp1, nil),
  1134  			types.NewOriginalTxOutput(result.assetID, 45, cp2, nil),
  1135  		}
  1136  	}
  1137  
  1138  	result.tx = &types.TxData{
  1139  		Version: result.txVersion,
  1140  		Inputs:  result.txInputs,
  1141  		Outputs: result.txOutputs,
  1142  	}
  1143  
  1144  	return &result
  1145  }
  1146  
  1147  func mockBlock() *bc.Block {
  1148  	return &bc.Block{
  1149  		BlockHeader: &bc.BlockHeader{
  1150  			Height: 666,
  1151  		},
  1152  	}
  1153  }
  1154  
  1155  func mockGasTxInput() *types.TxInput {
  1156  	cp, _ := vmutil.DefaultCoinbaseProgram()
  1157  	return types.NewSpendInput([][]byte{}, *newHash(8), *consensus.BTMAssetID, 100000000, 0, cp, nil)
  1158  }
  1159  
  1160  // Like errors.Root, but also unwraps vm.Error objects.
  1161  func rootErr(e error) error {
  1162  	return errors.Root(e)
  1163  }
  1164  
  1165  func hashData(data []byte) bc.Hash {
  1166  	var b32 [32]byte
  1167  	sha3pool.Sum256(b32[:], data)
  1168  	return bc.NewHash(b32)
  1169  }
  1170  
  1171  func newHash(n byte) *bc.Hash {
  1172  	h := bc.NewHash([32]byte{n})
  1173  	return &h
  1174  }
  1175  
  1176  func newAssetID(n byte) *bc.AssetID {
  1177  	a := bc.NewAssetID([32]byte{n})
  1178  	return &a
  1179  }
  1180  
  1181  func txIssuance(t *testing.T, tx *bc.Tx, index int) *bc.Issuance {
  1182  	id := tx.InputIDs[index]
  1183  	res, err := tx.Issuance(id)
  1184  	if err != nil {
  1185  		t.Fatal(err)
  1186  	}
  1187  	return res
  1188  }
  1189  
  1190  func txSpend(t *testing.T, tx *bc.Tx, index int) *bc.Spend {
  1191  	id := tx.InputIDs[index]
  1192  	res, err := tx.Spend(id)
  1193  	if err != nil {
  1194  		t.Fatal(err)
  1195  	}
  1196  	return res
  1197  }
  1198  
  1199  func getMuxID(tx *bc.Tx) *bc.Hash {
  1200  	out := tx.Entries[*tx.ResultIds[0]]
  1201  	switch result := out.(type) {
  1202  	case *bc.OriginalOutput:
  1203  		return result.Source.Ref
  1204  	case *bc.Retirement:
  1205  		return result.Source.Ref
  1206  	}
  1207  	return nil
  1208  }