def state_from_genesis_declaration(genesis_data, env, block=None, allow_empties=False): if block: assert isinstance(block, Block) else: block = block_from_genesis_declaration(genesis_data, env) state = State(env=env) for addr, data in genesis_data["alloc"].items(): addr = normalize_address(addr) assert len(addr) == 20 if 'wei' in data: state.set_balance(addr, parse_as_int(data['wei'])) if 'balance' in data: state.set_balance(addr, parse_as_int(data['balance'])) if 'code' in data: state.set_code(addr, parse_as_bin(data['code'])) if 'nonce' in data: state.set_nonce(addr, parse_as_int(data['nonce'])) if 'storage' in data: for k, v in data['storage'].items(): state.set_storage_data(addr, big_endian_to_int(parse_as_bin(k)), big_endian_to_int(parse_as_bin(v))) get_consensus_strategy(state.config).initialize(state, block) state.commit(allow_empties=allow_empties) print('deleting %d' % len(state.deletes)) rdb = RefcountDB(state.db) for delete in state.deletes: rdb.delete(delete) block.header.state_root = state.trie.root_hash state.prev_headers=[block.header] return state
def get_receipt_from_jsonrpc(response): if MODULE_DEBUG: print(response) assert response['jsonrpc'] == '2.0' assert 'id' in response assert 'result' in response receipt = response['result'] logs = [] for log in receipt['logs']: topics = [decode_int_from_hex(x) for x in log['topics']] logs.append(messages.Log( address = utils.normalize_address(log['address']), topics = topics, data = utils.decode_hex(log['data']))) # pre Byzantium returns a root if 'root' in receipt: return messages.Receipt( state_root = normalize_bytes(receipt['root']), gas_used = utils.parse_as_int(receipt['cumulativeGasUsed']), bloom = utils.parse_as_int(receipt['logsBloom']), logs = logs) receipt = messages.Receipt( state_root = (b'\x01' if receipt['status'] else b''), gas_used = utils.parse_as_int(receipt['cumulativeGasUsed']), bloom = utils.parse_as_int(receipt['logsBloom']), logs = logs) if MODULE_DEBUG: print("Rlp encoded receipt:") print(rec_hex(rlp.encode(receipt))) return receipt
def block_header(block_dict: dict): b = block.BlockHeader( normalize_bytes(block_dict["parentHash"]), normalize_bytes(block_dict["sha3Uncles"]), utils.normalize_address(block_dict["miner"]), normalize_bytes(block_dict["stateRoot"]), normalize_bytes(block_dict["transactionsRoot"]), normalize_bytes(block_dict["receiptsRoot"]), utils.bytes_to_int(normalize_bytes(block_dict["logsBloom"])), utils.parse_as_int(block_dict['difficulty']), utils.parse_as_int(block_dict['number']), utils.parse_as_int(block_dict['gasLimit']), utils.parse_as_int(block_dict['gasUsed']), utils.parse_as_int(block_dict['timestamp']), normalize_bytes(block_dict["extraData"]), normalize_bytes(block_dict["mixHash"]), normalize_bytes(block_dict["nonce"]), ) if normalize_bytes(block_dict["hash"]) != b.hash: raise ValueError( """Blockhash does not match. Received invalid block header? {} vs {}""".format( str(normalize_bytes(block_dict["hash"])), str(b.hash))) return b
def dict_to_prev_header(h): return FakeHeader(hash=parse_as_bin(h['hash']), number=parse_as_int(h['number']), timestamp=parse_as_int(h['timestamp']), difficulty=parse_as_int(h['difficulty']), gas_used=parse_as_int(h.get('gas_used', '0')), gas_limit=parse_as_int(h['gas_limit']), uncles_hash=parse_as_bin(h.get('uncles_hash', '0x' + encode_hex(BLANK_UNCLES_HASH))))
def from_snapshot(cls, snapshot_data, env, executing_on_head=False): state = State(env=env) if "alloc" in snapshot_data: for addr, data in snapshot_data["alloc"].items(): if len(addr) == 40: addr = decode_hex(addr) assert len(addr) == 20 if 'wei' in data: state.set_balance(addr, parse_as_int(data['wei'])) if 'balance' in data: state.set_balance(addr, parse_as_int(data['balance'])) if 'code' in data: state.set_code(addr, parse_as_bin(data['code'])) if 'nonce' in data: state.set_nonce(addr, parse_as_int(data['nonce'])) if 'storage' in data: for k, v in data['storage'].items(): state.set_storage_data( addr, big_endian_to_int(parse_as_bin(k)), big_endian_to_int(parse_as_bin(v))) elif "state_root" in snapshot_data: state.trie.root_hash = parse_as_bin(snapshot_data["state_root"]) else: raise Exception( "Must specify either alloc or state root parameter") for k, default in STATE_DEFAULTS.items(): default = copy.copy(default) v = snapshot_data[k] if k in snapshot_data else None if is_numeric(default): setattr(state, k, parse_as_int(v) if k in snapshot_data else default) elif is_string(default): setattr(state, k, parse_as_bin(v) if k in snapshot_data else default) elif k == 'prev_headers': if k in snapshot_data: headers = [dict_to_prev_header(h) for h in v] else: headers = default setattr(state, k, headers) elif k == 'recent_uncles': if k in snapshot_data: uncles = {} for height, _uncles in v.items(): uncles[int(height)] = [] for uncle in _uncles: uncles[int(height)].append(parse_as_bin(uncle)) else: uncles = default setattr(state, k, uncles) if executing_on_head: state.executing_on_head = True state.commit() state.changed = {} return state
def help_test_entire_block(self, path_to_jsonrpc_response): PRESENT = self.verifier_contract.TX_PROOF_RESULT_PRESENT() ABSENT = self.verifier_contract.TX_PROOF_RESULT_ABSENT() with open(path_to_jsonrpc_response, 'r') as f: jsonrpc = json.load(f) block_dict = jsonrpc['result'] for i in range(len(block_dict['transactions']) + 20): proof_blob = proveth.generate_proof_blob_from_jsonrpc_response( jsonrpc, i) result, index, nonce, gas_price, gas, to, value, data, v, r, s, contract_creation = self.verifier_contract.txProof( utils.decode_hex(block_dict['hash']), proof_blob, startgas=10**7) print(i) present = i < len(block_dict['transactions']) self.assertEqual(result, PRESENT if present else ABSENT) self.assertEqual(index, i) if present: self.assertEqual( nonce, utils.parse_as_int(block_dict['transactions'][i]['nonce'])) self.assertEqual( gas_price, utils.parse_as_int( block_dict['transactions'][i]['gasPrice'])) self.assertEqual( gas, utils.parse_as_int(block_dict['transactions'][i]['gas'])) # contract creation corner case if utils.normalize_address(block_dict['transactions'][i]['to'] or '', allow_blank=True) == b'': self.assertEqual( utils.normalize_address(to), utils.normalize_address( "0x0000000000000000000000000000000000000000")) self.assertEqual(utils.parse_as_int(contract_creation), 1) else: self.assertEqual( utils.normalize_address(to), utils.normalize_address( block_dict['transactions'][i]['to'])) self.assertEqual(utils.parse_as_int(contract_creation), 0) self.assertEqual( value, utils.parse_as_int(block_dict['transactions'][i]['value'])) self.assertEqual( data, utils.decode_hex(block_dict['transactions'][i]['input'])) self.assertEqual( v, utils.parse_as_int(block_dict['transactions'][i]['v'])) self.assertEqual( r, utils.parse_as_int(block_dict['transactions'][i]['r'])) self.assertEqual( s, utils.parse_as_int(block_dict['transactions'][i]['s'])) if i > 0 and i % 100 == 0: self.chain.mine()
def block_from_genesis_declaration(genesis_data, env): h = BlockHeader(nonce=parse_as_bin(genesis_data["nonce"]), difficulty=parse_as_int(genesis_data["difficulty"]), mixhash=parse_as_bin(genesis_data.get("mixhash", genesis_data.get("mixHash", "0"*64))), coinbase=parse_as_bin(genesis_data["coinbase"]), bloom=parse_as_int(genesis_data.get("bloom", "0")), timestamp=parse_as_int(genesis_data["timestamp"]), prevhash=parse_as_bin(genesis_data["parentHash"]), extra_data=parse_as_bin(genesis_data["extraData"]), gas_used=parse_as_int(genesis_data.get("gasUsed", "0")), gas_limit=parse_as_int(genesis_data["gasLimit"])) return Block(h, [], [])
def transaction(tx_dict: dict) -> transactions.Transaction: t = transactions.Transaction( utils.parse_as_int(tx_dict['nonce']), utils.parse_as_int(tx_dict['gasPrice']), utils.parse_as_int(tx_dict['gas']), normalize_bytes(tx_dict['to'] or ''), utils.parse_as_int(tx_dict['value']), utils.decode_hex(tx_dict['input']), utils.parse_as_int(tx_dict['v']), utils.bytes_to_int(normalize_bytes(tx_dict['r'])), utils.bytes_to_int(normalize_bytes(tx_dict['s'])), ) if normalize_bytes(tx_dict['hash']) != t.hash: raise ValueError( "Tx hash does not match. Received invalid transaction?") return t
def rlp_transaction(tx_dict: dict): t = transactions.Transaction( utils.parse_as_int(tx_dict['nonce']), utils.parse_as_int(tx_dict['gasPrice']), utils.parse_as_int(tx_dict['gas']), normalize_bytes(tx_dict['to'] or ''), utils.parse_as_int(tx_dict['value']), utils.decode_hex(tx_dict['input']), utils.parse_as_int(tx_dict['v']), utils.bytes_to_int(normalize_bytes(tx_dict['r'])), utils.bytes_to_int(normalize_bytes(tx_dict['s'])), ) if normalize_bytes(tx_dict['hash']) != t.hash: print("False transaction hash") return None return rlp.encode(t)
def verify_transaction(self, tx_hash, swap_id, initial_addr, target_addr, swap_money): target_tx = self.web3.eth.getTransaction(tx_hash) if target_tx is None: return False print(target_tx) if target_tx["from"].lower() != initial_addr.lower(): return False if target_tx["to"].lower() != target_addr.lower(): return False if target_tx["value"] != int(swap_money): return False if swap_id == "": if target_tx["input"] != "0x": return False else: if int(target_tx["input"], 0) != int(swap_id): return False block_info = self.web3.eth.getBlock(target_tx.blockHash, True) # verify the block hash if not self.verify_block(block_info): return False # verify the following 15 block hash block_num = utils.parse_as_int(block_info["number"]) parent_block_hash = normalize_bytes(block_info.hash) for i in range(1, 15): temp_block_info = self.web3.eth.getBlock(block_num + i) cur_block_parent_hash = normalize_bytes(temp_block_info["parentHash"]) if parent_block_hash != cur_block_parent_hash: return False parent_block_hash = normalize_bytes(temp_block_info.hash) self.verify_block(temp_block_info) # verify the transaction if not self.verify_transaction_hash(block_info, tx_hash): return False return True
def generate_proof_blob(block_dict, tx_index): header = block_header(block_dict) mpt = HexaryTrie(db={}) for tx_dict in block_dict["transactions"]: key = rlp.encode(utils.parse_as_int(tx_dict['transactionIndex'])) mpt.set(key, rlp_transaction(tx_dict)) if mpt.root_hash != normalize_bytes(block_dict['transactionsRoot']): raise ValueError( "Tx trie root hash does not match. Calculated: {} Sent: {}".format( mpt.root_hash.hex(), normalize_bytes(block_dict['transactionsRoot']).hex())) mpt_key_nibbles = bytes_to_nibbles(rlp.encode(tx_index)) mpt_path, stack_indexes, stack = generate_proof(mpt, mpt_key_nibbles) proof_blob = rlp.encode([ 1, # proof_type header, tx_index, bytes(mpt_path), bytes(stack_indexes), stack, ]) return proof_blob
def verify_block(block_info): # verify the difficulty if utils.parse_as_int(block_info['difficulty']) < 10000000: return False if int(normalize_bytes(block_info["nonce"]).hex(), 16) * utils.parse_as_int(block_info['difficulty']) \ > pow(2, 256): return False # get block header from block info header = block.BlockHeader( normalize_bytes(block_info["parentHash"]), normalize_bytes(block_info["sha3Uncles"]), utils.normalize_address(block_info["miner"]), normalize_bytes(block_info["stateRoot"]), normalize_bytes(block_info["transactionsRoot"]), normalize_bytes(block_info["receiptsRoot"]), utils.bytes_to_int(normalize_bytes(block_info["logsBloom"])), utils.parse_as_int(block_info['difficulty']), utils.parse_as_int(block_info['number']), utils.parse_as_int(block_info['gasLimit']), utils.parse_as_int(block_info['gasUsed']), utils.parse_as_int(block_info['timestamp']), normalize_bytes(block_info["extraData"]), normalize_bytes(block_info["mixHash"]), normalize_bytes(block_info["nonce"]), ) # calculate the block hash # compare the block hash with trusted block hash if normalize_bytes(block_info.hash) != header.hash: return False else: return True
def receipt(receipt_dict: dict) -> messages.Receipt: logs = [ Log(utils.normalize_address(l['address']), [utils.parse_as_int(t.hex()) for t in l['topics']], utils.decode_hex(l['data'])) for l in receipt_dict['logs'] ] root = receipt_dict.get('root') if root: state_root = normalize_bytes(root) elif receipt_dict['status'] == 1: state_root = bytes([1]) else: state_root = bytes() r = messages.Receipt( state_root, utils.parse_as_int(receipt_dict['cumulativeGasUsed']), utils.bytes_to_int(normalize_bytes(receipt_dict['logsBloom'])), logs, ) return r
def verify_transaction_hash(self, block_info, tx_hash): txns = block_info.transactions tx_index = 0 # generate the mpt mpt = HexaryTrie(db={}) for tx_dict in txns: if tx_dict.hash == tx_hash: tx_index = tx_dict.transactionIndex key = rlp.encode(utils.parse_as_int(tx_dict['transactionIndex'])) mpt.set(key, self.rlp_transaction(tx_dict)) # verify the tx root if mpt.root_hash != normalize_bytes(block_info.transactionsRoot): return False # generate the proof mpt_key_nibbles = bytes_to_nibbles(rlp.encode(tx_index)) proof = tuple(self.generate_proof(mpt, mpt_key_nibbles)) if HexaryTrie.get_from_proof(mpt.root_hash, rlp.encode(utils.parse_as_int(tx_index)), proof) \ != self.rlp_transaction(txns[tx_index]): return False return True
def block_header(block_dict: dict) -> block.BlockHeader: b = block.BlockHeader( normalize_bytes(block_dict['parentHash']), normalize_bytes(block_dict['sha3Uncles']), utils.normalize_address(block_dict['miner']), normalize_bytes(block_dict['stateRoot']), normalize_bytes(block_dict['transactionsRoot']), normalize_bytes(block_dict['receiptsRoot']), utils.bytes_to_int(normalize_bytes(block_dict['logsBloom'])), utils.parse_as_int(block_dict['difficulty']), utils.parse_as_int(block_dict['number']), utils.parse_as_int(block_dict['gasLimit']), utils.parse_as_int(block_dict['gasUsed']), utils.parse_as_int(block_dict['timestamp']), normalize_bytes(block_dict['extraData']), normalize_bytes(block_dict['mixHash']), normalize_bytes(block_dict['nonce']), ) if normalize_bytes(block_dict['hash']) != b.hash: raise ValueError( 'Blockhash does not match. Received invalid block header?') return b
def rlp_transaction(tx_dict: dict): t = transactions.Transaction( utils.parse_as_int(tx_dict['nonce']), utils.parse_as_int(tx_dict['gasPrice']), utils.parse_as_int(tx_dict['gas']), normalize_bytes(tx_dict['to'] or ''), utils.parse_as_int(tx_dict['value']), utils.decode_hex(tx_dict['input']), utils.parse_as_int(tx_dict['v']), utils.bytes_to_int(normalize_bytes(tx_dict['r'])), utils.bytes_to_int(normalize_bytes(tx_dict['s'])), ) if normalize_bytes(tx_dict['hash']) != t.hash: raise ValueError( """Tx hash does not match. Received invalid transaction? hashes: {} {} nonce: {} gasPrice: {} gas: {} to: {} value: {} input: {} v: {} r: {} s: {} """.format( tx_dict['hash'], t.hash, utils.parse_as_int(tx_dict['nonce']), utils.parse_as_int(tx_dict['gasPrice']), utils.parse_as_int(tx_dict['gas']), normalize_bytes(tx_dict['to'] or ''), utils.parse_as_int(tx_dict['value']), utils.decode_hex(tx_dict['input']), utils.parse_as_int(tx_dict['v']), utils.bytes_to_int(normalize_bytes(tx_dict['r'])), utils.bytes_to_int(normalize_bytes(tx_dict['s'])), )) return rlp.encode(t)
def generate_proof_blob(block_dict, tx_index): header = block_header(block_dict) mpt = HexaryTrie(db={}) for tx_dict in block_dict["transactions"]: key = rlp.encode(utils.parse_as_int(tx_dict['transactionIndex'])) mpt.set(key, rlp_transaction(tx_dict)) if mpt.root_hash != normalize_bytes(block_dict['transactionsRoot']): raise ValueError( "Tx trie root hash does not match. Calculated: {} Sent: {}" .format(mpt.root_hash.hex(), normalize_bytes(block_dict['transactionsRoot']).hex())) return construct_proof_from_mpt(mpt, header, tx_index, 1)
def generate_proof_blob_receipt(block_dict, tx_index, url): header = block_header(block_dict) mpt = HexaryTrie(db={}) for tx_dict in block_dict["transactions"]: key = rlp.encode(utils.parse_as_int(tx_dict['transactionIndex'])) receipt = get_receipt(url, tx_dict['hash']) mpt.set(key, rlp.encode(receipt)) if mpt.root_hash != normalize_bytes(block_dict['receiptsRoot']): if MODULE_DEBUG: print("mpt.root_hash " + str(utils.encode_hex(mpt.root_hash))) print("receiptRoot " + str(normalize_bytes(utils.encode_hex(block_dict['receiptsRoot'])))) raise ValueError("Block receiptRoot hash does not match.") return construct_proof_from_mpt(mpt, header, tx_index, 2)
def verify_transaction_exist(self, tx_hash): target_tx = self.web3.eth.getTransaction(tx_hash) block_info = self.web3.eth.getBlock(target_tx.blockHash, True) # verify the block hash if not self.verify_block(block_info): return False # verify the following 15 block hash block_num = utils.parse_as_int(block_info["number"]) parent_block_hash = normalize_bytes(block_info.hash) for i in range(1, 15): temp_block_info = self.web3.eth.getBlock(block_num + i) cur_block_parent_hash = normalize_bytes(temp_block_info["parentHash"]) if parent_block_hash != cur_block_parent_hash: return False parent_block_hash = normalize_bytes(temp_block_info.hash) self.verify_block(temp_block_info) # verify the transaction if not self.verify_transaction_hash(block_info, tx_hash): return False return True
def mk_basic_state(alloc, header=None, env=None, executing_on_head=False): env = env or Env() state = State(env=env, executing_on_head=executing_on_head) if not header: header = { "number": 0, "gas_limit": env.config['BLOCK_GAS_LIMIT'], "gas_used": 0, "timestamp": 1467446877, "difficulty": 1, "uncles_hash": '0x' + encode_hex(BLANK_UNCLES_HASH) } h = BlockHeader(number=parse_as_int(header['number']), timestamp=parse_as_int(header['timestamp']), difficulty=parse_as_int(header['difficulty']), gas_limit=parse_as_int(header['gas_limit']), uncles_hash=parse_as_bin(header['uncles_hash'])) state.prev_headers = [h] for addr, data in alloc.items(): addr = normalize_address(addr) assert len(addr) == 20 if 'wei' in data: state.set_balance(addr, parse_as_int(data['wei'])) if 'balance' in data: state.set_balance(addr, parse_as_int(data['balance'])) if 'code' in data: state.set_code(addr, parse_as_bin(data['code'])) if 'nonce' in data: state.set_nonce(addr, parse_as_int(data['nonce'])) if 'storage' in data: for k, v in data['storage'].items(): state.set_storage_data(addr, parse_as_bin(k), parse_as_bin(v)) state.block_number = header["number"] state.gas_limit = header["gas_limit"] state.timestamp = header["timestamp"] state.block_difficulty = header["difficulty"] state.commit() return state