mirror of
https://github.com/muun/recovery.git
synced 2025-11-10 22:10:14 -05:00
Release v0.3.0
This commit is contained in:
205
vendor/github.com/lightningnetwork/lnd/lnwallet/chanvalidate/validate.go
generated
vendored
Normal file
205
vendor/github.com/lightningnetwork/lnd/lnwallet/chanvalidate/validate.go
generated
vendored
Normal file
@@ -0,0 +1,205 @@
|
||||
package chanvalidate
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"fmt"
|
||||
|
||||
"github.com/btcsuite/btcd/txscript"
|
||||
"github.com/btcsuite/btcd/wire"
|
||||
"github.com/btcsuite/btcutil"
|
||||
"github.com/lightningnetwork/lnd/lnwire"
|
||||
)
|
||||
|
||||
var (
|
||||
// ErrInvalidOutPoint is returned when the ChanLocator is unable to
|
||||
// find the target outpoint.
|
||||
ErrInvalidOutPoint = fmt.Errorf("output meant to create channel cannot " +
|
||||
"be found")
|
||||
|
||||
// ErrWrongPkScript is returned when the alleged funding transaction is
|
||||
// found to have an incorrect pkSript.
|
||||
ErrWrongPkScript = fmt.Errorf("wrong pk script")
|
||||
|
||||
// ErrInvalidSize is returned when the alleged funding transaction
|
||||
// output has the wrong size (channel capacity).
|
||||
ErrInvalidSize = fmt.Errorf("channel has wrong size")
|
||||
)
|
||||
|
||||
// ErrScriptValidateError is returned when Script VM validation fails for an
|
||||
// alleged channel output.
|
||||
type ErrScriptValidateError struct {
|
||||
err error
|
||||
}
|
||||
|
||||
// Error returns a human readable string describing the error.
|
||||
func (e *ErrScriptValidateError) Error() string {
|
||||
return fmt.Sprintf("script validation failed: %v", e.err)
|
||||
}
|
||||
|
||||
// Unwrap returns the underlying wrapped VM execution failure error.
|
||||
func (e *ErrScriptValidateError) Unwrap() error {
|
||||
return e.err
|
||||
}
|
||||
|
||||
// ChanLocator abstracts away obtaining the output that created the channel, as
|
||||
// well as validating its existence given the funding transaction. We need
|
||||
// this as there are several ways (outpoint, short chan ID) to identify the
|
||||
// output of a channel given the funding transaction.
|
||||
type ChanLocator interface {
|
||||
// Locate attempts to locate the funding output within the funding
|
||||
// transaction. It also returns the final out point of the channel
|
||||
// which uniquely identifies the output which creates the channel. If
|
||||
// the target output cannot be found, or cannot exist on the funding
|
||||
// transaction, then an error is to be returned.
|
||||
Locate(*wire.MsgTx) (*wire.TxOut, *wire.OutPoint, error)
|
||||
}
|
||||
|
||||
// OutPointChanLocator is an implementation of the ChanLocator that can be used
|
||||
// when one already knows the expected chan point.
|
||||
type OutPointChanLocator struct {
|
||||
// ChanPoint is the expected chan point.
|
||||
ChanPoint wire.OutPoint
|
||||
}
|
||||
|
||||
// Locate attempts to locate the funding output within the passed funding
|
||||
// transaction.
|
||||
//
|
||||
// NOTE: Part of the ChanLocator interface.
|
||||
func (o *OutPointChanLocator) Locate(fundingTx *wire.MsgTx) (
|
||||
*wire.TxOut, *wire.OutPoint, error) {
|
||||
|
||||
// If the expected index is greater than the amount of output in the
|
||||
// transaction, then we'll reject this channel as it's invalid.
|
||||
if int(o.ChanPoint.Index) >= len(fundingTx.TxOut) {
|
||||
return nil, nil, ErrInvalidOutPoint
|
||||
}
|
||||
|
||||
// As an extra sanity check, we'll also ensure the txid hash matches.
|
||||
fundingHash := fundingTx.TxHash()
|
||||
if !bytes.Equal(fundingHash[:], o.ChanPoint.Hash[:]) {
|
||||
return nil, nil, ErrInvalidOutPoint
|
||||
}
|
||||
|
||||
return fundingTx.TxOut[o.ChanPoint.Index], &o.ChanPoint, nil
|
||||
}
|
||||
|
||||
// ShortChanIDChanLocator is an implementation of the ChanLocator that can be
|
||||
// used when one only knows the short channel ID of a channel. This should be
|
||||
// used in contexts when one is verifying a 3rd party channel.
|
||||
type ShortChanIDChanLocator struct {
|
||||
// ID is the short channel ID of the target channel.
|
||||
ID lnwire.ShortChannelID
|
||||
}
|
||||
|
||||
// Locate attempts to locate the funding output within the passed funding
|
||||
// transaction.
|
||||
//
|
||||
// NOTE: Part of the ChanLocator interface.
|
||||
func (s *ShortChanIDChanLocator) Locate(fundingTx *wire.MsgTx) (
|
||||
*wire.TxOut, *wire.OutPoint, error) {
|
||||
|
||||
// If the expected index is greater than the amount of output in the
|
||||
// transaction, then we'll reject this channel as it's invalid.
|
||||
outputIndex := s.ID.TxPosition
|
||||
if int(outputIndex) >= len(fundingTx.TxOut) {
|
||||
return nil, nil, ErrInvalidOutPoint
|
||||
}
|
||||
|
||||
chanPoint := wire.OutPoint{
|
||||
Hash: fundingTx.TxHash(),
|
||||
Index: uint32(outputIndex),
|
||||
}
|
||||
|
||||
return fundingTx.TxOut[outputIndex], &chanPoint, nil
|
||||
}
|
||||
|
||||
// CommitmentContext is optional validation context that can be passed into the
|
||||
// main Validate for self-owned channel. The information in this context allows
|
||||
// us to fully verify out initial commitment spend based on the on-chain state
|
||||
// of the funding output.
|
||||
type CommitmentContext struct {
|
||||
// Value is the known size of the channel.
|
||||
Value btcutil.Amount
|
||||
|
||||
// FullySignedCommitTx is the fully signed commitment transaction. This
|
||||
// should include a valid witness.
|
||||
FullySignedCommitTx *wire.MsgTx
|
||||
}
|
||||
|
||||
// Context is the main validation contxet. For a given channel, all fields but
|
||||
// the optional CommitCtx should be populated based on existing
|
||||
// known-to-be-valid parameters.
|
||||
type Context struct {
|
||||
// Locator is a concrete implementation of the ChanLocator interface.
|
||||
Locator ChanLocator
|
||||
|
||||
// MultiSigPkScript is the fully serialized witness script of the
|
||||
// multi-sig output. This is the final witness program that should be
|
||||
// found in the funding output.
|
||||
MultiSigPkScript []byte
|
||||
|
||||
// FundingTx is channel funding transaction as found confirmed in the
|
||||
// chain.
|
||||
FundingTx *wire.MsgTx
|
||||
|
||||
// CommitCtx is an optional additional set of validation context
|
||||
// required to validate a self-owned channel. If present, then a full
|
||||
// Script VM validation will be performed.
|
||||
CommitCtx *CommitmentContext
|
||||
}
|
||||
|
||||
// Validate given the specified context, this function validates that the
|
||||
// alleged channel is well formed, and spendable (if the optional CommitCtx is
|
||||
// specified). If this method returns an error, then the alleged channel is
|
||||
// invalid and should be abandoned immediately.
|
||||
func Validate(ctx *Context) (*wire.OutPoint, error) {
|
||||
// First, we'll attempt to locate the target outpoint in the funding
|
||||
// transaction. If this returns an error, then we know that the
|
||||
// outpoint doesn't actually exist, so we'll exit early.
|
||||
fundingOutput, chanPoint, err := ctx.Locator.Locate(
|
||||
ctx.FundingTx,
|
||||
)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
// The scripts should match up exactly, otherwise the channel is
|
||||
// invalid.
|
||||
fundingScript := fundingOutput.PkScript
|
||||
if !bytes.Equal(ctx.MultiSigPkScript, fundingScript) {
|
||||
return nil, ErrWrongPkScript
|
||||
}
|
||||
|
||||
// If there's no commitment context, then we're done here as this is a
|
||||
// 3rd party channel.
|
||||
if ctx.CommitCtx == nil {
|
||||
return chanPoint, nil
|
||||
}
|
||||
|
||||
// Now that we know this is our channel, we'll verify the amount of the
|
||||
// created output against our expected size of the channel.
|
||||
fundingValue := fundingOutput.Value
|
||||
if btcutil.Amount(fundingValue) != ctx.CommitCtx.Value {
|
||||
return nil, ErrInvalidSize
|
||||
}
|
||||
|
||||
// If we reach this point, then all other checks have succeeded, so
|
||||
// we'll now attempt a full Script VM execution to ensure that we're
|
||||
// able to close the channel using this initial state.
|
||||
vm, err := txscript.NewEngine(
|
||||
ctx.MultiSigPkScript, ctx.CommitCtx.FullySignedCommitTx,
|
||||
0, txscript.StandardVerifyFlags, nil, nil, fundingValue,
|
||||
)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
// Finally, we'll attempt to verify our full spend, if this fails then
|
||||
// the channel is definitely invalid.
|
||||
err = vm.Execute()
|
||||
if err != nil {
|
||||
return nil, &ErrScriptValidateError{err: err}
|
||||
}
|
||||
|
||||
return chanPoint, nil
|
||||
}
|
||||
Reference in New Issue
Block a user