github.com/Bytom/bytom@v1.1.2-0.20210127130405-ae40204c0b09/protocol/bc/types/transaction_test.go (about)

     1  package types
     2  
     3  import (
     4  	"bytes"
     5  	"encoding/hex"
     6  	"encoding/json"
     7  	"io/ioutil"
     8  	"strings"
     9  	"testing"
    10  
    11  	"github.com/davecgh/go-spew/spew"
    12  
    13  	"github.com/bytom/bytom/consensus"
    14  	"github.com/bytom/bytom/errors"
    15  	"github.com/bytom/bytom/protocol/bc"
    16  	"github.com/bytom/bytom/testutil"
    17  )
    18  
    19  func TestTransaction(t *testing.T) {
    20  	cases := []struct {
    21  		tx   *Tx
    22  		hex  string
    23  		hash bc.Hash
    24  	}{
    25  		{
    26  			tx: NewTx(TxData{
    27  				Version:        1,
    28  				SerializedSize: uint64(5),
    29  				Inputs:         nil,
    30  				Outputs:        nil,
    31  			}),
    32  			hex: strings.Join([]string{
    33  				"07", // serflags
    34  				"01", // transaction version
    35  				"00", // tx time range
    36  				"00", // inputs count
    37  				"00", // outputs count
    38  			}, ""),
    39  			hash: testutil.MustDecodeHash("8e88b9cb4615128c7209dff695f68b8de5b38648bf3d44d2d0e6a674848539c9"),
    40  		},
    41  		{
    42  			tx: NewTx(TxData{
    43  				Version:        1,
    44  				SerializedSize: uint64(261),
    45  				TimeRange:      654,
    46  				Inputs: []*TxInput{
    47  					NewIssuanceInput([]byte("nonce"), 254354, []byte("issuanceProgram"), [][]byte{[]byte("arguments1"), []byte("arguments2")}, []byte("assetDefinition")),
    48  					NewSpendInput([][]byte{[]byte("arguments3"), []byte("arguments4")}, testutil.MustDecodeHash("fad5195a0c8e3b590b86a3c0a95e7529565888508aecca96e9aeda633002f409"), *consensus.BTMAssetID, 254354, 3, []byte("spendProgram")),
    49  				},
    50  				Outputs: []*TxOutput{
    51  					NewTxOutput(testutil.MustDecodeAsset("a69849e11add96ac7053aad22ba2349a4abf5feb0475a0afcadff4e128be76cf"), 254354, []byte("true")),
    52  				},
    53  			}),
    54  			hex: strings.Join([]string{
    55  				"07",         // serflags
    56  				"01",         // transaction version
    57  				"8e05",       // tx time range
    58  				"02",         // inputs count
    59  				"01",         // input 0: asset version
    60  				"2a",         // input 0: serialization length
    61  				"00",         // input 0: issuance type flag
    62  				"05",         // input 0: nonce length
    63  				"6e6f6e6365", // input 0: nonce
    64  				"a69849e11add96ac7053aad22ba2349a4abf5feb0475a0afcadff4e128be76cf", // input 0: assetID
    65  				"92c30f", // input 0: amount
    66  				"38",     // input 0: input witness length
    67  				"0f",     // input 0: asset definition length
    68  				"6173736574446566696e6974696f6e", // input 0: asset definition
    69  				"01", // input 0: vm version
    70  				"0f", // input 0: issuanceProgram length
    71  				"69737375616e636550726f6772616d", // input 0: issuance program
    72  				"02", // input 0: argument array length
    73  				"0a", // input 0: first argument length
    74  				"617267756d656e747331", // input 0: first argument data
    75  				"0a", // input 0: second argument length
    76  				"617267756d656e747332", // input 0: second argument data
    77  				"01", // input 1: asset version
    78  				"54", // input 1: input commitment length
    79  				"01", // input 1: spend type flag
    80  				"52", // input 1: spend commitment length
    81  				"fad5195a0c8e3b590b86a3c0a95e7529565888508aecca96e9aeda633002f409", // input 1: source id
    82  				"ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff", // input 1: assetID
    83  				"92c30f", // input 1: amount
    84  				"03",     // input 1: source position
    85  				"01",     // input 1: vm version
    86  				"0c",     // input 1: spend program length
    87  				"7370656e6450726f6772616d", // input 1: spend program
    88  				"17", // input 1: witness length
    89  				"02", // input 1: argument array length
    90  				"0a", // input 1: first argument length
    91  				"617267756d656e747333", // input 1: first argument data
    92  				"0a", // input 1: second argument length
    93  				"617267756d656e747334", // input 1: second argument data
    94  				"01", // outputs count
    95  				"01", // output 0: asset version
    96  				"29", // output 0: serialization length
    97  				"a69849e11add96ac7053aad22ba2349a4abf5feb0475a0afcadff4e128be76cf", // output 0: assetID
    98  				"92c30f",   // output 0: amount
    99  				"01",       // output 0: version
   100  				"04",       // output 0: control program length
   101  				"74727565", // output 0: control program
   102  				"00",       // output 0: witness length
   103  			}, ""),
   104  			hash: testutil.MustDecodeHash("a0ece5ca48dca27708394852599cb4d04af22c36538c03cb72663f3091406c17"),
   105  		},
   106  		{
   107  			tx: NewTx(TxData{
   108  				Version:        1,
   109  				SerializedSize: uint64(108),
   110  				Inputs: []*TxInput{
   111  					NewCoinbaseInput([]byte("arbitrary")),
   112  				},
   113  				Outputs: []*TxOutput{
   114  					NewTxOutput(*consensus.BTMAssetID, 254354, []byte("true")),
   115  					NewTxOutput(*consensus.BTMAssetID, 254354, []byte("false")),
   116  				},
   117  			}),
   118  			hex: strings.Join([]string{
   119  				"07",                 // serflags
   120  				"01",                 // transaction version
   121  				"00",                 // tx time range
   122  				"01",                 // inputs count
   123  				"01",                 // input 0: asset version
   124  				"0b",                 // input 0: input commitment length
   125  				"02",                 // input 0: coinbase type flag
   126  				"09",                 // input 0: arbitrary length
   127  				"617262697472617279", // input 0: arbitrary data
   128  				"00",                 // input 0: witness length
   129  				"02",                 // outputs count
   130  				"01",                 // output 0: asset version
   131  				"29",                 // output 0: serialization length
   132  				"ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff", // output 0: assetID
   133  				"92c30f",   // output 0: amount
   134  				"01",       // output 0: version
   135  				"04",       // output 0: control program length
   136  				"74727565", // output 0: control program
   137  				"00",       // output 0: witness length
   138  				"01",       // output 1: asset version
   139  				"2a",       // output 1: serialization length
   140  				"ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff", // output 1: assetID
   141  				"92c30f",     // output 1: amount
   142  				"01",         // output 1: version
   143  				"05",         // output 1: control program length
   144  				"66616c7365", // output 1: control program
   145  				"00",         // output 1: witness length
   146  			}, ""),
   147  			hash: testutil.MustDecodeHash("c2e2f388706fc06cca6aba5e85e0e85029f772872e1b6e6c32a70da22d0309dc"),
   148  		},
   149  	}
   150  	for i, test := range cases {
   151  		got := testutil.Serialize(t, test.tx)
   152  		want, err := hex.DecodeString(test.hex)
   153  		if err != nil {
   154  			t.Fatal(err)
   155  		}
   156  
   157  		if !bytes.Equal(got, want) {
   158  			t.Errorf("test %d: bytes = %x want %x", i, got, want)
   159  		}
   160  		if test.tx.ID != test.hash {
   161  			t.Errorf("test %d: hash = %x want %x", i, test.tx.ID.Bytes(), test.hash.Bytes())
   162  		}
   163  
   164  		txJSON, err := json.Marshal(test.tx)
   165  		if err != nil {
   166  			t.Errorf("test %d: error marshaling tx to json: %s", i, err)
   167  		}
   168  		txFromJSON := Tx{}
   169  		if err := json.Unmarshal(txJSON, &txFromJSON); err != nil {
   170  			t.Errorf("test %d: error unmarshaling tx from json: %s", i, err)
   171  		}
   172  		if !testutil.DeepEqual(test.tx.TxData, txFromJSON.TxData) {
   173  			t.Errorf("test %d: types.TxData -> json -> types.TxData: got:\n%s\nwant:\n%s", i, spew.Sdump(txFromJSON.TxData), spew.Sdump(test.tx.TxData))
   174  		}
   175  
   176  		tx1 := new(TxData)
   177  		if err := tx1.UnmarshalText([]byte(test.hex)); err != nil {
   178  			t.Errorf("test %d: unexpected err %v", i, err)
   179  		}
   180  		if !testutil.DeepEqual(*tx1, test.tx.TxData) {
   181  			t.Errorf("test %d: tx1 is:\n%swant:\n%s", i, spew.Sdump(*tx1), spew.Sdump(test.tx.TxData))
   182  		}
   183  	}
   184  }
   185  
   186  func TestTransactionTrailingGarbage(t *testing.T) {
   187  	// validTxHex is a valid tx, we don't care what's inside as long as it's valid
   188  	validTxHex := `07010001012b00030a0908916133a0d64d1d973b631e226ef95338ad4a536b95635f32f0d04708a6f2a26380a094a58d1d09000101010103010203010129000000000000000000000000000000000000000000000000000000000000000080a094a58d1d01010100`
   189  	validTx := Tx{}
   190  	if err := validTx.UnmarshalText([]byte(validTxHex)); err != nil {
   191  		t.Fatal(err)
   192  	}
   193  
   194  	invalidTxHex := validTxHex + strings.Repeat("00", 10)
   195  	invalidTx := Tx{}
   196  	if err := invalidTx.UnmarshalText([]byte(invalidTxHex)); err == nil {
   197  		t.Fatal("expected error with trailing garbage but got nil")
   198  	}
   199  }
   200  
   201  func TestInvalidIssuance(t *testing.T) {
   202  	hex := strings.Join([]string{
   203  		"07",     // serflags
   204  		"01",     // transaction version
   205  		"00",     // tx maxtime
   206  		"01",     // inputs count
   207  		"01",     // input 0, asset version
   208  		"2b",     // input 0, input commitment length prefix
   209  		"00",     // input 0, input commitment, "issuance" type
   210  		"03",     // input 0, input commitment, nonce length prefix
   211  		"0a0908", // input 0, input commitment, nonce
   212  		"0000000000000000000000000000000000000000000000000000000000000000", // input 0, input commitment, WRONG asset id
   213  		"80a094a58d1d", // input 0, input commitment, amount
   214  		"29",           // input 0, issuance input witness length prefix
   215  		"03deff1d4319d67baa10a6d26c1fea9c3e8d30e33474efee1a610a9bb49d758d", // input 0, issuance input witness, initial block
   216  		"00",     // input 0, issuance input witness, asset definition
   217  		"01",     // input 0, issuance input witness, vm version
   218  		"01",     // input 0, issuance input witness, issuance program length prefix
   219  		"01",     // input 0, issuance input witness, issuance program
   220  		"01",     // input 0, issuance input witness, arguments count
   221  		"03",     // input 0, issuance input witness, argument 0 length prefix
   222  		"010203", // input 0, issuance input witness, argument 0
   223  		"01",     // outputs count
   224  		"01",     // output 0, asset version
   225  		"29",     // output 0, output commitment length
   226  		"0000000000000000000000000000000000000000000000000000000000000000", // output 0, output commitment, asset id
   227  		"80a094a58d1d",   // output 0, output commitment, amount
   228  		"01",             // output 0, output commitment, vm version
   229  		"0101",           // output 0, output commitment, control program
   230  		"066f7574707574", // output 0, reference data
   231  		"00",             // output 0, output witness
   232  		"0869737375616e6365",
   233  	}, "")
   234  
   235  	tx := new(TxData)
   236  	if err := tx.UnmarshalText([]byte(hex)); errors.Root(err) != errBadAssetID {
   237  		t.Errorf("want errBadAssetID, got %v", err)
   238  	}
   239  }
   240  
   241  func TestFuzzUnknownAssetVersion(t *testing.T) {
   242  	rawTx := `07010001012b00030a0908916133a0d64d1d973b631e226ef95338ad4a536b95635f32f0d04708a6f2a26380a094a58d1d09000101010103010203010129000000000000000000000000000000000000000000000000000000000000000080a094a58d1d01010100`
   243  	want := Tx{}
   244  	if err := want.UnmarshalText([]byte(rawTx)); err != nil {
   245  		t.Fatal(err)
   246  	}
   247  
   248  	b, err := want.MarshalText()
   249  	if err != nil {
   250  		t.Fatal(err)
   251  	}
   252  
   253  	got := Tx{}
   254  	if err = got.UnmarshalText(b); err != nil {
   255  		t.Fatal(err)
   256  	}
   257  	if got.ID.String() != want.ID.String() {
   258  		t.Errorf("tx id changed to %s", got.ID.String())
   259  	}
   260  }
   261  
   262  func BenchmarkTxWriteToTrue(b *testing.B) {
   263  	tx := &Tx{}
   264  	for i := 0; i < b.N; i++ {
   265  		tx.writeTo(ioutil.Discard, 0)
   266  	}
   267  }
   268  
   269  func BenchmarkTxWriteToFalse(b *testing.B) {
   270  	tx := &Tx{}
   271  	for i := 0; i < b.N; i++ {
   272  		tx.writeTo(ioutil.Discard, serRequired)
   273  	}
   274  }
   275  
   276  func BenchmarkTxWriteToTrue200(b *testing.B) {
   277  	tx := &Tx{}
   278  	for i := 0; i < 200; i++ {
   279  		tx.Inputs = append(tx.Inputs, NewSpendInput(nil, bc.Hash{}, bc.AssetID{}, 0, 0, nil))
   280  		tx.Outputs = append(tx.Outputs, NewTxOutput(bc.AssetID{}, 0, nil))
   281  	}
   282  	for i := 0; i < b.N; i++ {
   283  		tx.writeTo(ioutil.Discard, 0)
   284  	}
   285  }
   286  
   287  func BenchmarkTxWriteToFalse200(b *testing.B) {
   288  	tx := &Tx{}
   289  	for i := 0; i < 200; i++ {
   290  		tx.Inputs = append(tx.Inputs, NewSpendInput(nil, bc.Hash{}, bc.AssetID{}, 0, 0, nil))
   291  		tx.Outputs = append(tx.Outputs, NewTxOutput(bc.AssetID{}, 0, nil))
   292  	}
   293  	for i := 0; i < b.N; i++ {
   294  		tx.writeTo(ioutil.Discard, serRequired)
   295  	}
   296  }
   297  
   298  func BenchmarkTxInputWriteToTrue(b *testing.B) {
   299  	input := NewSpendInput(nil, bc.Hash{}, bc.AssetID{}, 0, 0, nil)
   300  	ew := errors.NewWriter(ioutil.Discard)
   301  	for i := 0; i < b.N; i++ {
   302  		input.writeTo(ew)
   303  	}
   304  }
   305  
   306  func BenchmarkTxInputWriteToFalse(b *testing.B) {
   307  	input := NewSpendInput(nil, bc.Hash{}, bc.AssetID{}, 0, 0, nil)
   308  	ew := errors.NewWriter(ioutil.Discard)
   309  	for i := 0; i < b.N; i++ {
   310  		input.writeTo(ew)
   311  	}
   312  }
   313  
   314  func BenchmarkTxOutputWriteToTrue(b *testing.B) {
   315  	output := NewTxOutput(bc.AssetID{}, 0, nil)
   316  	ew := errors.NewWriter(ioutil.Discard)
   317  	for i := 0; i < b.N; i++ {
   318  		output.writeTo(ew)
   319  	}
   320  }
   321  
   322  func BenchmarkTxOutputWriteToFalse(b *testing.B) {
   323  	output := NewTxOutput(bc.AssetID{}, 0, nil)
   324  	ew := errors.NewWriter(ioutil.Discard)
   325  	for i := 0; i < b.N; i++ {
   326  		output.writeTo(ew)
   327  	}
   328  }
   329  
   330  func BenchmarkAssetAmountWriteTo(b *testing.B) {
   331  	aa := bc.AssetAmount{}
   332  	for i := 0; i < b.N; i++ {
   333  		aa.WriteTo(ioutil.Discard)
   334  	}
   335  }