Skip to content

Commit

Permalink
Merge pull request #1428 from EspressoSystems/ts/feat/block-explorer
Browse files Browse the repository at this point in the history
Add Block Explorer to Demos
  • Loading branch information
Ayiga authored May 15, 2024
2 parents 97548f0 + 6cf2414 commit c41c0fd
Show file tree
Hide file tree
Showing 10 changed files with 121 additions and 5 deletions.
1 change: 1 addition & 0 deletions .env
Original file line number Diff line number Diff line change
Expand Up @@ -45,6 +45,7 @@ ESPRESSO_SEQUENCER0_DB_PORT=5432
ESPRESSO_SEQUENCER1_DB_PORT=5433
ESPRESSO_STATE_RELAY_SERVER_PORT=30011
ESPRESSO_STATE_RELAY_SERVER_URL=http://state-relay-server:${ESPRESSO_STATE_RELAY_SERVER_PORT}
ESPRESSO_BLOCK_EXPLORER_PORT=3000

# Ethereum accounts (note 11-15 are used by the sequencer nodes)
ESPRESSO_SEQUENCER_HOTSHOT_ACCOUNT_INDEX=5
Expand Down
12 changes: 11 additions & 1 deletion docker-compose.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -259,7 +259,7 @@ services:
image: ghcr.io/espressosystems/espresso-sequencer/sequencer:main
ports:
- "$ESPRESSO_SEQUENCER1_API_PORT:$ESPRESSO_SEQUENCER_API_PORT"
command: sequencer -- storage-sql -- http -- query -- catchup -- status -- state
command: sequencer -- storage-sql -- http -- query -- catchup -- status -- state -- explorer
environment:
- ESPRESSO_SEQUENCER_ORCHESTRATOR_URL
- ESPRESSO_SEQUENCER_CDN_ENDPOINT
Expand Down Expand Up @@ -553,3 +553,13 @@ services:
interval: 5s
timeout: 4s
retries: 20

block-explorer:
image: ghcr.io/espressosystems/espresso-block-explorer:main
ports:
- "$ESPRESSO_BLOCK_EXPLORER_PORT:3000"
environment:
- QUERY_SERVICE_URI:http://localhost:$ESPRESSO_SEQUENCER1_API_PORT/v0/
depends_on:
sequencer1:
condition: service_healthy
9 changes: 8 additions & 1 deletion process-compose.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ environment:
- ESPRESSO_SEQUENCER_L1_PROVIDER=http://localhost:$ESPRESSO_SEQUENCER_L1_PORT
- ESPRESSO_DEMO_L1_HTTP_PROVIDER=$ESPRESSO_SEQUENCER_L1_PROVIDER
- ESPRESSO_STATE_RELAY_SERVER_URL=http://localhost:$ESPRESSO_STATE_RELAY_SERVER_PORT
- QUERY_SERVICE_URI=http://localhost:$ESPRESSO_SEQUENCER1_API_PORT/v0/
processes:
# Cheating a bit here but since we don't usually have to debug go-ethereum
# it's using the docker compose service which is a bit easier.
Expand Down Expand Up @@ -146,7 +147,7 @@ processes:
failure_threshold: 100

sequencer1:
command: sequencer -- storage-sql -- http -- query -- catchup -- status -- state
command: sequencer -- storage-sql -- http -- query -- catchup -- status -- state -- explorer
environment:
- ESPRESSO_SEQUENCER_API_PORT=$ESPRESSO_SEQUENCER1_API_PORT
- ESPRESSO_SEQUENCER_LIBP2P_BIND_ADDRESS=0.0.0.0:$ESPRESSO_DEMO_SEQUENCER_LIBP2P_PORT_1
Expand Down Expand Up @@ -486,3 +487,9 @@ processes:
# See https://github.com/docker-library/postgres/issues/146 for discussion.
success_threshold: 2
failure_threshold: 20

block-explorer:
command: docker run --rm -p $ESPRESSO_BLOCK_EXPLORER_PORT:3000 -e QUERY_SERVICE_URI ghcr.io/espressosystems/espresso-block-explorer:main
depends_on:
sequencer1:
condition: process_healthy
16 changes: 16 additions & 0 deletions sequencer/src/api/endpoints.rs
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,8 @@ use committable::Committable;
use futures::{try_join, FutureExt};
use hotshot_query_service::{
availability::{self, AvailabilityDataSource, CustomSnafu, FetchBlockSnafu},
data_source::storage::ExplorerStorage,
explorer::{self},
merklized_state::{
self, MerklizedState, MerklizedStateDataSource, MerklizedStateHeightPersistence,
},
Expand Down Expand Up @@ -123,6 +125,20 @@ where
Ok(api)
}

