Run Mainnet Node

About Mainnet.

NOTE: Ensure you meet the prerequisites before running a Node.

Run a Mainnet Unit Zero node by following the steps:

Prerequisites

  • Hardware: Ensure you have 4 CPU cores, 8 GB RAM, and 250+ GB SSD.

  • Account: Create a Waves Account wallet in Mainnet.

  • Docker: Install the software.

  • Waves Blockchain Data:

  • UNIT0 Chaindata

    • Download op-geth-chaindata.tar via the link.

  • Optional. For Mining Only.:

Step 1: Configure Node

  1. Create the main directory and go to it:

    mkdir main
    cd main

    NOTE: Ensure you have the read and write access to the directory.

  2. In the main directory, create the subdirectories:

    mkdir -p data/{secrets,waves,op-geth}
  3. In the data/waves subdirectory, unpack the blockchain_last.tar archive.

  4. In the data/op-geth subdirectory, unpack the op-geth-chaindata.tar archive.

  5. Generate a node key and a JWT secret:

    NOTE: You can re-use existing secrets if you ran besu previously.

    mkdir -p data/secrets
    openssl rand -hex 32 | tr -d "\n" > data/secrets/p2p-key
    openssl rand -hex 32 | tr -d "\n" > data/secrets/jwtsecret
  6. In the main directory:

    1. Create the waves.conf file and paste the code block into it:

      WARNING: You must:

      • Insert your Mainnet account's seed converted to a base58-encoded byte array.

      • Set a password as a string.

      • Specify your server's static IP address. If your server does not have a static IP address, remove the declared-address line.

      NOTE: execution-client-address has changed to "http://op-geth:8551".

      waves {
        blockchain.type = MAINNET
        extensions = [
          units.ConsensusClient
        ]
      
        wallet {
          seed = <YOUR-BASE58-ENCODED-SEED>
          password = <YOUR-PASSWORD-AS-STRING>
          file = null
        }
      
        network {
          port = 6868
          declared-address = "<YOUR_SERVER_IP_ADDRESS>:6868" # Example: 11.22.33.44:6868.
        }
      
        rest-api.bind-address = "0.0.0.0"
      }
      
      units {
        defaults {
          jwt-secret-file = /etc/secrets/jwtsecret
        }
        chains = [{
          chain-contract = 3PKgN8rfmvF7hK7RWJbpvkh59e1pQkUzero
          execution-client-address = "http://op-geth:8551"
      
          network {
            port = 6865
            known-peers = [
              "mainnet-htz-fsn1-1.unit0.dev:6865"
              "mainnet-htz-hel1-1.unit0.dev:6865"
              "mainnet-htz-hel1-12.wavesnodes.com:6865"
            ]
            declared-address = "<YOUR_SERVER_IP_ADDRESS>:6865" # Example: 11.22.33.44:6865.
          }
          mining-enable = yes # Set to `no` to run a validating node that doesn't mine.
        }]
      }
    2. Create the genesis.json file and paste the code block into it:

      {
        "alloc": {
          "0x0000000000000000000000000000000000006a7e": {
            "code": "0x60806040526004361061006e575f3560e01c806396f396c31161004c57806396f396c3146100e3578063c4a4326d14610105578063e984df0e1461011d578063fccc281314610131575f80fd5b806339dd5d1b146100725780637157405a146100b957806378338413146100ce575b5f80fd5b34801561007d575f80fd5b506100a161008c36600461059e565b5f6020819052908152604090205461ffff1681565b60405161ffff90911681526020015b60405180910390f35b3480156100c4575f80fd5b506100a161040081565b6100e16100dc3660046105b5565b61015c565b005b3480156100ee575f80fd5b506100f761044e565b6040519081526020016100b0565b348015610110575f80fd5b506100f76402540be40081565b348015610128575f80fd5b506100f7610468565b34801561013c575f80fd5b506101445f81565b6040516001600160a01b0390911681526020016100b0565b61016c6402540be40060016105fc565b34101561017834610478565b61019061018b6402540be40060016105fc565b610478565b6040516020016101a1929190610630565b604051602081830303815290604052906101d75760405162461bcd60e51b81526004016101ce9190610688565b60405180910390fd5b506101ef6402540be400677fffffffffffffff6105fc565b3411156101fb34610478565b61021561018b6402540be400677fffffffffffffff6105fc565b6040516020016102269291906106bd565b604051602081830303815290604052906102535760405162461bcd60e51b81526004016101ce9190610688565b50435f8181526020819052604090205461ffff166104009081119061027790610478565b604051602001610287919061070c565b604051602081830303815290604052906102b45760405162461bcd60e51b81526004016101ce9190610688565b505f818152602081905260408120805461ffff16916102d283610786565b91906101000a81548161ffff021916908361ffff160217905550505f6402540be400346102ff91906107a6565b9050346103116402540be400836105fc565b1461031b34610478565b6103296402540be400610478565b60405160200161033a9291906107c5565b604051602081830303815290604052906103675760405162461bcd60e51b81526004016101ce9190610688565b506040515f90819034908281818185825af1925050503d805f81146103a7576040519150601f19603f3d011682016040523d82523d5f602084013e6103ac565b606091505b50509050806103fd5760405162461bcd60e51b815260206004820152601e60248201527f4661696c656420746f2073656e6420746f206275726e2061646472657373000060448201526064016101ce565b604080516bffffffffffffffffffffffff1986168152600784900b60208201527ffeadaf04de8d7c2594453835b9a93b747e20e7a09a7fdb9280579a6dbaf131a8910160405180910390a150505050565b6104656402540be400677fffffffffffffff6105fc565b81565b6104656402540be40060016105fc565b6060815f0361049e5750506040805180820190915260018152600360fc1b602082015290565b815f5b81156104c757806104b181610814565b91506104c09050600a836107a6565b91506104a1565b5f8167ffffffffffffffff8111156104e1576104e161082c565b6040519080825280601f01601f19166020018201604052801561050b576020820181803683370190505b509050815b851561059557610521600182610840565b90505f61052f600a886107a6565b61053a90600a6105fc565b6105449088610840565b61054f906030610853565b90505f8160f81b90508084848151811061056b5761056b61086c565b60200101906001600160f81b03191690815f1a90535061058c600a896107a6565b97505050610510565b50949350505050565b5f602082840312156105ae575f80fd5b5035919050565b5f602082840312156105c5575f80fd5b81356bffffffffffffffffffffffff19811681146105e1575f80fd5b9392505050565b634e487b7160e01b5f52601160045260245ffd5b8082028115828204841417610613576106136105e8565b92915050565b5f81518060208401855e5f93019283525090919050565b6a029b2b73a103b30b63ab2960ad1b81525f61064f600b830185610619565b7f206d7573742062652067726561746572206f7220657175616c20746f20000000815261067f601d820185610619565b95945050505050565b602081525f82518060208401528060208501604085015e5f604082850101526040601f19601f83011684010191505092915050565b6a029b2b73a103b30b63ab2960ad1b81525f6106dc600b830185610619565b7f206d757374206265206c657373206f7220657175616c20746f20000000000000815261067f601a820185610619565b7f4d6178207472616e7366657273206c696d6974206f662000000000000000000081525f61073d6017830184610619565b7f207265616368656420696e207468697320626c6f636b2e2054727920746f207381527232b732103a3930b739b332b9399030b3b0b4b760691b60208201526033019392505050565b5f61ffff821661ffff810361079d5761079d6105e8565b60010192915050565b5f826107c057634e487b7160e01b5f52601260045260245ffd5b500490565b6a029b2b73a103b30b63ab2960ad1b81525f6107e4600b830185610619565b7f206d7573742062652061206d756c7469706c65206f6620000000000000000000815261067f6017820185610619565b5f60018201610825576108256105e8565b5060010190565b634e487b7160e01b5f52604160045260245ffd5b81810381811115610613576106136105e8565b60ff8181168382160190811115610613576106136105e8565b634e487b7160e01b5f52603260045260245ffdfea2646970667358221220106399f534da089226c14e2f183f8421d059a924c65c97d7e4f3e931c54fe1bb64736f6c634300081a0033",
            "balance": "0x0"
          }
        },
        "baseFeePerGas": "0x3b9aca00",
        "blobGasUsed": null,
        "coinbase": "0x0000000000000000000000000000000000000000",
        "config": {
          "chainId": 88811,
          "arrowGlacierBlock": 0,
          "berlinBlock": 0,
          "byzantiumBlock": 0,
          "cancunTime": 0,
          "constantinopleBlock": 0,
          "daoForkBlock": 0,
          "eip150Block": 0,
          "eip155Block": 0,
          "eip158Block": 0,
          "ethash": {},
          "grayGlacierBlock": 0,
          "homesteadBlock": 0,
          "istanbulBlock": 0,
          "londonBlock": 0,
          "muirGlacierBlock": 0,
          "petersburgBlock": 0,
          "shanghaiTime": 0,
          "terminalTotalDifficulty": 0,
          "terminalTotalDifficultyPassed": true,
          "blobSchedule": {
            "cancun": {
              "target": 3,
              "max": 6,
              "baseFeeUpdateFraction": 3338477
            },
            "prague": {
              "target": 6,
              "max": 9,
              "baseFeeUpdateFraction": 5007716
            }
          }
        },
        "difficulty": "0x0",
        "excessBlobGas": null,
        "extraData": "0x",
        "gasLimit": "0x989680",
        "gasUsed": "0x0",
        "mixHash": "0x0000000000000000000000000000000000000000000000000000000000000000",
        "nonce": "0x0",
        "number": "0x0",
        "parentHash": "0x0000000000000000000000000000000000000000000000000000000000000000",
        "timestamp": "0x6720960b"
      }
    3. Create the peers.toml file and paste the code block into it:

      [Node.P2P]
      BootstrapNodes = [
        "enode://02718d9a9c6f829c14ea3fd143e526130c70ae43956682cd234046ec932b1c21ca321c484bbb6aa766322ee7e0089d3405747f31d156ec0d67cd80482aede5d7@81.82.238.146:30301",
        "enode://02884ba9163fe92e1aa5a940a050d12c7d857fed092e43d242ebb63472a3e16e77d3b626d50ad790ed454e0e93607ba7ccebd5ac8423d5745df5066708709ac9@185.241.151.12:30303",
        "enode://153a16432e725691d50dae6b0700faf4c3a1b92bd6584ea707ca184f9e6732b6a9360ef86ac5b35a0858d6ef5e408c96eadb070ddea230c1f8ea7bec54613fb9@135.181.178.5:30303",
        "enode://1937134aff8287fddfc80d2583c9218521b15719dc7782ec85322493b973d02a76edf23ad30657f2d827e04a573e8a5bb2a0052a696a960365c2f13e69cbc0f3@95.216.152.163:30303",
        "enode://5355b769f711ab1951c788d664d0ccbf4bc989013ea3a4f419ab01d9930b524956be65442fa4b72e7de9c470ceeac796235fb198ad9ef49dab559139f17282e2@38.242.222.27:30303",
        "enode://6b534a07943cbca55d6dff834cac2c77f3e82895f51b25fa8cca1689b5cc0921f68453165fa5c736e55e4c61d0b73795445ed2099c09008358805467d07d2066@81.82.238.146:30302",
        "enode://85389460716e3e3247b51139de2f11f1b886c7eb3dc849e2e9673447c81922f9955b2d271834cae9c1625e69f7805e2c89362d4dd8cb0ca972668d7262252790@63.250.53.184:30303",
        "enode://b232ad7ca7bd6156e1adaa28ee0d064f3d973a67c0ad507a1b9dc32b3d64b307c754bc48c274aa96852f0041c2f85792681495e21f5baa62f06d3db8097af258@142.132.251.180:30303",
        "enode://ded10bb464eea90d2a61ab7fef15531dca698845d93f7fc191a5383c22b09de282982872515f398ae527d300c2d5324bae61199dbb354843e6792f2d13b87880@172.104.241.53:30303",
        "enode://e15d6f32cddc2a8e69885fc5c445b8ca7bafd91e9a7a834e89ed688150aa55df20fc7ff14d1fc5dd1e266c2b6a2f9dc75b1d6ed5f80ac71cb27f6ba8af12ba4b@213.238.172.133:30303",
        "enode://e8f7dbec4b146ef0ed1852cd05e3c0654f78a5784a7584f45bc0073bf6206d55764600b586148dfca42bd711c1c1bc02cb20abb2210320f830f003aacf074396@95.217.59.114:30303",
        "enode://edab526402907ccbbdf51950f09b964d9ebc1b51e1a9a1dca44fdaf823d85f84e513e95503f1e4d9e4e90355674819d52e46b014e054da5f199d5406ae6a5e22@185.31.163.22:30303"
      ]
      BootstrapNodesV5 = []
      StaticNodes = [
        "enode://02718d9a9c6f829c14ea3fd143e526130c70ae43956682cd234046ec932b1c21ca321c484bbb6aa766322ee7e0089d3405747f31d156ec0d67cd80482aede5d7@81.82.238.146:30301",
        "enode://02884ba9163fe92e1aa5a940a050d12c7d857fed092e43d242ebb63472a3e16e77d3b626d50ad790ed454e0e93607ba7ccebd5ac8423d5745df5066708709ac9@185.241.151.12:30303",
        "enode://153a16432e725691d50dae6b0700faf4c3a1b92bd6584ea707ca184f9e6732b6a9360ef86ac5b35a0858d6ef5e408c96eadb070ddea230c1f8ea7bec54613fb9@135.181.178.5:30303",
        "enode://1937134aff8287fddfc80d2583c9218521b15719dc7782ec85322493b973d02a76edf23ad30657f2d827e04a573e8a5bb2a0052a696a960365c2f13e69cbc0f3@95.216.152.163:30303",
        "enode://5355b769f711ab1951c788d664d0ccbf4bc989013ea3a4f419ab01d9930b524956be65442fa4b72e7de9c470ceeac796235fb198ad9ef49dab559139f17282e2@38.242.222.27:30303",
        "enode://6b534a07943cbca55d6dff834cac2c77f3e82895f51b25fa8cca1689b5cc0921f68453165fa5c736e55e4c61d0b73795445ed2099c09008358805467d07d2066@81.82.238.146:30302",
        "enode://85389460716e3e3247b51139de2f11f1b886c7eb3dc849e2e9673447c81922f9955b2d271834cae9c1625e69f7805e2c89362d4dd8cb0ca972668d7262252790@63.250.53.184:30303",
        "enode://b232ad7ca7bd6156e1adaa28ee0d064f3d973a67c0ad507a1b9dc32b3d64b307c754bc48c274aa96852f0041c2f85792681495e21f5baa62f06d3db8097af258@142.132.251.180:30303",
        "enode://ded10bb464eea90d2a61ab7fef15531dca698845d93f7fc191a5383c22b09de282982872515f398ae527d300c2d5324bae61199dbb354843e6792f2d13b87880@172.104.241.53:30303",
        "enode://e15d6f32cddc2a8e69885fc5c445b8ca7bafd91e9a7a834e89ed688150aa55df20fc7ff14d1fc5dd1e266c2b6a2f9dc75b1d6ed5f80ac71cb27f6ba8af12ba4b@213.238.172.133:30303",
        "enode://e8f7dbec4b146ef0ed1852cd05e3c0654f78a5784a7584f45bc0073bf6206d55764600b586148dfca42bd711c1c1bc02cb20abb2210320f830f003aacf074396@95.217.59.114:30303",
        "enode://edab526402907ccbbdf51950f09b964d9ebc1b51e1a9a1dca44fdaf823d85f84e513e95503f1e4d9e4e90355674819d52e46b014e054da5f199d5406ae6a5e22@185.31.163.22:30303"
      ]
    4. Create the docker-compose.yml file and paste the code block into it:

      services:
        op-geth:
          container_name: op-geth
          image: ghcr.io/unitsnetwork/op-geth:v1.101503.1-simulate-fixes
          stop_grace_period: 5m
          entrypoint: /bin/sh -c
          command:
            - |
              if [ ! -d /root/.ethereum/geth/chaindata ] ; then
                geth init /tmp/genesis.json
              else
                echo geth already initialized
              fi
              exec geth \
              --config=/etc/peers.toml \
              --syncmode=full \
              --verbosity=4 \
              --http \
              --http.addr=0.0.0.0 \
              --http.vhosts=* \
              --http.api=eth,web3,txpool,net,debug,engine \
              --http.corsdomain=* \
              --ws \
              --ws.addr=0.0.0.0 \
              --ws.api=eth,web3,txpool,net,debug \
              --ws.rpcprefix=/ \
              --ws.origins=* \
              --authrpc.addr=0.0.0.0 \
              --authrpc.vhosts=* \
              --authrpc.jwtsecret=/etc/secrets/jwtsecret \
              --nodekey=/etc/secrets/p2p-key \
              --log.file=/root/logs/op-geth.log \
              --log.format=terminal \
              --log.rotate \
              --log.compress \
              --log.maxbackups=100 \
              --log.maxsize=1024
          logging:
            driver: local
            options:
              max-size: 1g
              max-file: 5
          healthcheck:
            test: 'wget -qO /dev/null --header "content-type: application/json" --post-data {\"jsonrpc\":\"2.0\",\"method\":\"eth_blockNumber\",\"params\":[],\"id\":1}  http://127.0.0.1:8545'
            interval: 5s
            timeout: 1s
            retries: 10
          environment:
            GETH_BOOTNODES: ""
            GETH_NAT: extip:<YOUR_SERVER_IP_ADDRESS> # Example: extip:11.22.33.44. If your server does not have an external IP, set value to `any`, e.g. `GETH_NAT: any`
          ports:
            - '30303:30303/tcp'
            - '30303:30303/udp'
          volumes:
            - ./data/secrets:/etc/secrets:ro
            - ./data/op-geth:/root/.ethereum/chaindata
            - ./genesis.json:/tmp/genesis.json:ro
            - ./peers.toml:/etc/peers.toml:ro
            - ./logs/op-geth:/root/logs
      
        waves-node:
          container_name: waves-node
          image: ghcr.io/unitsnetwork/consensus-client:mainnet
          restart: unless-stopped
          stop_grace_period: 5m
          ports:
            - "6865:6865"
            - "6868:6868"
            - "127.0.0.1:6869:6869"
          volumes:
            - ./data/secrets:/etc/secrets:ro
            - ./data/waves:/var/lib/waves/data
            - ./waves.conf:/etc/waves/waves.conf:ro
            - ./logs/waves:/var/log/waves

