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 Block Explorer to Demos #1428

Merged
merged 12 commits into from
May 15, 2024
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)
sveitser marked this conversation as resolved.
Show resolved Hide resolved
}

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
}
}
Loading