type ExplorerApi<N, P, D, Ver> = Api<AvailState<N, P, D, Ver>, explorer::Error, Ver>;

pub(super) fn explorer<N, P, D, Ver: StaticVersionType + 'static>(
bind_version: Ver,
) -> Result<ExplorerApi<N, P, D, Ver>>
where
N: network::Type,
D: ExplorerStorage<SeqTypes> + Send + Sync + 'static,
P: SequencerPersistence,
{
let api = explorer::define_api::<AvailState<N, P, D, Ver>, SeqTypes, Ver>(bind_version)?;
Ok(api)
}

type NodeApi<N, P, D, Ver> = Api<AvailState<N, P, D, Ver>, node::Error, Ver>;

pub(super) fn node<N, P, D, Ver: StaticVersionType + 'static>(
Expand Down
16 changes: 16 additions & 0 deletions sequencer/src/api/options.rs
Original file line number Diff line number Diff line change
Expand Up @@ -45,6 +45,7 @@ pub struct Options {
pub catchup: Option<Catchup>,
pub state: Option<State>,
pub hotshot_events: Option<HotshotEvents>,
pub explorer: Option<Explorer>,
pub storage_fs: Option<persistence::fs::Options>,
pub storage_sql: Option<persistence::sql::Options>,
}
Expand All @@ -59,6 +60,7 @@ impl From<Http> for Options {
catchup: None,
state: None,
hotshot_events: None,
explorer: None,
storage_fs: None,
storage_sql: None,
}
Expand Down Expand Up @@ -110,6 +112,12 @@ impl Options {
self
}

/// Add an explorer API module.
pub fn explorer(mut self, opt: Explorer) -> Self {
self.explorer = Some(opt);
self
}

