Merge pull request #2445 from codablock/pr_dip3_removerestriction
Remove restriction of payeeAddress being the same as collateralAddress
This commit is contained in:
commit
684f9ae0bf
@ -93,26 +93,10 @@ bool CheckProRegTx(const CTransaction& tx, const CBlockIndex* pindexPrev, CValid
|
||||
return state.DoS(100, false, REJECT_INVALID, "bad-protx-mode");
|
||||
}
|
||||
|
||||
// when collateralOutpoint refers to an external collateral, we check it further down
|
||||
if (ptx.collateralOutpoint.hash.IsNull()) {
|
||||
if (ptx.collateralOutpoint.n >= tx.vout.size()) {
|
||||
return state.DoS(10, false, REJECT_INVALID, "bad-protx-collateral-index");
|
||||
}
|
||||
if (tx.vout[ptx.collateralOutpoint.n].nValue != 1000 * COIN) {
|
||||
return state.DoS(10, false, REJECT_INVALID, "bad-protx-collateral");
|
||||
}
|
||||
|
||||
// This is a temporary restriction that will be lifted later
|
||||
// It is required while we are transitioning from the old MN list to the deterministic list
|
||||
if (tx.vout[ptx.collateralOutpoint.n].scriptPubKey != ptx.scriptPayout) {
|
||||
return state.DoS(10, false, REJECT_INVALID, "bad-protx-payee-collateral");
|
||||
}
|
||||
}
|
||||
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()) {
|
||||
if (!ptx.scriptPayout.IsPayToPublicKeyHash() && !ptx.scriptPayout.IsPayToScriptHash()) {
|
||||
return state.DoS(10, false, REJECT_INVALID, "bad-protx-payee");
|
||||
}
|
||||
|
||||
@ -121,7 +105,7 @@ bool CheckProRegTx(const CTransaction& tx, const CBlockIndex* pindexPrev, CValid
|
||||
// should not happen as we checked script types before
|
||||
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)
|
||||
// don't allow reuse of payout key for other keys (don't allow people to put the payee key onto an online server)
|
||||
if (payoutDest == CTxDestination(ptx.keyIDOwner) || payoutDest == CTxDestination(ptx.keyIDVoting)) {
|
||||
return state.DoS(10, false, REJECT_INVALID, "bad-protx-payee-reuse");
|
||||
}
|
||||
@ -136,6 +120,7 @@ bool CheckProRegTx(const CTransaction& tx, const CBlockIndex* pindexPrev, CValid
|
||||
return state.DoS(10, false, REJECT_INVALID, "bad-protx-operator-reward");
|
||||
}
|
||||
|
||||
CTxDestination collateralTxDest;
|
||||
CKeyID keyForPayloadSig;
|
||||
COutPoint collateralOutpoint;
|
||||
|
||||
@ -145,23 +130,38 @@ bool CheckProRegTx(const CTransaction& tx, const CBlockIndex* pindexPrev, CValid
|
||||
return state.DoS(10, false, REJECT_INVALID, "bad-protx-collateral");
|
||||
}
|
||||
|
||||
CTxDestination txDest;
|
||||
if (!ExtractDestination(coin.out.scriptPubKey, txDest)) {
|
||||
if (!ExtractDestination(coin.out.scriptPubKey, collateralTxDest)) {
|
||||
return state.DoS(10, false, REJECT_INVALID, "bad-protx-collateral-dest");
|
||||
}
|
||||
|
||||
// Extract key from collateral. This only works for P2PK and P2PKH collaterals and will fail for P2SH.
|
||||
// Issuer of this ProRegTx must prove ownership with this key by signing the ProRegTx
|
||||
CBitcoinAddress txAddr(txDest);
|
||||
if (!txAddr.GetKeyID(keyForPayloadSig)) {
|
||||
if (!CBitcoinAddress(collateralTxDest).GetKeyID(keyForPayloadSig)) {
|
||||
return state.DoS(10, false, REJECT_INVALID, "bad-protx-collateral-pkh");
|
||||
}
|
||||
|
||||
collateralOutpoint = ptx.collateralOutpoint;
|
||||
} else {
|
||||
if (ptx.collateralOutpoint.n >= tx.vout.size()) {
|
||||
return state.DoS(10, false, REJECT_INVALID, "bad-protx-collateral-index");
|
||||
}
|
||||
if (tx.vout[ptx.collateralOutpoint.n].nValue != 1000 * COIN) {
|
||||
return state.DoS(10, false, REJECT_INVALID, "bad-protx-collateral");
|
||||
}
|
||||
|
||||
if (!ExtractDestination(tx.vout[ptx.collateralOutpoint.n].scriptPubKey, collateralTxDest)) {
|
||||
return state.DoS(10, false, REJECT_INVALID, "bad-protx-collateral-dest");
|
||||
}
|
||||
|
||||
collateralOutpoint = COutPoint(tx.GetHash(), ptx.collateralOutpoint.n);
|
||||
}
|
||||
|
||||
// don't allow reuse of collateral key for other keys (don't allow people to put the collateral key onto an online server)
|
||||
// this check applies to internal and external collateral, but internal collaterals are not necessarely a P2PKH
|
||||
if (collateralTxDest == CTxDestination(ptx.keyIDOwner) || collateralTxDest == CTxDestination(ptx.keyIDVoting)) {
|
||||
return state.DoS(10, false, REJECT_INVALID, "bad-protx-collateral-reuse");
|
||||
}
|
||||
|
||||
if (pindexPrev) {
|
||||
auto mnList = deterministicMNManager->GetListForBlock(pindexPrev->GetBlockHash());
|
||||
|
||||
@ -272,8 +272,7 @@ bool CheckProUpRegTx(const CTransaction& tx, const CBlockIndex* pindexPrev, CVal
|
||||
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()) {
|
||||
if (!ptx.scriptPayout.IsPayToPublicKeyHash() && !ptx.scriptPayout.IsPayToScriptHash()) {
|
||||
return state.DoS(10, false, REJECT_INVALID, "bad-protx-payee");
|
||||
}
|
||||
|
||||
@ -290,19 +289,24 @@ 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)
|
||||
// don't allow reuse of payee key for other keys (don't allow people to put the payee key onto an online server)
|
||||
if (payoutDest == CTxDestination(dmn->pdmnState->keyIDOwner) || payoutDest == CTxDestination(ptx.keyIDVoting)) {
|
||||
return state.DoS(10, false, REJECT_INVALID, "bad-protx-payee-reuse");
|
||||
}
|
||||
|
||||
// This is a temporary restriction that will be lifted later
|
||||
// It is required while we are transitioning from the old MN list to the deterministic list
|
||||
Coin coin;
|
||||
if (!GetUTXOCoin(dmn->collateralOutpoint, coin)) {
|
||||
return state.DoS(100, false, REJECT_INVALID, "bad-protx-payee-collateral");
|
||||
// this should never happen (there would be no dmn otherwise)
|
||||
return state.DoS(100, false, REJECT_INVALID, "bad-protx-collateral");
|
||||
}
|
||||
if (coin.out.scriptPubKey != ptx.scriptPayout) {
|
||||
return state.DoS(10, false, REJECT_INVALID, "bad-protx-payee-collateral");
|
||||
|
||||
// don't allow reuse of collateral key for other keys (don't allow people to put the collateral key onto an online server)
|
||||
CTxDestination collateralTxDest;
|
||||
if (!ExtractDestination(coin.out.scriptPubKey, collateralTxDest)) {
|
||||
return state.DoS(100, false, REJECT_INVALID, "bad-protx-collateral-dest");
|
||||
}
|
||||
if (collateralTxDest == CTxDestination(dmn->pdmnState->keyIDOwner) || collateralTxDest == CTxDestination(ptx.keyIDVoting)) {
|
||||
return state.DoS(10, false, REJECT_INVALID, "bad-protx-collateral-reuse");
|
||||
}
|
||||
|
||||
if (mnList.HasUniqueProperty(ptx.pubKeyOperator)) {
|
||||
|
@ -56,13 +56,9 @@ CMasternode::CMasternode(const CMasternodeBroadcast& mnb) :
|
||||
|
||||
CMasternode::CMasternode(const uint256 &proTxHash, const CDeterministicMNCPtr& dmn) :
|
||||
masternode_info_t{ MASTERNODE_ENABLED, DMN_PROTO_VERSION, GetAdjustedTime(),
|
||||
dmn->collateralOutpoint, dmn->pdmnState->addr, CKeyID(), dmn->pdmnState->keyIDOwner, dmn->pdmnState->pubKeyOperator, dmn->pdmnState->keyIDVoting},
|
||||
dmn->collateralOutpoint, dmn->pdmnState->addr, CKeyID() /* not valid with DIP3 */, dmn->pdmnState->keyIDOwner, dmn->pdmnState->pubKeyOperator, dmn->pdmnState->keyIDVoting},
|
||||
fAllowMixingTx(true)
|
||||
{
|
||||
CTxDestination dest;
|
||||
if (!ExtractDestination(dmn->pdmnState->scriptPayout, dest) || !boost::get<CKeyID>(&dest))
|
||||
assert(false); // should not happen (previous verification forbids non p2pkh/p2pk
|
||||
keyIDCollateralAddress = *boost::get<CKeyID>(&dest);
|
||||
}
|
||||
|
||||
//
|
||||
|
@ -129,7 +129,7 @@ struct masternode_info_t
|
||||
CService addr{};
|
||||
CPubKey pubKeyCollateralAddress{}; // this will be invalid/unset when the network switches to deterministic MNs (luckely it's only important for the broadcast hash)
|
||||
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 keyIDCollateralAddress{}; // this is only used in compatibility code and won't be used when spork15 gets activated
|
||||
CKeyID keyIDOwner{};
|
||||
CKeyID legacyKeyIDOperator{};
|
||||
CBLSPublicKey blsPubKeyOperator;
|
||||
|
@ -605,18 +605,26 @@ bool CMasternodeMan::GetMasternodeInfo(const CKeyID& keyIDOperator, masternode_i
|
||||
|
||||
bool CMasternodeMan::GetMasternodeInfo(const CScript& payee, masternode_info_t& mnInfoRet)
|
||||
{
|
||||
CTxDestination dest;
|
||||
if (!ExtractDestination(payee, dest) || !boost::get<CKeyID>(&dest))
|
||||
if (deterministicMNManager->IsDeterministicMNsSporkActive()) {
|
||||
// we can't reliably search by payee as there might be duplicates. Also, keyIDCollateralAddress is not
|
||||
// always the payout address as DIP3 allows using different keys for collateral and payouts
|
||||
// this method is only used from ComputeBlockVersion, which has a different logic for deterministic MNs
|
||||
// this method won't be reimplemented when removing the compatibility code
|
||||
return false;
|
||||
CKeyID keyId = *boost::get<CKeyID>(&dest);
|
||||
LOCK(cs);
|
||||
for (const auto& mnpair : mapMasternodes) {
|
||||
if (mnpair.second.keyIDCollateralAddress == keyId) {
|
||||
mnInfoRet = mnpair.second.GetInfo();
|
||||
return true;
|
||||
} else {
|
||||
CTxDestination dest;
|
||||
if (!ExtractDestination(payee, dest) || !boost::get<CKeyID>(&dest))
|
||||
return false;
|
||||
CKeyID keyId = *boost::get<CKeyID>(&dest);
|
||||
LOCK(cs);
|
||||
for (const auto& mnpair : mapMasternodes) {
|
||||
if (mnpair.second.keyIDCollateralAddress == keyId) {
|
||||
mnInfoRet = mnpair.second.GetInfo();
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
bool CMasternodeMan::Has(const COutPoint& outpoint)
|
||||
|
@ -283,13 +283,22 @@ UniValue GetNextMasternodeForPayment(int heightShift)
|
||||
nHeight = pindex->nHeight + heightShift;
|
||||
mnodeman.UpdateLastPaid(pindex);
|
||||
|
||||
CScript payeeScript;
|
||||
if (deterministicMNManager->IsDeterministicMNsSporkActive()) {
|
||||
auto payee = deterministicMNManager->GetListAtChainTip().GetMNPayee();
|
||||
if (!payee || !mnodeman.GetMasternodeInfo(payee->proTxHash, mnInfo))
|
||||
return "unknown";
|
||||
payeeScript = payee->pdmnState->scriptPayout;
|
||||
} else {
|
||||
if (!mnodeman.GetNextMasternodeInQueueForPayment(nHeight, true, nCount, mnInfo))
|
||||
return "unknown";
|
||||
payeeScript = GetScriptForDestination(mnInfo.keyIDCollateralAddress);
|
||||
}
|
||||
|
||||
CTxDestination payeeDest;
|
||||
CBitcoinAddress payeeAddr;
|
||||
if (ExtractDestination(payeeScript, payeeDest)) {
|
||||
payeeAddr = CBitcoinAddress(payeeDest);
|
||||
}
|
||||
|
||||
UniValue obj(UniValue::VOBJ);
|
||||
@ -298,7 +307,7 @@ UniValue GetNextMasternodeForPayment(int heightShift)
|
||||
obj.push_back(Pair("IP:port", mnInfo.addr.ToString()));
|
||||
obj.push_back(Pair("protocol", mnInfo.nProtocolVersion));
|
||||
obj.push_back(Pair("outpoint", mnInfo.outpoint.ToStringShort()));
|
||||
obj.push_back(Pair("payee", CBitcoinAddress(mnInfo.keyIDCollateralAddress).ToString()));
|
||||
obj.push_back(Pair("payee", payeeAddr.IsValid() ? payeeAddr.ToString() : "UNKNOWN"));
|
||||
obj.push_back(Pair("lastseen", mnInfo.nTimeLastPing));
|
||||
obj.push_back(Pair("activeseconds", mnInfo.nTimeLastPing - mnInfo.sigTime));
|
||||
return obj;
|
||||
@ -877,6 +886,23 @@ UniValue masternodelist(const JSONRPCRequest& request)
|
||||
for (const auto& mnpair : mapMasternodes) {
|
||||
CMasternode mn = mnpair.second;
|
||||
std::string strOutpoint = mnpair.first.ToStringShort();
|
||||
|
||||
CScript payeeScript;
|
||||
if (deterministicMNManager->IsDeterministicMNsSporkActive()) {
|
||||
auto dmn = deterministicMNManager->GetListAtChainTip().GetMNByCollateral(mn.outpoint);
|
||||
if (dmn) {
|
||||
payeeScript = dmn->pdmnState->scriptPayout;
|
||||
}
|
||||
} else {
|
||||
payeeScript = GetScriptForDestination(mn.keyIDCollateralAddress);
|
||||
}
|
||||
|
||||
CTxDestination payeeDest;
|
||||
std::string payeeStr = "UNKOWN";
|
||||
if (ExtractDestination(payeeScript, payeeDest)) {
|
||||
payeeStr = CBitcoinAddress(payeeDest).ToString();
|
||||
}
|
||||
|
||||
if (strMode == "activeseconds") {
|
||||
if (strFilter !="" && strOutpoint.find(strFilter) == std::string::npos) continue;
|
||||
obj.push_back(Pair(strOutpoint, (int64_t)(mn.lastPing.sigTime - mn.sigTime)));
|
||||
@ -900,7 +926,7 @@ UniValue masternodelist(const JSONRPCRequest& request)
|
||||
streamFull << std::setw(18) <<
|
||||
mn.GetStatus() << " " <<
|
||||
mn.nProtocolVersion << " " <<
|
||||
CBitcoinAddress(mn.keyIDCollateralAddress).ToString() << " " <<
|
||||
payeeStr << " " <<
|
||||
(int64_t)mn.lastPing.sigTime << " " << std::setw(8) <<
|
||||
(int64_t)(mn.lastPing.sigTime - mn.sigTime) << " " << std::setw(10) <<
|
||||
mn.GetLastPaidTime() << " " << std::setw(6) <<
|
||||
@ -915,7 +941,7 @@ UniValue masternodelist(const JSONRPCRequest& request)
|
||||
streamInfo << std::setw(18) <<
|
||||
mn.GetStatus() << " " <<
|
||||
mn.nProtocolVersion << " " <<
|
||||
CBitcoinAddress(mn.keyIDCollateralAddress).ToString() << " " <<
|
||||
payeeStr << " " <<
|
||||
(int64_t)mn.lastPing.sigTime << " " << std::setw(8) <<
|
||||
(int64_t)(mn.lastPing.sigTime - mn.sigTime) << " " <<
|
||||
mn.lastPing.GetSentinelString() << " " <<
|
||||
@ -964,11 +990,9 @@ UniValue masternodelist(const JSONRPCRequest& request)
|
||||
if (strFilter !="" && strOutpoint.find(strFilter) == std::string::npos) continue;
|
||||
obj.push_back(Pair(strOutpoint, (int64_t)mn.lastPing.sigTime));
|
||||
} else if (strMode == "payee") {
|
||||
CBitcoinAddress address(mn.keyIDCollateralAddress);
|
||||
std::string strPayee = address.ToString();
|
||||
if (strFilter !="" && strPayee.find(strFilter) == std::string::npos &&
|
||||
if (strFilter !="" && payeeStr.find(strFilter) == std::string::npos &&
|
||||
strOutpoint.find(strFilter) == std::string::npos) continue;
|
||||
obj.push_back(Pair(strOutpoint, strPayee));
|
||||
obj.push_back(Pair(strOutpoint, payeeStr));
|
||||
} else if (strMode == "protocol") {
|
||||
if (strFilter !="" && strFilter != strprintf("%d", mn.nProtocolVersion) &&
|
||||
strOutpoint.find(strFilter) == std::string::npos) continue;
|
||||
|
@ -1807,26 +1807,34 @@ int32_t ComputeBlockVersion(const CBlockIndex* pindexPrev, const Consensus::Para
|
||||
ThresholdState state = VersionBitsState(pindexPrev, params, pos, versionbitscache);
|
||||
const struct BIP9DeploymentInfo& vbinfo = VersionBitsDeploymentInfo[pos];
|
||||
if (vbinfo.check_mn_protocol && state == THRESHOLD_STARTED && fCheckMasternodesUpgraded) {
|
||||
std::vector<CTxOut> voutMasternodePayments;
|
||||
masternode_info_t mnInfo;
|
||||
if (!mnpayments.GetBlockTxOuts(pindexPrev->nHeight + 1, 0, voutMasternodePayments)) {
|
||||
// no votes for this block
|
||||
continue;
|
||||
}
|
||||
bool mnKnown = false;
|
||||
for (const auto& txout : voutMasternodePayments) {
|
||||
if (mnodeman.GetMasternodeInfo(txout.scriptPubKey, mnInfo)) {
|
||||
mnKnown = true;
|
||||
break;
|
||||
if (deterministicMNManager->IsDeterministicMNsSporkActive()) {
|
||||
auto mnList = deterministicMNManager->GetListForBlock(pindexPrev->GetBlockHash());
|
||||
auto payee = mnList.GetMNPayee();
|
||||
if (!payee) {
|
||||
continue;
|
||||
}
|
||||
} else {
|
||||
std::vector<CTxOut> voutMasternodePayments;
|
||||
masternode_info_t mnInfo;
|
||||
if (!mnpayments.GetBlockTxOuts(pindexPrev->nHeight + 1, 0, voutMasternodePayments)) {
|
||||
// no votes for this block
|
||||
continue;
|
||||
}
|
||||
bool mnKnown = false;
|
||||
for (const auto& txout : voutMasternodePayments) {
|
||||
if (mnodeman.GetMasternodeInfo(txout.scriptPubKey, mnInfo)) {
|
||||
mnKnown = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (!mnKnown) {
|
||||
// unknown masternode
|
||||
continue;
|
||||
}
|
||||
if (mnInfo.nProtocolVersion < DMN_PROTO_VERSION) {
|
||||
// masternode is not upgraded yet
|
||||
continue;
|
||||
}
|
||||
}
|
||||
if (!mnKnown) {
|
||||
// unknown masternode
|
||||
continue;
|
||||
}
|
||||
if (mnInfo.nProtocolVersion < DMN_PROTO_VERSION) {
|
||||
// masternode is not upgraded yet
|
||||
continue;
|
||||
}
|
||||
}
|
||||
if (state == THRESHOLD_LOCKED_IN || state == THRESHOLD_STARTED) {
|
||||
|
Loading…
Reference in New Issue
Block a user