github.com/decred/dcrlnd@v0.7.6/lnwallet/chanfunding/psbt_assembler_test.go (about)

     1  package chanfunding
     2  
     3  import (
     4  	"bytes"
     5  	"crypto/sha256"
     6  	"fmt"
     7  	"reflect"
     8  	"sync"
     9  	"testing"
    10  	"time"
    11  
    12  	"github.com/davecgh/go-spew/spew"
    13  	"github.com/decred/dcrd/chaincfg/chainhash"
    14  	"github.com/decred/dcrd/chaincfg/v3"
    15  	"github.com/decred/dcrd/dcrec/secp256k1/v4"
    16  	"github.com/decred/dcrd/dcrutil/v4"
    17  	"github.com/decred/dcrd/txscript/v4/stdaddr"
    18  	"github.com/decred/dcrd/wire"
    19  	"github.com/decred/dcrlnd/input"
    20  	"github.com/decred/dcrlnd/internal/psbt"
    21  	"github.com/decred/dcrlnd/keychain"
    22  	"github.com/stretchr/testify/require"
    23  )
    24  
    25  var (
    26  	localPrivkey                  = []byte{1, 2, 3, 4, 5, 6} //nolint:unused
    27  	remotePrivkey                 = []byte{6, 5, 4, 3, 2, 1} //nolint:unused
    28  	chanCapacity   dcrutil.Amount = 644000
    29  	params                        = *chaincfg.SimNetParams() //nolint:unused
    30  	defaultTimeout                = 50 * time.Millisecond
    31  )
    32  
    33  func privKeyFromBytes(b []byte) (*secp256k1.PrivateKey, *secp256k1.PublicKey) { //nolint:unused
    34  	key := secp256k1.PrivKeyFromBytes(b)
    35  	return key, key.PubKey()
    36  }
    37  
    38  // TestPsbtIntent tests the basic happy path of the PSBT assembler and intent.
    39  func TestPsbtIntent(t *testing.T) {
    40  	t.Skipf("psbt not implemented")
    41  
    42  	t.Parallel()
    43  
    44  	// Create a simple assembler and ask it to provision a channel to get
    45  	// the funding intent.
    46  	a := NewPsbtAssembler(chanCapacity, nil, &params, true)
    47  	intent, err := a.ProvisionChannel(&Request{LocalAmt: chanCapacity})
    48  	if err != nil {
    49  		t.Fatalf("error provisioning channel: %v", err)
    50  	}
    51  	psbtIntent, ok := intent.(*PsbtIntent)
    52  	if !ok {
    53  		t.Fatalf("intent was not a PsbtIntent")
    54  	}
    55  	if psbtIntent.State != PsbtShimRegistered {
    56  		t.Fatalf("unexpected state. got %d wanted %d", psbtIntent.State,
    57  			PsbtShimRegistered)
    58  	}
    59  
    60  	// The first step with the intent is that the funding manager starts
    61  	// negotiating with the remote peer and they accept. By accepting, they
    62  	// send over their multisig key that's going to be used for the funding
    63  	// output. With that known, we can start crafting a PSBT.
    64  	_, localPubkey := privKeyFromBytes(localPrivkey)
    65  	_, remotePubkey := privKeyFromBytes(remotePrivkey)
    66  	psbtIntent.BindKeys(
    67  		&keychain.KeyDescriptor{PubKey: localPubkey}, remotePubkey,
    68  	)
    69  	if psbtIntent.State != PsbtOutputKnown {
    70  		t.Fatalf("unexpected state. got %d wanted %d", psbtIntent.State,
    71  			PsbtOutputKnown)
    72  	}
    73  
    74  	// Make sure the output script address is correct.
    75  	script, _, err := input.GenFundingPkScript(
    76  		localPubkey.SerializeCompressed(),
    77  		remotePubkey.SerializeCompressed(), int64(chanCapacity),
    78  	)
    79  	if err != nil {
    80  		t.Fatalf("error calculating script: %v", err)
    81  	}
    82  	witnessScriptHash := sha256.Sum256(script)
    83  	addr, err := stdaddr.NewAddressScriptHashV0(
    84  		witnessScriptHash[:], &params,
    85  	)
    86  	if err != nil {
    87  		t.Fatalf("unable to encode address: %v", err)
    88  	}
    89  	fundingAddr, amt, pendingPsbt, err := psbtIntent.FundingParams()
    90  	if err != nil {
    91  		t.Fatalf("unable to get funding params: %v", err)
    92  	}
    93  	if addr.String() != fundingAddr.String() {
    94  		t.Fatalf("unexpected address. got %s wanted %s", fundingAddr,
    95  			addr)
    96  	}
    97  	if amt != int64(chanCapacity) {
    98  		t.Fatalf("unexpected amount. got %d wanted %d", amt,
    99  			chanCapacity)
   100  	}
   101  
   102  	// Parse and check the returned PSBT packet.
   103  	if pendingPsbt == nil {
   104  		t.Fatalf("expected pending PSBT to be returned")
   105  	}
   106  	if len(pendingPsbt.UnsignedTx.TxOut) != 1 {
   107  		t.Fatalf("unexpected number of outputs. got %d wanted %d",
   108  			len(pendingPsbt.UnsignedTx.TxOut), 1)
   109  	}
   110  	txOut := pendingPsbt.UnsignedTx.TxOut[0]
   111  	if !bytes.Equal(txOut.PkScript[2:], witnessScriptHash[:]) {
   112  		t.Fatalf("unexpected PK script in output. got %x wanted %x",
   113  			txOut.PkScript[2:], witnessScriptHash)
   114  	}
   115  	if txOut.Value != int64(chanCapacity) {
   116  		t.Fatalf("unexpected value in output. got %d wanted %d",
   117  			txOut.Value, chanCapacity)
   118  	}
   119  
   120  	// Add an input to the pending TX to simulate it being funded.
   121  	pendingPsbt.UnsignedTx.TxIn = []*wire.TxIn{
   122  		{PreviousOutPoint: wire.OutPoint{Index: 0}},
   123  	}
   124  	pendingPsbt.Inputs = []psbt.PInput{
   125  		{WitnessUtxo: &wire.TxOut{Value: int64(chanCapacity + 1)}},
   126  	}
   127  
   128  	// Verify the dummy PSBT with the intent.
   129  	err = psbtIntent.Verify(pendingPsbt, false)
   130  	if err != nil {
   131  		t.Fatalf("error verifying pending PSBT: %v", err)
   132  	}
   133  	if psbtIntent.State != PsbtVerified {
   134  		t.Fatalf("unexpected state. got %d wanted %d", psbtIntent.State,
   135  			PsbtVerified)
   136  	}
   137  
   138  	// Add some fake witness data to the transaction so it thinks it's
   139  	// signed.
   140  	pendingPsbt.Inputs[0].WitnessUtxo = &wire.TxOut{
   141  		Value:    int64(chanCapacity) * 2,
   142  		PkScript: []byte{99, 99, 99},
   143  	}
   144  	pendingPsbt.Inputs[0].FinalScriptSig = []byte{88, 88, 88}
   145  	pendingPsbt.Inputs[0].FinalScriptWitness = []byte{2, 0, 0}
   146  
   147  	// If we call Finalize, the intent will signal to the funding manager
   148  	// that it can continue with the funding flow. We want to make sure
   149  	// the signal arrives.
   150  	var wg sync.WaitGroup
   151  	errChan := make(chan error, 1)
   152  	wg.Add(1)
   153  	go func() {
   154  		defer wg.Done()
   155  		select {
   156  		case err := <-psbtIntent.PsbtReady:
   157  			errChan <- err
   158  
   159  		case <-time.After(defaultTimeout):
   160  			errChan <- fmt.Errorf("timed out")
   161  		}
   162  	}()
   163  	err = psbtIntent.Finalize(pendingPsbt)
   164  	if err != nil {
   165  		t.Fatalf("error finalizing pending PSBT: %v", err)
   166  	}
   167  	wg.Wait()
   168  
   169  	// We should have a nil error in our channel now.
   170  	err = <-errChan
   171  	if err != nil {
   172  		t.Fatalf("unexpected error after finalize: %v", err)
   173  	}
   174  	if psbtIntent.State != PsbtFinalized {
   175  		t.Fatalf("unexpected state. got %d wanted %d", psbtIntent.State,
   176  			PsbtFinalized)
   177  	}
   178  
   179  	// Make sure the funding transaction can be compiled.
   180  	_, err = psbtIntent.CompileFundingTx()
   181  	if err != nil {
   182  		t.Fatalf("error compiling funding TX from PSBT: %v", err)
   183  	}
   184  	if psbtIntent.State != PsbtFundingTxCompiled {
   185  		t.Fatalf("unexpected state. got %d wanted %d", psbtIntent.State,
   186  			PsbtFundingTxCompiled)
   187  	}
   188  }
   189  
   190  // TestPsbtIntentBasePsbt tests that a channel funding output can be appended to
   191  // a given base PSBT in the funding flow.
   192  func TestPsbtIntentBasePsbt(t *testing.T) {
   193  	t.Skipf("psbt not implemented")
   194  	t.Parallel()
   195  
   196  	// First create a dummy PSBT with a single output.
   197  	pendingPsbt, err := psbt.New(
   198  		[]*wire.OutPoint{{}}, []*wire.TxOut{
   199  			{Value: 999, PkScript: []byte{99, 88, 77}},
   200  		}, 2, 0, []uint32{0},
   201  	)
   202  	if err != nil {
   203  		t.Fatalf("unable to create dummy PSBT")
   204  	}
   205  
   206  	// Generate the funding multisig keys and the address so we can compare
   207  	// it to the output of the intent.
   208  	_, localPubkey := privKeyFromBytes(localPrivkey)
   209  	_, remotePubkey := privKeyFromBytes(remotePrivkey)
   210  	// Make sure the output script address is correct.
   211  	script, _, err := input.GenFundingPkScript(
   212  		localPubkey.SerializeCompressed(),
   213  		remotePubkey.SerializeCompressed(), int64(chanCapacity),
   214  	)
   215  	if err != nil {
   216  		t.Fatalf("error calculating script: %v", err)
   217  	}
   218  	witnessScriptHash := sha256.Sum256(script)
   219  	addr, err := stdaddr.NewAddressScriptHashV0(
   220  		witnessScriptHash[:], &params,
   221  	)
   222  	if err != nil {
   223  		t.Fatalf("unable to encode address: %v", err)
   224  	}
   225  
   226  	// Now as the next step, create a new assembler/intent pair with a base
   227  	// PSBT to see that we can add an additional output to it.
   228  	a := NewPsbtAssembler(chanCapacity, pendingPsbt, &params, true)
   229  	intent, err := a.ProvisionChannel(&Request{LocalAmt: chanCapacity})
   230  	if err != nil {
   231  		t.Fatalf("error provisioning channel: %v", err)
   232  	}
   233  	psbtIntent, ok := intent.(*PsbtIntent)
   234  	if !ok {
   235  		t.Fatalf("intent was not a PsbtIntent")
   236  	}
   237  	psbtIntent.BindKeys(
   238  		&keychain.KeyDescriptor{PubKey: localPubkey}, remotePubkey,
   239  	)
   240  	newAddr, amt, twoOutPsbt, err := psbtIntent.FundingParams()
   241  	if err != nil {
   242  		t.Fatalf("unable to get funding params: %v", err)
   243  	}
   244  	if addr.String() != newAddr.String() {
   245  		t.Fatalf("unexpected address. got %s wanted %s", newAddr,
   246  			addr)
   247  	}
   248  	if amt != int64(chanCapacity) {
   249  		t.Fatalf("unexpected amount. got %d wanted %d", amt,
   250  			chanCapacity)
   251  	}
   252  	if len(twoOutPsbt.UnsignedTx.TxOut) != 2 {
   253  		t.Fatalf("unexpected number of outputs. got %d wanted %d",
   254  			len(twoOutPsbt.UnsignedTx.TxOut), 2)
   255  	}
   256  	if len(twoOutPsbt.UnsignedTx.TxIn) != 1 {
   257  		t.Fatalf("unexpected number of inputs. got %d wanted %d",
   258  			len(twoOutPsbt.UnsignedTx.TxIn), 1)
   259  	}
   260  	txOld := pendingPsbt.UnsignedTx
   261  	txNew := twoOutPsbt.UnsignedTx
   262  	prevoutEqual := reflect.DeepEqual(
   263  		txOld.TxIn[0].PreviousOutPoint, txNew.TxIn[0].PreviousOutPoint,
   264  	)
   265  	if !prevoutEqual {
   266  		t.Fatalf("inputs changed. got %s wanted %s",
   267  			spew.Sdump(txOld.TxIn[0].PreviousOutPoint),
   268  			spew.Sdump(txNew.TxIn[0].PreviousOutPoint))
   269  	}
   270  	if !reflect.DeepEqual(txOld.TxOut[0], txNew.TxOut[0]) {
   271  		t.Fatalf("existing output changed. got %v wanted %v",
   272  			txOld.TxOut[0], txNew.TxOut[0])
   273  	}
   274  }
   275  
   276  // TestPsbtVerify tests the PSBT verification process more deeply than just
   277  // the happy path.
   278  func TestPsbtVerify(t *testing.T) {
   279  	t.Skipf("psbt not implemented")
   280  	t.Parallel()
   281  
   282  	testCases := []struct {
   283  		name          string
   284  		expectedErr   string
   285  		shouldPublish bool
   286  		doVerify      func(int64, *psbt.Packet, *PsbtIntent) error
   287  	}{
   288  		{
   289  			name:          "nil packet",
   290  			expectedErr:   "PSBT is nil",
   291  			shouldPublish: true,
   292  			doVerify: func(amt int64, p *psbt.Packet,
   293  				i *PsbtIntent) error {
   294  
   295  				return i.Verify(nil, false)
   296  			},
   297  		},
   298  		{
   299  			name:          "wrong state",
   300  			shouldPublish: true,
   301  			expectedErr: "invalid state. got user_canceled " +
   302  				"expected output_known",
   303  			doVerify: func(amt int64, p *psbt.Packet,
   304  				i *PsbtIntent) error {
   305  
   306  				i.State = PsbtInitiatorCanceled
   307  				return i.Verify(p, false)
   308  			},
   309  		},
   310  		{
   311  			name:          "output not found, value wrong",
   312  			shouldPublish: true,
   313  			expectedErr:   "funding output not found in PSBT",
   314  			doVerify: func(amt int64, p *psbt.Packet,
   315  				i *PsbtIntent) error {
   316  
   317  				p.UnsignedTx.TxOut[0].Value = 123
   318  				return i.Verify(p, false)
   319  			},
   320  		},
   321  		{
   322  			name:          "output not found, pk script wrong",
   323  			shouldPublish: true,
   324  			expectedErr:   "funding output not found in PSBT",
   325  			doVerify: func(amt int64, p *psbt.Packet,
   326  				i *PsbtIntent) error {
   327  
   328  				p.UnsignedTx.TxOut[0].PkScript = []byte{1, 2, 3}
   329  				return i.Verify(p, false)
   330  			},
   331  		},
   332  		{
   333  			name:          "no inputs",
   334  			shouldPublish: true,
   335  			expectedErr:   "PSBT has no inputs",
   336  			doVerify: func(amt int64, p *psbt.Packet,
   337  				i *PsbtIntent) error {
   338  
   339  				return i.Verify(p, false)
   340  			},
   341  		},
   342  		{
   343  			name:          "input(s) too small",
   344  			shouldPublish: true,
   345  			expectedErr: "input amount sum must be larger than " +
   346  				"output amount sum",
   347  			doVerify: func(amt int64, p *psbt.Packet,
   348  				i *PsbtIntent) error {
   349  
   350  				p.UnsignedTx.TxIn = []*wire.TxIn{{}}
   351  				p.Inputs = []psbt.PInput{{
   352  					WitnessUtxo: &wire.TxOut{
   353  						Value: int64(chanCapacity),
   354  					},
   355  				}}
   356  				return i.Verify(p, false)
   357  			},
   358  		},
   359  		{
   360  			name:          "missing witness-utxo field",
   361  			shouldPublish: true,
   362  			expectedErr: "cannot use TX for channel funding, not " +
   363  				"all inputs are SegWit spends, risk of " +
   364  				"malleability: input 1 is non-SegWit spend " +
   365  				"or missing redeem script",
   366  			doVerify: func(amt int64, p *psbt.Packet,
   367  				i *PsbtIntent) error {
   368  
   369  				txOut := &wire.TxOut{
   370  					Value: int64(chanCapacity/2) + 1,
   371  				}
   372  				p.UnsignedTx.TxIn = []*wire.TxIn{
   373  					{},
   374  					{
   375  						PreviousOutPoint: wire.OutPoint{
   376  							Index: 0,
   377  						},
   378  					},
   379  				}
   380  				p.Inputs = []psbt.PInput{
   381  					{
   382  						WitnessUtxo: txOut,
   383  					},
   384  					{
   385  						NonWitnessUtxo: &wire.MsgTx{
   386  							TxOut: []*wire.TxOut{
   387  								txOut,
   388  							},
   389  						},
   390  					},
   391  				}
   392  				return i.Verify(p, false)
   393  			},
   394  		},
   395  		{
   396  			name:          "skip verify",
   397  			shouldPublish: false,
   398  			expectedErr:   "",
   399  			doVerify: func(amt int64, p *psbt.Packet,
   400  				i *PsbtIntent) error {
   401  
   402  				txOut := &wire.TxOut{
   403  					Value: int64(chanCapacity/2) + 1,
   404  				}
   405  				p.UnsignedTx.TxIn = []*wire.TxIn{
   406  					{},
   407  					{
   408  						PreviousOutPoint: wire.OutPoint{
   409  							Index: 0,
   410  						},
   411  					},
   412  				}
   413  				p.Inputs = []psbt.PInput{
   414  					{
   415  						WitnessUtxo: txOut,
   416  					},
   417  					{
   418  						WitnessUtxo: txOut,
   419  					},
   420  				}
   421  
   422  				if err := i.Verify(p, true); err != nil {
   423  					return err
   424  				}
   425  
   426  				if i.FinalTX != p.UnsignedTx {
   427  					return fmt.Errorf("expected final TX " +
   428  						"to be set")
   429  				}
   430  				if i.State != PsbtFinalized {
   431  					return fmt.Errorf("expected state to " +
   432  						"be finalized")
   433  				}
   434  
   435  				select {
   436  				case <-i.PsbtReady:
   437  
   438  				case <-time.After(50 * time.Millisecond):
   439  					return fmt.Errorf("expected PSBT " +
   440  						"ready to be signaled")
   441  				}
   442  
   443  				return nil
   444  			},
   445  		},
   446  		{
   447  			name:          "input correct",
   448  			shouldPublish: true,
   449  			expectedErr:   "",
   450  			doVerify: func(amt int64, p *psbt.Packet,
   451  				i *PsbtIntent) error {
   452  
   453  				txOut := &wire.TxOut{
   454  					Value: int64(chanCapacity/2) + 1,
   455  				}
   456  				p.UnsignedTx.TxIn = []*wire.TxIn{
   457  					{},
   458  					{
   459  						PreviousOutPoint: wire.OutPoint{
   460  							Index: 0,
   461  						},
   462  					},
   463  				}
   464  				p.Inputs = []psbt.PInput{
   465  					{
   466  						WitnessUtxo: txOut,
   467  					},
   468  					{
   469  						WitnessUtxo: txOut,
   470  					}}
   471  				return i.Verify(p, false)
   472  			},
   473  		},
   474  	}
   475  
   476  	// Create a simple assembler and ask it to provision a channel to get
   477  	// the funding intent.
   478  	a := NewPsbtAssembler(chanCapacity, nil, &params, true)
   479  	intent, err := a.ProvisionChannel(&Request{LocalAmt: chanCapacity})
   480  	if err != nil {
   481  		t.Fatalf("error provisioning channel: %v", err)
   482  	}
   483  	psbtIntent := intent.(*PsbtIntent)
   484  
   485  	// Bind our test keys to get the funding parameters.
   486  	_, localPubkey := privKeyFromBytes(localPrivkey)
   487  	_, remotePubkey := privKeyFromBytes(remotePrivkey)
   488  	psbtIntent.BindKeys(
   489  		&keychain.KeyDescriptor{PubKey: localPubkey}, remotePubkey,
   490  	)
   491  
   492  	// Loop through all our test cases.
   493  	for _, tc := range testCases {
   494  		tc := tc
   495  		t.Run(tc.name, func(t *testing.T) {
   496  			// Reset the state from a previous test and create a new
   497  			// pending PSBT that we can manipulate.
   498  			psbtIntent.shouldPublish = tc.shouldPublish
   499  			psbtIntent.State = PsbtOutputKnown
   500  			_, amt, pendingPsbt, err := psbtIntent.FundingParams()
   501  			if err != nil {
   502  				t.Fatalf("unable to get funding params: %v", err)
   503  			}
   504  
   505  			err = tc.doVerify(amt, pendingPsbt, psbtIntent)
   506  			if err != nil && tc.expectedErr == "" {
   507  				t.Fatalf("unexpected error, got '%v' wanted "+
   508  					"'%v'", err, tc.expectedErr)
   509  			}
   510  			if err != nil && err.Error() != tc.expectedErr {
   511  				t.Fatalf("unexpected error, got '%v' wanted "+
   512  					"'%v'", err, tc.expectedErr)
   513  			}
   514  		})
   515  	}
   516  }
   517  
   518  // TestPsbtFinalize tests the PSBT finalization process more deeply than just
   519  // the happy path.
   520  func TestPsbtFinalize(t *testing.T) {
   521  	t.Skipf("psbt not implemented")
   522  	t.Parallel()
   523  
   524  	testCases := []struct {
   525  		name        string
   526  		expectedErr string
   527  		doFinalize  func(int64, *psbt.Packet, *PsbtIntent) error
   528  	}{
   529  		{
   530  			name:        "nil packet",
   531  			expectedErr: "PSBT is nil",
   532  			doFinalize: func(amt int64, p *psbt.Packet,
   533  				i *PsbtIntent) error {
   534  
   535  				return i.Finalize(nil)
   536  			},
   537  		},
   538  		{
   539  			name: "wrong state",
   540  			expectedErr: "invalid state. got user_canceled " +
   541  				"expected verified",
   542  			doFinalize: func(amt int64, p *psbt.Packet,
   543  				i *PsbtIntent) error {
   544  
   545  				i.State = PsbtInitiatorCanceled
   546  				return i.Finalize(p)
   547  			},
   548  		},
   549  		{
   550  			name:        "not verified first",
   551  			expectedErr: "PSBT was not verified first",
   552  			doFinalize: func(amt int64, p *psbt.Packet,
   553  				i *PsbtIntent) error {
   554  
   555  				i.State = PsbtVerified
   556  				i.PendingPsbt = nil
   557  				return i.Finalize(p)
   558  			},
   559  		},
   560  		{
   561  			name: "output value changed",
   562  			expectedErr: "outputs differ from verified PSBT: " +
   563  				"output 0 is different",
   564  			doFinalize: func(amt int64, p *psbt.Packet,
   565  				i *PsbtIntent) error {
   566  
   567  				p.UnsignedTx.TxOut[0].Value = 123
   568  				return i.Finalize(p)
   569  			},
   570  		},
   571  		{
   572  			name: "output pk script changed",
   573  			expectedErr: "outputs differ from verified PSBT: " +
   574  				"output 0 is different",
   575  			doFinalize: func(amt int64, p *psbt.Packet,
   576  				i *PsbtIntent) error {
   577  
   578  				p.UnsignedTx.TxOut[0].PkScript = []byte{3, 2, 1}
   579  				return i.Finalize(p)
   580  			},
   581  		},
   582  		{
   583  			name: "input previous outpoint index changed",
   584  			expectedErr: "inputs differ from verified PSBT: " +
   585  				"previous outpoint of input 0 is different",
   586  			doFinalize: func(amt int64, p *psbt.Packet,
   587  				i *PsbtIntent) error {
   588  
   589  				p.UnsignedTx.TxIn[0].PreviousOutPoint.Index = 0
   590  				return i.Finalize(p)
   591  			},
   592  		},
   593  		{
   594  			name: "input previous outpoint hash changed",
   595  			expectedErr: "inputs differ from verified PSBT: " +
   596  				"previous outpoint of input 0 is different",
   597  			doFinalize: func(amt int64, p *psbt.Packet,
   598  				i *PsbtIntent) error {
   599  
   600  				prevout := &p.UnsignedTx.TxIn[0].PreviousOutPoint
   601  				prevout.Hash = chainhash.Hash{77, 88, 99, 11}
   602  				return i.Finalize(p)
   603  			},
   604  		},
   605  		{
   606  			name:        "raw tx - nil transaction",
   607  			expectedErr: "raw transaction is nil",
   608  			doFinalize: func(amt int64, p *psbt.Packet,
   609  				i *PsbtIntent) error {
   610  
   611  				return i.FinalizeRawTX(nil)
   612  			},
   613  		},
   614  		{
   615  			name: "raw tx - no witness data in raw tx",
   616  			expectedErr: "inputs not signed: input 0 has no " +
   617  				"signature data attached",
   618  			doFinalize: func(amt int64, p *psbt.Packet,
   619  				i *PsbtIntent) error {
   620  
   621  				rawTx, err := psbt.Extract(p)
   622  				require.NoError(t, err)
   623  				rawTx.TxIn[0].SignatureScript = nil
   624  
   625  				return i.FinalizeRawTX(rawTx)
   626  			},
   627  		},
   628  		{
   629  			name:        "happy path",
   630  			expectedErr: "",
   631  			doFinalize: func(amt int64, p *psbt.Packet,
   632  				i *PsbtIntent) error {
   633  
   634  				err := i.Finalize(p)
   635  				require.NoError(t, err)
   636  
   637  				require.Equal(t, PsbtFinalized, i.State)
   638  				require.NotNil(t, i.FinalTX)
   639  
   640  				return nil
   641  			},
   642  		},
   643  	}
   644  
   645  	// Create a simple assembler and ask it to provision a channel to get
   646  	// the funding intent.
   647  	a := NewPsbtAssembler(chanCapacity, nil, &params, true)
   648  	intent, err := a.ProvisionChannel(&Request{LocalAmt: chanCapacity})
   649  	if err != nil {
   650  		t.Fatalf("error provisioning channel: %v", err)
   651  	}
   652  	psbtIntent := intent.(*PsbtIntent)
   653  
   654  	// Bind our test keys to get the funding parameters.
   655  	_, localPubkey := privKeyFromBytes(localPrivkey)
   656  	_, remotePubkey := privKeyFromBytes(remotePrivkey)
   657  	psbtIntent.BindKeys(
   658  		&keychain.KeyDescriptor{PubKey: localPubkey}, remotePubkey,
   659  	)
   660  
   661  	// Loop through all our test cases.
   662  	for _, tc := range testCases {
   663  		tc := tc
   664  		t.Run(tc.name, func(t *testing.T) {
   665  			// Reset the state from a previous test and create a new
   666  			// pending PSBT that we can manipulate.
   667  			psbtIntent.State = PsbtOutputKnown
   668  			_, amt, pendingPsbt, err := psbtIntent.FundingParams()
   669  			if err != nil {
   670  				t.Fatalf("unable to get funding params: %v", err)
   671  			}
   672  
   673  			// We need to have a simulated transaction here that is
   674  			// fully funded and signed.
   675  			pendingPsbt.UnsignedTx.TxIn = []*wire.TxIn{{
   676  				PreviousOutPoint: wire.OutPoint{
   677  					Index: 1,
   678  					Hash:  chainhash.Hash{1, 2, 3},
   679  				},
   680  			}}
   681  			pendingPsbt.Inputs = []psbt.PInput{{
   682  				WitnessUtxo: &wire.TxOut{
   683  					Value:    int64(chanCapacity) + 1,
   684  					PkScript: []byte{1, 2, 3},
   685  				},
   686  				FinalScriptWitness: []byte{0x01, 0x00},
   687  			}}
   688  			err = psbtIntent.Verify(pendingPsbt, false)
   689  			if err != nil {
   690  				t.Fatalf("error verifying PSBT: %v", err)
   691  			}
   692  
   693  			// Deep clone the PSBT so we don't modify the pending
   694  			// one that was registered during Verify.
   695  			pendingPsbt = clonePsbt(t, pendingPsbt)
   696  
   697  			err = tc.doFinalize(amt, pendingPsbt, psbtIntent)
   698  			if (err == nil && tc.expectedErr != "") ||
   699  				(err != nil && err.Error() != tc.expectedErr) {
   700  
   701  				t.Fatalf("unexpected error, got '%v' wanted "+
   702  					"'%v'", err, tc.expectedErr)
   703  			}
   704  		})
   705  	}
   706  }
   707  
   708  // clonePsbt creates a clone of a PSBT packet by serializing then de-serializing
   709  // it.
   710  func clonePsbt(t *testing.T, p *psbt.Packet) *psbt.Packet {
   711  	var buf bytes.Buffer
   712  	err := p.Serialize(&buf)
   713  	if err != nil {
   714  		t.Fatalf("error serializing PSBT: %v", err)
   715  	}
   716  	newPacket, err := psbt.NewFromRawBytes(&buf, false)
   717  	if err != nil {
   718  		t.Fatalf("error unserializing PSBT: %v", err)
   719  	}
   720  	return newPacket
   721  }