/// Whether these options will run the query API.
pub fn has_query_module(&self) -> bool {
self.query.is_some() && (self.storage_fs.is_some() || self.storage_sql.is_some())
Expand Down Expand Up @@ -335,6 +343,10 @@ impl Options {
.init_app_modules(ds, state.clone(), tasks, bind_version)
.await?;

if self.explorer.is_some() {
app.register_module("explorer", endpoints::explorer(bind_version)?)?;
}

if self.state.is_some() {
// Initialize merklized state module for block merkle tree
app.register_module(
Expand Down Expand Up @@ -487,3 +499,7 @@ pub struct HotshotEvents {
#[clap(long, env = "ESPRESSO_SEQUENCER_HOTSHOT_EVENT_STREAMING_API_PORT")]
pub events_service_port: u16,
}

/// Options for the explorer API module.
#[derive(Parser, Clone, Copy, Debug, Default)]
pub struct Explorer;
45 changes: 42 additions & 3 deletions sequencer/src/header.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3,13 +3,13 @@ use crate::{
chain_config::ResolvableChainConfig,
eth_signature_key::BuilderSignature,
l1_client::L1Snapshot,
state::{BlockMerkleCommitment, FeeInfo, FeeMerkleCommitment},
ChainConfig, L1BlockInfo, Leaf, NodeState, SeqTypes, ValidatedState,
state::{BlockMerkleCommitment, FeeAccount, FeeAmount, FeeInfo, FeeMerkleCommitment},
ChainConfig, L1BlockInfo, Leaf, NamespaceId, NodeState, SeqTypes, ValidatedState,
};
use anyhow::{ensure, Context};
use ark_serialize::CanonicalSerialize;
use committable::{Commitment, Committable, RawCommitmentBuilder};
use hotshot_query_service::availability::QueryableHeader;
use hotshot_query_service::{availability::QueryableHeader, explorer::ExplorerHeader};
use hotshot_types::{
traits::{
block_contents::{BlockHeader, BlockPayload, BuilderFee},
Expand Down Expand Up @@ -429,6 +429,45 @@ impl QueryableHeader<SeqTypes> for Header {
}
}

impl ExplorerHeader<SeqTypes> for Header {
type BalanceAmount = FeeAmount;
type WalletAddress = FeeAccount;
type ProposerId = FeeAccount;
type NamespaceId = NamespaceId;

fn proposer_id(&self) -> Self::ProposerId {
self.fee_info.account()
}

fn fee_info_account(&self) -> Self::WalletAddress {
self.fee_info.account()
}

fn fee_info_balance(&self) -> Self::BalanceAmount {
self.fee_info.amount()
}

/// reward_balance at the moment is only implemented as a stub, as block
/// rewards have not yet been implemented.
///
/// TODO: update implementation when rewards have been created / supported.
/// Issue: https://github.com/EspressoSystems/espresso-sequencer/issues/1453
fn reward_balance(&self) -> Self::BalanceAmount {
FeeAmount::from(0)
}

fn namespace_ids(&self) -> Vec<Self::NamespaceId> {
let l = self.ns_table.len();
let mut result: Vec<Self::NamespaceId> = Vec::with_capacity(l);
for i in 0..l {
let (ns_id, _) = self.ns_table.get_table_entry(i);
result.push(ns_id);
}

result
}
}

#[cfg(test)]
mod test_headers {
use std::sync::Arc;
Expand Down
3 changes: 3 additions & 0 deletions sequencer/src/main.rs
Original file line number Diff line number Diff line change
Expand Up @@ -111,6 +111,9 @@ where
if let Some(hotshot_events) = modules.hotshot_events {
http_opt = http_opt.hotshot_events(hotshot_events);
}
if let Some(explorer) = modules.explorer {
http_opt = http_opt.explorer(explorer);
}

http_opt
.serve(
Expand Down
9 changes: 9 additions & 0 deletions sequencer/src/options.rs
Original file line number Diff line number Diff line change
Expand Up @@ -282,6 +282,9 @@ impl ModuleArgs {
SequencerModule::HotshotEvents(m) => {
curr = m.add(&mut modules.hotshot_events, &mut provided)?
}
SequencerModule::Explorer(m) => {
curr = m.add(&mut modules.explorer, &mut provided)?
}
}
}

Expand Down Expand Up @@ -315,6 +318,7 @@ module!("status", api::options::Status, requires: "http");
module!("state", api::options::State, requires: "http", "storage-sql");
module!("catchup", api::options::Catchup, requires: "http");
module!("hotshot-events", api::options::HotshotEvents, requires: "http");
module!("explorer", api::options::Explorer, requires: "http", "storage-sql");

#[derive(Clone, Debug, Args)]
struct Module<Options: ModuleInfo> {
Expand Down Expand Up @@ -392,6 +396,10 @@ enum SequencerModule {
///
/// This module requires the http module to be started.
HotshotEvents(Module<api::options::HotshotEvents>),
/// Run the explorer API module.
///
/// This module requires the http and storage-sql modules to be started.
Explorer(Module<api::options::Explorer>),
}

#[derive(Clone, Debug, Default)]
Expand All @@ -405,4 +413,5 @@ pub struct Modules {
pub state: Option<api::options::State>,
pub catchup: Option<api::options::Catchup>,
pub hotshot_events: Option<api::options::HotshotEvents>,
pub explorer: Option<api::options::Explorer>,
}
7 changes: 7 additions & 0 deletions sequencer/src/state.rs
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@ use hotshot::traits::ValidatedState as HotShotState;
use hotshot_query_service::{
availability::{AvailabilityDataSource, LeafQueryData},
data_source::VersionedDataSource,
explorer::MonetaryValue,
merklized_state::{MerklizedState, MerklizedStateHeightPersistence, UpdateStateData},
types::HeightIndexed,
};
Expand Down Expand Up @@ -943,6 +944,12 @@ impl From<u64> for FeeAmount {
}
}

impl From<FeeAmount> for MonetaryValue {
fn from(value: FeeAmount) -> Self {
MonetaryValue::eth(value.0.as_u128() as i128)
}
}

impl CheckedSub for FeeAmount {
fn checked_sub(&self, v: &Self) -> Option<Self> {
self.0.checked_sub(v.0).map(FeeAmount)
Expand Down
8 changes: 8 additions & 0 deletions sequencer/src/transaction.rs
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
use ark_serialize::{CanonicalDeserialize, CanonicalSerialize};
use committable::{Commitment, Committable};
use derive_more::{Display, From, Into};
use hotshot_query_service::explorer::ExplorerTransaction;
use hotshot_types::traits::block_contents::Transaction as HotShotTransaction;
use jf_merkle_tree::namespaced_merkle_tree::{Namespace, Namespaced};
use serde::{Deserialize, Serialize};
Expand Down Expand Up @@ -106,3 +107,10 @@ impl Committable for Transaction {
"TX".into()
}
}

impl ExplorerTransaction for Transaction {
type NamespaceId = NamespaceId;
fn namespace_id(&self) -> Self::NamespaceId {
self.namespace
}
}

0 comments on commit c41c0fd

Please sign in to comment.