From fc4a54b282a187987fbd2d248ffadffcdcf4cf10 Mon Sep 17 00:00:00 2001 From: DrPing Date: Fri, 16 Jun 2023 13:04:12 +0800 Subject: [PATCH] Add vmmap RPC and EVM hash indexes (#2018) * Add send to try block * Fix Linux builds * Fix eth_* RPC casing * Ignore *.bin from persistent state * Use a single-use context when context == 0 * Panic when wrong input format * Change to_eth_case fallback to lowercase casing * Use owner address as Eth miner address * Fix test build on Linux * Get updated owner for EVM miner if changed * Fix make.sh git hook, unsafe complaints * Fix commiting the test path * Update pkg_name with correct one * Switch to pre-commit hook to pre-push * Fix to_eth_case for non eth_* RPCs * Add Eth_Accounts RPC (#1916) * Add Eth_Accounts RPC * Return only Eth addresses in eth_accounts RPC * Resolve issues with RPC and address behaviour (#1919) * Simpler impl with #[rpc(server) macro * Clippy cleanup * Revert test changes * Cargo fmt * Quick fix * Add latest fork to getblockchaininfo * Bump regtest grpc ports to avoid conflict with devnet * Update RPC * Skip IsMine for destination address * Write Eth address on creation --------- Co-authored-by: jouzo Co-authored-by: Shoham Chakraborty * Reset fork height * Devnet hard fork at 1,586,750 * Fix eth_call output * Run individual Python tests via make.sh * Fix hex import * For mocknet use operator key as miner address * Cleanup RPC/gRPC server codegen (#1922) * Cleanup RPC/gRPC server codegen * Fix warnings * Additional cleanup and prettyplease types output * add hashrate RPC (#1921) * Restore load evm state on startup * Add mc_getState RPC call to debug EVMState + cleanup * Fix eth_hashrate * Add mock eth_gasPrice RPC * Add back eth_accounts logic for RPC (#1923) * Add few example debug call * Add evm balances to gettokenbalances (#1924) * WIP add EVM balances to gettokenbalances * Correct variable name * Add feature_evm to runnable tests * Remove combined log from test_py * Convert WEI to Sats * Do not try and restore inputs on an EVM TX * Add used_gas to TxResponse * Resolve datadir through FFI (#1925) * Resolve datadir through FFI * Fix format * Create evm dir * Fix EVM TX sending and receiving * Check nonce in EVM TX * Clean up rust double builds, respect debug builds * Add cargo.toml workaround undefined symbols * Disable unviable tests * Cleanup * fmt * Implement evm RPC into test framework (#1926) * Remove script test case that uses OP_SHA3 opcode * Modification of test framework to connect to evm RPC, and to correctly handle evm RPC to the correct jsonrpc port on defid node * Fix bug to not remove evm directory after initializing chain * Fix rpc_help functional test to include evm component. Fix rust lib env_logger to direct logs to stdout instead of the default stderr. * Create eth_rpc port and url utility functions, included chain initialization of ethrpcport inside datadir * Revert args in test-py * Add EVM JSON RPC port into chain param (#1929) * New port in chain params for eth-json-rpc. includes pipeline to read new arg ethrpcport when starting node. * Using ..50 for GRPC and ..51 for ETH JRPC * Fix port numbers * Update lib/ain-grpc/src/lib.rs * Update make.sh * Update make.sh --------- Co-authored-by: Bushstar Co-authored-by: Prasanna Loganathar * Clean up builds.rs, separate ffi impls and stub tests * Cleanup warnings, fmt * evm: Rename finalize_block (#1928) * Rename finalize_block * Revert "Rename finalize_block" This reverts commit efdfbc314da0c9a72abc440fe3f9bd1966975a5d. * Rename FFI call * Fixes to CI build workflows for dev, staging and production pipelines into feature/evm (#1906) * Enable aarch64-apple-darwin builds (#1893) (#1894) * Build pipeline for building on arm64 macOS host architecture. Included CI build workflow for building the arm64 binaries * Rename to aarch64-apple-darwin to resolve build dependency bug * Amended markdown documentation (cherry picked from commit 29e10bee147c68c22583f8a5752ee4db0e211689) * CI workflow fixes for dev, staging and production pipelines * Fix naming bug * Removed publishing to dockerhub pipeline in build staging workflow, and renamed "mac" to "osx" * Added workflow to push arm build image into Dockerhub. Rename docker tag convention to differentiate arm and x64 build images. * Fix docker tags * Reverting changes to pushing only linux-x64 into dockerhub registry. * Include image layer to install rust dependencies * Install protobuf-compiler pkg dep * bug fixes * Fix bug in pkg_local_ensure_osx_sysroot function that does not exit out of entered dir if the package exists. Include new gnu-tar support for macos in platform_init function to support tar --transform on macos * Install target toolchains in dockerfiles * Fix target toolchain for linux-arm docker build * Resolve rustc toolchain bug * Removed optional label in proto3 syntax to fix build error * Fix _tar func in make.sh to pass all args to gnu-tar, and fix docker release build workflow to only push x64 linux to docker registry. * Re-order build targets to select major dev envs first. * Fix merge errors * Revert to feature/evm branch version * Reverting eth.proto version to feature/evm version t Please enter the commit message for your changes. Lines starting * Debug fail tx * Add exit_reason to validate_raw_tx Err * Get block difficulty and chain work of block via CPP FFI (#1931) * FFI: Get block difficulty and chain work of block * Pass difficulty to finalise_block * Do not store total_difficulty * Move start servers to AppInitMain (#1930) * Add EVM functional tests (#1932) * Cleanup RPC error * Initial functional test of EVM rpc * Metachain JSON-RPC CLI (#1934) * Cleanup RPC error * Initial functional test of EVM rpc * Metachain JSON-RPC CLI * Format output * Fix help message * Move default target into build-dir * Add missing size field to RpcBlock (#1935) * Fix rust release build detection, build rs change detect, move types out of source (#1936) * Cleanup make.sh * Use gcc for depends * Add debug-env * Revert the rust, proto change in dockerfiles (#1937) * fix build and make.sh script * Update make.sh --------- Co-authored-by: Prasanna Loganathar * evm: Transaction receipts (#1927) * Minor make.sh cleanups * Mark items that needs fixing * Add git tree dirty check on hook * Add 0x to block size * Set block gas limit * Resolve make check errors (#1939) * eth_getpendingtransactions (#1933) * WIP eth_getpendingtransactions * Update for base branch and fmt * Complete eth_pendingTransactions impl * rustfmt rpc.rs * Move code to impls.rs * Fix errors on git push * Resolve compile errors after merge * Test EVM Tx showing in EVM block * Corrections * Cargo fmt * Use helper functions * evm: Update get_contract_address to return H160 (#1942) * Change get_contract_address to return H160 * Update test * Remove todo note * Add beneficiary, logs_bloom and gas_used to block (#1945) * Add deprecated mining stubs (#1943) * fix(lib/ain-cpp-imports): conditionally specific stdlib (#1948) * conditionally target lib based on diff os * fmt * use macro for conditinal compilation * Add lab project scaffolds (#1938) * Add scaffold for grpc-v2 * Add flatten serde checks * Use Request/Response convention to avoid confusion with `Result` types * Add missing doc for RPCs * Add 0x to block size * Set block gas limit * Resolve make check errors (#1939) * eth_getpendingtransactions (#1933) * WIP eth_getpendingtransactions * Update for base branch and fmt * Complete eth_pendingTransactions impl * rustfmt rpc.rs * Move code to impls.rs * Fix errors on git push * Resolve compile errors after merge * Test EVM Tx showing in EVM block * Corrections * Cargo fmt * Use helper functions * Use untagged enums * Cleanup, add servers * Cleanup mod * Add part of missing doc for proto messages * Add missing doc for proto messages * evm: Update get_contract_address to return H160 (#1942) * Change get_contract_address to return H160 * Update test * Remove todo note * Add beneficiary, logs_bloom and gas_used to block (#1945) * Add deprecated mining stubs (#1943) * fix(lib/ain-cpp-imports): conditionally specific stdlib (#1948) * conditionally target lib based on diff os * fmt * use macro for conditinal compilation * Cleanup gitignore * Add lab crates * Enable rust build * cargo fmt --------- Co-authored-by: DrPing Co-authored-by: Bushstar Co-authored-by: Shoham Chakraborty Co-authored-by: Jouzo <15011228+Jouzo@users.noreply.github.com> Co-authored-by: canonbrother * Use protobuf-src instead of external dep * Remove protoc lib includes * Resolve depends build issues * Consolidate persistent state to BlockchainDataHandler struct (#1944) * Consolidate persistent state to BlockchainDataHandler struct * Update cache after cache miss * Get receipts root before creating block * Update deps, add protobuf-src into runtime deps * Fix protobuf-src compilation * Use self contained rust toolchain * CI workflow for EVM RPC testing (#1821) * Add workflow for testing evm rpc * Add test workflow for EVM RPCs * Rename EVM RPC Test * Rename tests * Rename workflow job * Fix typo on environment var on CI * Rename tag 'test/rpc_evm' to 'evm' * Set NODE_URL to point devnet * estimateGas and gasPrice RPC implementations (#1940) * estimateGas and gasPrice rpc and ffi * Remove protoc lib includes * Resolve depends build issues * Consolidate persistent state to BlockchainDataHandler struct (#1944) * Consolidate persistent state to BlockchainDataHandler struct * Update cache after cache miss * Get receipts root before creating block * Update deps, add protobuf-src into runtime deps * Fix protobuf-src compilation * Use self contained rust toolchain * CI workflow for EVM RPC testing (#1821) * Add workflow for testing evm rpc * Add test workflow for EVM RPCs * Rename EVM RPC Test * Rename tests * Rename workflow job * Fix typo on environment var on CI * Rename tag 'test/rpc_evm' to 'evm' * Set NODE_URL to point devnet --------- Co-authored-by: Prasanna Loganathar Co-authored-by: Jouzo <15011228+Jouzo@users.noreply.github.com> Co-authored-by: dCorral <55594560+dcorral@users.noreply.github.com> Co-authored-by: canonbrother * CPP changes from master * Restore updated test * Fix exposed ports, env path variables (#1962) * Remove unwrap * Proto documentation (#1970) * Add partial doc example for proto messages * Add remaning doc example for proto messages * Replace line comment by block comment * Update doc proto messages * Update doc proto messages * Update doc proto messages * Update doc proto messages * Update doc proto messages * Fix doc error * Add more examples to proto messages doc and fix formating * fix feature evm rpc tests (#1972) * EVM State Trie (#1973) * Debug send_raw_transaction and return RPC error when could not publish eth tx via cpp_imports (#1975) * Add query by blockNumber RPC changes to metachain-cli (#1977) * Remove EVMState tests * Add latest RPC changes to CLI * Handle full_transactions flag in getBlock* RPCs (#1976) * Handle full_transactions flag in getBlock* RPCs * Few RPCs type fixes * Remove EVM block update after creation (#1978) * Add debug log and fix NoSuchAccount error * Don't mutate block after creation * Refactor and rename transferbalance to transferdomain (#1966) * Refactor transferbalance * Rename transfer types, use intiger in rpc for type, adapt test. * EVM RPC improvements (#1979) * Takes eth_call input as Bytes * Add dump_db debug RPC call * Add clang-15 to Ubuntu build instructions * Fix eth json RPC issue when running DFI in containerized environment (#1967) * Change ip to 0.0.0.0 * Fix rust log output in init_runtime * Include arg to pass address:port to bind eth rpc server * Include pipeline to bind gRPC address to gRPC server * Remove passing default ipv6 address to eth rpc and grpc servers * Include rust export to pass command line args into init function, and refactor to create init_evm_runtime function * Fix init_evm_runtime to be called after base chain params is initialized * Fix clippy linter warnings * Fix safety lint warning * Shift unsafe init function into ain-exports lib, wraps ain-grpc init * Fix lint * Rebroadcast and restore failed transactions to mempool (#1965) * Rebroadcast failed TXs * Takes native tx as input and use it to return fail txs * Update CPP FFI calls so code compiles * Return failed EvmIn/Out native tx hashes * WIP miner remove failed TXs. ConnectBlock revert failed TXs. * Update tests for new RPC name * Rename TransferBalance * Miner remove coinbase fees for failed TXs * Revert failed TransferDomain in ConnectBlock --------- Co-authored-by: jouzo * Trickle down block timestamp to EVM (#1980) * Merge branch 'master' into feature/evm * Clean up after merge * Remove unused include * lint: correct and include RPC argument names * lint: Update guards * lint: remove func with locale dep * lint: resolve Python errors * Pay gas to miner (#1981) * Move .vsdb to evm subfolder * Build cleanup, enable CI, fix logs (#1982) * Clean up build, separate rust toolchain * Windows build fixes * Cleanup builds, add protoc, noarch dockerfile * lint: correct and include RPC argument names * lint: Update guards * lint: remove func with locale dep * lint: resolve Python errors * Use c style header for c compile set * Delegate tests to makefile * Refactor lints and run through makefile * fmt * Remove clang builds from CI * Fix stable builds, fmt * Fix build dep * Update deps, patch vsdb, use our open forked versions --------- Co-authored-by: Peter Bushnell * Add package hashes * Fix default input * Add cross compile deps * Add second seed node * Add seeders as pnSeeds * Add transferdomain type to conversion table * Update to static IP * Change default builds to debug, fix fmt checks * Fix warnings * Add debug in validate raw tx * Get private key for Eth address (#1983) * evm: Fix receipts log output (#1985) * Fix receipts result output * Formatting * Return hex encoded index * Make logIndex index across block instead of transaction * Formatting * Track cumulative gas usage * Use enumerate * Fix build and warnings * Coinbase placeholder Eth block hash (#1986) * Coinbase placeholder Eth block hash * cargo fmt * Filter out TransferDomain TXs (#1988) * Add vinicity to EVM execution and update on each TX (#1987) * Remove receipt clones (#1989) * Restore check account balance on EvmOut RPC call (#1990) * evm: fix gas estimates (#1992) * Do not modify gas usage in estimate_gas * Set default gas limit to maximum * Fix warnings * Fix formatting * fix cross build target os * Fix debug format * Downgrade block_number RPC log level to trace * Add missing import * Fix failing EVM tests (#1995) * Fix EVM tests * Change to 0x for explorer compatibility * Remove setting of gas * chore(test): add `eth_sendRawTransaction` test (#1998) * add eth_sendRawTransaction test * rm print * move test to clean set up * Set correct Eth block hash in coinbase TX (#1993) * Read-only state root * Set correct Eth block hash in coinbase TX * Match fee to eth block --------- Co-authored-by: jouzo * feat(lib): add rpc `eth_sendTransaction` (#1984) * getprivkey * getprivkey from GetWallets * add rpc eth_sendtx * fix cross build target os * Change default builds to debug, fix fmt checks * fix getchainid * rm ffi::getprivkey, use ffi::getethprivkey * use h160.asfixedbytes * should use encoded signed tx * add eth_sendTransaction test --------- Co-authored-by: Prasanna Loganathar * Fix serialisation error * Return correct data encoding * Split up RPC namespaces (#2006) * RPC: call and estimateGas at specific block height (#2005) Co-authored-by: Shoham Chakraborty * Add RPC to get equivalent eth address from BTC address * Bump evm version and use shanghai config (#2009) * Document ain-rs-exports FFI calls. (#2004) Co-authored-by: Shoham Chakraborty * Check pointer is valid (#2008) * evm: Allow failed tx in `eth_sendRawTransaction` (#2003) * Do not validate EVM TX * Do not skip TX validation --------- Co-authored-by: Jouzo <15011228+Jouzo@users.noreply.github.com> * Fix warning (#2010) Co-authored-by: jouzo * Rollback latest EVM block (#2002) * Rename to prevalidate_raw_tx * Fix mapping EVM to DVM addresses * Add type parameter for evmmap RPC * Don't panic when restoring old code_map structure * Fix RPC names * Return reason for failure (#2012) Co-authored-by: Peter Bushnell * add mapping for dfi tx to evm tx (not working) * fix(evm): fix eth block type `nonce` & `extra_data` (#2015) * change extra_data type Vec to Bytes * change block nonce type U256 to H64 * fix req * Rename DFI to DVM for evmmap RPC * Remove unsed code in evmmap RPC * Fix evmmap RPC for tx from DVM to EVM * CI workflow for EVM test suites (#2017) * Include feature evm test suites into CI workflow * Fix indentation * Include workflow trigger when PR is made into feature/evm branch * Fix dependency bug * Fix superuser privileges * fix indentation and filepath * Separate build stage and rpc tests into different jobs * Fix bug for running test suite * Debug log * add fixtures.sh * on trigger push & target tag evm * pump required flags for defid cmd * Remove debug logs * clean * path correction & some refined * pretty print defid * add foundation member fixtures * revert pretty print defid * fix defid * pre-note contract addr --------- Co-authored-by: canonbrother * Fix default gas in eth_call * Adding block map indexes * Change block hash arg names for clarity * Fix bug for variable naming * state check for eth_getBlockByNumber == eth_getBlockByHash * Add RPC to convert block from EVM and DVM (not working) * Fix bug to use unique instance of customview * fix(evm): diff signer on tx2 and tx3 (#2022) * log * map access_list correctly * chore(py): impr `eth_sendtx` and `eth_sendrawtx` test (#2013) * wip * log * map access_list correctly * rm pdb * fix sendrawtx test * refine note * Fix publishEthTransaction catch error type * Include method to remove block index, update to rollback pipeline * test: fix intermittent updatemasternode test failure (#1996) * test: add eth port to bind test (#1994) * test: add eth port to bind test * update loopback bind test * lint: fix incorrectly identified dead code * lint: remove whitespace * lint: add expected export to first line of script * Fix evmmaptype to enum class, return JSON error for invalid evmmap RPC * lint: set bash before export * Reorder cases * Add ox prefix when mapping dvm to evm address * lint: comment unused vars in script * Refactor mapping order * Refactor get block hash from custom db to return Res type * Fix bugs * Fix indexing of EVM/DVM block * Refactor to use ResVal for evmmap db * Return Eth addresses with EIP-55 checksum applied (#2024) * Return Eth addresses with EIP-55 checksum applied * Update src/key_io.cpp * Fix formatting in added comments --------- Co-authored-by: Prasanna Loganathar * fix eth checksum addr (#2028) * test: test checksum address * evm: Support contracts in functional tests (#2023) * Add contract compilation and interaction to Python tests * Fix path * Clean up test * Change function name * Refactor to EVMProvider and KeyPair * Move files to test_framework * Add EVMProvider to TestNode * Add static from_node method to KeyPair * Add static from_file method to EVMContract * Add static from_node method to EVMProvider * Remove web3 checksum * refactor(workflows): move `./scripts/fixtures.sh` to `.github` (#2030) * move scripts/fixtures.sh to .github * update bob addr to checksum addr * Add evmmap function for transaction * Include EVM mnview in rollback. Convert miner fee to Sats. (#1999) * Convert miner fee to Sats * Move evm_finalize to ProcessDefi and include mnview changes in rollback * Fix error message * Remove debug lines * Rename evmmap RPC into xvmmap * Move EVM state changes to outside Connect/DisconnectBlock (#2032) * Demo work in progress code * Add iter method to keep transaction in queue instead of draining * Remove print from test * Rename iter to get_cloned_vec * Use get_cloned_vec * Update code after merge --------- Co-authored-by: jouzo * Fix logic for xvmmap RPC * Feature guard evm_finalize * lint: add known local deps * Remove free string and require for file evm.cpp * test: use arg for gas price * test: set utf8 encoding on open * Remove SPV calls * Remove useless code for validation and fix import * Add web3 test dependencies (#2033) * Install solc from make.sh * Add pkg_install_solc to ci_setup_deps * Install web3.py in make.sh * Restore ProcessEVMQueue * Make VMDomain class enum * Move tx mapping logic * Fix non void function not returning anything * Fix non void function not returning anything * Add logxvmindexes RPC * Fix crash when getting block and tx * Add test for xvmmap * Fix merge from master to feature/evmmap * Add setBlockHash indexes * Fix test xvmmap * Replace pcustomcsview by mnview * Replace call from pustomcsview to a cache * Remove unused function * Add lock before calling pcustomcsview * Remove previous commit that was deleted * Refactor * Minor cleanup * Fix vmmap RPC * Throw errro instead of returning string when unknown type in vmmap * Add more test cases for vmmap * Fix logic for vmmap RPC * Fix logic vmmap RPC * Add comments * Format comments * Add more TODO comments * Format comments * Fix lints --------- Co-authored-by: Bushstar Co-authored-by: Mihailo Milenkovic Co-authored-by: jouzo Co-authored-by: Prasanna Loganathar Co-authored-by: Shoham Chakraborty Co-authored-by: Jouzo <15011228+Jouzo@users.noreply.github.com> Co-authored-by: Niven Co-authored-by: canonbrother Co-authored-by: dCorral <55594560+dcorral@users.noreply.github.com> --- src/Makefile.am | 1 + src/masternodes/errors.h | 4 + src/masternodes/evm.cpp | 44 +++++++++ src/masternodes/evm.h | 24 +++++ src/masternodes/masternodes.h | 6 +- src/masternodes/mn_checks.cpp | 6 ++ src/masternodes/rpc_evm.cpp | 138 ++++++++++++++++++++++++++++- src/masternodes/validation.cpp | 5 ++ src/rpc/client.cpp | 2 + test/functional/feature_evm_rpc.py | 36 +++++++- 10 files changed, 262 insertions(+), 4 deletions(-) create mode 100644 src/masternodes/evm.cpp diff --git a/src/Makefile.am b/src/Makefile.am index 7d380b6cf87..dd39d3d3c4d 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -397,6 +397,7 @@ libdefi_server_a_SOURCES = \ masternodes/accountshistory.cpp \ masternodes/anchors.cpp \ masternodes/auctionhistory.cpp \ + masternodes/evm.cpp \ masternodes/govvariables/attributes.cpp \ masternodes/govvariables/icx_takerfee_per_btc.cpp \ masternodes/govvariables/loan_daily_reward.cpp \ diff --git a/src/masternodes/errors.h b/src/masternodes/errors.h index e43080a4d42..6595d12d8d4 100644 --- a/src/masternodes/errors.h +++ b/src/masternodes/errors.h @@ -441,6 +441,10 @@ class DeFiErrors { static Res TransferDomainInvalidDestinationDomain() { return Res::Err("Invalid domain set for \"dst\" argument"); } + + static Res DatabaseRWFailure(const std::string key) { + return Res::Err("DB r/w failure: %s", key); + } }; #endif // DEFI_MASTERNODES_ERRORS_H diff --git a/src/masternodes/evm.cpp b/src/masternodes/evm.cpp new file mode 100644 index 00000000000..11950e358be --- /dev/null +++ b/src/masternodes/evm.cpp @@ -0,0 +1,44 @@ +#include +#include +#include +#include + +Res CVMDomainMapView::SetVMDomainMapBlockHash(uint8_t type, uint256 blockHashKey, uint256 blockHash) +{ + return WriteBy(std::pair(type, blockHashKey), blockHash) ? Res::Ok() : DeFiErrors::DatabaseRWFailure(blockHashKey.GetHex()); +} + +ResVal CVMDomainMapView::GetVMDomainMapBlockHash(uint8_t type, uint256 blockHashKey) const +{ + uint256 blockHash; + if (ReadBy(std::pair(type, blockHashKey), blockHash)) + return ResVal(blockHash, Res::Ok()); + return DeFiErrors::DatabaseRWFailure(blockHashKey.GetHex()); +} + +Res CVMDomainMapView::SetVMDomainMapTxHash(uint8_t type, uint256 txHashKey, uint256 txHash) +{ + return WriteBy(std::pair(type, txHashKey), txHash) ? Res::Ok() : DeFiErrors::DatabaseRWFailure(txHashKey.GetHex()); +} + +ResVal CVMDomainMapView::GetVMDomainMapTxHash(uint8_t type, uint256 txHashKey) const +{ + uint256 txHash; + if (ReadBy(std::pair(type, txHashKey), txHash)) + return ResVal(txHash, Res::Ok()); + return DeFiErrors::DatabaseRWFailure(txHashKey.GetHex()); +} + +void CVMDomainMapView::ForEachVMDomainMapBlockIndexes(std::function &, const uint256 &)> callback) { + ForEach, uint256>( + [&callback](const std::pair &key, uint256 val) { + return callback(key, val); + }); +} + +void CVMDomainMapView::ForEachVMDomainMapTxIndexes(std::function &, const uint256 &)> callback) { + ForEach, uint256>( + [&callback](const std::pair &key, uint256 val) { + return callback(key, val); + }); +} \ No newline at end of file diff --git a/src/masternodes/evm.h b/src/masternodes/evm.h index cd9dc4da6d9..fcdf2c94138 100644 --- a/src/masternodes/evm.h +++ b/src/masternodes/evm.h @@ -26,4 +26,28 @@ struct CEvmTxMessage { } }; +enum VMDomainMapType : uint8_t { + DVMToEVM = 0x01, + EVMToDVM = 0x02, +}; + +class CVMDomainMapView : public virtual CStorageView { +public: + Res SetVMDomainMapBlockHash(uint8_t type, uint256 blockHashKey, uint256 blockHash); + ResVal GetVMDomainMapBlockHash(uint8_t type, uint256 blockHashKey) const; + void ForEachVMDomainMapBlockIndexes(std::function &, const uint256 &)> callback); + + Res SetVMDomainMapTxHash(uint8_t type, uint256 txHashKey, uint256 txHash); + ResVal GetVMDomainMapTxHash(uint8_t type, uint256 txHashKey) const; + void ForEachVMDomainMapTxIndexes(std::function &, const uint256 &)> callback); + + struct VMDomainBlockHash { + static constexpr uint8_t prefix() { return 'N'; } + }; + + struct VMDomainTxHash { + static constexpr uint8_t prefix() { return 'e'; } + }; +}; + #endif // DEFI_MASTERNODES_EVM_H diff --git a/src/masternodes/masternodes.h b/src/masternodes/masternodes.h index 62a22962043..f0c8ce80238 100644 --- a/src/masternodes/masternodes.h +++ b/src/masternodes/masternodes.h @@ -445,7 +445,8 @@ class CCustomCSView : public CMasternodesView, public CLoanView, public CVaultView, public CSettingsView, - public CProposalView { + public CProposalView, + public CVMDomainMapView { // clang-format off void CheckPrefixes() { @@ -477,7 +478,8 @@ class CCustomCSView : public CMasternodesView, LoanInterestV3ByVault, CVaultView :: VaultKey, OwnerVaultKey, CollateralKey, AuctionBatchKey, AuctionHeightKey, AuctionBidKey, CSettingsView :: KVSettings, - CProposalView :: ByType, ByCycle, ByMnVote, ByStatus + CProposalView :: ByType, ByCycle, ByMnVote, ByStatus, + CVMDomainMapView :: VMDomainBlockHash, VMDomainTxHash >(); } // clang-format on diff --git a/src/masternodes/mn_checks.cpp b/src/masternodes/mn_checks.cpp index 43c21f250ff..cbb2302377e 100644 --- a/src/masternodes/mn_checks.cpp +++ b/src/masternodes/mn_checks.cpp @@ -3875,6 +3875,12 @@ class CCustomTxApplyVisitor : public CCustomTxVisitor { gasUsed = hashAndGas.used_gas; + std::vector evmTxHashBytes; + sha3(obj.evmTx, evmTxHashBytes); + auto txHash = tx.GetHash(); + auto evmTxHash = uint256(evmTxHashBytes); + mnview.SetVMDomainMapTxHash(VMDomainMapType::DVMToEVM, txHash, evmTxHash); + mnview.SetVMDomainMapTxHash(VMDomainMapType::EVMToDVM, evmTxHash, txHash); return Res::Ok(); } diff --git a/src/masternodes/rpc_evm.cpp b/src/masternodes/rpc_evm.cpp index 3823d215851..9b9938bf6d7 100644 --- a/src/masternodes/rpc_evm.cpp +++ b/src/masternodes/rpc_evm.cpp @@ -4,6 +4,24 @@ #include #include +enum class VMDomainRPCMapType { + Auto, + AddressDVMToEVM, + AddressEVMToDVM, + TxHashDVMToEVM, + TxHashEVMToEVM, + BlockHashDVMToEVM, + BlockHashEVMToDVM +}; + +static int VMDomainRPCMapTypeCount = 7; + +enum class VMDomainIndexType { + BlockHash, + TxHash +}; + + UniValue evmtx(const JSONRPCRequest& request) { auto pwallet = GetWallet(request); @@ -122,11 +140,129 @@ UniValue evmtx(const JSONRPCRequest& request) { return send(MakeTransactionRef(std::move(rawTx)), optAuthTx)->GetHash().ToString(); } + +UniValue vmmap(const JSONRPCRequest& request) { + auto pwallet = GetWallet(request); + RPCHelpMan{"vmmap", + "Give the equivalent of an address, blockhash or transaction from EVM to DVM\n", + { + {"hash", RPCArg::Type::STR, RPCArg::Optional::NO, "DVM address, EVM blockhash, EVM transaction"}, + {"type", RPCArg::Type::NUM, RPCArg::Optional::NO, "Type of mapping: 1 - DFI Address to EVM, 2 - EVM to DFI Address, 3 - DFI Tx to EVM, 4 - EVM Tx to DFI, 5 - DFI Block to EVM, 6 - EVM Block to DFI"} + }, + RPCResult{ + "\"hash\" (string) The hex-encoded string for address, block or transaction\n" + }, + RPCExamples{ + HelpExampleCli("vmmap", R"('""' 1)") + }, + }.Check(request); + const std::string hash = request.params[0].get_str(); + + if (request.params[1].get_int() >= VMDomainRPCMapTypeCount) { + throw JSONRPCError(RPC_INVALID_PARAMETER, strprintf("Invalid parameters, argument \"type\" must be less than %d.", VMDomainRPCMapTypeCount)); + } + const auto type = static_cast(request.params[1].get_int()); + switch (type) { + case VMDomainRPCMapType::AddressDVMToEVM: { + const CPubKey key = AddrToPubKey(pwallet, hash); + return EncodeDestination(WitnessV16EthHash(key.GetID())); + } + case VMDomainRPCMapType::AddressEVMToDVM: { + const CPubKey key = AddrToPubKey(pwallet, hash); + return EncodeDestination(PKHash(key.GetID())); + } + default: + break; + } + + LOCK(cs_main); + + ResVal res = ResVal(uint256{}, Res::Ok()); + switch (type) { + case VMDomainRPCMapType::TxHashDVMToEVM: { + res = pcustomcsview->GetVMDomainMapTxHash(VMDomainMapType::DVMToEVM, uint256S(hash)); + break; + } + case VMDomainRPCMapType::TxHashEVMToEVM: { + res = pcustomcsview->GetVMDomainMapTxHash(VMDomainMapType::EVMToDVM, uint256S(hash)); + break; + } + case VMDomainRPCMapType::BlockHashDVMToEVM: { + res = pcustomcsview->GetVMDomainMapBlockHash(VMDomainMapType::DVMToEVM, uint256S(hash)); + break; + } + case VMDomainRPCMapType::BlockHashEVMToDVM: { + res = pcustomcsview->GetVMDomainMapBlockHash(VMDomainMapType::EVMToDVM, uint256S(hash)); + break; + } + default: { + throw JSONRPCError(RPC_INVALID_PARAMETER, "Unknown map type"); + } + } + if (!res) { + throw JSONRPCError(RPC_INVALID_REQUEST, res.msg); + } else { + return res.val->ToString(); + } +} + +UniValue logvmmaps(const JSONRPCRequest& request) { + RPCHelpMan{ + "logvmmaps", + "\nLogs all block or tx indexes for debugging.\n", + { + {"type", RPCArg::Type::NUM, RPCArg::Optional::NO, "Type of log: 0 - Blocks, 1 - Txs"} + }, + RPCResult{ + "{...} (array) Json object with account balances if rpcresult is enabled." + "This is for debugging purposes only.\n"}, + RPCExamples{ + HelpExampleCli("logvmmaps", R"('""' 1)")}, + }.Check(request); + + LOCK(cs_main); + + size_t count{}; + UniValue result{UniValue::VOBJ}; + UniValue indexesJson{UniValue::VOBJ}; + const auto type = static_cast(request.params[0].get_int()); + // TODO: For now, we iterate through the whole list. But this is just a debugging RPC. + // But there's no need to iterate the whole list, we can start at where we need to and + // return false, once we hit the limit and stop the iter. + switch (type) { + case VMDomainIndexType::BlockHash: { + pcustomcsview->ForEachVMDomainMapBlockIndexes([&](const std::pair &index, uint256 blockHash) { + if (index.first == VMDomainMapType::DVMToEVM) { + indexesJson.pushKV(index.second.GetHex(), blockHash.GetHex()); + ++count; + } + return true; + }); + } + case VMDomainIndexType::TxHash: { + pcustomcsview->ForEachVMDomainMapTxIndexes([&](const std::pair &index, uint256 txHash) { + if (index.first == VMDomainMapType::DVMToEVM) { + indexesJson.pushKV(index.second.GetHex(), txHash.GetHex()); + ++count; + } + return true; + }); + } + } + + result.pushKV("indexes", indexesJson); + result.pushKV("count", static_cast(count)); + return result; +} + + static const CRPCCommand commands[] = { // category name actor (function) params // --------------- ---------------------- --------------------- ---------- - {"evm", "evmtx", &evmtx, {"from", "nonce", "gasPrice", "gasLimit", "to", "value", "data"}}, + {"evm", "evmtx", &evmtx, {"from", "nonce", "gasPrice", "gasLimit", "to", "value", "data"}}, + {"evm", "vmmap", &vmmap, {"hash", "type"}}, + {"evm", "logvmmaps", &logvmmaps, {"type"}}, }; void RegisterEVMRPCCommands(CRPCTable& tableRPC) { diff --git a/src/masternodes/validation.cpp b/src/masternodes/validation.cpp index 1c7b0f5e37e..b5fba7340c3 100644 --- a/src/masternodes/validation.cpp +++ b/src/masternodes/validation.cpp @@ -2428,6 +2428,11 @@ static void ProcessEVMQueue(const CBlock &block, const CBlockIndex *pindex, CCus } const auto blockResult = evm_finalize(evmContext, false, block.nBits, beneficiary, block.GetBlockTime()); + auto evmBlockHash = std::vector(blockResult.block_hash.begin(), blockResult.block_hash.end()); + std::reverse(evmBlockHash.begin(), evmBlockHash.end()); + + cache.SetVMDomainMapBlockHash(VMDomainMapType::DVMToEVM, block.GetHash(), uint256(evmBlockHash)); + cache.SetVMDomainMapBlockHash(VMDomainMapType::EVMToDVM, uint256(evmBlockHash), block.GetHash()); if (!blockResult.failed_transactions.empty()) { std::vector failedTransactions; diff --git a/src/rpc/client.cpp b/src/rpc/client.cpp index 60930cb5477..4be111dd1af 100644 --- a/src/rpc/client.cpp +++ b/src/rpc/client.cpp @@ -365,6 +365,8 @@ static const CRPCConvertParam vRPCConvertParams[] = { "evmtx", 2, "gasPrice" }, { "evmtx", 3, "gasLimit" }, { "evmtx", 5, "value" }, + { "vmmap", 1, "type"}, + { "logvmmaps", 0, "type"}, }; // clang-format on diff --git a/test/functional/feature_evm_rpc.py b/test/functional/feature_evm_rpc.py index 25bce70ce7d..90a2505fee1 100755 --- a/test/functional/feature_evm_rpc.py +++ b/test/functional/feature_evm_rpc.py @@ -153,6 +153,39 @@ def test_block(self): block = self.nodes[0].eth_getBlockByHash(latest_block['hash']) assert_equal(block, latest_block) + def test_vmmap(self): + # TODO: This PR isn't ready just yet without proper tests. + # Current tests are very basic. Need to add proper tests. + # Merging for now, for faster feedback loop. But this is a key to-do. + # Check if xvmmap is working for addresses + eth_address = '0x2E04dbc946c6473DFd318d3bE2BE36E5dfbdACDC' + address = self.nodes[0].vmmap(eth_address, 2) + assert_equal(eth_address, self.nodes[0].vmmap(address, 1)) + + # Check that vmmap is failing on wrong input + eth_address = '0x0000000000000000000000000000000000000000' + assert_raises_rpc_error(-5, "0x0000000000000000000000000000000000000000 does not refer to a key", self.nodes[0].vmmap, eth_address, 2) + assert_raises_rpc_error(-5, "Invalid address: test", self.nodes[0].vmmap, 'test', 1) + + #Check if xvmmap is working for Txs + list_tx = self.nodes[0].logvmmaps(1) + dvm_tx = list(list_tx['indexes'].keys())[0] + evm_tx = self.nodes[0].vmmap(dvm_tx, 3) + assert_equal(dvm_tx, self.nodes[0].vmmap(evm_tx, 4)) + + # Check vmmap fail on wrong tx + evm_tx = '0x0000000000000000000000000000000000000000000000000000000000000000' + assert_raises_rpc_error(-32600, "DB r/w failure: 0000000000000000000000000000000000000000000000000000000000000000", self.nodes[0].vmmap, evm_tx, 4) + + # Check if xvmmap is working for Blocks + latest_block = self.nodes[0].eth_getBlockByNumber("latest", False) + dvm_block = self.nodes[0].vmmap(latest_block['hash'], 6) + assert_equal(latest_block['hash'], "0x" + self.nodes[0].vmmap(dvm_block, 5)) + + # Check vmmap fail on wrong block + evm_block = '0x0000000000000000000000000000000000000000000000000000000000000000' + assert_raises_rpc_error(-32600, "DB r/w failure: 0000000000000000000000000000000000000000000000000000000000000000", self.nodes[0].vmmap, evm_block, 6) + def run_test(self): self.setup() @@ -163,11 +196,12 @@ def run_test(self): self.test_accounts() self.nodes[0].transferdomain([{"src": {"address":self.address, "amount":"100@DFI", "domain": 2}, "dst":{"address":self.ethAddress, "amount":"100@DFI", "domain": 3}}]) - self.nodes[0].generate(1) + self.nodes[0].generate(2) self.test_address_state(self.ethAddress) # TODO test smart contract self.test_block() + self.test_vmmap() if __name__ == '__main__':