Skip to content

Commit

Permalink
Create a LayoutResolver to compute layout from VM types (MystenLabs#1…
Browse files Browse the repository at this point in the history
…1529)

## Description 

- Move expensive_check_sui_conservation to node init
- Expose a layout resolver based on a VM session
- Decouple MoveResolver traits from Storage traits

In some of the places where we want to use the layout resolver, we
don't have access to all the information to implement `StorageView`,
but we only need to use the `BackingPackageStore`.

To support these cases, we need to provide a state view to
`LinkageView` that can serve packages, and then shim the Module and
Resource resolution functions.

This requires that `LinkageView` no longer accept a reference
parameter, but a value (so we can inject state into it) -- similar to
the trick we pulled to allow `Session` to own a `LinkageView`.  Then
implementors (like `TemporaryStore`) that only need to be passed by
reference can be passed by explicit reference,

i.e. `LinkageView<'state, TemporaryStore>` becomes
`LinkageView<&'state TemporaryStore>`.

However, we cannot impose a `&'state S: StorageView` bound, because
some APIs in `StorageView` require a mutable reference, so we needed
to decouple the resolution traits (now `SuiResolver`) and the storage
traits, to impose twin constraints:

```
fn ...<'state, S>
where
  S: StorageView
  &'state S: SuiResolver
```

- Logging improvements
- Bring `invariant_violation!` macro into `sui-types`.
- Create a variant of it -- `make_invariant_violation!` -- that
  creates the error, but does not wrap it in a result of return it.
- Add `format!` string support to these macros
- Use this macro for invariant violations within conservation checking
  with extra context on what is failing (what stage, what type is
  involved)
- Enable telemetry_subscription in the `move_package_upgrade_tests` to
  see the logs from authorities during tests.
- (Temporary) Print the IDs of published/upgraded packages in the
  failing test, for context.

## Test Plan 

Existing tests

---
If your changes are not user-facing and not a breaking change, you can
skip the following section. Otherwise, please indicate what changed, and
then add to the Release Notes section as highlighted during the release
process.

### Type of Change (Check all that apply)

- [ ] user-visible impact
- [ ] breaking change for a client SDKs
- [ ] breaking change for FNs (FN binary must upgrade)
- [ ] breaking change for validators or node operators (must upgrade
binaries)
- [ ] breaking change for on-chain data layout
- [ ] necessitate either a data wipe or data migration

### Release notes
  • Loading branch information
dariorussi authored May 10, 2023
1 parent 166a492 commit 7c6acca
Show file tree
Hide file tree
Showing 34 changed files with 1,167 additions and 370 deletions.
1 change: 1 addition & 0 deletions Cargo.lock

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

12 changes: 7 additions & 5 deletions crates/sui-adapter/src/execution_engine.rs
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@ use sui_types::programmable_transaction_builder::ProgrammableTransactionBuilder;
use tracing::{info, instrument, trace, warn};

