Dockerized Rosetta API implementation mostly based off of blockchain-node:
- Rosetta specs: https://www.rosetta-api.org/
- This is NOT a full node, but rather works off the latest snapshot as specified in
blockchain-node
. As a result, there is currently no support for historical balances or reconciliation. blockchain-node
provides the basic blockchain that the Data API reads from./helium-constructor
implements a simple Express server written in TypeScript exposing helium-js for Construction API actions (transaction construction, signing mechanisms, etc)
This project was created by @syuan100 and supported, in part, by the DeWi Grants Program.
Mainnet:
DOCKER_BUILDKIT=1 docker build . -t rosetta-helium:latest
Testnet:
DOCKER_BUILDKIT=1 docker build . -t rosetta-helium:latest --build-arg NETWORK=testnet
Note: DOCKER_BUILDKIT=1
is not necessary but including it may reduce the image size due to the nature of the conditional build.
Mainnet:
DOCKER_BUILDKIT=1 docker build . -f Dockerfile_quick -t rosetta-helium:latest
Testnet:
DOCKER_BUILDKIT=1 docker build . -f Dockerfile_quick -t rosetta-helium:latest --build-arg NETWORK=testnet
Local data is stored in helium-data
docker run -d --rm --init --ulimit "nofile=1000000:1000000" -v "$(pwd)/helium-data:/data" -p 8080:8080 -p 44158:44158 rosetta-helium:latest
It's HIGHLY recommended that you set the internal/external NAT settings through environment variables for better performance:
NAT_INTERNAL_IP
-> 172.17.0.X
X depends on how many docker containers you have
NAT_INTERNAL_PORT
-> 44158
Default port for peering
NAT_EXTERNAL_IP
-> Your publicly accessible IP address
NAT_EXTERNAL_PORT
-> 44158
Generally would want to keep the same port that you exposed in the command line
docker run -d --rm --init --ulimit "nofile=1000000:1000000" -v "$(pwd)/helium-data:/data" -p 8080:8080 -p 44158:44158 -e NAT_INTERNAL_IP={{docker_ip}} -e NAT_INTERNAL_PORT={{docker_port}} -e NAT_EXTERNAL_IP={{public_ip}} -e NAT_EXTERNAL_PORT={{public_port}} rosetta-helium:latest
Mainnet:
rosetta-cli check:data --configuration-file rosetta-cli-config/mainnet/config.json
rosetta-cli check:construction --configuration-file rosetta-cli-config/mainnet/config.json
Testnet:
rosetta-cli check:data --configuration-file rosetta-cli-config/testnet/config.json
rosetta-cli check:construction --configuration-file rosetta-cli-config/testnet/config.json
(Please wait a few minutes for the Helium node to initialize before running this command)
Read more on using the rosetta-cli.
It's annoying to spin up a docker container for every change that you want to make. So for local development, it is recommended that you run each part of the implementation separately.
- Install golang if you haven't yet.
- At the root directory, run
go run .
to start the rosetta server at port:8080
- Checkout blockchain-node.
- Run
make && make release
to build a release - Run
make start
to start blockchain-node at port:4467
- Install
node
. I prefer nvm. cd helium-constructor
npm ci
npm run build
ornpm run watch
npm run nodemon
to start the express server at port:3000
At this point you should be able to run the rosetta-cli
check from above and get similiar results to the docker container. Remember, make sure to give blockchain-node
a few minutes to warm up before it picks up blocks.
- HNT (Helium Token)
- HST (Helium Security Token)
- DC (Data Credits): not implemented as they cannot be actively traded
Transactions support for reading from the Data API
Transaction | Implemented |
---|---|
payment_v1 |
✅ |
payment_v2 |
✅ |
reward_v1 |
✅ |
reward_v2 |
✅ |
security_coinbase_v1 |
✅ |
security_exchange_v1 |
✅ |
token_burn_v1 |
✅ |
transfer_hotspot_v1 |
✅ |
transfer_hotspot_v2 |
✅ |
stake_validator_v1 |
✅ |
unstake_validator_v1 |
✅ |
transfer_validator_v1 |
✅ |
create_htlc_v1 |
✅ |
redeem_htlc_v1 |
✅ |
Transaction | Implemented |
---|---|
add_gateway_v1 |
✅ |
assert_location_v1 |
✅ |
assert_location_v2 |
✅ |
oui_v1 |
✅ |
update_gateway_oui_v1 |
✅ |
routing_v1 |
✅ |
state_channel_open_v1 |
✅ |
Transaction | Notes |
---|---|
dc_coinbase_v1 |
DC only transaction |
state_channel_close_v1 |
DC only transaction |
gen_gateway_v1 |
Internal blockchain only |
poc_request_v1 |
Internal blockchain only |
poc_receipt_v1 |
Internal blockchain only |
consensus_group_v1 |
Internal blockchain only |
vars_v1 |
Internal blockchain only |
price_oracle_v1 |
Oracle HNT value transactions |
Transaction support for creation via the construction API
Transaction | Implemented |
---|---|
payment_v2 |
✅ |
security_exchange_v1 |
❌ |
create_htlc_v1 |
❌ |
redeem_htlc_v1 |
❌ |
stake_validator_v1 |
❌ |
unstake_validator_v1 |
❌ |
transfer_validator_v1 |
❌ |
The unstake_validator_v1
transaction is unique in that the balance changing portion of the transaction doesn't happen until the specified cooldown has passed. At that point, there is a callback on the ledger that records the balance change. Unfortunately, there is no way for blockchain-node
to surface information about this balance change when inspecting a block at a particular height. This is especially important for the rosetta-cli check:data
command to pass.
To mitigate this, we decided to store what we are calling "ghost transactions" that will be triggered when Rosetta queries a particular block. That way, Rosetta can notice the balance change and properly credit the appropriate account for reconciliation purposes.
Example:
- Unstake transaction dectected at block 5 with a cool down of 10 blocks (transaction fee is deducted here)
- We store a "ghost transaction" in our local BadgerDB at block 15 (current block + cool down) with the appropriate credit to the appropriate account
- When we query block 15, Rosetta will check BadgerDB for any ghost transactions and include them in the query response.