Skip to content

Commit

Permalink
tidying up with some helper methods and returning a new ErrMissingOut…
Browse files Browse the repository at this point in the history
…put error if an expected output isn't present on a parent tx
  • Loading branch information
theflyingcodr committed Sep 30, 2021
1 parent c2af346 commit d8ae780
Show file tree
Hide file tree
Showing 3 changed files with 31 additions and 17 deletions.
17 changes: 17 additions & 0 deletions spv/envelope.go
Original file line number Diff line number Diff line change
@@ -1,6 +1,9 @@
package spv

import (
"github.com/libsv/go-bt/v2"
"github.com/pkg/errors"

"github.com/libsv/go-bc"
)

Expand All @@ -19,3 +22,17 @@ type Envelope struct {
func (e *Envelope) IsAnchored() bool {
return e.Proof != nil
}

// HasParents returns true if this envelope has immediate parents.
func (e *Envelope) HasParents() bool {
return e.Parents == nil || len(e.Parents) == 0
}

// ParentTX will return a parent if found and convert the rawTx to a bt.TX, otherwise a ErrNotAllInputsSupplied error is returned.
func (e *Envelope) ParentTX(txID string) (*bt.Tx, error) {
env, ok := e.Parents[txID]
if !ok {
return nil, errors.Wrapf(ErrNotAllInputsSupplied, "expected parent tx %s is missing", txID)
}
return bt.NewTxFromString(env.RawTx)
}
3 changes: 3 additions & 0 deletions spv/errors.go
Original file line number Diff line number Diff line change
Expand Up @@ -43,4 +43,7 @@ var (

// ErrInvalidProof is returned if the merkle proof validation fails.
ErrInvalidProof = errors.New("invalid merkle proof, payment invalid")

// ErrMissingOutput is returned when checking fees if an output in a parent tx is missing.
ErrMissingOutput = errors.New("expected output used in payment tx missing")
)
28 changes: 11 additions & 17 deletions spv/verifypayment.go
Original file line number Diff line number Diff line change
Expand Up @@ -61,20 +61,20 @@ func (v *verifier) VerifyPayment(ctx context.Context, initialPayment *Envelope,
//
// If there are no parents the method will fail, also, if there are no fees the method will fail.
func (v *verifier) verifyFees(initialPayment *Envelope, tx *bt.Tx, opts *verifyOptions) error {
if initialPayment.Parents == nil || len(initialPayment.Parents) == 0 {
if initialPayment.HasParents() {
return ErrCannotCalculateFeePaid
}
if opts.feeQuote == nil {
return ErrNoFeeQuoteSupplied
}
for _, input := range tx.Inputs {
pTx, err := bt.NewTxFromString(initialPayment.Parents[input.PreviousTxIDStr()].RawTx)
parent, err := initialPayment.ParentTX(input.PreviousTxIDStr())
if err != nil {
return err
return errors.Wrapf(err, "tx %s failed to get parent tx", tx.TxID())
}
out := pTx.OutputIdx(int(input.PreviousTxOutIndex))
out := parent.OutputIdx(int(input.PreviousTxOutIndex))
if out == nil {
continue
return ErrMissingOutput
}
input.PreviousTxSatoshis = out.Satoshis
}
Expand All @@ -90,7 +90,7 @@ func (v *verifier) verifyFees(initialPayment *Envelope, tx *bt.Tx, opts *verifyO

func (v *verifier) verifyTxs(ctx context.Context, payment *Envelope, opts *verifyOptions) error {
// If at the beginning or middle of the tx chain and tx is unconfirmed, fail and error.
if opts.proofs && !payment.IsAnchored() && (payment.Parents == nil || len(payment.Parents) == 0) {
if opts.proofs && !payment.IsAnchored() && payment.HasParents() {
return errors.Wrapf(ErrNoConfirmedTransaction, "tx %s has no confirmed/anchored tx", payment.TxID)
}

Expand All @@ -108,7 +108,7 @@ func (v *verifier) verifyTxs(ctx context.Context, payment *Envelope, opts *verif

// If a Merkle Proof is provided, assume we are at the anchor/beginning of the tx chain.
// Verify and return the result.
if payment.IsAnchored() || payment.Parents == nil || len(payment.Parents) == 0 {
if payment.IsAnchored() || payment.HasParents() {
if opts.proofs {
return v.verifyTxAnchor(ctx, payment)
}
Expand Down Expand Up @@ -160,23 +160,17 @@ func (v *verifier) verifyUnconfirmedTx(tx *bt.Tx, payment *Envelope) error {
}

for _, input := range tx.Inputs {
parent, ok := payment.Parents[input.PreviousTxIDStr()]
if !ok {
return errors.Wrapf(ErrNotAllInputsSupplied, "tx %s is missing input %s in its envelope", tx.TxID(), input.PreviousTxIDStr())
}

parentTx, err := bt.NewTxFromString(parent.RawTx)
parent, err := payment.ParentTX(input.PreviousTxIDStr())
if err != nil {
return err
return errors.Wrapf(err, "tx %s missing parent", tx.TxID())
}

// If the input is indexing an output that is out of bounds, fail and error
if int(input.PreviousTxOutIndex) > len(parentTx.Outputs)-1 {
if int(input.PreviousTxOutIndex) > len(parent.Outputs)-1 {
return errors.Wrapf(ErrInputRefsOutOfBoundsOutput,
"input %s is referring out of bounds output %d", input.PreviousTxIDStr(), input.PreviousTxOutIndex)
}

output := parentTx.Outputs[int(input.PreviousTxOutIndex)]
output := parent.OutputIdx(int(input.PreviousTxOutIndex))
// TODO: verify script using input and previous output
_ = output
}
Expand Down

0 comments on commit d8ae780

Please sign in to comment.