diff --git a/chain/Dockerfile b/chain/Dockerfile index cf79b089b..eb4b86789 100644 --- a/chain/Dockerfile +++ b/chain/Dockerfile @@ -14,9 +14,9 @@ EXPOSE 26656 26657 1317 9090 8546 8545 9601 USER 0 -COPY scripts/start-rollup.sh start-rollup.sh -RUN chmod +x start-rollup.sh +COPY scripts/start-sequencer.sh start-sequencer.sh +RUN chmod +x start-sequencer.sh HEALTHCHECK --interval=5s --timeout=80s CMD curl --fail http://localhost:26657 || exit 1 -ENTRYPOINT ["./start-rollup.sh"] +ENTRYPOINT ["./start-sequencer.sh"] diff --git a/chain/README.md b/chain/README.md index 6bd0e81f7..f3669ab35 100644 --- a/chain/README.md +++ b/chain/README.md @@ -1,199 +1,185 @@ -# Polaris Integrated Cosmos Chain +# World Engine EVM Base Shard (world-evm) ## Installation -### From Binary +### From Source -The easiest way to install a Cosmos-SDK Blockchain running Polaris is to download a pre-built binary. You can find the latest binaries on the [releases](https://github.com/polaris/releases) page. +Clone the repo -### Makefile +`git clone https://github.com/Argus-Labs/world-engine.git` -To install the World Engine blockchain in your bin, making it globally accessable from your terminal, run this command in the `chain` directory: +Run the `install-rollup` makefile command -```bash -make install -``` +`make install-rollup` -To verify installation was successful, run: +Verify installation success -```bash -world version -``` - -### From Prebuilt Docker Image - -Pull `chain` prebuild Docker Image: -```bash -docker pull us-docker.pkg.dev/argus-labs/world-engine/chain: -``` +`world-evm version` -Run `chain` container, supply the DA_BASE_URL and DA_AUTH_TOKEN environment variables accordingly: -```bash -docker run -it --rm -e DA_BASE_URL=http://celestia-da-layer-url:26658 -e DA_AUTH_TOKEN=celestia-da-later-token us-docker.pkg.dev/argus-labs/world-engine/chain:latest -``` +## Running a Test Sequencer Node w/ Docker Compose -See the Docker Compose section below for instructions on running both the `chain` and `Celestia Devnet` stack. +World Engine provides simple scripts to start a testing sequencer node with a local celestia devnet for DA. -### From Source +Assuming you have the repository cloned and are in the root directory, run the following make command: -**Step 1: Install Golang & Foundry** +`make rollup` -Go v1.20+ or higher is required for Polaris +The rollups exposes the default ports that comes with the Cosmos SDK. Head over to the Cosmos SDK documentation to learn more about which ports are exposed: https://docs.cosmos.network/v0.50/learn/advanced/grpc_rest -1. Install [Go 1.20+ from the official site](https://go.dev/dl/) or the method of your choice. Ensure that your `GOPATH` and `GOBIN` environment variables are properly set up by using the following commands: +### From Prebuilt Docker Image - For Ubuntu: +If you want to make your own setup script, but still want to use the world-evm binary, you can grab a docker image of the chain here: - ```sh - cd $HOME - sudo apt-get install golang -y - export PATH=$PATH:/usr/local/go/bin - export PATH=$PATH:$(go env GOPATH)/bin - ``` +Prebuilt Docker Image: +```bash +us-docker.pkg.dev/argus-labs/world-engine/chain: +``` - For Mac: +## Features - ```sh - cd $HOME - brew install go - export PATH=$PATH:/opt/homebrew/bin/go - export PATH=$PATH:$(go env GOPATH)/bin - ``` +### Game Shard Transaction Sequencer -2. Confirm your Go installation by checking the version: +The rollup is extended via a special gRPC server that game shards can connect to for the purpose of submitting and storing transactions to the base shard. - ```sh - go version - ``` +This gRPC server runs, by default, at port `9601`, but can be configured by setting the `SHARD_SEQUENCER_PORT` environment variable. -[Foundry](https://book.getfoundry.sh/getting-started/installation) is required for Polaris +### Router -3. Install Foundry: - ```sh - curl -L https://foundry.paradigm.xyz | bash - ``` +The rollup provides an extension to its underlying EVM environment with a specialized precompile that allows messages to be forwarded from smart contracts to game shards that implement the router server. -**Step 2: Get Polaris source code** +In order for the router to communicate with game shards, their namespaces must be mapped to their gRPC address. These are stored through the x/namespace module, and can be updated via an authority address. The authority address is loaded at the start of the application from an environment variable named `NAMESPACE_AUTHORITY_ADDR`. If unset, the authority for the namespace module will be set to the governance module address, allowing for namespaces to be added via governance. -Clone the `polaris` repo from the [official repo](https://github.com/berachain/polaris/) and check -out the `main` branch for the latest stable release. -Build the binary. +When namespace authority is set, you can update the namespaces via the `register` command provided by world-evm. ```bash -cd $HOME -git clone https://github.com/berachain/polaris -cd polaris -git checkout main +world-evm tx namespace register foobar foo.bar.com:9020 ``` -**Step 3: Build the Node Software** -Run the following command to install `world` to your `GOPATH` and build the node. `world` is the node daemon and CLI for interacting with a polaris node. +#### Using the Router in Solidity -```bash -make install -``` +In order to use the precompile, you first need to copy over the precompile contract code. The contract lives at: -**Step 4: Verify your installation** +`chain/precompile/contracts/src/cosmos/precompile/router.sol` -Verify your installation with the following command: +The precompile address will always be `0x356833c4666fFB6bFccbF8D600fa7282290dE073`. -```bash -world version --long -``` +Instantiating the precompile: -A successful installation will return the following: +```solidity +// the path of import will change depending on where you copied the +// precompile contract code to. +import {IRouter} from "./precompile/router.sol"; + +contract SomeGame { + IRouter private immutable router; + + constructor () { + router = IRouter(0x356833c4666fFB6bFccbF8D600fa7282290dE073); + } +} -```bash -name: world-engine -server_name: world -version: -commit: -build_tags: netgo,ledger -go: go version go1.20.4 darwin/amd64 ``` -## Running a Local Network +#### Sending Messages -After ensuring dependecies are installed correctly, run the following command to start a local development network. +First, a smart contract needs structs that are mirrors of the EVM enabled message structs found in the game shard. -```bash -mage start -``` +For example: -## Running using Docker Compose +Game Shard Foo message: +```go +type Foo struct { + Bar int64 + Baz string +} -Start the `chain` and `celestia-devnet` using `chain/docker-compose.yml`, make sure to follow these steps: -- Start local-celestia-devnet - ``` - docker compose up celestia-devnet -d --wait - ``` +type FooResult struct { + Success bool +} +``` -- Get DA_AUTH_TOKEN (Celestia RPC Authentication token) from celestia_devnet logs. - ``` - export DA_AUTH_TOKEN=$(docker logs celestia_devnet 2>&1 | grep CELESTIA_NODE_AUTH_TOKEN -A 5 | tail -n 1) - echo "Auth Token >> $DA_AUTH_TOKEN" - ``` +Solidity Mirror: +```solidity +struct Foo { + int64 Bar; + string Baz; +} -- Start the `chain` / `evm_base_shard` - ``` - docker compose up chain --build --detach - ``` +struct FooResult { + bool Success; +} +``` -## Features +Then, we simply abi encode an instance of the struct, and pass it along to the router, along with the name of the message we are sending, and the namespace of the game shard instance we want to send the message to: -### Game Shard Tx Sequencer +```solidity +Foo memory fooMsg = Foo(420, "we are so back") +bytes memory encodedFoomsg = abi.encode(fooMsg) +bool ok = router.sendMessage(encodedFooMsg, "foo", "game-shard-1"); +``` -The rollup is extended via a special gRPC server that game shards can connect to for the purpose of submitting and storing transactions to the base shard. +#### Receiving Message Results -This gRPC server runs, by default, at port `9601`, but can be configured by setting the `SHARD_SEQUENCER_PORT` environment variable. +Receiving message results must be done in a separate transaction, due to World Engine's asynchronous architecture. In order to get the results of a message, we use another precompile method from the router: `messageResult`. -### Router -The rollup provides an extension to it's underlying EVM environment with a specialized precompile that allows messages to be forwarded from smart contracts to game shards that implement the router server. +messageResult takes in the transaction hash of the original EVM transaction that triggered the cross-shard transaction. It returns the abi encoded message result, an error message, and an arbitrary status code. -The router must be informed of the game shard's server address by setting the environment variable `CARDINAL_EVM_LISTENER_ADDR`. +```solidity + (bytes memory txResult, string memory errMsg, uint32 code) = router.messageResult(txHash); +``` -#### Using the Router in Solidity +To decode the result, use `abi.decode` -In order to use the precompile, you first need to copy over the precompile contract code. The contract lives at: +```solidity +FooResult memory res = abi.decode(txResult, (FooResult)); +``` +The following codes may be returned: -`chain/contracts/src/cosmos/precompile/router.sol` +Cardinal Codes: +1: CodeSuccess +2: CodeTxFailed +3: CodeNoResult +4: CodeServerUnresponsive +5: CodeUnauthorized +6: CodeUnsupportedMessage +7: CodeInvalidFormat -The precompile address will always be `0x356833c4666fFB6bFccbF8D600fa7282290dE073`. +EVM Base Shard Codes: +100: CodeConnectionError +101: CodeServerError -Instantiating the precompile is done like so: +### Querying Game Shards +Game shards can be queried using the same contructs as above, however, the precompile will return the results synchronously. ```solidity -// the path of import will change depending on where you copied the -// precompile contract code to. -import {IRouter} from "./precompile/router.sol"; + QueryLocation memory q = QueryLocation(name); + bytes memory queryBz = abi.encode(q); + bytes memory bz = router.query(queryBz, queryLocationName, Namespace); + QueryLocationResponse memory res = abi.decode(bz, (QueryLocationResponse)); +``` -contract SomeGame { - IRouter public immutable router; +# Running the Sequencer - constructor () { - router = IRouter(0x356833c4666fFB6bFccbF8D600fa7282290dE073); - } -} +Below are the following environment variables needed to run the sequencer. -``` +## Faucet -## Environment Variables -The following env variables must be set for the following features. +- FAUCET_ADDR +The application is capable of supplying a faucet address with funds. Setting the `FAUCET_ADDR` will keep an account topped up to be used in a faucet. ## x/namespace - NAMESPACE_AUTHORITY_ADDR= - the address of the account you want to be able to update namespace mappings with. ### Secure gRPC Connections -For production environments, you'll likely want to setup secure connections between gRPC servers handling system transactions. -To make use of these, set the following environment variables to the path of your SSL certification files: +For production environments, you'll want to setup secure connections between gRPC servers handling cross-shard communication. To make use of these, set the following environment variables to the path of your SSL certification files: - SERVER_CERT_PATH= - SERVER_KEY_PATH= - CLIENT_CERT_PATH= -### Celestia DA Layer Connections +### DA Layer The following variables are used to configure the connection to the Data Availability layer (Celestia). Required: @@ -219,8 +205,31 @@ Optional: - DA_BASE_URL=(default: `http://celestia-devnet:26658`) - Celestia RPC base URL, default value are based on `docker-compose.yml` services URL. + URL for the base DA client. - DA_CONFIG=(default: `{"base_url":"'$DA_BASE_URL'","timeout":60000000000,"fee":6000,"gas_limit":6000000,"fee":600000,"auth_token":"'$DA_AUTH_TOKEN'"}` - Configure custom json formatted value for `--rollkit.da_config` arguments, see: `chain/scripts/start-rollup.sh`. + Configuration for the DA. + +### Cosmos SDK + +The following variables are used to configure the Cosmos SDK node. + +- VALIDATOR_NAME + Moniker for the node. +- CHAIN_ID + ChainID of the rollup. +- KEY_NAME + The name of the key to use for the genesis account. +- KEY_MNEMONIC + The mnemonic to use for the genesis account. +- KEY_BACKEND + The backend type to use for the genesis account. +- TOKEN_AMOUNT + The amount of tokens to supply the genesis account with. +- STAKING_AMOUNT + The amount of tokens to use for stake. +- MIN_GAS_PRICE + The minimum gas prices for accounts executing transactions on this node. +- TOKEN_DENOM + The denom of the staking token. \ No newline at end of file diff --git a/chain/app/app.go b/chain/app/app.go index 12ddbff62..965cc68f4 100644 --- a/chain/app/app.go +++ b/chain/app/app.go @@ -24,6 +24,8 @@ import ( "github.com/cometbft/cometbft/abci/types" sdk "github.com/cosmos/cosmos-sdk/types" "io" + "math" + "math/big" "os" "path/filepath" evmtypes "pkg.berachain.dev/polaris/cosmos/x/evm/types" @@ -120,6 +122,8 @@ type App struct { Router router.Router ShardSequencer *shard.Sequencer + faucetAddr sdk.AccAddress + // simulation manager sm *module.SimulationManager } @@ -293,6 +297,9 @@ func (app *App) FinalizeBlockHook(ctx sdk.Context, _ *types.RequestFinalizeBlock } } } + if app.faucetAddr != nil { + app.EVMKeeper.SetBalance(ctx, app.faucetAddr, big.NewInt(math.MaxInt64)) + } return nil } diff --git a/chain/app/plugins.go b/chain/app/plugins.go index ab4849307..261a6402f 100644 --- a/chain/app/plugins.go +++ b/chain/app/plugins.go @@ -1,6 +1,7 @@ package app import ( + sdk "github.com/cosmos/cosmos-sdk/types" "os" "pkg.world.dev/world-engine/chain/router" "pkg.world.dev/world-engine/chain/shard" @@ -38,4 +39,16 @@ func (app *App) setPlugins(logger log.Logger) { } else { logger.Info("router is not running") } + + addr := os.Getenv("FAUCET_ADDR") + if addr != "" { + logger.Info("setting up faucet address", "address string", addr) + acc, err := sdk.AccAddressFromBech32(addr) + if err != nil { + panic(err) + } + app.faucetAddr = acc + } else { + logger.Info("no faucet address provided") + } } diff --git a/chain/router/router.go b/chain/router/router.go index e68ac4366..83a06a8a5 100644 --- a/chain/router/router.go +++ b/chain/router/router.go @@ -200,9 +200,6 @@ func (r *routerImpl) Query(ctx context.Context, request []byte, resource, namesp return res.Response, nil } -// TODO: we eventually want this to work via namespace mappings by registered game shards. -// https://linear.app/arguslabs/issue/WORLD-13/update-router-to-look-up-the-correct-namespace-mapping -// https://linear.app/arguslabs/issue/WORLD-370/register-game-shard-on-base-shard func (r *routerImpl) getConnectionForNamespace(ns string) (routerv1.MsgClient, error) { ctx := r.getSDKCtx() res, err := r.getAddr(ctx, &namespacetypes.AddressRequest{Namespace: ns}) diff --git a/chain/scripts/start.sh b/chain/scripts/start-celestia-devnet.sh similarity index 52% rename from chain/scripts/start.sh rename to chain/scripts/start-celestia-devnet.sh index 802ccda3e..ba3c91b0d 100755 --- a/chain/scripts/start.sh +++ b/chain/scripts/start-celestia-devnet.sh @@ -4,23 +4,6 @@ set -o errexit set -o nounset set -o pipefail -# Define a flag variable to determine whether to use --build -build_flag="" - -# Parse command-line arguments -while [[ "$#" -gt 0 ]]; do - case "$1" in - --build) - build_flag="--build" # Set the flag to "--build" if --build is present - shift # Shift the argument index to skip the flag - ;; - *) - echo "Unknown argument: $1" - exit 1 - ;; - esac -done - docker compose up celestia-devnet -d --wait # Initialize DA_AUTH_TOKEN to an empty value @@ -39,11 +22,6 @@ while [ -z "$DA_AUTH_TOKEN" ]; do echo "DA_AUTH_TOKEN set: $DA_AUTH_TOKEN" else echo "DA_AUTH_TOKEN is not set yet. Retrying..." - sleep 1 # Adjust the sleep duration as needed + sleep 2 # Adjust the sleep duration as needed fi done - -echo "starting rollup..." - -# Run the command with or without the --build flag based on the build_flag -docker compose up $build_flag chain --exit-code-from celestia-devnet diff --git a/chain/scripts/start-rollup.sh b/chain/scripts/start-sequencer.sh similarity index 55% rename from chain/scripts/start-rollup.sh rename to chain/scripts/start-sequencer.sh index b1491585f..dbfc052d7 100755 --- a/chain/scripts/start-rollup.sh +++ b/chain/scripts/start-sequencer.sh @@ -10,22 +10,25 @@ if [ -z "${DA_AUTH_TOKEN:-}" ]; then exit 1 fi -# Default variables -VALIDATOR_NAME=validator1 -CHAIN_ID=argus_90000-1 -KEY_NAME=argus-key -TOKEN_AMOUNT="10000000000000000000000000ether" -STAKING_AMOUNT="1000000000ether" +# Cosmos-SDK related vars +VALIDATOR_NAME=${VALIDATOR_NAME:-"testingValidator"} +CHAIN_ID=${CHAIN_ID:-"world-1"} +KEY_NAME=${KEY_NAME:-"world_admin"} +KEY_MNEMONIC=${KEY_MNEMONIC:-"enact adjust liberty squirrel bulk ticket invest tissue antique window thank slam unknown fury script among bread social switch glide wool clog flag enroll"} +KEY_BACKEND=${KEY_BACKEND:-"test"} +TOKEN_AMOUNT=${TOKEN_AMOUNT:-"10000000000000000000000000ether"} +STAKING_AMOUNT=${STAKING_AMOUNT:-"1000000000ether"} +MIN_GAS_PRICE=${MIN_GAS_PRICE:-"0ether"} +TOKEN_DENOM=${TOKEN_DENOM:-"ether"} +FAUCET_ADDR=${FAUCET_ADDR:-"world142fg37yzx04cslgeflezzh83wa4xlmjpms0sg5"} # DA related variables/configuration DA_BASE_URL="${DA_BASE_URL:-"http://celestia-devnet:26658"}" DA_BLOCK_HEIGHT=${DA_BLOCK_HEIGHT:-0} BLOCK_TIME="${BLOCK_TIME:-"10s"}" - # Use 10 bytes hex encoded value (generate random value: `openssl rand -hex 10`) DA_NAMESPACE_ID="${DA_NAMESPACE_ID:-"67480c4a88c4d12935d4"}" - -DA_CONFIG='{"base_url":"'$DA_BASE_URL'","timeout":60000000000,"fee":6000,"gas_limit":6000000,"fee":600000,"auth_token":"'$DA_AUTH_TOKEN'"}' +DA_CONFIG=${DA_CONFIG:-'{"base_url":"'$DA_BASE_URL'","timeout":60000000000,"fee":6000,"gas_limit":6000000,"fee":600000,"auth_token":"'$DA_AUTH_TOKEN'"}'} echo "DA_NAMESPACE_ID: $DA_NAMESPACE_ID" echo "DA_CONFIG: $DA_CONFIG" @@ -34,22 +37,22 @@ echo "DA_CONFIG: $DA_CONFIG" world-evm comet unsafe-reset-all rm -rf /root/.world-evm/ -world-evm init $VALIDATOR_NAME --chain-id $CHAIN_ID +# Initialize node +world-evm init $VALIDATOR_NAME --chain-id $CHAIN_ID --default-denom $TOKEN_DENOM -printf "enact adjust liberty squirrel bulk ticket invest tissue antique window thank slam unknown fury script among bread social switch glide wool clog flag enroll\n\n" | world-evm keys add $KEY_NAME --keyring-backend="test" --algo="eth_secp256k1" -i -world-evm genesis add-genesis-account $KEY_NAME $TOKEN_AMOUNT --keyring-backend test -world-evm genesis gentx $KEY_NAME $STAKING_AMOUNT --chain-id $CHAIN_ID --keyring-backend test +printf "%s\n\n" "${KEY_MNEMONIC}" | world-evm keys add $KEY_NAME --keyring-backend=$KEY_BACKEND --algo="eth_secp256k1" -i +world-evm genesis add-genesis-account $KEY_NAME $TOKEN_AMOUNT --keyring-backend=$KEY_BACKEND +world-evm genesis gentx $KEY_NAME $STAKING_AMOUNT --chain-id $CHAIN_ID --keyring-backend=$KEY_BACKEND world-evm genesis collect-gentxs +# Comet Rest API sed -i'.bak' 's#"tcp://127.0.0.1:26657"#"tcp://0.0.0.0:26657"#g' /root/.world-evm/config/config.toml - +# Cosmos SDK enable API server sed -i '/api\]/,/\[/ s/enable = false/enable = true/' /root/.world-evm/config/app.toml - # Cosmos SDK gRPC listener sed -i'.bak' 's#"localhost:9090"#"0.0.0.0:9090"#g' /root/.world-evm/config/app.toml # Cosmos SDK API server listener sed -i'.bak' 's#localhost:1317#0.0.0.0:1317#g' /root/.world-evm/config/app.toml -sed -i 's/"stake"/"ether"/g' /root/.world-evm/config/genesis.json - -world-evm start --rollkit.aggregator true --rollkit.da_layer celestia --rollkit.da_config=$DA_CONFIG --rollkit.namespace_id $DA_NAMESPACE_ID --rollkit.da_start_height $DA_BLOCK_HEIGHT --rollkit.block_time $BLOCK_TIME --minimum-gas-prices 0eth +# start the node. +world-evm start --rollkit.aggregator true --rollkit.da_layer celestia --rollkit.da_config=$DA_CONFIG --rollkit.namespace_id $DA_NAMESPACE_ID --rollkit.da_start_height $DA_BLOCK_HEIGHT --rollkit.block_time $BLOCK_TIME --minimum-gas-prices $MIN_GAS_PRICE diff --git a/docker-compose.yml b/docker-compose.yml index f7456d010..05a4ac80b 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -64,8 +64,8 @@ services: ## Env vars reference: https://github.com/Argus-Labs/world-engine/blob/main/chain/README.md ## Get AUTH_TOKEN from celestia_devnet container: `docker logs celestia_devnet 2>&1 | grep CELESTIA_NODE_AUTH_TOKEN -A 5 | tail -n 1` - DA_AUTH_TOKEN=${DA_AUTH_TOKEN:-} - - CARDINAL_EVM_LISTENER_ADDR=game:9020 - - NAMESPACE_AUTHORITY_ADDR=world142fg37yzx04cslgeflezzh83wa4xlmjpms0sg5 + - NAMESPACE_AUTHORITY_ADDR=${NAMESPACE_AUTHORITY_ADDR:-world142fg37yzx04cslgeflezzh83wa4xlmjpms0sg5} + - FAUCET_ADDR=${FAUCET_ADDR:-world142fg37yzx04cslgeflezzh83wa4xlmjpms0sg5} build: context: chain dockerfile: Dockerfile diff --git a/makefiles/build.mk b/makefiles/build.mk index 3a772710c..bc59ce6ce 100644 --- a/makefiles/build.mk +++ b/makefiles/build.mk @@ -3,7 +3,8 @@ rift: .PHONY: rift rollup: - ./chain/scripts/start.sh --build + @. ${CURDIR}/chain/scripts/start-celestia-devnet.sh && \ + docker compose up chain --build --exit-code-from celestia-devnet game: cd internal/e2e/tester/cardinal && go mod vendor