X-Git-Url: http://git.bitcoin.ninja/index.cgi?p=ldk-c-bindings;a=blobdiff_plain;f=lightning-c-bindings%2Fsrc%2Fc_types%2Fmod.rs;h=6267b80bc2dd007ba9476f76d01127d2b9a74937;hp=14e37229cf497a44140eee30731b2e6a95d52390;hb=d3d51441b4cd98389308d4cfaba6548f25598c4c;hpb=07fe5cf2e1b469125e8fdb97175593399888485b diff --git a/lightning-c-bindings/src/c_types/mod.rs b/lightning-c-bindings/src/c_types/mod.rs index 14e3722..6267b80 100644 --- a/lightning-c-bindings/src/c_types/mod.rs +++ b/lightning-c-bindings/src/c_types/mod.rs @@ -3,16 +3,31 @@ /// Auto-generated C-mapped types for templated containers pub mod derived; -use bitcoin::Script as BitcoinScript; use bitcoin::Transaction as BitcoinTransaction; use bitcoin::hashes::Hash; use bitcoin::secp256k1::key::PublicKey as SecpPublicKey; use bitcoin::secp256k1::key::SecretKey as SecpSecretKey; use bitcoin::secp256k1::Signature as SecpSignature; use bitcoin::secp256k1::Error as SecpError; +use bitcoin::secp256k1::recovery::RecoveryId; +use bitcoin::secp256k1::recovery::RecoverableSignature as SecpRecoverableSignature; +use bitcoin::bech32; use std::convert::TryInto; // Bindings need at least rustc 1.34 +/// Integer in the range `0..32` +#[derive(PartialEq, Eq, Copy, Clone)] +#[allow(non_camel_case_types)] +#[repr(C)] +pub struct u5(u8); + +impl From for u5 { + fn from(o: bech32::u5) -> Self { Self(o.to_u8()) } +} +impl Into for u5 { + fn into(self) -> bech32::u5 { bech32::u5::try_from_u8(self.0).expect("u5 objects must be in the range 0..32") } +} + #[derive(Clone)] #[repr(C)] /// Represents a valid secp256k1 public key serialized in "compressed form" as a 33 byte array. @@ -72,6 +87,32 @@ impl Signature { #[allow(unused)] pub(crate) fn null() -> Self { Self { compact_form: [0; 64] } } } +#[repr(C)] +#[derive(Clone)] +/// Represents a secp256k1 signature serialized as two 32-byte numbers as well as a tag which +/// allows recovering the exact public key which created the signature given the message. +pub struct RecoverableSignature { + /// The bytes of the signature in "compact" form plus a "Recovery ID" which allows for + /// recovery. + pub serialized_form: [u8; 68], +} +impl RecoverableSignature { + pub(crate) fn from_rust(pk: &SecpRecoverableSignature) -> Self { + let (id, compact_form) = pk.serialize_compact(); + let mut serialized_form = [0; 68]; + serialized_form[0..64].copy_from_slice(&compact_form[..]); + serialized_form[64..].copy_from_slice(&id.to_i32().to_le_bytes()); + Self { serialized_form } + } + pub(crate) fn into_rust(&self) -> SecpRecoverableSignature { + let mut id = [0; 4]; + id.copy_from_slice(&self.serialized_form[64..]); + SecpRecoverableSignature::from_compact(&self.serialized_form[0..64], + RecoveryId::from_i32(i32::from_le_bytes(id)).expect("Invalid Recovery ID")) + .unwrap() + } +} + #[repr(C)] /// Represents an error returned from libsecp256k1 during validation of some secp256k1 data pub enum Secp256k1Error { @@ -188,9 +229,10 @@ impl Transaction { if self.datalen == 0 { panic!("0-length buffer can never represent a valid Transaction"); } ::bitcoin::consensus::encode::deserialize(unsafe { std::slice::from_raw_parts(self.data, self.datalen) }).unwrap() } - pub(crate) fn from_vec(v: Vec) -> Self { - let datalen = v.len(); - let data = Box::into_raw(v.into_boxed_slice()); + pub(crate) fn from_bitcoin(btc: &BitcoinTransaction) -> Self { + let vec = ::bitcoin::consensus::encode::serialize(btc); + let datalen = vec.len(); + let data = Box::into_raw(vec.into_boxed_slice()); Self { data: unsafe { (*data).as_mut_ptr() }, datalen, @@ -296,6 +338,10 @@ pub struct TenBytes { /** The ten bytes */ pub data: [u8; 10], } #[repr(C)] /// A 16-byte byte array. pub struct SixteenBytes { /** The sixteen bytes */ pub data: [u8; 16], } +#[derive(Clone)] +#[repr(C)] +/// A 20-byte byte array. +pub struct TwentyBytes { /** The twenty bytes */ pub data: [u8; 20], } pub(crate) struct VecWriter(pub Vec); impl lightning::util::ser::Writer for VecWriter { @@ -320,27 +366,62 @@ pub(crate) fn deserialize_obj_arg>(s } #[repr(C)] -#[derive(Copy, Clone)] +#[derive(Clone)] /// A Rust str object, ie a reference to a UTF8-valid string. /// This is *not* null-terminated so cannot be used directly as a C string! pub struct Str { /// A pointer to the string's bytes, in UTF8 encoding pub chars: *const u8, /// The number of bytes (not characters!) pointed to by `chars` - pub len: usize + pub len: usize, + /// Whether the data pointed to by `chars` should be freed or not. + pub chars_is_owned: bool, } impl Into for &'static str { fn into(self) -> Str { - Str { chars: self.as_ptr(), len: self.len() } + Str { chars: self.as_ptr(), len: self.len(), chars_is_owned: false } } } -impl Into<&'static str> for Str { - fn into(self) -> &'static str { +impl Str { + pub(crate) fn into_str(&self) -> &'static str { if self.len == 0 { return ""; } std::str::from_utf8(unsafe { std::slice::from_raw_parts(self.chars, self.len) }).unwrap() } + pub(crate) fn into_string(mut self) -> String { + let bytes = if self.len == 0 { + Vec::new() + } else if self.chars_is_owned { + let ret = unsafe { + Box::from_raw(std::slice::from_raw_parts_mut(unsafe { self.chars as *mut u8 }, self.len)) + }.into(); + self.chars_is_owned = false; + ret + } else { + let mut ret = Vec::with_capacity(self.len); + ret.extend_from_slice(unsafe { std::slice::from_raw_parts(self.chars, self.len) }); + ret + }; + String::from_utf8(bytes).unwrap() + } +} +impl Into for String { + fn into(self) -> Str { + let s = Box::leak(self.into_boxed_str()); + Str { chars: s.as_ptr(), len: s.len(), chars_is_owned: true } + } } +impl Drop for Str { + fn drop(&mut self) { + if self.chars_is_owned && self.len != 0 { + let _ = derived::CVec_u8Z { data: self.chars as *mut u8, datalen: self.len }; + } + } +} +#[no_mangle] +/// Frees the data buffer, if chars_is_owned is set and len > 0. +pub extern "C" fn Str_free(_res: Str) { } + // Note that the C++ headers memset(0) all the Templ types to avoid deallocation! // Thus, they must gracefully handle being completely null in _free.