Skip to content
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
34 changes: 32 additions & 2 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ The format is loosely based on [Keep a Changelog](https://keepachangelog.com/en/
## [Unreleased]

### Added
- Node RPC: new method added - `chainstate_tokens_info`, `chainstate_orders_info_by_currencies`.
- Node RPC: new methods added - `chainstate_tokens_info`, `chainstate_orders_info_by_currencies`.

- Wallet RPC:
- new methods added: `node_get_tokens_info`, `order_list_own`, `order_list_all_active`.
Expand All @@ -30,6 +30,17 @@ The format is loosely based on [Keep a Changelog](https://keepachangelog.com/en/
- Now the wallet subscribes to events from the Mempool to include not yet confirmed transactions
relevant to this wallet.

- Node:
- new options added:
- `node-daemon`:
- `--import-bootstrap-file` - import a bootstrap file on start (previously bootstrapping
was only available via node RPC).

`node-daemon` and `node-gui`:
- `--enable-db-reckless-mode-in-ibd` - this enables the "reckless" mode of the chainstate
database during initial block download or bootstrapping, which significantly increases
its speed at the cost of a potential db corruption if the system crashes in the meantime.

### Changed
- Wallet RPC:
- `wallet_info`: the structure of the returned field `extra_info` was changed.
Expand All @@ -48,8 +59,16 @@ The format is loosely based on [Keep a Changelog](https://keepachangelog.com/en/
- Documentation-only changes:
- Certain parameters that were designated as "string" are now designated as "bech32 string".

- Node:
- The now redundant option `min_max_bootstrap_import_buffer_sizes` was removed from chainstate config.
- The option `--clean-data` is now a top-level option, i.e. instead of writing
`node-daemon testnet --clean-data` you have to write `node-daemon --clean-data testnet`.

- Node bootstrapping:
- The format of the bootstrap file was changed and the legacy format is no longer supported.

### Fixed
- p2p: when a peer sends a message that can't be decoded, it will now be discouraged (which is what
- P2p: when a peer sends a message that can't be decoded, it will now be discouraged (which is what
is normally done for misbehaving peers) and the node won't try connecting to it again.\
Also, the peer will be sent an appropriate `WillDisconnect` message prior to disconnection.

Expand All @@ -66,6 +85,17 @@ The format is loosely based on [Keep a Changelog](https://keepachangelog.com/en/
- Parameters and/or returned values having the "plain" `Destination` type were incorrectly
designated as "bech32 string", while in reality they are "hexified destination".

- Node bootstrapping:
- Fixed a bug where importing a bootstrap file would truncate the file to zero length
instead of actually importing it.

- Importing a bootstrap file will no longer fail if some of the blocks already exist in the
chainstate.

- Bootstrapping can now be interrupted via Ctrl-C.

- The speed of the import was improved.

- General
- Fixed a bug that could lead to indefinite stalling of the node during initial sync when there
are many peers and the host machine is slow.
Expand Down
10 changes: 8 additions & 2 deletions Cargo.lock

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

3 changes: 2 additions & 1 deletion blockprod/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -272,8 +272,8 @@ mod tests {
enable_heavy_checks: Some(false),

max_db_commit_attempts: Default::default(),
enable_db_reckless_mode_in_ibd: Default::default(),
max_orphan_blocks: Default::default(),
min_max_bootstrap_import_buffer_sizes: Default::default(),
allow_checkpoints_mismatch: Default::default(),
};

Expand All @@ -286,6 +286,7 @@ mod tests {
DefaultTransactionVerificationStrategy::new(),
None,
time_getter.clone(),
None,
)
.expect("Error initializing chainstate");

Expand Down
3 changes: 2 additions & 1 deletion chainstate/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ rust-version.workspace = true

[dependencies]
accounting = { path = "../accounting" }
chainstate-storage = { path = "./storage", features = ["mock"] }
chainstate-storage = { path = "./storage", features = ["lmdb", "mock"] }
chainstate-types = { path = "./types" }
common = { path = "../common" }
consensus = { path = "../consensus" }
Expand Down Expand Up @@ -40,6 +40,7 @@ parity-scale-codec.workspace = true
serde = { workspace = true, features = ["derive"] }
serde_json.workspace = true
static_assertions.workspace = true
strum.workspace = true
thiserror.workspace = true
tokio.workspace = true
tracing.workspace = true
Expand Down
1 change: 1 addition & 0 deletions chainstate/db-dumper/src/dumper_lib/utils.rs
Original file line number Diff line number Diff line change
Expand Up @@ -80,6 +80,7 @@ pub fn create_chainstate(
DefaultTransactionVerificationStrategy::new(),
None,
Default::default(),
None,
)?;

Ok(chainstate)
Expand Down
2 changes: 2 additions & 0 deletions chainstate/launcher/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -15,3 +15,5 @@ storage-inmemory = { path = "../../storage/inmemory" }
storage-lmdb = { path = "../../storage/lmdb" }
subsystem = { path = "../../subsystem" }
utils = { path = "../../utils" }

tokio.workspace = true
139 changes: 95 additions & 44 deletions chainstate/launcher/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -20,9 +20,12 @@ mod storage_compatibility;

use std::sync::Arc;

use tokio::sync::watch;

use chainstate::InitializationError;
use chainstate_storage::Transactional;
use chainstate_storage::{BlockchainStorage, BlockchainStorageBackend, Transactional};
use storage_lmdb::resize_callback::MapResizeCallback;
use utils::set_flag::SetFlag;

// Some useful reexports
pub use chainstate::{
Expand All @@ -32,68 +35,116 @@ pub use chainstate::{
pub use common::chain::ChainConfig;
pub use config::{ChainstateLauncherConfig, StorageBackendConfig};

pub use storage_compatibility::check_storage_compatibility;

/// Subdirectory under `datadir` where LMDB chainstate database is placed
pub const SUBDIRECTORY_LMDB: &str = "chainstate-lmdb";

pub use storage_compatibility::check_storage_compatibility;
pub type ChainstateMaker = Box<
dyn FnOnce(
/*shutdown_initiated_rx*/ Option<watch::Receiver<SetFlag>>,
) -> Result<ChainstateSubsystem, Error>
+ Send,
>;

fn make_chainstate_and_storage_impl<B: storage::SharedBackend + 'static>(
storage_backend: B,
/// Return a closure that will make the chainstate given the `shutdown_initiated_rx` parameter.
///
/// Note: the storage is created right away, so the corresponding errors (including compatibility
/// check failures) will cause `create_chainstate_maker` itself to fail and not the returned maker.
pub fn create_chainstate_maker(
datadir: &std::path::Path,
chain_config: Arc<ChainConfig>,
chainstate_config: ChainstateConfig,
) -> Result<ChainstateSubsystem, Error> {
let storage = chainstate_storage::Store::new(storage_backend, &chain_config)
.map_err(|e| Error::FailedToInitializeChainstate(e.into()))?;
config: ChainstateLauncherConfig,
) -> Result<ChainstateMaker, Error> {
let ChainstateLauncherConfig {
storage_backend,
chainstate_config,
} = config;

let db_tx = storage
.transaction_ro()
.map_err(|e| Error::FailedToInitializeChainstate(e.into()))?;
let maker: ChainstateMaker = match storage_backend {
StorageBackendConfig::Lmdb => {
let storage = create_lmdb_storage(datadir, &chain_config)?;

check_storage_compatibility(&db_tx, chain_config.as_ref())
.map_err(InitializationError::StorageCompatibilityCheckError)?;
drop(db_tx);
Box::new(|shutdown_initiated_rx| {
make_chainstate_impl(
storage,
chain_config,
chainstate_config,
shutdown_initiated_rx,
)
})
}
StorageBackendConfig::InMemory => {
let storage = create_inmemory_storage(&chain_config)?;

Box::new(|shutdown_initiated_rx| {
make_chainstate_impl(
storage,
chain_config,
chainstate_config,
shutdown_initiated_rx,
)
})
}
};

Ok(maker)
}

let chainstate = chainstate::make_chainstate(
fn make_chainstate_impl(
storage: impl BlockchainStorage + Sync + 'static,
chain_config: Arc<ChainConfig>,
chainstate_config: ChainstateConfig,
shutdown_initiated_rx: Option<watch::Receiver<SetFlag>>,
) -> Result<ChainstateSubsystem, Error> {
chainstate::make_chainstate(
chain_config,
chainstate_config,
storage,
DefaultTransactionVerificationStrategy::new(),
None,
Default::default(),
)?;
Ok(chainstate)
shutdown_initiated_rx,
)
}

/// Create chainstate together with its storage
pub fn make_chainstate(
fn create_lmdb_storage(
datadir: &std::path::Path,
chain_config: Arc<ChainConfig>,
config: ChainstateLauncherConfig,
) -> Result<ChainstateSubsystem, Error> {
let ChainstateLauncherConfig {
storage_backend,
chainstate_config,
} = config;

chain_config: &ChainConfig,
) -> Result<impl BlockchainStorage, Error> {
let lmdb_resize_callback = MapResizeCallback::new(Box::new(|resize_info| {
logging::log::info!("Lmdb resize happened: {:?}", resize_info)
}));

// There is some code duplication because `make_chainstate_and_storage_impl` is called with
// a different set of generic parameters in each case.
match storage_backend {
StorageBackendConfig::Lmdb => {
let storage = storage_lmdb::Lmdb::new(
datadir.join(SUBDIRECTORY_LMDB),
Default::default(),
Default::default(),
lmdb_resize_callback,
);
make_chainstate_and_storage_impl(storage, chain_config, chainstate_config)
}
StorageBackendConfig::InMemory => {
let storage = storage_inmemory::InMemory::new();
make_chainstate_and_storage_impl(storage, chain_config, chainstate_config)
}
}
let backend = storage_lmdb::Lmdb::new(
datadir.join(SUBDIRECTORY_LMDB),
Default::default(),
Default::default(),
lmdb_resize_callback,
);

create_storage(backend, chain_config)
}

fn create_inmemory_storage(chain_config: &ChainConfig) -> Result<impl BlockchainStorage, Error> {
create_storage(storage_inmemory::InMemory::new(), chain_config)
}

fn create_storage(
storage_backend: impl BlockchainStorageBackend + 'static,
chain_config: &ChainConfig,
) -> Result<impl BlockchainStorage, Error> {
let storage = chainstate_storage::Store::new(storage_backend, chain_config)
.map_err(|e| Error::FailedToInitializeChainstate(e.into()))?;

let db_tx = storage
.transaction_ro()
.map_err(|e| Error::FailedToInitializeChainstate(e.into()))?;

check_storage_compatibility(&db_tx, chain_config)
.map_err(InitializationError::StorageCompatibilityCheckError)?;

drop(db_tx);

Ok(storage)
}
Loading