Skip to content
This repository has been archived by the owner on Aug 14, 2023. It is now read-only.

Extend the FuncEnv to support Immutable Storage for Spawn Transactions #470

Open
YaronWittenstein opened this issue Dec 21, 2021 · 0 comments
Assignees
Labels
AA Related to the Accounts Abstraction simple-coin-iteration-3 svm svm-core SVM core change

Comments

@YaronWittenstein
Copy link
Contributor

YaronWittenstein commented Dec 21, 2021

Depends on: #469

When executing the verify method, we only allow access to the Immutable Storage of the Principal Account.
(and of course, we're only talking about read-access since it's immutable data).

We'll implement the Self Spawn feature in the Simple Coin Integration #4.
When we execute the verify within the Self-Spawn context, we won't know whether the Principal will become active. It'll depend on whether the verify returns true or not (and later whether the ctor will run to its completion without panicking).

Therefore we want to have these rules implemented:

Non-Self Spawn

That is the Spawn we've today. When running Non-Self Spawn, the Principal Account already exists as an active Account.

In that case, the immutable_data given in the Spawn Transaction (see #469) should not be used when running the verify method (since it runs on behalf of the Principal).

That immutable_data will be stored for the newly spawned account, right before executing its ctor (and of course, assuming that the verify passed).

Self Spawn

Again, we don't want to implement that feature fully. Instead, it's the topic of Simple Iteration #4.
So right now, the code will consistently execute Non-Self Spawn, but it'll have some preparation work done for when we'll want to finish that feature (next iteration).

Implementation Proposal

To have more fine-grained control, I propose to add these Rust structs:

  • FuncKind - holding the kind of function that the Runtime will execute
  • TxKind - holding the Transaction kind (the TxKind::Spawn refers to the Non-Self Spawn)
  • FuncData - encapsulates the current FuncKind and TxKind and immutable_data
    Lastly, it has an optional field named immutable. In practice, it'll hold the immutable_data supplied in the Spawn Transaction but only for Self-Spawn. So it's OK to assume that this value will always be None for now.

Important: We can discard the AccessMode struct in favor of the new FuncKind and TxKind.

#[derive(Debug, Copy, Clone, PartialEq, Hash)]
pub enum FuncKind {
  Verify,
  Ctor,
  Alloc,
  General,

  // Maybe in the future
  // Authorize
}

#[derive(Debug, Copy, Clone, PartialEq, Hash)]
pub enum TxKind {
  Deploy,
  Spawn,
  SelfSpawn,
  Call
}

#[derive(Debug, Clone, PartialEq)]
pub struct FuncData {
  fn_kind: FuncKind,
  tx_kind: TxKind,
  immutable_data: Option<Vec<u8>>
}

impl FuncData {
  fn within_alloc(&self) -> bool {
    matches!(self.tx_kind, TxKind::Alloc)
  }

  fn within_spawn(&self) -> bool {
    matches!(self.tx_kind, TxKind::Spawn)
  }

  fn within_self_spawn(&self) -> bool {
    matches!(self.tx_kind, TxKind::SelfSpawn)
  }

  fn within_call(&self) -> bool {
    matches!(self.tx_kind, TxKind::Call)
  }

  fn within_verify(&self) -> bool {
    matches!(self.fn_kind, FuncKind::Verify)
  }

  fn within_ctor(&self) -> bool {
    matches!(self.fn_kind, FuncKind::Ctor)
  }
  
  fn immutable_data(&self) -> Option<&[u8]> {
    self.immutable_data.as_ref()
  }
}

#[derive(wasmer::WasmerEnv, Clone)]
pub struct FuncEnv {
  pub fn new(
    storage: AccountStorage,
    envelope: &Envelope,
    context: &Context,
    template_addr: TemplateAddr,
    target_addr: Address,
    func_data: FuncData
  )
}

impl FuncEnv {
  fn within_alloc(&self) -> bool {
    self.func_data.within_alloc()
  }

  fn within_spawn(&self) -> bool {
    self.func_data.within_spawn()
  }
  
  fn within_self_spawn(&self) -> bool {
    self.func_data.within_self_spawn()
  }

  fn within_call(&self) -> bool {
    self.func_data.within_call()
  }

  fn within_self_spawn_verify(&self) -> bool {
    self.func_data.within_self_spawn() && self.within_verify()
  }

  fn within_verify(&self) -> bool {
    self.func_data.within_verify()
  }

  fn within_ctor(&self) -> bool {
    self.func_data.within_ctor()
  }

  fn assert_storage_allowed(&self) {
    if self.func_data.within_alloc() {
      panic("While allocating Memory can't ask for any Storage Access")
    }
  }
  
  fn read_allowed(&self, section_idx: i32) -> bool {
    // First, we need to confirm `Storage Access` isn't entirely disallowed. 
    self.assert_storage_allowed();
    
    // We disallow:
    // 1. Reads from `Non-Immutable Storage` within `verify`

    let disallowed = self.within_verify() && self.section_idx != 0;
    !(disallowed)
  }

  fn write_allowed(&self, section_idx: i32) -> bool {
    // First, we need to confirm `Storage Access` isn't entirely disallowed. 
    self.assert_storage_allowed();
    
    // We disallow:
    // 1. Writes within `verify`
    // 2. Writes to `Immutable Storage`

    let disallowed = self.within_verify() || self.section == 0;
    !(disallowed)
  }
}

After having the FuncEnv equipped with the new functionality, we need to update the Storage host functions:
https://github.com/spacemeshos/svm/blob/master/crates/runtime/src/vmcalls/storage.rs

Here is a draft of how it should probably look like.
The host functions dealing with Blob will probably have read_blob and write_blob helpers.

fn read<T, F: () -> T>(env: &FuncEnv, section_idx: u32, f: F) -> T {
  assert!(env.read_allowed(section_idx));

  if env.within_self_spawn_verify() {
    todo!("Simple Coin Iteration #4")
  }
  else {
    f()
  }
}

fn write<T, F: () -> ()>(env: &FuncEnv, section_idx: u32, f: F) {
  assert!(env.write_allowed(section_idx));
  f();
}

fn get32(env: &FuncEnv, var_id: u32, section_idx: u32) -> u32 {
  read(env, section_idx, || {
   let borrow = env.borrow();
   let storage = borrow.storage();
   storage.get_var_i64(var_id, section_idx).unwrap() as u32
  })
}

pub fn set32(env: &FuncEnv, var_id: u32, section_idx: u32, value: u32) {
  write(env, section_idx, || {
   let mut borrow = env.borrow_mut();
   let storage = borrow.storage_mut();
   storage.set_var_i32(var_id, section_idx, value as i32).unwrap();
  });
}
@YaronWittenstein YaronWittenstein added AA Related to the Accounts Abstraction simple-coin-iteration-3 svm svm-core SVM core change labels Dec 21, 2021
@YaronWittenstein YaronWittenstein changed the title Extend the Global State to support Account Immutable Storage Extend the FuncEnv to support Account Immutable Storage Dec 21, 2021
@YaronWittenstein YaronWittenstein changed the title Extend the FuncEnv to support Account Immutable Storage Extend the FuncEnv to support Immutable Storage for Spawn Dec 22, 2021
@YaronWittenstein YaronWittenstein changed the title Extend the FuncEnv to support Immutable Storage for Spawn Extend FuncEnv to support Immutable Storage for Spawn Transactions Dec 22, 2021
@YaronWittenstein YaronWittenstein changed the title Extend FuncEnv to support Immutable Storage for Spawn Transactions Extend the FuncEnv to support Immutable Storage for Spawn Transactions Dec 22, 2021
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Labels
AA Related to the Accounts Abstraction simple-coin-iteration-3 svm svm-core SVM core change
Projects
None yet
Development

No branches or pull requests

2 participants