Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
25 commits
Select commit Hold shift + click to select a range
bf41b31
support set of keys to sign spork
Sep 3, 2018
d449c00
several addresses support in -sporkkey
Sep 3, 2018
47249e5
tests for multykey sporks
Sep 5, 2018
6fc3998
command line option -minsporkkeys
Sep 6, 2018
656fad2
make spork active only after given number of signers
Sep 7, 2018
e327194
use signature in spork hash calculation
Sep 7, 2018
9724bb8
test for new and old spork messages interaction
Sep 12, 2018
633313c
add multikeyspork.py to integration tests
Sep 12, 2018
a3129eb
change test to have ability to distinguish default spork value
Sep 14, 2018
e8da6a5
require min spork keys number to be more than the half of the common …
Sep 14, 2018
187b87a
calc current spork value with majority of signers
Sep 14, 2018
17afe2a
set test nodes time in integration test
Sep 14, 2018
d51ceae
extract keyid from signed spork message directly
Sep 17, 2018
9ad4485
change -sporkaddr option syntax to process several addresses
Sep 17, 2018
4adf334
codestyle fixes
Sep 17, 2018
a094966
fix test comments
Sep 24, 2018
ea19a73
codestyle fixes
Sep 24, 2018
985ca1d
simplify CSporkManager::SporkValueIsActive
Sep 24, 2018
5c0c2ce
Calc signature hash without signature field
Sep 25, 2018
58da4c5
do not restore pubkey ids from cach
Sep 26, 2018
8aa814a
Calc different keyids to check signature because not all sporks can b…
Sep 26, 2018
167bf9f
codestyle fixes
Sep 26, 2018
d184ece
Fix CSporkManager::CheckAndRemove to use several keys
Sep 26, 2018
f60fbfb
codestyle fixes
Sep 27, 2018
8dc93fd
Correct processing of not actual spork6 value with GetSignerKeyID
Sep 27, 2018
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions qa/pull-tester/rpc-tests.py
Original file line number Diff line number Diff line change
Expand Up @@ -124,6 +124,7 @@
'wallet-accounts.py',
'wallet-dump.py',
'listtransactions.py',
'multikeysporks.py',
# vv Tests less than 60s vv
'sendheaders.py', # NOTE: needs dash_hash to pass
'zapwallettxes.py',
Expand Down
151 changes: 151 additions & 0 deletions qa/rpc-tests/multikeysporks.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,151 @@
#!/usr/bin/env python3
# Copyright (c) 2018 The Dash Core developers
# Distributed under the MIT software license, see the accompanying
# file COPYING or http://www.opensource.org/licenses/mit-license.php.

from test_framework.mininode import *
from test_framework.test_framework import BitcoinTestFramework
from test_framework.util import *
from time import *

'''
multikeysporks.py

Test logic for several signer keys usage for spork broadcast.

We set 5 possible keys for sporks signing and set minimum
required signers to 3. We check 1 and 2 signers can't set the spork
value, any 3 signers can change spork value and other 3 signers
can change it again.
'''


class MultiKeySporkTest(BitcoinTestFramework):
def __init__(self):
super().__init__()
self.num_nodes = 5
self.setup_clean_chain = True
self.is_network_split = False

def setup_network(self):
self.nodes = []

# secret(base58): 931wyuRNVYvhg18Uu9bky5Qg1z4QbxaJ7fefNBzjBPiLRqcd33F
# keyid(hex): 60f0f57f71f0081f1aacdd8432340a33a526f91b
# address(base58): yNsMZhEhYqv14TgdYb1NS2UmNZjE8FSJxa

# secret(base58): 91vbXGMSWKGHom62986XtL1q2mQDA12ngcuUNNe5NfMSj44j7g3
# keyid(hex): 43dff2b09de2f904f688ec14ee6899087b889ad0
# address(base58): yfLSXFfipnkgYioD6L8aUNyfRgEBuJv48h

# secret(base58): 92bxUjPT5AhgXuXJwfGGXqhomY2SdQ55MYjXyx9DZNxCABCSsRH
# keyid(hex): d9aa5fa00cce99101a4044e65dc544d1579890de
# address(base58): ygcG5S2pQz2U1UAaHvU6EznKZW7yapKMA7

