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