Plian Javascript Console

Opening the Javascript Console

Main Chain

To open the console for the main chain, execute:

~/pchain/bin/pchain attach ~/pchain/.pchain/pchain/pchain.ipc

Subchain

To open the console for the subchain, execute:

~/pchain/bin/pchain attach ~/pchain/.pchain/child_0/pchain.ipc

Creating an Executable Console

Main Chain

If you don't want to have to remember the command to open the console, you can create a simple bash script to open it. First, open a document called openconsole.sh

nano openconsole.sh

That will open a text editor. In the text editor, copy and paste the below:

#!/bin/bash
~/pchain/bin/pchain attach ~/pchain/.pchain/pchain/pchain.ipc

Then type ctrl-x then y to save and exit. To make it executable:

chmod u+x openconsole.sh

The console can now be opened by executing the command ./openconsole.sh

Subchain

The same can be done for creating an executable to attach to the subchain. To do that, open a document called openconsolecc.sh

nano openconsolecc.sh

That will open a text editor. In the text editor, copy and paste the below:

#!/bin/bash
~/pchain/bin/pchain attach ~/pchain/.pchain/pchain/pchain.ipc

Then type ctrl-x then y to save and exit. To make it executable:

chmod u+x openconsolecc.sh

The console can now be opened by executing the command ./openconsolecc.sh

Once the console opens, you will see something like this:

Welcome to the Pchain JavaScript console!
instance: pchain/linux-amd64/go1.12.5
coinbase: 0x00000017f6f17ce18faa53d7010fa66acd0e1fb9
at block: 20346346 (Sun, 07 Feb 2021 05:59:12 UTC)
datadir: /root/.pchain/pchain
modules: admin:1.0 chain:1.0 debug:1.0 del:1.0 eth:1.0 miner:1.0 net:1.0 personal:1.0 pi:1.0 rpc:1.0 tdm:1.0 txpool:1.0 web3:1.0
>

Don't worry if you don't have a coinbase line as that only shows when you have generated/imported a key.

How to Use It For General Node Maintenance

Import Keys

Imports the given unencrypted private key (hex string) into the key store, encrypting it with the passphrase.

Returns the address of the new account.

personal.importRawKey(keydata, passphrase)

Create New Account

Generates a new private key and stores it in the key store directory. The key file is encrypted with the given passphrase. Returns the address of the new account.

At the Pchain console, newAccount will prompt for a passphrase when it is not supplied as the argument.

personal.newAccount()

Unlock Your Account

Decrypts the key with the given address from the key store.

Both passphrase and unlock duration are optional when using the JavaScript console. If the passphrase is not supplied as an argument, the console will prompt for the passphrase interactively.

The unencrypted key will be held in memory until the unlock duration expires. If the unlock duration defaults to 300 seconds. An explicit duration of zero seconds unlocks the key until Pchain exits.

The account can be used with eth_sign and eth_sendTransaction while it is unlocked.

personal.unlockAccount(address, passphrase, duration)

Send a Transaction

Creates a new message call transaction or a contract creation, if the data field contains code.

Parameters

  • from: DATA, 20 Bytes - The address the transaction is sent from.

  • to: DATA, 20 Bytes - (optional when creating a new contract) The address the transaction is directed to.

  • gas: QUANTITY - (optional, default: 90000) Integer of the gas provided for the transaction execution. It will return unused gas.

  • gasPrice: QUANTITY - (optional, default: To-Be-Determined) Integer of the gasPrice used for each paid gas

  • value: QUANTITY - (optional) Integer of the value sent with this transaction

  • data: DATA - The compiled code of a contract OR the hash of the invoked method signature and encoded parameters. For details see Pchain Contract ABI

  • nonce: QUANTITY - (optional) Integer of a nonce. This allows to overwrite your own pending transactions that use the same nonce.

personal.sendTransaction({from: "youraddress", to: "toaddress", value: "amount"})

Where the amount is in p-wei. Alternatively, you can replace the "amount" with another fuction to convert PI to p-wei:

personal.sendTransaction({from: "youraddress", to: "toaddress", value: web3.toWei(1.23, "pi")})

This will error if your account is not unlocked, so you can either unlock it, or pass it your password:

personal.sendTransaction({from: "youraddress", to: "toaddress", value: web3.toWei(1.23, "pi")}, "password")

