mirror of
https://github.com/logos-blockchain/lssa.git
synced 2026-01-03 22:03:06 +00:00
feat: first db update
This commit is contained in:
parent
ae0c589d1e
commit
c58ef27224
@ -44,6 +44,7 @@ base64 = "0.22.1"
|
|||||||
bip39 = "2.2.0"
|
bip39 = "2.2.0"
|
||||||
hmac-sha512 = "1.1.7"
|
hmac-sha512 = "1.1.7"
|
||||||
chrono = "0.4.41"
|
chrono = "0.4.41"
|
||||||
|
borsh = "1.5.7"
|
||||||
|
|
||||||
rocksdb = { version = "0.21.0", default-features = false, features = [
|
rocksdb = { version = "0.21.0", default-features = false, features = [
|
||||||
"snappy",
|
"snappy",
|
||||||
|
|||||||
@ -17,6 +17,8 @@ log.workspace = true
|
|||||||
elliptic-curve.workspace = true
|
elliptic-curve.workspace = true
|
||||||
hex.workspace = true
|
hex.workspace = true
|
||||||
|
|
||||||
|
borsh.workspace = true
|
||||||
|
|
||||||
[dependencies.secp256k1-zkp]
|
[dependencies.secp256k1-zkp]
|
||||||
workspace = true
|
workspace = true
|
||||||
features = ["std", "rand-std", "rand", "serde", "global-context"]
|
features = ["std", "rand-std", "rand", "serde", "global-context"]
|
||||||
|
|||||||
@ -1,5 +1,5 @@
|
|||||||
|
use borsh::{BorshDeserialize, BorshSerialize};
|
||||||
use rs_merkle::Hasher;
|
use rs_merkle::Hasher;
|
||||||
use std::io::{Cursor, Read};
|
|
||||||
|
|
||||||
use crate::{OwnHasher, transaction::EncodedTransaction};
|
use crate::{OwnHasher, transaction::EncodedTransaction};
|
||||||
|
|
||||||
@ -27,7 +27,7 @@ pub struct Block {
|
|||||||
pub body: BlockBody,
|
pub body: BlockBody,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug, PartialEq, Eq)]
|
#[derive(Debug, PartialEq, Eq, BorshSerialize, BorshDeserialize)]
|
||||||
pub struct HashableBlockData {
|
pub struct HashableBlockData {
|
||||||
pub block_id: BlockId,
|
pub block_id: BlockId,
|
||||||
pub prev_block_hash: BlockHash,
|
pub prev_block_hash: BlockHash,
|
||||||
@ -37,7 +37,7 @@ pub struct HashableBlockData {
|
|||||||
|
|
||||||
impl HashableBlockData {
|
impl HashableBlockData {
|
||||||
pub fn into_block(self, signing_key: &nssa::PrivateKey) -> Block {
|
pub fn into_block(self, signing_key: &nssa::PrivateKey) -> Block {
|
||||||
let data_bytes = self.to_bytes();
|
let data_bytes = borsh::to_vec(&self).unwrap();
|
||||||
let signature = nssa::Signature::new(signing_key, &data_bytes);
|
let signature = nssa::Signature::new(signing_key, &data_bytes);
|
||||||
let hash = OwnHasher::hash(&data_bytes);
|
let hash = OwnHasher::hash(&data_bytes);
|
||||||
Block {
|
Block {
|
||||||
@ -66,75 +66,6 @@ impl From<Block> for HashableBlockData {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl HashableBlockData {
|
|
||||||
pub fn to_bytes(&self) -> Vec<u8> {
|
|
||||||
let mut bytes = Vec::new();
|
|
||||||
bytes.extend_from_slice(&self.block_id.to_le_bytes());
|
|
||||||
bytes.extend_from_slice(&self.prev_block_hash);
|
|
||||||
bytes.extend_from_slice(&self.timestamp.to_le_bytes());
|
|
||||||
let num_transactions: u32 = self.transactions.len() as u32;
|
|
||||||
bytes.extend_from_slice(&num_transactions.to_le_bytes());
|
|
||||||
for tx in &self.transactions {
|
|
||||||
let transaction_bytes = tx.to_bytes();
|
|
||||||
let num_transaction_bytes: u32 = transaction_bytes.len() as u32;
|
|
||||||
|
|
||||||
bytes.extend_from_slice(&num_transaction_bytes.to_le_bytes());
|
|
||||||
bytes.extend_from_slice(&tx.to_bytes());
|
|
||||||
}
|
|
||||||
bytes
|
|
||||||
}
|
|
||||||
|
|
||||||
// TODO: Improve error handling. Remove unwraps.
|
|
||||||
pub fn from_bytes(data: &[u8]) -> Self {
|
|
||||||
let mut cursor = Cursor::new(data);
|
|
||||||
|
|
||||||
let block_id = u64_from_cursor(&mut cursor);
|
|
||||||
|
|
||||||
let mut prev_block_hash = [0u8; 32];
|
|
||||||
cursor.read_exact(&mut prev_block_hash).unwrap();
|
|
||||||
|
|
||||||
let timestamp = u64_from_cursor(&mut cursor);
|
|
||||||
|
|
||||||
let num_transactions = u32_from_cursor(&mut cursor) as usize;
|
|
||||||
|
|
||||||
let mut transactions = Vec::with_capacity(num_transactions);
|
|
||||||
for _ in 0..num_transactions {
|
|
||||||
let tx_len = u32_from_cursor(&mut cursor) as usize;
|
|
||||||
let mut tx_bytes = Vec::with_capacity(tx_len);
|
|
||||||
|
|
||||||
for _ in 0..tx_len {
|
|
||||||
let mut buff = [0; 1];
|
|
||||||
cursor.read_exact(&mut buff).unwrap();
|
|
||||||
tx_bytes.push(buff[0]);
|
|
||||||
}
|
|
||||||
|
|
||||||
let tx = EncodedTransaction::from_bytes(tx_bytes);
|
|
||||||
transactions.push(tx);
|
|
||||||
}
|
|
||||||
|
|
||||||
Self {
|
|
||||||
block_id,
|
|
||||||
prev_block_hash,
|
|
||||||
timestamp,
|
|
||||||
transactions,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// TODO: Improve error handling. Remove unwraps.
|
|
||||||
pub fn u32_from_cursor(cursor: &mut Cursor<&[u8]>) -> u32 {
|
|
||||||
let mut word_buf = [0u8; 4];
|
|
||||||
cursor.read_exact(&mut word_buf).unwrap();
|
|
||||||
u32::from_le_bytes(word_buf)
|
|
||||||
}
|
|
||||||
|
|
||||||
// TODO: Improve error handling. Remove unwraps.
|
|
||||||
pub fn u64_from_cursor(cursor: &mut Cursor<&[u8]>) -> u64 {
|
|
||||||
let mut word_buf = [0u8; 8];
|
|
||||||
cursor.read_exact(&mut word_buf).unwrap();
|
|
||||||
u64::from_le_bytes(word_buf)
|
|
||||||
}
|
|
||||||
|
|
||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
mod tests {
|
mod tests {
|
||||||
use crate::{block::HashableBlockData, test_utils};
|
use crate::{block::HashableBlockData, test_utils};
|
||||||
@ -144,8 +75,8 @@ mod tests {
|
|||||||
let transactions = vec![test_utils::produce_dummy_empty_transaction()];
|
let transactions = vec![test_utils::produce_dummy_empty_transaction()];
|
||||||
let block = test_utils::produce_dummy_block(1, Some([1; 32]), transactions);
|
let block = test_utils::produce_dummy_block(1, Some([1; 32]), transactions);
|
||||||
let hashable = HashableBlockData::from(block);
|
let hashable = HashableBlockData::from(block);
|
||||||
let bytes = hashable.to_bytes();
|
let bytes = borsh::to_vec(&hashable).unwrap();
|
||||||
let block_from_bytes = HashableBlockData::from_bytes(&bytes);
|
let block_from_bytes = borsh::from_slice::<HashableBlockData>(&bytes).unwrap();
|
||||||
assert_eq!(hashable, block_from_bytes);
|
assert_eq!(hashable, block_from_bytes);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -150,7 +150,7 @@ impl SequencerClient {
|
|||||||
let transaction = EncodedTransaction::from(NSSATransaction::Public(transaction));
|
let transaction = EncodedTransaction::from(NSSATransaction::Public(transaction));
|
||||||
|
|
||||||
let tx_req = SendTxRequest {
|
let tx_req = SendTxRequest {
|
||||||
transaction: transaction.to_bytes(),
|
transaction: borsh::to_vec(&transaction).unwrap(),
|
||||||
};
|
};
|
||||||
|
|
||||||
let req = serde_json::to_value(tx_req)?;
|
let req = serde_json::to_value(tx_req)?;
|
||||||
|
|||||||
@ -1,3 +1,4 @@
|
|||||||
|
use borsh::{BorshDeserialize, BorshSerialize};
|
||||||
use k256::ecdsa::{Signature, SigningKey, VerifyingKey};
|
use k256::ecdsa::{Signature, SigningKey, VerifyingKey};
|
||||||
use log::info;
|
use log::info;
|
||||||
use serde::{Deserialize, Serialize};
|
use serde::{Deserialize, Serialize};
|
||||||
@ -34,13 +35,15 @@ pub type CipherText = Vec<u8>;
|
|||||||
pub type Nonce = GenericArray<u8, UInt<UInt<UInt<UInt<UTerm, B1>, B1>, B0>, B0>>;
|
pub type Nonce = GenericArray<u8, UInt<UInt<UInt<UInt<UTerm, B1>, B1>, B0>, B0>>;
|
||||||
pub type Tag = u8;
|
pub type Tag = u8;
|
||||||
|
|
||||||
#[derive(Debug, Serialize, Deserialize, Clone, Copy, PartialEq, Eq)]
|
#[derive(
|
||||||
|
Debug, Serialize, Deserialize, Clone, Copy, PartialEq, Eq, BorshSerialize, BorshDeserialize,
|
||||||
|
)]
|
||||||
pub enum TxKind {
|
pub enum TxKind {
|
||||||
Public,
|
Public,
|
||||||
PrivacyPreserving,
|
PrivacyPreserving,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug, Serialize, Deserialize, Clone, PartialEq, Eq)]
|
#[derive(Debug, Serialize, Deserialize, Clone, PartialEq, Eq, BorshSerialize, BorshDeserialize)]
|
||||||
///General transaction object
|
///General transaction object
|
||||||
pub struct EncodedTransaction {
|
pub struct EncodedTransaction {
|
||||||
pub tx_kind: TxKind,
|
pub tx_kind: TxKind,
|
||||||
@ -174,23 +177,12 @@ impl ActionData {
|
|||||||
impl EncodedTransaction {
|
impl EncodedTransaction {
|
||||||
/// Computes and returns the SHA-256 hash of the JSON-serialized representation of `self`.
|
/// Computes and returns the SHA-256 hash of the JSON-serialized representation of `self`.
|
||||||
pub fn hash(&self) -> TreeHashType {
|
pub fn hash(&self) -> TreeHashType {
|
||||||
let bytes_to_hash = self.to_bytes();
|
let bytes_to_hash = borsh::to_vec(&self).unwrap();
|
||||||
let mut hasher = sha2::Sha256::new();
|
let mut hasher = sha2::Sha256::new();
|
||||||
hasher.update(&bytes_to_hash);
|
hasher.update(&bytes_to_hash);
|
||||||
TreeHashType::from(hasher.finalize_fixed())
|
TreeHashType::from(hasher.finalize_fixed())
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn to_bytes(&self) -> Vec<u8> {
|
|
||||||
// TODO: Remove `unwrap` by implementing a `to_bytes` method
|
|
||||||
// that deterministically encodes all transaction fields to bytes
|
|
||||||
// and guarantees serialization will succeed.
|
|
||||||
serde_json::to_vec(&self).unwrap()
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn from_bytes(bytes: Vec<u8>) -> Self {
|
|
||||||
serde_json::from_slice(&bytes).unwrap()
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn log(&self) {
|
pub fn log(&self) {
|
||||||
info!("Transaction hash is {:?}", hex::encode(self.hash()));
|
info!("Transaction hash is {:?}", hex::encode(self.hash()));
|
||||||
info!("Transaction tx_kind is {:?}", self.tx_kind);
|
info!("Transaction tx_kind is {:?}", self.tx_kind);
|
||||||
@ -221,7 +213,7 @@ mod tests {
|
|||||||
fn test_transaction_hash_is_sha256_of_json_bytes() {
|
fn test_transaction_hash_is_sha256_of_json_bytes() {
|
||||||
let body = test_transaction_body();
|
let body = test_transaction_body();
|
||||||
let expected_hash = {
|
let expected_hash = {
|
||||||
let data = body.to_bytes();
|
let data = borsh::to_vec(&body).unwrap();
|
||||||
let mut hasher = sha2::Sha256::new();
|
let mut hasher = sha2::Sha256::new();
|
||||||
hasher.update(&data);
|
hasher.update(&data);
|
||||||
TreeHashType::from(hasher.finalize_fixed())
|
TreeHashType::from(hasher.finalize_fixed())
|
||||||
@ -236,8 +228,8 @@ mod tests {
|
|||||||
fn test_to_bytes_from_bytes() {
|
fn test_to_bytes_from_bytes() {
|
||||||
let body = test_transaction_body();
|
let body = test_transaction_body();
|
||||||
|
|
||||||
let body_bytes = body.to_bytes();
|
let body_bytes = borsh::to_vec(&body).unwrap();
|
||||||
let body_new = EncodedTransaction::from_bytes(body_bytes);
|
let body_new = borsh::from_slice::<EncodedTransaction>(&body_bytes).unwrap();
|
||||||
|
|
||||||
assert_eq!(body, body_new);
|
assert_eq!(body, body_new);
|
||||||
}
|
}
|
||||||
|
|||||||
@ -5,7 +5,6 @@ edition = "2024"
|
|||||||
|
|
||||||
[dependencies]
|
[dependencies]
|
||||||
anyhow.workspace = true
|
anyhow.workspace = true
|
||||||
serde_json.workspace = true
|
|
||||||
log.workspace = true
|
log.workspace = true
|
||||||
serde.workspace = true
|
serde.workspace = true
|
||||||
k256.workspace = true
|
k256.workspace = true
|
||||||
|
|||||||
@ -1,4 +1,3 @@
|
|||||||
use log::info;
|
|
||||||
use nssa_core::{
|
use nssa_core::{
|
||||||
NullifierPublicKey, SharedSecretKey,
|
NullifierPublicKey, SharedSecretKey,
|
||||||
encryption::{EphemeralPublicKey, EphemeralSecretKey, IncomingViewingPublicKey},
|
encryption::{EphemeralPublicKey, EphemeralSecretKey, IncomingViewingPublicKey},
|
||||||
@ -48,11 +47,4 @@ impl EphemeralKeyHolder {
|
|||||||
&receiver_incoming_viewing_public_key,
|
&receiver_incoming_viewing_public_key,
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn log(&self) {
|
|
||||||
info!(
|
|
||||||
"Ephemeral private key is {:?}",
|
|
||||||
hex::encode(serde_json::to_vec(&self.ephemeral_secret_key).unwrap())
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|||||||
@ -1,5 +1,4 @@
|
|||||||
use common::TreeHashType;
|
use common::TreeHashType;
|
||||||
use log::info;
|
|
||||||
use nssa_core::{
|
use nssa_core::{
|
||||||
NullifierPublicKey, SharedSecretKey,
|
NullifierPublicKey, SharedSecretKey,
|
||||||
encryption::{EphemeralPublicKey, IncomingViewingPublicKey},
|
encryption::{EphemeralPublicKey, IncomingViewingPublicKey},
|
||||||
@ -62,43 +61,13 @@ impl KeyChain {
|
|||||||
&ephemeral_public_key_sender,
|
&ephemeral_public_key_sender,
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn log(&self) {
|
|
||||||
info!(
|
|
||||||
"Secret spending key is {:?}",
|
|
||||||
hex::encode(serde_json::to_vec(&self.secret_spending_key).unwrap()),
|
|
||||||
);
|
|
||||||
info!(
|
|
||||||
"Nulifier secret key is {:?}",
|
|
||||||
hex::encode(serde_json::to_vec(&self.private_key_holder.nullifier_secret_key).unwrap()),
|
|
||||||
);
|
|
||||||
info!(
|
|
||||||
"Viewing secret key is {:?}",
|
|
||||||
hex::encode(
|
|
||||||
serde_json::to_vec(&self.private_key_holder.incoming_viewing_secret_key).unwrap()
|
|
||||||
),
|
|
||||||
);
|
|
||||||
info!(
|
|
||||||
"Viewing secret key is {:?}",
|
|
||||||
hex::encode(
|
|
||||||
serde_json::to_vec(&self.private_key_holder.outgoing_viewing_secret_key).unwrap()
|
|
||||||
),
|
|
||||||
);
|
|
||||||
info!(
|
|
||||||
"Nullifier public key is {:?}",
|
|
||||||
hex::encode(serde_json::to_vec(&self.nullifer_public_key).unwrap()),
|
|
||||||
);
|
|
||||||
info!(
|
|
||||||
"Viewing public key is {:?}",
|
|
||||||
hex::encode(serde_json::to_vec(&self.incoming_viewing_public_key).unwrap()),
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
mod tests {
|
mod tests {
|
||||||
use aes_gcm::aead::OsRng;
|
use aes_gcm::aead::OsRng;
|
||||||
use k256::AffinePoint;
|
use k256::AffinePoint;
|
||||||
|
use k256::elliptic_curve::group::GroupEncoding;
|
||||||
use rand::RngCore;
|
use rand::RngCore;
|
||||||
|
|
||||||
use super::*;
|
use super::*;
|
||||||
@ -147,7 +116,7 @@ mod tests {
|
|||||||
|
|
||||||
println!(
|
println!(
|
||||||
"Group generator {:?}",
|
"Group generator {:?}",
|
||||||
hex::encode(serde_json::to_vec(&AffinePoint::GENERATOR).unwrap())
|
hex::encode(AffinePoint::GENERATOR.to_bytes())
|
||||||
);
|
);
|
||||||
println!();
|
println!();
|
||||||
|
|
||||||
@ -164,11 +133,11 @@ mod tests {
|
|||||||
println!("Address{:?}", hex::encode(address.value()));
|
println!("Address{:?}", hex::encode(address.value()));
|
||||||
println!(
|
println!(
|
||||||
"Nulifier public key {:?}",
|
"Nulifier public key {:?}",
|
||||||
hex::encode(serde_json::to_vec(&nullifer_public_key).unwrap())
|
hex::encode(nullifer_public_key.to_byte_array())
|
||||||
);
|
);
|
||||||
println!(
|
println!(
|
||||||
"Viewing public key {:?}",
|
"Viewing public key {:?}",
|
||||||
hex::encode(serde_json::to_vec(&viewing_public_key).unwrap())
|
hex::encode(viewing_public_key.to_bytes())
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -16,6 +16,7 @@ base64.workspace = true
|
|||||||
|
|
||||||
actix-web.workspace = true
|
actix-web.workspace = true
|
||||||
tokio.workspace = true
|
tokio.workspace = true
|
||||||
|
borsh.workspace = true
|
||||||
|
|
||||||
[dependencies.sequencer_core]
|
[dependencies.sequencer_core]
|
||||||
path = "../sequencer_core"
|
path = "../sequencer_core"
|
||||||
|
|||||||
@ -75,7 +75,7 @@ impl JsonHandler {
|
|||||||
|
|
||||||
async fn process_send_tx(&self, request: Request) -> Result<Value, RpcErr> {
|
async fn process_send_tx(&self, request: Request) -> Result<Value, RpcErr> {
|
||||||
let send_tx_req = SendTxRequest::parse(Some(request.params))?;
|
let send_tx_req = SendTxRequest::parse(Some(request.params))?;
|
||||||
let tx = EncodedTransaction::from_bytes(send_tx_req.transaction);
|
let tx = borsh::from_slice::<EncodedTransaction>(&send_tx_req.transaction).unwrap();
|
||||||
let tx_hash = hex::encode(tx.hash());
|
let tx_hash = hex::encode(tx.hash());
|
||||||
|
|
||||||
{
|
{
|
||||||
@ -105,7 +105,7 @@ impl JsonHandler {
|
|||||||
};
|
};
|
||||||
|
|
||||||
let helperstruct = GetBlockDataResponse {
|
let helperstruct = GetBlockDataResponse {
|
||||||
block: HashableBlockData::from(block).to_bytes(),
|
block: borsh::to_vec(&HashableBlockData::from(block)).unwrap(),
|
||||||
};
|
};
|
||||||
|
|
||||||
respond(helperstruct)
|
respond(helperstruct)
|
||||||
@ -241,7 +241,7 @@ impl JsonHandler {
|
|||||||
.store
|
.store
|
||||||
.block_store
|
.block_store
|
||||||
.get_transaction_by_hash(hash)
|
.get_transaction_by_hash(hash)
|
||||||
.map(|tx| tx.to_bytes())
|
.map(|tx| borsh::to_vec(&tx).unwrap())
|
||||||
};
|
};
|
||||||
let base64_encoded = transaction.map(|tx| general_purpose::STANDARD.encode(tx));
|
let base64_encoded = transaction.map(|tx| general_purpose::STANDARD.encode(tx));
|
||||||
let helperstruct = GetTransactionByHashResponse {
|
let helperstruct = GetTransactionByHashResponse {
|
||||||
@ -625,7 +625,7 @@ mod tests {
|
|||||||
async fn test_get_transaction_by_hash_for_existing_transaction() {
|
async fn test_get_transaction_by_hash_for_existing_transaction() {
|
||||||
let (json_handler, _, tx) = components_for_tests();
|
let (json_handler, _, tx) = components_for_tests();
|
||||||
let tx_hash_hex = hex::encode(tx.hash());
|
let tx_hash_hex = hex::encode(tx.hash());
|
||||||
let expected_base64_encoded = general_purpose::STANDARD.encode(tx.to_bytes());
|
let expected_base64_encoded = general_purpose::STANDARD.encode(borsh::to_vec(&tx).unwrap());
|
||||||
|
|
||||||
let request = serde_json::json!({
|
let request = serde_json::json!({
|
||||||
"jsonrpc": "2.0",
|
"jsonrpc": "2.0",
|
||||||
|
|||||||
@ -5,9 +5,8 @@ edition = "2024"
|
|||||||
|
|
||||||
[dependencies]
|
[dependencies]
|
||||||
anyhow.workspace = true
|
anyhow.workspace = true
|
||||||
serde_json.workspace = true
|
|
||||||
serde.workspace = true
|
|
||||||
thiserror.workspace = true
|
thiserror.workspace = true
|
||||||
|
borsh.workspace = true
|
||||||
|
|
||||||
rocksdb.workspace = true
|
rocksdb.workspace = true
|
||||||
|
|
||||||
|
|||||||
@ -7,7 +7,7 @@ pub enum DbError {
|
|||||||
},
|
},
|
||||||
#[error("Serialization error")]
|
#[error("Serialization error")]
|
||||||
SerializationError {
|
SerializationError {
|
||||||
error: serde_json::Error,
|
error: borsh::io::Error,
|
||||||
additional_info: Option<String>,
|
additional_info: Option<String>,
|
||||||
},
|
},
|
||||||
#[error("Logic Error")]
|
#[error("Logic Error")]
|
||||||
@ -22,9 +22,9 @@ impl DbError {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn serde_cast_message(serr: serde_json::Error, message: Option<String>) -> Self {
|
pub fn borsh_cast_message(berr: borsh::io::Error, message: Option<String>) -> Self {
|
||||||
Self::SerializationError {
|
Self::SerializationError {
|
||||||
error: serr,
|
error: berr,
|
||||||
additional_info: message,
|
additional_info: message,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -5,10 +5,8 @@ use error::DbError;
|
|||||||
use rocksdb::{
|
use rocksdb::{
|
||||||
BoundColumnFamily, ColumnFamilyDescriptor, DBWithThreadMode, MultiThreaded, Options,
|
BoundColumnFamily, ColumnFamilyDescriptor, DBWithThreadMode, MultiThreaded, Options,
|
||||||
};
|
};
|
||||||
use sc_db_utils::{DataBlob, DataBlobChangeVariant, produce_blob_from_fit_vec};
|
|
||||||
|
|
||||||
pub mod error;
|
pub mod error;
|
||||||
pub mod sc_db_utils;
|
|
||||||
|
|
||||||
///Maximal size of stored blocks in base
|
///Maximal size of stored blocks in base
|
||||||
///
|
///
|
||||||
@ -22,9 +20,6 @@ pub const BUFF_SIZE_ROCKSDB: usize = usize::MAX;
|
|||||||
///Keeping small to not run out of memory
|
///Keeping small to not run out of memory
|
||||||
pub const CACHE_SIZE: usize = 1000;
|
pub const CACHE_SIZE: usize = 1000;
|
||||||
|
|
||||||
///Size in bytes of a singular smart contract data blob, stored in db
|
|
||||||
pub const SC_DATA_BLOB_SIZE: usize = 256;
|
|
||||||
|
|
||||||
///Key base for storing metainformation about id of first block in db
|
///Key base for storing metainformation about id of first block in db
|
||||||
pub const DB_META_FIRST_BLOCK_IN_DB_KEY: &str = "first_block_in_db";
|
pub const DB_META_FIRST_BLOCK_IN_DB_KEY: &str = "first_block_in_db";
|
||||||
///Key base for storing metainformation about id of last current block in db
|
///Key base for storing metainformation about id of last current block in db
|
||||||
@ -36,14 +31,6 @@ pub const DB_META_SC_LIST: &str = "sc_list";
|
|||||||
|
|
||||||
///Key base for storing snapshot which describe block id
|
///Key base for storing snapshot which describe block id
|
||||||
pub const DB_SNAPSHOT_BLOCK_ID_KEY: &str = "block_id";
|
pub const DB_SNAPSHOT_BLOCK_ID_KEY: &str = "block_id";
|
||||||
///Key base for storing snapshot which describe commitment
|
|
||||||
pub const DB_SNAPSHOT_COMMITMENT_KEY: &str = "commitment";
|
|
||||||
///Key base for storing snapshot which describe transaction
|
|
||||||
pub const DB_SNAPSHOT_TRANSACTION_KEY: &str = "transaction";
|
|
||||||
///Key base for storing snapshot which describe nullifier
|
|
||||||
pub const DB_SNAPSHOT_NULLIFIER_KEY: &str = "nullifier";
|
|
||||||
///Key base for storing snapshot which describe account
|
|
||||||
pub const DB_SNAPSHOT_ACCOUNT_KEY: &str = "account";
|
|
||||||
|
|
||||||
///Name of block column family
|
///Name of block column family
|
||||||
pub const CF_BLOCK_NAME: &str = "cf_block";
|
pub const CF_BLOCK_NAME: &str = "cf_block";
|
||||||
@ -54,9 +41,6 @@ pub const CF_SC_NAME: &str = "cf_sc";
|
|||||||
///Name of snapshot column family
|
///Name of snapshot column family
|
||||||
pub const CF_SNAPSHOT_NAME: &str = "cf_snapshot";
|
pub const CF_SNAPSHOT_NAME: &str = "cf_snapshot";
|
||||||
|
|
||||||
///Suffix, used to mark field, which contain length of smart contract
|
|
||||||
pub const SC_LEN_SUFFIX: &str = "sc_len";
|
|
||||||
|
|
||||||
pub type DbResult<T> = Result<T, DbError>;
|
pub type DbResult<T> = Result<T, DbError>;
|
||||||
|
|
||||||
pub struct RocksDBIO {
|
pub struct RocksDBIO {
|
||||||
@ -142,11 +126,24 @@ impl RocksDBIO {
|
|||||||
let cf_meta = self.meta_column();
|
let cf_meta = self.meta_column();
|
||||||
let res = self
|
let res = self
|
||||||
.db
|
.db
|
||||||
.get_cf(&cf_meta, DB_META_FIRST_BLOCK_IN_DB_KEY)
|
.get_cf(
|
||||||
|
&cf_meta,
|
||||||
|
borsh::to_vec(&DB_META_FIRST_BLOCK_IN_DB_KEY).map_err(|err| {
|
||||||
|
DbError::borsh_cast_message(
|
||||||
|
err,
|
||||||
|
Some("Failed to serialize DB_META_FIRST_BLOCK_IN_DB_KEY".to_string()),
|
||||||
|
)
|
||||||
|
})?,
|
||||||
|
)
|
||||||
.map_err(|rerr| DbError::rocksdb_cast_message(rerr, None))?;
|
.map_err(|rerr| DbError::rocksdb_cast_message(rerr, None))?;
|
||||||
|
|
||||||
if let Some(data) = res {
|
if let Some(data) = res {
|
||||||
Ok(u64::from_be_bytes(data.try_into().unwrap()))
|
Ok(borsh::from_slice::<u64>(&data).map_err(|err| {
|
||||||
|
DbError::borsh_cast_message(
|
||||||
|
err,
|
||||||
|
Some("Failed to deserialize first block".to_string()),
|
||||||
|
)
|
||||||
|
})?)
|
||||||
} else {
|
} else {
|
||||||
Err(DbError::db_interaction_error(
|
Err(DbError::db_interaction_error(
|
||||||
"First block not found".to_string(),
|
"First block not found".to_string(),
|
||||||
@ -158,11 +155,24 @@ impl RocksDBIO {
|
|||||||
let cf_meta = self.meta_column();
|
let cf_meta = self.meta_column();
|
||||||
let res = self
|
let res = self
|
||||||
.db
|
.db
|
||||||
.get_cf(&cf_meta, DB_META_LAST_BLOCK_IN_DB_KEY)
|
.get_cf(
|
||||||
|
&cf_meta,
|
||||||
|
borsh::to_vec(&DB_META_LAST_BLOCK_IN_DB_KEY).map_err(|err| {
|
||||||
|
DbError::borsh_cast_message(
|
||||||
|
err,
|
||||||
|
Some("Failed to serialize DB_META_LAST_BLOCK_IN_DB_KEY".to_string()),
|
||||||
|
)
|
||||||
|
})?,
|
||||||
|
)
|
||||||
.map_err(|rerr| DbError::rocksdb_cast_message(rerr, None))?;
|
.map_err(|rerr| DbError::rocksdb_cast_message(rerr, None))?;
|
||||||
|
|
||||||
if let Some(data) = res {
|
if let Some(data) = res {
|
||||||
Ok(u64::from_be_bytes(data.try_into().unwrap()))
|
Ok(borsh::from_slice::<u64>(&data).map_err(|err| {
|
||||||
|
DbError::borsh_cast_message(
|
||||||
|
err,
|
||||||
|
Some("Failed to deserialize last block".to_string()),
|
||||||
|
)
|
||||||
|
})?)
|
||||||
} else {
|
} else {
|
||||||
Err(DbError::db_interaction_error(
|
Err(DbError::db_interaction_error(
|
||||||
"Last block not found".to_string(),
|
"Last block not found".to_string(),
|
||||||
@ -174,7 +184,15 @@ impl RocksDBIO {
|
|||||||
let cf_meta = self.meta_column();
|
let cf_meta = self.meta_column();
|
||||||
let res = self
|
let res = self
|
||||||
.db
|
.db
|
||||||
.get_cf(&cf_meta, DB_META_FIRST_BLOCK_SET_KEY)
|
.get_cf(
|
||||||
|
&cf_meta,
|
||||||
|
borsh::to_vec(&DB_META_FIRST_BLOCK_SET_KEY).map_err(|err| {
|
||||||
|
DbError::borsh_cast_message(
|
||||||
|
err,
|
||||||
|
Some("Failed to serialize DB_META_FIRST_BLOCK_SET_KEY".to_string()),
|
||||||
|
)
|
||||||
|
})?,
|
||||||
|
)
|
||||||
.map_err(|rerr| DbError::rocksdb_cast_message(rerr, None))?;
|
.map_err(|rerr| DbError::rocksdb_cast_message(rerr, None))?;
|
||||||
|
|
||||||
Ok(res.is_some())
|
Ok(res.is_some())
|
||||||
@ -185,8 +203,18 @@ impl RocksDBIO {
|
|||||||
self.db
|
self.db
|
||||||
.put_cf(
|
.put_cf(
|
||||||
&cf_meta,
|
&cf_meta,
|
||||||
DB_META_FIRST_BLOCK_IN_DB_KEY.as_bytes(),
|
borsh::to_vec(&DB_META_FIRST_BLOCK_IN_DB_KEY).map_err(|err| {
|
||||||
block.header.block_id.to_be_bytes(),
|
DbError::borsh_cast_message(
|
||||||
|
err,
|
||||||
|
Some("Failed to serialize DB_META_FIRST_BLOCK_IN_DB_KEY".to_string()),
|
||||||
|
)
|
||||||
|
})?,
|
||||||
|
borsh::to_vec(&block.header.block_id).map_err(|err| {
|
||||||
|
DbError::borsh_cast_message(
|
||||||
|
err,
|
||||||
|
Some("Failed to serialize first block id".to_string()),
|
||||||
|
)
|
||||||
|
})?,
|
||||||
)
|
)
|
||||||
.map_err(|rerr| DbError::rocksdb_cast_message(rerr, None))?;
|
.map_err(|rerr| DbError::rocksdb_cast_message(rerr, None))?;
|
||||||
|
|
||||||
@ -199,8 +227,18 @@ impl RocksDBIO {
|
|||||||
self.db
|
self.db
|
||||||
.put_cf(
|
.put_cf(
|
||||||
&cf_meta,
|
&cf_meta,
|
||||||
DB_META_LAST_BLOCK_IN_DB_KEY.as_bytes(),
|
borsh::to_vec(&DB_META_LAST_BLOCK_IN_DB_KEY).map_err(|err| {
|
||||||
block_id.to_be_bytes(),
|
DbError::borsh_cast_message(
|
||||||
|
err,
|
||||||
|
Some("Failed to serialize DB_META_LAST_BLOCK_IN_DB_KEY".to_string()),
|
||||||
|
)
|
||||||
|
})?,
|
||||||
|
borsh::to_vec(&block_id).map_err(|err| {
|
||||||
|
DbError::borsh_cast_message(
|
||||||
|
err,
|
||||||
|
Some("Failed to serialize last block id".to_string()),
|
||||||
|
)
|
||||||
|
})?,
|
||||||
)
|
)
|
||||||
.map_err(|rerr| DbError::rocksdb_cast_message(rerr, None))?;
|
.map_err(|rerr| DbError::rocksdb_cast_message(rerr, None))?;
|
||||||
Ok(())
|
Ok(())
|
||||||
@ -212,8 +250,18 @@ impl RocksDBIO {
|
|||||||
self.db
|
self.db
|
||||||
.put_cf(
|
.put_cf(
|
||||||
&cf_meta,
|
&cf_meta,
|
||||||
DB_META_SC_LIST.as_bytes(),
|
borsh::to_vec(&DB_META_SC_LIST).map_err(|err| {
|
||||||
serde_json::to_vec(&sc_list).unwrap(),
|
DbError::borsh_cast_message(
|
||||||
|
err,
|
||||||
|
Some("Failed to serialize DB_META_SC_LIST".to_string()),
|
||||||
|
)
|
||||||
|
})?,
|
||||||
|
borsh::to_vec(&sc_list).map_err(|err| {
|
||||||
|
DbError::borsh_cast_message(
|
||||||
|
err,
|
||||||
|
Some("Failed to serialize list of sc".to_string()),
|
||||||
|
)
|
||||||
|
})?,
|
||||||
)
|
)
|
||||||
.map_err(|rerr| DbError::rocksdb_cast_message(rerr, None))?;
|
.map_err(|rerr| DbError::rocksdb_cast_message(rerr, None))?;
|
||||||
Ok(())
|
Ok(())
|
||||||
@ -222,7 +270,16 @@ impl RocksDBIO {
|
|||||||
pub fn put_meta_is_first_block_set(&self) -> DbResult<()> {
|
pub fn put_meta_is_first_block_set(&self) -> DbResult<()> {
|
||||||
let cf_meta = self.meta_column();
|
let cf_meta = self.meta_column();
|
||||||
self.db
|
self.db
|
||||||
.put_cf(&cf_meta, DB_META_FIRST_BLOCK_SET_KEY.as_bytes(), [1u8; 1])
|
.put_cf(
|
||||||
|
&cf_meta,
|
||||||
|
borsh::to_vec(&DB_META_FIRST_BLOCK_SET_KEY).map_err(|err| {
|
||||||
|
DbError::borsh_cast_message(
|
||||||
|
err,
|
||||||
|
Some("Failed to serialize DB_META_FIRST_BLOCK_SET_KEY".to_string()),
|
||||||
|
)
|
||||||
|
})?,
|
||||||
|
[1u8; 1],
|
||||||
|
)
|
||||||
.map_err(|rerr| DbError::rocksdb_cast_message(rerr, None))?;
|
.map_err(|rerr| DbError::rocksdb_cast_message(rerr, None))?;
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
@ -241,8 +298,18 @@ impl RocksDBIO {
|
|||||||
self.db
|
self.db
|
||||||
.put_cf(
|
.put_cf(
|
||||||
&cf_block,
|
&cf_block,
|
||||||
block.header.block_id.to_be_bytes(),
|
borsh::to_vec(&block.header.block_id).map_err(|err| {
|
||||||
HashableBlockData::from(block).to_bytes(),
|
DbError::borsh_cast_message(
|
||||||
|
err,
|
||||||
|
Some("Failed to serialize block id".to_string()),
|
||||||
|
)
|
||||||
|
})?,
|
||||||
|
borsh::to_vec(&HashableBlockData::from(block)).map_err(|err| {
|
||||||
|
DbError::borsh_cast_message(
|
||||||
|
err,
|
||||||
|
Some("Failed to serialize block data".to_string()),
|
||||||
|
)
|
||||||
|
})?,
|
||||||
)
|
)
|
||||||
.map_err(|rerr| DbError::rocksdb_cast_message(rerr, None))?;
|
.map_err(|rerr| DbError::rocksdb_cast_message(rerr, None))?;
|
||||||
Ok(())
|
Ok(())
|
||||||
@ -252,11 +319,26 @@ impl RocksDBIO {
|
|||||||
let cf_block = self.block_column();
|
let cf_block = self.block_column();
|
||||||
let res = self
|
let res = self
|
||||||
.db
|
.db
|
||||||
.get_cf(&cf_block, block_id.to_be_bytes())
|
.get_cf(
|
||||||
|
&cf_block,
|
||||||
|
borsh::to_vec(&block_id).map_err(|err| {
|
||||||
|
DbError::borsh_cast_message(
|
||||||
|
err,
|
||||||
|
Some("Failed to serialize block id".to_string()),
|
||||||
|
)
|
||||||
|
})?,
|
||||||
|
)
|
||||||
.map_err(|rerr| DbError::rocksdb_cast_message(rerr, None))?;
|
.map_err(|rerr| DbError::rocksdb_cast_message(rerr, None))?;
|
||||||
|
|
||||||
if let Some(data) = res {
|
if let Some(data) = res {
|
||||||
Ok(HashableBlockData::from_bytes(&data))
|
Ok(
|
||||||
|
borsh::from_slice::<HashableBlockData>(&data).map_err(|serr| {
|
||||||
|
DbError::borsh_cast_message(
|
||||||
|
serr,
|
||||||
|
Some("Failed to deserialize block data".to_string()),
|
||||||
|
)
|
||||||
|
})?,
|
||||||
|
)
|
||||||
} else {
|
} else {
|
||||||
Err(DbError::db_interaction_error(
|
Err(DbError::db_interaction_error(
|
||||||
"Block on this id not found".to_string(),
|
"Block on this id not found".to_string(),
|
||||||
@ -269,17 +351,23 @@ impl RocksDBIO {
|
|||||||
let cf_meta = self.meta_column();
|
let cf_meta = self.meta_column();
|
||||||
let sc_list = self
|
let sc_list = self
|
||||||
.db
|
.db
|
||||||
.get_cf(&cf_meta, DB_META_SC_LIST)
|
.get_cf(
|
||||||
.map_err(|rerr| DbError::rocksdb_cast_message(rerr, None))?;
|
&cf_meta,
|
||||||
if let Some(data) = sc_list {
|
borsh::to_vec(&DB_META_SC_LIST).map_err(|err| {
|
||||||
Ok(
|
DbError::borsh_cast_message(
|
||||||
serde_json::from_slice::<Vec<String>>(&data).map_err(|serr| {
|
err,
|
||||||
DbError::serde_cast_message(
|
Some("Failed to serialize DB_META_SC_LIST".to_string()),
|
||||||
serr,
|
|
||||||
Some("List of Sc Deserialization failed".to_string()),
|
|
||||||
)
|
)
|
||||||
})?,
|
})?,
|
||||||
)
|
)
|
||||||
|
.map_err(|rerr| DbError::rocksdb_cast_message(rerr, None))?;
|
||||||
|
if let Some(data) = sc_list {
|
||||||
|
Ok(borsh::from_slice::<Vec<String>>(&data).map_err(|serr| {
|
||||||
|
DbError::borsh_cast_message(
|
||||||
|
serr,
|
||||||
|
Some("List of Sc Deserialization failed".to_string()),
|
||||||
|
)
|
||||||
|
})?)
|
||||||
} else {
|
} else {
|
||||||
Err(DbError::db_interaction_error(
|
Err(DbError::db_interaction_error(
|
||||||
"Sc list not found".to_string(),
|
"Sc list not found".to_string(),
|
||||||
@ -297,250 +385,32 @@ impl RocksDBIO {
|
|||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
///Put/Modify sc state in db
|
|
||||||
pub fn put_sc_sc_state(
|
|
||||||
&self,
|
|
||||||
sc_addr: &str,
|
|
||||||
length: usize,
|
|
||||||
modifications: Vec<DataBlobChangeVariant>,
|
|
||||||
) -> DbResult<()> {
|
|
||||||
self.put_meta_sc(sc_addr.to_string())?;
|
|
||||||
|
|
||||||
let cf_sc = self.sc_column();
|
|
||||||
|
|
||||||
let sc_addr_loc = format!("{sc_addr:?}{SC_LEN_SUFFIX}");
|
|
||||||
let sc_len_addr = sc_addr_loc.as_bytes();
|
|
||||||
|
|
||||||
self.db
|
|
||||||
.put_cf(&cf_sc, sc_len_addr, length.to_be_bytes())
|
|
||||||
.map_err(|rerr| DbError::rocksdb_cast_message(rerr, None))?;
|
|
||||||
|
|
||||||
for data_change in modifications {
|
|
||||||
match data_change {
|
|
||||||
DataBlobChangeVariant::Created { id, blob } => {
|
|
||||||
let blob_addr = produce_address_for_data_blob_at_id(sc_addr, id);
|
|
||||||
|
|
||||||
self.db
|
|
||||||
.put_cf(&cf_sc, blob_addr, blob)
|
|
||||||
.map_err(|rerr| DbError::rocksdb_cast_message(rerr, None))?;
|
|
||||||
}
|
|
||||||
DataBlobChangeVariant::Modified {
|
|
||||||
id,
|
|
||||||
blob_old: _,
|
|
||||||
blob_new,
|
|
||||||
} => {
|
|
||||||
let blob_addr = produce_address_for_data_blob_at_id(sc_addr, id);
|
|
||||||
|
|
||||||
self.db
|
|
||||||
.put_cf(&cf_sc, blob_addr, blob_new)
|
|
||||||
.map_err(|rerr| DbError::rocksdb_cast_message(rerr, None))?;
|
|
||||||
}
|
|
||||||
DataBlobChangeVariant::Deleted { id } => {
|
|
||||||
let blob_addr = produce_address_for_data_blob_at_id(sc_addr, id);
|
|
||||||
|
|
||||||
self.db
|
|
||||||
.delete_cf(&cf_sc, blob_addr)
|
|
||||||
.map_err(|rerr| DbError::rocksdb_cast_message(rerr, None))?;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
Ok(())
|
|
||||||
}
|
|
||||||
|
|
||||||
///Get sc state length in blobs from DB
|
|
||||||
pub fn get_sc_sc_state_len(&self, sc_addr: &str) -> DbResult<usize> {
|
|
||||||
let cf_sc = self.sc_column();
|
|
||||||
let sc_addr_loc = format!("{sc_addr:?}{SC_LEN_SUFFIX}");
|
|
||||||
|
|
||||||
let sc_len_addr = sc_addr_loc.as_bytes();
|
|
||||||
|
|
||||||
let sc_len = self
|
|
||||||
.db
|
|
||||||
.get_cf(&cf_sc, sc_len_addr)
|
|
||||||
.map_err(|rerr| DbError::rocksdb_cast_message(rerr, None))?;
|
|
||||||
|
|
||||||
if let Some(sc_len) = sc_len {
|
|
||||||
Ok(usize::from_be_bytes(sc_len.as_slice().try_into().unwrap()))
|
|
||||||
} else {
|
|
||||||
Err(DbError::db_interaction_error(format!(
|
|
||||||
"Sc len for {sc_addr:?} not found"
|
|
||||||
)))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
///Get full sc state from DB
|
|
||||||
pub fn get_sc_sc_state(&self, sc_addr: &str) -> DbResult<Vec<DataBlob>> {
|
|
||||||
let cf_sc = self.sc_column();
|
|
||||||
let sc_len = self.get_sc_sc_state_len(sc_addr)?;
|
|
||||||
let mut data_blob_list = vec![];
|
|
||||||
|
|
||||||
for id in 0..sc_len {
|
|
||||||
let blob_addr = produce_address_for_data_blob_at_id(sc_addr, id);
|
|
||||||
|
|
||||||
let blob = self
|
|
||||||
.db
|
|
||||||
.get_cf(&cf_sc, blob_addr)
|
|
||||||
.map_err(|rerr| DbError::rocksdb_cast_message(rerr, None))?;
|
|
||||||
|
|
||||||
if let Some(blob_data) = blob {
|
|
||||||
data_blob_list.push(produce_blob_from_fit_vec(blob_data));
|
|
||||||
} else {
|
|
||||||
return Err(DbError::db_interaction_error(format!(
|
|
||||||
"Blob for {sc_addr:?} at id {id} not found"
|
|
||||||
)));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
Ok(data_blob_list)
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn get_snapshot_block_id(&self) -> DbResult<u64> {
|
pub fn get_snapshot_block_id(&self) -> DbResult<u64> {
|
||||||
let cf_snapshot = self.snapshot_column();
|
let cf_snapshot = self.snapshot_column();
|
||||||
let res = self
|
let res = self
|
||||||
.db
|
.db
|
||||||
.get_cf(&cf_snapshot, DB_SNAPSHOT_BLOCK_ID_KEY)
|
.get_cf(
|
||||||
|
&cf_snapshot,
|
||||||
|
borsh::to_vec(&DB_SNAPSHOT_BLOCK_ID_KEY).map_err(|err| {
|
||||||
|
DbError::borsh_cast_message(
|
||||||
|
err,
|
||||||
|
Some("Failed to serialize DB_SNAPSHOT_BLOCK_ID_KEY".to_string()),
|
||||||
|
)
|
||||||
|
})?,
|
||||||
|
)
|
||||||
.map_err(|rerr| DbError::rocksdb_cast_message(rerr, None))?;
|
.map_err(|rerr| DbError::rocksdb_cast_message(rerr, None))?;
|
||||||
|
|
||||||
if let Some(data) = res {
|
if let Some(data) = res {
|
||||||
Ok(u64::from_be_bytes(data.try_into().unwrap()))
|
Ok(borsh::from_slice::<u64>(&data).map_err(|err| {
|
||||||
|
DbError::borsh_cast_message(
|
||||||
|
err,
|
||||||
|
Some("Failed to deserialize last block".to_string()),
|
||||||
|
)
|
||||||
|
})?)
|
||||||
} else {
|
} else {
|
||||||
Err(DbError::db_interaction_error(
|
Err(DbError::db_interaction_error(
|
||||||
"Snapshot block ID not found".to_string(),
|
"Snapshot block ID not found".to_string(),
|
||||||
))
|
))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn get_snapshot_commitment(&self) -> DbResult<Vec<u8>> {
|
|
||||||
let cf_snapshot = self.snapshot_column();
|
|
||||||
let res = self
|
|
||||||
.db
|
|
||||||
.get_cf(&cf_snapshot, DB_SNAPSHOT_COMMITMENT_KEY)
|
|
||||||
.map_err(|rerr| DbError::rocksdb_cast_message(rerr, None))?;
|
|
||||||
|
|
||||||
if let Some(data) = res {
|
|
||||||
Ok(data)
|
|
||||||
} else {
|
|
||||||
Err(DbError::db_interaction_error(
|
|
||||||
"Snapshot commitment not found".to_string(),
|
|
||||||
))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn get_snapshot_transaction(&self) -> DbResult<Vec<u8>> {
|
|
||||||
let cf_snapshot = self.snapshot_column();
|
|
||||||
let res = self
|
|
||||||
.db
|
|
||||||
.get_cf(&cf_snapshot, DB_SNAPSHOT_TRANSACTION_KEY)
|
|
||||||
.map_err(|rerr| DbError::rocksdb_cast_message(rerr, None))?;
|
|
||||||
|
|
||||||
if let Some(data) = res {
|
|
||||||
Ok(data)
|
|
||||||
} else {
|
|
||||||
Err(DbError::db_interaction_error(
|
|
||||||
"Snapshot transaction not found".to_string(),
|
|
||||||
))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn get_snapshot_nullifier(&self) -> DbResult<Vec<u8>> {
|
|
||||||
let cf_snapshot = self.snapshot_column();
|
|
||||||
let res = self
|
|
||||||
.db
|
|
||||||
.get_cf(&cf_snapshot, DB_SNAPSHOT_NULLIFIER_KEY)
|
|
||||||
.map_err(|rerr| DbError::rocksdb_cast_message(rerr, None))?;
|
|
||||||
|
|
||||||
if let Some(data) = res {
|
|
||||||
Ok(data)
|
|
||||||
} else {
|
|
||||||
Err(DbError::db_interaction_error(
|
|
||||||
"Snapshot nullifier not found".to_string(),
|
|
||||||
))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn get_snapshot_account(&self) -> DbResult<Vec<u8>> {
|
|
||||||
let cf_snapshot = self.snapshot_column();
|
|
||||||
let res = self
|
|
||||||
.db
|
|
||||||
.get_cf(&cf_snapshot, DB_SNAPSHOT_ACCOUNT_KEY)
|
|
||||||
.map_err(|rerr| DbError::rocksdb_cast_message(rerr, None))?;
|
|
||||||
|
|
||||||
if let Some(data) = res {
|
|
||||||
Ok(data)
|
|
||||||
} else {
|
|
||||||
Err(DbError::db_interaction_error(
|
|
||||||
"Snapshot account not found".to_string(),
|
|
||||||
))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn put_snapshot_block_id_db(&self, block_id: u64) -> DbResult<()> {
|
|
||||||
let cf_snapshot = self.snapshot_column();
|
|
||||||
self.db
|
|
||||||
.put_cf(
|
|
||||||
&cf_snapshot,
|
|
||||||
DB_SNAPSHOT_BLOCK_ID_KEY.as_bytes(),
|
|
||||||
block_id.to_be_bytes(),
|
|
||||||
)
|
|
||||||
.map_err(|rerr| DbError::rocksdb_cast_message(rerr, None))?;
|
|
||||||
Ok(())
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn put_snapshot_commitement_db(&self, commitment: Vec<u8>) -> DbResult<()> {
|
|
||||||
let cf_snapshot = self.snapshot_column();
|
|
||||||
self.db
|
|
||||||
.put_cf(
|
|
||||||
&cf_snapshot,
|
|
||||||
DB_SNAPSHOT_COMMITMENT_KEY.as_bytes(),
|
|
||||||
commitment,
|
|
||||||
)
|
|
||||||
.map_err(|rerr| DbError::rocksdb_cast_message(rerr, None))?;
|
|
||||||
Ok(())
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn put_snapshot_transaction_db(&self, transaction: Vec<u8>) -> DbResult<()> {
|
|
||||||
let cf_snapshot = self.snapshot_column();
|
|
||||||
self.db
|
|
||||||
.put_cf(
|
|
||||||
&cf_snapshot,
|
|
||||||
DB_SNAPSHOT_TRANSACTION_KEY.as_bytes(),
|
|
||||||
transaction,
|
|
||||||
)
|
|
||||||
.map_err(|rerr| DbError::rocksdb_cast_message(rerr, None))?;
|
|
||||||
Ok(())
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn put_snapshot_nullifier_db(&self, nullifier: Vec<u8>) -> DbResult<()> {
|
|
||||||
let cf_snapshot = self.snapshot_column();
|
|
||||||
self.db
|
|
||||||
.put_cf(
|
|
||||||
&cf_snapshot,
|
|
||||||
DB_SNAPSHOT_NULLIFIER_KEY.as_bytes(),
|
|
||||||
nullifier,
|
|
||||||
)
|
|
||||||
.map_err(|rerr| DbError::rocksdb_cast_message(rerr, None))?;
|
|
||||||
Ok(())
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn put_snapshot_account_db(&self, account: Vec<u8>) -> DbResult<()> {
|
|
||||||
let cf_snapshot = self.snapshot_column();
|
|
||||||
self.db
|
|
||||||
.put_cf(&cf_snapshot, DB_SNAPSHOT_ACCOUNT_KEY.as_bytes(), account)
|
|
||||||
.map_err(|rerr| DbError::rocksdb_cast_message(rerr, None))?;
|
|
||||||
Ok(())
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
///Creates address for sc data blob at corresponding id
|
|
||||||
fn produce_address_for_data_blob_at_id(sc_addr: &str, id: usize) -> Vec<u8> {
|
|
||||||
let mut prefix_bytes: Vec<u8> = sc_addr.as_bytes().to_vec();
|
|
||||||
|
|
||||||
let id_bytes = id.to_be_bytes();
|
|
||||||
|
|
||||||
for byte in id_bytes {
|
|
||||||
prefix_bytes.push(byte);
|
|
||||||
}
|
|
||||||
|
|
||||||
prefix_bytes
|
|
||||||
}
|
}
|
||||||
|
|||||||
@ -1,160 +0,0 @@
|
|||||||
use serde::{Deserialize, Serialize, de::Error};
|
|
||||||
|
|
||||||
use crate::SC_DATA_BLOB_SIZE;
|
|
||||||
|
|
||||||
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
|
|
||||||
pub struct DataBlob(pub [u8; SC_DATA_BLOB_SIZE]);
|
|
||||||
|
|
||||||
impl From<[u8; SC_DATA_BLOB_SIZE]> for DataBlob {
|
|
||||||
fn from(value: [u8; SC_DATA_BLOB_SIZE]) -> Self {
|
|
||||||
Self(value)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl Serialize for DataBlob {
|
|
||||||
fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
|
|
||||||
where
|
|
||||||
S: serde::Serializer,
|
|
||||||
{
|
|
||||||
let data_vec = self.0.to_vec();
|
|
||||||
data_vec.serialize(serializer)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl AsRef<[u8]> for DataBlob {
|
|
||||||
fn as_ref(&self) -> &[u8] {
|
|
||||||
self.0.as_ref()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl<'de> Deserialize<'de> for DataBlob {
|
|
||||||
fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
|
|
||||||
where
|
|
||||||
D: serde::Deserializer<'de>,
|
|
||||||
{
|
|
||||||
let data_vec = Vec::<u8>::deserialize(deserializer)?;
|
|
||||||
let chunk: [u8; SC_DATA_BLOB_SIZE] = data_vec
|
|
||||||
.try_into()
|
|
||||||
.map_err(|data| {
|
|
||||||
anyhow::anyhow!("failed to fit vec {data:?} to {:?}", SC_DATA_BLOB_SIZE)
|
|
||||||
})
|
|
||||||
.map_err(D::Error::custom)?;
|
|
||||||
Ok(Self(chunk))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl DataBlob {
|
|
||||||
pub fn to_vec(&self) -> Vec<u8> {
|
|
||||||
self.0.to_vec()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#[allow(clippy::large_enum_variant)]
|
|
||||||
#[derive(Debug, Clone, Copy, Serialize, Deserialize, PartialEq, Eq)]
|
|
||||||
pub enum DataBlobChangeVariant {
|
|
||||||
Created {
|
|
||||||
id: usize,
|
|
||||||
blob: DataBlob,
|
|
||||||
},
|
|
||||||
Modified {
|
|
||||||
id: usize,
|
|
||||||
blob_old: DataBlob,
|
|
||||||
blob_new: DataBlob,
|
|
||||||
},
|
|
||||||
Deleted {
|
|
||||||
id: usize,
|
|
||||||
},
|
|
||||||
}
|
|
||||||
|
|
||||||
///Produce `DataBlob` from vector of size <= `SC_DATA_BLOB_SIZE`
|
|
||||||
///
|
|
||||||
///Extends to `SC_DATA_BLOB_SIZE`, if necessary.
|
|
||||||
///
|
|
||||||
///Panics, if size > `SC_DATA_BLOB_SIZE`
|
|
||||||
pub fn produce_blob_from_fit_vec(data: Vec<u8>) -> DataBlob {
|
|
||||||
let data_len = data.len();
|
|
||||||
|
|
||||||
assert!(data_len <= SC_DATA_BLOB_SIZE);
|
|
||||||
let mut blob: DataBlob = [0; SC_DATA_BLOB_SIZE].into();
|
|
||||||
|
|
||||||
for (idx, item) in data.into_iter().enumerate() {
|
|
||||||
blob.0[idx] = item
|
|
||||||
}
|
|
||||||
|
|
||||||
blob
|
|
||||||
}
|
|
||||||
|
|
||||||
#[cfg(test)]
|
|
||||||
mod tests {
|
|
||||||
use super::*;
|
|
||||||
use serde_json;
|
|
||||||
|
|
||||||
const TEST_BLOB_SIZE: usize = 256; // Define a test blob size for simplicity
|
|
||||||
static SC_DATA_BLOB_SIZE: usize = TEST_BLOB_SIZE;
|
|
||||||
|
|
||||||
fn sample_vec() -> Vec<u8> {
|
|
||||||
(0..SC_DATA_BLOB_SIZE)
|
|
||||||
.collect::<Vec<usize>>()
|
|
||||||
.iter()
|
|
||||||
.map(|&x| x as u8)
|
|
||||||
.collect()
|
|
||||||
}
|
|
||||||
|
|
||||||
fn sample_data_blob() -> DataBlob {
|
|
||||||
let vec: Vec<u8> = sample_vec();
|
|
||||||
produce_blob_from_fit_vec(vec)
|
|
||||||
}
|
|
||||||
|
|
||||||
#[test]
|
|
||||||
fn test_serialize_data_blob() {
|
|
||||||
let blob = sample_data_blob();
|
|
||||||
let json = serde_json::to_string(&blob).unwrap();
|
|
||||||
|
|
||||||
let expected_json = serde_json::to_string(&sample_vec()).unwrap();
|
|
||||||
assert_eq!(json, expected_json);
|
|
||||||
}
|
|
||||||
|
|
||||||
#[test]
|
|
||||||
fn test_deserialize_data_blob() {
|
|
||||||
let data = sample_vec();
|
|
||||||
let json = serde_json::to_string(&data).unwrap();
|
|
||||||
let deserialized: DataBlob = serde_json::from_str(&json).unwrap();
|
|
||||||
assert_eq!(deserialized.to_vec(), data);
|
|
||||||
}
|
|
||||||
|
|
||||||
#[test]
|
|
||||||
fn test_serialize_deserialize_data_blob_change_variant() {
|
|
||||||
let blob1 = sample_data_blob();
|
|
||||||
let blob2 = produce_blob_from_fit_vec((50..50 + SC_DATA_BLOB_SIZE as u8).collect());
|
|
||||||
|
|
||||||
let variants = vec![
|
|
||||||
DataBlobChangeVariant::Created { id: 1, blob: blob1 },
|
|
||||||
DataBlobChangeVariant::Modified {
|
|
||||||
id: 2,
|
|
||||||
blob_old: blob1,
|
|
||||||
blob_new: blob2,
|
|
||||||
},
|
|
||||||
DataBlobChangeVariant::Deleted { id: 3 },
|
|
||||||
];
|
|
||||||
|
|
||||||
for variant in variants {
|
|
||||||
let json = serde_json::to_string(&variant).unwrap();
|
|
||||||
let deserialized: DataBlobChangeVariant = serde_json::from_str(&json).unwrap();
|
|
||||||
assert_eq!(variant, deserialized);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#[test]
|
|
||||||
fn test_produce_blob_from_fit_vec() {
|
|
||||||
let data = (0..255).collect();
|
|
||||||
let blob = produce_blob_from_fit_vec(data);
|
|
||||||
assert_eq!(blob.0[..4], [0, 1, 2, 3]);
|
|
||||||
}
|
|
||||||
|
|
||||||
#[test]
|
|
||||||
#[should_panic]
|
|
||||||
fn test_produce_blob_from_fit_vec_panic() {
|
|
||||||
let data = vec![0; SC_DATA_BLOB_SIZE + 1];
|
|
||||||
let _ = produce_blob_from_fit_vec(data);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@ -15,6 +15,7 @@ clap.workspace = true
|
|||||||
nssa-core = { path = "../nssa/core" }
|
nssa-core = { path = "../nssa/core" }
|
||||||
base64.workspace = true
|
base64.workspace = true
|
||||||
bytemuck = "1.23.2"
|
bytemuck = "1.23.2"
|
||||||
|
borsh.workspace = true
|
||||||
|
|
||||||
[dependencies.key_protocol]
|
[dependencies.key_protocol]
|
||||||
path = "../key_protocol"
|
path = "../key_protocol"
|
||||||
|
|||||||
@ -175,7 +175,7 @@ impl WalletCore {
|
|||||||
pub async fn poll_public_native_token_transfer(&self, hash: String) -> Result<NSSATransaction> {
|
pub async fn poll_public_native_token_transfer(&self, hash: String) -> Result<NSSATransaction> {
|
||||||
let transaction_encoded = self.poller.poll_tx(hash).await?;
|
let transaction_encoded = self.poller.poll_tx(hash).await?;
|
||||||
let tx_base64_decode = BASE64.decode(transaction_encoded)?;
|
let tx_base64_decode = BASE64.decode(transaction_encoded)?;
|
||||||
let pub_tx = EncodedTransaction::from_bytes(tx_base64_decode);
|
let pub_tx = borsh::from_slice::<EncodedTransaction>(&tx_base64_decode).unwrap();
|
||||||
|
|
||||||
Ok(NSSATransaction::try_from(&pub_tx)?)
|
Ok(NSSATransaction::try_from(&pub_tx)?)
|
||||||
}
|
}
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user