-
Notifications
You must be signed in to change notification settings - Fork 20
#295 iterative execution #332
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
Changes from all commits
90a4e56
143913b
16c9bff
f2c0303
57f3b53
3369f67
af721bb
e512bb8
8dc5e29
8dce2a5
cef8f21
1bf8383
9672438
2d42b73
ac2755c
3519c61
bf313a2
3093fcc
e3c4e33
9b57e53
ccffcf4
4d685db
6f63338
4546926
7befc6b
b5010f8
5ebf76a
b464b1e
79088c6
52173a0
4fe15e9
607e74e
d9f762a
842ec7d
78de121
47cf219
0eebc1f
cec7a38
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -283,14 +283,17 @@ def make_noniterative_call_transaction(self, length_before: int = 0) -> Transact | |
| return trx | ||
|
|
||
|
|
||
| def make_partial_call_instruction(self) -> TransactionInstruction: | ||
| return TransactionInstruction( | ||
| def make_continue_transaction(self, steps, index=None) -> Transaction: | ||
| data = bytearray.fromhex("14") + self.collateral_pool_index_buf + steps.to_bytes(8, byteorder="little") | ||
| if index: | ||
| data = data + index.to_bytes(8, byteorder="little") | ||
|
|
||
| return Transaction().add(TransactionInstruction( | ||
| program_id = EVM_LOADER_ID, | ||
| data = bytearray.fromhex("13") + self.collateral_pool_index_buf + int(0).to_bytes(8, byteorder="little") + self.msg, | ||
| data = data, | ||
| keys = [ | ||
| AccountMeta(pubkey=self.storage, is_signer=False, is_writable=True), | ||
|
|
||
| AccountMeta(pubkey=SYSVAR_INSTRUCTION_PUBKEY, is_signer=False, is_writable=False), | ||
| AccountMeta(pubkey=self.operator_account, is_signer=True, is_writable=True), | ||
| AccountMeta(pubkey=self.collateral_pool_address, is_signer=False, is_writable=True), | ||
| AccountMeta(pubkey=self.operator_neon_address, is_signer=False, is_writable=True), | ||
|
|
@@ -301,28 +304,19 @@ def make_partial_call_instruction(self) -> TransactionInstruction: | |
|
|
||
| AccountMeta(pubkey=SYSVAR_INSTRUCTION_PUBKEY, is_signer=False, is_writable=False), | ||
| ] + obligatory_accounts | ||
| ) | ||
|
|
||
|
|
||
| def make_iterative_call_transaction(self, length_before: int = 0) -> Transaction: | ||
| trx = Transaction() | ||
| trx.add(self.make_keccak_instruction(length_before + 1, len(self.eth_trx.unsigned_msg()), 13)) | ||
| trx.add(self.make_partial_call_instruction()) | ||
| return trx | ||
| )) | ||
|
|
||
|
|
||
| def make_call_from_account_instruction(self) -> Transaction: | ||
| def make_cancel_transaction(self) -> Transaction: | ||
| return Transaction().add(TransactionInstruction( | ||
| program_id = EVM_LOADER_ID, | ||
| data = bytearray.fromhex("16") + self.collateral_pool_index_buf + int(0).to_bytes(8, byteorder="little"), | ||
| data = bytearray.fromhex("15") + self.eth_trx.nonce.to_bytes(8, 'little'), | ||
| keys = [ | ||
| AccountMeta(pubkey=self.holder, is_signer=False, is_writable=True), | ||
| AccountMeta(pubkey=self.storage, is_signer=False, is_writable=True), | ||
|
|
||
| AccountMeta(pubkey=self.operator_account, is_signer=True, is_writable=True), | ||
| AccountMeta(pubkey=self.collateral_pool_address, is_signer=False, is_writable=True), | ||
| AccountMeta(pubkey=self.operator_neon_address, is_signer=False, is_writable=True), | ||
| AccountMeta(pubkey=self.caller_token, is_signer=False, is_writable=True), | ||
| AccountMeta(pubkey=INCINERATOR_PUBKEY, is_signer=False, is_writable=True), | ||
| AccountMeta(pubkey=SYS_PROGRAM_ID, is_signer=False, is_writable=False), | ||
|
|
||
| ] + self.eth_accounts + [ | ||
|
|
@@ -332,17 +326,15 @@ def make_call_from_account_instruction(self) -> Transaction: | |
| )) | ||
|
|
||
|
|
||
| def make_continue_instruction(self, steps, index=None) -> Transaction: | ||
| data = bytearray.fromhex("14") + self.collateral_pool_index_buf + steps.to_bytes(8, byteorder="little") | ||
| if index: | ||
| data = data + index.to_bytes(8, byteorder="little") | ||
|
|
||
| return Transaction().add(TransactionInstruction( | ||
| def make_partial_call_or_continue_instruction(self, steps: int = 0) -> TransactionInstruction: | ||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Annotations |
||
| data = bytearray.fromhex("0D") + self.collateral_pool_index_buf + steps.to_bytes(8, byteorder="little") + self.msg | ||
vasiliy-zaznobin marked this conversation as resolved.
Show resolved
Hide resolved
|
||
| return TransactionInstruction( | ||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Isn't it better if it would be separated on two parts. The part that is passed in - is too long instraction =
...
return instruction
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. This remark could be connected to the previous definition as well |
||
| program_id = EVM_LOADER_ID, | ||
| data = data, | ||
| keys = [ | ||
| AccountMeta(pubkey=self.storage, is_signer=False, is_writable=True), | ||
|
|
||
| AccountMeta(pubkey=SYSVAR_INSTRUCTION_PUBKEY, is_signer=False, is_writable=False), | ||
| AccountMeta(pubkey=self.operator_account, is_signer=True, is_writable=True), | ||
| AccountMeta(pubkey=self.collateral_pool_address, is_signer=False, is_writable=True), | ||
| AccountMeta(pubkey=self.operator_neon_address, is_signer=False, is_writable=True), | ||
|
|
@@ -353,19 +345,31 @@ def make_continue_instruction(self, steps, index=None) -> Transaction: | |
|
|
||
| AccountMeta(pubkey=SYSVAR_INSTRUCTION_PUBKEY, is_signer=False, is_writable=False), | ||
| ] + obligatory_accounts | ||
| )) | ||
| ) | ||
|
|
||
|
|
||
| def make_cancel_instruction(self) -> Transaction: | ||
| def make_partial_call_or_continue_transaction(self, steps: int = 0, length_before: int = 0) -> Transaction: | ||
| trx = Transaction() | ||
| trx.add(self.make_keccak_instruction(length_before + 1, len(self.eth_trx.unsigned_msg()), 13)) | ||
| trx.add(self.make_partial_call_or_continue_instruction(steps)) | ||
| return trx | ||
|
|
||
|
|
||
| def make_partial_call_or_continue_from_account_data(self, steps, index=None) -> Transaction: | ||
| data = bytearray.fromhex("0E") + self.collateral_pool_index_buf + steps.to_bytes(8, byteorder='little') | ||
| if index: | ||
| data = data + index.to_bytes(8, byteorder="little") | ||
| return Transaction().add(TransactionInstruction( | ||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. transaction = Transaction()
transaction.add(...)
# or extend_trx_with
# or instruction = make_continue_instruction
return transaction() |
||
| program_id = EVM_LOADER_ID, | ||
| data = bytearray.fromhex("15") + self.eth_trx.nonce.to_bytes(8, 'little'), | ||
| data = data, | ||
| keys = [ | ||
| AccountMeta(pubkey=self.holder, is_signer=False, is_writable=True), | ||
| AccountMeta(pubkey=self.storage, is_signer=False, is_writable=True), | ||
|
|
||
| AccountMeta(pubkey=self.operator_account, is_signer=True, is_writable=True), | ||
| AccountMeta(pubkey=self.collateral_pool_address, is_signer=False, is_writable=True), | ||
| AccountMeta(pubkey=self.operator_neon_address, is_signer=False, is_writable=True), | ||
| AccountMeta(pubkey=self.caller_token, is_signer=False, is_writable=True), | ||
| AccountMeta(pubkey=INCINERATOR_PUBKEY, is_signer=False, is_writable=True), | ||
| AccountMeta(pubkey=SYS_PROGRAM_ID, is_signer=False, is_writable=False), | ||
|
|
||
| ] + self.eth_accounts + [ | ||
|
|
||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -5,18 +5,20 @@ | |
| import re | ||
| import time | ||
|
|
||
| from solana.rpc.api import Client as SolanaClient | ||
| from solana.rpc.commitment import Confirmed | ||
| from solana.rpc.types import TxOpts | ||
|
|
||
| from .costs import update_transaction_cost | ||
| from .utils import get_from_dict | ||
| from ..environment import EVM_LOADER_ID, CONFIRMATION_CHECK_DELAY, LOG_SENDING_SOLANA_TRANSACTION | ||
|
|
||
| logger = logging.getLogger(__name__) | ||
| logger.setLevel(logging.DEBUG) | ||
|
|
||
|
|
||
| class SolanaInteractor: | ||
| def __init__(self, signer, client) -> None: | ||
| def __init__(self, signer, client: SolanaClient) -> None: | ||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. signer needs its own annotation as well |
||
| self.signer = signer | ||
| self.client = client | ||
|
|
||
|
|
@@ -194,6 +196,16 @@ def check_if_program_exceeded_instructions(err_result): | |
| return False | ||
|
|
||
|
|
||
| def check_if_storage_is_empty_error(err_result): | ||
| error_arr = get_from_dict(err_result, "data", "err", "InstructionError") | ||
| if error_arr is not None and isinstance(error_arr, list): | ||
| error_dict = error_arr[1] | ||
| if isinstance(error_dict, dict) and 'Custom' in error_dict: | ||
| if error_dict['Custom'] == 1 or error_dict['Custom'] == 4: | ||
| return True | ||
| return False | ||
|
|
||
|
|
||
| def check_if_continue_returned(result): | ||
| tx_info = result['result'] | ||
| accounts = tx_info["transaction"]["message"]["accountKeys"] | ||
|
|
||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -1,5 +1,6 @@ | ||
| import json | ||
| import logging | ||
| import math | ||
| import os | ||
| import rlp | ||
| import time | ||
|
|
@@ -18,7 +19,8 @@ | |
| from .emulator_interactor import call_emulated | ||
| from .layouts import ACCOUNT_INFO_LAYOUT | ||
| from .neon_instruction import NeonInstruction | ||
| from .solana_interactor import SolanaInteractor, check_if_continue_returned, check_if_program_exceeded_instructions | ||
| from .solana_interactor import SolanaInteractor, check_if_continue_returned, \ | ||
| check_if_program_exceeded_instructions, check_if_storage_is_empty_error | ||
| from ..environment import EVM_LOADER_ID | ||
| from ..plugin.eth_proto import Trx as EthTrx | ||
|
|
||
|
|
@@ -67,7 +69,7 @@ def execute(self): | |
| try: | ||
| if call_iterative: | ||
| try: | ||
| return iterative_executor.call_signed_iterative() | ||
| return iterative_executor.call_signed_iterative_combined() | ||
| except Exception as err: | ||
| logger.debug(str(err)) | ||
| if str(err).startswith("transaction too large:"): | ||
|
|
@@ -77,7 +79,7 @@ def execute(self): | |
| raise | ||
|
|
||
| if call_from_holder: | ||
| return iterative_executor.call_signed_with_holder_acc() | ||
| return iterative_executor.call_signed_with_holder_combined() | ||
| finally: | ||
| self.free_perm_accs() | ||
|
|
||
|
|
@@ -93,7 +95,7 @@ def create_noniterative_executor(self): | |
|
|
||
| def create_iterative_executor(self): | ||
| self.instruction.init_iterative(self.storage, self.holder, self.perm_accs_id) | ||
| return IterativeTransactionSender(self.sender, self.instruction, self.create_acc_trx, self.eth_trx, self.steps) | ||
| return IterativeTransactionSender(self.sender, self.instruction, self.create_acc_trx, self.eth_trx, self.steps, self.steps_emulated) | ||
|
|
||
|
|
||
| def init_perm_accs(self): | ||
|
|
@@ -302,6 +304,8 @@ def create_account_list_by_emulate(self): | |
| AccountMeta(pubkey=self.caller_token, is_signer=False, is_writable=True), | ||
| ] + add_keys_05 | ||
|
|
||
| self.steps_emulated = output_json["steps_executed"] | ||
|
|
||
|
|
||
| class NoniterativeTransactionSender: | ||
| def __init__(self, solana_interactor: SolanaInteractor, neon_instruction: NeonInstruction, create_acc_trx: Transaction, eth_trx: EthTrx): | ||
|
|
@@ -321,53 +325,52 @@ def call_signed_noniterative(self): | |
|
|
||
|
|
||
| class IterativeTransactionSender: | ||
| def __init__(self, solana_interactor: SolanaInteractor, neon_instruction: NeonInstruction, create_acc_trx: Transaction, eth_trx: EthTrx, steps: int): | ||
| CONTINUE_REGULAR = 'ContinueV02' | ||
| CONTINUE_COMBINED = 'PartialCallOrContinueFromRawEthereumTX' | ||
| CONTINUE_HOLDER_COMB = 'ExecuteTrxFromAccountDataIterativeOrContinue' | ||
|
|
||
| def __init__(self, solana_interactor: SolanaInteractor, neon_instruction: NeonInstruction, create_acc_trx: Transaction, eth_trx: EthTrx, steps: int, steps_emulated: int): | ||
| self.sender = solana_interactor | ||
| self.instruction = neon_instruction | ||
| self.create_acc_trx = create_acc_trx | ||
| self.eth_trx = eth_trx | ||
| self.steps = steps | ||
| self.steps_emulated = steps_emulated | ||
| self.instruction_type = self.CONTINUE_REGULAR | ||
|
|
||
|
|
||
| def call_signed_iterative(self): | ||
| if len(self.create_acc_trx.instructions): | ||
| precall_txs = Transaction() | ||
| precall_txs.add(self.create_acc_trx) | ||
| self.sender.send_measured_transaction(precall_txs, self.eth_trx, 'CreateAccountsForTrx') | ||
|
|
||
| call_txs = self.instruction.make_iterative_call_transaction() | ||
|
|
||
| logger.debug("Partial call") | ||
| self.sender.send_measured_transaction(call_txs, self.eth_trx, 'PartialCallFromRawEthereumTXv02') | ||
|
|
||
| def call_signed_iterative_combined(self): | ||
| self.create_accounts_for_trx() | ||
| self.instruction_type = self.CONTINUE_COMBINED | ||
| return self.call_continue() | ||
|
|
||
|
|
||
| def call_signed_with_holder_acc(self): | ||
| def call_signed_with_holder_combined(self): | ||
| self.write_trx_to_holder_account() | ||
| if len(self.create_acc_trx.instructions): | ||
| precall_txs = Transaction() | ||
| precall_txs.add(self.create_acc_trx) | ||
| self.sender.send_measured_transaction(precall_txs, self.eth_trx, 'create_accounts_for_deploy') | ||
| self.create_accounts_for_trx() | ||
| self.instruction_type = self.CONTINUE_HOLDER_COMB | ||
| return self.call_continue() | ||
|
|
||
| # ExecuteTrxFromAccountDataIterative | ||
| logger.debug("ExecuteTrxFromAccountDataIterative:") | ||
| call_txs = self.instruction.make_call_from_account_instruction() | ||
| self.sender.send_measured_transaction(call_txs, self.eth_trx, 'ExecuteTrxFromAccountDataIterativeV02') | ||
|
|
||
| return self.call_continue() | ||
| def create_accounts_for_trx(self): | ||
| length = len(self.create_acc_trx.instructions) | ||
| if length == 0: | ||
| return | ||
| logger.debug(f"Create account for trx: {length}") | ||
| precall_txs = Transaction() | ||
| precall_txs.add(self.create_acc_trx) | ||
| self.sender.send_measured_transaction(precall_txs, self.eth_trx, 'CreateAccountsForTrx') | ||
|
|
||
|
|
||
| def write_trx_to_holder_account(self): | ||
| logger.debug('write_trx_to_holder_account') | ||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Does it really need here with no a context or it's rather a spam
Contributor
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Yep |
||
| msg = self.eth_trx.signature() + len(self.eth_trx.unsigned_msg()).to_bytes(8, byteorder="little") + self.eth_trx.unsigned_msg() | ||
|
|
||
| # Write transaction to transaction holder account | ||
| offset = 0 | ||
| receipts = [] | ||
| rest = msg | ||
| while len(rest): | ||
| (part, rest) = (rest[:1000], rest[1000:]) | ||
| # logger.debug("sender_sol %s %s %s", sender_sol, holder, acc.public_key()) | ||
| trx = self.instruction.make_write_transaction(offset, part) | ||
| receipts.append(self.sender.send_transaction_unconfirmed(trx)) | ||
| offset += len(part) | ||
|
|
@@ -377,6 +380,19 @@ def write_trx_to_holder_account(self): | |
|
|
||
|
|
||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. single blank line in python classes separates methods
Contributor
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I think we need just some issue for styling. Not here |
||
| def call_continue(self): | ||
| return_result = None | ||
| try: | ||
| return_result = self.call_continue_bucked() | ||
| except Exception as err: | ||
| logger.debug("call_continue_bucked_combined exception: {}".format(str(err))) | ||
|
|
||
| if return_result is not None: | ||
| return return_result | ||
|
|
||
| return self.call_continue_iterative() | ||
|
|
||
|
|
||
| def call_continue_iterative(self): | ||
| try: | ||
| return self.call_continue_step_by_step() | ||
| except Exception as err: | ||
|
|
@@ -398,7 +414,7 @@ def call_continue_step_by_step(self): | |
| def call_continue_step(self): | ||
| step_count = self.steps | ||
| while step_count > 0: | ||
| trx = self.instruction.make_continue_instruction(step_count) | ||
| trx = self.instruction.make_continue_transaction(step_count) | ||
|
|
||
| logger.debug("Step count {}".format(step_count)) | ||
| try: | ||
|
|
@@ -413,8 +429,71 @@ def call_continue_step(self): | |
|
|
||
|
|
||
| def call_cancel(self): | ||
| trx = self.instruction.make_cancel_instruction() | ||
| trx = self.instruction.make_cancel_transaction() | ||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Stay look wierd.
Contributor
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. if you want you can use this function the same way and it will work. trx = Transaction();
cancel_instruction = self.instraction.make_cancel_transaction()
trx.add(cancel_instruction)For me shorter - better
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. "shorter" tends to get |
||
|
|
||
| logger.debug("Cancel") | ||
| result = self.sender.send_measured_transaction(trx, self.eth_trx, 'CancelWithNonce') | ||
| return result['result']['transaction']['signatures'][0] | ||
|
|
||
|
|
||
| def call_continue_bucked(self): | ||
| logger.debug("Send bucked combined: %s", self.instruction_type) | ||
| steps = self.steps | ||
|
|
||
| receipts = [] | ||
| for index in range(math.ceil(self.steps_emulated/self.steps) + self.addition_count()): | ||
| try: | ||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. This method is too heave, you can isolate some logically independent parts |
||
| trx = self.make_bucked_trx(steps, index) | ||
| receipts.append(self.sender.send_transaction_unconfirmed(trx)) | ||
| except SendTransactionError as err: | ||
| logger.error(f"Failed to call continue bucked, error: {err.result}") | ||
| if check_if_storage_is_empty_error(err.result): | ||
| pass | ||
| elif check_if_program_exceeded_instructions(err.result): | ||
| steps = int(steps * 90 / 100) | ||
| else: | ||
| raise | ||
| except Exception as err: | ||
| logger.debug(str(err)) | ||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. f"Failed to call continue bucked, error: {err}"
Contributor
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. fixed |
||
| if str(err).startswith('failed to get recent blockhash'): | ||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Another one "umbrella" - |
||
| pass | ||
| else: | ||
| raise | ||
|
|
||
| return self.collect_bucked_results(receipts, self.instruction_type) | ||
|
|
||
|
|
||
| def addition_count(self): | ||
| ''' | ||
| How many transactions are needed depending on trx type: | ||
| CONTINUE_COMBINED: 2 (1 for begin and 1 for decreased steps) | ||
| CONTINUE_HOLDER_COMB: 1 for begin | ||
| 0 otherwise | ||
| ''' | ||
| addition_count = 0 | ||
| if self.instruction_type == self.CONTINUE_COMBINED: | ||
| addition_count = 2 | ||
| elif self.instruction_type == self.CONTINUE_HOLDER_COMB: | ||
| addition_count = 1 | ||
| return addition_count | ||
|
|
||
|
|
||
| def make_bucked_trx(self, steps, index): | ||
| if self.instruction_type == self.CONTINUE_REGULAR: | ||
| return self.instruction.make_continue_transaction(steps, index) | ||
| elif self.instruction_type == self.CONTINUE_COMBINED: | ||
| return self.instruction.make_partial_call_or_continue_transaction(steps - index) | ||
| elif self.instruction_type == self.CONTINUE_HOLDER_COMB: | ||
| return self.instruction.make_partial_call_or_continue_from_account_data(steps, index) | ||
| else: | ||
| raise Exception("Unknown continue type: {}".format(self.instruction_type)) | ||
|
|
||
|
|
||
| def collect_bucked_results(self, receipts, reason): | ||
| logger.debug(f"Collected bucked results: {receipts}") | ||
| result_list = self.sender.collect_results(receipts, eth_trx=self.eth_trx, reason=reason) | ||
| for result in result_list: | ||
| # self.sender.get_measurements(result) | ||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. It is not needed more
Contributor
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Disagree |
||
| signature = check_if_continue_returned(result) | ||
| if signature: | ||
| return signature | ||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The same. Annotations on arguments