def test_execution_of_call_with_single_bytes32(deploy_client, deployed_contracts, deploy_coinbase, deploy_future_block_call): client_contract = deployed_contracts.TestCallExecution call = deploy_future_block_call(client_contract.setBytes32) value = '\x00\x01\x02\x03\x04\x05\x06\x07\x08\t\n\x0b\x0c\r\x0e\x0f\x10\x11\x12\x13\x14\x15\x16\x17\x18\x19\x1a\x1b\x1c\x1d\x1e\x1f' signature = call.registerData.encoded_abi_signature data = abi.encode_single(abi.process_type('bytes32'), value) txn_data = ''.join((utils.encode_hex(signature), utils.encode_hex(data))) data_txn_hash = deploy_client.send_transaction( to=call._meta.address, data=txn_data, ) data_txn_receipt = deploy_client.wait_for_transaction(data_txn_hash) assert client_contract.v_bytes32() is None call_txn_hash = call.execute() deploy_client.wait_for_transaction(call_txn_hash) assert client_contract.v_bytes32() == value
def test_enumerate_upcoming_tree_positions(deploy_client, deployed_contracts): alarm = deployed_contracts.Alarm client_contract = deployed_contracts.SpecifyBlock anchor_block = deploy_client.get_block_number() blocks = (1, 4, 4, 8, 15, 25, 25, 25, 30, 40, 50, 60) call_keys = [] for n in blocks: txn_hash = client_contract.scheduleIt.sendTransaction(alarm._meta.address, anchor_block + 100 + n) wait_for_transaction(deploy_client, txn_hash) last_call_key = alarm.getLastCallKey() assert last_call_key is not None call_keys.append(last_call_key) expected_calls = tuple(utils.encode_hex(c) for c in call_keys[1:10]) actual_calls = tuple( utils.encode_hex(c) for c in enumerate_upcoming_calls(alarm, anchor_block + 100 + 4) ) assert actual_calls == expected_calls
def create_node_configuration(miner=True, port=30301, rpcport=8101, host='127.0.0.1', node_key_seed=0): """ Create configuration (ports, keys, etc...) for one node. :param miner: if True, setup to be a mining node :param port: the p2p port to assign :param rpcport: the port to assign :param host: the host for the node to run on :return: node configuration dict """ node = dict() if miner: node['minerthreads'] = 1 # conservative node['unlock'] = 0 node['nodekey'] = sha3('node:{}'.format(node_key_seed).encode()) node['nodekeyhex'] = encode_hex(node['nodekey']) node['pub'] = encode_hex(privtopub_enode(node['nodekey'])) node['address'] = privatekey_to_address(node['nodekey']) node['host'] = host node['port'] = port node['rpcport'] = rpcport node['enode'] = 'enode://{pub}@{host}:{port}'.format(**node) return node
def test_cancellable_after_call_window_if_missed(deploy_client, deployed_contracts, deploy_future_block_call, deploy_coinbase, denoms): client_contract = deployed_contracts.TestCallExecution call = deploy_future_block_call( scheduler_address=deploy_coinbase, target_block=deploy_client.get_block_number() + 400, ) assert call.state() == State.Pending deploy_client.wait_for_block(call.targetBlock() + call.gracePeriod()) assert call.state() == State.Missed assert call.isCancellable() is True # true for non-scheduler account assert call.isCancellable(_from=utils.encode_hex(accounts[1])) is True cancel_txn_hash = call.cancel() cancel_txn_receipt = deploy_client.wait_for_transaction(cancel_txn_hash) assert call.isCancellable() is False assert call.isCancellable(_from=utils.encode_hex(accounts[1])) is False
def test_execution_of_call_with_many_values(deploy_client, deployed_contracts, deploy_coinbase, deploy_future_block_call, CallLib): client_contract = deployed_contracts.TestCallExecution call = deploy_future_block_call(client_contract.setMany) values = ( 1234567890, -1234567890, 987654321, '\x00\x01\x02\x03\x04\x05\x06\x07\x08\t\n\x0b\x0c\r\x0e\x0f\x10\x11\x12\x13', 'd3cda913deb6f67967b99d67acdfa1712c293601', 'abcdefg', ) types = ( 'uint256', 'int256', 'uint256', 'bytes20', 'address', 'bytes', ) signature = call.registerData.encoded_abi_signature data = ''.join(( abi.encode_single(abi.process_type(t), v) for t, v in zip(types, values) )) txn_data = ''.join((utils.encode_hex(signature), utils.encode_hex(data))) data_txn_hash = deploy_client.send_transaction( to=call._meta.address, data=txn_data, ) data_txn_receipt = deploy_client.wait_for_transaction(data_txn_hash) assert client_contract.vm_a() == 0 assert client_contract.vm_b() == 0 assert client_contract.vm_c() == 0 assert client_contract.vm_d() == None assert client_contract.vm_e() == '0x0000000000000000000000000000000000000000' assert client_contract.vm_f() == '' call_txn_hash = call.execute() txn_r = deploy_client.wait_for_transaction(call_txn_hash) call_logs = CallLib.CallExecuted.get_transaction_logs(call_txn_hash) call_data = [CallLib.CallExecuted.get_log_data(l) for l in call_logs] assert client_contract.vm_a() == values[0] assert client_contract.vm_b() == values[1] assert client_contract.vm_c() == values[2] assert client_contract.vm_d() == values[3] assert client_contract.vm_e() == '0xd3cda913deb6f67967b99d67acdfa1712c293601' assert client_contract.vm_f() == values[5]
def generate_accounts(seeds): """Create private keys and addresses for all seeds. """ return { seed: dict( privatekey=encode_hex(sha3(seed)), address=encode_hex(privatekey_to_address(sha3(seed))) ) for seed in seeds}
def getWork(self): print 'Sending work...' h = self.chain.chain.head_candidate return [ encode_hex(h.header.mining_hash), encode_hex(h.header.seed), encode_hex(zpad(int_to_big_endian(2**256 // h.header.difficulty), 32)) ]
def __str__(self): return '<HashTimeLocked id={} amount={} token={} target={} expire={} hashlock={}>'.format( self.identifier, self.amount, encode_hex(self.token), encode_hex(self.target), self.expiration, encode_hex(self.hashlock), )
def to_dict(self): d = {} for name, _ in self.__class__.fields: d[name] = getattr(self, name) if name in ('to', 'data'): d[name] = '0x' + encode_hex(d[name]) d['sender'] = '0x' + encode_hex(self.sender) d['hash'] = '0x' + encode_hex(self.hash) return d
def get_proof(lst, proof_for, root=None): proof = [proof_for] root_hash = merkleroot(lst, proof) if root and root != root_hash: raise ValueError('root hashes did not match {} {}'.format( encode_hex(root_hash), encode_hex(root) )) return proof
def test(): # Test the arbiter mechanism t.gas_price = 0 t.gas_limit = 100000000 s = t.state() c = s.abi_contract('arbitration.se') o = [] s.block.log_listeners.append(lambda x: o.append(c._translator.listen(x))) x = c.mk_contract(t.a1, t.a2, [t.a3, t.a4, t.a5], 1000, "horse" * 10, value=100000) assert c.get_contract_value(x) == 99000 assert c.get_contract_recipients(x) == [t.a1.encode('hex'), t.a2.encode('hex')] assert c.get_contract_arbiters(x) == [utils.encode_hex(a) for a in [t.a3, t.a4, t.a5]] assert c.get_contract_arbiterFee(x) == 1000 assert c.get_contract_description(x) == "horse" * 10 assert o[-1]["value"] == 99000 assert o[-1]["arbiters"] == [utils.encode_hex(a) for a in [t.a3, t.a4, t.a5]] assert not c.vote(x, True, sender=t.k6) assert c.vote(x, False, sender=t.k5) assert not c.vote(x, True, sender=t.k5) prebals = [s.block.get_balance(y) for y in (t.a1, t.a2, t.a3, t.a4, t.a5, t.a6)] assert c.vote(x, False, sender=t.k4) assert o[-1]["_event_type"] == "PaidOut" assert o[-1]["recipient"] == utils.encode_hex(t.a2), (o[-1]["recipient"], utils.encode_hex(t.a1), utils.encode_hex(t.a2)) postbals = [s.block.get_balance(x) for x in (t.a1, t.a2, t.a3, t.a4, t.a5, t.a6)] diffs = [b - a for a, b in zip(prebals, postbals)] assert diffs == [0, 99000, 0, 500, 500, 0] # Test the arbiter registry c = s.abi_contract('arbiter_reg.se') assert not c.register(sender=t.k1, value=10**14) assert c.register(sender=t.k1, value=10**16) assert c.register(sender=t.k2, value=10**17) assert c.get_addresses(0) == [t.a1.encode('hex'), t.a2.encode('hex')] assert c.get_addresses(1) == [t.a2.encode('hex')] assert c.get_addresses(50) == [] assert c.get_tot_fee(t.a1) == 10**16, c.get_tot_fee(t.a1) assert c.get_tot_fee(t.a2) == 10**17 s.mine(100) f1 = c.get_tot_fee(t.a1) f2 = c.get_tot_fee(t.a2) assert f1 < 10**16 and f2 < 10**17 assert -1 <= f1 - f2 / 10 <= 1 # Accomodate a very small difference assert c.register(sender=t.k1, value=10**16) assert c.register(sender=t.k2, value=10**15) assert c.register(sender=t.k2, value=10**16) assert c.register(sender=t.k2, value=10**17 - 10**16 - 10**15) new_f1 = c.get_tot_fee(t.a1) new_f2 = c.get_tot_fee(t.a2) assert new_f1 - f1 == 10**16 assert new_f2 - f2 == 10**17 assert not c.set_description("The quick brown fox jumps over t", sender=t.k3) assert c.set_description("The quick brown fox jumps over t", sender=t.k1) assert c.get_description(t.a1) == "The quick brown fox jumps over t", c.get_description(t.a1) assert c.set_description("The quick brown fox jumps over the yellow doge", sender=t.k1) assert c.get_description(t.a1) == "The quick brown fox jumps over the yellow doge"
def get_proof(lst, proof_for, root=None): tree = Merkletree(lst) root_hash = tree.merkleroot if root and root != root_hash: raise ValueError('root hashes did not match {} {}'.format( encode_hex(root_hash), encode_hex(root) )) return tree.make_proof(proof_for)
def test_interop(): if 'solidity' not in tester.languages: return s = tester.state() c1 = s.abi_contract(serpent_contract) c2 = s.abi_contract(solidity_contract, language='solidity') # should be zoo assert c1.sub1() == 5 assert c2.sub2() == 7 assert c2.sub3(utils.encode_hex(c2.address)) == utils.encode_hex(c2.address) assert c1.main(c2.address) == 14 assert c2.main(c1.address) == 10
def warn_invalid(block, errortype='other'): try: make_request('http://badblocks.ethereum.org', { "block": utils.encode_hex(rlp.encode(block)), "errortype": errortype, "hints": { "receipts": [utils.encode_hex(rlp.encode(x)) for x in block.get_receipts()], "vmtrace": "NOT YET IMPLEMENTED" } }) except: sys.stderr.write('Failed to connect to badblocks.ethdev.com\n')
def test_currency_apis(): s = tester.state() c1 = s.abi_contract(serpent_currency, sender=tester.k0) c2 = s.abi_contract(solidity_currency, language='solidity', sender=tester.k0) o = [] s.block.log_listeners.append(lambda x: o.append(c._translator.listen(x))) for c in (c1, c2): o = [] assert c.coinBalanceOf(tester.a0) == 1000000 assert c.sendCoin(1000, tester.a2, sender=tester.k0) is True assert c.sendCoin(999001, tester.a2, sender=tester.k0) is False assert c.sendCoinFrom(tester.a2, 500, tester.a3, sender=tester.k0) is False c.approveOnce(tester.a0, 500, sender=tester.k2) assert c.sendCoinFrom(tester.a2, 400, tester.a3, sender=tester.k0) is True assert c.sendCoinFrom(tester.a2, 400, tester.a3, sender=tester.k0) is False assert c.sendCoinFrom(tester.a2, 100, tester.a3, sender=tester.k0) is True assert c.sendCoinFrom(tester.a2, 100, tester.a3, sender=tester.k0) is False c.approve(tester.a0, sender=tester.k2) assert c.sendCoinFrom(tester.a2, 100, tester.a3, sender=tester.k0) is True c.disapprove(tester.a0, sender=tester.k2) assert c.sendCoinFrom(tester.a2, 100, tester.a3, sender=tester.k0) is False assert c.coinBalance(sender=tester.k0) == 999000 assert c.coinBalanceOf(tester.a2) == 400 assert c.coinBalanceOf(tester.a3) == 600 assert o == [{"_event_type": b"CoinSent", "from": utils.encode_hex(tester.a0), "value": 1000, "to": utils.encode_hex(tester.a2)}, {"_event_type": b"CoinSent", "from": utils.encode_hex(tester.a2), "value": 400, "to": utils.encode_hex(tester.a3)}, {"_event_type": b"CoinSent", "from": utils.encode_hex(tester.a2), "value": 100, "to": utils.encode_hex(tester.a3)}, {"_event_type": b"CoinSent", "from": utils.encode_hex(tester.a2), "value": 100, "to": utils.encode_hex(tester.a3)}]
def to_dict(self): """Serialize the header to a readable dictionary.""" d = {} for field in ('prevhash', 'uncles_hash', 'extra_data', 'nonce', 'mixhash'): d[field] = '0x' + encode_hex(getattr(self, field)) for field in ('state_root', 'tx_list_root', 'receipts_root', 'coinbase'): d[field] = encode_hex(getattr(self, field)) for field in ('number', 'difficulty', 'gas_limit', 'gas_used', 'timestamp'): d[field] = utils.to_string(getattr(self, field)) d['bloom'] = encode_hex(int256.serialize(self.bloom)) assert len(d) == len(BlockHeader.fields) return d
def test_registration_of_many_values_via_fallback(deploy_client, deployed_contracts, deploy_coinbase, deploy_future_block_call): client_contract = deployed_contracts.TestCallExecution call = deploy_future_block_call( client_contract.setMany, target_block=deploy_client.get_block_number() + 40, ) values = ( 1234567890, -1234567890, 987654321, '\x00\x01\x02\x03\x04\x05\x06\x07\x08\t\n\x0b\x0c\r\x0e\x0f\x10\x11\x12\x13', '0xd3cda913deb6f67967b99d67acdfa1712c293601', 'abcdef', ) call_data = utils.encode_hex(client_contract.setMany.abi_args_signature(values)) deploy_client.send_transaction( to=call._meta.address, data=call_data, ) expected = '\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00I\x96\x02\xd2\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xb6i\xfd.\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00:\xdeh\xb1\x00\x01\x02\x03\x04\x05\x06\x07\x08\t\n\x0b\x0c\r\x0e\x0f\x10\x11\x12\x13\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xd3\xcd\xa9\x13\xde\xb6\xf6yg\xb9\x9dg\xac\xdf\xa1q,)6\x01\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xc0\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x06abcdef\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00' actual = call.callData() assert expected == actual
def patch_send_transaction(client, nonce_offset=0): """Check if the remote supports pyethapp's extended jsonrpc spec for local tx signing. If not, replace the `send_transaction` method with a more generic one. """ patch_necessary = False try: client.call('eth_nonce', encode_hex(client.sender), 'pending') except: patch_necessary = True def send_transaction(sender, to, value=0, data='', startgas=GAS_LIMIT, gasprice=GAS_PRICE, nonce=None): """Custom implementation for `pyethapp.rpc_client.JSONRPCClient.send_transaction`. This is necessary to support other remotes that don't support pyethapp's extended specs. @see https://github.com/ethereum/pyethapp/blob/develop/pyethapp/rpc_client.py#L359 """ pending_transactions_hex = client.call( 'eth_getTransactionCount', encode_hex(sender), 'pending', ) pending_transactions = int(pending_transactions_hex, 16) nonce = pending_transactions + nonce_offset tx = Transaction(nonce, gasprice, startgas, to, value, data) assert hasattr(client, 'privkey') and client.privkey tx.sign(client.privkey) result = client.call('eth_sendRawTransaction', rlp.encode(tx).encode('hex')) return result[2 if result.startswith('0x') else 0:] if patch_necessary: client.send_transaction = send_transaction
def unlock(self, our_address, unlock_proofs): # force a list to get the length (could be a generator) unlock_proofs = list(unlock_proofs) log.info( '%s locks to unlock', len(unlock_proofs), contract=pex(self.address), ) for merkle_proof, locked_encoded, secret in unlock_proofs: if isinstance(locked_encoded, messages.Lock): raise ValueError('unlock must be called with a lock encoded `.as_bytes`') merkleproof_encoded = ''.join(merkle_proof) transaction_hash = self.proxy.unlock.transact( locked_encoded, merkleproof_encoded, secret, startgas=self.startgas, gasprice=self.gasprice, ) self.client.poll(transaction_hash.decode('hex'), timeout=self.poll_timeout) # TODO: check if the ChannelSecretRevealed event was emitted and if # it wasn't raise an error # if log.getEffectiveLevel() >= logging.INFO: # only decode the lock if need to lock = messages.Lock.from_bytes(locked_encoded) log.info( 'unlock called', contract=pex(self.address), lock=lock, secret=encode_hex(secret), )
def unlock(self, our_address, unlock_proofs): # force a list to get the length (could be a generator) unlock_proofs = list(unlock_proofs) log.info('{} locks to unlock'.format(len(unlock_proofs)), contract=pex(self.address)) for merkle_proof, locked_encoded, secret in unlock_proofs: if isinstance(locked_encoded, messages.Lock): raise ValueError('unlock must be called with a lock encoded `.as_bytes`') merkleproof_encoded = ''.join(merkle_proof) self.proxy.unlock( locked_encoded, merkleproof_encoded, secret, ) self.tester_state.mine(number_of_blocks=1) lock = messages.Lock.from_bytes(locked_encoded) log.info( 'unlock called', contract=pex(self.address), lock=lock, secret=encode_hex(secret), )
def add_asset(self, asset_address): """ The equivalent of instatiating a new `ChannelManagerContract` contract that will manage channels for a given asset in the blockchain. Raises: ValueError: If asset_address is not a valid address or is already registered. """ if asset_address in self.address_asset: raise ValueError('duplicated address {}'.format(encode_hex(asset_address))) asset = AssetMock(address=asset_address) manager = ChannelManagerMock(asset_address) self.address_asset[asset_address] = asset self.asset_manager[asset_address] = manager data = { '_event_type': 'AssetAdded', 'asset_address': asset_address, 'channel_manager_address': manager.address, } event = ethereum_event(ASSETADDED_EVENTID, ASSETADDED_EVENT, data, self.address) for filter_ in BlockChainServiceMock.filters[self.address]: filter_.event(event) BlockChainServiceMock.address_asset[asset_address] = asset BlockChainServiceMock.address_manager[manager.address] = manager BlockChainServiceMock.asset_manager[asset_address] = manager
def run_test(name): pairs = load_tests()[name] def _dec(x): if utils.is_string(x) and x.startswith(b'0x'): return utils.decode_hex(x[2:]) return x pairs['in'] = [(_dec(k), _dec(v)) for k, v in pairs['in']] deletes = [(k, v) for k, v in pairs['in'] if v is None] N_PERMUTATIONS = 100 for i, permut in enumerate(itertools.permutations(pairs['in'])): if i > N_PERMUTATIONS: break db = RefcountDB(EphemDB()) db.ttl = 0 t = pruning_trie.Trie(db) for k, v in permut: # logger.debug('updating with (%s, %s)' %(k, v)) if v is not None: t.update(k, v) else: t.delete(k) db.commit_refcount_changes(0) db.cleanup(0) # make sure we have deletes at the end for k, v in deletes: t.delete(k) t.clear_all() db.commit_refcount_changes(1) db.cleanup(1) assert len(db.kv) == 0 assert pairs['root'] == b'0x' + utils.encode_hex(t.root_hash), (i, list(permut) + deletes)
def block(self, hash): try: if len(hash) == 32: hash = '0x' + encode_hex(hash) return self.get_json(hash) except KeyError: return None
def new_netting_channel(self, peer1, peer2, settle_timeout): """ Creates a new netting contract between peer1 and peer2. Raises: ValueError: If peer1 or peer2 is not a valid address. """ if not isaddress(peer1): raise ValueError('The pee1 must be a valid address') if not isaddress(peer2): raise ValueError('The peer2 must be a valid address') if peer1 == peer2: raise ValueError('Cannot open a channel with itself') pair = tuple(sorted((peer1, peer2))) if pair in self.pair_channel: raise ValueError('({}, {}) already have a channel'.format( encode_hex(peer1), encode_hex(peer2) )) channel = NettingChannelMock( self.asset_address(), peer1, peer2, settle_timeout, ) self.pair_channel[pair] = channel self.participant_channels[peer1].append(channel) self.participant_channels[peer2].append(channel) BlockChainServiceMock.address_contract[channel.address] = channel data = { '_event_type': 'ChannelNew', 'netting_channel': channel.address, 'participant1': peer1, 'participant2': peer2, 'settle_timeout': settle_timeout, } event = ethereum_event(CHANNELNEW_EVENTID, CHANNELNEW_EVENT, data, self.address) for filter_ in BlockChainServiceMock.filters[self.address]: filter_.event(event) return channel.address
def find_channel_by_address(self, netting_channel_address_bin): for manager in self.managers_by_address.itervalues(): channel = manager.address_channel.get(netting_channel_address_bin) if channel is not None: return channel raise ValueError('unknow channel {}'.format(encode_hex(netting_channel_address_bin)))
def find_channel_by_address(self, netting_channel_address_bin): for graph in self.token_to_channelgraph.values(): channel = graph.address_to_channel.get(netting_channel_address_bin) if channel is not None: return channel raise ValueError('unknown channel {}'.format(encode_hex(netting_channel_address_bin)))
def get_deploy_data(cls, *args): data = cls._config.code if args: if cls._config.constructor is None: raise ValueError("This contract does not appear to have a constructor") data += ethereum_utils.encode_hex(cls._config.constructor.abi_args_signature(args)) return data
def get_call_data(self, args): """ TODO: this needs tests. """ prefix = self.encoded_abi_signature suffix = self.abi_args_signature(args) data = prefix + suffix return ethereum_utils.encode_hex(data)
def inc_refcount(self, k, v): # raise Exception("WHY AM I CHANGING A REFCOUNT?!:?") try: node_object = rlp.decode(self.db.get(b'r:'+k)) refcount = utils.decode_int(node_object[0]) self.journal.append([node_object[0], k]) if refcount >= DEATH_ROW_OFFSET: refcount = 0 new_refcount = utils.encode_int(refcount + 1) self.db.put(b'r:'+k, rlp.encode([new_refcount, v])) if self.logging: sys.stderr.write('increasing %s %r to: %d\n' % (utils.encode_hex(k), v, refcount + 1)) except: self.db.put(b'r:'+k, rlp.encode([ONE_ENCODED, v])) self.journal.append([ZERO_ENCODED, k]) if self.logging: sys.stderr.write('increasing %s %r to: %d\n' % (utils.encode_hex(k), v, 1))
def get_state_for(self, node_address_bin): if self.our_state.address == node_address_bin: return self.our_state if self.partner_state.address == node_address_bin: return self.partner_state raise Exception('Unknow address {}'.format(encode_hex(node_address_bin)))
def test_closewithouttransfer_settle(deposit, settle_timeout, tester_state, tester_events, tester_nettingcontracts, tester_token): privatekey0, privatekey1, nettingchannel = tester_nettingcontracts[0] address0 = privatekey_to_address(privatekey0) address1 = privatekey_to_address(privatekey1) unknow_key = tester.k3 initial_balance0 = tester_token.balanceOf(address0, sender=privatekey0) initial_balance1 = tester_token.balanceOf(address1, sender=privatekey1) with pytest.raises(TransactionFailed): nettingchannel.closeWithoutTransfers(sender=unknow_key) # this method needs to be implemented, the name could be changed previous_events = list(tester_events) nettingchannel.closeWithoutTransfers(sender=privatekey0) assert len(previous_events) + 1 == len(tester_events) block_number = tester_state.block.number close_event = tester_events[-1] assert close_event == { '_event_type': 'ChannelClosed', 'closingAddress': encode_hex(address0), 'blockNumber': block_number, } assert nettingchannel.closed() == block_number assert nettingchannel.closingAddress() == encode_hex(address0) tester_state.mine(number_of_blocks=settle_timeout + 1) previous_events = list(tester_events) nettingchannel.settle(sender=privatekey0) block_number = tester_state.block.number assert len(previous_events) + 3 == len(tester_events) transfer0_event = tester_events[-3] assert transfer0_event == { '_from': nettingchannel.address, '_to': encode_hex(address0), '_value': deposit, } transfer1_event = tester_events[-2] assert transfer1_event == { '_from': nettingchannel.address, '_to': encode_hex(address1), '_value': deposit, } settle_event = tester_events[-1] assert settle_event == { '_event_type': 'ChannelSettled', 'blockNumber': block_number, } assert tester_token.balanceOf( address0, sender=privatekey0) == initial_balance0 + deposit assert tester_token.balanceOf( address1, sender=privatekey1) == initial_balance1 + deposit assert tester_token.balanceOf(nettingchannel.address, sender=privatekey1) == 0
def test_close_settle(deposit, settle_timeout, tester_state, tester_channels, tester_events, tester_token): privatekey0_raw, privatekey1_raw, nettingchannel, channel0, channel1 = tester_channels[ 0] privatekey0 = PrivateKey(privatekey0_raw, ctx=GLOBAL_CTX, raw=True) privatekey1 = PrivateKey(privatekey1_raw, ctx=GLOBAL_CTX, raw=True) address0 = privatekey_to_address(privatekey0_raw) address1 = privatekey_to_address(privatekey1_raw) unknow_key = tester.k3 initial_balance0 = tester_token.balanceOf(address0, sender=privatekey0_raw) initial_balance1 = tester_token.balanceOf(address1, sender=privatekey1_raw) transfer_amount0 = 10 direct_transfer0 = channel0.create_directtransfer( transfer_amount0, 1 # TODO: fill in identifier ) direct_transfer0.sign(privatekey0, address0) transfer_amount1 = 30 direct_transfer1 = channel1.create_directtransfer( transfer_amount1, 1 # TODO: fill in identifier ) direct_transfer1.sign(privatekey1, address1) with pytest.raises(TransactionFailed): nettingchannel.close( str(direct_transfer0.packed().data), str(direct_transfer1.packed().data), sender=unknow_key, ) previous_events = list(tester_events) nettingchannel.close( str(direct_transfer0.packed().data), str(direct_transfer1.packed().data), sender=privatekey0_raw, ) assert len(previous_events) + 1 == len(tester_events) block_number = tester_state.block.number close_event = tester_events[-1] assert close_event == { '_event_type': 'ChannelClosed', 'closingAddress': encode_hex(address0), 'blockNumber': block_number, } assert nettingchannel.closed(sender=privatekey0_raw) == block_number assert nettingchannel.closingAddress( sender=privatekey0_raw) == encode_hex(address0) tester_state.mine(number_of_blocks=settle_timeout + 1) previous_events = list(tester_events) nettingchannel.settle(sender=privatekey0_raw) assert len(previous_events) + 3 == len(tester_events) block_number = tester_state.block.number transfer0_event = tester_events[-3] assert transfer0_event == { '_event_type': 'Transfer', '_from': nettingchannel.address, '_to': encode_hex(address0), '_value': deposit - transfer_amount0 + transfer_amount1, } transfer1_event = tester_events[-2] assert transfer1_event == { '_event_type': 'Transfer', '_from': nettingchannel.address, '_to': encode_hex(address1), '_value': deposit + transfer_amount0 - transfer_amount1, } settle_event = tester_events[-1] assert settle_event == { '_event_type': 'ChannelSettled', 'blockNumber': block_number, } assert tester_token.balanceOf( address0, sender=privatekey0_raw ) == initial_balance0 + deposit - transfer_amount0 + transfer_amount1 # noqa assert tester_token.balanceOf( address1, sender=privatekey1_raw ) == initial_balance1 + deposit + transfer_amount0 - transfer_amount1 # noqa assert tester_token.balanceOf(nettingchannel.address, sender=privatekey1_raw) == 0
def _encode_hex(v): """ encodes hash as hex """ return '0x' + utils.encode_hex(v)
-2].gas_used - s.last_tx.intrinsic_gas_used print("500 bytes increment: %d" % (g2 - g1)) print("500 bytes increment: %d" % (g4 - g3)) print("25 items increment: %d" % (g3 - g1)) print("25 items increment: %d" % (g4 - g2)) # configure_logging(config_string=config_string) s.send( t.k0, c, 0, b'\xf8\xc7\x01\xa055555555555555555555555555555555\xa0\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x80\xa0\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xb8`\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x1b\x88\xa7\x85r\x1b3\x17\xcaP\x96\xca\xd3S\xfcgM\xec\xe0\xf5!\xc8\xb4m\xd9\xb7E\xf3\x81d\x87\x93VD\xe0Ej\xcd\xec\x80\x11\x86(qZ\x9b\x80\xbf\xce\xe5*\r\x9d.o\xcd\x11s\xc5\xbc\x8c\xcb\xb9\xa9 ' ) g = s.state.receipts[-1].gas_used - s.state.receipts[ -2].gas_used - s.last_tx.intrinsic_gas_used print("Casper prepare: %d" % g) # Create transaction t = transactions.Transaction(0, 30 * 10**9, 2999999, '', 0, rlp_decoder) t.startgas = t.intrinsic_gas_used + 50000 + 200 * len(rlp_decoder) t.v = 27 t.r = 45 t.s = 79 print("RLP decoder") print("Instructions for launching:") print('First send %d wei to %s' % (t.startgas * t.gasprice, utils.checksum_encode(t.sender))) print('Publish this tx to create the contract: 0x' + utils.encode_hex(rlp.encode(t))) print('This is the contract address: ' + utils.checksum_encode(utils.mk_contract_address(t.sender, 0)))
def tester_deploy_contract(tester_chain, private_key, contract_name, contract_path, constructor_parameters=None): all_contracts = _solidity.compile_file(contract_path, libraries=dict()) contract_key = solidity_get_contract_key(all_contracts, contract_path, contract_name) contract = all_contracts[contract_key] contract_interface = contract['abi'] log.info('Deploying "{}" contract'.format(os.path.basename(contract_path))) dependencies = deploy_dependencies_symbols(all_contracts) deployment_order = dependencies_order_of_build(contract_key, dependencies) log.info('Deploying dependencies: {}'.format(str(deployment_order))) deployment_order.pop() # remove `contract_name` from the list libraries = dict() for deploy_contract in deployment_order: dependency_contract = all_contracts[deploy_contract] hex_bytecode = _solidity.solidity_resolve_symbols( dependency_contract['bin_hex'], libraries, ) bytecode = unhexlify(hex_bytecode) dependency_contract['bin_hex'] = hex_bytecode dependency_contract['bin'] = bytecode log.info('Creating contract {}'.format(deploy_contract)) contract_address = tester_chain.contract(bytecode, language='evm', sender=private_key) tester_chain.mine(number_of_blocks=1) if len(tester_chain.head_state.get_code(contract_address)) == 0: raise Exception('Contract code empty') libraries[deploy_contract] = encode_hex(contract_address) hex_bytecode = _solidity.solidity_resolve_symbols(contract['bin_hex'], libraries) bytecode = unhexlify(hex_bytecode) contract['bin_hex'] = hex_bytecode contract['bin'] = bytecode if constructor_parameters: translator = ContractTranslator(contract_interface) parameters = translator.encode_constructor_arguments( constructor_parameters) bytecode = contract['bin'] + parameters else: bytecode = contract['bin'] log.info('Creating contract {}'.format(contract_name)) contract_address = tester_chain.contract(bytecode, language='evm', sender=private_key) tester_chain.mine(number_of_blocks=1) if len(tester_chain.head_state.get_code(contract_address)) == 0: raise Exception('Contract code empty') return contract_address
def valueconv(k, v): if k in ['r', 's']: return '0x' + encode_hex(utils.int_to_big_endian(v)) return v
import pytest from ethereum.tools import tester as t from ethereum import utils from tests.setup_transaction_tests import assert_tx_failed t.s = t.Chain() t.s.head_state.gas_limit = 10**9 x = t.s.contract(open('examples/wallet/wallet.v.py').read(), args=[[t.a1, t.a2, t.a3, t.a4, t.a5], 3], language='viper') print(t.s.last_tx.data[-192:]) # Sends wei to the contract for future transactions gas costs t.s.tx(sender=t.k1, to=x.address, value=10**17) print([utils.encode_hex(a) for a in [t.a1, t.a2, t.a3, t.a4, t.a5]]) # Signs a transaction with a given key def sign(seq, to, value, data, key): h1 = utils.sha3( utils.encode_int32(seq) + b'\x00' * 12 + to + utils.encode_int32(value) + data) h2 = utils.sha3(b"\x19Ethereum Signed Message:\n32" + h1) return list(utils.ecsign(h2, key)) def test_approve(assert_tx_failed): to, value, data = b'\x35' * 20, 10**16, b"" assert x.approve(0, to, value,
def __repr__(self): return '<TransientBlock(#%d %s)>' % (self.header.number, encode_hex(self.header.hash)[:8])
def add_block(self, block): now = self.localtime # Are we receiving the block too early? if block.header.timestamp > now: i = 0 while i < len(self.time_queue ) and block.timestamp > self.time_queue[i].timestamp: i += 1 self.time_queue.insert(i, block) log.info( 'Block received too early (%d vs %d). Delaying for %d seconds' % (now, block.header.timestamp, block.header.timestamp - now)) return False # Is the block being added to the head? self.state.deletes = [] if block.header.prevhash == self.head_hash: log.info('Adding to head', head=encode_hex(block.header.prevhash)) try: apply_block(self.state, block) except (AssertionError, KeyError, ValueError, InvalidTransaction, VerificationFailed) as e: log.info('Block %d (%s) with parent %s invalid, reason: %s' % (block.number, encode_hex(block.header.hash), encode_hex(block.header.prevhash), e)) return False self.db.put(b'block:%d' % block.header.number, block.header.hash) block_score = self.get_score( block) # side effect: put 'score:' cache in db self.head_hash = block.header.hash for i, tx in enumerate(block.transactions): self.db.put(b'txindex:' + tx.hash, rlp.encode([block.number, i])) assert self.get_blockhash_by_number( block.header.number) == block.header.hash deletes = self.state.deletes # Or is the block being added to a chain that is not currently the head? elif block.header.prevhash in self.env.db: log.info( 'Receiving block not on head, adding to secondary post state', prevhash=encode_hex(block.header.prevhash)) temp_state = self.mk_poststate_of_blockhash(block.header.prevhash) try: apply_block(temp_state, block) except (AssertionError, KeyError, ValueError, InvalidTransaction, VerificationFailed) as e: log.info('Block %s with parent %s invalid, reason: %s' % (encode_hex(block.header.hash), encode_hex(block.header.prevhash), e)) return False deletes = temp_state.deletes block_score = self.get_score(block) # If the block should be the new head, replace the head if block_score > self.get_score(self.head): b = block new_chain = {} # Find common ancestor while b.header.number >= int(self.db.get('GENESIS_NUMBER')): new_chain[b.header.number] = b key = b'block:%d' % b.header.number orig_at_height = self.db.get( key) if key in self.db else None if orig_at_height == b.header.hash: break if b.prevhash not in self.db or self.db.get( b.prevhash) == 'GENESIS': break b = self.get_parent(b) # Replace block index and tx indices replace_from = b.header.number for i in itertools.count(replace_from): log.info('Rewriting height %d' % i) key = b'block:%d' % i orig_at_height = self.db.get( key) if key in self.db else None if orig_at_height: self.db.delete(key) orig_block_at_height = self.get_block(orig_at_height) for tx in orig_block_at_height.transactions: if b'txindex:' + tx.hash in self.db: self.db.delete(b'txindex:' + tx.hash) if i in new_chain: new_block_at_height = new_chain[i] self.db.put(key, new_block_at_height.header.hash) for i, tx in enumerate( new_block_at_height.transactions): self.db.put( b'txindex:' + tx.hash, rlp.encode([new_block_at_height.number, i])) if i not in new_chain and not orig_at_height: break self.head_hash = block.header.hash self.state = temp_state # Block has no parent yet else: if block.header.prevhash not in self.parent_queue: self.parent_queue[block.header.prevhash] = [] self.parent_queue[block.header.prevhash].append(block) log.info( 'Got block %d (%s) with prevhash %s, parent not found. Delaying for now' % (block.number, encode_hex( block.hash), encode_hex(block.prevhash))) return False self.add_child(block) self.db.put('head_hash', self.head_hash) self.db.put(block.hash, rlp.encode(block)) self.db.put(b'deletes:' + block.hash, b''.join(deletes)) print('Saved %d trie node deletes for block %d (%s)' % (len(deletes), block.number, utils.encode_hex(block.hash))) # Delete old junk data old_block_hash = self.get_blockhash_by_number(block.number - self.max_history) if old_block_hash: try: deletes = self.db.get(b'deletes:' + old_block_hash) print('Deleting up to %d trie nodes' % (len(deletes) // 32)) rdb = RefcountDB(self.db) for i in range(0, len(deletes), 32): rdb.delete(deletes[i:i + 32]) self.db.delete(b'deletes:' + old_block_hash) except KeyError as e: print(e) pass self.db.commit() assert (b'deletes:' + block.hash) in self.db log.info('Added block %d (%s) with %d txs and %d gas' % \ (block.header.number, encode_hex(block.header.hash)[:8], len(block.transactions), block.header.gas_used)) if self.new_head_cb and block.header.number != 0: self.new_head_cb(block) if block.header.hash in self.parent_queue: for _blk in self.parent_queue[block.header.hash]: self.add_block(_blk) del self.parent_queue[block.header.hash] return True
def test_logs(casper, funded_privkey, new_epoch, get_logs, deposit_validator, mk_suggested_vote, get_last_log, casper_chain, logout_validator): new_epoch() assert casper.current_epoch() == 1 assert casper.next_validator_index() == 1 validator_index = casper.next_validator_index() deposit_validator(funded_privkey, 1900 * 10**18) # Deposit log log1 = get_last_log(casper_chain, casper) assert set(('_from', '_validation_address', '_validator_index', '_start_dyn', '_amount', '_event_type')) == log1.keys() assert log1['_event_type'] == b'Deposit' assert log1['_from'] == '0x' + utils.encode_hex( utils.privtoaddr(funded_privkey)) assert log1['_validator_index'] == validator_index new_epoch() # Test epoch logs receipt = casper_chain.head_state.receipts[-1] logs = get_logs(receipt, casper) log_old = logs[-2] log_new = logs[-1] assert set(('_number', '_checkpoint_hash', '_is_justified', '_is_finalized', '_event_type')) == log_old.keys() # New epoch log assert log_new['_event_type'] == b'Epoch' assert log_new['_number'] == 2 assert log_new['_is_justified'] is False assert log_new['_is_finalized'] is False # Insta finalized previous assert log_old['_event_type'] == b'Epoch' assert log_old['_number'] == 1 assert log_old['_is_justified'] is True assert log_old['_is_finalized'] is True new_epoch() new_epoch() casper.vote(mk_suggested_vote(validator_index, funded_privkey)) # vote log log2 = get_last_log(casper_chain, casper) assert set(('_from', '_validator_index', '_target_hash', '_target_epoch', '_source_epoch', '_event_type')) == log2.keys() assert log2['_event_type'] == b'Vote' assert log2['_from'] == '0x' + utils.encode_hex( utils.privtoaddr(funded_privkey)) new_epoch() casper.vote(mk_suggested_vote(validator_index, funded_privkey)) log3 = get_last_log(casper_chain, casper) assert log3['_event_type'] == b'Vote' logout_validator(validator_index, funded_privkey) # Logout log log4 = get_last_log(casper_chain, casper) assert set(('_from', '_validator_index', '_end_dyn', '_event_type')) == log4.keys() assert log4['_event_type'] == b'Logout' assert log4['_from'] == '0x' + utils.encode_hex( utils.privtoaddr(funded_privkey)) # Need to vote 'dynasty_logout_delay' epochs before logout is active for _ in range(casper.dynasty_logout_delay()): new_epoch() casper.vote(mk_suggested_vote(validator_index, funded_privkey)) for i in range(casper.withdrawal_delay() + 1): new_epoch() cur_epoch = casper.current_epoch() end_epoch = casper.dynasty_start_epoch( casper.validators__end_dynasty(validator_index) + 1) assert cur_epoch == end_epoch + casper.withdrawal_delay( ) # so we are allowed to withdraw casper.withdraw(validator_index) # Withdrawal log, finally log5 = get_last_log(casper_chain, casper) assert set( ('_to', '_validator_index', '_amount', '_event_type')) == log5.keys() assert log5['_event_type'] == b'Withdraw' assert log5['_to'] == '0x' + utils.encode_hex( utils.privtoaddr(funded_privkey))
def __repr__(self): return '<Transaction(%s)>' % encode_hex(self.hash)[:4]
def __structlog__(self): return encode_hex(self.hash)
def vm_execute(ext, msg, code): # precompute trace flag # if we trace vm, we're in slow mode anyway trace_vm = log_vm_op.is_active('trace') compustate = Compustate(gas=msg.gas) stk = compustate.stack mem = compustate.memory processed_code = preprocess_code(code) s = time.time() op = None steps = 0 _prevop = None # for trace only while True: # print('op: ', op, time.time() - s) # s = time.time() # stack size limit error if compustate.pc not in processed_code: return vm_exception('INVALID START POINT') _data = processed_code[compustate.pc] gas, min_stack, max_stack, compustate.pc = _data[:4] ops = _data[4:] # out of gas error if gas > compustate.gas: return vm_exception('OUT OF GAS') # insufficient stack error if not (min_stack <= len(compustate.stack) <= max_stack): return vm_exception('INCOMPATIBLE STACK LENGTH', min_stack=min_stack, have=len(compustate.stack), max_stack=max_stack) # Apply operation compustate.gas -= gas for op in ops: if trace_vm: """ This diverges from normal logging, as we use the logging namespace only to decide which features get logged in 'eth.vm.op' i.e. tracing can not be activated by activating a sub like 'eth.vm.op.stack' """ trace_data = {} trace_data['stack'] = list( map(to_string, list(compustate.stack))) if _prevop in (op_MLOAD, op_MSTORE, op_MSTORE8, op_SHA3, op_CALL, op_CALLCODE, op_CREATE, op_CALLDATACOPY, op_CODECOPY, op_EXTCODECOPY): if len(compustate.memory) < 1024: trace_data['memory'] = \ b''.join([encode_hex(ascii_chr(x)) for x in compustate.memory]) else: trace_data['sha3memory'] = \ encode_hex(utils.sha3(''.join([ascii_chr(x) for x in compustate.memory]))) if _prevop in (op_SSTORE, op_SLOAD) or steps == 0: trace_data['storage'] = ext.log_storage(msg.to) # trace_data['gas'] = to_string(compustate.gas + fee) trace_data['inst'] = op trace_data['pc'] = to_string(compustate.pc - 1) if steps == 0: trace_data['depth'] = msg.depth trace_data['address'] = msg.to trace_data['op'] = op trace_data['steps'] = steps # if op[:4] == 'PUSH': # trace_data['pushvalue'] = pushval log_vm_op.trace('vm', **trace_data) steps += 1 _prevop = op # Invalid operation if op == INVALID: return vm_exception('INVALID OP', opcode=op) # Valid operations if op < 0x10: if op == op_STOP: return peaceful_exit('STOP', compustate.gas, []) elif op == op_ADD: stk.append((stk.pop() + stk.pop()) & TT256M1) elif op == op_SUB: stk.append((stk.pop() - stk.pop()) & TT256M1) elif op == op_MUL: stk.append((stk.pop() * stk.pop()) & TT256M1) elif op == op_DIV: s0, s1 = stk.pop(), stk.pop() stk.append(0 if s1 == 0 else s0 // s1) elif op == op_MOD: s0, s1 = stk.pop(), stk.pop() stk.append(0 if s1 == 0 else s0 % s1) elif op == op_SDIV: s0, s1 = utils.to_signed(stk.pop()), utils.to_signed( stk.pop()) stk.append(0 if s1 == 0 else (abs(s0) // abs(s1) * (-1 if s0 * s1 < 0 else 1)) & TT256M1) elif op == op_SMOD: s0, s1 = utils.to_signed(stk.pop()), utils.to_signed( stk.pop()) stk.append(0 if s1 == 0 else (abs(s0) % abs(s1) * (-1 if s0 < 0 else 1)) & TT256M1) elif op == op_ADDMOD: s0, s1, s2 = stk.pop(), stk.pop(), stk.pop() stk.append((s0 + s1) % s2 if s2 else 0) elif op == op_MULMOD: s0, s1, s2 = stk.pop(), stk.pop(), stk.pop() stk.append((s0 * s1) % s2 if s2 else 0) elif op == op_EXP: base, exponent = stk.pop(), stk.pop() # fee for exponent is dependent on its bytes # calc n bytes to represent exponent nbytes = len(utils.encode_int(exponent)) expfee = nbytes * opcodes.GEXPONENTBYTE if compustate.gas < expfee: compustate.gas = 0 return vm_exception('OOG EXPONENT') compustate.gas -= expfee stk.append(pow(base, exponent, TT256)) elif op == op_SIGNEXTEND: s0, s1 = stk.pop(), stk.pop() if s0 <= 31: testbit = s0 * 8 + 7 if s1 & (1 << testbit): stk.append(s1 | (TT256 - (1 << testbit))) else: stk.append(s1 & ((1 << testbit) - 1)) else: stk.append(s1) elif op < 0x20: if op == op_LT: stk.append(1 if stk.pop() < stk.pop() else 0) elif op == op_GT: stk.append(1 if stk.pop() > stk.pop() else 0) elif op == op_SLT: s0, s1 = utils.to_signed(stk.pop()), utils.to_signed( stk.pop()) stk.append(1 if s0 < s1 else 0) elif op == op_SGT: s0, s1 = utils.to_signed(stk.pop()), utils.to_signed( stk.pop()) stk.append(1 if s0 > s1 else 0) elif op == op_EQ: stk.append(1 if stk.pop() == stk.pop() else 0) elif op == op_ISZERO: stk.append(0 if stk.pop() else 1) elif op == op_AND: stk.append(stk.pop() & stk.pop()) elif op == op_OR: stk.append(stk.pop() | stk.pop()) elif op == op_XOR: stk.append(stk.pop() ^ stk.pop()) elif op == op_NOT: stk.append(TT256M1 - stk.pop()) elif op == op_BYTE: s0, s1 = stk.pop(), stk.pop() if s0 >= 32: stk.append(0) else: stk.append((s1 // 256**(31 - s0)) % 256) elif op < 0x40: if op == op_SHA3: s0, s1 = stk.pop(), stk.pop() compustate.gas -= opcodes.GSHA3WORD * \ (utils.ceil32(s1) // 32) if compustate.gas < 0: return vm_exception('OOG PAYING FOR SHA3') if not mem_extend(mem, compustate, op, s0, s1): return vm_exception('OOG EXTENDING MEMORY') data = b''.join(map(ascii_chr, mem[s0:s0 + s1])) stk.append(utils.big_endian_to_int(utils.sha3(data))) elif op == op_ADDRESS: stk.append(utils.coerce_to_int(msg.to)) elif op == op_BALANCE: addr = utils.coerce_addr_to_hex(stk.pop() % 2**160) stk.append(ext.get_balance(addr)) elif op == op_ORIGIN: stk.append(utils.coerce_to_int(ext.tx_origin)) elif op == op_CALLER: stk.append(utils.coerce_to_int(msg.sender)) elif op == op_CALLVALUE: stk.append(msg.value) elif op == op_CALLDATALOAD: stk.append(msg.data.extract32(stk.pop())) elif op == op_CALLDATASIZE: stk.append(msg.data.size) elif op == op_CALLDATACOPY: mstart, dstart, size = stk.pop(), stk.pop(), stk.pop() if not mem_extend(mem, compustate, op, mstart, size): return vm_exception('OOG EXTENDING MEMORY') if not data_copy(compustate, size): return vm_exception('OOG COPY DATA') msg.data.extract_copy(mem, mstart, dstart, size) elif op == op_CODESIZE: stk.append(len(code)) elif op == op_CODECOPY: start, s1, size = stk.pop(), stk.pop(), stk.pop() if not mem_extend(mem, compustate, op, start, size): return vm_exception('OOG EXTENDING MEMORY') if not data_copy(compustate, size): return vm_exception('OOG COPY DATA') for i in range(size): if s1 + i < len(code): mem[start + i] = utils.safe_ord(code[s1 + i]) else: mem[start + i] = 0 elif op == op_GASPRICE: stk.append(ext.tx_gasprice) elif op == op_EXTCODESIZE: addr = utils.coerce_addr_to_hex(stk.pop() % 2**160) stk.append(len(ext.get_code(addr) or b'')) elif op == op_EXTCODECOPY: addr = utils.coerce_addr_to_hex(stk.pop() % 2**160) start, s2, size = stk.pop(), stk.pop(), stk.pop() extcode = ext.get_code(addr) or b'' assert utils.is_string(extcode) if not mem_extend(mem, compustate, op, start, size): return vm_exception('OOG EXTENDING MEMORY') if not data_copy(compustate, size): return vm_exception('OOG COPY DATA') for i in range(size): if s2 + i < len(extcode): mem[start + i] = utils.safe_ord(extcode[s2 + i]) else: mem[start + i] = 0 elif op < 0x50: if op == op_BLOCKHASH: stk.append( utils.big_endian_to_int(ext.block_hash(stk.pop()))) elif op == op_COINBASE: stk.append(utils.big_endian_to_int(ext.block_coinbase)) elif op == op_TIMESTAMP: stk.append(ext.block_timestamp) elif op == op_NUMBER: stk.append(ext.block_number) elif op == op_DIFFICULTY: stk.append(ext.block_difficulty) elif op == op_GASLIMIT: stk.append(ext.block_gas_limit) elif op < 0x60: if op == op_POP: stk.pop() elif op == op_MLOAD: s0 = stk.pop() if not mem_extend(mem, compustate, op, s0, 32): return vm_exception('OOG EXTENDING MEMORY') data = 0 for c in mem[s0:s0 + 32]: data = (data << 8) + c stk.append(data) elif op == op_MSTORE: s0, s1 = stk.pop(), stk.pop() if not mem_extend(mem, compustate, op, s0, 32): return vm_exception('OOG EXTENDING MEMORY') v = s1 for i in range(31, -1, -1): mem[s0 + i] = v % 256 v //= 256 elif op == op_MSTORE8: s0, s1 = stk.pop(), stk.pop() if not mem_extend(mem, compustate, op, s0, 1): return vm_exception('OOG EXTENDING MEMORY') mem[s0] = s1 % 256 elif op == op_SLOAD: stk.append(ext.get_storage_data(msg.to, stk.pop())) elif op == op_SSTORE: s0, s1 = stk.pop(), stk.pop() if ext.get_storage_data(msg.to, s0): gascost = opcodes.GSTORAGEMOD if s1 else opcodes.GSTORAGEKILL refund = 0 if s1 else opcodes.GSTORAGEREFUND else: gascost = opcodes.GSTORAGEADD if s1 else opcodes.GSTORAGEMOD refund = 0 if compustate.gas < gascost: return vm_exception('OUT OF GAS') compustate.gas -= gascost # adds neg gascost as a refund if below zero ext.add_refund(refund) ext.set_storage_data(msg.to, s0, s1) elif op == op_JUMP: compustate.pc = stk.pop() opnew = processed_code[compustate.pc][4] if \ compustate.pc in processed_code else op_STOP if opnew != op_JUMPDEST: return vm_exception('BAD JUMPDEST') elif op == op_JUMPI: s0, s1 = stk.pop(), stk.pop() if s1: compustate.pc = s0 opnew = processed_code[compustate.pc][4] if \ compustate.pc in processed_code else op_STOP if opnew != op_JUMPDEST: return vm_exception('BAD JUMPDEST') elif op == op_PC: stk.append(compustate.pc - 1) elif op == op_MSIZE: stk.append(len(mem)) elif op == op_GAS: stk.append(compustate.gas) # AFTER subtracting cost 1 elif op_PUSH1 <= (op & 255) <= op_PUSH32: # Hide push value in high-order bytes of op stk.append(op >> 8) elif op_DUP1 <= op <= op_DUP16: depth = op - op_DUP1 + 1 stk.append(stk[-depth]) elif op_SWAP1 <= op <= op_SWAP16: depth = op - op_SWAP1 + 1 temp = stk[-depth - 1] stk[-depth - 1] = stk[-1] stk[-1] = temp elif op_LOG0 <= op <= op_LOG4: """ 0xa0 ... 0xa4, 32/64/96/128/160 + len(data) gas a. Opcodes LOG0...LOG4 are added, takes 2-6 stack arguments MEMSTART MEMSZ (TOPIC1) (TOPIC2) (TOPIC3) (TOPIC4) b. Logs are kept track of during tx execution exactly the same way as suicides (except as an ordered list, not a set). Each log is in the form [address, [topic1, ... ], data] where: * address is what the ADDRESS opcode would output * data is mem[MEMSTART: MEMSTART + MEMSZ] * topics are as provided by the opcode c. The ordered list of logs in the transaction are expressed as [log0, log1, ..., logN]. """ depth = op - op_LOG0 mstart, msz = stk.pop(), stk.pop() topics = [stk.pop() for x in range(depth)] compustate.gas -= msz * opcodes.GLOGBYTE if not mem_extend(mem, compustate, op, mstart, msz): return vm_exception('OOG EXTENDING MEMORY') data = b''.join(map(ascii_chr, mem[mstart:mstart + msz])) ext.log(msg.to, topics, data) log_log.trace('LOG', to=msg.to, topics=topics, data=list(map(utils.safe_ord, data))) # print('LOG', msg.to, topics, list(map(ord, data))) elif op == op_CREATE: value, mstart, msz = stk.pop(), stk.pop(), stk.pop() if not mem_extend(mem, compustate, op, mstart, msz): return vm_exception('OOG EXTENDING MEMORY') if ext.get_balance(msg.to) >= value and msg.depth < 1024: cd = CallData(mem, mstart, msz) create_msg = Message(msg.to, b'', value, compustate.gas, cd, msg.depth + 1) o, gas, addr = ext.create(create_msg) if o: stk.append(utils.coerce_to_int(addr)) compustate.gas = gas else: stk.append(0) compustate.gas = 0 else: stk.append(0) elif op == op_CALL: gas, to, value, meminstart, meminsz, memoutstart, memoutsz = \ stk.pop(), stk.pop(), stk.pop(), stk.pop(), stk.pop(), stk.pop(), stk.pop() if not mem_extend(mem, compustate, op, meminstart, meminsz) or \ not mem_extend(mem, compustate, op, memoutstart, memoutsz): return vm_exception('OOG EXTENDING MEMORY') to = utils.encode_int(to) to = ((b'\x00' * (32 - len(to))) + to)[12:] extra_gas = (not ext.account_exists(to)) * opcodes.GCALLNEWACCOUNT + \ (value > 0) * opcodes.GCALLVALUETRANSFER submsg_gas = gas + opcodes.GSTIPEND * (value > 0) if compustate.gas < gas + extra_gas: return vm_exception('OUT OF GAS', needed=gas + extra_gas) if ext.get_balance(msg.to) >= value and msg.depth < 1024: compustate.gas -= (gas + extra_gas) cd = CallData(mem, meminstart, meminsz) call_msg = Message(msg.to, to, value, submsg_gas, cd, msg.depth + 1, code_address=to) result, gas, data = ext.msg(call_msg) if result == 0: stk.append(0) else: stk.append(1) compustate.gas += gas for i in range(min(len(data), memoutsz)): mem[memoutstart + i] = data[i] else: compustate.gas -= (gas + extra_gas - submsg_gas) stk.append(0) elif op == op_CALLCODE: gas, to, value, meminstart, meminsz, memoutstart, memoutsz = \ stk.pop(), stk.pop(), stk.pop(), stk.pop(), stk.pop(), stk.pop(), stk.pop() if not mem_extend(mem, compustate, op, meminstart, meminsz) or \ not mem_extend(mem, compustate, op, memoutstart, memoutsz): return vm_exception('OOG EXTENDING MEMORY') extra_gas = (value > 0) * opcodes.GCALLVALUETRANSFER submsg_gas = gas + opcodes.GSTIPEND * (value > 0) if compustate.gas < gas + extra_gas: return vm_exception('OUT OF GAS', needed=gas + extra_gas) if ext.get_balance(msg.to) >= value and msg.depth < 1024: compustate.gas -= (gas + extra_gas) to = utils.encode_int(to) to = ((b'\x00' * (32 - len(to))) + to)[12:] cd = CallData(mem, meminstart, meminsz) call_msg = Message(msg.to, msg.to, value, submsg_gas, cd, msg.depth + 1, code_address=to) result, gas, data = ext.msg(call_msg) if result == 0: stk.append(0) else: stk.append(1) compustate.gas += gas for i in range(min(len(data), memoutsz)): mem[memoutstart + i] = data[i] else: compustate.gas -= (gas + extra_gas - submsg_gas) stk.append(0) elif op == op_RETURN: s0, s1 = stk.pop(), stk.pop() if not mem_extend(mem, compustate, op, s0, s1): return vm_exception('OOG EXTENDING MEMORY') return peaceful_exit('RETURN', compustate.gas, mem[s0:s0 + s1]) elif op == op_SUICIDE: to = utils.encode_int(stk.pop()) to = ((b'\x00' * (32 - len(to))) + to)[12:] xfer = ext.get_balance(msg.to) ext.set_balance(to, ext.get_balance(to) + xfer) ext.set_balance(msg.to, 0) ext.add_suicide(msg.to) # print('suiciding %s %s %d' % (msg.to, to, xfer)) return 1, compustate.gas, []
ecrecover_test = """ def test_ecrecover(h: bytes32, v:num256, r:num256, s:num256) -> address: return ecrecover(h, v, r, s) def test_ecrecover2() -> address: return ecrecover(0x3535353535353535353535353535353535353535353535353535353535353535, as_num256(28), as_num256(63198938615202175987747926399054383453528475999185923188997970550032613358815), as_num256(6577251522710269046055727877571505144084475024240851440410274049870970796685)) """ c = s.abi_contract(ecrecover_test, language='viper') h = b'\x35' * 32 k = b'\x46' * 32 v, r, S = u.ecsign(h, k) assert c.test_ecrecover(h, v, r, S) == '0x' + u.encode_hex(u.privtoaddr(k)) assert c.test_ecrecover2() == '0x' + u.encode_hex(u.privtoaddr(k)) print("Passed ecrecover test") extract32_code = """ y: bytes <= 100 def extrakt32(inp: bytes <= 100, index: num) -> bytes32: return extract32(inp, index) def extrakt32_mem(inp: bytes <= 100, index: num) -> bytes32: x = inp return extract32(x, index) def extrakt32_storage(index: num, inp: bytes <= 100) -> bytes32: self.y = inp
def main(): ''' Main method. Runs the program if it is used standalone (rather than as an exported library). ''' parser = _get_args() if len(parser.target_address) != 42: log.error( "Target Address length does not appear to match the correct length of an Ethereum address" ) sys.exit(1) if len(parser.from_address) != 42: log.error( "From Address length does not appear to match the correct length of an Ethereum address" ) sys.exit(1) if parser.target_address[0:2] != "0x": log.error( "Target address not in expected format, expected address to start with 0x" ) sys.exit(1) if parser.from_address[0:2] != "0x": log.error( "From address not in expected format, expected address to start with 0x" ) sys.exit(1) if not check_checksum(parser.target_address): log.error( "Target address is not correctly encoded using EIP-55 {}".format( parser.target_address)) sys.exit(1) if not check_checksum(parser.from_address): log.error( "From address is not correctly encoded using EIP-55 {}".format( parser.from_address)) sys.exit(1) toAddress = normalize_address(parser.target_address) fromAddress = normalize_address(parser.from_address) gasPrice = parser.gas_price gasLimit = parser.gas_limit sendAmount = parser.amount if (parser.dapp_data): dappData = rec_bin(parser.dapp_data) else: dappData = b"" tx, addressB, commit, randw = _generateAddressBInternal( fromAddress, toAddress, sendAmount, dappData, gasPrice, gasLimit) # print("-"* 35) # printRemix(fromAddress, tx, encode_hex(randw)) print("-" * 35) print("AddressB: {}".format(addressB) ) # addressB also can retrieved using tx.to_dict().get("sender") print("commit: {}".format(encode_hex(commit))) print("witness (w): {}".format(encode_hex(randw))) # print("Reveal Transation (json): {}".format(tx.to_dict())) print("Reveal Transaction (hex): {}".format(encode_hex(rlp.encode(tx)))) print( "You can use the reveal transaction hex to broadcast with any service you like, e.g.: https://ropsten.etherscan.io/pushTx" )
0], [1, 0, 0, 1, 0, 0, 1, 0], [1, 0] * 8): assert decode_bin_path(encode_bin_path(bytes(path))) == bytes(path) r1 = None for _ in range(3): t = Trie(EphemDB(), b'') for i, (k, v) in enumerate(shuffle_in_place(kvpairs)): #print(t.to_dict()) t.update(k, v) assert t.get(k) == v if not i % 50: if not i % 250: t.to_dict() print("Length of branch at %d nodes: %d" % (i, len(rlp.encode(t.get_branch(k))))) assert r1 is None or t.root == r1 r1 = t.root t.update(kvpairs[0][0], kvpairs[0][1]) assert t.root == r1 print(t.get_branch(kvpairs[0][0])) print(t.get_branch(kvpairs[0][0][::-1])) print(encode_hex(t.root)) for k, v in shuffle_in_place(kvpairs): t.update(k, b'') if not random.randrange(100): t.to_dict() #t.print_nodes() assert t.root == b''
def rec_hex(x): if isinstance(x, list): return [rec_hex(elem) for elem in x] else: return utils.encode_hex(x)
from ethereum.utils import mk_contract_address, encode_hex source = '0x4a574510c7014e4ae985403536074abe582adfc8' L = [] # DAO L.append('0xbb9bc244d798123fde783fcc1c72d3bb8c189413') # DAO extrabalance L.append('0x807640a13483f8ac783c557fcdf27be11ea4ac7a') # child DAOs (created by DAO creator) L.extend( [b'0x' + encode_hex(mk_contract_address(source, i)) for i in range(1, 58)]) # child extrabalances L.extend([ b'0x' + encode_hex(mk_contract_address(mk_contract_address(source, i), 0)) for i in range(1, 58) ])
def decodeBlock(block): """ Decode various pieces of information (from hex) for a block and return the parsed data. Note that the block is of the form: { "id": 0, "jsonrpc": "2.0", "result": { "number": "0xf4241", "hash": "0xcb5cab7266694daa0d28cbf40496c08dd30bf732c41e0455e7ad389c10d79f4f", "parentHash": "0x8e38b4dbf6b11fcc3b9dee84fb7986e29ca0a02cecd8977c161ff7333329681e", "nonce": "0x9112b8c2b377fbe8", "sha3Uncles": "0x1dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d49347", "logsBloom": "0x0", "transactionsRoot": "0xc61c50a0a2800ddc5e9984af4e6668de96aee1584179b3141f458ffa7d4ecec6", "stateRoot": "0x7dd4aabb93795feba9866821c0c7d6a992eda7fbdd412ea0f715059f9654ef23", "receiptRoot": "0xb873ddefdb56d448343d13b188241a4919b2de10cccea2ea573acf8dbc839bef", "miner": "0x2a65aca4d5fc5b5c859090a6c34d164135398226", "difficulty": "0xb6b4bbd735f", "totalDifficulty": "0x63056041aaea71c9", "size": "0x292", "extraData": "0xd783010303844765746887676f312e352e31856c696e7578", "gasLimit": "0x2fefd8", "gasUsed": "0x5208", "timestamp": "0x56bfb41a", "transactions": [ { "hash": "0xefb6c796269c0d1f15fdedb5496fa196eb7fb55b601c0fa527609405519fd581", "nonce": "0x2a121", "blockHash": "0xcb5cab7266694daa0d28cbf40496c08dd30bf732c41e0455e7ad389c10d79f4f", "blockNumber": "0xf4241", "transactionIndex": "0x0", "from": "0x2a65aca4d5fc5b5c859090a6c34d164135398226", "to": "0x819f4b08e6d3baa33ba63f660baed65d2a6eb64c", "value": "0xe8e43bc79c88000", "gas": "0x15f90", "gasPrice": "0xba43b7400", "input": "0x" } ], "uncles": [] } } """ try: txs = [] b = block if "result" in block: b = block["result"] # Filter the block new_block = { "number": int(b["number"], 16), "timestamp": int(b["timestamp"], 16), # Timestamp is in unix time "transactions": [], } # Filter and decode each transaction and add it back # Value, gas, and gasPrice are all converted to ether reward = float(5.0) i = 1 to = "to" isContractCreation = False fromContract = False toContract = False for t in b["transactions"]: if t["to"] == None: to = "0x" + encode_hex( mk_contract_address(t["from"], int(t["nonce"], 16)) ) isContractCreation = True contractAddresses.append(to) elif t["to"] in contractAddresses: toContract = True else: to = t["to"] if t["from"] in contractAddresses: fromContract = True tx = makeTx( b["number"], i, b["timestamp"], t["from"], to, float(int(t["value"], 16)) / 1000000000000000000.0, isContractCreation, t["input"], t["gas"], t["gasPrice"], fromContract, toContract, ) reward += ( float(int(t["gas"], 16) * int(t["gasPrice"], 16)) / 1000000000000000000.0 ) txs.append(tx) i += 1 rewardTx = makeTx( b["number"], 0, b["timestamp"], "REWARD", b["miner"], reward, isContractCreation, "", "0x0", "0x0", False, False, ) txs.append(rewardTx) return txs except: return None
def test_channelnewbalance_event(private_keys, settle_timeout, tester_state, tester_events, tester_token, tester_registry): """ Check the correct events are generated for deposit calls. """ privatekey0 = private_keys[0] privatekey1 = private_keys[1] address0 = privatekey_to_address(privatekey0) address1 = privatekey_to_address(privatekey1) channel_manager = new_channelmanager( privatekey0, tester_state, tester_events.append, tester_registry, tester_token, ) nettingchannel = new_nettingcontract( privatekey0, privatekey1, tester_state, tester_events.append, channel_manager, settle_timeout, ) initial_balance0 = tester_token.balanceOf(address0, sender=privatekey0) deposit_amount = initial_balance0 // 10 assert tester_token.approve( nettingchannel.address, deposit_amount, sender=privatekey0) is True assert tester_token.approve( nettingchannel.address, deposit_amount, sender=privatekey1) is True previous_events = list(tester_events) assert nettingchannel.deposit(deposit_amount, sender=privatekey0) is True assert len(previous_events) + 2 == len(tester_events) block_number = tester_state.block.number transfer_event = tester_events[-2] assert transfer_event == { '_event_type': 'Transfer', '_from': encode_hex(address0), '_to': nettingchannel.address, '_value': deposit_amount, } newbalance_event = tester_events[-1] assert newbalance_event == { '_event_type': 'ChannelNewBalance', 'token_address': encode_hex(tester_token.address), 'participant': encode_hex(address0), 'balance': deposit_amount, 'block_number': block_number, } previous_events = list(tester_events) assert nettingchannel.deposit(deposit_amount, sender=privatekey1) is True assert len(previous_events) + 2 == len(tester_events) block_number = tester_state.block.number transfer_event = tester_events[-2] assert transfer_event == { '_event_type': 'Transfer', '_from': encode_hex(address1), '_to': nettingchannel.address, '_value': deposit_amount, } newbalance_event = tester_events[-1] assert newbalance_event == { '_event_type': 'ChannelNewBalance', 'token_address': encode_hex(tester_token.address), 'participant': encode_hex(address1), 'balance': deposit_amount, 'block_number': block_number, }
def geth_create_blockchain(private_keys, geth_private_keys, p2p_base_port, base_datadir, verbosity): # pylint: disable=too-many-locals,too-many-statements # TODO: handle better the errors cases: # - cant bind, port in use start_rpcport = 4000 account_addresses = [ privatekey_to_address(key) for key in set(private_keys) ] alloc = { address_encoder(address): { 'balance': DEFAULT_BALANCE_BIN, } for address in account_addresses } genesis = { 'config': { 'homesteadBlock': 0, }, 'nonce': '0x0000000000000042', 'mixhash': '0x0000000000000000000000000000000000000000000000000000000000000000', 'difficulty': '0x40', 'coinbase': '0x0000000000000000000000000000000000000000', 'timestamp': '0x00', 'parentHash': '0x0000000000000000000000000000000000000000000000000000000000000000', 'extraData': 'raiden', 'gasLimit': GAS_LIMIT_HEX, 'alloc': alloc, } nodes_configuration = [] for pos, key in enumerate(geth_private_keys): config = dict() # make the first node miner if pos == 0: config['minerthreads'] = 1 # conservative config['unlock'] = 0 config['nodekey'] = key config['nodekeyhex'] = encode_hex(key) config['pub'] = encode_hex(privtopub(key)) config['address'] = privatekey_to_address(key) config['port'] = p2p_base_port + pos config['rpcport'] = start_rpcport + pos config['enode'] = 'enode://{pub}@127.0.0.1:{port}'.format( pub=config['pub'], port=config['port'], ) config['bootnodes'] = ','.join(node['enode'] for node in nodes_configuration) nodes_configuration.append(config) cmds = [] for i, config in enumerate(nodes_configuration): nodedir = os.path.join(base_datadir, config['nodekeyhex']) os.makedirs(nodedir) geth_init_datadir(genesis, nodedir) if 'minerthreads' in config: geth_create_account(nodedir, private_keys[i]) commandline = geth_to_cmd(config, nodedir, verbosity) cmds.append(commandline) # save current term settings before running geth if isinstance(sys.stdin, file): # check that the test is running on non-capture mode term_settings = termios.tcgetattr(sys.stdin) processes_list = [] for cmd in cmds: if '--unlock' in cmd: process = subprocess.Popen(cmd, universal_newlines=True, stdin=subprocess.PIPE) # --password wont work, write password to unlock process.stdin.write(DEFAULT_PASSPHRASE + os.linesep) # Passphrase: process.stdin.write(DEFAULT_PASSPHRASE + os.linesep) # Repeat passphrase: else: process = subprocess.Popen(cmd) processes_list.append(process) assert process.returncode is None geth_wait_and_check(private_keys) # reenter echo mode (disabled by geth pasphrase prompt) if isinstance(sys.stdin, file): termios.tcsetattr(sys.stdin, termios.TCSADRAIN, term_settings) return processes_list
def int_to_0x_hex(v): o = encode_hex(int_to_big_endian(v)) if o and o[0] == '0': return '0x' + o[1:] else: return '0x' + o
def vm_execute(ext, msg, code): # precompute trace flag # if we trace vm, we're in slow mode anyway trace_vm = log_vm_op.is_active('trace') compustate = Compustate(gas=msg.gas) stk = compustate.stack mem = compustate.memory if code in code_cache: processed_code = code_cache[code] else: processed_code = preprocess_code(code) code_cache[code] = processed_code # print(processed_code.keys(), code) codelen = len(code) s = time.time() steps = 0 _prevop = None # for trace only while compustate.pc in processed_code: ops, minstack, maxstack, totgas, nextpos = processed_code[ compustate.pc] if len(compustate.stack) < minstack: return vm_exception('INSUFFICIENT STACK') if len(compustate.stack) > maxstack: return vm_exception('STACK SIZE LIMIT EXCEEDED') if totgas > compustate.gas: return vm_exception('OUT OF GAS %d %d' % (totgas, compustate.gas)) jumped = False compustate.gas -= totgas compustate.pc = nextpos # Invalid operation; can only come at the end of a chunk if ops[-1][0] == 'INVALID': return vm_exception('INVALID OP', opcode=ops[-1][1]) for op, opcode, pushval in ops: if trace_vm: """ This diverges from normal logging, as we use the logging namespace only to decide which features get logged in 'eth.vm.op' i.e. tracing can not be activated by activating a sub like 'eth.vm.op.stack' """ trace_data = {} trace_data['stack'] = list( map(to_string, list(compustate.stack))) if _prevop in ('MLOAD', 'MSTORE', 'MSTORE8', 'SHA3', 'CALL', 'CALLCODE', 'CREATE', 'CALLDATACOPY', 'CODECOPY', 'EXTCODECOPY'): if len(compustate.memory) < 1024: trace_data['memory'] = \ ''.join([encode_hex(ascii_chr(x)) for x in compustate.memory]) else: trace_data['sha3memory'] = \ encode_hex(utils.sha3(b''.join([ascii_chr(x) for x in compustate.memory]))) if _prevop in ('SSTORE', ) or steps == 0: trace_data['storage'] = ext.log_storage(msg.to) trace_data['gas'] = to_string(compustate.gas + totgas) trace_data['inst'] = opcode trace_data['pc'] = to_string(compustate.pc - 1) if steps == 0: trace_data['depth'] = msg.depth trace_data['address'] = msg.to trace_data['steps'] = steps trace_data['depth'] = msg.depth if op[:4] == 'PUSH': trace_data['pushvalue'] = pushval log_vm_op.trace('vm', op=op, **trace_data) steps += 1 _prevop = op # Valid operations # Pushes first because they are very frequent if 0x60 <= opcode <= 0x7f: # compustate.pc += opcode - 0x5f # Move 1 byte forward for # 0x60, up to 32 bytes for 0x7f stk.append(pushval) elif opcode < 0x10: if op == 'STOP': return peaceful_exit('STOP', compustate.gas, []) elif op == 'ADD': stk.append((stk.pop() + stk.pop()) & TT256M1) elif op == 'SUB': stk.append((stk.pop() - stk.pop()) & TT256M1) elif op == 'MUL': stk.append((stk.pop() * stk.pop()) & TT256M1) elif op == 'DIV': s0, s1 = stk.pop(), stk.pop() stk.append(0 if s1 == 0 else s0 // s1) elif op == 'MOD': s0, s1 = stk.pop(), stk.pop() stk.append(0 if s1 == 0 else s0 % s1) elif op == 'SDIV': s0, s1 = utils.to_signed(stk.pop()), utils.to_signed( stk.pop()) stk.append(0 if s1 == 0 else (abs(s0) // abs(s1) * (-1 if s0 * s1 < 0 else 1)) & TT256M1) elif op == 'SMOD': s0, s1 = utils.to_signed(stk.pop()), utils.to_signed( stk.pop()) stk.append(0 if s1 == 0 else (abs(s0) % abs(s1) * (-1 if s0 < 0 else 1)) & TT256M1) elif op == 'ADDMOD': s0, s1, s2 = stk.pop(), stk.pop(), stk.pop() stk.append((s0 + s1) % s2 if s2 else 0) elif op == 'MULMOD': s0, s1, s2 = stk.pop(), stk.pop(), stk.pop() stk.append((s0 * s1) % s2 if s2 else 0) elif op == 'EXP': base, exponent = stk.pop(), stk.pop() # fee for exponent is dependent on its bytes # calc n bytes to represent exponent nbytes = len(utils.encode_int(exponent)) expfee = nbytes * opcodes.GEXPONENTBYTE if ext.post_clearing_hardfork(): expfee += opcodes.EXP_SUPPLEMENTAL_GAS * nbytes if compustate.gas < expfee: compustate.gas = 0 return vm_exception('OOG EXPONENT') compustate.gas -= expfee stk.append(pow(base, exponent, TT256)) elif op == 'SIGNEXTEND': s0, s1 = stk.pop(), stk.pop() if s0 <= 31: testbit = s0 * 8 + 7 if s1 & (1 << testbit): stk.append(s1 | (TT256 - (1 << testbit))) else: stk.append(s1 & ((1 << testbit) - 1)) else: stk.append(s1) elif opcode < 0x20: if op == 'LT': stk.append(1 if stk.pop() < stk.pop() else 0) elif op == 'GT': stk.append(1 if stk.pop() > stk.pop() else 0) elif op == 'SLT': s0, s1 = utils.to_signed(stk.pop()), utils.to_signed( stk.pop()) stk.append(1 if s0 < s1 else 0) elif op == 'SGT': s0, s1 = utils.to_signed(stk.pop()), utils.to_signed( stk.pop()) stk.append(1 if s0 > s1 else 0) elif op == 'EQ': stk.append(1 if stk.pop() == stk.pop() else 0) elif op == 'ISZERO': stk.append(0 if stk.pop() else 1) elif op == 'AND': stk.append(stk.pop() & stk.pop()) elif op == 'OR': stk.append(stk.pop() | stk.pop()) elif op == 'XOR': stk.append(stk.pop() ^ stk.pop()) elif op == 'NOT': stk.append(TT256M1 - stk.pop()) elif op == 'BYTE': s0, s1 = stk.pop(), stk.pop() if s0 >= 32: stk.append(0) else: stk.append((s1 // 256**(31 - s0)) % 256) elif opcode < 0x40: if op == 'SHA3': s0, s1 = stk.pop(), stk.pop() compustate.gas -= opcodes.GSHA3WORD * \ (utils.ceil32(s1) // 32) if compustate.gas < 0: return vm_exception('OOG PAYING FOR SHA3') if not mem_extend(mem, compustate, op, s0, s1): return vm_exception('OOG EXTENDING MEMORY') data = bytearray_to_bytestr(mem[s0:s0 + s1]) stk.append(utils.big_endian_to_int(utils.sha3(data))) elif op == 'ADDRESS': stk.append(utils.coerce_to_int(msg.to)) elif op == 'BALANCE': if ext.post_anti_dos_hardfork(): if not eat_gas(compustate, opcodes.BALANCE_SUPPLEMENTAL_GAS): return vm_exception("OUT OF GAS") addr = utils.coerce_addr_to_hex(stk.pop() % 2**160) stk.append(ext.get_balance(addr)) elif op == 'ORIGIN': stk.append(utils.coerce_to_int(ext.tx_origin)) elif op == 'CALLER': stk.append(utils.coerce_to_int(msg.sender)) elif op == 'CALLVALUE': stk.append(msg.value) elif op == 'CALLDATALOAD': stk.append(msg.data.extract32(stk.pop())) elif op == 'CALLDATASIZE': stk.append(msg.data.size) elif op == 'CALLDATACOPY': mstart, dstart, size = stk.pop(), stk.pop(), stk.pop() if not mem_extend(mem, compustate, op, mstart, size): return vm_exception('OOG EXTENDING MEMORY') if not data_copy(compustate, size): return vm_exception('OOG COPY DATA') msg.data.extract_copy(mem, mstart, dstart, size) elif op == 'CODESIZE': stk.append(len(code)) elif op == 'CODECOPY': mstart, dstart, size = stk.pop(), stk.pop(), stk.pop() if not mem_extend(mem, compustate, op, mstart, size): return vm_exception('OOG EXTENDING MEMORY') if not data_copy(compustate, size): return vm_exception('OOG COPY DATA') for i in range(size): if dstart + i < len(code): mem[mstart + i] = utils.safe_ord(code[dstart + i]) else: mem[mstart + i] = 0 elif op == 'RETURNDATACOPY': mstart, dstart, size = stk.pop(), stk.pop(), stk.pop() if not mem_extend(mem, compustate, op, mstart, size): return vm_exception('OOG EXTENDING MEMORY') if not data_copy(compustate, size): return vm_exception('OOG COPY DATA') if dstart + size > len(compustate.last_returned): return vm_exception('RETURNDATACOPY out of range') mem[mstart:mstart + size] = compustate.last_returned elif op == 'RETURNDATASIZE': stk.append(len(compustate.last_returned)) elif op == 'GASPRICE': stk.append(ext.tx_gasprice) elif op == 'EXTCODESIZE': if ext.post_anti_dos_hardfork(): if not eat_gas(compustate, opcodes.EXTCODELOAD_SUPPLEMENTAL_GAS): return vm_exception("OUT OF GAS") addr = utils.coerce_addr_to_hex(stk.pop() % 2**160) stk.append(len(ext.get_code(addr) or b'')) elif op == 'EXTCODECOPY': if ext.post_anti_dos_hardfork(): if not eat_gas(compustate, opcodes.EXTCODELOAD_SUPPLEMENTAL_GAS): return vm_exception("OUT OF GAS") addr = utils.coerce_addr_to_hex(stk.pop() % 2**160) start, s2, size = stk.pop(), stk.pop(), stk.pop() extcode = ext.get_code(addr) or b'' assert utils.is_string(extcode) if not mem_extend(mem, compustate, op, start, size): return vm_exception('OOG EXTENDING MEMORY') if not data_copy(compustate, size): return vm_exception('OOG COPY DATA') for i in range(size): if s2 + i < len(extcode): mem[start + i] = utils.safe_ord(extcode[s2 + i]) else: mem[start + i] = 0 elif opcode < 0x50: if op == 'BLOCKHASH': if ext.post_metropolis_hardfork() and False: bh_addr = ext.blockhash_store stk.append(ext.get_storage_data(bh_addr, stk.pop())) else: stk.append( utils.big_endian_to_int(ext.block_hash(stk.pop()))) elif op == 'COINBASE': stk.append(utils.big_endian_to_int(ext.block_coinbase)) elif op == 'TIMESTAMP': stk.append(ext.block_timestamp) elif op == 'NUMBER': stk.append(ext.block_number) elif op == 'DIFFICULTY': stk.append(ext.block_difficulty) elif op == 'GASLIMIT': stk.append(ext.block_gas_limit) elif opcode < 0x60: if op == 'POP': stk.pop() elif op == 'MLOAD': s0 = stk.pop() if not mem_extend(mem, compustate, op, s0, 32): return vm_exception('OOG EXTENDING MEMORY') stk.append(utils.bytes_to_int(mem[s0:s0 + 32])) elif op == 'MSTORE': s0, s1 = stk.pop(), stk.pop() if not mem_extend(mem, compustate, op, s0, 32): return vm_exception('OOG EXTENDING MEMORY') mem[s0:s0 + 32] = utils.encode_int32(s1) elif op == 'MSTORE8': s0, s1 = stk.pop(), stk.pop() if not mem_extend(mem, compustate, op, s0, 1): return vm_exception('OOG EXTENDING MEMORY') mem[s0] = s1 % 256 elif op == 'SLOAD': if ext.post_anti_dos_hardfork(): if not eat_gas(compustate, opcodes.SLOAD_SUPPLEMENTAL_GAS): return vm_exception("OUT OF GAS") stk.append(ext.get_storage_data(msg.to, stk.pop())) elif op == 'SSTORE': s0, s1 = stk.pop(), stk.pop() if msg.static: return vm_exception( 'Cannot SSTORE inside a static context') if ext.get_storage_data(msg.to, s0): gascost = opcodes.GSTORAGEMOD if s1 else opcodes.GSTORAGEKILL refund = 0 if s1 else opcodes.GSTORAGEREFUND else: gascost = opcodes.GSTORAGEADD if s1 else opcodes.GSTORAGEMOD refund = 0 if compustate.gas < gascost: return vm_exception('OUT OF GAS') compustate.gas -= gascost # adds neg gascost as a refund if below zero ext.add_refund(refund) ext.set_storage_data(msg.to, s0, s1) elif op == 'JUMP': compustate.pc = stk.pop() opnew = code[ compustate.pc] if compustate.pc < codelen else 0 jumped = True if opnew != JUMPDEST: return vm_exception('BAD JUMPDEST') elif op == 'JUMPI': s0, s1 = stk.pop(), stk.pop() if s1: compustate.pc = s0 opnew = code[ compustate.pc] if compustate.pc < codelen else 0 jumped = True if opnew != JUMPDEST: return vm_exception('BAD JUMPDEST') elif op == 'PC': stk.append(compustate.pc - 1) elif op == 'MSIZE': stk.append(len(mem)) elif op == 'GAS': stk.append(compustate.gas) # AFTER subtracting cost 1 elif op[:3] == 'DUP': # 0x7f - opcode is a negative number, -1 for 0x80 ... -16 for # 0x8f stk.append(stk[0x7f - opcode]) elif op[:4] == 'SWAP': # 0x8e - opcode is a negative number, -2 for 0x90 ... -17 for # 0x9f temp = stk[0x8e - opcode] stk[0x8e - opcode] = stk[-1] stk[-1] = temp elif op[:3] == 'LOG': """ 0xa0 ... 0xa4, 32/64/96/128/160 + len(data) gas a. Opcodes LOG0...LOG4 are added, takes 2-6 stack arguments MEMSTART MEMSZ (TOPIC1) (TOPIC2) (TOPIC3) (TOPIC4) b. Logs are kept track of during tx execution exactly the same way as suicides (except as an ordered list, not a set). Each log is in the form [address, [topic1, ... ], data] where: * address is what the ADDRESS opcode would output * data is mem[MEMSTART: MEMSTART + MEMSZ] * topics are as provided by the opcode c. The ordered list of logs in the transaction are expressed as [log0, log1, ..., logN]. """ depth = int(op[3:]) mstart, msz = stk.pop(), stk.pop() topics = [stk.pop() for x in range(depth)] compustate.gas -= msz * opcodes.GLOGBYTE if msg.static: return vm_exception('Cannot LOG inside a static context') if not mem_extend(mem, compustate, op, mstart, msz): return vm_exception('OOG EXTENDING MEMORY') data = bytearray_to_bytestr(mem[mstart:mstart + msz]) ext.log(msg.to, topics, data) log_log.trace('LOG', to=msg.to, topics=topics, data=list(map(utils.safe_ord, data))) # print('LOG', msg.to, topics, list(map(ord, data))) elif op == 'CREATE': value, mstart, msz = stk.pop(), stk.pop(), stk.pop() if not mem_extend(mem, compustate, op, mstart, msz): return vm_exception('OOG EXTENDING MEMORY') if msg.static: return vm_exception( 'Cannot CREATE inside a static context') if ext.get_balance(msg.to) >= value and msg.depth < MAX_DEPTH: cd = CallData(mem, mstart, msz) ingas = compustate.gas if ext.post_anti_dos_hardfork(): ingas = all_but_1n(ingas, opcodes.CALL_CHILD_LIMIT_DENOM) create_msg = Message(msg.to, b'', value, ingas, cd, msg.depth + 1) o, gas, addr = ext.create(create_msg) if o: stk.append(utils.coerce_to_int(addr)) else: stk.append(0) compustate.gas = compustate.gas - ingas + gas else: stk.append(0) elif op in ('CALL', 'CALLCODE', 'DELEGATECALL', 'STATICCALL'): # Pull arguments from the stack if op in ('CALL', 'CALLCODE'): gas, to, value, meminstart, meminsz, memoutstart, memoutsz = \ stk.pop(), stk.pop(), stk.pop(), stk.pop(), stk.pop(), stk.pop(), stk.pop() else: gas, to, meminstart, meminsz, memoutstart, memoutsz = \ stk.pop(), stk.pop(), stk.pop(), stk.pop(), stk.pop(), stk.pop() value = 0 # Static context prohibition if msg.static and value > 0: return vm_exception( 'Cannot make a non-zero-value call inside a static context' ) # Expand memory if not mem_extend(mem, compustate, op, meminstart, meminsz) or \ not mem_extend(mem, compustate, op, memoutstart, memoutsz): return vm_exception('OOG EXTENDING MEMORY') to = utils.int_to_addr(to) # Extra gas costs based on hard fork-dependent factors extra_gas = (not ext.account_exists(to)) * (op == 'CALL') * (value > 0 or not ext.post_clearing_hardfork()) * opcodes.GCALLNEWACCOUNT + \ (value > 0) * opcodes.GCALLVALUETRANSFER + \ ext.post_anti_dos_hardfork() * opcodes.CALL_SUPPLEMENTAL_GAS # Compute child gas limit if ext.post_anti_dos_hardfork(): if compustate.gas < extra_gas: return vm_exception('OUT OF GAS', needed=extra_gas) gas = min( gas, all_but_1n(compustate.gas - extra_gas, opcodes.CALL_CHILD_LIMIT_DENOM)) else: if compustate.gas < gas + extra_gas: return vm_exception('OUT OF GAS', needed=gas + extra_gas) submsg_gas = gas + opcodes.GSTIPEND * (value > 0) # Verify that there is sufficient balance and depth if ext.get_balance(msg.to) < value or msg.depth >= MAX_DEPTH: compustate.gas -= (gas + extra_gas - submsg_gas) stk.append(0) else: # Subtract gas from parent compustate.gas -= (gas + extra_gas) assert compustate.gas >= 0 cd = CallData(mem, meminstart, meminsz) # Generate the message if op == 'CALL': call_msg = Message(msg.to, to, value, submsg_gas, cd, msg.depth + 1, code_address=to, static=msg.static) elif ext.post_homestead_hardfork( ) and op == 'DELEGATECALL': call_msg = Message(msg.sender, msg.to, msg.value, submsg_gas, cd, msg.depth + 1, code_address=to, transfers_value=False, static=msg.static) elif op == 'DELEGATECALL': return vm_exception('OPCODE INACTIVE') elif op == 'CALLCODE': call_msg = Message(msg.to, msg.to, value, submsg_gas, cd, msg.depth + 1, code_address=to, static=msg.static) elif op == 'STATICCALL': call_msg = Message(msg.to, to, value, submsg_gas, cd, msg.depth + 1, code_address=to, static=True) else: raise Exception("Lolwut") # Get result result, gas, data = ext.msg(call_msg) if result == 0: stk.append(0) else: stk.append(1) # Set output memory for i in range(min(len(data), memoutsz)): mem[memoutstart + i] = data[i] compustate.gas += gas compustate.last_returned = bytearray(data) elif op == 'RETURN': s0, s1 = stk.pop(), stk.pop() if not mem_extend(mem, compustate, op, s0, s1): return vm_exception('OOG EXTENDING MEMORY') return peaceful_exit('RETURN', compustate.gas, mem[s0:s0 + s1]) elif op == 'REVERT': if not ext.post_metropolis_hardfork(): return vm_exception('Opcode not yet enabled') s0, s1 = stk.pop(), stk.pop() if not mem_extend(mem, compustate, op, s0, s1): return vm_exception('OOG EXTENDING MEMORY') return revert(compustate.gas, mem[s0:s0 + s1]) elif op == 'SUICIDE': if msg.static: return vm_exception( 'Cannot SUICIDE inside a static context') to = utils.encode_int(stk.pop()) to = ((b'\x00' * (32 - len(to))) + to)[12:] xfer = ext.get_balance(msg.to) if ext.post_anti_dos_hardfork(): extra_gas = opcodes.SUICIDE_SUPPLEMENTAL_GAS + \ (not ext.account_exists( to)) * (xfer > 0 or not ext.post_clearing_hardfork()) * opcodes.GCALLNEWACCOUNT if not eat_gas(compustate, extra_gas): return vm_exception("OUT OF GAS") ext.set_balance(to, ext.get_balance(to) + xfer) ext.set_balance(msg.to, 0) ext.add_suicide(msg.to) log_msg.debug('SUICIDING', addr=utils.checksum_encode(msg.to), to=utils.checksum_encode(to), xferring=xfer) return 1, compustate.gas, [] # assert utils.is_numeric(compustate.gas) # this is slow! # for a in stk: # assert is_numeric(a), (op, stk) # assert a >= 0 and a < 2**256, (a, op, stk) # if not jumped: # assert compustate.pc == nextpos # compustate.pc = nextpos if compustate.pc >= codelen: return peaceful_exit('CODE OUT OF RANGE', compustate.gas, []) return vm_exception('INVALID JUMP')
def test_netting(deposit, settle_timeout, tester_channels, tester_state, tester_events, tester_token): """ This test ensures that Alice can send payments to Bob exceeding her initial deposit. A.sent > A.deposit the condition for this to work is that Bob has also sent payments to Alice in the meantime, so that B.sent >= (A.sent - A.deposit) A sample use case: A.deposit = 10 B.deposit = 10 A.send(10) # at this point Alice's deposit is exhausted A.send(5) --> fail B.send(5) # this replenishes the available tokens for Alice A.send(5) # is now possible """ privatekey0_raw, privatekey1_raw, nettingchannel, channel0, channel1 = tester_channels[ 0] privatekey0 = PrivateKey(privatekey0_raw, ctx=GLOBAL_CTX, raw=True) privatekey1 = PrivateKey(privatekey1_raw, ctx=GLOBAL_CTX, raw=True) address0 = privatekey_to_address(privatekey0_raw) address1 = privatekey_to_address(privatekey1_raw) unknown_key = tester.k3 initial_balance0 = tester_token.balanceOf(address0, sender=privatekey0_raw) initial_balance1 = tester_token.balanceOf(address1, sender=privatekey1_raw) transfer_amount0 = deposit first_direct_transfer0 = channel0.create_directtransfer( transfer_amount0, 1 # TODO: fill in identifier ) # at this point address0 deposit is exhausted first_direct_transfer0.sign(privatekey0, address0) first_direct_transfer0_data = str(first_direct_transfer0.packed().data) channel0.register_transfer(first_direct_transfer0) channel1.register_transfer(first_direct_transfer0) transfer_amount_failed = 5 with pytest.raises(ValueError): second_direct_transfer0 = channel0.create_directtransfer( transfer_amount_failed, 1 # TODO: fill in identifier ) # This will raise Insufficient funds Value error transfer_amount1 = 30 direct_transfer1 = channel1.create_directtransfer( transfer_amount1, 1 # TODO: fill in identifier ) # Replenishes tokens in the address0 direct_transfer1.sign(privatekey1, address1) direct_transfer1_data = str(direct_transfer1.packed().data) channel0.register_transfer(direct_transfer1) channel1.register_transfer(direct_transfer1) second_transfer_amount0 = 5 second_direct_transfer0 = channel0.create_directtransfer( second_transfer_amount0, 1 # TODO: fill in identifier ) second_direct_transfer0.sign(privatekey0, address0) second_direct_transfer0_data = str(second_direct_transfer0.packed().data) channel0.register_transfer(second_direct_transfer0) channel1.register_transfer(second_direct_transfer0) previous_events = list(tester_events) nettingchannel.close( second_direct_transfer0_data, sender=privatekey1_raw, ) assert len(previous_events) + 1 == len(tester_events) block_number = tester_state.block.number close_event = tester_events[-1] assert close_event == { '_event_type': 'ChannelClosed', 'closing_address': encode_hex(address1), 'block_number': block_number, } nettingchannel.updateTransfer( direct_transfer1_data, sender=privatekey0_raw, ) assert nettingchannel.closed(sender=privatekey0_raw) == block_number assert nettingchannel.closingAddress( sender=privatekey0_raw) == encode_hex(address1) tester_state.mine(number_of_blocks=settle_timeout + 1) previous_events = list(tester_events) nettingchannel.settle(sender=privatekey0_raw) assert len(previous_events) + 3 == len(tester_events) block_number = tester_state.block.number transfer0_event = tester_events[-3] assert transfer0_event == { '_event_type': 'Transfer', '_from': nettingchannel.address, '_to': encode_hex(address0), '_value': deposit - transfer_amount0 - second_transfer_amount0 + transfer_amount1, } transfer1_event = tester_events[-2] assert transfer1_event == { '_event_type': 'Transfer', '_from': nettingchannel.address, '_to': encode_hex(address1), '_value': deposit + transfer_amount0 + second_transfer_amount0 - transfer_amount1, } settle_event = tester_events[-1] assert settle_event == { '_event_type': 'ChannelSettled', 'block_number': block_number, } assert tester_token.balanceOf( address0, sender=privatekey0_raw) == (initial_balance0 + deposit - transfer_amount0 - second_transfer_amount0 + +transfer_amount1) assert tester_token.balanceOf( address1, sender=privatekey1_raw) == (initial_balance1 + deposit + transfer_amount0 + second_transfer_amount0 - transfer_amount1) assert tester_token.balanceOf(nettingchannel.address, sender=privatekey1_raw) == 0
def encode_node(nd): if is_string(nd): return encode_hex(nd) else: return encode_hex(rlp_encode(nd))
def test_two_messages_mediated_transfer(deposit, settle_timeout, tester_state, tester_channels, tester_token, tester_events): privatekey0_raw, privatekey1_raw, nettingchannel, channel0, channel1 = tester_channels[ 0] privatekey0 = PrivateKey(privatekey0_raw, ctx=GLOBAL_CTX, raw=True) privatekey1 = PrivateKey(privatekey1_raw, ctx=GLOBAL_CTX, raw=True) address0 = privatekey_to_address(privatekey0_raw) address1 = privatekey_to_address(privatekey1_raw) unknow_key = tester.k3 initial_balance0 = tester_token.balanceOf(address0, sender=privatekey0_raw) initial_balance1 = tester_token.balanceOf(address1, sender=privatekey1_raw) lock_amount0 = 29 lock_expiration0 = tester_state.block.number + DEFAULT_REVEAL_TIMEOUT + 3 hashlock0 = sha3(tester.k0) mediated_transfer0 = channel0.create_mediatedtransfer( transfer_initiator=address0, transfer_target=address1, fee=0, amount=lock_amount0, identifier=1, # TODO: fill in identifier expiration=lock_expiration0, hashlock=hashlock0, ) mediated_transfer0.sign(privatekey0, address0) lock_amount1 = 29 lock_expiration1 = tester_state.block.number + DEFAULT_REVEAL_TIMEOUT + 5 hashlock1 = sha3(tester.k1) mediated_transfer1 = channel1.create_mediatedtransfer( transfer_initiator=address1, transfer_target=address0, fee=0, amount=lock_amount1, identifier=1, # TODO: fill in identifier expiration=lock_expiration1, hashlock=hashlock1, ) mediated_transfer1.sign(privatekey1, address1) with pytest.raises(TransactionFailed): nettingchannel.close( str(mediated_transfer0.packed().data), str(mediated_transfer1.packed().data), sender=unknow_key, ) previous_events = list(tester_events) nettingchannel.close( str(mediated_transfer0.packed().data), str(mediated_transfer1.packed().data), sender=privatekey0_raw, ) assert len(previous_events) + 1 == len(tester_events) block_number = tester_state.block.number close_event = tester_events[-1] assert close_event == { '_event_type': 'ChannelClosed', 'closingAddress': encode_hex(address0), 'blockNumber': block_number, } assert nettingchannel.closed(sender=privatekey0_raw) == block_number assert nettingchannel.closingAddress( sender=privatekey0_raw) == encode_hex(address0) tester_state.mine(number_of_blocks=settle_timeout + 1) previous_events = list(tester_events) nettingchannel.settle(sender=privatekey0_raw) block_number = tester_state.block.number assert len(previous_events) + 3 == len(tester_events) transfer0_event = tester_events[-3] assert transfer0_event == { '_event_type': 'Transfer', '_from': nettingchannel.address, '_to': encode_hex(address0), '_value': deposit, } transfer1_event = tester_events[-2] assert transfer1_event == { '_event_type': 'Transfer', '_from': nettingchannel.address, '_to': encode_hex(address1), '_value': deposit, } settle_event = tester_events[-1] assert settle_event == { '_event_type': 'ChannelSettled', 'blockNumber': block_number, } assert tester_token.balanceOf( address0, sender=privatekey0_raw) == initial_balance0 + deposit # noqa assert tester_token.balanceOf( address1, sender=privatekey1_raw) == initial_balance1 + deposit # noqa assert tester_token.balanceOf(nettingchannel.address, sender=privatekey1_raw) == 0
def test_channeldeposit(private_keys, settle_timeout, tester_state, tester_token, tester_events, tester_registry): """ Guarantee the correct tracking of each participant deposits, checks the initial state (pre-deposit) and state changes for each deposits. """ # not using the tester_nettingcontracts fixture to control the # transfer/deposits privatekey0 = private_keys[0] privatekey1 = private_keys[1] address0 = privatekey_to_address(privatekey0) address1 = privatekey_to_address(privatekey1) unknow_key = tester.k3 channel_manager = new_channelmanager( privatekey0, tester_state, tester_events.append, tester_registry, tester_token, ) channel = new_nettingcontract( privatekey0, privatekey1, tester_state, tester_events.append, channel_manager, settle_timeout, ) # check initial state, needs to be zeroed out assert channel.settleTimeout(sender=privatekey0) == settle_timeout assert channel.tokenAddress(sender=privatekey0) == encode_hex( tester_token.address) assert channel.opened(sender=privatekey0) == 0 assert channel.closed(sender=privatekey0) == 0 assert channel.settled(sender=privatekey0) == 0 assert channel.addressAndBalance( sender=privatekey0)[0] == encode_hex(address0) assert channel.addressAndBalance(sender=privatekey0)[1] == 0 assert channel.addressAndBalance( sender=privatekey0)[2] == encode_hex(address1) assert channel.addressAndBalance(sender=privatekey0)[3] == 0 initial_balance0 = tester_token.balanceOf(address0, sender=privatekey0) deposit_amount = initial_balance0 // 10 # try to make invalid deposits with pytest.raises(TransactionFailed): channel.deposit(1, sender=unknow_key) # not participant assert tester_token.approve( channel.address, deposit_amount * 2, sender=privatekey0) is True assert channel.deposit(deposit_amount * 2 + 1, sender=privatekey0) is False with pytest.raises(abi.ValueOutOfBounds): channel.deposit(-1, sender=privatekey0) # create a first deposit with half of the allowance assert channel.deposit(deposit_amount, sender=privatekey0) is True assert tester_token.balanceOf(channel.address, sender=privatekey0) == deposit_amount assert tester_token.balanceOf( address0, sender=privatekey0) == initial_balance0 - deposit_amount # noqa assert channel.opened(sender=privatekey0) == tester_state.block.number assert channel.addressAndBalance( sender=privatekey0)[0] == encode_hex(address0) assert channel.addressAndBalance(sender=privatekey0)[1] == deposit_amount assert channel.addressAndBalance( sender=privatekey0)[2] == encode_hex(address1) assert channel.addressAndBalance(sender=privatekey0)[3] == 0 # check a second depoist with the rest of the allowance assert channel.deposit(deposit_amount, sender=privatekey0) is True assert tester_token.balanceOf(channel.address, sender=privatekey0) == deposit_amount * 2 assert tester_token.balanceOf( address0, sender=privatekey0) == initial_balance0 - deposit_amount * 2 # noqa assert channel.opened(sender=privatekey0) == tester_state.block.number assert channel.addressAndBalance( sender=privatekey0)[0] == encode_hex(address0) assert channel.addressAndBalance( sender=privatekey0)[1] == deposit_amount * 2 assert channel.addressAndBalance( sender=privatekey0)[2] == encode_hex(address1) assert channel.addressAndBalance(sender=privatekey0)[3] == 0 # allowance zeroed, we cant make a new deposit assert channel.deposit(deposit_amount, sender=privatekey0) is False # needs to be able to add aditional token assert tester_token.approve( channel.address, deposit_amount, sender=privatekey0) is True assert channel.deposit(deposit_amount, sender=privatekey0) is True assert tester_token.balanceOf(channel.address, sender=privatekey0) == deposit_amount * 3 assert tester_token.balanceOf( address0, sender=privatekey0) == initial_balance0 - deposit_amount * 3 # noqa assert channel.opened(sender=privatekey0) == tester_state.block.number assert channel.addressAndBalance( sender=privatekey0)[0] == encode_hex(address0) assert channel.addressAndBalance( sender=privatekey0)[1] == deposit_amount * 3 assert channel.addressAndBalance( sender=privatekey0)[2] == encode_hex(address1) assert channel.addressAndBalance(sender=privatekey0)[3] == 0
def print_address(name, address): print('Deployed {:25}: 0x{}'.format(name, utils.encode_hex(address)))
def test_closewithouttransfer_settle(deposit, settle_timeout, tester_state, tester_events, tester_nettingcontracts, tester_token): privatekey0, privatekey1, nettingchannel = tester_nettingcontracts[0] address0 = privatekey_to_address(privatekey0) address1 = privatekey_to_address(privatekey1) unknown_key = tester.k3 initial_balance0 = tester_token.balanceOf(address0, sender=privatekey0) initial_balance1 = tester_token.balanceOf(address1, sender=privatekey1) with pytest.raises(TransactionFailed): nettingchannel.close(sender=unknown_key) previous_events = list(tester_events) nettingchannel.close('', sender=privatekey0) assert len(previous_events) + 1 == len(tester_events) block_number = tester_state.block.number close_event = tester_events[-1] assert close_event == { '_event_type': 'ChannelClosed', 'closing_address': encode_hex(address0), 'block_number': block_number, } assert nettingchannel.closed(sender=privatekey0) == block_number assert nettingchannel.closingAddress( sender=privatekey0) == encode_hex(address0) tester_state.mine(number_of_blocks=settle_timeout + 1) previous_events = list(tester_events) # Anyone can call settle(), not just channel participants nettingchannel.settle(sender=unknown_key) block_number = tester_state.block.number assert len(previous_events) + 3 == len(tester_events) transfer0_event = tester_events[-3] assert transfer0_event == { '_event_type': 'Transfer', '_from': nettingchannel.address, '_to': encode_hex(address1), '_value': deposit, } transfer1_event = tester_events[-2] assert transfer1_event == { '_event_type': 'Transfer', '_from': nettingchannel.address, '_to': encode_hex(address0), '_value': deposit, } settle_event = tester_events[-1] assert settle_event == { '_event_type': 'ChannelSettled', 'block_number': block_number, } assert tester_token.balanceOf( address0, sender=privatekey0) == initial_balance0 + deposit assert tester_token.balanceOf( address1, sender=privatekey1) == initial_balance1 + deposit assert tester_token.balanceOf(nettingchannel.address, sender=privatekey1) == 0
def patch_send_transaction(client, nonce_offset=0): """Check if the remote supports pyethapp's extended jsonrpc spec for local tx signing. If not, replace the `send_transaction` method with a more generic one. """ patch_necessary = False try: client.call('eth_nonce', encode_hex(client.sender), 'pending') except: patch_necessary = True client.last_nonce_update = 0 client.current_nonce = None client.nonce_lock = Semaphore() def send_transaction(sender, to, value=0, data='', startgas=GAS_LIMIT, gasprice=GAS_PRICE, nonce=None): """Custom implementation for `pyethapp.rpc_client.JSONRPCClient.send_transaction`. This is necessary to support other remotes that don't support pyethapp's extended specs. @see https://github.com/ethereum/pyethapp/blob/develop/pyethapp/rpc_client.py#L359 """ def get_nonce(): """Eventually syncing nonce counter. This will keep a local nonce counter that is only syncing against the remote every `UPDATE_INTERVAL`. If the remote counter is lower than the current local counter, it will wait for the remote to catch up. """ with client.nonce_lock: UPDATE_INTERVAL = 5. query_time = now() needs_update = abs(query_time - client.last_nonce_update) > UPDATE_INTERVAL not_initialized = client.current_nonce is None if needs_update or not_initialized: nonce = _query_nonce() # we may have hammered the server and not all tx are # registered as `pending` yet while nonce < client.current_nonce: log.debug( "nonce on server too low; retrying", server=nonce, local=client.current_nonce ) nonce = _query_nonce() query_time = now() client.current_nonce = nonce client.last_nonce_update = query_time else: client.current_nonce += 1 return client.current_nonce def _query_nonce(): pending_transactions_hex = client.call( 'eth_getTransactionCount', address_encoder(sender), 'pending', ) pending_transactions = int(pending_transactions_hex, 16) nonce = pending_transactions + nonce_offset return nonce nonce = get_nonce() tx = Transaction(nonce, gasprice, startgas, to, value, data) assert hasattr(client, 'privkey') and client.privkey tx.sign(client.privkey) result = client.call( 'eth_sendRawTransaction', data_encoder(rlp.encode(tx)), ) return result[2 if result.startswith('0x') else 0:] if patch_necessary: client.send_transaction = send_transaction