mirror of
https://github.com/mimblewimble/mwixnet.git
synced 2025-01-20 19:11:09 +03:00
add SwapStore
(cherry picked from commit f1f23c4295097e0f806098647dcc2a4d31715355)
This commit is contained in:
parent
7882eb62b3
commit
b8dd2e42f7
5 changed files with 173 additions and 1 deletions
1
Cargo.lock
generated
1
Cargo.lock
generated
|
@ -2483,6 +2483,7 @@ dependencies = [
|
|||
"grin_keychain 5.2.0-alpha.1 (git+https://github.com/mimblewimble/grin)",
|
||||
"grin_secp256k1zkp",
|
||||
"grin_servers",
|
||||
"grin_store 5.2.0-alpha.1 (git+https://github.com/mimblewimble/grin)",
|
||||
"grin_util 5.1.1",
|
||||
"grin_wallet_api",
|
||||
"grin_wallet_impls",
|
||||
|
|
|
@ -38,6 +38,7 @@ grin_core = { git = "https://github.com/mimblewimble/grin", version = "5.2.0-alp
|
|||
grin_chain = { git = "https://github.com/mimblewimble/grin", version = "5.2.0-alpha.1" }
|
||||
grin_keychain = { git = "https://github.com/mimblewimble/grin", version = "5.2.0-alpha.1" }
|
||||
grin_servers = { git = "https://github.com/mimblewimble/grin", version = "5.2.0-alpha.1" }
|
||||
grin_store = { git = "https://github.com/mimblewimble/grin", version = "5.2.0-alpha.1" }
|
||||
grin_wallet_api = { git = "https://github.com/mimblewimble/grin-wallet", branch = "master" }
|
||||
grin_wallet_impls = { git = "https://github.com/mimblewimble/grin-wallet", branch = "master" }
|
||||
grin_wallet_libwallet = { git = "https://github.com/mimblewimble/grin-wallet", branch = "master" }
|
|
@ -19,6 +19,7 @@ mod onion;
|
|||
mod rpc;
|
||||
mod secp;
|
||||
mod server;
|
||||
mod store;
|
||||
mod types;
|
||||
mod wallet;
|
||||
|
||||
|
|
19
src/onion.rs
19
src/onion.rs
|
@ -4,7 +4,7 @@ use crate::types::Payload;
|
|||
use crate::onion::OnionError::{InvalidKeyLength, SerializationError};
|
||||
use chacha20::cipher::{NewCipher, StreamCipher};
|
||||
use chacha20::{ChaCha20, Key, Nonce};
|
||||
use grin_core::ser::{self, ProtocolVersion, Writeable, Writer};
|
||||
use grin_core::ser::{self, ProtocolVersion, Readable, Reader, Writeable, Writer};
|
||||
use grin_util::{self, ToHex};
|
||||
use hmac::digest::InvalidLength;
|
||||
use hmac::{Hmac, Mac};
|
||||
|
@ -122,6 +122,23 @@ impl Writeable for Onion {
|
|||
}
|
||||
}
|
||||
|
||||
impl Readable for Onion {
|
||||
fn read<R: Reader>(reader: &mut R) -> Result<Onion, ser::Error> {
|
||||
let ephemeral_pubkey = PublicKey::read(reader)?;
|
||||
let commit = Commitment::read(reader)?;
|
||||
let mut enc_payloads: Vec<RawBytes> = Vec::new();
|
||||
let len = reader.read_u64()?;
|
||||
for _ in 0..len {
|
||||
enc_payloads.push(RawBytes::read(reader)?);
|
||||
}
|
||||
Ok(Onion {
|
||||
ephemeral_pubkey,
|
||||
commit,
|
||||
enc_payloads,
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
impl serde::ser::Serialize for Onion {
|
||||
fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
|
||||
where
|
||||
|
|
152
src/store.rs
Normal file
152
src/store.rs
Normal file
|
@ -0,0 +1,152 @@
|
|||
use crate::onion::Onion;
|
||||
use crate::secp::{self, Commitment, RangeProof, SecretKey};
|
||||
|
||||
use grin_core::core::Input;
|
||||
use grin_core::ser::{self, ProtocolVersion, Readable, Reader, Writeable, Writer};
|
||||
use grin_store::{self as store, Store};
|
||||
use grin_util::ToHex;
|
||||
use thiserror::Error;
|
||||
|
||||
const DB_NAME: &str = "swap";
|
||||
const STORE_SUBPATH: &str = "swaps";
|
||||
|
||||
const CURRENT_VERSION: u8 = 0;
|
||||
const SWAP_PREFIX: u8 = b'S';
|
||||
|
||||
/// Data needed to swap a single output.
|
||||
#[derive(Clone, Debug, PartialEq)]
|
||||
pub struct SwapData {
|
||||
/// The total excess for the output commitment
|
||||
pub excess: SecretKey,
|
||||
/// The derived output commitment after applying excess and fee
|
||||
pub output_commit: Commitment,
|
||||
/// The rangeproof, included only for the final hop (node N)
|
||||
pub rangeproof: Option<RangeProof>,
|
||||
/// Transaction input being spent
|
||||
pub input: Input,
|
||||
/// Transaction fee
|
||||
pub fee: u64,
|
||||
/// The remaining onion after peeling off our layer
|
||||
pub onion: Onion,
|
||||
// todo: include a SwapStatus enum value
|
||||
}
|
||||
|
||||
impl Writeable for SwapData {
|
||||
fn write<W: Writer>(&self, writer: &mut W) -> Result<(), ser::Error> {
|
||||
writer.write_u8(CURRENT_VERSION)?;
|
||||
writer.write_fixed_bytes(&self.excess)?;
|
||||
writer.write_fixed_bytes(&self.output_commit)?;
|
||||
|
||||
// todo: duplicated in payload. Can we impl Writeable for Option<RangeProof>?
|
||||
match &self.rangeproof {
|
||||
Some(proof) => {
|
||||
writer.write_u8(1)?;
|
||||
proof.write(writer)?;
|
||||
}
|
||||
None => writer.write_u8(0)?,
|
||||
};
|
||||
|
||||
self.input.write(writer)?;
|
||||
writer.write_u64(self.fee.into())?;
|
||||
self.onion.write(writer)?;
|
||||
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
impl Readable for SwapData {
|
||||
fn read<R: Reader>(reader: &mut R) -> Result<SwapData, ser::Error> {
|
||||
let version = reader.read_u8()?;
|
||||
if version != CURRENT_VERSION {
|
||||
return Err(ser::Error::UnsupportedProtocolVersion);
|
||||
}
|
||||
|
||||
let excess = secp::read_secret_key(reader)?;
|
||||
let output_commit = Commitment::read(reader)?;
|
||||
let rangeproof = if reader.read_u8()? == 0 {
|
||||
None
|
||||
} else {
|
||||
Some(RangeProof::read(reader)?)
|
||||
};
|
||||
let input = Input::read(reader)?;
|
||||
let fee = reader.read_u64()?;
|
||||
let onion = Onion::read(reader)?;
|
||||
|
||||
Ok(SwapData {
|
||||
excess,
|
||||
output_commit,
|
||||
rangeproof,
|
||||
input,
|
||||
fee,
|
||||
onion,
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
/// Storage facility for swap data.
|
||||
pub struct SwapStore {
|
||||
db: Store,
|
||||
}
|
||||
|
||||
/// Store error types
|
||||
#[derive(Clone, Error, Debug, PartialEq)]
|
||||
pub enum StoreError {
|
||||
#[error("Error occurred while attempting to open db: {0}")]
|
||||
OpenError(store::lmdb::Error),
|
||||
#[error("Serialization error occurred: {0}")]
|
||||
SerializationError(ser::Error),
|
||||
#[error("Error occurred while attempting to read from db: {0}")]
|
||||
ReadError(store::lmdb::Error),
|
||||
#[error("Error occurred while attempting to write to db: {0}")]
|
||||
WriteError(store::lmdb::Error),
|
||||
}
|
||||
|
||||
impl From<ser::Error> for StoreError {
|
||||
fn from(e: ser::Error) -> StoreError {
|
||||
StoreError::SerializationError(e)
|
||||
}
|
||||
}
|
||||
|
||||
impl SwapStore {
|
||||
/// Create new chain store
|
||||
#[allow(dead_code)]
|
||||
pub fn new(db_root: &str) -> Result<SwapStore, StoreError> {
|
||||
let db = Store::new(db_root, Some(DB_NAME), Some(STORE_SUBPATH), None)
|
||||
.map_err(StoreError::OpenError)?;
|
||||
Ok(SwapStore { db })
|
||||
}
|
||||
|
||||
/// Writes a single key-value pair to the database
|
||||
fn write<K: AsRef<[u8]>>(
|
||||
&self,
|
||||
prefix: u8,
|
||||
k: K,
|
||||
value: &Vec<u8>,
|
||||
) -> Result<(), store::lmdb::Error> {
|
||||
let batch = self.db.batch()?;
|
||||
batch.put(&store::to_key(prefix, k)[..], &value[..])?;
|
||||
batch.commit()
|
||||
}
|
||||
|
||||
/// Reads a single value by key
|
||||
fn read<K: AsRef<[u8]> + Copy, V: Readable>(&self, prefix: u8, k: K) -> Result<V, StoreError> {
|
||||
store::option_to_not_found(self.db.get_ser(&store::to_key(prefix, k)[..], None), || {
|
||||
format!("{}:{}", prefix, k.to_hex())
|
||||
})
|
||||
.map_err(StoreError::ReadError)
|
||||
}
|
||||
|
||||
/// Saves a swap to the database
|
||||
#[allow(dead_code)]
|
||||
pub fn save_swap(&self, s: &SwapData) -> Result<(), StoreError> {
|
||||
let data = ser::ser_vec(&s, ProtocolVersion::local())?;
|
||||
self.write(SWAP_PREFIX, &s.output_commit, &data)
|
||||
.map_err(StoreError::WriteError)
|
||||
}
|
||||
|
||||
/// Reads a swap from the database
|
||||
#[allow(dead_code)]
|
||||
pub fn get_swap(&self, commit: &Commitment) -> Result<SwapData, StoreError> {
|
||||
self.read(SWAP_PREFIX, commit)
|
||||
}
|
||||
}
|
Loading…
Reference in a new issue