mirror of
https://github.com/aljazceru/lightning.git
synced 2026-02-10 08:34:19 +01:00
lightningd: clean up feerate handling, deprecate old terms.
Drop try_get_feerate() in favor of explicit feerate_for_deadline() and smoothed_feerate_for_deadline(). This shows us everywhere we deal with old-style feerates by names. `delayed_to_us` and `htlc_resolution` will be moving to dynamic fees, so deprecate those. Note that "penalty" is still used for generating penalty txs for watchtowers, and "unilateral_close" still used until we get zero-fee anchors. Changelog-Added: JSON-RPC: `feerates` `estimates` array shows fee estimates by blockcount from underlying plugin (usually *bcli*). Changelog-Changed: JSON-RPC: `close`, `fundchannel`, `fundpsbt`, `multifundchannel`, `multiwithdraw`, `txprepare`, `upgradewallet`, `withdraw` `feerate` (`feerange` for `close`) value *slow* is now 100 block-estimate, not half of 100-block estimate. Changelog-Deprecated: JSON-RPC: `close`, `fundchannel`, `fundpsbt`, `multifundchannel`, `multiwithdraw`, `txprepare`, `upgradewallet`, `withdraw` `feerate` (`feerange` for `close`) expressed as, "delayed_to_us", "htlc_resolution", "max_acceptable" or "min_acceptable". Use explicit block counts or *slow*/*normal*/*urgent*/*minimum*. Signed-off-by: Rusty Russell <rusty@rustcorp.com.au>
This commit is contained in:
48
.msggen.json
48
.msggen.json
@@ -357,6 +357,7 @@
|
||||
},
|
||||
"FeeratesPerkb": {
|
||||
"Feerates.perkb.delayed_to_us": 6,
|
||||
"Feerates.perkb.estimates[]": 9,
|
||||
"Feerates.perkb.htlc_resolution": 7,
|
||||
"Feerates.perkb.max_acceptable": 2,
|
||||
"Feerates.perkb.min_acceptable": 1,
|
||||
@@ -365,8 +366,14 @@
|
||||
"Feerates.perkb.penalty": 8,
|
||||
"Feerates.perkb.unilateral_close": 5
|
||||
},
|
||||
"FeeratesPerkbEstimates": {
|
||||
"Feerates.perkb.estimates[].blockcount": 1,
|
||||
"Feerates.perkb.estimates[].feerate": 2,
|
||||
"Feerates.perkb.estimates[].smoothed_feerate": 3
|
||||
},
|
||||
"FeeratesPerkw": {
|
||||
"Feerates.perkw.delayed_to_us": 6,
|
||||
"Feerates.perkw.estimates[]": 9,
|
||||
"Feerates.perkw.htlc_resolution": 7,
|
||||
"Feerates.perkw.max_acceptable": 2,
|
||||
"Feerates.perkw.min_acceptable": 1,
|
||||
@@ -375,6 +382,11 @@
|
||||
"Feerates.perkw.penalty": 8,
|
||||
"Feerates.perkw.unilateral_close": 5
|
||||
},
|
||||
"FeeratesPerkwEstimates": {
|
||||
"Feerates.perkw.estimates[].blockcount": 1,
|
||||
"Feerates.perkw.estimates[].feerate": 2,
|
||||
"Feerates.perkw.estimates[].smoothed_feerate": 3
|
||||
},
|
||||
"FeeratesRequest": {
|
||||
"Feerates.style": 1
|
||||
},
|
||||
@@ -1542,11 +1554,27 @@
|
||||
},
|
||||
"Feerates.perkb.delayed_to_us": {
|
||||
"added": "pre-v0.10.1",
|
||||
"deprecated": "v23.05"
|
||||
},
|
||||
"Feerates.perkb.estimates[]": {
|
||||
"added": "v23.05",
|
||||
"deprecated": false
|
||||
},
|
||||
"Feerates.perkb.estimates[].blockcount": {
|
||||
"added": "v23.05",
|
||||
"deprecated": false
|
||||
},
|
||||
"Feerates.perkb.estimates[].feerate": {
|
||||
"added": "v23.05",
|
||||
"deprecated": false
|
||||
},
|
||||
"Feerates.perkb.estimates[].smoothed_feerate": {
|
||||
"added": "v23.05",
|
||||
"deprecated": false
|
||||
},
|
||||
"Feerates.perkb.htlc_resolution": {
|
||||
"added": "pre-v0.10.1",
|
||||
"deprecated": false
|
||||
"deprecated": "v23.05"
|
||||
},
|
||||
"Feerates.perkb.max_acceptable": {
|
||||
"added": "pre-v0.10.1",
|
||||
@@ -1578,11 +1606,27 @@
|
||||
},
|
||||
"Feerates.perkw.delayed_to_us": {
|
||||
"added": "pre-v0.10.1",
|
||||
"deprecated": "v23.05"
|
||||
},
|
||||
"Feerates.perkw.estimates[]": {
|
||||
"added": "v23.05",
|
||||
"deprecated": false
|
||||
},
|
||||
"Feerates.perkw.estimates[].blockcount": {
|
||||
"added": "v23.05",
|
||||
"deprecated": false
|
||||
},
|
||||
"Feerates.perkw.estimates[].feerate": {
|
||||
"added": "v23.05",
|
||||
"deprecated": false
|
||||
},
|
||||
"Feerates.perkw.estimates[].smoothed_feerate": {
|
||||
"added": "v23.05",
|
||||
"deprecated": false
|
||||
},
|
||||
"Feerates.perkw.htlc_resolution": {
|
||||
"added": "pre-v0.10.1",
|
||||
"deprecated": false
|
||||
"deprecated": "v23.05"
|
||||
},
|
||||
"Feerates.perkw.max_acceptable": {
|
||||
"added": "pre-v0.10.1",
|
||||
|
||||
14
cln-grpc/proto/node.proto
generated
14
cln-grpc/proto/node.proto
generated
@@ -1130,6 +1130,7 @@ message FeeratesResponse {
|
||||
message FeeratesPerkb {
|
||||
uint32 min_acceptable = 1;
|
||||
uint32 max_acceptable = 2;
|
||||
repeated FeeratesPerkbEstimates estimates = 9;
|
||||
optional uint32 opening = 3;
|
||||
optional uint32 mutual_close = 4;
|
||||
optional uint32 unilateral_close = 5;
|
||||
@@ -1138,9 +1139,16 @@ message FeeratesPerkb {
|
||||
optional uint32 penalty = 8;
|
||||
}
|
||||
|
||||
message FeeratesPerkbEstimates {
|
||||
optional uint32 blockcount = 1;
|
||||
optional uint32 feerate = 2;
|
||||
optional uint32 smoothed_feerate = 3;
|
||||
}
|
||||
|
||||
message FeeratesPerkw {
|
||||
uint32 min_acceptable = 1;
|
||||
uint32 max_acceptable = 2;
|
||||
repeated FeeratesPerkwEstimates estimates = 9;
|
||||
optional uint32 opening = 3;
|
||||
optional uint32 mutual_close = 4;
|
||||
optional uint32 unilateral_close = 5;
|
||||
@@ -1149,6 +1157,12 @@ message FeeratesPerkw {
|
||||
optional uint32 penalty = 8;
|
||||
}
|
||||
|
||||
message FeeratesPerkwEstimates {
|
||||
optional uint32 blockcount = 1;
|
||||
optional uint32 feerate = 2;
|
||||
optional uint32 smoothed_feerate = 3;
|
||||
}
|
||||
|
||||
message FeeratesOnchain_fee_estimates {
|
||||
uint64 opening_channel_satoshis = 1;
|
||||
uint64 mutual_close_satoshis = 2;
|
||||
|
||||
52
cln-grpc/src/convert.rs
generated
52
cln-grpc/src/convert.rs
generated
@@ -915,32 +915,60 @@ impl From<responses::DisconnectResponse> for pb::DisconnectResponse {
|
||||
}
|
||||
}
|
||||
|
||||
#[allow(unused_variables,deprecated)]
|
||||
impl From<responses::FeeratesPerkbEstimates> for pb::FeeratesPerkbEstimates {
|
||||
fn from(c: responses::FeeratesPerkbEstimates) -> Self {
|
||||
Self {
|
||||
blockcount: c.blockcount, // Rule #2 for type u32?
|
||||
feerate: c.feerate, // Rule #2 for type u32?
|
||||
smoothed_feerate: c.smoothed_feerate, // Rule #2 for type u32?
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[allow(unused_variables,deprecated)]
|
||||
impl From<responses::FeeratesPerkb> for pb::FeeratesPerkb {
|
||||
fn from(c: responses::FeeratesPerkb) -> Self {
|
||||
Self {
|
||||
min_acceptable: c.min_acceptable, // Rule #2 for type u32
|
||||
max_acceptable: c.max_acceptable, // Rule #2 for type u32
|
||||
estimates: c.estimates.map(|arr| arr.into_iter().map(|i| i.into()).collect()).unwrap_or(vec![]), // Rule #3
|
||||
opening: c.opening, // Rule #2 for type u32?
|
||||
mutual_close: c.mutual_close, // Rule #2 for type u32?
|
||||
unilateral_close: c.unilateral_close, // Rule #2 for type u32?
|
||||
#[allow(deprecated)]
|
||||
delayed_to_us: c.delayed_to_us, // Rule #2 for type u32?
|
||||
#[allow(deprecated)]
|
||||
htlc_resolution: c.htlc_resolution, // Rule #2 for type u32?
|
||||
penalty: c.penalty, // Rule #2 for type u32?
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[allow(unused_variables,deprecated)]
|
||||
impl From<responses::FeeratesPerkwEstimates> for pb::FeeratesPerkwEstimates {
|
||||
fn from(c: responses::FeeratesPerkwEstimates) -> Self {
|
||||
Self {
|
||||
blockcount: c.blockcount, // Rule #2 for type u32?
|
||||
feerate: c.feerate, // Rule #2 for type u32?
|
||||
smoothed_feerate: c.smoothed_feerate, // Rule #2 for type u32?
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[allow(unused_variables,deprecated)]
|
||||
impl From<responses::FeeratesPerkw> for pb::FeeratesPerkw {
|
||||
fn from(c: responses::FeeratesPerkw) -> Self {
|
||||
Self {
|
||||
min_acceptable: c.min_acceptable, // Rule #2 for type u32
|
||||
max_acceptable: c.max_acceptable, // Rule #2 for type u32
|
||||
estimates: c.estimates.map(|arr| arr.into_iter().map(|i| i.into()).collect()).unwrap_or(vec![]), // Rule #3
|
||||
opening: c.opening, // Rule #2 for type u32?
|
||||
mutual_close: c.mutual_close, // Rule #2 for type u32?
|
||||
unilateral_close: c.unilateral_close, // Rule #2 for type u32?
|
||||
#[allow(deprecated)]
|
||||
delayed_to_us: c.delayed_to_us, // Rule #2 for type u32?
|
||||
#[allow(deprecated)]
|
||||
htlc_resolution: c.htlc_resolution, // Rule #2 for type u32?
|
||||
penalty: c.penalty, // Rule #2 for type u32?
|
||||
}
|
||||
@@ -3252,12 +3280,24 @@ impl From<pb::DisconnectResponse> for responses::DisconnectResponse {
|
||||
}
|
||||
}
|
||||
|
||||
#[allow(unused_variables,deprecated)]
|
||||
impl From<pb::FeeratesPerkbEstimates> for responses::FeeratesPerkbEstimates {
|
||||
fn from(c: pb::FeeratesPerkbEstimates) -> Self {
|
||||
Self {
|
||||
blockcount: c.blockcount, // Rule #1 for type u32?
|
||||
feerate: c.feerate, // Rule #1 for type u32?
|
||||
smoothed_feerate: c.smoothed_feerate, // Rule #1 for type u32?
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[allow(unused_variables,deprecated)]
|
||||
impl From<pb::FeeratesPerkb> for responses::FeeratesPerkb {
|
||||
fn from(c: pb::FeeratesPerkb) -> Self {
|
||||
Self {
|
||||
min_acceptable: c.min_acceptable, // Rule #1 for type u32
|
||||
max_acceptable: c.max_acceptable, // Rule #1 for type u32
|
||||
estimates: Some(c.estimates.into_iter().map(|s| s.into()).collect()), // Rule #4
|
||||
opening: c.opening, // Rule #1 for type u32?
|
||||
mutual_close: c.mutual_close, // Rule #1 for type u32?
|
||||
unilateral_close: c.unilateral_close, // Rule #1 for type u32?
|
||||
@@ -3268,12 +3308,24 @@ impl From<pb::FeeratesPerkb> for responses::FeeratesPerkb {
|
||||
}
|
||||
}
|
||||
|
||||
#[allow(unused_variables,deprecated)]
|
||||
impl From<pb::FeeratesPerkwEstimates> for responses::FeeratesPerkwEstimates {
|
||||
fn from(c: pb::FeeratesPerkwEstimates) -> Self {
|
||||
Self {
|
||||
blockcount: c.blockcount, // Rule #1 for type u32?
|
||||
feerate: c.feerate, // Rule #1 for type u32?
|
||||
smoothed_feerate: c.smoothed_feerate, // Rule #1 for type u32?
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[allow(unused_variables,deprecated)]
|
||||
impl From<pb::FeeratesPerkw> for responses::FeeratesPerkw {
|
||||
fn from(c: pb::FeeratesPerkw) -> Self {
|
||||
Self {
|
||||
min_acceptable: c.min_acceptable, // Rule #1 for type u32
|
||||
max_acceptable: c.max_acceptable, // Rule #1 for type u32
|
||||
estimates: Some(c.estimates.into_iter().map(|s| s.into()).collect()), // Rule #4
|
||||
opening: c.opening, // Rule #1 for type u32?
|
||||
mutual_close: c.mutual_close, // Rule #1 for type u32?
|
||||
unilateral_close: c.unilateral_close, // Rule #1 for type u32?
|
||||
|
||||
28
cln-rpc/src/model.rs
generated
28
cln-rpc/src/model.rs
generated
@@ -3217,36 +3217,64 @@ pub mod responses {
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug, Deserialize, Serialize)]
|
||||
pub struct FeeratesPerkbEstimates {
|
||||
#[serde(skip_serializing_if = "Option::is_none")]
|
||||
pub blockcount: Option<u32>,
|
||||
#[serde(skip_serializing_if = "Option::is_none")]
|
||||
pub feerate: Option<u32>,
|
||||
#[serde(skip_serializing_if = "Option::is_none")]
|
||||
pub smoothed_feerate: Option<u32>,
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug, Deserialize, Serialize)]
|
||||
pub struct FeeratesPerkb {
|
||||
pub min_acceptable: u32,
|
||||
pub max_acceptable: u32,
|
||||
#[serde(skip_serializing_if = "crate::is_none_or_empty")]
|
||||
pub estimates: Option<Vec<FeeratesPerkbEstimates>>,
|
||||
#[serde(skip_serializing_if = "Option::is_none")]
|
||||
pub opening: Option<u32>,
|
||||
#[serde(skip_serializing_if = "Option::is_none")]
|
||||
pub mutual_close: Option<u32>,
|
||||
#[serde(skip_serializing_if = "Option::is_none")]
|
||||
pub unilateral_close: Option<u32>,
|
||||
#[deprecated]
|
||||
#[serde(skip_serializing_if = "Option::is_none")]
|
||||
pub delayed_to_us: Option<u32>,
|
||||
#[deprecated]
|
||||
#[serde(skip_serializing_if = "Option::is_none")]
|
||||
pub htlc_resolution: Option<u32>,
|
||||
#[serde(skip_serializing_if = "Option::is_none")]
|
||||
pub penalty: Option<u32>,
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug, Deserialize, Serialize)]
|
||||
pub struct FeeratesPerkwEstimates {
|
||||
#[serde(skip_serializing_if = "Option::is_none")]
|
||||
pub blockcount: Option<u32>,
|
||||
#[serde(skip_serializing_if = "Option::is_none")]
|
||||
pub feerate: Option<u32>,
|
||||
#[serde(skip_serializing_if = "Option::is_none")]
|
||||
pub smoothed_feerate: Option<u32>,
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug, Deserialize, Serialize)]
|
||||
pub struct FeeratesPerkw {
|
||||
pub min_acceptable: u32,
|
||||
pub max_acceptable: u32,
|
||||
#[serde(skip_serializing_if = "crate::is_none_or_empty")]
|
||||
pub estimates: Option<Vec<FeeratesPerkwEstimates>>,
|
||||
#[serde(skip_serializing_if = "Option::is_none")]
|
||||
pub opening: Option<u32>,
|
||||
#[serde(skip_serializing_if = "Option::is_none")]
|
||||
pub mutual_close: Option<u32>,
|
||||
#[serde(skip_serializing_if = "Option::is_none")]
|
||||
pub unilateral_close: Option<u32>,
|
||||
#[deprecated]
|
||||
#[serde(skip_serializing_if = "Option::is_none")]
|
||||
pub delayed_to_us: Option<u32>,
|
||||
#[deprecated]
|
||||
#[serde(skip_serializing_if = "Option::is_none")]
|
||||
pub htlc_resolution: Option<u32>,
|
||||
#[serde(skip_serializing_if = "Option::is_none")]
|
||||
|
||||
@@ -71,6 +71,7 @@ enum jsonrpc_errcode {
|
||||
|
||||
/* bitcoin-cli plugin errors */
|
||||
BCLI_ERROR = 500,
|
||||
BCLI_NO_FEE_ESTIMATES = 501,
|
||||
|
||||
/* Errors from `invoice` or `delinvoice` commands */
|
||||
INVOICE_LABEL_ALREADY_EXISTS = 900,
|
||||
|
||||
@@ -729,10 +729,19 @@ def disconnect2py(m):
|
||||
})
|
||||
|
||||
|
||||
def feerates_perkb_estimates2py(m):
|
||||
return remove_default({
|
||||
"blockcount": m.blockcount, # PrimitiveField in generate_composite
|
||||
"feerate": m.feerate, # PrimitiveField in generate_composite
|
||||
"smoothed_feerate": m.smoothed_feerate, # PrimitiveField in generate_composite
|
||||
})
|
||||
|
||||
|
||||
def feerates_perkb2py(m):
|
||||
return remove_default({
|
||||
"min_acceptable": m.min_acceptable, # PrimitiveField in generate_composite
|
||||
"max_acceptable": m.max_acceptable, # PrimitiveField in generate_composite
|
||||
"estimates": [feerates_perkb_estimates2py(i) for i in m.estimates], # ArrayField[composite] in generate_composite
|
||||
"opening": m.opening, # PrimitiveField in generate_composite
|
||||
"mutual_close": m.mutual_close, # PrimitiveField in generate_composite
|
||||
"unilateral_close": m.unilateral_close, # PrimitiveField in generate_composite
|
||||
@@ -742,10 +751,19 @@ def feerates_perkb2py(m):
|
||||
})
|
||||
|
||||
|
||||
def feerates_perkw_estimates2py(m):
|
||||
return remove_default({
|
||||
"blockcount": m.blockcount, # PrimitiveField in generate_composite
|
||||
"feerate": m.feerate, # PrimitiveField in generate_composite
|
||||
"smoothed_feerate": m.smoothed_feerate, # PrimitiveField in generate_composite
|
||||
})
|
||||
|
||||
|
||||
def feerates_perkw2py(m):
|
||||
return remove_default({
|
||||
"min_acceptable": m.min_acceptable, # PrimitiveField in generate_composite
|
||||
"max_acceptable": m.max_acceptable, # PrimitiveField in generate_composite
|
||||
"estimates": [feerates_perkw_estimates2py(i) for i in m.estimates], # ArrayField[composite] in generate_composite
|
||||
"opening": m.opening, # PrimitiveField in generate_composite
|
||||
"mutual_close": m.mutual_close, # PrimitiveField in generate_composite
|
||||
"unilateral_close": m.unilateral_close, # PrimitiveField in generate_composite
|
||||
|
||||
@@ -50,25 +50,33 @@ On success, an object is returned, containing:
|
||||
- **perkb** (object, optional): If *style* parameter was perkb:
|
||||
- **min\_acceptable** (u32): The smallest feerate that we allow peers to specify: half the 100-block estimate
|
||||
- **max\_acceptable** (u32): The largest feerate we will accept from remote negotiations. If a peer attempts to set the feerate higher than this we will unilaterally close the channel (or simply forget it if it's not open yet).
|
||||
- **estimates** (array of objects): Feerate estimates from plugin which we are using (usuallly bcli) *(added v23.05)*:
|
||||
- **blockcount** (u32): The number of blocks the feerate is expected to get a transaction in *(added v23.05)*
|
||||
- **feerate** (u32): The feerate for this estimate, in given *style* *(added v23.05)*
|
||||
- **smoothed\_feerate** (u32): The feerate, smoothed over time (useful for coordinating with other nodes) *(added v23.05)*
|
||||
- **opening** (u32, optional): Default feerate for lightning-fundchannel(7) and lightning-withdraw(7)
|
||||
- **mutual\_close** (u32, optional): Feerate to aim for in cooperative shutdown. Note that since mutual close is a **negotiation**, the actual feerate used in mutual close will be somewhere between this and the corresponding mutual close feerate of the peer.
|
||||
- **unilateral\_close** (u32, optional): Feerate for commitment\_transaction in a live channel which we originally funded
|
||||
- **delayed\_to\_us** (u32, optional): Feerate for returning unilateral close funds to our wallet
|
||||
- **htlc\_resolution** (u32, optional): Feerate for returning unilateral close HTLC outputs to our wallet
|
||||
- **penalty** (u32, optional): Feerate to start at when penalizing a cheat attempt
|
||||
- **delayed\_to\_us** (u32, optional): Feerate for returning unilateral close funds to our wallet **deprecated, removal in v24.02**
|
||||
- **htlc\_resolution** (u32, optional): Feerate for returning unilateral close HTLC outputs to our wallet **deprecated, removal in v24.02**
|
||||
- **penalty** (u32, optional): Feerate to use when creating penalty tx for watchtowers
|
||||
- **perkw** (object, optional): If *style* parameter was perkw:
|
||||
- **min\_acceptable** (u32): The smallest feerate that you can use, usually the minimum relayed feerate of the backend
|
||||
- **max\_acceptable** (u32): The largest feerate we will accept from remote negotiations. If a peer attempts to set the feerate higher than this we will unilaterally close the channel (or simply forget it if it's not open yet).
|
||||
- **estimates** (array of objects): Feerate estimates from plugin which we are using (usuallly bcli) *(added v23.05)*:
|
||||
- **blockcount** (u32): The number of blocks the feerate is expected to get a transaction in *(added v23.05)*
|
||||
- **feerate** (u32): The feerate for this estimate, in given *style* *(added v23.05)*
|
||||
- **smoothed\_feerate** (u32): The feerate, smoothed over time (useful for coordinating with other nodes) *(added v23.05)*
|
||||
- **opening** (u32, optional): Default feerate for lightning-fundchannel(7) and lightning-withdraw(7)
|
||||
- **mutual\_close** (u32, optional): Feerate to aim for in cooperative shutdown. Note that since mutual close is a **negotiation**, the actual feerate used in mutual close will be somewhere between this and the corresponding mutual close feerate of the peer.
|
||||
- **unilateral\_close** (u32, optional): Feerate for commitment\_transaction in a live channel which we originally funded
|
||||
- **delayed\_to\_us** (u32, optional): Feerate for returning unilateral close funds to our wallet
|
||||
- **htlc\_resolution** (u32, optional): Feerate for returning unilateral close HTLC outputs to our wallet
|
||||
- **penalty** (u32, optional): Feerate to start at when penalizing a cheat attempt
|
||||
- **delayed\_to\_us** (u32, optional): Feerate for returning unilateral close funds to our wallet **deprecated, removal in v24.02**
|
||||
- **htlc\_resolution** (u32, optional): Feerate for returning unilateral close HTLC outputs to our wallet **deprecated, removal in v24.02**
|
||||
- **penalty** (u32, optional): Feerate to use when creating penalty tx for watchtowers
|
||||
- **onchain\_fee\_estimates** (object, optional):
|
||||
- **opening\_channel\_satoshis** (u64): Estimated cost of typical channel open
|
||||
- **mutual\_close\_satoshis** (u64): Estimated cost of typical channel close
|
||||
- **unilateral\_close\_satoshis** (u64): Estimated cost of typical unilateral close (without HTLCs)
|
||||
- **unilateral\_close\_satoshis** (u64): Estimated cost of typical (non-anchor) unilateral close (without HTLCs)
|
||||
- **htlc\_timeout\_satoshis** (u64): Estimated cost of typical HTLC timeout transaction
|
||||
- **htlc\_success\_satoshis** (u64): Estimated cost of typical HTLC fulfillment transaction
|
||||
|
||||
@@ -121,4 +129,4 @@ RESOURCES
|
||||
|
||||
Main web site: <https://github.com/ElementsProject/lightning>
|
||||
|
||||
[comment]: # ( SHA256STAMP:773e4e66cb3654b7c3aafe54c33d433c52ff89f7a5a8be0a71a93da21a6b7eaa)
|
||||
[comment]: # ( SHA256STAMP:c21d903c29fd6195d5890962eaa3265a26a57885b95714696916bd32168b66bc)
|
||||
|
||||
@@ -14,7 +14,8 @@
|
||||
"additionalProperties": false,
|
||||
"required": [
|
||||
"min_acceptable",
|
||||
"max_acceptable"
|
||||
"max_acceptable",
|
||||
"estimates"
|
||||
],
|
||||
"properties": {
|
||||
"min_acceptable": {
|
||||
@@ -25,6 +26,37 @@
|
||||
"type": "u32",
|
||||
"description": "The largest feerate we will accept from remote negotiations. If a peer attempts to set the feerate higher than this we will unilaterally close the channel (or simply forget it if it's not open yet)."
|
||||
},
|
||||
"estimates": {
|
||||
"type": "array",
|
||||
"added": "v23.05",
|
||||
"description": "Feerate estimates from plugin which we are using (usuallly bcli)",
|
||||
"items": {
|
||||
"type": "object",
|
||||
"additionalProperties": false,
|
||||
"required": [
|
||||
"blockcount",
|
||||
"feerate",
|
||||
"smoothed_feerate"
|
||||
],
|
||||
"properties": {
|
||||
"blockcount": {
|
||||
"type": "u32",
|
||||
"added": "v23.05",
|
||||
"description": "The number of blocks the feerate is expected to get a transaction in"
|
||||
},
|
||||
"feerate": {
|
||||
"type": "u32",
|
||||
"added": "v23.05",
|
||||
"description": "The feerate for this estimate, in given *style*"
|
||||
},
|
||||
"smoothed_feerate": {
|
||||
"type": "u32",
|
||||
"added": "v23.05",
|
||||
"description": "The feerate, smoothed over time (useful for coordinating with other nodes)"
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"opening": {
|
||||
"type": "u32",
|
||||
"description": "Default feerate for lightning-fundchannel(7) and lightning-withdraw(7)"
|
||||
@@ -39,15 +71,17 @@
|
||||
},
|
||||
"delayed_to_us": {
|
||||
"type": "u32",
|
||||
"deprecated": "v23.05",
|
||||
"description": "Feerate for returning unilateral close funds to our wallet"
|
||||
},
|
||||
"htlc_resolution": {
|
||||
"type": "u32",
|
||||
"deprecated": "v23.05",
|
||||
"description": "Feerate for returning unilateral close HTLC outputs to our wallet"
|
||||
},
|
||||
"penalty": {
|
||||
"type": "u32",
|
||||
"description": "Feerate to start at when penalizing a cheat attempt"
|
||||
"description": "Feerate to use when creating penalty tx for watchtowers"
|
||||
}
|
||||
}
|
||||
},
|
||||
@@ -57,7 +91,8 @@
|
||||
"additionalProperties": false,
|
||||
"required": [
|
||||
"min_acceptable",
|
||||
"max_acceptable"
|
||||
"max_acceptable",
|
||||
"estimates"
|
||||
],
|
||||
"properties": {
|
||||
"min_acceptable": {
|
||||
@@ -68,6 +103,37 @@
|
||||
"type": "u32",
|
||||
"description": "The largest feerate we will accept from remote negotiations. If a peer attempts to set the feerate higher than this we will unilaterally close the channel (or simply forget it if it's not open yet)."
|
||||
},
|
||||
"estimates": {
|
||||
"type": "array",
|
||||
"added": "v23.05",
|
||||
"description": "Feerate estimates from plugin which we are using (usuallly bcli)",
|
||||
"items": {
|
||||
"type": "object",
|
||||
"additionalProperties": false,
|
||||
"required": [
|
||||
"blockcount",
|
||||
"feerate",
|
||||
"smoothed_feerate"
|
||||
],
|
||||
"properties": {
|
||||
"blockcount": {
|
||||
"type": "u32",
|
||||
"added": "v23.05",
|
||||
"description": "The number of blocks the feerate is expected to get a transaction in"
|
||||
},
|
||||
"feerate": {
|
||||
"type": "u32",
|
||||
"added": "v23.05",
|
||||
"description": "The feerate for this estimate, in given *style*"
|
||||
},
|
||||
"smoothed_feerate": {
|
||||
"type": "u32",
|
||||
"added": "v23.05",
|
||||
"description": "The feerate, smoothed over time (useful for coordinating with other nodes)"
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"opening": {
|
||||
"type": "u32",
|
||||
"description": "Default feerate for lightning-fundchannel(7) and lightning-withdraw(7)"
|
||||
@@ -82,15 +148,17 @@
|
||||
},
|
||||
"delayed_to_us": {
|
||||
"type": "u32",
|
||||
"deprecated": "v23.05",
|
||||
"description": "Feerate for returning unilateral close funds to our wallet"
|
||||
},
|
||||
"htlc_resolution": {
|
||||
"type": "u32",
|
||||
"deprecated": "v23.05",
|
||||
"description": "Feerate for returning unilateral close HTLC outputs to our wallet"
|
||||
},
|
||||
"penalty": {
|
||||
"type": "u32",
|
||||
"description": "Feerate to start at when penalizing a cheat attempt"
|
||||
"description": "Feerate to use when creating penalty tx for watchtowers"
|
||||
}
|
||||
}
|
||||
},
|
||||
@@ -115,7 +183,7 @@
|
||||
},
|
||||
"unilateral_close_satoshis": {
|
||||
"type": "u64",
|
||||
"description": "Estimated cost of typical unilateral close (without HTLCs)"
|
||||
"description": "Estimated cost of typical (non-anchor) unilateral close (without HTLCs)"
|
||||
},
|
||||
"htlc_timeout_satoshis": {
|
||||
"type": "u64",
|
||||
|
||||
@@ -5,6 +5,7 @@
|
||||
#include <ccan/array_size/array_size.h>
|
||||
#include <ccan/io/io.h>
|
||||
#include <ccan/tal/str/str.h>
|
||||
#include <common/configdir.h>
|
||||
#include <common/htlc_tx.h>
|
||||
#include <common/json_command.h>
|
||||
#include <common/json_param.h>
|
||||
@@ -545,34 +546,66 @@ static void start_fee_estimate(struct chain_topology *topo)
|
||||
bitcoind_estimate_fees(topo->bitcoind, update_feerates);
|
||||
}
|
||||
|
||||
struct rate_conversion {
|
||||
u32 blockcount;
|
||||
};
|
||||
|
||||
static struct rate_conversion conversions[] = {
|
||||
[FEERATE_OPENING] = { 12 },
|
||||
[FEERATE_MUTUAL_CLOSE] = { 100 },
|
||||
[FEERATE_UNILATERAL_CLOSE] = { 6 },
|
||||
[FEERATE_DELAYED_TO_US] = { 12 },
|
||||
[FEERATE_HTLC_RESOLUTION] = { 6 },
|
||||
[FEERATE_PENALTY] = { 12 },
|
||||
};
|
||||
|
||||
u32 opening_feerate(struct chain_topology *topo)
|
||||
{
|
||||
return try_get_feerate(topo, FEERATE_OPENING);
|
||||
if (topo->ld->force_feerates)
|
||||
return topo->ld->force_feerates[FEERATE_OPENING];
|
||||
return feerate_for_deadline(topo,
|
||||
conversions[FEERATE_OPENING].blockcount);
|
||||
}
|
||||
|
||||
u32 mutual_close_feerate(struct chain_topology *topo)
|
||||
{
|
||||
return try_get_feerate(topo, FEERATE_MUTUAL_CLOSE);
|
||||
if (topo->ld->force_feerates)
|
||||
return topo->ld->force_feerates[FEERATE_MUTUAL_CLOSE];
|
||||
return smoothed_feerate_for_deadline(topo,
|
||||
conversions[FEERATE_MUTUAL_CLOSE].blockcount);
|
||||
}
|
||||
|
||||
u32 unilateral_feerate(struct chain_topology *topo)
|
||||
{
|
||||
return try_get_feerate(topo, FEERATE_UNILATERAL_CLOSE);
|
||||
if (topo->ld->force_feerates)
|
||||
return topo->ld->force_feerates[FEERATE_UNILATERAL_CLOSE];
|
||||
return smoothed_feerate_for_deadline(topo,
|
||||
conversions[FEERATE_UNILATERAL_CLOSE].blockcount)
|
||||
* topo->ld->config.commit_fee_percent / 100;
|
||||
}
|
||||
|
||||
u32 delayed_to_us_feerate(struct chain_topology *topo)
|
||||
{
|
||||
return try_get_feerate(topo, FEERATE_DELAYED_TO_US);
|
||||
if (topo->ld->force_feerates)
|
||||
return topo->ld->force_feerates[FEERATE_DELAYED_TO_US];
|
||||
return smoothed_feerate_for_deadline(topo,
|
||||
conversions[FEERATE_DELAYED_TO_US].blockcount);
|
||||
}
|
||||
|
||||
u32 htlc_resolution_feerate(struct chain_topology *topo)
|
||||
{
|
||||
return try_get_feerate(topo, FEERATE_HTLC_RESOLUTION);
|
||||
if (topo->ld->force_feerates)
|
||||
return topo->ld->force_feerates[FEERATE_HTLC_RESOLUTION];
|
||||
return smoothed_feerate_for_deadline(topo,
|
||||
conversions[FEERATE_HTLC_RESOLUTION].blockcount);
|
||||
}
|
||||
|
||||
u32 penalty_feerate(struct chain_topology *topo)
|
||||
{
|
||||
return try_get_feerate(topo, FEERATE_PENALTY);
|
||||
if (topo->ld->force_feerates)
|
||||
return topo->ld->force_feerates[FEERATE_PENALTY];
|
||||
return smoothed_feerate_for_deadline(topo,
|
||||
conversions[FEERATE_PENALTY].blockcount);
|
||||
}
|
||||
|
||||
u32 get_feerate_floor(const struct chain_topology *topo)
|
||||
@@ -588,39 +621,68 @@ static struct command_result *json_feerates(struct command *cmd,
|
||||
{
|
||||
struct chain_topology *topo = cmd->ld->topology;
|
||||
struct json_stream *response;
|
||||
u32 feerates[NUM_FEERATES];
|
||||
bool missing;
|
||||
enum feerate_style *style;
|
||||
u32 rate;
|
||||
|
||||
if (!param(cmd, buffer, params,
|
||||
p_req("style", param_feerate_style, &style),
|
||||
NULL))
|
||||
return command_param_failed();
|
||||
|
||||
missing = false;
|
||||
for (size_t i = 0; i < ARRAY_SIZE(feerates); i++) {
|
||||
feerates[i] = try_get_feerate(topo, i);
|
||||
if (!feerates[i])
|
||||
missing = true;
|
||||
}
|
||||
missing = (tal_count(topo->feerates[0]) == 0);
|
||||
|
||||
response = json_stream_success(cmd);
|
||||
|
||||
if (missing)
|
||||
json_add_string(response, "warning_missing_feerates",
|
||||
"Some fee estimates unavailable: bitcoind startup?");
|
||||
|
||||
json_object_start(response, feerate_style_name(*style));
|
||||
for (size_t i = 0; i < ARRAY_SIZE(feerates); i++) {
|
||||
if (!feerates[i] || i == FEERATE_MIN || i == FEERATE_MAX)
|
||||
continue;
|
||||
json_add_num(response, feerate_name(i),
|
||||
feerate_to_style(feerates[i], *style));
|
||||
rate = opening_feerate(topo);
|
||||
if (rate)
|
||||
json_add_num(response, "opening", feerate_to_style(rate, *style));
|
||||
rate = mutual_close_feerate(topo);
|
||||
if (rate)
|
||||
json_add_num(response, "mutual_close",
|
||||
feerate_to_style(rate, *style));
|
||||
rate = unilateral_feerate(topo);
|
||||
if (rate)
|
||||
json_add_num(response, "unilateral_close",
|
||||
feerate_to_style(rate, *style));
|
||||
rate = penalty_feerate(topo);
|
||||
if (rate)
|
||||
json_add_num(response, "penalty",
|
||||
feerate_to_style(rate, *style));
|
||||
if (deprecated_apis) {
|
||||
rate = delayed_to_us_feerate(topo);
|
||||
if (rate)
|
||||
json_add_num(response, "delayed_to_us",
|
||||
feerate_to_style(rate, *style));
|
||||
rate = htlc_resolution_feerate(topo);
|
||||
if (rate)
|
||||
json_add_num(response, "htlc_resolution",
|
||||
feerate_to_style(rate, *style));
|
||||
}
|
||||
|
||||
json_add_u64(response, "min_acceptable",
|
||||
feerate_to_style(feerate_min(cmd->ld, NULL), *style));
|
||||
json_add_u64(response, "max_acceptable",
|
||||
feerate_to_style(feerate_max(cmd->ld, NULL), *style));
|
||||
|
||||
json_array_start(response, "estimates");
|
||||
assert(tal_count(topo->smoothed_feerates) == tal_count(topo->feerates[0]));
|
||||
for (size_t i = 0; i < tal_count(topo->feerates[0]); i++) {
|
||||
json_object_start(response, NULL);
|
||||
json_add_num(response, "blockcount",
|
||||
topo->feerates[0][i].blockcount);
|
||||
json_add_u64(response, "feerate",
|
||||
feerate_to_style(topo->feerates[0][i].rate, *style));
|
||||
json_add_u64(response, "smoothed_feerate",
|
||||
feerate_to_style(topo->smoothed_feerates[i].rate,
|
||||
*style));
|
||||
json_object_end(response);
|
||||
}
|
||||
json_array_end(response);
|
||||
json_object_end(response);
|
||||
|
||||
if (!missing) {
|
||||
@@ -998,62 +1060,9 @@ u32 get_network_blockheight(const struct chain_topology *topo)
|
||||
return topo->headercount;
|
||||
}
|
||||
|
||||
struct rate_conversion {
|
||||
u32 blockcount;
|
||||
};
|
||||
|
||||
static struct rate_conversion conversions[] = {
|
||||
[FEERATE_OPENING] = { 12 },
|
||||
[FEERATE_MUTUAL_CLOSE] = { 100 },
|
||||
[FEERATE_UNILATERAL_CLOSE] = { 6 },
|
||||
[FEERATE_DELAYED_TO_US] = { 12 },
|
||||
[FEERATE_HTLC_RESOLUTION] = { 6 },
|
||||
[FEERATE_PENALTY] = { 12 },
|
||||
};
|
||||
|
||||
u32 try_get_feerate(const struct chain_topology *topo, enum feerate feerate)
|
||||
{
|
||||
u32 val;
|
||||
|
||||
/* Max and min look over history as well. */
|
||||
if (feerate == FEERATE_MAX) {
|
||||
u32 max = 0;
|
||||
for (size_t i = 0; i < ARRAY_SIZE(topo->feerates); i++) {
|
||||
for (size_t j = 0; j < tal_count(topo->feerates[i]); j++) {
|
||||
if (topo->feerates[i][j].rate > max)
|
||||
max = topo->feerates[i][j].rate;
|
||||
}
|
||||
}
|
||||
return max * topo->ld->config.max_fee_multiplier;
|
||||
}
|
||||
|
||||
if (feerate == FEERATE_MIN) {
|
||||
u32 min = 0xFFFFFFFF;
|
||||
for (size_t i = 0; i < ARRAY_SIZE(topo->feerates); i++) {
|
||||
for (size_t j = 0; j < tal_count(topo->feerates[i]); j++) {
|
||||
if (topo->feerates[i][j].rate < min)
|
||||
min = topo->feerates[i][j].rate;
|
||||
}
|
||||
}
|
||||
if (min == 0xFFFFFFFF)
|
||||
return 0;
|
||||
/* FIXME: This is what bcli used to do: halve the slow feerate! */
|
||||
min /= 2;
|
||||
return min;
|
||||
}
|
||||
|
||||
if (topo->ld->force_feerates)
|
||||
val = topo->ld->force_feerates[feerate];
|
||||
else
|
||||
val = smoothed_feerate_for_deadline(topo, conversions[feerate].blockcount);
|
||||
if (feerate == FEERATE_UNILATERAL_CLOSE)
|
||||
val = val * topo->ld->config.commit_fee_percent / 100;
|
||||
|
||||
return val;
|
||||
}
|
||||
|
||||
u32 feerate_min(struct lightningd *ld, bool *unknown)
|
||||
{
|
||||
const struct chain_topology *topo = ld->topology;
|
||||
u32 min;
|
||||
|
||||
if (unknown)
|
||||
@@ -1063,21 +1072,32 @@ u32 feerate_min(struct lightningd *ld, bool *unknown)
|
||||
if (ld->config.ignore_fee_limits)
|
||||
min = 1;
|
||||
else {
|
||||
min = try_get_feerate(ld->topology, FEERATE_MIN);
|
||||
if (!min) {
|
||||
min = 0xFFFFFFFF;
|
||||
for (size_t i = 0; i < ARRAY_SIZE(topo->feerates); i++) {
|
||||
for (size_t j = 0; j < tal_count(topo->feerates[i]); j++) {
|
||||
if (topo->feerates[i][j].rate < min)
|
||||
min = topo->feerates[i][j].rate;
|
||||
}
|
||||
}
|
||||
if (min == 0xFFFFFFFF) {
|
||||
if (unknown)
|
||||
*unknown = true;
|
||||
min = 0;
|
||||
}
|
||||
|
||||
/* FIXME: This is what bcli used to do: halve the slow feerate! */
|
||||
min /= 2;
|
||||
}
|
||||
|
||||
if (min < get_feerate_floor(ld->topology))
|
||||
return get_feerate_floor(ld->topology);
|
||||
if (min < get_feerate_floor(topo))
|
||||
return get_feerate_floor(topo);
|
||||
return min;
|
||||
}
|
||||
|
||||
u32 feerate_max(struct lightningd *ld, bool *unknown)
|
||||
{
|
||||
u32 feerate;
|
||||
const struct chain_topology *topo = ld->topology;
|
||||
u32 max = 0;
|
||||
|
||||
if (unknown)
|
||||
*unknown = false;
|
||||
@@ -1085,14 +1105,18 @@ u32 feerate_max(struct lightningd *ld, bool *unknown)
|
||||
if (ld->config.ignore_fee_limits)
|
||||
return UINT_MAX;
|
||||
|
||||
/* If we don't know feerate, don't limit other side. */
|
||||
feerate = try_get_feerate(ld->topology, FEERATE_MAX);
|
||||
if (!feerate) {
|
||||
for (size_t i = 0; i < ARRAY_SIZE(topo->feerates); i++) {
|
||||
for (size_t j = 0; j < tal_count(topo->feerates[i]); j++) {
|
||||
if (topo->feerates[i][j].rate > max)
|
||||
max = topo->feerates[i][j].rate;
|
||||
}
|
||||
}
|
||||
if (!max) {
|
||||
if (unknown)
|
||||
*unknown = true;
|
||||
return UINT_MAX;
|
||||
}
|
||||
return feerate;
|
||||
return max * topo->ld->config.max_fee_multiplier;
|
||||
}
|
||||
|
||||
/* On shutdown, channels get deleted last. That frees from our list, so
|
||||
|
||||
@@ -181,14 +181,12 @@ u32 get_network_blockheight(const struct chain_topology *topo);
|
||||
u32 feerate_for_deadline(const struct chain_topology *topo, u32 blockcount);
|
||||
u32 smoothed_feerate_for_deadline(const struct chain_topology *topo, u32 blockcount);
|
||||
|
||||
/* Get fee rate in satoshi per kiloweight, or 0 if unavailable! */
|
||||
u32 try_get_feerate(const struct chain_topology *topo, enum feerate feerate);
|
||||
|
||||
/* Get range of feerates to insist other side abide by for normal channels.
|
||||
* If we have to guess, sets *unknown to true, otherwise false. */
|
||||
u32 feerate_min(struct lightningd *ld, bool *unknown);
|
||||
u32 feerate_max(struct lightningd *ld, bool *unknown);
|
||||
|
||||
/* These return 0 if unknown */
|
||||
u32 opening_feerate(struct chain_topology *topo);
|
||||
u32 mutual_close_feerate(struct chain_topology *topo);
|
||||
u32 unilateral_feerate(struct chain_topology *topo);
|
||||
|
||||
@@ -38,12 +38,12 @@ static void update_feerates(struct lightningd *ld, struct channel *channel)
|
||||
feerate,
|
||||
feerate_min(ld, NULL),
|
||||
feerate_max(ld, NULL),
|
||||
try_get_feerate(ld->topology, FEERATE_PENALTY));
|
||||
penalty_feerate(ld->topology));
|
||||
|
||||
msg = towire_channeld_feerates(NULL, feerate,
|
||||
feerate_min(ld, NULL),
|
||||
feerate_max(ld, NULL),
|
||||
try_get_feerate(ld->topology, FEERATE_PENALTY));
|
||||
penalty_feerate(ld->topology));
|
||||
subd_send_msg(channel->owner, take(msg));
|
||||
}
|
||||
|
||||
@@ -736,7 +736,7 @@ bool peer_start_channeld(struct channel *channel,
|
||||
channel->fee_states,
|
||||
feerate_min(ld, NULL),
|
||||
feerate_max(ld, NULL),
|
||||
try_get_feerate(ld->topology, FEERATE_PENALTY),
|
||||
penalty_feerate(ld->topology),
|
||||
&channel->last_sig,
|
||||
&channel->channel_info.remote_fundingkey,
|
||||
&channel->channel_info.theirbase,
|
||||
@@ -1146,8 +1146,7 @@ static struct command_result *json_dev_feerate(struct command *cmd,
|
||||
msg = towire_channeld_feerates(NULL, *feerate,
|
||||
feerate_min(cmd->ld, NULL),
|
||||
feerate_max(cmd->ld, NULL),
|
||||
try_get_feerate(cmd->ld->topology,
|
||||
FEERATE_PENALTY));
|
||||
penalty_feerate(cmd->ld->topology));
|
||||
subd_send_msg(channel->owner, take(msg));
|
||||
|
||||
response = json_stream_success(cmd);
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
#include "config.h"
|
||||
#include <common/configdir.h>
|
||||
#include <common/json_command.h>
|
||||
#include <lightningd/chaintopology.h>
|
||||
#include <lightningd/feerate.h>
|
||||
@@ -45,36 +46,100 @@ struct command_result *param_feerate_style(struct command *cmd,
|
||||
json_tok_full_len(tok), json_tok_full(buffer, tok));
|
||||
}
|
||||
|
||||
/* This can set **feerate to 0, if it's unknown. */
|
||||
static struct command_result *param_feerate_unchecked(struct command *cmd,
|
||||
const char *name,
|
||||
const char *buffer,
|
||||
const jsmntok_t *tok,
|
||||
u32 **feerate)
|
||||
{
|
||||
*feerate = tal(cmd, u32);
|
||||
|
||||
if (json_tok_streq(buffer, tok, "opening")) {
|
||||
**feerate = opening_feerate(cmd->ld->topology);
|
||||
return NULL;
|
||||
}
|
||||
if (json_tok_streq(buffer, tok, "mutual_close")) {
|
||||
**feerate = mutual_close_feerate(cmd->ld->topology);
|
||||
return NULL;
|
||||
}
|
||||
if (json_tok_streq(buffer, tok, "penalty")) {
|
||||
**feerate = penalty_feerate(cmd->ld->topology);
|
||||
return NULL;
|
||||
}
|
||||
if (json_tok_streq(buffer, tok, "unilateral_close")) {
|
||||
**feerate = unilateral_feerate(cmd->ld->topology);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/* Other names are deprecated */
|
||||
for (size_t i = 0; i < NUM_FEERATES; i++) {
|
||||
bool unknown;
|
||||
|
||||
if (!json_tok_streq(buffer, tok, feerate_name(i)))
|
||||
continue;
|
||||
if (!deprecated_apis)
|
||||
return command_fail_badparam(cmd, name, buffer, tok,
|
||||
"removed feerate by names");
|
||||
switch (i) {
|
||||
case FEERATE_OPENING:
|
||||
case FEERATE_MUTUAL_CLOSE:
|
||||
case FEERATE_PENALTY:
|
||||
case FEERATE_UNILATERAL_CLOSE:
|
||||
/* Handled above */
|
||||
abort();
|
||||
case FEERATE_DELAYED_TO_US:
|
||||
**feerate = delayed_to_us_feerate(cmd->ld->topology);
|
||||
return NULL;
|
||||
case FEERATE_HTLC_RESOLUTION:
|
||||
**feerate = htlc_resolution_feerate(cmd->ld->topology);
|
||||
return NULL;
|
||||
case FEERATE_MAX:
|
||||
**feerate = feerate_max(cmd->ld, &unknown);
|
||||
if (unknown)
|
||||
**feerate = 0;
|
||||
return NULL;
|
||||
case FEERATE_MIN:
|
||||
**feerate = feerate_min(cmd->ld, &unknown);
|
||||
if (unknown)
|
||||
**feerate = 0;
|
||||
return NULL;
|
||||
}
|
||||
abort();
|
||||
}
|
||||
|
||||
/* We used SLOW, NORMAL, and URGENT as feerate targets previously,
|
||||
* and many commands rely on this syntax now.
|
||||
* It's also really more natural for an user interface. */
|
||||
if (json_tok_streq(buffer, tok, "slow")) {
|
||||
**feerate = feerate_for_deadline(cmd->ld->topology, 100);
|
||||
return NULL;
|
||||
} else if (json_tok_streq(buffer, tok, "normal")) {
|
||||
**feerate = feerate_for_deadline(cmd->ld->topology, 12);
|
||||
return NULL;
|
||||
} else if (json_tok_streq(buffer, tok, "urgent")) {
|
||||
**feerate = feerate_for_deadline(cmd->ld->topology, 6);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/* It's a number... */
|
||||
tal_free(*feerate);
|
||||
return param_feerate_val(cmd, name, buffer, tok, feerate);
|
||||
}
|
||||
|
||||
struct command_result *param_feerate(struct command *cmd, const char *name,
|
||||
const char *buffer, const jsmntok_t *tok,
|
||||
u32 **feerate)
|
||||
{
|
||||
for (size_t i = 0; i < NUM_FEERATES; i++) {
|
||||
if (json_tok_streq(buffer, tok, feerate_name(i)))
|
||||
return param_feerate_estimate(cmd, feerate, i);
|
||||
}
|
||||
/* We used SLOW, NORMAL, and URGENT as feerate targets previously,
|
||||
* and many commands rely on this syntax now.
|
||||
* It's also really more natural for an user interface. */
|
||||
if (json_tok_streq(buffer, tok, "slow"))
|
||||
return param_feerate_estimate(cmd, feerate, FEERATE_MIN);
|
||||
else if (json_tok_streq(buffer, tok, "normal"))
|
||||
return param_feerate_estimate(cmd, feerate, FEERATE_OPENING);
|
||||
else if (json_tok_streq(buffer, tok, "urgent"))
|
||||
return param_feerate_estimate(cmd, feerate, FEERATE_UNILATERAL_CLOSE);
|
||||
struct command_result *ret;
|
||||
|
||||
/* It's a number... */
|
||||
return param_feerate_val(cmd, name, buffer, tok, feerate);
|
||||
}
|
||||
ret = param_feerate_unchecked(cmd, name, buffer, tok, feerate);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
struct command_result *param_feerate_estimate(struct command *cmd,
|
||||
u32 **feerate_per_kw,
|
||||
enum feerate feerate)
|
||||
{
|
||||
*feerate_per_kw = tal(cmd, u32);
|
||||
**feerate_per_kw = try_get_feerate(cmd->ld->topology, feerate);
|
||||
if (!**feerate_per_kw)
|
||||
return command_fail(cmd, LIGHTNINGD, "Cannot estimate fees");
|
||||
if (**feerate == 0)
|
||||
return command_fail(cmd, BCLI_NO_FEE_ESTIMATES,
|
||||
"Cannot estimate fees (yet)");
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
@@ -28,11 +28,6 @@ struct command_result *param_feerate_style(struct command *cmd,
|
||||
const jsmntok_t *tok,
|
||||
enum feerate_style **style);
|
||||
|
||||
/* Set feerate_per_kw to this estimate & return NULL, or fail cmd */
|
||||
struct command_result *param_feerate_estimate(struct command *cmd,
|
||||
u32 **feerate_per_kw,
|
||||
enum feerate feerate);
|
||||
|
||||
/* Extract a feerate with optional style suffix. */
|
||||
struct command_result *param_feerate_val(struct command *cmd,
|
||||
const char *name, const char *buffer,
|
||||
|
||||
@@ -13,11 +13,23 @@ void db_begin_transaction_(struct db *db UNNEEDED, const char *location UNNEEDED
|
||||
/* Generated stub for db_commit_transaction */
|
||||
void db_commit_transaction(struct db *db UNNEEDED)
|
||||
{ fprintf(stderr, "db_commit_transaction called!\n"); abort(); }
|
||||
/* Generated stub for delayed_to_us_feerate */
|
||||
u32 delayed_to_us_feerate(struct chain_topology *topo UNNEEDED)
|
||||
{ fprintf(stderr, "delayed_to_us_feerate called!\n"); abort(); }
|
||||
/* Generated stub for deprecated_apis */
|
||||
bool deprecated_apis;
|
||||
/* Generated stub for fatal */
|
||||
void fatal(const char *fmt UNNEEDED, ...)
|
||||
{ fprintf(stderr, "fatal called!\n"); abort(); }
|
||||
/* Generated stub for feerate_for_deadline */
|
||||
u32 feerate_for_deadline(const struct chain_topology *topo UNNEEDED, u32 blockcount UNNEEDED)
|
||||
{ fprintf(stderr, "feerate_for_deadline called!\n"); abort(); }
|
||||
/* Generated stub for feerate_max */
|
||||
u32 feerate_max(struct lightningd *ld UNNEEDED, bool *unknown UNNEEDED)
|
||||
{ fprintf(stderr, "feerate_max called!\n"); abort(); }
|
||||
/* Generated stub for feerate_min */
|
||||
u32 feerate_min(struct lightningd *ld UNNEEDED, bool *unknown UNNEEDED)
|
||||
{ fprintf(stderr, "feerate_min called!\n"); abort(); }
|
||||
/* Generated stub for fromwire_bigsize */
|
||||
bigsize_t fromwire_bigsize(const u8 **cursor UNNEEDED, size_t *max UNNEEDED)
|
||||
{ fprintf(stderr, "fromwire_bigsize called!\n"); abort(); }
|
||||
@@ -28,6 +40,9 @@ bool fromwire_channel_id(const u8 **cursor UNNEEDED, size_t *max UNNEEDED,
|
||||
/* Generated stub for fromwire_node_id */
|
||||
void fromwire_node_id(const u8 **cursor UNNEEDED, size_t *max UNNEEDED, struct node_id *id UNNEEDED)
|
||||
{ fprintf(stderr, "fromwire_node_id called!\n"); abort(); }
|
||||
/* Generated stub for htlc_resolution_feerate */
|
||||
u32 htlc_resolution_feerate(struct chain_topology *topo UNNEEDED)
|
||||
{ fprintf(stderr, "htlc_resolution_feerate called!\n"); abort(); }
|
||||
/* Generated stub for json_to_jsonrpc_errcode */
|
||||
bool json_to_jsonrpc_errcode(const char *buffer UNNEEDED, const jsmntok_t *tok UNNEEDED,
|
||||
enum jsonrpc_errcode *errcode UNNEEDED)
|
||||
@@ -52,6 +67,9 @@ void log_io(struct log *log UNNEEDED, enum log_level dir UNNEEDED,
|
||||
/* Generated stub for log_level_name */
|
||||
const char *log_level_name(enum log_level level UNNEEDED)
|
||||
{ fprintf(stderr, "log_level_name called!\n"); abort(); }
|
||||
/* Generated stub for mutual_close_feerate */
|
||||
u32 mutual_close_feerate(struct chain_topology *topo UNNEEDED)
|
||||
{ fprintf(stderr, "mutual_close_feerate called!\n"); abort(); }
|
||||
/* Generated stub for new_log */
|
||||
struct log *new_log(const tal_t *ctx UNNEEDED, struct log_book *record UNNEEDED,
|
||||
const struct node_id *default_node_id UNNEEDED,
|
||||
@@ -63,6 +81,9 @@ struct oneshot *new_reltimer_(struct timers *timers UNNEEDED,
|
||||
struct timerel expire UNNEEDED,
|
||||
void (*cb)(void *) UNNEEDED, void *arg UNNEEDED)
|
||||
{ fprintf(stderr, "new_reltimer_ called!\n"); abort(); }
|
||||
/* Generated stub for opening_feerate */
|
||||
u32 opening_feerate(struct chain_topology *topo UNNEEDED)
|
||||
{ fprintf(stderr, "opening_feerate called!\n"); abort(); }
|
||||
/* Generated stub for param */
|
||||
bool param(struct command *cmd UNNEEDED, const char *buffer UNNEEDED,
|
||||
const jsmntok_t params[] UNNEEDED, ...)
|
||||
@@ -97,6 +118,9 @@ const char *param_subcommand(struct command *cmd UNNEEDED, const char *buffer UN
|
||||
const jsmntok_t tokens[] UNNEEDED,
|
||||
const char *name UNNEEDED, ...)
|
||||
{ fprintf(stderr, "param_subcommand called!\n"); abort(); }
|
||||
/* Generated stub for penalty_feerate */
|
||||
u32 penalty_feerate(struct chain_topology *topo UNNEEDED)
|
||||
{ fprintf(stderr, "penalty_feerate called!\n"); abort(); }
|
||||
/* Generated stub for plugin_hook_call_ */
|
||||
bool plugin_hook_call_(struct lightningd *ld UNNEEDED,
|
||||
const struct plugin_hook *hook UNNEEDED,
|
||||
@@ -112,9 +136,9 @@ void towire_channel_id(u8 **pptr UNNEEDED, const struct channel_id *channel_id U
|
||||
/* Generated stub for towire_node_id */
|
||||
void towire_node_id(u8 **pptr UNNEEDED, const struct node_id *id UNNEEDED)
|
||||
{ fprintf(stderr, "towire_node_id called!\n"); abort(); }
|
||||
/* Generated stub for try_get_feerate */
|
||||
u32 try_get_feerate(const struct chain_topology *topo UNNEEDED, enum feerate feerate UNNEEDED)
|
||||
{ fprintf(stderr, "try_get_feerate called!\n"); abort(); }
|
||||
/* Generated stub for unilateral_feerate */
|
||||
u32 unilateral_feerate(struct chain_topology *topo UNNEEDED)
|
||||
{ fprintf(stderr, "unilateral_feerate called!\n"); abort(); }
|
||||
/* AUTOGENERATED MOCKS END */
|
||||
|
||||
static int test_json_filter(void)
|
||||
|
||||
@@ -2688,7 +2688,7 @@ def test_onchain_all_dust(node_factory, bitcoind, executor):
|
||||
|
||||
# Make l1's fees really high (and wait for it to exceed 50000)
|
||||
l1.set_feerates((1000000, 1000000, 1000000, 1000000))
|
||||
l1.daemon.wait_for_log('Feerate estimate for unilateral_close set to [56789][0-9]{4}')
|
||||
l1.daemon.wait_for_log('feerate estimate for 6 blocks smoothed to [56789][0-9]{4}')
|
||||
|
||||
bitcoind.generate_block(1)
|
||||
l1.daemon.wait_for_log(' to ONCHAIN')
|
||||
|
||||
@@ -1524,8 +1524,7 @@ def test_feerates(node_factory):
|
||||
l1.start()
|
||||
|
||||
# All estimation types
|
||||
types = ["opening", "mutual_close", "unilateral_close", "delayed_to_us",
|
||||
"htlc_resolution", "penalty"]
|
||||
types = ["opening", "mutual_close", "unilateral_close", "penalty"]
|
||||
|
||||
# Try parsing the feerates, won't work because can't estimate
|
||||
for t in types:
|
||||
@@ -1533,21 +1532,23 @@ def test_feerates(node_factory):
|
||||
feerate = l1.rpc.parsefeerate(t)
|
||||
|
||||
# Query feerates (shouldn't give any!)
|
||||
wait_for(lambda: len(l1.rpc.feerates('perkw')['perkw']) == 2)
|
||||
wait_for(lambda: len(l1.rpc.feerates('perkw')['perkw']) == 3)
|
||||
feerates = l1.rpc.feerates('perkw')
|
||||
assert feerates['warning_missing_feerates'] == 'Some fee estimates unavailable: bitcoind startup?'
|
||||
assert 'perkb' not in feerates
|
||||
assert feerates['perkw']['max_acceptable'] == 2**32 - 1
|
||||
assert feerates['perkw']['min_acceptable'] == 253
|
||||
assert feerates['perkw']['min_acceptable'] == 253
|
||||
assert feerates['perkw']['estimates'] == []
|
||||
for t in types:
|
||||
assert t not in feerates['perkw']
|
||||
|
||||
wait_for(lambda: len(l1.rpc.feerates('perkb')['perkb']) == 2)
|
||||
feerates = l1.rpc.feerates('perkb')
|
||||
assert feerates['warning_missing_feerates'] == 'Some fee estimates unavailable: bitcoind startup?'
|
||||
assert 'perkw' not in feerates
|
||||
assert feerates['perkb']['max_acceptable'] == (2**32 - 1)
|
||||
assert feerates['perkb']['min_acceptable'] == 253 * 4
|
||||
assert feerates['perkb']['estimates'] == []
|
||||
for t in types:
|
||||
assert t not in feerates['perkb']
|
||||
|
||||
@@ -1561,24 +1562,30 @@ def test_feerates(node_factory):
|
||||
assert 'perkb' not in feerates
|
||||
# With only one data point, this is a terrible guess!
|
||||
assert feerates['perkw']['min_acceptable'] == 15000 // 2
|
||||
# assert feerates['perkw']['min_acceptable'] == 253
|
||||
assert feerates['perkw']['estimates'] == [{'blockcount': 2,
|
||||
'feerate': 15000,
|
||||
'smoothed_feerate': 15000}]
|
||||
|
||||
# Set ECONOMICAL/6 feerate, for unilateral_close and htlc_resolution
|
||||
l1.set_feerates((15000, 11000, 0, 0), True)
|
||||
feerates = l1.rpc.feerates('perkw')
|
||||
assert feerates['perkw']['unilateral_close'] == 11000
|
||||
assert feerates['perkw']['htlc_resolution'] == 11000
|
||||
assert 'warning_missing_feerates' not in feerates
|
||||
assert 'perkb' not in feerates
|
||||
assert feerates['perkw']['max_acceptable'] == 15000 * 10
|
||||
# With only two data points, this is a terrible guess!
|
||||
assert feerates['perkw']['min_acceptable'] == 11000 // 2
|
||||
assert feerates['perkw']['estimates'] == [{'blockcount': 2,
|
||||
'feerate': 15000,
|
||||
'smoothed_feerate': 15000},
|
||||
{'blockcount': 6,
|
||||
'feerate': 11000,
|
||||
'smoothed_feerate': 11000}]
|
||||
|
||||
# Set ECONOMICAL/12 feerate, for all but min (so, no mutual_close feerate)
|
||||
l1.set_feerates((15000, 11000, 6250, 0), True)
|
||||
feerates = l1.rpc.feerates('perkb')
|
||||
assert feerates['perkb']['unilateral_close'] == 11000 * 4
|
||||
assert feerates['perkb']['htlc_resolution'] == 11000 * 4
|
||||
# We dont' extrapolate, so it uses the same for mutual_close
|
||||
assert feerates['perkb']['mutual_close'] == 6250 * 4
|
||||
for t in types:
|
||||
@@ -1589,13 +1596,21 @@ def test_feerates(node_factory):
|
||||
assert feerates['perkb']['max_acceptable'] == 15000 * 4 * 10
|
||||
# With only three data points, this is a terrible guess!
|
||||
assert feerates['perkb']['min_acceptable'] == 6250 // 2 * 4
|
||||
assert feerates['perkb']['estimates'] == [{'blockcount': 2,
|
||||
'feerate': 15000 * 4,
|
||||
'smoothed_feerate': 15000 * 4},
|
||||
{'blockcount': 6,
|
||||
'feerate': 11000 * 4,
|
||||
'smoothed_feerate': 11000 * 4},
|
||||
{'blockcount': 12,
|
||||
'feerate': 6250 * 4,
|
||||
'smoothed_feerate': 6250 * 4}]
|
||||
|
||||
# Set ECONOMICAL/100 feerate for min and mutual_close
|
||||
l1.set_feerates((15000, 11000, 6250, 5000), True)
|
||||
wait_for(lambda: len(l1.rpc.feerates('perkw')['perkw']) >= len(types) + 2)
|
||||
feerates = l1.rpc.feerates('perkw')
|
||||
assert feerates['perkw']['unilateral_close'] == 11000
|
||||
assert feerates['perkw']['htlc_resolution'] == 11000
|
||||
assert feerates['perkw']['mutual_close'] == 5000
|
||||
for t in types:
|
||||
if t not in ("unilateral_close", "htlc_resolution", "mutual_close"):
|
||||
@@ -1604,12 +1619,25 @@ def test_feerates(node_factory):
|
||||
assert 'perkb' not in feerates
|
||||
assert feerates['perkw']['max_acceptable'] == 15000 * 10
|
||||
assert feerates['perkw']['min_acceptable'] == 5000 // 2
|
||||
assert feerates['perkw']['estimates'] == [{'blockcount': 2,
|
||||
'feerate': 15000,
|
||||
'smoothed_feerate': 15000},
|
||||
{'blockcount': 6,
|
||||
'feerate': 11000,
|
||||
'smoothed_feerate': 11000},
|
||||
{'blockcount': 12,
|
||||
'feerate': 6250,
|
||||
'smoothed_feerate': 6250},
|
||||
{'blockcount': 100,
|
||||
'feerate': 5000,
|
||||
'smoothed_feerate': 5000}]
|
||||
|
||||
assert len(feerates['onchain_fee_estimates']) == 5
|
||||
assert feerates['onchain_fee_estimates']['opening_channel_satoshis'] == feerates['perkw']['opening'] * 702 // 1000
|
||||
assert feerates['onchain_fee_estimates']['mutual_close_satoshis'] == feerates['perkw']['mutual_close'] * 673 // 1000
|
||||
assert feerates['onchain_fee_estimates']['unilateral_close_satoshis'] == feerates['perkw']['unilateral_close'] * 598 // 1000
|
||||
htlc_feerate = feerates["perkw"]["htlc_resolution"]
|
||||
# htlc resolution currently uses 6 block estimate
|
||||
htlc_feerate = [f['feerate'] for f in feerates['perkw']['estimates'] if f['blockcount'] == 6][0]
|
||||
htlc_timeout_cost = feerates["onchain_fee_estimates"]["htlc_timeout_satoshis"]
|
||||
htlc_success_cost = feerates["onchain_fee_estimates"]["htlc_success_satoshis"]
|
||||
|
||||
@@ -2908,15 +2936,28 @@ def test_force_feerates(node_factory):
|
||||
l1 = node_factory.get_node(options={'force-feerates': 1111})
|
||||
assert l1.rpc.listconfigs()['force-feerates'] == '1111'
|
||||
|
||||
# Note that estimates are still valid here, despite "force-feerates"
|
||||
estimates = [{"blockcount": 2,
|
||||
"feerate": 15000,
|
||||
"smoothed_feerate": 15000},
|
||||
{"blockcount": 6,
|
||||
"feerate": 11000,
|
||||
"smoothed_feerate": 11000},
|
||||
{"blockcount": 12,
|
||||
"feerate": 7500,
|
||||
"smoothed_feerate": 7500},
|
||||
{"blockcount": 100,
|
||||
"feerate": 3750,
|
||||
"smoothed_feerate": 3750}]
|
||||
|
||||
assert l1.rpc.feerates('perkw')['perkw'] == {
|
||||
"opening": 1111,
|
||||
"mutual_close": 1111,
|
||||
"unilateral_close": 1111,
|
||||
"delayed_to_us": 1111,
|
||||
"htlc_resolution": 1111,
|
||||
"penalty": 1111,
|
||||
"min_acceptable": 1875,
|
||||
"max_acceptable": 150000}
|
||||
"max_acceptable": 150000,
|
||||
"estimates": estimates}
|
||||
|
||||
l1.stop()
|
||||
l1.daemon.opts['force-feerates'] = '1111/2222'
|
||||
@@ -2927,11 +2968,10 @@ def test_force_feerates(node_factory):
|
||||
"opening": 1111,
|
||||
"mutual_close": 2222,
|
||||
"unilateral_close": 2222,
|
||||
"delayed_to_us": 2222,
|
||||
"htlc_resolution": 2222,
|
||||
"penalty": 2222,
|
||||
"min_acceptable": 1875,
|
||||
"max_acceptable": 150000}
|
||||
"max_acceptable": 150000,
|
||||
"estimates": estimates}
|
||||
|
||||
l1.stop()
|
||||
l1.daemon.opts['force-feerates'] = '1111/2222/3333/4444/5555/6666'
|
||||
@@ -2942,11 +2982,10 @@ def test_force_feerates(node_factory):
|
||||
"opening": 1111,
|
||||
"mutual_close": 2222,
|
||||
"unilateral_close": 3333,
|
||||
"delayed_to_us": 4444,
|
||||
"htlc_resolution": 5555,
|
||||
"penalty": 6666,
|
||||
"min_acceptable": 1875,
|
||||
"max_acceptable": 150000}
|
||||
"max_acceptable": 150000,
|
||||
"estimates": estimates}
|
||||
|
||||
|
||||
def test_datastore_escapeing(node_factory):
|
||||
@@ -3236,16 +3275,12 @@ def test_feerate_arg(node_factory):
|
||||
|
||||
fees["urgent"] = by_blocks[6]
|
||||
fees["normal"] = by_blocks[12]
|
||||
fees["slow"] = by_blocks[100] // 2
|
||||
fees["slow"] = by_blocks[100]
|
||||
|
||||
fees["opening"] = by_blocks[12]
|
||||
fees["mutual_close"] = by_blocks[100]
|
||||
fees["penalty"] = by_blocks[12]
|
||||
fees["unilateral_close"] = by_blocks[6]
|
||||
fees["delayed_to_us"] = by_blocks[12]
|
||||
fees["htlc_resolution"] = by_blocks[6]
|
||||
fees["min_acceptable"] = by_blocks[100] // 2
|
||||
fees["max_acceptable"] = by_blocks[2] * 10
|
||||
|
||||
for fee, expect in fees.items():
|
||||
# Put arg in assertion, so it gets printed on failure!
|
||||
|
||||
@@ -1658,12 +1658,12 @@ def test_upgradewallet(node_factory, bitcoind):
|
||||
|
||||
# Doing it with 'reserved ok' should have 1
|
||||
# We use a big feerate so we can get over the RBF hump
|
||||
upgrade = l1.rpc.upgradewallet(feerate="max_acceptable", reservedok=True)
|
||||
upgrade = l1.rpc.upgradewallet(feerate="urgent", reservedok=True)
|
||||
assert upgrade['upgraded_outs'] == 1
|
||||
assert bitcoind.rpc.getmempoolinfo()['size'] == 1
|
||||
|
||||
# Mine it, nothing to upgrade
|
||||
l1.bitcoin.generate_block(1)
|
||||
sync_blockheight(l1.bitcoin, [l1])
|
||||
upgrade = l1.rpc.upgradewallet(feerate="max_acceptable", reservedok=True)
|
||||
upgrade = l1.rpc.upgradewallet(feerate="urgent", reservedok=True)
|
||||
assert upgrade['upgraded_outs'] == 0
|
||||
|
||||
Reference in New Issue
Block a user