OSDN Git Service

open_gas_stand_tx_limit (#1953)
authorPaladz <yzhu101@uottawa.ca>
Wed, 9 Jun 2021 05:56:16 +0000 (13:56 +0800)
committerGitHub <noreply@github.com>
Wed, 9 Jun 2021 05:56:16 +0000 (13:56 +0800)
* open_gas_stand_tx_limit

* edit the error name

Co-authored-by: paladz <colt@ColtdeMacBook-Pro.local>
blockchain/txbuilder/finalize.go
protocol/bc/tx.go
protocol/bc/types/map.go
protocol/bc/types/map_test.go
protocol/validation/tx.go
protocol/validation/tx_test.go

index 3639b48..1d96618 100644 (file)
@@ -39,10 +39,6 @@ func FinalizeTx(ctx context.Context, c *protocol.Chain, tx *types.Tx) error {
                return err
        }
 
-       if len(tx.GasInputIDs) == 0 {
-               return ErrNoGasInput
-       }
-
        // This part is use for prevent tx size  is 0
        data, err := tx.TxData.MarshalText()
        if err != nil {
index 20191ce..4455239 100644 (file)
@@ -13,7 +13,6 @@ type Tx struct {
        InputIDs []Hash // 1:1 correspondence with TxData.Inputs
 
        SpentOutputIDs []Hash
-       GasInputIDs    []Hash
 }
 
 // SigHash ...
index 7067c75..7cc2047 100644 (file)
@@ -1,64 +1,11 @@
 package types
 
 import (
-       "github.com/bytom/bytom/consensus"
        "github.com/bytom/bytom/protocol/bc"
        "github.com/bytom/bytom/protocol/vm"
        "github.com/bytom/bytom/protocol/vm/vmutil"
 )
 
-// MapTx converts a types TxData object into its entries-based
-// representation.
-func MapTx(oldTx *TxData) *bc.Tx {
-       txID, txHeader, entries := mapTx(oldTx)
-       tx := &bc.Tx{
-               TxHeader: txHeader,
-               ID:       txID,
-               Entries:  entries,
-               InputIDs: make([]bc.Hash, len(oldTx.Inputs)),
-       }
-
-       spentOutputIDs := make(map[bc.Hash]bool)
-       for id, e := range entries {
-               var ord uint64
-               switch e := e.(type) {
-               case *bc.Issuance:
-                       ord = e.Ordinal
-
-               case *bc.Spend:
-                       ord = e.Ordinal
-                       spentOutputIDs[*e.SpentOutputId] = true
-                       if *e.WitnessDestination.Value.AssetId == *consensus.BTMAssetID {
-                               tx.GasInputIDs = append(tx.GasInputIDs, id)
-                       }
-
-               case *bc.VetoInput:
-                       ord = e.Ordinal
-                       spentOutputIDs[*e.SpentOutputId] = true
-                       if *e.WitnessDestination.Value.AssetId == *consensus.BTMAssetID {
-                               tx.GasInputIDs = append(tx.GasInputIDs, id)
-                       }
-
-               case *bc.Coinbase:
-                       ord = 0
-                       tx.GasInputIDs = append(tx.GasInputIDs, id)
-
-               default:
-                       continue
-               }
-
-               if ord >= uint64(len(oldTx.Inputs)) {
-                       continue
-               }
-               tx.InputIDs[ord] = id
-       }
-
-       for id := range spentOutputIDs {
-               tx.SpentOutputIDs = append(tx.SpentOutputIDs, id)
-       }
-       return tx
-}
-
 type mapHelper struct {
        txData   *TxData
        entryMap map[bc.Hash]bc.Entry
@@ -72,18 +19,22 @@ type mapHelper struct {
        muxSources []*bc.ValueSource
        mux        *bc.Mux
 
-       resultIDs []*bc.Hash
+       inputIDs       []bc.Hash
+       spentOutputIDs []bc.Hash
+       resultIDs      []*bc.Hash
 }
 
 func newMapHelper(txData *TxData) *mapHelper {
        return &mapHelper{
-               txData:     txData,
-               entryMap:   make(map[bc.Hash]bc.Entry),
-               spends:     []*bc.Spend{},
-               issuances:  []*bc.Issuance{},
-               vetos:      []*bc.VetoInput{},
-               muxSources: make([]*bc.ValueSource, len(txData.Inputs)),
-               resultIDs:  []*bc.Hash{},
+               txData:         txData,
+               entryMap:       make(map[bc.Hash]bc.Entry),
+               spends:         []*bc.Spend{},
+               issuances:      []*bc.Issuance{},
+               vetos:          []*bc.VetoInput{},
+               muxSources:     make([]*bc.ValueSource, len(txData.Inputs)),
+               inputIDs:       make([]bc.Hash, len(txData.Inputs)),
+               spentOutputIDs: []bc.Hash{},
+               resultIDs:      []*bc.Hash{},
        }
 }
 
@@ -93,9 +44,22 @@ func (mh *mapHelper) addEntry(e bc.Entry) bc.Hash {
        return id
 }
 
+func (mh *mapHelper) generateTx() *bc.Tx {
+       header := bc.NewTxHeader(mh.txData.Version, mh.txData.SerializedSize, mh.txData.TimeRange, mh.resultIDs)
+       return &bc.Tx{
+               TxHeader:       header,
+               ID:             mh.addEntry(header),
+               Entries:        mh.entryMap,
+               InputIDs:       mh.inputIDs,
+               SpentOutputIDs: mh.spentOutputIDs,
+       }
+
+}
+
 func (mh *mapHelper) mapCoinbaseInput(i int, input *CoinbaseInput) {
        mh.coinbase = bc.NewCoinbase(input.Arbitrary)
        id := mh.addEntry(mh.coinbase)
+       mh.inputIDs[i] = id
        mh.muxSources[i] = &bc.ValueSource{
                Ref:   &id,
                Value: &mh.txData.Outputs[0].AssetAmount,
@@ -123,6 +87,7 @@ func (mh *mapHelper) mapIssuanceInput(i int, input *IssuanceInput) {
        issuance.WitnessArguments = input.Arguments
        mh.issuances = append(mh.issuances, issuance)
        id := mh.addEntry(issuance)
+       mh.inputIDs[i] = id
        mh.muxSources[i] = &bc.ValueSource{
                Ref:   &id,
                Value: &value,
@@ -147,6 +112,8 @@ func (mh *mapHelper) mapSpendInput(i int, input *SpendInput) {
        spend.WitnessArguments = input.Arguments
        mh.spends = append(mh.spends, spend)
        id := mh.addEntry(spend)
+       mh.inputIDs[i] = id
+       mh.spentOutputIDs = append(mh.spentOutputIDs, prevoutID)
        mh.muxSources[i] = &bc.ValueSource{
                Ref:   &id,
                Value: &input.AssetAmount,
@@ -169,6 +136,8 @@ func (mh *mapHelper) mapVetoInput(i int, input *VetoInput) {
        vetoInput.WitnessArguments = input.Arguments
        mh.vetos = append(mh.vetos, vetoInput)
        id := mh.addEntry(vetoInput)
+       mh.inputIDs[i] = id
+       mh.spentOutputIDs = append(mh.spentOutputIDs, prevoutID)
        mh.muxSources[i] = &bc.ValueSource{
                Ref:   &id,
                Value: &input.AssetAmount,
@@ -251,14 +220,14 @@ func (mh *mapHelper) mapOutputs() {
        }
 }
 
-func mapTx(txData *TxData) (headerID bc.Hash, hdr *bc.TxHeader, entryMap map[bc.Hash]bc.Entry) {
+// MapTx converts a types TxData object into its entries-based
+// representation.
+func MapTx(txData *TxData) *bc.Tx {
        mh := newMapHelper(txData)
        mh.mapInputs()
        mh.initMux()
        mh.mapOutputs()
-
-       h := bc.NewTxHeader(txData.Version, txData.SerializedSize, txData.TimeRange, mh.resultIDs)
-       return mh.addEntry(h), h, mh.entryMap
+       return mh.generateTx()
 }
 
 func mapBlockHeader(old *BlockHeader) (bc.Hash, *bc.BlockHeader) {
index 6f0b2b5..3acdcea 100644 (file)
@@ -118,9 +118,6 @@ func TestMapCoinbaseTx(t *testing.T) {
        if len(tx.SpentOutputIDs) != 0 {
                t.Errorf("coinbase tx doesn't spend any utxo")
        }
-       if len(tx.GasInputIDs) != 1 {
-               t.Errorf("coinbase tx should have 1 gas input")
-       }
        if len(tx.ResultIds) != 1 {
                t.Errorf("expect to  only have one output")
        }
index aa0414c..4c14be3 100644 (file)
@@ -7,21 +7,18 @@ import (
        "sync"
 
        "github.com/bytom/bytom/consensus"
-       "github.com/bytom/bytom/consensus/segwit"
        "github.com/bytom/bytom/errors"
        "github.com/bytom/bytom/math/checked"
        "github.com/bytom/bytom/protocol/bc"
        "github.com/bytom/bytom/protocol/vm"
 )
 
-const ruleAA = 142500
-
 // validate transaction error
 var (
        ErrTxVersion                 = errors.New("invalid transaction version")
        ErrWrongTransactionSize      = errors.New("invalid transaction size")
        ErrBadTimeRange              = errors.New("invalid transaction time range")
-       ErrEmptyInputIDs             = errors.New("got the empty InputIDs")
+       ErrInputDoubleSend           = errors.New("got the double spend input")
        ErrNotStandardTx             = errors.New("not standard transaction")
        ErrWrongCoinbaseTransaction  = errors.New("wrong coinbase transaction")
        ErrWrongCoinbaseAsset        = errors.New("wrong coinbase assetID")
@@ -181,19 +178,6 @@ func checkValid(vs *validationState, e bc.Entry) (err error) {
                        }
                }
 
-               for _, BTMInputID := range vs.tx.GasInputIDs {
-                       e, ok := vs.tx.Entries[BTMInputID]
-                       if !ok {
-                               return errors.Wrapf(bc.ErrMissingEntry, "entry for bytom input %x not found", BTMInputID)
-                       }
-
-                       vs2 := *vs
-                       vs2.entryID = BTMInputID
-                       if err := checkValid(&vs2, e); err != nil {
-                               return errors.Wrap(err, "checking gas input")
-                       }
-               }
-
                for i, dest := range e.WitnessDestinations {
                        vs2 := *vs
                        vs2.destPos = uint64(i)
@@ -202,10 +186,6 @@ func checkValid(vs *validationState, e bc.Entry) (err error) {
                        }
                }
 
-               if err := vs.gasStatus.setGasValid(); err != nil {
-                       return err
-               }
-
                for i, src := range e.Sources {
                        vs2 := *vs
                        vs2.sourcePos = uint64(i)
@@ -214,6 +194,10 @@ func checkValid(vs *validationState, e bc.Entry) (err error) {
                        }
                }
 
+               if err := vs.gasStatus.setGasValid(); err != nil {
+                       return err
+               }
+
        case *bc.Output:
                vs2 := *vs
                vs2.sourcePos = 0
@@ -443,43 +427,16 @@ func checkValidDest(vs *validationState, vd *bc.ValueDestination) error {
        return nil
 }
 
-func checkStandardTx(tx *bc.Tx, blockHeight uint64) error {
+func checkDoubleSpend(tx *bc.Tx) error {
+       usedInputMap := make(map[bc.Hash]bool)
        for _, id := range tx.InputIDs {
-               if blockHeight >= ruleAA && id.IsZero() {
-                       return ErrEmptyInputIDs
-               }
-       }
-
-       for _, id := range tx.GasInputIDs {
-               spend, err := tx.Spend(id)
-               if err != nil {
-                       continue
-               }
-               spentOutput, err := tx.Output(*spend.SpentOutputId)
-               if err != nil {
-                       return err
+               if _, ok := usedInputMap[id]; ok {
+                       return ErrInputDoubleSend
                }
 
-               if !segwit.IsP2WScript(spentOutput.ControlProgram.Code) {
-                       return ErrNotStandardTx
-               }
+               usedInputMap[id] = true
        }
 
-       for _, id := range tx.ResultIds {
-               e, ok := tx.Entries[*id]
-               if !ok {
-                       return errors.Wrapf(bc.ErrMissingEntry, "id %x", id.Bytes())
-               }
-
-               output, ok := e.(*bc.Output)
-               if !ok || *output.Source.Value.AssetId != *consensus.BTMAssetID {
-                       continue
-               }
-
-               if !segwit.IsP2WScript(output.ControlProgram.Code) {
-                       return ErrNotStandardTx
-               }
-       }
        return nil
 }
 
@@ -508,7 +465,7 @@ func ValidateTx(tx *bc.Tx, block *bc.Block, converter ProgramConverterFunc) (*Ga
                return nil, err
        }
 
-       if err := checkStandardTx(tx, block.Height); err != nil {
+       if err := checkDoubleSpend(tx); err != nil {
                return nil, err
        }
 
index 8719c17..74ef533 100644 (file)
@@ -224,8 +224,8 @@ func TestOverflow(t *testing.T) {
                txInputs := make([]*types.TxInput, 0, len(inputs))
                txOutputs := make([]*types.TxOutput, 0, len(outputs))
 
-               for _, amount := range inputs {
-                       txInput := types.NewSpendInput(nil, *sourceID, *consensus.BTMAssetID, amount, 0, ctrlProgram, nil)
+               for i, amount := range inputs {
+                       txInput := types.NewSpendInput(nil, *sourceID, *consensus.BTMAssetID, amount, uint64(i), ctrlProgram, nil)
                        txInputs = append(txInputs, txInput)
                }
 
@@ -524,21 +524,11 @@ func TestTxValidation(t *testing.T) {
                        err: ErrOverGasCredit,
                },
                {
-                       desc: "can't find gas spend input in entries",
-                       f: func() {
-                               spendID := mux.Sources[len(mux.Sources)-1].Ref
-                               delete(tx.Entries, *spendID)
-                               mux.Sources = mux.Sources[:len(mux.Sources)-1]
-                       },
-                       err: bc.ErrMissingEntry,
-               },
-               {
                        desc: "no gas spend input",
                        f: func() {
                                spendID := mux.Sources[len(mux.Sources)-1].Ref
                                delete(tx.Entries, *spendID)
                                mux.Sources = mux.Sources[:len(mux.Sources)-1]
-                               tx.GasInputIDs = nil
                                vs.gasStatus.GasLeft = 0
                        },
                        err: vm.ErrRunLimitExceeded,
@@ -549,7 +539,6 @@ func TestTxValidation(t *testing.T) {
                                spendID := mux.Sources[len(mux.Sources)-1].Ref
                                delete(tx.Entries, *spendID)
                                mux.Sources = mux.Sources[:len(mux.Sources)-1]
-                               tx.GasInputIDs = nil
                        },
                        err: nil,
                },
@@ -823,7 +812,7 @@ func TestCoinbase(t *testing.T) {
        }
 }
 
-func TestRuleAA(t *testing.T) {
+func TestDoubleSpend(t *testing.T) {
        testData := "07010004016201609bc47dda88eee18c7433340c16e054cabee4318a8d638e873be19e979df81dc7ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0e3f9f5c80e0101160014f233267911e94dc74df706fe3b697273e212d5450063024088b5e730136407312980d3b1446004a8c552111721a4ba48044365cf7f7785542f2d7799f73d7cba1be2301fdfb91ad6ea99559b1857a25336eaefd90675870f207642ba797fd89d1f98a8559b4ca74123697dd4dee882955acd0da9010a80d64e0161015fe334d4fe18398f0232d2aca7050388ce4ee5ae82c8148d7f0cea748438b65135ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff80ace684200101160014f233267911e94dc74df706fe3b697273e212d545006302404a17a5995b8163ee448719b462a5694b22a35522dd9883333fd462cc3d0aabf049445c5cbb911a40e1906a5bea99b23b1a79e215eeb1a818d8b1dd27e06f3004207642ba797fd89d1f98a8559b4ca74123697dd4dee882955acd0da9010a80d64e016201609bc47dda88eee18c7433340c16e054cabee4318a8d638e873be19e979df81dc7ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0e3f9f5c80e0101160014f233267911e94dc74df706fe3b697273e212d5450063024088b5e730136407312980d3b1446004a8c552111721a4ba48044365cf7f7785542f2d7799f73d7cba1be2301fdfb91ad6ea99559b1857a25336eaefd90675870f207642ba797fd89d1f98a8559b4ca74123697dd4dee882955acd0da9010a80d64e0161015fe334d4fe18398f0232d2aca7050388ce4ee5ae82c8148d7f0cea748438b65135ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff80ace684200101160014f233267911e94dc74df706fe3b697273e212d545006302409278702c74eb3ae7666f9da4841443a4b001d6c7d7de631faf9f26eb464f6cdd741dcd4c2f3a1eb47cbc345f56a16902380b8f74b7a559f9bec854bd0e955b0c207642ba797fd89d1f98a8559b4ca74123697dd4dee882955acd0da9010a80d64e0201003fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffa08ba3fae80e01160014aac0345165045e612b3d7363f39a372bead80ce7000001003fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe08fe0fae80e01160014aac0345165045e612b3d7363f39a372bead80ce70000"
        /*
                07  // serflags
@@ -931,18 +920,10 @@ func TestRuleAA(t *testing.T) {
                {
                        block: &bc.Block{
                                BlockHeader: &bc.BlockHeader{
-                                       Height: ruleAA - 1,
-                               },
-                       },
-                       err: ErrMismatchedPosition,
-               },
-               {
-                       block: &bc.Block{
-                               BlockHeader: &bc.BlockHeader{
-                                       Height: ruleAA,
+                                       Height: 5000,
                                },
                        },
-                       err: ErrEmptyInputIDs,
+                       err: ErrInputDoubleSend,
                },
        }
 
@@ -1005,53 +986,6 @@ func TestTimeRange(t *testing.T) {
        }
 }
 
-func TestStandardTx(t *testing.T) {
-       fixture := sample(t, nil)
-       tx := types.NewTx(*fixture.tx).Tx
-
-       cases := []struct {
-               desc string
-               f    func()
-               err  error
-       }{
-               {
-                       desc: "normal standard tx",
-                       err:  nil,
-               },
-               {
-                       desc: "not standard tx in spend input",
-                       f: func() {
-                               inputID := tx.GasInputIDs[0]
-                               spend := tx.Entries[inputID].(*bc.Spend)
-                               spentOutput, err := tx.Output(*spend.SpentOutputId)
-                               if err != nil {
-                                       t.Fatal(err)
-                               }
-                               spentOutput.ControlProgram = &bc.Program{Code: []byte{0}}
-                       },
-                       err: ErrNotStandardTx,
-               },
-               {
-                       desc: "not standard tx in output",
-                       f: func() {
-                               outputID := tx.ResultIds[0]
-                               output := tx.Entries[*outputID].(*bc.Output)
-                               output.ControlProgram = &bc.Program{Code: []byte{0}}
-                       },
-                       err: ErrNotStandardTx,
-               },
-       }
-
-       for i, c := range cases {
-               if c.f != nil {
-                       c.f()
-               }
-               if err := checkStandardTx(tx, 0); err != c.err {
-                       t.Errorf("case #%d (%s) got error %t, want %t", i, c.desc, err, c.err)
-               }
-       }
-}
-
 func TestValidateTxVersion(t *testing.T) {
        converter := func(prog []byte) ([]byte, error) { return nil, nil }
        cases := []struct {