Sign Message

The sign method calculates a Pchain specific signature with: sign(keccack256("\x19Pchain Signed Message:\n" + len(message) + message))).

By adding a prefix to the message makes the calculated signature recognisable as a Pchain specific signature. This prevents misuse where a malicious DApp can sign arbitrary data (e.g. transaction) and use the signature to impersonate the victim.

See ecRecover to verify the signature.

personal.sign(message, account, [password])

Check If Your Node Is Syncing

pi.syncing

Returns either true or false. False can also mean you are fully synced.

Check If Your Node Is Mining

pi.mining

Returns either true or false depending on whether your node is a member of the validation set for the current epoch.

Check Current Block Number

pi.blockNumber

Returns the current block number your node is synced to.

Check Current Epoch

tdm.getCurrentEpochNumber

Returns the current epoch number your node is synced to in hex.

Check Epoch Details

tdm.getEpoch("epochNumber")

where epochNumber is the epoch number you want to get details on in hex, e.g. 0x16 for epoch 22. Returns details on epoch phases and the list of validators.

Example:

{
end_block: "0x1483995",
end_time: "0001-01-01T00:00:00Z",
number: "0x16",
reveal_end_block: "0x14739f4",
reveal_start_block: "0x1453ab4",
reward_per_block: "0x1bd572fe32063b0d",
start_block: "0x134410a",
start_time: "2021-02-03T21:45:33.18Z",
validators: [{
address: "0xdd619d482bc919b9ae199a4d23425c8a44ca414b",
public_key: "0x25ABA630012F59B503899FD74E503E6985F826A7C0129A596038C75AD80D8CEC50FAA34E98B1B05566CB0180D291BE01ACA93F0D631CE67B14B736CF63B2BB555F4997695661DB405D6FA78E065803827C328F36E53749670A088FBFEBA734AD70E5B6A92ABC6EA031F757CE9109E922D12EA32496B9B2C19C52E91D89732A98",
remain_epoch: "0x0",
voting_power: "0x2d0ff3bf21c88a9223f8cc"
},

Check Your Balance

Returns the balance of the account of a given address in p-wei.

Parameters

  1. DATA, 20 Bytes - address to check for balance.

  2. QUANTITY|TAG - integer block number, or the string "latest", "earliest" or "pending", see the default block parameter

pi.getBalance("address","latest")

Check Your Full Balance

Returns the full balance of the account of a given address. This includes the delegated balance as well as personal balance.

Parameters

  1. from: address, 20 Bytes - address to check for balance.

  2. blockNumber: QUANTITY|TAG - integer block number, or the string "latest", "earliest" or "pending"

  3. fullDetail: Boolean - If true it returns the full detail of proxied/reward object under this address

params: [
'0xd833b6738285f4a50cf42cf1a40c4000256589d4',
'latest',
true
]

Returns

  1. balance: QUANTITY - integer of the current balance in p-wei.

  2. total_delegateBalance: QUANTITY - total delegate balance in p-wei to other address

  3. total_depositBalance: QUANTITY - deposit balance in p-wei for Validator Stake

  4. total_depositProxiedBalance: QUANTITY - total deposit proxied balance in p-wei for Validator Stake

  5. total_pendingRefundBalance: QUANTITY - total pending refund balance in p-wei which will be return to delegate at the end of Current Epoch

  6. total_proxiedBalance: QUANTITY - total proxied balance in p-wei delegate from other address

  7. total_rewardBalance: QUANTITY - total pending reward balance in p-wei of this address

  8. proxied_detail: Object - detail record of each address's proxied data, including proxied balance, deposit proxied balance and pending refund balance

  9. reward_detail: Object - detail record of this address's reward data, including how much balance in p-wei will be given at the end of each epoch

pi.getFullBalance('address','latest',true)

Check Number of Peers Your Node is Connected To

web3.net.peerCount

Returns the number of other nodes your node is connected to.

How to Use It For More Complex Purposes

The Javascript console allows you to not only use predefined functions to pull information from the network, but you can also create custom functions using Javascript to do anything you can think of using the variety of functions defined in the RPC and PWeb3 API.

Since it is a JavaScript console, you have complete ECMA5 functionality(Go Pchain uses Otto JS VM, which is a JS interpreter written in Go). You can declare variables, use control structures, define new methods, and even use any of setInterval, clearInterval, setTimeout, and clearTimeout.

Example: Check For Number of Transactions Between a Range of Blocks

From within the console, you can write a Javascript function

function checkTransactionCount(startBlockNumber, endBlockNumber) {
console.log("Searching for non-zero transaction counts between blocks " + startBlockNumber + " and " + endBlockNumber);
for (var i = startBlockNumber; i <= endBlockNumber; i++) {
var block = pi.getBlock(i);
if (block != null) {
if (block.transactions != null && block.transactions.length != 0) {
console.log("Block #" + i + " has " + block.transactions.length + " transactions")
}
}
}
}

Then you can execute this function with:

checkTransactionCount(20370000,20375688)

Which returns:

Searching for non-zero transaction counts between blocks 20370000 and 20375688
Block #20370175 has 1 transactions
Block #20370692 has 1 transactions
Block #20371258 has 1 transactions
Block #20372828 has 1 transactions
Block #20373711 has 1 transactions
Block #20373743 has 1 transactions
Block #20375586 has 1 transactions

Example: Check For Blocks Your Node Has Mined

This one is a bit more complicated, requiring multiple function definitions. In practice, you can write these in a separate text editor as one concatenated function and paste it as one in order to simplify it down. This is broken down for simplicity.

First, a function to print transaction info:

function printTransaction(txHash) {
var tx = pi.getTransaction(txHash);
if (tx != null) {
console.log(" tx hash : " + tx.hash + "\n"
+ " nonce : " + tx.nonce + "\n"
+ " blockHash : " + tx.blockHash + "\n"
+ " blockNumber : " + tx.blockNumber + "\n"
+ " transactionIndex: " + tx.transactionIndex + "\n"
+ " from : " + tx.from + "\n"
+ " to : " + tx.to + "\n"
+ " value : " + tx.value + "\n"
+ " gasPrice : " + tx.gasPrice + "\n"
+ " gas : " + tx.gas + "\n"
+ " input : " + tx.input);
}
}

Next, a function to print block info:

function printBlock(block) {
console.log("Block number : " + block.number + "\n"
+ " hash : " + block.hash + "\n"
+ " parentHash : " + block.parentHash + "\n"
+ " nonce : " + block.nonce + "\n"
+ " logsBloom : " + block.logsBloom + "\n"
+ " transactionsRoot: " + block.transactionsRoot + "\n"
+ " stateRoot : " + block.stateRoot + "\n"
+ " miner : " + block.miner + "\n"
+ " difficulty : " + block.difficulty + "\n"
+ " totalDifficulty : " + block.totalDifficulty + "\n"
+ " extraData : " + block.extraData + "\n"
+ " size : " + block.size + "\n"
+ " gasLimit : " + block.gasLimit + "\n"
+ " gasUsed : " + block.gasUsed + "\n"
+ " timestamp : " + block.timestamp + "\n"
+ " transactions : " + block.transactions);
if (block.transactions != null) {
console.log("--- transactions ---");
block.transactions.forEach( function(e) {
printTransaction(e);
})
}
}

Then, a function to print block info from a specific miner.

function getMinedBlocks(miner, startBlockNumber, endBlockNumber) {
if (endBlockNumber == null) {
endBlockNumber = pi.blockNumber;
console.log("Using endBlockNumber: " + endBlockNumber);
}
if (startBlockNumber == null) {
startBlockNumber = endBlockNumber - 10000;
console.log("Using startBlockNumber: " + startBlockNumber);
}
console.log("Searching for miner \"" + miner + "\" within blocks " + startBlockNumber + " and " + endBlockNumber + "\"");
for (var i = startBlockNumber; i <= endBlockNumber; i++) {
if (i % 1000 == 0) {
console.log("Searching block " + i);
}
var block = pi.getBlock(i);
if (block != null) {
if (block.miner == miner || miner == "*") {
console.log("Found block " + block.number);
printBlock(block);
}
}
}
}

If startBlockNumber is not specified, it will default to the last 10,000 blocks. This takes some time to scan, so reduce this number to 1000 to reduce the scanning time.

If endBlockNumber is not specified, it will default to the latest block number.

Then one last one just to make entering your node address easier:

function getMyMinedBlocks(startBlockNumber, endBlockNumber) {
getMinedBlocks(pi.accounts[0], startBlockNumber, endBlockNumber);
}

Now you can use this to see block details of the blocks your node mined:

getMyMinedBlocks(startblock,endblock)

Which returns for example from getMyMinedBlocks(20376850,20376860)

Found block 20376853
Block number : 20376853
hash : 0x349a56b0ee7ca3b5c18cdaa9b58dc91b1c8be8b7b7a63dea70a6a92bf5b44359
parentHash : 0xd60c0ea757b25c6748662b3baa65dd1451149d975ed53905fd9428ce57c947d3
nonce : 0x0000000000000000
logsBloom : 0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000
transactionsRoot: 0x56e81f171bcc55a6ff8345e692c0f86e5b48e01b996cadc001622fb5e363b421
stateRoot : 0x2dca9b62e62d06ad72aff4d138d0a85ff28b1b0e78daace3dbe1a23f193954f7
miner : 0x00000017f6f17ce18faa53d7010fa66acd0e1fb9
difficulty : 1
totalDifficulty : 20377877
extraData : 0x010670636861696e000000000136ed1516619f1d2e89d0c0000000000000000000160114ad0fa07abd61134aa4e662eb63919b75575f1dcc0114ec3de6ec08b0210b7dedd06466038f9c620da88a010114839fa0d18e9c6238174b5f78fcef76b1d204591300000000000000010114b917b1e4f6b807345c75e01db1b7fa4f43f1d393000000000136ed1500014035bfb83ef839b83b8c339f61c5d7f951f10636447c7ef3e93877295e442fcbfe42279b0d6fe94f78ce27c022765d0fd3c5154ecaba62bbb91ac6d0bfceb5f0ba01000000000000003501010001ed5e6cfd5fbf00
size : 740
gasLimit : 8000000
gasUsed : 0
timestamp : 1612745088
transactions :
--- transactions ---

You can also check for specific blocks with any miner with wildcard "*":

getMinedBlocks("*",20370174,20370176)
Found block 20370175
Block number : 20370175
hash : 0x8f69fd62ce38d37a523bc878387458c6edb0d8f0593afa038acd21704b16f4c3
parentHash : 0x624bb8297dbae4ae6c95fc2ed0bc5c05fbf43e2eab3e86fd52c9d2ad0393446c
nonce : 0x0000000000000000
logsBloom : 0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000
transactionsRoot: 0x35fda788d4cb76f443d4b696511e8b851989775acf9de51b107ba4ec6812650f
stateRoot : 0xe2d9be449c0617a0d8930d6ce0e1706a663085766b78d386013aae6f80a6d7bd
miner : 0xf6a94ecd6347a051709f7f96061c6a0265b59181
difficulty : 1
totalDifficulty : 20371199
extraData : 0x010670636861696e000000000136d2ff16619210a6ce05c0000000000000000000160114bf47a48e5c2e2d5e1989ff83080909950cf12e080114ec3de6ec08b0210b7dedd06466038f9c620da88a0101148fe06ad92093838406cf6f53dc2e2132b04ff9c500000000000000010114eb8a78690667a10e23f21ef2aa37d3b66531c0b9000000000136d2ff000140597c929f33c0ae8509849996798b13935d94f3bb8cc28f97dc8bcf8a99cb81e84b5cdf97667e64893c26196d870eb955ef97842a0e10815836c7bafddb18c60201000000000000003501010001ed5e6cfd7f3f00
size : 887
gasLimit : 8000000
gasUsed : 21000
timestamp : 1612730741
transactions : 0xa6ef4c9631a3f82d9efdaedc1394c13ddd3faa84ffd6aaf0b60878f8a2e25a21
--- transactions ---
tx hash : 0xa6ef4c9631a3f82d9efdaedc1394c13ddd3faa84ffd6aaf0b60878f8a2e25a21
nonce : 2329
blockHash : 0x8f69fd62ce38d37a523bc878387458c6edb0d8f0593afa038acd21704b16f4c3
blockNumber : 20370175
transactionIndex: 0
from : 0x0d0707963952f2fba59dd06f2b425ace40b492fe
to : 0x8a14cdaf595ce2db5cdcf5268d481615be2aa953
value : 4900000000000000000
gasPrice : 10000000000
gas : 30000
input : 0x

The possibilities are pretty endless here. The only problem is