generate composite fields in grpc

This commit is contained in:
Jesse de Wit 2022-12-24 11:32:58 +01:00 committed by Christian Decker
parent 42e038b9ad
commit 241cd8d012
6 changed files with 521 additions and 330 deletions

View file

@ -70,6 +70,7 @@ message GetinfoResponse {
uint32 num_inactive_channels = 7;
string version = 8;
string lightning_dir = 9;
optional GetinfoOur_features our_features = 10;
uint32 blockheight = 11;
string network = 12;
optional uint64 msatoshi_fees_collected = 18;
@ -173,6 +174,7 @@ message ListpeersPeersChannels {
}
ListpeersPeersChannelsState state = 1;
optional bytes scratch_txid = 2;
optional ListpeersPeersChannelsFeerate feerate = 3;
optional string owner = 4;
optional string short_channel_id = 5;
optional bytes channel_id = 6;
@ -188,6 +190,7 @@ message ListpeersPeersChannels {
ChannelSide opener = 16;
optional ChannelSide closer = 17;
repeated string features = 18;
optional ListpeersPeersChannelsFunding funding = 19;
optional Amount to_us_msat = 20;
optional Amount min_to_us_msat = 21;
optional Amount max_to_us_msat = 22;
@ -206,6 +209,7 @@ message ListpeersPeersChannels {
optional uint32 their_to_self_delay = 33;
optional uint32 our_to_self_delay = 34;
optional uint32 max_accepted_htlcs = 35;
optional ListpeersPeersChannelsAlias alias = 50;
repeated string status = 37;
optional uint64 in_payments_offered = 38;
optional Amount in_offered_msat = 39;
@ -438,6 +442,7 @@ message ConnectResponse {
bytes id = 1;
bytes features = 2;
ConnectDirection direction = 3;
ConnectAddress address = 4;
}
message ConnectAddress {
@ -649,6 +654,7 @@ message ListinvoicesInvoices {
message SendonionRequest {
bytes onion = 1;
SendonionFirst_hop first_hop = 2;
bytes payment_hash = 3;
optional string label = 4;
repeated bytes shared_secrets = 5;
@ -1115,6 +1121,9 @@ message FeeratesRequest {
message FeeratesResponse {
optional string warning_missing_feerates = 1;
optional FeeratesPerkb perkb = 2;
optional FeeratesPerkw perkw = 3;
optional FeeratesOnchain_fee_estimates onchain_fee_estimates = 4;
}
message FeeratesPerkb {

124
cln-grpc/src/convert.rs generated
View file

@ -12,6 +12,18 @@ use bitcoin::hashes::sha256::Hash as Sha256;
use bitcoin::hashes::Hash;
use cln_rpc::primitives::PublicKey;
#[allow(unused_variables)]
impl From<responses::GetinfoOur_features> for pb::GetinfoOurFeatures {
fn from(c: responses::GetinfoOur_features) -> Self {
Self {
init: hex::decode(&c.init).unwrap(), // Rule #2 for type hex
node: hex::decode(&c.node).unwrap(), // Rule #2 for type hex
channel: hex::decode(&c.channel).unwrap(), // Rule #2 for type hex
invoice: hex::decode(&c.invoice).unwrap(), // Rule #2 for type hex
}
}
}
#[allow(unused_variables)]
impl From<responses::GetinfoAddress> for pb::GetinfoAddress {
fn from(c: responses::GetinfoAddress) -> Self {
@ -48,6 +60,7 @@ impl From<responses::GetinfoResponse> for pb::GetinfoResponse {
num_inactive_channels: c.num_inactive_channels, // Rule #2 for type u32
version: c.version, // Rule #2 for type string
lightning_dir: c.lightning_dir, // Rule #2 for type string
our_features: c.our_features.map(|v| v.into()),
blockheight: c.blockheight, // Rule #2 for type u32
network: c.network, // Rule #2 for type string
msatoshi_fees_collected: c.msatoshi_fees_collected, // Rule #2 for type u64?
@ -75,6 +88,16 @@ impl From<responses::ListpeersPeersLog> for pb::ListpeersPeersLog {
}
}
#[allow(unused_variables)]
impl From<responses::ListpeersPeersChannelsFeerate> for pb::ListpeersPeersChannelsFeerate {
fn from(c: responses::ListpeersPeersChannelsFeerate) -> Self {
Self {
perkw: c.perkw, // Rule #2 for type u32
perkb: c.perkb, // Rule #2 for type u32
}
}
}
#[allow(unused_variables)]
impl From<responses::ListpeersPeersChannelsInflight> for pb::ListpeersPeersChannelsInflight {
fn from(c: responses::ListpeersPeersChannelsInflight) -> Self {
@ -89,6 +112,31 @@ impl From<responses::ListpeersPeersChannelsInflight> for pb::ListpeersPeersChann
}
}
#[allow(unused_variables)]
impl From<responses::ListpeersPeersChannelsFunding> for pb::ListpeersPeersChannelsFunding {
fn from(c: responses::ListpeersPeersChannelsFunding) -> Self {
Self {
local_msat: c.local_msat.map(|f| f.into()), // Rule #2 for type msat?
remote_msat: c.remote_msat.map(|f| f.into()), // Rule #2 for type msat?
pushed_msat: c.pushed_msat.map(|f| f.into()), // Rule #2 for type msat?
local_funds_msat: Some(c.local_funds_msat.into()), // Rule #2 for type msat
remote_funds_msat: Some(c.remote_funds_msat.into()), // Rule #2 for type msat
fee_paid_msat: c.fee_paid_msat.map(|f| f.into()), // Rule #2 for type msat?
fee_rcvd_msat: c.fee_rcvd_msat.map(|f| f.into()), // Rule #2 for type msat?
}
}
}
#[allow(unused_variables)]
impl From<responses::ListpeersPeersChannelsAlias> for pb::ListpeersPeersChannelsAlias {
fn from(c: responses::ListpeersPeersChannelsAlias) -> Self {
Self {
local: c.local.map(|v| v.to_string()), // Rule #2 for type short_channel_id?
remote: c.remote.map(|v| v.to_string()), // Rule #2 for type short_channel_id?
}
}
}
#[allow(unused_variables)]
impl From<responses::ListpeersPeersChannelsHtlcs> for pb::ListpeersPeersChannelsHtlcs {
fn from(c: responses::ListpeersPeersChannelsHtlcs) -> Self {
@ -110,6 +158,7 @@ impl From<responses::ListpeersPeersChannels> for pb::ListpeersPeersChannels {
Self {
state: c.state as i32,
scratch_txid: c.scratch_txid.map(|v| hex::decode(v).unwrap()), // Rule #2 for type txid?
feerate: c.feerate.map(|v| v.into()),
owner: c.owner, // Rule #2 for type string?
short_channel_id: c.short_channel_id.map(|v| v.to_string()), // Rule #2 for type short_channel_id?
channel_id: c.channel_id.map(|v| v.to_vec()), // Rule #2 for type hash?
@ -125,6 +174,7 @@ impl From<responses::ListpeersPeersChannels> for pb::ListpeersPeersChannels {
opener: c.opener as i32,
closer: c.closer.map(|v| v as i32),
features: c.features.into_iter().map(|i| i.into()).collect(), // Rule #3 for type ListpeersPeersChannelsFeatures
funding: c.funding.map(|v| v.into()),
to_us_msat: c.to_us_msat.map(|f| f.into()), // Rule #2 for type msat?
min_to_us_msat: c.min_to_us_msat.map(|f| f.into()), // Rule #2 for type msat?
max_to_us_msat: c.max_to_us_msat.map(|f| f.into()), // Rule #2 for type msat?
@ -143,6 +193,7 @@ impl From<responses::ListpeersPeersChannels> for pb::ListpeersPeersChannels {
their_to_self_delay: c.their_to_self_delay, // Rule #2 for type u32?
our_to_self_delay: c.our_to_self_delay, // Rule #2 for type u32?
max_accepted_htlcs: c.max_accepted_htlcs, // Rule #2 for type u32?
alias: c.alias.map(|v| v.into()),
status: c.status.map(|arr| arr.into_iter().map(|i| i.into()).collect()).unwrap_or(vec![]), // Rule #3
in_payments_offered: c.in_payments_offered, // Rule #2 for type u64?
in_offered_msat: c.in_offered_msat.map(|f| f.into()), // Rule #2 for type msat?
@ -320,6 +371,18 @@ impl From<responses::CloseResponse> for pb::CloseResponse {
}
}
#[allow(unused_variables)]
impl From<responses::ConnectAddress> for pb::ConnectAddress {
fn from(c: responses::ConnectAddress) -> Self {
Self {
item_type: c.item_type as i32,
socket: c.socket, // Rule #2 for type string?
address: c.address, // Rule #2 for type string?
port: c.port.map(|v| v.into()), // Rule #2 for type u16?
}
}
}
#[allow(unused_variables)]
impl From<responses::ConnectResponse> for pb::ConnectResponse {
fn from(c: responses::ConnectResponse) -> Self {
@ -327,6 +390,7 @@ impl From<responses::ConnectResponse> for pb::ConnectResponse {
id: c.id.serialize().to_vec(), // Rule #2 for type pubkey
features: hex::decode(&c.features).unwrap(), // Rule #2 for type hex
direction: c.direction as i32,
address: Some(c.address.into()),
}
}
}
@ -850,11 +914,59 @@ impl From<responses::DisconnectResponse> for pb::DisconnectResponse {
}
}
#[allow(unused_variables)]
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
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?
delayed_to_us: c.delayed_to_us, // Rule #2 for type u32?
htlc_resolution: c.htlc_resolution, // Rule #2 for type u32?
penalty: c.penalty, // Rule #2 for type u32?
}
}
}
#[allow(unused_variables)]
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
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?
delayed_to_us: c.delayed_to_us, // Rule #2 for type u32?
htlc_resolution: c.htlc_resolution, // Rule #2 for type u32?
penalty: c.penalty, // Rule #2 for type u32?
}
}
}
#[allow(unused_variables)]
impl From<responses::FeeratesOnchain_fee_estimates> for pb::FeeratesOnchainFeeEstimates {
fn from(c: responses::FeeratesOnchain_fee_estimates) -> Self {
Self {
opening_channel_satoshis: c.opening_channel_satoshis, // Rule #2 for type u64
mutual_close_satoshis: c.mutual_close_satoshis, // Rule #2 for type u64
unilateral_close_satoshis: c.unilateral_close_satoshis, // Rule #2 for type u64
htlc_timeout_satoshis: c.htlc_timeout_satoshis, // Rule #2 for type u64
htlc_success_satoshis: c.htlc_success_satoshis, // Rule #2 for type u64
}
}
}
#[allow(unused_variables)]
impl From<responses::FeeratesResponse> for pb::FeeratesResponse {
fn from(c: responses::FeeratesResponse) -> Self {
Self {
warning_missing_feerates: c.warning_missing_feerates, // Rule #2 for type string?
perkb: c.perkb.map(|v| v.into()),
perkw: c.perkw.map(|v| v.into()),
onchain_fee_estimates: c.onchain_fee_estimates.map(|v| v.into()),
}
}
}
@ -1244,11 +1356,23 @@ impl From<pb::ListinvoicesRequest> for requests::ListinvoicesRequest {
}
}
#[allow(unused_variables)]
impl From<pb::SendonionFirstHop> for requests::SendonionFirst_hop {
fn from(c: pb::SendonionFirstHop) -> Self {
Self {
id: PublicKey::from_slice(&c.id).unwrap(), // Rule #1 for type pubkey
amount_msat: c.amount_msat.unwrap().into(), // Rule #1 for type msat
delay: c.delay as u16, // Rule #1 for type u16
}
}
}
#[allow(unused_variables)]
impl From<pb::SendonionRequest> for requests::SendonionRequest {
fn from(c: pb::SendonionRequest) -> Self {
Self {
onion: hex::encode(&c.onion), // Rule #1 for type hex
first_hop: c.first_hop.unwrap().into(),
payment_hash: Sha256::from_slice(&c.payment_hash).unwrap(), // Rule #1 for type hash
label: c.label, // Rule #1 for type string?
shared_secrets: Some(c.shared_secrets.into_iter().map(|s| s.try_into().unwrap()).collect()), // Rule #4

18
cln-rpc/src/model.rs generated
View file

@ -608,6 +608,8 @@ pub mod requests {
pub struct SendonionRequest {
#[serde(alias = "onion")]
pub onion: String,
#[serde(alias = "first_hop")]
pub first_hop: SendonionFirst_hop,
#[serde(alias = "payment_hash")]
pub payment_hash: Sha256,
#[serde(alias = "label", skip_serializing_if = "Option::is_none")]
@ -1455,6 +1457,8 @@ pub mod responses {
pub version: String,
#[serde(alias = "lightning-dir")]
pub lightning_dir: String,
#[serde(alias = "our_features", skip_serializing_if = "Option::is_none")]
pub our_features: Option<GetinfoOur_features>,
#[serde(alias = "blockheight")]
pub blockheight: u32,
#[serde(alias = "network")]
@ -1695,6 +1699,8 @@ pub mod responses {
pub state: ListpeersPeersChannelsState,
#[serde(alias = "scratch_txid", skip_serializing_if = "Option::is_none")]
pub scratch_txid: Option<String>,
#[serde(alias = "feerate", skip_serializing_if = "Option::is_none")]
pub feerate: Option<ListpeersPeersChannelsFeerate>,
#[serde(alias = "owner", skip_serializing_if = "Option::is_none")]
pub owner: Option<String>,
#[serde(alias = "short_channel_id", skip_serializing_if = "Option::is_none")]
@ -1726,6 +1732,8 @@ pub mod responses {
pub closer: Option<ChannelSide>,
#[serde(alias = "features")]
pub features: Vec<String>,
#[serde(alias = "funding", skip_serializing_if = "Option::is_none")]
pub funding: Option<ListpeersPeersChannelsFunding>,
#[serde(alias = "to_us_msat", skip_serializing_if = "Option::is_none")]
pub to_us_msat: Option<Amount>,
#[serde(alias = "min_to_us_msat", skip_serializing_if = "Option::is_none")]
@ -1762,6 +1770,8 @@ pub mod responses {
pub our_to_self_delay: Option<u32>,
#[serde(alias = "max_accepted_htlcs", skip_serializing_if = "Option::is_none")]
pub max_accepted_htlcs: Option<u32>,
#[serde(alias = "alias", skip_serializing_if = "Option::is_none")]
pub alias: Option<ListpeersPeersChannelsAlias>,
#[serde(alias = "state_changes", skip_serializing_if = "crate::is_none_or_empty")]
pub state_changes: Option<Vec<ListpeersPeersChannelsState_changes>>,
#[serde(alias = "status", skip_serializing_if = "crate::is_none_or_empty")]
@ -2194,6 +2204,8 @@ pub mod responses {
// Path `Connect.direction`
#[serde(rename = "direction")]
pub direction: ConnectDirection,
#[serde(alias = "address")]
pub address: ConnectAddress,
}
impl TryFrom<Response> for ConnectResponse {
@ -3488,6 +3500,12 @@ pub mod responses {
pub struct FeeratesResponse {
#[serde(alias = "warning_missing_feerates", skip_serializing_if = "Option::is_none")]
pub warning_missing_feerates: Option<String>,
#[serde(alias = "perkb", skip_serializing_if = "Option::is_none")]
pub perkb: Option<FeeratesPerkb>,
#[serde(alias = "perkw", skip_serializing_if = "Option::is_none")]
pub perkw: Option<FeeratesPerkw>,
#[serde(alias = "onchain_fee_estimates", skip_serializing_if = "Option::is_none")]
pub onchain_fee_estimates: Option<FeeratesOnchain_fee_estimates>,
}
impl TryFrom<Response> for FeeratesResponse {

View file

@ -210,6 +210,11 @@ class GrpcGenerator(IGenerator):
if f.path in overrides:
typename = overrides[f.path]
self.write(f"\t{opt}{typename} {f.normalized()} = {i};\n", False)
elif isinstance(f, CompositeField):
typename = f.typename
if f.path in overrides:
typename = overrides[f.path]
self.write(f"\t{opt}{typename} {f.normalized()} = {i};\n", False)
self.write(f"""}}
""")
@ -256,11 +261,14 @@ class GrpcConverterGenerator(IGenerator):
for f in field.fields:
if isinstance(f, ArrayField):
self.generate_array(prefix, f)
elif isinstance(f, CompositeField):
self.generate_composite(prefix, f)
pbname = self.to_camel_case(field.typename)
# And now we can convert the current field:
self.write(f"""\
#[allow(unused_variables)]
impl From<{prefix}::{field.typename}> for pb::{field.typename} {{
impl From<{prefix}::{field.typename}> for pb::{pbname} {{
fn from(c: {prefix}::{field.typename}) -> Self {{
Self {{
""")
@ -321,6 +329,13 @@ class GrpcConverterGenerator(IGenerator):
self.write(f"{name}: {rhs}, // Rule #2 for type {typ}\n", numindent=3)
elif isinstance(f, CompositeField):
rhs = ""
if f.required:
rhs = f'Some(c.{name}.into())'
else:
rhs = f'c.{name}.map(|v| v.into())'
self.write(f"{name}: {rhs},\n", numindent=3)
self.write(f"""\
}}
}}
@ -328,6 +343,12 @@ class GrpcConverterGenerator(IGenerator):
""")
def to_camel_case(self, snake_str):
components = snake_str.split('_')
# We capitalize the first letter of each component except the first one
# with the 'title' method and join them together.
return components[0] + ''.join(x.title() for x in components[1:])
def generate_requests(self, service):
for meth in service.methods:
req = meth.request
@ -380,12 +401,15 @@ class GrpcUnconverterGenerator(GrpcConverterGenerator):
for f in field.fields:
if isinstance(f, ArrayField):
self.generate_array(prefix, f)
elif isinstance(f, CompositeField):
self.generate_composite(prefix, f)
pbname = self.to_camel_case(field.typename)
# And now we can convert the current field:
self.write(f"""\
#[allow(unused_variables)]
impl From<pb::{field.typename}> for {prefix}::{field.typename} {{
fn from(c: pb::{field.typename}) -> Self {{
impl From<pb::{pbname}> for {prefix}::{field.typename} {{
fn from(c: pb::{pbname}) -> Self {{
Self {{
""")
@ -446,6 +470,13 @@ class GrpcUnconverterGenerator(GrpcConverterGenerator):
f'c.{name}' # default to just assignment
)
self.write(f"{name}: {rhs}, // Rule #1 for type {typ}\n", numindent=3)
elif isinstance(f, CompositeField):
rhs = ""
if f.required:
rhs = f'c.{name}.unwrap().into()'
else:
rhs = f'c.{name}.map(|v| v.into())'
self.write(f"{name}: {rhs},\n", numindent=3)
self.write(f"""\
}}

View file

@ -201,7 +201,16 @@ def gen_composite(c) -> Tuple[str, str]:
r += "".join([f[0] for f in fields])
r += "}\n\n"
return ("", r)
defi = ""
if c.deprecated:
defi += " #[deprecated]\n"
if c.required:
defi += f" #[serde(alias = \"{c.name.name}\")]\n pub {c.name}: {c.typename},\n"
else:
defi += f" #[serde(alias = \"{c.name.name}\", skip_serializing_if = \"Option::is_none\")]\n pub {c.name}: Option<{c.typename}>,\n"
return defi, r
class RustGenerator(IGenerator):

File diff suppressed because one or more lines are too long