diff --git a/LICENSE b/LICENSE new file mode 100644 index 00000000..261eeb9e --- /dev/null +++ b/LICENSE @@ -0,0 +1,201 @@ + Apache License + Version 2.0, January 2004 + http://www.apache.org/licenses/ + + TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + + 1. Definitions. + + "License" shall mean the terms and conditions for use, reproduction, + and distribution as defined by Sections 1 through 9 of this document. + + "Licensor" shall mean the copyright owner or entity authorized by + the copyright owner that is granting the License. + + "Legal Entity" shall mean the union of the acting entity and all + other entities that control, are controlled by, or are under common + control with that entity. For the purposes of this definition, + "control" means (i) the power, direct or indirect, to cause the + direction or management of such entity, whether by contract or + otherwise, or (ii) ownership of fifty percent (50%) or more of the + outstanding shares, or (iii) beneficial ownership of such entity. + + "You" (or "Your") shall mean an individual or Legal Entity + exercising permissions granted by this License. + + "Source" form shall mean the preferred form for making modifications, + including but not limited to software source code, documentation + source, and configuration files. + + "Object" form shall mean any form resulting from mechanical + transformation or translation of a Source form, including but + not limited to compiled object code, generated documentation, + and conversions to other media types. + + "Work" shall mean the work of authorship, whether in Source or + Object form, made available under the License, as indicated by a + copyright notice that is included in or attached to the work + (an example is provided in the Appendix below). + + "Derivative Works" shall mean any work, whether in Source or Object + form, that is based on (or derived from) the Work and for which the + editorial revisions, annotations, elaborations, or other modifications + represent, as a whole, an original work of authorship. For the purposes + of this License, Derivative Works shall not include works that remain + separable from, or merely link (or bind by name) to the interfaces of, + the Work and Derivative Works thereof. + + "Contribution" shall mean any work of authorship, including + the original version of the Work and any modifications or additions + to that Work or Derivative Works thereof, that is intentionally + submitted to Licensor for inclusion in the Work by the copyright owner + or by an individual or Legal Entity authorized to submit on behalf of + the copyright owner. For the purposes of this definition, "submitted" + means any form of electronic, verbal, or written communication sent + to the Licensor or its representatives, including but not limited to + communication on electronic mailing lists, source code control systems, + and issue tracking systems that are managed by, or on behalf of, the + Licensor for the purpose of discussing and improving the Work, but + excluding communication that is conspicuously marked or otherwise + designated in writing by the copyright owner as "Not a Contribution." + + "Contributor" shall mean Licensor and any individual or Legal Entity + on behalf of whom a Contribution has been received by Licensor and + subsequently incorporated within the Work. + + 2. Grant of Copyright License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + copyright license to reproduce, prepare Derivative Works of, + publicly display, publicly perform, sublicense, and distribute the + Work and such Derivative Works in Source or Object form. + + 3. Grant of Patent License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + (except as stated in this section) patent license to make, have made, + use, offer to sell, sell, import, and otherwise transfer the Work, + where such license applies only to those patent claims licensable + by such Contributor that are necessarily infringed by their + Contribution(s) alone or by combination of their Contribution(s) + with the Work to which such Contribution(s) was submitted. If You + institute patent litigation against any entity (including a + cross-claim or counterclaim in a lawsuit) alleging that the Work + or a Contribution incorporated within the Work constitutes direct + or contributory patent infringement, then any patent licenses + granted to You under this License for that Work shall terminate + as of the date such litigation is filed. + + 4. Redistribution. You may reproduce and distribute copies of the + Work or Derivative Works thereof in any medium, with or without + modifications, and in Source or Object form, provided that You + meet the following conditions: + + (a) You must give any other recipients of the Work or + Derivative Works a copy of this License; and + + (b) You must cause any modified files to carry prominent notices + stating that You changed the files; and + + (c) You must retain, in the Source form of any Derivative Works + that You distribute, all copyright, patent, trademark, and + attribution notices from the Source form of the Work, + excluding those notices that do not pertain to any part of + the Derivative Works; and + + (d) If the Work includes a "NOTICE" text file as part of its + distribution, then any Derivative Works that You distribute must + include a readable copy of the attribution notices contained + within such NOTICE file, excluding those notices that do not + pertain to any part of the Derivative Works, in at least one + of the following places: within a NOTICE text file distributed + as part of the Derivative Works; within the Source form or + documentation, if provided along with the Derivative Works; or, + within a display generated by the Derivative Works, if and + wherever such third-party notices normally appear. The contents + of the NOTICE file are for informational purposes only and + do not modify the License. You may add Your own attribution + notices within Derivative Works that You distribute, alongside + or as an addendum to the NOTICE text from the Work, provided + that such additional attribution notices cannot be construed + as modifying the License. + + You may add Your own copyright statement to Your modifications and + may provide additional or different license terms and conditions + for use, reproduction, or distribution of Your modifications, or + for any such Derivative Works as a whole, provided Your use, + reproduction, and distribution of the Work otherwise complies with + the conditions stated in this License. + + 5. Submission of Contributions. Unless You explicitly state otherwise, + any Contribution intentionally submitted for inclusion in the Work + by You to the Licensor shall be under the terms and conditions of + this License, without any additional terms or conditions. + Notwithstanding the above, nothing herein shall supersede or modify + the terms of any separate license agreement you may have executed + with Licensor regarding such Contributions. + + 6. Trademarks. This License does not grant permission to use the trade + names, trademarks, service marks, or product names of the Licensor, + except as required for reasonable and customary use in describing the + origin of the Work and reproducing the content of the NOTICE file. + + 7. Disclaimer of Warranty. Unless required by applicable law or + agreed to in writing, Licensor provides the Work (and each + Contributor provides its Contributions) on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + implied, including, without limitation, any warranties or conditions + of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A + PARTICULAR PURPOSE. You are solely responsible for determining the + appropriateness of using or redistributing the Work and assume any + risks associated with Your exercise of permissions under this License. + + 8. Limitation of Liability. In no event and under no legal theory, + whether in tort (including negligence), contract, or otherwise, + unless required by applicable law (such as deliberate and grossly + negligent acts) or agreed to in writing, shall any Contributor be + liable to You for damages, including any direct, indirect, special, + incidental, or consequential damages of any character arising as a + result of this License or out of the use or inability to use the + Work (including but not limited to damages for loss of goodwill, + work stoppage, computer failure or malfunction, or any and all + other commercial damages or losses), even if such Contributor + has been advised of the possibility of such damages. + + 9. Accepting Warranty or Additional Liability. While redistributing + the Work or Derivative Works thereof, You may choose to offer, + and charge a fee for, acceptance of support, warranty, indemnity, + or other liability obligations and/or rights consistent with this + License. However, in accepting such obligations, You may act only + on Your own behalf and on Your sole responsibility, not on behalf + of any other Contributor, and only if You agree to indemnify, + defend, and hold each Contributor harmless for any liability + incurred by, or claims asserted against, such Contributor by reason + of your accepting any such warranty or additional liability. + + END OF TERMS AND CONDITIONS + + APPENDIX: How to apply the Apache License to your work. + + To apply the Apache License to your work, attach the following + boilerplate notice, with the fields enclosed by brackets "[]" + replaced with your own identifying information. (Don't include + the brackets!) The text should be enclosed in the appropriate + comment syntax for the file format. We also recommend that a + file or class name and description of purpose be included on the + same "printed page" as the copyright notice for easier + identification within third-party archives. + + Copyright [yyyy] [name of copyright owner] + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. diff --git a/README.md b/README.md new file mode 100644 index 00000000..0970b251 --- /dev/null +++ b/README.md @@ -0,0 +1,109 @@ +# Nitro Testnode + +Nitro-testnode brings up a full environment for local nitro testing (with or without Stylus support) including a dev-mode geth L1, and multiple instances with different roles. + +### Requirements + +* bash shell +* docker and docker-compose + +All must be installed in PATH. + +## Using latest nitro release (recommended) + +### Without Stylus support + +Check out the release branch of the repository. + +> Notice: release branch may be force-pushed at any time. + +```bash +git clone -b release --recurse-submodules https://github.com/OffchainLabs/nitro-testnode.git +cd nitro-testnode +``` + +Initialize the node + +```bash +./test-node.bash --init +``` +To see more options, use `--help`. + +### With Stylus support + +Check out the stylus branch of the repository. +> Notice: stylus branch may be force-pushed at any time. + +```bash +git clone -b stylus --recurse-submodules https://github.com/OffchainLabs/nitro-testnode.git +cd nitro-testnode +``` + +Initialize the node + +```bash +./test-node.bash --init +``` +To see more options, use `--help`. + +## Using current nitro code (local compilation) + +Check out the nitro or stylus repository. Use the test-node submodule of nitro repository. + +> Notice: testnode may not always be up-to-date with config options of current nitro node, and is not considered stable when operated in that way. + +### Without Stylus support +```bash +git clone --recurse-submodules https://github.com/OffchainLabs/nitro.git +cd nitro/nitro-testnode +``` + +Initialize the node in dev-mode (this will build the docker images from source) +```bash +./test-node.bash --init --dev +``` +To see more options, use `--help`. + +### With Stylus support +```bash +git clone --recurse-submodules https://github.com/OffchainLabs/stylus.git +cd stylus/nitro-testnode +``` + +Initialize the node in dev-mode (this will build the docker images from source) +```bash +./test-node.bash --init --dev +``` +To see more options, use `--help`. + +## Further information + +### Working with docker containers + +**sequencer** is the main docker to be used to access the nitro testchain. It's http and websocket interfaces are exposed at localhost ports 8547 and 8548 ports, respectively. + +Stopping, restarting nodes can be done with docker-compose. + +### Helper scripts + +Some helper scripts are provided for simple testing of basic actions. + +To fund the address 0x1111222233334444555566667777888899990000 on l2, use: + +```bash +./test-node.bash script send-l2 --to address_0x1111222233334444555566667777888899990000 +``` + +For help and further scripts, see: + +```bash +./test-node.bash script --help +``` + +## Contact + +Discord - [Arbitrum](https://discord.com/invite/5KE54JwyTs) + +Twitter: [Arbitrum](https://twitter.com/arbitrum) + + diff --git a/docker-compose.yaml b/docker-compose.yaml index 0c693f43..033d36af 100644 --- a/docker-compose.yaml +++ b/docker-compose.yaml @@ -1,5 +1,18 @@ version: "3.9" services: + da: + platform: linux/x86_64 + image: "ghcr.io/rollkit/local-celestia-devnet:v0.11.0-rc8" + ports: + - "26657:26657" + - "26658:26658" + - "26659:26659" + healthcheck: + test: ["CMD", "curl", "-f", "http://localhost:26659/header/1"] + interval: 10s + timeout: 5s + retries: 5 + start_period: 30s blockscout: depends_on: - postgres @@ -293,7 +306,7 @@ services: - "validator-data:/home/user/.arbitrum/local/nitro" - "l1keystore:/home/user/l1keystore" - "config:/config" - command: --conf.file /config/l3node_config.json --http.port 3347 --http.api net,web3,arb,debug --ws.port 3348 + command: --conf.file /config/l3node_config.json --http.port 3347 --http.api net,web3,arb,debug,eth --ws.port 3348 depends_on: - sequencer - validation_node diff --git a/scripts/accounts.ts b/scripts/accounts.ts index 030f5d56..ae3cdf6e 100644 --- a/scripts/accounts.ts +++ b/scripts/accounts.ts @@ -82,14 +82,14 @@ export function namedAddress( export const namedAccountHelpString = "Valid account names:\n" + - "funnel | sequencer | validator - known keys\n" + - "user_[Alphanumeric] - key will be generated from username\n" + - "threaduser_[Alphanumeric] - same as user_[Alphanumeric]_thread_[thread-id]\n" + - "key_0x[full private key] - user with specified private key"; -"\n" + + " funnel | sequencer | validator - known keys\n" + + " user_[Alphanumeric] - key will be generated from username\n" + + " threaduser_[Alphanumeric] - same as user_[Alphanumeric]_thread_[thread-id]\n" + + " key_0x[full private key] - user with specified private key\n" + + "\n" + "Valid addresses: any account name, or\n" + - "address_0x[full eth address]\n" + - "random"; + " address_0x[full eth address]\n" + + " random"; async function handlePrintAddress(argv: any, threadId: number) { console.log(namedAddress(argv.account, threadId)); diff --git a/scripts/config.ts b/scripts/config.ts index e93074ca..a4994cd2 100644 --- a/scripts/config.ts +++ b/scripts/config.ts @@ -32,7 +32,7 @@ DEPOSIT_CONTRACT_ADDRESS: 0x4242424242424242424242424242424242424242 } function writeGethGenesisConfig(argv: any) { - const gethConfig = ` + const gethConfig = ` { "config": { "ChainName": "l1_chain", @@ -152,10 +152,10 @@ function writeGethGenesisConfig(argv: any) { function writeConfigs(argv: any) { const valJwtSecret = path.join(consts.configpath, "val_jwt.hex") - const chainInfoFile = path.join(consts.configpath, "l2_chain_info.json") + const chainInfoFile = path.join(consts.configpath, "l2_chain_info.json") const baseConfig = { "parent-chain": { - "connection" : { + "connection": { "url": argv.l1url, }, "wallet": { @@ -206,16 +206,22 @@ function writeConfigs(argv: any) { "max-delay": "30s", "data-poster": { "redis-signer": { - "signing-key": "0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef" + "signing-key": "0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef" }, "wait-for-l1-finality": false } }, "block-validator": { - "validation-server" : { - "url": argv.validationNodeUrl, - "jwtsecret": valJwtSecret, - } + "validation-server": { + "url": argv.validationNodeUrl, + "jwtsecret": valJwtSecret, + } + }, + "celestia-cfg": { + "enable": true, + "rpc": "http://da:26658", + "namespace-id": "000008e5f679bf7116cb", + "auth-token": argv.authToken, } }, "persistent": { @@ -258,7 +264,7 @@ function writeConfigs(argv: any) { fs.writeFileSync(path.join(consts.configpath, "poster_config.json"), JSON.stringify(posterConfig)) let l3Config = JSON.parse(baseConfJSON) - l3Config["parent-chain"].connection.url = argv.l2url + l3Config["parent-chain"].connection.url = argv.l2url l3Config["parent-chain"].wallet.account = namedAccount("l3sequencer").address l3Config.chain.id = 333333 const l3ChainInfoFile = path.join(consts.configpath, "l3_chain_info.json") @@ -296,32 +302,32 @@ function writeConfigs(argv: any) { function writeL2ChainConfig(argv: any) { const l2ChainConfig = { - "chainId": 412346, - "homesteadBlock": 0, - "daoForkSupport": true, - "eip150Block": 0, - "eip150Hash": "0x0000000000000000000000000000000000000000000000000000000000000000", - "eip155Block": 0, - "eip158Block": 0, - "byzantiumBlock": 0, - "constantinopleBlock": 0, - "petersburgBlock": 0, - "istanbulBlock": 0, - "muirGlacierBlock": 0, - "berlinBlock": 0, - "londonBlock": 0, - "clique": { - "period": 0, - "epoch": 0 - }, - "arbitrum": { - "EnableArbOS": true, - "AllowDebugPrecompiles": true, - "DataAvailabilityCommittee": false, - "InitialArbOSVersion": 11, - "InitialChainOwner": "0x0000000000000000000000000000000000000000", - "GenesisBlockNum": 0 - } + "chainId": 412346, + "homesteadBlock": 0, + "daoForkSupport": true, + "eip150Block": 0, + "eip150Hash": "0x0000000000000000000000000000000000000000000000000000000000000000", + "eip155Block": 0, + "eip158Block": 0, + "byzantiumBlock": 0, + "constantinopleBlock": 0, + "petersburgBlock": 0, + "istanbulBlock": 0, + "muirGlacierBlock": 0, + "berlinBlock": 0, + "londonBlock": 0, + "clique": { + "period": 0, + "epoch": 0 + }, + "arbitrum": { + "EnableArbOS": true, + "AllowDebugPrecompiles": true, + "DataAvailabilityCommittee": false, + "InitialArbOSVersion": 11, + "InitialChainOwner": argv.l2owner, + "GenesisBlockNum": 0 + } } const l2ChainConfigJSON = JSON.stringify(l2ChainConfig) fs.writeFileSync(path.join(consts.configpath, "l2_chain_config.json"), l2ChainConfigJSON) @@ -329,32 +335,32 @@ function writeL2ChainConfig(argv: any) { function writeL3ChainConfig(argv: any) { const l3ChainConfig = { - "chainId": 333333, - "homesteadBlock": 0, - "daoForkSupport": true, - "eip150Block": 0, - "eip150Hash": "0x0000000000000000000000000000000000000000000000000000000000000000", - "eip155Block": 0, - "eip158Block": 0, - "byzantiumBlock": 0, - "constantinopleBlock": 0, - "petersburgBlock": 0, - "istanbulBlock": 0, - "muirGlacierBlock": 0, - "berlinBlock": 0, - "londonBlock": 0, - "clique": { - "period": 0, - "epoch": 0 - }, - "arbitrum": { - "EnableArbOS": true, - "AllowDebugPrecompiles": true, - "DataAvailabilityCommittee": false, - "InitialArbOSVersion": 11, - "InitialChainOwner": "0x0000000000000000000000000000000000000000", - "GenesisBlockNum": 0 - } + "chainId": 333333, + "homesteadBlock": 0, + "daoForkSupport": true, + "eip150Block": 0, + "eip150Hash": "0x0000000000000000000000000000000000000000000000000000000000000000", + "eip155Block": 0, + "eip158Block": 0, + "byzantiumBlock": 0, + "constantinopleBlock": 0, + "petersburgBlock": 0, + "istanbulBlock": 0, + "muirGlacierBlock": 0, + "berlinBlock": 0, + "londonBlock": 0, + "clique": { + "period": 0, + "epoch": 0 + }, + "arbitrum": { + "EnableArbOS": true, + "AllowDebugPrecompiles": true, + "DataAvailabilityCommittee": false, + "InitialArbOSVersion": 11, + "InitialChainOwner": "0x0000000000000000000000000000000000000000", + "GenesisBlockNum": 0 + } } const l3ChainConfigJSON = JSON.stringify(l3ChainConfig) fs.writeFileSync(path.join(consts.configpath, "l3_chain_config.json"), l3ChainConfigJSON) diff --git a/scripts/index.ts b/scripts/index.ts index 8e5e7086..8240e6f4 100644 --- a/scripts/index.ts +++ b/scripts/index.ts @@ -25,6 +25,8 @@ async function main() { l2url: { string: true, default: "ws://sequencer:8548" }, l3url: { string: true, default: "ws://l3node:3348" }, validationNodeUrl: { string: true, default: "ws://validation_node:8549" }, + authToken: { string: true }, + l2owner: { string: true, default: "0x3f1Eae7D46d88F08fc2F8ed27FCb2AB183EB2d0E" }, }) .options(stressOptions) .command(bridgeFundsCommand) diff --git a/test-node.bash b/test-node.bash index ae61555b..b7ac848f 100755 --- a/test-node.bash +++ b/test-node.bash @@ -2,7 +2,7 @@ set -e -NITRO_NODE_VERSION=offchainlabs/nitro-node:v2.1.0-beta.1-03a2aea-dev +NITRO_NODE_VERSION=offchainlabs/nitro-node:v2.1.1-e9d8842-dev BLOCKSCOUT_VERSION=offchainlabs/blockscout:v1.0.0-c8db5b1 mydir=`dirname $0` @@ -247,6 +247,26 @@ if $force_build; then docker-compose build --no-rm $NODES scripts fi +# Helper method that waits for a given URL to be up. Can't use +# cURL's built-in retry logic because connection reset errors +# are ignored unless you're using a very recent version of cURL +function wait_up { + echo -n "Waiting for $1 to come up..." + i=0 + until curl -s -f -o /dev/null "$1" + do + echo -n . + sleep 0.25 + + ((i=i+1)) + if [ "$i" -eq 300 ]; then + echo " Timeout!" >&2 + exit 1 + fi + done + echo "Done!" +} + if $force_init; then echo == Removing old data.. docker-compose down @@ -260,6 +280,11 @@ if $force_init; then docker volume rm $leftoverVolumes fi + echo == Bringing up Celestia Devnet + docker-compose up -d da + wait_up http://localhost:26659/header/1 + export CELESTIA_NODE_AUTH_TOKEN="$(docker exec nitro-testnode-da-1 celestia bridge auth admin --node.store /bridge)" + echo == Generating l1 keys docker-compose run scripts write-accounts docker-compose run --entrypoint sh geth -c "echo passphrase > /datadir/passphrase" @@ -306,14 +331,15 @@ if $force_init; then docker-compose run --entrypoint /usr/local/bin/deploy poster --l1conn ws://geth:8546 --l1keystore /home/user/l1keystore --sequencerAddress $sequenceraddress --ownerAddress $sequenceraddress --l1DeployAccount $sequenceraddress --l1deployment /config/deployment.json --authorizevalidators 10 --wasmrootpath /home/user/target/machines --l1chainid=$l1chainid --l2chainconfig /config/l2_chain_config.json --l2chainname arb-dev-test --l2chaininfo /config/deployed_chain_info.json docker-compose run --entrypoint sh poster -c "jq [.[]] /config/deployed_chain_info.json > /config/l2_chain_info.json" echo == Writing configs - docker-compose run scripts write-config + docker-compose run scripts write-config --authToken $CELESTIA_NODE_AUTH_TOKEN echo == Initializing redis docker-compose run scripts redis-init --redundancy $redundantsequencers - echo == Funding l2 funnel + echo == Funding l2 funnel and dev key docker-compose up -d $INITIAL_SEQ_NODES docker-compose run scripts bridge-funds --ethamount 100000 --wait + docker-compose run scripts bridge-funds --ethamount 1000 --wait --from "key_0x$devprivkey" if $tokenbridge; then echo == Deploying token bridge @@ -343,9 +369,10 @@ if $force_init; then docker-compose run --entrypoint /usr/local/bin/deploy poster --l1conn ws://sequencer:8548 --l1keystore /home/user/l1keystore --sequencerAddress $l3sequenceraddress --ownerAddress $l3owneraddress --l1DeployAccount $l3owneraddress --l1deployment /config/l3deployment.json --authorizevalidators 10 --wasmrootpath /home/user/target/machines --l1chainid=412346 --l2chainconfig /config/l3_chain_config.json --l2chainname orbit-dev-test --l2chaininfo /config/deployed_l3_chain_info.json docker-compose run --entrypoint sh poster -c "jq [.[]] /config/deployed_l3_chain_info.json > /config/l3_chain_info.json" - echo == Funding l3 funnel + echo == Funding l3 funnel and dev key docker-compose up -d l3node poster docker-compose run scripts bridge-to-l3 --ethamount 50000 --wait + docker-compose run scripts bridge-to-l3 --ethamount 500 --wait --from "key_0x$devprivkey" fi fi