Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[Refactor] MN operator key migration to BLS #2421

Merged
merged 9 commits into from
Oct 8, 2021
3 changes: 3 additions & 0 deletions CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -286,6 +286,9 @@ target_include_directories(WALLET_A PUBLIC ${CMAKE_CURRENT_SOURCE_DIR}/src
${CMAKE_CURRENT_SOURCE_DIR}/src/secp256k1/include
${CMAKE_CURRENT_SOURCE_DIR}/src/univalue/include
${CMAKE_CURRENT_SOURCE_DIR}/src/leveldb/include
${CMAKE_CURRENT_SOURCE_DIR}/src/chiabls/src
${relic_SOURCE_DIR}/include
${relic_BINARY_DIR}/include
${BerkeleyDB_INCLUDE_DIRS}
)

Expand Down
57 changes: 32 additions & 25 deletions src/activemasternode.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@
#include "activemasternode.h"

#include "addrman.h"
#include "bls/bls_wrapper.h"
#include "evo/providertx.h"
#include "masternode-sync.h"
#include "masternode.h"
Expand Down Expand Up @@ -54,19 +55,19 @@ std::string CActiveDeterministicMasternodeManager::GetStatus() const

OperationResult CActiveDeterministicMasternodeManager::SetOperatorKey(const std::string& strMNOperatorPrivKey)
{

LOCK(cs_main); // Lock cs_main so the node doesn't perform any action while we setup the Masternode
LogPrintf("Initializing deterministic masternode...\n");
if (strMNOperatorPrivKey.empty()) {
return errorOut("ERROR: Masternode operator priv key cannot be empty.");
}
if (!CMessageSigner::GetKeysFromSecret(strMNOperatorPrivKey, info.keyOperator, info.keyIDOperator)) {
if (!info.keyOperator.SetHexStr(strMNOperatorPrivKey)) {
return errorOut(_("Invalid mnoperatorprivatekey. Please see the documentation."));
}
info.pubKeyOperator = info.keyOperator.GetPublicKey();
return OperationResult(true);
}

OperationResult CActiveDeterministicMasternodeManager::GetOperatorKey(CKey& key, CKeyID& keyID, CDeterministicMNCPtr& dmn) const
OperationResult CActiveDeterministicMasternodeManager::GetOperatorKey(CBLSSecretKey& key, CDeterministicMNCPtr& dmn) const
{
if (!IsReady()) {
return errorOut("Active masternode not ready");
Expand All @@ -75,12 +76,11 @@ OperationResult CActiveDeterministicMasternodeManager::GetOperatorKey(CKey& key,
if (!dmn) {
return errorOut(strprintf("Active masternode %s not registered or PoSe banned", info.proTxHash.ToString()));
}
if (info.keyIDOperator != dmn->pdmnState->keyIDOperator) {
if (info.pubKeyOperator != dmn->pdmnState->pubKeyOperator.Get()) {
return errorOut("Active masternode operator key changed or revoked");
}
// return keys
// return key
key = info.keyOperator;
keyID = info.keyIDOperator;
return OperationResult(true);
}

Expand Down Expand Up @@ -119,7 +119,7 @@ void CActiveDeterministicMasternodeManager::Init()

CDeterministicMNList mnList = deterministicMNManager->GetListAtChainTip();

CDeterministicMNCPtr dmn = mnList.GetMNByOperatorKey(info.keyIDOperator);
CDeterministicMNCPtr dmn = mnList.GetMNByOperatorKey(info.pubKeyOperator);
if (!dmn) {
// MN not appeared on the chain yet
return;
Expand Down Expand Up @@ -192,7 +192,7 @@ void CActiveDeterministicMasternodeManager::UpdatedBlockTip(const CBlockIndex* p
return;
}

if (newDmn->pdmnState->keyIDOperator != oldDmn->pdmnState->keyIDOperator) {
if (newDmn->pdmnState->pubKeyOperator != oldDmn->pdmnState->pubKeyOperator) {
// MN operator key changed or revoked
Reset(MASTERNODE_OPERATOR_KEY_CHANGED);
return;
Expand Down Expand Up @@ -466,32 +466,39 @@ void CActiveMasternode::GetKeys(CKey& _privKeyMasternode, CPubKey& _pubKeyMaster
_pubKeyMasternode = pubKeyMasternode;
}

bool GetActiveMasternodeKeys(CKey& key, CKeyID& keyID, CTxIn& vin)
bool GetActiveDMNKeys(CBLSSecretKey& key, CTxIn& vin)
{
if (activeMasternodeManager == nullptr) {
return error("%s: Active Masternode not initialized", __func__);
}
CDeterministicMNCPtr dmn;
auto res = activeMasternodeManager->GetOperatorKey(key, dmn);
if (!res) {
return error("%s: %s", __func__, res.getError());
}
vin = CTxIn(dmn->collateralOutpoint);
return true;
}

bool GetActiveMasternodeKeys(CTxIn& vin, Optional<CKey>& key, CBLSSecretKey& blsKey)
{
if (activeMasternodeManager != nullptr) {
// deterministic mn
CDeterministicMNCPtr dmn;
auto res = activeMasternodeManager->GetOperatorKey(key, keyID, dmn);
if (!res) {
LogPrint(BCLog::MNBUDGET,"%s: %s\n", __func__, res.getError());
return false;
}
vin = CTxIn(dmn->collateralOutpoint);
return true;
key = nullopt;
return GetActiveDMNKeys(blsKey, vin);
}

// legacy mn
if (activeMasternode.vin == nullopt) {
LogPrint(BCLog::MNBUDGET,"%s: Active Masternode not initialized\n", __func__);
return false;
return error("%s: Active Masternode not initialized", __func__);
}
if (activeMasternode.GetStatus() != ACTIVE_MASTERNODE_STARTED) {
LogPrint(BCLog::MNBUDGET,"%s: MN not started (%s)\n", __func__, activeMasternode.GetStatusMessage());
return false;
return error("%s: MN not started (%s)", __func__, activeMasternode.GetStatusMessage());
}
CPubKey mnPubKey;
activeMasternode.GetKeys(key, mnPubKey);
keyID = mnPubKey.GetID();
vin = *activeMasternode.vin;
CKey sk;
CPubKey pk;
activeMasternode.GetKeys(sk, pk);
key = Optional<CKey>(sk);
blsKey.Reset();
return true;
}
14 changes: 9 additions & 5 deletions src/activemasternode.h
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,8 @@
#include "wallet/wallet.h"

class CActiveDeterministicMasternodeManager;
class CBLSPublicKey;
class CBLSSecretKey;

#define ACTIVE_MASTERNODE_INITIAL 0 // initial state
#define ACTIVE_MASTERNODE_SYNC_IN_PROCESS 1
Expand All @@ -28,8 +30,8 @@ extern CActiveDeterministicMasternodeManager* activeMasternodeManager;
struct CActiveMasternodeInfo
{
// Keys for the active Masternode
CKeyID keyIDOperator;
CKey keyOperator;
CBLSPublicKey pubKeyOperator;
CBLSSecretKey keyOperator;
// Initialized while registering Masternode
uint256 proTxHash{UINT256_ZERO};
CService service;
Expand Down Expand Up @@ -63,7 +65,7 @@ class CActiveDeterministicMasternodeManager : public CValidationInterface
OperationResult SetOperatorKey(const std::string& strMNOperatorPrivKey);
// If the active masternode is ready, and the keyID matches with the registered one,
// return private key, keyID, and pointer to dmn.
OperationResult GetOperatorKey(CKey& key, CKeyID& keyID, CDeterministicMNCPtr& dmn) const;
OperationResult GetOperatorKey(CBLSSecretKey& key, CDeterministicMNCPtr& dmn) const;
void SetNullProTx() { info.proTxHash = UINT256_ZERO; }

const CActiveMasternodeInfo* GetInfo() const { return &info; }
Expand Down Expand Up @@ -116,7 +118,9 @@ class CActiveMasternode
void GetKeys(CKey& privKeyMasternode, CPubKey& pubKeyMasternode);
};

// Compatibility code: get keys for either legacy or deterministic masternode
bool GetActiveMasternodeKeys(CKey& key, CKeyID& keyID, CTxIn& vin);
// Compatibility code: get vin and keys for either legacy or deterministic masternode
bool GetActiveMasternodeKeys(CTxIn& vin, Optional<CKey>& key, CBLSSecretKey& blsKey);
// Get active masternode BLS operator keys for DMN
bool GetActiveDMNKeys(CBLSSecretKey& key, CTxIn& vin);

#endif
23 changes: 17 additions & 6 deletions src/budget/budgetmanager.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -504,8 +504,10 @@ void CBudgetManager::VoteOnFinalizedBudgets()
}

// Get the active masternode (operator) key
CKey mnKey; CKeyID mnKeyID; CTxIn mnVin;
if (!GetActiveMasternodeKeys(mnKey, mnKeyID, mnVin)) {
CTxIn mnVin;
Optional<CKey> mnKey{nullopt};
CBLSSecretKey blsKey;
if (!GetActiveMasternodeKeys(mnVin, mnKey, blsKey)) {
return;
}

Expand Down Expand Up @@ -543,9 +545,18 @@ void CBudgetManager::VoteOnFinalizedBudgets()
// Sign finalized budgets
for (const uint256& budgetHash: vBudgetHashes) {
CFinalizedBudgetVote vote(mnVin, budgetHash);
if (!vote.Sign(mnKey, mnKeyID)) {
LogPrintf("%s: Failure to sign budget %s", __func__, budgetHash.ToString());
continue;
if (mnKey != nullopt) {
// Legacy MN
if (!vote.Sign(*mnKey, mnKey->GetPubKey().GetID())) {
LogPrintf("%s: Failure to sign budget %s\n", __func__, budgetHash.ToString());
continue;
}
} else {
// DMN
if (!vote.Sign(blsKey)) {
LogPrintf("%s: Failure to sign budget %s with DMN\n", __func__, budgetHash.ToString());
continue;
}
}
std::string strError = "";
if (!UpdateFinalizedBudget(vote, NULL, strError)) {
Expand Down Expand Up @@ -1110,7 +1121,7 @@ bool CBudgetManager::ProcessFinalizedBudgetVote(CFinalizedBudgetVote& vote, CNod
if (dmn) {
const std::string& mn_protx_id = dmn->proTxHash.ToString();

if (!vote.CheckSignature(dmn->pdmnState->keyIDOperator)) {
if (!vote.CheckSignature(dmn->pdmnState->pubKeyOperator.Get())) {
err = strprintf("invalid fbvote sig from dmn: %s", mn_protx_id);
return state.DoS(100, false, REJECT_INVALID, "bad-fbvote-sig", false, err);
}
Expand Down
30 changes: 15 additions & 15 deletions src/evo/deterministicmns.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -37,9 +37,9 @@ std::string CDeterministicMNState::ToString() const
operatorPayoutAddress = EncodeDestination(dest);
}

return strprintf("CDeterministicMNState(nRegisteredHeight=%d, nLastPaidHeight=%d, nPoSePenalty=%d, nPoSeRevivedHeight=%d, nPoSeBanHeight=%d, nRevocationReason=%d, ownerAddress=%s, operatorAddress=%s, votingAddress=%s, addr=%s, payoutAddress=%s, operatorPayoutAddress=%s)",
return strprintf("CDeterministicMNState(nRegisteredHeight=%d, nLastPaidHeight=%d, nPoSePenalty=%d, nPoSeRevivedHeight=%d, nPoSeBanHeight=%d, nRevocationReason=%d, ownerAddress=%s, operatorPubKey=%s, votingAddress=%s, addr=%s, payoutAddress=%s, operatorPayoutAddress=%s)",
nRegisteredHeight, nLastPaidHeight, nPoSePenalty, nPoSeRevivedHeight, nPoSeBanHeight, nRevocationReason,
EncodeDestination(keyIDOwner), EncodeDestination(keyIDOperator), EncodeDestination(keyIDVoting), addr.ToStringIPPort(), payoutAddress, operatorPayoutAddress);
EncodeDestination(keyIDOwner), pubKeyOperator.Get().ToString(), EncodeDestination(keyIDVoting), addr.ToStringIPPort(), payoutAddress, operatorPayoutAddress);
}

void CDeterministicMNState::ToJson(UniValue& obj) const
Expand All @@ -54,7 +54,7 @@ void CDeterministicMNState::ToJson(UniValue& obj) const
obj.pushKV("PoSeBanHeight", nPoSeBanHeight);
obj.pushKV("revocationReason", nRevocationReason);
obj.pushKV("ownerAddress", EncodeDestination(keyIDOwner));
obj.pushKV("operatorAddress", keyIDOperator == CKeyID() ? "" : EncodeDestination(keyIDOperator));
obj.pushKV("operatorPubKey", pubKeyOperator.Get().ToString());
obj.pushKV("votingAddress", EncodeDestination(keyIDVoting));

CTxDestination dest1;
Expand Down Expand Up @@ -122,10 +122,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.Get() == pubKey) {
return p.second;
}
}
Expand Down Expand Up @@ -396,8 +396,8 @@ void CDeterministicMNList::AddMN(const CDeterministicMNCPtr& dmn, bool fBumpTota
if (HasUniqueProperty(dmn->pdmnState->addr)) {
throw(std::runtime_error(strprintf("%s: can't add a masternode with a duplicate address %s", __func__, dmn->pdmnState->addr.ToStringIPPort())));
}
if (HasUniqueProperty(dmn->pdmnState->keyIDOwner) || HasUniqueProperty(dmn->pdmnState->keyIDOperator)) {
throw(std::runtime_error(strprintf("%s: can't add a masternode with a duplicate key (%s or %s)", __func__, EncodeDestination(dmn->pdmnState->keyIDOwner), EncodeDestination(dmn->pdmnState->keyIDOperator))));
if (HasUniqueProperty(dmn->pdmnState->keyIDOwner) || HasUniqueProperty(dmn->pdmnState->pubKeyOperator)) {
throw(std::runtime_error(strprintf("%s: can't add a masternode with a duplicate key (%s or %s)", __func__, EncodeDestination(dmn->pdmnState->keyIDOwner), dmn->pdmnState->pubKeyOperator.Get().ToString())));
}

mnMap = mnMap.set(dmn->proTxHash, dmn);
Expand All @@ -407,7 +407,7 @@ void CDeterministicMNList::AddMN(const CDeterministicMNCPtr& dmn, bool fBumpTota
AddUniqueProperty(dmn, dmn->pdmnState->addr);
}
AddUniqueProperty(dmn, dmn->pdmnState->keyIDOwner);
AddUniqueProperty(dmn, dmn->pdmnState->keyIDOperator);
AddUniqueProperty(dmn, dmn->pdmnState->pubKeyOperator);

if (fBumpTotalCount) {
// nTotalRegisteredCount acts more like a checkpoint, not as a limit,
Expand All @@ -430,7 +430,7 @@ void CDeterministicMNList::UpdateMN(const CDeterministicMNCPtr& oldDmn, const CD

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::UpdateMN(const uint256& proTxHash, const CDeterministicMNStateCPtr& pdmnState)
Expand Down Expand Up @@ -462,7 +462,7 @@ void CDeterministicMNList::RemoveMN(const uint256& proTxHash)
DeleteUniqueProperty(dmn, dmn->pdmnState->addr);
}
DeleteUniqueProperty(dmn, dmn->pdmnState->keyIDOwner);
DeleteUniqueProperty(dmn, dmn->pdmnState->keyIDOperator);
DeleteUniqueProperty(dmn, dmn->pdmnState->pubKeyOperator);

mnMap = mnMap.erase(proTxHash);
mnInternalIdMap = mnInternalIdMap.erase(dmn->GetInternalId());
Expand Down Expand Up @@ -657,7 +657,7 @@ bool CDeterministicMNManager::BuildNewListFromBlock(const CBlock& block, const C
if (newList.HasUniqueProperty(pl.keyIDOwner)) {
return _state.DoS(100, false, REJECT_DUPLICATE, "bad-protx-dup-owner-key");
}
if (newList.HasUniqueProperty(pl.keyIDOperator)) {
if (newList.HasUniqueProperty(pl.pubKeyOperator)) {
return _state.DoS(100, false, REJECT_DUPLICATE, "bad-protx-dup-operator-key");
}

Expand Down Expand Up @@ -702,7 +702,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.Get().IsValid() && !newState->keyIDVoting.IsNull() && !newState->keyIDOwner.IsNull()) {
newState->nPoSePenalty = 0;
newState->nPoSeBanHeight = -1;
newState->nPoSeRevivedHeight = nHeight;
Expand Down Expand Up @@ -730,16 +730,16 @@ bool CDeterministicMNManager::BuildNewListFromBlock(const CBlock& block, const C
if (!dmn) {
return _state.DoS(100, false, REJECT_INVALID, "bad-protx-hash");
}
if (newList.HasUniqueProperty(pl.keyIDOperator) && newList.GetUniquePropertyMN(pl.keyIDOperator)->proTxHash != pl.proTxHash) {
if (newList.HasUniqueProperty(pl.pubKeyOperator) && newList.GetUniquePropertyMN(pl.pubKeyOperator)->proTxHash != pl.proTxHash) {
return _state.DoS(100, false, REJECT_DUPLICATE, "bad-protx-dup-operator-key");
}
auto newState = std::make_shared<CDeterministicMNState>(*dmn->pdmnState);
if (newState->keyIDOperator != pl.keyIDOperator) {
if (newState->pubKeyOperator.Get() != pl.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 = pl.keyIDOperator;
newState->pubKeyOperator.Set(pl.pubKeyOperator);
newState->keyIDVoting = pl.keyIDVoting;
newState->scriptPayout = pl.scriptPayout;

Expand Down
15 changes: 8 additions & 7 deletions src/evo/deterministicmns.h
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@
#define PIVX_DETERMINISTICMNS_H

#include "arith_uint256.h"
#include "bls/bls_wrapper.h"
#include "dbwrapper.h"
#include "evo/evodb.h"
#include "evo/providertx.h"
Expand Down Expand Up @@ -39,7 +40,7 @@ class CDeterministicMNState
uint256 confirmedHashWithProRegTxHash;

CKeyID keyIDOwner;
CKeyID keyIDOperator;
CBLSLazyPublicKey pubKeyOperator;
CKeyID keyIDVoting;
CService addr;
CScript scriptPayout;
Expand All @@ -50,7 +51,7 @@ class CDeterministicMNState
explicit CDeterministicMNState(const ProRegPL& pl)
{
keyIDOwner = pl.keyIDOwner;
keyIDOperator = pl.keyIDOperator;
pubKeyOperator.Set(pl.pubKeyOperator);
keyIDVoting = pl.keyIDVoting;
addr = pl.addr;
scriptPayout = pl.scriptPayout;
Expand All @@ -70,7 +71,7 @@ class CDeterministicMNState
READWRITE(obj.confirmedHash);
READWRITE(obj.confirmedHashWithProRegTxHash);
READWRITE(obj.keyIDOwner);
READWRITE(obj.keyIDOperator);
READWRITE(obj.pubKeyOperator);
READWRITE(obj.keyIDVoting);
READWRITE(obj.addr);
READWRITE(obj.scriptPayout);
Expand All @@ -79,7 +80,7 @@ class CDeterministicMNState

void ResetOperatorFields()
{
keyIDOperator = CKeyID();
pubKeyOperator.Set(CBLSPublicKey());
addr = CService();
scriptOperatorPayout = CScript();
nRevocationReason = ProUpRevPL::REASON_NOT_SPECIFIED;
Expand Down Expand Up @@ -119,7 +120,7 @@ class CDeterministicMNStateDiff
Field_confirmedHash = 0x0040,
Field_confirmedHashWithProRegTxHash = 0x0080,
Field_keyIDOwner = 0x0100,
Field_keyIDOperator = 0x0200,
Field_pubKeyOperator = 0x0200,
Field_keyIDVoting = 0x0400,
Field_addr = 0x0800,
Field_scriptPayout = 0x1000,
Expand All @@ -136,7 +137,7 @@ class CDeterministicMNStateDiff
DMN_STATE_DIFF_LINE(confirmedHash) \
DMN_STATE_DIFF_LINE(confirmedHashWithProRegTxHash) \
DMN_STATE_DIFF_LINE(keyIDOwner) \
DMN_STATE_DIFF_LINE(keyIDOperator) \
DMN_STATE_DIFF_LINE(pubKeyOperator) \
DMN_STATE_DIFF_LINE(keyIDVoting) \
DMN_STATE_DIFF_LINE(addr) \
DMN_STATE_DIFF_LINE(scriptPayout) \
Expand Down Expand Up @@ -360,7 +361,7 @@ class CDeterministicMNList
}
CDeterministicMNCPtr GetMN(const uint256& proTxHash) const;
CDeterministicMNCPtr GetValidMN(const uint256& proTxHash) const;
CDeterministicMNCPtr GetMNByOperatorKey(const CKeyID& keyID);
CDeterministicMNCPtr GetMNByOperatorKey(const CBLSPublicKey& pubKey);
CDeterministicMNCPtr GetMNByCollateral(const COutPoint& collateralOutpoint) const;
CDeterministicMNCPtr GetValidMNByCollateral(const COutPoint& collateralOutpoint) const;
CDeterministicMNCPtr GetMNByService(const CService& service) const;
Expand Down
Loading