Run Testnet UNIT1 Node

About Testnet UNIT1.

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

Run a Testnet UNIT1 node by following the steps:

Prerequisites

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/besu logs/besu data/waves
  3. In the data/waves subdirectory, unpack the blockchain_last.tar archive.

  4. Grant the user with the uid 1000 the write access to the subdirectories:

    chown 1000 data/besu logs/besu
  5. Generate a node key and a JWT secret:

    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 Testnet 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.

      waves {
        l2 {
          chain-contract-address = 3Mu7v4TAoTUQgpWaThQNFJo3Nx3BH6owhtf
          execution-client-address = "http://besu:8551"
          jwt-secret-file = /etc/secrets/jwtsecret
      
          network {
            port = 6850
            known-peers = [
              "testnet-l2-htz-hel1-1.wavesnodes.com:6850"
              "testnet-l2-htz-hel1-2.wavesnodes.com:6850"
              "testnet-htz-nbg1-1.wavesnodes.com:6850"
            ]
            declared-address = "<your server's IP address>:6850"   # Example: 11.22.33.44:6850
          }
          mining-enable = yes  
        }  
      }
    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": 888171,
          "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
        },
        "difficulty": "0x0",
        "excessBlobGas": null,
        "extraData": "0x",
        "gasLimit": "0x4c4b40",
        "gasUsed": "0x0",
        "mixHash": "0x0000000000000000000000000000000000000000000000000000000000000000",
        "nonce": "0x0",
        "number": "0x0",
        "parentHash": "0x0000000000000000000000000000000000000000000000000000000000000000",
        "timestamp": "0x6707c1c0"
      }

      NOTE: To verify that Besu is running with the correct genesis file, execute the following command on your host: curl -H 'content-type: application/json' -sd '{"jsonrpc":"2.0","method":"eth_getBlockByNumber","params":["0x0", false],"id":1}' 127.0.0.1:8545 | jq .result.hash. The expected result is: 0x55650023cd3c23f18d88073486a6caf4d4436b81a401877eb07a5ce6ba6689c2.

    3. Create the log4j2.xml file and paste the code block into it:

      <?xml version="1.0" encoding="UTF-8"?>
      <Configuration status="INFO" monitorInterval="5">
      
          <Properties>
              <Property name="root.log.pattern">%date %-5level [%-25.25thread] %35.35c{1.} - %msg%n%throwable</Property>
          </Properties>
      
          <Appenders>
              <Console name="Console" target="SYSTEM_OUT">
                  <PatternLayout alwaysWriteExceptions="false" pattern='${root.log.pattern}'/>
              </Console>
              <RollingFile name="RollingFile" fileName="/opt/besu/logs/besu.log" filePattern="/opt/besu/logs/besu-%d{yyyy-MM-dd}-%i.log.gz" >
                  <PatternLayout alwaysWriteExceptions="false" pattern='${root.log.pattern}'/>
                  <Policies>
                      <TimeBasedTriggeringPolicy />
                      <SizeBasedTriggeringPolicy size="1000 MB" />
                  </Policies>
                  <DefaultRolloverStrategy max="20"/>
              </RollingFile>
          </Appenders>
      
          <Loggers>
              <Logger name="oshi" level="OFF" additivity="false"/>
              <Logger name="io.vertx" level="OFF" additivity="false"/>
              <Root>
                  <AppenderRef ref="Console" level="INFO" />
                  <AppenderRef ref="RollingFile" level="TRACE" />
              </Root>
          </Loggers>
      
      </Configuration>
    4. Create the static-nodes.json file and paste the code block into it:

      [
        "enode://02af745f500a317e9f864e7b529e6797ebaf7eac8ecd4b68be8cc8f5f5615322cce74abb68d29ef837607c2df8cf2f51e6e389313301b789d13fbedcc7b9bbe7@95.31.7.226:31313",
        "enode://4c7bacdd8b0cf8486fef2205901a2332cccaedcce1fa12662b74b6c71fa663f067116cd19aa9ece5ad414d1e200fcd8d922108de579b7a4f35adacbf3b75228c@5.2.78.97:30304",
        "enode://a5202854470733aa13ec3d653948dc1b35c1a9a2c1db0ba4bf5325b01e750e8c9a392f3a7e51d6df157f37b457209e30d26fa6be0ca9805e5562c670fd4bb951@194.61.28.96:30304",
        "enode://b107600a91c65dcfc4a9e22e4770408b171f594b0d94f9a8ae2dfd0eed33c6039431641cf9121f57cc45ef349bc12f8ca481aa625924e5e16e4ef18da1bb9dbd@173.249.16.213:30304"
      ]
    5. Create the docker-compose.yml file and paste the code block into it:

      services:
        besu:
          container_name: besu
          image: hyperledger/besu:latest
          pull_policy: always
          stop_grace_period: 5m
          command:
            - --logging=ALL
            - --host-allowlist=*
            - --rpc-http-enabled
            - --rpc-http-api=ETH,NET,WEB3,TXPOOL,TRACE
            - --rpc-http-cors-origins=all
            - --rpc-ws-enabled
            - --discovery-enabled=true
            - --engine-rpc-enabled
            - --engine-jwt-secret=/etc/secrets/jwtsecret
            - --engine-host-allowlist=*
            - --node-private-key-file=/etc/secrets/p2p-key
            - --data-path=/var/lib/besu
            - --genesis-file=/etc/besu/genesis.json
            - --static-nodes-file=/etc/besu/static-nodes.json
            - --data-storage-format=BONSAI
            - --network-id=888171
            - --target-gas-limit=5000000
          volumes:
            - ./genesis.json:/etc/besu/genesis.json
            - ./data/secrets:/etc/secrets:ro
            - ./log4j2.xml:/etc/besu/log4j2.xml
            - ./data/besu:/var/lib/besu
            - ./logs/besu:/opt/besu/logs
            - ./static-nodes.json:/etc/besu/static-nodes.json
          ports:
            - '30303:30303/tcp'
            - '30303:30303/udp'
            - '127.0.0.1:8545:8545'
          environment:
            - LOG4J_CONFIGURATION_FILE=/etc/besu/log4j2.xml
      
        besu-check:
          image: curlimages/curl:8.8.0
          command: >
            --retry 20 
            --retry-all-errors 
            --retry-max-time 60 
            -d '{"jsonrpc":"2.0","method":"engine_exchangeCapabilities","params":[[]],"id":1}' 
            http://besu:8551
          depends_on:
            - besu
      
        waves-node:
          container_name: waves-node
          image: ghcr.io/unitsnetwork/consensus-client:testnet
          ports:
            - "6865:6865"
            - "6868:6868"
            - "127.0.0.1:6869:6869"
          environment:
            - JAVA_OPTS=-Dwaves.config.directory=/etc/waves -Dlogback.file.level=TRACE
          volumes:
            - ./data/secrets:/etc/secrets:ro
            - ./data/waves:/var/lib/waves/data
            - ./waves.conf:/etc/waves/waves.conf:ro
            - ./logs/waves:/var/log/waves
          depends_on:
            besu-check:
              condition: service_completed_successfully

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, Besu's 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): Configure Shared Setup

