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)
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,
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 {
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
-}
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) {
}
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) {
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 }
}
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
}
{
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,
},
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{
},
},
parent: parent,
- err: vm.ErrRunLimitExceeded,
+ err: nil,
},
}
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{
*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",
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{
types.NewIntraChainOutput(testutil.MustDecodeAsset("97575084e5161406a0977da729fbf51ad230e0ff0aec607a97e4336611c8707f"), 10000000000, testutil.MustDecodeHexString("00145931e1b7b65897f47845ac08fc136e0c0a4ff166")),
},
},
- err: true,
+ err: false,
gasValid: true,
},
{
},
{
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,
}
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
}
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 {
BTMValue: 0,
},
output: &GasState{
- GasLeft: 10000 / consensus.ActiveNetParams.VMGasRate,
+ GasLeft: 10000/consensus.ActiveNetParams.VMGasRate + consensus.ActiveNetParams.DefaultGasCredit,
GasUsed: 0,
BTMValue: 10000,
},
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)
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",