Manual Updates

Note that newer images are not pulled when container restarts, neither for the consensus client, nor for op-geth. Automatic pulls have not been enabled to prevent newer incompatible images from being pulled unexpectedly.

You can run the following command to check which version of the consensus client you're running:

docker inspect ghcr.io/unitsnetwork/consensus-client:mainnet | grep revision

Sample output:

❯ docker inspect ghcr.io/unitsnetwork/consensus-client:mainnet | grep revision
                "org.opencontainers.image.revision": "e94e576e19ec50f1dc7e0b8d716b6d01344ad781",

e94e576e19ec50f1dc7e0b8d716b6d01344ad781 is git commit hash the image was built from. This hash can be useful for debugging purposes.

Step 2: Launch Node

WARNING: Docker and UFW have a known incompatibility. This issue makes it impossible to map a container's port to a host port (e.g., '8545:8545') and restrict external access using UFW at the same time.

In the docker-compose.yml file, execution client JSON-RPC port (8545) and Waves node's HTTP API port (6869) are mapped to the host's local address: 127.0.0.1:8545:8545 and 127.0.0.1:6869:6869. This configuration ensures the endpoints are accessible only to consumers running locally on the host machine.

If you need to allow access from external addresses, adjust the port mappings to 8545:8545 and 6869:6869. Alternatively, consider using a reverse proxy like nginx for controlled access.

  1. Launch your node via the command:

    docker compose up -d

    NOTE: The Execution chain is synced with the network log indicates that the Consensus Client is synchronized with the network.

Step 3 (Optional): Start Mining

  1. Go to the Waves dApp page.

  2. In the header of the page, click Sign in. The Connect a wallet to get started window will open.

    The “Sign in” button in the header of the Waves dApp page
  3. In the Connect a wallet to get started window, select one of the sign-in options:

    • Sign in with Keeper.

    • Sign in with Exchange(Seed).

    • Sign in with Exchange(Email).

    • Sign in with Metamask.

      The sign-in options in the “Connect a wallet to get started” window

    The wallet extension will open.

  4. In the wallet extension, sign in to your node account.

  5. In the join block:

    1. In the rewardAddressHex field, enter your account address.

      LIMITATIONS: The data field accepts input only in string format.

    2. Click Invoke.

      NOTE: The transaction fee is 0.005 WAVES.

      A node account adddress entered
    3. Confirm the transaction in your wallet. Nodes chosen for block creation receive epoch rewards. Learn more about block generation probability.

NOTE: If you need help, contact us via our Developer chat for assistance.

Last updated