NOTE: With the shared setup, a single node with the Consensus Client module can participate in multiple Units networks simultaneously. This configuration allows the node to earn mining rewards in each network independently.

  1. In the main directory, create the besu.yml file and paste the code block into it:

     services:
       besu:
         container_name: besu
         image: hyperledger/besu:latest
         pull_policy: always
         stop_grace_period: 5m
         command:
           - --logging=ALL
           - --host-allowlist=*
           - --rpc-http-enabled
           - --rpc-http-api=ETH,NET,WEB3,TXPOOL,TRACE
           - --rpc-http-cors-origins=all
           - --rpc-ws-enabled
           - --discovery-enabled=true
           - --engine-rpc-enabled
           - --engine-jwt-secret=/etc/secrets/jwtsecret
           - --engine-host-allowlist=*
           - --node-private-key-file=/etc/secrets/p2p-key
           - --data-path=/var/lib/besu
           - --genesis-file=/etc/besu/genesis.json
           - --static-nodes-file=/etc/besu/static-nodes.json
           - --data-storage-format=BONSAI
         volumes:
           - ./data/secrets:/etc/secrets:ro
           - ./log4j2.xml:/etc/besu/log4j2.xml
         environment:
           - LOG4J_CONFIGURATION_FILE=/etc/besu/log4j2.xml
  2. Replace the content of the files:

    1. For docker-compose.yml:

      services:
        besu:
          container_name: besu
          extends:
            file: ./besu.yml
            service: besu
          environment:
            - BESU_NETWORK_ID=88817
            - BESU_TARGET_GAS_LIMIT=15000000
          volumes:
            - ./genesis.json:/etc/besu/genesis.json
            - ./data/besu:/var/lib/besu
            - ./logs/besu:/opt/besu/logs
            - ./static-nodes.json:/etc/besu/static-nodes.json
          ports:
            - '30303:30303/tcp'
            - '30303:30303/udp'
            - '127.0.0.1:8545:8545'
      
        besu-2:
          container_name: besu-2
          extends:
            file: ./besu.yml
            service: besu
          environment:
            - BESU_NETWORK_ID=888171
            - BESU_TARGET_GAS_LIMIT=5000000
          volumes:
            - ./genesis-2.json:/etc/besu/genesis.json
            - ./data/besu-2:/var/lib/besu
            - ./logs/besu-2:/opt/besu/logs
            - ./static-nodes-2.json:/etc/besu/static-nodes.json
          ports:
            - '30304:30303/tcp'
            - '30304:30303/udp'
            - '127.0.0.1:8546:8545'
      
        waves-node:
          container_name: waves-node
          image: ghcr.io/unitsnetwork/consensus-client:testnet-2
          ports:
            - "6850:6850"
            - "6865:6865"
            - "6868:6868"
            - "127.0.0.1:6869:6869"
          environment:
            - JAVA_OPTS=-Dwaves.config.directory=/etc/waves -Dlogback.file.level=TRACE
          volumes:
            - ./data/secrets:/etc/secrets:ro
            - ./data/waves:/var/lib/waves/data
            - ./waves.conf:/etc/waves/waves.conf:ro
            - ./logs/waves:/var/log/waves

      NOTE: The updates items:

      • The Waves node image: ghcr.io/unitsnetwork/consensus-client:testnet-2.

      • The extra port for the Eaves node: '6850:6850'.

    2. For waves.conf:

      waves {
        blockchain.type = TESTNET
        extensions = [
          units.ConsensusClient
        ]
      
        wallet {
          seed = <your-base58-encoded-seed>
          password = <some-string-as-password>
          file = null
        }
      
        network {
          port = 6868
          declared-address = "<your server's 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 = 3Msx4Aq69zWUKy4d1wyKnQ4ofzEDAfv5Ngf
          execution-client-address = "http://besu:8551"
          
          network {
            port = 6865
            known-peers = [
              "testnet-l2-htz-hel1-1.wavesnodes.com:6865"
              "testnet-l2-htz-hel1-2.wavesnodes.com:6865"
              "testnet-htz-nbg1-1.wavesnodes.com:6865"
            ]
            declared-address = "<your server's IP address>:6865"   # Example: 11.22.33.44:6865
          }
          mining-enable = yes
        },{
          chain-contract = 3Mu7v4TAoTUQgpWaThQNFJo3Nx3BH6owhtf
          execution-client-address = "http://besu-2:8551"
          
          network {
            port = 6850
            known-peers = [
              "testnet-l2-htz-hel1-1.wavesnodes.com:6850"
              "testnet-l2-htz-hel1-2.wavesnodes.com:6850"
              "testnet-htz-nbg1-1.wavesnodes.com:6850"
            ]
            declared-address = "<your server's IP address>:6850"   # Example: 11.22.33.44:6850
          }
          mining-enable = yes
        }]
      }
  3. Save the content:

    • From genesis.json to genesis-2.json.

    • From static-nodes.json to static-nodes-2.json.

  4. Create the data and log directories for the besu-2 container:

    mkdir -p data/besu-2 logs/besu-2
    chown 1000 data/besu-2 logs/besu-2

Step 4 (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.

  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 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.

    3. Confirm the transaction in your wallet. Nodes chosen for block creation receive both epoch rewards and transaction fees. Learn more about block generation probability.

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

Last updated