The Decred structure

16 minute read

Updated:

1. Introduction

To understand how Decred works and make the most of it, you need to understand the types of networks, components, connections and addresses.

2. Components

Figure 1 - An overview of Decred components
Figure 1 - An overview of Decred components

2.1. dcrd

The functionalities of Decred are divided into two main components: the first component is dcrd, the blockchain server, the full node. This component solves blockchain issues, executes consensus rules and establishes peer-to-peer communication to synchronize the blockchain. Dcrd is the backbone of Decred network.

2.2. dcrwallet

The second component is the wallet, which manages the coins (unspent transactions), private keys, deterministic generation of keys, etc. Unlike Bitcoin Core, where all functionality was built on a monolithic component, Decred spread its funcionalities through separate components.

To know your balance dcrwallet queries dcrd about information on the blockchain. This is one of the reasons dcrwallet talks to dcrd via RPC.

Figure 2 - Most basic components of Decred
Figure 2 - Most basic components of Decred

2.3. dcrctl

dcrctl is the client app that connects to the blockchain server (dcrd) and to the wallet server (dcrwallet) to perform queries and sign transactions.

2.4. Decrediton

Decrediton is the graphical app for the wallet, available in multiple platforms. With Decrediton there is no need to worry about dcrd, dcrwallet and dcrctl, because it is a 3-in-1 app.

2.5. Simple Payment Verification (SPV)

SPV is a mode of operation that does not depend on the local execution of a dcrd (full node) to perform its functions. SPV uses DNS Seeds to locate full nodes and connect to the peer-to-peer network.

2.6. Other components

Other components of the network will be addressed in other articles. Here is a brief description of each one.

atomicswap

An atomic swap is an exchange between two users of different cryptocurrencies, who want to trade Decred and Bitcoin, for example, without using an escrow. Because blockchains are unrelated and transactions can’t be reversed, there is no protection against one party failing to honor the deal (the one that will send the resources at the end).

An atomic swap solves this problem without the need for an intermediary, connecting the parties through a contractual transaction in each blockchain.

dcrdata

The block explorer of Decred network. It can be installed locally for privacy reasons and for improved reliability or it can be accessed directly at https://www.dcrdata.org.

dcrlnd

The Lightning Network Daemon (lnd) is a complete implementation of a Lightning Network node currently deployed in testnet3, a Bitcoin test network. Lightning Network enables instant payments, greater scalability and extremely low-cost transactions.

dcrpayments

The set of libraries and utilities for integration with a Decred payment gateway. There is also the library for integration of Magento e-commerce with Decred wallets.

dcrstakepool

The web application that coordinates the generation of 1-to-2 multisig addresses used in a pool of dcrwallet servers so that users can buy PoS (proof-of-stake) mining tickets in the Decred network and use the server pool to vote on their behalf when the ticket is drawn.

dcrtime

Client and server implementation of a timestamping service publicly verifiable in the blockchain.

dcrseeder

dcrseeder service is the Decred network aggregator, which exposes a list of trusted nodes using an internal DNS server. Read more about it in section 6.

Politeia

Politeia is the Decred proposal system for storing off-chain data with versioning and anchored to the Decred blockchain by dcrtime timestamps. Essentially, “git, a popular revision control system with timestamping”.

3. Networks and addresses

There are three networks used by Decred. Mainnet is the production network. This is the main network, the blockchain that contains the valuable resources, the network with the largest hash power.

Testnet is the development environment, a public environment where new code is tested without real losses. It is also the network for demonstrations and to learn how components work.

Simnet is a simulation network. It’s like a private Testnet used by developers and for advanced testing. To create your own Simnet, read https://docs.decred.org/advanced/simnet/.

Figure 3 - Decred networks
Figure 3 - Decred networks

A Decred address is a representation of a public key with a 2-byte prefix that identifies the network and the key type, plus a suffix that contains a checksum to detect erroneous addresses.

So it is always possible to know the type of address based on this 2-byte prefix.

The first byte identifies the network. All Mainnet addresses begin with “D”, the addresses of Testnet start with “T”, and those of Simnet with “S”.

The second byte identifies the type of address. The most commonly used addresses are the secp256k1 pubkey hashes, identified by the lowercase “s”. This type represents a single public key and therefore has a single associated private key that can be used to retrieve the resources.

