Cold node key management
Deprecation notice
Consortium networks have been deprecated. This guide is for historical reference.
By default, you can view your MultiChain wallet addresses and keys specific to the node that you deployed, provided that you are logged in as the same user with Chainstack. See View node access details.
You can use the default wallet addresses and key pairs for development and testing purposes.
If you are moving your MultiChain network to production, you are strongly recommended to use secure key management.
Cold node key management assumes that you do not store the keys in a hot MultiChain wallet. Instead, you have the keys stowed away in a MultiChain wallet on a cold node.
This section will guide you through setting up a MultiChain cold node, creating a key pair, issuing an asset, and signing the transaction on the cold node without exposing the private key to the MultiChain network.
For an overview of what a MultiChain cold node is, see Cold nodes and wallets.
Install MultiChain
On a server that meets your security requirements, install MultiChain. See Download and Install MultiChain.
Set up a MultiChain cold node on the server
-
Create a
~/.multichain-cold
directory on the server. -
In the
~/.multichain-cold
directory, create a subdirectory with the chain name. See Default chain name.Example:
~/.multichain-cold/nw-123-456-7
. -
In the directory, create an empty
params.dat
file.Example:
~/.multichain-cold/nw-123-456-7/params.dat
. -
Send a
getblockchainparams
request to a MultiChain node running with Chainstack.curl RPC_ENDPOINT -u "RPC_USER:RPC_PASSWORD" -d '{"method":"getblockchainparams","params":[],"id":1}'
where
- RPC_ENDPOINT — your cloud MultiChain node RPC endpoint
- RPC_USER — your cloud MultiChain node RPC username
- RPC_PASSWORD — your cloud MultiChain node RPC password
See also View node access details.
Example:
curl https://nd-123-456-789.p2pify.com -u "user-name:pass-word-pass-word-pass-word" -d '{"method":"getblockchainparams","params":[],"id":1}'
This will output the full blockchain parameters.
Example output:
{"result":{"chain-protocol":"multichain","chain-description":"My Network","root-stream-name":"root","root-stream-open":true,"chain-is-testnet":false,"target-block-time":15,"maximum-block-size":8388608,"maximum-chunk-size":1048576,"maximum-chunk-count":1024,"default-network-port":7447,"default-rpc-port":8000,"anyone-can-connect":false,"anyone-can-send":false,"anyone-can-receive":false,"anyone-can-receive-empty":true,"anyone-can-create":false,"anyone-can-issue":false,"anyone-can-mine":false,"anyone-can-activate":false,"anyone-can-admin":false,"support-miner-precheck":true,"allow-arbitrary-outputs":false,"allow-p2sh-outputs":true,"allow-multisig-outputs":true,"setup-first-blocks":60,"mining-diversity":0.3,"admin-consensus-upgrade":0.5,"admin-consensus-txfilter":0.5,"admin-consensus-admin":0.5,"admin-consensus-activate":0.5,"admin-consensus-mine":0.5,"admin-consensus-create":0,"admin-consensus-issue":0,"lock-admin-mine-rounds":10,"mining-requires-peers":true,"mine-empty-rounds":10,"mining-turnover":0.5,"first-block-reward":-1,"initial-block-reward":0,"reward-halving-interval":52560000,"reward-spendable-delay":1,"minimum-per-output":0,"maximum-per-output":100000000000000,"minimum-offchain-fee":0,"minimum-relay-fee":0,"native-currency-multiple":100000000,"skip-pow-check":false,"pow-minimum-bits":8,"target-adjust-freq":-1,"allow-min-difficulty-blocks":false,"only-accept-std-txs":true,"max-std-tx-size":4194304,"max-std-op-returns-count":32,"max-std-op-return-size":2097152,"max-std-op-drops-count":5,"max-std-element-size":40000,"chain-name":"nw-614-517-1","protocol-version":20004,"network-message-start":"f8d8cdf4","address-pubkeyhash-version":"007ee2f6","address-scripthash-version":"05d9757c","private-key-version":"80c92c0c","address-checksum-value":"08f94387","genesis-pubkey":"039b7ee52bffe13196037d5f4b1c8fd4f4fefbc1e9766d821bd40b6bc36fc74b2c","genesis-version":1,"genesis-timestamp":1564720379,"genesis-nbits":536936447,"genesis-nonce":936,"genesis-pubkey-hash":"06a9dbecfd60a7018c2c3916cdb9d99158906730","genesis-hash":"00d52e3c198c586eeca891bf44634fa244f3b3b59f456990c1ccbb2981d5c856","chain-params-hash":"0fed5218dd7fd4952d76e51c5fbe7c6fb46c2ebcdd4ca9b8aee19f1aca610bdd"},"error":null,"id":1} ``
-
Convert the output to the
params.dat
format.Example of the output converted to the
params.dat
format:chain-protocol = multichain chain-description = My Network root-stream-name = root root-stream-open = true chain-is-testnet = false target-block-time = 15 maximum-block-size = 8388608 maximum-chunk-size = 1048576 maximum-chunk-count = 1024 default-network-port = 7447 default-rpc-port = 8000 anyone-can-connect = false anyone-can-send = false anyone-can-receive = false anyone-can-receive-empty = true anyone-can-create = false anyone-can-issue = false anyone-can-mine = false anyone-can-activate = false anyone-can-admin = false support-miner-precheck = true allow-arbitrary-outputs = false allow-p2sh-outputs = true allow-multisig-outputs = true setup-first-blocks = 60 mining-diversity = 0.3 admin-consensus-upgrade = 0.5 admin-consensus-txfilter = 0.5 admin-consensus-admin = 0.5 admin-consensus-activate = 0.5 admin-consensus-mine = 0.5 admin-consensus-create = 0 admin-consensus-issue = 0 lock-admin-mine-rounds = mining-requires-peers = mine-empty-rounds = 10 mining-turnover = 0.5 first-block-reward = -1 initial-block-reward = 0 reward-halving-interval = 52560000 reward-spendable-delay = 1 minimum-per-output = 0 maximum-per-output = 100000000000000 minimum-offchain-fee = 0 minimum-relay-fee = 0 native-currency-multiple = 100000000 skip-pow-check = false pow-minimum-bits = 8 target-adjust-freq = -1 allow-min-difficulty-blocks = false only-accept-std-txs = true max-std-tx-size = 4194304 max-std-op-returns-count = 32 max-std-op-return-size = 2097152 max-std-op-drops-count = 5 max-std-element-size = 40000 chain-name = nw-614-517-1 protocol-version = 20004 network-message-start = f8d8cdf4 address-pubkeyhash-version = 007ee2f6 address-scripthash-version = 05d9757c private-key-version = 80c92c0c address-checksum-value = 08f94387 genesis-pubkey = 039b7ee52bffe13196037d5f4b1c8fd4f4fefbc1e9766d821bd40b6bc36fc74b2c genesis-version = 1 genesis-timestamp = 1564720379 genesis-nbits = 536936447 genesis-nonce = 936 genesis-pubkey-hash = 06a9dbecfd60a7018c2c3916cdb9d99158906730 genesis-hash = 00d52e3c198c586eeca891bf44634fa244f3b3b59f456990c1ccbb2981d5c856 chain-params-hash = 0fed5218dd7fd4952d76e51c5fbe7c6fb46c2ebcdd4ca9b8aee19f1aca610bdd
-
Save the converted output to the
params.dat
file
Start the MultiChain cold node
/path/to/multichaind-cold CHAIN_NAME -daemon
where CHAIN_NAME — your MultiChain network chain name. See Default chain name.
Example:
~/multichain-2.0.2/multichaind-cold nw-123-456-7 -daemon
Enter the interactive mode with the cold node
multichain-cli CHAIN_NAME -cold
Example:
multichain-cli nw-123-456-7 -cold
Get the cold wallet keys
By default, the cold wallet of multichaind-cold
contains an automatically generated key pair. You can use this key pair or generate new key pairs.
In the interactive multichain-cli
mode that you are running now, use the following commands:
getaddresses
— view the addresses currently stored in the cold wallet.dumpprivkey
— this will show the private key of the address stored in the cold wallet. The format isdumpprivkey ADDRESS
. Example:dumpprivkey 12ABcdiuezg8EDHx2GkPke8VS3oiKACMch4Vng
.createkeypairs
— create new key pairs. This will print the key pairs without storing them in the cold wallet.importprivkey
— import the private key to the cold wallet. This will also import the address to the cold wallet. The format isimportprivkey PRIVATE_KEY
. Example:importprivkey V1A2bCdSyzTVHFampTT6bghSshJXydHpdXJiZXGvNePmWWBNM6LoGPLX
.
Now that you have your keys securely stored on the cold node, you can safely import the addresses to the hot nodes running with Chainstack and create unsigned transactions on the hot nodes without exposing your private keys.
Import the address from the cold node to the hot node
Use the very first MultiChain node deployed with Chainstack as your hot node to send the requests to. This is your admin node. For details, see Node permissions.
curl RPC_ENDPOINT -u "RPC_USER:RPC_PASSWORD" -d '{"method":"importaddress","params":["IMPORT_ADDRESS","false"],"id":2}'
where
- IMPORT_ADDRESS — the address that you created at the previous step.
false
— the parameter instructs to not scan the blockchain for any activity of the address. Using thefalse
parameter here saves time, because you are importing a new address.
Example:
curl https://nd-123-456-789.p2pify.com -u "user-name:pass-word-pass-word-pass-word" -d '{"method":"importaddress","params":["12ABcdiuezg8EDHx2GkPke8VS3oiKACMch4Vng","false"],"id":2}'
This will import the address to the MultiChain hot node without exposing the private key.
Grant the receive
and send
permissions to the imported address
receive
and send
permissions to the imported addresscurl RPC_ENDPOINT -u "RPC_USER:RPC_PASSWORD" -d '{"method":"grant","params":["IMPORTED_ADDRESS","receive,send"],"id":3}'
Example:
curl https://nd-123-456-789.p2pify.com -u "user-name:pass-word-pass-word-pass-word" -d '{"method":"grant","params":["12ABcdiuezg8EDHx2GkPke8VS3oiKACMch4Vng","receive,send"],"id":3}'
Issue an asset to the imported address
Issuing an asset at this step is for demonstration purposes, so that later you can send the asset with a cold node key signature.
curl RPC_ENDPOINT -u "RPC_USER:RPC_PASSWORD" -d '{"method":"issue","params":["IMPORT_ADDRESS","ASSET_NAME",100,0.001],"id":4}'
where ASSET_NAME — any name for the asset you are issuing.
Example:
curl https://nd-123-456-789.p2pify.com -u "user-name:pass-word-pass-word-pass-word" -d '{"method":"issue","params":["12ABcdiuezg8EDHx2GkPke8VS3oiKACMch4Vng","token",100,0.001],"id":4}'
This will issue 100 units of the asset token
.
Create a raw unsigned transaction
Create a raw unsigned transaction that will send units of the issued asset from your address to a different address.
curl RPC_ENDPOINT -u "RPC_USER:RPC_PASSWORD" -d '{"method":"createrawsendfrom","params":["IMPORT_ADDRESS",{"ADDRESS":{"ASSET_NAME":50}}],"id":5}'
where ADDRESS — any address existing on the MultiChain network.
Example:
curl https://nd-123-456-789.p2pify.com -u "user-name:pass-word-pass-word-pass-word" -d '{"method":"createrawsendfrom","params":["12ABcdiuezg8EDHx2GkPke8VS3oiKACMch4Vng",{"1abc2PLVeVPF1CEkGSmuBtRScRAmKzVsLgaPf":{"token":50}}],"id":5}'
This will create a raw unsigned transaction to send 50 units of the asset token
and will give you a hexadecimal transaction ID.
Example output:
{"result":"010000000177acc507ee0b802f3b0dde19f3acb389a40498f388822fb3d48efa871135f1f60000000000ffffffff0200000000000000003776a914aab5af995a8d50eb35ca7044880b4ccc463b7e8c88ac1c73706b71a40498f388822fb3d48efa871135f1f650c30000000000007500000000000000003776a91421722e2f3414baa7c29cc31e833cfb01bef2eece88ac1c73706b71a40498f388822fb3d48efa871135f1f650c30000000000007500000000","error":null,"id":5}
Decode the raw transaction to get the spent output
curl RPC_ENDPOINT -u "RPC_USER:RPC_PASSWORD" -d '{"method":"decoderawtransaction","params":["TRANSACTION_HEX"],"id":6}'
where TRANSACTION_HEX — the hexadecimal transaction ID you received at the previous step.
Example:
curl https://nd-123-456-789.p2pify.com -u "user-name:pass-word-pass-word-pass-word" -d '{"method":"decoderawtransaction","params":["010000000177acc507ee0b802f3b0dde19f3acb389a40498f388822fb3d48efa871135f1f60000000000ffffffff0200000000000000003776a914aab5af995a8d50eb35ca7044880b4ccc463b7e8c88ac1c73706b71a40498f388822fb3d48efa871135f1f650c30000000000007500000000000000003776a91421722e2f3414baa7c29cc31e833cfb01bef2eece88ac1c73706b71a40498f388822fb3d48efa871135f1f650c30000000000007500000000"],"id":6}'
Example output:
{"result":{"txid":"5192ee142d70a124672d18f760b748c4373ee2c27331521bb5c825e0bf95b04e","version":1,"locktime":0,"vin":[{"txid":"f6f1351187fa8ed4b32f8288f39804a489b3acf319de0d3b2f800bee07c5ac77","vout":0,"scriptSig":{"asm":"","hex":""},"sequence":4294967295}],"vout":[{"value":0,"n":0,"scriptPubKey":{"asm":"OP_DUP OP_HASH160 aab5af995a8d50eb35ca7044880b4ccc463b7e8c OP_EQUALVERIFY OP_CHECKSIG 73706b71a40498f388822fb3d48efa871135f1f650c3000000000000 OP_DROP","hex":"76a914aab5af995a8d50eb35ca7044880b4ccc463b7e8c88ac1c73706b71a40498f388822fb3d48efa871135f1f650c300000000000075","reqSigs":1,"type":"pubkeyhash","addresses":["1Q5Bymiw44zwbMUKmX3uonwSdcxSXG2V35MLoq"]},"assets":[{"name":"token","issuetxid":"f6f1351187fa8ed4b32f8288f39804a489b3acf319de0d3b2f800bee07c5ac77","assetref":"71-265-61942","qty":50,"raw":50000,"type":"transfer"}]},{"value":0,"n":1,"scriptPubKey":{"asm":"OP_DUP OP_HASH160 21722e2f3414baa7c29cc31e833cfb01bef2eece OP_EQUALVERIFY OP_CHECKSIG 73706b71a40498f388822fb3d48efa871135f1f650c3000000000000 OP_DROP","hex":"76a91421722e2f3414baa7c29cc31e833cfb01bef2eece88ac1c73706b71a40498f388822fb3d48efa871135f1f650c300000000000075","reqSigs":1,"type":"pubkeyhash","addresses":["15XBaziuezg8EDHx2GkPke8VS3oiKACMch4Vng"]},"assets":[{"name":"token","issuetxid":"f6f1351187fa8ed4b32f8288f39804a489b3acf319de0d3b2f800bee07c5ac77","assetref":"71-265-61942","qty":50,"raw":50000,"type":"transfer"}]}]},"error":null,"id":6}
In the output, look for the vin
array. In the vin
array, copy the txid
value and the vout
value. For the example above, you would need to copy and save the following values:
txid
:f6f1351187fa8ed4b32f8288f39804a489b3acf319de0d3b2f800bee07c5ac77
vout
:0
Get the hexadecimal script for the txid
, vout
pair
txid
, vout
paircurl RPC_ENDPOINT -u "RPC_USER:RPC_PASSWORD -d '{"method":"gettxout","params":["TXID",VOUT],"id":7}'
where
- TXID — the
txid
value from the previous step - VOUT — the
vout
value from the previous step
Example:
curl https://nd-123-456-789.p2pify.com -u "user-name:pass-word-pass-word-pass-word" -d '{"method":"gettxout","params":["f6f1351187fa8ed4b32f8288f39804a489b3acf319de0d3b2f800bee07c5ac77",0],"id":7}'
Example output:
{"result":{"bestblock":"008b50f38e2884f7470cbe173ad16fc642e7159aec2007496fac47f13aad36b7","confirmations":11,"value":0,"scriptPubKey":{"asm":"OP_DUP OP_HASH160 21722e2f3414baa7c29cc31e833cfb01bef2eece OP_EQUALVERIFY OP_CHECKSIG 73706b67a086010000000000 OP_DROP","hex":"76a91421722e2f3414baa7c29cc31e833cfb01bef2eece88ac0c73706b67a08601000000000075","reqSigs":1,"type":"pubkeyhash","addresses":["15XBaziuezg8EDHx2GkPke8VS3oiKACMch4Vng"]},"version":1,"coinbase":false,"assets":[{"name":"token","issuetxid":"f6f1351187fa8ed4b32f8288f39804a489b3acf319de0d3b2f800bee07c5ac77","assetref":"71-265-61942","qty":100,"raw":100000,"issue":true}]},"error":null,"id":7}
In the output, look for the hex
value of the scriptPubKey
array. Copy the hex
value. For the example above, you would need to copy and save the following value:
hex
:76a91421722e2f3414baa7c29cc31e833cfb01bef2eece88ac0c73706b67a08601000000000075
Ensure you have all values to sign the transaction on the cold node
At this point, you should have the following values ready and at hand:
- Hexadecimal transaction ID
- Decoded
txid
- Decoded
vout
hex
value ofscriptPubKey
For the examples in this guide, the values are:
- Hexadecimal transaction ID:
010000000177acc507ee0b802f3b0dde19f3acb389a40498f388822fb3d48efa871135f1f60000000000ffffffff0200000000000000003776a914aab5af995a8d50eb35ca7044880b4ccc463b7e8c88ac1c73706b71a40498f388822fb3d48efa871135f1f650c30000000000007500000000000000003776a91421722e2f3414baa7c29cc31e833cfb01bef2eece88ac1c73706b71a40498f388822fb3d48efa871135f1f650c30000000000007500000000
- Decoded
txid
:f6f1351187fa8ed4b32f8288f39804a489b3acf319de0d3b2f800bee07c5ac77
- Decoded
vout
:0
hex
value ofscriptPubKey
:76a91421722e2f3414baa7c29cc31e833cfb01bef2eece88ac0c73706b67a08601000000000075
Move the saved values to the cold node
Move the saved values to the cold node in a manner that meets your security requirements.
Sign the transaction on the cold node
-
On the cold node, enter interactive mode:
multichain-cli CHAIN_NAME -cold
Example:
multichain-cli nw-123-456-7 -cold
-
Sign the transaction:
signrawtransaction TRANSACTION_HEX '[{"txid":"TXID","vout":VOUT,"scriptPubKey":"SCRIPT_HEX"}]'
For the examples in this guide, the full command is:
signrawtransaction 010000000177acc507ee0b802f3b0dde19f3acb389a40498f388822fb3d48efa871135f1f60000000000ffffffff0200000000000000003776a914aab5af995a8d50eb35ca7044880b4ccc463b7e8c88ac1c73706b71a40498f388822fb3d48efa871135f1f650c30000000000007500000000000000003776a91421722e2f3414baa7c29cc31e833cfb01bef2eece88ac1c73706b71a40498f388822fb3d48efa871135f1f650c30000000000007500000000 '[{"txid":"f6f1351187fa8ed4b32f8288f39804a489b3acf319de0d3b2f800bee07c5ac77","vout":0,"scriptPubKey":"76a91421722e2f3414baa7c29cc31e833cfb01bef2eece88ac0c73706b67a08601000000000075"}]'
Example output:
{"hex" : "010000000177acc507ee0b802f3b0dde19f3acb389a40498f388822fb3d48efa871135f1f6000000006b483045022100f905286e0f8a648b71625244eb623c641eb6e8caebbec30806e45c3b264342ad02200ef576fec5633326564e296e9d1698f7faa50536c919a0307abf5b08cd49264f012102251eece743174e0433086e1d978374de6a0d60e48c39282697b757ad968d3e1affffffff0200000000000000003776a914aab5af995a8d50eb35ca7044880b4ccc463b7e8c88ac1c73706b71a40498f388822fb3d48efa871135f1f650c30000000000007500000000000000003776a91421722e2f3414baa7c29cc31e833cfb01bef2eece88ac1c73706b71a40498f388822fb3d48efa871135f1f650c30000000000007500000000", "complete" : true}
Save the
hex
value from the output.
Send the signed transaction to the hot node running with Chainstack
Now that your transaction is signed, broadcast it to the MultiChain network.
curl RPC_ENDPOINT -u "RPC_USER:RPC_PASSWORD" -d '{"method":"sendrawtransaction","params":["HEX_VALUE"],"id":8}'
where HEX_VALUE — the hexadecimal value you received at the previous step.
For the example in this guide, the full command is:
curl https://nd-123-456-789.p2pify.com -u "user-name:pass-word-pass-word-pass-word" -d '{"method":"sendrawtransaction","params":["010000000177acc507ee0b802f3b0dde19f3acb389a40498f388822fb3d48efa871135f1f6000000006b483045022100f905286e0f8a648b71625244eb623c641eb6e8caebbec30806e45c3b264342ad02200ef576fec5633326564e296e9d1698f7faa50536c919a0307abf5b08cd49264f012102251eece743174e0433086e1d978374de6a0d60e48c39282697b757ad968d3e1affffffff0200000000000000003776a914aab5af995a8d50eb35ca7044880b4ccc463b7e8c88ac1c73706b71a40498f388822fb3d48efa871135f1f650c30000000000007500000000000000003776a91421722e2f3414baa7c29cc31e833cfb01bef2eece88ac1c73706b71a40498f388822fb3d48efa871135f1f650c30000000000007500000000"],"id":8}'
You created and signed the transaction without exposing your private key to the hot nodes on the MultiChain network.
Updated 2 months ago