Create basic PyEVMDebugBackend for injecting debugger on the computation.
This commit is contained in:
parent
bcb1eb03d5
commit
32d45a76fa
|
@ -4,18 +4,12 @@ import vyper
|
|||
from collections import Counter
|
||||
from pprint import pprint
|
||||
from vyper import compiler
|
||||
from vyper.parser import (
|
||||
parser,
|
||||
)
|
||||
from vdb.vdb import (
|
||||
set_evm_opcode_debugger,
|
||||
set_evm_opcode_pass
|
||||
)
|
||||
|
||||
from vdb.source_map import (
|
||||
produce_source_map
|
||||
)
|
||||
from eth_tester import (
|
||||
EthereumTester,
|
||||
from vdb.eth_tester_debug_backend import (
|
||||
PyEVMDebugBackend
|
||||
)
|
||||
from web3.providers.eth_tester import (
|
||||
EthereumTesterProvider,
|
||||
|
@ -30,7 +24,6 @@ aparser.add_argument('call_list', help='call list, without parameters: func, wit
|
|||
aparser.add_argument('-i', help='init args, comma separated', default=None, dest='init_args')
|
||||
|
||||
args = aparser.parse_args()
|
||||
set_evm_opcode_pass() # by default just pass over the debug opcode.
|
||||
|
||||
|
||||
def cast_types(args, abi_signature):
|
||||
|
@ -43,10 +36,15 @@ def cast_types(args, abi_signature):
|
|||
return newargs
|
||||
|
||||
|
||||
def get_tester():
|
||||
tester = EthereumTester()
|
||||
def get_tester(code):
|
||||
from eth_tester import (
|
||||
EthereumTester,
|
||||
)
|
||||
tester = EthereumTester(backend=PyEVMDebugBackend())
|
||||
import ipdb; ipdb.set_trace()
|
||||
def zero_gas_price_strategy(web3, transaction_params=None):
|
||||
return 0 # zero gas price makes testing simpler.
|
||||
|
||||
w3 = Web3(EthereumTesterProvider(tester))
|
||||
w3.eth.setGasPriceStrategy(zero_gas_price_strategy)
|
||||
return tester, w3
|
||||
|
@ -122,7 +120,7 @@ if __name__ == '__main__':
|
|||
code = fh.read()
|
||||
# Patch in vdb.
|
||||
init_args = args.init_args.split(',') if args.init_args else []
|
||||
tester, w3 = get_tester()
|
||||
tester, w3 = get_tester(code)
|
||||
|
||||
# Built list of calls to make.
|
||||
calls = []
|
||||
|
@ -146,7 +144,6 @@ if __name__ == '__main__':
|
|||
init_abi = next(filter(lambda func: func["name"] == '__init__', abi))
|
||||
init_args = cast_types(init_args, init_abi)
|
||||
|
||||
|
||||
# Compile contract to chain.
|
||||
contract = get_contract(w3, code, *init_args)
|
||||
|
||||
|
@ -167,10 +164,7 @@ if __name__ == '__main__':
|
|||
|
||||
res = getattr(contract.functions, func_name)(*cast_args).call({'gas': func_abi.get('gas', 0) + 50000})
|
||||
|
||||
source_map = produce_source_map(code)
|
||||
set_evm_opcode_debugger(source_code=code, source_map=source_map)
|
||||
tx_hash = getattr(contract.functions, func_name)(*cast_args).transact({'gas': func_abi.get('gas', 0) + 50000})
|
||||
set_evm_opcode_pass()
|
||||
|
||||
print('- Returns:')
|
||||
res = getattr(contract.functions, func_name)(*cast_args).call({'gas': func_abi['gas'] + 92000})
|
||||
|
|
|
@ -0,0 +1,54 @@
|
|||
from evm.vm.forks.byzantium.computation import (
|
||||
ByzantiumComputation,
|
||||
)
|
||||
from evm.exceptions import (
|
||||
Halt,
|
||||
)
|
||||
from vdb.vdb import VyperDebugCmd
|
||||
|
||||
|
||||
class DebugComputation(ByzantiumComputation):
|
||||
source_code = None
|
||||
source_map = None
|
||||
|
||||
def run_debugger(self, computation, line_no):
|
||||
VyperDebugCmd(
|
||||
computation,
|
||||
line_no=line_no,
|
||||
source_code=self.source_code,
|
||||
source_map=self.source_map,
|
||||
stdin=None,
|
||||
stdout=None
|
||||
).cmdloop()
|
||||
|
||||
@classmethod
|
||||
def apply_computation(cls, state, message, transaction_context):
|
||||
print('hello!!!!!!')
|
||||
import ipdb; ipdb.set_trace()
|
||||
with cls(state, message, transaction_context) as computation:
|
||||
|
||||
# Early exit on pre-compiles
|
||||
if message.code_address in computation.precompiles:
|
||||
computation.precompiles[message.code_address](computation)
|
||||
return computation
|
||||
|
||||
for opcode in computation.code:
|
||||
opcode_fn = computation.get_opcode_fn(opcode)
|
||||
|
||||
pc_to_execute = max(0, computation.code.pc - 1)
|
||||
computation.logger.trace(
|
||||
"OPCODE: 0x%x (%s) | pc: %s",
|
||||
opcode,
|
||||
opcode_fn.mnemonic,
|
||||
pc_to_execute,
|
||||
)
|
||||
|
||||
# if pc_to_execute in self.debugger.breakpoints:
|
||||
# import ipdb; ipdb.set_trace()
|
||||
|
||||
try:
|
||||
opcode_fn(computation=computation)
|
||||
except Halt:
|
||||
break
|
||||
|
||||
return computation
|
|
@ -0,0 +1,49 @@
|
|||
from evm.vm.forks.byzantium import ByzantiumVM
|
||||
from evm.vm.forks.byzantium.state import ByzantiumState
|
||||
|
||||
from vdb.debug_computation import DebugComputation
|
||||
|
||||
from eth_tester.backends.pyevm.main import (
|
||||
get_default_genesis_params,
|
||||
generate_genesis_state,
|
||||
get_default_genesis_params,
|
||||
get_default_account_keys,
|
||||
PyEVMBackend
|
||||
)
|
||||
|
||||
|
||||
class DebugState(ByzantiumState):
|
||||
computation_class = DebugComputation
|
||||
|
||||
|
||||
class DebugVM(ByzantiumVM):
|
||||
_state_class = DebugState # type: Type[BaseState]
|
||||
|
||||
|
||||
def _setup_tester_chain():
|
||||
from evm.chains.tester import MainnetTesterChain
|
||||
from evm.db import get_db_backend
|
||||
|
||||
class DebugNoProofVM(DebugVM):
|
||||
"""Byzantium VM rules, without validating any miner proof of work"""
|
||||
|
||||
def validate_seal(self, header):
|
||||
pass
|
||||
|
||||
class MainnetTesterNoProofChain(MainnetTesterChain):
|
||||
vm_configuration = ((0, DebugNoProofVM), )
|
||||
|
||||
genesis_params = get_default_genesis_params()
|
||||
account_keys = get_default_account_keys()
|
||||
genesis_state = generate_genesis_state(account_keys)
|
||||
|
||||
base_db = get_db_backend()
|
||||
|
||||
chain = MainnetTesterNoProofChain.from_genesis(base_db, genesis_params, genesis_state)
|
||||
return account_keys, chain
|
||||
|
||||
|
||||
class PyEVMDebugBackend(PyEVMBackend):
|
||||
|
||||
def reset_to_genesis(self):
|
||||
self.account_keys, self.chain = _setup_tester_chain()
|
55
vdb/vdb.py
55
vdb/vdb.py
|
@ -253,58 +253,3 @@ def set_evm_opcode_pass():
|
|||
gas_cost=0
|
||||
)
|
||||
setattr(evm.vm.forks.byzantium.computation.ByzantiumComputation, 'opcodes', opcodes)
|
||||
|
||||
|
||||
class DebugVM(ByzantiumVM):
|
||||
self.breakpoints = list()
|
||||
|
||||
def run_debugger(self, computation)
|
||||
VyperDebugCmd(
|
||||
computation,
|
||||
line_no=line_no,
|
||||
source_code=source_code,
|
||||
source_map=source_map,
|
||||
stdin=stdin,
|
||||
stdout=stdout
|
||||
).cmdloop()
|
||||
|
||||
@classmethod
|
||||
def apply_computation(cls,
|
||||
state: BaseState,
|
||||
message: Message,
|
||||
transaction_context: BaseTransactionContext) -> 'BaseComputation':
|
||||
|
||||
with cls(state, message, transaction_context) as computation:
|
||||
|
||||
# Early exit on pre-compiles
|
||||
if message.code_address in computation.precompiles:
|
||||
computation.precompiles[message.code_address](computation)
|
||||
return computation
|
||||
|
||||
for opcode in computation.code:
|
||||
opcode_fn = computation.get_opcode_fn(opcode)
|
||||
|
||||
pc_to_execute = max(0, computation.code.pc - 1)
|
||||
computation.logger.trace(
|
||||
"OPCODE: 0x%x (%s) | pc: %s",
|
||||
opcode,
|
||||
opcode_fn.mnemonic,
|
||||
pc_to_execute,
|
||||
)
|
||||
|
||||
if pc_to_execute in self.debugger.reakpoints:
|
||||
import ipdb; ipdb.set_trace()
|
||||
|
||||
try:
|
||||
opcode_fn(computation=computation)
|
||||
except Halt:
|
||||
break
|
||||
|
||||
return computation
|
||||
|
||||
original_vm = evm.vm.forks.byzantium.ByzantiumVM
|
||||
|
||||
|
||||
def set_debug_vm():
|
||||
setattr(evm.vm.forks.byzantium, 'ByzantiumVM', DebugVM)
|
||||
setattr(evm.vm.forks.byzantium.ByzantiumVM, 'breakpoints', [])
|
||||
|
|
Loading…
Reference in New Issue