The ticket pool uses a pay-to-script-hash address, which is identified by the second byte, a lowercase “c”. This type of script generates a multi-signature 1-of-2. Both the user and the ticket pool have their own private key. Since the script only requires one signature out of two (1-of-2), both the user and the pool can vote, and this is how the delegation of voting rights to the pool works without the user having to give up voting rights.

Next you see some keys used in each Decred environment. Other types of keys will be addressed in other articles.

Mainnet

PubKeyHashAddrID: [2]byte{0x07, 0x3f}, // starts with Ds
ScriptHashAddrID: [2]byte{0x07, 0x1a}, // starts with Dc

Simnet

PubKeyHashAddrID: [2]byte{0x0e, 0x91}, // starts with Ss
ScriptHashAddrID: [2]byte{0x0e, 0x6c}, // starts with Sc

Testnet

PubKeyHashAddrID: [2]byte{0x0f, 0x21}, // starts with Ts
ScriptHashAddrID: [2]byte{0x0e, 0xfc}, // starts with Tc

4. File and directory structure

4.1. dcrd, dcrwallet and dcrctl

Configuration files are located within the default directory of each application. Below, the default location for the directories on each operating system:

Windows

C:\Users\$USERNAME\AppData\Local\Dcrwallet\
C:\Users\$USERNAME\AppData\Local\Dcrd\
C:\Users\$USERNAME\AppData\Local\Dcrctl\

macOS

~/Library/Application Support/Dcrwallet/
~/Library/Application Support/Dcrd/
~/Library/Application Support/Dcrctl/

Linux

~/.dcrwallet/
~/.dcrd/
~/.dcrctl/

Within these folders are located the configuration files: dcrd.conf, dcrwallet.conf and dcrctl.conf.

If you can’t locate the configuration files, make a copy from the sample files: sample-dcrd.conf, sample-dcrwallet.conf and sample-dcrctl.conf. These files come with the dcrinstall installation package.

4.2. Decrediton

Decrediton stores the wallet, the log files and its configuration in a single directory. Decrediton configuration resides in a file named config.json on all operating systems.

Windows: C:\Users\$USERNAME\AppData\Local\Decrediton
macOS: ~/Library/Application Support/Decrediton
Linux: ~/.config/decrediton

Decrediton uses the default dcrd folder on each operating system to store the blockchain. The wallet.db file is stored in a folder with the network name (wallets/mainnet/$WALLET_NAME/mainnet, wallets/testnet/$WALLET_NAME/testnet2) within its own structure (unrelated to dcrwallet directory).

4.3. Blockchain data (dcrd and Decrediton)

You can change the directory for blockchain storage to improve performance or disk space usage. For dcrd the configuration is done changing the datadir parameter in dcrd.conf file. For Decrediton, the appdata_path parameter in config.json.

4.4. Wallet (dcrwallet and Decrediton)

The wallet is stored in the wallet.db file. Even if a device has dcrwallet and Decrediton installed, their wallets will be different files. You can copy the file between directories, for alternate use of the applications with the same wallet. You can also configure dcrwallet to use Decrediton wallet.db.

4.5. Configuration through command-line

Parameters may be altered for a single execution, without having to change the configuration file. You can even set up a completely different disk to store the testnet blockchain.

$ ./dcrd --datadir=/opt/blockchain
$ ./dcrd --testnet --datadir=/test/blockchain

To run any app on Testnet, simply include the --testnet option.

dcrd and dcrwallet also support command-line parameters for setting the default directory and directory to store log files. Log files may be stored on a separate disk to avoid compromising service performance.

--appdata=[dir], --logdir=[dir]

In both Linux and macOS it is possible to run Decrediton in Testnet mode via command-line. Use --help to see the other parameters.

$ ./decrediton --testnet
$ /Applications/decrediton.app/Contents/MacOS/decrediton --testnet

5. Network communication

Decrediton, dcrd, dcrwallet and dcrctl communicate over TCP ports. If all components are on the same device the communication should occur without problems. If any of these components are installed on a different device and some of these devices have a firewall configured, it may be necessary to open ports for communication between components.

Skip all section 5 if:

  • All components (dcrd, dcrwallet, dcrctl) are on the same device and there are no firewall rules;
  • All components (dcrd, dcrwallet, dcrctl) are on the same device, the firewall is used and there are firewall rules allowing localhost communication;
  • Not all components are on the same device but there is no firewall installed on the devices;
  • Not all components are on the same device but all devices are on the local network, there is a firewall installed but there is no rule blocking incoming traffic from devices on the local network

