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

evm: Implement eth_syncing RPC #2049

Merged
merged 7 commits into from
Jun 23, 2023
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
2 changes: 2 additions & 0 deletions lib/ain-cpp-imports/src/bridge.rs
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,8 @@ pub mod ffi {
fn getMinRelayTxFee() -> u64;
fn getEthPrivKey(key_id: [u8; 20]) -> [u8; 32];
fn getStateInputJSON() -> String;
fn getHighestBlock() -> i32;
fn getCurrentHeight() -> i32;
fn pastChangiIntermediateHeight2() -> bool;
}
}
12 changes: 12 additions & 0 deletions lib/ain-cpp-imports/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -49,6 +49,12 @@ mod ffi {
pub fn getStateInputJSON() -> String {
unimplemented!("{}", UNIMPL_MSG)
}
pub fn getHighestBlock() -> i32 {
unimplemented!("{}", UNIMPL_MSG)
}
pub fn getCurrentHeight() -> i32 {
unimplemented!("{}", UNIMPL_MSG)
}
pub fn pastChangiIntermediateHeight2() -> bool {
unimplemented!("{}", UNIMPL_MSG)
}
Expand Down Expand Up @@ -122,6 +128,12 @@ pub fn get_state_input_json() -> Option<String> {
}
}

pub fn get_sync_status() -> Result<(i32, i32), Box<dyn Error>> {
let current_block = ffi::getCurrentHeight();
let highest_block = ffi::getHighestBlock();
Ok((current_block, highest_block))
}

