mirror of
https://github.com/aljazceru/lightning.git
synced 2025-12-20 07:34:24 +01:00
cln-rpc: Add Sha256 and Secret types
This commit is contained in:
committed by
Rusty Russell
parent
cd9c00b629
commit
d0f6e8c8a6
@@ -180,10 +180,90 @@ impl ShortChannelId {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub type Secret = [u8; 32];
|
#[derive(Clone, Debug)]
|
||||||
pub type Txid = [u8; 32];
|
pub struct Secret([u8; 32]);
|
||||||
pub type Hash = [u8; 32];
|
|
||||||
pub type NodeId = Pubkey;
|
impl TryFrom<Vec<u8>> for Secret {
|
||||||
|
type Error = crate::Error;
|
||||||
|
fn try_from(v: Vec<u8>) -> Result<Self, crate::Error> {
|
||||||
|
if v.len() != 32 {
|
||||||
|
Err(anyhow!("Unexpected secret length: {}", hex::encode(v)))
|
||||||
|
} else {
|
||||||
|
Ok(Secret(v.try_into().unwrap()))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Serialize for Secret {
|
||||||
|
fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
|
||||||
|
where
|
||||||
|
S: Serializer,
|
||||||
|
{
|
||||||
|
serializer.serialize_str(&hex::encode(&self.0))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<'de> Deserialize<'de> for Secret {
|
||||||
|
fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
|
||||||
|
where
|
||||||
|
D: Deserializer<'de>,
|
||||||
|
{
|
||||||
|
use serde::de::Error;
|
||||||
|
let s: String = Deserialize::deserialize(deserializer)?;
|
||||||
|
let h = hex::decode(s).map_err(|_| Error::custom("not a valid hex string"))?;
|
||||||
|
Ok(Secret(h.try_into().map_err(|_| {
|
||||||
|
Error::custom("not a valid hex-encoded hash")
|
||||||
|
})?))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Secret {
|
||||||
|
pub fn to_vec(self) -> Vec<u8> {
|
||||||
|
self.0.to_vec()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Clone, Debug)]
|
||||||
|
pub struct Sha256([u8; 32]);
|
||||||
|
impl Sha256 {
|
||||||
|
pub fn to_vec(self) -> Vec<u8> {
|
||||||
|
self.0.to_vec()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl TryFrom<Vec<u8>> for Sha256 {
|
||||||
|
type Error = crate::Error;
|
||||||
|
fn try_from(v: Vec<u8>) -> Result<Self, crate::Error> {
|
||||||
|
if v.len() != 32 {
|
||||||
|
Err(anyhow!("Unexpected hash length: {}", hex::encode(v)))
|
||||||
|
} else {
|
||||||
|
Ok(Sha256(v.try_into().unwrap()))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Serialize for Sha256 {
|
||||||
|
fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
|
||||||
|
where
|
||||||
|
S: Serializer,
|
||||||
|
{
|
||||||
|
serializer.serialize_str(&hex::encode(&self.0))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<'de> Deserialize<'de> for Sha256 {
|
||||||
|
fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
|
||||||
|
where
|
||||||
|
D: Deserializer<'de>,
|
||||||
|
{
|
||||||
|
use serde::de::Error;
|
||||||
|
let s: String = Deserialize::deserialize(deserializer)?;
|
||||||
|
let h = hex::decode(s).map_err(|_| Error::custom("not a valid hex string"))?;
|
||||||
|
Ok(Sha256(h.try_into().map_err(|_| {
|
||||||
|
Error::custom("not a valid hex-encoded hash")
|
||||||
|
})?))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
#[derive(Clone, Debug, PartialEq)]
|
#[derive(Clone, Debug, PartialEq)]
|
||||||
pub struct Outpoint {
|
pub struct Outpoint {
|
||||||
|
|||||||
@@ -27,6 +27,8 @@ typemap = {
|
|||||||
"outpoint": "Outpoint",
|
"outpoint": "Outpoint",
|
||||||
"feerate": "Feerate",
|
"feerate": "Feerate",
|
||||||
"outputdesc": "OutputDesc",
|
"outputdesc": "OutputDesc",
|
||||||
|
"secret": "bytes",
|
||||||
|
"hash": "bytes",
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@@ -274,10 +276,11 @@ class GrpcConverterGenerator:
|
|||||||
# array. The current item is called `i`
|
# array. The current item is called `i`
|
||||||
mapping = {
|
mapping = {
|
||||||
'hex': f'hex::decode(i).unwrap()',
|
'hex': f'hex::decode(i).unwrap()',
|
||||||
|
'secret': f'i.clone().to_vec()',
|
||||||
}.get(typ, f'i.into()')
|
}.get(typ, f'i.into()')
|
||||||
|
|
||||||
if f.required:
|
if f.required:
|
||||||
self.write(f"{name}: c.{name}.iter().map(|i| {mapping}).collect(), // Rule #3 \n", numindent=3)
|
self.write(f"{name}: c.{name}.iter().map(|i| {mapping}).collect(), // Rule #3 for type {typ} \n", numindent=3)
|
||||||
else:
|
else:
|
||||||
self.write(f"{name}: c.{name}.as_ref().map(|arr| arr.iter().map(|i| {mapping}).collect()).unwrap_or(vec![]), // Rule #3 \n", numindent=3)
|
self.write(f"{name}: c.{name}.as_ref().map(|arr| arr.iter().map(|i| {mapping}).collect()).unwrap_or(vec![]), // Rule #3 \n", numindent=3)
|
||||||
elif isinstance(f, EnumField):
|
elif isinstance(f, EnumField):
|
||||||
@@ -306,6 +309,10 @@ class GrpcConverterGenerator:
|
|||||||
'txid?': f'c.{name}.as_ref().map(|v| hex::decode(&v).unwrap())',
|
'txid?': f'c.{name}.as_ref().map(|v| hex::decode(&v).unwrap())',
|
||||||
'short_channel_id': f'c.{name}.to_string()',
|
'short_channel_id': f'c.{name}.to_string()',
|
||||||
'short_channel_id?': f'c.{name}.as_ref().map(|v| v.to_string())',
|
'short_channel_id?': f'c.{name}.as_ref().map(|v| v.to_string())',
|
||||||
|
'hash': f'c.{name}.clone().to_vec()',
|
||||||
|
'hash?': f'c.{name}.clone().map(|v| v.to_vec())',
|
||||||
|
'secret': f'c.{name}.clone().to_vec()',
|
||||||
|
'secret?': f'c.{name}.clone().map(|v| v.to_vec())',
|
||||||
}.get(
|
}.get(
|
||||||
typ,
|
typ,
|
||||||
f'c.{name}.clone()' # default to just assignment
|
f'c.{name}.clone()' # default to just assignment
|
||||||
@@ -385,6 +392,7 @@ class GrpcUnconverterGenerator(GrpcConverterGenerator):
|
|||||||
mapping = {
|
mapping = {
|
||||||
'hex': f'hex::encode(s)',
|
'hex': f'hex::encode(s)',
|
||||||
'u32': f's.clone()',
|
'u32': f's.clone()',
|
||||||
|
'secret': f's.clone().try_into().unwrap()'
|
||||||
}.get(typ, f's.into()')
|
}.get(typ, f's.into()')
|
||||||
if f.required:
|
if f.required:
|
||||||
self.write(f"{name}: c.{name}.iter().map(|s| {mapping}).collect(), // Rule #4\n", numindent=3)
|
self.write(f"{name}: c.{name}.iter().map(|s| {mapping}).collect(), // Rule #4\n", numindent=3)
|
||||||
@@ -422,6 +430,11 @@ class GrpcUnconverterGenerator(GrpcConverterGenerator):
|
|||||||
'RoutehintList?': f'c.{name}.clone().map(|rl| rl.into())',
|
'RoutehintList?': f'c.{name}.clone().map(|rl| rl.into())',
|
||||||
'short_channel_id': f'cln_rpc::primitives::ShortChannelId::from_str(&c.{name}).unwrap()',
|
'short_channel_id': f'cln_rpc::primitives::ShortChannelId::from_str(&c.{name}).unwrap()',
|
||||||
'short_channel_id?': f'c.{name}.as_ref().map(|v| cln_rpc::primitives::ShortChannelId::from_str(&v).unwrap())',
|
'short_channel_id?': f'c.{name}.as_ref().map(|v| cln_rpc::primitives::ShortChannelId::from_str(&v).unwrap())',
|
||||||
|
'secret': f'c.{name}.clone().try_into().unwrap()',
|
||||||
|
'secret?': f'c.{name}.clone().map(|v| v.try_into().unwrap())',
|
||||||
|
'hash': f'c.{name}.clone().try_into().unwrap()',
|
||||||
|
'hash?': f'c.{name}.clone().map(|v| v.try_into().unwrap())',
|
||||||
|
'txid': f'hex::encode(&c.{name})',
|
||||||
}.get(
|
}.get(
|
||||||
typ,
|
typ,
|
||||||
f'c.{name}.clone()' # default to just assignment
|
f'c.{name}.clone()' # default to just assignment
|
||||||
|
|||||||
@@ -218,6 +218,7 @@ class EnumField(Field):
|
|||||||
values = ",".join([v for v in self.values if v is not None])
|
values = ",".join([v for v in self.values if v is not None])
|
||||||
return f"Enum[path={self.path}, required={self.required}, values=[{values}]]"
|
return f"Enum[path={self.path}, required={self.required}, values=[{values}]]"
|
||||||
|
|
||||||
|
|
||||||
class UnionField(Field):
|
class UnionField(Field):
|
||||||
"""A type that can be one of a number of types.
|
"""A type that can be one of a number of types.
|
||||||
|
|
||||||
@@ -278,6 +279,8 @@ class PrimitiveField(Field):
|
|||||||
"feerate",
|
"feerate",
|
||||||
"utxo", # A string representing the tuple (txid, outnum)
|
"utxo", # A string representing the tuple (txid, outnum)
|
||||||
"outputdesc", # A dict that maps an address to an amount (bitcoind style)
|
"outputdesc", # A dict that maps an address to an amount (bitcoind style)
|
||||||
|
"secret",
|
||||||
|
"hash",
|
||||||
]
|
]
|
||||||
|
|
||||||
def __init__(self, typename, path, description):
|
def __init__(self, typename, path, description):
|
||||||
|
|||||||
@@ -47,6 +47,8 @@ typemap = {
|
|||||||
'feerate': 'Feerate',
|
'feerate': 'Feerate',
|
||||||
'outpoint': 'Outpoint',
|
'outpoint': 'Outpoint',
|
||||||
'outputdesc': 'OutputDesc',
|
'outputdesc': 'OutputDesc',
|
||||||
|
'hash': 'Sha256',
|
||||||
|
'secret': 'Secret',
|
||||||
}
|
}
|
||||||
|
|
||||||
header = f"""#![allow(non_camel_case_types)]
|
header = f"""#![allow(non_camel_case_types)]
|
||||||
|
|||||||
@@ -316,6 +316,13 @@ def _extra_validator(is_request: bool):
|
|||||||
return False
|
return False
|
||||||
return instance[0:2] == "02" or instance[0:2] == "03"
|
return instance[0:2] == "02" or instance[0:2] == "03"
|
||||||
|
|
||||||
|
def is_32byte_hex(self, instance):
|
||||||
|
"""Fixed size 32 byte hex string
|
||||||
|
|
||||||
|
This matches a variety of hex types: secrets, hashes, txid
|
||||||
|
"""
|
||||||
|
return self.is_type(instance, "hex") and len(instance) == 64
|
||||||
|
|
||||||
def is_point32(checker, instance):
|
def is_point32(checker, instance):
|
||||||
"""x-only BIP-340 public key"""
|
"""x-only BIP-340 public key"""
|
||||||
if not checker.is_type(instance, "hex"):
|
if not checker.is_type(instance, "hex"):
|
||||||
@@ -389,6 +396,8 @@ def _extra_validator(is_request: bool):
|
|||||||
is_msat = is_msat_response
|
is_msat = is_msat_response
|
||||||
type_checker = jsonschema.Draft7Validator.TYPE_CHECKER.redefine_many({
|
type_checker = jsonschema.Draft7Validator.TYPE_CHECKER.redefine_many({
|
||||||
"hex": is_hex,
|
"hex": is_hex,
|
||||||
|
"hash": is_32byte_hex,
|
||||||
|
"secret": is_32byte_hex,
|
||||||
"u64": is_u64,
|
"u64": is_u64,
|
||||||
"u32": is_u32,
|
"u32": is_u32,
|
||||||
"u16": is_u16,
|
"u16": is_u16,
|
||||||
|
|||||||
Reference in New Issue
Block a user