From 8418d62edac5f315beb94f1f81809d58115a018f Mon Sep 17 00:00:00 2001 From: Shoham Chakraborty Date: Mon, 12 Jun 2023 14:42:54 +0800 Subject: [PATCH 1/6] Implement eth_syncing RPC --- lib/ain-cpp-imports/src/bridge.rs | 3 +++ lib/ain-cpp-imports/src/lib.rs | 20 +++++++++++++++++++ lib/ain-grpc/src/lib.rs | 1 + lib/ain-grpc/src/rpc/eth.rs | 32 +++++++++++++++++++++++++++++++ lib/ain-grpc/src/sync.rs | 30 +++++++++++++++++++++++++++++ src/ffi/ffiexports.cpp | 8 ++++++++ src/ffi/ffiexports.h | 2 ++ 7 files changed, 96 insertions(+) create mode 100644 lib/ain-grpc/src/sync.rs diff --git a/lib/ain-cpp-imports/src/bridge.rs b/lib/ain-cpp-imports/src/bridge.rs index 811903d44c..0b340db167 100644 --- a/lib/ain-cpp-imports/src/bridge.rs +++ b/lib/ain-cpp-imports/src/bridge.rs @@ -16,5 +16,8 @@ pub mod ffi { fn getMinRelayTxFee() -> u64; fn getEthPrivKey(key_id: [u8; 20]) -> [u8; 32]; fn getStateInputJSON() -> String; + fn isSyncing() -> bool; + fn getHighestBlock() -> i32; + fn getCurrentHeight() -> i32; } } diff --git a/lib/ain-cpp-imports/src/lib.rs b/lib/ain-cpp-imports/src/lib.rs index 4e81a4d5a7..1c83463f2b 100644 --- a/lib/ain-cpp-imports/src/lib.rs +++ b/lib/ain-cpp-imports/src/lib.rs @@ -49,6 +49,15 @@ mod ffi { pub fn getStateInputJSON() -> String { unimplemented!("{}", UNIMPL_MSG) } + pub fn isSyncing() -> bool { + unimplemented!("{}", UNIMPL_MSG) + } + pub fn getHighestBlock() -> i32 { + unimplemented!("{}", UNIMPL_MSG) + } + pub fn getCurrentHeight() -> i32 { + unimplemented!("{}", UNIMPL_MSG) + } } pub fn get_chain_id() -> Result> { @@ -119,5 +128,16 @@ pub fn get_state_input_json() -> Option { } } +pub fn is_syncing() -> Result> { + let syncing = ffi::isSyncing(); + Ok(syncing) +} + +pub fn get_sync_status() -> Result<(i32, i32), Box> { + let current_block = ffi::getCurrentHeight(); + let highest_block = ffi::getHighestBlock(); + Ok((current_block, highest_block)) +} + #[cfg(test)] mod tests {} diff --git a/lib/ain-grpc/src/lib.rs b/lib/ain-grpc/src/lib.rs index ed8ef1fc37..e5dda46b49 100644 --- a/lib/ain-grpc/src/lib.rs +++ b/lib/ain-grpc/src/lib.rs @@ -9,6 +9,7 @@ pub mod codegen; mod impls; mod receipt; pub mod rpc; +mod sync; mod transaction; mod transaction_request; mod utils; diff --git a/lib/ain-grpc/src/rpc/eth.rs b/lib/ain-grpc/src/rpc/eth.rs index da1d608318..2a66e25bc7 100644 --- a/lib/ain-grpc/src/rpc/eth.rs +++ b/lib/ain-grpc/src/rpc/eth.rs @@ -9,6 +9,7 @@ use ain_cpp_imports::get_eth_priv_key; use ain_evm::executor::TxResponse; use ain_evm::handler::Handlers; +use crate::sync::{SyncInfo, SyncState}; use ain_evm::storage::traits::{BlockStorage, ReceiptStorage, TransactionStorage}; use ain_evm::transaction::{SignedTx, TransactionError}; use ethereum::{EnvelopedEncodable, TransactionV2}; @@ -203,6 +204,9 @@ pub trait MetachainRPC { #[method(name = "maxPriorityFeePerGas")] fn max_priority_fee_per_gas(&self) -> RpcResult; + + #[method(name = "syncing")] + fn syncing(&self) -> RpcResult; } pub struct MetachainRPCModule { @@ -703,6 +707,34 @@ impl MetachainRPCServer for MetachainRPCModule { fn max_priority_fee_per_gas(&self) -> RpcResult { Ok(self.handler.block.suggested_priority_fee()) } + + fn syncing(&self) -> RpcResult { + let (current_native_height, highest_native_block) = ain_cpp_imports::get_sync_status() + .map_err(|e| { + Error::Custom(format!("ain_cpp_imports::get_sync_status error : {e:?}")) + })?; + + match current_native_height != highest_native_block { + true => { + let current_block = self + .handler + .storage + .get_latest_block() + .map(|block| block.header.number) + .expect("Unable to get current block"); + + let highest_block = current_block + (highest_native_block - current_native_height); + debug!("Highest native: {highest_native_block}\nCurrent native: {current_native_height}\nCurrent ETH: {current_block}\nHighest ETH: {highest_block}"); + + Ok(SyncState::Syncing(SyncInfo { + starting_block: U256::zero(), + current_block, + highest_block, + })) + } + false => Ok(SyncState::Synced(false)), + } + } } fn sign( diff --git a/lib/ain-grpc/src/sync.rs b/lib/ain-grpc/src/sync.rs new file mode 100644 index 0000000000..cf321a0f1e --- /dev/null +++ b/lib/ain-grpc/src/sync.rs @@ -0,0 +1,30 @@ +use primitive_types::U256; +use serde::{Serialize, Serializer}; + +#[derive(Debug, Serialize, Deserialize, Clone)] +pub struct SyncInfo { + pub starting_block: U256, + pub current_block: U256, + pub highest_block: U256, +} + +/// Sync state +#[derive(Debug, Deserialize, Clone)] +pub enum SyncState { + /// Only hashes + Synced(bool), + /// Full transactions + Syncing(SyncInfo), +} + +impl Serialize for SyncState { + fn serialize(&self, serializer: S) -> Result + where + S: Serializer, + { + match *self { + SyncState::Synced(ref sync) => sync.serialize(serializer), + SyncState::Syncing(ref sync_info) => sync_info.serialize(serializer), + } + } +} diff --git a/src/ffi/ffiexports.cpp b/src/ffi/ffiexports.cpp index dd1deecda4..5428bf6915 100644 --- a/src/ffi/ffiexports.cpp +++ b/src/ffi/ffiexports.cpp @@ -201,3 +201,11 @@ std::array getEthPrivKey(std::array keyID) { rust::string getStateInputJSON() { return gArgs.GetArg("-ethstartstate", ""); } + +int getHighestBlock() { + return pindexBestHeader ? pindexBestHeader->nHeight : (int) ::ChainActive().Height(); // return current block count if no peers +} + +int getCurrentHeight() { + return (int) ::ChainActive().Height(); +} diff --git a/src/ffi/ffiexports.h b/src/ffi/ffiexports.h index 1d3a29f038..e465ce9d95 100644 --- a/src/ffi/ffiexports.h +++ b/src/ffi/ffiexports.h @@ -17,5 +17,7 @@ uint64_t getNativeTxSize(rust::Vec rawTransaction); uint64_t getMinRelayTxFee(); std::array getEthPrivKey(std::array keyID); rust::string getStateInputJSON(); +int getHighestBlock(); +int getCurrentHeight(); #endif // DEFI_FFI_FFIEXPORTS_H From 730a6d2b3cfd39b255c98f312e860a7caf59578f Mon Sep 17 00:00:00 2001 From: Shoham Chakraborty Date: Mon, 12 Jun 2023 14:46:34 +0800 Subject: [PATCH 2/6] Remove old imports --- lib/ain-cpp-imports/src/bridge.rs | 1 - lib/ain-cpp-imports/src/lib.rs | 8 -------- 2 files changed, 9 deletions(-) diff --git a/lib/ain-cpp-imports/src/bridge.rs b/lib/ain-cpp-imports/src/bridge.rs index 0b340db167..119e7ccee1 100644 --- a/lib/ain-cpp-imports/src/bridge.rs +++ b/lib/ain-cpp-imports/src/bridge.rs @@ -16,7 +16,6 @@ pub mod ffi { fn getMinRelayTxFee() -> u64; fn getEthPrivKey(key_id: [u8; 20]) -> [u8; 32]; fn getStateInputJSON() -> String; - fn isSyncing() -> bool; fn getHighestBlock() -> i32; fn getCurrentHeight() -> i32; } diff --git a/lib/ain-cpp-imports/src/lib.rs b/lib/ain-cpp-imports/src/lib.rs index 1c83463f2b..bd06f136b5 100644 --- a/lib/ain-cpp-imports/src/lib.rs +++ b/lib/ain-cpp-imports/src/lib.rs @@ -49,9 +49,6 @@ mod ffi { pub fn getStateInputJSON() -> String { unimplemented!("{}", UNIMPL_MSG) } - pub fn isSyncing() -> bool { - unimplemented!("{}", UNIMPL_MSG) - } pub fn getHighestBlock() -> i32 { unimplemented!("{}", UNIMPL_MSG) } @@ -128,11 +125,6 @@ pub fn get_state_input_json() -> Option { } } -pub fn is_syncing() -> Result> { - let syncing = ffi::isSyncing(); - Ok(syncing) -} - pub fn get_sync_status() -> Result<(i32, i32), Box> { let current_block = ffi::getCurrentHeight(); let highest_block = ffi::getHighestBlock(); From 2ed3a942239442ea9a0d69428ae252c6e09ce250 Mon Sep 17 00:00:00 2001 From: Shoham Chakraborty Date: Mon, 12 Jun 2023 14:55:12 +0800 Subject: [PATCH 3/6] Fix segfault --- lib/ain-grpc/src/rpc/eth.rs | 6 +++++- src/ffi/ffiexports.cpp | 28 +++++++++++++++------------- 2 files changed, 20 insertions(+), 14 deletions(-) diff --git a/lib/ain-grpc/src/rpc/eth.rs b/lib/ain-grpc/src/rpc/eth.rs index 2a66e25bc7..22adc93ca4 100644 --- a/lib/ain-grpc/src/rpc/eth.rs +++ b/lib/ain-grpc/src/rpc/eth.rs @@ -714,6 +714,10 @@ impl MetachainRPCServer for MetachainRPCModule { Error::Custom(format!("ain_cpp_imports::get_sync_status error : {e:?}")) })?; + if current_native_height == -1 { + return Err(Error::Custom(format!("Block index not available"))); + } + match current_native_height != highest_native_block { true => { let current_block = self @@ -721,7 +725,7 @@ impl MetachainRPCServer for MetachainRPCModule { .storage .get_latest_block() .map(|block| block.header.number) - .expect("Unable to get current block"); + .ok_or_else(|| Error::Custom(String::from("Unable to get current block")))?; let highest_block = current_block + (highest_native_block - current_native_height); debug!("Highest native: {highest_native_block}\nCurrent native: {current_native_height}\nCurrent ETH: {current_block}\nHighest ETH: {highest_block}"); diff --git a/src/ffi/ffiexports.cpp b/src/ffi/ffiexports.cpp index 5428bf6915..a0743730ed 100644 --- a/src/ffi/ffiexports.cpp +++ b/src/ffi/ffiexports.cpp @@ -44,9 +44,9 @@ rust::string publishEthTransaction(rust::Vec rawTransaction) { try { execTestTx(CTransaction(rawTx), targetHeight, optAuthTx); send(MakeTransactionRef(std::move(rawTx)), optAuthTx)->GetHash().ToString(); - } catch (std::runtime_error& e) { + } catch (std::runtime_error &e) { return e.what(); - } catch (const UniValue& objError) { + } catch (const UniValue &objError) { const auto obj = objError.get_obj(); return obj["message"].get_str(); @@ -58,8 +58,8 @@ rust::string publishEthTransaction(rust::Vec rawTransaction) { rust::vec getAccounts() { rust::vec addresses; std::vector> const wallets = GetWallets(); - for (const std::shared_ptr& wallet : wallets) { - for (auto & it : wallet->mapAddressBook) + for (const std::shared_ptr &wallet: wallets) { + for (auto &it: wallet->mapAddressBook) if (std::holds_alternative(it.first)) { addresses.push_back(EncodeDestination(it.first)); } @@ -68,14 +68,14 @@ rust::vec getAccounts() { } rust::string getDatadir() { - #ifdef WIN32 +#ifdef WIN32 // https://learn.microsoft.com/en-us/cpp/cpp/char-wchar-t-char16-t-char32-t?view=msvc-170 // We're sidestepping this for now unsafely making an assumption. Can crash on Windows // if odd paths are used. Require testing. return rust::String(reinterpret_cast(GetDataDir().c_str())); - #else +#else return rust::String(GetDataDir().c_str()); - #endif +#endif } rust::string getNetwork() { @@ -86,7 +86,7 @@ uint32_t getDifficulty(std::array blockHash) { uint256 hash{}; std::copy(blockHash.begin(), blockHash.end(), hash.begin()); - const CBlockIndex* pblockindex; + const CBlockIndex *pblockindex; uint32_t difficulty{}; { LOCK(cs_main); @@ -106,7 +106,7 @@ std::array getChainWork(std::array blockHash) { uint256 hash{}; std::copy(blockHash.begin(), blockHash.end(), hash.begin()); - const CBlockIndex* pblockindex; + const CBlockIndex *pblockindex; std::array chainWork{}; { LOCK(cs_main); @@ -139,7 +139,8 @@ rust::vec getPoolTransactions() { } CCustomTxMessage txMessage{CEvmTxMessage{}}; - const auto res = CustomMetadataParse(std::numeric_limits::max(), Params().GetConsensus(), metadata, txMessage); + const auto res = CustomMetadataParse(std::numeric_limits::max(), Params().GetConsensus(), metadata, + txMessage); if (!res) { continue; } @@ -188,7 +189,7 @@ uint64_t getMinRelayTxFee() { std::array getEthPrivKey(std::array keyID) { CKey ethPrivKey; const auto ethKeyID = CKeyID{uint160{std::vector(keyID.begin(), keyID.end())}}; - for (const auto &wallet : GetWallets()) { + for (const auto &wallet: GetWallets()) { if (wallet->GetEthKey(ethKeyID, ethPrivKey)) { std::array privKeyArray{}; std::copy(ethPrivKey.begin(), ethPrivKey.end(), privKeyArray.begin()); @@ -203,9 +204,10 @@ rust::string getStateInputJSON() { } int getHighestBlock() { - return pindexBestHeader ? pindexBestHeader->nHeight : (int) ::ChainActive().Height(); // return current block count if no peers + return pindexBestHeader ? pindexBestHeader->nHeight + : (int) ::ChainActive().Height(); // return current block count if no peers } int getCurrentHeight() { - return (int) ::ChainActive().Height(); + return ::ChainActive().Height() ? (int) ::ChainActive().Height() : -1; } From e04a8ea0377ee3b82b8420ada5b6713cc393836f Mon Sep 17 00:00:00 2001 From: Shoham Chakraborty Date: Wed, 21 Jun 2023 17:45:46 +0800 Subject: [PATCH 4/6] Add starting block data --- lib/ain-evm/src/block.rs | 13 ++++++++++++- lib/ain-grpc/src/rpc/eth.rs | 4 +++- 2 files changed, 15 insertions(+), 2 deletions(-) diff --git a/lib/ain-evm/src/block.rs b/lib/ain-evm/src/block.rs index 1055a8b985..b8354abfcd 100644 --- a/lib/ain-evm/src/block.rs +++ b/lib/ain-evm/src/block.rs @@ -14,6 +14,7 @@ use crate::{ pub struct BlockHandler { storage: Arc, + first_block_number: U256, } pub struct FeeHistoryData { @@ -25,7 +26,17 @@ pub struct FeeHistoryData { impl BlockHandler { pub fn new(storage: Arc) -> Self { - Self { storage } + let mut block_handler = Self { storage, first_block_number: U256::zero() }; + let (_, block_number) = block_handler.get_latest_block_hash_and_number().unwrap_or_default(); + + block_handler.first_block_number = block_number; + debug!("Current block number is {:#?}", block_number); + + block_handler + } + + pub fn get_first_block_number(&self) -> U256 { + self.first_block_number } pub fn get_latest_block_hash_and_number(&self) -> Option<(H256, U256)> { diff --git a/lib/ain-grpc/src/rpc/eth.rs b/lib/ain-grpc/src/rpc/eth.rs index 22adc93ca4..33ef9cdb63 100644 --- a/lib/ain-grpc/src/rpc/eth.rs +++ b/lib/ain-grpc/src/rpc/eth.rs @@ -727,11 +727,13 @@ impl MetachainRPCServer for MetachainRPCModule { .map(|block| block.header.number) .ok_or_else(|| Error::Custom(String::from("Unable to get current block")))?; + let starting_block = self.handler.block.get_first_block_number(); + let highest_block = current_block + (highest_native_block - current_native_height); debug!("Highest native: {highest_native_block}\nCurrent native: {current_native_height}\nCurrent ETH: {current_block}\nHighest ETH: {highest_block}"); Ok(SyncState::Syncing(SyncInfo { - starting_block: U256::zero(), + starting_block, current_block, highest_block, })) From 375005c5e9d5e2bb231075001c1a25dabf195488 Mon Sep 17 00:00:00 2001 From: Shoham Chakraborty Date: Wed, 21 Jun 2023 17:55:51 +0800 Subject: [PATCH 5/6] Format --- lib/ain-evm/src/block.rs | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/lib/ain-evm/src/block.rs b/lib/ain-evm/src/block.rs index 4082666f21..2a4209e9b7 100644 --- a/lib/ain-evm/src/block.rs +++ b/lib/ain-evm/src/block.rs @@ -25,8 +25,13 @@ pub const INITIAL_BASE_FEE: U256 = U256([10_000_000_000, 0, 0, 0]); // wei impl BlockHandler { pub fn new(storage: Arc) -> Self { - let mut block_handler = Self { storage, first_block_number: U256::zero() }; - let (_, block_number) = block_handler.get_latest_block_hash_and_number().unwrap_or_default(); + let mut block_handler = Self { + storage, + first_block_number: U256::zero(), + }; + let (_, block_number) = block_handler + .get_latest_block_hash_and_number() + .unwrap_or_default(); block_handler.first_block_number = block_number; debug!("Current block number is {:#?}", block_number); From 94a75cceeb62ab8cd12173ae53b73791ed4eb771 Mon Sep 17 00:00:00 2001 From: Shoham Chakraborty Date: Wed, 21 Jun 2023 18:08:48 +0800 Subject: [PATCH 6/6] Fix formatting --- src/ffi/ffiexports.cpp | 20 ++++++++++---------- 1 file changed, 10 insertions(+), 10 deletions(-) diff --git a/src/ffi/ffiexports.cpp b/src/ffi/ffiexports.cpp index 35d7775f90..0d592eba29 100644 --- a/src/ffi/ffiexports.cpp +++ b/src/ffi/ffiexports.cpp @@ -12,8 +12,8 @@ bool isMining() { return gArgs.GetBoolArg("-gen", false); } -rust::string publishEthTransaction(rust::Vec rawTransaction) { - std::vector evmTx(rawTransaction.size()); +rust::string publishEthTransaction(rust::Vec rawTransaction) { + std::vector evmTx(rawTransaction.size()); std::copy(rawTransaction.begin(), rawTransaction.end(), evmTx.begin()); CDataStream metadata(DfTxMarker, SER_NETWORK, PROTOCOL_VERSION); metadata << static_cast(CustomTxType::EvmTx) @@ -55,10 +55,10 @@ rust::string publishEthTransaction(rust::Vec rawTransaction) { return {}; } -rust::vec getAccounts() { - rust::vec addresses; - std::vector > const wallets = GetWallets(); - for (const std::shared_ptr &wallet: wallets) { +rust::vec getAccounts() { + rust::vec addresses; + std::vector> const wallets = GetWallets(); + for (const std::shared_ptr &wallet: wallets) { for (auto &it: wallet->mapAddressBook) if (std::holds_alternative(it.first)) { addresses.push_back(EncodeDestination(it.first)); @@ -123,8 +123,8 @@ std::array getChainWork(std::array blockHash) { return chainWork; } -rust::vec getPoolTransactions() { - rust::vec poolTransactions; +rust::vec getPoolTransactions() { + rust::vec poolTransactions; for (auto mi = mempool.mapTx.get().begin(); mi != mempool.mapTx.get().end(); ++mi) { const auto &tx = mi->GetTx(); @@ -152,8 +152,8 @@ rust::vec getPoolTransactions() { return poolTransactions; } -uint64_t getNativeTxSize(rust::Vec rawTransaction) { - std::vector evmTx(rawTransaction.size()); +uint64_t getNativeTxSize(rust::Vec rawTransaction) { + std::vector evmTx(rawTransaction.size()); std::copy(rawTransaction.begin(), rawTransaction.end(), evmTx.begin()); CDataStream metadata(DfTxMarker, SER_NETWORK, PROTOCOL_VERSION); metadata << static_cast(CustomTxType::EvmTx)