Skip to content

Commit

Permalink
Merge #4900
Browse files Browse the repository at this point in the history
4900: Add block info support to EE and Casper VM (#4853) r=EdHastingsCasperAssociation a=EdHastingsCasperAssociation

This PR adds block info support to the ExecutionEngine and Casper VM. Wasm based logic can request the following fields via a new ffi method directly:

    /// This function gets the requested field at `field_idx`. It is up to
    /// the caller to ensure that the correct number of bytes for the field data
    /// are allocated at `dest_ptr`, otherwise data corruption in the wasm memory may occur.
    ///
    /// # Arguments
    ///
    /// * `field_idx` - what info field is requested?
    ///     0 => block time (functionally equivalent to earlier get_blocktime ffi)
    ///     1 => block height
    ///     2 => parent block hash
    ///     3 => state hash
    /// * `dest_ptr` => pointer in wasm memory where to write the result
    pub fn casper_get_block_info(field_idx: u8, dest_ptr: *const u8);

Alternately, the following convenience methods in the contract api offer easy access to each of the four fields, handling the ffi interactions for the user:
* get_blocktime() -> BlockTime (pre-existing)
* get_block_height() -> u64
* get_parent_block_hash() -> Digest
* get_state_hash() -> Digest

This new mechanism is extensible, and we may add more fields in future releases.

Co-authored-by: Ed Hastings <[email protected]>
  • Loading branch information
2 parents 515aac5 + 073b149 commit b25664a
Show file tree
Hide file tree
Showing 25 changed files with 583 additions and 118 deletions.
8 changes: 8 additions & 0 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

8 changes: 4 additions & 4 deletions execution_engine/src/engine_state/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,7 @@ pub use engine_config::{
};
pub use error::Error;
use execution_kind::ExecutionKind;
pub use wasm_v1::{ExecutableItem, InvalidRequest, WasmV1Request, WasmV1Result};
pub use wasm_v1::{BlockInfo, ExecutableItem, InvalidRequest, WasmV1Request, WasmV1Result};

/// The maximum amount of motes that payment code execution can cost.
pub const MAX_PAYMENT_AMOUNT: u64 = 2_500_000_000;
Expand Down Expand Up @@ -60,8 +60,7 @@ impl ExecutionEngineV1 {
&self,
state_provider: &impl StateProvider,
WasmV1Request {
state_hash,
block_time,
block_info,
transaction_hash,
gas_limit,
initiator_addr,
Expand All @@ -80,6 +79,7 @@ impl ExecutionEngineV1 {

let account_hash = initiator_addr.account_hash();
let protocol_version = self.config.protocol_version();
let state_hash = block_info.state_hash;
let tc = match state_provider.tracking_copy(state_hash) {
Ok(Some(tracking_copy)) => Rc::new(RefCell::new(tracking_copy)),
Ok(None) => return WasmV1Result::root_not_found(gas_limit, state_hash),
Expand Down Expand Up @@ -133,7 +133,7 @@ impl ExecutionEngineV1 {
access_rights,
authorization_keys,
account_hash,
block_time,
block_info,
transaction_hash,
gas_limit,
protocol_version,
Expand Down
111 changes: 77 additions & 34 deletions execution_engine/src/engine_state/wasm_v1.rs
Original file line number Diff line number Diff line change
Expand Up @@ -9,9 +9,9 @@ use thiserror::Error;
use casper_storage::data_access_layer::TransferResult;
use casper_types::{
account::AccountHash, bytesrepr::Bytes, contract_messages::Messages, execution::Effects,
BlockTime, DeployHash, Digest, ExecutableDeployItem, Gas, InitiatorAddr, Phase, PricingMode,
RuntimeArgs, Transaction, TransactionCategory, TransactionEntryPoint, TransactionHash,
TransactionInvocationTarget, TransactionTarget, TransactionV1, Transfer,
BlockHash, BlockTime, DeployHash, Digest, ExecutableDeployItem, Gas, InitiatorAddr, Phase,
PricingMode, RuntimeArgs, Transaction, TransactionCategory, TransactionEntryPoint,
TransactionHash, TransactionInvocationTarget, TransactionTarget, TransactionV1, Transfer,
};

use crate::engine_state::{DeployItem, Error as EngineError};
Expand Down Expand Up @@ -65,13 +65,66 @@ pub enum ExecutableItem {
Invocation(TransactionInvocationTarget),
}

/// A request to execute the given Wasm on the V1 runtime.
#[derive(Debug)]
pub struct WasmV1Request {
/// Block info.
#[derive(Copy, Clone, Debug)]
pub struct BlockInfo {
/// State root hash of the global state in which the transaction will be executed.
pub state_hash: Digest,
/// Block time represented as a unix timestamp.
pub block_time: BlockTime,
/// Parent block hash
pub parent_block_hash: BlockHash,
/// Block height
pub block_height: u64,
}

impl BlockInfo {
/// A new instance of `[BlockInfo]`.
pub fn new(
state_hash: Digest,
block_time: BlockTime,
parent_block_hash: BlockHash,
block_height: u64,
) -> Self {
BlockInfo {
state_hash,
block_time,
parent_block_hash,
block_height,
}
}

/// Apply different state hash.
pub fn with_state_hash(&mut self, state_hash: Digest) {
self.state_hash = state_hash;
}

/// State hash.
pub fn state_hash(&self) -> Digest {
self.state_hash
}

/// Block time.
pub fn block_time(&self) -> BlockTime {
self.block_time
}

/// Parent block hash.
pub fn parent_block_hash(&self) -> BlockHash {
self.parent_block_hash
}

/// Block height.
pub fn block_height(&self) -> u64 {
self.block_height
}
}

/// A request to execute the given Wasm on the V1 runtime.
#[derive(Debug)]
pub struct WasmV1Request {
/// Block info.
pub block_info: BlockInfo,
/// The hash identifying the transaction.
pub transaction_hash: TransactionHash,
/// The number of Motes per unit of Gas to be paid for execution.
Expand All @@ -92,8 +145,7 @@ pub struct WasmV1Request {

impl WasmV1Request {
pub(crate) fn new_from_executable_info(
state_hash: Digest,
block_time: BlockTime,
block_info: BlockInfo,
gas_limit: Gas,
transaction_hash: TransactionHash,
initiator_addr: InitiatorAddr,
Expand All @@ -102,8 +154,7 @@ impl WasmV1Request {
) -> Self {
let executable_item = executable_info.item();
Self {
state_hash,
block_time,
block_info,
transaction_hash,
gas_limit,
initiator_addr,
Expand All @@ -117,12 +168,11 @@ impl WasmV1Request {

/// Creates a new request from a transaction for use as the session code.
pub fn new_session(
state_hash: Digest,
block_time: BlockTime,
block_info: BlockInfo,
gas_limit: Gas,
transaction: &Transaction,
) -> Result<Self, InvalidRequest> {
let info = match transaction {
let session_info = match transaction {
Transaction::Deploy(deploy) => {
SessionInfo::try_from((deploy.session(), deploy.hash()))?
}
Expand All @@ -133,24 +183,22 @@ impl WasmV1Request {
let initiator_addr = transaction.initiator_addr();
let authorization_keys = transaction.signers();
Ok(WasmV1Request::new_from_executable_info(
state_hash,
block_time,
block_info,
gas_limit,
transaction_hash,
initiator_addr,
authorization_keys,
info,
session_info,
))
}

/// Creates a new request from a transaction for use as custom payment.
pub fn new_custom_payment(
state_hash: Digest,
block_time: BlockTime,
block_info: BlockInfo,
gas_limit: Gas,
transaction: &Transaction,
) -> Result<Self, InvalidRequest> {
let info = match transaction {
let payment_info = match transaction {
Transaction::Deploy(deploy) => {
PaymentInfo::try_from((deploy.payment(), deploy.hash()))?
}
Expand All @@ -161,20 +209,18 @@ impl WasmV1Request {
let initiator_addr = transaction.initiator_addr();
let authorization_keys = transaction.signers();
Ok(WasmV1Request::new_from_executable_info(
state_hash,
block_time,
block_info,
gas_limit,
transaction_hash,
initiator_addr,
authorization_keys,
info,
payment_info,
))
}

/// Creates a new request from a deploy item for use as the session code.
pub fn new_session_from_deploy_item(
state_hash: Digest,
block_time: BlockTime,
block_info: BlockInfo,
gas_limit: Gas,
DeployItem {
ref address,
Expand All @@ -184,25 +230,23 @@ impl WasmV1Request {
..
}: &DeployItem,
) -> Result<Self, InvalidRequest> {
let info = SessionInfo::try_from((session, deploy_hash))?;
let session_info = SessionInfo::try_from((session, deploy_hash))?;
let transaction_hash = TransactionHash::Deploy(*deploy_hash);
let initiator_addr = InitiatorAddr::AccountHash(*address);
let authorization_keys = authorization_keys.clone();
Ok(WasmV1Request::new_from_executable_info(
state_hash,
block_time,
block_info,
gas_limit,
transaction_hash,
initiator_addr,
authorization_keys,
info,
session_info,
))
}

/// Creates a new request from a deploy item for use as custom payment.
pub fn new_custom_payment_from_deploy_item(
state_hash: Digest,
block_time: BlockTime,
block_info: BlockInfo,
gas_limit: Gas,
DeployItem {
ref address,
Expand All @@ -212,18 +256,17 @@ impl WasmV1Request {
..
}: &DeployItem,
) -> Result<Self, InvalidRequest> {
let info = PaymentInfo::try_from((payment, deploy_hash))?;
let payment_info = PaymentInfo::try_from((payment, deploy_hash))?;
let transaction_hash = TransactionHash::Deploy(*deploy_hash);
let initiator_addr = InitiatorAddr::AccountHash(*address);
let authorization_keys = authorization_keys.clone();
Ok(WasmV1Request::new_from_executable_info(
state_hash,
block_time,
block_info,
gas_limit,
transaction_hash,
initiator_addr,
authorization_keys,
info,
payment_info,
))
}
}
Expand Down
6 changes: 3 additions & 3 deletions execution_engine/src/execution/error.rs
Original file line number Diff line number Diff line change
Expand Up @@ -183,9 +183,9 @@ pub enum Error {
/// The EntryPoints contains an invalid entry.
#[error("The EntryPoints contains an invalid entry")]
InvalidEntryPointType,
/// Invalid message topic operation.
#[error("The requested operation is invalid for a message topic")]
InvalidMessageTopicOperation,
/// Invalid operation.
#[error("The imputed operation is invalid")]
InvalidImputedOperation,
/// Invalid string encoding.
#[error("Invalid UTF-8 string encoding: {0}")]
InvalidUtf8Encoding(Utf8Error),
Expand Down
12 changes: 6 additions & 6 deletions execution_engine/src/execution/executor.rs
Original file line number Diff line number Diff line change
Expand Up @@ -7,13 +7,13 @@ use casper_storage::{
};
use casper_types::{
account::AccountHash, addressable_entity::NamedKeys, contract_messages::Messages,
execution::Effects, AddressableEntity, AddressableEntityHash, BlockTime, ContextAccessRights,
execution::Effects, AddressableEntity, AddressableEntityHash, ContextAccessRights,
EntryPointType, Gas, Key, Phase, ProtocolVersion, RuntimeArgs, StoredValue, Tagged,
TransactionHash, U512,
};

use crate::{
engine_state::{execution_kind::ExecutionKind, EngineConfig, WasmV1Result},
engine_state::{execution_kind::ExecutionKind, BlockInfo, EngineConfig, WasmV1Result},
execution::ExecError,
runtime::{Runtime, RuntimeStack},
runtime_context::{CallingAddContractVersion, RuntimeContext},
Expand Down Expand Up @@ -53,7 +53,7 @@ impl Executor {
access_rights: ContextAccessRights,
authorization_keys: BTreeSet<AccountHash>,
account_hash: AccountHash,
blocktime: BlockTime,
block_info: BlockInfo,
txn_hash: TransactionHash,
gas_limit: Gas,
protocol_version: ProtocolVersion,
Expand Down Expand Up @@ -101,7 +101,7 @@ impl Executor {
account_hash,
address_generator,
tracking_copy,
blocktime,
block_info,
protocol_version,
txn_hash,
phase,
Expand Down Expand Up @@ -163,7 +163,7 @@ impl Executor {
account_hash: AccountHash,
address_generator: Rc<RefCell<AddressGenerator>>,
tracking_copy: Rc<RefCell<TrackingCopy<R>>>,
blocktime: BlockTime,
block_info: BlockInfo,
protocol_version: ProtocolVersion,
txn_hash: TransactionHash,
phase: Phase,
Expand All @@ -189,7 +189,7 @@ impl Executor {
address_generator,
tracking_copy,
self.config.clone(),
blocktime,
block_info,
protocol_version,
txn_hash,
phase,
Expand Down
1 change: 1 addition & 0 deletions execution_engine/src/resolvers/v1_function_index.rs
Original file line number Diff line number Diff line change
Expand Up @@ -60,6 +60,7 @@ pub(crate) enum FunctionIndex {
ManageMessageTopic,
EmitMessage,
LoadCallerInformation,
GetBlockInfoIndex,
}

impl From<FunctionIndex> for usize {
Expand Down
4 changes: 4 additions & 0 deletions execution_engine/src/resolvers/v1_resolver.rs
Original file line number Diff line number Diff line change
Expand Up @@ -253,6 +253,10 @@ impl ModuleImportResolver for RuntimeModuleImportResolver {
Signature::new(&[ValueType::I32; 4][..], Some(ValueType::I32)),
FunctionIndex::EmitMessage.into(),
),
"casper_get_block_info" => FuncInstance::alloc_host(
Signature::new(&[ValueType::I32; 2][..], None),
FunctionIndex::GetBlockInfoIndex.into(),
),
_ => {
return Err(InterpreterError::Function(format!(
"host module doesn't export function with name {}",
Expand Down
Loading

0 comments on commit b25664a

Please sign in to comment.