OSDN Git Service

add free gas (#295)
authoroysheng <33340252+oysheng@users.noreply.github.com>
Wed, 17 Jul 2019 03:15:46 +0000 (11:15 +0800)
committerPaladz <yzhu101@uottawa.ca>
Wed, 17 Jul 2019 03:15:46 +0000 (11:15 +0800)
* add free gas

* unit test

* delete checkout nobtm input

* optimise

api/errors.go
blockchain/txbuilder/finalize.go
protocol/txpool.go
protocol/txpool_test.go
protocol/validation/block_test.go
protocol/validation/test/tx_ugly_test.go
protocol/validation/tx.go
protocol/validation/tx_test.go

index 5f8fe2f..0a6c38f 100644 (file)
@@ -73,9 +73,8 @@ var respErrFormatter = map[error]httperror.Info{
        txbuilder.ErrBadContractArgType: {400, "BTM715", "Invalid contract argument type"},
        txbuilder.ErrOrphanTx:           {400, "BTM716", "Transaction input UTXO not found"},
        txbuilder.ErrExtTxFee:           {400, "BTM717", "Transaction fee exceeded max limit"},
-       txbuilder.ErrNoGasInput:         {400, "BTM718", "Transaction has no gas input"},
-       txbuilder.ErrRejected:           {400, "BTM719", "Transaction rejected"},
-       protocol.ErrDustTx:              {400, "BTM720", "Dust Transaction"},
+       txbuilder.ErrRejected:           {400, "BTM718", "Transaction rejected"},
+       protocol.ErrDustTx:              {400, "BTM719", "Dust Transaction"},
 
        // Submit transaction error namespace (73x ~ 79x)
        // Validation error (73x ~ 75x)
index 270bb3b..0955876 100644 (file)
@@ -24,8 +24,6 @@ var (
        ErrOrphanTx = errors.New("finalize can't find transaction input utxo")
        // ErrExtTxFee means transaction fee exceed max limit
        ErrExtTxFee = errors.New("transaction fee exceed max limit")
-       // ErrNoGasInput means transaction has no gas input
-       ErrNoGasInput = errors.New("transaction has no gas input")
 )
 
 // FinalizeTx validates a transaction signature template,
@@ -42,10 +40,6 @@ func FinalizeTx(ctx context.Context, c *protocol.Chain, tx *types.Tx) error {
                return err
        }
 
-       if err := checkGasInputIDs(tx); err != nil {
-               return err
-       }
-
        // This part is use for prevent tx size  is 0
        data, err := tx.TxData.MarshalText()
        if err != nil {
@@ -131,17 +125,3 @@ func checkTxSighashCommitment(tx *types.Tx) error {
 
        return lastError
 }
-
-func checkGasInputIDs(tx *types.Tx) error {
-       for _, inp := range tx.Inputs {
-               switch inp.InputType() {
-               case types.CrossChainInputType:
-                       return nil
-               }
-       }
-
-       if len(tx.GasInputIDs) == 0 {
-               return ErrNoGasInput
-       }
-       return nil
-}
index 912091c..5a06c67 100644 (file)
@@ -192,20 +192,6 @@ func (tp *TxPool) HaveTransaction(txHash *bc.Hash) bool {
        return tp.IsTransactionInPool(txHash) || tp.IsTransactionInErrCache(txHash)
 }
 
-func isTransactionNoBtmInput(tx *types.Tx) bool {
-       for _, input := range tx.TxData.Inputs {
-               switch input.InputType() {
-               case types.CrossChainInputType:
-                       return false
-               }
-               if input.AssetID() == *consensus.BTMAssetID {
-                       return false
-               }
-       }
-
-       return true
-}
-
 func isTransactionZeroOutput(tx *types.Tx) bool {
        for _, output := range tx.TxData.Outputs {
                if value := output.AssetAmount(); value.Amount == uint64(0) {
@@ -216,7 +202,7 @@ func isTransactionZeroOutput(tx *types.Tx) bool {
 }
 
 func (tp *TxPool) IsDust(tx *types.Tx) bool {
-       return isTransactionNoBtmInput(tx) || isTransactionZeroOutput(tx)
+       return isTransactionZeroOutput(tx)
 }
 
 func (tp *TxPool) processTransaction(tx *types.Tx, statusFail bool, height, fee uint64) (bool, error) {
index 7b96cb0..9af97ef 100644 (file)
@@ -118,7 +118,7 @@ func (s *mockStore) GetStoreStatus() *BlockStoreState
 func (s *mockStore) GetTransactionStatus(*bc.Hash) (*bc.TransactionStatus, error) { return nil, nil }
 func (s *mockStore) GetTransactionsUtxo(*state.UtxoViewpoint, []*bc.Tx) error     { return nil }
 func (s *mockStore) GetUtxo(*bc.Hash) (*storage.UtxoEntry, error)                 { return nil, nil }
-func (s *mockStore) GetConsensusResult(uint64) (*state.ConsensusResult, error)              { return nil, nil }
+func (s *mockStore) GetConsensusResult(uint64) (*state.ConsensusResult, error)    { return nil, nil }
 func (s *mockStore) GetMainChainHash(uint64) (*bc.Hash, error)                    { return nil, nil }
 func (s *mockStore) GetBlockHashesByHeight(uint64) ([]*bc.Hash, error)            { return nil, nil }
 func (s *mockStore) SaveBlock(*types.Block, *bc.TransactionStatus) error          { return nil }
@@ -668,12 +668,12 @@ func (s *mockStore1) GetTransactionsUtxo(utxoView *state.UtxoViewpoint, tx []*bc
        }
        return nil
 }
-func (s *mockStore1) GetUtxo(*bc.Hash) (*storage.UtxoEntry, error)        { return nil, nil }
-func (s *mockStore1) GetConsensusResult(uint64) (*state.ConsensusResult, error)     { return nil, nil }
-func (s *mockStore1) GetMainChainHash(uint64) (*bc.Hash, error)           { return nil, nil }
-func (s *mockStore1) GetBlockHashesByHeight(uint64) ([]*bc.Hash, error)   { return nil, nil }
-func (s *mockStore1) SaveBlock(*types.Block, *bc.TransactionStatus) error { return nil }
-func (s *mockStore1) SaveBlockHeader(*types.BlockHeader) error            { return nil }
+func (s *mockStore1) GetUtxo(*bc.Hash) (*storage.UtxoEntry, error)              { return nil, nil }
+func (s *mockStore1) GetConsensusResult(uint64) (*state.ConsensusResult, error) { return nil, nil }
+func (s *mockStore1) GetMainChainHash(uint64) (*bc.Hash, error)                 { return nil, nil }
+func (s *mockStore1) GetBlockHashesByHeight(uint64) ([]*bc.Hash, error)         { return nil, nil }
+func (s *mockStore1) SaveBlock(*types.Block, *bc.TransactionStatus) error       { return nil }
+func (s *mockStore1) SaveBlockHeader(*types.BlockHeader) error                  { return nil }
 func (s *mockStore1) SaveChainStatus(*types.BlockHeader, *types.BlockHeader, []*types.BlockHeader, *state.UtxoViewpoint, []*state.ConsensusResult) error {
        return nil
 }
@@ -695,22 +695,6 @@ func TestProcessTransaction(t *testing.T) {
                {
                        want: &TxPool{},
                        addTx: &TxDesc{
-                               Tx:         testTxs[3],
-                               StatusFail: false,
-                       },
-               },
-               //Dust tx
-               {
-                       want: &TxPool{},
-                       addTx: &TxDesc{
-                               Tx:         testTxs[4],
-                               StatusFail: false,
-                       },
-               },
-               //Dust tx
-               {
-                       want: &TxPool{},
-                       addTx: &TxDesc{
                                Tx:         testTxs[5],
                                StatusFail: false,
                        },
index 6749963..f7a0f7b 100644 (file)
@@ -338,10 +338,12 @@ func TestValidateBlock(t *testing.T) {
                        block: &bc.Block{
                                ID: bc.Hash{V0: 1},
                                BlockHeader: &bc.BlockHeader{
-                                       Version:         1,
-                                       Height:          1,
-                                       Timestamp:       1523352601000,
-                                       PreviousBlockId: &parentHash,
+                                       Version:               1,
+                                       Height:                1,
+                                       Timestamp:             1523352601000,
+                                       PreviousBlockId:       &parentHash,
+                                       TransactionsRoot:      &bc.Hash{V0: 16229071813194843118, V1: 7413717724217377663, V2: 10255217553502780716, V3: 17975900656333257644},
+                                       TransactionStatusHash: &txStatusHash,
                                },
                                Transactions: []*bc.Tx{
                                        types.MapTx(&types.TxData{
@@ -362,7 +364,7 @@ func TestValidateBlock(t *testing.T) {
                                },
                        },
                        parent: parent,
-                       err:    vm.ErrRunLimitExceeded,
+                       err:    nil,
                },
        }
 
index 5d9a210..a189797 100644 (file)
@@ -66,7 +66,7 @@ func TestValidateUglyTx(t *testing.T) {
                        gasValid: false,
                },
                {
-                       category: "fee insufficient",
+                       category: "normal with no fee",
                        desc:     "sum of btm output equals to input btm",
                        insts:    []*signingInst{singleSignInst},
                        txData: types.TxData{
@@ -77,11 +77,11 @@ func TestValidateUglyTx(t *testing.T) {
                                                *consensus.BTMAssetID, 10000000000, 0, nil),
                                },
                                Outputs: []*types.TxOutput{
-                                       types.NewIntraChainOutput(*consensus.BTMAssetID, 10000000001, testutil.MustDecodeHexString("00145931e1b7b65897f47845ac08fc136e0c0a4ff166")),
+                                       types.NewIntraChainOutput(*consensus.BTMAssetID, 10000000000, testutil.MustDecodeHexString("00145931e1b7b65897f47845ac08fc136e0c0a4ff166")),
                                },
                        },
-                       err:      true,
-                       gasValid: false,
+                       err:      false,
+                       gasValid: true,
                },
                {
                        category: "fee insufficient",
@@ -98,11 +98,11 @@ func TestValidateUglyTx(t *testing.T) {
                                        types.NewIntraChainOutput(*consensus.BTMAssetID, 10000000000, testutil.MustDecodeHexString("00145931e1b7b65897f47845ac08fc136e0c0a4ff166")),
                                },
                        },
-                       err:      true,
-                       gasValid: false,
+                       err:      false,
+                       gasValid: true,
                },
                {
-                       category: "fee insufficient",
+                       category: "normal with no fee",
                        desc:     "no btm input",
                        insts:    []*signingInst{singleSignInst},
                        txData: types.TxData{
@@ -116,7 +116,7 @@ func TestValidateUglyTx(t *testing.T) {
                                        types.NewIntraChainOutput(testutil.MustDecodeAsset("97575084e5161406a0977da729fbf51ad230e0ff0aec607a97e4336611c8707f"), 10000000000, testutil.MustDecodeHexString("00145931e1b7b65897f47845ac08fc136e0c0a4ff166")),
                                },
                        },
-                       err:      true,
+                       err:      false,
                        gasValid: true,
                },
                {
@@ -286,24 +286,6 @@ func TestValidateUglyTx(t *testing.T) {
                },
                {
                        category: "input output unbalance",
-                       desc:     "input utxo is zero",
-                       insts:    []*signingInst{singleSignInst},
-                       txData: types.TxData{
-                               Version: 1,
-                               Inputs: []*types.TxInput{
-                                       types.NewSpendInput(nil,
-                                               bc.Hash{V0: 14760873410800997144, V1: 1698395500822741684, V2: 5965908492734661392, V3: 9445539829830863994},
-                                               *consensus.BTMAssetID, 0, 0, nil),
-                               },
-                               Outputs: []*types.TxOutput{
-                                       types.NewIntraChainOutput(*consensus.BTMAssetID, 0, testutil.MustDecodeHexString("00145931e1b7b65897f47845ac08fc136e0c0a4ff166")),
-                               },
-                       },
-                       err:      true,
-                       gasValid: false,
-               },
-               {
-                       category: "input output unbalance",
                        desc:     "no btm input",
                        txData: types.TxData{
                                Version: 1,
index 9364455..d360854 100644 (file)
@@ -58,12 +58,15 @@ func (g *GasState) setGas(BTMValue int64, txSize int64) error {
        }
 
        g.BTMValue = uint64(BTMValue)
-
        var ok bool
        if g.GasLeft, ok = checked.DivInt64(BTMValue, consensus.ActiveNetParams.VMGasRate); !ok {
                return errors.Wrap(ErrGasCalculate, "setGas calc gas amount")
        }
 
+       if g.GasLeft, ok = checked.AddInt64(g.GasLeft, consensus.ActiveNetParams.DefaultGasCredit); !ok {
+               return errors.Wrap(ErrGasCalculate, "setGas calc free gas")
+       }
+
        if g.GasLeft > consensus.ActiveNetParams.MaxGasAmount {
                g.GasLeft = consensus.ActiveNetParams.MaxGasAmount
        }
@@ -172,16 +175,19 @@ func checkValid(vs *validationState, e bc.Entry) (err error) {
                        parity[*dest.Value.AssetId] = diff
                }
 
+               btmAmount := int64(0)
                for assetID, amount := range parity {
                        if assetID == *consensus.BTMAssetID {
-                               if err = vs.gasStatus.setGas(amount, int64(vs.tx.SerializedSize)); err != nil {
-                                       return err
-                               }
+                               btmAmount = amount
                        } else if amount != 0 {
                                return errors.WithDetailf(ErrUnbalanced, "asset %x sources - destinations = %d (should be 0)", assetID.Bytes(), amount)
                        }
                }
 
+               if err = vs.gasStatus.setGas(btmAmount, int64(vs.tx.SerializedSize)); err != nil {
+                       return err
+               }
+
                for _, BTMInputID := range vs.tx.GasInputIDs {
                        e, ok := vs.tx.Entries[BTMInputID]
                        if !ok {
index 17664df..60b34ab 100644 (file)
@@ -34,7 +34,7 @@ func TestGasStatus(t *testing.T) {
                                BTMValue: 0,
                        },
                        output: &GasState{
-                               GasLeft:  10000 / consensus.ActiveNetParams.VMGasRate,
+                               GasLeft:  10000/consensus.ActiveNetParams.VMGasRate + consensus.ActiveNetParams.DefaultGasCredit,
                                GasUsed:  0,
                                BTMValue: 10000,
                        },
@@ -500,7 +500,7 @@ func TestTxValidation(t *testing.T) {
                        err: bc.ErrMissingEntry,
                },
                {
-                       desc: "no gas spend input",
+                       desc: "normal check with no gas spend input",
                        f: func() {
                                spendID := mux.Sources[len(mux.Sources)-1].Ref
                                delete(tx.Entries, *spendID)
@@ -508,7 +508,7 @@ func TestTxValidation(t *testing.T) {
                                tx.GasInputIDs = nil
                                vs.gasStatus.GasLeft = 0
                        },
-                       err: vm.ErrRunLimitExceeded,
+                       err: nil,
                },
                {
                        desc: "no gas spend input, but set gas left, so it's ok",