X-Git-Url: http://git.osdn.net/view?p=bytom%2Fvapor.git;a=blobdiff_plain;f=protocol%2Fvalidation%2Ftx_test.go;fp=protocol%2Fvalidation%2Ftx_test.go;h=4fd3a66a5f6e9a24fa4559edd0c13f00406c131c;hp=33f3690505ba8b690c463bc633892880f2a8d014;hb=54373c1a3efe0e373ec1605840a4363e4b246c46;hpb=ee01d543fdfe1fd0a4d548965c66f7923ea7b062 diff --git a/protocol/validation/tx_test.go b/protocol/validation/tx_test.go index 33f36905..4fd3a66a 100644 --- a/protocol/validation/tx_test.go +++ b/protocol/validation/tx_test.go @@ -77,6 +77,22 @@ func TestGasStatus(t *testing.T) { }, { input: &GasState{ + GasLeft: consensus.DefaultGasCredit, + GasUsed: 0, + BTMValue: 0, + }, + output: &GasState{ + GasLeft: 200000, + GasUsed: 0, + BTMValue: math.MaxInt64, + }, + f: func(input *GasState) error { + return input.setGas(math.MaxInt64, 0) + }, + err: nil, + }, + { + input: &GasState{ GasLeft: 10000, GasUsed: 0, BTMValue: 0, @@ -107,6 +123,94 @@ func TestGasStatus(t *testing.T) { }, err: nil, }, + { + input: &GasState{ + GasLeft: -10000, + GasUsed: 0, + BTMValue: 0, + }, + output: &GasState{ + GasLeft: -10000, + GasUsed: 0, + BTMValue: 0, + }, + f: func(input *GasState) error { + return input.updateUsage(math.MaxInt64) + }, + err: ErrGasCalculate, + }, + { + input: &GasState{ + GasLeft: 1000, + GasUsed: 10, + StorageGas: 1000, + GasValid: false, + }, + output: &GasState{ + GasLeft: 0, + GasUsed: 1010, + StorageGas: 1000, + GasValid: true, + }, + f: func(input *GasState) error { + return input.setGasValid() + }, + err: nil, + }, + { + input: &GasState{ + GasLeft: 900, + GasUsed: 10, + StorageGas: 1000, + GasValid: false, + }, + output: &GasState{ + GasLeft: -100, + GasUsed: 10, + StorageGas: 1000, + GasValid: false, + }, + f: func(input *GasState) error { + return input.setGasValid() + }, + err: ErrGasCalculate, + }, + { + input: &GasState{ + GasLeft: 1000, + GasUsed: math.MaxInt64, + StorageGas: 1000, + GasValid: false, + }, + output: &GasState{ + GasLeft: 0, + GasUsed: 0, + StorageGas: 1000, + GasValid: false, + }, + f: func(input *GasState) error { + return input.setGasValid() + }, + err: ErrGasCalculate, + }, + { + input: &GasState{ + GasLeft: math.MinInt64, + GasUsed: 0, + StorageGas: 1000, + GasValid: false, + }, + output: &GasState{ + GasLeft: 0, + GasUsed: 0, + StorageGas: 1000, + GasValid: false, + }, + f: func(input *GasState) error { + return input.setGasValid() + }, + err: ErrGasCalculate, + }, } for i, c := range cases { @@ -133,7 +237,7 @@ func TestOverflow(t *testing.T) { } for _, amount := range outputs { - txOutput := types.NewTxOutput(*consensus.BTMAssetID, amount, ctrlProgram) + txOutput := types.NewIntraChainOutput(*consensus.BTMAssetID, amount, ctrlProgram) txOutputs = append(txOutputs, txOutput) } @@ -219,24 +323,25 @@ func TestTxValidation(t *testing.T) { addCoinbase := func(assetID *bc.AssetID, amount uint64, arbitrary []byte) { coinbase := bc.NewCoinbase(arbitrary) - txOutput := types.NewTxOutput(*assetID, amount, []byte{byte(vm.OP_TRUE)}) + txOutput := types.NewIntraChainOutput(*assetID, amount, []byte{byte(vm.OP_TRUE)}) + assetAmount := txOutput.AssetAmount() muxID := getMuxID(tx) - coinbase.SetDestination(muxID, &txOutput.AssetAmount, uint64(len(mux.Sources))) + coinbase.SetDestination(muxID, &assetAmount, uint64(len(mux.Sources))) coinbaseID := bc.EntryID(coinbase) tx.Entries[coinbaseID] = coinbase mux.Sources = append(mux.Sources, &bc.ValueSource{ Ref: &coinbaseID, - Value: &txOutput.AssetAmount, + Value: &assetAmount, }) src := &bc.ValueSource{ Ref: muxID, - Value: &txOutput.AssetAmount, + Value: &assetAmount, Position: uint64(len(tx.ResultIds)), } - prog := &bc.Program{txOutput.VMVersion, txOutput.ControlProgram} - output := bc.NewOutput(src, prog, uint64(len(tx.ResultIds))) + prog := &bc.Program{txOutput.VMVersion(), txOutput.ControlProgram()} + output := bc.NewIntraChainOutput(src, prog, uint64(len(tx.ResultIds))) outputID := bc.EntryID(output) tx.Entries[outputID] = output @@ -261,15 +366,6 @@ func TestTxValidation(t *testing.T) { { desc: "unbalanced mux amounts", f: func() { - mux.Sources[0].Value.Amount++ - iss := tx.Entries[*mux.Sources[0].Ref].(*bc.Issuance) - iss.WitnessDestination.Value.Amount++ - }, - err: ErrUnbalanced, - }, - { - desc: "unbalanced mux amounts", - f: func() { mux.WitnessDestinations[0].Value.Amount++ }, err: ErrUnbalanced, @@ -283,22 +379,13 @@ func TestTxValidation(t *testing.T) { err: nil, }, { - desc: "overflowing mux source amounts", - f: func() { - mux.Sources[0].Value.Amount = math.MaxInt64 - iss := tx.Entries[*mux.Sources[0].Ref].(*bc.Issuance) - iss.WitnessDestination.Value.Amount = math.MaxInt64 - }, - err: ErrOverflow, - }, - { desc: "underflowing mux destination amounts", f: func() { mux.WitnessDestinations[0].Value.Amount = math.MaxInt64 - out := tx.Entries[*mux.WitnessDestinations[0].Ref].(*bc.Output) + out := tx.Entries[*mux.WitnessDestinations[0].Ref].(*bc.IntraChainOutput) out.Source.Value.Amount = math.MaxInt64 mux.WitnessDestinations[1].Value.Amount = math.MaxInt64 - out = tx.Entries[*mux.WitnessDestinations[1].Ref].(*bc.Output) + out = tx.Entries[*mux.WitnessDestinations[1].Ref].(*bc.IntraChainOutput) out.Source.Value.Amount = math.MaxInt64 }, err: ErrOverflow, @@ -315,7 +402,14 @@ func TestTxValidation(t *testing.T) { { desc: "mismatched output source / mux dest position", f: func() { - tx.Entries[*tx.ResultIds[0]].(*bc.Output).Source.Position = 1 + tx.Entries[*tx.ResultIds[0]].(*bc.IntraChainOutput).Source.Position = 1 + }, + err: ErrMismatchedPosition, + }, + { + desc: "mismatched input dest / mux source position", + f: func() { + mux.Sources[0].Position = 1 }, err: ErrMismatchedPosition, }, @@ -329,7 +423,7 @@ func TestTxValidation(t *testing.T) { fixture2 := sample(t, fixture) tx2 := types.NewTx(*fixture2.tx).Tx out2ID := tx2.ResultIds[0] - out2 := tx2.Entries[*out2ID].(*bc.Output) + out2 := tx2.Entries[*out2ID].(*bc.IntraChainOutput) tx.Entries[*out2ID] = out2 mux.WitnessDestinations[0].Ref = out2ID }, @@ -346,7 +440,7 @@ func TestTxValidation(t *testing.T) { desc: "mismatched mux dest value / output source value", f: func() { outID := tx.ResultIds[0] - out := tx.Entries[*outID].(*bc.Output) + out := tx.Entries[*outID].(*bc.IntraChainOutput) mux.WitnessDestinations[0].Value = &bc.AssetAmount{ AssetId: out.Source.Value.AssetId, Amount: out.Source.Value.Amount + 1, @@ -370,14 +464,6 @@ func TestTxValidation(t *testing.T) { }, }, { - desc: "issuance program failure", - f: func() { - iss := txIssuance(t, tx, 0) - iss.WitnessArguments[0] = []byte{} - }, - err: vm.ErrFalseVMResult, - }, - { desc: "spend control program failure", f: func() { spend := txSpend(t, tx, 1) @@ -389,7 +475,7 @@ func TestTxValidation(t *testing.T) { desc: "mismatched spent source/witness value", f: func() { spend := txSpend(t, tx, 1) - spentOutput := tx.Entries[*spend.SpentOutputId].(*bc.Output) + spentOutput := tx.Entries[*spend.SpentOutputId].(*bc.IntraChainOutput) spentOutput.Source.Value = &bc.AssetAmount{ AssetId: spend.WitnessDestination.Value.AssetId, Amount: spend.WitnessDestination.Value.Amount + 1, @@ -447,24 +533,6 @@ func TestTxValidation(t *testing.T) { err: ErrMismatchedValue, }, { - desc: "mismatched witness asset destination", - f: func() { - issuanceID := mux.Sources[0].Ref - issuance := tx.Entries[*issuanceID].(*bc.Issuance) - issuance.WitnessAssetDefinition.Data = &bc.Hash{V0: 9999} - }, - err: ErrMismatchedAssetID, - }, - { - desc: "issuance witness position greater than length of mux sources", - f: func() { - issuanceID := mux.Sources[0].Ref - issuance := tx.Entries[*issuanceID].(*bc.Issuance) - issuance.WitnessDestination.Position = uint64(len(mux.Sources) + 1) - }, - err: ErrPosition, - }, - { desc: "normal coinbase tx", f: func() { addCoinbase(consensus.BTMAssetID, 100000, nil) @@ -498,7 +566,7 @@ func TestTxValidation(t *testing.T) { desc: "normal retirement output", f: func() { outputID := tx.ResultIds[0] - output := tx.Entries[*outputID].(*bc.Output) + output := tx.Entries[*outputID].(*bc.IntraChainOutput) retirement := bc.NewRetirement(output.Source, output.Ordinal) retirementID := bc.EntryID(retirement) tx.Entries[retirementID] = retirement @@ -512,8 +580,8 @@ func TestTxValidation(t *testing.T) { desc: "ordinal doesn't matter for prevouts", f: func() { spend := txSpend(t, tx, 1) - prevout := tx.Entries[*spend.SpentOutputId].(*bc.Output) - newPrevout := bc.NewOutput(prevout.Source, prevout.ControlProgram, 10) + prevout := tx.Entries[*spend.SpentOutputId].(*bc.IntraChainOutput) + newPrevout := bc.NewIntraChainOutput(prevout.Source, prevout.ControlProgram, 10) hash := bc.EntryID(newPrevout) spend.SpentOutputId = &hash }, @@ -565,29 +633,145 @@ func TestTxValidation(t *testing.T) { } } +// TestCoinbase test the coinbase transaction is valid (txtest#1016) func TestCoinbase(t *testing.T) { - CbTx := mockCoinbaseTx(5000000000) + cp, _ := vmutil.DefaultCoinbaseProgram() + retire, _ := vmutil.RetireProgram([]byte{}) + CbTx := types.MapTx(&types.TxData{ + SerializedSize: 1, + Inputs: []*types.TxInput{ + types.NewCoinbaseInput(nil), + }, + Outputs: []*types.TxOutput{ + types.NewIntraChainOutput(*consensus.BTMAssetID, 888, cp), + }, + }) + cases := []struct { block *bc.Block - tx *bc.Tx + txIndex int GasValid bool err error }{ { block: &bc.Block{ - BlockHeader: &bc.BlockHeader{ - Height: 666, - }, + BlockHeader: &bc.BlockHeader{Height: 666}, Transactions: []*bc.Tx{CbTx}, }, - tx: CbTx, + txIndex: 0, GasValid: true, err: nil, }, + { + block: &bc.Block{ + BlockHeader: &bc.BlockHeader{Height: 666}, + Transactions: []*bc.Tx{ + CbTx, + types.MapTx(&types.TxData{ + SerializedSize: 1, + Inputs: []*types.TxInput{ + types.NewCoinbaseInput(nil), + }, + Outputs: []*types.TxOutput{ + types.NewIntraChainOutput(*consensus.BTMAssetID, 888, cp), + }, + }), + }, + }, + txIndex: 1, + GasValid: false, + err: ErrWrongCoinbaseTransaction, + }, + { + block: &bc.Block{ + BlockHeader: &bc.BlockHeader{Height: 666}, + Transactions: []*bc.Tx{ + CbTx, + types.MapTx(&types.TxData{ + SerializedSize: 1, + Inputs: []*types.TxInput{ + types.NewCoinbaseInput(nil), + types.NewSpendInput([][]byte{}, *newHash(8), *consensus.BTMAssetID, 100000000, 0, cp), + }, + Outputs: []*types.TxOutput{ + types.NewIntraChainOutput(*consensus.BTMAssetID, 888, cp), + types.NewIntraChainOutput(*consensus.BTMAssetID, 90000000, cp), + }, + }), + }, + }, + txIndex: 1, + GasValid: false, + err: ErrWrongCoinbaseTransaction, + }, + { + block: &bc.Block{ + BlockHeader: &bc.BlockHeader{Height: 666}, + Transactions: []*bc.Tx{ + CbTx, + types.MapTx(&types.TxData{ + SerializedSize: 1, + Inputs: []*types.TxInput{ + types.NewSpendInput([][]byte{}, *newHash(8), *consensus.BTMAssetID, 100000000, 0, cp), + types.NewCoinbaseInput(nil), + }, + Outputs: []*types.TxOutput{ + types.NewIntraChainOutput(*consensus.BTMAssetID, 888, cp), + types.NewIntraChainOutput(*consensus.BTMAssetID, 90000000, cp), + }, + }), + }, + }, + txIndex: 1, + GasValid: false, + err: ErrWrongCoinbaseTransaction, + }, + { + block: &bc.Block{ + BlockHeader: &bc.BlockHeader{Height: 666}, + Transactions: []*bc.Tx{ + types.MapTx(&types.TxData{ + SerializedSize: 1, + Inputs: []*types.TxInput{ + types.NewCoinbaseInput(nil), + types.NewSpendInput([][]byte{}, *newHash(8), *consensus.BTMAssetID, 100000000, 0, cp), + }, + Outputs: []*types.TxOutput{ + types.NewIntraChainOutput(*consensus.BTMAssetID, 888, cp), + types.NewIntraChainOutput(*consensus.BTMAssetID, 90000000, cp), + }, + }), + }, + }, + txIndex: 0, + GasValid: true, + err: nil, + }, + { + block: &bc.Block{ + BlockHeader: &bc.BlockHeader{Height: 666}, + Transactions: []*bc.Tx{ + types.MapTx(&types.TxData{ + SerializedSize: 1, + Inputs: []*types.TxInput{ + types.NewCoinbaseInput(nil), + types.NewSpendInput([][]byte{}, *newHash(8), *consensus.BTMAssetID, 100000000, 0, retire), + }, + Outputs: []*types.TxOutput{ + types.NewIntraChainOutput(*consensus.BTMAssetID, 888, cp), + types.NewIntraChainOutput(*consensus.BTMAssetID, 90000000, cp), + }, + }), + }, + }, + txIndex: 0, + GasValid: false, + err: vm.ErrReturn, + }, } for i, c := range cases { - gasStatus, err := ValidateTx(c.tx, c.block) + gasStatus, err := ValidateTx(c.block.Transactions[c.txIndex], c.block) if rootErr(err) != c.err { t.Errorf("#%d got error %s, want %s", i, err, c.err) @@ -598,6 +782,7 @@ func TestCoinbase(t *testing.T) { } } +// TestTimeRange test the checkTimeRange function (txtest#1004) func TestTimeRange(t *testing.T) { cases := []struct { timeRange uint64 @@ -624,7 +809,7 @@ func TestTimeRange(t *testing.T) { block := &bc.Block{ BlockHeader: &bc.BlockHeader{ Height: 333, - Timestamp: 1521625823, + Timestamp: 1521625823000, }, } @@ -635,7 +820,7 @@ func TestTimeRange(t *testing.T) { mockGasTxInput(), }, Outputs: []*types.TxOutput{ - types.NewTxOutput(*consensus.BTMAssetID, 1, []byte{0x6a}), + types.NewIntraChainOutput(*consensus.BTMAssetID, 1, []byte{0x6a}), }, }) @@ -647,6 +832,51 @@ func TestTimeRange(t *testing.T) { } } +func TestValidateTxVersion(t *testing.T) { + cases := []struct { + desc string + block *bc.Block + err error + }{ + { + desc: "tx version greater than 1 (txtest#1001)", + block: &bc.Block{ + BlockHeader: &bc.BlockHeader{Version: 1}, + Transactions: []*bc.Tx{ + {TxHeader: &bc.TxHeader{Version: 2}}, + }, + }, + err: ErrTxVersion, + }, + { + desc: "tx version equals 0 (txtest#1002)", + block: &bc.Block{ + BlockHeader: &bc.BlockHeader{Version: 1}, + Transactions: []*bc.Tx{ + {TxHeader: &bc.TxHeader{Version: 0}}, + }, + }, + err: ErrTxVersion, + }, + { + desc: "tx version equals max uint64 (txtest#1003)", + block: &bc.Block{ + BlockHeader: &bc.BlockHeader{Version: 1}, + Transactions: []*bc.Tx{ + {TxHeader: &bc.TxHeader{Version: math.MaxUint64}}, + }, + }, + err: ErrTxVersion, + }, + } + + for i, c := range cases { + if _, err := ValidateTx(c.block.Transactions[0], c.block); rootErr(err) != c.err { + t.Errorf("case #%d (%s) got error %t, want %t", i, c.desc, err, c.err) + } + } +} + // A txFixture is returned by sample (below) to produce a sample // transaction, which takes a separate, optional _input_ txFixture to // affect the transaction that's built. The components of the @@ -699,14 +929,13 @@ func sample(tb testing.TB, in *txFixture) *txFixture { result.issuanceProg = bc.Program{VmVersion: 1, Code: prog} } if len(result.issuanceArgs) == 0 { - result.issuanceArgs = [][]byte{[]byte{2}, []byte{3}} + result.issuanceArgs = [][]byte{{2}, {3}} } if len(result.assetDef) == 0 { result.assetDef = []byte{2} } if result.assetID.IsZero() { - refdatahash := hashData(result.assetDef) - result.assetID = bc.ComputeAssetID(result.issuanceProg.Code, result.issuanceProg.VmVersion, &refdatahash) + result.assetID = bc.AssetID{V0: 9999} } if result.txVersion == 0 { @@ -717,16 +946,16 @@ func sample(tb testing.TB, in *txFixture) *txFixture { if err != nil { tb.Fatal(err) } - args1 := [][]byte{[]byte{4}, []byte{5}} + args1 := [][]byte{{4}, {5}} cp2, err := vm.Assemble("ADD 13 NUMEQUAL") if err != nil { tb.Fatal(err) } - args2 := [][]byte{[]byte{6}, []byte{7}} + args2 := [][]byte{{6}, {7}} result.txInputs = []*types.TxInput{ - types.NewIssuanceInput([]byte{3}, 10, result.issuanceProg.Code, result.issuanceArgs, result.assetDef), + types.NewSpendInput(nil, *newHash(9), result.assetID, 10, 0, []byte{byte(vm.OP_TRUE)}), types.NewSpendInput(args1, *newHash(5), result.assetID, 20, 0, cp1), types.NewSpendInput(args2, *newHash(8), result.assetID, 40, 0, cp2), } @@ -745,8 +974,8 @@ func sample(tb testing.TB, in *txFixture) *txFixture { } result.txOutputs = []*types.TxOutput{ - types.NewTxOutput(result.assetID, 25, cp1), - types.NewTxOutput(result.assetID, 45, cp2), + types.NewIntraChainOutput(result.assetID, 25, cp1), + types.NewIntraChainOutput(result.assetID, 45, cp2), } } @@ -767,19 +996,6 @@ func mockBlock() *bc.Block { } } -func mockCoinbaseTx(amount uint64) *bc.Tx { - 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() *types.TxInput { cp, _ := vmutil.DefaultCoinbaseProgram() return types.NewSpendInput([][]byte{}, *newHash(8), *consensus.BTMAssetID, 100000000, 0, cp) @@ -806,15 +1022,6 @@ func newAssetID(n byte) *bc.AssetID { return &a } -func txIssuance(t *testing.T, tx *bc.Tx, index int) *bc.Issuance { - id := tx.InputIDs[index] - res, err := tx.Issuance(id) - if err != nil { - t.Fatal(err) - } - return res -} - func txSpend(t *testing.T, tx *bc.Tx, index int) *bc.Spend { id := tx.InputIDs[index] res, err := tx.Spend(id) @@ -827,7 +1034,7 @@ func txSpend(t *testing.T, tx *bc.Tx, index int) *bc.Spend { func getMuxID(tx *bc.Tx) *bc.Hash { out := tx.Entries[*tx.ResultIds[0]] switch result := out.(type) { - case *bc.Output: + case *bc.IntraChainOutput: return result.Source.Ref case *bc.Retirement: return result.Source.Ref