mirror of
https://github.com/darkrenaissance/darkfi.git
synced 2026-04-28 03:00:18 -04:00
WIP runtime: remove Batches logic, write directly to overlay
This commit is contained in:
@@ -1034,7 +1034,7 @@ impl ValidatorState {
|
||||
Ok(())
|
||||
}
|
||||
|
||||
pub async fn verify_transactions2(&self, txs: &[Transaction], write: bool) -> Result<()> {
|
||||
pub async fn verify_transactions2(&self, _txs: &[Transaction], _write: bool) -> Result<()> {
|
||||
/*
|
||||
let mut sled_overlay = SledDbOverlay::new();
|
||||
|
||||
|
||||
@@ -30,10 +30,7 @@ use log::{debug, error, info};
|
||||
use wasmer::{FunctionEnvMut, WasmPtr};
|
||||
|
||||
use crate::{
|
||||
runtime::{
|
||||
import,
|
||||
vm_runtime::{ContractSection, Env, SMART_CONTRACT_ZKAS_DB_NAME},
|
||||
},
|
||||
runtime::vm_runtime::{ContractSection, Env, SMART_CONTRACT_ZKAS_DB_NAME},
|
||||
zk::{empty_witnesses, VerifyingKey, ZkCircuit},
|
||||
zkas::ZkBinary,
|
||||
};
|
||||
@@ -120,14 +117,8 @@ pub(crate) fn db_init(ctx: FunctionEnvMut<Env>, ptr: WasmPtr<u8>, len: u32) -> i
|
||||
|
||||
// TODO: Make sure we don't duplicate the DbHandle in the vec.
|
||||
// It should behave like an ordered set.
|
||||
// In `lookup()` we also create a `sled::Batch`. This is done for
|
||||
// some simplicity reasons, and also for possible future changes.
|
||||
// However, we make sure that unauthorized writes are not available
|
||||
// from other functions that interface with the databases.
|
||||
let mut db_handles = env.db_handles.borrow_mut();
|
||||
let mut db_batches = env.db_batches.borrow_mut();
|
||||
db_handles.push(DbHandle::new(cid, tree_handle));
|
||||
db_batches.push(import::util::Batch::default());
|
||||
(db_handles.len() - 1) as i32
|
||||
}
|
||||
|
||||
@@ -203,14 +194,8 @@ pub(crate) fn db_lookup(ctx: FunctionEnvMut<Env>, ptr: WasmPtr<u8>, len: u32) ->
|
||||
|
||||
// TODO: Make sure we don't duplicate the DbHandle in the vec.
|
||||
// It should behave like an ordered set.
|
||||
// In `lookup()` we also create a `sled::Batch`. This is done for
|
||||
// some simplicity reasons, and also for possible future changes.
|
||||
// However, we make sure that unauthorized writes are not available
|
||||
// from other functions that interface with the databases.
|
||||
let mut db_handles = env.db_handles.borrow_mut();
|
||||
let mut db_batches = env.db_batches.borrow_mut();
|
||||
db_handles.push(DbHandle::new(cid, tree_handle));
|
||||
db_batches.push(import::util::Batch::default());
|
||||
(db_handles.len() - 1) as i32
|
||||
}
|
||||
|
||||
@@ -274,23 +259,33 @@ pub(crate) fn db_set(ctx: FunctionEnvMut<Env>, ptr: WasmPtr<u8>, len: u32) -> i3
|
||||
}*/
|
||||
|
||||
let db_handles = env.db_handles.borrow();
|
||||
let mut db_batches = env.db_batches.borrow_mut();
|
||||
|
||||
if db_handles.len() <= db_handle || db_batches.len() <= db_handle {
|
||||
if db_handles.len() <= db_handle {
|
||||
error!(target: "runtime::db::db_set()", "Requested DbHandle that is out of bounds");
|
||||
return DB_SET_FAILED
|
||||
}
|
||||
|
||||
let handle_idx = db_handle;
|
||||
let db_handle = &db_handles[handle_idx];
|
||||
let db_batch = &mut db_batches[handle_idx];
|
||||
|
||||
if db_handle.contract_id != env.contract_id {
|
||||
error!(target: "runtime::db::db_set()", "Unauthorized to write to DbHandle");
|
||||
return CALLER_ACCESS_DENIED
|
||||
}
|
||||
|
||||
db_batch.insert(key, value);
|
||||
if env
|
||||
.blockchain
|
||||
.lock()
|
||||
.unwrap()
|
||||
.overlay
|
||||
.lock()
|
||||
.unwrap()
|
||||
.insert(&db_handle.tree, &key, &value)
|
||||
.is_err()
|
||||
{
|
||||
error!(target: "runtime::db::db_set()", "Couldn't insert to db_handle tree");
|
||||
return DB_SET_FAILED
|
||||
}
|
||||
|
||||
DB_SUCCESS
|
||||
}
|
||||
@@ -347,23 +342,25 @@ pub(crate) fn db_del(ctx: FunctionEnvMut<Env>, ptr: WasmPtr<u8>, len: u32) -> i3
|
||||
}*/
|
||||
|
||||
let db_handles = env.db_handles.borrow();
|
||||
let mut db_batches = env.db_batches.borrow_mut();
|
||||
|
||||
if db_handles.len() <= db_handle || db_batches.len() <= db_handle {
|
||||
if db_handles.len() <= db_handle {
|
||||
error!(target: "runtime::db::db_del()", "Requested DbHandle that is out of bounds");
|
||||
return DB_DEL_FAILED
|
||||
}
|
||||
|
||||
let handle_idx = db_handle;
|
||||
let db_handle = &db_handles[handle_idx];
|
||||
let db_batch = &mut db_batches[handle_idx];
|
||||
|
||||
if db_handle.contract_id != env.contract_id {
|
||||
error!(target: "runtime::db::db_del()", "Unauthorized to write to DbHandle");
|
||||
return CALLER_ACCESS_DENIED
|
||||
}
|
||||
|
||||
db_batch.remove(key);
|
||||
if env.blockchain.lock().unwrap().overlay.lock().unwrap().remove(&db_handle.tree, &key).is_err()
|
||||
{
|
||||
error!(target: "runtime::db::db_del()", "Couldn't remove key from db_handle tree");
|
||||
return DB_DEL_FAILED
|
||||
}
|
||||
|
||||
DB_SUCCESS
|
||||
}
|
||||
@@ -565,9 +562,7 @@ pub(crate) fn zkas_db_set(ctx: FunctionEnvMut<Env>, ptr: WasmPtr<u8>, len: u32)
|
||||
|
||||
// Because of `Runtime::Deploy`, we should be sure that the zkas db is index zero.
|
||||
let db_handles = env.db_handles.borrow();
|
||||
let mut db_batches = env.db_batches.borrow_mut();
|
||||
let db_handle = &db_handles[0];
|
||||
let db_batch = &mut db_batches[0];
|
||||
// Redundant check
|
||||
if &db_handle.contract_id != contract_id {
|
||||
error!(target: "runtime::db::zkas_db_set()", "Internal error, zkas db at index 0 incorrect");
|
||||
@@ -617,7 +612,19 @@ pub(crate) fn zkas_db_set(ctx: FunctionEnvMut<Env>, ptr: WasmPtr<u8>, len: u32)
|
||||
|
||||
let key = serialize(&zkbin.namespace);
|
||||
let value = serialize(&(zkas_bincode, vk_buf));
|
||||
db_batch.insert(key, value);
|
||||
if env
|
||||
.blockchain
|
||||
.lock()
|
||||
.unwrap()
|
||||
.overlay
|
||||
.lock()
|
||||
.unwrap()
|
||||
.insert(&db_handle.tree, &key, &value)
|
||||
.is_err()
|
||||
{
|
||||
error!(target: "runtime::db::zkas_db_set()", "Couldn't insert to db_handle tree");
|
||||
return DB_SET_FAILED
|
||||
}
|
||||
|
||||
DB_SUCCESS
|
||||
}
|
||||
|
||||
@@ -73,11 +73,9 @@ pub(crate) fn merkle_add(ctx: FunctionEnvMut<Env>, ptr: WasmPtr<u8>, len: u32) -
|
||||
let db_info = db_info as usize;
|
||||
let db_roots = db_roots as usize;
|
||||
let db_handles = env.db_handles.borrow();
|
||||
let mut db_batches = env.db_batches.borrow_mut();
|
||||
let n_dbs = db_handles.len();
|
||||
let n_bat = db_batches.len();
|
||||
|
||||
if n_dbs <= db_info || n_bat <= db_info || n_dbs <= db_roots || n_bat <= db_roots {
|
||||
if n_dbs <= db_info || n_dbs <= db_roots {
|
||||
error!(target: "runtime::merkle", "Requested DbHandle that is out of bounds");
|
||||
return -2
|
||||
}
|
||||
@@ -184,12 +182,17 @@ pub(crate) fn merkle_add(ctx: FunctionEnvMut<Env>, ptr: WasmPtr<u8>, len: u32) -
|
||||
error!(target: "runtime::merkle", "Couldn't reserialize modified tree");
|
||||
return -2
|
||||
}
|
||||
let db_info_batch = &mut db_batches[info_handle_idx];
|
||||
db_info_batch.insert(key, tree_data);
|
||||
|
||||
// Apply changes to overlay
|
||||
let lock = env.blockchain.lock().unwrap();
|
||||
let mut overlay = lock.overlay.lock().unwrap();
|
||||
if overlay.insert(&db_info.tree, &key, &tree_data).is_err() {
|
||||
error!(target: "runtime::merkle", "Couldn't insert to db_info tree");
|
||||
return -2
|
||||
}
|
||||
|
||||
// Here we add the Merkle root to our set of roots
|
||||
// TODO: We should probably make sure that this root isn't in the set
|
||||
let db_roots_batch = &mut db_batches[roots_handle_idx];
|
||||
for root in new_roots.iter() {
|
||||
// FIXME: Why were we writing the set size here?
|
||||
//let root_index: Vec<u8> = serialize(&(set_size as u32));
|
||||
@@ -198,8 +201,10 @@ pub(crate) fn merkle_add(ctx: FunctionEnvMut<Env>, ptr: WasmPtr<u8>, len: u32) -
|
||||
let root_value: Vec<u8> = serialize(root);
|
||||
// FIXME: This assert can be used to DoS nodes from contracts
|
||||
assert_eq!(root_value.len(), 32);
|
||||
//db_roots_batch.insert(root_index, root_value);
|
||||
db_roots_batch.insert(root_value, &[]);
|
||||
if overlay.insert(&db_roots.tree, &root_value, &[]).is_err() {
|
||||
error!(target: "runtime::merkle", "Couldn't insert to db_roots tree");
|
||||
return -2
|
||||
}
|
||||
}
|
||||
|
||||
0
|
||||
|
||||
@@ -16,10 +16,6 @@
|
||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
// NOTE: temporary imports
|
||||
use sled::IVec;
|
||||
use std::collections::BTreeMap as Map;
|
||||
|
||||
use log::error;
|
||||
use wasmer::{FunctionEnvMut, WasmPtr};
|
||||
|
||||
@@ -152,40 +148,3 @@ pub(crate) fn get_object_size(ctx: FunctionEnvMut<Env>, idx: u32) -> i64 {
|
||||
let obj = &objects[idx as usize];
|
||||
obj.len() as i64
|
||||
}
|
||||
|
||||
// TODO: This is a direct copy of [`sled::Batch`](late night adventures).
|
||||
// Options:
|
||||
// 1. Upstream a get_writes() function
|
||||
// 2. Make writes public to external crates in upstream
|
||||
// 3. Drop Batches usage since we can write directly to the overlay
|
||||
// 4. Upstream batches support to sled_overlay
|
||||
#[derive(Debug, Default, Clone, PartialEq, Eq)]
|
||||
pub struct Batch {
|
||||
pub(crate) writes: Map<IVec, Option<IVec>>,
|
||||
}
|
||||
|
||||
impl Batch {
|
||||
/// Set a key to a new value
|
||||
pub fn insert<K, V>(&mut self, key: K, value: V)
|
||||
where
|
||||
K: Into<IVec>,
|
||||
V: Into<IVec>,
|
||||
{
|
||||
self.writes.insert(key.into(), Some(value.into()));
|
||||
}
|
||||
|
||||
/// Remove a key
|
||||
pub fn remove<K>(&mut self, key: K)
|
||||
where
|
||||
K: Into<IVec>,
|
||||
{
|
||||
self.writes.insert(key.into(), None);
|
||||
}
|
||||
|
||||
/// Get a value if it is present in the `Batch`.
|
||||
/// `Some(None)` means it's present as a deletion.
|
||||
pub fn get<K: AsRef<[u8]>>(&self, k: K) -> Option<Option<&IVec>> {
|
||||
let inner = self.writes.get(k.as_ref())?;
|
||||
Some(inner.as_ref())
|
||||
}
|
||||
}
|
||||
|
||||
@@ -76,10 +76,8 @@ impl ContractSection {
|
||||
pub struct Env {
|
||||
/// Blockchain overlay access
|
||||
pub blockchain: BlockchainOverlayPtr,
|
||||
/// sled tree handles used with `db_*`
|
||||
/// Overlay tree handles used with `db_*`
|
||||
pub db_handles: RefCell<Vec<DbHandle>>,
|
||||
/// sled tree batches, indexed the same as `db_handles`.
|
||||
pub db_batches: RefCell<Vec<import::util::Batch>>,
|
||||
/// The contract ID being executed
|
||||
pub contract_id: ContractId,
|
||||
/// The compiled wasm bincode being executed,
|
||||
@@ -157,7 +155,6 @@ impl Runtime {
|
||||
|
||||
// Initialize data
|
||||
let db_handles = RefCell::new(vec![]);
|
||||
let db_batches = RefCell::new(vec![]);
|
||||
let logs = RefCell::new(vec![]);
|
||||
|
||||
debug!(target: "runtime::vm_runtime", "Importing functions");
|
||||
@@ -167,7 +164,6 @@ impl Runtime {
|
||||
Env {
|
||||
blockchain,
|
||||
db_handles,
|
||||
db_batches,
|
||||
contract_id,
|
||||
contract_bincode: wasm_bytes.to_vec(),
|
||||
contract_section: ContractSection::Null,
|
||||
@@ -336,10 +332,10 @@ impl Runtime {
|
||||
/// The runtime will look for an `INITIALIZE` symbol in the wasm code, and execute
|
||||
/// it if found. Optionally, it is possible to pass in a payload for any kind of special
|
||||
/// instructions the developer wants to manage in the initialize function.
|
||||
/// This process is supposed to set up the sled db trees for storing the smart contract
|
||||
/// This process is supposed to set up the overlay trees for storing the smart contract
|
||||
/// state, and it can create, delete, modify, read, and write to databases it's allowed to.
|
||||
/// The permissions for this are handled by the `ContractId` in the sled db API so we
|
||||
/// assume that the contract is only able to do write operations on its own sled trees.
|
||||
/// The permissions for this are handled by the `ContractId` in the overlay db API so we
|
||||
/// assume that the contract is only able to do write operations on its own overlay trees.
|
||||
pub fn deploy(&mut self, payload: &[u8]) -> Result<()> {
|
||||
info!(target: "runtime::vm_runtime", "[wasm-runtime] Running deploy");
|
||||
|
||||
@@ -364,17 +360,12 @@ impl Runtime {
|
||||
};
|
||||
|
||||
let mut db_handles = env_mut.db_handles.borrow_mut();
|
||||
let mut db_batches = env_mut.db_batches.borrow_mut();
|
||||
db_handles.push(DbHandle::new(env_mut.contract_id, zkas_tree_handle));
|
||||
db_batches.push(import::util::Batch::default());
|
||||
}
|
||||
|
||||
debug!(target: "runtime::vm_runtime", "[wasm-runtime] payload: {:?}", payload);
|
||||
let _ = self.call(ContractSection::Deploy, payload)?;
|
||||
|
||||
// If the above didn't fail, we write the batches.
|
||||
self.write_batches()?;
|
||||
|
||||
// Update the wasm bincode in the WasmStore
|
||||
let env_mut = self.ctx.as_mut(&mut self.store);
|
||||
env_mut
|
||||
@@ -387,25 +378,6 @@ impl Runtime {
|
||||
Ok(())
|
||||
}
|
||||
|
||||
/// Apply all batches to the overlay
|
||||
fn write_batches(&mut self) -> Result<()> {
|
||||
let env_mut = self.ctx.as_mut(&mut self.store);
|
||||
let batches = env_mut.db_batches.borrow();
|
||||
let blockchain = env_mut.blockchain.lock().unwrap();
|
||||
let mut overlay = blockchain.overlay.lock().unwrap();
|
||||
for (idx, db) in env_mut.db_handles.get_mut().iter().enumerate() {
|
||||
let tree_handle = &db.tree;
|
||||
for (k, v) in &batches[idx].writes {
|
||||
match v {
|
||||
Some(u) => overlay.insert(tree_handle, &k, &u)?,
|
||||
None => overlay.remove(tree_handle, &k)?,
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
/// This funcion runs when someone wants to execute a smart contract.
|
||||
/// The runtime will look for an `ENTRYPOINT` symbol in the wasm code, and
|
||||
/// execute it if found. A payload is also passed as an instruction that can
|
||||
@@ -416,7 +388,7 @@ impl Runtime {
|
||||
}
|
||||
|
||||
/// This function runs after successful execution of `exec` and tries to
|
||||
/// apply the state change to the sled databases.
|
||||
/// apply the state change to the overlay databases.
|
||||
/// The runtime will lok for an `UPDATE` symbol in the wasm code, and execute
|
||||
/// it if found. The function does not take an arbitrary payload, but just takes
|
||||
/// a state update from `env` and passes it into the wasm runtime.
|
||||
@@ -424,9 +396,6 @@ impl Runtime {
|
||||
debug!(target: "runtime::vm_runtime", "apply: {:?}", update);
|
||||
let _ = self.call(ContractSection::Update, update)?;
|
||||
|
||||
// If the above didn't fail, we write the batches.
|
||||
self.write_batches()?;
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user