# secret(base58): 934yPXiVGf4RCY2qTs2Bt5k3TEtAiAg12sMxCt8yVWbSU7p3fuD
# keyid(hex): 0b23935ce0bea3b997a334f6fa276c9fa17687b2
# address(base58): ycbRQWbovrhQMTuxg9p4LAuW5SCMAKqPrn

# secret(base58): 92Cxwia363Wg2qGF1fE5z4GKi8u7r1nrWQXdtsj2ACZqaDPSihD
# keyid(hex): 1d1098b2b1f759b678a0a7a098637a9b898adcac
# address(base58): yc5TGfcHYoLCrcbVy4umsiDjsYUn39vLui

self.nodes.append(start_node(0, self.options.tmpdir,
["-debug", "-sporkkey=931wyuRNVYvhg18Uu9bky5Qg1z4QbxaJ7fefNBzjBPiLRqcd33F",
"-sporkaddr=ygcG5S2pQz2U1UAaHvU6EznKZW7yapKMA7",
"-sporkaddr=yfLSXFfipnkgYioD6L8aUNyfRgEBuJv48h",
"-sporkaddr=yNsMZhEhYqv14TgdYb1NS2UmNZjE8FSJxa",
"-sporkaddr=ycbRQWbovrhQMTuxg9p4LAuW5SCMAKqPrn",
"-sporkaddr=yc5TGfcHYoLCrcbVy4umsiDjsYUn39vLui",
"-minsporkkeys=3"]))
self.nodes.append(start_node(1, self.options.tmpdir,
["-debug", "-sporkkey=91vbXGMSWKGHom62986XtL1q2mQDA12ngcuUNNe5NfMSj44j7g3",
"-sporkaddr=ygcG5S2pQz2U1UAaHvU6EznKZW7yapKMA7",
"-sporkaddr=yfLSXFfipnkgYioD6L8aUNyfRgEBuJv48h",
"-sporkaddr=yNsMZhEhYqv14TgdYb1NS2UmNZjE8FSJxa",
"-sporkaddr=ycbRQWbovrhQMTuxg9p4LAuW5SCMAKqPrn",
"-sporkaddr=yc5TGfcHYoLCrcbVy4umsiDjsYUn39vLui",
"-minsporkkeys=3"]))
self.nodes.append(start_node(2, self.options.tmpdir,
["-debug", "-sporkkey=92bxUjPT5AhgXuXJwfGGXqhomY2SdQ55MYjXyx9DZNxCABCSsRH",
"-sporkaddr=ygcG5S2pQz2U1UAaHvU6EznKZW7yapKMA7",
"-sporkaddr=yfLSXFfipnkgYioD6L8aUNyfRgEBuJv48h",
"-sporkaddr=yNsMZhEhYqv14TgdYb1NS2UmNZjE8FSJxa",
"-sporkaddr=ycbRQWbovrhQMTuxg9p4LAuW5SCMAKqPrn",
"-sporkaddr=yc5TGfcHYoLCrcbVy4umsiDjsYUn39vLui",
"-minsporkkeys=3"]))
self.nodes.append(start_node(3, self.options.tmpdir,
["-debug", "-sporkkey=934yPXiVGf4RCY2qTs2Bt5k3TEtAiAg12sMxCt8yVWbSU7p3fuD",
"-sporkaddr=ygcG5S2pQz2U1UAaHvU6EznKZW7yapKMA7",
"-sporkaddr=yfLSXFfipnkgYioD6L8aUNyfRgEBuJv48h",
"-sporkaddr=yNsMZhEhYqv14TgdYb1NS2UmNZjE8FSJxa",
"-sporkaddr=ycbRQWbovrhQMTuxg9p4LAuW5SCMAKqPrn",
"-sporkaddr=yc5TGfcHYoLCrcbVy4umsiDjsYUn39vLui",
"-minsporkkeys=3"]))
self.nodes.append(start_node(4, self.options.tmpdir,
["-debug", "-sporkkey=92Cxwia363Wg2qGF1fE5z4GKi8u7r1nrWQXdtsj2ACZqaDPSihD",
"-sporkaddr=ygcG5S2pQz2U1UAaHvU6EznKZW7yapKMA7",
"-sporkaddr=yfLSXFfipnkgYioD6L8aUNyfRgEBuJv48h",
"-sporkaddr=yNsMZhEhYqv14TgdYb1NS2UmNZjE8FSJxa",
"-sporkaddr=ycbRQWbovrhQMTuxg9p4LAuW5SCMAKqPrn",
"-sporkaddr=yc5TGfcHYoLCrcbVy4umsiDjsYUn39vLui",
"-minsporkkeys=3"]))
# connect nodes at start
for i in range(0, 5):
for j in range(i, 5):
connect_nodes(self.nodes[i], j)

