├── Dockerfile ├── LICENSE ├── README.md ├── README_misc.md ├── docker-compose.yml ├── pruner ├── Dockerfile ├── cron │ └── cron.d │ │ └── prune └── scripts │ └── prune.sh └── pub_key.asc /Dockerfile: -------------------------------------------------------------------------------- 1 | FROM ubuntu:24.04 2 | 3 | ARG USERNAME=hluser 4 | ARG USER_UID=10000 5 | ARG USER_GID=$USER_UID 6 | 7 | # Define URLs as environment variables 8 | ARG PUB_KEY_URL=https://raw.githubusercontent.com/hyperliquid-dex/node/refs/heads/main/pub_key.asc 9 | ARG HL_VISOR_URL=https://binaries.hyperliquid-testnet.xyz/Testnet/hl-visor 10 | ARG HL_VISOR_ASC_URL=https://binaries.hyperliquid-testnet.xyz/Testnet/hl-visor.asc 11 | 12 | # Create user and install dependencies 13 | RUN groupadd --gid $USER_GID $USERNAME \ 14 | && useradd --uid $USER_UID --gid $USER_GID -m $USERNAME \ 15 | && apt-get update -y && apt-get install -y curl gnupg \ 16 | && apt-get clean && rm -rf /var/lib/apt/lists/* \ 17 | && mkdir -p /home/$USERNAME/hl/data && chown -R $USERNAME:$USERNAME /home/$USERNAME/hl 18 | 19 | USER $USERNAME 20 | WORKDIR /home/$USERNAME 21 | 22 | # Configure chain to testnet 23 | RUN echo '{"chain": "Testnet"}' > /home/$USERNAME/visor.json 24 | 25 | # Import GPG public key 26 | RUN curl -o /home/$USERNAME/pub_key.asc $PUB_KEY_URL \ 27 | && gpg --import /home/$USERNAME/pub_key.asc 28 | 29 | # Download and verify hl-visor binary 30 | RUN curl -o /home/$USERNAME/hl-visor $HL_VISOR_URL \ 31 | && curl -o /home/$USERNAME/hl-visor.asc $HL_VISOR_ASC_URL \ 32 | && gpg --verify /home/$USERNAME/hl-visor.asc /home/$USERNAME/hl-visor \ 33 | && chmod +x /home/$USERNAME/hl-visor 34 | 35 | # Expose gossip ports 36 | EXPOSE 4000-4010 37 | 38 | # Run a non-validating node 39 | ENTRYPOINT ["/home/hluser/hl-visor", "run-non-validator", "--replica-cmds-style", "recent-actions"] 40 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | Apache License
Version 2.0, January 2004
http://www.apache.org/licenses/ 2 | TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION 3 | 1. Definitions. 4 | "License" shall mean the terms and conditions for use, reproduction, and distribution as defined by Sections 1 through 9 of this document. 5 | "Licensor" shall mean the copyright owner or entity authorized by the copyright owner that is granting the License. 6 | "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. 7 | "You" (or "Your") shall mean an individual or Legal Entity exercising permissions granted by this License. 8 | "Source" form shall mean the preferred form for making modifications, including but not limited to software source code, documentation source, and configuration files. 9 | "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. 10 | "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). 11 | "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. 12 | "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." 13 | "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. 14 | 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. 15 | 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. 16 | 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: 17 | You must give any other recipients of the Work or Derivative Works a copy of this License; and 18 | You must cause any modified files to carry prominent notices stating that You changed the files; and 19 | 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 20 | 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. 21 | 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. 22 | 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. 23 | 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. 24 | 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. 25 | 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. 26 | 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. 27 | END OF TERMS AND CONDITIONS 28 | 29 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Running a node 2 | 3 | ## Machine Specs 4 | Recommended minimum hardware: 4 CPU cores, 32 GB RAM, 200 GB disk. 5 | 6 | Currently only Ubuntu 24.04 is supported. 7 | 8 | Ports 4001 and 4002 are used for gossip and must be open to the public. Otherwise, the node IP address will be deprioritized by peers in the p2p network. 9 | 10 | For lowest latency, run the node in Tokyo, Japan. 11 | 12 | --- 13 | 14 | ## Setup 15 | 16 | ### Configure Chain 17 | For testing, configure your chain as follows: 18 | 19 | - **Testnet**: 20 | ```bash 21 | echo '{"chain": "Testnet"}' > ~/visor.json 22 | ``` 23 | - **Mainnet**: 24 | ```bash 25 | echo '{"chain": "Mainnet"}' > ~/visor.json 26 | ``` 27 | 28 | ### Download the Visor Binary 29 | The visor binary spawns and manages the child node process. 30 | 31 | - **Testnet**: 32 | ```bash 33 | curl https://binaries.hyperliquid-testnet.xyz/Testnet/hl-visor > ~/hl-visor && chmod a+x ~/hl-visor 34 | ``` 35 | - **Mainnet**: 36 | ```bash 37 | curl https://binaries.hyperliquid.xyz/Mainnet/hl-visor > ~/hl-visor && chmod a+x ~/hl-visor 38 | ``` 39 | 40 | --- 41 | 42 | ## Verify Signed Binaries 43 | 44 | Binaries are signed for extra security. The public key is found at `pub_key.asc` in this repo. 45 | 46 | 1. **Import the Key:** 47 | ```bash 48 | gpg --import pub_key.asc 49 | ``` 50 | 51 | 2. **Verify the Binary:** 52 | Signatures are located at `{binary}.asc`. 53 | 54 | - **Testnet**: 55 | ```bash 56 | curl https://binaries.hyperliquid-testnet.xyz/Testnet/hl-visor.asc > hl-visor.asc 57 | gpg --verify hl-visor.asc hl-visor 58 | ``` 59 | - **Mainnet**: 60 | ```bash 61 | curl https://binaries.hyperliquid.xyz/Mainnet/hl-visor.asc > hl-visor.asc 62 | gpg --verify hl-visor.asc hl-visor 63 | ``` 64 | 65 | `hl-visor` will also verify `hl-node` automatically and will not upgrade on verification failure. **Important:** The public key must be imported as shown above. Optionally, sign the key using `gpg --sign-key` to avoid warnings when verifying its signatures. 66 | 67 | --- 68 | 69 | ## Running Non-Validator 70 | 71 | To start a non-validator node: 72 | 73 | ```bash 74 | ~/hl-visor run-non-validator 75 | ``` 76 | 77 | It may take a while as the node navigates the network to find an appropriate peer to stream from. Logs such as `applied block X` indicate that the node is streaming live data. 78 | 79 | > **Note:** The same command is used regardless of whether your chain is set to Testnet or Mainnet (as configured in `~/visor.json`). 80 | 81 | --- 82 | 83 | ## Reading L1 Data 84 | 85 | The node writes data to `~/hl/data`. With default settings, the network will generate around 100 GB of logs per day, so it is recommended to archive or delete old files. 86 | 87 | For more information about examples and all the data types that can be written, refer to [docs](https://hyperliquid.gitbook.io/hyperliquid-docs/for-developers/nodes/reading-l1-data). 88 | 89 | - **Transaction Blocks:** 90 | Blocks parsed as transactions are streamed to: 91 | ``` 92 | ~/hl/data/replica_cmds/{start_time}/{date}/{height} 93 | ``` 94 | 95 | - **State Snapshots:** 96 | State snapshots are saved every 10,000 blocks to: 97 | ``` 98 | ~/hl/data/periodic_abci_states/{date}/{height}.rmp 99 | ``` 100 | 101 | To translate the state to JSON for examination: 102 | 103 | - **Testnet**: 104 | ```bash 105 | ./hl-node --chain Testnet translate-abci-state ~/hl/data/periodic_abci_states/{date}/{height}.rmp /tmp/out.json 106 | ``` 107 | - **Mainnet**: 108 | ```bash 109 | ./hl-node --chain Mainnet translate-abci-state ~/hl/data/periodic_abci_states/{date}/{height}.rmp /tmp/out.json 110 | ``` 111 | 112 | --- 113 | 114 | ## Flags 115 | 116 | When running validators or non-validators, you can use the following flags. The data schemas for the output data are documented [here](https://hyperliquid.gitbook.io/hyperliquid-docs/for-developers/nodes/l1-data-schemas). 117 | 118 | - `--write-trades`: Streams trades to `~/hl/data/node_trades/hourly/{date}/{hour}`. 119 | - `--write-fills`: Streams fills in the API fills format to `~/hl/data/node_fills/hourly/{date}/{hour}`. This overrides `--write-trades` if both are set. 120 | - `--write-order-statuses`: Writes every L1 order status to `~/hl/data/node_order_statuses/hourly/{date}/{hour}`. (Note that orders can be a substantial amount of data.) 121 | - `--write-misc-events`: Writes miscellaneous event data to `~/hl/data/misc_events/hourly/{date}/{hour}`. See [docs](https://hyperliquid.gitbook.io/hyperliquid-docs/for-developers/nodes/reading-l1-data#miscellaneous-events) for more details. 122 | - `--replica-cmds-style`: Configures what is written to `~/hl/data/replica_cmds/{start_time}/{date}/{height}`. 123 | Options: 124 | - `actions` (default) – only actions 125 | - `actions-and-responses` – both actions and responses 126 | - `recent-actions` – only preserves the two latest height files 127 | - `--compute-l4-snapshots `: Outputs the order book with all order information from `` and outputs it to `` 128 | - `--disable-output-file-buffering`: Flush each line immediately when writing output files. This reduces latency but leads to more disk IO operations. 129 | - `--serve-eth-rpc`: Enables the EVM RPC (see next section). 130 | 131 | For example, to run a non-validator with all flags enabled: 132 | ```bash 133 | ~/hl-visor run-non-validator --write-trades --write-order-statuses --serve-eth-rpc 134 | ``` 135 | 136 | > **Note:** These flags work independently of the chain setting. Just ensure that your `~/visor.json` is configured for Testnet or Mainnet as needed. 137 | 138 | --- 139 | 140 | ## EVM 141 | 142 | Enable the EVM RPC by adding the `--serve-eth-rpc` flag: 143 | ```bash 144 | ~/hl-visor run-non-validator --serve-eth-rpc 145 | ``` 146 | 147 | Once running, you can send RPC requests. For example, to retrieve the latest block: 148 | ```bash 149 | curl -X POST --header 'Content-Type: application/json' --data '{"jsonrpc":"2.0","method":"eth_getBlockByNumber","params":["latest",false],"id":1}' http://localhost:3001/evm 150 | ``` 151 | 152 | > **This applies for both Testnet and Mainnet.** 153 | 154 | --- 155 | 156 | ## Delegation 157 | 158 | The native token on Testnet is **HYPE** with token address: 159 | ``` 160 | 0x7317beb7cceed72ef0b346074cc8e7ab 161 | ``` 162 | 163 | **Delegation Process (applies to both chains):** 164 | 165 | 1. **Staking Deposit:** 166 | Transfer tokens from your spot balance into the staking balance: 167 | - **Testnet:** 168 | ```bash 169 | ./hl-node --chain Testnet --key staking-deposit 170 | ``` 171 | - **Mainnet:** 172 | ```bash 173 | ./hl-node --chain Mainnet --key staking-deposit 174 | ``` 175 | 176 | 2. **Delegate Tokens:** 177 | Delegate tokens to a validator: 178 | - **Testnet:** 179 | ```bash 180 | ./hl-node --chain Testnet --key delegate 181 | ``` 182 | - **Mainnet:** 183 | ```bash 184 | ./hl-node --chain Mainnet --key delegate 185 | ``` 186 | 187 | Optionally, add `--undelegate` to undelegate from the validator. 188 | 189 | 3. **View Delegations:** 190 | - **Testnet:** 191 | ```bash 192 | curl -X POST --header "Content-Type: application/json" --data '{ "type": "delegations", "user": }' https://api.hyperliquid-testnet.xyz/info 193 | ``` 194 | - **Mainnet:** 195 | Use the corresponding API endpoint for mainnet (if available). 196 | 197 | 4. **Staking Withdrawal:** 198 | Initiate a staking withdrawal (subject to a 5-minute unbonding period): 199 | - **Testnet:** 200 | ```bash 201 | ./hl-node --chain Testnet --key staking-withdrawal 202 | ``` 203 | - **Mainnet:** 204 | ```bash 205 | ./hl-node --chain Mainnet --key staking-withdrawal 206 | ``` 207 | The withdrawal will reflect in the exchange balance automatically once the unbonding period ends. 208 | 209 | --- 210 | 211 | ## Running a Validating Node 212 | 213 | *Note: The non-validating node setup above is a prerequisite for running a validating node.* 214 | 215 | ### Generate Config 216 | 217 | Generate two wallets: 218 | - **Validator wallet:** Holds funds and receives delegation rewards (cold wallet). 219 | - **Signer wallet:** Used solely for signing consensus messages (hot wallet). 220 | 221 | They can be the same wallet for simplicity. 222 | 223 | Create a config file for the signer wallet: 224 | ```bash 225 | echo '{"key": ""}' > ~/hl/hyperliquid_data/node_config.json 226 | ``` 227 | Keep both `` and `` secure. 228 | 229 | ### Ensure Validator User Exists 230 | 231 | Both the signer and validator addresses must have a non-zero perps USDC balance to be able to send signed actions. Print the addresses: 232 | 233 | - **Testnet:** 234 | ```bash 235 | ~/hl-node --chain Testnet --key print-address 236 | ~/hl-node --chain Testnet --key print-address 237 | ``` 238 | - **Mainnet:** 239 | ```bash 240 | ~/hl-node --chain Mainnet --key print-address 241 | ~/hl-node --chain Mainnet --key print-address 242 | ``` 243 | 244 | ### Join Network 245 | 246 | The validator set on Testnet is entirely permissionless. 247 | 248 | - **Register and Self-Delegate:** 249 | 250 | On **Testnet** (self-delegate 10_000, i.e. 1000000000000 wei): 251 | ```bash 252 | ~/hl-node --chain Testnet --key send-signed-action '{"type": "CValidatorAction", "register": {"profile": {"node_ip": {"Ip": "1.2.3.4"}, "signer": "", "name": "...", "description": "..." }, "initial_wei": 1000000000000}}' 253 | ``` 254 | 255 | On **Mainnet**: 256 | ```bash 257 | ~/hl-node --chain Mainnet --key send-signed-action '{"type": "CValidatorAction", "register": {"profile": {"node_ip": {"Ip": "1.2.3.4"}, "signer": "", "name": "...", "description": "..." }, "initial_wei": 1000000000000}}' 258 | ``` 259 | 260 | Make sure ports 4000-4010 are open to other validators. (Currently, only ports 4001-4006 are used, but additional ports in this range may be used in the future.) Either open the ports publicly or configure your firewall to allow validators (which can be found in `c_staking` in the state snapshots). Note that the validator set and IPs are dynamic. 261 | 262 | ### Run the Validator 263 | 264 | - **Testnet:** 265 | ```bash 266 | curl https://binaries.hyperliquid-testnet.xyz/Testnet/hl-visor > hl-visor && ./hl-visor run-validator 267 | ``` 268 | - **Mainnet:** 269 | ```bash 270 | curl https://binaries.hyperliquid.xyz/Mainnet/hl-visor > hl-visor && ./hl-visor run-validator 271 | ``` 272 | 273 | > **Debugging Tip:** To see stderr immediately and disable restarts, run: 274 | > - **Testnet:** 275 | > ```bash 276 | > ./hl-node --chain Testnet run-validator 277 | > ``` 278 | > - **Mainnet:** 279 | > ```bash 280 | > ./hl-node --chain Mainnet run-validator 281 | > ``` 282 | 283 | For faster bootstrapping, use a known reliable peer: 284 | - **Testnet:** 285 | ```bash 286 | echo '{ "root_node_ips": [{"Ip": "1.2.3.4"}], "try_new_peers": false, "chain": "Testnet" }' > ~/override_gossip_config.json 287 | ``` 288 | - **Mainnet:** 289 | ```bash 290 | echo '{ "root_node_ips": [{"Ip": "1.2.3.4"}], "try_new_peers": false, "chain": "Mainnet" }' > ~/override_gossip_config.json 291 | ``` 292 | 293 | ### Begin Validating 294 | 295 | When first registered or after changing your IP, the validator is automatically jailed (i.e. it does not participate in consensus initially). Once you see the expected outputs streaming to: 296 | ``` 297 | ~/hl/data/node_logs/consensus/hourly/{date}/{hour} 298 | ``` 299 | send the following action to begin participating in consensus: 300 | 301 | - **Testnet:** 302 | ```bash 303 | ~/hl-node --chain Testnet --key send-signed-action '{"type": "CSignerAction", "unjailSelf": null}' 304 | ``` 305 | - **Mainnet:** 306 | ```bash 307 | ~/hl-node --chain Mainnet --key send-signed-action '{"type": "CSignerAction", "unjailSelf": null}' 308 | ``` 309 | 310 | To exit consensus (i.e. “self jail”) and wait for the validator to leave the active set before shutting down: 311 | 312 | - **Testnet:** 313 | ```bash 314 | ~/hl-node --chain Testnet --key send-signed-action '{"type": "CSignerAction", "jailSelf": null}' 315 | ``` 316 | - **Mainnet:** 317 | ```bash 318 | ~/hl-node --chain Mainnet --key send-signed-action '{"type": "CSignerAction", "jailSelf": null}' 319 | ``` 320 | 321 | ### Jailing 322 | 323 | Performance and uptime are critical for the mainnet L1. To achieve this, a key feature of HyperBFT consensus is "jailing." When a validator is jailed, it can still participate in the consensus network by forwarding messages to peers, but does not vote on or propose blocks. To avoid jailing, it is recommended to achieve 200ms two-way latency to at least one‑third of validators by stake. 324 | 325 | Once jailed, a validator can only be unjailed through the `unjailSelf` action (which will succeed only after the L1 time exceeds the "jailed until" time). Self‑jailing does not extend the jailing duration. 326 | 327 | If a validator repeatedly gets jailed, check stdout for signs of crashing or other unusual logs. Also, logs in `~/hl/data/node_logs/status/` may help diagnose latency or connectivity issues. 328 | 329 | ### Alerting 330 | 331 | It is recommended that validators set up an alerting system to maintain optimal uptime. 332 | 333 | - **Testnet Example (Slack Alerts):** 334 | ```bash 335 | echo '{"testnet_slack_channel": "C000...", "slack_key": "Bearer xoxb-..."}' > ~/hl/api_secrets.json 336 | ``` 337 | Test the Slack alert configuration: 338 | ```bash 339 | ~/hl-node --chain Testnet send-slack-alert "hello hyperliquid" 340 | ``` 341 | 342 | For **Mainnet**, use a similar configuration (with keys/channels specific to Mainnet if needed). 343 | 344 | --- 345 | 346 | ## Logs 347 | 348 | The directory `node_logs/consensus` contains most messages sent and received by the consensus algorithm, which is often useful for debugging. 349 | 350 | For example, to check whether Vote messages were sent to validator `0x5ac9...` around `2024-12-10T09:25`, you can run: 351 | ```bash 352 | grep destination...0x5ac9 ~/hl/data/node_logs/consensus/hourly/20241210/9 | grep T09:25 | grep Vote 353 | ``` 354 | 355 | Validators with issues may experience timeouts on rounds when they do not propose a block. Searching for `suspect` in the consensus logs can help pinpoint the cause, which is often correlated with jailing. 356 | 357 | Crash logs from the child process are written to: 358 | ``` 359 | ~/hl/data/visor_child_stderr/{date}/{node_binary_index} 360 | ``` 361 | 362 | --- 363 | 364 | ## Validator Endpoints 365 | 366 | To view current validator information: 367 | 368 | - **Testnet:** 369 | ```bash 370 | curl -X POST --header "Content-Type: application/json" --data '{ "type": "validatorSummaries"}' https://api.hyperliquid-testnet.xyz/info 371 | ``` 372 | - **Mainnet:** 373 | Use the corresponding Mainnet endpoint if available. 374 | 375 | To change your validator profile (for example, updating your IP address): 376 | 377 | - **Testnet:** 378 | ```bash 379 | ~/hl-node --chain Testnet --key send-signed-action '{"type": "CValidatorAction", "changeProfile": {"node_ip": {"Ip": "1.2.3.4"}, "name": "..."}}' 380 | ``` 381 | - **Mainnet:** 382 | ```bash 383 | ~/hl-node --chain Mainnet --key send-signed-action '{"type": "CValidatorAction", "changeProfile": {"node_ip": {"Ip": "1.2.3.4"}, "name": "..."}}' 384 | ``` 385 | 386 | Other validator profile options include: 387 | - `disable_delegations`: Disables delegations when set to true. 388 | - `commission_bps`: Sets the percentage of staking rewards the validator takes before the remainder is distributed proportionally to stake delegated (defaults to 10000, meaning all rewards go to the validator, and is not allowed to increase). 389 | - `signer`: Allows the validator to set a hot address for signing consensus messages. 390 | 391 | --- 392 | 393 | ## Mainnet Non-Validator Seed Peers 394 | 395 | The community runs several independent root peers for non-validators to connect to on Mainnet. To run a non-validator on Mainnet, add at least one of these IP addresses to your `~/override_gossip_config.json`: 396 | ``` 397 | operator_name,root_ips 398 | NodeOps,35.213.122.164 399 | NodeOps,35.213.89.139 400 | ASXN,20.188.6.225 401 | ASXN,74.226.182.22 402 | B-Harvest,180.189.55.18 403 | B-Harvest,180.189.55.19 404 | Nansen x HypurrCollective,46.105.222.166 405 | Nansen x HypurrCollective,91.134.41.52 406 | Hypurrscan,57.180.50.253 407 | Hypurrscan,54.248.41.39 408 | Infinite Field,52.68.71.160 409 | Infinite Field,13.114.116.44 410 | LiquidSpirit x Rekt Gang,199.254.199.190 411 | LiquidSpirit x Rekt Gang,199.254.199.247 412 | Imperator.co,45.32.32.21 413 | Imperator.co,157.90.207.92 414 | Enigma,148.251.76.7 415 | Enigma,109.123.230.189 416 | TMNT,31.223.196.172 417 | TMNT,31.223.196.238 418 | HyperStake,91.134.71.237 419 | HyperStake,57.129.140.247 420 | ValiDAO,160.202.131.51 421 | ValiDAO,72.46.87.141 422 | Hyperbeat x P2P.org x Hypio,199.254.199.12 423 | Hyperbeat x P2P.org x Hypio,199.254.199.54 424 | Luganodes,45.250.255.111 425 | Luganodes,109.94.99.131 426 | HypurrCorea: SKYGG x DeSpread,47.74.39.46 427 | HypurrCorea: SKYGG x DeSpread,8.211.133.129 428 | ``` 429 | 430 | --- 431 | 432 | ## Troubleshooting 433 | 434 | Crash logs from the child process are written to: 435 | ``` 436 | ~/hl/data/visor_child_stderr/{date}/{node_binary_index} 437 | ``` 438 | 439 | --- 440 | -------------------------------------------------------------------------------- /README_misc.md: -------------------------------------------------------------------------------- 1 | This file contains optional configuration. Refer to `README.md` the essential information. 2 | 3 | ## Running as a System Service 4 | Many node operators prefer to run the node as a system service. 5 | 6 | Create the system service config file: 7 | ``` 8 | sudo nano /etc/systemd/system/hl-visor.service 9 | ``` 10 | 11 | Add the required information to the config, replace ALL instances of USERNAME: 12 | ``` 13 | [Unit] 14 | Description=HL-Visor Non-Validator Service 15 | After=network.target 16 | 17 | [Service] 18 | Type=simple 19 | User=USERNAME 20 | WorkingDirectory=/home/USERNAME 21 | ExecStart=/home/USERNAME/hl-visor run-non-validator 22 | Restart=always 23 | RestartSec=10 24 | 25 | [Install] 26 | WantedBy=multi-user.target 27 | 28 | ``` 29 | Enable the service: 30 | ``` 31 | sudo systemctl enable hl-visor.service 32 | ``` 33 | 34 | Start the service: 35 | ``` 36 | sudo systemctl start hl-visor 37 | ``` 38 | 39 | And finally to follow the logs use command: 40 | ``` 41 | journalctl -u hl-visor -f 42 | ``` 43 | 44 | ### Running with Docker 45 | To build the node, run: 46 | 47 | ```bash 48 | docker compose build 49 | ``` 50 | 51 | To run the node, run: 52 | 53 | ```bash 54 | docker compose up -d 55 | ``` 56 | -------------------------------------------------------------------------------- /docker-compose.yml: -------------------------------------------------------------------------------- 1 | name: "hyperliquid" 2 | 3 | services: 4 | node: 5 | restart: unless-stopped 6 | build: . 7 | ports: 8 | - "4000-4010:4000-4010" 9 | volumes: 10 | - hl-data:/home/hluser/hl/data 11 | 12 | pruner: 13 | restart: unless-stopped 14 | build: ./pruner 15 | volumes: 16 | - hl-data:/home/hluser/hl/data 17 | 18 | 19 | volumes: 20 | hl-data: 21 | driver: local 22 | -------------------------------------------------------------------------------- /pruner/Dockerfile: -------------------------------------------------------------------------------- 1 | FROM debian:12.6-slim 2 | 3 | ARG USERNAME=hluser 4 | ARG USER_UID=10000 5 | ARG USER_GID=$USER_UID 6 | 7 | # create custom user, install dependencies, create data directory 8 | RUN groupadd --gid $USER_GID $USERNAME \ 9 | && useradd --uid $USER_UID --gid $USER_GID -m $USERNAME \ 10 | && apt-get update -y && apt-get install curl cron procps -y \ 11 | && mkdir -p /home/$USERNAME/hl/data && mkdir -p /home/$USERNAME/scripts && chown -R $USERNAME:$USERNAME /home/$USERNAME/hl 12 | 13 | # Add our scripts 14 | COPY scripts/ /home/$USERNAME/scripts/ 15 | # Add cron file 16 | COPY cron/ /etc/ 17 | 18 | # Give execution rights on the cron jobs 19 | RUN chmod 0644 /etc/cron.d/* && \ 20 | chmod +x /home/$USERNAME/scripts/* && chown -R $USERNAME:$USERNAME /home/$USERNAME/scripts 21 | 22 | # Start cron service directly 23 | CMD ["bash", "-c", "crontab /etc/cron.d/prune && /usr/sbin/cron -f -L 15"] 24 | -------------------------------------------------------------------------------- /pruner/cron/cron.d/prune: -------------------------------------------------------------------------------- 1 | 0 3 * * * /bin/bash -c '/home/hluser/scripts/prune.sh > /proc/1/fd/1 2>&1' 2 | -------------------------------------------------------------------------------- /pruner/scripts/prune.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | DATA_PATH="/home/hluser/hl/data" 3 | 4 | # Folders to exclude from pruning 5 | # Example: EXCLUDES=("visor_child_stderr" "rate_limited_ips" "node_logs") 6 | EXCLUDES=("visor_child_stderr") 7 | 8 | # Log startup for debugging 9 | echo "$(date): Prune script started" >> /proc/1/fd/1 10 | 11 | # Check if data directory exists 12 | if [ ! -d "$DATA_PATH" ]; then 13 | echo "$(date): Error: Data directory $DATA_PATH does not exist." >> /proc/1/fd/1 14 | exit 1 15 | fi 16 | 17 | echo "$(date): Starting pruning process at $(date)" >> /proc/1/fd/1 18 | 19 | # Get directory size before pruning 20 | size_before=$(du -sh "$DATA_PATH" | cut -f1) 21 | files_before=$(find "$DATA_PATH" -type f | wc -l) 22 | echo "$(date): Size before pruning: $size_before with $files_before files" >> /proc/1/fd/1 23 | 24 | # Build the exclusion part of the find command 25 | EXCLUDE_EXPR="" 26 | for name in "${EXCLUDES[@]}"; do 27 | EXCLUDE_EXPR+=" ! -name \"$name\"" 28 | done 29 | 30 | # Delete data older than 48 hours = 60 minutes * 48 hours 31 | HOURS=$((60*48)) 32 | eval "find \"$DATA_PATH\" -mindepth 1 -depth -mmin +$HOURS -type f $EXCLUDE_EXPR -delete" 33 | 34 | # Get directory size after pruning 35 | size_after=$(du -sh "$DATA_PATH" | cut -f1) 36 | files_after=$(find "$DATA_PATH" -type f | wc -l) 37 | echo "$(date): Size after pruning: $size_after with $files_after files" >> /proc/1/fd/1 38 | echo "$(date): Pruning completed. Reduced from $size_before to $size_after ($(($files_before - $files_after)) files removed)." >> /proc/1/fd/1 39 | -------------------------------------------------------------------------------- /pub_key.asc: -------------------------------------------------------------------------------- 1 | -----BEGIN PGP PUBLIC KEY BLOCK----- 2 | 3 | mDMEZ39gmBYJKwYBBAHaRw8BAQdA6jl1v1J4DZGgYGLGC0tg1XphjQwR9bo5rwet 4 | iF3WtKC0KUh5cGVybGlxdWlkIDxub3RpY2VzQGh5cGVyZm91bmRhdGlvbi5vcmc+ 5 | iJMEExYKADsWIQTPLC6j3D6PBCpV+2UDJUqTSfGCCwUCZ39gmAIbAwULCQgHAgIi 6 | AgYVCgkICwIEFgIDAQIeBwIXgAAKCRADJUqTSfGCC01lAQCpT09fi2TxINZjA97a 7 | lTBHVpgmr31HYax2LB8zaMz2DgEA8egOdj1qRQLPeYr0RpNrdCHbRwkAKB+IU/Bn 8 | hn+K3wm4OARnf2CYEgorBgEEAZdVAQUBAQdAoYfQgm2kSYiKNkHIrFijGXt/ragf 9 | e2iEUUgN3wDWShEDAQgHiHgEGBYKACAWIQTPLC6j3D6PBCpV+2UDJUqTSfGCCwUC 10 | Z39gmAIbDAAKCRADJUqTSfGCC9gsAP9+eSxhNWjJ7lFin3WGj7lTIJdZhx8FQVTt 11 | F8TrP9+KuAEAlMObDSz0YcHSwhpTHv+GOdNnMpj3sl/vlLVNF+sk/gg= 12 | =HZx/ 13 | -----END PGP PUBLIC KEY BLOCK----- 14 | --------------------------------------------------------------------------------