├── .gitignore ├── .gitmodules ├── LICENSE ├── README.md ├── build-contracts.sh ├── build-l1-geth.sh ├── build-l2-geth.sh ├── build-rollup-node.sh ├── bytecode_l1_depositfeed.txt ├── bytecode_l2_l1block.txt ├── cast-env ├── clean.sh ├── gen_confs.py ├── get-genesis-hashes.sh ├── install.sh ├── killall.sh ├── requirements.txt ├── rollup.yaml ├── setup.sh ├── start-l1-geth-killable.sh ├── start-l1-geth.sh ├── start-l2-geth-killable.sh ├── start-l2-geth.sh ├── start-rollup-node-killable.sh ├── start-rollup-node.sh └── test.sh /.gitignore: -------------------------------------------------------------------------------- 1 | venv 2 | *_genesis.json 3 | 4 | l1geth 5 | refl2geth 6 | data_l1 7 | data_l2 8 | signer_* 9 | l1_genesis_hash.txt 10 | l2_genesis_hash.txt 11 | rollupnode 12 | .mnemonic 13 | 14 | /logs 15 | -------------------------------------------------------------------------------- /.gitmodules: -------------------------------------------------------------------------------- 1 | [submodule "optimistic-specs"] 2 | path = optimistic-specs 3 | url = https://github.com/ethereum-optimism/optimistic-specs 4 | branch = input-deriv-test-cleanup 5 | [submodule "reference-optimistic-geth"] 6 | path = reference-optimistic-geth 7 | url = https://github.com/ethereum-optimism/reference-optimistic-geth 8 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2021 @protolambda 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # rollup node experiments 2 | 3 | Test scripts etc. for *experimental* optimistic rollup testing of the new [Optimism 1.0 specs](https://github.com/ethereum-optimism/optimistic-specs). 4 | 5 | Running `./install.sh` will run a complete configuration + installation of the system, so that it is 6 | ready to run. Alteratively, follow the instructions below for more figne grained steps. 7 | 8 | ## Config preparation 9 | 10 | Change `rollup.yaml` for custom premine / testnet ID / L1 clique signers. 11 | 12 | Then run `./setup.sh`, or follow the steps below. 13 | 14 | `setup.sh` is idempotent: it produces no changes if ran twice in a row. It does, 15 | as needed rebuild the contracts, regenerate the genesis file configuraiton and 16 | update the `optimistic-specs` and `reference-optimistic-geth` submodule. 17 | 18 | `setup.sh` does not build the nodes. To do that, runs `./install.sh`, which also 19 | calls `setup.sh`. 20 | 21 | ### Initialize submodules 22 | 23 | Run 24 | 25 | ``` 26 | git submodule init 27 | git submodule update 28 | ``` 29 | 30 | Alternatively, you can run with these directories being located elsewhere. In 31 | that case, follow the code snippets in this README and do not run the provided 32 | shell scripts. 33 | 34 | ### Optional: recompile system contracts bytecode. 35 | 36 | To compile and fetch deployed bytecode, to embed in local testnet genesis states, 37 | run `./build-contracts.sh`, or: 38 | 39 | ```shell 40 | cd ../optimistic-specs/packages/contracts 41 | yarn 42 | yarn build 43 | cat artifacts/contracts/L2/L1Block.sol/L1Block.json | jq -r .deployedBytecode > ../../../rollup-node-experiments/bytecode_l2_l1block.txt 44 | cat artifacts/contracts/L1/DepositFeed.sol/DepositFeed.json | jq -r .deployedBytecode > ../../../rollup-node-experiments/bytecode_l1_depositfeed.txt 45 | ``` 46 | 47 | ### generate configs 48 | 49 | Build the L1 and L2 chain genesis configurations: 50 | 51 | ```shell 52 | python -m venv venv 53 | source venv/bin/activate 54 | pip install -r requirements.txt 55 | 56 | # generate a `l1_genesis.json` and `l2_genesis.json` for local L1 and L2 geth instances 57 | python gen_confs.py 58 | ``` 59 | 60 | ## Node setup 61 | 62 | ### L1 setup 63 | 64 | Run `./build-l1-geth.sh`, or: 65 | 66 | ```shell 67 | # install upstream geth: 68 | go install github.com/ethereum/go-ethereum/cmd/geth@v1.10.15 69 | 70 | # Create L1 data dir 71 | geth init --datadir data_l1 l1_genesis.json 72 | 73 | # Import the clique signer secret key into geth 74 | echo -n "foobar" > signer_password.txt 75 | geth --datadir data_l1 account import --password=signer_password.txt signer_0x30eC912c5b1D14aa6d1cb9AA7A6682415C4F7Eb0 76 | ``` 77 | 78 | Run `./start-l1-geth.sh`, or: 79 | 80 | ``` 81 | # Start L1 Geth with block production enabled: 82 | geth --datadir data_l1 \ 83 | --networkid 900 \ 84 | --http --http.api "net,eth,consensus" \ 85 | --http.port 8545 \ 86 | --http.addr 127.0.0.1 \ 87 | --http.corsdomain "*" \ 88 | --ws --ws.api "net,eth,consensus" \ 89 | --ws.port=8546 \ 90 | --ws.addr 0.0.0.0 \ 91 | --maxpeers=0 \ 92 | --vmodule=rpc=5 \ 93 | --allow-insecure-unlock --unlock 0x30eC912c5b1D14aa6d1cb9AA7A6682415C4F7Eb0 \ 94 | --password=signer_password.txt --mine 95 | --dev --dev.period=0 96 | ``` 97 | 98 | ### L2 exec-engine setup 99 | 100 | Run `./build-l2-geth.sh` or... 101 | 102 | Clone and build the `optimism-prototype` branch into the parent directory containing this repo: 103 | 104 | ```shell 105 | # Prepare L2 binary (or `go run` directly from source instead) 106 | git clone --branch optimism-prototype https://github.com/ethereum-optimism/reference-optimistic-geth 107 | cd reference-optimistic-geth 108 | go mod download 109 | go build -o refl2geth ./cmd/geth 110 | mv refl2geth ../rollup-node-experiments/ 111 | cd ../rollup-node-experiments/ 112 | 113 | # Create L2 data dir 114 | ./refl2geth init --datadir data_l2 l2_genesis.json 115 | ``` 116 | 117 | Then run `./start-l2-geth.sh` or... 118 | 119 | ``` 120 | # Run L2 geth 121 | # Important: expose engine RPC namespace and activate the merge functionality. 122 | 123 | ./refl2geth --datadir data_l2 \ 124 | --networkid 901 --catalyst \ 125 | --http --http.api "net,eth,consensus,engine" \ 126 | --http.port 9000 \ 127 | --http.addr 127.0.0.1 \ 128 | --http.corsdomain "*" \ 129 | --ws --ws.api "net,eth,consensus,engine" \ 130 | --ws.port=9001 \ 131 | --ws.addr 0.0.0.0 \ 132 | --port=30304 \ 133 | --nat=none \ 134 | --maxpeers=0 \ 135 | --vmodule=rpc=5 136 | # TODO: remove maxpeers=0 and --nat=none if testing with more local nodes 137 | 138 | 139 | ``` 140 | 141 | ### Rollup-node setup 142 | 143 | Run `./get-genesis-hashes.sh` or, 144 | 145 | ``` 146 | # Get the L1 genesis block hash 147 | curl -X POST -H "Content-Type: application/json" --data '{"jsonrpc":"2.0","method":"eth_getBlockByNumber","params":["0x0", false],"id":1}' http://localhost:8545 | jq -r ".result.hash" | tee l1_genesis_hash.txt 148 | 149 | # Get the L2 genesis block hash 150 | curl -X POST -H "Content-Type: application/json" --data '{"jsonrpc":"2.0","method":"eth_getBlockByNumber","params":["0x0", false],"id":1}' http://localhost:9000 | jq -r ".result.hash" | tee l2_genesis_hash.txt 151 | ``` 152 | 153 | Run `./build-rollup-node.sh` or, 154 | 155 | ```shell 156 | # Prepare rollup-node binary (or `go run` directly from source instead) 157 | git clone https://github.com/ethereum-optimism/optimistic-specs 158 | cd optimistic-specs 159 | go mod download 160 | go build -o rollupnode ./opnode/cmd 161 | mv rollupnode ../rollup-node-experiments/ 162 | cd ../rollup-node-experiments/ 163 | ``` 164 | 165 | 166 | Then run `./start-rollup-node.sh` or, 167 | 168 | ``` 169 | ./rollupnode run \ 170 | --l1=ws://localhost:8546 \ 171 | --l2=ws://localhost:9001 \ 172 | --log.level=debug \ 173 | --genesis.l1-hash=$(cat l1_genesis_hash.txt) \ 174 | --genesis.l1-num=0 \ 175 | --genesis.l2-hash=$(cat l2_genesis_hash.txt) 176 | ``` 177 | 178 | ### Running nodes in the background 179 | 180 | ``` 181 | ./start-l1-geth-killable.sh & 182 | L1PID=$! 183 | ./start-l2-geth-killable.sh & 184 | L2PID=$! 185 | ./start-rollup-node-killable.sh & 186 | RNPID=$! 187 | 188 | # killing 189 | kill $L1PID 190 | kill $L2PID 191 | kill $L3PID 192 | ``` 193 | 194 | ### Verifying that the system works 195 | 196 | Run `./test.sh`, this will run all nodes in the background (just like the previous section) and 197 | additionally submit a deposit on L1. 198 | 199 | To further play around with the system, you might find it useful to source the `cast-env` file which 200 | sets useful environment variables. 201 | 202 | ### Resetting 203 | 204 | In order to restart the test with a new build, you will likely want to wipe the chainstate, which 205 | will also require rebuilding the l1 and l2 nodes. This can be accomplished by running the following 206 | scripts: 207 | 208 | ``` 209 | # kill all running L1, L2 and rollup nodes (may include other mainnet nodes!) 210 | ./killall.sh 211 | 212 | # deletes both data_l1 and data_l2 dirs 213 | ./clean.sh 214 | 215 | # rebuild and start l1-geth 216 | ./build-l1-geth.sh && ./start-l1-geth.sh 217 | 218 | # rebuild and start l2-geth 219 | ./build-l2-geth.sh && ./start-l2-geth.sh 220 | 221 | # rebuild and start rollup-node 222 | ./get-genesis-hashes.sh && ./build-rollup-node.sh && ./start-rollup-node.sh 223 | ``` 224 | 225 | 226 | ## License 227 | 228 | MIT, see [`LICENSE`](./LICENSE) file. 229 | -------------------------------------------------------------------------------- /build-contracts.sh: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | 3 | echo "building and getting contract bytecode" 4 | cd ./optimistic-specs/packages/contracts 5 | yarn 6 | yarn build 7 | cat artifacts/contracts/L2/L1Block.sol/L1Block.json | jq -r .deployedBytecode > ../../../bytecode_l2_l1block.txt 8 | cat artifacts/contracts/L1/DepositFeed.sol/DepositFeed.json | jq -r .deployedBytecode > ../../../bytecode_l1_depositfeed.txt 9 | 10 | -------------------------------------------------------------------------------- /build-l1-geth.sh: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | 3 | # install upstream geth: 4 | echo "Install upstream geth" 5 | go install github.com/ethereum/go-ethereum/cmd/geth@v1.10.15 6 | 7 | echo "Create L1 data dir" 8 | geth init --datadir data_l1 l1_genesis.json 9 | 10 | echo "import clique signer" 11 | echo "foobar\c" > signer_password.txt 12 | geth --datadir data_l1 account import --password=signer_password.txt signer_0x30eC912c5b1D14aa6d1cb9AA7A6682415C4F7Eb0 13 | -------------------------------------------------------------------------------- /build-l2-geth.sh: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | 3 | echo "building refl2geth to current directory" 4 | cd ./reference-optimistic-geth 5 | go mod download 6 | go build -o refl2geth ./cmd/geth 7 | mv refl2geth .. 8 | cd .. 9 | 10 | 11 | # Create L2 data dir 12 | echo "initializing refl2geth with l2_genesis.json" 13 | ./refl2geth init --datadir data_l2 l2_genesis.json 14 | -------------------------------------------------------------------------------- /build-rollup-node.sh: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | 3 | echo "building rollup node binary to ./rollupnode" 4 | cd ./optimistic-specs 5 | go mod download 6 | go build -o rollupnode ./opnode/cmd 7 | mv rollupnode .. 8 | cd .. 9 | -------------------------------------------------------------------------------- /bytecode_l1_depositfeed.txt: -------------------------------------------------------------------------------- 1 | 0x60806040526004361061001e5760003560e01c8063fa92670c14610023575b600080fd5b61003d6004803603810190610038919061039d565b61003f565b005b8180156100795750600073ffffffffffffffffffffffffffffffffffffffff168573ffffffffffffffffffffffffffffffffffffffff1614155b156100b0576040517ff98844ef00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b60003390503273ffffffffffffffffffffffffffffffffffffffff163373ffffffffffffffffffffffffffffffffffffffff161461010257731111000000000000000000000000000000001111330190505b8573ffffffffffffffffffffffffffffffffffffffff168173ffffffffffffffffffffffffffffffffffffffff167f26137a5e34446f63aa9ea28797a0e70c3987720913879898802dd60b944615ad34888888886040516101679594939291906104da565b60405180910390a3505050505050565b6000604051905090565b600080fd5b600080fd5b600073ffffffffffffffffffffffffffffffffffffffff82169050919050565b60006101b68261018b565b9050919050565b6101c6816101ab565b81146101d157600080fd5b50565b6000813590506101e3816101bd565b92915050565b6000819050919050565b6101fc816101e9565b811461020757600080fd5b50565b600081359050610219816101f3565b92915050565b60008115159050919050565b6102348161021f565b811461023f57600080fd5b50565b6000813590506102518161022b565b92915050565b600080fd5b600080fd5b6000601f19601f8301169050919050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052604160045260246000fd5b6102aa82610261565b810181811067ffffffffffffffff821117156102c9576102c8610272565b5b80604052505050565b60006102dc610177565b90506102e882826102a1565b919050565b600067ffffffffffffffff82111561030857610307610272565b5b61031182610261565b9050602081019050919050565b82818337600083830152505050565b600061034061033b846102ed565b6102d2565b90508281526020810184848401111561035c5761035b61025c565b5b61036784828561031e565b509392505050565b600082601f83011261038457610383610257565b5b813561039484826020860161032d565b91505092915050565b600080600080600060a086880312156103b9576103b8610181565b5b60006103c7888289016101d4565b95505060206103d88882890161020a565b94505060406103e98882890161020a565b93505060606103fa88828901610242565b925050608086013567ffffffffffffffff81111561041b5761041a610186565b5b6104278882890161036f565b9150509295509295909350565b61043d816101e9565b82525050565b61044c8161021f565b82525050565b600081519050919050565b600082825260208201905092915050565b60005b8381101561048c578082015181840152602081019050610471565b8381111561049b576000848401525b50505050565b60006104ac82610452565b6104b6818561045d565b93506104c681856020860161046e565b6104cf81610261565b840191505092915050565b600060a0820190506104ef6000830188610434565b6104fc6020830187610434565b6105096040830186610434565b6105166060830185610443565b818103608083015261052881846104a1565b9050969550505050505056fea264697066735822122025140b7451be29e927d33c9ad0e2dd3744f824f592e16cb35f009b57442e2c9364736f6c634300080a0033 2 | -------------------------------------------------------------------------------- /bytecode_l2_l1block.txt: -------------------------------------------------------------------------------- 1 | 0x608060405234801561001057600080fd5b50600436106100625760003560e01c806309bd5a60146100675780635cf24969146100855780638381f58a146100a3578063b80777ea146100c1578063c03ba43e146100df578063e591b282146100fb575b600080fd5b61006f610119565b60405161007c91906101fd565b60405180910390f35b61008d61011f565b60405161009a9190610231565b60405180910390f35b6100ab610125565b6040516100b89190610231565b60405180910390f35b6100c961012b565b6040516100d69190610231565b60405180910390f35b6100f960048036038101906100f491906102a9565b610131565b005b6101036101cc565b6040516101109190610351565b60405180910390f35b60035481565b60025481565b60005481565b60015481565b73deaddeaddeaddeaddeaddeaddeaddeaddead000173ffffffffffffffffffffffffffffffffffffffff163373ffffffffffffffffffffffffffffffffffffffff16146101aa576040517fce8c104800000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b8360008190555082600181905550816002819055508060038190555050505050565b73deaddeaddeaddeaddeaddeaddeaddeaddead000181565b6000819050919050565b6101f7816101e4565b82525050565b600060208201905061021260008301846101ee565b92915050565b6000819050919050565b61022b81610218565b82525050565b60006020820190506102466000830184610222565b92915050565b600080fd5b61025a81610218565b811461026557600080fd5b50565b60008135905061027781610251565b92915050565b610286816101e4565b811461029157600080fd5b50565b6000813590506102a38161027d565b92915050565b600080600080608085870312156102c3576102c261024c565b5b60006102d187828801610268565b94505060206102e287828801610268565b93505060406102f387828801610268565b925050606061030487828801610294565b91505092959194509250565b600073ffffffffffffffffffffffffffffffffffffffff82169050919050565b600061033b82610310565b9050919050565b61034b81610330565b82525050565b60006020820190506103666000830184610342565b9291505056fea2646970667358221220cdaea4f1ee477c3fe7f1b3caa2283ad58d53d6a652006ec9e6f6bf22354b258264736f6c634300080a0033 2 | -------------------------------------------------------------------------------- /cast-env: -------------------------------------------------------------------------------- 1 | # source this file to define useful testing variables 2 | 3 | L1_RPC=http://localhost:8545 4 | L2_RPC=http://localhost:9000 5 | 6 | # set default RPC to L1 7 | export ETH_RPC_URL=$L1_RPC 8 | 9 | # this is the address matching the mnemonic in rollup.yaml (and .mnemonic if you ran setup.sh) 10 | DEV_ADDR=0x30eC912c5b1D14aa6d1cb9AA7A6682415C4F7Eb0 11 | 12 | # set the default sender to the dev address 13 | export ETH_FROM=$DEV_ADDR 14 | 15 | # deposit contract address on L1 16 | DEPOSIT_CONTRACT=0xdeaddeaddeaddeaddeaddeaddeaddeaddead0001 17 | 18 | # signature for deposit call in deposit contract 19 | DEPOSIT_SIG='depositTransaction(address,uint256,uint256,bool,bytes)' 20 | -------------------------------------------------------------------------------- /clean.sh: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | 3 | echo "deleting l1 and l2 data-dirs" 4 | rm -rf data_* 5 | -------------------------------------------------------------------------------- /gen_confs.py: -------------------------------------------------------------------------------- 1 | from web3.auto import w3 2 | import json 3 | import ruamel.yaml as yaml 4 | import sys 5 | import time 6 | 7 | # software hierarchical derivation, use a hardware wallet for production instead! 8 | w3.eth.account.enable_unaudited_hdwallet_features() 9 | 10 | rollup_config_path = "rollup.yaml" 11 | if len(sys.argv) > 1: 12 | rollup_config_path = sys.argv[1] 13 | 14 | with open(rollup_config_path) as stream: 15 | data = yaml.safe_load(stream) 16 | 17 | common_forks = { 18 | "homesteadBlock": 0, 19 | "eip150Block": 0, 20 | "eip155Block": 0, 21 | "eip158Block": 0, 22 | "byzantiumBlock": 0, 23 | "constantinopleBlock": 0, 24 | "petersburgBlock": 0, 25 | "istanbulBlock": 0, 26 | "berlinBlock": 0, 27 | "londonBlock": 0, 28 | } 29 | 30 | l1_genesis_time = int(time.time()) 31 | 32 | # Allocate 1 wei to all possible pre-compiles. 33 | # See https://github.com/ethereum/EIPs/issues/716 "SpuriousDragon RIPEMD bug" 34 | # E.g. Rinkeby allocates it like this. 35 | # See https://github.com/ethereum/go-ethereum/blob/092856267067dd78b527a773f5b240d5c9f5693a/core/genesis.go#L370 36 | precompile_alloc = { 37 | "0x" + i.to_bytes(length=20, byteorder='big').hex(): { 38 | "balance": "1", 39 | } for i in range(256) 40 | } 41 | 42 | premine_alloc = {} 43 | for key, value in data['premine'].items(): 44 | if key.startswith('m/'): 45 | acct = w3.eth.account.from_mnemonic(data['mnemonic'], account_path=key, passphrase='') 46 | weival = value.replace('ETH', '0' * 18) 47 | premine_alloc[acct.address] = {"balance": weival} 48 | if key.startswith('0x'): 49 | premine_alloc[key] = {"balance": weival} 50 | 51 | clique_extra_data = b'\x00' * 32 52 | for signer_path in data['clique_signers']: 53 | clique_signer_acct = w3.eth.account.from_mnemonic(data['mnemonic'], account_path=signer_path, passphrase='') 54 | clique_extra_data += bytes.fromhex(clique_signer_acct.address[2:]) 55 | print("added clique signer", clique_signer_acct.address) 56 | with open(f"signer_{clique_signer_acct.address}", "wt") as f: 57 | f.write(clique_signer_acct.key.hex()[2:]) # strip 0x 58 | clique_extra_data += b'\x00' * 65 59 | 60 | with open('bytecode_l2_l1block.txt', 'rt') as f: 61 | bytecode_l2_l1block = f.read().strip() 62 | 63 | with open('bytecode_l1_depositfeed.txt', 'rt') as f: 64 | bytecode_l1_depositfeed = f.read().strip() 65 | 66 | l1_out = { 67 | "config": { 68 | "chainId": int(data['l1_chain_id']), 69 | **common_forks, 70 | "clique": { 71 | "period": 6, # block time 72 | "epoch": 30000 73 | } 74 | }, 75 | "alloc": { 76 | **precompile_alloc, 77 | **premine_alloc, 78 | data['deposit_contract_address']: { 79 | "balance": "0", 80 | "code": bytecode_l1_depositfeed, 81 | "storage": {} 82 | } 83 | }, 84 | "coinbase": "0x0000000000000000000000000000000000000000", 85 | "difficulty": "0x01", 86 | "extraData": "0x" + clique_extra_data.hex(), 87 | "gasLimit": "0x400000", 88 | "nonce": "0x1234", 89 | "mixhash": "0x0000000000000000000000000000000000000000000000000000000000000000", 90 | "parentHash": "0x0000000000000000000000000000000000000000000000000000000000000000", 91 | "timestamp": str(l1_genesis_time), 92 | "baseFeePerGas": "0x7" 93 | } 94 | 95 | l2_out = { 96 | "config": { 97 | "chainId": int(data['l2_chain_id']), 98 | **common_forks, 99 | # activate merge features from genesis 100 | "mergeForkBlock": 0, 101 | "terminalTotalDifficulty": 0, 102 | }, 103 | "alloc": { 104 | **precompile_alloc, 105 | **premine_alloc, 106 | data['l1_info_predeploy_address']: { 107 | "balance": "0", 108 | "code": bytecode_l2_l1block, 109 | "storage": {} 110 | }, 111 | }, 112 | "coinbase": "0x0000000000000000000000000000000000000000", 113 | "difficulty": "0x01", 114 | "extraData": "", 115 | "gasLimit": "0x400000", 116 | "nonce": "0x1234", 117 | "mixhash": "0x0000000000000000000000000000000000000000000000000000000000000000", 118 | "parentHash": "0x0000000000000000000000000000000000000000000000000000000000000000", 119 | "timestamp": str(l1_genesis_time), 120 | "baseFeePerGas": "0x7" 121 | } 122 | 123 | with open("l1_genesis.json", "wt") as f: 124 | json.dump(l1_out, f, indent=' ') 125 | 126 | with open("l2_genesis.json", "wt") as f: 127 | json.dump(l2_out, f, indent=' ') 128 | -------------------------------------------------------------------------------- /get-genesis-hashes.sh: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | 3 | echo "curl genesis hash from L1 geth, and save to file." 4 | curl -X POST -H "Content-Type: application/json" \ 5 | --data '{"jsonrpc":"2.0","method":"eth_getBlockByNumber","params":["0x0", false],"id":1}' \ 6 | http://localhost:8545 \ 7 | | jq -r ".result.hash" \ 8 | | tee l1_genesis_hash.txt 9 | 10 | 11 | 12 | echo "curl genesis hash from L2 geth, and save to file." 13 | curl -X POST -H "Content-Type: application/json" \ 14 | --data '{"jsonrpc":"2.0","method":"eth_getBlockByNumber","params":["0x0", false],"id":1}' \ 15 | http://localhost:9000 \ 16 | | jq -r ".result.hash" \ 17 | | tee l2_genesis_hash.txt 18 | -------------------------------------------------------------------------------- /install.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | echo "Fully automated installation" 4 | 5 | if [[ -d data_l1 || -d data_l2 ]] ; then 6 | read -p "This will wipe data L1 & L2 data directories. Are you sure? (y/n) " -n 1 -r 7 | echo 8 | echo $REPLY 9 | if [[ $REPLY =~ ^[Yy]$ ]]; then 10 | ./clean.sh 11 | else 12 | echo "aborting" 13 | exit 1 14 | fi 15 | fi 16 | 17 | ./setup.sh 18 | ./build-l1-geth.sh 19 | ./build-l2-geth.sh 20 | 21 | ./start-l1-geth-killable.sh & 22 | L1PID=$! 23 | ./start-l2-geth-killable.sh & 24 | L2PID=$! 25 | echo "sleep 10 sec while L1 and L2 nodes boot up" 26 | 27 | sleep 10 28 | ./get-genesis-hashes.sh 29 | 30 | echo "killing L1 and L2 nodes" 31 | kill $L1PID 32 | kill $L2PID 33 | 34 | ./build-rollup-node.sh 35 | -------------------------------------------------------------------------------- /killall.sh: -------------------------------------------------------------------------------- 1 | #/bin/sh 2 | 3 | # kill all instances of L1 geth, L2 geth and rollup node running on the system 4 | 5 | killall geth 6 | killall refl2geth 7 | killall rollupnode 8 | -------------------------------------------------------------------------------- /requirements.txt: -------------------------------------------------------------------------------- 1 | web3 2 | ruamel.yaml -------------------------------------------------------------------------------- /rollup.yaml: -------------------------------------------------------------------------------- 1 | # Don't use this in production. This is a mnemonic for allocating ETH in local short-lived testnets. 2 | mnemonic: "squirrel green gallery layer logic title habit chase clog actress language enrich body plate fun pledge gap abuse mansion define either blast alien witness" 3 | l1_chain_id: 900 4 | l2_chain_id: 901 5 | premine: 6 | "m/44'/60'/0'/0/0": 10000000ETH 7 | "m/44'/60'/0'/0/1": 10000000ETH 8 | "m/44'/60'/0'/0/2": 10000000ETH 9 | # add a custom address here: 10 | # "0xb68C41d7A1eE61c33106C3d011b876Ab088D1248": 1000000000ETH 11 | clique_signers: ["m/44'/60'/0'/0/0"] 12 | deposit_contract_address: '0xdeaddeaddeaddeaddeaddeaddeaddeaddead0001' 13 | l1_info_predeploy_address: '0x4242424242424242424242424242424242424242' 14 | -------------------------------------------------------------------------------- /setup.sh: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | 3 | echo "Running initial setup" 4 | 5 | echo "creating .mnemonic file from rollup.yaml" 6 | echo $(grep "mnemonic:" rollup.yaml | cut -c12- | rev | cut -c2- | rev ) > .mnemonic 7 | 8 | echo "Fetching submodules" 9 | git submodule init 10 | git submodule update 11 | 12 | ./build-contracts.sh 13 | 14 | echo "Build the L1 and L2 chain genesis configurations" 15 | 16 | mkdir -p logs 17 | python -m venv venv 18 | . venv/bin/activate 19 | echo "logging pip install results to logs/pip.log" 20 | pip install -r requirements.txt > logs/pip.log 2>&1 21 | if [[ $? != 0 ]]; then 22 | "PIP INSTALL FAILED -- check logs/pip.log for details" 23 | fi 24 | python gen_confs.py 25 | -------------------------------------------------------------------------------- /start-l1-geth-killable.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | # The trap/wait logic ensures that killing this script also kills the node. 4 | # cf. https://stackoverflow.com/a/1645157 for details 5 | 6 | trap : SIGTERM SIGINT 7 | 8 | mkdir -p logs 9 | LOGFILE=logs/l1-geth.log 10 | PORT=8545 11 | 12 | nohup geth --datadir data_l1 \ 13 | --networkid 900 \ 14 | --http --http.api "net,eth,consensus" \ 15 | --http.port $PORT \ 16 | --http.addr 127.0.0.1 \ 17 | --http.corsdomain "*" \ 18 | --ws --ws.api "net,eth,consensus" \ 19 | --ws.port=8546 \ 20 | --ws.addr 0.0.0.0 \ 21 | --maxpeers=0 \ 22 | --vmodule=rpc=5 \ 23 | --allow-insecure-unlock --unlock 0x30eC912c5b1D14aa6d1cb9AA7A6682415C4F7Eb0 \ 24 | --password=signer_password.txt --mine \ 25 | --dev --dev.period=0 \ 26 | > $LOGFILE 2>&1 & 27 | PID=$! 28 | 29 | echo "running L1 geth in background, port: $PORT, PID: $PID, logging to $LOGFILE" 30 | 31 | wait $PID 32 | EXIT=$? 33 | 34 | if [[ $EXIT -gt 128 ]]; then 35 | kill $PID 36 | fi 37 | -------------------------------------------------------------------------------- /start-l1-geth.sh: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | 3 | echo "import clique signer" 4 | geth --datadir data_l1 account import --password=signer_password.txt signer_0x30eC912c5b1D14aa6d1cb9AA7A6682415C4F7Eb0 5 | 6 | echo "start L1 geth with block production enabled" 7 | geth --datadir data_l1 \ 8 | --networkid 900 \ 9 | --http --http.api "net,eth,consensus" \ 10 | --http.port 8545 \ 11 | --http.addr 127.0.0.1 \ 12 | --http.corsdomain "*" \ 13 | --ws --ws.api "net,eth,consensus" \ 14 | --ws.port=8546 \ 15 | --ws.addr 0.0.0.0 \ 16 | --maxpeers=0 \ 17 | --vmodule=rpc=5 \ 18 | --allow-insecure-unlock --unlock 0x30eC912c5b1D14aa6d1cb9AA7A6682415C4F7Eb0 \ 19 | --password=signer_password.txt --mine \ 20 | --dev --dev.period=0 21 | -------------------------------------------------------------------------------- /start-l2-geth-killable.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | # The trap/wait logic ensures that killing this script also kills the node. 4 | # cf. https://stackoverflow.com/a/1645157 for details 5 | 6 | trap : SIGTERM SIGINT 7 | 8 | mkdir -p logs 9 | LOGFILE=logs/l2-geth.log 10 | PORT=9000 11 | 12 | nohup ./refl2geth --datadir data_l2 \ 13 | --networkid 901 --catalyst \ 14 | --http --http.api "net,eth,consensus,engine" \ 15 | --http.port $PORT \ 16 | --http.addr 127.0.0.1 \ 17 | --http.corsdomain "*" \ 18 | --ws --ws.api "net,eth,consensus,engine" \ 19 | --ws.port=9001 \ 20 | --ws.addr 0.0.0.0 \ 21 | --port=30304 \ 22 | --nat=none \ 23 | --maxpeers=0 \ 24 | --vmodule=rpc=5 \ 25 | > $LOGFILE 2>&1 & 26 | PID=$! 27 | 28 | echo "running L2 geth in background, port: $PORT, PID: $PID, logging to $LOGFILE" 29 | 30 | wait $PID 31 | EXIT=$? 32 | 33 | if [[ $EXIT -gt 128 ]]; then 34 | kill $PID 35 | fi 36 | -------------------------------------------------------------------------------- /start-l2-geth.sh: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | 3 | echo "Start L2 geth" 4 | ./refl2geth --datadir data_l2 \ 5 | --networkid 901 --catalyst \ 6 | --http --http.api "net,eth,consensus,engine" \ 7 | --http.port 9000 \ 8 | --http.addr 127.0.0.1 \ 9 | --http.corsdomain "*" \ 10 | --ws --ws.api "net,eth,consensus,engine" \ 11 | --ws.port=9001 \ 12 | --ws.addr 0.0.0.0 \ 13 | --port=30304 \ 14 | --nat=none \ 15 | --maxpeers=0 \ 16 | --vmodule=rpc=5 17 | -------------------------------------------------------------------------------- /start-rollup-node-killable.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | # The trap/wait logic ensures that killing the scripts also kills the node. 4 | # cf. https://stackoverflow.com/a/1645157 for details 5 | 6 | trap : SIGTERM SIGINT 7 | 8 | mkdir -p logs 9 | LOGFILE=logs/rollup-node.log 10 | 11 | nohup ./rollupnode run \ 12 | --l1=ws://localhost:8546,ws://localhost:8546,ws://localhost:8546,ws://localhost:8546 \ 13 | --l2=ws://localhost:9001 \ 14 | --log.level=debug \ 15 | --genesis.l1-hash=$(cat l1_genesis_hash.txt) \ 16 | --genesis.l1-num=0 \ 17 | --genesis.l2-hash=$(cat l2_genesis_hash.txt) \ 18 | > $LOGFILE 2>&1 & 19 | PID=$! 20 | 21 | echo "running rollup in background, PID: $PID, logging to $LOGFILE" 22 | 23 | wait $PID 24 | EXIT=$? 25 | 26 | if [[ $EXIT -gt 128 ]]; then 27 | kill $PID 28 | fi 29 | -------------------------------------------------------------------------------- /start-rollup-node.sh: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | 3 | echo "Running rollupnode" 4 | ./rollupnode run \ 5 | --l1=ws://localhost:8546,ws://localhost:8546,ws://localhost:8546,ws://localhost:8546 \ 6 | --l2=ws://localhost:9001 \ 7 | --log.level=debug \ 8 | --genesis.l1-hash=$(cat l1_genesis_hash.txt) \ 9 | --genesis.l1-num=0 \ 10 | --genesis.l2-hash=$(cat l2_genesis_hash.txt) 11 | -------------------------------------------------------------------------------- /test.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | ./start-l1-geth-killable.sh & 4 | ./start-l2-geth-killable.sh & 5 | echo "sleep 10 sec while nodes boot up" 6 | sleep 10 7 | ./start-rollup-node-killable.sh & 8 | 9 | export ETH_RPC_URL=http://localhost:8545 10 | DEPOSIT_CONTRACT=0xdeaddeaddeaddeaddeaddeaddeaddeaddead0001 11 | DEV_ADDR=0x30eC912c5b1D14aa6d1cb9AA7A6682415C4F7Eb0 12 | DEPOSIT_SIG='depositTransaction(address,uint256,uint256,bool,bytes)' 13 | 14 | echo $(grep "mnemonic:" rollup.yaml | cut -c12- | rev | cut -c2- | rev ) > .mnemonic 15 | 16 | cast send --mnemonic-path .mnemonic --from $DEV_ADDR $DEPOSIT_CONTRACT "$DEPOSIT_SIG" 0xABBAABBAABBAABBAABBAABBAABBAABBAABBAABBA 1000 1000000 false 0x00000000000000000000000011111111111111111111111111111111111111110000000000000000000000001111111111111111111111111111111111111111000000000000000000000000000000000000000000000000000000000000008000000000000000000000000000000000000000000000000000000000000000140000000000000000000000000000000000000000000000000000000000000000 17 | 18 | # alternatively: 19 | # seth send -V 1000 $CONTRACT_ADDRESS 'depositTransaction(address,uint256,uint256,bool,bytes)' 0xABBAABBAABBAABBAABBAABBAABBAABBAABBAABBA 1000 1000000 false 0x00000000000000000000000011111111111111111111111111111111111111110000000000000000000000001111111111111111111111111111111111111111000000000000000000000000000000000000000000000000000000000000008000000000000000000000000000000000000000000000000000000000000000140000000000000000000000000000000000000000000000000000000000000000 -F $SENDER_ADDRESS 20 | --------------------------------------------------------------------------------