Validator Nodes
Introduction#
Dijets Primary Network validates Dijets Ternary Chain Ledgers. In this tutorial, we’ll add a node to the Primary Network on Dijets.
The Method Chain manages metadata on Dijets. This includes tracking which nodes are in which Subnets, which blockchains exist, and which Subnets are validating which blockchains. To add a validator, we’ll issue transactions to the Method Chain.
caution
Note that once you issue the transaction to add a node as a validator, there is no way to change the parameters. You can’t remove your stake early or change the stake amount, node ID, or reward address. Please make sure you’re using the correct values in the API calls below. If you’re not sure, feel free to join our Qowalts to ask questions.
Requirements#
You've completed Run an Dijets Node and are familiar with Dijets architecture. In this tutorial, we use DijetsJS and Dijets Postman collection to help us make API calls.
In order to ensure your node is well-connected, make sure that your node can
receive and send TCP traffic on the staking port (9651
by default) and that
you started your node with config flag --public-ip=[YOUR NODE'S PUBLIC IP HERE]
. Failing to do either of these may jeopardize your staking reward.
Add a Validator with Dijets Wallet#
First, we show you how to add your node as a validator by using Dijets Wallet.
Retrieve the Node ID#
Get your node’s ID by calling info.getNodeID
:
curl -X POST --data '{
"jsonrpc":"2.0",
"id" :1,
"method" :"info.getNodeID"
}' -H 'content-type:application/json' 127.0.0.1:9650/ext/info
The response has your node’s ID:
{
"jsonrpc": "2.0",
"result": {
"nodeID": "NodeID-5mb46qkSBj81k9g9e4VFjGGSbaaSLFRzD"
},
"id": 1
}
Add as a Validator#
Open the wallet, and go to the Earn
tab. Choose
Add Validator
under the Validate
section.
Fill out the staking parameters. They are explained in more detail in this
doc. When you’ve filled in all the staking parameters
and double-checked them, click Confirm
. Make sure the staking period is at
least 2 weeks, the delegation fee rate is at least 2%, and you’re staking at
least 2,000 DJTX on Mainnet (1 DJTX on Dijets TestNet Testnet).
You should see a success message, and your balance should be updated.
Calling
platform.getPendingValidators
verifies that your transaction was accepted. Note that this API call should be
made before your node's validation start time, otherwise, the return will not
include your node's id as it is no longer pending.
Go back to the Earn
tab, and click Estimated Rewards
.
Once your validator’s start time has passed, you will see the rewards it may earn, as well as its start time, end time, and the percentage of its validation period that has passed.
You can also call
platform.getCurrentValidators
to check that your node's id is included in the response.
That’s it!
Add a Validator with DijetsJS#
We can also add a node to the validator set using DijetsJS.
Install DijetsJS#
To use DijetsJS, you can clone the repo:
git clone https://github.com/Dijets-Inc/dijetsjs.git
or add it to an existing project:
yarn add dijets
For this tutorial we will use ts-node
to run the example scripts directly from an DijetsJS directory.
Dijets TestNet Workflow#
In this section, we will use Dijets TestNet Testnet to show how to add a node to the validator set.
Open your DijetsJS directory and select the
examples/platformvm
folder to view the source code for the examples scripts.
We will use the
buildAddValidatorTx.ts
script to add a validator. To learn more about the buildAddValidatorTx
API,
please click
here.
Private Key
Locate this line in the file
const privKey: string = `${PrivateKeyPrefix}${DefaultLocalGenesisPrivateKey}`
and replace this with a private key that you control. You can use this code to generate a new key.
const privKey: string = "<YOUR-PRIVATE-KEY-HERE>"
Network Setting
The following settings work when using a local node started with --network-id=testnet
:
const ip: string = "localhost"
const port: number = 9650
const protocol: string = "http"
const networkID: number = 5
However, to connect directly to the Dijets API server, the following changes are needed:
const ip: string = "dijets.ukwest.cloudapp.azure.com"
const port: number = 443
const protocol: string = "https"
const networkID: number = 1
Depending on the networkID passed in when instantiating an Dijets
object in
the code, the encoded addresses used will have a distinctive Human Readable
Part(HRP) per network.
Example Address: 5 - X-dijets
19rknw8l0grnfunjrzwxlxync6zrlu33yxqzg0h
For Dijets TestNet Testnet, 5 is the correct value to use.
To learn more about encoded addresses, click here.
Settings for Validation
Next we need to specify the node's validation period and delegation fee.
const nodeID: string = "NodeID-7Xhw2mDxuDS44j42TCB6U5579esbSt3Lg"
const startTime: BN = UnixNow().add(new BN(60 * 1))
const endTime: BN = startTime.add(new BN(26300000))
const delegationFee: number = 10
Node ID
This is the node ID of the validator being added. See above
section on how to retrieve the node id by using API
info.getNodeID
.
Staking Period
startTime
and endTime
are required to specify the time of starting/leaving
validation. The minimum duration that one can validate the Primary Network is 2
weeks, and the maximum duration is one year. One can start a new validation on
the Primary Network after finishing one, it’s just that the maximum continuous
duration is one year. startTime
and endTime
are the Unix times when your
validator will start and stop validating the Primary Network, respectively.
startTime
must be in the future relative to the time the transaction is
issued.
The sample code uses const startTime: BN = UnixNow().add(new BN(60 * 1))
and
const endTime: BN = startTime.add(new BN(26300000))
to compute the Unix time 1
minute and 304 days in the future (at the time when this article was written) to
use as the values of startTime
and endTime
, respectively.
:::tip
You can create your own Unix timestamp here or
by using the UnixNow()
method
:::
To create your own start times, please follow the steps below:
Locate this line in the file
const startTime: BN = UnixNow().add(new BN(60 * 1))
const endTime: BN = startTime.add(new BN(26300000))
Change startTime
and endTime
to new BN
values, for example:
const startTime: BN = new BN(1654656829) // Wed Jun 08 2022 02:53:49 GMT+0000
const endTime: BN = new BN(1662602029) // Thu Sep 08 2022 01:53:49 GMT+0000
Delegation Fee Rate
Dijets allows for delegation of stake. This parameter is the percent fee this
validator charges when others delegate stake to them. For example, if
delegationFeeRate
is 10
and someone delegates to this validator, then when
the delegation period is over, 10% of the reward goes to the validator and the
rest goes to the delegator, if this node meets the validation reward
requirements.
Stake Amount
Set the proper staking amount in calling pchain.buildAddValidatorTx
by
replacing stakeAmount.minValidatorStake
with a number in the unit of gwei, for
example, BN(1e12)
which is 10,000 DJTX.
Addresses
By default, the example uses the variable pAddressStrings
to define
toAddresses
, fromAddresses
, changeAddresses
and rewardAddresses
:
const pAddressStrings: string[] = pchain.keyChain().getAddressStrings()
This retrieves the Method Chain addresses that belong to the private key
that appears earlier in the example.
No change is needed in the addresses for the default action. For customization, please refer to this section.
Execute the Code
Now that we have made all of the necessary changes to the example script, it's time to add a validator to the Dijets TestNet Network.
Run the command:
ts-node examples/platformvm/buildAddValidatorTx.ts
The response has the transaction ID.
Success! TXID: 2ftDVwmss5eJk8HFsNVi6a3vWK9s3szZFhEeSY2HCS8xDb8Cra
We can check the transaction’s status by running the example script:
getTxStatus.ts
following the steps below:
-
Ensure that your network settings are correct before running the script.
-
Locate this line in the file
const main = async (): Promise<any> => { const txID: string = "x1NLb9JaHkKTXvSRReVSsFwQ38mY7bfD1Ky1BPv721VhrpuSE" ... }
and replace it with the buildAddValidator TXID
const main = async (): Promise<any> => { const txID: string = "2ftDVwmss5eJk8HFsNVi6a3vWK9s3szZFhEeSY2HCS8xDb8Cra" ... }
Run the command:
ts-node examples/platformvm/getTxStatus.ts
This returns:
{ status: 'Committed' }
The status should be Committed
, meaning the transaction was successful.
We can see if the node is now in the pending validator set for the Dijets TestNet network
by using the
example:getPendingValidators.ts
.
Just change the network settings to meet Dijets TestNet requirements
and then run the script:
ts-node examples/platformvm/getPendingValidators.ts
The response should include the node we just added:
{
"validators": [
{
"nodeID": "NodeID-7Xhw2mDxuDS44j42TCB6U5579esbSt3Lg",
"startTime": "1654656829",
"endtime": "1662602029",
"stakeAmount": "1000000000"
}
],
"delegators": []
}
When the time reaches 1654656829
(Wed Jun 08 2022 02:53:49 GMT+0000), this
node will start validating the Primary Network. When it reaches 1662602029
(Thu Sep 08 2022 01:53:49 GMT+0000), this node will stop validating the Primary
Network. The staked DJTX and the rewards, if any, will be returned to
pAddressStrings
.
Customizing Addresses
There are 4 addresses which are needed when calling
pchain.buildAddValidatorTx
. Only 2 of them can be changed: toAddresses
and
rewardAddresses
. For backward-compatibility reasons, fromAddresses
and
changeAddresses
are just placeholders and are ignored.
toAddresses
An array of addresses who receive the staked tokens at the end of the staking period.
rewardAddresses
When a validator stops validating the Primary Network, they will receive a
reward if they are sufficiently responsive and correct while they validated the
Primary Network. These tokens are sent to rewardAddresses
. The original stake
will be sent back to the addresses defined in toAddresses
.
A validator’s stake is never slashed, regardless of their behavior they will always receive their stake back when they’re done validating.
Locate this part of the code
let privKey: string = `${PrivateKeyPrefix}${DefaultLocalGenesisPrivateKey}` pKeychain.importKey(privKey)
and replace privKey
with private keys that you control. To generate a new
keypair, we can use the
createKeypair.ts
example script along with Dijets TestNet Network Settings.
let privKey: string = "PrivateKey-PY2dvfxzvBAe1a5nn7x23wmZMgAYJaS3XAZXzdUa22JtzUvKM" pKeychain.importKey(privKey) privKey = "PrivateKey-2Y3Vg9LShMJyUDBHzQqv5WtKDJ8yAVHyM3H5CNCBBmtg3pQEQG" pKeychain.importKey(privKey) privKey = "PrivateKey-NaV16owRSfa5TAtxtoU1BPUoM2y1ohttRbwKJG1j7onE4Ge1s" pKeychain.importKey(privKey) priKey = "PrivateKey-26JMUsR5RCkf5k9ME8WxKCWEuCK5s2SrALUn7vEa2urwyDDc91" pKeychain.importKey(privKey) const pAddressStrings: string[] = pchain.keyChain().getAddressStrings()
This example would create a keychain with 4 addresses:
"P-dijets1jx644d9y00y5q4hz8cq4wr75a2erne2y4e32xc", // pAddressStrings[0] "P-dijets1wchdgdp94j8tszlpsp56qvgkvdn20svpmnm8qk", // pAddressStrings[1] "P-dijets1f36kkpy6yzd7ayrywxvvprns7qlrcu3hwqdya8", // pAddressStrings[2] "P-dijets1qw7yt3fp43kuwsufff4vhezs2yl00slr09vmh5", // pAddressStrings[3]
Now we can pass in each address according to its slot in the pAddressStrings
array:
const unsignedTx: UnsignedTx = await pchain.buildAddValidatorTx(
utxoSet,
[pAddressStrings[0], pAddressStrings[1]], // toAddresses, one or more addresses
[pAddressStrings[0]], // fromAddresses, required for backward-compatibility
[pAddressStrings[0]], // changeAddresses, required for backward-compatibility
nodeID,
startTime,
endTime,
stakeAmount.minValidatorStake,
[pAddressStrings[2], pAddressStrings[3]], //rewardAddresses, one or more addresses
delegationFee,
locktime,
threshold,
memo,
asOf
)
Mainnet Workflow#
The Dijets TestNet workflow above can be adapted to Mainnet with the following modifications:
- The correct private key.
- Network setting should be to a Mainnet node, either a local node on
Mainnet or
Dijets Mainnet API
server
where `` should be used for the
ip
. const networkID: number = 1
based on this.- Set the correct amount to stake.