Skip to content
A rewrite of Komodo's Delayed Proof of Work Mechanism for compatibility with The Blur Network (BLUR) and, by extension, all RingCT-capable coins. An attempt at the first-ever cross-chain security mechanism, between XMR, ZEC, and BTC worlds.
C++ C CMake Objective-C Makefile Shell Other
Branch: dpow
Clone or download
Fetching latest commit…
Cannot retrieve the latest commit at this time.
Type Name Latest commit message Commit time
Failed to load latest commit information.

This repository is under contruction

There are files in here from many different projects, including but not limited to BLUR, BTC, KMD, and XMR. Please retain proper licensing if you reuse any files, and be aware that this repo is under heavy development... So files will not yet be in their proper homes.


Automatically performed operations:

Manually performed operations

Compile from Source and Chain-Build with Dependencies

Libhydrogen requires CMake 3.14+ to compile. If your distribution does not include this in the package manager, you can download the latest release's source from here: CMake 3.15.2 from Kitware's github

Once Downloaded, run ./configure or ./bootstrap, then make && sudo make install

Minimal Dependencies: sudo apt-get install autotools-dev curl cmake build-essential

The following will chain-build dependencies and then all binaries in source: make release-cross-linux-x86_64


Libhydrogen requires CMake 3.14+ to compile. If your distribution does not include this in the package manager, you can download the latest release's source from here: CMake 3.15.2 from Kitware's github

Both libbtc and the native blur files require GCC 8.3 or below to compile. GCC 9+ will error out.

Once that is extracted from the archive, building and installing is as simple as ./configure && make && sudo make install

Ubuntu/Debian One-Liner:

sudo apt install build-essential cmake pkg-config libssl-dev libunwind-dev libevent-dev libsodium-dev binutils-dev libboost-all-dev autoconf

Arch Linux One-Liner:

sudo pacman -S base-devel cmake boost openssl libsodium libunwind binutils-devel libevent autoconf

Fedora One-Liner:

sudo dnf install cmake boost-devel openssl-devel sodium-devel libunwind-devel binutils-devel libevent-devel autoconf

After installing the dependencies, clone this repo with:

git clone

Cd into the proper directory, and then compile with:

cd dpow-blur && make release-static

Creating a Notarization Wallet for Notarization Tx's on BLUR

To create a wallet on BLUR's network, for notary nodes already owning a secp256k1 private key:

Step 1: Compile binaries from source, then create a json-formatted wallet configuration file as follows: (named btc.json in our example)

        "version": 1,
        "filename": "test_wallet",
        "scan_from_height": 0,

Substitute the hexidecimal representation of your node's public key into the field titled btc_pubkey.

Step 2: Launch blurd with the following options:

./blurd --testnet

Step 3: Launch blur-notary-server-rpc with the following options:

Note: Change the name of the json file if you named yours something other than btc.json

./blur-notary-server-rpc --generate-from-btc-pubkey btc.json --rpc-bind-port 12121 --testnet

You should see the following:

Your wallet should now be running. Skip the Starting the Notary Server Wallet heading if you don't plan to shut down your notary node between this point and testing.

Starting the Notary Server Wallet

Step 1: Start blurd with the following options:

./blurd --testnet

After your wallet is generated, you can reopen this existing file with the following startup flags:

./blur-notary-server-rpc --wallet-file test_wallet --rpc-bind-port 12121 --prompt-for-password --testnet --disable-rpc-login

The RPC interface will prompt you for the wallet password. Enter the password you entered into btc.json on creation.

Creating a Notarization Transaction

Please note: Everything after step 3 will be performed automatically (without any action on your part) after launching the notary server.

What is shown below, excluding steps 1-3, is for informational purposes. You should never need to call create_ntz_transfer or append_ntz_sig methods manually.

Step 1: Before creating a transaction, you must paste the public spendkey that was generated when creating your wallet, into the 4th column in the Notaries_elected1 table, located in src/komodo/komodo_notaries.h. If your public spendkey is not located in this table, the wallet will not permit you to create a notarization tx.

Step 2: Compile source again, and start up the daemon with ./blurd --testnet.

