diff --git a/packages/protocol/deployments/local_deployment.md b/packages/protocol/deployments/local_deployment.md index 9e60ba58916e..1fe9ea8d0396 100644 --- a/packages/protocol/deployments/local_deployment.md +++ b/packages/protocol/deployments/local_deployment.md @@ -23,6 +23,8 @@ participants: el_image: ghcr.io/paradigmxyz/reth # We can use custom image, (remote, e.g.: ethpandaops/reth:main-9c0bc84 or locally: taiko_reth) cl_type: teku cl_image: consensys/teku:latest +network_params: + network_id: '160010' ``` #### 1.1 Local reth-based network diff --git a/packages/protocol/scripts/L2_txn_simulation/ProposeBlock.s.sol b/packages/protocol/scripts/L2_txn_simulation/ProposeBlock.s.sol new file mode 100644 index 000000000000..61328c80c9fa --- /dev/null +++ b/packages/protocol/scripts/L2_txn_simulation/ProposeBlock.s.sol @@ -0,0 +1,78 @@ +// SPDX-License-Identifier: MIT +// _____ _ _ _ _ +// |_ _|_ _(_) |_____ | | __ _| |__ ___ +// | |/ _` | | / / _ \ | |__/ _` | '_ (_-< +// |_|\__,_|_|_\_\___/ |____\__,_|_.__/__/ + +pragma solidity ^0.8.20; + +import "forge-std/Script.sol"; +import "forge-std/console2.sol"; + +import "../../contracts/L1/TaikoL1.sol"; + +contract ProposeBlock is Script { + address public taikoL1Address = 0x9fCF7D13d10dEdF17d0f24C62f0cf4ED462f65b7;//address(0);// TaikoL1 proxy address -> Get from the deployment + address sender = 0x8943545177806ED17B9F23F0a21ee5948eCaa776; // With pre-generated eth + + function run() external { + + require(taikoL1Address != address(0), "based operator not set"); + + vm.startBroadcast(); + + bytes[] memory txLists = new bytes[](1); + // The L2 chainId with which i encoded the TXNs were 167011 + // THe nonce was 0 + bytes memory firstAddressSendingNonce0 = hex"02f87683028c6380843b9aca00847735940083030d4094f93ee4cf8c6c40b329b0c0626f28333c132cf24188016345785d8a000080c080a08f0f52d943504cecea0d6ce317c2fde8b0c27b1e449d85fcf98ccd2f50ac804ba04d5d56356518c1de0c1ece644a8a2fe64e6cc136cd8db0a21a21f72c167353c6"; + bytes memory secondAddressSendingNonce0 = hex"02f87683028c6380843b9aca00847735940083030d4094f93ee4cf8c6c40b329b0c0626f28333c132cf24188016345785d8a000080c080a0622e7060e09afd2100784bdc88ebb838729128bb6eb40f8b7f458430d56dafd4a006fe5d1a466788f941020a2278860c3f2642e44108c666ecd25b30d1b2f7a420"; + bytes memory thirdAddressSendingNonce0 = hex"02f87683028c6380843b9aca00847735940083030d4094f93ee4cf8c6c40b329b0c0626f28333c132cf24188016345785d8a000080c001a0558488f3af91777c382d2ab6ac3507f5d6b906431534193c1a45cc2a08b2825ea0495efd571c9ea5a5290f10efaa219f8c31b4e714745737c4e019df76f7a6df4b"; + + // The outcome of the above is the rlp encoded list (not concatenated but RLP encoded with: https://toolkit.abdk.consulting/ethereum#key-to-address,rlp) + txLists[0] = hex"f90171b87902f87683028c6280843b9aca00847735940083030d4094f93ee4cf8c6c40b329b0c0626f28333c132cf241880de0b6b3a764000080c080a07f983645ddf8365d14e5fb4e3b07c19fe31e23edd9ee4a737388acc2da7e64a3a072a56043512806a6de5f66f28bb659236eea41c9d66db8493f436804c42723d3b87902f87683028c6280843b9aca00847735940083030d4094f93ee4cf8c6c40b329b0c0626f28333c132cf241880de0b6b3a764000080c001a030911ab2ebf76f1e1bfe00d721207d929053efb051d50708a10dd9f66f84bacba07705a7cdb86ff00aa8c131ef3c4cb2ea2f2f4730d93308f1afbb94a04c1c9ae9b87902f87683028c6280843b9aca00847735940083030d4094f93ee4cf8c6c40b329b0c0626f28333c132cf241880de0b6b3a764000080c001a07da8dfb5bc3b7b353f9614bcd83733168500d1e06f2bcdac761cc54c85847e6aa03b041b0605e86aa379ff0f58a60743da411dfd1a9d4f1d18422a862f67a57fee"; + + bytes32 txListHash = keccak256(txLists[0]); //Since we not using Blobs, we need this + + // MetaData related + bytes[] memory metasEncoded = new bytes[](1); + TaikoData.BlockMetadata memory meta; + console2.log(txLists[0].length); + + meta = createBlockMetaDataForFirstBlockDebug(sender, 1, uint64(block.timestamp), uint24(txLists[0].length), txListHash); + + metasEncoded[0] = abi.encode(meta); + + TaikoL1(taikoL1Address).proposeBlock{value: 0.1 ether }(metasEncoded, txLists); + + vm.stopBroadcast(); + } + + function createBlockMetaDataForFirstBlockDebug( + address coinbase, + uint64 l2BlockNumber, + uint64 unixTimestamp, + uint24 txListByteSize, + bytes32 txListHash + ) + internal + returns (TaikoData.BlockMetadata memory meta) + { + meta.blockHash = 0xab80a9c4daa571aa308e967c9a6b4bf21ba8842d95d73d28be112b6fe0618e7c; // Randomly set it to smth + + //TaikoData.Block memory parentBlock = L1.getBlock(l2BlockNumber - 1); + meta.parentMetaHash = 0x0000000000000000000000000000000000000000000000000000000000000000; // This is the genesis block's metaHash + meta.parentBlockHash = 0xdf90a9c4daa571aa308e967c9a6b4bf21ba8842d95d73d28be112b6fe0618e8c; // This is the genesis block's blockhash + meta.l1Hash = blockhash(30); //L1 private network's L1 blockheight, submit this block between 30 and 30+128 blcok of L1. + meta.difficulty = block.prevrandao; + meta.blobHash = txListHash; + meta.coinbase = coinbase; + meta.l2BlockNumber = l2BlockNumber; + meta.gasLimit = 15_000_000; + meta.l1StateBlockNumber = uint32(30); // Submit this block between 30 and 30+128 blcok of L1. + meta.timestamp = unixTimestamp; + + meta.txListByteOffset = 0; + meta.txListByteSize = txListByteSize; // Corresponding txn list byte size + meta.blobUsed = false; + } +} diff --git a/packages/protocol/scripts/L2_txn_simulation/createL2Txn.py b/packages/protocol/scripts/L2_txn_simulation/createL2Txn.py new file mode 100644 index 000000000000..279a86d3f6ca --- /dev/null +++ b/packages/protocol/scripts/L2_txn_simulation/createL2Txn.py @@ -0,0 +1,50 @@ +from web3 import Web3 +from eth_abi import encode +import argparse + +RPC_URL_L2 = 'http://127.0.0.1:8545' # Anything is fine for now as long as we dont have the L2 network, but if we have we can automate nonce and gas settings +w3_taiko_l2 = Web3(Web3.HTTPProvider(RPC_URL_L2)) + +# Some pre-loaded ETH addresses from Kurtosis private network (NO secret, no harm to use for private testnets!) +sender_addresses = ['0x8943545177806ED17B9F23F0a21ee5948eCaa776', '0xE25583099BA105D9ec0A67f5Ae86D90e50036425', '0x614561D2d143621E126e87831AEF287678B442b8'] +sender_pks = ['bcdf20249abf0ed6d944c0288fad489e33f66b3960d9e6229c1cd214ed3bbe31', '39725efee3fb28614de3bacaffe4cc4bd8c436257e2c8bb887c4b5c4be45e76d', '53321db7c1e331d93a11a41d16f004d7ff63972ec8ec7c25db329728ceeb1710'] + +receiver = '0xf93Ee4Cf8c6c40b329b0c0626F28333c132CF241' # This address also has pre-loaded ETH addresses + +parser = argparse.ArgumentParser() + +parser.add_argument("-n", "--nonce", help="collective nonce", + type=int, required=True) +parser.add_argument("-c", "--chainid", help="l2 chainId", + type=int, required=True) + +transaction_list = [] + +if __name__ == "__main__": + args = parser.parse_args() + nonce = args.nonce + chainId = args.chainid + + # Build the new tx list + idx = 0 + for sender in sender_addresses: + # Build the tx + transaction = { + 'chainId': chainId, + 'from': sender, + 'to': receiver, + 'value': w3_taiko_l2.to_wei('1', 'ether'), + 'nonce': nonce, # later we can use something like: w3_taiko_l2.eth.get_transaction_count(address1), + 'gas': 200000, + 'maxFeePerGas': 2000000000, # w3_taiko_l2.eth.gas_price or something + 'maxPriorityFeePerGas': 1000000000, + } + + # 2. Sign tx with a private key + signed_txn = w3_taiko_l2.eth.account.sign_transaction(transaction, sender_pks[idx]) + + # Most probably we need to zlib + rlp encode transactions not only just "concatenate" + print("Txn ",idx, " bytes:") + print(signed_txn.rawTransaction.hex()) + transaction_list.append(signed_txn) + idx += 1 \ No newline at end of file diff --git a/packages/protocol/scripts/L2_txn_simulation/readme.md b/packages/protocol/scripts/L2_txn_simulation/readme.md new file mode 100644 index 000000000000..2728ab26b631 --- /dev/null +++ b/packages/protocol/scripts/L2_txn_simulation/readme.md @@ -0,0 +1,46 @@ +# Create / simulate L2 transactions + +In order to test the L2 node execution hook functionality, we need create valid L2 transactions and submit those to TaikoL1 - where a hook will be built in, to listen the proposeBlock and execute those transactions. This folder is to create L2 transactions (using the same pre-funded accounts Kurtosis is setting up by default) and submit it to our "L1" while using the local taiko_reth image as the EL. + +## Prerequisites + +Prerequisites can also be found in `deployments/local_deployment.md` file. + +1. Testnet up and running: +```shell +kurtosis run github.com/ethpandaops/ethereum-package --args-file YOUR_PATH_TO_NETWORK_CONFIG/network_params.yaml +``` + +2. Main contracts deployed: +```shell +forge script --rpc-url http://127.0.0.1:PORT scripts/DeployL1Locally.s.sol -vvvv --broadcast --private-key PK --legacy +``` + +## 1. Create and print L2 transactions ("off-chain") + +Run script to gather 3 ether transactions, and print them out. `-n` flag stands for the nonce, and `-c` is for the L2 chainId. + +```shell +$ python3 createL2Txns.py -n -c +``` + +## 2. Prepare the script with proper data and fire away the L1 transaction + +Edit the `ProposeBlock.s.sol` file to to set the valid `basedOperatorAddress` and also add the above generated 3 signed transactions (already in the `ProposeBlock.s.sol` file, not needed to run and add them, unless the network `id` or `nonce` is different), then fire away the L1 transaction with the script below: + +```shell +$ forge script --rpc-url http://127.0.0.1:YOUR_PORT scripts/L2_txn_simulation/ProposeBlock.s.sol -vvvv --broadcast --private-key --legacy +``` + +## 3. In case of TXN failure, you can get the error via the debug trace transaction RPC call + +Command + +```shell +curl http://127.0.0.1:YOUR_PORT \ +-X POST \ +-H "Content-Type: application/json" \ +--data '{"method":"debug_traceTransaction","params":["YOUR_TXN_HASH", {"tracer": "callTracer"}], "id":1,"jsonrpc":"2.0"}' +``` + +