mirror of
https://github.com/lightningnetwork/lnd.git
synced 2025-02-22 22:25:24 +01:00
Merge pull request #4653 from LN-Zap/feat/spend-unconfirmed
Ability to spend unconfirmed coins when making onchain transactions
This commit is contained in:
commit
1a73bc7d74
15 changed files with 1030 additions and 764 deletions
|
@ -21,8 +21,7 @@ import (
|
|||
)
|
||||
|
||||
const (
|
||||
defaultUtxoMinConf = 1
|
||||
userMsgFund = `PSBT funding initiated with peer %x.
|
||||
userMsgFund = `PSBT funding initiated with peer %x.
|
||||
Please create a PSBT that sends %v (%d satoshi) to the funding address %s.
|
||||
|
||||
Note: The whole process should be completed within 10 minutes, otherwise there
|
||||
|
@ -43,7 +42,7 @@ Paste the funded PSBT here to continue the funding flow.
|
|||
Base64 encoded PSBT: `
|
||||
|
||||
userMsgSign = `
|
||||
PSBT verified by lnd, please continue the funding flow by signing the PSBT by
|
||||
PSBT verified by lnd, please continue the funding flow by signing the PSBT by
|
||||
all required parties/devices. Once the transaction is fully signed, paste it
|
||||
again here either in base64 PSBT or hex encoded raw wire TX format.
|
||||
|
||||
|
@ -68,7 +67,7 @@ var openChannelCommand = cli.Command{
|
|||
amount to the remote node as part of the channel opening. Once the channel is open,
|
||||
a channelPoint (txid:vout) of the funding output is returned.
|
||||
|
||||
If the remote peer supports the option upfront shutdown feature bit (query
|
||||
If the remote peer supports the option upfront shutdown feature bit (query
|
||||
listpeers to see their supported feature bits), an address to enforce
|
||||
payout of funds on cooperative close can optionally be provided. Note that
|
||||
if you set this value, you will not be able to cooperatively close out to
|
||||
|
|
|
@ -35,6 +35,10 @@ import (
|
|||
|
||||
const defaultRecoveryWindow int32 = 2500
|
||||
|
||||
const (
|
||||
defaultUtxoMinConf = 1
|
||||
)
|
||||
|
||||
func printJSON(resp interface{}) {
|
||||
b, err := json.Marshal(resp)
|
||||
if err != nil {
|
||||
|
@ -238,6 +242,13 @@ var sendCoinsCommand = cli.Command{
|
|||
"sat/byte that should be used when crafting " +
|
||||
"the transaction",
|
||||
},
|
||||
cli.Uint64Flag{
|
||||
Name: "min_confs",
|
||||
Usage: "(optional) the minimum number of confirmations " +
|
||||
"each one of your outputs used for the transaction " +
|
||||
"must satisfy",
|
||||
Value: defaultUtxoMinConf,
|
||||
},
|
||||
txLabelFlag,
|
||||
},
|
||||
Action: actionDecorator(sendCoins),
|
||||
|
@ -292,13 +303,16 @@ func sendCoins(ctx *cli.Context) error {
|
|||
client, cleanUp := getClient(ctx)
|
||||
defer cleanUp()
|
||||
|
||||
minConfs := int32(ctx.Uint64("min_confs"))
|
||||
req := &lnrpc.SendCoinsRequest{
|
||||
Addr: addr,
|
||||
Amount: amt,
|
||||
TargetConf: int32(ctx.Int64("conf_target")),
|
||||
SatPerByte: ctx.Int64("sat_per_byte"),
|
||||
SendAll: ctx.Bool("sweepall"),
|
||||
Label: ctx.String(txLabelFlag.Name),
|
||||
Addr: addr,
|
||||
Amount: amt,
|
||||
TargetConf: int32(ctx.Int64("conf_target")),
|
||||
SatPerByte: ctx.Int64("sat_per_byte"),
|
||||
SendAll: ctx.Bool("sweepall"),
|
||||
Label: ctx.String(txLabelFlag.Name),
|
||||
MinConfs: minConfs,
|
||||
SpendUnconfirmed: minConfs == 0,
|
||||
}
|
||||
txid, err := client.SendCoins(ctxb, req)
|
||||
if err != nil {
|
||||
|
@ -454,6 +468,13 @@ var sendManyCommand = cli.Command{
|
|||
Usage: "(optional) a manual fee expressed in sat/byte that should be " +
|
||||
"used when crafting the transaction",
|
||||
},
|
||||
cli.Uint64Flag{
|
||||
Name: "min_confs",
|
||||
Usage: "(optional) the minimum number of confirmations " +
|
||||
"each one of your outputs used for the transaction " +
|
||||
"must satisfy",
|
||||
Value: defaultUtxoMinConf,
|
||||
},
|
||||
txLabelFlag,
|
||||
},
|
||||
Action: actionDecorator(sendMany),
|
||||
|
@ -476,11 +497,14 @@ func sendMany(ctx *cli.Context) error {
|
|||
client, cleanUp := getClient(ctx)
|
||||
defer cleanUp()
|
||||
|
||||
minConfs := int32(ctx.Uint64("min_confs"))
|
||||
txid, err := client.SendMany(ctxb, &lnrpc.SendManyRequest{
|
||||
AddrToAmount: amountToAddr,
|
||||
TargetConf: int32(ctx.Int64("conf_target")),
|
||||
SatPerByte: ctx.Int64("sat_per_byte"),
|
||||
Label: ctx.String(txLabelFlag.Name),
|
||||
AddrToAmount: amountToAddr,
|
||||
TargetConf: int32(ctx.Int64("conf_target")),
|
||||
SatPerByte: ctx.Int64("sat_per_byte"),
|
||||
Label: ctx.String(txLabelFlag.Name),
|
||||
MinConfs: minConfs,
|
||||
SpendUnconfirmed: minConfs == 0,
|
||||
})
|
||||
if err != nil {
|
||||
return err
|
||||
|
@ -1814,7 +1838,7 @@ var listChainTxnsCommand = cli.Command{
|
|||
To get all transactions until the chain tip, including unconfirmed
|
||||
transactions (identifiable with BlockHeight=0), set end_height to -1.
|
||||
By default, this call will get all transactions our wallet was involved
|
||||
in, including unconfirmed transactions.
|
||||
in, including unconfirmed transactions.
|
||||
`,
|
||||
Action: actionDecorator(listChainTxns),
|
||||
}
|
||||
|
|
1215
lnrpc/rpc.pb.go
1215
lnrpc/rpc.pb.go
File diff suppressed because it is too large
Load diff
|
@ -863,6 +863,13 @@ message SendManyRequest {
|
|||
|
||||
// An optional label for the transaction, limited to 500 characters.
|
||||
string label = 6;
|
||||
|
||||
// The minimum number of confirmations each one of your outputs used for
|
||||
// the transaction must satisfy.
|
||||
int32 min_confs = 7;
|
||||
|
||||
// Whether unconfirmed outputs should be used as inputs for the transaction.
|
||||
bool spend_unconfirmed = 8;
|
||||
}
|
||||
message SendManyResponse {
|
||||
// The id of the transaction
|
||||
|
@ -893,6 +900,13 @@ message SendCoinsRequest {
|
|||
|
||||
// An optional label for the transaction, limited to 500 characters.
|
||||
string label = 7;
|
||||
|
||||
// The minimum number of confirmations each one of your outputs used for
|
||||
// the transaction must satisfy.
|
||||
int32 min_confs = 8;
|
||||
|
||||
// Whether unconfirmed outputs should be used as inputs for the transaction.
|
||||
bool spend_unconfirmed = 9;
|
||||
}
|
||||
message SendCoinsResponse {
|
||||
// The transaction ID of the transaction
|
||||
|
|
|
@ -5243,6 +5243,16 @@
|
|||
"label": {
|
||||
"type": "string",
|
||||
"description": "An optional label for the transaction, limited to 500 characters."
|
||||
},
|
||||
"min_confs": {
|
||||
"type": "integer",
|
||||
"format": "int32",
|
||||
"description": "The minimum number of confirmations each one of your outputs used for\nthe transaction must satisfy."
|
||||
},
|
||||
"spend_unconfirmed": {
|
||||
"type": "boolean",
|
||||
"format": "boolean",
|
||||
"description": "Whether unconfirmed outputs should be used as inputs for the transaction."
|
||||
}
|
||||
}
|
||||
},
|
||||
|
@ -5279,6 +5289,16 @@
|
|||
"label": {
|
||||
"type": "string",
|
||||
"description": "An optional label for the transaction, limited to 500 characters."
|
||||
},
|
||||
"min_confs": {
|
||||
"type": "integer",
|
||||
"format": "int32",
|
||||
"description": "The minimum number of confirmations each one of your outputs used for\nthe transaction must satisfy."
|
||||
},
|
||||
"spend_unconfirmed": {
|
||||
"type": "boolean",
|
||||
"format": "boolean",
|
||||
"description": "Whether unconfirmed outputs should be used as inputs for the transaction."
|
||||
}
|
||||
}
|
||||
},
|
||||
|
|
|
@ -2,6 +2,7 @@ package lnrpc
|
|||
|
||||
import (
|
||||
"encoding/hex"
|
||||
"errors"
|
||||
"sort"
|
||||
|
||||
"github.com/lightningnetwork/lnd/lnwallet"
|
||||
|
@ -52,3 +53,38 @@ func RPCTransactionDetails(txns []*lnwallet.TransactionDetail) *TransactionDetai
|
|||
|
||||
return txDetails
|
||||
}
|
||||
|
||||
// ExtractMinConfs extracts the minimum number of confirmations that each
|
||||
// output used to fund a transaction should satisfy.
|
||||
func ExtractMinConfs(minConfs int32, spendUnconfirmed bool) (int32, error) {
|
||||
switch {
|
||||
// Ensure that the MinConfs parameter is non-negative.
|
||||
case minConfs < 0:
|
||||
return 0, errors.New("minimum number of confirmations must " +
|
||||
"be a non-negative number")
|
||||
|
||||
// The transaction should not be funded with unconfirmed outputs
|
||||
// unless explicitly specified by SpendUnconfirmed. We do this to
|
||||
// provide sane defaults to the OpenChannel RPC, as otherwise, if the
|
||||
// MinConfs field isn't explicitly set by the caller, we'll use
|
||||
// unconfirmed outputs without the caller being aware.
|
||||
case minConfs == 0 && !spendUnconfirmed:
|
||||
return 1, nil
|
||||
|
||||
// In the event that the caller set MinConfs > 0 and SpendUnconfirmed to
|
||||
// true, we'll return an error to indicate the conflict.
|
||||
case minConfs > 0 && spendUnconfirmed:
|
||||
return 0, errors.New("SpendUnconfirmed set to true with " +
|
||||
"MinConfs > 0")
|
||||
|
||||
// The funding transaction of the new channel to be created can be
|
||||
// funded with unconfirmed outputs.
|
||||
case spendUnconfirmed:
|
||||
return 0, nil
|
||||
|
||||
// If none of the above cases matched, we'll return the value set
|
||||
// explicitly by the caller.
|
||||
default:
|
||||
return minConfs, nil
|
||||
}
|
||||
}
|
||||
|
|
|
@ -626,7 +626,12 @@ type SendOutputsRequest struct {
|
|||
//A slice of the outputs that should be created in the transaction produced.
|
||||
Outputs []*signrpc.TxOut `protobuf:"bytes,2,rep,name=outputs,proto3" json:"outputs,omitempty"`
|
||||
// An optional label for the transaction, limited to 500 characters.
|
||||
Label string `protobuf:"bytes,3,opt,name=label,proto3" json:"label,omitempty"`
|
||||
Label string `protobuf:"bytes,3,opt,name=label,proto3" json:"label,omitempty"`
|
||||
// The minimum number of confirmations each one of your outputs used for
|
||||
// the transaction must satisfy.
|
||||
MinConfs int32 `protobuf:"varint,4,opt,name=min_confs,json=minConfs,proto3" json:"min_confs,omitempty"`
|
||||
// Whether unconfirmed outputs should be used as inputs for the transaction.
|
||||
SpendUnconfirmed bool `protobuf:"varint,5,opt,name=spend_unconfirmed,json=spendUnconfirmed,proto3" json:"spend_unconfirmed,omitempty"`
|
||||
XXX_NoUnkeyedLiteral struct{} `json:"-"`
|
||||
XXX_unrecognized []byte `json:"-"`
|
||||
XXX_sizecache int32 `json:"-"`
|
||||
|
@ -678,6 +683,20 @@ func (m *SendOutputsRequest) GetLabel() string {
|
|||
return ""
|
||||
}
|
||||
|
||||
func (m *SendOutputsRequest) GetMinConfs() int32 {
|
||||
if m != nil {
|
||||
return m.MinConfs
|
||||
}
|
||||
return 0
|
||||
}
|
||||
|
||||
func (m *SendOutputsRequest) GetSpendUnconfirmed() bool {
|
||||
if m != nil {
|
||||
return m.SpendUnconfirmed
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
type SendOutputsResponse struct {
|
||||
//
|
||||
//The serialized transaction sent out on the network.
|
||||
|
@ -1381,97 +1400,99 @@ func init() {
|
|||
func init() { proto.RegisterFile("walletrpc/walletkit.proto", fileDescriptor_6cc6942ac78249e5) }
|
||||
|
||||
var fileDescriptor_6cc6942ac78249e5 = []byte{
|
||||
// 1428 bytes of a gzipped FileDescriptorProto
|
||||
0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0xac, 0x57, 0xff, 0x6f, 0xda, 0xc8,
|
||||
0x12, 0x6f, 0xbe, 0x40, 0x60, 0x0c, 0x84, 0x2c, 0x24, 0xa1, 0x34, 0x6d, 0x52, 0x57, 0xef, 0xbd,
|
||||
0xe8, 0xbd, 0x96, 0xe8, 0xa5, 0xea, 0xa9, 0xed, 0x49, 0xa7, 0x4b, 0xc0, 0x11, 0x11, 0x04, 0x52,
|
||||
0x43, 0x1a, 0xf5, 0xee, 0x07, 0xcb, 0xe0, 0x2d, 0xb1, 0x02, 0xb6, 0xbb, 0x5e, 0x8a, 0xf9, 0xed,
|
||||
0xfe, 0x8a, 0x93, 0xfa, 0x6f, 0xdd, 0x5f, 0x74, 0xda, 0x5d, 0x63, 0xd6, 0x40, 0x7a, 0x3a, 0xe9,
|
||||
0x7e, 0x8a, 0x77, 0x3e, 0x33, 0x9f, 0x99, 0x9d, 0x99, 0xcc, 0x0e, 0xf0, 0x78, 0x62, 0x0e, 0x87,
|
||||
0x98, 0x12, 0xaf, 0x7f, 0x22, 0xbe, 0xee, 0x6d, 0x5a, 0xf1, 0x88, 0x4b, 0x5d, 0x94, 0x8e, 0xa0,
|
||||
0x72, 0x9a, 0x78, 0x7d, 0x21, 0x2d, 0x17, 0x7d, 0x7b, 0xe0, 0x30, 0x75, 0xf6, 0x17, 0x13, 0x21,
|
||||
0x55, 0x5b, 0x80, 0x9a, 0xb6, 0x4f, 0x6f, 0x1c, 0xdf, 0xc3, 0x0e, 0xd5, 0xf1, 0x97, 0x31, 0xf6,
|
||||
0x29, 0x7a, 0x02, 0xe9, 0x91, 0xed, 0x18, 0x7d, 0xd7, 0xf9, 0xec, 0x97, 0xd6, 0x8e, 0xd6, 0x8e,
|
||||
0x13, 0x7a, 0x6a, 0x64, 0x3b, 0x55, 0x76, 0xe6, 0xa0, 0x19, 0x84, 0xe0, 0x7a, 0x08, 0x9a, 0x01,
|
||||
0x07, 0xd5, 0xb7, 0x50, 0x88, 0xf1, 0xf9, 0x9e, 0xeb, 0xf8, 0x18, 0x3d, 0x87, 0xc4, 0x98, 0x06,
|
||||
0x2e, 0x23, 0xdb, 0x38, 0x56, 0x4e, 0x95, 0xca, 0x90, 0x85, 0x52, 0xb9, 0xa1, 0x81, 0xab, 0x0b,
|
||||
0x44, 0xfd, 0x00, 0xa8, 0x89, 0x4d, 0x1f, 0xb7, 0xc7, 0xd4, 0x1b, 0x47, 0x91, 0xe4, 0x60, 0xdd,
|
||||
0xb6, 0x78, 0x08, 0x19, 0x7d, 0xdd, 0xb6, 0xd0, 0xff, 0x20, 0xe5, 0x8e, 0xa9, 0xe7, 0xda, 0x0e,
|
||||
0xe5, 0xbe, 0x95, 0xd3, 0xed, 0x90, 0xab, 0x3d, 0xa6, 0xd7, 0x4c, 0xac, 0x47, 0x0a, 0xea, 0x1b,
|
||||
0x28, 0xc4, 0x28, 0xc3, 0x60, 0x9e, 0x01, 0xe0, 0xc0, 0xb3, 0x89, 0x49, 0x6d, 0xd7, 0xe1, 0xdc,
|
||||
0x9b, 0xba, 0x24, 0x51, 0x3b, 0x50, 0xd4, 0xf1, 0xf0, 0x1f, 0x8e, 0x65, 0x1f, 0x76, 0x17, 0x48,
|
||||
0x45, 0x34, 0xea, 0x07, 0x48, 0x36, 0xf0, 0x54, 0xc7, 0x5f, 0xd0, 0x31, 0xe4, 0xef, 0xf1, 0xd4,
|
||||
0xf8, 0x6c, 0x3b, 0x03, 0x4c, 0x0c, 0x8f, 0x30, 0x5e, 0x91, 0xfc, 0xdc, 0x3d, 0x9e, 0x5e, 0x70,
|
||||
0xf1, 0x35, 0x93, 0xa2, 0xa7, 0x00, 0x5c, 0xd3, 0x1c, 0xd9, 0xc3, 0x69, 0x58, 0x83, 0x34, 0xd3,
|
||||
0xe1, 0x02, 0x35, 0x0b, 0xca, 0x99, 0x65, 0x91, 0x30, 0x6e, 0x55, 0x85, 0x8c, 0x38, 0x86, 0xf7,
|
||||
0x47, 0xb0, 0x69, 0x5a, 0x16, 0xe1, 0xdc, 0x69, 0x9d, 0x7f, 0xab, 0xef, 0x41, 0xe9, 0x12, 0xd3,
|
||||
0xf1, 0xcd, 0x3e, 0x4b, 0x01, 0xda, 0x85, 0x24, 0x0d, 0x8c, 0x3b, 0x1c, 0x84, 0xd7, 0x4d, 0xd0,
|
||||
0xa0, 0x8e, 0x03, 0x54, 0x84, 0xc4, 0xd0, 0xec, 0xe1, 0x21, 0x77, 0x99, 0xd6, 0xc5, 0x41, 0xfd,
|
||||
0x01, 0xb6, 0xaf, 0xc7, 0xbd, 0xa1, 0xed, 0xdf, 0x45, 0x2e, 0x5e, 0x40, 0xd6, 0x13, 0x22, 0x03,
|
||||
0x13, 0xe2, 0xce, 0x7c, 0x65, 0x42, 0xa1, 0xc6, 0x64, 0x2a, 0x01, 0xd4, 0xc1, 0x8e, 0x25, 0xf2,
|
||||
0xe1, 0xcf, 0xb2, 0x7c, 0x00, 0xe0, 0x9b, 0xd4, 0xf0, 0x30, 0x31, 0xee, 0x27, 0xdc, 0x6e, 0x43,
|
||||
0x4f, 0xf9, 0x26, 0xbd, 0xc6, 0xa4, 0x31, 0x41, 0xc7, 0xb0, 0xe5, 0x0a, 0xfd, 0xd2, 0x3a, 0x6f,
|
||||
0xa5, 0x5c, 0x25, 0xec, 0xeb, 0x4a, 0x37, 0x68, 0x8f, 0xa9, 0x3e, 0x83, 0xe7, 0xb1, 0x6e, 0xc8,
|
||||
0xb1, 0xbe, 0x84, 0x42, 0xcc, 0x67, 0x18, 0xef, 0x2e, 0x24, 0x89, 0x39, 0x31, 0x68, 0x74, 0x5f,
|
||||
0x62, 0x4e, 0xba, 0x81, 0xfa, 0x06, 0x90, 0xe6, 0x53, 0x7b, 0x64, 0x52, 0x7c, 0x81, 0xf1, 0x2c,
|
||||
0xc2, 0x43, 0x50, 0x58, 0xf3, 0x1b, 0xd4, 0x24, 0x03, 0x3c, 0x2b, 0x11, 0x30, 0x51, 0x97, 0x4b,
|
||||
0xd4, 0xd7, 0x50, 0x88, 0x99, 0x85, 0x4e, 0xbe, 0x7b, 0x33, 0xf5, 0xdb, 0x06, 0x64, 0xae, 0xb1,
|
||||
0x63, 0xd9, 0xce, 0xa0, 0x33, 0xc1, 0xd8, 0x8b, 0xb5, 0xd7, 0xda, 0x5f, 0xb4, 0x17, 0x7a, 0x07,
|
||||
0x99, 0x89, 0x4d, 0x1d, 0xec, 0xfb, 0x06, 0x9d, 0x7a, 0x98, 0x17, 0x28, 0x77, 0xba, 0x57, 0x89,
|
||||
0x46, 0x41, 0xe5, 0x56, 0xc0, 0xdd, 0xa9, 0x87, 0x75, 0x65, 0x32, 0x3f, 0xb0, 0x66, 0x32, 0x47,
|
||||
0xee, 0xd8, 0xa1, 0x86, 0x6f, 0x52, 0x9e, 0xad, 0xac, 0x9e, 0x16, 0x92, 0x8e, 0x49, 0xd1, 0x11,
|
||||
0x64, 0x66, 0x51, 0xf7, 0xa6, 0x14, 0x97, 0x36, 0xb9, 0x02, 0x88, 0xb8, 0xcf, 0xa7, 0x14, 0xa3,
|
||||
0x57, 0x80, 0x7a, 0xc4, 0x35, 0xad, 0xbe, 0xe9, 0x53, 0xc3, 0xa4, 0x14, 0x8f, 0x3c, 0xea, 0x97,
|
||||
0x12, 0x5c, 0x6f, 0x27, 0x42, 0xce, 0x42, 0x00, 0x9d, 0xc2, 0xae, 0x83, 0x03, 0x6a, 0xcc, 0x6d,
|
||||
0xee, 0xb0, 0x3d, 0xb8, 0xa3, 0xa5, 0x24, 0xb7, 0x28, 0x30, 0xf0, 0x7c, 0x86, 0xd5, 0x39, 0xc4,
|
||||
0x6c, 0x88, 0xc8, 0x3e, 0xb6, 0x0c, 0x39, 0xf9, 0x29, 0x61, 0x13, 0x81, 0xd5, 0xa8, 0x0a, 0xe8,
|
||||
0x35, 0xec, 0xcd, 0x6d, 0x62, 0x57, 0x48, 0x2f, 0x18, 0x75, 0xe6, 0x77, 0x29, 0x42, 0xe2, 0xb3,
|
||||
0x4b, 0xfa, 0xb8, 0xb4, 0x75, 0xb4, 0x76, 0x9c, 0xd2, 0xc5, 0x41, 0xdd, 0x83, 0xa2, 0x5c, 0x9a,
|
||||
0x59, 0xaf, 0xaa, 0xb7, 0xb0, 0xbb, 0x20, 0x0f, 0x4b, 0xfd, 0x13, 0xe4, 0x3c, 0x01, 0x18, 0x3e,
|
||||
0x47, 0xc2, 0xc1, 0xb7, 0x2f, 0x15, 0x44, 0xb6, 0xd4, 0xb3, 0x9e, 0xcc, 0xa3, 0xfe, 0xbe, 0x06,
|
||||
0xb9, 0xf3, 0xf1, 0xc8, 0x93, 0xba, 0xee, 0x6f, 0xb5, 0xc3, 0x21, 0x28, 0x22, 0x41, 0x3c, 0x59,
|
||||
0xbc, 0x1b, 0xb2, 0x3a, 0x08, 0x11, 0x4b, 0xd1, 0x52, 0x55, 0x37, 0x96, 0xaa, 0x1a, 0x65, 0x62,
|
||||
0x53, 0xce, 0xc4, 0x0e, 0x6c, 0x47, 0x71, 0x85, 0x03, 0xec, 0x15, 0xec, 0xb0, 0x91, 0x1f, 0xcb,
|
||||
0x0c, 0x2a, 0xc1, 0xd6, 0x57, 0x4c, 0x7a, 0xae, 0x8f, 0x79, 0xb0, 0x29, 0x7d, 0x76, 0x54, 0x7f,
|
||||
0x5b, 0x17, 0x4f, 0xce, 0x42, 0xc6, 0x9a, 0x50, 0xa0, 0xf3, 0x01, 0x64, 0x58, 0x98, 0x9a, 0xf6,
|
||||
0xd0, 0x0f, 0x6f, 0xfa, 0x38, 0xbc, 0xa9, 0x34, 0xa2, 0x6a, 0x42, 0xa1, 0xfe, 0x48, 0x47, 0x74,
|
||||
0x49, 0x8a, 0x6e, 0x61, 0x5b, 0x66, 0xb3, 0x2d, 0x3f, 0x9c, 0xd0, 0x2f, 0xa5, 0x02, 0x2c, 0x47,
|
||||
0x21, 0x3b, 0xb8, 0xac, 0x31, 0xf2, 0x9c, 0x44, 0x73, 0x69, 0xf9, 0xe5, 0x77, 0x90, 0x8b, 0xeb,
|
||||
0xa0, 0xff, 0x2c, 0xbb, 0x62, 0xb5, 0x4e, 0x2f, 0x9a, 0x9e, 0xa7, 0x20, 0x29, 0x7a, 0x41, 0x35,
|
||||
0x61, 0xbf, 0xc9, 0xa6, 0x91, 0xc4, 0x34, 0xcb, 0x1b, 0x82, 0x4d, 0x1a, 0x44, 0xaf, 0x0c, 0xff,
|
||||
0x5e, 0x3d, 0x75, 0xd1, 0x01, 0xa4, 0xdd, 0xaf, 0x98, 0x4c, 0x88, 0x1d, 0x96, 0x2f, 0xa5, 0xcf,
|
||||
0x05, 0x6a, 0x19, 0x4a, 0xcb, 0x2e, 0xc4, 0x25, 0xff, 0xfb, 0x6d, 0x03, 0x14, 0x69, 0x1a, 0xa0,
|
||||
0x02, 0x6c, 0xdf, 0xb4, 0x1a, 0xad, 0xf6, 0x6d, 0xcb, 0xb8, 0xbd, 0xec, 0xb6, 0xb4, 0x4e, 0x27,
|
||||
0xff, 0x08, 0x95, 0xa0, 0x58, 0x6d, 0x5f, 0x5d, 0x5d, 0x76, 0xaf, 0xb4, 0x56, 0xd7, 0xe8, 0x5e,
|
||||
0x5e, 0x69, 0x46, 0xb3, 0x5d, 0x6d, 0xe4, 0xd7, 0xd0, 0x3e, 0x14, 0x24, 0xa4, 0xd5, 0x36, 0x6a,
|
||||
0x5a, 0xf3, 0xec, 0x53, 0x7e, 0x1d, 0xed, 0xc2, 0x8e, 0x04, 0xe8, 0xda, 0xc7, 0x76, 0x43, 0xcb,
|
||||
0x6f, 0x30, 0xfd, 0x7a, 0xb7, 0x59, 0x35, 0xda, 0x17, 0x17, 0x9a, 0xae, 0xd5, 0x66, 0xc0, 0x26,
|
||||
0x73, 0xc1, 0x81, 0xb3, 0x6a, 0x55, 0xbb, 0xee, 0xce, 0x91, 0x04, 0xfa, 0x17, 0x3c, 0x8f, 0x99,
|
||||
0x30, 0xf7, 0xed, 0x9b, 0xae, 0xd1, 0xd1, 0xaa, 0xed, 0x56, 0xcd, 0x68, 0x6a, 0x1f, 0xb5, 0x66,
|
||||
0x3e, 0x89, 0xfe, 0x0d, 0x6a, 0x9c, 0xa0, 0x73, 0x53, 0xad, 0x6a, 0x9d, 0x4e, 0x5c, 0x6f, 0x0b,
|
||||
0x1d, 0xc2, 0x93, 0x85, 0x08, 0xae, 0xda, 0x5d, 0x6d, 0xc6, 0x9a, 0x4f, 0xa1, 0x23, 0x38, 0x58,
|
||||
0x8c, 0x84, 0x6b, 0x84, 0x7c, 0xf9, 0x34, 0x3a, 0x80, 0x12, 0xd7, 0x90, 0x99, 0x67, 0xf1, 0x02,
|
||||
0x2a, 0x42, 0x3e, 0xcc, 0x9c, 0xd1, 0xd0, 0x3e, 0x19, 0xf5, 0xb3, 0x4e, 0x3d, 0xaf, 0xa0, 0x27,
|
||||
0xb0, 0xdf, 0xd2, 0x3a, 0x8c, 0x6e, 0x09, 0xcc, 0x2c, 0x24, 0xeb, 0xac, 0x55, 0xad, 0xb7, 0xf5,
|
||||
0x7c, 0xf6, 0xf4, 0x8f, 0x2d, 0x48, 0xdf, 0xf2, 0x0e, 0x6d, 0xd8, 0x14, 0x35, 0x41, 0x91, 0xb6,
|
||||
0x29, 0xf4, 0x74, 0xa1, 0x79, 0xe3, 0x5b, 0x5b, 0xf9, 0xd9, 0x43, 0x70, 0xf4, 0x2f, 0xa6, 0x48,
|
||||
0xeb, 0x50, 0x9c, 0x6d, 0x69, 0xdb, 0x89, 0xb3, 0xad, 0xd8, 0xa2, 0x74, 0xc8, 0xc6, 0x16, 0x1a,
|
||||
0x74, 0x28, 0x19, 0xac, 0xda, 0x9f, 0xca, 0x47, 0x0f, 0x2b, 0x84, 0x9c, 0xef, 0x21, 0x5b, 0xc3,
|
||||
0xc4, 0xfe, 0x8a, 0x5b, 0x38, 0xa0, 0x0d, 0x3c, 0x45, 0x3b, 0x92, 0x89, 0xd8, 0x92, 0xca, 0x7b,
|
||||
0xd1, 0x83, 0xdf, 0xc0, 0xd3, 0x1a, 0xf6, 0xfb, 0xc4, 0xf6, 0xa8, 0x4b, 0xd0, 0x5b, 0x48, 0x0b,
|
||||
0x5b, 0x66, 0x57, 0x90, 0x95, 0x9a, 0x6e, 0xdf, 0xa4, 0x2e, 0x79, 0xd0, 0xf2, 0x47, 0x48, 0x31,
|
||||
0x7f, 0x6c, 0x47, 0x42, 0xf2, 0x8b, 0x29, 0xed, 0x50, 0xe5, 0xfd, 0x25, 0x79, 0x18, 0x72, 0x1d,
|
||||
0x50, 0xb8, 0xfc, 0xc8, 0xfb, 0x93, 0x4c, 0x23, 0xc9, 0xcb, 0x65, 0x79, 0xfe, 0x2f, 0xec, 0x4c,
|
||||
0x4d, 0x50, 0xa4, 0xd5, 0x24, 0x56, 0x9e, 0xe5, 0x35, 0x29, 0x56, 0x9e, 0x55, 0x1b, 0x4d, 0x13,
|
||||
0x14, 0x69, 0x07, 0x89, 0xb1, 0x2d, 0xaf, 0x34, 0x31, 0xb6, 0x55, 0xab, 0x8b, 0x0e, 0xd9, 0xd8,
|
||||
0x43, 0x17, 0x2b, 0xf6, 0xaa, 0xa7, 0x31, 0x56, 0xec, 0xd5, 0x6f, 0xe4, 0xcf, 0xb0, 0x15, 0x3e,
|
||||
0x25, 0xe8, 0xb1, 0xa4, 0x1c, 0x7f, 0xf6, 0x62, 0x19, 0x5b, 0x78, 0x79, 0xd0, 0x25, 0xc0, 0x7c,
|
||||
0x86, 0xa3, 0x83, 0x07, 0x46, 0xbb, 0xe0, 0x79, 0xfa, 0xdd, 0xc1, 0x8f, 0x7e, 0x85, 0xfc, 0xe2,
|
||||
0xbc, 0x44, 0xaa, 0x6c, 0xb2, 0x7a, 0x5e, 0x97, 0x5f, 0x7c, 0x57, 0x47, 0x90, 0x9f, 0xff, 0xff,
|
||||
0x97, 0x93, 0x81, 0x4d, 0xef, 0xc6, 0xbd, 0x4a, 0xdf, 0x1d, 0x9d, 0x0c, 0xd9, 0x46, 0xe3, 0xd8,
|
||||
0xce, 0xc0, 0xc1, 0x74, 0xe2, 0x92, 0xfb, 0x93, 0xa1, 0x63, 0x9d, 0xf0, 0xf7, 0xed, 0x24, 0xe2,
|
||||
0xea, 0x25, 0xf9, 0xcf, 0xb3, 0xd7, 0x7f, 0x06, 0x00, 0x00, 0xff, 0xff, 0x01, 0xb2, 0xa4, 0x25,
|
||||
0xe7, 0x0d, 0x00, 0x00,
|
||||
// 1460 bytes of a gzipped FileDescriptorProto
|
||||
0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0xac, 0x57, 0x6f, 0x6f, 0x1a, 0x47,
|
||||
0x13, 0x8f, 0xff, 0x61, 0x98, 0x03, 0x8c, 0x17, 0x6c, 0x13, 0xe2, 0xc4, 0xce, 0x45, 0xcf, 0x53,
|
||||
0xab, 0x49, 0xb0, 0xea, 0x28, 0x55, 0x92, 0x4a, 0x55, 0x6d, 0x38, 0x0b, 0x0b, 0x0c, 0xce, 0x81,
|
||||
0x63, 0xa5, 0x7d, 0x71, 0x3a, 0xb8, 0x0d, 0x3e, 0x19, 0xee, 0x2e, 0x7b, 0x4b, 0x38, 0xde, 0xf5,
|
||||
0x53, 0x54, 0xca, 0x77, 0xe9, 0xa7, 0xe8, 0x27, 0xaa, 0x76, 0xf7, 0x38, 0xf6, 0x00, 0xa7, 0xaa,
|
||||
0xd4, 0x57, 0xbe, 0x9d, 0xdf, 0xcc, 0x6f, 0x67, 0x67, 0xc6, 0x33, 0x03, 0x3c, 0x1c, 0x9b, 0x83,
|
||||
0x01, 0xa6, 0xc4, 0xeb, 0x1d, 0x8b, 0xaf, 0x3b, 0x9b, 0x96, 0x3d, 0xe2, 0x52, 0x17, 0xa5, 0x22,
|
||||
0xa8, 0x94, 0x22, 0x5e, 0x4f, 0x48, 0x4b, 0x05, 0xdf, 0xee, 0x3b, 0x4c, 0x9d, 0xfd, 0xc5, 0x44,
|
||||
0x48, 0xd5, 0x26, 0xa0, 0x86, 0xed, 0xd3, 0x6b, 0xc7, 0xf7, 0xb0, 0x43, 0x75, 0xfc, 0x79, 0x84,
|
||||
0x7d, 0x8a, 0x1e, 0x41, 0x6a, 0x68, 0x3b, 0x46, 0xcf, 0x75, 0x3e, 0xf9, 0xc5, 0x95, 0xc3, 0x95,
|
||||
0xa3, 0x0d, 0x3d, 0x39, 0xb4, 0x9d, 0x0a, 0x3b, 0x73, 0xd0, 0x0c, 0x42, 0x70, 0x35, 0x04, 0xcd,
|
||||
0x80, 0x83, 0xea, 0x1b, 0xc8, 0xc7, 0xf8, 0x7c, 0xcf, 0x75, 0x7c, 0x8c, 0x9e, 0xc2, 0xc6, 0x88,
|
||||
0x06, 0x2e, 0x23, 0x5b, 0x3b, 0x52, 0x4e, 0x94, 0xf2, 0x80, 0xb9, 0x52, 0xbe, 0xa6, 0x81, 0xab,
|
||||
0x0b, 0x44, 0x7d, 0x0f, 0xa8, 0x81, 0x4d, 0x1f, 0xb7, 0x46, 0xd4, 0x1b, 0x45, 0x9e, 0x64, 0x61,
|
||||
0xd5, 0xb6, 0xb8, 0x0b, 0x69, 0x7d, 0xd5, 0xb6, 0xd0, 0x73, 0x48, 0xba, 0x23, 0xea, 0xb9, 0xb6,
|
||||
0x43, 0xf9, 0xdd, 0xca, 0xc9, 0x56, 0xc8, 0xd5, 0x1a, 0xd1, 0x2b, 0x26, 0xd6, 0x23, 0x05, 0xf5,
|
||||
0x35, 0xe4, 0x63, 0x94, 0xa1, 0x33, 0x4f, 0x00, 0x70, 0xe0, 0xd9, 0xc4, 0xa4, 0xb6, 0xeb, 0x70,
|
||||
0xee, 0x75, 0x5d, 0x92, 0xa8, 0x6d, 0x28, 0xe8, 0x78, 0xf0, 0x1f, 0xfb, 0xb2, 0x07, 0x3b, 0x73,
|
||||
0xa4, 0xc2, 0x1b, 0xf5, 0x3d, 0x24, 0xea, 0x78, 0xa2, 0xe3, 0xcf, 0xe8, 0x08, 0x72, 0x77, 0x78,
|
||||
0x62, 0x7c, 0xb2, 0x9d, 0x3e, 0x26, 0x86, 0x47, 0x18, 0xaf, 0x08, 0x7e, 0xf6, 0x0e, 0x4f, 0xce,
|
||||
0xb9, 0xf8, 0x8a, 0x49, 0xd1, 0x63, 0x00, 0xae, 0x69, 0x0e, 0xed, 0xc1, 0x24, 0xcc, 0x41, 0x8a,
|
||||
0xe9, 0x70, 0x81, 0x9a, 0x01, 0xe5, 0xd4, 0xb2, 0x48, 0xe8, 0xb7, 0xaa, 0x42, 0x5a, 0x1c, 0xc3,
|
||||
0xf7, 0x23, 0x58, 0x37, 0x2d, 0x8b, 0x70, 0xee, 0x94, 0xce, 0xbf, 0xd5, 0x77, 0xa0, 0x74, 0x88,
|
||||
0xe9, 0xf8, 0x66, 0x8f, 0x85, 0x00, 0xed, 0x40, 0x82, 0x06, 0xc6, 0x2d, 0x0e, 0xc2, 0xe7, 0x6e,
|
||||
0xd0, 0xa0, 0x86, 0x03, 0x54, 0x80, 0x8d, 0x81, 0xd9, 0xc5, 0x03, 0x7e, 0x65, 0x4a, 0x17, 0x07,
|
||||
0xf5, 0x47, 0xd8, 0xba, 0x1a, 0x75, 0x07, 0xb6, 0x7f, 0x1b, 0x5d, 0xf1, 0x0c, 0x32, 0x9e, 0x10,
|
||||
0x19, 0x98, 0x10, 0x77, 0x7a, 0x57, 0x3a, 0x14, 0x6a, 0x4c, 0xa6, 0xfe, 0xb9, 0x02, 0xa8, 0x8d,
|
||||
0x1d, 0x4b, 0x04, 0xc4, 0x9f, 0x86, 0x79, 0x1f, 0xc0, 0x37, 0xa9, 0xe1, 0x61, 0x62, 0xdc, 0x8d,
|
||||
0xb9, 0xe1, 0x9a, 0x9e, 0xf4, 0x4d, 0x7a, 0x85, 0x49, 0x7d, 0x8c, 0x8e, 0x60, 0xd3, 0x15, 0xfa,
|
||||
0xc5, 0x55, 0x5e, 0x4b, 0xd9, 0x72, 0x58, 0xd8, 0xe5, 0x4e, 0xd0, 0x1a, 0x51, 0x7d, 0x0a, 0xcf,
|
||||
0x9c, 0x5d, 0x93, 0x9c, 0x8d, 0x97, 0xf6, 0xfa, 0x5c, 0x69, 0x3f, 0x87, 0x6d, 0x56, 0xb7, 0x96,
|
||||
0x31, 0x72, 0x98, 0x82, 0x4d, 0x86, 0xd8, 0x2a, 0x6e, 0x1c, 0xae, 0x1c, 0x25, 0xf5, 0x1c, 0x07,
|
||||
0xae, 0x67, 0x72, 0xf5, 0x05, 0xe4, 0x63, 0xde, 0x87, 0x4f, 0xdf, 0x81, 0x04, 0x31, 0xc7, 0x06,
|
||||
0x8d, 0x42, 0x47, 0xcc, 0x71, 0x27, 0x50, 0x5f, 0x03, 0xd2, 0x7c, 0x6a, 0x0f, 0x4d, 0x8a, 0xcf,
|
||||
0x31, 0x9e, 0xbe, 0xf5, 0x00, 0x14, 0x46, 0x68, 0x50, 0x93, 0xf4, 0xf1, 0x34, 0xdb, 0xc0, 0x44,
|
||||
0x1d, 0x2e, 0x51, 0x5f, 0x41, 0x3e, 0x66, 0x16, 0x5e, 0xf2, 0xcd, 0x18, 0xa9, 0x5f, 0xd7, 0x20,
|
||||
0x7d, 0x85, 0x1d, 0xcb, 0x76, 0xfa, 0xed, 0x31, 0xc6, 0x5e, 0xac, 0x52, 0x57, 0xfe, 0xa1, 0x52,
|
||||
0xd1, 0x5b, 0x48, 0x8f, 0x6d, 0xea, 0x60, 0xdf, 0x37, 0xe8, 0xc4, 0xc3, 0x3c, 0xd7, 0xd9, 0x93,
|
||||
0xdd, 0x72, 0xd4, 0x55, 0xca, 0x37, 0x02, 0xee, 0x4c, 0x3c, 0xac, 0x2b, 0xe3, 0xd9, 0x81, 0xd5,
|
||||
0xa5, 0x39, 0x74, 0x47, 0x0e, 0x35, 0x7c, 0x93, 0xf2, 0xb8, 0x67, 0xf4, 0x94, 0x90, 0xb4, 0x4d,
|
||||
0x8a, 0x0e, 0x21, 0x3d, 0xf5, 0xba, 0x3b, 0xa1, 0x98, 0x87, 0x3f, 0xa3, 0x83, 0xf0, 0xfb, 0x6c,
|
||||
0x42, 0x31, 0x7a, 0x09, 0xa8, 0x4b, 0x5c, 0xd3, 0xea, 0x99, 0x3e, 0x35, 0x4c, 0x4a, 0xf1, 0xd0,
|
||||
0xa3, 0x3e, 0xcf, 0x40, 0x46, 0xdf, 0x8e, 0x90, 0xd3, 0x10, 0x40, 0x27, 0xb0, 0xe3, 0xe0, 0x80,
|
||||
0x1a, 0x33, 0x9b, 0x5b, 0x6c, 0xf7, 0x6f, 0x69, 0x31, 0xc1, 0x2d, 0xf2, 0x0c, 0x3c, 0x9b, 0x62,
|
||||
0x35, 0x0e, 0x31, 0x1b, 0x22, 0xa2, 0x8f, 0x2d, 0x43, 0x0e, 0x7e, 0x52, 0xd8, 0x44, 0x60, 0x25,
|
||||
0xca, 0x02, 0x7a, 0x05, 0xbb, 0x33, 0x9b, 0xd8, 0x13, 0x52, 0x73, 0x46, 0xed, 0xd9, 0x5b, 0x0a,
|
||||
0xb0, 0xf1, 0xc9, 0x25, 0x3d, 0x5c, 0xdc, 0xe4, 0x05, 0x24, 0x0e, 0xea, 0x2e, 0x14, 0xe4, 0xd4,
|
||||
0x4c, 0xab, 0x5e, 0xbd, 0x81, 0x9d, 0x39, 0x79, 0x98, 0xea, 0x9f, 0x21, 0xeb, 0x09, 0xc0, 0xf0,
|
||||
0x39, 0x12, 0xf6, 0xd0, 0x3d, 0x29, 0x21, 0xb2, 0xa5, 0x9e, 0xf1, 0x64, 0x1e, 0xf5, 0x8f, 0x15,
|
||||
0xc8, 0x9e, 0x8d, 0x86, 0x9e, 0x54, 0x75, 0xff, 0xaa, 0x1c, 0x0e, 0x40, 0x11, 0x01, 0xe2, 0xc1,
|
||||
0xe2, 0xd5, 0x90, 0xd1, 0x41, 0x88, 0x58, 0x88, 0x16, 0xb2, 0xba, 0xb6, 0x90, 0xd5, 0x28, 0x12,
|
||||
0xeb, 0x72, 0x24, 0xb6, 0x61, 0x2b, 0xf2, 0x2b, 0xec, 0x85, 0x2f, 0x61, 0x9b, 0x4d, 0x8f, 0x58,
|
||||
0x64, 0x50, 0x11, 0x36, 0xbf, 0x60, 0xd2, 0x75, 0x7d, 0xcc, 0x9d, 0x4d, 0xea, 0xd3, 0xa3, 0xfa,
|
||||
0xfb, 0xaa, 0x98, 0x5e, 0x73, 0x11, 0x6b, 0x40, 0x9e, 0xce, 0x7a, 0x99, 0x61, 0x61, 0x6a, 0xda,
|
||||
0x03, 0x3f, 0x7c, 0xe9, 0xc3, 0xf0, 0xa5, 0x52, 0xb7, 0xab, 0x0a, 0x85, 0xda, 0x03, 0x1d, 0xd1,
|
||||
0x05, 0x29, 0xba, 0x81, 0x2d, 0x99, 0xcd, 0xb6, 0xfc, 0xb0, 0xd9, 0xbf, 0x90, 0x12, 0xb0, 0xe8,
|
||||
0x85, 0x7c, 0xc1, 0x45, 0x95, 0x91, 0x67, 0x25, 0x9a, 0x0b, 0xcb, 0x2f, 0xbd, 0x85, 0x6c, 0x5c,
|
||||
0x07, 0x7d, 0xb7, 0x78, 0x15, 0xcb, 0x75, 0x6a, 0xde, 0xf4, 0x2c, 0x09, 0x09, 0x51, 0x0b, 0xaa,
|
||||
0x09, 0x7b, 0x0d, 0xd6, 0xd7, 0x24, 0xa6, 0x69, 0xdc, 0x10, 0xac, 0xd3, 0x20, 0x1a, 0x58, 0xfc,
|
||||
0x7b, 0x79, 0x03, 0x47, 0xfb, 0x90, 0x72, 0xbf, 0x60, 0x32, 0x26, 0x76, 0x98, 0xbe, 0xa4, 0x3e,
|
||||
0x13, 0xa8, 0x25, 0x28, 0x2e, 0x5e, 0x21, 0x1e, 0xf9, 0xfd, 0xd7, 0x35, 0x50, 0xa4, 0x6e, 0x80,
|
||||
0xf2, 0xb0, 0x75, 0xdd, 0xac, 0x37, 0x5b, 0x37, 0x4d, 0xe3, 0xe6, 0xa2, 0xd3, 0xd4, 0xda, 0xed,
|
||||
0xdc, 0x03, 0x54, 0x84, 0x42, 0xa5, 0x75, 0x79, 0x79, 0xd1, 0xb9, 0xd4, 0x9a, 0x1d, 0xa3, 0x73,
|
||||
0x71, 0xa9, 0x19, 0x8d, 0x56, 0xa5, 0x9e, 0x5b, 0x41, 0x7b, 0x90, 0x97, 0x90, 0x66, 0xcb, 0xa8,
|
||||
0x6a, 0x8d, 0xd3, 0x8f, 0xb9, 0x55, 0xb4, 0x03, 0xdb, 0x12, 0xa0, 0x6b, 0x1f, 0x5a, 0x75, 0x2d,
|
||||
0xb7, 0xc6, 0xf4, 0x6b, 0x9d, 0x46, 0xc5, 0x68, 0x9d, 0x9f, 0x6b, 0xba, 0x56, 0x9d, 0x02, 0xeb,
|
||||
0xec, 0x0a, 0x0e, 0x9c, 0x56, 0x2a, 0xda, 0x55, 0x67, 0x86, 0x6c, 0xa0, 0xff, 0xc1, 0xd3, 0x98,
|
||||
0x09, 0xbb, 0xbe, 0x75, 0xdd, 0x31, 0xda, 0x5a, 0xa5, 0xd5, 0xac, 0x1a, 0x0d, 0xed, 0x83, 0xd6,
|
||||
0xc8, 0x25, 0xd0, 0xff, 0x41, 0x8d, 0x13, 0xb4, 0xaf, 0x2b, 0x15, 0xad, 0xdd, 0x8e, 0xeb, 0x6d,
|
||||
0xa2, 0x03, 0x78, 0x34, 0xe7, 0xc1, 0x65, 0xab, 0xa3, 0x4d, 0x59, 0x73, 0x49, 0x74, 0x08, 0xfb,
|
||||
0xf3, 0x9e, 0x70, 0x8d, 0x90, 0x2f, 0x97, 0x42, 0xfb, 0x50, 0xe4, 0x1a, 0x32, 0xf3, 0xd4, 0x5f,
|
||||
0x40, 0x05, 0xc8, 0x85, 0x91, 0x33, 0xea, 0xda, 0x47, 0xa3, 0x76, 0xda, 0xae, 0xe5, 0x14, 0xf4,
|
||||
0x08, 0xf6, 0x9a, 0x5a, 0x9b, 0xd1, 0x2d, 0x80, 0xe9, 0xb9, 0x60, 0x9d, 0x36, 0x2b, 0xb5, 0x96,
|
||||
0x9e, 0xcb, 0x9c, 0xfc, 0xb5, 0x09, 0xa9, 0x1b, 0x5e, 0xa1, 0x75, 0x9b, 0xa2, 0x06, 0x28, 0xd2,
|
||||
0x62, 0x86, 0x1e, 0xcf, 0x15, 0x6f, 0x7c, 0x01, 0x2c, 0x3d, 0xb9, 0x0f, 0x8e, 0xfe, 0xc5, 0x14,
|
||||
0x69, 0xb3, 0x8a, 0xb3, 0x2d, 0x2c, 0x4e, 0x71, 0xb6, 0x25, 0x0b, 0x99, 0x0e, 0x99, 0xd8, 0x6e,
|
||||
0x84, 0x0e, 0x24, 0x83, 0x65, 0xab, 0x58, 0xe9, 0xf0, 0x7e, 0x85, 0x90, 0xf3, 0x1d, 0x64, 0xaa,
|
||||
0x98, 0xd8, 0x5f, 0x70, 0x13, 0x07, 0xb4, 0x8e, 0x27, 0x68, 0x5b, 0x32, 0x11, 0x0b, 0x57, 0x69,
|
||||
0x37, 0x5a, 0x1d, 0xea, 0x78, 0x52, 0xc5, 0x7e, 0x8f, 0xd8, 0x1e, 0x75, 0x09, 0x7a, 0x03, 0x29,
|
||||
0x61, 0xcb, 0xec, 0xf2, 0xb2, 0x52, 0xc3, 0xed, 0x99, 0xd4, 0x25, 0xf7, 0x5a, 0xfe, 0x04, 0x49,
|
||||
0x76, 0x1f, 0x5b, 0xb7, 0x90, 0x3c, 0x31, 0xa5, 0x75, 0xac, 0xb4, 0xb7, 0x20, 0x0f, 0x5d, 0xae,
|
||||
0x01, 0x0a, 0xf7, 0x28, 0x79, 0x15, 0x93, 0x69, 0x24, 0x79, 0xa9, 0x24, 0xf7, 0xff, 0xb9, 0xf5,
|
||||
0xab, 0x01, 0x8a, 0xb4, 0x9a, 0xc4, 0xd2, 0xb3, 0xb8, 0x70, 0xc5, 0xd2, 0xb3, 0x6c, 0xa3, 0x69,
|
||||
0x80, 0x22, 0xed, 0x20, 0x31, 0xb6, 0xc5, 0x95, 0x26, 0xc6, 0xb6, 0x6c, 0x75, 0xd1, 0x21, 0x13,
|
||||
0x1b, 0x74, 0xb1, 0x64, 0x2f, 0x1b, 0x8d, 0xb1, 0x64, 0x2f, 0x9f, 0x91, 0xbf, 0xc0, 0x66, 0x38,
|
||||
0x4a, 0xd0, 0x43, 0x49, 0x39, 0x3e, 0xf6, 0x62, 0x11, 0x9b, 0x9b, 0x3c, 0xe8, 0x02, 0x60, 0xd6,
|
||||
0xc3, 0xd1, 0xfe, 0x3d, 0xad, 0x5d, 0xf0, 0x3c, 0xfe, 0x66, 0xe3, 0x47, 0xbf, 0x41, 0x6e, 0xbe,
|
||||
0x5f, 0x22, 0x55, 0x36, 0x59, 0xde, 0xaf, 0x4b, 0xcf, 0xbe, 0xa9, 0x23, 0xc8, 0xcf, 0x7e, 0xf8,
|
||||
0xf5, 0xb8, 0x6f, 0xd3, 0xdb, 0x51, 0xb7, 0xdc, 0x73, 0x87, 0xc7, 0x03, 0xb6, 0xd1, 0x38, 0xb6,
|
||||
0xd3, 0x77, 0x30, 0x1d, 0xbb, 0xe4, 0xee, 0x78, 0xe0, 0x58, 0xc7, 0x7c, 0xbe, 0x1d, 0x47, 0x5c,
|
||||
0xdd, 0x04, 0xff, 0xa5, 0xf7, 0xea, 0xef, 0x00, 0x00, 0x00, 0xff, 0xff, 0x49, 0x6e, 0x8a, 0xc5,
|
||||
0x32, 0x0e, 0x00, 0x00,
|
||||
}
|
||||
|
||||
// Reference imports to suppress errors if they are not otherwise used.
|
||||
|
|
|
@ -233,6 +233,13 @@ message SendOutputsRequest {
|
|||
|
||||
// An optional label for the transaction, limited to 500 characters.
|
||||
string label = 3;
|
||||
|
||||
// The minimum number of confirmations each one of your outputs used for
|
||||
// the transaction must satisfy.
|
||||
int32 min_confs = 4;
|
||||
|
||||
// Whether unconfirmed outputs should be used as inputs for the transaction.
|
||||
bool spend_unconfirmed = 5;
|
||||
}
|
||||
message SendOutputsResponse {
|
||||
/*
|
||||
|
|
|
@ -877,6 +877,16 @@
|
|||
"label": {
|
||||
"type": "string",
|
||||
"description": "An optional label for the transaction, limited to 500 characters."
|
||||
},
|
||||
"min_confs": {
|
||||
"type": "integer",
|
||||
"format": "int32",
|
||||
"description": "The minimum number of confirmations each one of your outputs used for\nthe transaction must satisfy."
|
||||
},
|
||||
"spend_unconfirmed": {
|
||||
"type": "boolean",
|
||||
"format": "boolean",
|
||||
"description": "Whether unconfirmed outputs should be used as inputs for the transaction."
|
||||
}
|
||||
}
|
||||
},
|
||||
|
|
|
@ -473,6 +473,13 @@ func (w *WalletKit) SendOutputs(ctx context.Context,
|
|||
})
|
||||
}
|
||||
|
||||
// Then, we'll extract the minimum number of confirmations that each
|
||||
// output we use to fund the transaction should satisfy.
|
||||
minConfs, err := lnrpc.ExtractMinConfs(req.MinConfs, req.SpendUnconfirmed)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
label, err := labels.ValidateAPI(req.Label)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
|
@ -481,7 +488,7 @@ func (w *WalletKit) SendOutputs(ctx context.Context,
|
|||
// Now that we have the outputs mapped, we can request that the wallet
|
||||
// attempt to create this transaction.
|
||||
tx, err := w.cfg.Wallet.SendOutputs(
|
||||
outputsToCreate, chainfee.SatPerKWeight(req.SatPerKw), label,
|
||||
outputsToCreate, chainfee.SatPerKWeight(req.SatPerKw), minConfs, label,
|
||||
)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
|
|
|
@ -78,7 +78,7 @@ func (w *WalletController) IsOurAddress(a btcutil.Address) bool {
|
|||
|
||||
// SendOutputs currently returns dummy values.
|
||||
func (w *WalletController) SendOutputs(outputs []*wire.TxOut,
|
||||
_ chainfee.SatPerKWeight, _ string) (*wire.MsgTx, error) {
|
||||
_ chainfee.SatPerKWeight, _ int32, _ string) (*wire.MsgTx, error) {
|
||||
|
||||
return nil, nil
|
||||
}
|
||||
|
|
|
@ -297,7 +297,7 @@ func (b *BtcWallet) IsOurAddress(a btcutil.Address) bool {
|
|||
//
|
||||
// This is a part of the WalletController interface.
|
||||
func (b *BtcWallet) SendOutputs(outputs []*wire.TxOut,
|
||||
feeRate chainfee.SatPerKWeight, label string) (*wire.MsgTx, error) {
|
||||
feeRate chainfee.SatPerKWeight, minconf int32, label string) (*wire.MsgTx, error) {
|
||||
|
||||
// Convert our fee rate from sat/kw to sat/kb since it's required by
|
||||
// SendOutputs.
|
||||
|
@ -308,8 +308,13 @@ func (b *BtcWallet) SendOutputs(outputs []*wire.TxOut,
|
|||
return nil, lnwallet.ErrNoOutputs
|
||||
}
|
||||
|
||||
// Sanity check minconf.
|
||||
if minconf < 0 {
|
||||
return nil, lnwallet.ErrInvalidMinconf
|
||||
}
|
||||
|
||||
return b.wallet.SendOutputs(
|
||||
outputs, defaultAccount, 1, feeSatPerKB, label,
|
||||
outputs, defaultAccount, minconf, feeSatPerKB, label,
|
||||
)
|
||||
}
|
||||
|
||||
|
|
|
@ -56,6 +56,11 @@ var (
|
|||
// or send coins to a set of outputs that is empty.
|
||||
var ErrNoOutputs = errors.New("no outputs")
|
||||
|
||||
// ErrInvalidMinconf is returned if we try to create a transaction with
|
||||
// invalid minconf value.
|
||||
var ErrInvalidMinconf = errors.New("minimum number of confirmations must " +
|
||||
"be a non-negative number")
|
||||
|
||||
// Utxo is an unspent output denoted by its outpoint, and output value of the
|
||||
// original output.
|
||||
type Utxo struct {
|
||||
|
@ -181,7 +186,7 @@ type WalletController interface {
|
|||
//
|
||||
// NOTE: This method requires the global coin selection lock to be held.
|
||||
SendOutputs(outputs []*wire.TxOut,
|
||||
feeRate chainfee.SatPerKWeight, label string) (*wire.MsgTx, error)
|
||||
feeRate chainfee.SatPerKWeight, minconf int32, label string) (*wire.MsgTx, error)
|
||||
|
||||
// CreateSimpleTx creates a Bitcoin transaction paying to the specified
|
||||
// outputs. The transaction is not broadcasted to the network. In the
|
||||
|
|
|
@ -171,18 +171,20 @@ func newPkScript(t *testing.T, w *lnwallet.LightningWallet,
|
|||
// parties to send on-chain funds to each other.
|
||||
func sendCoins(t *testing.T, miner *rpctest.Harness,
|
||||
sender, receiver *lnwallet.LightningWallet, output *wire.TxOut,
|
||||
feeRate chainfee.SatPerKWeight) *wire.MsgTx { //nolint:unparam
|
||||
feeRate chainfee.SatPerKWeight, mineBlock bool, minConf int32) *wire.MsgTx { //nolint:unparam
|
||||
|
||||
t.Helper()
|
||||
|
||||
tx, err := sender.SendOutputs(
|
||||
[]*wire.TxOut{output}, 2500, labels.External,
|
||||
[]*wire.TxOut{output}, feeRate, minConf, labels.External,
|
||||
)
|
||||
if err != nil {
|
||||
t.Fatalf("unable to send transaction: %v", err)
|
||||
}
|
||||
|
||||
mineAndAssertTxInBlock(t, miner, tx.TxHash())
|
||||
if mineBlock {
|
||||
mineAndAssertTxInBlock(t, miner, tx.TxHash())
|
||||
}
|
||||
|
||||
if err := waitForWalletSync(miner, sender); err != nil {
|
||||
t.Fatalf("unable to sync alice: %v", err)
|
||||
|
@ -201,12 +203,6 @@ func assertTxInWallet(t *testing.T, w *lnwallet.LightningWallet,
|
|||
|
||||
t.Helper()
|
||||
|
||||
// If the backend is Neutrino, then we can't determine unconfirmed
|
||||
// transactions since it's not aware of the mempool.
|
||||
if !confirmed && w.BackEnd() == "neutrino" {
|
||||
return
|
||||
}
|
||||
|
||||
// We'll fetch all of our transaction and go through each one until
|
||||
// finding the expected transaction with its expected confirmation
|
||||
// status.
|
||||
|
@ -1269,7 +1265,7 @@ func testListTransactionDetails(miner *rpctest.Harness,
|
|||
}
|
||||
burnOutput := wire.NewTxOut(outputAmt, outputScript)
|
||||
burnTX, err := alice.SendOutputs(
|
||||
[]*wire.TxOut{burnOutput}, 2500, labels.External,
|
||||
[]*wire.TxOut{burnOutput}, 2500, 1, labels.External,
|
||||
)
|
||||
if err != nil {
|
||||
t.Fatalf("unable to create burn tx: %v", err)
|
||||
|
@ -1544,7 +1540,7 @@ func testTransactionSubscriptions(miner *rpctest.Harness,
|
|||
}
|
||||
burnOutput := wire.NewTxOut(outputAmt, outputScript)
|
||||
tx, err := alice.SendOutputs(
|
||||
[]*wire.TxOut{burnOutput}, 2500, labels.External,
|
||||
[]*wire.TxOut{burnOutput}, 2500, 1, labels.External,
|
||||
)
|
||||
if err != nil {
|
||||
t.Fatalf("unable to create burn tx: %v", err)
|
||||
|
@ -1737,7 +1733,7 @@ func newTx(t *testing.T, r *rpctest.Harness, pubKey *btcec.PublicKey,
|
|||
PkScript: keyScript,
|
||||
}
|
||||
tx, err := alice.SendOutputs(
|
||||
[]*wire.TxOut{newOutput}, 2500, labels.External,
|
||||
[]*wire.TxOut{newOutput}, 2500, 1, labels.External,
|
||||
)
|
||||
if err != nil {
|
||||
t.Fatalf("unable to create output: %v", err)
|
||||
|
@ -2028,7 +2024,7 @@ func testSignOutputUsingTweaks(r *rpctest.Harness,
|
|||
PkScript: keyScript,
|
||||
}
|
||||
tx, err := alice.SendOutputs(
|
||||
[]*wire.TxOut{newOutput}, 2500, labels.External,
|
||||
[]*wire.TxOut{newOutput}, 2500, 1, labels.External,
|
||||
)
|
||||
if err != nil {
|
||||
t.Fatalf("unable to create output: %v", err)
|
||||
|
@ -2152,7 +2148,7 @@ func testReorgWalletBalance(r *rpctest.Harness, w *lnwallet.LightningWallet,
|
|||
PkScript: script,
|
||||
}
|
||||
tx, err := w.SendOutputs(
|
||||
[]*wire.TxOut{output}, 2500, labels.External,
|
||||
[]*wire.TxOut{output}, 2500, 1, labels.External,
|
||||
)
|
||||
if err != nil {
|
||||
t.Fatalf("unable to send outputs: %v", err)
|
||||
|
@ -2311,7 +2307,7 @@ func testChangeOutputSpendConfirmation(r *rpctest.Harness,
|
|||
}
|
||||
bobPkScript := newPkScript(t, bob, lnwallet.WitnessPubKey)
|
||||
|
||||
// We'll use a transaction fee of 13020 satoshis, which will allow us to
|
||||
// We'll use a transaction fee of 14380 satoshis, which will allow us to
|
||||
// sweep all of Alice's balance in one transaction containing 1 input
|
||||
// and 1 output.
|
||||
//
|
||||
|
@ -2323,7 +2319,7 @@ func testChangeOutputSpendConfirmation(r *rpctest.Harness,
|
|||
Value: int64(aliceBalance - txFee),
|
||||
PkScript: bobPkScript,
|
||||
}
|
||||
tx := sendCoins(t, r, alice, bob, output, txFeeRate)
|
||||
tx := sendCoins(t, r, alice, bob, output, txFeeRate, true, 1)
|
||||
txHash := tx.TxHash()
|
||||
assertTxInWallet(t, alice, txHash, true)
|
||||
assertTxInWallet(t, bob, txHash, true)
|
||||
|
@ -2345,7 +2341,7 @@ func testChangeOutputSpendConfirmation(r *rpctest.Harness,
|
|||
Value: btcutil.SatoshiPerBitcoin,
|
||||
PkScript: alicePkScript,
|
||||
}
|
||||
tx = sendCoins(t, r, bob, alice, output, txFeeRate)
|
||||
tx = sendCoins(t, r, bob, alice, output, txFeeRate, true, 1)
|
||||
txHash = tx.TxHash()
|
||||
assertTxInWallet(t, alice, txHash, true)
|
||||
assertTxInWallet(t, bob, txHash, true)
|
||||
|
@ -2357,14 +2353,14 @@ func testChangeOutputSpendConfirmation(r *rpctest.Harness,
|
|||
Value: btcutil.SatoshiPerBitcent,
|
||||
PkScript: bobPkScript,
|
||||
}
|
||||
tx = sendCoins(t, r, alice, bob, output, txFeeRate)
|
||||
tx = sendCoins(t, r, alice, bob, output, txFeeRate, true, 1)
|
||||
txHash = tx.TxHash()
|
||||
assertTxInWallet(t, alice, txHash, true)
|
||||
assertTxInWallet(t, bob, txHash, true)
|
||||
|
||||
// Then, we'll spend the change output and ensure we see its
|
||||
// confirmation come in.
|
||||
tx = sendCoins(t, r, alice, bob, output, txFeeRate)
|
||||
tx = sendCoins(t, r, alice, bob, output, txFeeRate, true, 1)
|
||||
txHash = tx.TxHash()
|
||||
assertTxInWallet(t, alice, txHash, true)
|
||||
assertTxInWallet(t, bob, txHash, true)
|
||||
|
@ -2376,6 +2372,101 @@ func testChangeOutputSpendConfirmation(r *rpctest.Harness,
|
|||
}
|
||||
}
|
||||
|
||||
// testSpendUnconfirmed ensures that when can spend unconfirmed outputs.
|
||||
func testSpendUnconfirmed(miner *rpctest.Harness,
|
||||
alice, bob *lnwallet.LightningWallet, t *testing.T) {
|
||||
|
||||
bobPkScript := newPkScript(t, bob, lnwallet.WitnessPubKey)
|
||||
alicePkScript := newPkScript(t, alice, lnwallet.WitnessPubKey)
|
||||
txFeeRate := chainfee.SatPerKWeight(2500)
|
||||
|
||||
// First we will empty out bob's wallet, sending the entire balance
|
||||
// to alice.
|
||||
bobBalance, err := bob.ConfirmedBalance(0)
|
||||
if err != nil {
|
||||
t.Fatalf("unable to retrieve bob's balance: %v", err)
|
||||
}
|
||||
txFee := btcutil.Amount(28760)
|
||||
output := &wire.TxOut{
|
||||
Value: int64(bobBalance - txFee),
|
||||
PkScript: alicePkScript,
|
||||
}
|
||||
tx := sendCoins(t, miner, bob, alice, output, txFeeRate, true, 1)
|
||||
txHash := tx.TxHash()
|
||||
assertTxInWallet(t, alice, txHash, true)
|
||||
assertTxInWallet(t, bob, txHash, true)
|
||||
|
||||
// Verify that bob doesn't have enough balance to send coins.
|
||||
output = &wire.TxOut{
|
||||
Value: btcutil.SatoshiPerBitcoin * 0.5,
|
||||
PkScript: alicePkScript,
|
||||
}
|
||||
_, err = bob.SendOutputs(
|
||||
[]*wire.TxOut{output}, txFeeRate, 0, labels.External,
|
||||
)
|
||||
if err == nil {
|
||||
t.Fatalf("should have not been able to pay due to insufficient balance: %v", err)
|
||||
}
|
||||
|
||||
// Next we will send a transaction to bob but leave it in an
|
||||
// unconfirmed state.
|
||||
output = &wire.TxOut{
|
||||
Value: btcutil.SatoshiPerBitcoin,
|
||||
PkScript: bobPkScript,
|
||||
}
|
||||
tx = sendCoins(t, miner, alice, bob, output, txFeeRate, false, 1)
|
||||
txHash = tx.TxHash()
|
||||
assertTxInWallet(t, alice, txHash, false)
|
||||
assertTxInWallet(t, bob, txHash, false)
|
||||
|
||||
// Now, try to spend some of the unconfirmed funds from bob's wallet.
|
||||
output = &wire.TxOut{
|
||||
Value: btcutil.SatoshiPerBitcoin * 0.5,
|
||||
PkScript: alicePkScript,
|
||||
}
|
||||
|
||||
// First, verify that we don't have enough balance to send the coins
|
||||
// using confirmed outputs only.
|
||||
_, err = bob.SendOutputs(
|
||||
[]*wire.TxOut{output}, txFeeRate, 1, labels.External,
|
||||
)
|
||||
if err == nil {
|
||||
t.Fatalf("should have not been able to pay due to insufficient balance: %v", err)
|
||||
}
|
||||
|
||||
// Now try the send again using unconfirmed outputs.
|
||||
tx = sendCoins(t, miner, bob, alice, output, txFeeRate, false, 0)
|
||||
txHash = tx.TxHash()
|
||||
assertTxInWallet(t, alice, txHash, false)
|
||||
assertTxInWallet(t, bob, txHash, false)
|
||||
|
||||
// Mine the unconfirmed transactions.
|
||||
err = waitForMempoolTx(miner, &txHash)
|
||||
if err != nil {
|
||||
t.Fatalf("tx not relayed to miner: %v", err)
|
||||
}
|
||||
if _, err := miner.Node.Generate(1); err != nil {
|
||||
t.Fatalf("unable to generate block: %v", err)
|
||||
}
|
||||
if err := waitForWalletSync(miner, alice); err != nil {
|
||||
t.Fatalf("unable to sync alice: %v", err)
|
||||
}
|
||||
if err := waitForWalletSync(miner, bob); err != nil {
|
||||
t.Fatalf("unable to sync bob: %v", err)
|
||||
}
|
||||
|
||||
// Finally, send the remainder of bob's wallet balance back to him so
|
||||
// that these money movements dont mess up later tests.
|
||||
output = &wire.TxOut{
|
||||
Value: int64(bobBalance) - (btcutil.SatoshiPerBitcoin * 0.4),
|
||||
PkScript: bobPkScript,
|
||||
}
|
||||
tx = sendCoins(t, miner, alice, bob, output, txFeeRate, true, 1)
|
||||
txHash = tx.TxHash()
|
||||
assertTxInWallet(t, alice, txHash, true)
|
||||
assertTxInWallet(t, bob, txHash, true)
|
||||
}
|
||||
|
||||
// testLastUnusedAddr tests that the LastUnusedAddress returns the address if
|
||||
// it isn't used, and also that once the address becomes used, then it's
|
||||
// properly rotated.
|
||||
|
@ -2418,7 +2509,7 @@ func testLastUnusedAddr(miner *rpctest.Harness,
|
|||
Value: 1000000,
|
||||
PkScript: addrScript,
|
||||
}
|
||||
sendCoins(t, miner, bob, alice, output, feeRate)
|
||||
sendCoins(t, miner, bob, alice, output, feeRate, true, 1)
|
||||
|
||||
// If we make a new address, then it should be brand new, as
|
||||
// the prior address has been used.
|
||||
|
@ -2534,7 +2625,7 @@ func testCreateSimpleTx(r *rpctest.Harness, w *lnwallet.LightningWallet,
|
|||
// _very_ similar to the one we just created being sent. The
|
||||
// only difference is that the dry run tx is not signed, and
|
||||
// that the change output position might be different.
|
||||
tx, sendErr := w.SendOutputs(outputs, feeRate, labels.External)
|
||||
tx, sendErr := w.SendOutputs(outputs, feeRate, 1, labels.External)
|
||||
switch {
|
||||
case test.valid && sendErr != nil:
|
||||
t.Fatalf("got unexpected error when sending tx: %v",
|
||||
|
@ -2678,6 +2769,10 @@ var walletTests = []walletTestCase{
|
|||
name: "change output spend confirmation",
|
||||
test: testChangeOutputSpendConfirmation,
|
||||
},
|
||||
{
|
||||
name: "spend unconfirmed outputs",
|
||||
test: testSpendUnconfirmed,
|
||||
},
|
||||
{
|
||||
name: "insane fee reject",
|
||||
test: testReservationInitiatorBalanceBelowDustCancel,
|
||||
|
@ -3310,6 +3405,10 @@ func runTests(t *testing.T, walletDriver *lnwallet.WalletDriver,
|
|||
strings.Contains(walletTest.name, "dual funder") {
|
||||
t.Skip("skipping dual funder tests for neutrino")
|
||||
}
|
||||
if backEnd == "neutrino" &&
|
||||
strings.Contains(walletTest.name, "spend unconfirmed") {
|
||||
t.Skip("skipping spend unconfirmed tests for neutrino")
|
||||
}
|
||||
|
||||
walletTest.test(miningNode, alice, bob, t)
|
||||
})
|
||||
|
|
66
rpcserver.go
66
rpcserver.go
|
@ -1042,14 +1042,15 @@ func allowCORS(handler http.Handler, origins []string) http.Handler {
|
|||
// more addresses specified in the passed payment map. The payment map maps an
|
||||
// address to a specified output value to be sent to that address.
|
||||
func (r *rpcServer) sendCoinsOnChain(paymentMap map[string]int64,
|
||||
feeRate chainfee.SatPerKWeight, label string) (*chainhash.Hash, error) {
|
||||
feeRate chainfee.SatPerKWeight, minconf int32,
|
||||
label string) (*chainhash.Hash, error) {
|
||||
|
||||
outputs, err := addrPairsToOutputs(paymentMap, r.cfg.ActiveNetParams.Params)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
tx, err := r.server.cc.wallet.SendOutputs(outputs, feeRate, label)
|
||||
tx, err := r.server.cc.wallet.SendOutputs(outputs, feeRate, minconf, label)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
@ -1180,8 +1181,16 @@ func (r *rpcServer) SendCoins(ctx context.Context,
|
|||
return nil, err
|
||||
}
|
||||
|
||||
rpcsLog.Infof("[sendcoins] addr=%v, amt=%v, sat/kw=%v, sweep_all=%v",
|
||||
in.Addr, btcutil.Amount(in.Amount), int64(feePerKw),
|
||||
// Then, we'll extract the minimum number of confirmations that each
|
||||
// output we use to fund the transaction should satisfy.
|
||||
minConfs, err := lnrpc.ExtractMinConfs(in.MinConfs, in.SpendUnconfirmed)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
rpcsLog.Infof("[sendcoins] addr=%v, amt=%v, sat/kw=%v, min_confs=%v, "+
|
||||
"sweep_all=%v",
|
||||
in.Addr, btcutil.Amount(in.Amount), int64(feePerKw), minConfs,
|
||||
in.SendAll)
|
||||
|
||||
// Decode the address receiving the coins, we need to check whether the
|
||||
|
@ -1273,7 +1282,7 @@ func (r *rpcServer) SendCoins(ctx context.Context,
|
|||
paymentMap := map[string]int64{targetAddr.String(): in.Amount}
|
||||
err := wallet.WithCoinSelectLock(func() error {
|
||||
newTXID, err := r.sendCoinsOnChain(
|
||||
paymentMap, feePerKw, label,
|
||||
paymentMap, feePerKw, minConfs, label,
|
||||
)
|
||||
if err != nil {
|
||||
return err
|
||||
|
@ -1311,6 +1320,13 @@ func (r *rpcServer) SendMany(ctx context.Context,
|
|||
return nil, err
|
||||
}
|
||||
|
||||
// Then, we'll extract the minimum number of confirmations that each
|
||||
// output we use to fund the transaction should satisfy.
|
||||
minConfs, err := lnrpc.ExtractMinConfs(in.MinConfs, in.SpendUnconfirmed)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
label, err := labels.ValidateAPI(in.Label)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
|
@ -1327,7 +1343,7 @@ func (r *rpcServer) SendMany(ctx context.Context,
|
|||
wallet := r.server.cc.wallet
|
||||
err = wallet.WithCoinSelectLock(func() error {
|
||||
sendManyTXID, err := r.sendCoinsOnChain(
|
||||
in.AddrToAmount, feePerKw, label,
|
||||
in.AddrToAmount, feePerKw, minConfs, label,
|
||||
)
|
||||
if err != nil {
|
||||
return err
|
||||
|
@ -1587,42 +1603,6 @@ func (r *rpcServer) DisconnectPeer(ctx context.Context,
|
|||
return &lnrpc.DisconnectPeerResponse{}, nil
|
||||
}
|
||||
|
||||
// extractOpenChannelMinConfs extracts the minimum number of confirmations from
|
||||
// the OpenChannelRequest that each output used to fund the channel's funding
|
||||
// transaction should satisfy.
|
||||
func extractOpenChannelMinConfs(in *lnrpc.OpenChannelRequest) (int32, error) {
|
||||
switch {
|
||||
// Ensure that the MinConfs parameter is non-negative.
|
||||
case in.MinConfs < 0:
|
||||
return 0, errors.New("minimum number of confirmations must " +
|
||||
"be a non-negative number")
|
||||
|
||||
// The funding transaction should not be funded with unconfirmed outputs
|
||||
// unless explicitly specified by SpendUnconfirmed. We do this to
|
||||
// provide sane defaults to the OpenChannel RPC, as otherwise, if the
|
||||
// MinConfs field isn't explicitly set by the caller, we'll use
|
||||
// unconfirmed outputs without the caller being aware.
|
||||
case in.MinConfs == 0 && !in.SpendUnconfirmed:
|
||||
return 1, nil
|
||||
|
||||
// In the event that the caller set MinConfs > 0 and SpendUnconfirmed to
|
||||
// true, we'll return an error to indicate the conflict.
|
||||
case in.MinConfs > 0 && in.SpendUnconfirmed:
|
||||
return 0, errors.New("SpendUnconfirmed set to true with " +
|
||||
"MinConfs > 0")
|
||||
|
||||
// The funding transaction of the new channel to be created can be
|
||||
// funded with unconfirmed outputs.
|
||||
case in.SpendUnconfirmed:
|
||||
return 0, nil
|
||||
|
||||
// If none of the above cases matched, we'll return the value set
|
||||
// explicitly by the caller.
|
||||
default:
|
||||
return in.MinConfs, nil
|
||||
}
|
||||
}
|
||||
|
||||
// newFundingShimAssembler returns a new fully populated
|
||||
// chanfunding.CannedAssembler using a FundingShim obtained from an RPC caller.
|
||||
func newFundingShimAssembler(chanPointShim *lnrpc.ChanPointShim, initiator bool,
|
||||
|
@ -1832,7 +1812,7 @@ func (r *rpcServer) parseOpenChannelReq(in *lnrpc.OpenChannelRequest,
|
|||
// Then, we'll extract the minimum number of confirmations that each
|
||||
// output we use to fund the channel's funding transaction should
|
||||
// satisfy.
|
||||
minConfs, err := extractOpenChannelMinConfs(in)
|
||||
minConfs, err := lnrpc.ExtractMinConfs(in.MinConfs, in.SpendUnconfirmed)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
|
Loading…
Add table
Reference in a new issue