def test_if_enough_time_passed_since_last_play_then_grant_earnings_to_last_player( self): # Player 1 presses the button result = self.contract.process(MIN_AMOUNT_REQUIRED, value=140, sender=t.k0) self.assertEquals(result, 1) self.state.mine(1) winningBalanceBefore = State().get_balance(u.int_to_addr(t.k1)) losingBalanceBefore = State().get_balance(u.int_to_addr(t.k0)) # Player 2 presses the button result = self.contract.process(MIN_AMOUNT_REQUIRED, value=140, sender=t.k1) self.assertEquals(result, 1) self.state.mine(3) # Player 2 presses the button again result = self.contract.process(MIN_AMOUNT_REQUIRED, value=140, sender=t.k1) self.assertEquals(result, 2) winningBalanceAfter = State().get_balance(u.int_to_addr(t.k1)) losingBalanceAfter = State().get_balance(u.int_to_addr(t.k0)) self.assertEquals(losingBalanceAfter, losingBalanceBefore) self.assertTrue(winningBalanceAfter > losingBalanceBefore)
def test_send_transaction_with_contract(test_app): serpent_code = ''' def main(a,b): return(a ^ b) ''' tx_to = b'' evm_code = serpent.compile(serpent_code) chain = test_app.services.chain.chain chainservice = test_app.services.chain hc_state = State(chainservice.head_candidate.state_root, chain.env) sender = test_app.services.accounts.unlocked_accounts[0].address assert hc_state.get_balance(sender) > 0 eth = test_app.services.console.console_locals['eth'] tx = eth.transact(to='', data=evm_code, startgas=500000, sender=sender) hc_state_dict = State(chainservice.head_candidate.state_root, chain.env).to_dict() code = hc_state_dict[encode_hex(tx.creates)]['code'] assert len(code) > 2 assert code != '0x' test_app.mine_next_block() creates = chain.head.transactions[0].creates code = chain.state.to_dict()[encode_hex(creates)]['code'] assert len(code) > 2 assert code != '0x'
def test_send_transaction_with_contract(test_app): serpent_code = ''' def main(a,b): return(a ^ b) ''' tx_to = b'' evm_code = serpent.compile(serpent_code) chainservice = test_app.services.chain chain = test_app.services.chain.chain state = State(chainservice.head_candidate.state_root, chain.env) sender = test_app.services.accounts.unlocked_accounts[0].address assert state.get_balance(sender) > 0 tx = { 'from': address_encoder(sender), 'to': address_encoder(tx_to), 'data': encode_hex(evm_code) } data_decoder(test_app.client.call('eth_sendTransaction', tx)) assert len(chainservice.head_candidate.transactions) == 1 creates = chainservice.head_candidate.transactions[0].creates candidate_state_dict = State(chainservice.head_candidate.state_root, chain.env).to_dict() code = candidate_state_dict[encode_hex(creates)]['code'] assert len(code) > 2 assert code != '0x' test_app.mine_next_block() assert len(chain.head.transactions) == 1 creates = chain.head.transactions[0].creates state_dict = State(chain.head.state_root, chain.env).to_dict() code = state_dict[encode_hex(creates)]['code'] assert len(code) > 2 assert code != '0x'
def test_genesis_config(): "test setting genesis alloc using the config" alloc = { '1' * 40: { 'wei': 1 }, # wei '2' * 40: { 'balance': 2 }, # balance '3' * 20: { 'balance': 3 }, # 20 bytes } config = dict(eth=dict(genesis=dict(alloc=alloc))) konfig.update_config_with_defaults(config, {'eth': { 'block': default_config }}) # Load genesis config update_config_from_genesis_json(config, config['eth']['genesis']) bc = config['eth']['block'] pprint(bc) env = Env(DB(), bc) genesis = mk_genesis_block(env) state = State(genesis.state_root, env) for address, value_dict in list(alloc.items()): value = list(value_dict.values())[0] assert state.get_balance(address) == value
def post(self): try: App = _eth_worker.App parser = reqparse.RequestParser() parser.add_argument('account', type=str) args = parser.parse_args() # do something this values _accounts = App.services.accounts.accounts account_index = ENUMS[args['account']] account_info = _accounts[account_index] block_head = App.services.chain.chain.head state = State(block_head.state_root, App.services.chain.chain.env) log.info(state.get_balance(account_info.address)) balance_amount = int( state.get_balance(account_info.address) / 10**22) # TODO: account info parsing return { 'status': 200, 'pubkey': account_info.pubkey[0], 'balance_amount': balance_amount } except Exception as e: return {'error': str(e)}
def get_contract_code(init_code): s = State(env=Env(config=casper_config)) s.gas_limit = 10**9 apply_transaction(s, Transaction(0, 0, 10**8, '', 0, init_code)) addr = utils.mk_metropolis_contract_address( casper_config['METROPOLIS_ENTRY_POINT'], init_code) o = s.get_code(addr) assert o return o
def test_console_name_reg_contract(test_app, solidity_code): """ exercise the console service with the NameReg contract found in The_Console wiki https://github.com/ethereum/pyethapp/wiki/The_Console#creating-contracts """ import ethereum.tools._solidity solidity = ethereum.tools._solidity.get_solidity() if solidity is None: pytest.xfail("solidity not installed, not tested") else: # create the NameReg contract tx_to = b'' evm_code = solidity.compile(solidity_code) chainservice = test_app.services.chain chain = test_app.services.chain.chain hc_state = State(chainservice.head_candidate.state_root, chain.env) sender = test_app.services.accounts.unlocked_accounts[0].address assert hc_state.get_balance(sender) > 0 eth = test_app.services.console.console_locals['eth'] tx = eth.transact(to='', data=evm_code, startgas=500000, sender=sender) hc_state_dict = State(chainservice.head_candidate.state_root, chain.env).to_dict() code = hc_state_dict[encode_hex(tx.creates)]['code'] assert len(code) > 2 assert code != '0x' test_app.mine_next_block() creates = chain.head.transactions[0].creates state_dict = chain.state.to_dict() code = state_dict[encode_hex(creates)]['code'] assert len(code) > 2 assert code != '0x' # interact with the NameReg contract abi = solidity.mk_full_signature(solidity_code) namereg = eth.new_contract(abi, creates, sender=sender) register_tx = namereg.register('alice', startgas=90000, gasprice=50 * 10**9) test_app.mine_next_block() result = namereg.resolve(sender) assert result == b'alice' + ('\x00' * 27).encode()
def make_head_candidate(chain, txqueue=None, parent=None, timestamp=None, coinbase='\x35' * 20, extra_data='moo ha ha says the laughing cow.', min_gasprice=0): log.info('Creating head candidate') if parent is None: temp_state = State.from_snapshot( chain.state.to_snapshot(root_only=True), chain.env) else: temp_state = chain.mk_poststate_of_blockhash(parent.hash) cs = get_consensus_strategy(chain.env.config) # Initialize a block with the given parent and variables blk = mk_block_from_prevstate(chain, temp_state, timestamp, coinbase, extra_data) # Find and set the uncles blk.uncles = cs.get_uncles(chain, temp_state) blk.header.uncles_hash = sha3(rlp.encode(blk.uncles)) # Call the initialize state transition function cs.initialize(temp_state, blk) # Add transactions add_transactions(temp_state, blk, txqueue, min_gasprice) # Call the finalize state transition function cs.finalize(temp_state, blk) # Set state root, receipt root, etc set_execution_results(temp_state, blk) log.info('Created head candidate successfully') return blk, temp_state
def test_update_collation_env_variables(): """Test update_collation_env_variables(state, collation) """ collation = Collation(CollationHeader(coinbase=tester.a2)) state = State() state_transition.update_collation_env_variables(state, collation) assert state.block_coinbase == tester.a2
def transact(this, to, value=0, data='', sender=None, startgas=25000, gasprice=60 * denoms.shannon): sender = normalize_address(sender or this.coinbase) to = normalize_address(to, allow_blank=True) state = State(this.head_candidate.state_root, this.chain.env) nonce = state.get_nonce(sender) tx = Transaction(nonce, gasprice, startgas, to, value, data) this.app.services.accounts.sign_tx(sender, tx) assert tx.sender == sender this.chainservice.add_transaction(tx) return tx
def trace(code, calldata=""): log_handlers = [ "eth.vm.op", "eth.vm.op.stack", "eth.vm.op.memory", "eth.vm.op.storage", ] output = StringIO() stream_handler = StreamHandler(output) for handler in log_handlers: log_vm_op = get_logger(handler) log_vm_op.setLevel("TRACE") log_vm_op.addHandler(stream_handler) addr = bytes.fromhex("0123456789ABCDEF0123456789ABCDEF01234567") state = State() ext = messages.VMExt(state, transactions.Transaction(0, 0, 21000, addr, 0, addr)) message = vm.Message(addr, addr, 0, 21000, calldata) vm.vm_execute(ext, message, util.safe_decode(code)) stream_handler.flush() ret = output.getvalue() lines = ret.split("\n") state_trace = [] for line in lines: m = re.search(r"pc=b\'(\d+)\'.*op=([A-Z0-9]+)", line) if m: pc = m.group(1) op = m.group(2) m = re.match(r".*stack=(\[.*?\])", line) if m: stackitems = re.findall(r"b\'(\d+)\'", m.group(1)) stack = "[" if len(stackitems): for i in range(0, len(stackitems) - 1): stack += hex(int(stackitems[i])) + ", " stack += hex(int(stackitems[-1])) stack += "]" else: stack = "[]" if re.match(r"^PUSH.*", op): val = re.search(r"pushvalue=(\d+)", line).group(1) pushvalue = hex(int(val)) state_trace.append({ "pc": pc, "op": op, "stack": stack, "pushvalue": pushvalue }) else: state_trace.append({"pc": pc, "op": op, "stack": stack}) return state_trace
def trace(code, address = "", calldata = ""): logHandlers = ['eth.vm.op', 'eth.vm.op.stack', 'eth.vm.op.memory', 'eth.vm.op.storage'] output = StringIO() streamHandler = StreamHandler(output) for handler in logHandlers: log_vm_op = get_logger(handler) log_vm_op.setLevel("TRACE") log_vm_op.addHandler(streamHandler) addr_from = codecs.decode('0123456789ABCDEF0123456789ABCDEF01234567', 'hex_codec') addr_to = safe_decode(address) state = State() ext = messages.VMExt(state, transactions.Transaction(0, 0, 21000, addr_from, 0, addr_to)) message = vm.Message(addr_from, addr_to, 0, 21000, calldata, code_address=addr_to) res, gas, dat = vm.vm_execute(ext, message, code) streamHandler.flush() # print(output.getvalue()) ret = output.getvalue() return ret
def send_transaction(app, sender_id, receiver_id,value): chain = app.services.chain.chain chainservice = app.services.chain hc_state = State(chainservice.head_candidate.state_root, chain.env) sender = app.services.accounts.unlocked_accounts[sender_id].address receiver = app.services.accounts.unlocked_accounts[receiver_id].address print sender print type(sender) assert hc_state.get_balance(sender) > 0 eth = app.services.console.console_locals['eth'] tx = eth.transact(to=receiver, value=value, startgas=500000, sender=sender) return tx
def create_state_snapshot(chain, block): env = chain.env state = State(block.state_root, env) alloc = dict() count = 0 for addr, account_rlp in state.trie.iter_branch(): alloc[encode_hex(addr)] = create_account_snapshot(env, account_rlp) count += 1 print("[%d] created account snapshot %s" % (count, encode_hex(addr))) return alloc
def test_set_execution_results(): """Test set_execution_results(state, collation) """ collation = Collation(CollationHeader(coinbase=tester.a2)) state = State() state_transition.set_execution_results(state, collation) assert collation.header.receipts_root == mk_receipt_sha(state.receipts) assert collation.header.tx_list_root == mk_transaction_sha( collation.transactions) assert collation.header.post_state_root == state.trie.root_hash
def test_send_transaction_with_contract(test_app, serpent_code, sender_id, receiver_id): evm_code = serpent.compile(serpent_code) chain = test_app.services.chain.chain chainservice = test_app.services.chain hc_state = State(chainservice.head_candidate.state_root, chain.env) sender = test_app.services.accounts.unlocked_accounts[sender_id].address receiver = test_app.services.accounts.unlocked_accounts[ receiver_id].address print sender print type(sender) assert hc_state.get_balance(sender) > 0 eth = test_app.services.console.console_locals['eth'] tx = eth.transact(to=receiver, value=1, data=evm_code, startgas=500000, sender=sender) test_app.mine_next_block() return tx
def test_send_transaction(test_app): chainservice = test_app.services.chain chain = chainservice.chain hc = chainservice.head_candidate state = State(hc.state_root, chain.env) assert state.get_balance(b'\xff' * 20) == 0 sender = test_app.services.accounts.unlocked_accounts[0].address assert state.get_balance(sender) > 0 tx = { 'from': address_encoder(sender), 'to': address_encoder(b'\xff' * 20), 'value': quantity_encoder(1) } tx_hash = data_decoder(test_app.client.call('eth_sendTransaction', tx)) test_app.mine_next_block() assert len(chain.head.transactions) == 1 assert tx_hash == chain.head.transactions[0].hash assert chain.state.get_balance(b'\xff' * 20) == 1 # send transactions from account which can't pay gas tx['from'] = address_encoder( test_app.services.accounts.unlocked_accounts[1].address) tx_hash = data_decoder(test_app.client.call('eth_sendTransaction', tx)) assert chainservice.head_candidate.transactions == []
def mk_poststate_of_blockhash(self, blockhash, convert=False): if blockhash not in self.db: raise Exception("Block hash %s not found" % encode_hex(blockhash)) block_rlp = self.db.get(blockhash) if block_rlp == b'GENESIS': return State.from_snapshot( json.loads(self.db.get(b'GENESIS_STATE')), self.env) block = rlp.decode(block_rlp, Block) state = State(env=self.env) state.trie.root_hash = block.header.state_root if convert else self.db.get( b'state:' + blockhash) update_block_env_variables(state, block) state.gas_used = block.header.gas_used state.txindex = len(block.transactions) state.recent_uncles = {} state.prev_headers = [] b = block header_depth = state.config['PREV_HEADER_DEPTH'] for i in range(header_depth + 1): state.prev_headers.append(b.header) if i < 6: state.recent_uncles[state.block_number - i] = [] for u in b.uncles: state.recent_uncles[state.block_number - i].append(u.hash) try: b = rlp.decode(state.db.get(b.header.prevhash), Block) except: break if i < header_depth: if state.db.get(b.header.prevhash) == b'GENESIS': jsondata = json.loads(state.db.get(b'GENESIS_STATE')) for h in jsondata["prev_headers"][:header_depth - i]: state.prev_headers.append(dict_to_prev_header(h)) for blknum, uncles in jsondata["recent_uncles"].items(): if int(blknum) >= state.block_number - int( state.config['MAX_UNCLE_DEPTH']): state.recent_uncles[blknum] = [ parse_as_bin(u) for u in uncles ] else: raise Exception("Dangling prevhash") assert len(state.journal) == 0, state.journal return state
def mk_poststate_of_collation_hash(self, collation_hash): """Return the post-state of the collation """ if collation_hash not in self.db: raise Exception("Collation hash %s not found" % encode_hex(collation_hash)) collation_rlp = self.db.get(collation_hash) if collation_rlp == 'GENESIS': return State.from_snapshot( json.loads(self.db.get('GENESIS_STATE')), self.env) collation = rlp.decode(collation_rlp, Collation) state = State(env=self.env) state.trie.root_hash = collation.header.post_state_root update_collation_env_variables(state, collation) state.gas_used = 0 state.txindex = len(collation.transactions) state.recent_uncles = {} state.prev_headers = [] assert len(state.journal) == 0, state.journal return state
def test_send_raw_transaction_with_contract(test_app): serpent_code = ''' def main(a,b): return(a ^ b) ''' tx_to = b'' evm_code = serpent.compile(serpent_code) chainservice = test_app.services.chain chain = test_app.services.chain.chain state = State(chainservice.head_candidate.state_root, chain.env) sender = test_app.services.accounts.unlocked_accounts[0].address assert state.get_balance(sender) > 0 nonce = state.get_nonce(sender) tx = ethereum.transactions.Transaction(nonce, default_gasprice, default_startgas, tx_to, 0, evm_code, 0, 0, 0) test_app.services.accounts.sign_tx(sender, tx) raw_transaction = data_encoder( rlp.codec.encode(tx, ethereum.transactions.Transaction)) data_decoder( test_app.client.call('eth_sendRawTransaction', raw_transaction)) assert len(chainservice.head_candidate.transactions) == 1 creates = chainservice.head_candidate.transactions[0].creates candidate_state_dict = State(chainservice.head_candidate.state_root, chain.env).to_dict() code = candidate_state_dict[encode_hex(creates)]['code'] assert len(code) > 2 assert code != '0x' test_app.mine_next_block() assert len(chain.head.transactions) == 1 creates = chain.head.transactions[0].creates state_dict = State(chain.head.state_root, chain.env).to_dict() code = state_dict[encode_hex(creates)]['code'] assert len(code) > 2 assert code != '0x'
def state_from_genesis_declaration(genesis_data, env, block=None, allow_empties=False, executing_on_head=False): if block: assert isinstance(block, Block) else: block = block_from_genesis_declaration(genesis_data, env) state = State(env=env) for addr, data in genesis_data["alloc"].items(): addr = normalize_address(addr) assert len(addr) == 20 if 'wei' in data: state.set_balance(addr, parse_as_int(data['wei'])) if 'balance' in data: state.set_balance(addr, parse_as_int(data['balance'])) if 'code' in data: state.set_code(addr, parse_as_bin(data['code'])) if 'nonce' in data: state.set_nonce(addr, parse_as_int(data['nonce'])) if 'storage' in data: for k, v in data['storage'].items(): state.set_storage_data(addr, big_endian_to_int(parse_as_bin(k)), big_endian_to_int(parse_as_bin(v))) get_consensus_strategy(state.config).initialize(state, block) if executing_on_head: state.executing_on_head = True state.commit(allow_empties=allow_empties) print('deleting %d' % len(state.deletes)) rdb = RefcountDB(state.db) for delete in state.deletes: rdb.delete(delete) block.header.state_root = state.trie.root_hash state.changed = {} state.prev_headers = [block.header] return state
def mk_basic_state(alloc, header=None, env=None, executing_on_head=False): env = env or Env() state = State(env=env, executing_on_head=executing_on_head) if not header: header = { "number": 0, "gas_limit": env.config['BLOCK_GAS_LIMIT'], "gas_used": 0, "timestamp": 1467446877, "difficulty": 1, "uncles_hash": '0x' + encode_hex(BLANK_UNCLES_HASH) } h = BlockHeader(number=parse_as_int(header['number']), timestamp=parse_as_int(header['timestamp']), difficulty=parse_as_int(header['difficulty']), gas_limit=parse_as_int(header['gas_limit']), uncles_hash=parse_as_bin(header['uncles_hash'])) state.prev_headers = [h] for addr, data in alloc.items(): addr = normalize_address(addr) assert len(addr) == 20 if 'wei' in data: state.set_balance(addr, parse_as_int(data['wei'])) if 'balance' in data: state.set_balance(addr, parse_as_int(data['balance'])) if 'code' in data: state.set_code(addr, parse_as_bin(data['code'])) if 'nonce' in data: state.set_nonce(addr, parse_as_int(data['nonce'])) if 'storage' in data: for k, v in data['storage'].items(): state.set_storage_data(addr, parse_as_bin(k), parse_as_bin(v)) state.block_number = header["number"] state.gas_limit = header["gas_limit"] state.timestamp = header["timestamp"] state.block_difficulty = header["difficulty"] state.commit() return state
def __init__(self, genesis=None, env=None, new_head_cb=None, reset_genesis=False, localtime=None, max_history=1000, **kwargs): self.env = env or Env() # Initialize the state if b'head_hash' in self.db: # new head tag self.state = self.mk_poststate_of_blockhash( self.db.get('head_hash')) self.state.executing_on_head = True print('Initializing chain from saved head, #%d (%s)' % (self.state.prev_headers[0].number, encode_hex(self.state.prev_headers[0].hash))) elif genesis is None: raise Exception("Need genesis decl!") elif isinstance(genesis, State): assert env is None self.state = genesis self.env = self.state.env print('Initializing chain from provided state') reset_genesis = True elif "extraData" in genesis: self.state = state_from_genesis_declaration(genesis, self.env, executing_on_head=True) reset_genesis = True print('Initializing chain from provided genesis declaration') elif "prev_headers" in genesis: self.state = State.from_snapshot(genesis, self.env, executing_on_head=True) reset_genesis = True print('Initializing chain from provided state snapshot, %d (%s)' % (self.state.block_number, encode_hex(self.state.prev_headers[0].hash[:8]))) elif isinstance(genesis, dict): print('Initializing chain from new state based on alloc') self.state = mk_basic_state( genesis, { "number": kwargs.get('number', 0), "gas_limit": kwargs.get('gas_limit', self.env.config['BLOCK_GAS_LIMIT']), "gas_used": kwargs.get('gas_used', 0), "timestamp": kwargs.get('timestamp', 1467446877), "difficulty": kwargs.get('difficulty', 2**25), "hash": kwargs.get('prevhash', '00' * 32), "uncles_hash": kwargs.get('uncles_hash', '0x' + encode_hex(BLANK_UNCLES_HASH)) }, self.env) reset_genesis = True assert self.env.db == self.state.db initialize(self.state) self.new_head_cb = new_head_cb if self.state.block_number == 0: assert self.state.block_number == self.state.prev_headers[0].number else: assert self.state.block_number - 1 == self.state.prev_headers[ 0].number if reset_genesis: if isinstance(self.state.prev_headers[0], FakeHeader): header = self.state.prev_headers[0].to_block_header() else: header = self.state.prev_headers[0] self.genesis = Block(header) self.state.prev_headers[0] = header initialize_genesis_keys(self.state, self.genesis) else: self.genesis = self.get_block_by_number(0) self.head_hash = self.state.prev_headers[0].hash self.time_queue = [] self.parent_queue = {} self.localtime = time.time() if localtime is None else localtime self.max_history = max_history
def __init__(self, genesis=None, env=None, coinbase=b'\x00' * 20, new_head_cb=None, reset_genesis=False, localtime=None, **kwargs): self.env = env or Env() # Initialize the state if b'head_hash' in self.db: # new head tag self.state = self.mk_poststate_of_blockhash( self.db.get(b'head_hash')) print('Initializing chain from saved head, #%d (%s)' % (self.state.prev_headers[0].number, encode_hex(self.state.prev_headers[0].hash))) elif genesis is None: raise Exception("Need genesis decl!") elif isinstance(genesis, State): assert env is None self.state = genesis self.env = self.state.env print('Initializing chain from provided state') elif "extraData" in genesis: self.state = state_from_genesis_declaration(genesis, self.env) reset_genesis = True print('Initializing chain from provided genesis declaration') elif "prev_headers" in genesis: self.state = State.from_snapshot(genesis, self.env) reset_genesis = True print('Initializing chain from provided state snapshot, %d (%s)' % (self.state.block_number, encode_hex(self.state.prev_headers[0].hash[:8]))) else: print('Initializing chain from new state based on alloc') self.state = mk_basic_state( genesis, { "number": kwargs.get('number', 0), "gas_limit": kwargs.get('gas_limit', 4712388), "gas_used": kwargs.get('gas_used', 0), "timestamp": kwargs.get('timestamp', 1467446877), "difficulty": kwargs.get('difficulty', 2**25), "hash": kwargs.get('prevhash', '00' * 32), "uncles_hash": kwargs.get('uncles_hash', '0x' + encode_hex(BLANK_UNCLES_HASH)) }, self.env) reset_genesis = True assert self.env.db == self.state.db initialize(self.state) self.new_head_cb = new_head_cb self.head_hash = self.state.prev_headers[0].hash self.checkpoint_head_hash = b'\x00' * 32 self.db.put(b'cp_subtree_score' + b'\x00' * 32, 2 / 3.) self.commit_logs = [] self.casper_address = self.config['CASPER_ADDRESS'] self.db.put(b'GENESIS_NUMBER', to_string(self.state.block_number)) assert self.state.block_number == self.state.prev_headers[0].number if reset_genesis: self.genesis = Block(self.state.prev_headers[0], [], []) initialize_genesis_keys(self.state, self.genesis) else: self.genesis = self.get_block_by_number(0) self.db.put(b'cp_subtree_score' + self.genesis.hash, 2 / 3.) self.min_gasprice = kwargs.get('min_gasprice', 5 * 10**9) self.coinbase = coinbase self.extra_data = 'moo ha ha says the laughing cow.' self.time_queue = [] self.parent_queue = {} self.localtime = time.time() if localtime is None else localtime
def trace(code, calldata=""): logHandlers = [ 'eth.vm.op', 'eth.vm.op.stack', 'eth.vm.op.memory', 'eth.vm.op.storage' ] output = StringIO() streamHandler = StreamHandler(output) for handler in logHandlers: log_vm_op = get_logger(handler) log_vm_op.setLevel("TRACE") log_vm_op.addHandler(streamHandler) addr = bytes.fromhex('0123456789ABCDEF0123456789ABCDEF01234567') state = State() ext = messages.VMExt(state, transactions.Transaction(0, 0, 21000, addr, 0, addr)) message = vm.Message(addr, addr, 0, 21000, calldata) res, gas, dat = vm.vm_execute(ext, message, util.safe_decode(code)) streamHandler.flush() ret = output.getvalue() lines = ret.split("\n") trace = [] for line in lines: m = re.search(r'pc=b\'(\d+)\'.*op=([A-Z0-9]+)', line) if m: pc = m.group(1) op = m.group(2) m = re.match(r'.*stack=(\[.*?\])', line) if (m): stackitems = re.findall(r'b\'(\d+)\'', m.group(1)) stack = "[" if (len(stackitems)): for i in range(0, len(stackitems) - 1): stack += hex(int(stackitems[i])) + ", " stack += hex(int(stackitems[-1])) stack += "]" else: stack = "[]" if (re.match(r'^PUSH.*', op)): val = re.search(r'pushvalue=(\d+)', line).group(1) pushvalue = hex(int(val)) trace.append({ 'pc': pc, 'op': op, 'stack': stack, 'pushvalue': pushvalue }) else: trace.append({'pc': pc, 'op': op, 'stack': stack}) return trace
class ShardChain(object): def __init__(self, shard_id, env=None, new_head_cb=None, reset_genesis=False, localtime=None, max_history=1000, initial_state=None, main_chain=None, **kwargs): self.env = env or Env() self.shard_id = shard_id self.collation_blockhash_lists = defaultdict( list) # M1: collation_header_hash -> list[blockhash] self.head_collation_of_block = {} # M2: blockhash -> head_collation self.main_chain = main_chain # Initialize the state head_hash_key = 'shard_' + str(shard_id) + '_head_hash' if head_hash_key in self.db: # new head tag self.state = self.mk_poststate_of_collation_hash( self.db.get(head_hash_key)) log.info('Initializing shard chain from saved head, #%d (%s)' % (self.state.prev_headers[0].number, encode_hex(self.state.prev_headers[0].hash))) self.head_hash = self.state.prev_headers[0].hash else: # no head_hash in db -> empty shard chain if initial_state is not None and isinstance(initial_state, State): # Normally, initial_state is for testing assert env is None self.state = initial_state self.env = self.state.env log.info('Initializing chain from provided state') else: self.state = State(env=self.env) self.last_state = self.state.to_snapshot() self.head_hash = self.env.config['GENESIS_PREVHASH'] self.db.put(self.head_hash, 'GENESIS') self.db.put(head_hash_key, self.head_hash) # initial score key = b'score:' + self.head_hash self.db.put(key, str(0)) self.db.commit() reset_genesis = True assert self.env.db == self.state.db initialize(self.state) self.new_head_cb = new_head_cb if reset_genesis: initialize_genesis_keys(self.state, Collation(CollationHeader())) self.time_queue = [] self.parent_queue = {} self.localtime = time.time() if localtime is None else localtime self.max_history = max_history @property def db(self): return self.env.db # TODO: use head_collation_of_block to update head collation @property def head(self): """head collation """ try: collation_rlp = self.db.get(self.head_hash) # [TODO] no genesis collation if collation_rlp == 'GENESIS': return Collation(CollationHeader()) # return self.genesis else: return rlp.decode(collation_rlp, Collation) return rlp.decode(collation_rlp, Collation) except Exception as e: log.info(str(e)) return None def add_collation(self, collation, period_start_prevblock, handle_ignored_collation): """Add collation to db and update score """ if collation.header.parent_collation_hash in self.env.db: log.info('Receiving collation(%s) which its parent is in db: %s' % (encode_hex(collation.header.hash), encode_hex(collation.header.parent_collation_hash))) if self.is_first_collation(collation): log.debug('It is the first collation of shard {}'.format( self.shard_id)) temp_state = self.mk_poststate_of_collation_hash( collation.header.parent_collation_hash) try: apply_collation( temp_state, collation, period_start_prevblock, None if self.main_chain is None else self.main_chain.state, self.shard_id) except (AssertionError, KeyError, ValueError, InvalidTransaction, VerificationFailed) as e: log.info('Collation %s with parent %s invalid, reason: %s' % (encode_hex(collation.header.hash), encode_hex( collation.header.parent_collation_hash), str(e))) return False deletes = temp_state.deletes changed = temp_state.changed collation_score = self.get_score(collation) log.info('collation_score of {} is {}'.format( encode_hex(collation.header.hash), collation_score)) # Collation has no parent yet else: changed = [] deletes = [] log.info( 'Receiving collation(%s) which its parent is NOT in db: %s' % (encode_hex(collation.header.hash), encode_hex(collation.header.parent_collation_hash))) if collation.header.parent_collation_hash not in self.parent_queue: self.parent_queue[collation.header.parent_collation_hash] = [] self.parent_queue[collation.header.parent_collation_hash].append( collation) log.info('No parent found. Delaying for now') return False self.db.put(collation.header.hash, rlp.encode(collation)) self.db.put(b'changed:' + collation.hash, b''.join(list(changed.keys()))) # log.debug('Saved %d address change logs' % len(changed.keys())) self.db.put(b'deletes:' + collation.hash, b''.join(deletes)) # log.debug('Saved %d trie node deletes for collation (%s)' % (len(deletes), encode_hex(collation.hash))) # TODO: Delete old junk data # deletes, changed self.db.commit() log.info('Added collation (%s) with %d txs' % (encode_hex( collation.header.hash)[:8], len(collation.transactions))) # Call optional callback if self.new_head_cb and self.is_first_collation(collation): self.new_head_cb(collation) # TODO: It seems weird to use callback function to access member of MainChain try: handle_ignored_collation(collation) except Exception as e: log.info('handle_ignored_collation exception: {}'.format(str(e))) return False return True def mk_poststate_of_collation_hash(self, collation_hash): """Return the post-state of the collation """ if collation_hash not in self.db: raise Exception("Collation hash %s not found" % encode_hex(collation_hash)) collation_rlp = self.db.get(collation_hash) if collation_rlp == 'GENESIS': return State.from_snapshot( json.loads(self.db.get('GENESIS_STATE')), self.env) collation = rlp.decode(collation_rlp, Collation) state = State(env=self.env) state.trie.root_hash = collation.header.post_state_root update_collation_env_variables(state, collation) state.gas_used = 0 state.txindex = len(collation.transactions) state.recent_uncles = {} state.prev_headers = [] assert len(state.journal) == 0, state.journal return state def get_parent(self, collation): """Get the parent collation of a given collation """ if self.is_first_collation(collation): return None return self.get_collation(collation.header.parent_collation_hash) def get_collation(self, collation_hash): """Get the collation with a given collation hash """ try: collation_rlp = self.db.get(collation_hash) if collation_rlp == 'GENESIS': return Collation(CollationHeader()) # if not hasattr(self, 'genesis'): # self.genesis = rlp.decode(self.db.get('GENESIS_RLP'), sedes=Block) # return self.genesis else: return rlp.decode(collation_rlp, Collation) except Exception as e: log.debug("Failed to get collation", hash=encode_hex(collation_hash), error=str(e)) return None def get_score(self, collation): """Get the score of a given collation """ score = 0 if not collation: return 0 key = b'score:' + collation.header.hash fills = [] while key not in self.db and collation is not None: fills.insert(0, collation.header.hash) key = b'score:' + collation.header.parent_collation_hash collation = self.get_parent(collation) score = int(self.db.get(key)) log.debug('int(self.db.get(key)):{}'.format(int(self.db.get(key)))) for h in fills: key = b'score:' + h score += 1 self.db.put(key, str(score)) return score def get_head_coll_score(self, blockhash): if blockhash in self.head_collation_of_block: prev_head_coll_hash = self.head_collation_of_block[blockhash] prev_head_coll = self.get_collation(prev_head_coll_hash) prev_head_coll_score = self.get_score(prev_head_coll) else: prev_head_coll_score = 0 return prev_head_coll_score def is_first_collation(self, collation): """Check if the given collation is the first collation of this shard """ return collation.header.parent_collation_hash == self.env.config[ 'GENESIS_PREVHASH']
def __init__(self, shard_id, env=None, new_head_cb=None, reset_genesis=False, localtime=None, max_history=1000, initial_state=None, main_chain=None, **kwargs): self.env = env or Env() self.shard_id = shard_id self.collation_blockhash_lists = defaultdict( list) # M1: collation_header_hash -> list[blockhash] self.head_collation_of_block = {} # M2: blockhash -> head_collation self.main_chain = main_chain # Initialize the state head_hash_key = 'shard_' + str(shard_id) + '_head_hash' if head_hash_key in self.db: # new head tag self.state = self.mk_poststate_of_collation_hash( self.db.get(head_hash_key)) log.info('Initializing shard chain from saved head, #%d (%s)' % (self.state.prev_headers[0].number, encode_hex(self.state.prev_headers[0].hash))) self.head_hash = self.state.prev_headers[0].hash else: # no head_hash in db -> empty shard chain if initial_state is not None and isinstance(initial_state, State): # Normally, initial_state is for testing assert env is None self.state = initial_state self.env = self.state.env log.info('Initializing chain from provided state') else: self.state = State(env=self.env) self.last_state = self.state.to_snapshot() self.head_hash = self.env.config['GENESIS_PREVHASH'] self.db.put(self.head_hash, 'GENESIS') self.db.put(head_hash_key, self.head_hash) # initial score key = b'score:' + self.head_hash self.db.put(key, str(0)) self.db.commit() reset_genesis = True assert self.env.db == self.state.db initialize(self.state) self.new_head_cb = new_head_cb if reset_genesis: initialize_genesis_keys(self.state, Collation(CollationHeader())) self.time_queue = [] self.parent_queue = {} self.localtime = time.time() if localtime is None else localtime self.max_history = max_history
def test_console_name_reg_contract(test_app): solidity_code = """ contract NameReg { event AddressRegistered(bytes32 indexed name, address indexed account); mapping (address => bytes32) toName; function register(bytes32 name) { toName[msg.sender] = name; AddressRegistered(name, msg.sender); } function resolve(address addr) constant returns (bytes32 name) { return toName[addr]; } } """ import ethereum.tools._solidity solidity = ethereum.tools._solidity.get_solidity() if solidity is None: pytest.xfail("solidity not installed, not tested") else: # create the NameReg contract tx_to = b'' evm_code = solidity.compile(solidity_code) chainservice = test_app.services.chain chain = test_app.services.chain.chain hc_state = State(chainservice.head_candidate.state_root, chain.env) sender = test_app.services.accounts.unlocked_accounts[0].address assert hc_state.get_balance(sender) > 0 eth = test_app.services.console.console_locals['eth'] tx = eth.transact(to='', data=evm_code, startgas=500000, sender=sender) hc_state_dict = State(chainservice.head_candidate.state_root, chain.env).to_dict() code = hc_state_dict[encode_hex(tx.creates)]['code'] assert len(code) > 2 assert code != '0x' test_app.mine_next_block() creates = chain.head.transactions[0].creates state_dict = chain.state.to_dict() code = state_dict[encode_hex(creates)]['code'] assert len(code) > 2 assert code != '0x' # interact with the NameReg contract abi = solidity.mk_full_signature(solidity_code) namereg = eth.new_contract(abi, creates, sender=sender) register_tx = namereg.register('alice', startgas=90000, gasprice=50 * 10**9) test_app.mine_next_block() result = namereg.resolve(sender) assert result == b'alice' + ('\x00' * 27).encode()
# Check latest block block_head = test.services.chain.chain.head log.info(block_head.header) value = test.config['node']['id'].encode('hex') # read_blocks = read_blocks_thread(test) # time.sleep(2) # test_receive_newblock(test) # # Make contract code serpent_code = ''' def main(a,b): return(a ^ b) ''' state = State(block_head.state_root, test.services.chain.chain.env) log.info('Andy accounts\' coin amount: ' + str(state.get_balance(accounts_list[Andy].address))) # Make transaction with contract, sender of transaction is 'Andy', receiver is 'Choi' tx = test_send_transaction_with_contract(test, serpent_code, sender_id=Andy, receiver_id=Choi) log.info(tx.__dict__) log.info(tx.sender.encode('hex')) # Check latest block, Not mining yet block_head = test.services.chain.chain.head state = State(block_head.state_root, test.services.chain.chain.env) log.info('Andy accounts\' coin amount: ' + str(state.get_balance(accounts_list[Andy].address)))
def init_state(env, pre): # Setup env state = State( env=Env(config=konfig), block_prevhash=decode_hex(remove_0x_head(env['previousHash'])), prev_headers=[mk_fake_header(i) for i in range(parse_int_or_hex(env['currentNumber']) - 1, max(-1, parse_int_or_hex(env['currentNumber']) - 257), -1)], block_number=parse_int_or_hex(env['currentNumber']), block_coinbase=decode_hex(remove_0x_head(env['currentCoinbase'])), block_difficulty=parse_int_or_hex(env['currentDifficulty']), gas_limit=parse_int_or_hex(env['currentGasLimit']), timestamp=parse_int_or_hex(env['currentTimestamp'])) # Fill up pre for address, h in list(pre.items()): assert len(address) in (40, 42) address = decode_hex(remove_0x_head(address)) assert set(h.keys()) == set(['code', 'nonce', 'balance', 'storage']) state.set_nonce(address, parse_int_or_hex(h['nonce'])) state.set_balance(address, parse_int_or_hex(h['balance'])) state.set_code(address, decode_hex(remove_0x_head(h['code']))) for k, v in h['storage'].items(): state.set_storage_data(address, big_endian_to_int(decode_hex(k[2:])), big_endian_to_int(decode_hex(v[2:]))) state.commit(allow_empties=True) # state.commit() return state