By default the operating system (firewall) usually allows outgoing network communication. If the firewall is configured to reject outgoing packets that are not explicitly allowed, see the ports that need to be allowed in the following sections.

5.1. localhost and Decrediton

If all components (dcrd, dcrwallet, dcrctl) are running on the same device the communication should flow as expected. However, it is possible that with very strict firewall rules even localhost communication (on the same device) may be blocked. If the communication does not flow as expected, verify that firewall rules allowing the communication are in place:

$ sudo iptables -A INPUT -i lo -j ACCEPT
$ sudo iptables -A INPUT ! -i lo -s 127.0.0.0/8 -j DROP
$ sudo iptables -A OUTPUT -o lo -j ACCEPT

If Decrediton has not been configured to use an external dcrd or dcrwallet, then all components are on the same device and the above description is applicable.

5.2. dcrd

To allow your dcrd server (including the one that comes with Decrediton) to talk to other dcrd servers in the outside world with only one rule in iptables:

$ sudo iptables -A OUTPUT -m multiport -p tcp --dports 9108,19108 -m comment --comment "dcrd to dcrd mainnet,testnet" -j ACCEPT

To allow incoming traffic from other dcrd servers in the world:

$ sudo iptables -A INPUT -m multiport -p tcp --dports 9108,19108 -m comment --comment "dcrd from dcrd mainnet,testnet" -j ACCEPT

To allow incoming traffic from a dcrwallet installed on another device:

$ sudo iptables -A INPUT -m multiport -p tcp --dports 9109,19109 -s $LOCALNET -m comment --comment "dcrd from dcrwallet mainnet,testnet" -j ACCEPT

5.3. dcrwallet

If dcrwallet will connect to a dcrd installed on another device it may be necessary to configure rules for outgoing connections:

$ sudo iptables -A OUTPUT -m multiport -p tcp --dports 9109,19109 -d $LOCALNET -m comment --comment "dcrwallet to dcrd mainnet,testnet" -j ACCEPT

If dcrwallet will be controlled by a dcrctl installed on another device:

$ sudo iptables -A INPUT -m multiport -p tcp --dports 9110,19110 -s $LOCALNET -m comment --comment "dcrwallet from dcrctl mainnet,testnet" -j ACCEPT

5.4. dcrctl

If dcrctl will be used to manage a dcrd installed on another device it may be necessary to configure rules for outgoing connections:

$ sudo iptables -A OUTPUT -m multiport -p tcp --dports 9109,19109 -d $LOCALNET -m comment --comment "dcrctl to dcrd mainnet,testnet" -j ACCEPT

If dcrctl will be used to manage a dcrwallet installed on another device it may be necessary to configure rules for outgoing connections:

$ sudo iptables -A OUTPUT -m multiport -p tcp --dports 9110,19110 -d $LOCALNET -m comment --comment "dcrctl to dcrwallet mainnet,testnet" -j ACCEPT

5.5. Other services

It will be necessary to allow other outgoing connections for minimal usage of the device and Decred functionality. This usage includes:

  • Download new versions of Decrediton and other binaries;
  • Verify digital signatures;
  • Query DNS servers searching for other nodes of the Decred network;
  • Lease an IP address from the DHCP Server;
  • Update the operating system
  • Update system time
$ sudo iptables -A OUTPUT -p udp --dport 53 -m comment --comment "DNS Queries" -j ACCEPT
$ sudo iptables -A OUTPUT -p tcp --dport 53 -m comment --comment "DNS Extended Queries" -j ACCEPT
$ sudo iptables -A OUTPUT -p tcp --dport 11371 -d pgp.mit.edu -m comment --comment "GPG HKP" -j ACCEPT
$ sudo iptables -A OUTPUT -p udp --dport 67 -d $LOCALNET -m comment --comment "dhcp" -j ACCEPT
$ sudo iptables -A OUTPUT -p udp --dport 123 -m comment --comment "ntp" -j ACCEPT
$ sudo iptables -A OUTPUT -m multiport -p tcp --dports 80,443 -d ftp.debian.org -j ACCEPT
$ sudo iptables -A OUTPUT -m multiport -p tcp --dports 80,443 -d github.com -j ACCEPT

To send ICMP Echo Request packets to any destination and send ICMP Echo Reply only to the local network (PINGs):