pub fn past_changi_intermediate_height_2_height() -> Result<bool, Box<dyn Error>> {
let height = ffi::pastChangiIntermediateHeight2();
Ok(height)
Expand Down
18 changes: 17 additions & 1 deletion lib/ain-evm/src/block.rs
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ use crate::storage::{traits::BlockStorage, Storage};

pub struct BlockHandler {
storage: Arc<Storage>,
first_block_number: U256,
}

pub struct FeeHistoryData {
Expand All @@ -24,7 +25,22 @@ pub const INITIAL_BASE_FEE: U256 = U256([10_000_000_000, 0, 0, 0]); // wei

impl BlockHandler {
pub fn new(storage: Arc<Storage>) -> 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)> {
Expand Down
1 change: 1 addition & 0 deletions lib/ain-grpc/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ pub mod codegen;
mod impls;
mod receipt;
pub mod rpc;
mod sync;
mod transaction;
mod transaction_log;
mod transaction_request;
Expand Down
41 changes: 39 additions & 2 deletions lib/ain-grpc/src/rpc/eth.rs
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ use ain_evm::evm::MAX_GAS_PER_BLOCK;
use ain_evm::executor::TxResponse;
use ain_evm::handler::Handlers;

use crate::sync::{SyncInfo, SyncState};
use crate::transaction_log::{GetLogsRequest, LogResult};
use ain_evm::storage::traits::{BlockStorage, ReceiptStorage, TransactionStorage};
use ain_evm::transaction::{SignedTx, TransactionError};
Expand Down Expand Up @@ -44,6 +45,9 @@ pub trait MetachainRPC {
#[method(name = "chainId")]
fn chain_id(&self) -> RpcResult<String>;

#[method(name = "syncing")]
fn syncing(&self) -> RpcResult<SyncState>;

// ----------------------------------------
// Block
// ----------------------------------------
Expand Down Expand Up @@ -255,7 +259,7 @@ impl MetachainRPCModule {
.get_block_by_number(&U256::from(n))
.map(|block| block.header.number)
.unwrap_or(U256::max_value())
},
}
_ => {
self.handler
.storage
Expand Down Expand Up @@ -590,7 +594,7 @@ impl MetachainRPCServer for MetachainRPCModule {
_ => {
return Err(Error::Custom(String::from(
"invalid transaction parameters",
)))
)));
}
};

Expand Down Expand Up @@ -743,6 +747,39 @@ impl MetachainRPCServer for MetachainRPCModule {
Ok(self.handler.block.suggested_priority_fee())
}

fn syncing(&self) -> RpcResult<SyncState> {
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:?}"))
})?;

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
.handler
.storage
.get_latest_block()
.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,
current_block,
highest_block,
}))
}
false => Ok(SyncState::Synced(false)),
}
}
fn get_uncle_count_by_block_number(&self) -> RpcResult<U256> {
Ok(Default::default())
}
Expand Down
30 changes: 30 additions & 0 deletions lib/ain-grpc/src/sync.rs
Original file line number Diff line number Diff line change
@@ -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<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
where
S: Serializer,
{
match *self {
SyncState::Synced(ref sync) => sync.serialize(serializer),
SyncState::Syncing(ref sync_info) => sync_info.serialize(serializer),
}
}
}
32 changes: 21 additions & 11 deletions src/ffi/ffiexports.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -44,9 +44,9 @@ rust::string publishEthTransaction(rust::Vec<uint8_t> 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();
Expand All @@ -58,8 +58,8 @@ rust::string publishEthTransaction(rust::Vec<uint8_t> rawTransaction) {
rust::vec<rust::string> getAccounts() {
rust::vec<rust::string> addresses;
std::vector<std::shared_ptr<CWallet>> const wallets = GetWallets();
for (const std::shared_ptr<CWallet>& wallet : wallets) {
for (auto & it : wallet->mapAddressBook)
for (const std::shared_ptr<CWallet> &wallet: wallets) {
for (auto &it: wallet->mapAddressBook)
if (std::holds_alternative<WitnessV16EthHash>(it.first)) {
addresses.push_back(EncodeDestination(it.first));
}
Expand All @@ -68,14 +68,14 @@ rust::vec<rust::string> 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<const char16_t*>(GetDataDir().c_str()));
#else
#else
return rust::String(GetDataDir().c_str());
#endif
#endif
}

rust::string getNetwork() {
Expand All @@ -86,7 +86,7 @@ uint32_t getDifficulty(std::array<uint8_t, 32> blockHash) {
uint256 hash{};
std::copy(blockHash.begin(), blockHash.end(), hash.begin());

const CBlockIndex* pblockindex;
const CBlockIndex *pblockindex;
uint32_t difficulty{};
{
LOCK(cs_main);
Expand All @@ -106,7 +106,7 @@ std::array<uint8_t, 32> getChainWork(std::array<uint8_t, 32> blockHash) {
uint256 hash{};
std::copy(blockHash.begin(), blockHash.end(), hash.begin());

const CBlockIndex* pblockindex;
const CBlockIndex *pblockindex;
std::array<uint8_t, 32> chainWork{};
{
LOCK(cs_main);
Expand Down Expand Up @@ -139,7 +139,8 @@ rust::vec<rust::string> getPoolTransactions() {
}

CCustomTxMessage txMessage{CEvmTxMessage{}};
const auto res = CustomMetadataParse(std::numeric_limits<uint32_t>::max(), Params().GetConsensus(), metadata, txMessage);
const auto res = CustomMetadataParse(std::numeric_limits<uint32_t>::max(), Params().GetConsensus(), metadata,
txMessage);
if (!res) {
continue;
}
Expand Down Expand Up @@ -188,7 +189,7 @@ uint64_t getMinRelayTxFee() {
std::array<uint8_t, 32> getEthPrivKey(std::array<uint8_t, 20> keyID) {
CKey ethPrivKey;
const auto ethKeyID = CKeyID{uint160{std::vector<uint8_t>(keyID.begin(), keyID.end())}};
for (const auto &wallet : GetWallets()) {
for (const auto &wallet: GetWallets()) {
if (wallet->GetEthKey(ethKeyID, ethPrivKey)) {
std::array<uint8_t, 32> privKeyArray{};
std::copy(ethPrivKey.begin(), ethPrivKey.end(), privKeyArray.begin());
Expand All @@ -202,6 +203,15 @@ 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 ::ChainActive().Height() ? (int) ::ChainActive().Height() : -1;
}

bool pastChangiIntermediateHeight2() {
return ::ChainActive().Height() >= Params().GetConsensus().ChangiIntermediateHeight2;
}
2 changes: 2 additions & 0 deletions src/ffi/ffiexports.h
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,8 @@ uint64_t getNativeTxSize(rust::Vec<uint8_t> rawTransaction);
uint64_t getMinRelayTxFee();
std::array<uint8_t, 32> getEthPrivKey(std::array<uint8_t, 20> keyID);
rust::string getStateInputJSON();
int getHighestBlock();
int getCurrentHeight();
bool pastChangiIntermediateHeight2();

#endif // DEFI_FFI_FFIEXPORTS_H