OSDN Git Service

update master (#487)
[bytom/bytom.git] / protocol / validation / validation_test.go
index 4dee5f0..182db3a 100644 (file)
@@ -4,18 +4,18 @@ import (
        "fmt"
        "math"
        "testing"
-       "time"
+
+       "github.com/davecgh/go-spew/spew"
+       "github.com/golang/protobuf/proto"
 
        "github.com/bytom/consensus"
        "github.com/bytom/crypto/sha3pool"
        "github.com/bytom/errors"
        "github.com/bytom/protocol/bc"
-       "github.com/bytom/protocol/bc/legacy"
+       "github.com/bytom/protocol/bc/types"
        "github.com/bytom/protocol/vm"
+       "github.com/bytom/protocol/vm/vmutil"
        "github.com/bytom/testutil"
-
-       "github.com/davecgh/go-spew/spew"
-       "github.com/golang/protobuf/proto"
 )
 
 func init() {
@@ -24,100 +24,100 @@ func init() {
 
 func TestGasStatus(t *testing.T) {
        cases := []struct {
-               input  *gasState
-               output *gasState
-               f      func(*gasState) error
+               input  *GasState
+               output *GasState
+               f      func(*GasState) error
                err    error
        }{
                {
-                       input: &gasState{
-                               gasLeft:  10000,
-                               gasUsed:  0,
+                       input: &GasState{
+                               GasLeft:  10000,
+                               GasUsed:  0,
                                BTMValue: 0,
                        },
-                       output: &gasState{
-                               gasLeft:  10000 / gasRate,
-                               gasUsed:  0,
+                       output: &GasState{
+                               GasLeft:  10000 / consensus.VMGasRate,
+                               GasUsed:  0,
                                BTMValue: 10000,
                        },
-                       f: func(input *gasState) error {
-                               return input.setGas(10000)
+                       f: func(input *GasState) error {
+                               return input.setGas(10000, 0)
                        },
                        err: nil,
                },
                {
-                       input: &gasState{
-                               gasLeft:  10000,
-                               gasUsed:  0,
+                       input: &GasState{
+                               GasLeft:  10000,
+                               GasUsed:  0,
                                BTMValue: 0,
                        },
-                       output: &gasState{
-                               gasLeft:  10000,
-                               gasUsed:  0,
+                       output: &GasState{
+                               GasLeft:  10000,
+                               GasUsed:  0,
                                BTMValue: 0,
                        },
-                       f: func(input *gasState) error {
-                               return input.setGas(-10000)
+                       f: func(input *GasState) error {
+                               return input.setGas(-10000, 0)
                        },
                        err: errGasCalculate,
                },
                {
-                       input: &gasState{
-                               gasLeft:  defaultGasLimit,
-                               gasUsed:  0,
+                       input: &GasState{
+                               GasLeft:  consensus.DefaultGasCredit,
+                               GasUsed:  0,
                                BTMValue: 0,
                        },
-                       output: &gasState{
-                               gasLeft:  defaultGasLimit,
-                               gasUsed:  0,
+                       output: &GasState{
+                               GasLeft:  100000,
+                               GasUsed:  0,
                                BTMValue: 80000000000,
                        },
-                       f: func(input *gasState) error {
-                               return input.setGas(80000000000)
+                       f: func(input *GasState) error {
+                               return input.setGas(80000000000, 0)
                        },
                        err: nil,
                },
                {
-                       input: &gasState{
-                               gasLeft:  10000,
-                               gasUsed:  0,
+                       input: &GasState{
+                               GasLeft:  10000,
+                               GasUsed:  0,
                                BTMValue: 0,
                        },
-                       output: &gasState{
-                               gasLeft:  10000,
-                               gasUsed:  0,
+                       output: &GasState{
+                               GasLeft:  10000,
+                               GasUsed:  0,
                                BTMValue: 0,
                        },
-                       f: func(input *gasState) error {
+                       f: func(input *GasState) error {
                                return input.updateUsage(-1)
                        },
                        err: errGasCalculate,
                },
                {
-                       input: &gasState{
-                               gasLeft:  10000,
-                               gasUsed:  0,
+                       input: &GasState{
+                               GasLeft:  10000,
+                               GasUsed:  0,
                                BTMValue: 0,
                        },
-                       output: &gasState{
-                               gasLeft:  9999,
-                               gasUsed:  1,
+                       output: &GasState{
+                               GasLeft:  9999,
+                               GasUsed:  1,
                                BTMValue: 0,
                        },
-                       f: func(input *gasState) error {
+                       f: func(input *GasState) error {
                                return input.updateUsage(9999)
                        },
                        err: nil,
                },
        }
 
-       for _, c := range cases {
+       for i, c := range cases {
                err := c.f(c.input)
 
-               if err != c.err {
-                       t.Errorf("got error %s, want %s", err, c.err)
+               if rootErr(err) != c.err {
+                       t.Errorf("case %d: got error %s, want %s", i, err, c.err)
                } else if *c.input != *c.output {
-                       t.Errorf("got gasStatus %s, want %s;", c.input, c.output)
+                       t.Errorf("case %d: gasStatus %v, want %v;", i, c.input, c.output)
                }
        }
 }
@@ -241,9 +241,8 @@ func TestTxValidation(t *testing.T) {
                                // identical second transaction in order to get a similar but
                                // not equal output entry for the mux to falsely point
                                // to. That entry must be added to the first tx's Entries map.
-                               fixture.txOutputs[0].ReferenceData = []byte{1}
                                fixture2 := sample(t, fixture)
-                               tx2 := legacy.NewTx(*fixture2.tx).Tx
+                               tx2 := types.NewTx(*fixture2.tx).Tx
                                out2ID := tx2.ResultIds[0]
                                out2 := tx2.Entries[*out2ID].(*bc.Output)
                                tx.Entries[*out2ID] = out2
@@ -378,14 +377,14 @@ func TestTxValidation(t *testing.T) {
        for _, c := range cases {
                t.Run(c.desc, func(t *testing.T) {
                        fixture = sample(t, nil)
-                       tx = legacy.NewTx(*fixture.tx).Tx
+                       tx = types.NewTx(*fixture.tx).Tx
                        vs = &validationState{
                                block:   mockBlock(),
                                tx:      tx,
                                entryID: tx.ID,
-                               gas: &gasState{
-                                       gasLeft: int64(80000),
-                                       gasUsed: 0,
+                               gasStatus: &GasState{
+                                       GasLeft: int64(80000),
+                                       GasUsed: 0,
                                },
                                cache: make(map[bc.Hash]error),
                        }
@@ -413,43 +412,41 @@ func TestValidateBlock(t *testing.T) {
                {
                        block: &bc.Block{
                                BlockHeader: &bc.BlockHeader{
-                                       Height: 1,
+                                       Height:          0,
+                                       Bits:            2305843009230471167,
+                                       PreviousBlockId: &bc.Hash{},
                                },
-                               Transactions: []*bc.Tx{mockCoinbaseTx(624000000000)},
+                               Transactions: []*bc.Tx{mockCoinbaseTx(1470000000000000000)},
                        },
                        err: nil,
                },
                {
                        block: &bc.Block{
                                BlockHeader: &bc.BlockHeader{
-                                       Height: 1,
+                                       Height:          0,
+                                       Bits:            2305843009230471167,
+                                       PreviousBlockId: &bc.Hash{},
                                },
                                Transactions: []*bc.Tx{mockCoinbaseTx(1)},
                        },
                        err: errWrongCoinbaseTransaction,
                },
-               {
-                       block: &bc.Block{
-                               BlockHeader: &bc.BlockHeader{
-                                       Height:         1,
-                                       SerializedSize: 88888888,
-                               },
-                               Transactions: []*bc.Tx{mockCoinbaseTx(1)},
-                       },
-                       err: errWrongBlockSize,
-               },
        }
 
+       txStatus := bc.NewTransactionStatus()
+       txStatusHash := bc.EntryID(txStatus)
+
        for _, c := range cases {
                txRoot, err := bc.MerkleRoot(c.block.Transactions)
                if err != nil {
-                       t.Errorf("computing transaction merkle root", err)
+                       t.Errorf("computing transaction merkle root error: %v", err)
                        continue
                }
+               c.block.BlockHeader.TransactionStatus = bc.NewTransactionStatus()
                c.block.TransactionsRoot = &txRoot
-               err = ValidateBlock(c.block, nil)
+               c.block.TransactionStatusHash = &txStatusHash
 
-               if rootErr(err) != c.err {
+               if err = ValidateBlock(c.block, nil, &bc.Hash{}, nil); rootErr(err) != c.err {
                        t.Errorf("got error %s, want %s", err, c.err)
                }
        }
@@ -457,58 +454,86 @@ func TestValidateBlock(t *testing.T) {
 
 func TestCoinbase(t *testing.T) {
        CbTx := mockCoinbaseTx(5000000000)
-       errCbTx := legacy.MapTx(&legacy.TxData{
-               Outputs: []*legacy.TxOutput{
-                       legacy.NewTxOutput(bc.AssetID{
-                               V0: uint64(18446744073709551611),
-                               V1: uint64(18446744073709551615),
-                               V2: uint64(18446744073709551615),
-                               V3: uint64(18446744073709551615),
-                       }, 800000000000, []byte{1}, nil),
-               },
-       })
        cases := []struct {
-               block *bc.Block
-               tx    *bc.Tx
-               err   error
+               block    *bc.Block
+               tx       *bc.Tx
+               GasVaild bool
+               err      error
        }{
                {
                        block: &bc.Block{
                                BlockHeader: &bc.BlockHeader{
                                        Height: 666,
                                },
-                               Transactions: []*bc.Tx{errCbTx},
+                               Transactions: []*bc.Tx{CbTx},
                        },
-                       tx:  CbTx,
-                       err: errWrongCoinbaseTransaction,
+                       tx:       CbTx,
+                       GasVaild: true,
+                       err:      nil,
                },
+       }
+
+       for i, c := range cases {
+               gasStatus, err := ValidateTx(c.tx, c.block)
+
+               if rootErr(err) != c.err {
+                       t.Errorf("#%d got error %s, want %s", i, err, c.err)
+               }
+               if c.GasVaild != gasStatus.GasVaild {
+                       t.Errorf("#%d got GasVaild %t, want %t", i, gasStatus.GasVaild, c.GasVaild)
+               }
+       }
+}
+
+func TestTimeRange(t *testing.T) {
+       cases := []struct {
+               timeRange uint64
+               err       bool
+       }{
                {
-                       block: &bc.Block{
-                               BlockHeader: &bc.BlockHeader{
-                                       Height: 666,
-                               },
-                               Transactions: []*bc.Tx{CbTx},
-                       },
-                       tx:  CbTx,
-                       err: nil,
+                       timeRange: 0,
+                       err:       false,
                },
                {
-                       block: &bc.Block{
-                               BlockHeader: &bc.BlockHeader{
-                                       Height: 666,
-                               },
-                               Transactions: []*bc.Tx{errCbTx},
-                       },
-                       tx:  errCbTx,
-                       err: errWrongCoinbaseAsset,
+                       timeRange: 334,
+                       err:       false,
+               },
+               {
+                       timeRange: 332,
+                       err:       true,
+               },
+               {
+                       timeRange: 1521625824,
+                       err:       false,
+               },
+               {
+                       timeRange: 1421625824,
+                       err:       true,
                },
        }
 
-       for _, c := range cases {
-               _, err := ValidateTx(c.tx, c.block)
+       block := &bc.Block{
+               BlockHeader: &bc.BlockHeader{
+                       Height:    333,
+                       Timestamp: 1521625823,
+               },
+       }
 
-               if rootErr(err) != c.err {
-                       t.Errorf("got error %s, want %s", err, c.err)
+       tx := types.MapTx(&types.TxData{
+               SerializedSize: 1,
+               TimeRange:      0,
+               Inputs: []*types.TxInput{
+                       mockGasTxInput(),
+               },
+               Outputs: []*types.TxOutput{
+                       types.NewTxOutput(*consensus.BTMAssetID, 1, []byte{0x6a}),
+               },
+       })
+
+       for i, c := range cases {
+               tx.TimeRange = c.timeRange
+               if _, err := ValidateTx(tx, block); (err != nil) != c.err {
+                       t.Errorf("#%d got error %s, want %s", i, !c.err, c.err)
                }
        }
 }
@@ -546,17 +571,16 @@ func TestBlockHeaderValid(t *testing.T) {
 // affect the transaction that's built. The components of the
 // transaction are the fields of txFixture.
 type txFixture struct {
-       initialBlockID       bc.Hash
-       issuanceProg         bc.Program
-       issuanceArgs         [][]byte
-       assetDef             []byte
-       assetID              bc.AssetID
-       txVersion            uint64
-       txInputs             []*legacy.TxInput
-       txOutputs            []*legacy.TxOutput
-       txMinTime, txMaxTime uint64
-       txRefData            []byte
-       tx                   *legacy.TxData
+       initialBlockID bc.Hash
+       issuanceProg   bc.Program
+       issuanceArgs   [][]byte
+       assetDef       []byte
+       assetID        bc.AssetID
+       txVersion      uint64
+       txInputs       []*types.TxInput
+       txOutputs      []*types.TxOutput
+       txRefData      []byte
+       tx             *types.TxData
 }
 
 // Produces a sample transaction in a txFixture object (see above). A
@@ -602,7 +626,7 @@ func sample(tb testing.TB, in *txFixture) *txFixture {
        }
        if result.assetID.IsZero() {
                refdatahash := hashData(result.assetDef)
-               result.assetID = bc.ComputeAssetID(result.issuanceProg.Code, &result.initialBlockID, result.issuanceProg.VmVersion, &refdatahash)
+               result.assetID = bc.ComputeAssetID(result.issuanceProg.Code, result.issuanceProg.VmVersion, &refdatahash)
        }
 
        if result.txVersion == 0 {
@@ -621,10 +645,10 @@ func sample(tb testing.TB, in *txFixture) *txFixture {
                }
                args2 := [][]byte{[]byte{6}, []byte{7}}
 
-               result.txInputs = []*legacy.TxInput{
-                       legacy.NewIssuanceInput([]byte{3}, 10, []byte{4}, result.initialBlockID, result.issuanceProg.Code, result.issuanceArgs, result.assetDef),
-                       legacy.NewSpendInput(args1, *newHash(5), result.assetID, 20, 0, cp1, *newHash(6), []byte{7}),
-                       legacy.NewSpendInput(args2, *newHash(8), result.assetID, 40, 0, cp2, *newHash(9), []byte{10}),
+               result.txInputs = []*types.TxInput{
+                       types.NewIssuanceInput([]byte{3}, 10, result.issuanceProg.Code, result.issuanceArgs, result.assetDef),
+                       types.NewSpendInput(args1, *newHash(5), result.assetID, 20, 0, cp1),
+                       types.NewSpendInput(args2, *newHash(8), result.assetID, 40, 0, cp2),
                }
        }
 
@@ -640,28 +664,19 @@ func sample(tb testing.TB, in *txFixture) *txFixture {
                        tb.Fatal(err)
                }
 
-               result.txOutputs = []*legacy.TxOutput{
-                       legacy.NewTxOutput(result.assetID, 25, cp1, []byte{11}),
-                       legacy.NewTxOutput(result.assetID, 45, cp2, []byte{12}),
+               result.txOutputs = []*types.TxOutput{
+                       types.NewTxOutput(result.assetID, 25, cp1),
+                       types.NewTxOutput(result.assetID, 45, cp2),
                }
        }
-       if result.txMinTime == 0 {
-               result.txMinTime = bc.Millis(time.Now().Add(-time.Minute))
-       }
-       if result.txMaxTime == 0 {
-               result.txMaxTime = bc.Millis(time.Now().Add(time.Minute))
-       }
        if len(result.txRefData) == 0 {
                result.txRefData = []byte{13}
        }
 
-       result.tx = &legacy.TxData{
-               Version:       result.txVersion,
-               Inputs:        result.txInputs,
-               Outputs:       result.txOutputs,
-               MinTime:       result.txMinTime,
-               MaxTime:       result.txMaxTime,
-               ReferenceData: result.txRefData,
+       result.tx = &types.TxData{
+               Version: result.txVersion,
+               Inputs:  result.txInputs,
+               Outputs: result.txOutputs,
        }
 
        return &result
@@ -676,15 +691,21 @@ func mockBlock() *bc.Block {
 }
 
 func mockCoinbaseTx(amount uint64) *bc.Tx {
-       return legacy.MapTx(&legacy.TxData{
-               Outputs: []*legacy.TxOutput{
-                       legacy.NewTxOutput(*consensus.BTMAssetID, amount, []byte{1}, nil),
+       cp, _ := vmutil.DefaultCoinbaseProgram()
+       return types.MapTx(&types.TxData{
+               SerializedSize: 1,
+               Inputs: []*types.TxInput{
+                       types.NewCoinbaseInput(nil),
+               },
+               Outputs: []*types.TxOutput{
+                       types.NewTxOutput(*consensus.BTMAssetID, amount, cp),
                },
        })
 }
 
-func mockGasTxInput() *legacy.TxInput {
-       return legacy.NewSpendInput([][]byte{}, *newHash(8), *consensus.BTMAssetID, 100000000, 0, []byte{byte(vm.OP_TRUE)}, *newHash(9), []byte{})
+func mockGasTxInput() *types.TxInput {
+       cp, _ := vmutil.DefaultCoinbaseProgram()
+       return types.NewSpendInput([][]byte{}, *newHash(8), *consensus.BTMAssetID, 100000000, 0, cp)
 }
 
 // Like errors.Root, but also unwraps vm.Error objects.