11import json
22import logging
3+ import math
34import os
45import rlp
56import time
1819from .emulator_interactor import call_emulated
1920from .layouts import ACCOUNT_INFO_LAYOUT
2021from .neon_instruction import NeonInstruction
21- from .solana_interactor import SolanaInteractor , check_if_continue_returned , check_if_program_exceeded_instructions
22+ from .solana_interactor import SolanaInteractor , check_if_continue_returned , \
23+ check_if_program_exceeded_instructions , check_if_storage_is_empty_error
2224from ..environment import EVM_LOADER_ID
2325from ..plugin .eth_proto import Trx as EthTrx
2426
@@ -67,7 +69,7 @@ def execute(self):
6769 try :
6870 if call_iterative :
6971 try :
70- return iterative_executor .call_signed_iterative ()
72+ return iterative_executor .call_signed_iterative_combined ()
7173 except Exception as err :
7274 logger .debug (str (err ))
7375 if str (err ).startswith ("transaction too large:" ):
@@ -77,7 +79,7 @@ def execute(self):
7779 raise
7880
7981 if call_from_holder :
80- return iterative_executor .call_signed_with_holder_acc ()
82+ return iterative_executor .call_signed_with_holder_combined ()
8183 finally :
8284 self .free_perm_accs ()
8385
@@ -93,7 +95,7 @@ def create_noniterative_executor(self):
9395
9496 def create_iterative_executor (self ):
9597 self .instruction .init_iterative (self .storage , self .holder , self .perm_accs_id )
96- return IterativeTransactionSender (self .sender , self .instruction , self .create_acc_trx , self .eth_trx , self .steps )
98+ return IterativeTransactionSender (self .sender , self .instruction , self .create_acc_trx , self .eth_trx , self .steps , self . steps_emulated )
9799
98100
99101 def init_perm_accs (self ):
@@ -302,6 +304,8 @@ def create_account_list_by_emulate(self):
302304 AccountMeta (pubkey = self .caller_token , is_signer = False , is_writable = True ),
303305 ] + add_keys_05
304306
307+ self .steps_emulated = output_json ["steps_executed" ]
308+
305309
306310class NoniterativeTransactionSender :
307311 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):
321325
322326
323327class IterativeTransactionSender :
324- def __init__ (self , solana_interactor : SolanaInteractor , neon_instruction : NeonInstruction , create_acc_trx : Transaction , eth_trx : EthTrx , steps : int ):
328+ CONTINUE_REGULAR = 'ContinueV02'
329+ CONTINUE_COMBINED = 'PartialCallOrContinueFromRawEthereumTX'
330+ CONTINUE_HOLDER_COMB = 'ExecuteTrxFromAccountDataIterativeOrContinue'
331+
332+ def __init__ (self , solana_interactor : SolanaInteractor , neon_instruction : NeonInstruction , create_acc_trx : Transaction , eth_trx : EthTrx , steps : int , steps_emulated : int ):
325333 self .sender = solana_interactor
326334 self .instruction = neon_instruction
327335 self .create_acc_trx = create_acc_trx
328336 self .eth_trx = eth_trx
329337 self .steps = steps
338+ self .steps_emulated = steps_emulated
339+ self .instruction_type = self .CONTINUE_REGULAR
330340
331341
332- def call_signed_iterative (self ):
333- if len (self .create_acc_trx .instructions ):
334- precall_txs = Transaction ()
335- precall_txs .add (self .create_acc_trx )
336- self .sender .send_measured_transaction (precall_txs , self .eth_trx , 'CreateAccountsForTrx' )
337-
338- call_txs = self .instruction .make_iterative_call_transaction ()
339-
340- logger .debug ("Partial call" )
341- self .sender .send_measured_transaction (call_txs , self .eth_trx , 'PartialCallFromRawEthereumTXv02' )
342-
342+ def call_signed_iterative_combined (self ):
343+ self .create_accounts_for_trx ()
344+ self .instruction_type = self .CONTINUE_COMBINED
343345 return self .call_continue ()
344346
345347
346- def call_signed_with_holder_acc (self ):
348+ def call_signed_with_holder_combined (self ):
347349 self .write_trx_to_holder_account ()
348- if len (self .create_acc_trx .instructions ):
349- precall_txs = Transaction ()
350- precall_txs .add (self .create_acc_trx )
351- self .sender .send_measured_transaction (precall_txs , self .eth_trx , 'create_accounts_for_deploy' )
350+ self .create_accounts_for_trx ()
351+ self .instruction_type = self .CONTINUE_HOLDER_COMB
352+ return self .call_continue ()
352353
353- # ExecuteTrxFromAccountDataIterative
354- logger .debug ("ExecuteTrxFromAccountDataIterative:" )
355- call_txs = self .instruction .make_call_from_account_instruction ()
356- self .sender .send_measured_transaction (call_txs , self .eth_trx , 'ExecuteTrxFromAccountDataIterativeV02' )
357354
358- return self .call_continue ()
355+ def create_accounts_for_trx (self ):
356+ length = len (self .create_acc_trx .instructions )
357+ if length == 0 :
358+ return
359+ logger .debug (f"Create account for trx: { length } " )
360+ precall_txs = Transaction ()
361+ precall_txs .add (self .create_acc_trx )
362+ self .sender .send_measured_transaction (precall_txs , self .eth_trx , 'CreateAccountsForTrx' )
359363
360364
361365 def write_trx_to_holder_account (self ):
366+ logger .debug ('write_trx_to_holder_account' )
362367 msg = self .eth_trx .signature () + len (self .eth_trx .unsigned_msg ()).to_bytes (8 , byteorder = "little" ) + self .eth_trx .unsigned_msg ()
363368
364- # Write transaction to transaction holder account
365369 offset = 0
366370 receipts = []
367371 rest = msg
368372 while len (rest ):
369373 (part , rest ) = (rest [:1000 ], rest [1000 :])
370- # logger.debug("sender_sol %s %s %s", sender_sol, holder, acc.public_key())
371374 trx = self .instruction .make_write_transaction (offset , part )
372375 receipts .append (self .sender .send_transaction_unconfirmed (trx ))
373376 offset += len (part )
@@ -377,6 +380,19 @@ def write_trx_to_holder_account(self):
377380
378381
379382 def call_continue (self ):
383+ return_result = None
384+ try :
385+ return_result = self .call_continue_bucked ()
386+ except Exception as err :
387+ logger .debug ("call_continue_bucked_combined exception: {}" .format (str (err )))
388+
389+ if return_result is not None :
390+ return return_result
391+
392+ return self .call_continue_iterative ()
393+
394+
395+ def call_continue_iterative (self ):
380396 try :
381397 return self .call_continue_step_by_step ()
382398 except Exception as err :
@@ -398,7 +414,7 @@ def call_continue_step_by_step(self):
398414 def call_continue_step (self ):
399415 step_count = self .steps
400416 while step_count > 0 :
401- trx = self .instruction .make_continue_instruction (step_count )
417+ trx = self .instruction .make_continue_transaction (step_count )
402418
403419 logger .debug ("Step count {}" .format (step_count ))
404420 try :
@@ -413,8 +429,71 @@ def call_continue_step(self):
413429
414430
415431 def call_cancel (self ):
416- trx = self .instruction .make_cancel_instruction ()
432+ trx = self .instruction .make_cancel_transaction ()
417433
418434 logger .debug ("Cancel" )
419435 result = self .sender .send_measured_transaction (trx , self .eth_trx , 'CancelWithNonce' )
420436 return result ['result' ]['transaction' ]['signatures' ][0 ]
437+
438+
439+ def call_continue_bucked (self ):
440+ logger .debug ("Send bucked combined: %s" , self .instruction_type )
441+ steps = self .steps
442+
443+ receipts = []
444+ for index in range (math .ceil (self .steps_emulated / self .steps ) + self .addition_count ()):
445+ try :
446+ trx = self .make_bucked_trx (steps , index )
447+ receipts .append (self .sender .send_transaction_unconfirmed (trx ))
448+ except SendTransactionError as err :
449+ logger .error (f"Failed to call continue bucked, error: { err .result } " )
450+ if check_if_storage_is_empty_error (err .result ):
451+ pass
452+ elif check_if_program_exceeded_instructions (err .result ):
453+ steps = int (steps * 90 / 100 )
454+ else :
455+ raise
456+ except Exception as err :
457+ logger .debug (str (err ))
458+ if str (err ).startswith ('failed to get recent blockhash' ):
459+ pass
460+ else :
461+ raise
462+
463+ return self .collect_bucked_results (receipts , self .instruction_type )
464+
465+
466+ def addition_count (self ):
467+ '''
468+ How many transactions are needed depending on trx type:
469+ CONTINUE_COMBINED: 2 (1 for begin and 1 for decreased steps)
470+ CONTINUE_HOLDER_COMB: 1 for begin
471+ 0 otherwise
472+ '''
473+ addition_count = 0
474+ if self .instruction_type == self .CONTINUE_COMBINED :
475+ addition_count = 2
476+ elif self .instruction_type == self .CONTINUE_HOLDER_COMB :
477+ addition_count = 1
478+ return addition_count
479+
480+
481+ def make_bucked_trx (self , steps , index ):
482+ if self .instruction_type == self .CONTINUE_REGULAR :
483+ return self .instruction .make_continue_transaction (steps , index )
484+ elif self .instruction_type == self .CONTINUE_COMBINED :
485+ return self .instruction .make_partial_call_or_continue_transaction (steps - index )
486+ elif self .instruction_type == self .CONTINUE_HOLDER_COMB :
487+ return self .instruction .make_partial_call_or_continue_from_account_data (steps , index )
488+ else :
489+ raise Exception ("Unknown continue type: {}" .format (self .instruction_type ))
490+
491+
492+ def collect_bucked_results (self , receipts , reason ):
493+ logger .debug (f"Collected bucked results: { receipts } " )
494+ result_list = self .sender .collect_results (receipts , eth_trx = self .eth_trx , reason = reason )
495+ for result in result_list :
496+ # self.sender.get_measurements(result)
497+ signature = check_if_continue_returned (result )
498+ if signature :
499+ return signature
0 commit comments