Skip to content

Commit d381117

Browse files
committed
Light client: validate contract code with account
1 parent db9d25c commit d381117

File tree

2 files changed

+24
-5
lines changed

2 files changed

+24
-5
lines changed

p2p/lightchain.py

Lines changed: 23 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -144,14 +144,33 @@ async def get_account(self, block_hash: Hash32, address: Address) -> Account:
144144
return rlp.decode(rlp_account, sedes=Account)
145145

146146
@alru_cache(maxsize=1024, cache_exceptions=False)
147-
async def get_contract_code(self, block_hash: Hash32, key: bytes) -> bytes:
147+
async def get_contract_code(self, block_hash: Hash32, address: Address) -> bytes:
148+
"""
149+
:param block_hash: find code as of the block with block_hash
150+
:param address: which contract to look up
151+
152+
:return: bytecode of the contract, ``b''`` if no code is set
153+
"""
148154
peer = cast(LESPeer, self.peer_pool.highest_td_peer)
149155
request_id = gen_request_id()
150-
peer.sub_proto.send_get_contract_code(block_hash, key, request_id)
156+
peer.sub_proto.send_get_contract_code(block_hash, keccak(address), request_id)
151157
reply = await self._wait_for_reply(request_id)
158+
152159
if not reply['codes']:
153-
return b''
154-
return reply['codes'][0]
160+
bytecode = b''
161+
else:
162+
bytecode = reply['codes'][0]
163+
164+
# validate bytecode against a proven account
165+
account = await self.get_account(block_hash, address)
166+
167+
if account.code_hash == keccak(bytecode):
168+
return bytecode
169+
else:
170+
# disconnect from this bad peer
171+
await self.disconnect_peer(peer, DisconnectReason.subprotocol_error)
172+
# try again with another peer
173+
return await self.get_contract_code(block_hash, address)
155174

156175
async def _get_block_header_by_hash(self, peer: LESPeer, block_hash: Hash32) -> BlockHeader:
157176
self.logger.debug("Fetching header %s from %s", encode_hex(block_hash), peer)

tests/p2p/test_lightchain_integration.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -89,7 +89,7 @@ async def wait_for_header_sync(block_number):
8989
# blocks, so we use the current head to lookup the code for the contract below.
9090
# https://ropsten.etherscan.io/address/0x95a48dca999c89e4e284930d9b9af973a7481287
9191
contract_addr = decode_hex('95a48dca999c89e4e284930d9b9af973a7481287')
92-
contract_code = await peer_chain.get_contract_code(head.hash, keccak(contract_addr))
92+
contract_code = await peer_chain.get_contract_code(head.hash, contract_addr)
9393
assert encode_hex(keccak(contract_code)) == (
9494
'0x1e0b2ad970b365a217c40bcf3582cbb4fcc1642d7a5dd7a82ae1e278e010123e')
9595

0 commit comments

Comments
 (0)