$ sudo iptables -A INPUT -p icmp --icmp-type echo-request -s $LOCALNET -m comment --comment "icmp ping reply" -j ACCEPT
$ sudo iptables -A OUTPUT -p icmp --icmp-type any -d $LOCALNET -m comment --comment "icmp out" -j ACCEPT

5.6. General rules

To configure a policy for a chain in iptables use option -P. To maintain a whitelist setting (everything is forbidden except what is specifically allowed), the chains are configured to refuse (DROP) any packet that does not fit into one of the rules.

It is not common to block outgoing connections (OUTPUT DROP). Usually a policy ‘OUTPUT ACCEPT’ is used.

$ sudo iptables -P INPUT DROP
$ sudo iptables -P FORWARD DROP
$ sudo iptables -P OUTPUT DROP

To control incoming packets, the following rules are generally used: the first one blocks invalid packets (without flags, with undocumented characteristics, etc.), and the second allows connection-related packets that already matched some rule of the chain.

$ sudo iptables -A INPUT -m state --state INVALID -j DROP
$ sudo iptables -A INPUT -m state --state ESTABLISHED -j ACCEPT

All packets that initiate a connection and do not have the SYN flag should be dropped.

$ sudo iptables -A INPUT -m state --state NEW ! --syn -j DROP

In the end all packets that did not match any rule will be logged before being dropped in case an analysis is necessary.

$ sudo iptables -A INPUT -m limit --limit 3/min -j LOG --log-prefix "iptables_INPUT_denied: " --log-level 4
$ sudo iptables -A OUTPUT -m limit --limit 3/min -j LOG --log-prefix "iptables_OUTPUT_denied: " --log-level 4

5.7. NAT

It is likely that, depending on your network structure, you still need to create a NAT rule on the router. NAT (or PAT) is a translation of IP addresses and ports into the router so that servers in a private network are accessible from a public network.

5.8. Putting it all together

Next you see a list of the rules suggested so far. The order of the rules is related to the expectation of use of each one of them. Since the rules are processed sequentially from top to bottom, the rules that are expected to be most used are placed at the top of the chain (INPUT, OUTPUT). The list is not exhaustive.

$ sudo iptables -A INPUT -i lo -j ACCEPT
$ sudo iptables -A INPUT ! -i lo -s 127.0.0.0/8 -j DROP
$ sudo iptables -A INPUT -m state --state INVALID -j DROP
$ sudo iptables -A INPUT -m state --state ESTABLISHED -j ACCEPT
$ sudo iptables -A INPUT -p tcp -m state --state NEW ! --syn -j DROP
$ sudo iptables -A INPUT -m multiport -p tcp --dports 9108,19108 -m comment --comment "dcrd from dcrd mainnet,testnet" -j ACCEPT
$ sudo iptables -A INPUT -m multiport -p tcp --dports 9109,19109 -s $LOCALNET -m comment --comment "dcrd from dcrwallet mainnet,testnet" -j ACCEPT
$ sudo iptables -A INPUT -m multiport -p tcp --dports 9110,19110 -s $LOCALNET -m comment --comment "dcrwallet from dcrctl mainnet,testnet" -j ACCEPT
$ sudo iptables -A INPUT -p icmp --icmp-type echo-request -s $LOCALNET -m comment --comment "icmp ping reply" -j ACCEPT
$ sudo iptables -A INPUT -m limit --limit 3/min -j LOG --log-prefix "iptables_INPUT_denied: " --log-level 4
$ sudo iptables -P INPUT DROP
$ sudo iptables -P FORWARD DROP
$ sudo iptables -A OUTPUT -o lo -j ACCEPT
$ sudo iptables -A OUTPUT -m state --state RELATED,ESTABLISHED -j ACCEPT
$ sudo iptables -A OUTPUT -m multiport -p tcp --dports 9108,19108 -m comment --comment "dcrd to dcrd mainnet,testnet" -j ACCEPT
$ sudo iptables -A OUTPUT -m multiport -p tcp --dports 9109,19109 -d $LOCALNET -m comment --comment "dcrwallet/ctl to dcrd/wallet mainnet,testnet" -j ACCEPT
$ sudo iptables -A OUTPUT -m multiport -p tcp --dports 9110,19110 -d $LOCALNET -m comment --comment "dcrctl to dcrwallet mainnet,testnet" -j ACCEPT
$ sudo iptables -A OUTPUT -p udp --dport 53 -m comment --comment "DNS Queries" -j ACCEPT
$ sudo iptables -A OUTPUT -p tcp --dport 53 -m comment --comment "DNS Extended Queries" -j ACCEPT
$ sudo iptables -A OUTPUT -p tcp --dport 11371 -d pgp.mit.edu -m comment --comment "GPG HKP" -j ACCEPT
$ sudo iptables -A OUTPUT -p udp --dport 67 -d $LOCALNET -m comment --comment "dhcp" -j ACCEPT
$ sudo iptables -A OUTPUT -p udp --dport 123 -m comment --comment "ntp" -j ACCEPT
$ sudo iptables -A OUTPUT -p icmp --icmp-type any -d $LOCALNET -m comment --comment "icmp out" -j ACCEPT
$ sudo iptables -A OUTPUT -m multiport -p tcp --dports 80,443 -d ftp.debian.org -j ACCEPT
$ sudo iptables -A OUTPUT -m multiport -p tcp --dports 80,443 -d github.com -j ACCEPT
$ sudo iptables -A OUTPUT -m limit --limit 3/min -j LOG --log-prefix "iptables_OUTPUT_denied: " --log-level 4
$ sudo iptables -P OUTPUT DROP

