#![deny(missing_docs)]
#![deny(clippy::all)]
#![deny(unused_crate_dependencies)]
#![deny(unused_extern_crates)]
extern crate alloc;
pub use self::execute::feature::Activation as FeatureActivation;
pub use self::execute::{Config as ExecutionConfig, execute, gen_contract_id};
pub use piecrust::{
CallReceipt, CallTree, CallTreeElem, ContractData, Error, PageOpening,
Session,
};
pub struct ContractMetadata {
pub contract_id: ContractId,
pub owner: Vec<u8>,
}
unsafe impl Send for ContractMetadata {}
unsafe impl Sync for ContractMetadata {}
use alloc::vec::Vec;
use std::collections::HashMap;
use std::fmt::{self, Debug, Formatter};
use std::path::{Path, PathBuf};
use std::thread;
use dusk_core::abi::{ContractId, Metadata, Query};
use piecrust::{SessionData, VM as PiecrustVM};
use self::host_queries::{
host_hash, host_keccak256, host_poseidon_hash, host_secp256k1_recover,
host_sha256, host_verify_bls, host_verify_bls_multisig,
host_verify_groth16_bn254, host_verify_kzg_proof, host_verify_plonk,
host_verify_schnorr,
};
pub(crate) mod cache;
mod execute;
pub mod host_queries;
pub struct VM {
inner: PiecrustVM,
hq_activation: HashMap<String, FeatureActivation>,
}
impl From<PiecrustVM> for VM {
fn from(piecrust_vm: PiecrustVM) -> Self {
VM {
inner: piecrust_vm,
hq_activation: HashMap::new(),
}
}
}
impl Debug for VM {
fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
self.inner.fmt(f)
}
}
impl VM {
pub fn new(
root_dir: impl AsRef<Path> + Into<PathBuf>,
) -> Result<Self, Error> {
let mut vm: Self = PiecrustVM::new(root_dir)?.into();
vm.register_host_queries();
Ok(vm)
}
pub fn ephemeral() -> Result<VM, Error> {
let mut vm: Self = PiecrustVM::ephemeral()?.into();
vm.register_host_queries();
Ok(vm)
}
pub fn with_hq_activation<S: Into<String>>(
&mut self,
host_query: S,
activation: FeatureActivation,
) {
let host_query = host_query.into();
if self.inner.host_queries().get(&host_query).is_none() {
panic!(
"Host query '{host_query}' must be registered before setting activation"
);
}
self.hq_activation.insert(host_query, activation);
}
pub fn session(
&self,
base: [u8; 32],
chain_id: u8,
block_height: u64,
) -> Result<Session, Error> {
let mut builder = SessionData::builder()
.base(base)
.insert(Metadata::CHAIN_ID, chain_id)?
.insert(Metadata::BLOCK_HEIGHT, block_height)?;
if block_height > 0 {
for (host_query, activation) in &self.hq_activation {
if !activation.is_active_at(block_height) {
builder = builder.exclude_hq(host_query.clone());
}
}
}
self.inner.session(builder)
}
pub fn genesis_session(&self, chain_id: u8) -> Session {
self.inner
.session(
SessionData::builder()
.insert(Metadata::CHAIN_ID, chain_id)
.expect("Inserting chain ID in metadata should succeed")
.insert(Metadata::BLOCK_HEIGHT, 0)
.expect(
"Inserting block height in metadata should succeed",
),
)
.expect("Creating a genesis session should always succeed")
}
pub fn commits(&self) -> Vec<[u8; 32]> {
self.inner.commits()
}
pub fn delete_commit(&self, root: [u8; 32]) -> Result<(), Error> {
self.inner.delete_commit(root)
}
pub fn finalize_commit(&self, root: [u8; 32]) -> Result<(), Error> {
self.inner.finalize_commit(root)
}
pub fn root_dir(&self) -> &Path {
self.inner.root_dir()
}
pub fn sync_thread(&self) -> &thread::Thread {
self.inner.sync_thread()
}
fn register_host_queries(&mut self) {
self.inner.register_host_query(Query::HASH, host_hash);
self.inner
.register_host_query(Query::POSEIDON_HASH, host_poseidon_hash);
self.inner
.register_host_query(Query::VERIFY_PLONK, host_verify_plonk);
self.inner.register_host_query(
Query::VERIFY_GROTH16_BN254,
host_verify_groth16_bn254,
);
self.inner
.register_host_query(Query::VERIFY_SCHNORR, host_verify_schnorr);
self.inner
.register_host_query(Query::VERIFY_BLS, host_verify_bls);
self.inner.register_host_query(
Query::VERIFY_BLS_MULTISIG,
host_verify_bls_multisig,
);
self.inner
.register_host_query(Query::KECCAK256, host_keccak256);
self.inner.register_host_query(Query::SHA256, host_sha256);
self.inner.register_host_query(
Query::VERIFY_KZG_PROOF,
host_verify_kzg_proof,
);
self.inner.register_host_query(
Query::SECP256K1_RECOVER,
host_secp256k1_recover,
);
}
pub fn remove_3rd_party(
&self,
contract_id: ContractId,
) -> Result<(), Error> {
self.inner.remove_module(contract_id)
}
pub fn recompile_3rd_party(
&self,
contract_id: ContractId,
) -> Result<(), Error> {
self.inner.recompile_module(contract_id)
}
}