![Blog post cover art for A First Look at Dashmate](https://ajc.pics/2024/07/15/00-dashmate-640-336.webp)
A First Look at Dashmate
Published:
A beginner friendly tutorial for running a local version of Dash Platform with Dashmate. Includes creating an identity, data contract, and documents.
Outline
Overview
Dashmate is a software tool designed to simplify the process of setting up and managing Dash masternodes. Key features include:
- Easy setup: It automates much of the complex process of setting up a Dash masternode.
- Management: Dashmate provides a user-friendly interface for monitoring and managing masternodes.
- Updates: It helps users keep their masternodes up-to-date with the latest software versions.
- Configuration: The tool allows for easy configuration of masternode settings.
- Multiple node support: Users can manage multiple masternodes from a single interface.
- Security: Dashmate implements best practices for securing masternodes.
By simplifying these technical aspects, Dashmate makes it more accessible for individuals to participate in the Dash network.
Prerequisites
- Node.js v20+
- Docker (latest)
- Dashmate installed
Install Dashmate
npm i -g dashmate@v1.0.0-dev.16
See all available dashmate
commands with dashmate --help
.
Setup and Start Dashmate Local Network
To avoid problems with variable network speeds and other challenges related to interacting with testnet, Dashmate makes it (mostly) easy to create a local development network. The network is only accessible to your computer since the nodes are exclusively running locally on your machine.
Setup Group of Local Nodes
Local networks can be set up with Dashmate via the dashmate setup local
command. This command sets up a full local Dash network environment on your machine for development purposes by creating a group of nodes that simulate a small network running the actual Dash network.
dashmate setup local
Other setup commands can configure nodes to connect to existing Dash networks including dashmate setup mainnet
or dashmate setup testnet
. The local
preset creates an isolated, self-contained network on your machine whereas mainnet
and testnet
presets connect to public Dash networks. With the local
setup, developers have more control over the network parameters and can easily reset or modify the environment.
The local
setup includes features that are not typically part of mainnet
or testnet
setups:
- Can create multiple nodes as part of a group while other setups typically configure a single node.
- Generates configs, mines some test Dash (tDash), registers masternodes, and populates nodes with data required for local development.
- Allows setting a miner interval between blocks using the
-m
or--miner-interval
flag.
All commands related to interacting or manipulating your group of nodes will start with dashmate group ...
. Every time you reset the network, the entire transaction history of the chain is also dropped.
Start Local Group and Check Network Status
Run the group of nodes with dashmate group start
.
dashmate group start
Check the status of your network with dashmate group status
.
dashmate group status
You can also check everything by hand by using docker ps
.
- Check to see if everything is in the
running
state. - If something is not running, check the logs via
docker logs
.
Always ensure the health of your local network before you start. Laptops will be more prone to chain halts and network crashes since many include automatic sleep timers that reduce computing resources for power conservation.
Stop or Restart Group
Various commands exist to provide different levels of “resetting” your node group. These range from simply stopping to completely wiping and starting over. Choosing the appropriate command will be based on how much you want to reset including whether you want to preserve configurations. Here’s a high level description of each method, followed by a more detailed explanation.
dashmate group:stop --force
only stops the nodes.dashmate group restart
restarts the nodes without changing data or configuration.dashmate group reset --force
resets the data but keeps configurations.dashmate group reset --hard --force
performs a complete reset, removing both data and configurations.
dashmate group:stop --force
forcefully stops all nodes in the current group. --force
ensures the stop operation is carried out even if services are still running or have any issues.
dashmate group:stop --force
Use Case: Quickly shut down all nodes in a group regardless of their current state.
dashmate group restart
restarts all nodes in the current group, essentially equivalent to stopping the group and then starting it again.
dashmate group restart
Use Case: Apply configuration changes or refresh the state of all nodes in the group.
Reset Group
dashmate group reset --force
resets all nodes in the current group, forcefully removing all data associated with them. The --force
flag ensures the reset happens even if services are running. All services are stopped, all data for each node in the group is removed, and configuration files are kept intact.
dashmate group reset --force
Use Case: Start fresh with your node data while keeping your existing configuration.
dashmate group reset --hard --force
is the most aggressive reset command. The --hard
flag in addition to --force
means it will stop all services forcefully by removing all data for each node in the group plus removing and resetting all configuration files.
dashmate group reset --hard --force
Use Case: You want a completely clean state for your group as if it had never been set up. To use the group, the setup process must be run again.
Setup JavaScript Project
Create a new Node.js project and set type
to module
for ESM imports and exports.
mkdir dashmate-examplecd dashmate-examplenpm init -ynpm pkg set type="module"npm i dash@4.0.0-dev.16
Set scripts
:
npm pkg set \ 'scripts.createWallet=node --no-warnings createWallet.js' \ 'scripts.registerIdentity=node --env-file=.env --no-warnings registerIdentity.js' \ 'scripts.createContract=node --env-file=.env --no-warnings createContract.js' \ 'scripts.submitDocument=node --env-file=.env --no-warnings submitDocument.js' \ 'scripts.getDocument=node --env-file=.env --no-warnings getDocument.js'
Create Wallet
Create a function for generating a new wallet and a function for getting the next unused address.
echo > createWallet.js
createWallet
creates a new wallet and console logs your new mnemonic and address.
import Dash from "dash"
const client = new Dash.Client({ network: "local", dapiAddress: [ "http://127.0.0.1:3001" ], wallet: { mnemonic: null, offlineMode: true },})
async function createWallet() { try { const account = await client.getWalletAccount() const mnemonic = client.wallet.exportWallet() const { address } = account.getUnusedAddress()
console.log("WALLET_ADDRESS=" + `"${address}"`) console.log("MNEMONIC=" + `"${mnemonic}"`) } catch (error) { console.error('Something went wrong:\n', error) } finally { client.disconnect() }}
createWallet()
npm run createWallet
Create Client File and Set Environment Variables
Add the following to .env
with the mnemonic and wallet address from the previous command.
NETWORK="local"DAPI_ADDRESS_URL="http://127.0.0.1:3001"WALLET_ADDRESS=""MNEMONIC=""
Create a client.js
file for initializing and exporting a reusable Dash client.
echo > client.js
Import Dash
and set the network
, dapiAddress
, and MNEMONIC
options.
import Dash from "dash"
const { NETWORK, DAPI_ADDRESS_URL, MNEMONIC } = process.env
export const client = new Dash.Client({ network: NETWORK, dapiAddress: [ DAPI_ADDRESS_URL ], wallet: { mnemonic: MNEMONIC, },})
This connects to the DAPI endpoint of the local Dash network and syncs up your wallet.
Mint Local tDash with Wallet Command
Lets mint some coins with our new wallet address. To do that, you must stop your network (dashmate group:stop --force
), issue the dashmate wallet mint
command with your address, and start your network again (dashmate group start
):
dashmate group:stop --forcedashmate wallet mint --config local_seed --address=yVyQx9D9pAsmtv1H3yd2Y8jFQpi1WkCpCF 50dashmate group start
Output:
✔ Generate 10 dash to address ✔ Start Core ✔ Create a new address › Address: yYFFb4MQmRoxx3DitnKHV6iYN1aVGqfJja Private key: cT9vMyFtCzAsnSnMq9WemG7S3mfiTDoY4LW8QJRmFqUKPr8uen2S ✔ Generate ≈10 dash to address yYFFb4MQmRoxx3DitnKHV6iYN1aVGqfJja › Generated 10.2652105 dash ✔ Wait for balance to confirm ✔ Stop Core
Register Identity
Registering an identity creates a unique account in the Dash Platform network. You must register an identity before you can use any Dash Platform features.
echo > registerIdentity.js
import { client } from "./client.js"
async function registerIdentity() { try { const identity = await client.platform.identities.register() console.log(`IDENTITY_ID="${identity.getId().toString()}"`) } catch (error) { console.error('Something went wrong:\n', error) } finally { client.disconnect() }}
registerIdentity()
npm run registerIdentity
Create Data Contract
A Data Contract is a data type definition for your application that is like a schema for a database application that lets you store and query data.
echo > createContract.js
The contractDefinitions
includes an object
type with one property, a message
set to type
string.
import { client } from "./client.js"
const { IDENTITY_ID } = process.env
const createContract = async () => { try { const identity = await client.platform.identities.get(IDENTITY_ID) const contractDefinitions = { note: { type: 'object', properties: { message: { type: "string", position: 0 } }, additionalProperties: false } } const contract = await client.platform.contracts.create(contractDefinitions, identity) await client.platform.contracts.publish(contract, identity) console.log("\nCONTRACT_ID=" + `"${contract.toJSON().id}"`) console.log('\nContract registered:\n\n', contract.toJSON()) } catch (e) { console.error('Something went wrong:\n', e) } finally { client.disconnect() }}
createContract()
npm run createContract
Once the schema has been created and we have our data contract, we can being storing our data in the chain. We can write and read data in the designed object format.
Submit and Query Documents
To insert documents in the data contract, we must define it in our Dash.Client
options:
import Dash from "dash"
const { NETWORK, DAPI_ADDRESS_URL, MNEMONIC, CONTRACT_ID } = process.env
export const client = new Dash.Client({ network: NETWORK, dapiAddress: [ DAPI_ADDRESS_URL ], wallet: { mnemonic: MNEMONIC, }, apps: { helloWorld: { contractId: CONTRACT_ID, }, },})
Create a submitDocument.js
file.
echo > submitDocument.js
To ensure your identity has the necessary credits to create the document, we’ll top up our identity before broadcasting our state change.
import { client } from "./client.js"
const { IDENTITY_ID } = process.env
const submitDocument = async () => { try { await client.platform.identities.topUp(IDENTITY_ID, 100000000) const identity = await client.platform.identities.get(IDENTITY_ID) const helloWorldDocument = await client.platform.documents.create( 'helloWorld.note', identity, { message: 'Hello from Dash local network'} ) await client.platform.documents.broadcast( { create: [helloWorldDocument], replace: [], delete: [], }, identity ) console.log(`DOCUMENT_ID="${helloWorldDocument.toJSON().$id}"`) console.log(helloWorldDocument.toJSON()) } catch (e) { console.error('Something went wrong:\n', e) } finally { client.disconnect() }}
submitDocument()
npm run submitDocument
Our data is now in Dash Platform’s global state and using GroveDB we can make queries and retrieve our data. Create a getDocument.js
file.
echo > getDocument.js
Use the helloWorld.note
query syntax to get all documents.
import { client } from "./client.js"
const getDocuments = async () => { try { const documents = await client.platform.documents.get( 'helloWorld.note', { limit: null } ) documents.forEach(n => console.log(n.toJSON().message)) } catch (e) { console.error('Something went wrong:\n', e) } finally { client.disconnect() }}
getDocuments()
npm run getDocument