use crate::programmable_transactions;
use crate::type_layout_resolver::TypeLayoutResolver;
use move_binary_format::access::ModuleAccess;
use sui_macros::checked_arithmetic;
use sui_protocol_config::{check_limit_by_meter, LimitThresholdCrossed, ProtocolConfig};
Expand Down Expand Up @@ -413,18 +414,19 @@ fn execute_transaction<
temporary_store.conserve_unmetered_storage_rebate(gas_status.unmetered_storage_rebate());
if !is_genesis_tx && !Mode::allow_arbitrary_values() {
// ensure that this transaction did not create or destroy SUI, try to recover if the check fails
let conservation_result = temporary_store
.check_sui_conserved(advance_epoch_gas_summary, enable_expensive_checks);
let conservation_result = {
let mut layout_resolver = TypeLayoutResolver::new(move_vm, &*temporary_store);
temporary_store.check_sui_conserved(advance_epoch_gas_summary, &mut layout_resolver, enable_expensive_checks)
};
if let Err(conservation_err) = conservation_result {
// conservation violated. try to avoid panic by dumping all writes, charging for gas, re-checking
// conservation, and surfacing an aborted transaction with an invariant violation if all of that works
result = Err(conservation_err);
temporary_store.reset(gas, &mut gas_status);
temporary_store.charge_gas(gas_object_id, &mut gas_status, &mut result, gas);
// check conservation once more more
if let Err(recovery_err) = temporary_store
.check_sui_conserved(advance_epoch_gas_summary, enable_expensive_checks)
{
let mut layout_resolver = TypeLayoutResolver::new(move_vm, &*temporary_store);
if let Err(recovery_err) = temporary_store.check_sui_conserved(advance_epoch_gas_summary, &mut layout_resolver, enable_expensive_checks) {
// if we still fail, it's a problem with gas
// charging that happens even in the "aborted" case--no other option but panic.
// we will create or destroy SUI otherwise
Expand Down
99 changes: 65 additions & 34 deletions crates/sui-adapter/src/execution_mode.rs
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ use sui_types::{error::ExecutionError, transaction::Argument};

use crate::programmable_transactions::{
context::ExecutionContext,
types::{RawValueType, StorageView, Value},
types::{RawValueType, StorageView, SuiResolver, Value},
};

pub type TransactionIndex = usize;
Expand All @@ -32,19 +32,23 @@ pub trait ExecutionMode {

fn empty_results() -> Self::ExecutionResults;

fn add_argument_update<S: StorageView>(
context: &mut ExecutionContext<S>,
fn add_argument_update<'vm, 'state, 'a, S: StorageView>(
context: &mut ExecutionContext<'vm, 'state, 'a, S>,
acc: &mut Self::ArgumentUpdates,
arg: Argument,
_new_value: &Value,
) -> Result<(), ExecutionError>;
) -> Result<(), ExecutionError>
where
&'state S: SuiResolver;

fn finish_command<S: StorageView>(
context: &mut ExecutionContext<S>,
fn finish_command<'vm, 'state, 'a, S: StorageView>(
context: &mut ExecutionContext<'vm, 'state, 'a, S>,
acc: &mut Self::ExecutionResults,
argument_updates: Self::ArgumentUpdates,
command_result: &[Value],
) -> Result<(), ExecutionError>;
) -> Result<(), ExecutionError>
where
&'state S: SuiResolver;
}

#[derive(Copy, Clone)]
Expand All @@ -70,21 +74,27 @@ impl ExecutionMode for Normal {

fn empty_results() -> Self::ExecutionResults {}

fn add_argument_update<S: StorageView>(
_context: &mut ExecutionContext<S>,
fn add_argument_update<'vm, 'state, 'a, S: StorageView>(
_context: &mut ExecutionContext<'vm, 'state, 'a, S>,
_acc: &mut Self::ArgumentUpdates,
_arg: Argument,
_new_value: &Value,
) -> Result<(), ExecutionError> {
) -> Result<(), ExecutionError>
where
&'state S: SuiResolver,
{
Ok(())
}

fn finish_command<S: StorageView>(
_context: &mut ExecutionContext<S>,
fn finish_command<'vm, 'state, 'a, S: StorageView>(
_context: &mut ExecutionContext<'vm, 'state, 'a, S>,
_acc: &mut Self::ExecutionResults,
_argument_updates: Self::ArgumentUpdates,
_command_result: &[Value],
) -> Result<(), ExecutionError> {
) -> Result<(), ExecutionError>
where
&'state S: SuiResolver,
{
Ok(())
}
}
Expand Down Expand Up @@ -112,21 +122,27 @@ impl ExecutionMode for Genesis {

fn empty_results() -> Self::ExecutionResults {}

fn add_argument_update<S: StorageView>(
_context: &mut ExecutionContext<S>,
fn add_argument_update<'vm, 'state, 'a, S: StorageView>(
_context: &mut ExecutionContext<'vm, 'state, 'a, S>,
_acc: &mut Self::ArgumentUpdates,
_arg: Argument,
_new_value: &Value,
) -> Result<(), ExecutionError> {
) -> Result<(), ExecutionError>
where
&'state S: SuiResolver,
{
Ok(())
}

fn finish_command<S: StorageView>(
_context: &mut ExecutionContext<S>,
fn finish_command<'vm, 'state, 'a, S: StorageView>(
_context: &mut ExecutionContext<'vm, 'state, 'a, S>,
_acc: &mut Self::ExecutionResults,
_argument_updates: Self::ArgumentUpdates,
_command_result: &[Value],
) -> Result<(), ExecutionError> {
) -> Result<(), ExecutionError>
where
&'state S: SuiResolver,
{
Ok(())
}
}
Expand Down Expand Up @@ -157,21 +173,27 @@ impl ExecutionMode for System {

fn empty_results() -> Self::ExecutionResults {}

fn add_argument_update<S: StorageView>(
_context: &mut ExecutionContext<S>,
fn add_argument_update<'vm, 'state, 'a, S: StorageView>(
_context: &mut ExecutionContext<'vm, 'state, 'a, S>,
_acc: &mut Self::ArgumentUpdates,
_arg: Argument,
_new_value: &Value,
) -> Result<(), ExecutionError> {
) -> Result<(), ExecutionError>
where
&'state S: SuiResolver,
{
Ok(())
}

fn finish_command<S: StorageView>(
_context: &mut ExecutionContext<S>,
fn finish_command<'vm, 'state, 'a, S: StorageView>(
_context: &mut ExecutionContext<'vm, 'state, 'a, S>,
_acc: &mut Self::ExecutionResults,
_argument_updates: Self::ArgumentUpdates,
_command_result: &[Value],
) -> Result<(), ExecutionError> {
) -> Result<(), ExecutionError>
where
&'state S: SuiResolver,
{
Ok(())
}
}
Expand Down Expand Up @@ -210,23 +232,29 @@ impl ExecutionMode for DevInspect {
vec![]
}

fn add_argument_update<S: StorageView>(
context: &mut ExecutionContext<S>,
fn add_argument_update<'vm, 'state, 'a, S: StorageView>(
context: &mut ExecutionContext<'vm, 'state, 'a, S>,
acc: &mut Self::ArgumentUpdates,
arg: Argument,
new_value: &Value,
) -> Result<(), ExecutionError> {
) -> Result<(), ExecutionError>
where
&'state S: SuiResolver,
{
let (bytes, type_tag) = value_to_bytes_and_tag(context, new_value)?;
acc.push((arg, bytes, type_tag));
Ok(())
}

fn finish_command<S: StorageView>(
context: &mut ExecutionContext<S>,
fn finish_command<'vm, 'state, 'a, S: StorageView>(
context: &mut ExecutionContext<'vm, 'state, 'a, S>,
acc: &mut Self::ExecutionResults,
argument_updates: Self::ArgumentUpdates,
command_result: &[Value],
) -> Result<(), ExecutionError> {
) -> Result<(), ExecutionError>
where
&'state S: SuiResolver,
{
let command_bytes = command_result
.iter()
.map(|value| value_to_bytes_and_tag(context, value))
Expand All @@ -236,10 +264,13 @@ impl ExecutionMode for DevInspect {
}
}

fn value_to_bytes_and_tag<S: StorageView>(
context: &mut ExecutionContext<S>,
fn value_to_bytes_and_tag<'vm, 'state, 'a, S: StorageView>(
context: &mut ExecutionContext<'vm, 'state, 'a, S>,
value: &Value,
) -> Result<(Vec<u8>, TypeTag), ExecutionError> {
) -> Result<(Vec<u8>, TypeTag), ExecutionError>
where
&'state S: SuiResolver,
{
let (type_tag, bytes) = match value {
Value::Object(obj) => {
let tag = context
Expand Down
19 changes: 3 additions & 16 deletions crates/sui-adapter/src/lib.rs
Original file line number Diff line number Diff line change
@@ -1,25 +1,12 @@
// Copyright (c) Mysten Labs, Inc.
// SPDX-License-Identifier: Apache-2.0

macro_rules! invariant_violation {
($msg:expr) => {{
if cfg!(debug_assertions) {
panic!("{}", $msg)
}
return Err(sui_types::error::ExecutionError::invariant_violation($msg).into());
}};
}

macro_rules! assert_invariant {
($cond:expr, $msg:expr) => {{
if !$cond {
invariant_violation!($msg)
}
}};
}
#[macro_use]
extern crate sui_types;

pub mod adapter;
pub mod error;
pub mod execution_engine;
pub mod execution_mode;
pub mod programmable_transactions;
pub mod type_layout_resolver;
Loading

0 comments on commit 7c6acca

Please sign in to comment.