Step 3: After the daemon is running, launch the notary wallet with blur-notary-server-rpc --wallet-file=test_wallet.keys --rpc-bind-port 12121 --prompt-for-password --disable-rpc-login --testnet

Step 4: Issue the following curl command in a separate terminal:

curl -X POST -d '{"method":"create_ntz_transfer"}'


The command above will create a new notarization tx with one signature.

The first two times this command is called, the generated transactions will be added to a cache (ntz_ptx_cache).

Once there are two pending_txs in the cache, the third call will be relayed as a request for more signatures using NOTIFY_REQUEST_NTZ_SIG

Destinations for the transaction are automatically populated, using the BTC & CryptoNote pubkeys provided in komodo_notaries.h. Each notary wallet is sent 0.00000001 BLUR.

TL;DR: The above is performed automatically, upon launching a wallet with pubkeys matching one of the 64 hardcoded keypairs. The method create_ntz_sig is called twice before the wallet will check the notarization pool for pending ntz's. These two calls cache the tx blob and data, and the cache serves to speed up the addition of new signatures to pending ntz's, when found in the ntzpool. Each call takes about 15 seconds to complete.

Appending signatures to a pending notarization

Note: This should be performed automatically, if the cache is full (contains two transactions), and a notarization sequence has already begun (Pending notarization is in pool already)

If you wish to call it manually, use the syntax below:

curl -X POST -d '{"method":"append_ntz_sig"}'

This command will check the notarization pool for pending tx's, and fetch the one with the highest value in the sig_count field. This field's value should match the quantity of non-negative elements in the signers_index field.

The called function will return false for any keypair that is not hardcoded in src/komodo/komodo_notaries.h

This function will automatically pull in all necessary tx data, as well as cleaning all transactions from the ntzpool, except two pending txs.

These two transactions are:

1.) The transaction which has just been signed
2.) The transaction itself, prior to signing.

#2 is left in pool in the event that after leaving the wallet side, the transaction becomes invalid. This transaction will be cleaned after the next notary node appends its signatures.

Once your signatures have been addded, you will see the following message displayed from the RPC interface:

   [RPC0]    WARN     wallet.wallet2    src/wallet/wallet2.cpp:5046    transaction <45f1e4c9c48da583e294d0fb5f225ee4c5999b7f3f067b2bb753100e31ced9b0> generated ok and sent to request ntz sigs, key_images: [<3d1bd440676b6a32cf1b6b7b21fb6b25ca13038a18f4456c7165cff91a66c5aa> ]

    [RPC0]    WARN     wallet.wallet2    src/wallet/wallet2.cpp:5052    Signatures added. 4 more needed. Relaying NOTIFY_REQUEST_NTZ_SIG <<45f1e4c9c48da583e294d0fb5f225ee4c5999b7f3f067b2bb753100e31ced9b0>>

Signatures count: 9, Commission: 0.058350240000
Balance: 400.000000000000
Unlocked: 400.000000000000
Please, wait for further signatures

    [RPC0]    WARN     notary_server.rpc    src/komodo_notary_server/notary_server.cpp:1534    Signatures < 13: [request_ntz_sig] sent with sig_count: 9, signers_index =  12 35 5 61 55 47 21 20 26 -1 -1 -1 -1

Relaying a request for Notarization Signatures from other Notary Nodes:

This will also be performed automatically, upon a successful and non-cacheing call to either of the above RPC methods

To relay the created tx_blob from the previous command ntz_transfer issued to the wallet, perform the following:

Using the tx_blob from terminal output, issue the following curl command to the daemon's port 21111 (not the wallet):

curl -X POST http://localhost:21111/json_rpc -d '{"method":"request_ntz_sig","params":{"tx_blob":"long hex here","sig_count":1,"signers_index:[51,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1],"payment_id":"0c9a0f1fc513e0aa5d70cccb0b00e9ff924ce9c4b0e2ec373060fbde1c5cc4e0"}}'

This protocol command will not relay an actual transaction unless sig_count is greater than 12.

Viewing Pending Notarizations

