How to deploy a local testnet
To start with Klever blockchain, make sure you have Docker and Docker-Compose installed and download the latest Klever Toolchain image.
Follow instructions on https://docs.docker.com/engine/install to install Docker.
How many validators do you want?
The first thing we must do when creating our local blockchain is know how many validator nodes you want to use. For this tutorial the default will be 2 validators.
Generate Keys
To generate the necessary keys you will need to execute the command below. If you want to generate a different number of validator nodes, just change the value in --num-keys=2
docker run -it --rm -v $(pwd):/opt/klever-blockchain \
--user "$(id -u):$(id -g)" \
--entrypoint='' kleverapp/klever-go:latest keygenerator --num-keys=2 --key-type=both
The file structure you will have after running the command will be this.
localchain
├── node-0
│ ├── validatorKey.pem
│ └── walletKey.pem
└── node-1
├── validatorKey.pem
└── walletKey.pem
For our examples in this tutorial, we will assume that the data generated by the command is the following:
Node 0:
- Address 0: klv1lay4f5657l535g7j5nx8wenhqvlhjune2zfvt94sv5kv7qk3snwqajpux3
- BLS 0: 158449b4219fff1151d2e0eaf50c63cb95ba8b582ac2ff5429f90f500dd816068ac071c5a13490b65296b22a5fb0ab07359029a3fce0761441dd2c820713e52fc0a8ef3b9a0d8af28c9f2b74b5a5542956e481e596911b559b8c76cb66fa0685
Node 1:
- Address 1: klv14nwrysndqs29wvvskwk8lq3ch9v4jatf6l6mxa6vrj9wylt0gxssw0xvmm
- BLS 1: 9eb5fe005d5ad50a621ac9728ed2dcaf780c1d69fae86399997d0b9bc3f53c1b968a56a048f083b60290ebd037267f12a2965220100e85324b3a68fd940574873b7bed6d6cdf66fa404f337e52e306010d8297f0d89c9b04e4514c7c7536d293
Node Config
Any node needs the following configuration files to run successfully.
- nodesSetup.json
- genesis.json
- api.yaml
- config.yaml
- enableEpochs.yaml
- external.yaml
To make configuring the nodes easier, we will download the klever mainnet configuration files and edit them as we need. To download the configuration files, just run the command below.
curl -k https://backup.mainnet.klever.finance/config.mainnet.108.tar.gz \
| tar -xz -C .
The file structure you will have after running the command will be this.
localchain
├── config
│ ├── api.yaml
│ ├── config.yaml
│ ├── enableEpochs.yaml
│ ├── external.yaml
│ ├── genesis.json
│ └── nodesSetup.json
├── node-0
│ ├── validatorKey.pem
│ └── walletKey.pem
└── node-1
├── validatorKey.pem
└── walletKey.pem
P.S.: You can use the same configurations for all nodes, but if you want to have a node indexer, I recommend you make a separate configuration just for that node.
genesis.json
In genesis.json you should have a list that will contain data from each genesis node. First, we will delete the current configuration and write it according to our generated keys.
Ex:
{
"address": "klv1vx2j8lwdskc9z5mr9z2ttlpfpaf6dkxes7mf7zg883x2lcl5m9dselkspy", // Validator Address
"balance": 3323333333333333, // KLV Balance
"kfiBalance": 7000000000000, // KFI Balance
"delegation": { // Delegation List
"address": "klv1vx2j8lwdskc9z5mr9z2ttlpfpaf6dkxes7mf7zg883x2lcl5m9dselkspy", // Self Delegation
"value": 10000000000000
}
}
Based on the data we generate, this is what the configuration will look like:
[
{
"address": "klv1lay4f5657l535g7j5nx8wenhqvlhjune2zfvt94sv5kv7qk3snwqajpux3",
"balance": 3323333333333333,
"kfiBalance": 7000000000000,
"delegation": {
"address": "klv1lay4f5657l535g7j5nx8wenhqvlhjune2zfvt94sv5kv7qk3snwqajpux3",
"value": 10000000000000
}
},
{
"address": "klv14nwrysndqs29wvvskwk8lq3ch9v4jatf6l6mxa6vrj9wylt0gxssw0xvmm",
"balance": 3323333333333333,
"kfiBalance": 7000000000000,
"delegation": {
"address": "klv14nwrysndqs29wvvskwk8lq3ch9v4jatf6l6mxa6vrj9wylt0gxssw0xvmm",
"value": 10000000000000
}
}
]
nodesSetup.json
In nodesSetup.json, we have some basic blockchain configurations and the initial list of nodes. First, we will delete the current configuration and write it according to our generated keys.
Ex:
{
"startTime": 1720483200, // Genesis start time
"slotInterval": 4000, // Time of a slot (block)
"slotsPerEpoch": 20, // How many slot a epoch have. slotInterval * slotsPerEpoch = EpochInterval
"consensusGroupSize": 3, // Consensus Size
"minNodes": 3, // Min Nodes
"chainID": "79652",
"minTransactionVersion": 1,
"klvDenomination": 6,
"initialNodes": [ // Initial Nodes List
{
"pubkey": "807cf3168ec886165ac2128c77354bfd80004bfc0ac2a9f3a2b24f0805071a8bc352020338de993ca3bd85a4efe757124553ca9bc65de2c28f5450a42cbdc82bb7ad14857ddfea6577e6859de2d07e89ed663951ca55c6892deafc7c5f4a4807", // BLS
"address": "klv1y6snwael5jpfgfzrf3wzlsddhwew93v2lf5wda6uz9u2ep9e8uvsehufg6" // Address
},
]
}
Based on the data we generate, this is what the configuration will look like:
{
"startTime": 1720477239,
"slotInterval": 4000,
"slotsPerEpoch": 20,
"consensusGroupSize": 2,
"minNodes": 2,
"chainID": "4123",
"minTransactionVersion": 1,
"klvDenomination": 6,
"initialNodes": [
{
"pubkey": "158449b4219fff1151d2e0eaf50c63cb95ba8b582ac2ff5429f90f500dd816068ac071c5a13490b65296b22a5fb0ab07359029a3fce0761441dd2c820713e52fc0a8ef3b9a0d8af28c9f2b74b5a5542956e481e596911b559b8c76cb66fa0685",
"address": "klv1lay4f5657l535g7j5nx8wenhqvlhjune2zfvt94sv5kv7qk3snwqajpux3"
},
{
"pubkey": "9eb5fe005d5ad50a621ac9728ed2dcaf780c1d69fae86399997d0b9bc3f53c1b968a56a048f083b60290ebd037267f12a2965220100e85324b3a68fd940574873b7bed6d6cdf66fa404f337e52e306010d8297f0d89c9b04e4514c7c7536d293",
"address": "klv14nwrysndqs29wvvskwk8lq3ch9v4jatf6l6mxa6vrj9wylt0gxssw0xvmm"
}
]
}
enableEpochs.yaml
Just use the configuration below so that the blockchain is the same as mainnet.
maxNodesChangeEnableEpoch:
- epochEnable: 0
nodesToShuffle: 4
enableEpochs:
claimKFI: 0
processorFlowITOPrice: 0
fixStakingBuckets: 0
kdaFpr: 0
bigBucketsCompute: 0
fprComputeAndKdaFeeFlow: 0
fixDelegationSameEpoch: 0
config.yaml
Just change thresholdMinConnectedPeers to 0
external.yaml
Make sure the enabled config is false. if you want to use a node-indexer, you must change the node-indexer config to true.
Seed Node Config
To run a localnet with more than one validator, it will be necessary to configure the seed node so that the validators can communicate correctly.
- Create a folder to seednode config
Create a folder for seednode settings and create an empty file called config.yaml, the folder structure should look something like this.
localchain
├── config
│ ├── api.yaml
│ ├── config.yaml
│ ├── enableEpochs.yaml
│ ├── external.yaml
│ ├── genesis.json
│ └── nodesSetup.json
├── node-0
│ ├── validatorKey.pem
│ └── walletKey.pem
├── node-1
│ ├── validatorKey.pem
│ └── walletKey.pem
└── seednode
└── config.yaml
- Config Seednode
Just use this configs for you seednode.
p2p:
node:
port: 37373-37373
seed: beklever
maximumExpectedPeerCount: 0
thresholdMinConnectedPeers: 0
kadDhtPeerDiscovery:
enabled: true
refreshIntervalInSec: 10
protocolID: /klv/kad/0.0.1
initialPeerList:
bucketSize: 100
routingTableRefreshIntervalInSec: 300
sharding:
targetPeerCount: 0
maxIntraShardValidators: 0
maxCrossShardValidators: 0
maxIntraShardObservers: 0
maxCrossShardObservers: 0
type: NilListSharder
logs:
LogFileLifeSpanInSec: 86400
marshalizer:
type: protobuf
- P2P Node config
After you configure your seed node, you need to add one more change to your validator's config.yaml file.Change the initialPeerList setting to the one below
initialPeerList:
- /ip4/172.20.0.5/tcp/37373/p2p/16Uiu2HAkwUme4SM2uQSBydi8s3FhZDVqA3RbNQDEojzQGnE5bv4Z
Running the blockchain
Ensuring that all settings are correct. Now we can finally run our blockchain.
Create a docker-compose.yaml file and add the code below.
version: '3'
services:
seednode:
image: kleverapp/klever-go:latest
container_name: seednode
restart: unless-stopped
volumes:
- ./seednode:/opt/klever-blockchain/config/seednode
entrypoint: /usr/local/bin/seednode
command: [
"--rest-api-interface=0.0.0.0:8799",
]
networks:
klever:
ipv4_address: 172.20.0.5
node0:
image: kleverapp/klever-go:latest
container_name: node0
restart: unless-stopped
networks:
- klever
volumes:
- ./config:/opt/klever-blockchain/config/node
- ./node-0/validatorKey.pem:/opt/klever-blockchain/config/validatorKey.pem
- ./dbs/node-0:/opt/klever-blockchain/db
- ./logs/node-0:/opt/klever-blockchain/logs
entrypoint: /usr/local/bin/validator
command: [
"--log-level=*:INFO",
"--use-log-view",
"--validator-key-pem-file=./config/validatorKey.pem",
"--rest-api-interface=0.0.0.0:8800"
]
node1:
image: kleverapp/klever-go:latest
container_name: node1
restart: unless-stopped
networks:
- klever
volumes:
- ./config:/opt/klever-blockchain/config/node
- ./node-1/validatorKey.pem:/opt/klever-blockchain/config/validatorKey.pem
- ./dbs/node-1:/opt/klever-blockchain/db
- ./logs/node-1:/opt/klever-blockchain/logs
entrypoint: /usr/local/bin/validator
command: [
"--log-level=*:INFO",
"--use-log-view",
"--validator-key-pem-file=./config/validatorKey.pem",
"--rest-api-interface=0.0.0.0:8801"
]
networks:
klever:
driver: bridge
ipam:
config:
- subnet: 172.20.0.0/24
You can now run the blockchain on your machine using the command below.
docker-compose up -d