From 75f0b8e916862dd524ce7607a3fe91a541dba022 Mon Sep 17 00:00:00 2001 From: Christian Decker Date: Thu, 27 Jan 2022 18:17:10 +0100 Subject: [PATCH] cln-grpc: Add `listpeers` RPC method This is pretty much the hardest to map, but we map it correctly, with the exception of the state_changes[] array we truncated out in the last commit. --- cln-grpc/proto/node.proto | 147 ++++++++++++ cln-grpc/src/convert.rs | 129 ++++++++++ cln-grpc/src/server.rs | 30 +++ cln-rpc/src/model.rs | 381 +++++++++++++++++++++++++++++- contrib/msggen/msggen/__main__.py | 2 +- 5 files changed, 687 insertions(+), 2 deletions(-) diff --git a/cln-grpc/proto/node.proto b/cln-grpc/proto/node.proto index e7d7f5267..76610e9f6 100644 --- a/cln-grpc/proto/node.proto +++ b/cln-grpc/proto/node.proto @@ -9,6 +9,7 @@ import "primitives.proto"; service Node { rpc Getinfo(GetinfoRequest) returns (GetinfoResponse) {} + rpc ListPeers(ListpeersRequest) returns (ListpeersResponse) {} rpc ListFunds(ListfundsRequest) returns (ListfundsResponse) {} rpc ListChannels(ListchannelsRequest) returns (ListchannelsResponse) {} rpc AddGossip(AddgossipRequest) returns (AddgossipResponse) {} @@ -69,6 +70,152 @@ message GetinfoBinding { optional string socket = 4; } +message ListpeersRequest { + optional bytes id = 1; + optional string level = 2; +} + +message ListpeersResponse { + repeated ListpeersPeers peers = 1; +} + +message ListpeersPeers { + bytes id = 1; + bool connected = 2; + repeated ListpeersPeersLog log = 3; + repeated ListpeersPeersChannels channels = 4; + repeated string netaddr = 5; + optional bytes features = 6; +} + +message ListpeersPeersLog { + // ListPeers.peers[].log[].type + enum ListpeersPeersLogType { + SKIPPED = 0; + BROKEN = 1; + UNUSUAL = 2; + INFO = 3; + DEBUG = 4; + IO_IN = 5; + IO_OUT = 6; + } + ListpeersPeersLogType item_type = 1; + optional uint32 num_skipped = 2; + optional string time = 3; + optional string source = 4; + optional string log = 5; + optional bytes node_id = 6; + optional bytes data = 7; +} + +message ListpeersPeersChannels { + // ListPeers.peers[].channels[].state + enum ListpeersPeersChannelsState { + OPENINGD = 0; + CHANNELD_AWAITING_LOCKIN = 1; + CHANNELD_NORMAL = 2; + CHANNELD_SHUTTING_DOWN = 3; + CLOSINGD_SIGEXCHANGE = 4; + CLOSINGD_COMPLETE = 5; + AWAITING_UNILATERAL = 6; + FUNDING_SPEND_SEEN = 7; + ONCHAIN = 8; + DUALOPEND_OPEN_INIT = 9; + DUALOPEND_AWAITING_LOCKIN = 10; + } + ListpeersPeersChannelsState state = 1; + optional bytes scratch_txid = 2; + optional string owner = 4; + optional string short_channel_id = 5; + optional bytes channel_id = 6; + optional bytes funding_txid = 7; + optional string initial_feerate = 8; + optional string last_feerate = 9; + optional string next_feerate = 10; + optional uint32 next_fee_step = 11; + repeated ListpeersPeersChannelsInflight inflight = 12; + optional bytes close_to = 13; + optional bool private = 14; + ChannelSide opener = 15; + optional ChannelSide closer = 16; + repeated string features = 17; + optional Amount to_us_msat = 19; + optional Amount min_to_us_msat = 20; + optional Amount max_to_us_msat = 21; + optional Amount total_msat = 22; + optional Amount fee_base_msat = 23; + optional uint32 fee_proportional_millionths = 24; + optional Amount dust_limit_msat = 25; + optional Amount max_total_htlc_in_msat = 26; + optional Amount their_reserve_msat = 27; + optional Amount our_reserve_msat = 28; + optional Amount spendable_msat = 29; + optional Amount receivable_msat = 30; + optional Amount minimum_htlc_in_msat = 31; + optional uint32 their_to_self_delay = 32; + optional uint32 our_to_self_delay = 33; + optional uint32 max_accepted_htlcs = 34; + repeated string status = 36; + optional uint64 in_payments_offered = 37; + optional Amount in_offered_msat = 38; + optional uint64 in_payments_fulfilled = 39; + optional Amount in_fulfilled_msat = 40; + optional uint64 out_payments_offered = 41; + optional Amount out_offered_msat = 42; + optional uint64 out_payments_fulfilled = 43; + optional Amount out_fulfilled_msat = 44; + repeated ListpeersPeersChannelsHtlcs htlcs = 45; + optional string close_to_addr = 46; +} + +message ListpeersPeersChannelsFeerate { + uint32 perkw = 1; + uint32 perkb = 2; +} + +message ListpeersPeersChannelsInflight { + bytes funding_txid = 1; + uint32 funding_outnum = 2; + string feerate = 3; + Amount total_funding_msat = 4; + Amount our_funding_msat = 5; + bytes scratch_txid = 6; +} + +message ListpeersPeersChannelsFunding { + Amount local_msat = 1; + Amount remote_msat = 2; +} + +message ListpeersPeersChannelsHtlcs { + // ListPeers.peers[].channels[].htlcs[].direction + enum ListpeersPeersChannelsHtlcsDirection { + IN = 0; + OUT = 1; + } + // ListPeers.peers[].channels[].htlcs[].state + enum ListpeersPeersChannelsHtlcsState { + SENT_ADD_HTLC = 0; + SENT_ADD_COMMIT = 1; + RCVD_ADD_REVOCATION = 2; + RCVD_ADD_ACK_COMMIT = 3; + SENT_ADD_ACK_REVOCATION = 4; + RCVD_REMOVE_HTLC = 5; + RCVD_REMOVE_COMMIT = 6; + SENT_REMOVE_REVOCATION = 7; + SENT_REMOVE_ACK_COMMIT = 8; + RCVD_REMOVE_ACK_REVOCATION = 9; + } + ListpeersPeersChannelsHtlcsDirection direction = 1; + uint64 id = 2; + Amount amount_msat = 3; + uint32 expiry = 4; + bytes payment_hash = 5; + optional bool local_trimmed = 6; + optional string status = 7; + ListpeersPeersChannelsHtlcsState state = 8; +} + message ListfundsRequest { optional bool spent = 1; } diff --git a/cln-grpc/src/convert.rs b/cln-grpc/src/convert.rs index a7c5caa25..3efce232d 100644 --- a/cln-grpc/src/convert.rs +++ b/cln-grpc/src/convert.rs @@ -55,6 +55,125 @@ impl From<&responses::GetinfoResponse> for pb::GetinfoResponse { } } +#[allow(unused_variables)] +impl From<&responses::ListpeersPeersLog> for pb::ListpeersPeersLog { + fn from(c: &responses::ListpeersPeersLog) -> Self { + Self { + item_type: c.item_type as i32, + num_skipped: c.num_skipped.clone(), + time: c.time.clone(), + source: c.source.clone(), + log: c.log.clone(), + node_id: c.node_id.as_ref().map(|v| hex::decode(&v).unwrap()), + data: c.data.as_ref().map(|v| hex::decode(&v).unwrap()), + } + } +} + +#[allow(unused_variables)] +impl From<&responses::ListpeersPeersChannelsInflight> for pb::ListpeersPeersChannelsInflight { + fn from(c: &responses::ListpeersPeersChannelsInflight) -> Self { + Self { + funding_txid: hex::decode(&c.funding_txid).unwrap(), + funding_outnum: c.funding_outnum.clone(), + feerate: c.feerate.clone(), + total_funding_msat: Some(c.total_funding_msat.into()), + our_funding_msat: Some(c.our_funding_msat.into()), + scratch_txid: hex::decode(&c.scratch_txid).unwrap(), + } + } +} + +#[allow(unused_variables)] +impl From<&responses::ListpeersPeersChannelsHtlcs> for pb::ListpeersPeersChannelsHtlcs { + fn from(c: &responses::ListpeersPeersChannelsHtlcs) -> Self { + Self { + direction: c.direction as i32, + id: c.id.clone(), + amount_msat: Some(c.amount_msat.into()), + expiry: c.expiry.clone(), + payment_hash: hex::decode(&c.payment_hash).unwrap(), + local_trimmed: c.local_trimmed.clone(), + status: c.status.clone(), + state: c.state as i32, + } + } +} + +#[allow(unused_variables)] +impl From<&responses::ListpeersPeersChannels> for pb::ListpeersPeersChannels { + fn from(c: &responses::ListpeersPeersChannels) -> Self { + Self { + state: c.state as i32, + scratch_txid: c.scratch_txid.as_ref().map(|v| hex::decode(&v).unwrap()), + owner: c.owner.clone(), + short_channel_id: c.short_channel_id.clone(), + channel_id: c.channel_id.as_ref().map(|v| hex::decode(&v).unwrap()), + funding_txid: c.funding_txid.as_ref().map(|v| hex::decode(&v).unwrap()), + initial_feerate: c.initial_feerate.clone(), + last_feerate: c.last_feerate.clone(), + next_feerate: c.next_feerate.clone(), + next_fee_step: c.next_fee_step.clone(), + inflight: c.inflight.iter().map(|s| s.into()).collect(), + close_to: c.close_to.as_ref().map(|v| hex::decode(&v).unwrap()), + private: c.private.clone(), + opener: c.opener as i32, + closer: c.closer.map(|v| v as i32), + features: c.features.iter().map(|s| s.into()).collect(), + to_us_msat: c.to_us_msat.map(|f| f.into()), + min_to_us_msat: c.min_to_us_msat.map(|f| f.into()), + max_to_us_msat: c.max_to_us_msat.map(|f| f.into()), + total_msat: c.total_msat.map(|f| f.into()), + fee_base_msat: c.fee_base_msat.map(|f| f.into()), + fee_proportional_millionths: c.fee_proportional_millionths.clone(), + dust_limit_msat: c.dust_limit_msat.map(|f| f.into()), + max_total_htlc_in_msat: c.max_total_htlc_in_msat.map(|f| f.into()), + their_reserve_msat: c.their_reserve_msat.map(|f| f.into()), + our_reserve_msat: c.our_reserve_msat.map(|f| f.into()), + spendable_msat: c.spendable_msat.map(|f| f.into()), + receivable_msat: c.receivable_msat.map(|f| f.into()), + minimum_htlc_in_msat: c.minimum_htlc_in_msat.map(|f| f.into()), + their_to_self_delay: c.their_to_self_delay.clone(), + our_to_self_delay: c.our_to_self_delay.clone(), + max_accepted_htlcs: c.max_accepted_htlcs.clone(), + status: c.status.iter().map(|s| s.into()).collect(), + in_payments_offered: c.in_payments_offered.clone(), + in_offered_msat: c.in_offered_msat.map(|f| f.into()), + in_payments_fulfilled: c.in_payments_fulfilled.clone(), + in_fulfilled_msat: c.in_fulfilled_msat.map(|f| f.into()), + out_payments_offered: c.out_payments_offered.clone(), + out_offered_msat: c.out_offered_msat.map(|f| f.into()), + out_payments_fulfilled: c.out_payments_fulfilled.clone(), + out_fulfilled_msat: c.out_fulfilled_msat.map(|f| f.into()), + htlcs: c.htlcs.iter().map(|s| s.into()).collect(), + close_to_addr: c.close_to_addr.clone(), + } + } +} + +#[allow(unused_variables)] +impl From<&responses::ListpeersPeers> for pb::ListpeersPeers { + fn from(c: &responses::ListpeersPeers) -> Self { + Self { + id: hex::decode(&c.id).unwrap(), + connected: c.connected.clone(), + log: c.log.iter().map(|s| s.into()).collect(), + channels: c.channels.iter().map(|s| s.into()).collect(), + netaddr: c.netaddr.iter().map(|s| s.into()).collect(), + features: c.features.as_ref().map(|v| hex::decode(&v).unwrap()), + } + } +} + +#[allow(unused_variables)] +impl From<&responses::ListpeersResponse> for pb::ListpeersResponse { + fn from(c: &responses::ListpeersResponse) -> Self { + Self { + peers: c.peers.iter().map(|s| s.into()).collect(), + } + } +} + #[allow(unused_variables)] impl From<&responses::ListfundsOutputs> for pb::ListfundsOutputs { fn from(c: &responses::ListfundsOutputs) -> Self { @@ -176,6 +295,16 @@ impl From<&pb::GetinfoRequest> for requests::GetinfoRequest { } } +#[allow(unused_variables)] +impl From<&pb::ListpeersRequest> for requests::ListpeersRequest { + fn from(c: &pb::ListpeersRequest) -> Self { + Self { + id: c.id.clone().map(|v| hex::encode(v)), + level: c.level.clone(), + } + } +} + #[allow(unused_variables)] impl From<&pb::ListfundsRequest> for requests::ListfundsRequest { fn from(c: &pb::ListfundsRequest) -> Self { diff --git a/cln-grpc/src/server.rs b/cln-grpc/src/server.rs index b1bb9d8c1..21b06a67c 100644 --- a/cln-grpc/src/server.rs +++ b/cln-grpc/src/server.rs @@ -57,6 +57,36 @@ async fn getinfo( } +async fn list_peers( + &self, + request: tonic::Request, +) -> Result, tonic::Status> { + let req = request.into_inner(); + let req: requests::ListpeersRequest = (&req).into(); + debug!("Client asked for getinfo"); + let mut rpc = ClnRpc::new(&self.rpc_path) + .await + .map_err(|e| Status::new(Code::Internal, e.to_string()))?; + let result = rpc.call(Request::ListPeers(req)) + .await + .map_err(|e| Status::new( + Code::Unknown, + format!("Error calling method ListPeers: {:?}", e)))?; + match result { + Response::ListPeers(r) => Ok( + tonic::Response::new((&r).into()) + ), + r => Err(Status::new( + Code::Internal, + format!( + "Unexpected result {:?} to method call ListPeers", + r + ) + )), + } + +} + async fn list_funds( &self, request: tonic::Request, diff --git a/cln-rpc/src/model.rs b/cln-rpc/src/model.rs index ebc697023..d7c6e6995 100644 --- a/cln-rpc/src/model.rs +++ b/cln-rpc/src/model.rs @@ -2,7 +2,7 @@ //! This file was automatically generated using the following command: //! //! ```bash -//! msggen +//! contrib/msggen/msggen/__main__.py //! ``` //! //! Do not edit this file, it'll be overwritten. Rather edit the schema that @@ -17,6 +17,7 @@ pub use responses::*; #[serde(rename_all = "lowercase")] pub enum Request { Getinfo(requests::GetinfoRequest), + ListPeers(requests::ListpeersRequest), ListFunds(requests::ListfundsRequest), ListChannels(requests::ListchannelsRequest), AddGossip(requests::AddgossipRequest), @@ -30,6 +31,7 @@ pub enum Request { #[serde(rename_all = "lowercase")] pub enum Response { Getinfo(responses::GetinfoResponse), + ListPeers(responses::ListpeersResponse), ListFunds(responses::ListfundsResponse), ListChannels(responses::ListchannelsResponse), AddGossip(responses::AddgossipResponse), @@ -48,6 +50,14 @@ pub mod requests { pub struct GetinfoRequest { } + #[derive(Clone, Debug, Deserialize, Serialize)] + pub struct ListpeersRequest { + #[serde(alias = "id", skip_serializing_if = "Option::is_none")] + pub id: Option, + #[serde(alias = "level", skip_serializing_if = "Option::is_none")] + pub level: Option, + } + #[derive(Clone, Debug, Deserialize, Serialize)] pub struct ListfundsRequest { #[serde(alias = "spent", skip_serializing_if = "Option::is_none")] @@ -125,6 +135,20 @@ pub mod responses { WEBSOCKET, } + impl TryFrom for GetinfoAddressType { + type Error = anyhow::Error; + fn try_from(c: i32) -> Result { + match c { + 0 => Ok(GetinfoAddressType::DNS), + 1 => Ok(GetinfoAddressType::IPV4), + 2 => Ok(GetinfoAddressType::IPV6), + 3 => Ok(GetinfoAddressType::TORV2), + 4 => Ok(GetinfoAddressType::TORV3), + 5 => Ok(GetinfoAddressType::WEBSOCKET), + o => Err(anyhow::anyhow!("Unknown variant {} for enum GetinfoAddressType", o)), + } + } + } #[derive(Clone, Debug, Deserialize, Serialize)] pub struct GetinfoAddress { // Path `Getinfo.address[].type` @@ -147,6 +171,19 @@ pub mod responses { TORV3, } + impl TryFrom for GetinfoBindingType { + type Error = anyhow::Error; + fn try_from(c: i32) -> Result { + match c { + 0 => Ok(GetinfoBindingType::LOCAL_SOCKET), + 1 => Ok(GetinfoBindingType::IPV4), + 2 => Ok(GetinfoBindingType::IPV6), + 3 => Ok(GetinfoBindingType::TORV2), + 4 => Ok(GetinfoBindingType::TORV3), + o => Err(anyhow::anyhow!("Unknown variant {} for enum GetinfoBindingType", o)), + } + } + } #[derive(Clone, Debug, Deserialize, Serialize)] pub struct GetinfoBinding { // Path `Getinfo.binding[].type` @@ -196,6 +233,326 @@ pub mod responses { pub warning_lightningd_sync: Option, } + #[derive(Copy, Clone, Debug, Deserialize, Serialize)] + #[serde(rename_all = "lowercase")] + pub enum ListpeersPeersLogType { + SKIPPED, + BROKEN, + UNUSUAL, + INFO, + DEBUG, + IO_IN, + IO_OUT, + } + + impl TryFrom for ListpeersPeersLogType { + type Error = anyhow::Error; + fn try_from(c: i32) -> Result { + match c { + 0 => Ok(ListpeersPeersLogType::SKIPPED), + 1 => Ok(ListpeersPeersLogType::BROKEN), + 2 => Ok(ListpeersPeersLogType::UNUSUAL), + 3 => Ok(ListpeersPeersLogType::INFO), + 4 => Ok(ListpeersPeersLogType::DEBUG), + 5 => Ok(ListpeersPeersLogType::IO_IN), + 6 => Ok(ListpeersPeersLogType::IO_OUT), + o => Err(anyhow::anyhow!("Unknown variant {} for enum ListpeersPeersLogType", o)), + } + } + } + #[derive(Clone, Debug, Deserialize, Serialize)] + pub struct ListpeersPeersLog { + // Path `ListPeers.peers[].log[].type` + #[serde(rename = "type")] + pub item_type: ListpeersPeersLogType, + #[serde(alias = "num_skipped", skip_serializing_if = "Option::is_none")] + pub num_skipped: Option, + #[serde(alias = "time", skip_serializing_if = "Option::is_none")] + pub time: Option, + #[serde(alias = "source", skip_serializing_if = "Option::is_none")] + pub source: Option, + #[serde(alias = "log", skip_serializing_if = "Option::is_none")] + pub log: Option, + #[serde(alias = "node_id", skip_serializing_if = "Option::is_none")] + pub node_id: Option, + #[serde(alias = "data", skip_serializing_if = "Option::is_none")] + pub data: Option, + } + + /// the channel state, in particular "CHANNELD_NORMAL" means the channel can be used normally + #[derive(Copy, Clone, Debug, Deserialize, Serialize)] + #[serde(rename_all = "lowercase")] + pub enum ListpeersPeersChannelsState { + OPENINGD, + CHANNELD_AWAITING_LOCKIN, + CHANNELD_NORMAL, + CHANNELD_SHUTTING_DOWN, + CLOSINGD_SIGEXCHANGE, + CLOSINGD_COMPLETE, + AWAITING_UNILATERAL, + FUNDING_SPEND_SEEN, + ONCHAIN, + DUALOPEND_OPEN_INIT, + DUALOPEND_AWAITING_LOCKIN, + } + + impl TryFrom for ListpeersPeersChannelsState { + type Error = anyhow::Error; + fn try_from(c: i32) -> Result { + match c { + 0 => Ok(ListpeersPeersChannelsState::OPENINGD), + 1 => Ok(ListpeersPeersChannelsState::CHANNELD_AWAITING_LOCKIN), + 2 => Ok(ListpeersPeersChannelsState::CHANNELD_NORMAL), + 3 => Ok(ListpeersPeersChannelsState::CHANNELD_SHUTTING_DOWN), + 4 => Ok(ListpeersPeersChannelsState::CLOSINGD_SIGEXCHANGE), + 5 => Ok(ListpeersPeersChannelsState::CLOSINGD_COMPLETE), + 6 => Ok(ListpeersPeersChannelsState::AWAITING_UNILATERAL), + 7 => Ok(ListpeersPeersChannelsState::FUNDING_SPEND_SEEN), + 8 => Ok(ListpeersPeersChannelsState::ONCHAIN), + 9 => Ok(ListpeersPeersChannelsState::DUALOPEND_OPEN_INIT), + 10 => Ok(ListpeersPeersChannelsState::DUALOPEND_AWAITING_LOCKIN), + o => Err(anyhow::anyhow!("Unknown variant {} for enum ListpeersPeersChannelsState", o)), + } + } + } + #[derive(Clone, Debug, Deserialize, Serialize)] + pub struct ListpeersPeersChannelsFeerate { + #[serde(alias = "perkw")] + pub perkw: u32, + #[serde(alias = "perkb")] + pub perkb: u32, + } + + #[derive(Clone, Debug, Deserialize, Serialize)] + pub struct ListpeersPeersChannelsInflight { + #[serde(alias = "funding_txid")] + pub funding_txid: String, + #[serde(alias = "funding_outnum")] + pub funding_outnum: u32, + #[serde(alias = "feerate")] + pub feerate: String, + #[serde(alias = "total_funding_msat")] + pub total_funding_msat: Amount, + #[serde(alias = "our_funding_msat")] + pub our_funding_msat: Amount, + #[serde(alias = "scratch_txid")] + pub scratch_txid: String, + } + + #[derive(Clone, Debug, Deserialize, Serialize)] + pub struct ListpeersPeersChannelsFunding { + #[serde(alias = "local_msat")] + pub local_msat: Amount, + #[serde(alias = "remote_msat")] + pub remote_msat: Amount, + } + + #[derive(Clone, Debug, Deserialize, Serialize)] + pub struct ListpeersPeersChannelsState_changes { + #[serde(alias = "timestamp")] + pub timestamp: String, + // Path `ListPeers.peers[].channels[].state_changes[].old_state` + #[serde(rename = "old_state")] + pub old_state: ChannelState, + // Path `ListPeers.peers[].channels[].state_changes[].new_state` + #[serde(rename = "new_state")] + pub new_state: ChannelState, + // Path `ListPeers.peers[].channels[].state_changes[].cause` + #[serde(rename = "cause")] + pub cause: ChannelStateChangeCause, + #[serde(alias = "message")] + pub message: String, + } + + /// Whether it came from peer, or is going to peer + #[derive(Copy, Clone, Debug, Deserialize, Serialize)] + #[serde(rename_all = "lowercase")] + pub enum ListpeersPeersChannelsHtlcsDirection { + IN, + OUT, + } + + impl TryFrom for ListpeersPeersChannelsHtlcsDirection { + type Error = anyhow::Error; + fn try_from(c: i32) -> Result { + match c { + 0 => Ok(ListpeersPeersChannelsHtlcsDirection::IN), + 1 => Ok(ListpeersPeersChannelsHtlcsDirection::OUT), + o => Err(anyhow::anyhow!("Unknown variant {} for enum ListpeersPeersChannelsHtlcsDirection", o)), + } + } + } + /// Status of the HTLC + #[derive(Copy, Clone, Debug, Deserialize, Serialize)] + #[serde(rename_all = "lowercase")] + pub enum ListpeersPeersChannelsHtlcsState { + SENT_ADD_HTLC, + SENT_ADD_COMMIT, + RCVD_ADD_REVOCATION, + RCVD_ADD_ACK_COMMIT, + SENT_ADD_ACK_REVOCATION, + RCVD_REMOVE_HTLC, + RCVD_REMOVE_COMMIT, + SENT_REMOVE_REVOCATION, + SENT_REMOVE_ACK_COMMIT, + RCVD_REMOVE_ACK_REVOCATION, + } + + impl TryFrom for ListpeersPeersChannelsHtlcsState { + type Error = anyhow::Error; + fn try_from(c: i32) -> Result { + match c { + 0 => Ok(ListpeersPeersChannelsHtlcsState::SENT_ADD_HTLC), + 1 => Ok(ListpeersPeersChannelsHtlcsState::SENT_ADD_COMMIT), + 2 => Ok(ListpeersPeersChannelsHtlcsState::RCVD_ADD_REVOCATION), + 3 => Ok(ListpeersPeersChannelsHtlcsState::RCVD_ADD_ACK_COMMIT), + 4 => Ok(ListpeersPeersChannelsHtlcsState::SENT_ADD_ACK_REVOCATION), + 5 => Ok(ListpeersPeersChannelsHtlcsState::RCVD_REMOVE_HTLC), + 6 => Ok(ListpeersPeersChannelsHtlcsState::RCVD_REMOVE_COMMIT), + 7 => Ok(ListpeersPeersChannelsHtlcsState::SENT_REMOVE_REVOCATION), + 8 => Ok(ListpeersPeersChannelsHtlcsState::SENT_REMOVE_ACK_COMMIT), + 9 => Ok(ListpeersPeersChannelsHtlcsState::RCVD_REMOVE_ACK_REVOCATION), + o => Err(anyhow::anyhow!("Unknown variant {} for enum ListpeersPeersChannelsHtlcsState", o)), + } + } + } + #[derive(Clone, Debug, Deserialize, Serialize)] + pub struct ListpeersPeersChannelsHtlcs { + // Path `ListPeers.peers[].channels[].htlcs[].direction` + #[serde(rename = "direction")] + pub direction: ListpeersPeersChannelsHtlcsDirection, + #[serde(alias = "id")] + pub id: u64, + #[serde(alias = "amount_msat")] + pub amount_msat: Amount, + #[serde(alias = "expiry")] + pub expiry: u32, + #[serde(alias = "payment_hash")] + pub payment_hash: String, + #[serde(alias = "local_trimmed", skip_serializing_if = "Option::is_none")] + pub local_trimmed: Option, + #[serde(alias = "status", skip_serializing_if = "Option::is_none")] + pub status: Option, + // Path `ListPeers.peers[].channels[].htlcs[].state` + #[serde(rename = "state")] + pub state: ListpeersPeersChannelsHtlcsState, + } + + #[derive(Clone, Debug, Deserialize, Serialize)] + pub struct ListpeersPeersChannels { + // Path `ListPeers.peers[].channels[].state` + #[serde(rename = "state")] + pub state: ListpeersPeersChannelsState, + #[serde(alias = "scratch_txid", skip_serializing_if = "Option::is_none")] + pub scratch_txid: Option, + #[serde(alias = "owner", skip_serializing_if = "Option::is_none")] + pub owner: Option, + #[serde(alias = "short_channel_id", skip_serializing_if = "Option::is_none")] + pub short_channel_id: Option, + #[serde(alias = "channel_id", skip_serializing_if = "Option::is_none")] + pub channel_id: Option, + #[serde(alias = "funding_txid", skip_serializing_if = "Option::is_none")] + pub funding_txid: Option, + #[serde(alias = "initial_feerate", skip_serializing_if = "Option::is_none")] + pub initial_feerate: Option, + #[serde(alias = "last_feerate", skip_serializing_if = "Option::is_none")] + pub last_feerate: Option, + #[serde(alias = "next_feerate", skip_serializing_if = "Option::is_none")] + pub next_feerate: Option, + #[serde(alias = "next_fee_step", skip_serializing_if = "Option::is_none")] + pub next_fee_step: Option, + #[serde(alias = "inflight[]")] + pub inflight: Vec, + #[serde(alias = "close_to", skip_serializing_if = "Option::is_none")] + pub close_to: Option, + #[serde(alias = "private", skip_serializing_if = "Option::is_none")] + pub private: Option, + // Path `ListPeers.peers[].channels[].opener` + #[serde(rename = "opener")] + pub opener: ChannelSide, + pub closer: Option, + #[serde(alias = "features[]")] + pub features: Vec, + #[serde(alias = "to_us_msat", skip_serializing_if = "Option::is_none")] + pub to_us_msat: Option, + #[serde(alias = "min_to_us_msat", skip_serializing_if = "Option::is_none")] + pub min_to_us_msat: Option, + #[serde(alias = "max_to_us_msat", skip_serializing_if = "Option::is_none")] + pub max_to_us_msat: Option, + #[serde(alias = "total_msat", skip_serializing_if = "Option::is_none")] + pub total_msat: Option, + #[serde(alias = "fee_base_msat", skip_serializing_if = "Option::is_none")] + pub fee_base_msat: Option, + #[serde(alias = "fee_proportional_millionths", skip_serializing_if = "Option::is_none")] + pub fee_proportional_millionths: Option, + #[serde(alias = "dust_limit_msat", skip_serializing_if = "Option::is_none")] + pub dust_limit_msat: Option, + #[serde(alias = "max_total_htlc_in_msat", skip_serializing_if = "Option::is_none")] + pub max_total_htlc_in_msat: Option, + #[serde(alias = "their_reserve_msat", skip_serializing_if = "Option::is_none")] + pub their_reserve_msat: Option, + #[serde(alias = "our_reserve_msat", skip_serializing_if = "Option::is_none")] + pub our_reserve_msat: Option, + #[serde(alias = "spendable_msat", skip_serializing_if = "Option::is_none")] + pub spendable_msat: Option, + #[serde(alias = "receivable_msat", skip_serializing_if = "Option::is_none")] + pub receivable_msat: Option, + #[serde(alias = "minimum_htlc_in_msat", skip_serializing_if = "Option::is_none")] + pub minimum_htlc_in_msat: Option, + #[serde(alias = "their_to_self_delay", skip_serializing_if = "Option::is_none")] + pub their_to_self_delay: Option, + #[serde(alias = "our_to_self_delay", skip_serializing_if = "Option::is_none")] + pub our_to_self_delay: Option, + #[serde(alias = "max_accepted_htlcs", skip_serializing_if = "Option::is_none")] + pub max_accepted_htlcs: Option, + #[serde(alias = "state_changes[]")] + pub state_changes: Vec, + #[serde(alias = "status[]")] + pub status: Vec, + #[serde(alias = "in_payments_offered", skip_serializing_if = "Option::is_none")] + pub in_payments_offered: Option, + #[serde(alias = "in_offered_msat", skip_serializing_if = "Option::is_none")] + pub in_offered_msat: Option, + #[serde(alias = "in_payments_fulfilled", skip_serializing_if = "Option::is_none")] + pub in_payments_fulfilled: Option, + #[serde(alias = "in_fulfilled_msat", skip_serializing_if = "Option::is_none")] + pub in_fulfilled_msat: Option, + #[serde(alias = "out_payments_offered", skip_serializing_if = "Option::is_none")] + pub out_payments_offered: Option, + #[serde(alias = "out_offered_msat", skip_serializing_if = "Option::is_none")] + pub out_offered_msat: Option, + #[serde(alias = "out_payments_fulfilled", skip_serializing_if = "Option::is_none")] + pub out_payments_fulfilled: Option, + #[serde(alias = "out_fulfilled_msat", skip_serializing_if = "Option::is_none")] + pub out_fulfilled_msat: Option, + #[serde(alias = "htlcs[]")] + pub htlcs: Vec, + #[serde(alias = "close_to_addr", skip_serializing_if = "Option::is_none")] + pub close_to_addr: Option, + } + + #[derive(Clone, Debug, Deserialize, Serialize)] + pub struct ListpeersPeers { + #[serde(alias = "id")] + pub id: String, + #[serde(alias = "connected")] + pub connected: bool, + #[serde(alias = "log[]")] + pub log: Vec, + #[serde(alias = "channels[]")] + pub channels: Vec, + #[serde(alias = "netaddr[]")] + pub netaddr: Vec, + #[serde(alias = "features", skip_serializing_if = "Option::is_none")] + pub features: Option, + } + + #[derive(Clone, Debug, Deserialize, Serialize)] + pub struct ListpeersResponse { + #[serde(alias = "peers[]")] + pub peers: Vec, + } + #[derive(Copy, Clone, Debug, Deserialize, Serialize)] #[serde(rename_all = "lowercase")] pub enum ListfundsOutputsStatus { @@ -204,6 +561,17 @@ pub mod responses { SPENT, } + impl TryFrom for ListfundsOutputsStatus { + type Error = anyhow::Error; + fn try_from(c: i32) -> Result { + match c { + 0 => Ok(ListfundsOutputsStatus::UNCONFIRMED), + 1 => Ok(ListfundsOutputsStatus::CONFIRMED), + 2 => Ok(ListfundsOutputsStatus::SPENT), + o => Err(anyhow::anyhow!("Unknown variant {} for enum ListfundsOutputsStatus", o)), + } + } + } #[derive(Clone, Debug, Deserialize, Serialize)] pub struct ListfundsOutputs { #[serde(alias = "txid")] @@ -323,6 +691,17 @@ pub mod responses { UNOPENED, } + impl TryFrom for CloseType { + type Error = anyhow::Error; + fn try_from(c: i32) -> Result { + match c { + 0 => Ok(CloseType::MUTUAL), + 1 => Ok(CloseType::UNILATERAL), + 2 => Ok(CloseType::UNOPENED), + o => Err(anyhow::anyhow!("Unknown variant {} for enum CloseType", o)), + } + } + } #[derive(Clone, Debug, Deserialize, Serialize)] pub struct CloseResponse { // Path `Close.type` diff --git a/contrib/msggen/msggen/__main__.py b/contrib/msggen/msggen/__main__.py index df4addea0..6b4069e17 100644 --- a/contrib/msggen/msggen/__main__.py +++ b/contrib/msggen/msggen/__main__.py @@ -35,7 +35,7 @@ def load_jsonrpc_method(name): def load_jsonrpc_service(): method_names = [ "Getinfo", - # "ListPeers", + "ListPeers", "ListFunds", # "ListConfigs", "ListChannels",