lnrpc+rpcserver: define and implement EstimateFee RPC
This commit is contained in:
5 files changed
+886
-567
No files matched your search
+710
-567
File diff suppressed because it is too large.
Load diff
@@ -111,6 +111,23 @@ func request_Lightning_GetTransactions_0(ctx context.Context, marshaler runtime.
|
|||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
var (
|
||||||
|
filter_Lightning_EstimateFee_0 = &utilities.DoubleArray{Encoding: map[string]int{}, Base: []int(nil), Check: []int(nil)}
|
||||||
|
)
|
||||||
|
|
||||||
|
func request_Lightning_EstimateFee_0(ctx context.Context, marshaler runtime.Marshaler, client LightningClient, req *http.Request, pathParams map[string]string) (proto.Message, runtime.ServerMetadata, error) {
|
||||||
|
var protoReq EstimateFeeRequest
|
||||||
|
var metadata runtime.ServerMetadata
|
||||||
|
|
||||||
|
if err := runtime.PopulateQueryParameters(&protoReq, req.URL.Query(), filter_Lightning_EstimateFee_0); err != nil {
|
||||||
|
return nil, metadata, status.Errorf(codes.InvalidArgument, "%v", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
msg, err := client.EstimateFee(ctx, &protoReq, grpc.Header(&metadata.HeaderMD), grpc.Trailer(&metadata.TrailerMD))
|
||||||
|
return msg, metadata, err
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
func request_Lightning_SendCoins_0(ctx context.Context, marshaler runtime.Marshaler, client LightningClient, req *http.Request, pathParams map[string]string) (proto.Message, runtime.ServerMetadata, error) {
|
func request_Lightning_SendCoins_0(ctx context.Context, marshaler runtime.Marshaler, client LightningClient, req *http.Request, pathParams map[string]string) (proto.Message, runtime.ServerMetadata, error) {
|
||||||
var protoReq SendCoinsRequest
|
var protoReq SendCoinsRequest
|
||||||
var metadata runtime.ServerMetadata
|
var metadata runtime.ServerMetadata
|
||||||
@@ -1006,6 +1023,35 @@ func RegisterLightningHandler(ctx context.Context, mux *runtime.ServeMux, conn *
|
|||||||
|
|
||||||
})
|
})
|
||||||
|
|
||||||
|
mux.Handle("GET", pattern_Lightning_EstimateFee_0, func(w http.ResponseWriter, req *http.Request, pathParams map[string]string) {
|
||||||
|
ctx, cancel := context.WithCancel(ctx)
|
||||||
|
defer cancel()
|
||||||
|
if cn, ok := w.(http.CloseNotifier); ok {
|
||||||
|
go func(done <-chan struct{}, closed <-chan bool) {
|
||||||
|
select {
|
||||||
|
case <-done:
|
||||||
|
case <-closed:
|
||||||
|
cancel()
|
||||||
|
}
|
||||||
|
}(ctx.Done(), cn.CloseNotify())
|
||||||
|
}
|
||||||
|
inboundMarshaler, outboundMarshaler := runtime.MarshalerForRequest(mux, req)
|
||||||
|
rctx, err := runtime.AnnotateContext(ctx, mux, req)
|
||||||
|
if err != nil {
|
||||||
|
runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
resp, md, err := request_Lightning_EstimateFee_0(rctx, inboundMarshaler, client, req, pathParams)
|
||||||
|
ctx = runtime.NewServerMetadataContext(ctx, md)
|
||||||
|
if err != nil {
|
||||||
|
runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
forward_Lightning_EstimateFee_0(ctx, mux, outboundMarshaler, w, req, resp, mux.GetForwardResponseOptions()...)
|
||||||
|
|
||||||
|
})
|
||||||
|
|
||||||
mux.Handle("POST", pattern_Lightning_SendCoins_0, func(w http.ResponseWriter, req *http.Request, pathParams map[string]string) {
|
mux.Handle("POST", pattern_Lightning_SendCoins_0, func(w http.ResponseWriter, req *http.Request, pathParams map[string]string) {
|
||||||
ctx, cancel := context.WithCancel(ctx)
|
ctx, cancel := context.WithCancel(ctx)
|
||||||
defer cancel()
|
defer cancel()
|
||||||
@@ -1944,6 +1990,8 @@ var (
|
|||||||
|
|
||||||
pattern_Lightning_GetTransactions_0 = runtime.MustPattern(runtime.NewPattern(1, []int{2, 0, 2, 1}, []string{"v1", "transactions"}, ""))
|
pattern_Lightning_GetTransactions_0 = runtime.MustPattern(runtime.NewPattern(1, []int{2, 0, 2, 1}, []string{"v1", "transactions"}, ""))
|
||||||
|
|
||||||
|
pattern_Lightning_EstimateFee_0 = runtime.MustPattern(runtime.NewPattern(1, []int{2, 0, 2, 1, 2, 2}, []string{"v1", "transactions", "fee"}, ""))
|
||||||
|
|
||||||
pattern_Lightning_SendCoins_0 = runtime.MustPattern(runtime.NewPattern(1, []int{2, 0, 2, 1}, []string{"v1", "transactions"}, ""))
|
pattern_Lightning_SendCoins_0 = runtime.MustPattern(runtime.NewPattern(1, []int{2, 0, 2, 1}, []string{"v1", "transactions"}, ""))
|
||||||
|
|
||||||
pattern_Lightning_ListUnspent_0 = runtime.MustPattern(runtime.NewPattern(1, []int{2, 0, 2, 1}, []string{"v1", "utxos"}, ""))
|
pattern_Lightning_ListUnspent_0 = runtime.MustPattern(runtime.NewPattern(1, []int{2, 0, 2, 1}, []string{"v1", "utxos"}, ""))
|
||||||
@@ -2016,6 +2064,8 @@ var (
|
|||||||
|
|
||||||
forward_Lightning_GetTransactions_0 = runtime.ForwardResponseMessage
|
forward_Lightning_GetTransactions_0 = runtime.ForwardResponseMessage
|
||||||
|
|
||||||
|
forward_Lightning_EstimateFee_0 = runtime.ForwardResponseMessage
|
||||||
|
|
||||||
forward_Lightning_SendCoins_0 = runtime.ForwardResponseMessage
|
forward_Lightning_SendCoins_0 = runtime.ForwardResponseMessage
|
||||||
|
|
||||||
forward_Lightning_ListUnspent_0 = runtime.ForwardResponseMessage
|
forward_Lightning_ListUnspent_0 = runtime.ForwardResponseMessage
|
||||||
|
|||||||
@@ -220,6 +220,16 @@ service Lightning {
|
|||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/** lncli: `estimatefee`
|
||||||
|
EstimateFee asks the chain backend to estimate the fee rate and total fees
|
||||||
|
for a transaction that pays to multiple specified outputs.
|
||||||
|
*/
|
||||||
|
rpc EstimateFee (EstimateFeeRequest) returns (EstimateFeeResponse) {
|
||||||
|
option (google.api.http) = {
|
||||||
|
get: "/v1/transactions/fee"
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
/** lncli: `sendcoins`
|
/** lncli: `sendcoins`
|
||||||
SendCoins executes a request to send coins to a particular address. Unlike
|
SendCoins executes a request to send coins to a particular address. Unlike
|
||||||
SendMany, this RPC call only allows creating a single output at a time. If
|
SendMany, this RPC call only allows creating a single output at a time. If
|
||||||
@@ -839,6 +849,22 @@ message LightningAddress {
|
|||||||
string host = 2 [json_name = "host"];
|
string host = 2 [json_name = "host"];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
message EstimateFeeRequest {
|
||||||
|
/// The map from addresses to amounts for the transaction.
|
||||||
|
map<string, int64> AddrToAmount = 1;
|
||||||
|
|
||||||
|
/// The target number of blocks that this transaction should be confirmed by.
|
||||||
|
int32 target_conf = 2;
|
||||||
|
}
|
||||||
|
|
||||||
|
message EstimateFeeResponse {
|
||||||
|
/// The total fee in satoshis.
|
||||||
|
int64 fee_sat = 1 [json_name = "fee_sat"];
|
||||||
|
|
||||||
|
/// The fee rate in satoshi/byte.
|
||||||
|
int64 feerate_sat_per_byte = 2 [json_name = "feerate_sat_per_byte"];
|
||||||
|
}
|
||||||
|
|
||||||
message SendManyRequest {
|
message SendManyRequest {
|
||||||
/// The map from addresses to amounts
|
/// The map from addresses to amounts
|
||||||
map<string, int64> AddrToAmount = 1;
|
map<string, int64> AddrToAmount = 1;
|
||||||
|
|||||||
@@ -1044,6 +1044,33 @@
|
|||||||
]
|
]
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"/v1/transactions/fee": {
|
||||||
|
"get": {
|
||||||
|
"summary": "* lncli: `estimatefee`\nEstimateFee asks the chain backend to estimate the fee rate and total fees\nfor a transaction that pays to multiple specified outputs.",
|
||||||
|
"operationId": "EstimateFee",
|
||||||
|
"responses": {
|
||||||
|
"200": {
|
||||||
|
"description": "",
|
||||||
|
"schema": {
|
||||||
|
"$ref": "#/definitions/lnrpcEstimateFeeResponse"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"parameters": [
|
||||||
|
{
|
||||||
|
"name": "target_conf",
|
||||||
|
"description": "/ The target number of blocks that this transaction should be confirmed by.",
|
||||||
|
"in": "query",
|
||||||
|
"required": false,
|
||||||
|
"type": "integer",
|
||||||
|
"format": "int32"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"tags": [
|
||||||
|
"Lightning"
|
||||||
|
]
|
||||||
|
}
|
||||||
|
},
|
||||||
"/v1/unlockwallet": {
|
"/v1/unlockwallet": {
|
||||||
"post": {
|
"post": {
|
||||||
"summary": "* lncli: `unlock`\nUnlockWallet is used at startup of lnd to provide a password to unlock\nthe wallet database.",
|
"summary": "* lncli: `unlock`\nUnlockWallet is used at startup of lnd to provide a password to unlock\nthe wallet database.",
|
||||||
@@ -1747,6 +1774,21 @@
|
|||||||
"lnrpcDisconnectPeerResponse": {
|
"lnrpcDisconnectPeerResponse": {
|
||||||
"type": "object"
|
"type": "object"
|
||||||
},
|
},
|
||||||
|
"lnrpcEstimateFeeResponse": {
|
||||||
|
"type": "object",
|
||||||
|
"properties": {
|
||||||
|
"fee_sat": {
|
||||||
|
"type": "string",
|
||||||
|
"format": "int64",
|
||||||
|
"description": "/ The total fee in satoshis."
|
||||||
|
},
|
||||||
|
"feerate_sat_per_byte": {
|
||||||
|
"type": "string",
|
||||||
|
"format": "int64",
|
||||||
|
"description": "/ The fee rate in satoshi/byte."
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
"lnrpcFeeLimit": {
|
"lnrpcFeeLimit": {
|
||||||
"type": "object",
|
"type": "object",
|
||||||
"properties": {
|
"properties": {
|
||||||
|
|||||||
@@ -25,6 +25,7 @@ import (
|
|||||||
"github.com/btcsuite/btcd/wire"
|
"github.com/btcsuite/btcd/wire"
|
||||||
"github.com/btcsuite/btcutil"
|
"github.com/btcsuite/btcutil"
|
||||||
"github.com/btcsuite/btcwallet/waddrmgr"
|
"github.com/btcsuite/btcwallet/waddrmgr"
|
||||||
|
"github.com/btcsuite/btcwallet/wallet/txauthor"
|
||||||
"github.com/coreos/bbolt"
|
"github.com/coreos/bbolt"
|
||||||
"github.com/davecgh/go-spew/spew"
|
"github.com/davecgh/go-spew/spew"
|
||||||
proxy "github.com/grpc-ecosystem/grpc-gateway/runtime"
|
proxy "github.com/grpc-ecosystem/grpc-gateway/runtime"
|
||||||
@@ -236,6 +237,10 @@ var (
|
|||||||
Entity: "onchain",
|
Entity: "onchain",
|
||||||
Action: "read",
|
Action: "read",
|
||||||
}},
|
}},
|
||||||
|
"/lnrpc.Lightning/EstimateFee": {{
|
||||||
|
Entity: "onchain",
|
||||||
|
Action: "read",
|
||||||
|
}},
|
||||||
"/lnrpc.Lightning/ChannelBalance": {{
|
"/lnrpc.Lightning/ChannelBalance": {{
|
||||||
Entity: "offchain",
|
Entity: "offchain",
|
||||||
Action: "read",
|
Action: "read",
|
||||||
@@ -800,6 +805,59 @@ func (r *rpcServer) ListUnspent(ctx context.Context,
|
|||||||
return resp, nil
|
return resp, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// EstimateFee handles a request for estimating the fee for sending a
|
||||||
|
// transaction spending to multiple specified outputs in parallel.
|
||||||
|
func (r *rpcServer) EstimateFee(ctx context.Context,
|
||||||
|
in *lnrpc.EstimateFeeRequest) (*lnrpc.EstimateFeeResponse, error) {
|
||||||
|
|
||||||
|
// Create the list of outputs we are spending to.
|
||||||
|
outputs, err := addrPairsToOutputs(in.AddrToAmount)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
// Query the fee estimator for the fee rate for the given confirmation
|
||||||
|
// target.
|
||||||
|
target := in.TargetConf
|
||||||
|
feePerKw, err := sweep.DetermineFeePerKw(
|
||||||
|
r.server.cc.feeEstimator, sweep.FeePreference{
|
||||||
|
ConfTarget: uint32(target),
|
||||||
|
},
|
||||||
|
)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
// We will ask the wallet to create a tx using this fee rate. We set
|
||||||
|
// dryRun=true to avoid inflating the change addresses in the db.
|
||||||
|
var tx *txauthor.AuthoredTx
|
||||||
|
wallet := r.server.cc.wallet
|
||||||
|
err = wallet.WithCoinSelectLock(func() error {
|
||||||
|
tx, err = wallet.CreateSimpleTx(outputs, feePerKw, true)
|
||||||
|
return err
|
||||||
|
})
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
// Use the created tx to calculate the total fee.
|
||||||
|
totalOutput := int64(0)
|
||||||
|
for _, out := range tx.Tx.TxOut {
|
||||||
|
totalOutput += out.Value
|
||||||
|
}
|
||||||
|
totalFee := int64(tx.TotalInput) - totalOutput
|
||||||
|
|
||||||
|
resp := &lnrpc.EstimateFeeResponse{
|
||||||
|
FeeSat: totalFee,
|
||||||
|
FeerateSatPerByte: int64(feePerKw.FeePerKVByte() / 1000),
|
||||||
|
}
|
||||||
|
|
||||||
|
rpcsLog.Debugf("[estimatefee] fee estimate for conf target %d: %v",
|
||||||
|
target, resp)
|
||||||
|
|
||||||
|
return resp, nil
|
||||||
|
}
|
||||||
|
|
||||||
// SendCoins executes a request to send coins to a particular address. Unlike
|
// SendCoins executes a request to send coins to a particular address. Unlike
|
||||||
// SendMany, this RPC call only allows creating a single output at a time.
|
// SendMany, this RPC call only allows creating a single output at a time.
|
||||||
func (r *rpcServer) SendCoins(ctx context.Context,
|
func (r *rpcServer) SendCoins(ctx context.Context,
|
||||||
|
|||||||
Reference in new issue
Block a user