def get_test_spork_state(self, node):
info = node.spork('show')
# use InstantSend spork for tests
return info['SPORK_2_INSTANTSEND_ENABLED']

def set_test_spork_state(self, node, value):
# use InstantSend spork for tests
node.spork('SPORK_2_INSTANTSEND_ENABLED', value)

def wait_for_test_spork_state(self, node, value):
start = time()
got_state = False
while True:
if self.get_test_spork_state(node) == value:
got_state = True
break
if time() > start + 10:
break
sleep(0.1)
return got_state

def run_test(self):
# check test spork default state
for node in self.nodes:
assert(self.get_test_spork_state(node) == 0)

set_mocktime(get_mocktime() + 1)
set_node_times(self.nodes, get_mocktime())
# first and second signers set spork value
self.set_test_spork_state(self.nodes[0], 1)
self.set_test_spork_state(self.nodes[1], 1)
# spork change requires at least 3 signers
for node in self.nodes:
assert(not self.wait_for_test_spork_state(node, 1))

# third signer set spork value
self.set_test_spork_state(self.nodes[2], 1)
# now spork state is changed
for node in self.nodes:
assert(self.wait_for_test_spork_state(node, 1))

set_mocktime(get_mocktime() + 1)
set_node_times(self.nodes, get_mocktime())
# now set the spork again with other signers to test
# old and new spork messages interaction
self.set_test_spork_state(self.nodes[2], 2)
self.set_test_spork_state(self.nodes[3], 2)
self.set_test_spork_state(self.nodes[4], 2)
for node in self.nodes:
assert(self.wait_for_test_spork_state(node, 2))


