diff --git a/Cargo.lock b/Cargo.lock index f3043b4a..d60df76a 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -316,6 +316,15 @@ dependencies = [ "serde", ] +[[package]] +name = "bincode" +version = "1.3.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b1f45e9417d87227c7a56d22e471c6206462cba514c7590c09aff4cf6d1ddcad" +dependencies = [ + "serde", +] + [[package]] name = "bindgen" version = "0.68.1" @@ -1535,6 +1544,7 @@ dependencies = [ "anyhow", "arcode", "bech32 0.8.1", + "bincode", "bitcoin", "bitflags 2.6.0", "ckb-chain-spec", diff --git a/Cargo.toml b/Cargo.toml index ebec1315..e3c2ed12 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -62,6 +62,7 @@ tokio = { version = "1", features = [ ] } indicatif = "0.16" console = "0.15.8" +bincode = "1.3.3" [profile.release] panic = "abort" diff --git a/src/fiber/serde_utils.rs b/src/fiber/serde_utils.rs index 744665b7..bfea31b9 100644 --- a/src/fiber/serde_utils.rs +++ b/src/fiber/serde_utils.rs @@ -110,3 +110,28 @@ uint_as_hex!(U128Hex, u128); uint_as_hex!(U64Hex, u64); uint_as_hex!(U32Hex, u32); uint_as_hex!(U16Hex, u16); + +pub(crate) mod compact_signature_serde { + use musig2::{BinaryEncoding, CompactSignature, SCHNORR_SIGNATURE_SIZE}; + use serde::{self, Deserialize, Deserializer, Serializer}; + + pub fn serialize(signature: &CompactSignature, serializer: S) -> Result + where + S: Serializer, + { + serializer.serialize_bytes(&signature.to_bytes()) + } + + pub fn deserialize<'de, D>(deserializer: D) -> Result + where + D: Deserializer<'de>, + { + let bytes: &[u8] = Deserialize::deserialize(deserializer)?; + if bytes.len() != SCHNORR_SIGNATURE_SIZE { + return Err(serde::de::Error::custom("expected 64 bytes")); + } + let mut array = [0u8; SCHNORR_SIGNATURE_SIZE]; + array.copy_from_slice(bytes); + Ok(CompactSignature::from_bytes(&array).map_err(serde::de::Error::custom)?) + } +} diff --git a/src/store.rs b/src/store.rs index 02708814..b4704f5a 100644 --- a/src/store.rs +++ b/src/store.rs @@ -13,7 +13,6 @@ use ckb_jsonrpc_types::JsonBytes; use ckb_types::packed::{OutPoint, Script}; use ckb_types::prelude::Entity; use rocksdb::{prelude::*, DBIterator, Direction, IteratorMode, WriteBatch, DB}; -use serde_json; use std::io::Write; use std::{ cmp::Ordering, @@ -141,30 +140,28 @@ impl Batch { match key_value { KeyValue::ChannelActorState(id, state) => { let key = [&[CHANNEL_ACTOR_STATE_PREFIX], id.as_ref()].concat(); - self.put( - key, - serde_json::to_vec(&state).expect("serialize ChannelActorState should be OK"), - ); + let value = + bincode::serialize(&state).expect("serialize ChannelActorState should be OK"); + self.put(key, value); } KeyValue::CkbInvoice(id, invoice) => { let key = [&[CKB_INVOICE_PREFIX], id.as_ref()].concat(); - self.put( - key, - serde_json::to_vec(&invoice).expect("serialize CkbInvoice should be OK"), - ); + let value = + bincode::serialize(&invoice).expect("serialize CkbInvoice should be OK"); + self.put(key, value); } KeyValue::CkbInvoicePreimage(id, preimage) => { let key = [&[CKB_INVOICE_PREIMAGE_PREFIX], id.as_ref()].concat(); self.put( key, - serde_json::to_vec(&preimage).expect("serialize Hash256 should be OK"), + bincode::serialize(&preimage).expect("serialize Hash256 should be OK"), ); } KeyValue::CkbInvoiceStatus(id, status) => { let key = [&[CKB_INVOICE_STATUS_PREFIX], id.as_ref()].concat(); self.put( key, - serde_json::to_vec(&status).expect("serialize CkbInvoiceStatus should be OK"), + bincode::serialize(&status).expect("serialize CkbInvoiceStatus should be OK"), ); } KeyValue::PeerIdChannelId((peer_id, channel_id), state) => { @@ -176,7 +173,7 @@ impl Batch { .concat(); self.put( key, - serde_json::to_vec(&state).expect("serialize ChannelState should be OK"), + bincode::serialize(&state).expect("serialize ChannelState should be OK"), ); } KeyValue::ChannelInfo(channel_id, channel) => { @@ -206,14 +203,14 @@ impl Batch { key.extend_from_slice(channel_id.as_slice()); self.put( key, - serde_json::to_vec(&channel).expect("serialize ChannelInfo should be OK"), + bincode::serialize(&channel).expect("serialize ChannelInfo should be OK"), ); } KeyValue::PaymentSession(payment_hash, payment_session) => { let key = [&[PAYMENT_SESSION_PREFIX], payment_hash.as_ref()].concat(); self.put( key, - serde_json::to_vec(&payment_session) + bincode::serialize(&payment_session) .expect("serialize PaymentSession should be OK"), ); } @@ -233,21 +230,21 @@ impl Batch { key.extend_from_slice(id.serialize().as_ref()); self.put( key, - serde_json::to_vec(&node).expect("serialize NodeInfo should be OK"), + bincode::serialize(&node).expect("serialize NodeInfo should be OK"), ); } KeyValue::WatchtowerChannel(channel_id, channel_data) => { let key = [&[WATCHTOWER_CHANNEL_PREFIX], channel_id.as_ref()].concat(); self.put( key, - serde_json::to_vec(&channel_data).expect("serialize ChannelData should be OK"), + bincode::serialize(&channel_data).expect("serialize ChannelData should be OK"), ); } KeyValue::NetworkActorState(peer_id, persistent_network_actor_state) => { let key = [&[PEER_ID_NETWORK_ACTOR_STATE_PREFIX], peer_id.as_bytes()].concat(); self.put( key, - serde_json::to_vec(&persistent_network_actor_state) + bincode::serialize(&persistent_network_actor_state) .expect("serialize PersistentNetworkActorState should be OK"), ); } @@ -325,7 +322,7 @@ impl NetworkActorStateStore for Store { .prefix_iterator(key.as_ref()) .find(|(col_key, _)| col_key.starts_with(&key)); iter.map(|(_key, value)| { - serde_json::from_slice(value.as_ref()) + bincode::deserialize(value.as_ref()) .expect("deserialize PersistentNetworkActorState should be OK") }) } @@ -344,7 +341,7 @@ impl ChannelActorStateStore for Store { key.extend_from_slice(id.as_ref()); self.get(key).map(|v| { - serde_json::from_slice(v.as_ref()).expect("deserialize ChannelActorState should be OK") + bincode::deserialize(v.as_ref()).expect("deserialize ChannelActorState should be OK") }) } @@ -405,7 +402,7 @@ impl ChannelActorStateStore for Store { let channel_id: [u8; 32] = key[key_len - 32..] .try_into() .expect("channel id should be 32 bytes"); - let state = serde_json::from_slice(value.as_ref()) + let state = bincode::deserialize(value.as_ref()) .expect("deserialize ChannelState should be OK"); (peer_id, channel_id.into(), state) }) @@ -419,9 +416,8 @@ impl InvoiceStore for Store { key.extend_from_slice(&[CKB_INVOICE_PREFIX]); key.extend_from_slice(id.as_ref()); - self.get(key).map(|v| { - serde_json::from_slice(v.as_ref()).expect("deserialize CkbInvoice should be OK") - }) + self.get(key) + .map(|v| bincode::deserialize(v.as_ref()).expect("deserialize CkbInvoice should be OK")) } fn insert_invoice( @@ -453,7 +449,7 @@ impl InvoiceStore for Store { key.extend_from_slice(id.as_ref()); self.get(key) - .map(|v| serde_json::from_slice(v.as_ref()).expect("deserialize Hash256 should be OK")) + .map(|v| bincode::deserialize(v.as_ref()).expect("deserialize Hash256 should be OK")) } fn update_invoice_status( @@ -477,7 +473,7 @@ impl InvoiceStore for Store { key.extend_from_slice(id.as_ref()); self.get(key).map(|v| { - serde_json::from_slice(v.as_ref()).expect("deserialize CkbInvoiceStatus should be OK") + bincode::deserialize(v.as_ref()).expect("deserialize CkbInvoiceStatus should be OK") }) } } @@ -521,7 +517,7 @@ impl NetworkGraphStateStore for Store { return None; } } - let channel: ChannelInfo = serde_json::from_slice(value.as_ref()) + let channel: ChannelInfo = bincode::deserialize(value.as_ref()) .expect("deserialize ChannelInfo should be OK"); if !channel.is_explicitly_disabled() { last_key = col_key.to_vec(); @@ -573,7 +569,7 @@ impl NetworkGraphStateStore for Store { } last_key = col_key.to_vec(); Some( - serde_json::from_slice(value.as_ref()) + bincode::deserialize(value.as_ref()) .expect("deserialize NodeInfo should be OK"), ) }) @@ -598,7 +594,7 @@ impl NetworkGraphStateStore for Store { fn get_payment_session(&self, payment_hash: Hash256) -> Option { let prefix = [&[PAYMENT_SESSION_PREFIX], payment_hash.as_ref()].concat(); self.get(prefix).map(|v| { - serde_json::from_slice(v.as_ref()).expect("deserialize PaymentSession should be OK") + bincode::deserialize(v.as_ref()).expect("deserialize PaymentSession should be OK") }) } @@ -617,7 +613,7 @@ impl WatchtowerStore for Store { .prefix_iterator(prefix.as_ref()) .take_while(|(col_key, _)| col_key.starts_with(&prefix)); iter.map(|(_key, value)| { - serde_json::from_slice(value.as_ref()).expect("deserialize ChannelData should be OK") + bincode::deserialize(value.as_ref()).expect("deserialize ChannelData should be OK") }) .collect() } @@ -625,15 +621,13 @@ impl WatchtowerStore for Store { fn insert_watch_channel(&self, channel_id: Hash256, funding_tx_lock: Script) { let mut batch = self.batch(); let key = [&[WATCHTOWER_CHANNEL_PREFIX], channel_id.as_ref()].concat(); - batch.put( - key, - serde_json::to_vec(&ChannelData { - channel_id, - funding_tx_lock, - revocation_data: None, - }) - .expect("serialize ChannelData should be OK"), - ); + let value = bincode::serialize(&ChannelData { + channel_id, + funding_tx_lock, + revocation_data: None, + }) + .expect("serialize ChannelData should be OK"); + batch.put(key, value); batch.commit(); } @@ -645,11 +639,12 @@ impl WatchtowerStore for Store { fn update_revocation(&self, channel_id: Hash256, revocation_data: RevocationData) { let key = [&[WATCHTOWER_CHANNEL_PREFIX], channel_id.as_ref()].concat(); if let Some(mut channel_data) = self.get(key).map(|v| { - serde_json::from_slice::(v.as_ref()) + bincode::deserialize::(v.as_ref()) .expect("deserialize ChannelData should be OK") }) { channel_data.revocation_data = Some(revocation_data); let mut batch = self.batch(); + eprintln!("update_revocation key: {:?}", channel_id); batch.put_kv(KeyValue::WatchtowerChannel(channel_id, channel_data)); batch.commit(); } diff --git a/src/tests/store.rs b/src/tests/store.rs index 8ab9be12..bd5ef618 100644 --- a/src/tests/store.rs +++ b/src/tests/store.rs @@ -171,6 +171,20 @@ fn test_store_nodes() { assert_eq!(res, nodes[1..=3]); } +#[test] +fn test_compact_signature() { + let revocation_data = RevocationData { + commitment_number: 0, + x_only_aggregated_pubkey: [0u8; 32], + aggregated_signature: CompactSignature::from_bytes(&[0u8; 64]).unwrap(), + output: CellOutput::default(), + output_data: Bytes::default(), + }; + let bincode_encoded = bincode::serialize(&revocation_data).unwrap(); + let revocation_data: RevocationData = bincode::deserialize(&bincode_encoded).unwrap(); + assert_eq!(revocation_data, revocation_data); +} + #[test] fn test_store_wacthtower() { let dir = tempdir().unwrap(); @@ -196,6 +210,7 @@ fn test_store_wacthtower() { output: CellOutput::default(), output_data: Bytes::default(), }; + store.update_revocation(channel_id, revocation_data.clone()); assert_eq!( store.get_watch_channels(), diff --git a/src/watchtower/store.rs b/src/watchtower/store.rs index 916118c0..93eef1c5 100644 --- a/src/watchtower/store.rs +++ b/src/watchtower/store.rs @@ -3,7 +3,7 @@ use musig2::CompactSignature; use serde::{Deserialize, Serialize}; use serde_with::serde_as; -use crate::fiber::{serde_utils::EntityHex, types::Hash256}; +use crate::fiber::{serde_utils::compact_signature_serde, serde_utils::EntityHex, types::Hash256}; pub trait WatchtowerStore { /// Get the channels that are currently being watched by the watchtower @@ -32,6 +32,7 @@ pub struct ChannelData { pub struct RevocationData { pub commitment_number: u64, pub x_only_aggregated_pubkey: [u8; 32], + #[serde(with = "compact_signature_serde")] pub aggregated_signature: CompactSignature, #[serde_as(as = "EntityHex")] pub output: CellOutput,