Skip to content
Merged
Show file tree
Hide file tree
Changes from 30 commits
Commits
Show all changes
38 commits
Select commit Hold shift + click to select a range
90a4e56
#291 extract transaction sender class
otselnik Nov 14, 2021
143913b
#291 move perm accs to transaction sender
otselnik Nov 16, 2021
16c9bff
#291 fix state
otselnik Nov 22, 2021
f2c0303
#291 fix errors
otselnik Nov 23, 2021
57f3b53
Merge remote-tracking branch 'origin/develop' into 291_proxy_refactoring
otselnik Nov 23, 2021
3369f67
#291 merge fixes
otselnik Nov 23, 2021
af721bb
#291 refactoring
otselnik Nov 23, 2021
e512bb8
#291 move EXTRA_GAS to environment
otselnik Nov 23, 2021
8dc5e29
#291 capitalize CONFIRMATION_CHECK_DELAY
otselnik Nov 23, 2021
8dce2a5
#291 sort imports
otselnik Nov 23, 2021
cef8f21
#291 relative paths
otselnik Nov 24, 2021
1bf8383
#291 Should be fixed in #326
otselnik Nov 24, 2021
9672438
#291 testing chnages
otselnik Nov 24, 2021
2d42b73
fix storage account check
sinev-valentine Nov 24, 2021
ac2755c
Merge remote-tracking branch 'origin/develop' into 291_proxy_refactoring
otselnik Nov 24, 2021
3519c61
Merge branch '371_add_FinalizedStorage_to_check' into 291_proxy_refac…
otselnik Nov 24, 2021
bf313a2
#291 rename `trx_with_create_and_airdrop` -> `make_trx_with_create_an…
otselnik Nov 24, 2021
3093fcc
Merge remote-tracking branch 'origin/develop' into 291_proxy_refactoring
otselnik Nov 24, 2021
e3c4e33
#295 fix state
otselnik Nov 24, 2021
9b57e53
#291 iterative combined
otselnik Nov 25, 2021
ccffcf4
#295 do not get measurments
otselnik Nov 25, 2021
4d685db
#291 pull request fixes
otselnik Nov 25, 2021
6f63338
Merge remote-tracking branch 'origin/develop' into 291_proxy_refactoring
otselnik Nov 25, 2021
4546926
Merge branch '291_proxy_refactoring' into 295_iterative_execution
otselnik Nov 25, 2021
7befc6b
#295 turn combined instructions ON
otselnik Nov 29, 2021
b5010f8
#295 make neon_instructions return transasactions
otselnik Nov 29, 2021
5ebf76a
Merge remote-tracking branch 'origin/develop' into 291_proxy_refactoring
otselnik Dec 2, 2021
b464b1e
#291 merge fix
otselnik Dec 2, 2021
79088c6
#295 get rid of `USE_COMBINED_START_CONTINUE`
otselnik Dec 2, 2021
52173a0
Merge branch '291_proxy_refactoring' into 295_iterative_execution
otselnik Dec 2, 2021
4fe15e9
#295 requested fixes
otselnik Dec 2, 2021
607e74e
Merge remote-tracking branch 'origin/develop' into 295_iterative_exec…
otselnik Dec 2, 2021
d9f762a
#295 call_continue_bucked refactoring
otselnik Dec 2, 2021
842ec7d
#295 fix
otselnik Dec 3, 2021
78de121
#295 leave only combined iterative transactions
otselnik Dec 3, 2021
47cf219
#295 move constants into class
otselnik Dec 3, 2021
0eebc1f
#295 refactoring
otselnik Dec 3, 2021
cec7a38
Merge remote-tracking branch 'origin/develop' into 295_iterative_exec…
otselnik Dec 6, 2021
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion .buildkite/steps/build-image.sh
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ set -euo pipefail

REVISION=$(git rev-parse HEAD)

set ${SOLANA_REVISION:=v1.7.9-resources}
set ${SOLANA_REVISION:=v1.7.9-testnet}
set ${EVM_LOADER_REVISION:=latest}

# Refreshing neonlabsorg/solana:latest image is required to run .buildkite/steps/build-image.sh locally
Expand Down
2 changes: 1 addition & 1 deletion Dockerfile
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
ARG SOLANA_REVISION=v1.7.9-resources
ARG SOLANA_REVISION=v1.7.9-testnet
ARG EVM_LOADER_REVISION=latest

FROM neonlabsorg/solana:${SOLANA_REVISION} AS cli
Expand Down
70 changes: 70 additions & 0 deletions proxy/common_neon/address.py
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))
12 changes: 12 additions & 0 deletions proxy/common_neon/constants.py
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
93 changes: 93 additions & 0 deletions proxy/common_neon/costs.py
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 ''
)
34 changes: 34 additions & 0 deletions proxy/common_neon/emulator_interactor.py
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)
11 changes: 11 additions & 0 deletions proxy/common_neon/errors.py
Original file line number Diff line number Diff line change
@@ -1,6 +1,17 @@
from enum import Enum


class EthereumError(Exception):
def __init__(self, code, message, data=None):
self.code = code
self.message = message
self.data = data

def getError(self):
error = {'code': self.code, 'message': self.message}
if self.data: error['data'] = self.data
return error

class SolanaErrors(Enum):
AccountNotFound = "Invalid param: could not find account"

Expand Down
39 changes: 39 additions & 0 deletions proxy/common_neon/layouts.py
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
)
Loading