Merge pull request #22 from TheBlueMatt/main
[ldk-c-bindings] / lightning-c-bindings / src / c_types / mod.rs
index 14e37229cf497a44140eee30731b2e6a95d52390..6267b80bc2dd007ba9476f76d01127d2b9a74937 100644 (file)
@@ -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<bech32::u5> for u5 {
+       fn from(o: bech32::u5) -> Self { Self(o.to_u8()) }
+}
+impl Into<bech32::u5> 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<u8>) -> 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<u8>);
 impl lightning::util::ser::Writer for VecWriter {
@@ -320,27 +366,62 @@ pub(crate) fn deserialize_obj_arg<A, I: lightning::util::ser::ReadableArgs<A>>(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<Str> 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<Str> 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.