package validation
import (
- "blockchain/consensus"
"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() {
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)
}
}
}
// 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
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),
}
{
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)
}
}
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)
}
}
}
// 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
}
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 {
}
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),
}
}
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
}
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.