# Mantle (https://docs.axelar.dev/infrastructure/chain-nodes/mantle)



<Callout title="Consensus chain">
  This chain is verified by Axelar validators. Before setting up this node,
  [set up your Axelar validator](https://docs.axelar.dev/llms.mdx/infrastructure/validators/content.md).
  Once the node is running, connect it to `vald` as described in [Verify consensus
  chains](https://docs.axelar.dev/llms.mdx/infrastructure/verifiers/consensus-chains/content.md).
</Callout>

<Callout type="warn" title="Check the official documentation">
  The node setup steps below follow Mantle's own documentation at the time of
  writing and may be out of date. Check the [official
  documentation](https://github.com/mantlenetworkio/networks/blob/main/run-node-mainnet.md) before you start. The Axelar-specific steps (connecting
  the node to `vald` or `ampd`) are maintained here.
</Callout>

Set up your Mantle RPC node

## Requirements [#requirements]

* [Setup your Axelar validator](https://docs.axelar.dev/llms.mdx/infrastructure/validators/content.md)
* Minimum hardware requirements: 8 AWS vCPU+, 16GB RAM, 500GB+ SSD free storage space.
* MacOS or Ubuntu 22.04 (tested on 22.04)
* [Official Documentation](https://github.com/mantlenetworkio/networks/blob/main/run-node-mainnet.md)

## Prerequisites [#prerequisites]

Install docker

```bash
sudo apt update
sudo apt install snapd
sudo apt-get install jq -y
snap install docker
curl -L https://foundry.paradigm.xyz | bash && source /root/.bashrc && foundryup
```

* [Common Docker Compose Commands](https://docs.axelar.dev/llms.mdx/infrastructure/chain-nodes/optimism/content.md#common-node-operations)

### Download configs [#download-configs]

```bash
git clone https://github.com/mantlenetworkio/networks.git mantlenetworks
cd mantlenetworks
```

### Generate JWT secret and p2p node key [#generate-jwt-secret-and-p2p-node-key]

<Tabs items="[&#x22;Mainnet&#x22;,&#x22;Testnet&#x22;]">
  <Tab value="Mainnet">
    ```bash
    mkdir -p mainnet/secret
    node -e "console.log(require('crypto').randomBytes(32).toString('hex'))" > mainnet/secret/jwt_secret_txt
    cast w n |grep -i "Private Key" |awk -F ": " '{print $2}' |sed 's/0x//' > mainnet/secret/p2p_node_key_txt
    ```
  </Tab>

  <Tab value="Testnet">
    ```bash
    mkdir sepolia/secret
    node -e "console.log(require('crypto').randomBytes(32).toString('hex'))" > sepolia/secret/jwt_secret_txt
    cast w n |grep -i "Private Key" |awk -F ": " '{print $2}' |sed 's/0x//' > sepolia/secret/p2p_node_key_txt
    ```
  </Tab>
</Tabs>

### Update node config [#update-node-config]

<Callout type="warning" emoji="⚠️">
  Make sure to set `ETH1_HTTP` to your own Ethereum RPC node for security.
</Callout>

<Tabs items="[&#x22;Mainnet&#x22;,&#x22;Testnet&#x22;]">
  <Tab value="Mainnet">
    Set the following config option in
    [mainnet/envs/geth.env](https://github.com/mantlenetworkio/networks/blob/99344b50e3b792d91a83ba89304ef6f479585ae7/mainnet/envs/geth.env#L31):
    `bash ETH1_HTTP=your_ethereum_mainnet_l1_node GCMODE=full # or archive `
  </Tab>

  <Tab value="Testnet">
    Set the following config option in `docker-compose-sepolia.yml` `bash
        OP_NODE_L1_ETH_RPC=your_ethereum_sepolia_l1_node `
  </Tab>
</Tabs>

### Download latest snapshot [#download-latest-snapshot]

Download the latest snapshot for a quicker sync: [Mainnet](https://github.com/mantlenetworkio/networks/blob/main/run-node-mainnetv2.md) | [Testnet](https://github.com/mantlenetworkio/networks/blob/main/run-node-sepolia.md)

<Tabs items="[&#x22;Mainnet&#x22;,&#x22;Testnet&#x22;]">
  <Tab value="Mainnet">
    ```bash mkdir -p ./data/mainnet-geth tarball="[latest snapshot].tar" wget
    https://s3.ap-southeast-1.amazonaws.com/snapshot.mantle.xyz/${tarball}
    tar vxf ${tarball} -C ./data/mainnet-geth 
    ```
  </Tab>

  <Tab value="Testnet">
    ```bash mkdir -p ./data/geth tarball="[latest snapshot].tar" wget
    https://s3.ap-southeast-1.amazonaws.com/static.testnet.mantle.xyz/${tarball}
    tar vxf ${tarball} -C ./data/geth 
    ```
  </Tab>
</Tabs>

### Start the node [#start-the-node]

<Tabs items="[&#x22;Mainnet&#x22;,&#x22;Testnet&#x22;]">
  <Tab value="Mainnet">
    `bash docker compose -f docker-compose-mainnetv2.yml up -d `
  </Tab>

  <Tab value="Testnet">
    `bash docker compose -f docker-compose-sepolia.yml up -d `
  </Tab>
</Tabs>

An output similar to the following will be shown:

```bash
[+] Running 6/6
 ✔ replica 5 layers [⣿⣿⣿⣿⣿]      0B/0B      Pulled
   ✔ 0cdfa0c98ed7 Pull complete
   ✔ da01580fbcc6 Pull complete
[+] Running 1/1
 ✔ Container mantlenetworks-replica-1  Started
```

After it is done, verify by listing the services and their status

<Tabs items="[&#x22;Mainnet&#x22;,&#x22;Testnet&#x22;]">
  <Tab value="Mainnet">
    `bash docker compose -f docker-compose-mainnetv2.yml ps `
  </Tab>

  <Tab value="Testnet">
    `bash docker compose -f docker-compose-sepolia.yml ps `
  </Tab>
</Tabs>

You should see these 2 services running

```bash
NAME                       IMAGE                                  COMMAND             SERVICE             CREATED             STATUS              PORTS
NAME                       IMAGE                                    COMMAND                  SERVICE             CREATED             STATUS                          PORTS
mantlenetworks-op-geth-1   mantlenetworkio/op-geth:v1.0.0-alpha.1   "geth --datadir=/db …"   op-geth             7 minutes ago       Up 7 minutes                    0.0.0.0:8545-8546->8545-8546/tcp, :::8545-8546->8545-8546/tcp, 0.0.0.0:8551->8551/tcp, :::8551->8551/tcp, 30303/tcp, 30303/udp
mantlenetworks-op-node-1   mantlenetworkio/op-node:v1.0.0-alpha.1   "op-node"                op-node             7 minutes ago       Up 7 minutes
```

## Check logs [#check-logs]

#### Verify mantle geth logs [#verify-mantle-geth-logs]

```bash
docker compose logs op-geth --since 2m -f
```

```bash
mantlenetworks-op-geth-1  | INFO [04-01|11:02:21.459] Starting peer-to-peer node               instance=Geth/v0.1.0-unstable-e1c72d53-20240312/linux-amd64/go1.20.14
mantlenetworks-op-geth-1  | INFO [04-01|11:02:21.502] New local node record                    seq=1,711,969,341,501 id=d90665a63ea4440a ip=127.0.0.1 udp=30300 tcp=30300
mantlenetworks-op-geth-1  | INFO [04-01|11:02:21.502] Started P2P networking                   self=enode://904642693e46d2f64234e635d4b3777e23d9227920ea27eaf62d76387eee2ecfe3a1c8881f2cc71b1c68b2e148a6215fc9e4c361b285f1bec9c5f0e92978e408@127.0.0.1:30300
mantlenetworks-op-geth-1  | INFO [04-01|11:02:21.503] IPC endpoint opened                      url=/db/geth.ipc
mantlenetworks-op-geth-1  | INFO [04-01|11:02:21.503] Loaded JWT secret file                   path=/secret/jwt_secret_txt crc32=0x61dfbe40
mantlenetworks-op-geth-1  | INFO [04-01|11:02:21.503] HTTP server started                      endpoint=[::]:8545 auth=false prefix= cors=* vhosts=*
mantlenetworks-op-geth-1  | INFO [04-01|11:02:21.503] WebSocket enabled                        url=ws://[::]:8546
mantlenetworks-op-geth-1  | INFO [04-01|11:02:21.503] WebSocket enabled                        url=ws://[::]:8551
mantlenetworks-op-geth-1  | INFO [04-01|11:02:21.503] HTTP server started                      endpoint=[::]:8551 auth=true  prefix= cors=localhost vhosts=*
mantlenetworks-op-geth-1  | INFO [04-01|11:02:23.907] New local node record                    seq=1,711,969,341,502 id=d90665a63ea4440a ip=65.108.239.113 udp=30300 tcp=30300
```

It will not import new headers until your op-node is synced, once your op-node is synced, your blast-geth logs should look like this

```bash
mantlenetworks-op-geth-1  | INFO [02-29|08:08:15.219] Starting work on payload                 id=0x48323feb74b0d35a
mantlenetworks-op-geth-1  | INFO [02-29|08:08:15.237] Imported new potential chain segment     number=3083 hash=96c535..584bd5 blocks=1 txs=1 mgas=0.047 elapsed=16.962ms    mgasps=2.768 age=1mo3w1d snapdiffs=606.60KiB triedirty=0.00B
mantlenetworks-op-geth-1  | INFO [02-29|08:08:15.243] Chain head was updated                   number=3083 hash=96c535..584bd5 root=52730a..6a9c02 elapsed=5.42431ms   age=1mo3w1d
mantlenetworks-op-geth-1  | INFO [02-29|08:08:15.256] Starting work on payload                 id=0x180234ae531457a1
mantlenetworks-op-geth-1  | INFO [02-29|08:08:15.274] Imported new potential chain segment     number=3084 hash=9687bc..de7e94 blocks=1 txs=1 mgas=0.047 elapsed=16.911ms    mgasps=2.776 age=1mo3w1d snapdiffs=606.78KiB triedirty=0.00B
mantlenetworks-op-geth-1  | INFO [02-29|08:08:15.285] Chain head was updated                   number=3084 hash=9687bc..de7e94 root=8081fb..43e327 elapsed=10.075637ms age=1mo3w1d
mantlenetworks-op-geth-1  | INFO [02-29|08:08:15.307] Starting work on payload                 id=0x44c95802c3652dbd
```

#### Verify OP node logs [#verify-op-node-logs]

```bash
docker compose logs op-node --since 2m -f
```

You should see logs like

```bash
mantlenetworks-op-node-1  | t=2024-02-27T07:43:46+0000 lvl=info msg="Starting JSON-RPC server"
mantlenetworks-op-node-1  | t=2024-02-27T07:43:46+0000 lvl=info msg="metrics disabled"
mantlenetworks-op-node-1  | t=2024-02-27T07:43:46+0000 lvl=info msg="Starting execution engine driver"
mantlenetworks-op-node-1  | t=2024-02-27T07:43:46+0000 lvl=info msg="Starting driver"                   sequencerEnabled=false sequencerStopped=false
mantlenetworks-op-node-1  | t=2024-02-27T07:43:46+0000 lvl=info msg="Rollup node started"
mantlenetworks-op-node-1  | t=2024-02-27T07:43:46+0000 lvl=info msg="State loop started"
mantlenetworks-op-node-1  | t=2024-02-27T07:43:46+0000 lvl=info msg="Loaded current L2 heads"           unsafe=0x26a1c0faad7b041f34569a1bb383f00ab74b335883a44bed53e9f41ced5fd906:0 safe=0x26a1c0faad7b041f34569a1bb383f00ab74b335883a44bed53e9f41ced5fd906:0 finalized=0x26a1c0faad7b041f34569a1bb383f00ab74b335883a44bed53e9f41ced5fd906:0 unsafe_origin=0x17728cf4d8e0b4f292d2390a869fd7c632d39e72efb00ca3462b4387c6aa2437:5044255 safe_origin=0x17728cf4d8e0b4f292d2390a869fd7c632d39e72efb00ca3462b4387c6aa2437:5044255
mantlenetworks-op-node-1  | t=2024-02-27T07:43:47+0000 lvl=info msg="Walking back L1Block by number"    curr=0x17728cf4d8e0b4f292d2390a869fd7c632d39e72efb00ca3462b4387c6aa2437:5044255 next=0x17728cf4d8e0b4f292d2390a869fd7c632d39e72efb00ca3462b4387c6aa2437:5044255 l2block=0x26a1c0faad7b041f34569a1bb383f00ab74b335883a44bed53e9f41ced5fd906:0
mantlenetworks-op-node-1  | t=2024-02-27T07:43:47+0000 lvl=info msg="Hit finalized L2 head, returning immediately" unsafe=0x26a1c0faad7b041f34569a1bb383f00ab74b335883a44bed53e9f41ced5fd906:0 safe=0x26a1c0faad7b041f34569a1bb383f00ab74b335883a44bed53e9f41ced5fd906:0 finalized=0x26a1c0faad7b041f34569a1bb383f00ab74b335883a44bed53e9f41ced5fd906:0 unsafe_origin=0x17728cf4d8e0b4f292d2390a869fd7c632d39e72efb00ca3462b4387c6aa2437:5044255 safe_origin=0x17728cf4d8e0b4f292d2390a869fd7c632d39e72efb00ca3462b4387c6aa2437:5044255
mantlenetworks-op-node-1  | t=2024-02-27T07:43:47+0000 lvl=info msg="Sync progress"                     reason="reset derivation work" l2_finalized=0x26a1c0faad7b041f34569a1bb383f00ab74b335883a44bed53e9f41ced5fd906:0 l2_safe=0x26a1c0faad7b041f34569a1bb383f00ab74b335883a44bed53e9f41ced5fd906:0 l2_unsafe=0x26a1c0faad7b041f34569a1bb383f00ab74b335883a44bed53e9f41ced5fd906:0 l2_engineSyncTarget=0x26a1c0faad7b041f34569a1bb383f00ab74b335883a44bed53e9f41ced5fd906:0 l2_time=1,704,686,688 l1_derived=0x17728cf4d8e0b4f292d2390a869fd7c632d39e72efb00ca3462b4387c6aa2437:5044255
```

### Verify node sync status [#verify-node-sync-status]

RPC Endpoint

```bash
echo "$(curl -4 ifconfig.co):8545"
```

#### Method 1: [#method-1]

```bash
curl -X POST [rpc] -H "Content-Type: application/json" --data '{"jsonrpc":"2.0","method":"eth_blockNumber","params":[],"id":1}' | jq
```

If you get something like this in response to the above rpc call, your node is setup correctly

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": "0x4e4c"
}
```

You can use a [hex to number convertor](https://www.binaryhexconverter.com/hex-to-decimal-converter) to get the block height

#### Method 2: [#method-2]

You can also check your status by connecting to geth console

```bash
docker exec -it mantlenetworks-op-geth-1 geth attach http://localhost:8545
> eth.blockNumber
1209 # it will show you the latest block - number here is just an example
```

You can compare the block height on your node with explorer ([mainnet](https://explorer.mantle.xyz) or [testnet](https://explorer.testnet.mantle.xyz)),
use your RPC node only when it has caught up with the latest block height.

### Configure vald [#configure-vald]

In order for `vald` to connect to your mantle node, your `rpc_addr` should be exposed in
vald's `config.toml`

<Tabs items="[&#x22;Mainnet&#x22;,&#x22;Testnet&#x22;]">
  <Tab value="Mainnet">
    ```bash [[axelar_bridge_evm]] name = "mantle" rpc_addr = "http://IP:PORT"
    start-with-bridge = true 
    ```
  </Tab>

  <Tab value="Testnet">
    ```bash [[axelar_bridge_evm]] name = "mantle" rpc_addr = "http://IP:PORT"
    start-with-bridge = true 

    ```
  </Tab>
</Tabs>


---

All pages of these docs, as Markdown: https://docs.axelar.dev/llms.txt