diff --git a/proxy/common_neon/compute_budget.py b/proxy/common_neon/compute_budget.py index 78c7ac626..1c81281b4 100644 --- a/proxy/common_neon/compute_budget.py +++ b/proxy/common_neon/compute_budget.py @@ -1,5 +1,6 @@ from solana.transaction import TransactionInstruction, Transaction from .constants import COMPUTE_BUDGET_ID +from ..environment import NEON_HEAP_FRAME, NEON_COMPUTE_UNITS, NEON_ADDITIONAL_FEE class ComputeBudget(): @staticmethod @@ -18,11 +19,8 @@ def requestHeapFrame(heapFrame): data=bytes.fromhex("01")+heapFrame.to_bytes(4,"little") ) -DEFAULT_UNITS=500*1000 -DEFAULT_HEAP_FRAME=256*1024 -DEFAULT_ADDITIONAL_FEE=0 -def TransactionWithComputeBudget(units=DEFAULT_UNITS, additional_fee=DEFAULT_ADDITIONAL_FEE, heapFrame=DEFAULT_HEAP_FRAME, **args): +def TransactionWithComputeBudget(units=NEON_COMPUTE_UNITS, additional_fee=NEON_ADDITIONAL_FEE, heapFrame=NEON_HEAP_FRAME, **args): trx = Transaction(**args) if units: trx.add(ComputeBudget.requestUnits(units, additional_fee)) if heapFrame: trx.add(ComputeBudget.requestHeapFrame(heapFrame)) diff --git a/proxy/common_neon/errors.py b/proxy/common_neon/errors.py index d715b4a52..e3c1773eb 100644 --- a/proxy/common_neon/errors.py +++ b/proxy/common_neon/errors.py @@ -12,7 +12,7 @@ def getError(self): class InvalidParamError(EthereumError): def __init__(self, message, data=None): - EthereumError.__init__(message=message, code=-32602, data=data) + EthereumError.__init__(self, message=message, code=-32602, data=data) class PendingTxError(Exception): diff --git a/proxy/common_neon/neon_instruction.py b/proxy/common_neon/neon_instruction.py index b5e2bdac4..fb0f6330b 100644 --- a/proxy/common_neon/neon_instruction.py +++ b/proxy/common_neon/neon_instruction.py @@ -242,9 +242,9 @@ def make_cancel_transaction(self, storage=None, nonce=None, cancel_keys=None) -> else: append_keys = self.eth_accounts append_keys += obligatory_accounts - if not nonce: + if nonce is None: nonce = self.eth_trx.nonce - if not storage: + if storage is None: storage = self.storage return TransactionWithComputeBudget().add(TransactionInstruction( program_id = EVM_LOADER_ID, diff --git a/proxy/common_neon/solana_interactor.py b/proxy/common_neon/solana_interactor.py index 65c130bed..d3bf25813 100644 --- a/proxy/common_neon/solana_interactor.py +++ b/proxy/common_neon/solana_interactor.py @@ -347,6 +347,7 @@ def get_storage_account_info(self, storage_account: PublicKey) -> Optional[Stora if info is None: return None elif info.tag != 30: + self.debug(f'Storage account {str(storage_account)} has tag {info.tag}') return None elif len(info.data) < STORAGE_ACCOUNT_INFO_LAYOUT.sizeof(): raise RuntimeError(f"Wrong data length for storage data {storage_account}: " + @@ -536,7 +537,8 @@ def _send_multiple_transactions(self, signer: SolanaAccount, tx_list: [Transacti error = response.get('error') if error: if get_from_dict(error, 'data', 'err') == 'AlreadyProcessed': - result = tx.signature() + result = b58encode(tx.signature()).decode("utf-8") + self.debug(f'Transaction is already processed: {str(result)}') error = None else: self.debug(f'Got error on transaction execution: {json.dumps(error)}') diff --git a/proxy/common_neon/transaction_sender.py b/proxy/common_neon/transaction_sender.py index db8f8ad21..57d27b1c4 100644 --- a/proxy/common_neon/transaction_sender.py +++ b/proxy/common_neon/transaction_sender.py @@ -65,9 +65,13 @@ def __init__(self, sender, account: PublicKey): self._storage = self.s.solana.get_storage_account_info(account) def _cancel_tx(self): + key_list = [] + for is_writable, account in self._storage.account_list: + key_list.append(AccountMeta(pubkey=account, is_signer=False, is_writable=is_writable)) + return self.s.builder.make_cancel_transaction(storage=self._account, nonce=self._storage.nonce, - cancel_keys=self._storage.account_list) + cancel_keys=key_list) def build(self): assert self._is_empty() @@ -458,7 +462,7 @@ def _create_perm_accounts(self, seed_list): elif account.tag not in (FINALIZED_STORAGE_TAG, EMPTY_STORAGE_TAG): raise RuntimeError(f"not empty, not finalized: {str(stage.sol_account)}") - if len(tx.instructions): + if len(tx_name_list): SolTxListSender(self._s, [tx], ' + '.join(tx_name_list)).send() else: self.debug(f"Use existing accounts for resource {opkey}:{rid}") @@ -560,7 +564,7 @@ def _execute(self): raise self.error(f'No strategy to execute the Neon transaction: {self.eth_tx}') - raise RuntimeError('No strategy to execute the Neon transaction') + raise EthereumError(message="transaction is too big for execution") def on_wait_confirm(self, _, slot: int): self._pend_tx_into_db(slot) @@ -668,7 +672,7 @@ def _build_txs(self): def build_account_txs(self, skip_create_accounts=False) -> [Transaction]: tx_list = [s.tx for s in self._resize_contract_list] - if (not skip_create_accounts) and len(self.create_account_tx.instructions): + if (not skip_create_accounts) and len(self._create_account_list): tx_list.append(self.create_account_tx) return tx_list @@ -695,7 +699,7 @@ def execute(self) -> (NeonTxResultInfo, [str]): return NeonTxResultInfo(), [] @abc.abstractmethod - def build_tx(self) -> Transaction: + def build_tx(self, _=0) -> Transaction: return TransactionWithComputeBudget() @abc.abstractmethod @@ -775,7 +779,7 @@ def _validate_steps(self) -> bool: return False return True - def build_tx(self) -> Transaction: + def build_tx(self, _=0) -> Transaction: tx = TransactionWithComputeBudget() if not self._skip_create_account: tx.add(self.s.create_account_tx) @@ -822,15 +826,24 @@ def _cancel(self): self._tx_list = [self._s.builder.make_cancel_transaction()] def _decrease_steps(self): - self._strategy.steps -= 150 - self.debug(f'Decrease EVM steps to {self._strategy.steps}') - if self._strategy.steps < 50: + prev_total_cnt = len(self._get_full_list()) + prev_steps = self._strategy.steps + total_steps = prev_total_cnt * self._strategy.steps + + if self._strategy.steps <= 10: return self._cancel() - total_cnt = len(self._get_full_list()) * 2 + if self._strategy.steps > 170: + self._strategy.steps -= 150 + else: + self._strategy.steps = 10 + total_cnt = math.ceil(total_steps / self._strategy.steps) + + self.debug(f'Decrease EVM steps from {prev_steps} to {self._strategy.steps}, ' + + f'iterations increase from {prev_total_cnt} to {total_cnt}') self.clear() - self._tx_list = [self._strategy.build_tx() for _ in range(total_cnt)] + self._tx_list = [self._strategy.build_tx(idx) for idx in range(total_cnt)] def _on_success_send(self, tx: Transaction, receipt: {}): if self._is_canceled: @@ -915,10 +928,9 @@ def _validate_evm_steps(self): return False return True - def build_tx(self) -> Transaction: + def build_tx(self, idx=0) -> Transaction: # generate unique tx - self.steps -= 1 - return self.s.builder.make_partial_call_or_continue_transaction(self.steps) + return self.s.builder.make_partial_call_or_continue_transaction(self.steps + idx) def _build_preparation_txs(self) -> [Transaction]: self._preparation_txs_name = self.s.account_txs_name @@ -932,7 +944,7 @@ def execute(self) -> (NeonTxResultInfo, [str]): cnt = math.ceil(self.s.steps_emulated / self.steps) cnt = math.ceil(self.s.steps_emulated / (self.steps - cnt)) + 2 # +1 on begin, +1 on end - tx_list = [self.build_tx() for _ in range(cnt)] + tx_list = [self.build_tx(idx) for idx in range(cnt)] self.debug(f'Total iterations {len(tx_list)} for {self.s.steps_emulated} ({self.steps}) EVM steps') tx_sender = IterativeNeonTxSender(self, self.s, tx_list, self.NAME) tx_sender.send() @@ -944,15 +956,13 @@ class HolderNeonTxStrategy(IterativeNeonTxStrategy, abc.ABC): NAME = 'ExecuteTrxFromAccountDataIterativeOrContinue' def __init__(self, *args, **kwargs): - self._tx_idx = 0 IterativeNeonTxStrategy.__init__(self, *args, **kwargs) def _validate(self) -> bool: return self._validate_txsize() - def build_tx(self) -> Transaction: - self._tx_idx += 1 - return self.s.builder.make_partial_call_or_continue_from_account_data(self.steps, self._tx_idx) + def build_tx(self, idx=0) -> Transaction: + return self.s.builder.make_partial_call_or_continue_from_account_data(self.steps, idx) def _build_preparation_txs(self) -> [Transaction]: tx_list = super()._build_preparation_txs() diff --git a/proxy/environment.py b/proxy/environment.py index 98af2eba1..ae369b4dc 100644 --- a/proxy/environment.py +++ b/proxy/environment.py @@ -170,3 +170,6 @@ def read_elf_params(out_dict, *, logger): CHAIN_ID = int(ELF_PARAMS.get('NEON_CHAIN_ID', None)) NEON_EVM_VERSION = ELF_PARAMS.get("NEON_PKG_VERSION") NEON_EVM_REVISION = ELF_PARAMS.get('NEON_REVISION') +NEON_COMPUTE_UNITS = int(ELF_PARAMS.get('NEON_COMPUTE_UNITS')) +NEON_HEAP_FRAME = int(ELF_PARAMS.get('NEON_HEAP_FRAME')) +NEON_ADDITIONAL_FEE = int(ELF_PARAMS.get('NEON_ADDITIONAL_FEE')) diff --git a/proxy/plugin/solana_rest_api.py b/proxy/plugin/solana_rest_api.py index b2891614d..8d6fb3523 100644 --- a/proxy/plugin/solana_rest_api.py +++ b/proxy/plugin/solana_rest_api.py @@ -50,7 +50,7 @@ modelInstanceLock = threading.Lock() modelInstance = None -NEON_PROXY_PKG_VERSION = '0.7.9-dev' +NEON_PROXY_PKG_VERSION = '0.7.14-dev' NEON_PROXY_REVISION = 'NEON_PROXY_REVISION_TO_BE_REPLACED' @@ -439,18 +439,19 @@ def eth_getCode(self, account: str, tag) -> str: return self._db.get_contract_code(account) def eth_sendRawTransaction(self, rawTrx: str) -> str: - self._stat_tx_begin() + try: + trx = EthTrx.fromString(bytearray.fromhex(rawTrx[2:])) + except: + raise EthereumError(message="wrong transaction format") - trx = EthTrx.fromString(bytearray.fromhex(rawTrx[2:])) - self.debug(f"{json.dumps(trx.as_dict(), cls=JsonEncoder, sort_keys=True)}") - min_gas_price = self.gas_price_calculator.get_min_gas_price() + eth_signature = '0x' + trx.hash_signed().hex() + self.debug(f"sendRawTransaction {eth_signature}: {json.dumps(trx.as_dict(), cls=JsonEncoder, sort_keys=True)}") + min_gas_price = self.gas_price_calculator.get_min_gas_price() if trx.gasPrice < min_gas_price: - self._stat_tx_failed() raise EthereumError(message="The transaction gasPrice is less than the minimum allowable value" + f"({trx.gasPrice}<{min_gas_price})") - - eth_signature = '0x' + trx.hash_signed().hex() + self._stat_tx_begin() try: tx_sender = NeonTxSender(self._db, self._solana, trx, steps=EVM_STEP_COUNT)