From 36a7c15979c89faebeaab6d499ee9173341d58bf Mon Sep 17 00:00:00 2001 From: Rozhkov Dmitrii Date: Wed, 20 Jul 2022 19:59:08 +0400 Subject: [PATCH] Revert "Indexer: use logs of Tx to extract events and results (#776)" (#836) This reverts commit a2377c232118d0eae7fbc72e430d3e2ade6b9c6e. --- .buildkite/steps/revision.sh | 2 +- proxy/common_neon/data.py | 23 ---- proxy/common_neon/environment_data.py | 2 +- proxy/common_neon/evm_decoder.py | 124 ------------------ proxy/common_neon/utils/utils.py | 63 ++++++++- proxy/indexer/indexer.py | 39 ++---- .../neon_rpc_api_model/transaction_sender.py | 5 +- proxy/testing/test_eth_event_log_limit.py | 114 ---------------- proxy/testing/test_indexer_work.py | 57 +------- 9 files changed, 74 insertions(+), 355 deletions(-) delete mode 100644 proxy/common_neon/evm_decoder.py delete mode 100644 proxy/testing/test_eth_event_log_limit.py diff --git a/.buildkite/steps/revision.sh b/.buildkite/steps/revision.sh index 394f64e46..5aade1d1b 100644 --- a/.buildkite/steps/revision.sh +++ b/.buildkite/steps/revision.sh @@ -1,4 +1,4 @@ -set ${NEON_EVM_COMMIT:=ed2de51b11cc676c9305eb660d66b2bd05796153} +set ${NEON_EVM_COMMIT:=latest} set ${FAUCET_COMMIT:=latest} export REVISION=${BUILDKITE_COMMIT} export NEON_EVM_COMMIT diff --git a/proxy/common_neon/data.py b/proxy/common_neon/data.py index 8753e3760..08bfddfcc 100644 --- a/proxy/common_neon/data.py +++ b/proxy/common_neon/data.py @@ -1,5 +1,3 @@ -from dataclasses import dataclass, field -from typing import List, Optional class NeonTxStatData: @@ -12,24 +10,3 @@ def __init__(self, neon_tx_hash: str, neon_income: int, tx_type: str, is_cancele def add_instruction(self, sol_tx_hash: str, sol_spent: int, steps: int, bpf: int) -> None: self.instructions.append((sol_tx_hash, sol_spent, steps, bpf)) - - -@dataclass -class NeonTxReturn: - exit_status: int = 0 - gas_used: int = 0 - return_value: Optional[bytes] = None - - -@dataclass -class NeonEvent: - address: Optional[bytes] = None - count_topics: int = 0 - topics: Optional[List[bytes]] = None - log_data: Optional[bytes] = None - - -@dataclass -class NeonLogIx: - neon_return: Optional[NeonTxReturn] = None - neon_events: List[NeonEvent] = field(default_factory=list) diff --git a/proxy/common_neon/environment_data.py b/proxy/common_neon/environment_data.py index d885fe8ae..a77dc25c8 100644 --- a/proxy/common_neon/environment_data.py +++ b/proxy/common_neon/environment_data.py @@ -44,7 +44,7 @@ SKIP_PREFLIGHT = os.environ.get("SKIP_PREFLIGHT", "NO") == "YES" CONTRACT_EXTRA_SPACE = int(os.environ.get("CONTRACT_EXTRA_SPACE", 2048)) EVM_STEP_COUNT = int(os.environ.get("EVM_STEP_COUNT", 750)) # number of evm-steps, performed by one iteration -MAX_EVM_STEPS_TO_EXECUTE = int(os.environ.get("MAX_EVM_STEPS_TO_EXECUTE", 300000)) +MAX_EVM_STEPS_TO_EXECUTE = int(os.environ.get("MAX_EVM_STEPS_TO_EXECUTE", 100000)) ENABLE_PRIVATE_API = os.environ.get("ENABLE_PRIVATE_API", "NO") == "YES" GATHER_STATISTICS = os.environ.get("GATHER_STATISTICS", "NO") == "YES" ALLOW_UNDERPRICED_TX_WITHOUT_CHAINID = os.environ.get("ALLOW_UNDERPRICED_TX_WITHOUT_CHAINID", "NO") == "YES" diff --git a/proxy/common_neon/evm_decoder.py b/proxy/common_neon/evm_decoder.py deleted file mode 100644 index b39e4d784..000000000 --- a/proxy/common_neon/evm_decoder.py +++ /dev/null @@ -1,124 +0,0 @@ -import re -import base64 - -from typing import Any, Dict, List -from logged_groups import logged_group - -from .environment_data import EVM_LOADER_ID -from .utils import NeonTxResultInfo -from .data import NeonTxReturn, NeonEvent, NeonLogIx - - -@logged_group("neon.Decoder") -def decode_neon_tx_return(data: List[str], logger) -> NeonTxReturn: - """Unpacks base64-encoded return data""" - if len(data) < 2: - logger.error('Failed to decode return data') - return None - bs = base64.b64decode(data[0]) - exit_status = int.from_bytes(bs, "little") - exit_status = 0x1 if exit_status < 0xd0 else 0x0 - bs = base64.b64decode(data[1]) - gas_used = int.from_bytes(bs, "little") - return_value = b'' - if len(data) > 2: - return_value = base64.b64decode(data[2]) - return NeonTxReturn(exit_status, gas_used, return_value) - - -@logged_group("neon.Decoder") -def decode_neon_event(data: List[str], *, logger) -> NeonEvent: - """Unpacks base64-encoded event data""" - if len(data) < 3: - logger.error('Failed to decode events data: less then 3 elements in {data}') - return None - address = base64.b64decode(data[0]) - count_topics = int.from_bytes(base64.b64decode(data[1]), 'little') - if count_topics > 4: - logger.error(f'Failed to decode events data: count of topics more than 4 = {count_topics}') - return None - t = [] - for i in range(count_topics): - t.append(base64.b64decode(data[2 + i])) - log_data = b'' - log_data_index = 2 + count_topics - if log_data_index < len(data): - log_data = base64.b64decode(data[log_data_index]) - return NeonEvent(address, count_topics, t, log_data) - - -@logged_group("neon.Decoder") -def decode_neon_log_instructions(logs: List[str], logger) -> List[NeonLogIx]: - """Reads log messages from a transaction receipt. Parses each line to rebuild sequence of Neon instructions. Extracts return and events information from these lines.""" - program_invoke = re.compile(r'^Program (\w+) invoke \[(\d+)\]') - program_failed = re.compile(r'^Program (\w+) failed') - program_data = re.compile(r'^Program data: (.+)$') - tx_list: List[NeonLogIx] = [] - - for line in logs: - match = program_invoke.match(line) - if match: - program_id = match.group(1) - if program_id == EVM_LOADER_ID: - tx_list.append(NeonLogIx()) - match = program_failed.match(line) - if match: - program_id = match.group(1) - if program_id == EVM_LOADER_ID: - tx_list.pop(-1) # remove failed invocation - match = program_data.match(line) - if match: - tail = match.group(1) - data = re.findall("\S+", tail) - mnemonic = base64.b64decode(data[0]).decode('utf-8') - if mnemonic == "RETURN": - tx_list[-1].neon_return = decode_neon_tx_return(data[1:]) - elif mnemonic.startswith("LOG"): - tx_list[-1].neon_events.append(decode_neon_event(data[1:])) - else: - logger.error(f'Failed to decode log instructions, unexpected mnemonic: {mnemonic}, instruction line: {line}') - raise Exception('Failed to decode log instructions, unexpected mnemonic: %s, instruction line: %s' % (mnemonic, line)) - - return tx_list - - -def decode_neon_tx_result(info: NeonTxResultInfo, neon_sign: str, tx: Dict[Any, Any], ix_idx=-1) -> NeonTxResultInfo: - """Extracts Neon transaction result information""" - log = decode_neon_log_instructions(tx['meta']['logMessages']) - - if ix_idx < 0: - ix_idx = 0 - - if ix_idx >= 0: - log_ix = log[ix_idx] - - if log_ix.neon_return is not None: - if info.slot != -1: - info.warning(f'NeonTxResultInfo already loaded') - info.gas_used = hex(log_ix.neon_return.gas_used) - info.status = hex(log_ix.neon_return.exit_status) - info.return_value = log_ix.neon_return.return_value.hex() - info.sol_sign = tx['transaction']['signatures'][0] - info.slot = tx['slot'] - info.idx = ix_idx - - log_idx = len(info.logs) - for e in log_ix.neon_events: - topics = [] - for i in range(e.count_topics): - topics.append('0x' + e.topics[i].hex()) - rec = { - 'address': '0x' + e.address.hex(), - 'topics': topics, - 'data': '0x' + e.log_data.hex(), - 'transactionLogIndex': hex(log_idx), - 'transactionIndex': hex(info.idx), - 'logIndex': hex(log_idx), - 'transactionHash': neon_sign, - } - info.logs.append(rec) - - if len(info.logs) > 0: - assert info.slot != -1, 'Events without result' - - return info diff --git a/proxy/common_neon/utils/utils.py b/proxy/common_neon/utils/utils.py index 056583214..9da04264d 100644 --- a/proxy/common_neon/utils/utils.py +++ b/proxy/common_neon/utils/utils.py @@ -1,15 +1,17 @@ from __future__ import annotations - from typing import Dict, Any, Optional, List + import json -from enum import Enum +import base58 -from logged_groups import logged_group +from enum import Enum from eth_utils import big_endian_to_int from proxy.indexer.utils import SolanaIxSignInfo -# TODO: move it out from here + +#TODO: move it out from here from ..environment_data import EVM_LOADER_ID, LOG_FULL_OBJECT_INFO + from ..eth_proto import Trx as EthTx @@ -80,7 +82,6 @@ def is_empty(self) -> bool: return self.time is None -@logged_group("neon.Parser") class NeonTxResultInfo: def __init__(self): self._set_defaults() @@ -104,12 +105,44 @@ def _set_defaults(self): self.block_hash = '' self.idx = -1 + def _decode_event(self, neon_sign, log, tx_idx): + log_idx = len(self.logs) + address = log[1:21] + count_topics = int().from_bytes(log[21:29], 'little') + topics = [] + pos = 29 + for _ in range(count_topics): + topic_bin = log[pos:pos + 32] + topics.append('0x' + topic_bin.hex()) + pos += 32 + data = log[pos:] + rec = { + 'address': '0x' + address.hex(), + 'topics': topics, + 'data': '0x' + data.hex(), + 'transactionLogIndex': hex(log_idx), + 'transactionIndex': hex(tx_idx), + 'logIndex': hex(log_idx), + 'transactionHash': neon_sign, + # 'blockNumber': block_number, # set when transaction found + # 'blockHash': block_hash # set when transaction found + } + self.logs.append(rec) + def append_record(self, rec): log_idx = len(self.logs) rec['transactionLogIndex'] = hex(log_idx) rec['logIndex'] = hex(log_idx) self.logs.append(rec) + def _decode_return(self, log: bytes, ix_idx: int, tx: {}): + self.status = '0x1' if log[1] < 0xd0 else '0x0' + self.gas_used = hex(int.from_bytes(log[2:10], 'little')) + self.return_value = log[10:].hex() + self.sol_sign = tx['transaction']['signatures'][0] + self.slot = tx['slot'] + self.idx = ix_idx + def set_result(self, sign: SolanaIxSignInfo, status, gas_used, return_value): self.status = status self.gas_used = gas_used @@ -125,7 +158,25 @@ def fill_block_info(self, block: SolanaBlockInfo): rec['blockHash'] = block.hash rec['blockNumber'] = hex(block.slot) - def canceled(self, tx: Dict[Any, Any]): + def decode(self, neon_sign: str, tx: {}, ix_idx=-1) -> NeonTxResultInfo: + self._set_defaults() + meta_ixs = tx['meta']['innerInstructions'] + msg = tx['transaction']['message'] + accounts = msg['accountKeys'] + + for inner_ix in meta_ixs: + ix_idx = inner_ix['index'] + for event in inner_ix['instructions']: + if accounts[event['programIdIndex']] == EVM_LOADER_ID: + log = base58.b58decode(event['data']) + evm_ix = int(log[0]) + if evm_ix == 7: + self._decode_event(neon_sign, log, ix_idx) + elif evm_ix == 6: + self._decode_return(log, ix_idx, tx) + return self + + def canceled(self, tx: {}): self._set_defaults() self.sol_sign = tx['transaction']['signatures'][0] self.slot = tx['slot'] diff --git a/proxy/indexer/indexer.py b/proxy/indexer/indexer.py index 530d622e1..bd8c8c4ff 100644 --- a/proxy/indexer/indexer.py +++ b/proxy/indexer/indexer.py @@ -1,9 +1,10 @@ +import copy from typing import Iterator, List, Optional, Dict -import time -from enum import Enum import base58 +import time import sha3 +from enum import Enum from logged_groups import logged_group, logging_context from solana.system_program import SYS_PROGRAM_ID @@ -14,10 +15,11 @@ from ..indexer.indexer_db import IndexerDB from ..indexer.utils import SolanaIxSignInfo, MetricsToLogBuff, CostInfo from ..indexer.canceller import Canceller + from ..common_neon.utils import NeonTxResultInfo, NeonTxInfo, str_fmt_object from ..common_neon.solana_interactor import SolanaInteractor from ..common_neon.solana_receipt_parser import SolReceiptParser -from ..common_neon.evm_decoder import decode_neon_tx_result + from ..common_neon.environment_data import EVM_LOADER_ID, FINALIZED, CANCEL_TIMEOUT, SKIP_CANCEL_TIMEOUT, HOLDER_TIMEOUT @@ -38,7 +40,6 @@ def _set_defaults(self): self.ix = {} self.neon_obj = None self.evm_ix = 0xFF - self.evm_ix_idx = -1 self.ix_data = None def _decode_ixdata(self) -> bool: @@ -80,16 +81,14 @@ def iter_ixs(self): if self._get_neon_instruction(): evm_ix_idx += 1 - self.evm_ix_idx = evm_ix_idx - yield self.evm_ix_idx + yield evm_ix_idx for inner_tx in self.tx['meta']['innerInstructions']: if inner_tx['index'] == ix_idx: for self.ix in inner_tx['instructions']: if self._get_neon_instruction(): evm_ix_idx += 1 - self.evm_ix_idx = evm_ix_idx - yield self.evm_ix_idx + yield evm_ix_idx self._set_defaults() @@ -199,7 +198,6 @@ class ReceiptsParserState: - All instructions are removed from the _used_ixs; - If number of the smallest slot in the _used_ixs is changed, it's stored into the DB for the future restart. """ - def __init__(self, db: IndexerDB, solana: SolanaInteractor, indexer_user: IIndexerUser): self._db = db self._solana = solana @@ -462,7 +460,7 @@ def _decode_tx(self, tx: NeonTxResult): If the transaction doesn't have results, then try to get results for the transaction. If the transaction has received results, then call done for the transaction. The transaction can already have results, because parser waits all ixs in the slot, because - the parsing order can be other than the execution order. + the parsing order can be other than the execution order """ self.ix.neon_obj = tx return self._decoding_success(tx, 'mark ix used') @@ -585,7 +583,7 @@ def execute(self) -> bool: if len(self.ix.ix_data) < 41: return self._decoding_skip(f'not enough data to get the Neon account {len(self.ix.ix_data)}') - neon_account = "0x" + self.ix.ix_data[8 + 8 + 4:][:20].hex() + neon_account = "0x" + self.ix.ix_data[8+8+4:][:20].hex() pda_account = self.ix.get_account(1) code_account = self.ix.get_account(3) if code_account == str(SYS_PROGRAM_ID) or code_account == '': @@ -667,9 +665,6 @@ def execute(self) -> bool: tx = NeonTxResult('') tx.neon_tx = neon_tx - if decode_neon_tx_result(tx.neon_res, tx.neon_tx.sign, self.ix.tx, self.ix.evm_ix_idx).is_valid(): - return self._decoding_done(tx, 'found Neon results') - return self._decode_tx(tx) @@ -720,6 +715,8 @@ def execute(self) -> bool: 'data': '0x' + data.hex(), 'transactionIndex': hex(self.ix.sign.idx), 'transactionHash': self.ix.neon_obj.neon_tx.sign, + # 'blockNumber': block_number, # set when transaction found + # 'blockHash': block_hash # set when transaction found } self.ix.neon_obj.neon_res.append_record(rec) @@ -754,11 +751,8 @@ def execute(self) -> bool: return self._decoding_skip(f'Neon tx rlp error "{neon_tx.error}"') tx = self._getadd_tx(storage_account, blocked_accounts, neon_tx) - self.ix.sign.set_steps(step_count) - - if decode_neon_tx_result(tx.neon_res, tx.neon_tx.sign, self.ix.tx, self.ix.evm_ix_idx).is_valid(): - return self._decoding_done(tx, 'found Neon results') + self.ix.sign.set_steps(step_count) return self._decode_tx(tx) @@ -797,10 +791,6 @@ def execute(self) -> bool: return self._decode_skip(f'no transaction at the storage {storage_account}') self.ix.sign.set_steps(step_count) - - if decode_neon_tx_result(tx.neon_res, tx.neon_tx.sign, self.ix.tx, self.ix.evm_ix_idx).is_valid(): - return self._decoding_done(tx, 'found Neon results') - return self._decode_tx(tx) @@ -834,7 +824,6 @@ def execute(self) -> bool: return self._decoding_skip(f'fail to init in storage {storage_account} from holder {holder_account}') self.ix.sign.set_steps(step_count) - return self._decode_tx(tx) @@ -899,10 +888,6 @@ def execute(self) -> bool: return self._decoding_skip(f'fail to init the storage {storage_account} from the holder {holder_account}') self.ix.sign.set_steps(step_count) - - if decode_neon_tx_result(tx.neon_res, tx.neon_tx.sign, self.ix.tx, self.ix.evm_ix_idx).is_valid(): - return self._decoding_done(tx, 'found Neon results') - return self._decode_tx(tx) diff --git a/proxy/neon_rpc_api_model/transaction_sender.py b/proxy/neon_rpc_api_model/transaction_sender.py index 30bc598ea..e3df2499f 100644 --- a/proxy/neon_rpc_api_model/transaction_sender.py +++ b/proxy/neon_rpc_api_model/transaction_sender.py @@ -25,9 +25,8 @@ from ..common_neon.types import NeonTxPrecheckResult, NeonEmulatingResult from ..common_neon.environment_data import RETRY_ON_FAIL from ..common_neon.elf_params import ElfParams -from ..common_neon.utils import get_holder_msg -from ..common_neon.evm_decoder import decode_neon_tx_result from ..memdb.memdb import MemDB, NeonPendingTxInfo +from ..common_neon.utils import get_holder_msg @logged_group("neon.Proxy") @@ -268,7 +267,7 @@ def __init__(self, strategy: BaseNeonTxStrategy, *args, **kwargs): def _on_success_send(self, tx: Transaction, receipt: {}): if not self.neon_res.is_valid(): - decode_neon_tx_result(self.neon_res, self._s.neon_sign, receipt).is_valid() + self.neon_res.decode(self._s.neon_sign, receipt).is_valid() super()._on_success_send(tx, receipt) def _on_post_send(self): diff --git a/proxy/testing/test_eth_event_log_limit.py b/proxy/testing/test_eth_event_log_limit.py deleted file mode 100644 index 339a911e8..000000000 --- a/proxy/testing/test_eth_event_log_limit.py +++ /dev/null @@ -1,114 +0,0 @@ -import unittest -import os -from web3 import Web3 -from solcx import compile_source - -from proxy.testing.testing_helpers import request_airdrop -from proxy.common_neon import environment_data - -SEED = 'https://github.com/neonlabsorg/proxy-model.py/issues/812' -EXTRA_GAS = int(os.environ.get("EXTRA_GAS", "0")) -proxy_url = os.environ.get('PROXY_URL', 'http://localhost:9090/solana') -proxy = Web3(Web3.HTTPProvider(proxy_url)) -eth_account = proxy.eth.account.create(SEED) -proxy.eth.default_account = eth_account.address - -TEST_EVENT_SOURCE_812 = ''' -// SPDX-License-Identifier: MIT -pragma solidity >=0.7.0; - -contract GenerateEvents { - event Frob(bytes); - - function frobnicate(uint size, bytes1 char) public { - bytes memory s = new bytes(size); - for (uint i = 0; i < size; i++) { - s[i] = char; - } - emit Frob(s); - } -} -''' - -class Test_eth_event_log_limit(unittest.TestCase): - @classmethod - def setUpClass(cls): - print("\n\n") - print(SEED) - print('eth_account.address:', eth_account.address) - print('eth_account.key:', eth_account.key.hex()) - request_airdrop(eth_account.address) - - cls.block_hashes = [] - cls.block_numbers = [] - cls.topics = [] - - cls.deploy_contract(cls) - cls.commit_transactions(cls) - - print(cls.block_hashes) - print(cls.block_numbers) - print(cls.topics) - - @classmethod - def tearDownClass(cls) -> None: - pass - - def deploy_contract(self): - compiled_sol = compile_source(TEST_EVENT_SOURCE_812) - contract_id, contract_interface = compiled_sol.popitem() - storage = proxy.eth.contract(abi=contract_interface['abi'], bytecode=contract_interface['bin']) - trx_deploy = proxy.eth.account.sign_transaction(dict( - nonce=proxy.eth.get_transaction_count(proxy.eth.default_account), - chainId=proxy.eth.chain_id, - gas=987654321, - gasPrice=1000000000, - to='', - value=0, - data=storage.bytecode), - eth_account.key - ) - print('trx_deploy:', trx_deploy) - trx_deploy_hash = proxy.eth.send_raw_transaction(trx_deploy.rawTransaction) - print('trx_deploy_hash:', trx_deploy_hash.hex()) - trx_deploy_receipt = proxy.eth.wait_for_transaction_receipt(trx_deploy_hash) - print('trx_deploy_receipt:', trx_deploy_receipt) - - self.storage_contract = proxy.eth.contract( - address=trx_deploy_receipt.contractAddress, - abi=storage.abi - ) - - def commit_transactions(self): - self.commit_event_trx(self, 1000, 41) - self.commit_event_trx(self, 2000, 42) - self.commit_event_trx(self, 3000, 43) - pass - - def commit_event_trx(self, event_size: int, char: int) -> None: - print("\ncommit_event_trx(", event_size, char, ")") - right_nonce = proxy.eth.get_transaction_count(proxy.eth.default_account) - trx_store = self.storage_contract.functions.frobnicate(event_size, bytes([char])).buildTransaction({'nonce': right_nonce}) - trx_store_signed = proxy.eth.account.sign_transaction(trx_store, eth_account.key) - trx_store_hash = proxy.eth.send_raw_transaction(trx_store_signed.rawTransaction) - trx_store_receipt = proxy.eth.wait_for_transaction_receipt(trx_store_hash) - - print('trx_store_receipt:', trx_store_receipt) - self.block_hashes.append(trx_store_receipt['blockHash'].hex()) - self.block_numbers.append(hex(trx_store_receipt['blockNumber'])) - for log in trx_store_receipt['logs']: - for topic in log['topics']: - self.topics.append(topic.hex()) - - def test_get_logs_by_blockHash(self): - print("\ntest_get_logs_by_blockHash") - receipts = proxy.eth.get_logs({'blockHash': self.block_hashes[0]}) - print('receipts[0]: ', receipts) - receipts = proxy.eth.get_logs({'blockHash': self.block_hashes[1]}) - print('receipts[1]: ', receipts) - receipts = proxy.eth.get_logs({'blockHash': self.block_hashes[2]}) - print('receipts[2]: ', receipts) - pass - -if __name__ == '__main__': - unittest.main() diff --git a/proxy/testing/test_indexer_work.py b/proxy/testing/test_indexer_work.py index e32d01dba..93f7fbb74 100644 --- a/proxy/testing/test_indexer_work.py +++ b/proxy/testing/test_indexer_work.py @@ -88,7 +88,7 @@ class CancelTest(unittest.TestCase): @classmethod def setUpClass(cls): - print("\ntest_indexer_work.py setUpClass") + print("\ntest_cancel_hanged.py setUpClass") request_airdrop(eth_account.address) request_airdrop(eth_account_invoked.address) @@ -134,7 +134,6 @@ def setUpClass(cls): cls.create_hanged_transaction(cls) cls.create_invoked_transaction(cls) cls.create_invoked_transaction_combined(cls) - cls.create_two_calls_in_transaction(cls) def get_accounts(self, ether): (sol_address, _) = self.loader.ether2program(str(ether)) @@ -286,51 +285,6 @@ def create_invoked_transaction_combined(self): SolanaClient(solana_url).send_transaction(tx, self.acc, opts=TxOpts(skip_preflight=False, skip_confirmation=False)) - def create_two_calls_in_transaction(self): - print("\ncreate_two_calls_in_transaction") - - account_list = [ - AccountMeta(pubkey=self.caller, is_signer=False, is_writable=True), - AccountMeta(pubkey=self.reId, is_signer=False, is_writable=True), - AccountMeta(pubkey=self.re_code, is_signer=False, is_writable=True), - ] - - nonce1 = proxy.eth.get_transaction_count(proxy.eth.default_account) - tx = {'nonce': nonce1, 'gasPrice': MINIMAL_GAS_PRICE} - call1_dict = self.storage_contract.functions.addReturn(1, 1).buildTransaction(tx) - call1_signed = proxy.eth.account.sign_transaction(call1_dict, eth_account.key) - (from_addr, sign1, msg1) = make_instruction_data_from_tx(call1_signed.rawTransaction.hex()) - (raw, self.tx_hash_call1, from_addr) = self.get_trx_receipts(self, msg1, sign1) - print('tx_hash_call1:', self.tx_hash_call1) - - nonce2 = nonce1 + 1 - tx = {'nonce': nonce2, 'gasPrice': MINIMAL_GAS_PRICE} - call2_dict = self.storage_contract.functions.addReturnEvent(2, 2).buildTransaction(tx) - call2_signed = proxy.eth.account.sign_transaction(call2_dict, eth_account.key) - (from_addr, sign2, msg2) = make_instruction_data_from_tx(call2_signed.rawTransaction.hex()) - (raw, self.tx_hash_call2, from_addr) = self.get_trx_receipts(self, msg2, sign2) - print('tx_hash_call2:', self.tx_hash_call2) - - tx = TransactionWithComputeBudget() - - call1_tx = Trx.fromString(bytearray.fromhex(call1_signed.rawTransaction.hex()[2:])) - builder = NeonInstruction(self.acc.public_key()) - builder.init_operator_ether(self.caller_ether) - builder.init_eth_trx(call1_tx, account_list) - noniterative1 = builder.make_noniterative_call_transaction(len(tx.instructions)) - tx.add(noniterative1) - - call2_tx = Trx.fromString(bytearray.fromhex(call2_signed.rawTransaction.hex()[2:])) - builder = NeonInstruction(self.acc.public_key()) - builder.init_operator_ether(self.caller_ether) - builder.init_eth_trx(call2_tx, account_list) - noniterative2 = builder.make_noniterative_call_transaction(len(tx.instructions)) - tx.add(noniterative2) - - #print(tx.__dict__) - opts=TxOpts(skip_preflight=False, skip_confirmation=False, preflight_commitment=Confirmed) - SolanaClient(solana_url).send_transaction(tx, self.acc, opts=opts) - def get_trx_receipts(self, unsigned_msg, signature): trx = rlp.decode(unsigned_msg, EthTrx) @@ -414,15 +368,6 @@ def test_04_right_result_for_invoked(self): trx_receipt = proxy.eth.wait_for_transaction_receipt(self.tx_hash_invoked_combined) print('trx_receipt:', trx_receipt) - def test_05_check_two_calls_in_transaction(self): - print("\ntest_05_check_two_calls_in_transaction") - call1_receipt = proxy.eth.wait_for_transaction_receipt(self.tx_hash_call1) - print('test_05 receipt1:', call1_receipt) - self.assertEqual(len(call1_receipt['logs']), 0) - call2_receipt = proxy.eth.wait_for_transaction_receipt(self.tx_hash_call2) - print('test_05 receipt2:', call2_receipt) - self.assertEqual(len(call2_receipt['logs']), 1) - if __name__ == '__main__': unittest.main()