if __name__ == '__main__':
MultiKeySporkTest().main()
12 changes: 8 additions & 4 deletions src/chainparams.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -237,7 +237,8 @@ class CMainParams : public CChainParams {
nPoolMaxTransactions = 3;
nFulfilledRequestExpireTime = 60*60; // fulfilled requests expire in 1 hour

strSporkAddress = "Xgtyuk76vhuFW2iT7UAiHgNdWXCf3J34wh";
vSporkAddresses = {"Xgtyuk76vhuFW2iT7UAiHgNdWXCf3J34wh"};
nMinSporkKeys = 1;

checkpointData = (CCheckpointData) {
boost::assign::map_list_of
Expand Down Expand Up @@ -391,7 +392,8 @@ class CTestNetParams : public CChainParams {
nPoolMaxTransactions = 3;
nFulfilledRequestExpireTime = 5*60; // fulfilled requests expire in 5 minutes

strSporkAddress = "yjPtiKh2uwk3bDutTEA2q9mCtXyiZRWn55";
vSporkAddresses = {"yjPtiKh2uwk3bDutTEA2q9mCtXyiZRWn55"};
nMinSporkKeys = 1;

checkpointData = (CCheckpointData) {
boost::assign::map_list_of
Expand Down Expand Up @@ -535,7 +537,8 @@ class CDevNetParams : public CChainParams {
nPoolMaxTransactions = 3;
nFulfilledRequestExpireTime = 5*60; // fulfilled requests expire in 5 minutes

strSporkAddress = "yjPtiKh2uwk3bDutTEA2q9mCtXyiZRWn55";
vSporkAddresses = {"yjPtiKh2uwk3bDutTEA2q9mCtXyiZRWn55"};
nMinSporkKeys = 1;

checkpointData = (CCheckpointData) {
boost::assign::map_list_of
Expand Down Expand Up @@ -641,7 +644,8 @@ class CRegTestParams : public CChainParams {
nFulfilledRequestExpireTime = 5*60; // fulfilled requests expire in 5 minutes

// privKey: cP4EKFyJsHT39LDqgdcB43Y3YXjNyjb5Fuas1GQSeAtjnZWmZEQK
strSporkAddress = "yj949n1UH6fDhw6HtVE5VMj2iSTaSWBMcW";
vSporkAddresses = {"yj949n1UH6fDhw6HtVE5VMj2iSTaSWBMcW"};
nMinSporkKeys = 1;

checkpointData = (CCheckpointData){
boost::assign::map_list_of
Expand Down
6 changes: 4 additions & 2 deletions src/chainparams.h
Original file line number Diff line number Diff line change
Expand Up @@ -88,7 +88,8 @@ class CChainParams
const ChainTxData& TxData() const { return chainTxData; }
int PoolMaxTransactions() const { return nPoolMaxTransactions; }
int FulfilledRequestExpireTime() const { return nFulfilledRequestExpireTime; }
const std::string& SporkAddress() const { return strSporkAddress; }
const std::vector<std::string>& SporkAddresses() const { return vSporkAddresses; }
int MinSporkKeys() const { return nMinSporkKeys; }
protected:
CChainParams() {}

Expand Down Expand Up @@ -116,7 +117,8 @@ class CChainParams
ChainTxData chainTxData;
int nPoolMaxTransactions;
int nFulfilledRequestExpireTime;
std::string strSporkAddress;
std::vector<std::string> vSporkAddresses;
int nMinSporkKeys;
};

/**
Expand Down
26 changes: 21 additions & 5 deletions src/init.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -570,6 +570,7 @@ std::string HelpMessage(HelpMessageMode mode)
AppendParamsHelpMessages(strUsage, showDebug);
strUsage += HelpMessageOpt("-litemode=<n>", strprintf(_("Disable all Dash specific functionality (Masternodes, PrivateSend, InstantSend, Governance) (0-1, default: %u)"), 0));
strUsage += HelpMessageOpt("-sporkaddr=<hex>", strprintf(_("Override spork address. Only useful for regtest and devnet. Using this on mainnet or testnet will ban you.")));
strUsage += HelpMessageOpt("-minsporkkeys=<n>", strprintf(_("Overrides minimum spork signers to change spork value. Only useful for regtest and devnet. Using this on mainnet or testnet will ban you.")));

strUsage += HelpMessageGroup(_("Masternode options:"));
strUsage += HelpMessageOpt("-masternode=<n>", strprintf(_("Enable the client to act as a masternode (0-1, default: %u)"), 0));
Expand Down Expand Up @@ -1398,13 +1399,28 @@ bool AppInitMain(boost::thread_group& threadGroup, CScheduler& scheduler)
threadGroup.create_thread(&ThreadScriptCheck);
}

if (!sporkManager.SetSporkAddress(GetArg("-sporkaddr", Params().SporkAddress())))
return InitError(_("Invalid spork address specified with -sporkaddr"));
std::vector<std::string> vSporkAddresses;
if (mapMultiArgs.count("-sporkaddr")) {
vSporkAddresses = mapMultiArgs.at("-sporkaddr");
} else {
vSporkAddresses = Params().SporkAddresses();
}
for (const auto& address: vSporkAddresses) {
if (!sporkManager.SetSporkAddress(address)) {
return InitError(_("Invalid spork address specified with -sporkaddr"));
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

bodies of an if should either be on the same line or in brackets

If an if only has a single-statement then-clause, it can appear on the same line as the if, without braces. In every other case, braces are required, and the then and else clauses must appear correctly indented on a new line.

}
}

if (IsArgSet("-sporkkey")) // spork priv key
{
if (!sporkManager.SetPrivKey(GetArg("-sporkkey", "")))
int minsporkkeys = GetArg("-minsporkkeys", Params().MinSporkKeys());
if (!sporkManager.SetMinSporkKeys(minsporkkeys)) {
return InitError(_("Invalid minimum number of spork signers specified with -minsporkkeys"));
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

same as above, same line or braces. Also if( -> if (

}


if (IsArgSet("-sporkkey")) { // spork priv key
if (!sporkManager.SetPrivKey(GetArg("-sporkkey", ""))) {
return InitError(_("Unable to sign spork message, wrong key?"));
}
}

// Start the lightweight task scheduler thread
Expand Down
Loading