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

     1  package validation
     2  
     3  import (
     4  	"math"
     5  	"testing"
     6  	"time"
     7  
     8  	"github.com/bytom/bytom/consensus"
     9  	"github.com/bytom/bytom/mining/tensority"
    10  	"github.com/bytom/bytom/protocol/bc"
    11  	"github.com/bytom/bytom/protocol/bc/types"
    12  	"github.com/bytom/bytom/protocol/state"
    13  	"github.com/bytom/bytom/protocol/vm"
    14  	"github.com/bytom/bytom/protocol/vm/vmutil"
    15  	"github.com/bytom/bytom/testutil"
    16  )
    17  
    18  func TestCheckBlockTime(t *testing.T) {
    19  	cases := []struct {
    20  		desc       string
    21  		blockTime  uint64
    22  		parentTime []uint64
    23  		err        error
    24  	}{
    25  		{
    26  			blockTime:  1520000001,
    27  			parentTime: []uint64{1520000000},
    28  			err:        nil,
    29  		},
    30  		{
    31  			desc:       "timestamp less than past median time (blocktest#1005)",
    32  			blockTime:  1510000094,
    33  			parentTime: []uint64{1520000000, 1510000099, 1510000098, 1510000097, 1510000096, 1510000095, 1510000094, 1510000093, 1510000092, 1510000091, 1510000090},
    34  			err:        errBadTimestamp,
    35  		},
    36  		{
    37  			desc:       "timestamp greater than max limit (blocktest#1006)",
    38  			blockTime:  9999999999,
    39  			parentTime: []uint64{1520000000},
    40  			err:        errBadTimestamp,
    41  		},
    42  		{
    43  			desc:       "timestamp of the block and the parent block are both greater than max limit (blocktest#1007)",
    44  			blockTime:  uint64(time.Now().Unix()) + consensus.MaxTimeOffsetSeconds + 2,
    45  			parentTime: []uint64{uint64(time.Now().Unix()) + consensus.MaxTimeOffsetSeconds + 1},
    46  			err:        errBadTimestamp,
    47  		},
    48  	}
    49  
    50  	parent := &state.BlockNode{Version: 1}
    51  	block := &bc.Block{
    52  		BlockHeader: &bc.BlockHeader{Version: 1},
    53  	}
    54  
    55  	for i, c := range cases {
    56  		parent.Timestamp = c.parentTime[0]
    57  		parentSuccessor := parent
    58  		for i := 1; i < len(c.parentTime); i++ {
    59  			parentSuccessor.Parent = &state.BlockNode{Version: 1, Timestamp: c.parentTime[i]}
    60  			parentSuccessor = parentSuccessor.Parent
    61  		}
    62  
    63  		block.Timestamp = c.blockTime
    64  		if err := checkBlockTime(block, parent); rootErr(err) != c.err {
    65  			t.Errorf("case %d got error %s, want %s", i, err, c.err)
    66  		}
    67  	}
    68  }
    69  
    70  func TestCheckCoinbaseAmount(t *testing.T) {
    71  	cases := []struct {
    72  		txs    []*types.Tx
    73  		amount uint64
    74  		err    error
    75  	}{
    76  		{
    77  			txs: []*types.Tx{
    78  				types.NewTx(types.TxData{
    79  					Inputs:  []*types.TxInput{types.NewCoinbaseInput(nil)},
    80  					Outputs: []*types.TxOutput{types.NewTxOutput(*consensus.BTMAssetID, 5000, nil)},
    81  				}),
    82  			},
    83  			amount: 5000,
    84  			err:    nil,
    85  		},
    86  		{
    87  			txs: []*types.Tx{
    88  				types.NewTx(types.TxData{
    89  					Inputs:  []*types.TxInput{types.NewCoinbaseInput(nil)},
    90  					Outputs: []*types.TxOutput{types.NewTxOutput(*consensus.BTMAssetID, 5000, nil)},
    91  				}),
    92  			},
    93  			amount: 6000,
    94  			err:    ErrWrongCoinbaseTransaction,
    95  		},
    96  		{
    97  			txs:    []*types.Tx{},
    98  			amount: 5000,
    99  			err:    ErrWrongCoinbaseTransaction,
   100  		},
   101  	}
   102  
   103  	block := new(types.Block)
   104  	for i, c := range cases {
   105  		block.Transactions = c.txs
   106  		if err := checkCoinbaseAmount(types.MapBlock(block), c.amount); rootErr(err) != c.err {
   107  			t.Errorf("case %d got error %s, want %s", i, err, c.err)
   108  		}
   109  	}
   110  }
   111  
   112  func TestValidateBlockHeader(t *testing.T) {
   113  	iniTtensority()
   114  
   115  	cases := []struct {
   116  		desc   string
   117  		block  *bc.Block
   118  		parent *state.BlockNode
   119  		err    error
   120  	}{
   121  		{
   122  			block: &bc.Block{BlockHeader: &bc.BlockHeader{
   123  				Version: 2,
   124  			}},
   125  			parent: &state.BlockNode{
   126  				Version: 1,
   127  			},
   128  			err: errVersionRegression,
   129  		},
   130  		{
   131  			block: &bc.Block{BlockHeader: &bc.BlockHeader{
   132  				Version: 1,
   133  				Height:  20,
   134  			}},
   135  			parent: &state.BlockNode{
   136  				Version: 1,
   137  				Height:  18,
   138  			},
   139  			err: errMisorderedBlockHeight,
   140  		},
   141  		{
   142  			desc: "the difficulty of the block is not equals to the next difficulty of parent block (blocktest#1008)",
   143  			block: &bc.Block{BlockHeader: &bc.BlockHeader{
   144  				Version: 1,
   145  				Height:  20,
   146  				Bits:    0,
   147  			}},
   148  			parent: &state.BlockNode{
   149  				Version: 1,
   150  				Height:  19,
   151  				Bits:    2305843009214532812,
   152  			},
   153  			err: errBadBits,
   154  		},
   155  		{
   156  			desc: "the prev block hash not equals to the hash of parent (blocktest#1004)",
   157  			block: &bc.Block{BlockHeader: &bc.BlockHeader{
   158  				Version:         1,
   159  				Height:          20,
   160  				PreviousBlockId: &bc.Hash{V0: 18},
   161  			}},
   162  			parent: &state.BlockNode{
   163  				Version: 1,
   164  				Height:  19,
   165  				Hash:    bc.Hash{V0: 19},
   166  			},
   167  			err: errMismatchedBlock,
   168  		},
   169  		{
   170  			desc: "check work proof fail (blocktest#1011)",
   171  			block: &bc.Block{
   172  				ID: bc.Hash{V0: 0},
   173  				BlockHeader: &bc.BlockHeader{
   174  					Version:         1,
   175  					Height:          1,
   176  					Timestamp:       1523352601,
   177  					PreviousBlockId: &bc.Hash{V0: 0},
   178  					Bits:            2305843009214532812,
   179  				},
   180  			},
   181  			parent: &state.BlockNode{
   182  				Version:   1,
   183  				Height:    0,
   184  				Timestamp: 1523352600,
   185  				Hash:      bc.Hash{V0: 0},
   186  				Seed:      &bc.Hash{V1: 1},
   187  				Bits:      2305843009214532812,
   188  			},
   189  			err: errWorkProof,
   190  		},
   191  		{
   192  			block: &bc.Block{
   193  				ID: bc.Hash{V0: 1},
   194  				BlockHeader: &bc.BlockHeader{
   195  					Version:         1,
   196  					Height:          1,
   197  					Timestamp:       1523352601,
   198  					PreviousBlockId: &bc.Hash{V0: 0},
   199  					Bits:            2305843009214532812,
   200  				},
   201  			},
   202  			parent: &state.BlockNode{
   203  				Version:   1,
   204  				Height:    0,
   205  				Timestamp: 1523352600,
   206  				Hash:      bc.Hash{V0: 0},
   207  				Seed:      &bc.Hash{V1: 1},
   208  				Bits:      2305843009214532812,
   209  			},
   210  			err: nil,
   211  		},
   212  		{
   213  			desc: "version greater than 1 (blocktest#1001)",
   214  			block: &bc.Block{
   215  				ID: bc.Hash{V0: 1},
   216  				BlockHeader: &bc.BlockHeader{
   217  					Version: 2,
   218  				},
   219  			},
   220  			parent: &state.BlockNode{
   221  				Version: 1,
   222  			},
   223  			err: errVersionRegression,
   224  		},
   225  		{
   226  			desc: "version equals 0 (blocktest#1002)",
   227  			block: &bc.Block{
   228  				ID: bc.Hash{V0: 1},
   229  				BlockHeader: &bc.BlockHeader{
   230  					Version: 0,
   231  				},
   232  			},
   233  			parent: &state.BlockNode{
   234  				Version: 1,
   235  			},
   236  			err: errVersionRegression,
   237  		},
   238  		{
   239  			desc: "version equals max uint64 (blocktest#1003)",
   240  			block: &bc.Block{
   241  				ID: bc.Hash{V0: 1},
   242  				BlockHeader: &bc.BlockHeader{
   243  					Version: math.MaxUint64,
   244  				},
   245  			},
   246  			parent: &state.BlockNode{
   247  				Version: 1,
   248  			},
   249  			err: errVersionRegression,
   250  		},
   251  	}
   252  
   253  	for i, c := range cases {
   254  		if err := ValidateBlockHeader(c.block, c.parent); rootErr(err) != c.err {
   255  			t.Errorf("case %d (%s) got error %s, want %s", i, c.desc, err, c.err)
   256  		}
   257  	}
   258  }
   259  
   260  // TestValidateBlock test the ValidateBlock function
   261  func TestValidateBlock(t *testing.T) {
   262  	iniTtensority()
   263  
   264  	cp, _ := vmutil.DefaultCoinbaseProgram()
   265  	cases := []struct {
   266  		desc   string
   267  		block  *bc.Block
   268  		parent *state.BlockNode
   269  		err    error
   270  	}{
   271  		{
   272  			desc: "The calculated transaction merkel root hash is not equals to the hash of the block header (blocktest#1009)",
   273  			block: &bc.Block{
   274  				ID: bc.Hash{V0: 1},
   275  				BlockHeader: &bc.BlockHeader{
   276  					Version:          1,
   277  					Height:           1,
   278  					Timestamp:        1523352601,
   279  					PreviousBlockId:  &bc.Hash{V0: 0},
   280  					Bits:             2305843009214532812,
   281  					TransactionsRoot: &bc.Hash{V0: 1},
   282  				},
   283  				Transactions: []*bc.Tx{
   284  					types.MapTx(&types.TxData{
   285  						Version:        1,
   286  						SerializedSize: 1,
   287  						Inputs:         []*types.TxInput{types.NewCoinbaseInput(nil)},
   288  						Outputs:        []*types.TxOutput{types.NewTxOutput(*consensus.BTMAssetID, 41250000000, cp)},
   289  					}),
   290  				},
   291  			},
   292  			parent: &state.BlockNode{
   293  				Version:   1,
   294  				Height:    0,
   295  				Timestamp: 1523352600,
   296  				Hash:      bc.Hash{V0: 0},
   297  				Seed:      &bc.Hash{V1: 1},
   298  				Bits:      2305843009214532812,
   299  			},
   300  			err: errMismatchedMerkleRoot,
   301  		},
   302  		{
   303  			desc: "The calculated transaction status merkel root hash is not equals to the hash of the block header (blocktest#1009)",
   304  			block: &bc.Block{
   305  				ID: bc.Hash{V0: 1},
   306  				BlockHeader: &bc.BlockHeader{
   307  					Version:               1,
   308  					Height:                1,
   309  					Timestamp:             1523352601,
   310  					PreviousBlockId:       &bc.Hash{V0: 0},
   311  					Bits:                  2305843009214532812,
   312  					TransactionsRoot:      &bc.Hash{V0: 6294987741126419124, V1: 12520373106916389157, V2: 5040806596198303681, V3: 1151748423853876189},
   313  					TransactionStatusHash: &bc.Hash{V0: 1},
   314  				},
   315  				Transactions: []*bc.Tx{
   316  					types.MapTx(&types.TxData{
   317  						Version:        1,
   318  						SerializedSize: 1,
   319  						Inputs:         []*types.TxInput{types.NewCoinbaseInput(nil)},
   320  						Outputs:        []*types.TxOutput{types.NewTxOutput(*consensus.BTMAssetID, 41250000000, cp)},
   321  					}),
   322  				},
   323  			},
   324  			parent: &state.BlockNode{
   325  				Version:   1,
   326  				Height:    0,
   327  				Timestamp: 1523352600,
   328  				Hash:      bc.Hash{V0: 0},
   329  				Seed:      &bc.Hash{V1: 1},
   330  				Bits:      2305843009214532812,
   331  			},
   332  			err: errMismatchedMerkleRoot,
   333  		},
   334  		{
   335  			desc: "the coinbase amount is less than the real coinbase amount (txtest#1014)",
   336  			block: &bc.Block{
   337  				ID: bc.Hash{V0: 1},
   338  				BlockHeader: &bc.BlockHeader{
   339  					Version:         1,
   340  					Height:          1,
   341  					Timestamp:       1523352601,
   342  					PreviousBlockId: &bc.Hash{V0: 0},
   343  					Bits:            2305843009214532812,
   344  				},
   345  				Transactions: []*bc.Tx{
   346  					types.MapTx(&types.TxData{
   347  						Version:        1,
   348  						SerializedSize: 1,
   349  						Inputs:         []*types.TxInput{types.NewCoinbaseInput(nil)},
   350  						Outputs:        []*types.TxOutput{types.NewTxOutput(*consensus.BTMAssetID, 41250000000, cp)},
   351  					}),
   352  					types.MapTx(&types.TxData{
   353  						Version:        1,
   354  						SerializedSize: 1,
   355  						Inputs:         []*types.TxInput{types.NewSpendInput([][]byte{}, *newHash(8), *consensus.BTMAssetID, 100000000, 0, cp)},
   356  						Outputs:        []*types.TxOutput{types.NewTxOutput(*consensus.BTMAssetID, 90000000, cp)},
   357  					}),
   358  				},
   359  			},
   360  			parent: &state.BlockNode{
   361  				Version:   1,
   362  				Height:    0,
   363  				Timestamp: 1523352600,
   364  				Hash:      bc.Hash{V0: 0},
   365  				Seed:      &bc.Hash{V1: 1},
   366  				Bits:      2305843009214532812,
   367  			},
   368  			err: ErrWrongCoinbaseTransaction,
   369  		},
   370  	}
   371  
   372  	for i, c := range cases {
   373  		err := ValidateBlock(c.block, c.parent)
   374  		if rootErr(err) != c.err {
   375  			t.Errorf("case #%d (%s) got error %s, want %s", i, c.desc, err, c.err)
   376  		}
   377  	}
   378  }
   379  
   380  // TestGasOverBlockLimit check if the gas of the block has the max limit (blocktest#1012)
   381  func TestGasOverBlockLimit(t *testing.T) {
   382  	iniTtensority()
   383  
   384  	cp, _ := vmutil.DefaultCoinbaseProgram()
   385  	parent := &state.BlockNode{
   386  		Version:   1,
   387  		Height:    0,
   388  		Timestamp: 1523352600,
   389  		Hash:      bc.Hash{V0: 0},
   390  		Seed:      &bc.Hash{V1: 1},
   391  		Bits:      2305843009214532812,
   392  	}
   393  	block := &bc.Block{
   394  		ID: bc.Hash{V0: 1},
   395  		BlockHeader: &bc.BlockHeader{
   396  			Version:          1,
   397  			Height:           1,
   398  			Timestamp:        1523352601,
   399  			PreviousBlockId:  &bc.Hash{V0: 0},
   400  			Bits:             2305843009214532812,
   401  			TransactionsRoot: &bc.Hash{V0: 1},
   402  		},
   403  		Transactions: []*bc.Tx{
   404  			types.MapTx(&types.TxData{
   405  				Version:        1,
   406  				SerializedSize: 1,
   407  				Inputs:         []*types.TxInput{types.NewCoinbaseInput(nil)},
   408  				Outputs:        []*types.TxOutput{types.NewTxOutput(*consensus.BTMAssetID, 41250000000, cp)},
   409  			}),
   410  		},
   411  	}
   412  
   413  	for i := 0; i < 100; i++ {
   414  		block.Transactions = append(block.Transactions, types.MapTx(&types.TxData{
   415  			Version:        1,
   416  			SerializedSize: 100000,
   417  			Inputs: []*types.TxInput{
   418  				types.NewSpendInput([][]byte{}, *newHash(8), *consensus.BTMAssetID, 10000000000, 0, cp),
   419  			},
   420  			Outputs: []*types.TxOutput{
   421  				types.NewTxOutput(*consensus.BTMAssetID, 9000000000, cp),
   422  			},
   423  		}))
   424  	}
   425  
   426  	if err := ValidateBlock(block, parent); err != errOverBlockLimit {
   427  		t.Errorf("got error %s, want %s", err, errOverBlockLimit)
   428  	}
   429  }
   430  
   431  // TestSetTransactionStatus verify the transaction status is set correctly (blocktest#1010)
   432  func TestSetTransactionStatus(t *testing.T) {
   433  	iniTtensority()
   434  
   435  	cp, _ := vmutil.DefaultCoinbaseProgram()
   436  	parent := &state.BlockNode{
   437  		Version:   1,
   438  		Height:    0,
   439  		Timestamp: 1523352600,
   440  		Hash:      bc.Hash{V0: 0},
   441  		Seed:      &bc.Hash{V1: 1},
   442  		Bits:      2305843009214532812,
   443  	}
   444  	block := &bc.Block{
   445  		ID: bc.Hash{V0: 1},
   446  		BlockHeader: &bc.BlockHeader{
   447  			Version:               1,
   448  			Height:                1,
   449  			Timestamp:             1523352601,
   450  			PreviousBlockId:       &bc.Hash{V0: 0},
   451  			Bits:                  2305843009214532812,
   452  			TransactionsRoot:      &bc.Hash{V0: 3413931728524254295, V1: 300490676707850231, V2: 1886132055969225110, V3: 10216139531293906088},
   453  			TransactionStatusHash: &bc.Hash{V0: 8682965660674182538, V1: 8424137560837623409, V2: 6979974817894224946, V3: 4673809519342015041},
   454  		},
   455  		Transactions: []*bc.Tx{
   456  			types.MapTx(&types.TxData{
   457  				Version:        1,
   458  				SerializedSize: 1,
   459  				Inputs:         []*types.TxInput{types.NewCoinbaseInput(nil)},
   460  				Outputs:        []*types.TxOutput{types.NewTxOutput(*consensus.BTMAssetID, 41449998224, cp)},
   461  			}),
   462  			types.MapTx(&types.TxData{
   463  				Version:        1,
   464  				SerializedSize: 1,
   465  				Inputs: []*types.TxInput{
   466  					types.NewSpendInput([][]byte{}, *newHash(8), *consensus.BTMAssetID, 100000000, 0, cp),
   467  					types.NewSpendInput([][]byte{}, *newHash(8), bc.AssetID{V0: 1}, 1000, 0, []byte{byte(vm.OP_FALSE)}),
   468  				},
   469  				Outputs: []*types.TxOutput{
   470  					types.NewTxOutput(*consensus.BTMAssetID, 888, cp),
   471  					types.NewTxOutput(bc.AssetID{V0: 1}, 1000, cp),
   472  				},
   473  			}),
   474  			types.MapTx(&types.TxData{
   475  				Version:        1,
   476  				SerializedSize: 1,
   477  				Inputs: []*types.TxInput{
   478  					types.NewSpendInput([][]byte{}, *newHash(8), *consensus.BTMAssetID, 100000000, 0, cp),
   479  				},
   480  				Outputs: []*types.TxOutput{
   481  					types.NewTxOutput(*consensus.BTMAssetID, 888, cp),
   482  				},
   483  			}),
   484  		},
   485  	}
   486  
   487  	if err := ValidateBlock(block, parent); err != nil {
   488  		t.Fatal(err)
   489  	}
   490  
   491  	expectTxStatuses := []bool{false, true, false}
   492  	txStatuses := block.GetTransactionStatus().VerifyStatus
   493  	if len(expectTxStatuses) != len(txStatuses) {
   494  		t.Error("the size of expect tx status is not equals to size of got tx status")
   495  	}
   496  
   497  	for i, status := range txStatuses {
   498  		if expectTxStatuses[i] != status.StatusFail {
   499  			t.Errorf("got tx status: %v, expect tx status: %v\n", status.StatusFail, expectTxStatuses[i])
   500  		}
   501  	}
   502  }
   503  
   504  func iniTtensority() {
   505  	// add (hash, seed) --> (tensority hash) to the  tensority cache for avoid
   506  	// real matrix calculate cost.
   507  	tensority.AIHash.AddCache(&bc.Hash{V0: 0}, &bc.Hash{}, testutil.MaxHash)
   508  	tensority.AIHash.AddCache(&bc.Hash{V0: 1}, &bc.Hash{}, testutil.MinHash)
   509  	tensority.AIHash.AddCache(&bc.Hash{V0: 1}, consensus.InitialSeed, testutil.MinHash)
   510  }