mirror of
https://github.com/logos-blockchain/lssa.git
synced 2026-01-16 12:13:08 +00:00
fix: private state operations added
This commit is contained in:
parent
aa88d1c8f4
commit
bb9b28933d
1
Cargo.lock
generated
1
Cargo.lock
generated
@ -4541,6 +4541,7 @@ dependencies = [
|
||||
"serde_json",
|
||||
"sha2 0.10.8",
|
||||
"storage",
|
||||
"thiserror 1.0.69",
|
||||
"utxo",
|
||||
]
|
||||
|
||||
|
||||
@ -15,6 +15,7 @@ use common::{
|
||||
};
|
||||
use k256::AffinePoint;
|
||||
use public_context::PublicSCContext;
|
||||
use sc_core::private_state::PrivateSCState;
|
||||
use utxo::utxo_core::UTXO;
|
||||
|
||||
use crate::ActionData;
|
||||
@ -29,6 +30,10 @@ pub struct NodeChainStore {
|
||||
pub nullifier_store: NullifierSparseMerkleTree,
|
||||
pub utxo_commitments_store: UTXOCommitmentsMerkleTree,
|
||||
pub pub_tx_store: PublicTransactionMerkleTree,
|
||||
/// Contract private state
|
||||
///
|
||||
/// ToDo: Replace regualar BTreeMap with weighted binary tree
|
||||
pub contracts_private_state: HashMap<String, PrivateSCState>,
|
||||
}
|
||||
|
||||
impl NodeChainStore {
|
||||
@ -37,6 +42,7 @@ impl NodeChainStore {
|
||||
let nullifier_store = NullifierSparseMerkleTree::default();
|
||||
let utxo_commitments_store = UTXOCommitmentsMerkleTree::new(vec![]);
|
||||
let pub_tx_store = PublicTransactionMerkleTree::new(vec![]);
|
||||
let contracts_private_state = HashMap::new();
|
||||
|
||||
//Sequencer should panic if unable to open db,
|
||||
//as fixing this issue may require actions non-native to program scope
|
||||
@ -50,6 +56,7 @@ impl NodeChainStore {
|
||||
nullifier_store,
|
||||
utxo_commitments_store,
|
||||
pub_tx_store,
|
||||
contracts_private_state,
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@ -101,6 +101,7 @@ impl NodeCore {
|
||||
let mut storage = NodeChainStore::new_with_genesis(&config.home, genesis_block);
|
||||
|
||||
pre_start::setup_empty_sc_states(&storage).await?;
|
||||
pre_start::setup_empty_private_sc_states(&mut storage);
|
||||
|
||||
let mut chain_height = genesis_id.genesis_id;
|
||||
|
||||
|
||||
@ -1,3 +1,5 @@
|
||||
use std::collections::BTreeMap;
|
||||
|
||||
use anyhow::Result;
|
||||
use log::info;
|
||||
|
||||
@ -73,3 +75,57 @@ pub async fn setup_empty_sc_states(node: &NodeChainStore) -> Result<()> {
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
///Setups private states of default smart conracts as empty
|
||||
pub fn setup_empty_private_sc_states(node: &mut NodeChainStore) {
|
||||
info!("Filling up private states of default smart contracts");
|
||||
|
||||
let empty_mmap = BTreeMap::new();
|
||||
|
||||
let public_deposit_addr = hex::encode(PUBLIC_DEPOSIT_ID);
|
||||
node.contracts_private_state
|
||||
.insert(public_deposit_addr, empty_mmap.clone());
|
||||
info!("Public transfer state set");
|
||||
|
||||
let mint_utxo_addr_bytes: Vec<u8> = zkvm::test_methods::MINT_UTXO_ID
|
||||
.iter()
|
||||
.map(|num| num.to_le_bytes())
|
||||
.flatten()
|
||||
.collect();
|
||||
let mint_utxo_addr = hex::encode(mint_utxo_addr_bytes);
|
||||
node.contracts_private_state
|
||||
.insert(mint_utxo_addr, empty_mmap.clone());
|
||||
info!("Mint UTXO state set");
|
||||
|
||||
let single_utxo_transfer_addr_bytes: Vec<u8> = zkvm::test_methods::SEND_UTXO_ID
|
||||
.iter()
|
||||
.map(|num| num.to_le_bytes())
|
||||
.flatten()
|
||||
.collect();
|
||||
let single_utxo_transfer_addr = hex::encode(single_utxo_transfer_addr_bytes);
|
||||
node.contracts_private_state
|
||||
.insert(single_utxo_transfer_addr, empty_mmap.clone());
|
||||
info!("Single UTXO transfer state set");
|
||||
|
||||
let mint_utxo_multiple_assets_addr_bytes: Vec<u8> =
|
||||
zkvm::test_methods::MINT_UTXO_MULTIPLE_ASSETS_ID
|
||||
.iter()
|
||||
.map(|num| num.to_le_bytes())
|
||||
.flatten()
|
||||
.collect();
|
||||
let mint_utxo_multiple_assets_addr = hex::encode(mint_utxo_multiple_assets_addr_bytes);
|
||||
node.contracts_private_state
|
||||
.insert(mint_utxo_multiple_assets_addr, empty_mmap.clone());
|
||||
info!("Mint UTXO multiple assets state set");
|
||||
|
||||
let multiple_assets_utxo_transfer_addr_bytes: Vec<u8> =
|
||||
zkvm::test_methods::SEND_UTXO_MULTIPLE_ASSETS_ID
|
||||
.iter()
|
||||
.map(|num| num.to_le_bytes())
|
||||
.flatten()
|
||||
.collect();
|
||||
let multiple_assets_utxo_transfer_addr = hex::encode(multiple_assets_utxo_transfer_addr_bytes);
|
||||
node.contracts_private_state
|
||||
.insert(multiple_assets_utxo_transfer_addr, empty_mmap.clone());
|
||||
info!("Multiple_assets UTXO transfer state set");
|
||||
}
|
||||
|
||||
@ -19,6 +19,7 @@ hex.workspace = true
|
||||
light-poseidon.workspace = true
|
||||
ark-bn254.workspace = true
|
||||
ark-ff.workspace = true
|
||||
thiserror.workspace = true
|
||||
|
||||
risc0-zkvm = { git = "https://github.com/risc0/risc0.git", branch = "release-2.0" }
|
||||
|
||||
|
||||
@ -1,4 +1,5 @@
|
||||
pub mod cryptography;
|
||||
pub mod private_state;
|
||||
pub mod proofs_circuits;
|
||||
pub mod transaction_payloads_tools;
|
||||
pub mod utxo_manipulator;
|
||||
|
||||
216
sc_core/src/private_state.rs
Normal file
216
sc_core/src/private_state.rs
Normal file
@ -0,0 +1,216 @@
|
||||
use std::collections::BTreeMap;
|
||||
|
||||
use serde::{de::Error, Deserialize, Serialize};
|
||||
|
||||
pub const PRIVATE_BLOB_SIZE: usize = 32;
|
||||
|
||||
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
|
||||
pub struct PrivateDataBlob(pub [u8; PRIVATE_BLOB_SIZE]);
|
||||
|
||||
pub type PrivateSCState = BTreeMap<usize, PrivateDataBlob>;
|
||||
|
||||
#[derive(thiserror::Error, Debug)]
|
||||
pub enum PrivateStateError {
|
||||
#[error("Trying to read from slot too big: Read slot {0}, max_slot {1}")]
|
||||
ReadSizeMismatch(usize, usize),
|
||||
#[error("Can not write empty bytes into state")]
|
||||
EmptyWrite,
|
||||
}
|
||||
|
||||
impl From<[u8; PRIVATE_BLOB_SIZE]> for PrivateDataBlob {
|
||||
fn from(value: [u8; PRIVATE_BLOB_SIZE]) -> Self {
|
||||
Self(value)
|
||||
}
|
||||
}
|
||||
|
||||
impl Serialize for PrivateDataBlob {
|
||||
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 PrivateDataBlob {
|
||||
fn as_ref(&self) -> &[u8] {
|
||||
self.0.as_ref()
|
||||
}
|
||||
}
|
||||
|
||||
impl<'de> Deserialize<'de> for PrivateDataBlob {
|
||||
fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
|
||||
where
|
||||
D: serde::Deserializer<'de>,
|
||||
{
|
||||
let data_vec = Vec::<u8>::deserialize(deserializer)?;
|
||||
let chunk: [u8; PRIVATE_BLOB_SIZE] = data_vec
|
||||
.try_into()
|
||||
.map_err(|data| {
|
||||
anyhow::anyhow!("failed to fit vec {data:?} to {:?}", PRIVATE_BLOB_SIZE)
|
||||
})
|
||||
.map_err(D::Error::custom)?;
|
||||
Ok(Self(chunk))
|
||||
}
|
||||
}
|
||||
|
||||
impl PrivateDataBlob {
|
||||
pub fn to_vec(&self) -> Vec<u8> {
|
||||
self.0.to_vec()
|
||||
}
|
||||
}
|
||||
|
||||
///Produce `DataBlob` from vector of size <= `PRIVATE_BLOB_SIZE`
|
||||
///
|
||||
///Extends to `PRIVATE_BLOB_SIZE`, if necessary.
|
||||
///
|
||||
///Panics, if size > `PRIVATE_BLOB_SIZE`
|
||||
pub fn produce_blob_from_fit_vec(data: Vec<u8>) -> PrivateDataBlob {
|
||||
let data_len = data.len();
|
||||
|
||||
assert!(data_len <= PRIVATE_BLOB_SIZE);
|
||||
let mut blob: PrivateDataBlob = [0; PRIVATE_BLOB_SIZE].into();
|
||||
|
||||
for (idx, item) in data.into_iter().enumerate() {
|
||||
blob.0[idx] = item
|
||||
}
|
||||
|
||||
blob
|
||||
}
|
||||
|
||||
///Produce `DataBlob` from slice of size <= `PRIVATE_BLOB_SIZE`
|
||||
///
|
||||
///Extends to `PRIVATE_BLOB_SIZE`, if necessary.
|
||||
///
|
||||
///Panics, if size > `PRIVATE_BLOB_SIZE`
|
||||
pub fn produce_blob_from_fit_slice(data: &[u8]) -> PrivateDataBlob {
|
||||
let data_len = data.len();
|
||||
|
||||
assert!(data_len <= PRIVATE_BLOB_SIZE);
|
||||
let mut blob: PrivateDataBlob = [0; PRIVATE_BLOB_SIZE].into();
|
||||
|
||||
for (idx, item) in data.into_iter().enumerate() {
|
||||
blob.0[idx] = *item
|
||||
}
|
||||
|
||||
blob
|
||||
}
|
||||
|
||||
pub fn calculate_offset_slot(offset: usize) -> usize {
|
||||
offset / PRIVATE_BLOB_SIZE
|
||||
}
|
||||
|
||||
pub fn max_slot(state: &PrivateSCState) -> usize {
|
||||
*state.keys().max().unwrap_or(&0)
|
||||
}
|
||||
|
||||
///Read at least `num` bytes from the start of a state
|
||||
pub fn read_num_bytes_start(
|
||||
state: &PrivateSCState,
|
||||
num: usize,
|
||||
) -> Result<Vec<PrivateDataBlob>, PrivateStateError> {
|
||||
let mut resp = vec![];
|
||||
|
||||
let max_offset_slot = calculate_offset_slot(num);
|
||||
let max_slot_state = max_slot(state);
|
||||
if max_offset_slot > max_slot_state {
|
||||
return Err(PrivateStateError::ReadSizeMismatch(
|
||||
max_offset_slot,
|
||||
max_slot_state,
|
||||
));
|
||||
}
|
||||
|
||||
for i in 0..max_offset_slot {
|
||||
resp.push(*state.get(&i).unwrap());
|
||||
}
|
||||
|
||||
Ok(resp)
|
||||
}
|
||||
|
||||
///Read at least `num` bytes from the `offset` slot
|
||||
pub fn read_num_bytes_offset(
|
||||
state: &PrivateSCState,
|
||||
num: usize,
|
||||
offset: usize,
|
||||
) -> Result<Vec<PrivateDataBlob>, PrivateStateError> {
|
||||
let mut resp = vec![];
|
||||
|
||||
let max_offset_slot = offset + calculate_offset_slot(num);
|
||||
let max_slot_state = max_slot(state);
|
||||
if max_offset_slot > max_slot_state {
|
||||
return Err(PrivateStateError::ReadSizeMismatch(
|
||||
max_offset_slot,
|
||||
max_slot_state,
|
||||
));
|
||||
}
|
||||
|
||||
for i in offset..max_offset_slot {
|
||||
resp.push(*state.get(&i).unwrap());
|
||||
}
|
||||
|
||||
Ok(resp)
|
||||
}
|
||||
|
||||
///Write at least `bytes.len()` bytes at the end of the state
|
||||
///
|
||||
/// Returns new last slot
|
||||
pub fn write_num_bytes_append(
|
||||
state: &mut PrivateSCState,
|
||||
bytes: Vec<u8>,
|
||||
) -> Result<usize, PrivateStateError> {
|
||||
if bytes.is_empty() {
|
||||
return Err(PrivateStateError::EmptyWrite);
|
||||
}
|
||||
|
||||
let mut max_slot_state = max_slot(state) + 1;
|
||||
|
||||
let mut curr = 0;
|
||||
|
||||
while (curr + PRIVATE_BLOB_SIZE) < bytes.len() {
|
||||
let data_blob = produce_blob_from_fit_slice(&bytes[curr..(curr + PRIVATE_BLOB_SIZE)]);
|
||||
|
||||
state.insert(max_slot_state, data_blob);
|
||||
|
||||
curr += PRIVATE_BLOB_SIZE;
|
||||
max_slot_state += 1;
|
||||
}
|
||||
|
||||
let data_blob = produce_blob_from_fit_slice(&bytes[curr..(bytes.len())]);
|
||||
|
||||
state.insert(max_slot_state, data_blob);
|
||||
|
||||
Ok(max_slot_state)
|
||||
}
|
||||
|
||||
/// Rewrite at least `bytes.len()` bytes starting from the offset slot
|
||||
///
|
||||
/// Returns last (re)written slot
|
||||
pub fn write_num_bytes_rewrite(
|
||||
state: &mut PrivateSCState,
|
||||
bytes: Vec<u8>,
|
||||
offset: usize,
|
||||
) -> Result<usize, PrivateStateError> {
|
||||
if bytes.is_empty() {
|
||||
return Err(PrivateStateError::EmptyWrite);
|
||||
}
|
||||
|
||||
let mut curr_slot = offset;
|
||||
|
||||
let mut curr = 0;
|
||||
|
||||
while (curr + PRIVATE_BLOB_SIZE) < bytes.len() {
|
||||
let data_blob = produce_blob_from_fit_slice(&bytes[curr..(curr + PRIVATE_BLOB_SIZE)]);
|
||||
|
||||
state.insert(curr_slot, data_blob);
|
||||
|
||||
curr += PRIVATE_BLOB_SIZE;
|
||||
curr_slot += 1;
|
||||
}
|
||||
|
||||
let data_blob = produce_blob_from_fit_slice(&bytes[curr..(bytes.len())]);
|
||||
|
||||
state.insert(curr_slot, data_blob);
|
||||
|
||||
Ok(curr_slot)
|
||||
}
|
||||
Loading…
x
Reference in New Issue
Block a user