-
Notifications
You must be signed in to change notification settings - Fork 19
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
* #291 extract transaction sender class * #291 move perm accs to transaction sender * #291 fix state * #291 fix errors * #291 merge fixes * #291 refactoring * #291 move EXTRA_GAS to environment * #291 capitalize CONFIRMATION_CHECK_DELAY * #291 sort imports * #291 relative paths * #291 Should be fixed in #326 * #291 testing chnages * fix storage account check * #291 rename `trx_with_create_and_airdrop` -> `make_trx_with_create_and_airdrop` * #291 pull request fixes * #291 merge fix * #291 rename operator and associated token accounts Co-authored-by: sinev-valentine <[email protected]>
- Loading branch information
1 parent
c7ef793
commit e74e568
Showing
24 changed files
with
1,376 additions
and
1,266 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,70 @@ | ||
import logging | ||
import random | ||
|
||
from eth_keys import keys as eth_keys | ||
from hashlib import sha256 | ||
from solana.publickey import PublicKey | ||
from spl.token.instructions import get_associated_token_address | ||
from typing import NamedTuple | ||
|
||
from .layouts import ACCOUNT_INFO_LAYOUT | ||
from ..environment import neon_cli, ETH_TOKEN_MINT_ID, EVM_LOADER_ID | ||
|
||
|
||
logger = logging.getLogger(__name__) | ||
logger.setLevel(logging.DEBUG) | ||
|
||
|
||
class EthereumAddress: | ||
def __init__(self, data, private=None): | ||
if isinstance(data, str): | ||
data = bytes(bytearray.fromhex(data[2:])) | ||
self.data = data | ||
self.private = private | ||
|
||
@staticmethod | ||
def random(): | ||
letters = '0123456789abcdef' | ||
data = bytearray.fromhex(''.join([random.choice(letters) for k in range(64)])) | ||
pk = eth_keys.PrivateKey(data) | ||
return EthereumAddress(pk.public_key.to_canonical_address(), pk) | ||
|
||
def __str__(self): | ||
return '0x'+self.data.hex() | ||
|
||
def __repr__(self): | ||
return self.__str__() | ||
|
||
def __bytes__(self): return self.data | ||
|
||
|
||
def accountWithSeed(base, seed): | ||
result = PublicKey(sha256(bytes(base) + bytes(seed) + bytes(PublicKey(EVM_LOADER_ID))).digest()) | ||
return result | ||
|
||
|
||
def ether2program(ether): | ||
if isinstance(ether, str): | ||
pass | ||
elif isinstance(ether, EthereumAddress): | ||
ether = str(ether) | ||
else: | ||
ether = ether.hex() | ||
output = neon_cli().call("create-program-address", ether) | ||
items = output.rstrip().split(' ') | ||
return items[0], int(items[1]) | ||
|
||
|
||
def getTokenAddr(account): | ||
return get_associated_token_address(PublicKey(account), ETH_TOKEN_MINT_ID) | ||
|
||
|
||
class AccountInfo(NamedTuple): | ||
ether: eth_keys.PublicKey | ||
trx_count: int | ||
code_account: PublicKey | ||
|
||
@staticmethod | ||
def frombytes(data): | ||
cont = ACCOUNT_INFO_LAYOUT.parse(data) | ||
return AccountInfo(cont.ether, cont.trx_count, PublicKey(cont.code_account)) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,12 @@ | ||
KECCAK_PROGRAM = "KeccakSecp256k11111111111111111111111111111" | ||
INCINERATOR_PUBKEY = "1nc1nerator11111111111111111111111111111111" | ||
SYSVAR_INSTRUCTION_PUBKEY = "Sysvar1nstructions1111111111111111111111111" | ||
|
||
STORAGE_SIZE = 128*1024 | ||
|
||
ACCOUNT_SEED_VERSION=b'\1' | ||
|
||
COLLATERALL_POOL_MAX=10 | ||
|
||
EMPTY_STORAGE_TAG=0 | ||
FINALIZED_STORAGE_TAG=5 |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,93 @@ | ||
import base58 | ||
import psycopg2 | ||
|
||
from ..environment import EVM_LOADER_ID | ||
from ..indexer.sql_dict import POSTGRES_USER, POSTGRES_HOST, POSTGRES_DB, POSTGRES_PASSWORD | ||
|
||
class SQLCost(): | ||
def __init__(self): | ||
|
||
self.conn = psycopg2.connect( | ||
dbname=POSTGRES_DB, | ||
user=POSTGRES_USER, | ||
password=POSTGRES_PASSWORD, | ||
host=POSTGRES_HOST | ||
) | ||
|
||
self.conn.set_isolation_level(psycopg2.extensions.ISOLATION_LEVEL_AUTOCOMMIT) | ||
cur = self.conn.cursor() | ||
cur.execute(''' | ||
CREATE TABLE IF NOT EXISTS OPERATOR_COST | ||
( | ||
hash char(64), | ||
cost bigint, | ||
used_gas bigint, | ||
sender char(40), | ||
to_address char(40) , | ||
sig char(100), | ||
status varchar(100), | ||
reason varchar(100) | ||
)''' | ||
) | ||
|
||
def close(self): | ||
self.conn.close() | ||
|
||
def insert(self, hash, cost, used_gas, sender, to_address, sig, status, reason): | ||
cur = self.conn.cursor() | ||
cur.execute(''' | ||
INSERT INTO OPERATOR_COST (hash, cost, used_gas, sender, to_address, sig, status, reason) | ||
VALUES (%s,%s,%s,%s,%s,%s,%s,%s) | ||
''', | ||
(hash, cost, used_gas, sender, to_address, sig, status, reason) | ||
) | ||
|
||
|
||
class CostSingleton(object): | ||
def __new__(cls): | ||
if not hasattr(cls, 'instance'): | ||
cls.instance = super(CostSingleton, cls).__new__(cls) | ||
cls.instance.operator_cost = SQLCost() | ||
return cls.instance | ||
|
||
|
||
def update_transaction_cost(receipt, eth_trx, extra_sol_trx=False, reason=None): | ||
cost = receipt['result']['meta']['preBalances'][0] - receipt['result']['meta']['postBalances'][0] | ||
if eth_trx: | ||
hash = eth_trx.hash_signed().hex() | ||
sender = eth_trx.sender() | ||
to_address = eth_trx.toAddress.hex() if eth_trx.toAddress else "None" | ||
else: | ||
hash = None | ||
sender = None | ||
to_address = None | ||
|
||
sig = receipt['result']['transaction']['signatures'][0] | ||
used_gas=None | ||
|
||
tx_info = receipt['result'] | ||
accounts = tx_info["transaction"]["message"]["accountKeys"] | ||
evm_loader_instructions = [] | ||
|
||
for idx, instruction in enumerate(tx_info["transaction"]["message"]["instructions"]): | ||
if accounts[instruction["programIdIndex"]] == EVM_LOADER_ID: | ||
evm_loader_instructions.append(idx) | ||
|
||
for inner in (tx_info['meta']['innerInstructions']): | ||
if inner["index"] in evm_loader_instructions: | ||
for event in inner['instructions']: | ||
if accounts[event['programIdIndex']] == EVM_LOADER_ID: | ||
used_gas = base58.b58decode(event['data'])[2:10] | ||
used_gas = int().from_bytes(used_gas, "little") | ||
|
||
table = CostSingleton().operator_cost | ||
table.insert( | ||
hash, | ||
cost, | ||
used_gas if used_gas else 0, | ||
sender, | ||
to_address, | ||
sig, | ||
'extra' if extra_sol_trx else 'ok', | ||
reason if reason else '' | ||
) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,34 @@ | ||
import json | ||
import logging | ||
|
||
from .errors import EthereumError | ||
from ..environment import neon_cli | ||
|
||
|
||
logger = logging.getLogger(__name__) | ||
logger.setLevel(logging.DEBUG) | ||
|
||
|
||
def call_emulated(contract_id, caller_id, data=None, value=None): | ||
output = emulator(contract_id, caller_id, data, value) | ||
logger.debug("call_emulated %s %s %s %s return %s", contract_id, caller_id, data, value, output) | ||
result = json.loads(output) | ||
exit_status = result['exit_status'] | ||
if exit_status == 'revert': | ||
result_value = result['result'] | ||
if len(result_value) < 8 or result_value[:8] != '08c379a0': | ||
raise EthereumError(code=3, message='execution reverted') | ||
|
||
offset = int(result_value[8:8+64], 16) | ||
length = int(result_value[8+64:8+64+64], 16) | ||
message = str(bytes.fromhex(result_value[8+offset*2+64:8+offset*2+64+length*2]), 'utf8') | ||
raise EthereumError(code=3, message='execution reverted: '+message, data='0x'+result_value) | ||
if result["exit_status"] != "succeed": | ||
raise Exception("evm emulator error ", result) | ||
return result | ||
|
||
|
||
def emulator(contract, sender, data, value): | ||
data = data or "none" | ||
value = value or "" | ||
return neon_cli().call("emulate", sender, contract, data, value) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,39 @@ | ||
|
||
from construct import Bytes, Int8ul, Int64ul | ||
from construct import Struct | ||
|
||
STORAGE_ACCOUNT_INFO_LAYOUT = Struct( | ||
# "tag" / Int8ul, | ||
"caller" / Bytes(20), | ||
"nonce" / Int64ul, | ||
"gas_limit" / Int64ul, | ||
"gas_price" / Int64ul, | ||
"slot" / Int64ul, | ||
"operator" / Bytes(32), | ||
"accounts_len" / Int64ul, | ||
"executor_data_size" / Int64ul, | ||
"evm_data_size" / Int64ul, | ||
"gas_used_and_paid" / Int64ul, | ||
"number_of_payments" / Int64ul, | ||
"sign" / Bytes(65), | ||
) | ||
|
||
ACCOUNT_INFO_LAYOUT = Struct( | ||
"type" / Int8ul, | ||
"ether" / Bytes(20), | ||
"nonce" / Int8ul, | ||
"trx_count" / Bytes(8), | ||
"code_account" / Bytes(32), | ||
"is_rw_blocked" / Int8ul, | ||
"rw_blocked_acc" / Bytes(32), | ||
"eth_token_account" / Bytes(32), | ||
"ro_blocked_cnt" / Int8ul, | ||
) | ||
|
||
|
||
CREATE_ACCOUNT_LAYOUT = Struct( | ||
"lamports" / Int64ul, | ||
"space" / Int64ul, | ||
"ether" / Bytes(20), | ||
"nonce" / Int8ul | ||
) |
Oops, something went wrong.