From 2c807de3b147423cfb063913c9f147b110458c2c Mon Sep 17 00:00:00 2001 From: Niven Date: Tue, 16 Jan 2024 18:34:05 +0800 Subject: [PATCH 01/17] Propagate errors when stopping evm services and http server --- lib/ain-evm/src/lib.rs | 2 + lib/ain-evm/src/services.rs | 21 ++++---- lib/ain-evm/src/storage/block_store.rs | 4 +- lib/ain-grpc/src/lib.rs | 5 +- lib/ain-rs-exports/src/core.rs | 71 +++++++++++++------------- src/init.cpp | 4 +- 6 files changed, 56 insertions(+), 51 deletions(-) diff --git a/lib/ain-evm/src/lib.rs b/lib/ain-evm/src/lib.rs index f1244523e9a..d8a3f3ae0fb 100644 --- a/lib/ain-evm/src/lib.rs +++ b/lib/ain-evm/src/lib.rs @@ -54,6 +54,8 @@ pub enum EVMError { StorageError(String), #[error("EVM: serde_json error")] JsonError(#[from] serde_json::Error), + #[error("EVM: serde_json error")] + JsonRpcError(#[from] jsonrpsee_core::Error), #[error("EVM: rocksdb error")] RocksDBError(#[from] rocksdb::Error), #[error("EVM: ethabi error")] diff --git a/lib/ain-evm/src/services.rs b/lib/ain-evm/src/services.rs index cd7cb2fdafa..3481190322f 100644 --- a/lib/ain-evm/src/services.rs +++ b/lib/ain-evm/src/services.rs @@ -6,7 +6,7 @@ use std::{ thread::{self, JoinHandle}, }; -use anyhow::Result; +use anyhow::{format_err, Result}; use jsonrpsee_server::ServerHandle; use parking_lot::Mutex; use tokio::{ @@ -74,33 +74,34 @@ impl Services { { let json_rpc_handles = self.json_rpc_handles.lock(); for server in &*json_rpc_handles { - server.stop().unwrap(); + server.stop()?; } } { let websocket_handles = self.websocket_handles.lock(); for server in &*websocket_handles { - server.stop().unwrap(); + server.stop()?; } } - - // TODO: Propogate error Ok(()) } - pub fn stop(&self) { + pub fn stop(&self) -> Result<()> { let _ = self.tokio_runtime_channel_tx.blocking_send(()); self.tokio_worker .lock() .take() - .expect("runtime terminated?") + .ok_or(format_err!( + "failed to stop tokio runtime, early termination" + ))? .join() - .unwrap(); + .map_err(|_| format_err!("failed to stop tokio runtime"))?; // Persist EVM State to disk - self.evm.core.flush().expect("Could not flush evm state"); - self.evm.storage.flush().expect("Could not flush storage"); + self.evm.core.flush()?; + self.evm.storage.flush()?; + Ok(()) } } diff --git a/lib/ain-evm/src/storage/block_store.rs b/lib/ain-evm/src/storage/block_store.rs index e2a816015a3..40cc9197a18 100644 --- a/lib/ain-evm/src/storage/block_store.rs +++ b/lib/ain-evm/src/storage/block_store.rs @@ -140,7 +140,7 @@ impl BlockStorage for BlockStore { if let Some(block) = block { let latest_block_cf = self.column::(); let block_number = block.header.number; - latest_block_cf.put(&"latest_block", &block_number)?; + latest_block_cf.put(&"", &block_number)?; } Ok(()) } @@ -228,7 +228,7 @@ impl Rollback for BlockStore { if let Some(block) = self.get_block_by_hash(&block.header.parent_hash)? { let latest_block_cf = self.column::(); - latest_block_cf.put(&"latest_block", &block.header.number)?; + latest_block_cf.put(&"", &block.header.number)?; } let logs_cf = self.column::(); diff --git a/lib/ain-grpc/src/lib.rs b/lib/ain-grpc/src/lib.rs index ec225b15c3d..f45b5e2af3d 100644 --- a/lib/ain-grpc/src/lib.rs +++ b/lib/ain-grpc/src/lib.rs @@ -152,11 +152,12 @@ fn is_services_init_called() -> bool { IS_SERVICES_INIT_CALL.load(Ordering::SeqCst) } -pub fn stop_services() { +pub fn stop_services() -> Result<()> { if is_services_init_called() { info!("Shutdown rs services"); - SERVICES.stop(); + SERVICES.stop()?; } + Ok(()) } pub fn wipe_evm_folder() -> Result<()> { diff --git a/lib/ain-rs-exports/src/core.rs b/lib/ain-rs-exports/src/core.rs index 9b8ebf8ac9e..02d1d34c22c 100644 --- a/lib/ain-rs-exports/src/core.rs +++ b/lib/ain-rs-exports/src/core.rs @@ -1,56 +1,57 @@ -use crate::{ffi::CrossBoundaryResult, prelude::*}; +use crate::{ffi, prelude::*}; +use ain_macros::ffi_fallible; +use anyhow::Result; -pub fn ain_rs_preinit(result: &mut CrossBoundaryResult) { +#[ffi_fallible] +pub fn ain_rs_preinit() -> Result<()> { ain_grpc::preinit(); - cross_boundary_success(result); + Ok(()) } -pub fn ain_rs_init_logging(result: &mut CrossBoundaryResult) { +#[ffi_fallible] +pub fn ain_rs_init_logging() -> Result<()> { ain_grpc::init_logging(); - cross_boundary_success(result); + Ok(()) } -pub fn ain_rs_init_core_services(result: &mut CrossBoundaryResult) { +#[ffi_fallible] +pub fn ain_rs_init_core_services() -> Result<()> { ain_grpc::init_services(); - result.ok = true; + Ok(()) } -pub fn ain_rs_stop_core_services(result: &mut CrossBoundaryResult) { - ain_grpc::stop_services(); - cross_boundary_success(result); +#[ffi_fallible] +pub fn ain_rs_stop_core_services() -> Result<()> { + ain_grpc::stop_services()?; + Ok(()) } -pub fn ain_rs_init_network_json_rpc_service(result: &mut CrossBoundaryResult, addr: String) { - match ain_grpc::init_network_json_rpc_service(addr) { - Ok(()) => cross_boundary_success(result), - Err(e) => cross_boundary_error_return(result, e.to_string()), - } +#[ffi_fallible] +pub fn ain_rs_init_network_json_rpc_service(addr: String) -> Result<()> { + ain_grpc::init_network_json_rpc_service(addr)?; + Ok(()) } -pub fn ain_rs_init_network_grpc_service(result: &mut CrossBoundaryResult, addr: String) { - match ain_grpc::init_network_grpc_service(addr) { - Ok(()) => cross_boundary_success(result), - Err(e) => cross_boundary_error_return(result, e.to_string()), - } +#[ffi_fallible] +pub fn ain_rs_init_network_grpc_service(addr: String) -> Result<()> { + ain_grpc::init_network_grpc_service(addr)?; + Ok(()) } -pub fn ain_rs_init_network_subscriptions_service(result: &mut CrossBoundaryResult, addr: String) { - match ain_grpc::init_network_subscriptions_service(addr) { - Ok(()) => cross_boundary_success(result), - Err(e) => cross_boundary_error_return(result, e.to_string()), - } +#[ffi_fallible] +pub fn ain_rs_init_network_subscriptions_service(addr: String) -> Result<()> { + ain_grpc::init_network_subscriptions_service(addr)?; + Ok(()) } -pub fn ain_rs_stop_network_services(result: &mut CrossBoundaryResult) { - match ain_grpc::stop_network_services() { - Ok(()) => cross_boundary_success(result), - Err(e) => cross_boundary_error_return(result, e.to_string()), - } +#[ffi_fallible] +pub fn ain_rs_stop_network_services() -> Result<()> { + ain_grpc::stop_network_services()?; + Ok(()) } -pub fn ain_rs_wipe_evm_folder(result: &mut CrossBoundaryResult) { - match ain_grpc::wipe_evm_folder() { - Ok(()) => cross_boundary_success(result), - Err(e) => cross_boundary_error_return(result, e.to_string()), - } +#[ffi_fallible] +pub fn ain_rs_wipe_evm_folder() -> Result<()> { + ain_grpc::wipe_evm_folder()?; + Ok(()) } diff --git a/src/init.cpp b/src/init.cpp index 385f4b5d143..5f332fdbc19 100644 --- a/src/init.cpp +++ b/src/init.cpp @@ -226,7 +226,7 @@ void Shutdown(InitInterfaces& interfaces) for (const auto& client : interfaces.chain_clients) { client->flush(); } - XResultStatusLogged(ain_rs_stop_network_services(result)); + auto res = XResultStatusLogged(ain_rs_stop_network_services(result)); StopMapPort(); // Because these depend on each-other, we make sure that neither can be @@ -292,7 +292,7 @@ void Shutdown(InitInterfaces& interfaces) // next startup faster by avoiding rescan. ShutdownDfTxGlobalTaskPool(); - XResultStatusLogged(ain_rs_stop_core_services(result)); + res = XResultStatusLogged(ain_rs_stop_core_services(result)); LogPrint(BCLog::SPV, "Releasing\n"); spv::pspv.reset(); { From 2aab10af0bc61c69c924ff3b3c19d8620285f1b4 Mon Sep 17 00:00:00 2001 From: Niven Date: Tue, 16 Jan 2024 21:27:02 +0800 Subject: [PATCH 02/17] Add dirty flag into init pipeline --- src/init.cpp | 13 ++++++++++++- 1 file changed, 12 insertions(+), 1 deletion(-) diff --git a/src/init.cpp b/src/init.cpp index 5f332fdbc19..f6ae82dc4c4 100644 --- a/src/init.cpp +++ b/src/init.cpp @@ -94,6 +94,8 @@ static const bool DEFAULT_STOPAFTERBLOCKIMPORT = false; // Dump addresses to banlist.dat every 15 minutes (900s) static constexpr int DUMP_BANS_INTERVAL = 60 * 15; +static bool fEvmDatabaseDirty = false; + std::unique_ptr g_connman; std::unique_ptr peerLogic; std::unique_ptr g_banman; @@ -227,6 +229,9 @@ void Shutdown(InitInterfaces& interfaces) client->flush(); } auto res = XResultStatusLogged(ain_rs_stop_network_services(result)); + if (!res) { + fEvmDatabaseDirty = true; + } StopMapPort(); // Because these depend on each-other, we make sure that neither can be @@ -293,6 +298,12 @@ void Shutdown(InitInterfaces& interfaces) ShutdownDfTxGlobalTaskPool(); res = XResultStatusLogged(ain_rs_stop_core_services(result)); + if (!res) { + fEvmDatabaseDirty = true; + } + + // Save evm database dirty flag to disk + LogPrint(BCLog::SPV, "Releasing\n"); spv::pspv.reset(); { @@ -1828,7 +1839,7 @@ bool AppInitMain(InitInterfaces& interfaces) InitDfTxGlobalTaskPool(); bool fLoaded = false; - fReindex = gArgs.GetBoolArg("-reindex", false); + fReindex = gArgs.GetBoolArg("-reindex", fEvmDatabaseDirty); bool fReindexChainState = gArgs.GetBoolArg("-reindex-chainstate", false); while (!fLoaded && !ShutdownRequested()) { bool fReset = fReindex; From 50bb3cb78ae8d21d7337c39d3bfbdca7ba0c08dc Mon Sep 17 00:00:00 2001 From: Niven Date: Tue, 16 Jan 2024 21:31:26 +0800 Subject: [PATCH 03/17] Set evm database dirty flag --- src/init.cpp | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/init.cpp b/src/init.cpp index f6ae82dc4c4..a683c399490 100644 --- a/src/init.cpp +++ b/src/init.cpp @@ -686,6 +686,9 @@ void SetupServerArgs() RPCMetadata::SetupArgs(gArgs); // Add the hidden options gArgs.AddHiddenArgs(hidden_args); + + // Set evm datbase dirty flag + } std::string LicenseInfo() From 2d63446e4827ef5a43360507153eac161578e1d3 Mon Sep 17 00:00:00 2001 From: Niven Date: Wed, 17 Jan 2024 14:05:09 +0800 Subject: [PATCH 04/17] Write evm db dirty flag to leveldb --- src/dfi/masternodes.cpp | 12 +++++++++++ src/dfi/masternodes.h | 8 ++++++- src/init.cpp | 47 +++++++++++++++++++++++------------------ 3 files changed, 45 insertions(+), 22 deletions(-) diff --git a/src/dfi/masternodes.cpp b/src/dfi/masternodes.cpp index 94d86e4dbbf..7b56eedaecf 100644 --- a/src/dfi/masternodes.cpp +++ b/src/dfi/masternodes.cpp @@ -815,6 +815,18 @@ void CCustomCSView::SetDbVersion(int version) { Write(DbVersion::prefix(), version); } +bool CCustomCSView::GetEvmDirtyFlag() const { + bool dirtyFlag; + if (Read(EvmDirtyFlag::prefix(), dirtyFlag)) { + return dirtyFlag; + } + return false; +} + +void CCustomCSView::SetEvmDirtyFlag(bool flag) { + Write(EvmDirtyFlag::prefix(), flag); +} + CTeamView::CTeam CCustomCSView::CalcNextTeam(int height, const uint256 &stakeModifier) { if (stakeModifier == uint256()) { return Params().GetGenesisTeam(); diff --git a/src/dfi/masternodes.h b/src/dfi/masternodes.h index 6d2b5733729..c72809d94c7 100644 --- a/src/dfi/masternodes.h +++ b/src/dfi/masternodes.h @@ -605,9 +605,11 @@ class CCustomCSView : public CMasternodesView, const DCT_ID &id) const override; void SetDbVersion(int version); - int GetDbVersion() const; + void SetEvmDirtyFlag(bool flag); + bool GetEvmDirtyFlag() const; + uint256 MerkleRoot(); virtual CHistoryWriters &GetHistoryWriters() { return writers; } @@ -624,6 +626,10 @@ class CCustomCSView : public CMasternodesView, struct DbVersion { static constexpr uint8_t prefix() { return 'D'; } }; + + struct EvmDirtyFlag { + static constexpr uint8_t prefix() { return 'p'; } + }; }; std::map AmISignerNow(int height, const CAnchorData::CTeam &team); diff --git a/src/init.cpp b/src/init.cpp index a683c399490..32435f1eb00 100644 --- a/src/init.cpp +++ b/src/init.cpp @@ -228,10 +228,7 @@ void Shutdown(InitInterfaces& interfaces) for (const auto& client : interfaces.chain_clients) { client->flush(); } - auto res = XResultStatusLogged(ain_rs_stop_network_services(result)); - if (!res) { - fEvmDatabaseDirty = true; - } + XResultStatusLogged(ain_rs_stop_network_services(result)); StopMapPort(); // Because these depend on each-other, we make sure that neither can be @@ -297,12 +294,11 @@ void Shutdown(InitInterfaces& interfaces) // next startup faster by avoiding rescan. ShutdownDfTxGlobalTaskPool(); - res = XResultStatusLogged(ain_rs_stop_core_services(result)); + auto res = XResultStatusLogged(ain_rs_stop_core_services(result)); if (!res) { fEvmDatabaseDirty = true; } - - // Save evm database dirty flag to disk + pcustomcsview->SetEvmDirtyFlag(fEvmDatabaseDirty); LogPrint(BCLog::SPV, "Releasing\n"); spv::pspv.reset(); @@ -686,9 +682,6 @@ void SetupServerArgs() RPCMetadata::SetupArgs(gArgs); // Add the hidden options gArgs.AddHiddenArgs(hidden_args); - - // Set evm datbase dirty flag - } std::string LicenseInfo() @@ -1842,10 +1835,10 @@ bool AppInitMain(InitInterfaces& interfaces) InitDfTxGlobalTaskPool(); bool fLoaded = false; - fReindex = gArgs.GetBoolArg("-reindex", fEvmDatabaseDirty); + fReindex = gArgs.GetBoolArg("-reindex", false); bool fReindexChainState = gArgs.GetBoolArg("-reindex-chainstate", false); while (!fLoaded && !ShutdownRequested()) { - bool fReset = fReindex; + bool fReset = (fReindex || fEvmDatabaseDirty); std::string strLoadError; uiInterface.InitMessage(_("Loading block index...").translated); @@ -1935,6 +1928,13 @@ bool AppInitMain(InitInterfaces& interfaces) // Ensure we are on latest DB version pcustomcsview->SetDbVersion(CCustomCSView::DbVersion); + // Set evm database dirty flag + fEvmDatabaseDirty = pcustomcsview->GetEvmDirtyFlag(); + if (!fReset && fEvmDatabaseDirty) { + LogPrintf("Evm database dirty, re-indexing chain state.\n"); + break; + } + // make account history db paccountHistoryDB.reset(); if (gArgs.GetBoolArg("-acindex", DEFAULT_ACINDEX)) { @@ -2063,18 +2063,23 @@ bool AppInitMain(InitInterfaces& interfaces) } while(false); if (!fLoaded && !ShutdownRequested()) { - // first suggest a reindex if (!fReset) { - bool fRet = uiInterface.ThreadSafeQuestion( - strLoadError + ".\n\n" + _("Do you want to rebuild the block database now?").translated, - strLoadError + ".\nPlease restart with -reindex or -reindex-chainstate to recover.", - "", CClientUIInterface::MSG_ERROR | CClientUIInterface::BTN_ABORT); - if (fRet) { - fReindex = true; + if (fEvmDatabaseDirty) { + // Evm database dirty. Abort shutdown and run re-index pipeline. AbortShutdown(); } else { - LogPrintf("Aborted block database rebuild. Exiting.\n"); - return false; + // first suggest a reindex + bool fRet = uiInterface.ThreadSafeQuestion( + strLoadError + ".\n\n" + _("Do you want to rebuild the block database now?").translated, + strLoadError + ".\nPlease restart with -reindex or -reindex-chainstate to recover.", + "", CClientUIInterface::MSG_ERROR | CClientUIInterface::BTN_ABORT); + if (fRet) { + fReindex = true; + AbortShutdown(); + } else { + LogPrintf("Aborted block database rebuild. Exiting.\n"); + return false; + } } } else { return InitError(strLoadError); From 6343fccf0c208b5aa16b5cb7810625c5d3fa3e28 Mon Sep 17 00:00:00 2001 From: Niven Date: Wed, 17 Jan 2024 22:06:51 +0800 Subject: [PATCH 05/17] Add explicit flush on every commit block --- lib/ain-evm/src/evm.rs | 38 +++++++++++++++++++------------------- 1 file changed, 19 insertions(+), 19 deletions(-) diff --git a/lib/ain-evm/src/evm.rs b/lib/ain-evm/src/evm.rs index e64c579fd4c..b0c0623819e 100644 --- a/lib/ain-evm/src/evm.rs +++ b/lib/ain-evm/src/evm.rs @@ -252,27 +252,27 @@ impl EVMServices { /// across all usages. Note: To be replaced with a proper lock flow later. /// pub unsafe fn commit_block(&self, template: &BlockTemplate) -> Result<()> { - { - let Some(BlockData { block, receipts }) = template.block_data.clone() else { - return Err(format_err!("no constructed EVM block exist in template id").into()); - }; - - debug!( - "[finalize_block] Finalizing block number {:#x}, state_root {:#x}", - block.header.number, block.header.state_root - ); + let Some(BlockData { block, receipts }) = template.block_data.clone() else { + return Err(format_err!("no constructed EVM block exist in template id").into()); + }; - self.block.connect_block(&block)?; - self.logs - .generate_logs_from_receipts(&receipts, block.header.number)?; - self.receipt.put_receipts(receipts)?; - self.channel - .sender - .send(Notification::Block(block.header.hash())) - .map_err(|e| format_err!(e.to_string()))?; - } - self.core.clear_account_nonce(); + debug!( + "[finalize_block] Finalizing block number {:#x}, state_root {:#x}", + block.header.number, block.header.state_root + ); + self.block.connect_block(&block)?; + self.logs + .generate_logs_from_receipts(&receipts, block.header.number)?; + self.receipt.put_receipts(receipts)?; + self.channel + .sender + .send(Notification::Block(block.header.hash())) + .map_err(|e| format_err!(e.to_string()))?; + + self.core.clear_account_nonce(); + self.core.flush()?; + self.storage.flush()?; Ok(()) } From 5e4bc82073b953eb38ecd19f6dc506d4bee07c0a Mon Sep 17 00:00:00 2001 From: Niven Date: Wed, 17 Jan 2024 22:09:23 +0800 Subject: [PATCH 06/17] Add flush on disconnect block pipeline --- lib/ain-evm/src/storage/mod.rs | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/lib/ain-evm/src/storage/mod.rs b/lib/ain-evm/src/storage/mod.rs index 00f5eda18dc..b01ad8dcde8 100644 --- a/lib/ain-evm/src/storage/mod.rs +++ b/lib/ain-evm/src/storage/mod.rs @@ -227,6 +227,7 @@ impl Storage { impl Rollback for Storage { fn disconnect_latest_block(&self) -> Result<()> { self.cache.disconnect_latest_block()?; - self.blockstore.disconnect_latest_block() + self.blockstore.disconnect_latest_block()?; + self.flush() } } From e860e3c751828917cf4ab5d908bb6de135da9f4c Mon Sep 17 00:00:00 2001 From: Niven Date: Wed, 17 Jan 2024 22:51:25 +0800 Subject: [PATCH 07/17] Add pipeline to rewind chain to last evm block height --- lib/ain-rs-exports/src/evm.rs | 23 +++++++++++++++++++++++ lib/ain-rs-exports/src/lib.rs | 2 ++ src/init.cpp | 23 +++++++++++++++-------- 3 files changed, 40 insertions(+), 8 deletions(-) diff --git a/lib/ain-rs-exports/src/evm.rs b/lib/ain-rs-exports/src/evm.rs index 46ac52b4785..2fedaccd161 100644 --- a/lib/ain-rs-exports/src/evm.rs +++ b/lib/ain-rs-exports/src/evm.rs @@ -606,6 +606,15 @@ fn evm_try_get_block_number_by_hash(hash: XHash) -> Result { Ok(block_number) } +/// Return the block header for a given blockhash. +/// +/// # Arguments +/// +/// * `hash` - The hash of the block we want to get the block header. +/// +/// # Returns +/// +/// Returns the block header associated with the given blockhash. #[ffi_fallible] fn evm_try_get_block_header_by_hash(hash: XHash) -> Result { let hash = H256::from(hash); @@ -637,6 +646,20 @@ fn evm_try_get_block_header_by_hash(hash: XHash) -> Result Ok(out) } +/// Return the latest block header from storage. +/// +/// # Returns +/// +/// Returns the latest block header. +#[ffi_fallible] +fn evm_try_get_latest_block_hash() -> Result<[u8; 32]> { + let block = SERVICES + .evm + .storage + .get_latest_block()?; + Ok(block.header.hash().to_fixed_bytes()) +} + #[ffi_fallible] fn evm_try_get_tx_by_hash(tx_hash: XHash) -> Result { let tx_hash = H256::from(tx_hash); diff --git a/lib/ain-rs-exports/src/lib.rs b/lib/ain-rs-exports/src/lib.rs index 09a9fd2f236..07ff3ef055e 100644 --- a/lib/ain-rs-exports/src/lib.rs +++ b/lib/ain-rs-exports/src/lib.rs @@ -292,6 +292,8 @@ pub mod ffi { hash: [u8; 32], ) -> EVMBlockHeader; + fn evm_try_get_latest_block_hash(result: &mut CrossBoundaryResult) -> [u8; 32]; + fn evm_try_get_tx_by_hash( result: &mut CrossBoundaryResult, tx_hash: [u8; 32], diff --git a/src/init.cpp b/src/init.cpp index 32435f1eb00..a9b5d8033e0 100644 --- a/src/init.cpp +++ b/src/init.cpp @@ -1838,7 +1838,7 @@ bool AppInitMain(InitInterfaces& interfaces) fReindex = gArgs.GetBoolArg("-reindex", false); bool fReindexChainState = gArgs.GetBoolArg("-reindex-chainstate", false); while (!fLoaded && !ShutdownRequested()) { - bool fReset = (fReindex || fEvmDatabaseDirty); + bool fReset = fReindex; std::string strLoadError; uiInterface.InitMessage(_("Loading block index...").translated); @@ -1928,13 +1928,6 @@ bool AppInitMain(InitInterfaces& interfaces) // Ensure we are on latest DB version pcustomcsview->SetDbVersion(CCustomCSView::DbVersion); - // Set evm database dirty flag - fEvmDatabaseDirty = pcustomcsview->GetEvmDirtyFlag(); - if (!fReset && fEvmDatabaseDirty) { - LogPrintf("Evm database dirty, re-indexing chain state.\n"); - break; - } - // make account history db paccountHistoryDB.reset(); if (gArgs.GetBoolArg("-acindex", DEFAULT_ACINDEX)) { @@ -1973,6 +1966,20 @@ bool AppInitMain(InitInterfaces& interfaces) auto res = XResultStatusLogged(ain_rs_init_core_services(result)); if (!res) return false; + // Set evm database dirty flag + fEvmDatabaseDirty = pcustomcsview->GetEvmDirtyFlag(); + if (fEvmDatabaseDirty) { + LogPrintf("Evm database dirty, rollback chain state to latest EVM block height.\n"); + auto res = XResultValueLogged(evm_try_get_latest_block_hash(result)); + auto lastEvmBlockHash = uint256::FromByteArray(*res).GetHex(); + auto lastDvmBlockHash = pcustomcsview->GetVMDomainBlockEdge(VMDomainEdge::EVMToDVM, lastEvmBlockHash); + if (!lastDvmBlockHash.val.has_value()) { + strLoadError = _("Unable to get DVM block height from latest EVM block height. You will need to rebuild the database using -reindex-chainstate.").translated; + } + CBlockIndex *pindex = LookupBlockIndex(uint256S(*lastDvmBlockHash.val)); + uint64_t lastDvmBlockNumber = pindex->GetBlockHeader().deprecatedHeight; + } + // ReplayBlocks is a no-op if we cleared the coinsviewdb with -reindex or -reindex-chainstate if (!ReplayBlocks(chainparams, &::ChainstateActive().CoinsDB(), pcustomcsview.get())) { strLoadError = _("Unable to replay blocks. You will need to rebuild the database using -reindex-chainstate.").translated; From 85d07d7ca29e5b780764e3da70f30d33aad25aed Mon Sep 17 00:00:00 2001 From: Niven Date: Wed, 17 Jan 2024 23:29:59 +0800 Subject: [PATCH 08/17] Remove dirty flag, add EVM and DVM db block height check in init --- src/dfi/masternodes.cpp | 12 -------- src/dfi/masternodes.h | 8 +----- src/init.cpp | 62 +++++++++++++++++------------------------ 3 files changed, 27 insertions(+), 55 deletions(-) diff --git a/src/dfi/masternodes.cpp b/src/dfi/masternodes.cpp index 7b56eedaecf..94d86e4dbbf 100644 --- a/src/dfi/masternodes.cpp +++ b/src/dfi/masternodes.cpp @@ -815,18 +815,6 @@ void CCustomCSView::SetDbVersion(int version) { Write(DbVersion::prefix(), version); } -bool CCustomCSView::GetEvmDirtyFlag() const { - bool dirtyFlag; - if (Read(EvmDirtyFlag::prefix(), dirtyFlag)) { - return dirtyFlag; - } - return false; -} - -void CCustomCSView::SetEvmDirtyFlag(bool flag) { - Write(EvmDirtyFlag::prefix(), flag); -} - CTeamView::CTeam CCustomCSView::CalcNextTeam(int height, const uint256 &stakeModifier) { if (stakeModifier == uint256()) { return Params().GetGenesisTeam(); diff --git a/src/dfi/masternodes.h b/src/dfi/masternodes.h index c72809d94c7..6d2b5733729 100644 --- a/src/dfi/masternodes.h +++ b/src/dfi/masternodes.h @@ -605,10 +605,8 @@ class CCustomCSView : public CMasternodesView, const DCT_ID &id) const override; void SetDbVersion(int version); - int GetDbVersion() const; - void SetEvmDirtyFlag(bool flag); - bool GetEvmDirtyFlag() const; + int GetDbVersion() const; uint256 MerkleRoot(); @@ -626,10 +624,6 @@ class CCustomCSView : public CMasternodesView, struct DbVersion { static constexpr uint8_t prefix() { return 'D'; } }; - - struct EvmDirtyFlag { - static constexpr uint8_t prefix() { return 'p'; } - }; }; std::map AmISignerNow(int height, const CAnchorData::CTeam &team); diff --git a/src/init.cpp b/src/init.cpp index a9b5d8033e0..48f7e80dad4 100644 --- a/src/init.cpp +++ b/src/init.cpp @@ -94,8 +94,6 @@ static const bool DEFAULT_STOPAFTERBLOCKIMPORT = false; // Dump addresses to banlist.dat every 15 minutes (900s) static constexpr int DUMP_BANS_INTERVAL = 60 * 15; -static bool fEvmDatabaseDirty = false; - std::unique_ptr g_connman; std::unique_ptr peerLogic; std::unique_ptr g_banman; @@ -294,12 +292,7 @@ void Shutdown(InitInterfaces& interfaces) // next startup faster by avoiding rescan. ShutdownDfTxGlobalTaskPool(); - auto res = XResultStatusLogged(ain_rs_stop_core_services(result)); - if (!res) { - fEvmDatabaseDirty = true; - } - pcustomcsview->SetEvmDirtyFlag(fEvmDatabaseDirty); - + XResultStatusLogged(ain_rs_stop_core_services(result)); LogPrint(BCLog::SPV, "Releasing\n"); spv::pspv.reset(); { @@ -1966,20 +1959,6 @@ bool AppInitMain(InitInterfaces& interfaces) auto res = XResultStatusLogged(ain_rs_init_core_services(result)); if (!res) return false; - // Set evm database dirty flag - fEvmDatabaseDirty = pcustomcsview->GetEvmDirtyFlag(); - if (fEvmDatabaseDirty) { - LogPrintf("Evm database dirty, rollback chain state to latest EVM block height.\n"); - auto res = XResultValueLogged(evm_try_get_latest_block_hash(result)); - auto lastEvmBlockHash = uint256::FromByteArray(*res).GetHex(); - auto lastDvmBlockHash = pcustomcsview->GetVMDomainBlockEdge(VMDomainEdge::EVMToDVM, lastEvmBlockHash); - if (!lastDvmBlockHash.val.has_value()) { - strLoadError = _("Unable to get DVM block height from latest EVM block height. You will need to rebuild the database using -reindex-chainstate.").translated; - } - CBlockIndex *pindex = LookupBlockIndex(uint256S(*lastDvmBlockHash.val)); - uint64_t lastDvmBlockNumber = pindex->GetBlockHeader().deprecatedHeight; - } - // ReplayBlocks is a no-op if we cleared the coinsviewdb with -reindex or -reindex-chainstate if (!ReplayBlocks(chainparams, &::ChainstateActive().CoinsDB(), pcustomcsview.get())) { strLoadError = _("Unable to replay blocks. You will need to rebuild the database using -reindex-chainstate.").translated; @@ -2018,6 +1997,22 @@ bool AppInitMain(InitInterfaces& interfaces) break; } } + + // Check that EVM db and DVM db states are consistent + auto res = XResultValueLogged(evm_try_get_latest_block_hash(result)); + auto evmBlockHash = uint256::FromByteArray(*res).GetHex(); + auto dvmBlockHash = pcustomcsview->GetVMDomainBlockEdge(VMDomainEdge::EVMToDVM, evmBlockHash); + if (!dvmBlockHash.val.has_value()) { + strLoadError = _("Unable to get DVM block hash from latest EVM block hash, inconsistent chainstate detected. " + "This may be due to corrupted block databases between DVM and EVM, and you will need to " + "rebuild the database using -reindex.").translated; + } + CBlockIndex *pindex = LookupBlockIndex(uint256S(*dvmBlockHash.val)); + uint64_t dvmBlockHeight = pindex->GetBlockHeader().deprecatedHeight; + + if (dvmBlockHeight != ::ChainActive().Tip()->nHeight) { + LogPrintf("DVM and EVM block databases are inconsistent, rollback chain height to last consistent height.\n"); + } } catch (const std::exception& e) { LogPrintf("%s\n", e.what()); strLoadError = _("Error opening block database").translated; @@ -2070,23 +2065,18 @@ bool AppInitMain(InitInterfaces& interfaces) } while(false); if (!fLoaded && !ShutdownRequested()) { + // first suggest a reindex if (!fReset) { - if (fEvmDatabaseDirty) { - // Evm database dirty. Abort shutdown and run re-index pipeline. + bool fRet = uiInterface.ThreadSafeQuestion( + strLoadError + ".\n\n" + _("Do you want to rebuild the block database now?").translated, + strLoadError + ".\nPlease restart with -reindex or -reindex-chainstate to recover.", + "", CClientUIInterface::MSG_ERROR | CClientUIInterface::BTN_ABORT); + if (fRet) { + fReindex = true; AbortShutdown(); } else { - // first suggest a reindex - bool fRet = uiInterface.ThreadSafeQuestion( - strLoadError + ".\n\n" + _("Do you want to rebuild the block database now?").translated, - strLoadError + ".\nPlease restart with -reindex or -reindex-chainstate to recover.", - "", CClientUIInterface::MSG_ERROR | CClientUIInterface::BTN_ABORT); - if (fRet) { - fReindex = true; - AbortShutdown(); - } else { - LogPrintf("Aborted block database rebuild. Exiting.\n"); - return false; - } + LogPrintf("Aborted block database rebuild. Exiting.\n"); + return false; } } else { return InitError(strLoadError); From 55995203e039c34850500bd99dd7b3342231abb3 Mon Sep 17 00:00:00 2001 From: Niven Date: Wed, 17 Jan 2024 23:34:35 +0800 Subject: [PATCH 09/17] Fmt rs --- lib/ain-evm/src/evm.rs | 7 +++++-- lib/ain-rs-exports/src/evm.rs | 3 ++- 2 files changed, 7 insertions(+), 3 deletions(-) diff --git a/lib/ain-evm/src/evm.rs b/lib/ain-evm/src/evm.rs index b0c0623819e..ae725fcf7d5 100644 --- a/lib/ain-evm/src/evm.rs +++ b/lib/ain-evm/src/evm.rs @@ -29,7 +29,10 @@ use crate::{ filters::FilterService, log::{LogService, Notification}, receipt::ReceiptService, - storage::{traits::BlockStorage, Storage}, + storage::{ + traits::{BlockStorage, FlushableStorage}, + Storage, + }, transaction::{cache::TransactionCache, SignedTx}, trie::GENESIS_STATE_ROOT, Result, @@ -269,7 +272,7 @@ impl EVMServices { .sender .send(Notification::Block(block.header.hash())) .map_err(|e| format_err!(e.to_string()))?; - + self.core.clear_account_nonce(); self.core.flush()?; self.storage.flush()?; diff --git a/lib/ain-rs-exports/src/evm.rs b/lib/ain-rs-exports/src/evm.rs index 2fedaccd161..4b2b7a00bc3 100644 --- a/lib/ain-rs-exports/src/evm.rs +++ b/lib/ain-rs-exports/src/evm.rs @@ -656,7 +656,8 @@ fn evm_try_get_latest_block_hash() -> Result<[u8; 32]> { let block = SERVICES .evm .storage - .get_latest_block()?; + .get_latest_block()? + .ok_or(format_err!("latest block not found"))?; Ok(block.header.hash().to_fixed_bytes()) } From e3958b2d90832cb29d48e7c8354569db06a30c88 Mon Sep 17 00:00:00 2001 From: Niven Date: Wed, 17 Jan 2024 23:39:50 +0800 Subject: [PATCH 10/17] Handle before EVM activation --- lib/ain-rs-exports/src/evm.rs | 2 +- src/init.cpp | 25 ++++++++++++++----------- 2 files changed, 15 insertions(+), 12 deletions(-) diff --git a/lib/ain-rs-exports/src/evm.rs b/lib/ain-rs-exports/src/evm.rs index 4b2b7a00bc3..c9a5f8d9776 100644 --- a/lib/ain-rs-exports/src/evm.rs +++ b/lib/ain-rs-exports/src/evm.rs @@ -657,7 +657,7 @@ fn evm_try_get_latest_block_hash() -> Result<[u8; 32]> { .evm .storage .get_latest_block()? - .ok_or(format_err!("latest block not found"))?; + .ok_or(format_err!("latest EVM block not found"))?; Ok(block.header.hash().to_fixed_bytes()) } diff --git a/src/init.cpp b/src/init.cpp index 48f7e80dad4..f181f141a90 100644 --- a/src/init.cpp +++ b/src/init.cpp @@ -2000,18 +2000,21 @@ bool AppInitMain(InitInterfaces& interfaces) // Check that EVM db and DVM db states are consistent auto res = XResultValueLogged(evm_try_get_latest_block_hash(result)); - auto evmBlockHash = uint256::FromByteArray(*res).GetHex(); - auto dvmBlockHash = pcustomcsview->GetVMDomainBlockEdge(VMDomainEdge::EVMToDVM, evmBlockHash); - if (!dvmBlockHash.val.has_value()) { - strLoadError = _("Unable to get DVM block hash from latest EVM block hash, inconsistent chainstate detected. " - "This may be due to corrupted block databases between DVM and EVM, and you will need to " - "rebuild the database using -reindex.").translated; - } - CBlockIndex *pindex = LookupBlockIndex(uint256S(*dvmBlockHash.val)); - uint64_t dvmBlockHeight = pindex->GetBlockHeader().deprecatedHeight; + if (res) { + // After EVM activation + auto evmBlockHash = uint256::FromByteArray(*res).GetHex(); + auto dvmBlockHash = pcustomcsview->GetVMDomainBlockEdge(VMDomainEdge::EVMToDVM, evmBlockHash); + if (!dvmBlockHash.val.has_value()) { + strLoadError = _("Unable to get DVM block hash from latest EVM block hash, inconsistent chainstate detected. " + "This may be due to corrupted block databases between DVM and EVM, and you will need to " + "rebuild the database using -reindex.").translated; + } + CBlockIndex *pindex = LookupBlockIndex(uint256S(*dvmBlockHash.val)); + uint64_t dvmBlockHeight = pindex->GetBlockHeader().deprecatedHeight; - if (dvmBlockHeight != ::ChainActive().Tip()->nHeight) { - LogPrintf("DVM and EVM block databases are inconsistent, rollback chain height to last consistent height.\n"); + if (dvmBlockHeight != ::ChainActive().Tip()->nHeight) { + LogPrintf("DVM and EVM block databases are inconsistent, rollback chain height to last consistent height.\n"); + } } } catch (const std::exception& e) { LogPrintf("%s\n", e.what()); From f667d472ddf06c91e75081e9f756c616b94bcf34 Mon Sep 17 00:00:00 2001 From: Niven Date: Thu, 18 Jan 2024 00:04:47 +0800 Subject: [PATCH 11/17] Add pipeline to enter reindex if evm and dvm dbs are inconsistent --- src/init.cpp | 43 ++++++++++++++++++++++++------------------- 1 file changed, 24 insertions(+), 19 deletions(-) diff --git a/src/init.cpp b/src/init.cpp index f181f141a90..74134965ce8 100644 --- a/src/init.cpp +++ b/src/init.cpp @@ -1997,25 +1997,6 @@ bool AppInitMain(InitInterfaces& interfaces) break; } } - - // Check that EVM db and DVM db states are consistent - auto res = XResultValueLogged(evm_try_get_latest_block_hash(result)); - if (res) { - // After EVM activation - auto evmBlockHash = uint256::FromByteArray(*res).GetHex(); - auto dvmBlockHash = pcustomcsview->GetVMDomainBlockEdge(VMDomainEdge::EVMToDVM, evmBlockHash); - if (!dvmBlockHash.val.has_value()) { - strLoadError = _("Unable to get DVM block hash from latest EVM block hash, inconsistent chainstate detected. " - "This may be due to corrupted block databases between DVM and EVM, and you will need to " - "rebuild the database using -reindex.").translated; - } - CBlockIndex *pindex = LookupBlockIndex(uint256S(*dvmBlockHash.val)); - uint64_t dvmBlockHeight = pindex->GetBlockHeader().deprecatedHeight; - - if (dvmBlockHeight != ::ChainActive().Tip()->nHeight) { - LogPrintf("DVM and EVM block databases are inconsistent, rollback chain height to last consistent height.\n"); - } - } } catch (const std::exception& e) { LogPrintf("%s\n", e.what()); strLoadError = _("Error opening block database").translated; @@ -2063,6 +2044,30 @@ bool AppInitMain(InitInterfaces& interfaces) break; } + // Check that EVM db and DVM db states are consistent + auto res = XResultValueLogged(evm_try_get_latest_block_hash(result)); + if (res) { + // After EVM activation + auto evmBlockHash = uint256::FromByteArray(*res).GetHex(); + auto dvmBlockHash = pcustomcsview->GetVMDomainBlockEdge(VMDomainEdge::EVMToDVM, evmBlockHash); + if (!dvmBlockHash.val.has_value()) { + strLoadError = _("Unable to get DVM block hash from latest EVM block hash, inconsistent chainstate detected. " + "This may be due to corrupted block databases between DVM and EVM, and you will need to " + "rebuild the database using -reindex.").translated; + break; + } + CBlockIndex *pindex = LookupBlockIndex(uint256S(*dvmBlockHash.val)); + auto dvmBlockHeight = pindex->GetBlockHeader().nHeight; + + if (dvmBlockHeight != ::ChainActive().Tip()->nHeight) { + strLoadError = _("Inconsistent chainstate detected between DVM block database and EVM block database. " + "This may be due to corrupted block databases between DVM and EVM, and you will need to " + "rebuild the database using -reindex.").translated; + } + break; + } + } + fLoaded = true; LogPrintf(" block index %15dms\n", GetTimeMillis() - load_block_index_start_time); } while(false); From 8ac31698b2f100455ac9471ad97bdb8d0350f7aa Mon Sep 17 00:00:00 2001 From: Niven Date: Thu, 18 Jan 2024 00:07:18 +0800 Subject: [PATCH 12/17] Fmt cpp --- src/init.cpp | 1 - 1 file changed, 1 deletion(-) diff --git a/src/init.cpp b/src/init.cpp index 74134965ce8..99a4a7a7c51 100644 --- a/src/init.cpp +++ b/src/init.cpp @@ -2063,7 +2063,6 @@ bool AppInitMain(InitInterfaces& interfaces) strLoadError = _("Inconsistent chainstate detected between DVM block database and EVM block database. " "This may be due to corrupted block databases between DVM and EVM, and you will need to " "rebuild the database using -reindex.").translated; - } break; } } From 379034e127bca380bbc838e508a10296460939bb Mon Sep 17 00:00:00 2001 From: Niven Date: Thu, 18 Jan 2024 00:10:17 +0800 Subject: [PATCH 13/17] Fix cpp --- src/init.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/init.cpp b/src/init.cpp index 99a4a7a7c51..67b0a46742b 100644 --- a/src/init.cpp +++ b/src/init.cpp @@ -2057,7 +2057,7 @@ bool AppInitMain(InitInterfaces& interfaces) break; } CBlockIndex *pindex = LookupBlockIndex(uint256S(*dvmBlockHash.val)); - auto dvmBlockHeight = pindex->GetBlockHeader().nHeight; + auto dvmBlockHeight = pindex->nHeight; if (dvmBlockHeight != ::ChainActive().Tip()->nHeight) { strLoadError = _("Inconsistent chainstate detected between DVM block database and EVM block database. " From 79e82f22d4d20516acce41e26c195fc3982b48bc Mon Sep 17 00:00:00 2001 From: Niven Date: Thu, 18 Jan 2024 01:40:29 +0800 Subject: [PATCH 14/17] Skip state check when in regtest --- lib/ain-evm/src/core.rs | 7 ++++++- src/init.cpp | 41 ++++++++++++++++++++++------------------- 2 files changed, 28 insertions(+), 20 deletions(-) diff --git a/lib/ain-evm/src/core.rs b/lib/ain-evm/src/core.rs index cb97d3dc1da..7ef263b21c0 100644 --- a/lib/ain-evm/src/core.rs +++ b/lib/ain-evm/src/core.rs @@ -31,7 +31,10 @@ use crate::{ gas::check_tx_intrinsic_gas, precompiles::MetachainPrecompiles, receipt::ReceiptService, - storage::{traits::BlockStorage, Storage}, + storage::{ + traits::{BlockStorage, FlushableStorage}, + Storage, + }, transaction::{ cache::{TransactionCache, ValidateTxInfo}, SignedTx, @@ -143,6 +146,8 @@ impl EVMCoreService { ); storage.put_latest_block(Some(&block))?; storage.put_block(&block)?; + handler.flush()?; + storage.flush()?; Ok(handler) } diff --git a/src/init.cpp b/src/init.cpp index 67b0a46742b..bc5419ffa11 100644 --- a/src/init.cpp +++ b/src/init.cpp @@ -2044,26 +2044,29 @@ bool AppInitMain(InitInterfaces& interfaces) break; } - // Check that EVM db and DVM db states are consistent - auto res = XResultValueLogged(evm_try_get_latest_block_hash(result)); - if (res) { - // After EVM activation - auto evmBlockHash = uint256::FromByteArray(*res).GetHex(); - auto dvmBlockHash = pcustomcsview->GetVMDomainBlockEdge(VMDomainEdge::EVMToDVM, evmBlockHash); - if (!dvmBlockHash.val.has_value()) { - strLoadError = _("Unable to get DVM block hash from latest EVM block hash, inconsistent chainstate detected. " - "This may be due to corrupted block databases between DVM and EVM, and you will need to " - "rebuild the database using -reindex.").translated; - break; - } - CBlockIndex *pindex = LookupBlockIndex(uint256S(*dvmBlockHash.val)); - auto dvmBlockHeight = pindex->nHeight; + // State consistency check is skipped for regtest (EVM state can be initialized with state input) + if (Params().NetworkIDString() != CBaseChainParams::REGTEST) { + // Check that EVM db and DVM db states are consistent + auto res = XResultValueLogged(evm_try_get_latest_block_hash(result)); + if (res) { + // After EVM activation + auto evmBlockHash = uint256::FromByteArray(*res).GetHex(); + auto dvmBlockHash = pcustomcsview->GetVMDomainBlockEdge(VMDomainEdge::EVMToDVM, evmBlockHash); + if (!dvmBlockHash.val.has_value()) { + strLoadError = _("Unable to get DVM block hash from latest EVM block hash, inconsistent chainstate detected. " + "This may be due to corrupted block databases between DVM and EVM, and you will need to " + "rebuild the database using -reindex.").translated; + break; + } + CBlockIndex *pindex = LookupBlockIndex(uint256S(*dvmBlockHash.val)); + auto dvmBlockHeight = pindex->nHeight; - if (dvmBlockHeight != ::ChainActive().Tip()->nHeight) { - strLoadError = _("Inconsistent chainstate detected between DVM block database and EVM block database. " - "This may be due to corrupted block databases between DVM and EVM, and you will need to " - "rebuild the database using -reindex.").translated; - break; + if (dvmBlockHeight != ::ChainActive().Tip()->nHeight) { + strLoadError = _("Inconsistent chainstate detected between DVM block database and EVM block database. " + "This may be due to corrupted block databases between DVM and EVM, and you will need to " + "rebuild the database using -reindex.").translated; + break; + } } } From d48109084b826e7beea7235202c71e7f9cdbbe91 Mon Sep 17 00:00:00 2001 From: Niven Date: Mon, 22 Jan 2024 14:37:04 +0800 Subject: [PATCH 15/17] Check for nullptr --- src/dfi/errors.h | 4 ++++ src/dfi/rpc_evm.cpp | 3 +++ src/init.cpp | 5 +++++ 3 files changed, 12 insertions(+) diff --git a/src/dfi/errors.h b/src/dfi/errors.h index e371829c681..4c6f3aee2cb 100644 --- a/src/dfi/errors.h +++ b/src/dfi/errors.h @@ -422,6 +422,10 @@ class DeFiErrors { static Res InvalidBlockNumberString(const std::string &number) { return Res::Err("Invalid block number: %s", number); } + + static Res InvalidBlockHashString(const std::string &hash) { + return Res::Err("Invalid block hash: %s", hash); + } }; #endif // DEFI_DFI_ERRORS_H diff --git a/src/dfi/rpc_evm.cpp b/src/dfi/rpc_evm.cpp index 1b7eb834a2d..41fd5f35008 100644 --- a/src/dfi/rpc_evm.cpp +++ b/src/dfi/rpc_evm.cpp @@ -339,6 +339,9 @@ UniValue vmmap(const JSONRPCRequest &request) { throwInvalidParam(dvmBlockHash.msg); } CBlockIndex *pindex = LookupBlockIndex(uint256S(*dvmBlockHash.val)); + if (!pindex) { + throwInvalidParam(DeFiErrors::InvalidBlockHashString(*dvmBlockHash.val).msg); + } uint64_t blockNumber = pindex->GetBlockHeader().deprecatedHeight; return ResVal(std::to_string(blockNumber), Res::Ok()); }; diff --git a/src/init.cpp b/src/init.cpp index bc5419ffa11..bb33bd030cc 100644 --- a/src/init.cpp +++ b/src/init.cpp @@ -2059,6 +2059,11 @@ bool AppInitMain(InitInterfaces& interfaces) break; } CBlockIndex *pindex = LookupBlockIndex(uint256S(*dvmBlockHash.val)); + if (!pindex) { + strLoadError = _("Unable to get DVM block index from block hash, possible corrupted block database detected. " + "You will need to rebuild the database using -reindex.").translated; + break; + } auto dvmBlockHeight = pindex->nHeight; if (dvmBlockHeight != ::ChainActive().Tip()->nHeight) { From c862f067565623dd4c2527bff7d7e419236097fa Mon Sep 17 00:00:00 2001 From: Niven Date: Mon, 22 Jan 2024 14:39:49 +0800 Subject: [PATCH 16/17] fmt cpp --- src/dfi/errors.h | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/src/dfi/errors.h b/src/dfi/errors.h index 4c6f3aee2cb..d06b7be2c97 100644 --- a/src/dfi/errors.h +++ b/src/dfi/errors.h @@ -423,9 +423,7 @@ class DeFiErrors { return Res::Err("Invalid block number: %s", number); } - static Res InvalidBlockHashString(const std::string &hash) { - return Res::Err("Invalid block hash: %s", hash); - } + static Res InvalidBlockHashString(const std::string &hash) { return Res::Err("Invalid block hash: %s", hash); } }; #endif // DEFI_DFI_ERRORS_H From c86861f0bc8d8339622ffd7f41747053a92f36e2 Mon Sep 17 00:00:00 2001 From: Niven Date: Wed, 24 Jan 2024 15:59:04 +0800 Subject: [PATCH 17/17] Shift evm db flush in DVM db flush pipeline --- lib/ain-evm/src/core.rs | 7 +------ lib/ain-evm/src/evm.rs | 14 +++++++++++--- lib/ain-evm/src/storage/mod.rs | 3 +-- lib/ain-rs-exports/src/evm.rs | 5 +++++ lib/ain-rs-exports/src/lib.rs | 2 ++ src/validation.cpp | 7 +++++++ 6 files changed, 27 insertions(+), 11 deletions(-) diff --git a/lib/ain-evm/src/core.rs b/lib/ain-evm/src/core.rs index 7ef263b21c0..cb97d3dc1da 100644 --- a/lib/ain-evm/src/core.rs +++ b/lib/ain-evm/src/core.rs @@ -31,10 +31,7 @@ use crate::{ gas::check_tx_intrinsic_gas, precompiles::MetachainPrecompiles, receipt::ReceiptService, - storage::{ - traits::{BlockStorage, FlushableStorage}, - Storage, - }, + storage::{traits::BlockStorage, Storage}, transaction::{ cache::{TransactionCache, ValidateTxInfo}, SignedTx, @@ -146,8 +143,6 @@ impl EVMCoreService { ); storage.put_latest_block(Some(&block))?; storage.put_block(&block)?; - handler.flush()?; - storage.flush()?; Ok(handler) } diff --git a/lib/ain-evm/src/evm.rs b/lib/ain-evm/src/evm.rs index ae725fcf7d5..91c4926bac2 100644 --- a/lib/ain-evm/src/evm.rs +++ b/lib/ain-evm/src/evm.rs @@ -272,10 +272,7 @@ impl EVMServices { .sender .send(Notification::Block(block.header.hash())) .map_err(|e| format_err!(e.to_string()))?; - self.core.clear_account_nonce(); - self.core.flush()?; - self.storage.flush()?; Ok(()) } @@ -467,6 +464,17 @@ impl EVMServices { template.backend.increase_tx_count(); Ok(()) } + + /// + /// # Safety + /// + /// Result cannot be used safety unless `cs_main` lock is taken on C++ side + /// across all usages. Note: To be replaced with a proper lock flow later. + /// + pub unsafe fn flush_state_to_db(&self) -> Result<()> { + self.core.flush()?; + self.storage.flush() + } } // Block template methods diff --git a/lib/ain-evm/src/storage/mod.rs b/lib/ain-evm/src/storage/mod.rs index b01ad8dcde8..00f5eda18dc 100644 --- a/lib/ain-evm/src/storage/mod.rs +++ b/lib/ain-evm/src/storage/mod.rs @@ -227,7 +227,6 @@ impl Storage { impl Rollback for Storage { fn disconnect_latest_block(&self) -> Result<()> { self.cache.disconnect_latest_block()?; - self.blockstore.disconnect_latest_block()?; - self.flush() + self.blockstore.disconnect_latest_block() } } diff --git a/lib/ain-rs-exports/src/evm.rs b/lib/ain-rs-exports/src/evm.rs index c9a5f8d9776..082a76903de 100644 --- a/lib/ain-rs-exports/src/evm.rs +++ b/lib/ain-rs-exports/src/evm.rs @@ -858,3 +858,8 @@ fn evm_try_dispatch_pending_transactions_event(raw_tx: &str) -> Result<()> { .send(Notification::Transaction(signed_tx.hash())) .map_err(|e| format_err!(e.to_string()))?) } + +#[ffi_fallible] +fn evm_try_flush_db() -> Result<()> { + unsafe { SERVICES.evm.flush_state_to_db() } +} diff --git a/lib/ain-rs-exports/src/lib.rs b/lib/ain-rs-exports/src/lib.rs index 07ff3ef055e..e97f7e9a538 100644 --- a/lib/ain-rs-exports/src/lib.rs +++ b/lib/ain-rs-exports/src/lib.rs @@ -341,6 +341,8 @@ pub mod ffi { result: &mut CrossBoundaryResult, raw_tx: &str, ); + + fn evm_try_flush_db(result: &mut CrossBoundaryResult); } // ========= Debug ========== diff --git a/src/validation.cpp b/src/validation.cpp index 733348709da..1682c651917 100644 --- a/src/validation.cpp +++ b/src/validation.cpp @@ -3583,6 +3583,13 @@ bool CChainState::FlushStateToDisk(const CChainParams &chainparams, if (!CoinsTip().Flush() || !pcustomcsDB->Flush()) { return AbortNode(state, "Failed to write to coin or masternode db to disk"); } + // Flush the EVM chainstate + if (IsEVMEnabled(pcustomcsview->GetAttributes())) { + auto res = XResultStatusLogged(evm_try_flush_db(result)); + if (!res) { + return AbortNode(state, "Failed to write to EVM db to disk"); + } + } if (!compactBegin.empty() && !compactEnd.empty()) { auto time = GetTimeMillis(); pcustomcsDB->Compact(compactBegin, compactEnd);