Skip to content

Commit

Permalink
feat: add balance trait for the substrate layer
Browse files Browse the repository at this point in the history
Balance trait can be used to inject external balance handler
inside the MoveVM.
  • Loading branch information
Rqnsom committed Jan 11, 2024
1 parent b633a25 commit 9ec76b5
Show file tree
Hide file tree
Showing 14 changed files with 221 additions and 156 deletions.
10 changes: 7 additions & 3 deletions language/move-core/types/src/resolver.rs
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@
use crate::{
account_address::AccountAddress,
language_storage::{ModuleId, StructTag},
vm_status::StatusCode,
};
use alloc::vec::Vec;
use core::fmt::Debug;
Expand Down Expand Up @@ -47,7 +48,7 @@ pub trait ResourceResolver {

/// A balance backend that can resolve balance handling.
pub trait BalanceResolver {
type Error: Debug;
type Error: Into<StatusCode>;

/// Resolver should update the inner state for the external balance handler.
///
Expand Down Expand Up @@ -80,20 +81,23 @@ pub trait BalanceResolver {
pub trait MoveResolver:
ModuleResolver<Error = Self::Err>
+ ResourceResolver<Error = Self::Err>
+ BalanceResolver<Error = Self::Err>
+ BalanceResolver<Error = Self::StatusCodeErr>
{
type Err: Debug;
type StatusCodeErr: Into<StatusCode>;
}

impl<
E: Debug,
S: Into<StatusCode>,
T: ModuleResolver<Error = E>
+ ResourceResolver<Error = E>
+ BalanceResolver<Error = E>
+ BalanceResolver<Error = S>
+ ?Sized,
> MoveResolver for T
{
type Err = E;
type StatusCodeErr = S;
}

impl<T: ResourceResolver + ?Sized> ResourceResolver for &T {
Expand Down
3 changes: 3 additions & 0 deletions language/move-core/types/src/vm_status.rs
Original file line number Diff line number Diff line change
Expand Up @@ -687,6 +687,9 @@ pub enum StatusCode {
RESERVED_RUNTIME_ERROR_4 = 4036,
RESERVED_RUNTIME_ERROR_5 = 4037,

// Substrate related codes: 9000-9999
INSUFFICIENT_BALANCE = 9000,

// A reserved status to represent an unknown vm status.
// this is core::u64::MAX, but we can't pattern match on that, so put the hardcoded value in
UNKNOWN_STATUS = 18446744073709551615,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -529,7 +529,7 @@ impl ResourceResolver for BogusStorage {
}

// This is not supposed to be used in these tests.
quick_balance_resolver_impl!(BogusStorage, VMError);
quick_balance_resolver_impl!(BogusStorage, StatusCode);

const LIST_OF_ERROR_CODES: &[StatusCode] = &[
StatusCode::UNKNOWN_VALIDATION_STATUS,
Expand Down
2 changes: 1 addition & 1 deletion language/move-vm/runtime/src/data_cache.rs
Original file line number Diff line number Diff line change
Expand Up @@ -312,7 +312,7 @@ impl<'r, 'l, S: MoveResolver> DataStore for TransactionDataCache<'r, 'l, S> {
) -> PartialVMResult<bool> {
self.remote
.transfer(src, dst, cheque_amount)
.map_err(|_| PartialVMError::new(StatusCode::INTERNAL_TYPE_ERROR))
.map_err(|e| PartialVMError::new(e.into()))
}

fn cheque_amount(&self, account: AccountAddress) -> PartialVMResult<u128> {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -269,7 +269,7 @@ impl ResourceResolver for RemoteStore {
}

// This is not supposed to be used in these tests.
quick_balance_resolver_impl!(RemoteStore, VMError);
quick_balance_resolver_impl!(RemoteStore, StatusCode);

fn combine_signers_and_args(
signers: Vec<AccountAddress>,
Expand Down
5 changes: 3 additions & 2 deletions language/move-vm/test-utils/src/storage.rs
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@ use move_core_types::{
language_storage::{ModuleId, StructTag},
quick_balance_resolver_impl,
resolver::{BalanceResolver, ModuleResolver, MoveResolver, ResourceResolver},
vm_status::StatusCode,
};

#[cfg(feature = "table-extension")]
Expand Down Expand Up @@ -55,7 +56,7 @@ impl ResourceResolver for BlankStorage {
}

// This is not supposed to be used in these tests.
quick_balance_resolver_impl!(BlankStorage, ());
quick_balance_resolver_impl!(BlankStorage, StatusCode);

#[cfg(feature = "table-extension")]
impl TableResolver for BlankStorage {
Expand Down Expand Up @@ -350,4 +351,4 @@ impl TableResolver for InMemoryStorage {
}

// This is not supposed to be used in these tests.
quick_balance_resolver_impl!(InMemoryStorage, ());
quick_balance_resolver_impl!(InMemoryStorage, StatusCode);
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@
// SPDX-License-Identifier: Apache-2.0

use crate::{BCS_EXTENSION, DEFAULT_BUILD_DIR, DEFAULT_STORAGE_DIR};
use anyhow::{anyhow, bail, Error as AnyhowError, Result};
use anyhow::{anyhow, bail, Result};
use move_binary_format::{
access::ModuleAccess,
binary_views::BinaryIndexedView,
Expand All @@ -17,6 +17,7 @@ use move_core_types::{
language_storage::{ModuleId, StructTag, TypeTag},
parser, quick_balance_resolver_impl,
resolver::{BalanceResolver, ModuleResolver, ResourceResolver},
vm_status::StatusCode,
};
use move_disassembler::disassembler::Disassembler;
use move_ir_types::location::Spanned;
Expand Down Expand Up @@ -420,7 +421,7 @@ impl ResourceResolver for OnDiskStateView {
}

// This is not supposed to be used in these tests.
quick_balance_resolver_impl!(OnDiskStateView, AnyhowError);
quick_balance_resolver_impl!(OnDiskStateView, StatusCode);

impl GetModule for &OnDiskStateView {
type Error = anyhow::Error;
Expand Down
44 changes: 44 additions & 0 deletions move-vm-backend/src/balance.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
use move_core_types::{account_address::AccountAddress, vm_status::StatusCode};

/// Trait for a balance handler.
///
/// This is used to provide an access to external balance handling functionality from within the
/// MoveVM.
pub trait BalanceHandler {
type Error: Into<StatusCode>;

fn transfer(
&self,
src: AccountAddress,
dst: AccountAddress,
cheque_amount: u128,
) -> Result<bool, Self::Error>;

fn cheque_amount(&self, account: AccountAddress) -> Result<u128, Self::Error>;

fn total_amount(&self, account: AccountAddress) -> Result<u128, Self::Error>;
}

/// An unused [`BalanceHandler`] implementation that is needed for special cases (genesis configuration).
pub(crate) struct DummyBalanceHandler;

impl BalanceHandler for DummyBalanceHandler {
type Error = StatusCode;

fn transfer(
&self,
_src: AccountAddress,
_dst: AccountAddress,
_cheque_amount: u128,
) -> Result<bool, Self::Error> {
unreachable!()
}

fn cheque_amount(&self, _account: AccountAddress) -> Result<u128, Self::Error> {
unreachable!()
}

fn total_amount(&self, _account: AccountAddress) -> Result<u128, Self::Error> {
unreachable!()
}
}
4 changes: 3 additions & 1 deletion move-vm-backend/src/genesis.rs
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
//! Provides a configuration to prepare the initial MoveVM storage state.
use crate::balance::DummyBalanceHandler;
use crate::Mvm;
use crate::VmResult;
use crate::{storage::Storage, types::GasStrategy};
Expand Down Expand Up @@ -65,7 +66,8 @@ impl VmGenesisConfig {
/// Apply the configuration to the storage.
pub fn apply<S: Storage>(self, storage: S) -> Result<(), GenesisConfigError> {
let storage_safe = StorageSafe::new(storage);
let vm = Mvm::new(&storage_safe).map_err(|_| GenesisConfigError::MoveVmInitFailure)?;
let vm = Mvm::new(&storage_safe, DummyBalanceHandler {})
.map_err(|_| GenesisConfigError::MoveVmInitFailure)?;

let publish_under_stdaddr = |bundle: &[u8]| {
let result =
Expand Down
61 changes: 12 additions & 49 deletions move-vm-backend/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@

extern crate alloc;

pub mod balance;
pub mod genesis;
pub mod storage;
pub mod types;
Expand All @@ -12,7 +13,7 @@ use crate::types::{Call, Transaction, VmResult};
use crate::warehouse::Warehouse;
use alloc::{format, string::ToString, vec, vec::Vec};
use anyhow::{anyhow, Error};
use core::fmt::Display;
use balance::BalanceHandler;
use move_binary_format::{
errors::VMResult,
file_format::StructHandleIndex,
Expand All @@ -35,72 +36,34 @@ use move_vm_runtime::move_vm::MoveVM;
use move_vm_types::loaded_data::runtime_types::{CachedStructIndex, Type};
use types::{GasHandler, GasStrategy};

/// Represents failures that might occur during native token transaction
#[derive(Debug)]
pub enum TransferError {
InsuficientBalance,
NoSessionTokenPresent,
}

impl Display for TransferError {
fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
f.write_str(format!("{:?}", self).as_str())
}
}

/*
pub trait SubstrateAPI {
/// Callback signature of method to do the transfer between accounts
/// # Params
/// * `from` - 'AccountAddress' is of a sender;
/// * `to` - 'AccountAddress' is of recepient;
/// * `amount` - 'u128' is amount to transfer;
/// # Returns
/// * Result of success or 'TransferError' variant on error.
fn transfer(
&self,
from: AccountAddress,
to: AccountAddress,
amount: u128,
) -> Result<(), TransferError>;
/// Callback to fetch account's balance in Substrate native currency
/// # Params
/// `of` - 'AccountAddress' of the account in question;
/// # Returns 'u128' value of account's balance.
fn get_balance(&self, of: AccountAddress) -> u128;
}
*/

/// Main MoveVM structure, which is used to represent the virutal machine itself.
pub struct Mvm<S>
//, Api>
pub struct Mvm<S, B>
where
S: Storage,
// Api: SubstrateAPI,
B: BalanceHandler,
{
// MoveVM instance - from move_vm_runtime crate
vm: MoveVM,
// Storage instance
warehouse: Warehouse<S>, //, Api>,
warehouse: Warehouse<S, B>,
}

impl<S> Mvm<S>
//, Api>
impl<S, B> Mvm<S, B>
where
S: Storage,
// Api: SubstrateAPI,
B: BalanceHandler,
{
/// Create a new Move VM with the given storage.
pub fn new(storage: S /*, substrate_api: Api*/) -> Result<Mvm<S /*, Api*/>, Error> {
Self::new_with_config(storage /*, substrate_api*/)
pub fn new(storage: S, balance_handler: B) -> Result<Mvm<S, B>, Error> {
Self::new_with_config(storage, balance_handler)
}

/// Create a new Move VM with the given storage and configuration.
pub(crate) fn new_with_config(
storage: S,
// substrate_api: Api,
balance_handler: B,
// config: VMConfig,
) -> Result<Mvm<S> /*, Api>*/, Error> {
) -> Result<Mvm<S, B>, Error> {
Ok(Mvm {
// TODO(rqnsom): see if we can avoid GAS_PARAMS cloning
vm: MoveVM::new(all_natives(CORE_CODE_ADDRESS, NATIVE_COST_PARAMS.clone())).map_err(
Expand All @@ -109,7 +72,7 @@ where
anyhow!("Error code:{:?}: msg: '{}'", code, msg.unwrap_or_default())
},
)?,
warehouse: Warehouse::new(storage /*, substrate_api*/),
warehouse: Warehouse::new(storage, balance_handler),
})
}

Expand Down
Loading

0 comments on commit 9ec76b5

Please sign in to comment.