To view pending notarization txs, which have requested further notarization signatures:

Issue the following command to the running daemon interface: print_pool

If a notarization is currently idling in the mempool, awaiting further signatures, they will show up under the heading Pending Notarization Transactions:


User input:


Output of a pending ntz tx with 9 signatures:

Pending Notarization Transactions: 
id: e5f38b36e7efd4275e32ad90d578dd36acbeae86301b7033df963f6416937419
ptx_hash: 8c152cb5b997b6f2f299f3d625808feaa6d2aefa0a9478b8842858aa3e53eb37
sig_count: 9
signers_index:  16 36 60 10 21 63 47 51 00 -1 -1 -1 -1 
blob_size: 53602
fee: 0.059570940000
fee/byte: 0.000001111356
receive_time: 1572956332 (33 minutes ago)
relayed: no
do_not_relay: F
kept_by_block: F
double_spend_seen: F
max_used_block_height: 2546
max_used_block_id: b56701d1d774e070aebd8366489cc63ec75e8c4bac4e37475f090f253a01e304
last_failed_height: 0
last_failed_id: 0000000000000000000000000000000000000000000000000000000000000000

Notes on fields not present in a standard BLUR tx:

ptx_hash is the hash of a corresponding ptx_blob binary archive. This archive contains all transaction data from the previous signer, for the next signer to add to their vectorized txs.

sig_count is a count of signatures currently added to the transaction.

signers_index is an array with 13 values, each of which corresponds to a Notary Node, and their row number in the hardcoded pubkeys.

If a value in the signers_index field is not a default -1, the number should correspond to a notary node that has already signed and appended their transactions to the pending request. Indices are added in time-sequential order.

Regarding Validation: Because these notarization transactions use a completely separate validation structure (located in src/cryptonote_basic/verification_context.h), they will not validate as normal transactions until sig_count reaches a point of being greater than 12.

At that point, the ntz_tx_verification_context will be converted to the standard tx_verification_context, and relayed to the network as a normal transcation. Prior to this point, the separate context will prevent a pending notarization from being handled as a normal transaction, or validated as such by other nodes.

RPC Calls for KMD-BLUR Data

To retrieve the current blockchain data, and notarization data (not yet populated):

curl -X POST http://localhost:52542/json_rpc -d '{"method":"get_notarization_data"}'


  "id": 0,
  "jsonrpc": "2.0",
  "result": {
    "assetchains_symbol": "BLUR",
    "current_chain_hash": "0d6b7b0de6106877972fdafb806932cdd4c30dd007fc9510dfdec4db8b5ca69c",
    "current_chain_height": 155736,
    "current_chain_pow": "73ab840dcb63e247df9d98988a195b2ba17def30daa835073a8377be65010000",
    "notarized_hash": "0000000000000000000000000000000000000000000000000000000000000000",
    "notarized_height": 0,
    "notarized_txid": "0000000000000000000000000000000000000000000000000000000000000000"

To retrieve the merkle root of a given block, by block hash or by vector of transaction hashes (b.miner_tx + b.tx_hashes):

By block hash:

$ curl -X POST http://localhost:52542/json_rpc -d '{"method":"get_merkle_root","params":{"block_hash":"fcef71dbd8138c1bb738df9848307bd766af11e763c9125014a023db706877d"}}'
  "id": 0,
  "jsonrpc": "2.0",
  "result": {
    "status": "OK",
    "tree_hash": "8f85f91445345bfdc47633fb8f81002781994ace103706568f97249e5f5efee1"

By transaction hashes:

$ curl -X POST http://localhost:52542/json_rpc -d '{"method":"get_merkle_root","params":{"tx_hashes":["6ca1743cb1db1f4f34b132919b7941f766146b4dbf36fd6db88ff9563b7710b","abdbab0a70288fc8106de68715db988e901cf51f77696011c6479822a9236b8b"]}}'
  "id": 0,
  "jsonrpc": "2.0",
  "result": {
    "status": "OK",
    "tree_hash": "8f85f91445345bfdc47633fb8f81002781994ace103706568f97249e5f5efee1"
You can’t perform that action at this time.