blockchain: Combine ErrDoubleSpend & ErrMissingTx.
This replaces the ErrDoubleSpend and ErrMissingTx error codes with a single error code named ErrMissingTxOut and updates the relevant errors and expected test results accordingly. Once upon a time, the code relied on a transaction index, so it was able to definitively differentiate between a transaction output that legitimately did not exist and one that had already been spent. However, since the code now uses a pruned utxoset, it is no longer possible to reliably differentiate since once all outputs of a transaction are spent, it is removed from the utxoset completely. Consequently, a missing transaction could be either because the transaction never existed or because it is fully spent.
This commit is contained in:
parent
e736ae125d
commit
19eada0b4b
9 changed files with 43 additions and 60 deletions
|
@ -348,9 +348,7 @@ type SequenceLock struct {
|
||||||
// the candidate transaction to be included in a block.
|
// the candidate transaction to be included in a block.
|
||||||
//
|
//
|
||||||
// This function is safe for concurrent access.
|
// This function is safe for concurrent access.
|
||||||
func (b *BlockChain) CalcSequenceLock(tx *btcutil.Tx, utxoView *UtxoViewpoint,
|
func (b *BlockChain) CalcSequenceLock(tx *btcutil.Tx, utxoView *UtxoViewpoint, mempool bool) (*SequenceLock, error) {
|
||||||
mempool bool) (*SequenceLock, error) {
|
|
||||||
|
|
||||||
b.chainLock.Lock()
|
b.chainLock.Lock()
|
||||||
defer b.chainLock.Unlock()
|
defer b.chainLock.Unlock()
|
||||||
|
|
||||||
|
@ -361,9 +359,7 @@ func (b *BlockChain) CalcSequenceLock(tx *btcutil.Tx, utxoView *UtxoViewpoint,
|
||||||
// transaction. See the exported version, CalcSequenceLock for further details.
|
// transaction. See the exported version, CalcSequenceLock for further details.
|
||||||
//
|
//
|
||||||
// This function MUST be called with the chain state lock held (for writes).
|
// This function MUST be called with the chain state lock held (for writes).
|
||||||
func (b *BlockChain) calcSequenceLock(node *blockNode, tx *btcutil.Tx,
|
func (b *BlockChain) calcSequenceLock(node *blockNode, tx *btcutil.Tx, utxoView *UtxoViewpoint, mempool bool) (*SequenceLock, error) {
|
||||||
utxoView *UtxoViewpoint, mempool bool) (*SequenceLock, error) {
|
|
||||||
|
|
||||||
// A value of -1 for each relative lock type represents a relative time
|
// A value of -1 for each relative lock type represents a relative time
|
||||||
// lock value that will allow a transaction to be included in a block
|
// lock value that will allow a transaction to be included in a block
|
||||||
// at any given height or time. This value is returned as the relative
|
// at any given height or time. This value is returned as the relative
|
||||||
|
@ -411,10 +407,11 @@ func (b *BlockChain) calcSequenceLock(node *blockNode, tx *btcutil.Tx,
|
||||||
for txInIndex, txIn := range mTx.TxIn {
|
for txInIndex, txIn := range mTx.TxIn {
|
||||||
utxo := utxoView.LookupEntry(&txIn.PreviousOutPoint.Hash)
|
utxo := utxoView.LookupEntry(&txIn.PreviousOutPoint.Hash)
|
||||||
if utxo == nil {
|
if utxo == nil {
|
||||||
str := fmt.Sprintf("unable to find unspent output "+
|
str := fmt.Sprintf("output %v referenced from "+
|
||||||
"%v referenced from transaction %s:%d",
|
"transaction %s:%d either does not exist or "+
|
||||||
txIn.PreviousOutPoint, tx.Hash(), txInIndex)
|
"has already been spent", txIn.PreviousOutPoint,
|
||||||
return sequenceLock, ruleError(ErrMissingTx, str)
|
tx.Hash(), txInIndex)
|
||||||
|
return sequenceLock, ruleError(ErrMissingTxOut, str)
|
||||||
}
|
}
|
||||||
|
|
||||||
// If the input height is set to the mempool height, then we
|
// If the input height is set to the mempool height, then we
|
||||||
|
|
|
@ -128,9 +128,9 @@ const (
|
||||||
// range or not referencing one at all.
|
// range or not referencing one at all.
|
||||||
ErrBadTxInput
|
ErrBadTxInput
|
||||||
|
|
||||||
// ErrMissingTx indicates a transaction referenced by an input is
|
// ErrMissingTxOut indicates a transaction output referenced by an input
|
||||||
// missing.
|
// either does not exist or has already been spent.
|
||||||
ErrMissingTx
|
ErrMissingTxOut
|
||||||
|
|
||||||
// ErrUnfinalizedTx indicates a transaction has not been finalized.
|
// ErrUnfinalizedTx indicates a transaction has not been finalized.
|
||||||
// A valid block may only contain finalized transactions.
|
// A valid block may only contain finalized transactions.
|
||||||
|
@ -150,10 +150,6 @@ const (
|
||||||
// coinbase that has not yet reached the required maturity.
|
// coinbase that has not yet reached the required maturity.
|
||||||
ErrImmatureSpend
|
ErrImmatureSpend
|
||||||
|
|
||||||
// ErrDoubleSpend indicates a transaction is attempting to spend coins
|
|
||||||
// that have already been spent.
|
|
||||||
ErrDoubleSpend
|
|
||||||
|
|
||||||
// ErrSpendTooHigh indicates a transaction is attempting to spend more
|
// ErrSpendTooHigh indicates a transaction is attempting to spend more
|
||||||
// value than the sum of all of its inputs.
|
// value than the sum of all of its inputs.
|
||||||
ErrSpendTooHigh
|
ErrSpendTooHigh
|
||||||
|
@ -242,12 +238,11 @@ var errorCodeStrings = map[ErrorCode]string{
|
||||||
ErrBadTxOutValue: "ErrBadTxOutValue",
|
ErrBadTxOutValue: "ErrBadTxOutValue",
|
||||||
ErrDuplicateTxInputs: "ErrDuplicateTxInputs",
|
ErrDuplicateTxInputs: "ErrDuplicateTxInputs",
|
||||||
ErrBadTxInput: "ErrBadTxInput",
|
ErrBadTxInput: "ErrBadTxInput",
|
||||||
ErrMissingTx: "ErrMissingTx",
|
ErrMissingTxOut: "ErrMissingTxOut",
|
||||||
ErrUnfinalizedTx: "ErrUnfinalizedTx",
|
ErrUnfinalizedTx: "ErrUnfinalizedTx",
|
||||||
ErrDuplicateTx: "ErrDuplicateTx",
|
ErrDuplicateTx: "ErrDuplicateTx",
|
||||||
ErrOverwriteTx: "ErrOverwriteTx",
|
ErrOverwriteTx: "ErrOverwriteTx",
|
||||||
ErrImmatureSpend: "ErrImmatureSpend",
|
ErrImmatureSpend: "ErrImmatureSpend",
|
||||||
ErrDoubleSpend: "ErrDoubleSpend",
|
|
||||||
ErrSpendTooHigh: "ErrSpendTooHigh",
|
ErrSpendTooHigh: "ErrSpendTooHigh",
|
||||||
ErrBadFees: "ErrBadFees",
|
ErrBadFees: "ErrBadFees",
|
||||||
ErrTooManySigOps: "ErrTooManySigOps",
|
ErrTooManySigOps: "ErrTooManySigOps",
|
||||||
|
|
|
@ -38,12 +38,11 @@ func TestErrorCodeStringer(t *testing.T) {
|
||||||
{blockchain.ErrDuplicateTxInputs, "ErrDuplicateTxInputs"},
|
{blockchain.ErrDuplicateTxInputs, "ErrDuplicateTxInputs"},
|
||||||
{blockchain.ErrBadTxInput, "ErrBadTxInput"},
|
{blockchain.ErrBadTxInput, "ErrBadTxInput"},
|
||||||
{blockchain.ErrBadCheckpoint, "ErrBadCheckpoint"},
|
{blockchain.ErrBadCheckpoint, "ErrBadCheckpoint"},
|
||||||
{blockchain.ErrMissingTx, "ErrMissingTx"},
|
{blockchain.ErrMissingTxOut, "ErrMissingTxOut"},
|
||||||
{blockchain.ErrUnfinalizedTx, "ErrUnfinalizedTx"},
|
{blockchain.ErrUnfinalizedTx, "ErrUnfinalizedTx"},
|
||||||
{blockchain.ErrDuplicateTx, "ErrDuplicateTx"},
|
{blockchain.ErrDuplicateTx, "ErrDuplicateTx"},
|
||||||
{blockchain.ErrOverwriteTx, "ErrOverwriteTx"},
|
{blockchain.ErrOverwriteTx, "ErrOverwriteTx"},
|
||||||
{blockchain.ErrImmatureSpend, "ErrImmatureSpend"},
|
{blockchain.ErrImmatureSpend, "ErrImmatureSpend"},
|
||||||
{blockchain.ErrDoubleSpend, "ErrDoubleSpend"},
|
|
||||||
{blockchain.ErrSpendTooHigh, "ErrSpendTooHigh"},
|
{blockchain.ErrSpendTooHigh, "ErrSpendTooHigh"},
|
||||||
{blockchain.ErrBadFees, "ErrBadFees"},
|
{blockchain.ErrBadFees, "ErrBadFees"},
|
||||||
{blockchain.ErrTooManySigOps, "ErrTooManySigOps"},
|
{blockchain.ErrTooManySigOps, "ErrTooManySigOps"},
|
||||||
|
|
|
@ -997,7 +997,7 @@ func Generate(includeLargeReorg bool) (tests [][]TestInstance, err error) {
|
||||||
acceptedToSideChainWithExpectedTip("b6")
|
acceptedToSideChainWithExpectedTip("b6")
|
||||||
|
|
||||||
g.nextBlock("b8", outs[4])
|
g.nextBlock("b8", outs[4])
|
||||||
rejected(blockchain.ErrMissingTx)
|
rejected(blockchain.ErrMissingTxOut)
|
||||||
|
|
||||||
// ---------------------------------------------------------------------
|
// ---------------------------------------------------------------------
|
||||||
// Too much proof-of-work coinbase tests.
|
// Too much proof-of-work coinbase tests.
|
||||||
|
@ -1078,7 +1078,7 @@ func Generate(includeLargeReorg bool) (tests [][]TestInstance, err error) {
|
||||||
// \-> b3(1) -> b4(2)
|
// \-> b3(1) -> b4(2)
|
||||||
g.setTip("b15")
|
g.setTip("b15")
|
||||||
g.nextBlock("b17", &b3Tx1Out)
|
g.nextBlock("b17", &b3Tx1Out)
|
||||||
rejected(blockchain.ErrMissingTx)
|
rejected(blockchain.ErrMissingTxOut)
|
||||||
|
|
||||||
// Create block that forks and spends a tx created on a third fork.
|
// Create block that forks and spends a tx created on a third fork.
|
||||||
//
|
//
|
||||||
|
@ -1090,7 +1090,7 @@ func Generate(includeLargeReorg bool) (tests [][]TestInstance, err error) {
|
||||||
acceptedToSideChainWithExpectedTip("b15")
|
acceptedToSideChainWithExpectedTip("b15")
|
||||||
|
|
||||||
g.nextBlock("b19", outs[6])
|
g.nextBlock("b19", outs[6])
|
||||||
rejected(blockchain.ErrMissingTx)
|
rejected(blockchain.ErrMissingTxOut)
|
||||||
|
|
||||||
// ---------------------------------------------------------------------
|
// ---------------------------------------------------------------------
|
||||||
// Immature coinbase tests.
|
// Immature coinbase tests.
|
||||||
|
@ -1278,11 +1278,11 @@ func Generate(includeLargeReorg bool) (tests [][]TestInstance, err error) {
|
||||||
doubleSpendTx := createSpendTx(outs[11], lowFee)
|
doubleSpendTx := createSpendTx(outs[11], lowFee)
|
||||||
g.nextBlock("b37", outs[11], additionalTx(doubleSpendTx))
|
g.nextBlock("b37", outs[11], additionalTx(doubleSpendTx))
|
||||||
b37Tx1Out := makeSpendableOut(g.tip, 1, 0)
|
b37Tx1Out := makeSpendableOut(g.tip, 1, 0)
|
||||||
rejected(blockchain.ErrDoubleSpend)
|
rejected(blockchain.ErrMissingTxOut)
|
||||||
|
|
||||||
g.setTip("b35")
|
g.setTip("b35")
|
||||||
g.nextBlock("b38", &b37Tx1Out)
|
g.nextBlock("b38", &b37Tx1Out)
|
||||||
rejected(blockchain.ErrMissingTx)
|
rejected(blockchain.ErrMissingTxOut)
|
||||||
|
|
||||||
// ---------------------------------------------------------------------
|
// ---------------------------------------------------------------------
|
||||||
// Pay-to-script-hash signature operation count tests.
|
// Pay-to-script-hash signature operation count tests.
|
||||||
|
@ -1536,7 +1536,7 @@ func Generate(includeLargeReorg bool) (tests [][]TestInstance, err error) {
|
||||||
b.Transactions[1].TxIn[0].PreviousOutPoint.Hash = *hash
|
b.Transactions[1].TxIn[0].PreviousOutPoint.Hash = *hash
|
||||||
b.Transactions[1].TxIn[0].PreviousOutPoint.Index = 0
|
b.Transactions[1].TxIn[0].PreviousOutPoint.Index = 0
|
||||||
})
|
})
|
||||||
rejected(blockchain.ErrMissingTx)
|
rejected(blockchain.ErrMissingTxOut)
|
||||||
|
|
||||||
// ---------------------------------------------------------------------
|
// ---------------------------------------------------------------------
|
||||||
// Block header median time tests.
|
// Block header median time tests.
|
||||||
|
@ -1688,7 +1688,7 @@ func Generate(includeLargeReorg bool) (tests [][]TestInstance, err error) {
|
||||||
g.nextBlock("b58", outs[17], func(b *wire.MsgBlock) {
|
g.nextBlock("b58", outs[17], func(b *wire.MsgBlock) {
|
||||||
b.Transactions[1].TxIn[0].PreviousOutPoint.Index = 42
|
b.Transactions[1].TxIn[0].PreviousOutPoint.Index = 42
|
||||||
})
|
})
|
||||||
rejected(blockchain.ErrMissingTx)
|
rejected(blockchain.ErrMissingTxOut)
|
||||||
|
|
||||||
// Create block with transaction that pays more than its inputs.
|
// Create block with transaction that pays more than its inputs.
|
||||||
//
|
//
|
||||||
|
@ -1816,7 +1816,7 @@ func Generate(includeLargeReorg bool) (tests [][]TestInstance, err error) {
|
||||||
b.AddTransaction(tx3)
|
b.AddTransaction(tx3)
|
||||||
b.AddTransaction(tx2)
|
b.AddTransaction(tx2)
|
||||||
})
|
})
|
||||||
rejected(blockchain.ErrMissingTx)
|
rejected(blockchain.ErrMissingTxOut)
|
||||||
|
|
||||||
// Create block that double spends a transaction created in the same
|
// Create block that double spends a transaction created in the same
|
||||||
// block.
|
// block.
|
||||||
|
@ -1831,7 +1831,7 @@ func Generate(includeLargeReorg bool) (tests [][]TestInstance, err error) {
|
||||||
b.AddTransaction(tx3)
|
b.AddTransaction(tx3)
|
||||||
b.AddTransaction(tx4)
|
b.AddTransaction(tx4)
|
||||||
})
|
})
|
||||||
rejected(blockchain.ErrDoubleSpend)
|
rejected(blockchain.ErrMissingTxOut)
|
||||||
|
|
||||||
// ---------------------------------------------------------------------
|
// ---------------------------------------------------------------------
|
||||||
// Extra subsidy tests.
|
// Extra subsidy tests.
|
||||||
|
@ -2022,7 +2022,7 @@ func Generate(includeLargeReorg bool) (tests [][]TestInstance, err error) {
|
||||||
// to effective negate that behavior.
|
// to effective negate that behavior.
|
||||||
b75OpReturnOut.amount++
|
b75OpReturnOut.amount++
|
||||||
g.nextBlock("b80", &b75OpReturnOut)
|
g.nextBlock("b80", &b75OpReturnOut)
|
||||||
rejected(blockchain.ErrMissingTx)
|
rejected(blockchain.ErrMissingTxOut)
|
||||||
|
|
||||||
// Create a block that has a transaction with multiple OP_RETURNs. Even
|
// Create a block that has a transaction with multiple OP_RETURNs. Even
|
||||||
// though it's not considered a standard transaction, it is still valid
|
// though it's not considered a standard transaction, it is still valid
|
||||||
|
|
|
@ -65,7 +65,7 @@ out:
|
||||||
"transaction %v referenced from "+
|
"transaction %v referenced from "+
|
||||||
"transaction %v", originTxHash,
|
"transaction %v", originTxHash,
|
||||||
txVI.tx.Hash())
|
txVI.tx.Hash())
|
||||||
err := ruleError(ErrMissingTx, str)
|
err := ruleError(ErrMissingTxOut, str)
|
||||||
v.sendResult(err)
|
v.sendResult(err)
|
||||||
break out
|
break out
|
||||||
}
|
}
|
||||||
|
|
|
@ -389,10 +389,11 @@ func CountP2SHSigOps(tx *btcutil.Tx, isCoinBaseTx bool, utxoView *UtxoViewpoint)
|
||||||
originTxIndex := txIn.PreviousOutPoint.Index
|
originTxIndex := txIn.PreviousOutPoint.Index
|
||||||
txEntry := utxoView.LookupEntry(originTxHash)
|
txEntry := utxoView.LookupEntry(originTxHash)
|
||||||
if txEntry == nil || txEntry.IsOutputSpent(originTxIndex) {
|
if txEntry == nil || txEntry.IsOutputSpent(originTxIndex) {
|
||||||
str := fmt.Sprintf("unable to find unspent output "+
|
str := fmt.Sprintf("output %v referenced from "+
|
||||||
"%v referenced from transaction %s:%d",
|
"transaction %s:%d either does not exist or "+
|
||||||
txIn.PreviousOutPoint, tx.Hash(), txInIndex)
|
"has already been spent", txIn.PreviousOutPoint,
|
||||||
return 0, ruleError(ErrMissingTx, str)
|
tx.Hash(), txInIndex)
|
||||||
|
return 0, ruleError(ErrMissingTxOut, str)
|
||||||
}
|
}
|
||||||
|
|
||||||
// We're only interested in pay-to-script-hash types, so skip
|
// We're only interested in pay-to-script-hash types, so skip
|
||||||
|
@ -897,12 +898,14 @@ func CheckTransactionInputs(tx *btcutil.Tx, txHeight int32, utxoView *UtxoViewpo
|
||||||
for txInIndex, txIn := range tx.MsgTx().TxIn {
|
for txInIndex, txIn := range tx.MsgTx().TxIn {
|
||||||
// Ensure the referenced input transaction is available.
|
// Ensure the referenced input transaction is available.
|
||||||
originTxHash := &txIn.PreviousOutPoint.Hash
|
originTxHash := &txIn.PreviousOutPoint.Hash
|
||||||
|
originTxIndex := txIn.PreviousOutPoint.Index
|
||||||
utxoEntry := utxoView.LookupEntry(originTxHash)
|
utxoEntry := utxoView.LookupEntry(originTxHash)
|
||||||
if utxoEntry == nil {
|
if utxoEntry == nil || utxoEntry.IsOutputSpent(originTxIndex) {
|
||||||
str := fmt.Sprintf("unable to find unspent output "+
|
str := fmt.Sprintf("output %v referenced from "+
|
||||||
"%v referenced from transaction %s:%d",
|
"transaction %s:%d either does not exist or "+
|
||||||
txIn.PreviousOutPoint, tx.Hash(), txInIndex)
|
"has already been spent", txIn.PreviousOutPoint,
|
||||||
return 0, ruleError(ErrMissingTx, str)
|
tx.Hash(), txInIndex)
|
||||||
|
return 0, ruleError(ErrMissingTxOut, str)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Ensure the transaction is not spending coins which have not
|
// Ensure the transaction is not spending coins which have not
|
||||||
|
@ -922,15 +925,6 @@ func CheckTransactionInputs(tx *btcutil.Tx, txHeight int32, utxoView *UtxoViewpo
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Ensure the transaction is not double spending coins.
|
|
||||||
originTxIndex := txIn.PreviousOutPoint.Index
|
|
||||||
if utxoEntry.IsOutputSpent(originTxIndex) {
|
|
||||||
str := fmt.Sprintf("transaction %s:%d tried to double "+
|
|
||||||
"spend output %v", txHash, txInIndex,
|
|
||||||
txIn.PreviousOutPoint)
|
|
||||||
return 0, ruleError(ErrDoubleSpend, str)
|
|
||||||
}
|
|
||||||
|
|
||||||
// Ensure the transaction amounts are in range. Each of the
|
// Ensure the transaction amounts are in range. Each of the
|
||||||
// output values of the input transactions must not be negative
|
// output values of the input transactions must not be negative
|
||||||
// or more than the max allowed per transaction. All amounts in
|
// or more than the max allowed per transaction. All amounts in
|
||||||
|
@ -1017,7 +1011,7 @@ func (b *BlockChain) checkConnectBlock(node *blockNode, block *btcutil.Block, vi
|
||||||
// an error now.
|
// an error now.
|
||||||
if node.hash.IsEqual(b.chainParams.GenesisHash) {
|
if node.hash.IsEqual(b.chainParams.GenesisHash) {
|
||||||
str := "the coinbase for the genesis block is not spendable"
|
str := "the coinbase for the genesis block is not spendable"
|
||||||
return ruleError(ErrMissingTx, str)
|
return ruleError(ErrMissingTxOut, str)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Ensure the view is for the node being checked.
|
// Ensure the view is for the node being checked.
|
||||||
|
|
|
@ -91,10 +91,12 @@ func GetSigOpCost(tx *btcutil.Tx, isCoinBaseTx bool, utxoView *UtxoViewpoint,
|
||||||
originTxIndex := txIn.PreviousOutPoint.Index
|
originTxIndex := txIn.PreviousOutPoint.Index
|
||||||
txEntry := utxoView.LookupEntry(originTxHash)
|
txEntry := utxoView.LookupEntry(originTxHash)
|
||||||
if txEntry == nil || txEntry.IsOutputSpent(originTxIndex) {
|
if txEntry == nil || txEntry.IsOutputSpent(originTxIndex) {
|
||||||
str := fmt.Sprintf("unable to find unspent output "+
|
str := fmt.Sprintf("output %v referenced from "+
|
||||||
"%v referenced from transaction %s:%d",
|
"transaction %s:%d either does not "+
|
||||||
txIn.PreviousOutPoint, tx.Hash(), txInIndex)
|
"exist or has already been spent",
|
||||||
return 0, ruleError(ErrMissingTx, str)
|
txIn.PreviousOutPoint, tx.Hash(),
|
||||||
|
txInIndex)
|
||||||
|
return 0, ruleError(ErrMissingTxOut, str)
|
||||||
}
|
}
|
||||||
|
|
||||||
witness := txIn.Witness
|
witness := txIn.Witness
|
||||||
|
|
|
@ -74,8 +74,6 @@ func extractRejectCode(err error) (wire.RejectCode, bool) {
|
||||||
switch err.ErrorCode {
|
switch err.ErrorCode {
|
||||||
// Rejected due to duplicate.
|
// Rejected due to duplicate.
|
||||||
case blockchain.ErrDuplicateBlock:
|
case blockchain.ErrDuplicateBlock:
|
||||||
fallthrough
|
|
||||||
case blockchain.ErrDoubleSpend:
|
|
||||||
code = wire.RejectDuplicate
|
code = wire.RejectDuplicate
|
||||||
|
|
||||||
// Rejected due to obsolete version.
|
// Rejected due to obsolete version.
|
||||||
|
|
|
@ -1995,7 +1995,7 @@ func chainErrToGBTErrString(err error) string {
|
||||||
return "bad-txns-dupinputs"
|
return "bad-txns-dupinputs"
|
||||||
case blockchain.ErrBadTxInput:
|
case blockchain.ErrBadTxInput:
|
||||||
return "bad-txns-badinput"
|
return "bad-txns-badinput"
|
||||||
case blockchain.ErrMissingTx:
|
case blockchain.ErrMissingTxOut:
|
||||||
return "bad-txns-missinginput"
|
return "bad-txns-missinginput"
|
||||||
case blockchain.ErrUnfinalizedTx:
|
case blockchain.ErrUnfinalizedTx:
|
||||||
return "bad-txns-unfinalizedtx"
|
return "bad-txns-unfinalizedtx"
|
||||||
|
@ -2005,8 +2005,6 @@ func chainErrToGBTErrString(err error) string {
|
||||||
return "bad-txns-overwrite"
|
return "bad-txns-overwrite"
|
||||||
case blockchain.ErrImmatureSpend:
|
case blockchain.ErrImmatureSpend:
|
||||||
return "bad-txns-maturity"
|
return "bad-txns-maturity"
|
||||||
case blockchain.ErrDoubleSpend:
|
|
||||||
return "bad-txns-dblspend"
|
|
||||||
case blockchain.ErrSpendTooHigh:
|
case blockchain.ErrSpendTooHigh:
|
||||||
return "bad-txns-highspend"
|
return "bad-txns-highspend"
|
||||||
case blockchain.ErrBadFees:
|
case blockchain.ErrBadFees:
|
||||||
|
|
Loading…
Reference in a new issue