Skip to content

Commit

Permalink
Merge branch 'develop' into 755_indexer_catch_inner_instruction_call
Browse files Browse the repository at this point in the history
  • Loading branch information
otselnik authored May 11, 2022
2 parents c5f5332 + 944737d commit 89a5565
Show file tree
Hide file tree
Showing 7 changed files with 75 additions and 28 deletions.
1 change: 1 addition & 0 deletions .dockerignore
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@
!run-airdropper.sh
!log_cfg.json
!pretty_log_cfg.json
!proxy-cli
!proxy-cli.sh
!health_check_proxy.sh
!health_check_faucet.sh
Expand Down
27 changes: 23 additions & 4 deletions proxy-cli/account.py
Original file line number Diff line number Diff line change
Expand Up @@ -18,8 +18,10 @@ def init_args_parser(parsers) -> AccountHandler:
h.subparsers = h.root_parser.add_subparsers(title='command', dest='subcommand', description='valid commands')
h.new_parser = h.subparsers.add_parser('new')
h.list_parser = h.subparsers.add_parser('list')
h.list_parser.add_argument('--private-key', action='store_true')
h.import_parser = h.subparsers.add_parser('import')
h.import_parser.add_argument('file', metavar='file', type=str, nargs=1, help='an input file with private key')
h.import_parser.add_argument('--private-key', type=str, nargs=1, help='private-key as parameterag')
h.import_parser.add_argument('file', metavar='file', type=str, nargs='?', help='an input file with private key')
return h

def execute(self, args):
Expand All @@ -39,7 +41,15 @@ def _execute_new(self, args):
print(f'Address: {"{"+str(eth_address)[2:]+"}"}')

def _execute_import(self, args):
file = args.file[0]
if args.file:
self._execute_import_file(args)
elif len(args.private_key):
self._execute_import_key(args)
else:
print(f"You should specify one of <file> or <private-key>", file=sys.stderr)

def _execute_import_file(self, args):
file = args.file
if not os.path.isfile(file):
print(f"File {file} doesn't exist", file=sys.stderr)
return
Expand All @@ -50,8 +60,17 @@ def _execute_import(self, args):
eth_address = self._storage.import_private_key(pk_key)
print(f'Address: {"{" + str(eth_address)[2:] + "}"}')

def _execute_import_key(self, args):
pk_key = bytes.fromhex(args.private_key[0])
eth_address = self._storage.import_private_key(pk_key)
print(f'Address: {"{" + str(eth_address)[2:] + "}"}')

def _execute_list(self, args):
eth_address_list = self._storage.get_list()
path = self._storage.storage_path()
for i, eth_address in enumerate(eth_address_list):
print(f'Account #{i}: {"{"+str(eth_address)[2:]+"}"} keystore:///{path}')
for i, eth_address in enumerate(sorted(eth_address_list, key=lambda x: str(x))):
s = f'Account #{i}: {"{"}{str(eth_address)[2:]}{"}"} keystore:///{path}'
if args.private_key:
s += f' private: {"{"}{str(eth_address.private)}{"}"}'

print(s)
2 changes: 1 addition & 1 deletion proxy/common_neon/emulator_interactor.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@
from logged_groups import logged_group

from typing import Optional, Dict, Any
from ethereum.transactions import Transaction as NeonTrx
from ..common_neon.eth_proto import Trx as NeonTrx

from ..environment import neon_cli, NEON_TOKEN_MINT, CHAIN_ID

Expand Down
6 changes: 5 additions & 1 deletion proxy/common_neon/keys_storage.py
Original file line number Diff line number Diff line change
Expand Up @@ -50,7 +50,11 @@ def import_private_key(self, pk_key) -> EthereumAddress:
def get_list(self) -> [EthereumAddress]:
return [EthereumAddress.from_private_key(bytes.fromhex(p)) for p in self._key_list]

def get_key(self, address) -> Optional[EthereumAddress]:
def get_key(self, address: str) -> Optional[EthereumAddress]:
if not isinstance(address, str):
return None

address = address.lower()
account_list = self.get_list()
for account in account_list:
if str(account) == address:
Expand Down
2 changes: 2 additions & 0 deletions proxy/environment.py
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,8 @@

EXTRA_GAS = int(os.environ.get("EXTRA_GAS", "0"))
LOG_NEON_CLI_DEBUG = os.environ.get("LOG_NEON_CLI_DEBUG", "NO") == "YES"
# uses the "earliest" tag if "0x0" or "0" is passed to the "eth_getBlockByNumber" RPC
USE_EARLIEST_BLOCK_IF_0_PASSED = os.environ.get("USE_EARLIEST_BLOCK_IF_0_PASSED", "NO") == "YES"
RETRY_ON_FAIL = int(os.environ.get("RETRY_ON_FAIL", "10"))
RETRY_ON_FAIL_ON_GETTING_CONFIRMED_TRANSACTION = max(int(os.environ.get("RETRY_ON_FAIL_ON_GETTING_CONFIRMED_TRANSACTION", "1000")), 1)
FUZZING_BLOCKHASH = os.environ.get("FUZZING_BLOCKHASH", "NO") == "YES"
Expand Down
8 changes: 5 additions & 3 deletions proxy/memdb/blocks_db.py
Original file line number Diff line number Diff line change
Expand Up @@ -286,13 +286,15 @@ def slot_hash(slot: int):
num_len = len(hex_num)
hex_num = '00' + hex_num.rjust(((num_len >> 1) + (num_len % 2)) << 1, '0')
return '0x' + hex_num.rjust(64, 'f')

