mirror of
https://github.com/darkrenaissance/darkfi.git
synced 2026-01-09 14:48:08 -05:00
runtime: sled blockchain access
This commit is contained in:
1
example/smart-contract/Cargo.lock
generated
1
example/smart-contract/Cargo.lock
generated
@@ -2601,6 +2601,7 @@ dependencies = [
|
||||
"darkfi-serial",
|
||||
"getrandom",
|
||||
"simplelog",
|
||||
"sled",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
|
||||
@@ -27,4 +27,4 @@ getrandom = { version = "0.2", features = ["custom"] }
|
||||
[dev-dependencies]
|
||||
darkfi = { path = "../../", features = ["wasm-runtime"] }
|
||||
simplelog = "0.12.0"
|
||||
|
||||
sled = "0.34.7"
|
||||
|
||||
@@ -16,11 +16,14 @@
|
||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
use darkfi::{crypto::contract_id::ContractId, runtime::vm_runtime::Runtime, Result};
|
||||
use darkfi_sdk::{
|
||||
pasta::pallas,
|
||||
tx::FuncCall
|
||||
use darkfi::{
|
||||
blockchain::Blockchain,
|
||||
consensus::{TESTNET_GENESIS_HASH_BYTES, TESTNET_GENESIS_TIMESTAMP},
|
||||
crypto::contract_id::ContractId,
|
||||
runtime::vm_runtime::Runtime,
|
||||
Result,
|
||||
};
|
||||
use darkfi_sdk::{pasta::pallas, tx::FuncCall};
|
||||
use darkfi_serial::{serialize, Encodable, WriteExt};
|
||||
|
||||
use smart_contract::{FooCallData, Function};
|
||||
@@ -36,20 +39,20 @@ fn run_contract() -> Result<()> {
|
||||
simplelog::TerminalMode::Mixed,
|
||||
simplelog::ColorChoice::Auto,
|
||||
)?;
|
||||
// =============================================================
|
||||
// Build a ledger state so the runtime has something to work on
|
||||
// =============================================================
|
||||
//let state_machine = State::dummy()?;
|
||||
|
||||
// Add a nullifier to the nullifier set. (This is checked by the contract)
|
||||
//state_machine.nullifiers.insert(&[Nullifier::from(pallas::Base::from(0x10))])?;
|
||||
// =============================
|
||||
// Initialize a dummy blockchain
|
||||
// =============================
|
||||
// TODO: This blockchain interface should perhaps be ValidatorState and Mutex/RwLock.
|
||||
let db = sled::Config::new().temporary(true).open()?;
|
||||
let blockchain = Blockchain::new(&db, *TESTNET_GENESIS_TIMESTAMP, *TESTNET_GENESIS_HASH_BYTES)?;
|
||||
|
||||
// ================================================================
|
||||
// Load the wasm binary into memory and create an execution runtime
|
||||
// ================================================================
|
||||
let wasm_bytes = std::fs::read("contract.wasm")?;
|
||||
let contract_id = ContractId::new(pallas::Base::from(1));
|
||||
let mut runtime = Runtime::new(&wasm_bytes, contract_id)?;
|
||||
let mut runtime = Runtime::new(&wasm_bytes, blockchain, contract_id)?;
|
||||
|
||||
// Deploy function to initialize the smart contract state.
|
||||
// Here we pass an empty payload, but it's possible to feed in arbitrary data.
|
||||
@@ -59,9 +62,9 @@ fn run_contract() -> Result<()> {
|
||||
// Build some kind of payload to show an example
|
||||
// =============================================
|
||||
let func_calls = vec![FuncCall {
|
||||
contract_id: pallas::Base::from(110),
|
||||
func_id: pallas::Base::from(4),
|
||||
call_data: serialize(&FooCallData { a: 777, b: 666 }),
|
||||
contract_id: pallas::Base::from(110),
|
||||
func_id: pallas::Base::from(4),
|
||||
call_data: serialize(&FooCallData { a: 777, b: 666 }),
|
||||
}];
|
||||
let func_call_index: u32 = 0;
|
||||
|
||||
|
||||
@@ -19,7 +19,22 @@
|
||||
use log::error;
|
||||
use wasmer::{FunctionEnvMut, WasmPtr};
|
||||
|
||||
use crate::runtime::vm_runtime::{ContractSection, Env};
|
||||
use crate::{
|
||||
crypto::contract_id::ContractId,
|
||||
runtime::vm_runtime::{ContractSection, Env},
|
||||
};
|
||||
|
||||
/// Internal wasm runtime API for sled trees
|
||||
pub struct DbHandle {
|
||||
contract_id: ContractId,
|
||||
tree: sled::Tree,
|
||||
}
|
||||
|
||||
impl DbHandle {
|
||||
pub fn new(contract_id: ContractId, tree: sled::Tree) -> Self {
|
||||
Self { contract_id, tree }
|
||||
}
|
||||
}
|
||||
|
||||
/// Only deploy() can call this. Creates a new database instance for this contract.
|
||||
///
|
||||
@@ -31,23 +46,32 @@ pub(crate) fn db_init(mut ctx: FunctionEnvMut<Env>, ptr: WasmPtr<u8>, len: u32)
|
||||
let env = ctx.data();
|
||||
match env.contract_section {
|
||||
ContractSection::Deploy => {
|
||||
let env = ctx.data();
|
||||
let memory_view = env.memory_view(&ctx);
|
||||
let db = &env.blockchain.sled_db;
|
||||
let contracts = &env.blockchain.contracts;
|
||||
let contract_id = &env.contract_id;
|
||||
|
||||
match ptr.read_utf8_string(&memory_view, len) {
|
||||
Ok(db_name) => {
|
||||
// TODO:
|
||||
// * db_name = blake3_hash(contract_id, db_name)
|
||||
// * create db_name sled database
|
||||
}
|
||||
Err(_) => {
|
||||
error!(target: "wasm_runtime::drk_log", "Failed to read UTF-8 string from VM memory");
|
||||
let Ok(db_name) = ptr.read_utf8_string(&memory_view, len) else {
|
||||
error!(target: "wasm_runtime::db_init", "Failed to read string from VM memory");
|
||||
return -2
|
||||
};
|
||||
|
||||
let tree_handle = match contracts.init(db, contract_id, &db_name) {
|
||||
Ok(v) => v,
|
||||
Err(e) => {
|
||||
error!(target: "wasm_runtime::db_init", "Failed to init db: {}", e);
|
||||
return -2
|
||||
}
|
||||
}
|
||||
0
|
||||
};
|
||||
|
||||
let mut db_handles = env.db_handles.borrow_mut();
|
||||
db_handles.push(DbHandle::new(*contract_id, tree_handle));
|
||||
return (db_handles.len() - 1) as i32
|
||||
}
|
||||
_ => {
|
||||
error!(target: "wasm_runtime::db_init", "db_init called in unauthorized section");
|
||||
return -1
|
||||
}
|
||||
_ => -1,
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -33,12 +33,8 @@ use wasmer_middlewares::{
|
||||
Metering,
|
||||
};
|
||||
|
||||
use super::{
|
||||
import,
|
||||
//chain_state::{is_valid_merkle, nullifier_exists, set_update},
|
||||
memory::MemoryManipulation,
|
||||
};
|
||||
use crate::{crypto::contract_id::ContractId, Error, Result};
|
||||
use super::{import, import::db::DbHandle, memory::MemoryManipulation};
|
||||
use crate::{blockchain::Blockchain, crypto::contract_id::ContractId, Error, Result};
|
||||
|
||||
/// Name of the wasm linear memory in our guest module
|
||||
const MEMORY: &str = "memory";
|
||||
@@ -60,10 +56,16 @@ pub enum ContractSection {
|
||||
|
||||
/// The wasm vm runtime instantiated for every smart contract that runs.
|
||||
pub struct Env {
|
||||
/// Blockchain access
|
||||
pub blockchain: Blockchain,
|
||||
/// sled tree handles used with `db_*`
|
||||
pub db_handles: RefCell<Vec<DbHandle>>,
|
||||
/// The contract ID being executed
|
||||
pub contract_id: ContractId,
|
||||
/// The contract section being executed
|
||||
pub contract_section: ContractSection,
|
||||
/// State update produced by a smart contract function call
|
||||
pub contract_update: Cell<Option<(u8, Vec<u8>)>>,
|
||||
//pub func_id:
|
||||
/// Logs produced by the contract
|
||||
pub logs: RefCell<Vec<String>>,
|
||||
/// Direct memory access to the VM
|
||||
@@ -96,7 +98,7 @@ pub struct Runtime {
|
||||
|
||||
impl Runtime {
|
||||
/// Create a new wasm runtime instance that contains the given wasm module.
|
||||
pub fn new(wasm_bytes: &[u8], contract_id: ContractId) -> Result<Self> {
|
||||
pub fn new(wasm_bytes: &[u8], blockchain: Blockchain, contract_id: ContractId) -> Result<Self> {
|
||||
info!(target: "warm_runtime::new", "Instantiating a new runtime");
|
||||
// This function will be called for each `Operator` encountered during
|
||||
// the wasm module execution. It should return the cost of the operator
|
||||
@@ -124,13 +126,17 @@ impl Runtime {
|
||||
debug!(target: "wasm_runtime::new", "Compiling module");
|
||||
let module = Module::new(&store, wasm_bytes)?;
|
||||
|
||||
// This section will need changing
|
||||
debug!(target: "wasm_runtime::new", "Importing functions");
|
||||
// Initialize data
|
||||
let db_handles = RefCell::new(vec![]);
|
||||
let logs = RefCell::new(vec![]);
|
||||
|
||||
debug!(target: "wasm_runtime::new", "Importing functions");
|
||||
|
||||
let ctx = FunctionEnv::new(
|
||||
&mut store,
|
||||
Env {
|
||||
blockchain,
|
||||
db_handles,
|
||||
contract_id,
|
||||
contract_section: ContractSection::Null,
|
||||
contract_update: Cell::new(None),
|
||||
|
||||
Reference in New Issue
Block a user