Running PulseChain Ethereum fork full node on Akashnet
This write-up will guide you to deploy PulseChain Ethereum fork full node on Akashnet.
WARNING: this write-up was written for PulseChain v1, make sure to adjust it to the changes for PulseChain v2 in https://gitlab.com/pulsechaincom/pulsechain-testnet
This write-up will guide you to deploy PulseChain Ethereum-fork full node on Akashnet.
IMPORTANT: this will not connect you to the real PulseChain nodes yet, the bootnodes, network configs (config.toml, genesis.json) are missing. Wait for the complete instructions provided by the PulseChain devs here https://gitlab.com/pulsechaincom/go-pulse/-/blob/16178c59/README.md#a-full-node-on-the-pulsechain-testnet
But before getting that, you can still learn to deploy it and connect to the Ethereum network.
Make sure to deploy geth on a provider with the SSD. One can't run geth on the HDD, because geth stores data on a disk in a horrible way which is outlined in their FAQ https://geth.ethereum.org/docs/faq
I used Ubuntu 20.04.2 LTS
Linux distribution and the following software:
- akash: v0.12.1
(to work with the Akashnet);
- geth: v0.2.0-6abf18d00
(to deploy it on the Akashnet);
Meet your new friends:
- Akashnet is a decentralized cloud of future;
- PulseChain is Energy Efficient, Cheaper, Faster, Fee-Burning Ethereum fork.
The idea is simple - leverage the Akashnet decloud in order to deploy PulseChain container.
It's up to 86% cheaper to run an instance on Akashnet than on Amazon AWS https://akashlytics.com/price-compare (at the time I wrote this write-up)
Ok, I'm not good at talking much, so to save your and my time let's jump straight to the CLI.
1. Install akash client
AKASH_NET="https://raw.githubusercontent.com/ovrclk/net/master/mainnet"
AKASH_VERSION="$(curl -s "$AKASH_NET/version.txt")"
curl https://raw.githubusercontent.com/ovrclk/akash/master/godownloader.sh | sh -s -- "v$AKASH_VERSION"
Please also install jq
tool as it will be used in this write-up.
2. Create your akash wallet
akash keys add default
This command will output the mnemonic phrase, make sure to save it in a safe place.
It will also output your address, in my case the address was akash1h24fljt7p0nh82cq0za0uhsct3sfwsfu9w3c9h
.
export AKASH_ACCOUNT_ADDRESS=akash1h24fljt7p0nh82cq0za0uhsct3sfwsfu9w3c9h
More about the Akash wallet https://docs.akash.network/guides/wallet
3. Fund your akash wallet
You will need about 10 AKT
(Akash Token) to get you started.
You can purchase them at one of the exchanges mentioned here https://akash.network/token/
You can query the balance of your wallet
export AKASH_NET="https://raw.githubusercontent.com/ovrclk/net/master/mainnet"
export AKASH_NODE="$(curl -s "$AKASH_NET/rpc-nodes.txt" | shuf -n 1)"
akash \
--node "$AKASH_NODE" \
query bank balances "$AKASH_ACCOUNT_ADDRESS"
Denomination: 1 akt = 1000000 uakt (akt*10^6), or you can add -o json | jq -r '(.balances[0].amount | tonumber / pow(10; 6))'
on the command line ;-)
I'm using production akashnet-2 Akash network. For more on different Akash networks please refer to https://docs.akash.network/guides/version
4. Create certificate file
To create a deployment, a certificate must first be created. To do this, run:
export AKASH_CHAIN_ID="$(curl -s "$AKASH_NET/chain-id.txt")"
akash tx cert create client \
--from default \
--chain-id $AKASH_CHAIN_ID \
--node $AKASH_NODE \
--gas-prices="0.025uakt" --gas="auto" --gas-adjustment=1.15
certificate needs to be created only once per account and can be used across all deployments. More about the certificate https://docs.akash.network/design/mtls
5. Prepare the deployment manifest file
Create a file named go-pulse-geth.yml
with the following contents:
---
version: "2.0"
services:
geth:
image: andrey01/go-pulse-geth:0.2.0-6abf18d00
expose:
## 8545/tcp RPC port
## SECURITY RISK: someone can transfer all your funds out of your wallet,
## in case if you unlock your wallet there!
##- port: 8545
## as: 8545
## proto: tcp
## to:
## - global: true
### 8546/tcp WS port
##- port: 8546
## as: 8546
## proto: tcp
## to:
## - global: true
# 30303 TCP and UDP, used by the P2P protocol running the network
- port: 30303
as: 30303
proto: tcp
to:
- global: true
- port: 30303
as: 30303
proto: udp
to:
- global: true
args:
- "--syncmode=fast"
- "--cache=2048" # make sure you have requested more RAM for the container.
#- "--mine"
#- "--miner.etherbase=0xabcdef...."
##- "--rpc"
##- "--rpcapi=admin,eth,net,web3"
##- "--rpcaddr=0.0.0.0"
##- "--rpcport=8545"
##- "--rpcvhosts=*"
##- "--ws"
##- "--wsaddr=0.0.0.0"
##- "--wsport=8546"
##- "--wsorigins=*"
profiles:
compute:
geth:
resources:
cpu:
units: 2
memory:
size: 4Gi
storage:
size: 1024Gi
placement:
akash:
#signedBy:
# anyOf:
# # - "akash1365yvmc4s7awdyj3n2sav7xfx76adc6dnmlx63" ## AKASH verified hosts only
pricing:
geth:
denom: uakt
amount: 500
deployment:
geth:
akash:
profile: geth
count: 1
Pricing - Note that there are bids from multiple different providers. In this case, both providers happen to be willing to accept a price of 1 uAKT. This means that the lease can be created using 1 uAKT or 0.000001 AKT per block to execute the container.
pricing sets the limits so providers know how to bid on your deployment. i.e. amount of uakt per block (each block happens every 6 seconds) you are willing to pay.
So in case with 1uakt, you are going to be paying:
((1*((60/6)*60*24*30.436875))/10^6)*2.68
= $1.17
per month having 1akt worth $2.68
as of 25th July 2021
.signedBy
is a "validation" thing, after a provider is approved by akash they get signed by akash to ensure security and reliability. If you don't care about which provider will be running your container, then just keep it commented.
More on SDL (Stack Definition Language) used to write the Akash manifest https://docs.akash.network/documentation/sdl
You can use my container andrey01/go-pulse-geth:0.2.0-6abf18d00
, or you can build your own, that's how you can do it:
$ git clone git@gitlab.com:pulsechaincom/go-pulse.git
$ cd go-pulse
$ git log --oneline -1
6abf18d00 (HEAD -> master, upstream/master) Merge branch 'readme' into 'master'
$ docker build -t go-pulse-geth:0.2.0-6abf18d00 .
$ docker tag go-pulse-geth:0.2.0-6abf18d00 andrey01/go-pulse-geth:0.2.0-6abf18d00
$ docker push andrey01/go-pulse-geth:0.2.0-6abf18d00
6. Create your deployment
akash tx deployment create go-pulse-geth.yml \
--from default \
--node $AKASH_NODE \
--chain-id $AKASH_CHAIN_ID \
--gas-prices="0.025uakt" --gas="auto" --gas-adjustment=1.15
If this command ends with Error: RPC error -32603 - Internal error: timed out waiting for tx to be included in a block
then no worries, you can query the akash blockchain in order to find your deployment ID:
$ akash query txs \
--events "message.sender=$AKASH_ACCOUNT_ADDRESS&message.action=create-deployment" \
--page 1 --limit 999999 \
| jq -r '.txs[] | [ .tx.body.messages[].id[] ] | @csv' | \
tail -5
"akash1h24fljt7p0nh82cq0za0uhsct3sfwsfu9w3c9h","1933977"
Query the deployment:
I'm explicitly not "export"'ing the following 3 "SEQ" variables as to avoid 'failed to execute message; message index: 0: Deployment closed' error on 'akash tx deployment create' later. If you get this error, then simply unset AKASH_DSEQ
.
$ AKASH_DSEQ=1933977
$ AKASH_GSEQ=1
$ AKASH_OSEQ=1
$ akash query deployment get \
--owner $AKASH_ACCOUNT_ADDRESS \
--node $AKASH_NODE \
--dseq $AKASH_DSEQ
deployment:
created_at: "1933981"
deployment_id:
dseq: "1933977"
owner: akash1h24fljt7p0nh82cq0za0uhsct3sfwsfu9w3c9h
state: active
version: Zqi3K8lyZ/XLGwe2gM9cho6VzAoKnO72FgnXlIVF/NA=
escrow_account:
balance:
amount: "5000000"
denom: uakt
id:
scope: deployment
xid: akash1h24fljt7p0nh82cq0za0uhsct3sfwsfu9w3c9h/1933977
owner: akash1h24fljt7p0nh82cq0za0uhsct3sfwsfu9w3c9h
settled_at: "1934322"
state: open
transferred:
amount: "0"
denom: uakt
groups:
- created_at: "1933981"
group_id:
dseq: "1933977"
gseq: 1
owner: akash1h24fljt7p0nh82cq0za0uhsct3sfwsfu9w3c9h
group_spec:
name: akash
requirements:
attributes: []
signed_by:
all_of: []
any_of: []
resources:
- count: 1
price:
amount: "50"
denom: uakt
resources:
cpu:
attributes: []
units:
val: "2000"
endpoints:
- kind: RANDOM_PORT
- kind: RANDOM_PORT
memory:
attributes: []
quantity:
val: "4294967296"
storage:
attributes: []
quantity:
val: "1099511627776"
state: open
As you may have noticed the 5 AKT are now under the escrow_account
and your akash wallet balance was reduced by that value. These tokens are going to be used by this deployment as soon as you create a lease. And they will be returned as soon as you close the lease / deployment (minus few of them which were used for the lease itself).
More on deployment https://docs.akash.network/guides/deploy
7. Query the market for bids
Now that we want to actually run our deployment, we will need to see what market offers, accept the bid we feel comfortable with, create the lease and send manifest of our deployment to get it up and running.
$ akash query market bid list \
--owner=$AKASH_ACCOUNT_ADDRESS \
--node $AKASH_NODE \
--dseq $AKASH_DSEQ \
--state open
bids:
- bid:
bid_id:
dseq: "1933977"
gseq: 1
oseq: 1
owner: akash1h24fljt7p0nh82cq0za0uhsct3sfwsfu9w3c9h
provider: akash1nxq8gmsw2vlz3m68qvyvcf3kh6q269ajvqw6y0
created_at: "1933982"
price:
amount: "17"
denom: uakt
state: open
escrow_account:
balance:
amount: "50000000"
denom: uakt
id:
scope: bid
xid: akash1h24fljt7p0nh82cq0za0uhsct3sfwsfu9w3c9h/1933977/1/1/akash1nxq8gmsw2vlz3m68qvyvcf3kh6q269ajvqw6y0
owner: akash1nxq8gmsw2vlz3m68qvyvcf3kh6q269ajvqw6y0
settled_at: "1933982"
state: open
transferred:
amount: "0"
denom: uakt
pagination:
next_key: null
total: "0"
Set the AKASH_PROVIDER
environment variable to the one you picked from the available market bids:
AKASH_PROVIDER=akash1nxq8gmsw2vlz3m68qvyvcf3kh6q269ajvqw6y0
If akash query market bid list
isn't showing any bids, make sure you unset AKASH_PROVIDER
environment variable!
8. Create lease / Accept the bid
Create a lease for the bid from the chosen provider above by running:
akash tx market lease create \
--chain-id $AKASH_CHAIN_ID \
--node $AKASH_NODE \
--owner $AKASH_ACCOUNT_ADDRESS \
--dseq $AKASH_DSEQ \
--gseq $AKASH_GSEQ \
--oseq $AKASH_OSEQ \
--provider $AKASH_PROVIDER \
--from default \
--gas-prices="0.025uakt" --gas="auto" --gas-adjustment=1.15
Please note that once the lease is created, the provider will begin debiting your deployment's escrow account, even if you have not completed the deployment process by uploading the manifest in the following step.
9. Send the manifest to deploy PulseChain node
Now, to get your PulseChain deployment started, you need to send your manifest to the provider:
akash provider send-manifest go-pulse-geth.yml \
--node $AKASH_NODE \
--dseq $AKASH_DSEQ \
--provider $AKASH_PROVIDER \
--from default
After few moments, you will be able to see your deployment:
$ akash provider lease-status \
--node $AKASH_NODE \
--dseq $AKASH_DSEQ \
--provider $AKASH_PROVIDER \
--from default
{
"services": {
"geth": {
"name": "geth",
"available": 1,
"total": 1,
"uris": null,
"observed_generation": 1,
"replicas": 1,
"updated_replicas": 1,
"ready_replicas": 1,
"available_replicas": 1
}
},
"forwarded_ports": {
"geth": [
{
"host": "provider.akash.nixaid.com",
"port": 30303,
"externalPort": 30396,
"proto": "TCP",
"available": 1,
"name": "geth"
},
{
"host": "provider.akash.nixaid.com",
"port": 30303,
"externalPort": 31438,
"proto": "UDP",
"available": 1,
"name": "geth"
}
]
}
}
The only caveat is that it is not possible to export non-http/https (80/443) TCP ports, so-called nodePort ports directly as-is, that's why you are seeing the actual ports are the externalPort
.
The Akashnet providers use Kubernetes under the hood for actually running your containers. The Kubernetes control plane allocates a port from a range specified by --service-node-port-range
flag (default: 30000-32767)
(nodePort)
This means you should always check to what ports your Akash deployment gets assigned by the provider's Kubernetes.
If you really need the exact ports to be exposed, you can negotiate with the Akash provider or use some load balancer / reverse proxy (i.e. nginx / haprorxy / traefik) to forward to these ports.
10. See the logs of your PulseChain container on Akashnet
You can see your PulseChain node's mnemonic seed phrase there.
$ akash \
--node "$AKASH_NODE" \
provider lease-logs \
--dseq "$AKASH_DSEQ" \
--gseq "$AKASH_GSEQ" \
--oseq "$AKASH_OSEQ" \
--provider "$AKASH_PROVIDER" \
--from default \
--follow
[geth-67b86dfcbb-t8ppz] INFO [07-25|16:16:19.890] Starting Geth on Ethereum mainnet...
[geth-67b86dfcbb-t8ppz] WARN [07-25|16:16:19.891] Sanitizing cache to Go's GC limits provided=2048 updated=682
[geth-67b86dfcbb-t8ppz] INFO [07-25|16:16:19.892] Maximum peer count ETH=50 LES=0 total=50
[geth-67b86dfcbb-t8ppz] INFO [07-25|16:16:19.892] Smartcard socket not found, disabling err="stat /run/pcscd/pcscd.comm: no such file or directory"
[geth-67b86dfcbb-t8ppz] INFO [07-25|16:16:19.895] Starting peer-to-peer node instance=Geth/v1.0.6-6abf18d0-20210720/linux-amd64/go1.15.5
[geth-67b86dfcbb-t8ppz] INFO [07-25|16:16:19.895] Allocated trie memory caches clean=102.00MiB dirty=170.00MiB
[geth-67b86dfcbb-t8ppz] INFO [07-25|16:16:19.895] Allocated cache and file handles database=/root/.ethereum/geth/chaindata cache=341.00MiB handles=524288
[geth-67b86dfcbb-t8ppz] INFO [07-25|16:16:20.594] Opened ancient database database=/root/.ethereum/geth/chaindata/ancient
[geth-67b86dfcbb-t8ppz] INFO [07-25|16:16:20.595] Writing default main-net genesis block
[geth-67b86dfcbb-t8ppz] INFO [07-25|16:16:20.822] Persisted trie from memory database nodes=12356 size=1.78MiB time=40.929224ms gcnodes=0 gcsize=0.00B gctime=0s livenodes=1 livesize=0.00B
[geth-67b86dfcbb-t8ppz] INFO [07-25|16:16:20.822] Initialised chain configuration config="{ChainID: 1 Homestead: 1150000 DAO: 1920000 DAOSupport: true EIP150: 2463000 EIP155: 2675000 EIP158: 2675000 Byzantium: 4370000 Constantinople: 7280000 Petersburg: 7280000 Istanbul: 9069000, Muir Glacier: 9200000, Ramanujan: <nil>, Niels: <nil>, MirrorSync: <nil>, PrimordialPulse: <nil>, Engine: ethash}"
[geth-67b86dfcbb-t8ppz] INFO [07-25|16:16:20.823] Disk storage enabled for ethash caches dir=/root/.ethereum/geth/ethash count=3
[geth-67b86dfcbb-t8ppz] INFO [07-25|16:16:20.823] Disk storage enabled for ethash DAGs dir=/root/.ethash count=2
[geth-67b86dfcbb-t8ppz] INFO [07-25|16:16:20.823] Initialising Ethereum protocol versions="[65 64 63]" network=1 dbversion=<nil>
[geth-67b86dfcbb-t8ppz] WARN [07-25|16:16:20.823] Upgrade blockchain database version from=<nil> to=7
[geth-67b86dfcbb-t8ppz] INFO [07-25|16:16:20.823] Loaded most recent local header number=0 hash=d4e567…cb8fa3 td=17179869184 age=52y3mo3w
[geth-67b86dfcbb-t8ppz] INFO [07-25|16:16:20.823] Loaded most recent local full block number=0 hash=d4e567…cb8fa3 td=17179869184 age=52y3mo3w
[geth-67b86dfcbb-t8ppz] INFO [07-25|16:16:20.823] Loaded most recent local fast block number=0 hash=d4e567…cb8fa3 td=17179869184 age=52y3mo3w
[geth-67b86dfcbb-t8ppz] INFO [07-25|16:16:20.846] Regenerated local transaction journal transactions=0 accounts=0
[geth-67b86dfcbb-t8ppz] INFO [07-25|16:16:20.851] Allocated fast sync bloom size=272.00MiB
[geth-67b86dfcbb-t8ppz] INFO [07-25|16:16:20.921] Initialized fast sync bloom items=12356 errorrate=0.000 elapsed=69.368ms
[geth-67b86dfcbb-t8ppz] INFO [07-25|16:16:21.001] New local node record seq=1 id=151c6e3553cee58f ip=127.0.0.1 udp=30303 tcp=30303
[geth-67b86dfcbb-t8ppz] INFO [07-25|16:16:21.003] Started P2P networking self=enode://8648620db3f7924aa5ebb6ee9282e487b5fe72f8c60a29de3a48dac715a54096d71dfe761b1c495d15f0f699b8774c8174b0a08b616ba57d9ab6579528c4c5ab@127.0.0.1:30303
[geth-67b86dfcbb-t8ppz] INFO [07-25|16:16:21.010] IPC endpoint opened url=/root/.ethereum/geth.ipc
[geth-67b86dfcbb-t8ppz] INFO [07-25|16:16:31.004] Looking for peers peercount=0 tried=3 static=0
[geth-67b86dfcbb-t8ppz] INFO [07-25|16:16:41.008] Looking for peers peercount=0 tried=3 static=0
[geth-67b86dfcbb-t8ppz] INFO [07-25|16:16:51.100] Looking for peers peercount=0 tried=4 static=0
[geth-67b86dfcbb-t8ppz] INFO [07-25|16:17:01.103] Looking for peers peercount=0 tried=5 static=0
[geth-67b86dfcbb-t8ppz] INFO [07-25|16:17:01.132] Block synchronisation started
[geth-67b86dfcbb-t8ppz] INFO [07-25|16:17:01.444] Imported new state entries count=273 elapsed=2.247µs processed=273 pending=4369 retry=0 duplicate=0 unexpected=0
[geth-67b86dfcbb-t8ppz] INFO [07-25|16:17:01.487] Imported new state entries count=384 elapsed=2.152µs processed=657 pending=10513 retry=0 duplicate=0 unexpected=0
[geth-67b86dfcbb-t8ppz] INFO [07-25|16:17:01.528] Imported new state entries count=384 elapsed=1.701µs processed=1041 pending=16657 retry=0 duplicate=0 unexpected=0
[geth-67b86dfcbb-t8ppz] INFO [07-25|16:17:01.591] Imported new state entries count=384 elapsed=2.128µs processed=1425 pending=22795 retry=0 duplicate=0 unexpected=0
[geth-67b86dfcbb-t8ppz] INFO [07-25|16:17:01.756] Imported new state entries count=768 elapsed=868.707µs processed=2193 pending=25017 retry=0 duplicate=0 unexpected=0
[geth-67b86dfcbb-t8ppz] INFO [07-25|16:17:01.933] Imported new state entries count=768 elapsed=2.808ms processed=2961 pending=24601 retry=0 duplicate=0 unexpected=0
[geth-67b86dfcbb-t8ppz] INFO [07-25|16:17:02.335] Imported new state entries count=768 elapsed=7.270ms processed=3729 pending=24391 retry=0 duplicate=0 unexpected=0
[geth-67b86dfcbb-t8ppz] INFO [07-25|16:17:02.358] Imported new block headers count=192 elapsed=865.475ms number=192 hash=723899…123390 age=6y3w6d
[geth-67b86dfcbb-t8ppz] INFO [07-25|16:17:02.361] Migrated ancient blocks count=1 elapsed=325.756µs
[geth-67b86dfcbb-t8ppz] INFO [07-25|16:17:02.441] Imported new block headers count=192 elapsed=79.563ms number=384 hash=d3d5d5…c79cf3 age=6y3w6d
[geth-67b86dfcbb-t8ppz] INFO [07-25|16:17:02.929] Imported new state entries count=1536 elapsed=15.404ms processed=5265 pending=24216 retry=0 duplicate=0 unexpected=0
...
In case your geth
isn't finding the peers, refer to https://geth.ethereum.org/docs/interface/peer-to-peer
They explain how peers are found and how to tackle the common problems with connectivity.
11. Terminating the deployment
When you are done testing, you can terminate your deployment.
akash tx deployment close \
--node $AKASH_NODE \
--chain-id $AKASH_CHAIN_ID \
--dseq $AKASH_DSEQ \
--owner $AKASH_ACCOUNT_ADDRESS \
--from default \
--gas-prices="0.025uakt" --gas="auto" --gas-adjustment=1.15
12. Depositing more AKT for the deployment
If you are happy with your deployment and would not want it to stop one day, you can deposit more AKT tokens for the escrow account:
akash tx deployment deposit \
--from default \
--chain-id $AKASH_CHAIN_ID \
--node $AKASH_NODE 1000000uakt \
--dseq $AKASH_DSEQ \
--gas-prices="0.025uakt" --gas="auto" --gas-adjustment=1.15