Skip to content

Commit

Permalink
feat(ethexe): handle incoming transfers: from messaging and from dire…
Browse files Browse the repository at this point in the history
…ct WVara erc20.transfer(..) (#4291)
  • Loading branch information
breathx authored Oct 17, 2024
1 parent cf4112e commit 6f943d7
Show file tree
Hide file tree
Showing 4 changed files with 156 additions and 5 deletions.
113 changes: 113 additions & 0 deletions ethexe/cli/src/tests.rs
Original file line number Diff line number Diff line change
Expand Up @@ -322,6 +322,108 @@ async fn mailbox() {
assert!(schedule.is_empty(), "{:?}", schedule);
}

#[tokio::test(flavor = "multi_thread")]
#[ntest::timeout(60_000)]
async fn incoming_transfers() {
gear_utils::init_default_logger();

let mut env = TestEnv::new(Default::default()).await.unwrap();

let sequencer_public_key = env.wallets.next();
let mut node = env.new_node(
NodeConfig::default()
.sequencer(sequencer_public_key)
.validator(env.validators[0]),
);
node.start_service().await;

let res = env
.upload_code(demo_ping::WASM_BINARY)
.await
.unwrap()
.wait_for()
.await
.unwrap();

let code_id = res.code_id;

let res = env
.create_program(code_id, b"PING", 0)
.await
.unwrap()
.wait_for()
.await
.unwrap();

let ping_id = res.program_id;

let wvara = env.ethereum.router().wvara();
let ping = env.ethereum.mirror(ping_id.to_address_lossy().into());

let on_eth_balance = wvara
.query()
.balance_of(ping.address().0.into())
.await
.unwrap();
assert_eq!(on_eth_balance, 0);

let state_hash = ping.query().state_hash().await.unwrap();
let local_balance = node.db.read_state(state_hash).unwrap().balance;
assert_eq!(local_balance, 0);

// 1_000 tokens
const VALUE_SENT: u128 = 1_000_000_000_000_000;

let mut listener = env.events_publisher().subscribe().await;

env.transfer_wvara(ping_id, VALUE_SENT).await;

listener
.apply_until_block_event(|e| {
Ok(matches!(e, BlockEvent::Router(RouterEvent::BlockCommitted { .. })).then_some(()))
})
.await
.unwrap();

let on_eth_balance = wvara
.query()
.balance_of(ping.address().0.into())
.await
.unwrap();
assert_eq!(on_eth_balance, VALUE_SENT);

let state_hash = ping.query().state_hash().await.unwrap();
let local_balance = node.db.read_state(state_hash).unwrap().balance;
assert_eq!(local_balance, VALUE_SENT);

env.approve_wvara(ping_id).await;

let res = env
.send_message(ping_id, b"PING", VALUE_SENT)
.await
.unwrap()
.wait_for()
.await
.unwrap();

assert_eq!(
res.reply_code,
ReplyCode::Success(SuccessReplyReason::Manual)
);
assert_eq!(res.reply_value, 0);

let on_eth_balance = wvara
.query()
.balance_of(ping.address().0.into())
.await
.unwrap();
assert_eq!(on_eth_balance, 2 * VALUE_SENT);

let state_hash = ping.query().state_hash().await.unwrap();
let local_balance = node.db.read_state(state_hash).unwrap().balance;
assert_eq!(local_balance, 2 * VALUE_SENT);
}

#[tokio::test(flavor = "multi_thread")]
#[ntest::timeout(120_000)]
async fn ping_reorg() {
Expand Down Expand Up @@ -934,6 +1036,17 @@ mod utils {
wvara.approve_all(program_address.0.into()).await.unwrap();
}

pub async fn transfer_wvara(&self, program_id: ActorId, value: u128) {
log::info!("📗 Transferring {value} WVara to {program_id}");

let program_address = ethexe_signer::Address::try_from(program_id).unwrap();
let wvara = self.ethereum.router().wvara();
wvara
.transfer(program_address.0.into(), value)
.await
.unwrap();
}

pub fn events_publisher(&self) -> EventsPublisher {
EventsPublisher {
broadcaster: self.broadcaster.clone(),
Expand Down
18 changes: 15 additions & 3 deletions ethexe/processor/src/handling/events.rs
Original file line number Diff line number Diff line change
Expand Up @@ -151,12 +151,24 @@ impl Processor {

pub(crate) fn handle_wvara_event(
&mut self,
_in_block_transitions: &mut InBlockTransitions,
in_block_transitions: &mut InBlockTransitions,
event: WVaraEvent,
) -> Result<()> {
match event {
WVaraEvent::Transfer { .. } => {
log::debug!("Handler not yet implemented: {event:?}");
WVaraEvent::Transfer { from, to, value } => {
if let Some(state_hash) = in_block_transitions.state_of(&to) {
if in_block_transitions.state_of(&from).is_none() {
let new_state_hash = self.db.mutate_state(state_hash, |_, state| {
state.balance += value;
Ok(())
})?;

in_block_transitions
.modify_state(to, new_state_hash)
.expect("queried above so infallible here");
}
}

Ok(())
}
}
Expand Down
16 changes: 15 additions & 1 deletion ethexe/runtime/common/src/journal.rs
Original file line number Diff line number Diff line change
Expand Up @@ -374,7 +374,21 @@ impl<S: Storage> JournalHandler for Handler<'_, S> {
}

fn send_value(&mut self, from: ProgramId, to: Option<ProgramId>, value: u128) {
// TODO: implement
// TODO (breathx): implement rest of cases.
if let Some(to) = to {
if self.in_block_transitions.state_of(&from).is_some() {
return;
}

let state_hash = self.update_state(to, |state| {
state.balance += value;
Ok(())
});

self.in_block_transitions
.modify_state_with(to, state_hash, value, vec![], vec![])
.expect("queried above; infallible");
}
}

fn store_new_programs(
Expand Down
14 changes: 13 additions & 1 deletion ethexe/signer/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,7 @@ pub use sha3;
pub use signature::Signature;

use anyhow::{anyhow, Result};
use gprimitives::ActorId;
use gprimitives::{ActorId, H160};
use parity_scale_codec::{Decode, Encode};
use sha3::Digest as _;
use signature::RawSignature;
Expand All @@ -51,6 +51,18 @@ impl From<PrivateKey> for PublicKey {
#[derive(Encode, Decode, Default, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)]
pub struct Address(pub [u8; 20]);

impl From<[u8; 20]> for Address {
fn from(value: [u8; 20]) -> Self {
Self(value)
}
}

impl From<H160> for Address {
fn from(value: H160) -> Self {
Self(value.into())
}
}

impl TryFrom<ActorId> for Address {
type Error = anyhow::Error;

Expand Down

0 comments on commit 6f943d7

Please sign in to comment.