After including the rules in the kernel, do not forget to save the configuration:

$ sudo iptables-save > /etc/iptables/rules.v4

If there is no iptables-save executable:

$ sudo apt-get install iptables-persistent

6. DNS Seeds

Dcrd stores information about other nodes in the peers.json file, located in dcrd’s default directory, inside the network directory ( mainnet, testnet2). When searching for other nodes in the network dcrd reads this file and tries to connect to known nodes. After a while without running dcrd, it is possible that all those nodes have been turned off or their IP addresses have already changed.

Figura 4 - dcrd uses DNS Seeds to locate other nodes
Figura 4 - dcrd uses DNS Seeds to locate other nodes

To solve this issue dcrd connects to the network’s DNS servers and searches for valid nodes. This service frequently validates known nodes and make this information available to other nodes and so on.

Simnet is a private simulation network used for testing. The discovery of network nodes does not work like on Mainnet or Testnet, otherwise this network would just be another public Testnet. That’s why Simnet’s DNSSeed has no address for node location, as shown next.

The following information about DNS seeds are located in the source code of https://github.com/decred/dcrd/blob/master/chaincfg/params.go#L476.

  DNSSeeds: []DNSSeed{
    {"mainnet-seed.decred.mindcry.org", true},
    {"mainnet-seed.decred.netpurgatory.com", true},
    {"mainnet-seed.decred.org", true},
  },
(...)
  DNSSeeds: []DNSSeed{
    {"testnet-seed.decred.mindcry.org", true},
    {"testnet-seed.decred.netpurgatory.com", true},
    {"testnet-seed.decred.org", true},
  },
(...)
  DNSSeeds:    []DNSSeed{}, // NOTE: There must NOT be any seeds.

Dcrd receives the information about other nodes and records the IP address of each new node and the IP of the node that sent this information in the peers.json file in the following format:

"Addresses":[
{
  "Addr":"45.55.161.169:9108",
  "Src":"45.77.55.251:9108",
  "Attempts":0,
  "TimeStamp":1519833581,
  "LastAttempt":-62135596800,
  "LastSuccess":-62135596800
},
{
  "Addr":"192.71.144.233:9108",
  "Src":"192.155.93.22:9108",
  "Attempts":0,
  "TimeStamp":1519833581,
  "LastAttempt":-62135596800,
  "LastSuccess":-62135596800
},
]

For more information, read https://github.com/decred/dcrseeder.

7. A common scenario

In Decred network we find various scenarios:

  • Decrediton running on Mac, Linux or Windows;
  • Decrediton connected to a dcrd in the local network;
  • dcrd, dcrwallet and dcrctl running on the same device;
  • dcrd on one device; dcrwallet and dcrctl on another;
  • A node with dcrd, a Raspberry Pi with dcrwallet and Decrediton as the front end

Decred’s modularity allows for numerous configurations, adapting to the user profile, network and security needs.

Figure 5 - A common scenario
Figure 5 - A common scenario

Information about the addresses and much more can be learned while reading the code at https://github.com/decred/dcrd/blob/master/chaincfg/params.go#L326