diff --git a/cln-grpc/proto/primitives.proto b/cln-grpc/proto/primitives.proto index b440936d3..2f04e1410 100644 --- a/cln-grpc/proto/primitives.proto +++ b/cln-grpc/proto/primitives.proto @@ -39,4 +39,9 @@ message Feerate { uint32 perkb = 4; uint32 perkw = 5; } +} + +message OutputDesc { + string address = 1; + Amount amount = 2; } \ No newline at end of file diff --git a/cln-grpc/src/pb.rs b/cln-grpc/src/pb.rs index 12ae1d117..2c2b98828 100644 --- a/cln-grpc/src/pb.rs +++ b/cln-grpc/src/pb.rs @@ -1,6 +1,8 @@ tonic::include_proto!("cln"); -use cln_rpc::primitives::{Amount as JAmount, Utxo as JUtxo}; +use cln_rpc::primitives::{ + Amount as JAmount, Feerate as JFeerate, OutputDesc as JOutputDesc, Utxo as JUtxo, +}; impl From for Amount { fn from(a: JAmount) -> Self { @@ -34,7 +36,6 @@ impl From<&Utxo> for JUtxo { impl From<&Feerate> for cln_rpc::primitives::Feerate { fn from(f: &Feerate) -> cln_rpc::primitives::Feerate { - use cln_rpc::primitives::Feerate as JFeerate; use feerate::Style; match f.style.clone().unwrap() { Style::Slow(_) => JFeerate::Slow, @@ -45,3 +46,12 @@ impl From<&Feerate> for cln_rpc::primitives::Feerate { } } } + +impl From<&OutputDesc> for JOutputDesc { + fn from(od: &OutputDesc) -> JOutputDesc { + JOutputDesc { + address: od.address.clone(), + amount: od.amount.as_ref().unwrap().into(), + } + } +} diff --git a/cln-rpc/src/primitives.rs b/cln-rpc/src/primitives.rs index 355e42142..b9a2349cc 100644 --- a/cln-rpc/src/primitives.rs +++ b/cln-rpc/src/primitives.rs @@ -368,8 +368,60 @@ mod test { for (input, output) in tests.into_iter() { let parsed: Feerate = input.try_into().unwrap(); assert_eq!(parsed, output); - let serialized: String = (&parsed).into(); - assert_eq!(serialized, input); + let serialized: String = (&parsed).into(); + assert_eq!(serialized, input); } } + + #[test] + fn test_parse_output_desc() { + let a = r#"{"address":"1234msat"}"#; + let od = serde_json::from_str(a).unwrap(); + + assert_eq!( + OutputDesc { + address: "address".to_string(), + amount: Amount { msat: 1234 } + }, + od + ); + let serialized: String = serde_json::to_string(&od).unwrap(); + assert_eq!(a, serialized); + } +} + +#[derive(Clone, Debug, PartialEq)] +pub struct OutputDesc { + pub address: String, + pub amount: Amount, +} + +impl<'de> Deserialize<'de> for OutputDesc { + fn deserialize(deserializer: D) -> Result + where + D: Deserializer<'de>, + { + let map: std::collections::HashMap = + Deserialize::deserialize(deserializer)?; + + let (address, amount) = map.iter().next().unwrap(); + + Ok(OutputDesc { + address: address.to_string(), + amount: *amount, + }) + } +} + +impl Serialize for OutputDesc { + fn serialize(&self, serializer: S) -> Result + where + S: Serializer, + { + use serde::ser::SerializeMap; + let mut map = serializer.serialize_map(Some(1))?; + map.serialize_key(&self.address)?; + map.serialize_value(&self.amount)?; + map.end() + } } diff --git a/contrib/msggen/msggen/model.py b/contrib/msggen/msggen/model.py index 532a8ec91..db5812917 100644 --- a/contrib/msggen/msggen/model.py +++ b/contrib/msggen/msggen/model.py @@ -232,6 +232,7 @@ class PrimitiveField(Field): "number", "feerate", "utxo", # A string representing the tuple (txid, outnum) + "OutputDesc", # A dict that maps an address to an amount (bitcoind style) ] def __init__(self, typename, path, description):