-
Notifications
You must be signed in to change notification settings - Fork 3
/
Copy pathwalletkit_server.go
86 lines (73 loc) · 2.96 KB
/
walletkit_server.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
// Copyright (C) 2013-2017 The btcsuite developers
// Copyright (C) 2015-2016 The Decred developers
// Copyright (C) 2015-2022 Lightning Labs and The Lightning Network Developers
// Copyright (C) 2022 Bottlepay and The Lightning Network Developers
package lndsigner
import (
"bytes"
"context"
"fmt"
"github.com/btcsuite/btcd/btcutil/psbt"
"github.com/nydig-oss/lndsigner/proto"
)
// walletKit is a sub-RPC server that exposes a tool kit which allows clients
// to execute common wallet operations. This includes requesting new addresses,
// keys (for contracts!), and publishing transactions.
type walletKit struct {
// Required by the grpc-gateway/v2 library for forward compatibility.
proto.UnimplementedWalletKitServer
server *rpcServer
}
// A compile time check to ensure that walletKit fully implements the
// proto.WalletKitServer gRPC service.
var _ proto.WalletKitServer = (*walletKit)(nil)
// SignPsbt expects a partial transaction with all inputs and outputs fully
// declared and tries to sign all unsigned inputs that have all required fields
// (UTXO information, BIP32 derivation information, witness or sig scripts)
// set.
// If no error is returned, the PSBT is ready to be given to the next signer or
// to be finalized if lndsignerd was the last signer.
//
// NOTE: This RPC only signs inputs (and only those it can sign), it does not
// perform any other tasks (such as coin selection, UTXO locking or
// input/output/fee value validation, PSBT finalization). Any input that is
// incomplete will be skipped.
func (w *walletKit) SignPsbt(_ context.Context, req *proto.SignPsbtRequest) (
*proto.SignPsbtResponse, error) {
packet, err := psbt.NewFromRawBytes(
bytes.NewReader(req.FundedPsbt), false,
)
if err != nil {
signerLog.Debugf("Error parsing PSBT: %v, raw input: %x", err,
req.FundedPsbt)
return nil, fmt.Errorf("error parsing PSBT: %v", err)
}
// Before we attempt to sign the packet, ensure that every input either
// has a witness UTXO, or a non witness UTXO.
for idx := range packet.UnsignedTx.TxIn {
in := packet.Inputs[idx]
// Doesn't have either a witness or non witness UTXO so we need
// to exit here as otherwise signing will fail.
if in.WitnessUtxo == nil && in.NonWitnessUtxo == nil {
return nil, fmt.Errorf("input (index=%v) doesn't "+
"specify any UTXO info", idx)
}
}
// Let the wallet do the heavy lifting. This will sign all inputs that
// we have the UTXO for. If some inputs can't be signed and don't have
// witness data attached, they will just be skipped.
signedInputs, err := w.server.keyRing.SignPsbt(packet)
if err != nil {
return nil, fmt.Errorf("error signing PSBT: %v", err)
}
// Serialize the signed PSBT in both the packet and wire format.
var signedPsbtBytes bytes.Buffer
err = packet.Serialize(&signedPsbtBytes)
if err != nil {
return nil, fmt.Errorf("error serializing PSBT: %v", err)
}
return &proto.SignPsbtResponse{
SignedPsbt: signedPsbtBytes.Bytes(),
SignedInputs: signedInputs,
}, nil
}