Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
25 changes: 24 additions & 1 deletion internal/webapi/payfee.go
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
// Copyright (c) 2021-2024 The Decred developers
// Copyright (c) 2021-2026 The Decred developers
// Use of this source code is governed by an ISC
// license that can be found in the LICENSE file.

Expand Down Expand Up @@ -143,6 +143,29 @@ func (w *WebAPI) payFee(c *gin.Context) {
return
}

// Confirm all inputs of the fee transaction exist.
for _, input := range feeTx.TxIn {
prevOut := input.PreviousOutPoint
txOut, err := dcrdClient.GetTxOut(prevOut.Hash, prevOut.Index, prevOut.Tree)
if err != nil {
w.log.Errorf("%s: dcrd.GetTxOut for fee tx input failed "+
"(ticketHash=%s, output=%s:%d:%d, clientIP=%s): %v",
funcName, ticket.Hash, prevOut.Hash, prevOut.Index, prevOut.Tree,
c.ClientIP(), err)
w.sendError(types.ErrInternalError, c)
return
}
if txOut == nil {
w.log.Warnf("%s: Fee tx contains non-existent input "+
"(ticketHash=%s, output=%s:%d:%d, clientIP=%s)",
funcName, ticket.Hash, prevOut.Hash, prevOut.Index, prevOut.Tree,
c.ClientIP())
w.sendErrorWithMsg("fee tx includes non-existent input",
types.ErrInvalidFeeTx, c)
return
}
}

// Decode fee address to get its payment script details.
feeAddr, err := stdaddr.DecodeAddress(ticket.FeeAddress, w.cfg.Network)
if err != nil {
Expand Down
16 changes: 15 additions & 1 deletion rpc/dcrd.go
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
// Copyright (c) 2021-2025 The Decred developers
// Copyright (c) 2021-2026 The Decred developers
// Use of this source code is governed by an ISC
// license that can be found in the LICENSE file.

Expand Down Expand Up @@ -306,6 +306,20 @@ func (c *DcrdRPC) GetBlockHash(height int64) (string, error) {
return resp, nil
}

// GetTxOut returns the transaction output info if it's unspent and nil
// otherwise.
func (c *DcrdRPC) GetTxOut(hash chainhash.Hash, index uint32,
tree int8) (*dcrdtypes.GetTxOutResult, error) {
var resp *dcrdtypes.GetTxOutResult
const includeMempool = true
err := c.Call(context.TODO(), "gettxout", &resp, hash.String(), index, tree,
includeMempool)
if err != nil {
return nil, err
}
return resp, nil
}

// GetCFilterV2 retrieves the GCS filter for the provided block header,
// optionally verifies the inclusion proof, then returns the filter along with
// its key.
Expand Down
Loading