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

Move eth mapping creation to a background task #4474

Merged
merged 68 commits into from
Jul 17, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
68 commits
Select commit Hold shift + click to select a range
3f85d8f
Move eth mapping populate to a background task
elmattic Jul 2, 2024
f7651c5
Merge branch 'main' into elmattic/eth-mapping-bg-task
elmattic Jul 3, 2024
dbe49a2
Rename functions
elmattic Jul 3, 2024
9600eb9
Remove todos
elmattic Jul 3, 2024
d851a17
Refactor
elmattic Jul 3, 2024
1136944
Remove commented out code
elmattic Jul 3, 2024
a09f06d
Remove commented out code
elmattic Jul 3, 2024
b9a2cc1
Fix stateless mode
elmattic Jul 3, 2024
12b846b
Merge branch 'main' into elmattic/eth-mapping-bg-task
elmattic Jul 3, 2024
9bdf3db
Disable population task for devnets
elmattic Jul 3, 2024
479ad87
Try fix eth mapping script
elmattic Jul 3, 2024
7d9bd40
Fix indentation
elmattic Jul 3, 2024
c9d478d
Merge branch 'main' into elmattic/eth-mapping-bg-task
elmattic Jul 3, 2024
bc06cf0
Fix eth mapping check
elmattic Jul 3, 2024
e982d49
Fix eth mapping check job
elmattic Jul 4, 2024
f7c4e06
Move task logic into a function
elmattic Jul 4, 2024
19a2607
Try to wait using /readyz endpoint
elmattic Jul 4, 2024
40694eb
Try to use the -f flag
elmattic Jul 4, 2024
6e35a34
Merge branch 'main' into elmattic/eth-mapping-bg-task
elmattic Jul 4, 2024
56d6fdf
Add curl to dockerfile
elmattic Jul 4, 2024
d1d6ea0
Wait for ready in api compare script instead
elmattic Jul 5, 2024
d63e9a3
Merge branch 'main' into elmattic/eth-mapping-bg-task
elmattic Jul 5, 2024
557094d
Merge branch 'main' into elmattic/eth-mapping-bg-task
elmattic Jul 5, 2024
3aaa6a3
Add doc comments
elmattic Jul 5, 2024
e8f6838
Add forest-rpc-ready docker service
elmattic Jul 5, 2024
e7fabb1
Add a build context
elmattic Jul 5, 2024
a86b5b6
Merge branch 'main' into elmattic/eth-mapping-bg-task
elmattic Jul 5, 2024
eceee54
Add curl install step
elmattic Jul 5, 2024
13d5b29
Remove echo
elmattic Jul 5, 2024
3977e79
Try removing -e flag
elmattic Jul 5, 2024
2982638
Change localhost to forest and print verbose response
elmattic Jul 5, 2024
e7fdd1d
Add some timeout
elmattic Jul 5, 2024
d544021
Remove local
elmattic Jul 5, 2024
bdb434a
Test just sleeping
elmattic Jul 5, 2024
a073637
Wait longer
elmattic Jul 5, 2024
b3be302
Fix forest-rpc-ready service
elmattic Jul 8, 2024
0e9f9e3
Merge branch 'main' into elmattic/eth-mapping-bg-task
elmattic Jul 8, 2024
d243542
Add limited number of retries
elmattic Jul 8, 2024
48a2fe8
Add logs for debugging service
elmattic Jul 8, 2024
ade518b
Force curl installation if not present
elmattic Jul 8, 2024
f76b37b
Use regular for loop instead
elmattic Jul 8, 2024
7cee0c7
Try fix for loop
elmattic Jul 8, 2024
71c83b1
Increase timeout
elmattic Jul 8, 2024
1d8c4b7
Test
elmattic Jul 8, 2024
3db9328
Revert changes
elmattic Jul 9, 2024
7be17b4
Update documentation
elmattic Jul 9, 2024
c88cd1c
Fix check readyz test
elmattic Jul 9, 2024
e3e61e0
Merge branch 'main' into elmattic/eth-mapping-bg-task
elmattic Jul 9, 2024
7fc9a0d
Fix lint error and refactor
elmattic Jul 10, 2024
3e1951e
Merge branch 'main' into elmattic/eth-mapping-bg-task
elmattic Jul 10, 2024
8e18d1c
Use const definition for car_db
elmattic Jul 10, 2024
2bfca98
Merge branch 'main' into elmattic/eth-mapping-bg-task
elmattic Jul 10, 2024
1180327
Merge branch 'main' into elmattic/eth-mapping-bg-task
elmattic Jul 11, 2024
1c292f5
Merge branch 'main' into elmattic/eth-mapping-bg-task
elmattic Jul 12, 2024
0eb6274
Implement healthcheck ready subcommand
elmattic Jul 12, 2024
9ab1cb1
Merge branch 'main' into elmattic/eth-mapping-bg-task
elmattic Jul 12, 2024
eba6b74
Make use of healthcheck subcommand
elmattic Jul 12, 2024
8eb5435
Try fix forest-rpc-ready service
elmattic Jul 12, 2024
7d66095
Merge branch 'main' into elmattic/eth-mapping-bg-task
elmattic Jul 15, 2024
815323c
Update CHANGELOG
elmattic Jul 15, 2024
3d192c6
Move methods to an extension trait
elmattic Jul 15, 2024
33dcc1f
Merge branch 'main' into elmattic/eth-mapping-bg-task
elmattic Jul 16, 2024
ce70b02
Merge branch 'main' into elmattic/eth-mapping-bg-task
elmattic Jul 17, 2024
17b2a3a
Swap heights for clarity
elmattic Jul 17, 2024
7f37281
Wait using healthcheck ready subcommand
elmattic Jul 17, 2024
5107f52
Merge branch 'main' into elmattic/eth-mapping-bg-task
elmattic Jul 17, 2024
b668ce3
Merge branch 'main' into elmattic/eth-mapping-bg-task
elmattic Jul 17, 2024
b781554
Fix bad merge
elmattic Jul 17, 2024
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
3 changes: 3 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -48,6 +48,9 @@
- [#4511](https://github.com/ChainSafe/forest/pull/4511) Add support for the
`Filecoin.EthMaxPriorityFeePerGas` RPC method.

- [#4474](https://github.com/ChainSafe/forest/pull/4474) Add new subcommand
`forest-cli healthcheck ready`.

### Changed

### Removed
Expand Down
9 changes: 6 additions & 3 deletions documentation/src/healthcheck.md
Original file line number Diff line number Diff line change
Expand Up @@ -53,8 +53,9 @@ accept traffic. In our case, we require:
- The node is in sync with the network
- The current epoch of the node is not too far behind the network
- The RPC server is running
- The Ethereum mapping is up to date

If any of these conditions are not met, the nod is **not** ready to serve
If any of these conditions are not met, the node is **not** ready to serve
requests.

Sample _ready_ response:
Expand All @@ -63,7 +64,8 @@ Sample _ready_ response:
❯ curl "http://127.0.0.1:2346/readyz?verbose"
[+] sync complete
[+] epoch up to date
[+] rpc server running⏎
[+] rpc server running
[+] eth mapping up to date⏎
```

Sample _not ready_ response:
Expand All @@ -72,7 +74,8 @@ Sample _not ready_ response:
❯ curl "http://127.0.0.1:2346/readyz?verbose"
[!] sync incomplete
[!] epoch outdated
[+] rpc server running⏎
[+] rpc server running
[!] no eth mapping⏎
```

### `/healthz`
Expand Down
1 change: 1 addition & 0 deletions scripts/tests/api_compare/.env
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ FIL_PROOFS_PARAMETER_CACHE=/var/tmp/filecoin-proof-parameters
LOTUS_RPC_PORT=1234
FOREST_RPC_PORT=2345
FOREST_OFFLINE_RPC_PORT=3456
FOREST_HEALTHZ_RPC_PORT=2346
CHAIN=calibnet

# This is a pre-generated miner generated from Lotus
Expand Down
23 changes: 23 additions & 0 deletions scripts/tests/api_compare/docker-compose.yml
Original file line number Diff line number Diff line change
Expand Up @@ -52,6 +52,7 @@ services:

forest --chain ${CHAIN} --encrypt-keystore false --no-gc \
--rpc-address 0.0.0.0:${FOREST_RPC_PORT} \
--healthcheck-address 0.0.0.0:${FOREST_HEALTHZ_RPC_PORT} \
--height=-50 \
--import-snapshot $(ls /data/*.car.zst | tail -n 1)
healthcheck:
Expand All @@ -60,6 +61,26 @@ services:
timeout: 10m
retries: 3
start_period: 10m
forest-rpc-ready:
elmattic marked this conversation as resolved.
Show resolved Hide resolved
depends_on:
forest:
condition: service_healthy
build:
context: ../../../.
dockerfile: ${FOREST_DOCKERFILE_OVERRIDE:-Dockerfile}
volumes:
- node-data:/data
networks:
- api-tests
entrypoint: [ "/bin/bash", "-c" ]
user: 0:0
command:
- |
set -euo pipefail

export FULLNODE_API_INFO="$(cat /data/forest-token):/dns/forest/tcp/${FOREST_RPC_PORT}/http"
echo "Waiting till Forest is ready"
forest-cli healthcheck ready --healthcheck-port ${FOREST_HEALTHZ_RPC_PORT} --wait
forest-wallet-import:
depends_on:
forest:
Expand Down Expand Up @@ -165,6 +186,8 @@ services:
condition: service_healthy
forest-wallet-import:
condition: service_completed_successfully
forest-rpc-ready:
condition: service_completed_successfully
build:
context: ../../../.
dockerfile: ${FOREST_DOCKERFILE_OVERRIDE:-Dockerfile}
Expand Down
5 changes: 5 additions & 0 deletions scripts/tests/calibnet_eth_mapping_check.sh
Original file line number Diff line number Diff line change
Expand Up @@ -44,6 +44,11 @@ for ((i=0; i<=NUM_TIPSETS; i++)); do
EPOCH=$((EPOCH - 1))
done

echo "Done"

echo "Waiting eth mapping to be up to date"
$FOREST_CLI_PATH healthcheck ready --wait

ERROR=0
echo "Testing Ethereum mapping"

Expand Down
4 changes: 4 additions & 0 deletions src/chain/store/chain_store.rs
Original file line number Diff line number Diff line change
Expand Up @@ -380,6 +380,10 @@ where
Ok((lbts, *next_ts.parent_state()))
}

pub fn settings(&self) -> Arc<dyn SettingsStore + Sync + Send> {
self.settings.clone()
}

/// Filter [`SignedMessage`]'s to keep only the most recent ones, then write corresponding entries to the Ethereum mapping.
pub fn process_signed_messages(&self, messages: &[(SignedMessage, u64)]) -> anyhow::Result<()>
where
Expand Down
1 change: 1 addition & 0 deletions src/cli/main.rs
Original file line number Diff line number Diff line change
Expand Up @@ -47,6 +47,7 @@ where
Subcommand::Snapshot(cmd) => cmd.run(client).await,
Subcommand::Attach { .. } => bail!("the `attach` subcommand has been removed. Please raise an issue if this breaks a workflow for you"),
Subcommand::Shutdown(cmd) => cmd.run(client).await,
Subcommand::Healthcheck(cmd) => cmd.run(client).await,
}
})
}
72 changes: 72 additions & 0 deletions src/cli/subcommands/healthcheck_cmd.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,72 @@
// Copyright 2019-2024 ChainSafe Systems
// SPDX-License-Identifier: Apache-2.0, MIT

use std::{
io::{stdout, Write},
time::Duration,
};

use crate::health::DEFAULT_HEALTHCHECK_PORT;
use crate::rpc;
use clap::Subcommand;
use http::StatusCode;
use ticker::Ticker;

#[derive(Debug, Subcommand)]
pub enum HealthcheckCommand {
/// Display ready status
Ready {
/// Don't exit until node is ready
#[arg(long)]
wait: bool,
/// Healthcheck port
#[arg(long, default_value_t=DEFAULT_HEALTHCHECK_PORT)]
healthcheck_port: u16,
},
}

impl HealthcheckCommand {
pub async fn run(self, client: rpc::Client) -> anyhow::Result<()> {
match self {
Self::Ready {
wait,
healthcheck_port,
} => {
let ticker = Ticker::new(0.., Duration::from_secs(1));
let mut stdout = stdout();

let url = format!(
"http://{}:{}/readyz?verbose",
client.base_url().host_str().unwrap_or("localhost"),
healthcheck_port,
);

for _ in ticker {
let response = reqwest::get(&url).await?;
let status = response.status();
let text = response.text().await?;

println!("{}", text);

if !wait {
break;
}
if status == StatusCode::OK {
println!("Done!");
break;
}

for _ in 0..(text.matches('\n').count() + 1) {
write!(
stdout,
"\r{}{}",
anes::MoveCursorUp(1),
anes::ClearLine::All,
)?;
}
}
Ok(())
}
}
}
}
11 changes: 8 additions & 3 deletions src/cli/subcommands/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@
mod auth_cmd;
mod chain_cmd;
mod config_cmd;
mod healthcheck_cmd;
mod info_cmd;
mod mpool_cmd;
mod net_cmd;
Expand All @@ -29,9 +30,9 @@ use tracing::error;

pub(super) use self::{
auth_cmd::AuthCommands, chain_cmd::ChainCommands, config_cmd::ConfigCommands,
mpool_cmd::MpoolCommands, net_cmd::NetCommands, send_cmd::SendCommand,
shutdown_cmd::ShutdownCommand, snapshot_cmd::SnapshotCommands, state_cmd::StateCommands,
sync_cmd::SyncCommands,
healthcheck_cmd::HealthcheckCommand, mpool_cmd::MpoolCommands, net_cmd::NetCommands,
send_cmd::SendCommand, shutdown_cmd::ShutdownCommand, snapshot_cmd::SnapshotCommands,
state_cmd::StateCommands, sync_cmd::SyncCommands,
};
use crate::cli::subcommands::info_cmd::InfoCommand;

Expand Down Expand Up @@ -94,6 +95,10 @@ pub enum Subcommand {

/// Shutdown Forest
Shutdown(ShutdownCommand),

/// Print healthcheck info
#[command(subcommand)]
Healthcheck(HealthcheckCommand),
}

/// Format a vector to a prettified string
Expand Down
10 changes: 10 additions & 0 deletions src/cli_shared/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,8 @@ pub mod cli;
pub mod logger;

use crate::cli_shared::cli::{find_config_path, Config, ConfigPath};
use crate::db::db_engine::db_root;
use crate::db::CAR_DB_DIR_NAME;
use crate::networks::NetworkChain;
use crate::utils::io::read_toml;
use std::path::PathBuf;
Expand All @@ -19,6 +21,14 @@ pub fn chain_path(config: &Config) -> PathBuf {
PathBuf::from(&config.client.data_dir).join(config.chain.to_string())
}

/// Gets car db path
pub fn car_db_path(config: &Config) -> anyhow::Result<PathBuf> {
let chain_data_path = chain_path(config);
let db_root_dir = db_root(&chain_data_path)?;
let forest_car_db_dir = db_root_dir.join(CAR_DB_DIR_NAME);
Ok(forest_car_db_dir)
}

pub fn read_config(
config_path_opt: Option<&PathBuf>,
chain_opt: Option<NetworkChain>,
Expand Down
9 changes: 7 additions & 2 deletions src/daemon/db_util.rs
Original file line number Diff line number Diff line change
Expand Up @@ -168,15 +168,20 @@ where
{
let mut delegated_messages = vec![];

info!("Populating column EthMappings");
let hygge = state_manager.chain_config().epoch(Height::Hygge);
tracing::info!(
"Populating column EthMappings from range: [{}, {}]",
elmattic marked this conversation as resolved.
Show resolved Hide resolved
hygge,
head_ts.epoch()
);

for ts in head_ts
.clone()
.chain(&state_manager.chain_store().blockstore())
{
// Hygge is the start of Ethereum support in the FVM (through the FEVM actor).
// Before this height, no notion of an Ethereum-like API existed.
if ts.epoch() < state_manager.chain_config().epoch(Height::Hygge) {
if ts.epoch() < hygge {
break;
}
delegated_messages.append(
Expand Down
50 changes: 45 additions & 5 deletions src/daemon/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ use crate::auth::{create_token, generate_priv_key, ADMIN, JWT_IDENTIFIER};
use crate::blocks::Tipset;
use crate::chain::ChainStore;
use crate::chain_sync::ChainMuxer;
use crate::cli_shared::snapshot;
use crate::cli_shared::{car_db_path, snapshot};
use crate::cli_shared::{
chain_path,
cli::{CliOpts, Config},
Expand All @@ -20,7 +20,7 @@ use crate::daemon::db_util::{
};
use crate::db::car::ManyCar;
use crate::db::db_engine::{db_root, open_db};
use crate::db::{ttl::EthMappingCollector, MarkAndSweep};
use crate::db::{ttl::EthMappingCollector, MarkAndSweep, MemoryDB, SettingsExt, CAR_DB_DIR_NAME};
use crate::genesis::{get_network_name_from_genesis, read_genesis_header};
use crate::key_management::{
KeyStore, KeyStoreConfig, ENCRYPTED_KEYSTORE_NAME, FOREST_KEYSTORE_PHRASE_ENV,
Expand All @@ -43,6 +43,7 @@ use bundle::load_actor_bundles;
use dialoguer::console::Term;
use dialoguer::theme::ColorfulTheme;
use futures::{select, Future, FutureExt};
use fvm_ipld_blockstore::Blockstore;
use once_cell::sync::Lazy;
use raw_sync_2::events::{Event, EventInit as _, EventState};
use shared_memory::ShmemConf;
Expand Down Expand Up @@ -181,7 +182,7 @@ pub(super) async fn start(
let db_root_dir = db_root(&chain_data_path)?;
let db_writer = Arc::new(open_db(db_root_dir.clone(), config.db_config().clone())?);
let db = Arc::new(ManyCar::new(db_writer.clone()));
let forest_car_db_dir = db_root_dir.join("car_db");
let forest_car_db_dir = db_root_dir.join(CAR_DB_DIR_NAME);
load_all_forest_cars(&db, &forest_car_db_dir)?;

if config.client.load_actors && !opts.stateless {
Expand Down Expand Up @@ -368,6 +369,7 @@ pub(super) async fn start(
genesis_timestamp: genesis_header.timestamp,
sync_state: sync_state.clone(),
peer_manager,
settings_store: chain_store.settings(),
};

let listener =
Expand Down Expand Up @@ -453,8 +455,6 @@ pub(super) async fn start(
state_manager
.chain_store()
.set_heaviest_tipset(Arc::new(ts.clone()))?;

populate_eth_mappings(&state_manager, &ts)?;
}
}

Expand Down Expand Up @@ -483,6 +483,17 @@ pub(super) async fn start(
return Ok(());
}

// Populate task
if !opts.stateless && !chain_config.is_devnet() {
let state_manager = Arc::clone(&state_manager);
services.spawn(async move {
if let Err(err) = init_ethereum_mapping(state_manager, &config) {
tracing::warn!("Init Ethereum mapping failed: {}", err)
}
Ok(())
});
}

if !opts.stateless {
ensure_params_downloaded().await?;
}
Expand Down Expand Up @@ -758,3 +769,32 @@ fn display_chain_logo(chain: &NetworkChain) {
info!("\n{logo}");
}
}

fn init_ethereum_mapping<DB: Blockstore>(
state_manager: Arc<StateManager<DB>>,
config: &Config,
) -> anyhow::Result<()> {
match state_manager
.chain_store()
.settings()
.eth_mapping_up_to_date()?
{
Some(false) | None => {
let car_db_path = car_db_path(config)?;
let db: Arc<ManyCar<MemoryDB>> = Arc::default();
load_all_forest_cars(&db, &car_db_path)?;
let ts = db.heaviest_tipset()?;

populate_eth_mappings(&state_manager, &ts)?;

state_manager
.chain_store()
.settings()
.set_eth_mapping_up_to_date()
}
Some(true) => {
tracing::info!("Ethereum mapping up to date");
Ok(())
}
}
}
Loading
Loading