Repository navigation
Running a ledger node
Upcoming. This page describes the
ledger-nodebranch. It is not part of a release, and details may change. No genesis comes with the node yet, so a ledger runs only on a genesis that is given to it.
Part of Ledger. A node runs the ledger when it is started with --ledger. It then follows the
chain, checks every block and serves the blocks it holds to its peers. Given the key of a validator that the
genesis lists, it also votes and signs blocks. Without --ledger a node behaves as one of the earlier
release, and nothing on this page applies.
| Observer | Validator | |
|---|---|---|
A build of the ledger-node branch, see Build, testing and native image
|
yes | yes |
--ledger |
yes | yes |
The genesis of the chain, given with --ledger-genesis
|
yes | yes |
The bootstrap snapshot that the genesis names, bootstrap.dat in the data directory |
yes | yes |
A key file, given with --ledger-key, whose public key the genesis lists |
yes | |
| The ledger sporks held by the node, for mints, claims and transfers to be taken | yes |
The snapshot is the one of Legacy chain snapshot. A daemon downloads it in the background when it has none, and the ledger waits for it, since every claim is checked against it.
A validator first makes its key and gives the public key to whoever writes the genesis:
$ hedgehog util ledger-key-generate ~/.ledger.key
3f2a…c9The command writes a random seed into a new file that only its owner can read, prints the public key, and refuses a path that exists, so a key is never replaced. The seed is never printed. Keep the file: a validator that loses it can no longer sign as that key.
Then start the daemon:
$ hedgehog daemon --ledger --ledger-genesis genesis.json --ledger-key ~/.ledger.keyLeave out --ledger-key to run an observer. The node logs, in order:
-
The ledger is of the chain <chain id>. The chain id is the hash of the genesis: compare it with other operators to know that you are on the same chain. -
Waiting for the bootstrap snapshot <file> before the ledger starts, once a minute while the snapshot is missing. The ledger looks for it every 5 seconds. -
The ledger keeps its block log and its sign state in <folder>, once the snapshot is there and is the one of the genesis. The folder is the one of this chain, see Where the files are. - Nothing more while all is well. The node replays its block log, starts as an observer, catches up with its peers, and after a grace period of 30 seconds a validator starts to vote.
These go after daemon. They are checked before anything else starts, and a value that is wrong stops the
daemon with a message and exit code 2.
| Option | Meaning |
|---|---|
--ledger |
Run the ledger: follow and serve its blocks. Off by default |
--ledger-genesis <file> |
The genesis of the chain. Needed until a genesis comes with the node |
--ledger-key <file> |
Validate with the seed in this file, as made by util ledger-key-generate. Without it the node follows the ledger and never signs |
--ledger-trusted <height>:<hash> |
The block a synced ledger must have, with the hash as 128 hexadecimal characters and a height of 1 or more |
A key that the genesis does not list is not an error. The node warns
The key <public key> is not a validator of this genesis, this node will not sign and runs as an observer.
A trusted checkpoint protects a new node against a fork. Take the height and hash of a block from a node you trust. A node whose ledger holds another block at that height, or that sees two certified blocks at one height, halts its ledger instead of following a fork.
The genesis is a JSON file with exactly these fields:
{
"time": 1796083200000,
"roundLength": 100,
"validators": [
"3f2a…c9",
"8be0…14"
],
"snapshotHash": "<128 hex characters>",
"snapshotTotal": 12345678900000000
}| Field | Meaning |
|---|---|
time |
When the chain starts, in Unix milliseconds |
roundLength |
The blocks of a round, after which votes on the validator set take effect |
validators |
The public keys of the first validators, 64 hex characters each, 1 to 1000 of them, in the order that decides who proposes. They can never be voted out |
snapshotHash |
The SHA-512 of the bootstrap snapshot, without its signature |
snapshotTotal |
The sum of the snapshot's balances, in units of 1e-8 coins |
A field that is missing, repeated or unknown is refused, and so is a key that is listed twice, so a typo cannot pass. The file is public: it holds no secret. Every node of a chain must use the same values, since the chain id is computed from them and every signature on the chain covers the chain id. Spacing and the order of the fields do not matter, the order of the validators does.
The ledger keeps its files in the folder ledger of the data directory, see
Running Hedgehog, in a folder of its own for each chain. The name of
that folder is the first 16 characters of the chain id, and the node logs it at start as
The ledger keeps its block log and its sign state in <folder>:
| File | Holds |
|---|---|
ledger/<chain>/blocks.log |
Every block of the chain |
ledger/<chain>/sign.state |
What this validator signed for the height it works on, with sign.state.lock beside it |
-
Never delete or roll back
sign.stateof a validator. It is what keeps the validator from signing two different blocks at one height after a restart, and a deleted or older copy is not noticed. - The block log can be fetched again from peers, but not on its own: a log that is shorter than the sign state needs stops the node, which asks for the tail of the log to be restored from a peer.
- The state is not stored. At every start the node replays the whole log and checks every block again, so a long chain takes a while to start. A validator replays it twice.
- Another genesis, another folder. A genesis with other values has another chain id, so the node starts on an empty folder and never meets the files of the chain it had. The folders of chains that are left stay as they were.
A wrong option, genesis or key file stops the daemon at start, before anything runs, with one of these messages and exit code 2:
| Message | Cause | What to do |
|---|---|---|
--ledger needs a genesis: give --ledger-genesis <file> (no genesis is bundled with this release) |
No genesis given, and none comes with the node | Give --ledger-genesis
|
The ledger genesis <file>: … |
The genesis is not valid; the rest names the field | Fix the file, or get it again |
… must be readable by its owner only, try chmod 600 |
The key file can be read by others |
chmod 600 the key file |
--ledger-trusted must be <height>:<128 hexadecimal characters of the hash>, … |
The checkpoint is malformed | Give a height of 1 or more and the full hash |
What goes wrong later leaves the node running without its ledger, and the node logs why once:
| Log line | Cause | What to do |
|---|---|---|
The ledger is not running, the node goes on without it: The snapshot <file> has the content hash … |
The snapshot is not the one of the genesis | Fetch the snapshot release that the genesis names |
The ledger driver halted: The ledger node could not be built: … Cannot replay the block log … |
The log does not fit this genesis or snapshot, or is damaged in the middle | Check the genesis; move the folder of the chain away to start over |
The ledger driver halted: … |
The checkpoint differs, two certified blocks were seen at one height, or the node failed twice within 10 seconds | Read the reason; a fork needs an operator |
After a halt the service also says once:
The ledger halted and serves the blocks it has, the node goes on: <reason>.
A halted ledger still serves the blocks it holds, so its peers can go on syncing from it. Restart the daemon to try again.
A node that runs the ledger answers over the REST interface, and the commands of Ledger command line use it. This one shows that the node is up and on your chain:
$ hedgehog cli ledger infoIt shows "running" : true, the chain id to compare with other operators, the height of the tip, and a
signing of true once a validator that holds a key the genesis lists has caught up and votes. Its unsetSporks and laggingSporks
name the ledger sporks the node still waits for. While one is listed, what depends on it is
not minted, claimed or taken, and a chain on a running node may stand still. A transfer, a claim and a vote
are sent with the same command, signed on the machine that runs it.
- Start without a genesis file. No genesis comes with the node.
- Keep waiting transactions across a restart. They are lost when the process stops.
-
application/src/main/java/org/unigrid/hedgehog/command/option/LedgerOptions.java: the options -
application/src/main/java/org/unigrid/hedgehog/service/ledger/LedgerSetup.java: the checks at start -
application/src/main/java/org/unigrid/hedgehog/service/ledger/GenesisFile.java: the genesis -
application/src/main/java/org/unigrid/hedgehog/service/ledger/LedgerService.java: what the node does with the ledger -
application/src/main/java/org/unigrid/hedgehog/server/rest/LedgerResource.java: how the ledger is read and used over REST
Using Hedgehog
Code
Network
Releases
Upcoming