casperlabs-engine-test-support 0.8.1

Library to support testing of Wasm smart contracts for use on the CasperLabs network.
Documentation
use std::{collections::BTreeSet, path::Path};

use engine_core::{
    engine_state::{deploy_item::DeployItem, executable_deploy_item::ExecutableDeployItem},
    DeployHash,
};
use types::{
    account::AccountHash, bytesrepr::ToBytes, contracts::ContractVersion, ContractHash, HashAddr,
    RuntimeArgs,
};

use crate::internal::utils;

#[derive(Default)]
struct DeployItemData {
    pub address: Option<AccountHash>,
    pub payment_code: Option<ExecutableDeployItem>,
    pub session_code: Option<ExecutableDeployItem>,
    pub gas_price: u64,
    pub authorization_keys: BTreeSet<AccountHash>,
    pub deploy_hash: DeployHash,
}

pub struct DeployItemBuilder {
    deploy_item: DeployItemData,
}

impl DeployItemBuilder {
    pub fn new() -> Self {
        Default::default()
    }

    pub fn with_address(mut self, address: AccountHash) -> Self {
        self.deploy_item.address = Some(address);
        self
    }

    pub fn with_payment_bytes(mut self, module_bytes: Vec<u8>, args: RuntimeArgs) -> Self {
        let args = Self::serialize_args(args);
        self.deploy_item.payment_code =
            Some(ExecutableDeployItem::ModuleBytes { module_bytes, args });
        self
    }

    pub fn with_empty_payment_bytes(self, args: RuntimeArgs) -> Self {
        self.with_payment_bytes(vec![], args)
    }

    pub fn with_payment_code<T: AsRef<Path>>(self, file_name: T, args: RuntimeArgs) -> Self {
        let module_bytes = utils::read_wasm_file_bytes(file_name);
        self.with_payment_bytes(module_bytes, args)
    }

    pub fn with_stored_payment_hash(
        mut self,
        hash: ContractHash,
        entry_point: &str,
        args: RuntimeArgs,
    ) -> Self {
        let args = Self::serialize_args(args);
        self.deploy_item.payment_code = Some(ExecutableDeployItem::StoredContractByHash {
            hash,
            entry_point: entry_point.into(),
            args,
        });
        self
    }

    pub fn with_stored_payment_named_key(
        mut self,
        uref_name: &str,
        entry_point_name: &str,
        args: RuntimeArgs,
    ) -> Self {
        let args = Self::serialize_args(args);
        self.deploy_item.payment_code = Some(ExecutableDeployItem::StoredContractByName {
            name: uref_name.to_owned(),
            entry_point: entry_point_name.into(),
            args,
        });
        self
    }

    pub fn with_session_bytes(mut self, module_bytes: Vec<u8>, args: RuntimeArgs) -> Self {
        let args = Self::serialize_args(args);
        self.deploy_item.session_code =
            Some(ExecutableDeployItem::ModuleBytes { module_bytes, args });
        self
    }

    pub fn with_session_code<T: AsRef<Path>>(self, file_name: T, args: RuntimeArgs) -> Self {
        let module_bytes = utils::read_wasm_file_bytes(file_name);
        self.with_session_bytes(module_bytes, args)
    }

    pub fn with_transfer_args(mut self, args: RuntimeArgs) -> Self {
        let args = Self::serialize_args(args);
        self.deploy_item.session_code = Some(ExecutableDeployItem::Transfer { args });
        self
    }

    pub fn with_stored_session_hash(
        mut self,
        hash: ContractHash,
        entry_point: &str,
        args: RuntimeArgs,
    ) -> Self {
        let args = Self::serialize_args(args);
        self.deploy_item.session_code = Some(ExecutableDeployItem::StoredContractByHash {
            hash,
            entry_point: entry_point.into(),
            args,
        });
        self
    }

    pub fn with_stored_session_named_key(
        mut self,
        name: &str,
        entry_point: &str,
        args: RuntimeArgs,
    ) -> Self {
        let args = Self::serialize_args(args);
        self.deploy_item.session_code = Some(ExecutableDeployItem::StoredContractByName {
            name: name.to_owned(),
            entry_point: entry_point.into(),
            args,
        });
        self
    }

    pub fn with_stored_versioned_contract_by_name(
        mut self,
        name: &str,
        version: Option<ContractVersion>,
        entry_point: &str,
        args: RuntimeArgs,
    ) -> Self {
        self.deploy_item.session_code = Some(ExecutableDeployItem::StoredVersionedContractByName {
            name: name.to_owned(),
            version,
            entry_point: entry_point.to_owned(),
            args: args.to_bytes().expect("should serialize runtime args"),
        });
        self
    }

    pub fn with_stored_versioned_contract_by_hash(
        mut self,
        hash: HashAddr,
        version: Option<ContractVersion>,
        entry_point: &str,
        args: RuntimeArgs,
    ) -> Self {
        self.deploy_item.session_code = Some(ExecutableDeployItem::StoredVersionedContractByHash {
            hash,
            version,
            entry_point: entry_point.to_owned(),
            args: args.to_bytes().expect("should serialize runtime args"),
        });
        self
    }

    pub fn with_stored_versioned_payment_contract_by_name(
        mut self,
        key_name: &str,
        version: Option<ContractVersion>,
        entry_point: &str,
        args: RuntimeArgs,
    ) -> Self {
        self.deploy_item.payment_code = Some(ExecutableDeployItem::StoredVersionedContractByName {
            name: key_name.to_owned(),
            version,
            entry_point: entry_point.to_owned(),
            args: args.to_bytes().expect("should serialize runtime args"),
        });
        self
    }

    pub fn with_stored_versioned_payment_contract_by_hash(
        mut self,
        hash: HashAddr,
        version: Option<ContractVersion>,
        entry_point: &str,
        args: RuntimeArgs,
    ) -> Self {
        self.deploy_item.payment_code = Some(ExecutableDeployItem::StoredVersionedContractByHash {
            hash,
            version,
            entry_point: entry_point.to_owned(),
            args: args.to_bytes().expect("should serialize runtime args"),
        });
        self
    }

    pub fn with_authorization_keys<T: Clone + Into<AccountHash>>(
        mut self,
        authorization_keys: &[T],
    ) -> Self {
        self.deploy_item.authorization_keys = authorization_keys
            .iter()
            .cloned()
            .map(|v| v.into())
            .collect();
        self
    }

    pub fn with_gas_price(mut self, gas_price: u64) -> Self {
        self.deploy_item.gas_price = gas_price;
        self
    }

    pub fn with_deploy_hash(mut self, hash: [u8; 32]) -> Self {
        self.deploy_item.deploy_hash = hash;
        self
    }

    pub fn build(self) -> DeployItem {
        DeployItem {
            address: self
                .deploy_item
                .address
                .unwrap_or_else(|| AccountHash::new([0u8; 32])),
            session: self
                .deploy_item
                .session_code
                .expect("should have session code"),
            payment: self
                .deploy_item
                .payment_code
                .expect("should have payment code"),
            gas_price: self.deploy_item.gas_price,
            authorization_keys: self.deploy_item.authorization_keys,
            deploy_hash: self.deploy_item.deploy_hash,
        }
    }

    fn serialize_args(args: RuntimeArgs) -> Vec<u8> {
        args.into_bytes().expect("should serialize args")
    }
}

impl Default for DeployItemBuilder {
    fn default() -> Self {
        let mut deploy_item: DeployItemData = Default::default();
        deploy_item.gas_price = 1;
        DeployItemBuilder { deploy_item }
    }
}