Skip to content

Commit

Permalink
Merge branch 'master' into vs/ethexe-sync
Browse files Browse the repository at this point in the history
  • Loading branch information
grishasobol authored Jul 31, 2024
2 parents 66e2898 + 3945a2f commit a31b761
Show file tree
Hide file tree
Showing 38 changed files with 1,559 additions and 1,707 deletions.
603 changes: 361 additions & 242 deletions Cargo.lock

Large diffs are not rendered by default.

16 changes: 8 additions & 8 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -128,6 +128,7 @@ codec = { package = "parity-scale-codec", version = "3.6.4", default-features =
color-eyre = "0.6.3"
colored = "2.1.0"
const-str = "0.5"
defer = "0.2.1"
derive_more = "0.99.18"
dirs = "4.0.0"
dyn-clonable = "0.9.0"
Expand Down Expand Up @@ -174,11 +175,12 @@ thiserror = "1.0.62"
tokio = { version = "1.38.0" }
uluru = "3.1.0"
url = "2.5.2"
wat = "1.0.83"
# wasmer 4.3.4 for some reason have wat's version "=1.0.71" nailed down, so we have to do the same
wat = "1.0.71"
wabt = "0.10.0"
wasmer = "2.2"
wasmer-cache = "2.2.1"
wasmer-types = "2.2"
wasmer = "4.3.4"
wasmer-cache = "4.3.4"
wasmer-types = "4.3.4"
wasmi = { version = "0.14.0", default-features = false }
wasmtime = "8.0.1"
wasmparser = { package = "wasmparser-nostd", version = "0.100.1", default-features = false }
Expand Down Expand Up @@ -297,10 +299,8 @@ ethexe-rpc = { path = "ethexe/rpc", default-features = false }
ethexe-common = { path = "ethexe/common" }

# Common executors between `sandbox-host` and `calc-stack-height`
sandbox-wasmer = { package = "wasmer", version = "2.2", features = [
"singlepass",
] }
sandbox-wasmer-types = { package = "wasmer-types", version = "2.2" }
sandbox-wasmer = { package = "wasmer", version = "4.3.4", features = ["singlepass"] }
sandbox-wasmer-types = { package = "wasmer-types", version = "4.3.4" }
sandbox-wasmi = { package = "wasmi", git = "https://github.com/gear-tech/wasmi", branch = "v0.13.2-sign-ext", features = ["virtual_memory"] }

# Substrate deps
Expand Down
216 changes: 50 additions & 166 deletions core-processor/src/ext.rs
Original file line number Diff line number Diff line change
Expand Up @@ -38,8 +38,8 @@ use gear_core::{
AllocError, AllocationsContext, GrowHandler, Memory, MemoryError, MemoryInterval, PageBuf,
},
message::{
ContextOutcomeDrain, ContextStore, Dispatch, GasLimit, HandlePacket, InitPacket,
MessageContext, Packet, ReplyPacket,
ContextOutcomeDrain, ContextStore, Dispatch, DispatchKind, GasLimit, HandlePacket,
InitPacket, MessageContext, Packet, ReplyPacket,
},
pages::{
numerated::{interval::Interval, tree::IntervalsTree},
Expand Down Expand Up @@ -422,66 +422,6 @@ impl<'a, LP: LazyPagesInterface> ExtMutator<'a, LP> {
Ok(())
}

// It's temporary fn, used to solve `core-audit/issue#22`.
fn safe_gasfull_sends<T: Packet>(
&mut self,
packet: &T,
delay: u32,
) -> Result<(), FallibleExtError> {
// In case of delayed sending from origin message we keep some gas
// for it while processing outgoing sending notes so gas for
// previously gasless sends should appear to prevent their
// invasion for gas for storing delayed message.
match (packet.gas_limit(), delay != 0) {
// Zero gasfull instant.
//
// In this case there is nothing to do.
(Some(0), false) => Ok(()),

// Any non-zero gasfull or zero gasfull with delay.
//
// In case of zero gasfull with delay it's pretty similar to
// gasless with delay case.
//
// In case of any non-zero gasfull we prevent stealing for any
// previous gasless-es's thresholds from gas supposed to be
// sent with this `packet`.
(Some(_), _) => {
let prev_gasless_fee = self
.outgoing_gasless
.saturating_mul(self.ext.context.mailbox_threshold);
self.reduce_gas(prev_gasless_fee)?;
self.outgoing_gasless = 0;
Ok(())
}

// Gasless with delay.
//
// In this case we must give threshold for each uncovered gasless-es
// sent, otherwise they will steal gas from this `packet` that was
// supposed to pay for delay.
//
// It doesn't guarantee threshold for itself.
(None, true) => {
let prev_gasless_fee = self
.outgoing_gasless
.saturating_mul(self.ext.context.mailbox_threshold);
self.reduce_gas(prev_gasless_fee)?;
self.outgoing_gasless = 1;
Ok(())
}

// Gasless instant.
//
// In this case there is no need to give any thresholds for previous
// gasless-es: only counter should be increased.
(None, false) => {
self.outgoing_gasless = self.outgoing_gasless.saturating_add(1);
Ok(())
}
}
}

fn mark_reservation_used(
&mut self,
reservation_id: ReservationId,
Expand All @@ -506,21 +446,47 @@ impl<'a, LP: LazyPagesInterface> ExtMutator<'a, LP> {
Ok(())
}

fn charge_expiring_resources<T: Packet>(
&mut self,
packet: &T,
check_gas_limit: bool,
) -> Result<(), FallibleExtError> {
let gas_limit = if check_gas_limit {
self.check_gas_limit(packet.gas_limit())?
} else {
packet.gas_limit().unwrap_or(0)
};
fn charge_expiring_resources<T: Packet>(&mut self, packet: &T) -> Result<(), FallibleExtError> {
let reducing_gas_limit = self.get_reducing_gas_limit(packet)?;

self.reduce_gas(gas_limit)?;
self.reduce_gas(reducing_gas_limit)?;
self.charge_message_value(packet.value())
}

fn get_reducing_gas_limit<T: Packet>(&self, packet: &T) -> Result<u64, FallibleExtError> {
match T::kind() {
DispatchKind::Handle => {
// Any "handle" gasless and gasful *non zero* message must
// cover mailbox threshold. That's because destination
// of the message is unknown, so it could be a user,
// and if gasless message is sent, there must be a
// guaranteed gas to cover mailbox.
let mailbox_threshold = self.context.mailbox_threshold;
let gas_limit = packet.gas_limit().unwrap_or(mailbox_threshold);

// Zero gasful message is a special case.
if gas_limit != 0 && gas_limit < mailbox_threshold {
return Err(MessageError::InsufficientGasLimit.into());
}

Ok(gas_limit)
}
DispatchKind::Init | DispatchKind::Reply => {
// Init and reply messages never go to mailbox.
//
// For init case, even if there's no code with a provided
// code id, the init message still goes to queue and then is handled as non
// executable, as there is no code for the destination actor.
//
// Also no reply to user messages go to mailbox, they all are emitted
// within events.

Ok(packet.gas_limit().unwrap_or(0))
}
DispatchKind::Signal => unreachable!("Signals can't be sent as a syscall"),
}
}

fn charge_sending_fee(&mut self, delay: u32) -> Result<(), ChargeError> {
if delay == 0 {
self.charge_gas_if_enough(self.context.message_context.settings().sending_fee)
Expand Down Expand Up @@ -720,18 +686,6 @@ impl<LP: LazyPagesInterface> Ext<LP> {
Ok(result)
}

fn check_gas_limit(&self, gas_limit: Option<GasLimit>) -> Result<GasLimit, FallibleExtError> {
let mailbox_threshold = self.context.mailbox_threshold;
let gas_limit = gas_limit.unwrap_or(0);

// Sending gas should apply the range {0} ∪ [mailbox_threshold; +inf)
if gas_limit < mailbox_threshold && gas_limit != 0 {
Err(MessageError::InsufficientGasLimit.into())
} else {
Ok(gas_limit)
}
}

/// Checking that reservation could be charged for
/// dispatch stash with given delay.
fn check_reservation_gas_limit_for_delayed_sending(
Expand All @@ -753,7 +707,11 @@ impl<LP: LazyPagesInterface> Ext<LP> {
.dispatch_stash
.cost_for(self.context.reserve_for.saturating_add(delay).into());

if limit < waiting_reserve {
// Gas reservation is known for covering mailbox threshold, as reservation
// is created after passing a check for that.
// By this check we guarantee that reservation is enough both for delay
// and for mailbox threshold.
if limit < waiting_reserve.saturating_add(self.context.mailbox_threshold) {
return Err(MessageError::InsufficientGasForDelayedSending.into());
}
}
Expand Down Expand Up @@ -978,8 +936,7 @@ impl<LP: LazyPagesInterface> Externalities for Ext<LP> {
) -> Result<MessageId, Self::FallibleError> {
self.with_changes(|mutator| {
mutator.check_forbidden_destination(msg.destination())?;
mutator.safe_gasfull_sends(&msg, delay)?;
mutator.charge_expiring_resources(&msg, true)?;
mutator.charge_expiring_resources(&msg)?;
mutator.charge_sending_fee(delay)?;
mutator.charge_for_dispatch_stash_hold(delay)?;

Expand Down Expand Up @@ -1029,8 +986,7 @@ impl<LP: LazyPagesInterface> Externalities for Ext<LP> {
self.with_changes(|mutator| {
mutator
.check_forbidden_destination(mutator.context.message_context.reply_destination())?;
mutator.safe_gasfull_sends(&msg, 0)?;
mutator.charge_expiring_resources(&msg, false)?;
mutator.charge_expiring_resources(&msg)?;
mutator.charge_sending_fee(0)?;

mutator
Expand Down Expand Up @@ -1360,9 +1316,10 @@ impl<LP: LazyPagesInterface> Externalities for Ext<LP> {
) -> Result<(MessageId, ProgramId), Self::FallibleError> {
let ed = self.context.existential_deposit;
self.with_changes(|mutator| {
// We don't check for forbidden destination here, since dest is always unique and almost impossible to match SYSTEM_ID
mutator.safe_gasfull_sends(&packet, delay)?;
mutator.charge_expiring_resources(&packet, true)?;
// We don't check for forbidden destination here, since dest is always unique
// and almost impossible to match SYSTEM_ID

mutator.charge_expiring_resources(&packet)?;
mutator.charge_sending_fee(delay)?;
mutator.charge_for_dispatch_stash_hold(delay)?;

Expand Down Expand Up @@ -1501,12 +1458,6 @@ mod tests {
self
}

fn with_mailbox_threshold(mut self, mailbox_threshold: u64) -> Self {
self.0.mailbox_threshold = mailbox_threshold;

self
}

fn with_existential_deposit(mut self, ed: u128) -> Self {
self.0.existential_deposit = ed;

Expand Down Expand Up @@ -2109,73 +2060,6 @@ mod tests {
));
}

#[test]
fn test_gasful_after_gasless() {
let gas = 1_000_000_000;
let mut ext = Ext::new(
ProcessorContextBuilder::new()
.with_message_context(
MessageContextBuilder::new()
.with_outgoing_limit(u32::MAX)
.build(),
)
.with_gas(GasCounter::new(gas))
.with_allowance(GasAllowanceCounter::new(gas))
.with_mailbox_threshold(1000)
.build(),
);

// Sending some gasless messages
let gasless_packet = HandlePacket::new(ProgramId::zero(), Default::default(), 0);
assert!(ext.send(gasless_packet.clone(), 0).is_ok());
assert_eq!(ext.outgoing_gasless, 1);
assert!(ext.send(gasless_packet.clone(), 0).is_ok());
assert_eq!(ext.outgoing_gasless, 2);
assert!(ext.send(gasless_packet.clone(), 0).is_ok());
assert_eq!(ext.outgoing_gasless, 3);

// Sending fee is zero
assert_eq!(ext.current_counter_value(), gas);

// Now sending gasful message
let msg_gas = 1000;
let gasful_packet =
HandlePacket::new_with_gas(ProgramId::zero(), Default::default(), msg_gas, 0);
assert!(ext.send(gasful_packet.clone(), 0).is_ok());
assert_eq!(ext.outgoing_gasless, 0);
assert_eq!(
ext.current_counter_value(),
// reducing gas for the sent message and for mailbox threshold for each gasless
gas - msg_gas - 3 * ext.context.mailbox_threshold
);

// Sending another gasful
let gas = ext.current_counter_value();
assert!(ext.send(gasful_packet.clone(), 0).is_ok());
assert_eq!(ext.outgoing_gasless, 0);
assert_eq!(
ext.current_counter_value(),
// reducing gas the sent message only
gas - msg_gas
);

// Sending some more gasless
assert!(ext.send(gasless_packet.clone(), 0).is_ok());
assert_eq!(ext.outgoing_gasless, 1);
assert!(ext.send(gasless_packet.clone(), 0).is_ok());
assert_eq!(ext.outgoing_gasless, 2);

// And another gasful
let gas = ext.current_counter_value();
assert!(ext.send(gasful_packet.clone(), 0).is_ok());
assert_eq!(ext.outgoing_gasless, 0);
assert_eq!(
ext.current_counter_value(),
// reducing gas for the sent message and for mailbox threshold for each gasless
gas - msg_gas - 2 * ext.context.mailbox_threshold
);
}

#[test]
// This function tests:
//
Expand Down
4 changes: 4 additions & 0 deletions core/src/message/handle.rs
Original file line number Diff line number Diff line change
Expand Up @@ -196,4 +196,8 @@ impl Packet for HandlePacket {
fn value(&self) -> Value {
self.value
}

fn kind() -> DispatchKind {
DispatchKind::Handle
}
}
4 changes: 4 additions & 0 deletions core/src/message/init.rs
Original file line number Diff line number Diff line change
Expand Up @@ -200,4 +200,8 @@ impl Packet for InitPacket {
fn value(&self) -> Value {
self.value
}

fn kind() -> DispatchKind {
DispatchKind::Init
}
}
3 changes: 3 additions & 0 deletions core/src/message/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -229,6 +229,9 @@ pub trait Packet {

/// Packet value.
fn value(&self) -> Value;

/// A dispatch kind the will be generated from the packet.
fn kind() -> DispatchKind;
}

/// The struct contains results of read only send message RPC call.
Expand Down
4 changes: 4 additions & 0 deletions core/src/message/reply.rs
Original file line number Diff line number Diff line change
Expand Up @@ -253,4 +253,8 @@ impl Packet for ReplyPacket {
fn value(&self) -> Value {
self.value
}

fn kind() -> DispatchKind {
DispatchKind::Reply
}
}
2 changes: 1 addition & 1 deletion ethexe/cli/src/tests.rs
Original file line number Diff line number Diff line change
Expand Up @@ -618,7 +618,7 @@ async fn ping_reorg() {
let validator_private_key = env.validator_private_key;
drop(env);

log::info!("📗 Sending PING message, db cleanup and service shuting down");
log::info!("📗 Sending PING message, db cleanup and service shutting down");
let _tx = ping_program
.send_message(b"PING", 10_000_000_000, 0)
.await
Expand Down
Loading

0 comments on commit a31b761

Please sign in to comment.