hash = slot_hash(block_slot)
# TODO: return predictable information about block time
return SolanaBlockInfo(
slot=block_slot,
time=(block_time or 1),
hash=slot_hash(block_slot),
parent_hash=slot_hash(block_slot - 1),
hash=hash,
# return the prev block's computed hash if the block is not the first block
# if the block is the first block (0x0) -- then just return the hash of this block itself
parent_hash=slot_hash(block_slot - 1) if block_slot > 0 else hash,
is_fake=True
)

Expand Down
57 changes: 38 additions & 19 deletions proxy/neon_rpc_api_model/neon_rpc_api_model.py
Original file line number Diff line number Diff line change
@@ -1,6 +1,8 @@
import json
import multiprocessing
import traceback

import eth_utils
from typing import Optional, Union

import sha3
Expand All @@ -17,7 +19,7 @@
from ..common_neon.utils import SolanaBlockInfo
from ..common_neon.types import NeonTxPrecheckResult, NeonEmulatingResult
from ..environment import SOLANA_URL, PP_SOLANA_URL, PYTH_MAPPING_ACCOUNT, NEON_EVM_VERSION, NEON_EVM_REVISION, \
CHAIN_ID, neon_cli, EVM_STEP_COUNT
CHAIN_ID, USE_EARLIEST_BLOCK_IF_0_PASSED, neon_cli, EVM_STEP_COUNT
from ..memdb.memdb import MemDB
from ..common_neon.gas_price_calculator import GasPriceCalculator
from ..statistics_exporter.proxy_metrics_interface import StatisticsExporter
Expand Down Expand Up @@ -90,7 +92,14 @@ def eth_gasPrice(self):
gas_price = self.gas_price_calculator.get_suggested_gas_price()
return hex(gas_price)

def eth_estimateGas(self, param):
def eth_estimateGas(self, param: dict) -> str:
if not isinstance(param, dict):
raise InvalidParamError('invalid param')
if 'from' in param:
param['from'] = self._normalize_account(param['from'])
if 'to' in param:
param['to'] = self._normalize_account(param['to'])

try:
calculator = GasEstimate(param, self._solana)
calculator.execute()
Expand All @@ -106,10 +115,13 @@ def eth_estimateGas(self, param):
def __repr__(self):
return str(self.__dict__)

def _should_return_starting_block(self, tag) -> bool:
return tag == 'earliest' \
or ((tag == '0x0' or str(tag) == '0') and USE_EARLIEST_BLOCK_IF_0_PASSED)
def _process_block_tag(self, tag) -> SolanaBlockInfo:
if tag in ("latest", "pending"):
block = self._db.get_latest_block()
elif tag == 'earliest':
elif self._should_return_starting_block(tag):
block = self._db.get_starting_block()
elif isinstance(tag, str):
try:
Expand Down Expand Up @@ -160,10 +172,13 @@ def _validate_block_tag(tag: str):
def _normalize_account(account: str) -> str:
try:
sender = account.strip().lower()
bin_sender = bytes.fromhex(sender[2:])
assert sender[:2] == '0x'
sender = sender[2:]

bin_sender = bytes.fromhex(sender)
assert len(bin_sender) == 20

return sender
return eth_utils.to_checksum_address(sender)
except (Exception,):
raise InvalidParamError(message='bad account')

Expand Down Expand Up @@ -259,15 +274,16 @@ def _get_block_by_slot(self, block: SolanaBlockInfo, full: bool, skip_transactio
"gasLimit": '0xec8563e271ac',
"transactionsRoot": '0x' + '0' * 63 + '1',
"receiptsRoot": '0x' + '0' * 63 + '1',
"stateRoot": '0x' + '0' * 64 + '1',
"stateRoot": '0x' + '0' * 63 + '1',

"uncles": [],
"sha3Uncles": '0x1dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d49347',

"miner": '0x' + '0' * 40,
"nonce": '0x0',
"mixHash": '0x0',
"size": '0x0',
# 8 byte nonce
"nonce": '0x0000000000000000',
"mixHash": '0x' + '0' * 63 + '1',
"size": '0x' + '0' * 63 + '1',

"gasUsed": hex(gas_used),
"hash": block.hash,
Expand Down Expand Up @@ -578,22 +594,23 @@ def eth_signTransaction(self, tx: dict) -> dict:
raise InvalidParamError(message='no sender in transaction')

sender = tx['from']
del tx['from']
sender = self._normalize_account(sender)

if 'to' in tx:
tx['to'] = self._normalize_account(tx['to'])

account = KeyStorage().get_key(sender)
if not account:
raise EthereumError(message='unknown account')

try:
if 'from' in tx:
del tx['from']
if 'to' in tx:
del tx['to']
if 'nonce' not in tx:
tx['nonce'] = self.eth_getTransactionCount(sender, 'latest')
if 'chainId' not in tx:
tx['chainId'] = hex(CHAIN_ID)
if 'nonce' not in tx:
tx['nonce'] = self.eth_getTransactionCount(sender, 'latest')

if 'chainId' not in tx:
tx['chainId'] = hex(CHAIN_ID)

try:
signed_tx = w3.eth.account.sign_transaction(tx, account.private)
raw_tx = signed_tx.rawTransaction.hex()

Expand All @@ -608,7 +625,9 @@ def eth_signTransaction(self, tx: dict) -> dict:
'raw': raw_tx,
'tx': tx
}
except (Exception,):
except Exception as e:
err_tb = "".join(traceback.format_tb(e.__traceback__))
self.error(f'Exception {type(e)}({str(e)}: {err_tb}')
raise InvalidParamError(message='bad transaction')

def eth_sendTransaction(self, tx: dict) -> str:
Expand Down

0 comments on commit 89a5565

Please sign in to comment.