Use BLS keys for the DIP3 operator key (#2352)

* Use BLS keys for operator keys

* Add "bls generate" RPC to generate BLS keys

* Use unique_ptr to store blsKeyOperator and blsPubKeyOperator

Needed because the Chia BLS library crashes when keys are created before
the library is initialized, even if keys are not used. This is the case here
as we have static instances here.

* Remove unnecessary CheckSignature calls

This seems to be some garbage I left in by mistake.

* Fixed review comments

* Fix rpc help for operator keys

All keys that are used as examples are random. None of the secret keys
belongs to any of the public keys.

* Use .GetHash() instead of ::SerializeHash() for BLS pubkeys in txmempool.cpp

* Rename mapProTxBlsPubKeys to mapProTxBlsPubKeyHashes
This commit is contained in:
Alexander Block 2018-10-21 21:45:16 +02:00 committed by UdjinM6
parent 3313bbd515
commit c9d2745188
33 changed files with 485 additions and 262 deletions

View File

@ -279,7 +279,9 @@ class DIP3Test(BitcoinTestFramework):
mn.is_protx = False
mn.p2p_port = p2p_port(mn.idx)
mn.mnkey = node.masternode('genkey')
blsKey = node.bls('generate')
mn.legacyMnkey = node.masternode('genkey')
mn.blsMnkey = blsKey['secret']
mn.collateral_address = node.getnewaddress()
mn.collateral_txid = node.sendtoaddress(mn.collateral_address, 1000)
rawtx = node.getrawtransaction(mn.collateral_txid, 1)
@ -302,10 +304,12 @@ class DIP3Test(BitcoinTestFramework):
mn.is_protx = True
mn.p2p_port = p2p_port(mn.idx)
blsKey = node.bls('generate')
mn.ownerAddr = node.getnewaddress()
mn.operatorAddr = mn.ownerAddr
mn.operatorAddr = blsKey['public']
mn.votingAddr = mn.ownerAddr
mn.mnkey = node.dumpprivkey(mn.operatorAddr)
mn.legacyMnkey = node.masternode('genkey')
mn.blsMnkey = blsKey['secret']
mn.collateral_address = node.getnewaddress()
mn.collateral_txid = node.protx('register', mn.collateral_address, '1000', '127.0.0.1:%d' % mn.p2p_port, '0', mn.ownerAddr, mn.operatorAddr, mn.votingAddr, 0, mn.collateral_address)
@ -323,7 +327,7 @@ class DIP3Test(BitcoinTestFramework):
def start_mn(self, mn):
while len(self.nodes) <= mn.idx:
self.nodes.append(None)
extra_args = ['-masternode=1', '-masternodeprivkey=%s' % mn.mnkey]
extra_args = ['-masternode=1', '-masternodeprivkey=%s' % mn.legacyMnkey, '-masternodeblsprivkey=%s' % mn.blsMnkey]
n = start_node(mn.idx, self.options.tmpdir, self.extra_args + extra_args, redirect_stderr=True)
self.nodes[mn.idx] = n
for i in range(0, self.num_nodes):
@ -341,7 +345,7 @@ class DIP3Test(BitcoinTestFramework):
return mn
def test_protx_update_service(self, mn):
self.nodes[0].protx('update_service', mn.collateral_txid, '127.0.0.2:%d' % mn.p2p_port, '0')
self.nodes[0].protx('update_service', mn.collateral_txid, '127.0.0.2:%d' % mn.p2p_port, '0', mn.blsMnkey)
self.nodes[0].generate(1)
self.sync_all()
for node in self.nodes:
@ -351,7 +355,7 @@ class DIP3Test(BitcoinTestFramework):
assert_equal(mn_list['%s-%d' % (mn.collateral_txid, mn.collateral_vout)]['address'], '127.0.0.2:%d' % mn.p2p_port)
# undo
self.nodes[0].protx('update_service', mn.collateral_txid, '127.0.0.1:%d' % mn.p2p_port, '0')
self.nodes[0].protx('update_service', mn.collateral_txid, '127.0.0.1:%d' % mn.p2p_port, '0', mn.blsMnkey)
self.nodes[0].generate(1)
def force_finish_mnsync(self, node):
@ -374,7 +378,7 @@ class DIP3Test(BitcoinTestFramework):
time.sleep(0.1)
def write_mnconf_line(self, mn, f):
conf_line = "%s %s:%d %s %s %d\n" % (mn.alias, '127.0.0.1', mn.p2p_port, mn.mnkey, mn.collateral_txid, mn.collateral_vout)
conf_line = "%s %s:%d %s %s %d\n" % (mn.alias, '127.0.0.1', mn.p2p_port, mn.legacyMnkey, mn.collateral_txid, mn.collateral_vout)
f.write(conf_line)
def write_mnconf(self, mns):
@ -594,12 +598,14 @@ class DIP3Test(BitcoinTestFramework):
# Try to create ProTx (should still fail)
address = node.getnewaddress()
key = node.getnewaddress()
assert_raises_jsonrpc(None, "bad-tx-type", node.protx, 'register', address, '1000', '127.0.0.1:10000', '0', key, key, key, 0, address)
blsKey = node.bls('generate')
assert_raises_jsonrpc(None, "bad-tx-type", node.protx, 'register', address, '1000', '127.0.0.1:10000', '0', key, blsKey['public'], key, 0, address)
def test_success_create_protx(self, node):
address = node.getnewaddress()
key = node.getnewaddress()
txid = node.protx('register', address, '1000', '127.0.0.1:10000', '0', key, key, key, 0, address)
blsKey = node.bls('generate')
txid = node.protx('register', address, '1000', '127.0.0.1:10000', '0', key, blsKey['public'], key, 0, address)
rawtx = node.getrawtransaction(txid, 1)
self.mine_double_spend(node, rawtx['vin'], address, use_mnmerkleroot_from_tip=True)
self.sync_all()

View File

@ -59,7 +59,7 @@ void CActiveDeterministicMasternodeManager::Init()
CDeterministicMNList mnList = deterministicMNManager->GetListAtChainTip();
CDeterministicMNCPtr dmn = mnList.GetMNByOperatorKey(activeMasternodeInfo.keyIDOperator);
CDeterministicMNCPtr dmn = mnList.GetMNByOperatorKey(*activeMasternodeInfo.blsPubKeyOperator);
if (!dmn) {
// MN not appeared on the chain yet
return;
@ -234,7 +234,7 @@ bool CActiveLegacyMasternodeManager::SendMasternodePing(CConnman& connman)
mnp.nSentinelVersion = nSentinelVersion;
mnp.fSentinelIsCurrent =
(abs(GetAdjustedTime() - nSentinelPingTime) < MASTERNODE_SENTINEL_PING_MAX_SECONDS);
if(!mnp.Sign(activeMasternodeInfo.keyOperator, activeMasternodeInfo.keyIDOperator)) {
if(!mnp.Sign(activeMasternodeInfo.legacyKeyOperator, activeMasternodeInfo.legacyKeyIDOperator)) {
LogPrintf("CActiveLegacyMasternodeManager::SendMasternodePing -- ERROR: Couldn't sign Masternode Ping\n");
return false;
}
@ -351,11 +351,11 @@ void CActiveLegacyMasternodeManager::ManageStateRemote()
return;
LogPrint("masternode", "CActiveLegacyMasternodeManager::ManageStateRemote -- Start status = %s, type = %s, pinger enabled = %d, keyIDOperator = %s\n",
GetStatus(), GetTypeString(), fPingerEnabled, activeMasternodeInfo.keyIDOperator.ToString());
GetStatus(), GetTypeString(), fPingerEnabled, activeMasternodeInfo.legacyKeyIDOperator.ToString());
mnodeman.CheckMasternode(activeMasternodeInfo.keyIDOperator, true);
mnodeman.CheckMasternode(activeMasternodeInfo.legacyKeyIDOperator, true);
masternode_info_t infoMn;
if(mnodeman.GetMasternodeInfo(activeMasternodeInfo.keyIDOperator, infoMn)) {
if(mnodeman.GetMasternodeInfo(activeMasternodeInfo.legacyKeyIDOperator, infoMn)) {
if(infoMn.nProtocolVersion != PROTOCOL_VERSION) {
nState = ACTIVE_MASTERNODE_NOT_CAPABLE;
strNotCapableReason = "Invalid protocol version";
@ -376,12 +376,6 @@ void CActiveLegacyMasternodeManager::ManageStateRemote()
}
auto dmn = deterministicMNManager->GetListAtChainTip().GetMN(infoMn.outpoint.hash);
if (dmn) {
if (dmn->pdmnState->keyIDOperator != infoMn.keyIDOperator) {
nState = ACTIVE_MASTERNODE_NOT_CAPABLE;
strNotCapableReason = strprintf("Masternode collateral is a ProTx and masternode key does not match key from -masternodeprivkey");
LogPrintf("CActiveLegacyMasternodeManager::ManageStateRemote -- %s: %s\n", GetStateString(), strNotCapableReason);
return;
}
if (dmn->pdmnState->addr != infoMn.addr) {
nState = ACTIVE_MASTERNODE_NOT_CAPABLE;
strNotCapableReason = strprintf("Masternode collateral is a ProTx and ProTx address does not match local address");

View File

@ -30,8 +30,11 @@ extern CActiveDeterministicMasternodeManager* activeMasternodeManager;
struct CActiveMasternodeInfo {
// Keys for the active Masternode
CKeyID keyIDOperator;
CKey keyOperator;
CKeyID legacyKeyIDOperator;
CKey legacyKeyOperator;
std::unique_ptr<CBLSPublicKey> blsPubKeyOperator;
std::unique_ptr<CBLSSecretKey> blsKeyOperator;
// Initialized while registering Masternode
COutPoint outpoint;

View File

@ -33,9 +33,9 @@ std::string CDeterministicMNState::ToString() const
}
return strprintf("CDeterministicMNState(nRegisteredHeight=%d, nLastPaidHeight=%d, nPoSePenalty=%d, nPoSeRevivedHeight=%d, nPoSeBanHeight=%d, nRevocationReason=%d, "
"keyIDOwner=%s, keyIDOperator=%s, keyIDVoting=%s, addr=%s, nProtocolVersion=%d, payoutAddress=%s, operatorRewardAddress=%s)",
"keyIDOwner=%s, pubKeyOperator=%s, keyIDVoting=%s, addr=%s, nProtocolVersion=%d, payoutAddress=%s, operatorRewardAddress=%s)",
nRegisteredHeight, nLastPaidHeight, nPoSePenalty, nPoSeRevivedHeight, nPoSeBanHeight, nRevocationReason,
keyIDOwner.ToString(), keyIDOperator.ToString(), keyIDVoting.ToString(), addr.ToStringIPPort(false), nProtocolVersion, payoutAddress, operatorRewardAddress);
keyIDOwner.ToString(), pubKeyOperator.ToString(), keyIDVoting.ToString(), addr.ToStringIPPort(false), nProtocolVersion, payoutAddress, operatorRewardAddress);
}
void CDeterministicMNState::ToJson(UniValue& obj) const
@ -49,7 +49,7 @@ void CDeterministicMNState::ToJson(UniValue& obj) const
obj.push_back(Pair("PoSeBanHeight", nPoSeBanHeight));
obj.push_back(Pair("revocationReason", nRevocationReason));
obj.push_back(Pair("keyIDOwner", keyIDOwner.ToString()));
obj.push_back(Pair("keyIDOperator", keyIDOperator.ToString()));
obj.push_back(Pair("pubKeyOperator", pubKeyOperator.ToString()));
obj.push_back(Pair("keyIDVoting", keyIDVoting.ToString()));
obj.push_back(Pair("addr", addr.ToStringIPPort(false)));
obj.push_back(Pair("protocolVersion", nProtocolVersion));
@ -132,10 +132,10 @@ CDeterministicMNCPtr CDeterministicMNList::GetValidMN(const uint256& proTxHash)
return dmn;
}
CDeterministicMNCPtr CDeterministicMNList::GetMNByOperatorKey(const CKeyID& keyID)
CDeterministicMNCPtr CDeterministicMNList::GetMNByOperatorKey(const CBLSPublicKey& pubKey)
{
for (const auto& p : mnMap) {
if (p.second->pdmnState->keyIDOperator == keyID) {
if (p.second->pdmnState->pubKeyOperator == pubKey) {
return p.second;
}
}
@ -256,7 +256,7 @@ void CDeterministicMNList::AddMN(const CDeterministicMNCPtr &dmn)
mnMap = mnMap.set(dmn->proTxHash, dmn);
AddUniqueProperty(dmn, dmn->pdmnState->addr);
AddUniqueProperty(dmn, dmn->pdmnState->keyIDOwner);
AddUniqueProperty(dmn, dmn->pdmnState->keyIDOperator);
AddUniqueProperty(dmn, dmn->pdmnState->pubKeyOperator);
}
void CDeterministicMNList::UpdateMN(const uint256 &proTxHash, const CDeterministicMNStateCPtr &pdmnState)
@ -270,7 +270,7 @@ void CDeterministicMNList::UpdateMN(const uint256 &proTxHash, const CDeterminist
UpdateUniqueProperty(dmn, oldState->addr, pdmnState->addr);
UpdateUniqueProperty(dmn, oldState->keyIDOwner, pdmnState->keyIDOwner);
UpdateUniqueProperty(dmn, oldState->keyIDOperator, pdmnState->keyIDOperator);
UpdateUniqueProperty(dmn, oldState->pubKeyOperator, pdmnState->pubKeyOperator);
}
void CDeterministicMNList::RemoveMN(const uint256& proTxHash)
@ -279,7 +279,7 @@ void CDeterministicMNList::RemoveMN(const uint256& proTxHash)
assert(dmn != nullptr);
DeleteUniqueProperty(dmn, dmn->pdmnState->addr);
DeleteUniqueProperty(dmn, dmn->pdmnState->keyIDOwner);
DeleteUniqueProperty(dmn, dmn->pdmnState->keyIDOperator);
DeleteUniqueProperty(dmn, dmn->pdmnState->pubKeyOperator);
mnMap = mnMap.erase(proTxHash);
}
@ -387,7 +387,7 @@ bool CDeterministicMNManager::BuildNewListFromBlock(const CBlock& block, const C
if (newList.HasUniqueProperty(proTx.addr))
return _state.DoS(100, false, REJECT_CONFLICT, "bad-protx-dup-addr");
if (newList.HasUniqueProperty(proTx.keyIDOwner) || newList.HasUniqueProperty(proTx.keyIDOperator))
if (newList.HasUniqueProperty(proTx.keyIDOwner) || newList.HasUniqueProperty(proTx.pubKeyOperator))
return _state.DoS(100, false, REJECT_CONFLICT, "bad-protx-dup-key");
auto dmn = std::make_shared<CDeterministicMN>(tx.GetHash(), proTx);
@ -426,7 +426,7 @@ bool CDeterministicMNManager::BuildNewListFromBlock(const CBlock& block, const C
if (newState->nPoSeBanHeight != -1) {
// only revive when all keys are set
if (!newState->keyIDOperator.IsNull() && !newState->keyIDVoting.IsNull() && !newState->keyIDOwner.IsNull()) {
if (newState->pubKeyOperator.IsValid() && !newState->keyIDVoting.IsNull() && !newState->keyIDOwner.IsNull()) {
newState->nPoSeBanHeight = -1;
newState->nPoSeRevivedHeight = nHeight;
@ -450,12 +450,12 @@ bool CDeterministicMNManager::BuildNewListFromBlock(const CBlock& block, const C
return _state.DoS(100, false, REJECT_INVALID, "bad-protx-hash");
}
auto newState = std::make_shared<CDeterministicMNState>(*dmn->pdmnState);
if (newState->keyIDOperator != proTx.keyIDOperator) {
if (newState->pubKeyOperator != proTx.pubKeyOperator) {
// reset all operator related fields and put MN into PoSe-banned state in case the operator key changes
newState->ResetOperatorFields();
newState->BanIfNotBanned(nHeight);
}
newState->keyIDOperator = proTx.keyIDOperator;
newState->pubKeyOperator = proTx.pubKeyOperator;
newState->keyIDVoting = proTx.keyIDVoting;
newState->scriptPayout = proTx.scriptPayout;

View File

@ -9,6 +9,7 @@
#include "providertx.h"
#include "dbwrapper.h"
#include "sync.h"
#include "bls/bls.h"
#include "immer/map.hpp"
#include "immer/map_transient.hpp"
@ -30,7 +31,7 @@ public:
uint16_t nRevocationReason{CProUpRevTx::REASON_NOT_SPECIFIED};
CKeyID keyIDOwner;
CKeyID keyIDOperator;
CBLSPublicKey pubKeyOperator;
CKeyID keyIDVoting;
CService addr;
int32_t nProtocolVersion;
@ -42,7 +43,7 @@ public:
CDeterministicMNState(const CProRegTx& proTx)
{
keyIDOwner = proTx.keyIDOwner;
keyIDOperator = proTx.keyIDOperator;
pubKeyOperator = proTx.pubKeyOperator;
keyIDVoting = proTx.keyIDVoting;
addr = proTx.addr;
nProtocolVersion = proTx.nProtocolVersion;
@ -63,7 +64,7 @@ public:
READWRITE(nPoSeBanHeight);
READWRITE(nRevocationReason);
READWRITE(keyIDOwner);
READWRITE(keyIDOperator);
READWRITE(pubKeyOperator);
READWRITE(keyIDVoting);
READWRITE(addr);
READWRITE(nProtocolVersion);
@ -73,7 +74,7 @@ public:
void ResetOperatorFields()
{
keyIDOperator.SetNull();
pubKeyOperator = CBLSPublicKey();
addr = CService();
nProtocolVersion = 0;
scriptOperatorPayout = CScript();
@ -95,7 +96,7 @@ public:
nPoSeBanHeight == rhs.nPoSeBanHeight &&
nRevocationReason == rhs.nRevocationReason &&
keyIDOwner == rhs.keyIDOwner &&
keyIDOperator == rhs.keyIDOperator &&
pubKeyOperator == rhs.pubKeyOperator &&
keyIDVoting == rhs.keyIDVoting &&
addr == rhs.addr &&
nProtocolVersion == rhs.nProtocolVersion &&
@ -257,7 +258,7 @@ public:
}
CDeterministicMNCPtr GetMN(const uint256& proTxHash) const;
CDeterministicMNCPtr GetValidMN(const uint256& proTxHash) const;
CDeterministicMNCPtr GetMNByOperatorKey(const CKeyID& keyID);
CDeterministicMNCPtr GetMNByOperatorKey(const CBLSPublicKey& pubKey);
CDeterministicMNCPtr GetMNPayee() const;
/**

View File

@ -42,15 +42,31 @@ static bool CheckService(const uint256& proTxHash, const ProTx& proTx, const CBl
}
template <typename ProTx>
static bool CheckInputsHashAndSig(const CTransaction &tx, const ProTx& proTx, const CKeyID &keyID, CValidationState& state)
static bool CheckSig(const ProTx& proTx, const CKeyID& keyID, CValidationState& state)
{
std::string strError;
if (!CHashSigner::VerifyHash(::SerializeHash(proTx), keyID, proTx.vchSig, strError))
return state.DoS(100, false, REJECT_INVALID, "bad-protx-sig", false, strError);
return true;
}
template <typename ProTx>
static bool CheckSig(const ProTx& proTx, const CBLSPublicKey& pubKey, CValidationState& state)
{
if (!proTx.sig.VerifyInsecure(pubKey, ::SerializeHash(proTx)))
return state.DoS(100, false, REJECT_INVALID, "bad-protx-sig", false);
return true;
}
template <typename ProTx, typename PubKey>
static bool CheckInputsHashAndSig(const CTransaction &tx, const ProTx& proTx, const PubKey& pubKey, CValidationState& state)
{
uint256 inputsHash = CalcTxInputsHash(tx);
if (inputsHash != proTx.inputsHash)
return state.DoS(100, false, REJECT_INVALID, "bad-protx-inputs-hash");
std::string strError;
if (!CHashSigner::VerifyHash(::SerializeHash(proTx), keyID, proTx.vchSig, strError))
return state.DoS(100, false, REJECT_INVALID, "bad-protx-sig", false, strError);
if (!CheckSig(proTx, pubKey, state))
return false;
return true;
}
@ -70,7 +86,7 @@ bool CheckProRegTx(const CTransaction& tx, const CBlockIndex* pindexPrev, CValid
return state.DoS(10, false, REJECT_INVALID, "bad-protx-collateral-index");
if (tx.vout[ptx.nCollateralIndex].nValue != 1000 * COIN)
return state.DoS(10, false, REJECT_INVALID, "bad-protx-collateral");
if (ptx.keyIDOwner.IsNull() || ptx.keyIDOperator.IsNull() || ptx.keyIDVoting.IsNull())
if (ptx.keyIDOwner.IsNull() || !ptx.pubKeyOperator.IsValid() || ptx.keyIDVoting.IsNull())
return state.DoS(10, false, REJECT_INVALID, "bad-protx-key-null");
// we may support P2SH later, but restrict it for now (while in transitioning phase from old MN list to deterministic list)
if (!ptx.scriptPayout.IsPayToPublicKeyHash())
@ -82,7 +98,7 @@ bool CheckProRegTx(const CTransaction& tx, const CBlockIndex* pindexPrev, CValid
return state.DoS(10, false, REJECT_INVALID, "bad-protx-payee-dest");
}
// don't allow reuse of collateral key for other keys (don't allow people to put the collateral key onto an online server)
if (payoutDest == CTxDestination(ptx.keyIDOwner) || payoutDest == CTxDestination(ptx.keyIDOperator) || payoutDest == CTxDestination(ptx.keyIDVoting)) {
if (payoutDest == CTxDestination(ptx.keyIDOwner) || payoutDest == CTxDestination(ptx.keyIDVoting)) {
return state.DoS(10, false, REJECT_INVALID, "bad-protx-payee-reuse");
}
@ -101,12 +117,12 @@ bool CheckProRegTx(const CTransaction& tx, const CBlockIndex* pindexPrev, CValid
if (pindexPrev) {
auto mnList = deterministicMNManager->GetListForBlock(pindexPrev->GetBlockHash());
if (mnList.HasUniqueProperty(ptx.keyIDOwner) || mnList.HasUniqueProperty(ptx.keyIDOperator)) {
if (mnList.HasUniqueProperty(ptx.keyIDOwner) || mnList.HasUniqueProperty(ptx.pubKeyOperator)) {
return state.DoS(10, false, REJECT_DUPLICATE, "bad-protx-dup-key");
}
if (!deterministicMNManager->IsDeterministicMNsSporkActive(pindexPrev->nHeight)) {
if (ptx.keyIDOwner != ptx.keyIDOperator || ptx.keyIDOwner != ptx.keyIDVoting) {
if (ptx.keyIDOwner != ptx.keyIDVoting) {
return state.DoS(10, false, REJECT_INVALID, "bad-protx-key-not-same");
}
}
@ -147,7 +163,7 @@ bool CheckProUpServTx(const CTransaction& tx, const CBlockIndex* pindexPrev, CVa
}
// we can only check the signature if pindexPrev != NULL and the MN is known
if (!CheckInputsHashAndSig(tx, ptx, mn->pdmnState->keyIDOperator, state))
if (!CheckInputsHashAndSig(tx, ptx, mn->pdmnState->pubKeyOperator, state))
return false;
}
@ -165,7 +181,7 @@ bool CheckProUpRegTx(const CTransaction& tx, const CBlockIndex* pindexPrev, CVal
if (ptx.nVersion > CProRegTx::CURRENT_VERSION)
return state.DoS(100, false, REJECT_INVALID, "bad-protx-version");
if (ptx.keyIDOperator.IsNull() || ptx.keyIDVoting.IsNull())
if (!ptx.pubKeyOperator.IsValid() || ptx.keyIDVoting.IsNull())
return state.DoS(10, false, REJECT_INVALID, "bad-protx-key-null");
// we may support P2SH later, but restrict it for now (while in transitioning phase from old MN list to deterministic list)
if (!ptx.scriptPayout.IsPayToPublicKeyHash())
@ -184,7 +200,7 @@ bool CheckProUpRegTx(const CTransaction& tx, const CBlockIndex* pindexPrev, CVal
return state.DoS(100, false, REJECT_INVALID, "bad-protx-hash");
// don't allow reuse of collateral key for other keys (don't allow people to put the collateral key onto an online server)
if (payoutDest == CTxDestination(dmn->pdmnState->keyIDOwner) || payoutDest == CTxDestination(ptx.keyIDOperator) || payoutDest == CTxDestination(ptx.keyIDVoting)) {
if (payoutDest == CTxDestination(dmn->pdmnState->keyIDOwner) || payoutDest == CTxDestination(ptx.keyIDVoting)) {
return state.DoS(10, false, REJECT_INVALID, "bad-protx-payee-reuse");
}
@ -197,15 +213,15 @@ bool CheckProUpRegTx(const CTransaction& tx, const CBlockIndex* pindexPrev, CVal
if (coin.out.scriptPubKey != ptx.scriptPayout)
return state.DoS(10, false, REJECT_INVALID, "bad-protx-payee-collateral");
if (mnList.HasUniqueProperty(ptx.keyIDOperator)) {
auto otherDmn = mnList.GetUniquePropertyMN(ptx.keyIDOperator);
if (mnList.HasUniqueProperty(ptx.pubKeyOperator)) {
auto otherDmn = mnList.GetUniquePropertyMN(ptx.pubKeyOperator);
if (ptx.proTxHash != otherDmn->proTxHash) {
return state.DoS(10, false, REJECT_DUPLICATE, "bad-protx-dup-key");
}
}
if (!deterministicMNManager->IsDeterministicMNsSporkActive(pindexPrev->nHeight)) {
if (dmn->pdmnState->keyIDOwner != ptx.keyIDOperator || dmn->pdmnState->keyIDOwner != ptx.keyIDVoting) {
if (dmn->pdmnState->keyIDOwner != ptx.keyIDVoting) {
return state.DoS(10, false, REJECT_INVALID, "bad-protx-key-not-same");
}
}
@ -239,7 +255,7 @@ bool CheckProUpRevTx(const CTransaction& tx, const CBlockIndex* pindexPrev, CVal
if (!dmn)
return state.DoS(100, false, REJECT_INVALID, "bad-protx-hash");
if (!CheckInputsHashAndSig(tx, ptx, dmn->pdmnState->keyIDOperator, state))
if (!CheckInputsHashAndSig(tx, ptx, dmn->pdmnState->pubKeyOperator, state))
return false;
}
@ -254,8 +270,8 @@ std::string CProRegTx::ToString() const
payee = CBitcoinAddress(dest).ToString();
}
return strprintf("CProRegTx(nVersion=%d, nProtocolVersion=%d, nCollateralIndex=%d, addr=%s, nOperatorReward=%f, keyIDOwner=%s, keyIDOperator=%s, keyIDVoting=%s, scriptPayout=%s)",
nVersion, nProtocolVersion, nCollateralIndex, addr.ToString(), (double)nOperatorReward / 100, keyIDOwner.ToString(), keyIDOperator.ToString(), keyIDVoting.ToString(), payee);
return strprintf("CProRegTx(nVersion=%d, nProtocolVersion=%d, nCollateralIndex=%d, addr=%s, nOperatorReward=%f, keyIDOwner=%s, pubKeyOperator=%s, keyIDVoting=%s, scriptPayout=%s)",
nVersion, nProtocolVersion, nCollateralIndex, addr.ToString(), (double)nOperatorReward / 100, keyIDOwner.ToString(), pubKeyOperator.ToString(), keyIDVoting.ToString(), payee);
}
void CProRegTx::ToJson(UniValue& obj) const
@ -267,7 +283,7 @@ void CProRegTx::ToJson(UniValue& obj) const
obj.push_back(Pair("collateralIndex", (int)nCollateralIndex));
obj.push_back(Pair("service", addr.ToString(false)));
obj.push_back(Pair("keyIDOwner", keyIDOwner.ToString()));
obj.push_back(Pair("keyIDOperator", keyIDOperator.ToString()));
obj.push_back(Pair("pubKeyOperator", pubKeyOperator.ToString()));
obj.push_back(Pair("keyIDVoting", keyIDVoting.ToString()));
CTxDestination dest;
@ -316,8 +332,8 @@ std::string CProUpRegTx::ToString() const
payee = CBitcoinAddress(dest).ToString();
}
return strprintf("CProUpRegTx(nVersion=%d, proTxHash=%s, keyIDOperator=%s, keyIDVoting=%s, payoutAddress=%s)",
nVersion, proTxHash.ToString(), keyIDOperator.ToString(), keyIDVoting.ToString(), payee);
return strprintf("CProUpRegTx(nVersion=%d, proTxHash=%s, pubKeyOperator=%s, keyIDVoting=%s, payoutAddress=%s)",
nVersion, proTxHash.ToString(), pubKeyOperator.ToString(), keyIDVoting.ToString(), payee);
}
void CProUpRegTx::ToJson(UniValue& obj) const
@ -326,7 +342,7 @@ void CProUpRegTx::ToJson(UniValue& obj) const
obj.setObject();
obj.push_back(Pair("version", nVersion));
obj.push_back(Pair("proTxHash", proTxHash.ToString()));
obj.push_back(Pair("keyIDOperator", keyIDOperator.ToString()));
obj.push_back(Pair("pubKeyOperator", pubKeyOperator.ToString()));
obj.push_back(Pair("keyIDVoting", keyIDVoting.ToString()));
CTxDestination dest;
if (ExtractDestination(scriptPayout, dest)) {

View File

@ -7,6 +7,7 @@
#include "primitives/transaction.h"
#include "consensus/validation.h"
#include "bls/bls.h"
#include "netaddress.h"
#include "pubkey.h"
@ -25,7 +26,7 @@ public:
uint32_t nCollateralIndex{(uint32_t) - 1};
CService addr;
CKeyID keyIDOwner;
CKeyID keyIDOperator;
CBLSPublicKey pubKeyOperator;
CKeyID keyIDVoting;
uint16_t nOperatorReward{0};
CScript scriptPayout;
@ -43,7 +44,7 @@ public:
READWRITE(nCollateralIndex);
READWRITE(addr);
READWRITE(keyIDOwner);
READWRITE(keyIDOperator);
READWRITE(pubKeyOperator);
READWRITE(keyIDVoting);
READWRITE(*(CScriptBase*)(&scriptPayout));
READWRITE(nOperatorReward);
@ -69,7 +70,7 @@ public:
CService addr;
CScript scriptOperatorPayout;
uint256 inputsHash; // replay protection
std::vector<unsigned char> vchSig;
CBLSSignature sig;
public:
ADD_SERIALIZE_METHODS;
@ -84,7 +85,7 @@ public:
READWRITE(*(CScriptBase*)(&scriptOperatorPayout));
READWRITE(inputsHash);
if (!(s.GetType() & SER_GETHASH)) {
READWRITE(vchSig);
READWRITE(sig);
}
}
@ -101,7 +102,7 @@ public:
public:
uint16_t nVersion{CURRENT_VERSION}; // message version
uint256 proTxHash;
CKeyID keyIDOperator;
CBLSPublicKey pubKeyOperator;
CKeyID keyIDVoting;
CScript scriptPayout;
uint256 inputsHash; // replay protection
@ -115,7 +116,7 @@ public:
{
READWRITE(nVersion);
READWRITE(proTxHash);
READWRITE(keyIDOperator);
READWRITE(pubKeyOperator);
READWRITE(keyIDVoting);
READWRITE(*(CScriptBase*)(&scriptPayout));
READWRITE(inputsHash);
@ -148,7 +149,7 @@ public:
uint256 proTxHash;
uint16_t nReason{REASON_NOT_SPECIFIED};
uint256 inputsHash; // replay protection
std::vector<unsigned char> vchSig;
CBLSSignature sig;
public:
ADD_SERIALIZE_METHODS;
@ -161,7 +162,7 @@ public:
READWRITE(nReason);
READWRITE(inputsHash);
if (!(s.GetType() & SER_GETHASH)) {
READWRITE(vchSig);
READWRITE(sig);
}
}

View File

@ -15,7 +15,7 @@
CSimplifiedMNListEntry::CSimplifiedMNListEntry(const CDeterministicMN& dmn) :
proRegTxHash(dmn.proTxHash),
service(dmn.pdmnState->addr),
keyIDOperator(dmn.pdmnState->keyIDOperator),
pubKeyOperator(dmn.pdmnState->pubKeyOperator),
keyIDVoting(dmn.pdmnState->keyIDVoting),
isValid(dmn.pdmnState->nPoSeBanHeight == -1)
{
@ -30,8 +30,8 @@ uint256 CSimplifiedMNListEntry::CalcHash() const
std::string CSimplifiedMNListEntry::ToString() const
{
return strprintf("CSimplifiedMNListEntry(proRegTxHash=%s, service=%s, keyIDOperator=%s, keyIDVoting=%s, isValie=%d)",
proRegTxHash.ToString(), service.ToString(false), keyIDOperator.ToString(), keyIDVoting.ToString(), isValid);
return strprintf("CSimplifiedMNListEntry(proRegTxHash=%s, service=%s, pubKeyOperator=%s, keyIDVoting=%s, isValie=%d)",
proRegTxHash.ToString(), service.ToString(false), pubKeyOperator.ToString(), keyIDVoting.ToString(), isValid);
}
void CSimplifiedMNListEntry::ToJson(UniValue& obj) const
@ -40,8 +40,8 @@ void CSimplifiedMNListEntry::ToJson(UniValue& obj) const
obj.setObject();
obj.push_back(Pair("proRegTxHash", proRegTxHash.ToString()));
obj.push_back(Pair("service", service.ToString(false)));
obj.push_back(Pair("keyIDOperator", keyIDOperator.ToString()));
obj.push_back(Pair("keyIDVoting", keyIDOperator.ToString()));
obj.push_back(Pair("pubKeyOperator", pubKeyOperator.ToString()));
obj.push_back(Pair("keyIDVoting", keyIDVoting.ToString()));
obj.push_back(Pair("isValid", isValid));
}

View File

@ -9,6 +9,7 @@
#include "pubkey.h"
#include "netaddress.h"
#include "merkleblock.h"
#include "bls/bls.h"
class UniValue;
class CDeterministicMNList;
@ -19,7 +20,7 @@ class CSimplifiedMNListEntry
public:
uint256 proRegTxHash;
CService service;
CKeyID keyIDOperator;
CBLSPublicKey pubKeyOperator;
CKeyID keyIDVoting;
bool isValid;
@ -35,7 +36,7 @@ public:
{
READWRITE(proRegTxHash);
READWRITE(service);
READWRITE(keyIDOperator);
READWRITE(pubKeyOperator);
READWRITE(keyIDVoting);
READWRITE(isValid);
}

View File

@ -330,6 +330,24 @@ bool CGovernanceObject::CheckSignature(const CKeyID& keyID) const
return true;
}
bool CGovernanceObject::Sign(const CBLSSecretKey& key)
{
CBLSSignature sig = key.Sign(GetSignatureHash());
sig.GetBuf(vchSig);
return true;
}
bool CGovernanceObject::CheckSignature(const CBLSPublicKey& pubKey) const
{
CBLSSignature sig;
sig.SetBuf(vchSig);
if (!sig.VerifyInsecure(pubKey, GetSignatureHash())) {
LogPrintf("CGovernanceObject::CheckSignature -- VerifyInsecure() failed\n");
return false;
}
return true;
}
/**
Return the actual object from the vchData JSON structure.
@ -508,9 +526,16 @@ bool CGovernanceObject::IsValidLocally(std::string& strError, bool& fMissingMast
}
// Check that we have a valid MN signature
if (!CheckSignature(infoMn.keyIDOperator)) {
strError = "Invalid masternode signature for: " + strOutpoint + ", pubkey id = " + infoMn.keyIDOperator.ToString();
return false;
if (deterministicMNManager->IsDeterministicMNsSporkActive()) {
if (!CheckSignature(infoMn.blsPubKeyOperator)) {
strError = "Invalid masternode signature for: " + strOutpoint + ", pubkey id = " + infoMn.blsPubKeyOperator.ToString();
return false;
}
} else {
if (!CheckSignature(infoMn.legacyKeyIDOperator)) {
strError = "Invalid masternode signature for: " + strOutpoint + ", pubkey id = " + infoMn.legacyKeyIDOperator.ToString();
return false;
}
}
return true;

View File

@ -16,6 +16,7 @@
#include "sync.h"
#include "util.h"
#include "utilstrencodings.h"
#include "bls/bls.h"
#include <univalue.h>
@ -260,6 +261,8 @@ public:
void SetMasternodeOutpoint(const COutPoint& outpoint);
bool Sign(const CKey& key, const CKeyID& keyID);
bool CheckSignature(const CKeyID& keyID) const;
bool Sign(const CBLSSecretKey& key);
bool CheckSignature(const CBLSPublicKey& pubKey) const;
std::string GetSignatureMessage() const;
uint256 GetSignatureHash() const;

View File

@ -214,6 +214,26 @@ bool CGovernanceVote::CheckSignature(const CKeyID& keyID) const
return true;
}
bool CGovernanceVote::Sign(const CBLSSecretKey& key)
{
uint256 hash = GetSignatureHash();
CBLSSignature sig = key.Sign(hash);
sig.GetBuf(vchSig);
return true;
}
bool CGovernanceVote::CheckSignature(const CBLSPublicKey& pubKey) const
{
uint256 hash = GetSignatureHash();
CBLSSignature sig;
sig.SetBuf(vchSig);
if (!sig.VerifyInsecure(pubKey, hash)) {
LogPrintf("CGovernanceVote::CheckSignature -- VerifyInsecure() failed\n");
return false;
}
return true;
}
bool CGovernanceVote::IsValid(bool useVotingKey) const
{
if (nTime > GetAdjustedTime() + (60 * 60)) {
@ -239,7 +259,15 @@ bool CGovernanceVote::IsValid(bool useVotingKey) const
return false;
}
return CheckSignature(useVotingKey ? infoMn.keyIDVoting : infoMn.keyIDOperator);
if (useVotingKey) {
return CheckSignature(infoMn.keyIDVoting);
} else {
if (deterministicMNManager->IsDeterministicMNsSporkActive()) {
return CheckSignature(infoMn.blsPubKeyOperator);
} else {
return CheckSignature(infoMn.legacyKeyIDOperator);
}
}
}
bool operator==(const CGovernanceVote& vote1, const CGovernanceVote& vote2)

View File

@ -7,6 +7,7 @@
#include "key.h"
#include "primitives/transaction.h"
#include "bls/bls.h"
class CGovernanceVote;
class CConnman;
@ -96,6 +97,8 @@ public:
bool Sign(const CKey& key, const CKeyID& keyID);
bool CheckSignature(const CKeyID& keyID) const;
bool Sign(const CBLSSecretKey& key);
bool CheckSignature(const CBLSPublicKey& pubKey) const;
bool IsValid(bool useVotingKey) const;
void Relay(CConnman& connman) const;

View File

@ -1899,21 +1899,44 @@ bool AppInitMain(boost::thread_group& threadGroup, CScheduler& scheduler)
std::string strMasterNodePrivKey = GetArg("-masternodeprivkey", "");
if(!strMasterNodePrivKey.empty()) {
CPubKey pubKeyMasternode;
if(!CMessageSigner::GetKeysFromSecret(strMasterNodePrivKey, activeMasternodeInfo.keyOperator, pubKeyMasternode))
if(!CMessageSigner::GetKeysFromSecret(strMasterNodePrivKey, activeMasternodeInfo.legacyKeyOperator, pubKeyMasternode))
return InitError(_("Invalid masternodeprivkey. Please see documenation."));
activeMasternodeInfo.keyIDOperator = pubKeyMasternode.GetID();
activeMasternodeInfo.legacyKeyIDOperator = pubKeyMasternode.GetID();
LogPrintf(" keyIDOperator: %s\n", CBitcoinAddress(activeMasternodeInfo.keyIDOperator).ToString());
LogPrintf(" keyIDOperator: %s\n", CBitcoinAddress(activeMasternodeInfo.legacyKeyIDOperator).ToString());
} else {
return InitError(_("You must specify a masternodeprivkey in the configuration. Please see documentation for help."));
}
std::string strMasterNodeBLSPrivKey = GetArg("-masternodeblsprivkey", "");
if(!strMasterNodeBLSPrivKey.empty()) {
auto binKey = ParseHex(strMasterNodeBLSPrivKey);
CBLSSecretKey keyOperator;
keyOperator.SetBuf(binKey);
if (keyOperator.IsValid()) {
activeMasternodeInfo.blsKeyOperator = std::make_unique<CBLSSecretKey>(keyOperator);
activeMasternodeInfo.blsPubKeyOperator = std::make_unique<CBLSPublicKey>(activeMasternodeInfo.blsKeyOperator->GetPublicKey());
LogPrintf(" blsPubKeyOperator: %s\n", keyOperator.GetPublicKey().ToString());
} else {
return InitError(_("Invalid masternodeblsprivkey. Please see documenation."));
}
} else {
InitWarning(_("You should specify a masternodeblsprivkey in the configuration. Please see documentation for help."));
}
// init and register activeMasternodeManager
activeMasternodeManager = new CActiveDeterministicMasternodeManager();
RegisterValidationInterface(activeMasternodeManager);
}
if (activeMasternodeInfo.blsKeyOperator == nullptr) {
activeMasternodeInfo.blsKeyOperator = std::make_unique<CBLSSecretKey>();
}
if (activeMasternodeInfo.blsPubKeyOperator == nullptr) {
activeMasternodeInfo.blsPubKeyOperator = std::make_unique<CBLSPublicKey>();
}
#ifdef ENABLE_WALLET
LogPrintf("Using masternode config file %s\n", GetMasternodeConfigFile().string());

View File

@ -1071,13 +1071,22 @@ bool CTxLockVote::CheckSignature() const
return false;
}
if (sporkManager.IsSporkActive(SPORK_6_NEW_SIGS)) {
if (deterministicMNManager->IsDeterministicMNsSporkActive()) {
uint256 hash = GetSignatureHash();
if (!CHashSigner::VerifyHash(hash, infoMn.keyIDOperator, vchMasternodeSignature, strError)) {
CBLSSignature sig;
sig.SetBuf(vchMasternodeSignature);
if (!sig.IsValid() || !sig.VerifyInsecure(infoMn.blsPubKeyOperator, hash)) {
LogPrintf("CTxLockVote::CheckSignature -- VerifyInsecure() failed\n");
return false;
}
} else if (sporkManager.IsSporkActive(SPORK_6_NEW_SIGS)) {
uint256 hash = GetSignatureHash();
if (!CHashSigner::VerifyHash(hash, infoMn.legacyKeyIDOperator, vchMasternodeSignature, strError)) {
// could be a signature in old format
std::string strMessage = txHash.ToString() + outpoint.ToStringShort();
if (!CMessageSigner::VerifyMessage(infoMn.keyIDOperator, vchMasternodeSignature, strMessage, strError)) {
if (!CMessageSigner::VerifyMessage(infoMn.legacyKeyIDOperator, vchMasternodeSignature, strMessage, strError)) {
// nope, not in old format either
LogPrintf("CTxLockVote::CheckSignature -- VerifyMessage() failed, error: %s\n", strError);
return false;
@ -1085,7 +1094,7 @@ bool CTxLockVote::CheckSignature() const
}
} else {
std::string strMessage = txHash.ToString() + outpoint.ToStringShort();
if (!CMessageSigner::VerifyMessage(infoMn.keyIDOperator, vchMasternodeSignature, strMessage, strError)) {
if (!CMessageSigner::VerifyMessage(infoMn.legacyKeyIDOperator, vchMasternodeSignature, strMessage, strError)) {
LogPrintf("CTxLockVote::CheckSignature -- VerifyMessage() failed, error: %s\n", strError);
return false;
}
@ -1098,27 +1107,32 @@ bool CTxLockVote::Sign()
{
std::string strError;
if (sporkManager.IsSporkActive(SPORK_6_NEW_SIGS)) {
if (deterministicMNManager->IsDeterministicMNsSporkActive()) {
uint256 hash = GetSignatureHash();
if (!CHashSigner::SignHash(hash, activeMasternodeInfo.keyOperator, vchMasternodeSignature)) {
CBLSSignature sig = activeMasternodeInfo.blsKeyOperator->Sign(hash);
sig.GetBuf(vchMasternodeSignature);
} else if (sporkManager.IsSporkActive(SPORK_6_NEW_SIGS)) {
uint256 hash = GetSignatureHash();
if (!CHashSigner::SignHash(hash, activeMasternodeInfo.legacyKeyOperator, vchMasternodeSignature)) {
LogPrintf("CTxLockVote::Sign -- SignHash() failed\n");
return false;
}
if (!CHashSigner::VerifyHash(hash, activeMasternodeInfo.keyIDOperator, vchMasternodeSignature, strError)) {
if (!CHashSigner::VerifyHash(hash, activeMasternodeInfo.legacyKeyIDOperator, vchMasternodeSignature, strError)) {
LogPrintf("CTxLockVote::Sign -- VerifyHash() failed, error: %s\n", strError);
return false;
}
} else {
std::string strMessage = txHash.ToString() + outpoint.ToStringShort();
if (!CMessageSigner::SignMessage(strMessage, vchMasternodeSignature, activeMasternodeInfo.keyOperator)) {
if (!CMessageSigner::SignMessage(strMessage, vchMasternodeSignature, activeMasternodeInfo.legacyKeyOperator)) {
LogPrintf("CTxLockVote::Sign -- SignMessage() failed\n");
return false;
}
if (!CMessageSigner::VerifyMessage(activeMasternodeInfo.keyIDOperator, vchMasternodeSignature, strMessage, strError)) {
if (!CMessageSigner::VerifyMessage(activeMasternodeInfo.legacyKeyIDOperator, vchMasternodeSignature, strMessage, strError)) {
LogPrintf("CTxLockVote::Sign -- VerifyMessage() failed, error: %s\n", strError);
return false;
}

View File

@ -491,7 +491,7 @@ void CMasternodePayments::ProcessMessage(CNode* pfrom, const std::string& strCom
}
int nDos = 0;
if(!vote.CheckSignature(mnInfo.keyIDOperator, nCachedBlockHeight, nDos)) {
if(!vote.CheckSignature(mnInfo.legacyKeyIDOperator, nCachedBlockHeight, nDos)) {
if(nDos) {
LOCK(cs_main);
LogPrintf("MASTERNODEPAYMENTVOTE -- ERROR: invalid signature\n");
@ -551,12 +551,12 @@ bool CMasternodePaymentVote::Sign()
if (sporkManager.IsSporkActive(SPORK_6_NEW_SIGS)) {
uint256 hash = GetSignatureHash();
if(!CHashSigner::SignHash(hash, activeMasternodeInfo.keyOperator, vchSig)) {
if(!CHashSigner::SignHash(hash, activeMasternodeInfo.legacyKeyOperator, vchSig)) {
LogPrintf("CMasternodePaymentVote::%s -- SignHash() failed\n", __func__);
return false;
}
if (!CHashSigner::VerifyHash(hash, activeMasternodeInfo.keyIDOperator, vchSig, strError)) {
if (!CHashSigner::VerifyHash(hash, activeMasternodeInfo.legacyKeyIDOperator, vchSig, strError)) {
LogPrintf("CMasternodePaymentVote::%s -- VerifyHash() failed, error: %s\n", __func__, strError);
return false;
}
@ -565,12 +565,12 @@ bool CMasternodePaymentVote::Sign()
std::to_string(nBlockHeight) +
ScriptToAsmStr(payee);
if(!CMessageSigner::SignMessage(strMessage, vchSig, activeMasternodeInfo.keyOperator)) {
if(!CMessageSigner::SignMessage(strMessage, vchSig, activeMasternodeInfo.legacyKeyOperator)) {
LogPrintf("CMasternodePaymentVote::%s -- SignMessage() failed\n", __func__);
return false;
}
if(!CMessageSigner::VerifyMessage(activeMasternodeInfo.keyIDOperator, vchSig, strMessage, strError)) {
if(!CMessageSigner::VerifyMessage(activeMasternodeInfo.legacyKeyIDOperator, vchSig, strMessage, strError)) {
LogPrintf("CMasternodePaymentVote::%s -- VerifyMessage() failed, error: %s\n", __func__, strError);
return false;
}

View File

@ -56,7 +56,7 @@ CMasternode::CMasternode(const CMasternodeBroadcast& mnb) :
CMasternode::CMasternode(const uint256 &proTxHash, const CDeterministicMNCPtr& dmn) :
masternode_info_t{ MASTERNODE_ENABLED, dmn->pdmnState->nProtocolVersion, GetAdjustedTime(),
COutPoint(proTxHash, dmn->nCollateralIndex), dmn->pdmnState->addr, CKeyID(), dmn->pdmnState->keyIDOwner, dmn->pdmnState->keyIDOperator, dmn->pdmnState->keyIDVoting},
COutPoint(proTxHash, dmn->nCollateralIndex), dmn->pdmnState->addr, CKeyID(), dmn->pdmnState->keyIDOwner, dmn->pdmnState->pubKeyOperator, dmn->pdmnState->keyIDVoting},
fAllowMixingTx(true)
{
CTxDestination dest;
@ -74,7 +74,7 @@ bool CMasternode::UpdateFromNewBroadcast(CMasternodeBroadcast& mnb, CConnman& co
pubKeyMasternode = mnb.pubKeyMasternode;
keyIDOwner = mnb.pubKeyMasternode.GetID();
keyIDOperator = mnb.pubKeyMasternode.GetID();
legacyKeyIDOperator = mnb.pubKeyMasternode.GetID();
keyIDVoting = mnb.pubKeyMasternode.GetID();
sigTime = mnb.sigTime;
vchSig = mnb.vchSig;
@ -89,7 +89,7 @@ bool CMasternode::UpdateFromNewBroadcast(CMasternodeBroadcast& mnb, CConnman& co
mnodeman.mapSeenMasternodePing.insert(std::make_pair(lastPing.GetHash(), lastPing));
}
// if it matches our Masternode privkey...
if(fMasternodeMode && keyIDOperator == activeMasternodeInfo.keyIDOperator) {
if(fMasternodeMode && legacyKeyIDOperator == activeMasternodeInfo.legacyKeyIDOperator) {
nPoSeBanScore = -MASTERNODE_POSE_BAN_MAX_SCORE;
if(nProtocolVersion == PROTOCOL_VERSION) {
// ... and PROTOCOL_VERSION, then we've been remotely activated ...
@ -203,7 +203,7 @@ void CMasternode::Check(bool fForce)
}
int nActiveStatePrev = nActiveState;
bool fOurMasternode = fMasternodeMode && activeMasternodeInfo.keyIDOperator == keyIDOperator;
bool fOurMasternode = fMasternodeMode && activeMasternodeInfo.legacyKeyIDOperator == legacyKeyIDOperator;
// masternode doesn't meet payment protocol requirements ...
bool fRequireUpdate = nProtocolVersion < mnpayments.GetMinMasternodePaymentsProto() ||
@ -512,7 +512,7 @@ bool CMasternodeBroadcast::SimpleCheck(int& nDos)
}
CScript pubkeyScript2;
pubkeyScript2 = GetScriptForDestination(keyIDOperator);
pubkeyScript2 = GetScriptForDestination(legacyKeyIDOperator);
if(pubkeyScript2.size() != 25) {
LogPrintf("CMasternodeBroadcast::SimpleCheck -- keyIDOperator has the wrong size\n");
@ -569,7 +569,7 @@ bool CMasternodeBroadcast::Update(CMasternode* pmn, int& nDos, CConnman& connman
}
// if ther was no masternode broadcast recently or if it matches our Masternode privkey...
if(!pmn->IsBroadcastedWithin(MASTERNODE_MIN_MNB_SECONDS) || (fMasternodeMode && keyIDOperator == activeMasternodeInfo.keyIDOperator)) {
if(!pmn->IsBroadcastedWithin(MASTERNODE_MIN_MNB_SECONDS) || (fMasternodeMode && legacyKeyIDOperator == activeMasternodeInfo.legacyKeyIDOperator)) {
// take the newest entry
LogPrintf("CMasternodeBroadcast::Update -- Got UPDATED Masternode entry: addr=%s\n", addr.ToString());
if(pmn->UpdateFromNewBroadcast(*this, connman)) {
@ -586,7 +586,7 @@ bool CMasternodeBroadcast::CheckOutpoint(int& nDos)
{
// we are a masternode with the same outpoint (i.e. already activated) and this mnb is ours (matches our Masternode privkey)
// so nothing to do here for us
if(fMasternodeMode && outpoint == activeMasternodeInfo.outpoint && keyIDOperator == activeMasternodeInfo.keyIDOperator) {
if(fMasternodeMode && outpoint == activeMasternodeInfo.outpoint && legacyKeyIDOperator == activeMasternodeInfo.legacyKeyIDOperator) {
return false;
}
@ -692,7 +692,7 @@ bool CMasternodeBroadcast::Sign(const CKey& keyCollateralAddress)
}
} else {
std::string strMessage = addr.ToString(false) + std::to_string(sigTime) +
keyIDCollateralAddress.ToString() + keyIDOperator.ToString() +
keyIDCollateralAddress.ToString() + legacyKeyIDOperator.ToString() +
std::to_string(nProtocolVersion);
if (!CMessageSigner::SignMessage(strMessage, vchSig, keyCollateralAddress)) {
@ -720,7 +720,7 @@ bool CMasternodeBroadcast::CheckSignature(int& nDos) const
if (!CHashSigner::VerifyHash(hash, keyIDCollateralAddress, vchSig, strError)) {
// maybe it's in old format
std::string strMessage = addr.ToString(false) + std::to_string(sigTime) +
keyIDCollateralAddress.ToString() + keyIDOperator.ToString() +
keyIDCollateralAddress.ToString() + legacyKeyIDOperator.ToString() +
std::to_string(nProtocolVersion);
if (!CMessageSigner::VerifyMessage(keyIDCollateralAddress, vchSig, strMessage, strError)){
@ -732,7 +732,7 @@ bool CMasternodeBroadcast::CheckSignature(int& nDos) const
}
} else {
std::string strMessage = addr.ToString(false) + std::to_string(sigTime) +
keyIDCollateralAddress.ToString() + keyIDOperator.ToString() +
keyIDCollateralAddress.ToString() + legacyKeyIDOperator.ToString() +
std::to_string(nProtocolVersion);
if(!CMessageSigner::VerifyMessage(keyIDCollateralAddress, vchSig, strMessage, strError)){
@ -935,7 +935,7 @@ bool CMasternodePing::CheckAndUpdate(CMasternode* pmn, bool fFromNewBroadcast, i
return false;
}
if (!CheckSignature(pmn->keyIDOperator, nDos)) return false;
if (!CheckSignature(pmn->legacyKeyIDOperator, nDos)) return false;
// so, ping seems to be ok

View File

@ -8,6 +8,7 @@
#include "key.h"
#include "validation.h"
#include "spork.h"
#include "bls/bls.h"
#include "evo/deterministicmns.h"
@ -110,15 +111,15 @@ struct masternode_info_t
CPubKey const& pkCollAddr, CPubKey const& pkMN) :
nActiveState{activeState}, nProtocolVersion{protoVer}, sigTime{sTime},
outpoint{outpnt}, addr{addr},
pubKeyCollateralAddress{pkCollAddr}, pubKeyMasternode{pkMN}, keyIDCollateralAddress{pkCollAddr.GetID()}, keyIDOwner{pkMN.GetID()}, keyIDOperator{pkMN.GetID()}, keyIDVoting{pkMN.GetID()} {}
pubKeyCollateralAddress{pkCollAddr}, pubKeyMasternode{pkMN}, keyIDCollateralAddress{pkCollAddr.GetID()}, keyIDOwner{pkMN.GetID()}, legacyKeyIDOperator{pkMN.GetID()}, keyIDVoting{pkMN.GetID()} {}
// only called when the network is in deterministic MN list mode
masternode_info_t(int activeState, int protoVer, int64_t sTime,
COutPoint const& outpnt, CService const& addr,
CKeyID const& pkCollAddr, CKeyID const& pkOwner, CKeyID const& pkOperator, CKeyID const& pkVoting) :
CKeyID const& pkCollAddr, CKeyID const& pkOwner, CBLSPublicKey const& pkOperator, CKeyID const& pkVoting) :
nActiveState{activeState}, nProtocolVersion{protoVer}, sigTime{sTime},
outpoint{outpnt}, addr{addr},
pubKeyCollateralAddress{}, pubKeyMasternode{}, keyIDCollateralAddress{pkCollAddr}, keyIDOwner{pkOwner}, keyIDOperator{pkOperator}, keyIDVoting{pkVoting} {}
pubKeyCollateralAddress{}, pubKeyMasternode{}, keyIDCollateralAddress{pkCollAddr}, keyIDOwner{pkOwner}, blsPubKeyOperator{pkOperator}, keyIDVoting{pkVoting} {}
int nActiveState = 0;
int nProtocolVersion = 0;
@ -130,7 +131,8 @@ struct masternode_info_t
CPubKey pubKeyMasternode{}; // this will be invalid/unset when the network switches to deterministic MNs (luckely it's only important for the broadcast hash)
CKeyID keyIDCollateralAddress{};
CKeyID keyIDOwner{};
CKeyID keyIDOperator{};
CKeyID legacyKeyIDOperator{};
CBLSPublicKey blsPubKeyOperator;
CKeyID keyIDVoting{};
int64_t nLastDsq = 0; //the dsq count from the last dsq broadcast of this node
@ -201,7 +203,8 @@ public:
READWRITE(pubKeyMasternode);
READWRITE(keyIDCollateralAddress);
READWRITE(keyIDOwner);
READWRITE(keyIDOperator);
READWRITE(legacyKeyIDOperator);
READWRITE(blsPubKeyOperator);
READWRITE(keyIDVoting);
READWRITE(lastPing);
READWRITE(vchSig);
@ -358,7 +361,7 @@ public:
if (ser_action.ForRead()) {
keyIDCollateralAddress = pubKeyCollateralAddress.GetID();
keyIDOwner = pubKeyMasternode.GetID();
keyIDOperator = pubKeyMasternode.GetID();
legacyKeyIDOperator = pubKeyMasternode.GetID();
keyIDVoting = pubKeyMasternode.GetID();
}
}

View File

@ -388,7 +388,7 @@ void CMasternodeMan::AddDeterministicMasternodes()
// make sure we use the splitted keys from now on
mn->keyIDOwner = dmn->pdmnState->keyIDOwner;
mn->keyIDOperator = dmn->pdmnState->keyIDOperator;
mn->blsPubKeyOperator = dmn->pdmnState->pubKeyOperator;
mn->keyIDVoting = dmn->pdmnState->keyIDVoting;
mn->addr = dmn->pdmnState->addr;
mn->nProtocolVersion = dmn->pdmnState->nProtocolVersion;
@ -598,15 +598,10 @@ bool CMasternodeMan::GetMasternodeInfo(const COutPoint& outpoint, masternode_inf
bool CMasternodeMan::GetMasternodeInfo(const CKeyID& keyIDOperator, masternode_info_t& mnInfoRet) {
LOCK(cs);
if (deterministicMNManager->IsDeterministicMNsSporkActive()) {
auto mnList = deterministicMNManager->GetListAtChainTip();
auto dmn = mnList.GetMNByOperatorKey(keyIDOperator);
if (dmn) {
return GetMasternodeInfo(COutPoint(dmn->proTxHash, dmn->nCollateralIndex), mnInfoRet);
}
return false;
} else {
for (const auto& mnpair : mapMasternodes) {
if (mnpair.second.keyIDOperator == keyIDOperator) {
if (mnpair.second.legacyKeyIDOperator == keyIDOperator) {
mnInfoRet = mnpair.second.GetInfo();
return true;
}
@ -615,11 +610,6 @@ bool CMasternodeMan::GetMasternodeInfo(const CKeyID& keyIDOperator, masternode_i
}
}
bool CMasternodeMan::GetMasternodeInfo(const CPubKey& pubKeyOperator, masternode_info_t& mnInfoRet)
{
return GetMasternodeInfo(pubKeyOperator.GetID(), mnInfoRet);
}
bool CMasternodeMan::GetMasternodeInfo(const CScript& payee, masternode_info_t& mnInfoRet)
{
CTxDestination dest;
@ -1399,24 +1389,24 @@ void CMasternodeMan::SendVerifyReply(CNode* pnode, CMasternodeVerification& mnv,
if (sporkManager.IsSporkActive(SPORK_6_NEW_SIGS)) {
uint256 hash = mnv.GetSignatureHash1(blockHash);
if(!CHashSigner::SignHash(hash, activeMasternodeInfo.keyOperator, mnv.vchSig1)) {
if(!CHashSigner::SignHash(hash, activeMasternodeInfo.legacyKeyOperator, mnv.vchSig1)) {
LogPrintf("CMasternodeMan::SendVerifyReply -- SignHash() failed\n");
return;
}
if (!CHashSigner::VerifyHash(hash, activeMasternodeInfo.keyIDOperator, mnv.vchSig1, strError)) {
if (!CHashSigner::VerifyHash(hash, activeMasternodeInfo.legacyKeyIDOperator, mnv.vchSig1, strError)) {
LogPrintf("CMasternodeMan::SendVerifyReply -- VerifyHash() failed, error: %s\n", strError);
return;
}
} else {
std::string strMessage = strprintf("%s%d%s", activeMasternodeInfo.service.ToString(false), mnv.nonce, blockHash.ToString());
if(!CMessageSigner::SignMessage(strMessage, mnv.vchSig1, activeMasternodeInfo.keyOperator)) {
if(!CMessageSigner::SignMessage(strMessage, mnv.vchSig1, activeMasternodeInfo.legacyKeyOperator)) {
LogPrintf("MasternodeMan::SendVerifyReply -- SignMessage() failed\n");
return;
}
if(!CMessageSigner::VerifyMessage(activeMasternodeInfo.keyIDOperator, mnv.vchSig1, strMessage, strError)) {
if(!CMessageSigner::VerifyMessage(activeMasternodeInfo.legacyKeyIDOperator, mnv.vchSig1, strMessage, strError)) {
LogPrintf("MasternodeMan::SendVerifyReply -- VerifyMessage() failed, error: %s\n", strError);
return;
}
@ -1486,10 +1476,10 @@ void CMasternodeMan::ProcessVerifyReply(CNode* pnode, CMasternodeVerification& m
if(CAddress(mnpair.second.addr, NODE_NETWORK) == pnode->addr) {
bool fFound = false;
if (sporkManager.IsSporkActive(SPORK_6_NEW_SIGS)) {
fFound = CHashSigner::VerifyHash(hash1, mnpair.second.keyIDOperator, mnv.vchSig1, strError);
fFound = CHashSigner::VerifyHash(hash1, mnpair.second.legacyKeyIDOperator, mnv.vchSig1, strError);
// we don't care about mnv with signature in old format
} else {
fFound = CMessageSigner::VerifyMessage(mnpair.second.keyIDOperator, mnv.vchSig1, strMessage1, strError);
fFound = CMessageSigner::VerifyMessage(mnpair.second.legacyKeyIDOperator, mnv.vchSig1, strMessage1, strError);
}
if (fFound) {
// found it!
@ -1511,12 +1501,12 @@ void CMasternodeMan::ProcessVerifyReply(CNode* pnode, CMasternodeVerification& m
if (sporkManager.IsSporkActive(SPORK_6_NEW_SIGS)) {
uint256 hash2 = mnv.GetSignatureHash2(blockHash);
if(!CHashSigner::SignHash(hash2, activeMasternodeInfo.keyOperator, mnv.vchSig2)) {
if(!CHashSigner::SignHash(hash2, activeMasternodeInfo.legacyKeyOperator, mnv.vchSig2)) {
LogPrintf("MasternodeMan::ProcessVerifyReply -- SignHash() failed\n");
return;
}
if(!CHashSigner::VerifyHash(hash2, activeMasternodeInfo.keyIDOperator, mnv.vchSig2, strError)) {
if(!CHashSigner::VerifyHash(hash2, activeMasternodeInfo.legacyKeyIDOperator, mnv.vchSig2, strError)) {
LogPrintf("MasternodeMan::ProcessVerifyReply -- VerifyHash() failed, error: %s\n", strError);
return;
}
@ -1524,12 +1514,12 @@ void CMasternodeMan::ProcessVerifyReply(CNode* pnode, CMasternodeVerification& m
std::string strMessage2 = strprintf("%s%d%s%s%s", mnv.addr.ToString(false), mnv.nonce, blockHash.ToString(),
mnv.masternodeOutpoint1.ToStringShort(), mnv.masternodeOutpoint2.ToStringShort());
if(!CMessageSigner::SignMessage(strMessage2, mnv.vchSig2, activeMasternodeInfo.keyOperator)) {
if(!CMessageSigner::SignMessage(strMessage2, mnv.vchSig2, activeMasternodeInfo.legacyKeyOperator)) {
LogPrintf("MasternodeMan::ProcessVerifyReply -- SignMessage() failed\n");
return;
}
if(!CMessageSigner::VerifyMessage(activeMasternodeInfo.keyIDOperator, mnv.vchSig2, strMessage2, strError)) {
if(!CMessageSigner::VerifyMessage(activeMasternodeInfo.legacyKeyIDOperator, mnv.vchSig2, strMessage2, strError)) {
LogPrintf("MasternodeMan::ProcessVerifyReply -- VerifyMessage() failed, error: %s\n", strError);
return;
}
@ -1642,12 +1632,12 @@ void CMasternodeMan::ProcessVerifyBroadcast(CNode* pnode, const CMasternodeVerif
uint256 hash1 = mnv.GetSignatureHash1(blockHash);
uint256 hash2 = mnv.GetSignatureHash2(blockHash);
if(!CHashSigner::VerifyHash(hash1, pmn1->keyIDOperator, mnv.vchSig1, strError)) {
if(!CHashSigner::VerifyHash(hash1, pmn1->legacyKeyIDOperator, mnv.vchSig1, strError)) {
LogPrintf("MasternodeMan::ProcessVerifyBroadcast -- VerifyHash() failed, error: %s\n", strError);
return;
}
if(!CHashSigner::VerifyHash(hash2, pmn2->keyIDOperator, mnv.vchSig2, strError)) {
if(!CHashSigner::VerifyHash(hash2, pmn2->legacyKeyIDOperator, mnv.vchSig2, strError)) {
LogPrintf("MasternodeMan::ProcessVerifyBroadcast -- VerifyHash() failed, error: %s\n", strError);
return;
}
@ -1656,12 +1646,12 @@ void CMasternodeMan::ProcessVerifyBroadcast(CNode* pnode, const CMasternodeVerif
std::string strMessage2 = strprintf("%s%d%s%s%s", mnv.addr.ToString(false), mnv.nonce, blockHash.ToString(),
mnv.masternodeOutpoint1.ToStringShort(), mnv.masternodeOutpoint2.ToStringShort());
if(!CMessageSigner::VerifyMessage(pmn1->keyIDOperator, mnv.vchSig1, strMessage1, strError)) {
if(!CMessageSigner::VerifyMessage(pmn1->legacyKeyIDOperator, mnv.vchSig1, strMessage1, strError)) {
LogPrintf("CMasternodeMan::ProcessVerifyBroadcast -- VerifyMessage() for masternode1 failed, error: %s\n", strError);
return;
}
if(!CMessageSigner::VerifyMessage(pmn2->keyIDOperator, mnv.vchSig2, strMessage2, strError)) {
if(!CMessageSigner::VerifyMessage(pmn2->legacyKeyIDOperator, mnv.vchSig2, strMessage2, strError)) {
LogPrintf("CMasternodeMan::ProcessVerifyBroadcast -- VerifyMessage() for masternode2 failed, error: %s\n", strError);
return;
}
@ -1781,7 +1771,7 @@ bool CMasternodeMan::CheckMnbAndUpdateMasternodeList(CNode* pfrom, CMasternodeBr
Add(mnb);
masternodeSync.BumpAssetLastTime("CMasternodeMan::CheckMnbAndUpdateMasternodeList - new");
// if it matches our Masternode privkey...
if(fMasternodeMode && mnb.keyIDOperator == activeMasternodeInfo.keyIDOperator) {
if(fMasternodeMode && mnb.legacyKeyIDOperator == activeMasternodeInfo.legacyKeyIDOperator) {
mnb.nPoSeBanScore = -MASTERNODE_POSE_BAN_MAX_SCORE;
if(mnb.nProtocolVersion == PROTOCOL_VERSION) {
// ... and PROTOCOL_VERSION, then we've been remotely activated ...
@ -1865,7 +1855,7 @@ void CMasternodeMan::CheckMasternode(const CKeyID& keyIDOperator, bool fForce)
if (deterministicMNManager->IsDeterministicMNsSporkActive())
return;
for (auto& mnpair : mapMasternodes) {
if (mnpair.second.keyIDOperator == keyIDOperator) {
if (mnpair.second.legacyKeyIDOperator == keyIDOperator) {
mnpair.second.Check(fForce);
return;
}

View File

@ -173,7 +173,6 @@ public:
bool GetMasternodeInfo(const uint256& proTxHash, masternode_info_t& mnInfoRet);
bool GetMasternodeInfo(const COutPoint& outpoint, masternode_info_t& mnInfoRet);
bool GetMasternodeInfo(const CKeyID& keyIDOperator, masternode_info_t& mnInfoRet);
bool GetMasternodeInfo(const CPubKey& pubKeyOperator, masternode_info_t& mnInfoRet);
bool GetMasternodeInfo(const CScript& payee, masternode_info_t& mnInfoRet);
/// Find an entry in the masternode list that is next to be paid

View File

@ -1997,7 +1997,7 @@ bool static ProcessMessage(CNode* pfrom, const std::string& strCommand, CDataStr
// we have no idea about (e.g we were offline)? How to handle them?
}
if(!dstx.CheckSignature(mn.keyIDOperator)) {
if (!dstx.CheckSignature(mn.legacyKeyIDOperator, mn.blsPubKeyOperator)) {
LogPrint("privatesend", "DSTX -- CheckSignature() failed for %s\n", hashTx.ToString());
return false;
}

View File

@ -64,7 +64,7 @@ void CPrivateSendClientManager::ProcessMessage(CNode* pfrom, const std::string&
masternode_info_t infoMn;
if(!mnodeman.GetMasternodeInfo(dsq.masternodeOutpoint, infoMn)) return;
if(!dsq.CheckSignature(infoMn.keyIDOperator)) {
if(!dsq.CheckSignature(infoMn.legacyKeyIDOperator, infoMn.blsPubKeyOperator)) {
// we probably have outdated info
mnodeman.AskForMN(pfrom, dsq.masternodeOutpoint, connman);
return;

View File

@ -102,7 +102,7 @@ void CPrivateSendServer::ProcessMessage(CNode* pfrom, const std::string& strComm
masternode_info_t mnInfo;
if(!mnodeman.GetMasternodeInfo(dsq.masternodeOutpoint, mnInfo)) return;
if(!dsq.CheckSignature(mnInfo.keyIDOperator)) {
if(!dsq.CheckSignature(mnInfo.legacyKeyIDOperator, mnInfo.blsPubKeyOperator)) {
// we probably have outdated info
mnodeman.AskForMN(pfrom, dsq.masternodeOutpoint, connman);
return;

View File

@ -51,15 +51,19 @@ bool CDarksendQueue::Sign()
std::string strError = "";
if (sporkManager.IsSporkActive(SPORK_6_NEW_SIGS)) {
if (deterministicMNManager->IsDeterministicMNsSporkActive()) {
uint256 hash = GetSignatureHash();
CBLSSignature sig = activeMasternodeInfo.blsKeyOperator->Sign(hash);
sig.GetBuf(vchSig);
} else if (sporkManager.IsSporkActive(SPORK_6_NEW_SIGS)) {
uint256 hash = GetSignatureHash();
if (!CHashSigner::SignHash(hash, activeMasternodeInfo.keyOperator, vchSig)) {
if (!CHashSigner::SignHash(hash, activeMasternodeInfo.legacyKeyOperator, vchSig)) {
LogPrintf("CDarksendQueue::Sign -- SignHash() failed\n");
return false;
}
if (!CHashSigner::VerifyHash(hash, activeMasternodeInfo.keyIDOperator, vchSig, strError)) {
if (!CHashSigner::VerifyHash(hash, activeMasternodeInfo.legacyKeyIDOperator, vchSig, strError)) {
LogPrintf("CDarksendQueue::Sign -- VerifyHash() failed, error: %s\n", strError);
return false;
}
@ -69,12 +73,12 @@ bool CDarksendQueue::Sign()
std::to_string(nTime) +
std::to_string(fReady);
if(!CMessageSigner::SignMessage(strMessage, vchSig, activeMasternodeInfo.keyOperator)) {
if(!CMessageSigner::SignMessage(strMessage, vchSig, activeMasternodeInfo.legacyKeyOperator)) {
LogPrintf("CDarksendQueue::Sign -- SignMessage() failed, %s\n", ToString());
return false;
}
if(!CMessageSigner::VerifyMessage(activeMasternodeInfo.keyIDOperator, vchSig, strMessage, strError)) {
if(!CMessageSigner::VerifyMessage(activeMasternodeInfo.legacyKeyIDOperator, vchSig, strMessage, strError)) {
LogPrintf("CDarksendQueue::Sign -- VerifyMessage() failed, error: %s\n", strError);
return false;
}
@ -83,11 +87,19 @@ bool CDarksendQueue::Sign()
return true;
}
bool CDarksendQueue::CheckSignature(const CKeyID& keyIDOperator) const
bool CDarksendQueue::CheckSignature(const CKeyID& keyIDOperator, const CBLSPublicKey& blsPubKey) const
{
std::string strError = "";
if (deterministicMNManager->IsDeterministicMNsSporkActive()) {
uint256 hash = GetSignatureHash();
if (sporkManager.IsSporkActive(SPORK_6_NEW_SIGS)) {
CBLSSignature sig;
sig.SetBuf(vchSig);
if (!sig.IsValid() || !sig.VerifyInsecure(blsPubKey, hash)) {
LogPrintf("CTxLockVote::CheckSignature -- VerifyInsecure() failed\n");
return false;
}
} else if (sporkManager.IsSporkActive(SPORK_6_NEW_SIGS)) {
uint256 hash = GetSignatureHash();
if (!CHashSigner::VerifyHash(hash, keyIDOperator, vchSig, strError)) {
@ -131,27 +143,32 @@ bool CDarksendBroadcastTx::Sign()
std::string strError = "";
if (sporkManager.IsSporkActive(SPORK_6_NEW_SIGS)) {
if (deterministicMNManager->IsDeterministicMNsSporkActive()) {
uint256 hash = GetSignatureHash();
if (!CHashSigner::SignHash(hash, activeMasternodeInfo.keyOperator, vchSig)) {
CBLSSignature sig = activeMasternodeInfo.blsKeyOperator->Sign(hash);
sig.GetBuf(vchSig);
} else if (sporkManager.IsSporkActive(SPORK_6_NEW_SIGS)) {
uint256 hash = GetSignatureHash();
if (!CHashSigner::SignHash(hash, activeMasternodeInfo.legacyKeyOperator, vchSig)) {
LogPrintf("CDarksendBroadcastTx::Sign -- SignHash() failed\n");
return false;
}
if (!CHashSigner::VerifyHash(hash, activeMasternodeInfo.keyIDOperator, vchSig, strError)) {
if (!CHashSigner::VerifyHash(hash, activeMasternodeInfo.legacyKeyIDOperator, vchSig, strError)) {
LogPrintf("CDarksendBroadcastTx::Sign -- VerifyHash() failed, error: %s\n", strError);
return false;
}
} else {
std::string strMessage = tx->GetHash().ToString() + std::to_string(sigTime);
if(!CMessageSigner::SignMessage(strMessage, vchSig, activeMasternodeInfo.keyOperator)) {
if(!CMessageSigner::SignMessage(strMessage, vchSig, activeMasternodeInfo.legacyKeyOperator)) {
LogPrintf("CDarksendBroadcastTx::Sign -- SignMessage() failed\n");
return false;
}
if(!CMessageSigner::VerifyMessage(activeMasternodeInfo.keyIDOperator, vchSig, strMessage, strError)) {
if(!CMessageSigner::VerifyMessage(activeMasternodeInfo.legacyKeyIDOperator, vchSig, strMessage, strError)) {
LogPrintf("CDarksendBroadcastTx::Sign -- VerifyMessage() failed, error: %s\n", strError);
return false;
}
@ -160,11 +177,20 @@ bool CDarksendBroadcastTx::Sign()
return true;
}
bool CDarksendBroadcastTx::CheckSignature(const CKeyID& keyIDOperator) const
bool CDarksendBroadcastTx::CheckSignature(const CKeyID& keyIDOperator, const CBLSPublicKey& blsPubKey) const
{
std::string strError = "";
if (sporkManager.IsSporkActive(SPORK_6_NEW_SIGS)) {
if (deterministicMNManager->IsDeterministicMNsSporkActive()) {
uint256 hash = GetSignatureHash();
CBLSSignature sig;
sig.SetBuf(vchSig);
if (!sig.IsValid() || !sig.VerifyInsecure(blsPubKey, hash)) {
LogPrintf("CTxLockVote::CheckSignature -- VerifyInsecure() failed\n");
return false;
}
} else if (sporkManager.IsSporkActive(SPORK_6_NEW_SIGS)) {
uint256 hash = GetSignatureHash();
if (!CHashSigner::VerifyHash(hash, keyIDOperator, vchSig, strError)) {

View File

@ -12,6 +12,7 @@
#include "sync.h"
#include "tinyformat.h"
#include "timedata.h"
#include "bls/bls.h"
class CPrivateSend;
class CConnman;
@ -229,7 +230,7 @@ public:
*/
bool Sign();
/// Check if we have a valid Masternode address
bool CheckSignature(const CKeyID& keyIDOperator) const;
bool CheckSignature(const CKeyID& keyIDOperator, const CBLSPublicKey& blsPubKey) const;
bool Relay(CConnman &connman);
@ -307,7 +308,7 @@ public:
uint256 GetSignatureHash() const;
bool Sign();
bool CheckSignature(const CKeyID& keyIDOperator) const;
bool CheckSignature(const CKeyID& keyIDOperator, const CBLSPublicKey& blsPubKey) const;
void SetConfirmedHeight(int nConfirmedHeightIn) { nConfirmedHeight = nConfirmedHeightIn; }
bool IsExpired(int nHeight);

View File

@ -244,7 +244,7 @@ UniValue gobject_submit(const JSONRPCRequest& request)
bool fMnFound = mnodeman.Has(activeMasternodeInfo.outpoint);
DBG( std::cout << "gobject: submit activeMasternodeInfo.keyIDOperator = " << activeMasternodeInfo.keyIDOperator.ToString()
DBG( std::cout << "gobject: submit activeMasternodeInfo.keyIDOperator = " << activeMasternodeInfo.legacyKeyIDOperator.ToString()
<< ", outpoint = " << activeMasternodeInfo.outpoint.ToStringShort()
<< ", params.size() = " << request.params.size()
<< ", fMnFound = " << fMnFound << std::endl; );
@ -294,7 +294,11 @@ UniValue gobject_submit(const JSONRPCRequest& request)
if (govobj.GetObjectType() == GOVERNANCE_OBJECT_TRIGGER) {
if (fMnFound) {
govobj.SetMasternodeOutpoint(activeMasternodeInfo.outpoint);
govobj.Sign(activeMasternodeInfo.keyOperator, activeMasternodeInfo.keyIDOperator);
if (deterministicMNManager->IsDeterministicMNsSporkActive()) {
govobj.Sign(*activeMasternodeInfo.blsKeyOperator);
} else {
govobj.Sign(activeMasternodeInfo.legacyKeyOperator, activeMasternodeInfo.legacyKeyIDOperator);
}
} else {
LogPrintf("gobject(submit) -- Object submission rejected because node is not a masternode\n");
throw JSONRPCError(RPC_INVALID_PARAMETER, "Only valid masternodes can submit this type of object");
@ -353,6 +357,10 @@ UniValue gobject_vote_conf(const JSONRPCRequest& request)
if (request.fHelp || request.params.size() != 4)
gobject_vote_conf_help();
if(deterministicMNManager->IsDeterministicMNsSporkActive()) {
throw JSONRPCError(RPC_INVALID_PARAMETER, "Can't use vote-conf when deterministic masternodes are active");
}
uint256 hash;
hash = ParseHashV(request.params[1], "Object hash");
@ -402,20 +410,8 @@ UniValue gobject_vote_conf(const JSONRPCRequest& request)
return returnObj;
}
if (deterministicMNManager->IsDeterministicMNsSporkActive()) {
if (govObjType == GOVERNANCE_OBJECT_PROPOSAL && mn.keyIDVoting != activeMasternodeInfo.keyIDOperator) {
nFailed++;
statusObj.push_back(Pair("result", "failed"));
statusObj.push_back(Pair("errorMessage", "Can't vote on proposal when operator key does not match voting key"));
resultsObj.push_back(Pair("dash.conf", statusObj));
returnObj.push_back(Pair("overall", strprintf("Voted successfully %d time(s) and failed %d time(s).", nSuccessful, nFailed)));
returnObj.push_back(Pair("detail", resultsObj));
return returnObj;
}
}
CGovernanceVote vote(mn.outpoint, hash, eVoteSignal, eVoteOutcome);
if (!vote.Sign(activeMasternodeInfo.keyOperator, activeMasternodeInfo.keyIDOperator)) {
if (!vote.Sign(activeMasternodeInfo.legacyKeyOperator, activeMasternodeInfo.legacyKeyIDOperator)) {
nFailed++;
statusObj.push_back(Pair("result", "failed"));
statusObj.push_back(Pair("errorMessage", "Failure to sign."));

View File

@ -1063,7 +1063,7 @@ UniValue masternodelist(const JSONRPCRequest& request)
obj.push_back(Pair(strOutpoint, HexStr(mn.keyIDOwner)));
} else if (strMode == "keyIDOperator") {
if (strFilter !="" && strOutpoint.find(strFilter) == std::string::npos) continue;
obj.push_back(Pair(strOutpoint, HexStr(mn.keyIDOperator)));
obj.push_back(Pair(strOutpoint, HexStr(mn.legacyKeyIDOperator)));
} else if (strMode == "keyIDVoting") {
if (strFilter !="" && strOutpoint.find(strFilter) == std::string::npos) continue;
obj.push_back(Pair(strOutpoint, HexStr(mn.keyIDVoting)));
@ -1248,7 +1248,7 @@ UniValue masternodebroadcast(const JSONRPCRequest& request)
resultObj.push_back(Pair("outpoint", mnb.outpoint.ToStringShort()));
resultObj.push_back(Pair("addr", mnb.addr.ToString()));
resultObj.push_back(Pair("keyIDCollateralAddress", CBitcoinAddress(mnb.keyIDCollateralAddress).ToString()));
resultObj.push_back(Pair("keyIDMasternode", CBitcoinAddress(mnb.keyIDOperator).ToString()));
resultObj.push_back(Pair("keyIDMasternode", CBitcoinAddress(mnb.legacyKeyIDOperator).ToString()));
resultObj.push_back(Pair("vchSig", EncodeBase64(&mnb.vchSig[0], mnb.vchSig.size())));
resultObj.push_back(Pair("sigTime", mnb.sigTime));
resultObj.push_back(Pair("protocolVersion", mnb.nProtocolVersion));

View File

@ -22,6 +22,8 @@
#include "evo/deterministicmns.h"
#include "evo/simplifiedmns.h"
#include "bls/bls.h"
#ifdef ENABLE_WALLET
extern UniValue signrawtransaction(const JSONRPCRequest& request);
extern UniValue sendrawtransaction(const JSONRPCRequest& request);
@ -57,15 +59,33 @@ static CKeyID ParsePubKeyIDFromAddress(const std::string& strAddress, const std:
return keyID;
}
static CBLSPublicKey ParseBLSPubKey(const std::string& hexKey, const std::string& paramName)
{
auto binKey = ParseHex(hexKey);
CBLSPublicKey pubKey;
pubKey.SetBuf(binKey);
if (!pubKey.IsValid()) {
throw JSONRPCError(RPC_INVALID_PARAMETER, strprintf("%s must be a valid BLS address, not %s", paramName, hexKey));
}
return pubKey;
}
static CBLSSecretKey ParseBLSSecretKey(const std::string& hexKey, const std::string& paramName)
{
auto binKey = ParseHex(hexKey);
CBLSSecretKey secKey;
secKey.SetBuf(binKey);
if (!secKey.IsValid()) {
throw JSONRPCError(RPC_INVALID_PARAMETER, strprintf("%s must be a valid BLS secret key", paramName));
}
return secKey;
}
#ifdef ENABLE_WALLET
template<typename SpecialTxPayload>
static void FundSpecialTx(CMutableTransaction& tx, SpecialTxPayload payload)
{
// resize so that fee calculation is correct
payload.vchSig.resize(65);
CDataStream ds(SER_NETWORK, PROTOCOL_VERSION);
ds << payload;
tx.vExtraPayload.assign(ds.begin(), ds.end());
@ -107,6 +127,15 @@ static void SignSpecialTxPayload(const CMutableTransaction& tx, SpecialTxPayload
}
}
template<typename SpecialTxPayload>
static void SignSpecialTxPayload(const CMutableTransaction& tx, SpecialTxPayload& payload, const CBLSSecretKey& key)
{
payload.inputsHash = CalcTxInputsHash(tx);
uint256 hash = ::SerializeHash(payload);
payload.sig = key.Sign(hash);
}
static std::string SignAndSendSpecialTx(const CMutableTransaction& tx)
{
LOCK(cs_main);
@ -160,7 +189,7 @@ void protx_register_help()
"9. \"payoutAddress\" (string, required) The dash address to use for masternode reward payments\n"
" Must match \"collateralAddress\"."
"\nExamples:\n"
+ HelpExampleCli("protx", "register \"XwnLY9Tf7Zsef8gMGL2fhWA9ZmMjt4KPwG\" 1000 \"1.2.3.4:1234\" 0 \"93Fd7XY2zF4q9YKTZUSFxLgp4Xs7MuaMnvY9kpvH7V8oXWqsCC1\" XwnLY9Tf7Zsef8gMGL2fhWA9ZmMjt4KPwG")
+ HelpExampleCli("protx", "register \"XrVhS9LogauRJGJu2sHuryjhpuex4RNPSb\" 1000 \"1.2.3.4:1234\" 0 \"Xt9AMWaYSz7tR7Uo7gzXA3m4QmeWgrR3rr\" \"Xt9AMWaYSz7tR7Uo7gzXA3m4QmeWgrR3rr\" \"Xt9AMWaYSz7tR7Uo7gzXA3m4QmeWgrR3rr\" 0 \"XrVhS9LogauRJGJu2sHuryjhpuex4RNPSb\"")
);
}
@ -200,11 +229,8 @@ UniValue protx_register(const JSONRPCRequest& request)
ptx.nProtocolVersion = PROTOCOL_VERSION;
CKey keyOwner = ParsePrivKey(request.params[5].get_str(), true);
CKeyID keyIDOperator = keyOwner.GetPubKey().GetID();
CBLSPublicKey pubKeyOperator = ParseBLSPubKey(request.params[6].get_str(), "operator BLS address");
CKeyID keyIDVoting = keyOwner.GetPubKey().GetID();
if (request.params[6].get_str() != "0" && request.params[6].get_str() != "") {
keyIDOperator = ParsePubKeyIDFromAddress(request.params[6].get_str(), "operator address");
}
if (request.params[7].get_str() != "0" && request.params[7].get_str() != "") {
keyIDVoting = ParsePubKeyIDFromAddress(request.params[7].get_str(), "voting address");
}
@ -219,10 +245,11 @@ UniValue protx_register(const JSONRPCRequest& request)
throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, strprintf("invalid payout address: %s", request.params[9].get_str()));
ptx.keyIDOwner = keyOwner.GetPubKey().GetID();
ptx.keyIDOperator = keyIDOperator;
ptx.pubKeyOperator = pubKeyOperator;
ptx.keyIDVoting = keyIDVoting;
ptx.scriptPayout = GetScriptForDestination(payoutAddress.Get());
SignSpecialTxPayload(tx, ptx, keyOwner); // make sure sig is set, otherwise fee calculation won't be correct
FundSpecialTx(tx, ptx);
uint32_t collateralIndex = (uint32_t) - 1;
@ -235,7 +262,7 @@ UniValue protx_register(const JSONRPCRequest& request)
assert(collateralIndex != (uint32_t) - 1);
ptx.nCollateralIndex = collateralIndex;
SignSpecialTxPayload(tx, ptx, keyOwner);
SignSpecialTxPayload(tx, ptx, keyOwner); // redo signing
SetTxPayload(tx, ptx);
return SignAndSendSpecialTx(tx);
@ -244,7 +271,7 @@ UniValue protx_register(const JSONRPCRequest& request)
void protx_update_service_help()
{
throw std::runtime_error(
"protx update_service \"proTxHash\" \"ipAndPort\" protocolVersion (\"operatorPayoutAddress\")\n"
"protx update_service \"proTxHash\" \"ipAndPort\" protocolVersion \"operatorKey\" (\"operatorPayoutAddress\")\n"
"\nCreates and sends a ProUpServTx to the network. This will update the address and protocol version\n"
"of a masternode. The operator key of the masternode must be known to your wallet.\n"
"If this is done for a masternode that got PoSe-banned, the ProUpServTx will also revive this masternode.\n"
@ -254,10 +281,12 @@ void protx_update_service_help()
" Must be unique on the network.\n"
"3. \"protocolVersion\" (numeric, required) The protocol version of your masternode.\n"
" Can be 0 to default to the clients protocol version\n"
"4. \"operatorPayoutAddress\" (string, optional) The address used for operator reward payments.\n"
"4. \"operatorKey\" (string, required) The operator private key belonging to the\n"
" registered operator public key.\n"
"5. \"operatorPayoutAddress\" (string, optional) The address used for operator reward payments.\n"
" Only allowed when the ProRegTx had a non-zero operatorReward value.\n"
"\nExamples:\n"
+ HelpExampleCli("protx", "update_service \"0123456701234567012345670123456701234567012345670123456701234567\" \"1.2.3.4:1234\" 0")
+ HelpExampleCli("protx", "update_service \"0123456701234567012345670123456701234567012345670123456701234567\" \"1.2.3.4:1234\" 0 5a2e15982e62f1e0b7cf9783c64cf7e3af3f90a52d6c40f6f95d624c0b1621cd")
);
}
@ -279,8 +308,10 @@ UniValue protx_update_service(const JSONRPCRequest& request)
ptx.nProtocolVersion = PROTOCOL_VERSION;
}
if (request.params.size() > 4) {
CBitcoinAddress payoutAddress(request.params[4].get_str());
CBLSSecretKey keyOperator = ParseBLSSecretKey(request.params[4].get_str(), "operatorKey");
if (request.params.size() > 5) {
CBitcoinAddress payoutAddress(request.params[5].get_str());
if (!payoutAddress.IsValid())
throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, strprintf("invalid operator payout address: %s", request.params[4].get_str()));
ptx.scriptOperatorPayout = GetScriptForDestination(payoutAddress.Get());
@ -291,9 +322,8 @@ UniValue protx_update_service(const JSONRPCRequest& request)
throw std::runtime_error(strprintf("masternode with proTxHash %s not found", ptx.proTxHash.ToString()));
}
CKey keyOperator;
if (!pwalletMain->GetKey(dmn->pdmnState->keyIDOperator, keyOperator)) {
throw std::runtime_error(strprintf("operator key %s not found in your wallet", dmn->pdmnState->keyIDOperator.ToString()));
if (keyOperator.GetPublicKey() != dmn->pdmnState->pubKeyOperator) {
throw JSONRPCError(RPC_INVALID_PARAMETER, strprintf("the operator key does not belong to the registered public key"));
}
CMutableTransaction tx;
@ -316,7 +346,7 @@ void protx_update_registrar_help()
"The owner key of the masternode must be known to your wallet.\n"
"\nArguments:\n"
"1. \"proTxHash\" (string, required) The hash of the initial ProRegTx.\n"
"2. \"operatorKeyAddr\" (string, required) The operator key address. The private key does not have to be known by your wallet.\n"
"2. \"operatorPubKey\" (string, required) The operator public key. The private key does not have to be known by you.\n"
" It has to match the private key which is later used when operating the masternode.\n"
" If set to \"0\" or an empty string, the last on-chain operator key of the masternode will be used.\n"
"3. \"votingKeyAddr\" (string, required) The voting key address. The private key does not have to be known by your wallet.\n"
@ -326,7 +356,7 @@ void protx_update_registrar_help()
" Must match \"collateralAddress\" of initial ProRegTx.\n"
" If set to \"0\" or an empty string, the last on-chain payout address of the masternode will be used.\n"
"\nExamples:\n"
+ HelpExampleCli("protx", "update_registrar \"0123456701234567012345670123456701234567012345670123456701234567\" \"<operatorKeyAddr>\" \"0\" \"XwnLY9Tf7Zsef8gMGL2fhWA9ZmMjt4KPwG\"")
+ HelpExampleCli("protx", "update_registrar \"0123456701234567012345670123456701234567012345670123456701234567\" \"982eb34b7c7f614f29e5c665bc3605f1beeef85e3395ca12d3be49d2868ecfea5566f11cedfad30c51b2403f2ad95b67\" \"0\" \"XwnLY9Tf7Zsef8gMGL2fhWA9ZmMjt4KPwG\"")
);
}
@ -343,12 +373,12 @@ UniValue protx_update_registrar(const JSONRPCRequest& request)
if (!dmn) {
throw JSONRPCError(RPC_INVALID_PARAMETER, strprintf("masternode %s not found", ptx.proTxHash.ToString()));
}
ptx.keyIDOperator = dmn->pdmnState->keyIDOperator;
ptx.pubKeyOperator = dmn->pdmnState->pubKeyOperator;
ptx.keyIDVoting = dmn->pdmnState->keyIDVoting;
ptx.scriptPayout = dmn->pdmnState->scriptPayout;
if (request.params[2].get_str() != "0" && request.params[2].get_str() != "") {
ptx.keyIDOperator = ParsePubKeyIDFromAddress(request.params[2].get_str(), "operator address");
ptx.pubKeyOperator = ParseBLSPubKey(request.params[2].get_str(), "operator BLS address");
}
if (request.params[3].get_str() != "0" && request.params[3].get_str() != "") {
ptx.keyIDVoting = ParsePubKeyIDFromAddress(request.params[3].get_str(), "operator address");
@ -386,9 +416,11 @@ void protx_revoke_help()
"The operator key of the masternode must be known to your wallet.\n"
"\nArguments:\n"
"1. \"proTxHash\" (string, required) The hash of the initial ProRegTx.\n"
"2. reason (numeric, optional) The reason for revocation.\n"
"2. \"operatorKey\" (string, required) The operator private key belonging to the\n"
" registered operator public key.\n"
"3. reason (numeric, optional) The reason for revocation.\n"
"\nExamples:\n"
+ HelpExampleCli("protx", "revoke \"0123456701234567012345670123456701234567012345670123456701234567\" \"<operatorKeyAddr>\"")
+ HelpExampleCli("protx", "revoke \"0123456701234567012345670123456701234567012345670123456701234567\" \"072f36a77261cdd5d64c32d97bac417540eddca1d5612f416feb07ff75a8e240\"")
);
}
@ -401,8 +433,10 @@ UniValue protx_revoke(const JSONRPCRequest& request)
ptx.nVersion = CProRegTx::CURRENT_VERSION;
ptx.proTxHash = ParseHashV(request.params[1], "proTxHash");
if (request.params.size() > 2) {
int32_t nReason = ParseInt32V(request.params[2], "reason");
CBLSSecretKey keyOperator = ParseBLSSecretKey(request.params[2].get_str(), "operatorKey");
if (request.params.size() > 3) {
int32_t nReason = ParseInt32V(request.params[3], "reason");
if (nReason < 0 || nReason >= CProUpRevTx::REASON_LAST)
throw JSONRPCError(RPC_INVALID_PARAMETER, strprintf("invalid reason %d, must be between 0 and %d", nReason, CProUpRevTx::REASON_LAST));
ptx.nReason = (uint16_t)nReason;
@ -413,9 +447,8 @@ UniValue protx_revoke(const JSONRPCRequest& request)
throw JSONRPCError(RPC_INVALID_PARAMETER, strprintf("masternode %s not found", ptx.proTxHash.ToString()));
}
CKey keyOperator;
if (!pwalletMain->GetKey(dmn->pdmnState->keyIDOperator, keyOperator)) {
throw std::runtime_error(strprintf("operator key %s not found in your wallet", dmn->pdmnState->keyIDOwner.ToString()));
if (keyOperator.GetPublicKey() != dmn->pdmnState->pubKeyOperator) {
throw JSONRPCError(RPC_INVALID_PARAMETER, strprintf("the operator key does not belong to the registered public key"));
}
CMutableTransaction tx;
@ -471,7 +504,7 @@ UniValue BuildDMNListEntry(const CDeterministicMNCPtr& dmn, bool detailed)
o.push_back(Pair("confirmations", confirmations));
bool hasOwnerKey = pwalletMain->HaveKey(dmn->pdmnState->keyIDOwner);
bool hasOperatorKey = pwalletMain->HaveKey(dmn->pdmnState->keyIDOperator);
bool hasOperatorKey = false; //pwalletMain->HaveKey(dmn->pdmnState->keyIDOperator);
bool hasVotingKey = pwalletMain->HaveKey(dmn->pdmnState->keyIDVoting);
bool ownsCollateral = false;
@ -522,7 +555,6 @@ UniValue protx_list(const JSONRPCRequest& request)
deterministicMNManager->GetListAtChainTip().ForEachMN(false, [&](const CDeterministicMNCPtr& dmn) {
if (setOutpts.count(dmn->proTxHash) ||
pwalletMain->HaveKey(dmn->pdmnState->keyIDOwner) ||
pwalletMain->HaveKey(dmn->pdmnState->keyIDOperator) ||
pwalletMain->HaveKey(dmn->pdmnState->keyIDVoting) ||
CheckWalletOwnsScript(dmn->pdmnState->scriptPayout) ||
CheckWalletOwnsScript(dmn->pdmnState->scriptOperatorPayout)) {
@ -646,9 +678,38 @@ UniValue protx(const JSONRPCRequest& request)
}
#endif//ENABLE_WALLET
UniValue bls_generate(const JSONRPCRequest& request)
{
CBLSSecretKey sk;
sk.MakeNewKey();
UniValue ret(UniValue::VOBJ);
ret.push_back(Pair("secret", sk.ToString()));
ret.push_back(Pair("public", sk.GetPublicKey().ToString()));
return ret;
}
UniValue _bls(const JSONRPCRequest& request)
{
if (request.params.empty()) {
throw std::runtime_error(
"bls \"command\" ...\n"
);
}
std::string command = request.params[0].get_str();
if (command == "generate") {
return bls_generate(request);
} else {
throw std::runtime_error("invalid command: " + command);
}
}
static const CRPCCommand commands[] =
{ // category name actor (function) okSafeMode
// --------------------- ------------------------ ----------------------- ----------
{ "evo", "bls", &_bls, false, {} },
#ifdef ENABLE_WALLET
// these require the wallet to be enabled to fund the transactions
{ "evo", "protx", &protx, false, {} },

View File

@ -94,9 +94,10 @@ static void SignTransaction(CMutableTransaction& tx, const CKey& coinbaseKey)
}
}
static CMutableTransaction CreateProRegTx(SimpleUTXOMap& utxos, int port, const CScript& scriptPayout, const CKey& coinbaseKey, CKey& mnKeyRet)
static CMutableTransaction CreateProRegTx(SimpleUTXOMap& utxos, int port, const CScript& scriptPayout, const CKey& coinbaseKey, CKey& ownerKeyRet, CBLSSecretKey& operatorKeyRet)
{
mnKeyRet.MakeNewKey(true);
ownerKeyRet.MakeNewKey(true);
operatorKeyRet.MakeNewKey();
CAmount change;
auto inputs = SelectUTXOs(utxos, 1000 * COIN, change);
@ -105,9 +106,9 @@ static CMutableTransaction CreateProRegTx(SimpleUTXOMap& utxos, int port, const
proTx.nProtocolVersion = PROTOCOL_VERSION;
proTx.nCollateralIndex = 0;
proTx.addr = LookupNumeric("1.1.1.1", port);
proTx.keyIDOwner = mnKeyRet.GetPubKey().GetID();
proTx.keyIDOperator = mnKeyRet.GetPubKey().GetID();
proTx.keyIDVoting = mnKeyRet.GetPubKey().GetID();
proTx.keyIDOwner = ownerKeyRet.GetPubKey().GetID();
proTx.pubKeyOperator = operatorKeyRet.GetPublicKey();
proTx.keyIDVoting = ownerKeyRet.GetPubKey().GetID();
proTx.scriptPayout = scriptPayout;
CMutableTransaction tx;
@ -115,14 +116,14 @@ static CMutableTransaction CreateProRegTx(SimpleUTXOMap& utxos, int port, const
tx.nType = TRANSACTION_PROVIDER_REGISTER;
FundTransaction(tx, utxos, scriptPayout, 1000 * COIN, coinbaseKey);
proTx.inputsHash = CalcTxInputsHash(tx);
CHashSigner::SignHash(::SerializeHash(proTx), mnKeyRet, proTx.vchSig);
CHashSigner::SignHash(::SerializeHash(proTx), ownerKeyRet, proTx.vchSig);
SetTxPayload(tx, proTx);
SignTransaction(tx, coinbaseKey);
return tx;
}
static CMutableTransaction CreateProUpServTx(SimpleUTXOMap& utxos, const uint256& proTxHash, const CKey& mnKey, int port, const CScript& scriptOperatorPayout, const CKey& coinbaseKey)
static CMutableTransaction CreateProUpServTx(SimpleUTXOMap& utxos, const uint256& proTxHash, const CBLSSecretKey& operatorKey, int port, const CScript& scriptOperatorPayout, const CKey& coinbaseKey)
{
CAmount change;
auto inputs = SelectUTXOs(utxos, 1 * COIN, change);
@ -138,21 +139,21 @@ static CMutableTransaction CreateProUpServTx(SimpleUTXOMap& utxos, const uint256
tx.nType = TRANSACTION_PROVIDER_UPDATE_SERVICE;
FundTransaction(tx, utxos, GetScriptForDestination(coinbaseKey.GetPubKey().GetID()), 1 * COIN, coinbaseKey);
proTx.inputsHash = CalcTxInputsHash(tx);
CHashSigner::SignHash(::SerializeHash(proTx), mnKey, proTx.vchSig);
proTx.sig = operatorKey.Sign(::SerializeHash(proTx));
SetTxPayload(tx, proTx);
SignTransaction(tx, coinbaseKey);
return tx;
}
static CMutableTransaction CreateProUpRegTx(SimpleUTXOMap& utxos, const uint256& proTxHash, const CKey& mnKey, const CKeyID& keyIDOperator, const CKeyID& keyIDVoting, const CScript& scriptPayout, const CKey& coinbaseKey)
static CMutableTransaction CreateProUpRegTx(SimpleUTXOMap& utxos, const uint256& proTxHash, const CKey& mnKey, const CBLSPublicKey& pubKeyOperator, const CKeyID& keyIDVoting, const CScript& scriptPayout, const CKey& coinbaseKey)
{
CAmount change;
auto inputs = SelectUTXOs(utxos, 1 * COIN, change);
CProUpRegTx proTx;
proTx.proTxHash = proTxHash;
proTx.keyIDOperator = keyIDOperator;
proTx.pubKeyOperator = pubKeyOperator;
proTx.keyIDVoting = keyIDVoting;
proTx.scriptPayout = scriptPayout;
@ -168,7 +169,7 @@ static CMutableTransaction CreateProUpRegTx(SimpleUTXOMap& utxos, const uint256&
return tx;
}
static CMutableTransaction CreateProUpRevTx(SimpleUTXOMap& utxos, const uint256& proTxHash, const CKey& mnKey, const CKey& coinbaseKey)
static CMutableTransaction CreateProUpRevTx(SimpleUTXOMap& utxos, const uint256& proTxHash, const CBLSSecretKey& operatorKey, const CKey& coinbaseKey)
{
CAmount change;
auto inputs = SelectUTXOs(utxos, 1 * COIN, change);
@ -181,7 +182,7 @@ static CMutableTransaction CreateProUpRevTx(SimpleUTXOMap& utxos, const uint256&
tx.nType = TRANSACTION_PROVIDER_UPDATE_REVOKE;
FundTransaction(tx, utxos, GetScriptForDestination(coinbaseKey.GetPubKey().GetID()), 1 * COIN, coinbaseKey);
proTx.inputsHash = CalcTxInputsHash(tx);
CHashSigner::SignHash(::SerializeHash(proTx), mnKey, proTx.vchSig);
proTx.sig = operatorKey.Sign(::SerializeHash(proTx));
SetTxPayload(tx, proTx);
SignTransaction(tx, coinbaseKey);
@ -218,8 +219,9 @@ BOOST_AUTO_TEST_SUITE(evo_dip3_activation_tests)
BOOST_FIXTURE_TEST_CASE(dip3_activation, TestChainDIP3BeforeActivationSetup)
{
auto utxos = BuildSimpleUtxoMap(coinbaseTxns);
CKey mnKey;
auto tx = CreateProRegTx(utxos, 1, GetScriptForDestination(payoutAddress.Get()), coinbaseKey, mnKey);
CKey ownerKey;
CBLSSecretKey operatorKey;
auto tx = CreateProRegTx(utxos, 1, GetScriptForDestination(payoutAddress.Get()), coinbaseKey, ownerKey, operatorKey);
std::vector<CMutableTransaction> txns = {tx};
int nHeight = chainActive.Height();
@ -260,14 +262,17 @@ BOOST_FIXTURE_TEST_CASE(dip3_protx, TestChainDIP3Setup)
int port = 1;
std::vector<uint256> dmnHashes;
std::map<uint256, CKey> mnKeys;
std::map<uint256, CKey> ownerKeys;
std::map<uint256, CBLSSecretKey> operatorKeys;
// register one MN per block
for (size_t i = 0; i < 6; i++) {
CKey mnKey;
auto tx = CreateProRegTx(utxos, port++, GenerateRandomAddress(), coinbaseKey, mnKey);
CKey ownerKey;
CBLSSecretKey operatorKey;
auto tx = CreateProRegTx(utxos, port++, GenerateRandomAddress(), coinbaseKey, ownerKey, operatorKey);
dmnHashes.emplace_back(tx.GetHash());
mnKeys.emplace(tx.GetHash(), mnKey);
ownerKeys.emplace(tx.GetHash(), ownerKey);
operatorKeys.emplace(tx.GetHash(), operatorKey);
CreateAndProcessBlock({tx}, coinbaseKey);
deterministicMNManager->UpdatedBlockTip(chainActive.Tip());
@ -302,10 +307,12 @@ BOOST_FIXTURE_TEST_CASE(dip3_protx, TestChainDIP3Setup)
for (size_t i = 0; i < 3; i++) {
std::vector<CMutableTransaction> txns;
for (size_t j = 0; j < 3; j++) {
CKey mnKey;
auto tx = CreateProRegTx(utxos, port++, GenerateRandomAddress(), coinbaseKey, mnKey);
CKey ownerKey;
CBLSSecretKey operatorKey;
auto tx = CreateProRegTx(utxos, port++, GenerateRandomAddress(), coinbaseKey, ownerKey, operatorKey);
dmnHashes.emplace_back(tx.GetHash());
mnKeys.emplace(tx.GetHash(), mnKey);
ownerKeys.emplace(tx.GetHash(), ownerKey);
operatorKeys.emplace(tx.GetHash(), operatorKey);
txns.emplace_back(tx);
}
CreateAndProcessBlock(txns, coinbaseKey);
@ -320,7 +327,7 @@ BOOST_FIXTURE_TEST_CASE(dip3_protx, TestChainDIP3Setup)
}
// test ProUpServTx
auto tx = CreateProUpServTx(utxos, dmnHashes[0], mnKeys[dmnHashes[0]], 1000, CScript(), coinbaseKey);
auto tx = CreateProUpServTx(utxos, dmnHashes[0], operatorKeys[dmnHashes[0]], 1000, CScript(), coinbaseKey);
CreateAndProcessBlock({tx}, coinbaseKey);
deterministicMNManager->UpdatedBlockTip(chainActive.Tip());
BOOST_ASSERT(chainActive.Height() == nHeight + 1);
@ -330,7 +337,7 @@ BOOST_FIXTURE_TEST_CASE(dip3_protx, TestChainDIP3Setup)
BOOST_ASSERT(dmn != nullptr && dmn->pdmnState->addr.GetPort() == 1000);
// test ProUpRevTx
tx = CreateProUpRevTx(utxos, dmnHashes[0], mnKeys[dmnHashes[0]], coinbaseKey);
tx = CreateProUpRevTx(utxos, dmnHashes[0], operatorKeys[dmnHashes[0]], coinbaseKey);
CreateAndProcessBlock({tx}, coinbaseKey);
deterministicMNManager->UpdatedBlockTip(chainActive.Tip());
BOOST_ASSERT(chainActive.Height() == nHeight + 1);
@ -356,10 +363,10 @@ BOOST_FIXTURE_TEST_CASE(dip3_protx, TestChainDIP3Setup)
}
// test reviving the MN
CKey newOperatorKey;
newOperatorKey.MakeNewKey(false);
CBLSSecretKey newOperatorKey;
newOperatorKey.MakeNewKey();
dmn = deterministicMNManager->GetListAtChainTip().GetMN(dmnHashes[0]);
tx = CreateProUpRegTx(utxos, dmnHashes[0], mnKeys[dmnHashes[0]], newOperatorKey.GetPubKey().GetID(), newOperatorKey.GetPubKey().GetID(), dmn->pdmnState->scriptPayout, coinbaseKey);
tx = CreateProUpRegTx(utxos, dmnHashes[0], ownerKeys[dmnHashes[0]], newOperatorKey.GetPublicKey(), ownerKeys[dmnHashes[0]].GetPubKey().GetID(), dmn->pdmnState->scriptPayout, coinbaseKey);
CreateAndProcessBlock({tx}, coinbaseKey);
deterministicMNManager->UpdatedBlockTip(chainActive.Tip());
BOOST_ASSERT(chainActive.Height() == nHeight + 1);

View File

@ -4,6 +4,7 @@
#include "test/test_dash.h"
#include "bls/bls.h"
#include "evo/simplifiedmns.h"
#include "netbase.h"
@ -21,7 +22,13 @@ BOOST_AUTO_TEST_CASE(simplifiedmns_merkleroots)
std::string ip = strprintf("%d.%d.%d.%d", 0, 0, 0, i);
Lookup(ip.c_str(), smle.service, i, false);
smle.keyIDOperator.SetHex(strprintf("%040x", i));
uint8_t skBuf[CBLSSecretKey::SerSize];
memset(skBuf, 0, sizeof(skBuf));
skBuf[0] = (uint8_t)i;
CBLSSecretKey sk;
sk.SetBuf(skBuf, sizeof(skBuf));
smle.pubKeyOperator = sk.GetPublicKey();
smle.keyIDVoting.SetHex(strprintf("%040x", i));
smle.isValid = true;
@ -29,21 +36,21 @@ BOOST_AUTO_TEST_CASE(simplifiedmns_merkleroots)
}
std::vector<std::string> expectedHashes = {
"aa8bfb825f433bcd6f1039f27c77ed269386e05577b0fe9afc4e16b1af0076b2",
"686a19dba9b515f77f11027cd1e92e6a8c650448bf4616101fd5ddbe6e2629e7",
"c2efc1b08daa791c71e1d5887be3eaa136381f783fcc5b7efdc5909db38701bb",
"ce394197d6e1684467fbf2e1619f71ae9d1a6cf6548b2235e4289f95d4bccbbd",
"aeeaf7b498aa7d5fa92ee0028499b4f165c31662f5e9b0a80e6e13b38fd61f8d",
"0c1c8dc9dc82eb5432a557580e5d3d930943ce0d0db5daebc51267afb46b6d48",
"1c4add10ea844a46734473e48c2f781059b35382219d0cf67d6432b540e0bbbe",
"1ae1ad5ff4dd4c09469d21d569a025d467dca1e407581a2815175528e139b7da",
"d59b231cdc80ce7eda3a3f37608abda818659c189d31a7ef42024d496e290cbc",
"2d5e6c87e3d4e5b3fdd600f561e8dec1ea720560569398006050480232f1257c",
"3d6af35f08efeea22f3c8fcb78038e56dac221f3173ca4e2230ea8ae3cbd3c60",
"ecf547077c37b79da954c4ef46a3c4fb136746366bfb81192ed01de96fd66348",
"626af5fb8192ead7bbd79ad7bfe2c3ea82714fdfd9ac49b88d7a411aa6956853",
"6c84a4485fb2ba35b4dcd4d89cbdd3d813446514bb7a2046b6b1b9813beaac0f",
"453ca2a83140da73a37794fe6fddd701ea5066f21c2f1df8a33b6ff6134043c3",
"1465924a81df1d0fb46d2571e65296c0fddab30d1b4d104f182f80a6e45362fa",
"cb466084403067b699a50bd46e53145ebfd57af9a076a13432f524e41ec2d899",
"0f6a720d0119f5b83469d884ec2a7d739c1d653142e5d36b569cddaf735a6149",
"8794379559c77d67902a5e894739bd574f25ff6cd48612f7156c5fafaefefd4e",
"4738d4f17c76b4e61f028d9426f40242eb56977fe805704d980ff57ad3f60b90",
"6342b7ce87a299a0fb070ec040a45613f082b0c99395698a6f712e85be87ad06",
"0be7143f4fb357333350a7e28606713933e9819c83c71009b9ea97476d86b78e",
"d13dfedc920490a8c6d9b555d740f2944ac83eeb8c3923a51261371a8118ffe0",
"c0c4638fcefe09380adff61d59c064be03a18690245b89be20223df737590d46",
"4cce41032bb341adb9b9f3f6ba1de3c812f0d1630e3a561c7aae00f39e49c6d4",
"3e8c9ad9e2cf0520a96b6bc58aafb7009365a1d8f357047a40430b782142ed69",
"bde7a1b61a263a7e0dfe474c850c4f9d642d9a03da501a366800e03093e48cd9",
"e221a3e14868251083eea718e698cc81739b016665a9024d798a14c0e9417c35",
"b1be038e40bc8ee6a19dbbe70c92d7bc0880ccc54c4bd54eab6b7a30d0650ab1",
"0607e1d850e27c336e8d65722fc82eae7ab5331fd88a4fbfcff6c3a1bb6364da",
};
std::vector<std::string> calculatedHashes;
@ -56,8 +63,9 @@ BOOST_AUTO_TEST_CASE(simplifiedmns_merkleroots)
CSimplifiedMNList sml(entries);
std::string expectedMerkleRoot = "926efc8dc7b5b060254b102670b918133fea67c5e1bc2703d596e49672878c22";
std::string expectedMerkleRoot = "a7fae13820022ddba6cf54ba9b234dfed54ccfa86c2635c5627287f1ffa5497f";
std::string calculatedMerkleRoot = sml.CalcMerkleRoot(nullptr).ToString();
//printf("merkleRoot=\"%s\",\n", calculatedMerkleRoot.c_str());
BOOST_CHECK(expectedMerkleRoot == calculatedMerkleRoot);
}

View File

@ -43,6 +43,7 @@ extern void noui_connect();
BasicTestingSetup::BasicTestingSetup(const std::string& chainName)
{
ECC_Start();
BLSInit();
SetupEnvironment();
SetupNetworking();
InitSignatureCache();

View File

@ -448,7 +448,7 @@ bool CTxMemPool::addUnchecked(const uint256& hash, const CTxMemPoolEntry &entry,
}
mapProTxAddresses.emplace(proTx.addr, tx.GetHash());
mapProTxPubKeyIDs.emplace(proTx.keyIDOwner, tx.GetHash());
mapProTxPubKeyIDs.emplace(proTx.keyIDOperator, tx.GetHash());
mapProTxBlsPubKeyHashes.emplace(proTx.pubKeyOperator.GetHash(), tx.GetHash());
} else if (tx.nType == TRANSACTION_PROVIDER_UPDATE_SERVICE) {
CProUpServTx proTx;
if (!GetTxPayload(tx, proTx)) {
@ -460,7 +460,7 @@ bool CTxMemPool::addUnchecked(const uint256& hash, const CTxMemPoolEntry &entry,
if (!GetTxPayload(tx, proTx)) {
assert(false);
}
mapProTxPubKeyIDs.emplace(proTx.keyIDOperator, tx.GetHash());
mapProTxBlsPubKeyHashes.emplace(proTx.pubKeyOperator.GetHash(), tx.GetHash());
}
return true;
@ -645,7 +645,7 @@ void CTxMemPool::removeUnchecked(txiter it, MemPoolRemovalReason reason)
}
mapProTxAddresses.erase(proTx.addr);
mapProTxPubKeyIDs.erase(proTx.keyIDOwner);
mapProTxPubKeyIDs.erase(proTx.keyIDOperator);
mapProTxBlsPubKeyHashes.erase(proTx.pubKeyOperator.GetHash());
} else if (it->GetTx().nType == TRANSACTION_PROVIDER_UPDATE_SERVICE) {
CProUpServTx proTx;
if (!GetTxPayload(it->GetTx(), proTx)) {
@ -657,7 +657,7 @@ void CTxMemPool::removeUnchecked(txiter it, MemPoolRemovalReason reason)
if (!GetTxPayload(it->GetTx(), proTx)) {
assert(false);
}
mapProTxPubKeyIDs.erase(proTx.keyIDOperator);
mapProTxBlsPubKeyHashes.erase(proTx.pubKeyOperator.GetHash());
}
totalTxSize -= it->GetTxSize();
@ -796,6 +796,16 @@ void CTxMemPool::removeProTxPubKeyConflicts(const CTransaction &tx, const CKeyID
}
}
void CTxMemPool::removeProTxPubKeyConflicts(const CTransaction &tx, const CBLSPublicKey &pubKey)
{
if (mapProTxBlsPubKeyHashes.count(pubKey.GetHash())) {
uint256 conflictHash = mapProTxBlsPubKeyHashes[pubKey.GetHash()];
if (conflictHash != tx.GetHash() && mapTx.count(conflictHash)) {
removeRecursive(mapTx.find(conflictHash)->GetTx(), MemPoolRemovalReason::CONFLICT);
}
}
}
void CTxMemPool::removeProTxConflicts(const CTransaction &tx)
{
if (tx.nType == TRANSACTION_PROVIDER_REGISTER) {
@ -811,7 +821,7 @@ void CTxMemPool::removeProTxConflicts(const CTransaction &tx)
}
}
removeProTxPubKeyConflicts(tx, proTx.keyIDOwner);
removeProTxPubKeyConflicts(tx, proTx.keyIDOperator);
removeProTxPubKeyConflicts(tx, proTx.pubKeyOperator);
} else if (tx.nType == TRANSACTION_PROVIDER_UPDATE_SERVICE) {
CProUpServTx proTx;
if (!GetTxPayload(tx, proTx)) {
@ -830,7 +840,7 @@ void CTxMemPool::removeProTxConflicts(const CTransaction &tx)
assert(false);
}
removeProTxPubKeyConflicts(tx, proTx.keyIDOperator);
removeProTxPubKeyConflicts(tx, proTx.pubKeyOperator);
}
}
@ -1117,7 +1127,7 @@ bool CTxMemPool::existsProviderTxConflict(const CTransaction &tx) const {
CProRegTx proTx;
if (!GetTxPayload(tx, proTx))
assert(false);
return mapProTxAddresses.count(proTx.addr) || mapProTxPubKeyIDs.count(proTx.keyIDOwner) || mapProTxPubKeyIDs.count(proTx.keyIDOperator);
return mapProTxAddresses.count(proTx.addr) || mapProTxPubKeyIDs.count(proTx.keyIDOwner) || mapProTxBlsPubKeyHashes.count(proTx.pubKeyOperator.GetHash());
} else if (tx.nType == TRANSACTION_PROVIDER_UPDATE_SERVICE) {
CProUpServTx proTx;
if (!GetTxPayload(tx, proTx))
@ -1128,8 +1138,8 @@ bool CTxMemPool::existsProviderTxConflict(const CTransaction &tx) const {
CProUpRegTx proTx;
if (!GetTxPayload(tx, proTx))
assert(false);
auto it = mapProTxPubKeyIDs.find(proTx.keyIDOperator);
return it != mapProTxPubKeyIDs.end() && it->second != proTx.proTxHash;
auto it = mapProTxBlsPubKeyHashes.find(proTx.pubKeyOperator.GetHash());
return it != mapProTxBlsPubKeyHashes.end() && it->second != proTx.proTxHash;
}
return false;
}

View File

@ -22,6 +22,7 @@
#include "sync.h"
#include "random.h"
#include "netaddress.h"
#include "bls/bls.h"
#undef foreach
#include "boost/multi_index_container.hpp"
@ -535,6 +536,7 @@ private:
std::map<CService, uint256> mapProTxAddresses;
std::map<CKeyID, uint256> mapProTxPubKeyIDs;
std::map<uint256, uint256> mapProTxBlsPubKeyHashes;
void UpdateParent(txiter entry, txiter parent, bool add);
void UpdateChild(txiter entry, txiter child, bool add);
@ -579,6 +581,7 @@ public:
void removeForReorg(const CCoinsViewCache *pcoins, unsigned int nMemPoolHeight, int flags);
void removeConflicts(const CTransaction &tx);
void removeProTxPubKeyConflicts(const CTransaction &tx, const CKeyID &keyId);
void removeProTxPubKeyConflicts(const CTransaction &tx, const CBLSPublicKey &pubKey);
void removeProTxConflicts(const CTransaction &tx);
void removeForBlock(const std::vector<CTransactionRef>& vtx, unsigned int nBlockHeight);