Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add endpoint for direct submission of Ethereum events #294

Merged
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
107 changes: 107 additions & 0 deletions Cargo.lock

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

3 changes: 3 additions & 0 deletions apps/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -128,6 +128,9 @@ web30 = "0.19.1"
websocket = "0.26.2"
winapi = "0.3.9"

warp = "0.3.2"
bytes = "1.1.0"

[dev-dependencies]
assert_matches = "1.5.0"
namada = {path = "../shared", features = ["testing", "wasm-runtime"]}
Expand Down
11 changes: 11 additions & 0 deletions apps/src/lib/config/ethereum.rs
Original file line number Diff line number Diff line change
@@ -1,3 +1,6 @@
//! Configuration settings to do with the Ethereum bridge.
#[allow(unused_imports)]
use namada::types::ethereum_events::EthereumEvent;
batconjurer marked this conversation as resolved.
Show resolved Hide resolved
use serde::{Deserialize, Serialize};

/// Default [Ethereum JSON-RPC](https://ethereum.org/en/developers/docs/apis/json-rpc/) endpoint used by the oracle
Expand All @@ -8,12 +11,20 @@ pub struct Config {
/// The Ethereum JSON-RPC endpoint that the Ethereum event oracle will use
/// to listen for events from the Ethereum bridge smart contracts
pub oracle_rpc_endpoint: String,
/// If this is set to `true`, then instead of the oracle listening for
/// events at a Ethereum JSON-RPC endpoint, an endpoint will be exposed by
/// the ledger for submission of Borsh-serialized
/// [`EthereumEvent`]s
#[cfg(not(feature = "eth-fullnode"))]
pub oracle_event_endpoint: bool,
}

impl Default for Config {
fn default() -> Self {
Self {
oracle_rpc_endpoint: DEFAULT_ORACLE_RPC_ENDPOINT.to_owned(),
#[cfg(not(feature = "eth-fullnode"))]
oracle_event_endpoint: false,
}
}
}
4 changes: 0 additions & 4 deletions apps/src/lib/node/ledger/ethereum_node/mod.rs
Original file line number Diff line number Diff line change
@@ -1,12 +1,8 @@
pub mod events;
pub mod oracle;
#[cfg(feature = "eth-fullnode")]
pub use oracle::{run_oracle, Oracle};
pub mod test_tools;
use std::ffi::OsString;

#[cfg(not(feature = "eth-fullnode"))]
pub use test_tools::mock_oracle::run_oracle;
use thiserror::Error;
use tokio::sync::oneshot::{Receiver, Sender};

Expand Down
63 changes: 63 additions & 0 deletions apps/src/lib/node/ledger/ethereum_node/test_tools.rs
Original file line number Diff line number Diff line change
Expand Up @@ -47,6 +47,69 @@ pub mod mock_oracle {
}
}

#[cfg(not(feature = "eth-fullnode"))]
pub mod event_endpoint {
use borsh::BorshDeserialize;
use namada::types::ethereum_events::EthereumEvent;
use tokio::sync::mpsc::UnboundedSender;

const ETHEREUM_EVENTS_ENDPOINT: ([u8; 4], u16) = ([127, 0, 0, 1], 3030);

/// The path to which Borsh-serialized Ethereum events should be submitted
const PATH: &str = "eth_events";

pub fn start_oracle(
sender: UnboundedSender<EthereumEvent>,
) -> tokio::task::JoinHandle<()> {
tokio::spawn(async move {
use warp::Filter;

tracing::info!(
?ETHEREUM_EVENTS_ENDPOINT,
"Ethereum event endpoint is starting"
);

let eth_events = warp::post()
.and(warp::path(PATH))
.and(warp::body::bytes())
.map(move |bytes: bytes::Bytes| {
tracing::info!(len = bytes.len(), "Received request");
let event = match EthereumEvent::try_from_slice(&bytes) {
Ok(event) => event,
Err(error) => {
tracing::warn!(?error, "Couldn't handle request");
return warp::reply::with_status(
"Bad request",
warp::http::StatusCode::BAD_REQUEST,
);
}
};
tracing::debug!("Serialized event - {:#?}", event);
match sender.send(event) {
Ok(()) => warp::reply::with_status(
"OK",
warp::http::StatusCode::OK,
),
Err(error) => {
tracing::warn!(?error, "Couldn't send event");
warp::reply::with_status(
"Internal server error",
warp::http::StatusCode::INTERNAL_SERVER_ERROR,
)
}
}
});

warp::serve(eth_events).run(ETHEREUM_EVENTS_ENDPOINT).await;

tracing::info!(
?ETHEREUM_EVENTS_ENDPOINT,
"Ethereum event endpoint is no longer running"
);
})
}
}

#[cfg(all(test, feature = "eth-fullnode"))]
pub mod mock_web3_client {
use std::cell::RefCell;
Expand Down
22 changes: 20 additions & 2 deletions apps/src/lib/node/ledger/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -340,8 +340,26 @@ async fn run_aux(config: config::Ledger, wasm_dir: PathBuf) {
res
});

let oracle =
ethereum_node::run_oracle(ethereum_url, eth_sender, abort_sender);
let oracle = {
#[cfg(not(feature = "eth-fullnode"))]
if config.ethereum.oracle_event_endpoint {
ethereum_node::test_tools::event_endpoint::start_oracle(
eth_sender,
)
} else {
ethereum_node::test_tools::mock_oracle::run_oracle(
ethereum_url,
eth_sender,
abort_sender,
)
}
#[cfg(feature = "eth-fullnode")]
ethereum_node::oracle::run_oracle(
ethereum_url,
eth_sender,
abort_sender,
)
};

// Shutdown ethereum_node via a message to ensure that the child process
// is properly cleaned-up.
Expand Down