Skip to content

Commit

Permalink
Update host to account for the XDR changes. (#954)
Browse files Browse the repository at this point in the history
* Update host to account for the XDR changes.
  • Loading branch information
dmkozh authored Jul 18, 2023
1 parent 1b9e67e commit 0bbeec2
Show file tree
Hide file tree
Showing 17 changed files with 212 additions and 265 deletions.
6 changes: 3 additions & 3 deletions Cargo.lock

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

2 changes: 1 addition & 1 deletion Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,7 @@ soroban-native-sdk-macros = { version = "0.0.17", path = "soroban-native-sdk-mac
[workspace.dependencies.stellar-xdr]
version = "0.0.17"
git = "https://github.com/stellar/rs-stellar-xdr"
rev = "54c183e91573d8a5882ff1dda21d444ef42cc426"
rev = "3a853f63639ba729454f53c16545dcddcaa59737"
default-features = false

[workspace.dependencies.wasmi]
Expand Down
48 changes: 22 additions & 26 deletions soroban-env-host/src/auth.rs
Original file line number Diff line number Diff line change
Expand Up @@ -5,10 +5,9 @@ use std::rc::Rc;
use rand::Rng;
use soroban_env_common::xdr::{
ContractDataEntry, ContractDataEntryBody, ContractDataEntryData, CreateContractArgs,
HashIdPreimage, HashIdPreimageSorobanAuthorization, LedgerEntry, LedgerEntryData,
LedgerEntryExt, ScAddress, ScErrorCode, ScErrorType, ScNonceKey, ScVal,
SorobanAuthorizationEntry, SorobanAuthorizedContractFunction, SorobanAuthorizedFunction,
SorobanCredentials,
HashIdPreimage, HashIdPreimageSorobanAuthorization, InvokeContractArgs, LedgerEntry,
LedgerEntryData, LedgerEntryExt, ScAddress, ScErrorCode, ScErrorType, ScNonceKey, ScVal,
SorobanAuthorizationEntry, SorobanAuthorizedFunction, SorobanCredentials,
};
use soroban_env_common::{AddressObject, Compare, Symbol, TryFromVal, TryIntoVal, Val, VecObject};

Expand Down Expand Up @@ -209,9 +208,9 @@ struct AccountAuthorizationTracker {
// Helper for matching the tree that address authorized to the invocation
// tree.
invocation_tracker: InvocationTracker,
// Arguments representing the signature(s) made by the address to authorize
// Value representing the signature created by the address to authorize
// the invocations tracked here.
signature_args: Vec<Val>,
signature: Val,
// Indicates whether this tracker is still valid. If invalidated once, this
// can't be used to authorize anything anymore
is_valid: bool,
Expand Down Expand Up @@ -382,14 +381,11 @@ impl AuthorizedFunction {
&[],
));
};
Ok(SorobanAuthorizedFunction::ContractFn(
SorobanAuthorizedContractFunction {
contract_address: host
.scaddress_from_address(contract_fn.contract_address)?,
function_name,
args: host.rawvals_to_scvec(contract_fn.args.as_slice())?,
},
))
Ok(SorobanAuthorizedFunction::ContractFn(InvokeContractArgs {
contract_address: host.scaddress_from_address(contract_fn.contract_address)?,
function_name,
args: host.rawvals_to_sc_val_vec(contract_fn.args.as_slice())?,
}))
}
AuthorizedFunction::CreateContractHostFn(create_contract_args) => {
Ok(SorobanAuthorizedFunction::CreateContractHostFn(
Expand All @@ -401,16 +397,16 @@ impl AuthorizedFunction {

fn to_xdr_non_metered(&self, host: &Host) -> Result<xdr::SorobanAuthorizedFunction, HostError> {
match self {
AuthorizedFunction::ContractFn(contract_fn) => Ok(
SorobanAuthorizedFunction::ContractFn(SorobanAuthorizedContractFunction {
AuthorizedFunction::ContractFn(contract_fn) => {
Ok(SorobanAuthorizedFunction::ContractFn(InvokeContractArgs {
contract_address: host
.visit_obj(contract_fn.contract_address, |addr: &ScAddress| {
Ok(addr.clone())
})?,
function_name: contract_fn.function_name.try_into_val(host)?,
args: host.rawvals_to_scvec_non_metered(contract_fn.args.as_slice())?,
}),
),
args: host.rawvals_to_sc_val_vec_non_metered(contract_fn.args.as_slice())?,
}))
}
AuthorizedFunction::CreateContractHostFn(create_contract_args) => Ok(
SorobanAuthorizedFunction::CreateContractHostFn(create_contract_args.clone()),
),
Expand Down Expand Up @@ -1273,7 +1269,7 @@ impl AccountAuthorizationTracker {
host: &Host,
auth_entry: SorobanAuthorizationEntry,
) -> Result<Self, HostError> {
let (address, nonce, signature_args) = match auth_entry.credentials {
let (address, nonce, signature) = match auth_entry.credentials {
SorobanCredentials::SourceAccount => (
host.source_account_address()?.ok_or_else(|| {
host.err(
Expand All @@ -1284,22 +1280,22 @@ impl AccountAuthorizationTracker {
)
})?,
None,
vec![],
Val::VOID.into(),
),
SorobanCredentials::Address(address_creds) => (
host.add_host_object(address_creds.address)?,
Some((
address_creds.nonce,
address_creds.signature_expiration_ledger,
)),
host.scvals_to_rawvals(address_creds.signature_args.0.as_slice())?,
host.to_host_val(&address_creds.signature)?,
),
};
let is_invoker = nonce.is_none();
Ok(Self {
address,
invocation_tracker: InvocationTracker::from_xdr(host, auth_entry.root_invocation)?,
signature_args,
signature,
authenticated: false,
need_nonce: !is_invoker,
is_invoker,
Expand Down Expand Up @@ -1347,7 +1343,7 @@ impl AccountAuthorizationTracker {
Ok(Self {
address,
invocation_tracker: InvocationTracker::new_recording(function, current_stack_len),
signature_args: Default::default(),
signature: Val::VOID.into(),
is_valid: true,
authenticated: true,
need_nonce: false,
Expand Down Expand Up @@ -1543,14 +1539,14 @@ impl AccountAuthorizationTracker {
let payload = self.get_signature_payload(host)?;
match sc_addr {
ScAddress::Account(acc) => {
check_account_authentication(host, acc, &payload, &self.signature_args)?;
check_account_authentication(host, acc, &payload, self.signature)?;
}
ScAddress::Contract(acc_contract) => {
check_account_contract_auth(
host,
&acc_contract,
&payload,
&self.signature_args,
self.signature,
&self.invocation_tracker.root_authorized_invocation,
)?;
}
Expand Down
19 changes: 3 additions & 16 deletions soroban-env-host/src/events/internal.rs
Original file line number Diff line number Diff line change
@@ -1,9 +1,6 @@
use std::rc::Rc;

use soroban_env_common::{
xdr::{ScErrorCode, ScErrorType},
BytesObject, VecObject,
};
use soroban_env_common::{BytesObject, VecObject};

use super::{Events, HostEvent};
use crate::{
Expand All @@ -28,16 +25,7 @@ pub struct InternalContractEvent {
impl InternalContractEvent {
// Metering: covered by components
pub fn to_xdr(&self, host: &Host) -> Result<xdr::ContractEvent, HostError> {
let topics = if let ScVal::Vec(Some(v)) = host.from_host_obj(self.topics)?.into() {
Ok(v)
} else {
Err(host.err(
ScErrorType::Events,
ScErrorCode::InvalidInput,
"converting event topics to vector",
&[self.topics.to_val()],
))
}?;
let topics = host.call_args_to_sc_val_vec(self.topics)?;
let data = host.from_host_val(self.data)?;
let contract_id = match self.contract_id {
Some(id) => Some(host.hash_from_bytesobj_input("contract_id", id)?),
Expand Down Expand Up @@ -100,8 +88,7 @@ fn externalize_args(host: &Host, args: &[InternalDiagnosticArg]) -> Result<Vec<S

impl InternalDiagnosticEvent {
pub fn to_xdr(&self, host: &Host) -> Result<xdr::ContractEvent, HostError> {
let topics: Vec<ScVal> = externalize_args(host, &self.topics)?;
let topics = xdr::ScVec::from(xdr::VecM::try_from(topics)?);
let topics: xdr::VecM<ScVal> = externalize_args(host, &self.topics)?.try_into()?;
let args = externalize_args(host, &self.args)?;
let data = if args.len() > 1 {
ScVal::Vec(Some(xdr::ScVec::from(xdr::VecM::try_from(args)?)))
Expand Down
2 changes: 1 addition & 1 deletion soroban-env-host/src/events/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -117,7 +117,7 @@ impl core::fmt::Display for HostEvent {
match &self.event.body {
ContractEventBody::V0(ceb) => {
write!(f, "topics:[")?;
for (i, topic) in ceb.topics.0.iter().enumerate() {
for (i, topic) in ceb.topics.iter().enumerate() {
if i != 0 {
write!(f, ", ")?;
}
Expand Down
79 changes: 40 additions & 39 deletions soroban-env-host/src/host/conversion.rs
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ use soroban_env_common::num::{
use soroban_env_common::xdr::{
self, int128_helpers, AccountId, ContractDataDurability, ContractEntryBodyType, DepthLimiter,
Int128Parts, Int256Parts, ScAddress, ScBytes, ScErrorCode, ScErrorType, ScMap, ScMapEntry,
UInt128Parts, UInt256Parts,
UInt128Parts, UInt256Parts, VecM,
};
use soroban_env_common::{
AddressObject, BytesObject, Convert, Object, ScValObjRef, ScValObject, TryFromVal, TryIntoVal,
Expand Down Expand Up @@ -231,52 +231,53 @@ impl Host {
})
}

// Metering: free?
pub(crate) fn call_args_to_scvec(&self, args: VecObject) -> Result<ScVec, HostError> {
self.visit_obj(args, |hv: &HostVec| self.rawvals_to_scvec(hv.as_slice()))
// Metering: covered by rawvals_to_vec
pub(crate) fn call_args_to_sc_val_vec(
&self,
args: VecObject,
) -> Result<VecM<ScVal>, HostError> {
self.visit_obj(args, |hv: &HostVec| {
self.rawvals_to_sc_val_vec(hv.as_slice())
})
}

pub(crate) fn rawvals_to_scvec(&self, raw_vals: &[Val]) -> Result<ScVec, HostError> {
pub(crate) fn rawvals_to_sc_val_vec(&self, raw_vals: &[Val]) -> Result<VecM<ScVal>, HostError> {
charge_container_bulk_init_with_elts::<Vec<Val>, Val>(
raw_vals.len() as u64,
self.as_budget(),
)?;
Ok(ScVec(
raw_vals
.iter()
.map(|v| self.from_host_val(*v))
.collect::<Result<Vec<ScVal>, HostError>>()?
.try_into()
.map_err(|_| {
err!(
self,
(ScErrorType::Object, ScErrorCode::ExceededLimit),
"vector size limit exceeded",
raw_vals.len()
)
})?,
))
}

pub(crate) fn rawvals_to_scvec_non_metered(
raw_vals
.iter()
.map(|v| self.from_host_val(*v))
.collect::<Result<Vec<ScVal>, HostError>>()?
.try_into()
.map_err(|_| {
err!(
self,
(ScErrorType::Object, ScErrorCode::ExceededLimit),
"vector size limit exceeded",
raw_vals.len()
)
})
}

pub(crate) fn rawvals_to_sc_val_vec_non_metered(
&self,
raw_vals: &[Val],
) -> Result<ScVec, HostError> {
Ok(ScVec(
raw_vals
.iter()
.map(|v| v.try_into_val(self)?)
.collect::<Result<Vec<ScVal>, HostError>>()?
.try_into()
.map_err(|_| {
err!(
self,
(ScErrorType::Object, ScErrorCode::ExceededLimit),
"vector size limit exceeded",
raw_vals.len()
)
})?,
))
) -> Result<VecM<ScVal>, HostError> {
raw_vals
.iter()
.map(|v| v.try_into_val(self)?)
.collect::<Result<Vec<ScVal>, HostError>>()?
.try_into()
.map_err(|_| {
err!(
self,
(ScErrorType::Object, ScErrorCode::ExceededLimit),
"vector size limit exceeded",
raw_vals.len()
)
})
}

pub(crate) fn scvals_to_rawvals(&self, sc_vals: &[ScVal]) -> Result<Vec<Val>, HostError> {
Expand Down
48 changes: 18 additions & 30 deletions soroban-env-host/src/host/frame.rs
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,6 @@ use soroban_env_common::{
use crate::{
auth::AuthorizationManagerSnapshot,
budget::AsBudget,
err,
storage::{InstanceStorageMap, StorageMap},
xdr::{ContractCostType, ContractExecutable, Hash, HostFunction, HostFunctionType, ScVal},
Error, Host, HostError, Object, Symbol, SymbolStr, TryFromVal, TryIntoVal, Val,
Expand Down Expand Up @@ -656,35 +655,24 @@ impl Host {
fn invoke_function_raw(&self, hf: HostFunction) -> Result<Val, HostError> {
let hf_type = hf.discriminant();
match hf {
HostFunction::InvokeContract(args) => {
if let [ScVal::Address(ScAddress::Contract(contract_id)), ScVal::Symbol(scsym), rest @ ..] =
args.as_slice()
{
self.with_frame(Frame::HostFunction(hf_type), || {
// Metering: conversions to host objects are covered. Cost of collecting
// Vals into Vec is ignored. Since 1. Vals are cheap to clone 2. the
// max number of args is fairly limited.

let symbol: Symbol = scsym.as_slice().try_into_val(self)?;
let args = self.scvals_to_rawvals(rest)?;
// since the `HostFunction` frame must be the bottom of the call stack,
// reentry is irrelevant, we always pass in `ContractReentryMode::Prohibited`.
self.call_n_internal(
contract_id,
symbol,
&args[..],
ContractReentryMode::Prohibited,
false,
)
})
} else {
Err(err!(
self,
(ScErrorType::Context, ScErrorCode::UnexpectedSize),
"unexpected number of arguments to 'call' host function",
args.len()
))
}
HostFunction::InvokeContract(invoke_args) => {
self.with_frame(Frame::HostFunction(hf_type), || {
// Metering: conversions to host objects are covered.
let ScAddress::Contract(ref contract_id) = invoke_args.contract_address else {
return Err(self.err(ScErrorType::Value, ScErrorCode::UnexpectedType, "invoked address doesn't belong to a contract", &[]));
};
let function_name: Symbol = invoke_args.function_name.try_into_val(self)?;
let args = self.scvals_to_rawvals(invoke_args.args.as_slice())?;
// since the `HostFunction` frame must be the bottom of the call stack,
// reentry is irrelevant, we always pass in `ContractReentryMode::Prohibited`.
self.call_n_internal(
contract_id,
function_name,
args.as_slice(),
ContractReentryMode::Prohibited,
false,
)
})
}
HostFunction::CreateContract(args) => {
self.with_frame(Frame::HostFunction(hf_type), || {
Expand Down
Loading

0 comments on commit 0bbeec2

Please sign in to comment.