Depends on #470 #467 (from the Simple Coin Iteration 3)
In this SMIP, we want to extend the verify of the Runtime to work for Self-Spawn transactions.
(and not only for Non-Self Spawn ones).
Running verify in Self-Spawn mode is unique because the Principal account is in a Pending state (see #467).
It has no Template it's associated with yet.
The way to make it work is to make the Runtime execute the verify functionally.
We know what code needs to run for verify (since the Template is specified at the Spawn transaction).
Additionally, we know that we are only allowed reads from the Immutable Storage of the-to-be-self-spawned Account.
Even though the Account isn't active and has no Storage yet, we can make that verify behave as if it had Storage.
We'll use the immutable_data supplied in the Spawn Transaction, add another layer of indirection to the Storage host functions, and it should work.
To add that layer of indirection, we'd bypass the AccountStorage and leverage the FuncData struct we've introduced in #470. Until now, the immutable_data was being ignored - not anymore...
Now the read should in high-level work such as this:
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() {
let immutable_data = env.func_data();
// We need to extract the `immutable layout` by taking the `Template Address`
// given in the `Spawn Transaction` and then do something such as:
//
// let gs = func_env.gs();
// immutable_section_idx = 0;
let immutable_layout = AccountStorge::template_layout(gs.clone(), &template_addr, immutable_section_idx)?;
// use the same code as in `AccountStorage::get_var`
// see issue #470: https://github.com/spacemeshos/svm/issues/471
}
else {
f()
}
}
We essentially reuse the same logic as in issue #471.
Given the immutable_data buffer and the Immutable Storage Section Layout, we should be able to extract the required variable.
We need to load that Layout only once to optimize the code.
So the above line of code:
let immutable_layout = AccountStorge::template_layout(gs.clone(), &template_addr, immutable_section_idx)?;
The loading of the Immutable Storage Section Layout should be done externally.
Probably it should become part of the FuncData.
It is better to make it optional (of type Option<FixedLayout>) since we want to have it only for Self-Spawn Verify.
In any other case, we just hit the AccountStorage directly.
Before the ctor running
We've another leftover from issue #477 that we need to fill in.
Here is the code appearing under #477.
impl Runtime {
pub fn spawn(
&mut self,
envelope: &Envelope,
message: &[u8],
context: &Context,
) -> SpawnReceipt {
info!("Runtime `spawn`");
let gas_left = GasTank::new(envelope.gas_limit());
let spawn = SpawnAccount::decode_bytes(message).expect(ERR_VALIDATE_SPAWN);
// If the `Principal` is a `Pending Account` (a.k.a a `Stub Account`)
// then we say we're running a `Self-Spawn` transaction.
let self_spawn = ...
if self_spawn {
todo!("Simple Coin Iteration #4")
}
else {
// now the `self.create_account` expects an additional `immutable_data` param
self.create_account(
&target,
template_addr.clone(),
account.name().to_string(),
0,
0,
&spawn.immutable_data;
)
.unwrap();
self.call_ctor(&spawn, target, envelope, context, gas_left)
}
}
We need to do the following:
impl Runtime {
pub fn spawn(
&mut self,
envelope: &Envelope,
message: &[u8],
context: &Context,
) -> SpawnReceipt {
info!("Runtime `spawn`");
let gas_left = GasTank::new(envelope.gas_limit());
let spawn = SpawnAccount::decode_bytes(message).expect(ERR_VALIDATE_SPAWN);
// If the `Principal` is a `Pending Account` (a.k.a a `Stub Account`)
// then we say we're running a `Self-Spawn` transaction.
let self_spawn = ...
let mut spawned_account: Option<AccountStorage> = None;
if self_spawn {
// We don't need to create the `Account`
let mut account = AccountStorage::new(..);
account.set_immutable( &spawn.immutable_data);
}
else {
// now the `self.create_account` expects an additional `immutable_data` param
spawned_account = self.create_account(
&target,
template_addr.clone(),
account.name().to_string(),
0,
0,
&spawn.immutable_data;
)
.unwrap();
}
let receipt = self.call_ctor(&spawn, target, envelope, context, gas_left);
if receipt.success {
if self_spawn {
// Turn the `Account` into `Active` and set it's `Template Address`.
// We've set above its `Immutable Storage` so that the `ctor` would work.
AccountStorage::activate(&account_addr, &template_addr);
}
else {
spawned_account.activate(&account_addr);
}
}
else {
// The Transaction has failed
if self_spawn {
// We can do nothing, but it'd be nicer to remove the `immutable_storage`
// of the `Pending Principal`
let mut account = AccountStorage::new(..);
account.set_immutable(&[]);
}
else {
// The `Non-Self Spawn` has failed
// We need to rollback the account created before the `call_ctor`.
// Everything related to the `spawned_account` should be deleted.
//
// It was created as an implementation decision.
// But basically, we can't call it an `Account` only after the `ctor` has succeeded.
spawned_account.destroy();
}
}
receipt
}
Depends on #470 #467 (from the
Simple Coin Iteration 3
)In this SMIP, we want to extend the
verify
of theRuntime
to work forSelf-Spawn
transactions. (and not only forNon-Self Spawn
ones).Running
verify
inSelf-Spawn
mode is unique because thePrincipal
account is in aPending
state (see #467). It has noTemplate
it's associated with yet.The way to make it work is to make the
Runtime
execute theverify
functionally. We know what code needs to run forverify
(since theTemplate
is specified at theSpawn
transaction). Additionally, we know that we are only allowed reads from theImmutable Storage
of the-to-be-self-spawnedAccount.
Even though the
Account
isn't active and has no Storage yet, we can make thatverify
behave as if it had Storage. We'll use theimmutable_data
supplied in theSpawn Transaction,
add another layer of indirection to the Storage host functions, and it should work.To add that layer of indirection, we'd bypass the
AccountStorage
and leverage theFuncData struct
we've introduced in #470. Until now, theimmutable_data
was being ignored - not anymore...Implementation Proposal
In #470, we had this code:
Now the
read
should in high-level work such as this:We essentially reuse the same logic as in issue #471.
Given the
immutable_data
buffer and theImmutable Storage Section Layout,
we should be able to extract the required variable.We need to load that
Layout
only once to optimize the code. So the above line of code:The loading of the
Immutable Storage Section Layout
should be done externally. Probably it should become part of theFuncData
.It is better to make it optional (of type
Option<FixedLayout>
) since we want to have it only forSelf-Spawn Verify
. In any other case, we just hit theAccountStorage
directly.Before the
ctor
runningWe've another leftover from issue #477 that we need to fill in. Here is the code appearing under #477.
We need to do the following: