Implementation of ProRegTx with basic validation (no processing)

This commit is contained in:
Alexander Block 2018-02-13 13:36:36 +01:00
parent c9a72e8880
commit 958b84ace3
7 changed files with 202 additions and 1 deletions

View File

@ -108,6 +108,7 @@ BITCOIN_CORE_H = \
cuckoocache.h \ cuckoocache.h \
evo/evodb.h \ evo/evodb.h \
evo/specialtx.h \ evo/specialtx.h \
evo/providertx.h \
privatesend.h \ privatesend.h \
privatesend-client.h \ privatesend-client.h \
privatesend-server.h \ privatesend-server.h \
@ -220,6 +221,7 @@ libdash_server_a_SOURCES = \
dsnotificationinterface.cpp \ dsnotificationinterface.cpp \
evo/evodb.cpp \ evo/evodb.cpp \
evo/specialtx.cpp \ evo/specialtx.cpp \
evo/providertx.cpp \
httprpc.cpp \ httprpc.cpp \
httpserver.cpp \ httpserver.cpp \
init.cpp \ init.cpp \

122
src/evo/providertx.cpp Normal file
View File

@ -0,0 +1,122 @@
// Copyright (c) 2018 The Dash Core developers
// Distributed under the MIT software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
#include "providertx.h"
#include "specialtx.h"
#include "hash.h"
#include "clientversion.h"
#include "streams.h"
#include "messagesigner.h"
#include "chainparams.h"
#include "validation.h"
#include "univalue.h"
#include "core_io.h"
#include "script/standard.h"
#include "base58.h"
template <typename ProTx>
static bool CheckService(const uint256& proTxHash, const ProTx& proTx, const CBlockIndex* pindexPrev, CValidationState& state)
{
if (proTx.nProtocolVersion < MIN_PROTX_PROTO_VERSION || proTx.nProtocolVersion > MAX_PROTX_PROTO_VERSION)
return state.DoS(10, false, REJECT_INVALID, "bad-protx-proto-version");
if (!proTx.addr.IsValid())
return state.DoS(10, false, REJECT_INVALID, "bad-protx-addr");
if (Params().NetworkIDString() != CBaseChainParams::REGTEST && !proTx.addr.IsRoutable())
return state.DoS(10, false, REJECT_INVALID, "bad-protx-addr");
if (!proTx.addr.IsIPv4())
return state.DoS(10, false, REJECT_INVALID, "bad-protx-addr");
return true;
}
template <typename ProTx>
static bool CheckInputsHashAndSig(const CTransaction &tx, const ProTx& proTx, const CKeyID &keyID, 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);
return true;
}
bool CheckProRegTx(const CTransaction& tx, const CBlockIndex* pindexPrev, CValidationState& state)
{
AssertLockHeld(cs_main);
CProRegTx ptx;
if (!GetTxPayload(tx, ptx))
return state.DoS(100, false, REJECT_INVALID, "bad-tx-payload");
if (ptx.nVersion > CProRegTx::CURRENT_VERSION)
return state.DoS(100, false, REJECT_INVALID, "bad-protx-version");
if (ptx.nCollateralIndex >= tx.vout.size())
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())
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())
return state.DoS(10, false, REJECT_INVALID, "bad-protx-payee");
// 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.nCollateralIndex].scriptPubKey != ptx.scriptPayout)
return state.DoS(10, false, REJECT_INVALID, "bad-protx-payee-collateral");
// It's allowed to set addr/protocolVersion to 0, which will put the MN into PoSe-banned state and require a ProUpServTx to be issues later
// If any of both is set, it must be valid however
if ((ptx.addr != CService() || ptx.nProtocolVersion != 0) && !CheckService(tx.GetHash(), ptx, pindexPrev, state))
return false;
if (ptx.nOperatorReward > 10000)
return state.DoS(10, false, REJECT_INVALID, "bad-protx-operator-reward");
if (!CheckInputsHashAndSig(tx, ptx, ptx.keyIDOwner, state))
return false;
return true;
}
std::string CProRegTx::ToString() const
{
CTxDestination dest;
std::string payee = "unknown";
if (ExtractDestination(scriptPayout, dest)) {
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);
}
void CProRegTx::ToJson(UniValue& obj) const
{
obj.clear();
obj.setObject();
obj.push_back(Pair("version", nVersion));
obj.push_back(Pair("protocolVersion", nProtocolVersion));
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("keyIDVoting", keyIDVoting.ToString()));
CTxDestination dest;
if (ExtractDestination(scriptPayout, dest)) {
CBitcoinAddress bitcoinAddress(dest);
obj.push_back(Pair("payoutAddress", bitcoinAddress.ToString()));
}
obj.push_back(Pair("operatorReward", (double)nOperatorReward / 100));
obj.push_back(Pair("inputsHash", inputsHash.ToString()));
}

62
src/evo/providertx.h Normal file
View File

@ -0,0 +1,62 @@
// Copyright (c) 2018 The Dash Core developers
// Distributed under the MIT software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
#ifndef DASH_PROVIDERTX_H
#define DASH_PROVIDERTX_H
#include "primitives/transaction.h"
#include "consensus/validation.h"
#include "netaddress.h"
#include "pubkey.h"
class CBlockIndex;
class UniValue;
class CProRegTx
{
public:
static const uint16_t CURRENT_VERSION = 1;
public:
uint16_t nVersion{CURRENT_VERSION}; // message version
int32_t nProtocolVersion{0};
uint32_t nCollateralIndex{(uint32_t) - 1};
CService addr;
CKeyID keyIDOwner;
CKeyID keyIDOperator;
CKeyID keyIDVoting;
uint16_t nOperatorReward{0};
CScript scriptPayout;
uint256 inputsHash; // replay protection
std::vector<unsigned char> vchSig;
public:
ADD_SERIALIZE_METHODS;
template <typename Stream, typename Operation>
inline void SerializationOp(Stream& s, Operation ser_action)
{
READWRITE(nVersion);
READWRITE(nProtocolVersion);
READWRITE(nCollateralIndex);
READWRITE(addr);
READWRITE(keyIDOwner);
READWRITE(keyIDOperator);
READWRITE(keyIDVoting);
READWRITE(*(CScriptBase*)(&scriptPayout));
READWRITE(nOperatorReward);
READWRITE(inputsHash);
if (!(s.GetType() & SER_GETHASH)) {
READWRITE(vchSig);
}
}
std::string ToString() const;
void ToJson(UniValue& obj) const;
};
bool CheckProRegTx(const CTransaction& tx, const CBlockIndex* pindexPrev, CValidationState& state);
#endif//DASH_PROVIDERTX_H

View File

@ -24,6 +24,8 @@ bool CheckSpecialTx(const CTransaction& tx, const CBlockIndex* pindexPrev, CVali
} }
switch (tx.nType) { switch (tx.nType) {
case TRANSACTION_PROVIDER_REGISTER:
return CheckProRegTx(tx, pindexPrev, state);
} }
return state.DoS(10, false, REJECT_INVALID, "bad-tx-type"); return state.DoS(10, false, REJECT_INVALID, "bad-tx-type");
@ -35,6 +37,8 @@ bool ProcessSpecialTx(const CTransaction& tx, const CBlockIndex* pindex, CValida
return true; return true;
switch (tx.nType) { switch (tx.nType) {
case TRANSACTION_PROVIDER_REGISTER:
return true; // handled in batches per block
} }
return state.DoS(100, false, REJECT_INVALID, "bad-tx-type"); return state.DoS(100, false, REJECT_INVALID, "bad-tx-type");
@ -46,6 +50,8 @@ bool UndoSpecialTx(const CTransaction& tx, const CBlockIndex* pindex)
return true; return true;
switch (tx.nType) { switch (tx.nType) {
case TRANSACTION_PROVIDER_REGISTER:
return true; // handled in batches per block
} }
return false; return false;

View File

@ -14,6 +14,7 @@
/** Transaction types */ /** Transaction types */
enum { enum {
TRANSACTION_NORMAL = 0, TRANSACTION_NORMAL = 0,
TRANSACTION_PROVIDER_REGISTER = 1,
}; };
/** An outpoint - a combination of a transaction hash and an index n into its vout */ /** An outpoint - a combination of a transaction hash and an index n into its vout */

View File

@ -43,6 +43,7 @@
#include "masternode-payments.h" #include "masternode-payments.h"
#include "evo/specialtx.h" #include "evo/specialtx.h"
#include "evo/providertx.h"
#include <atomic> #include <atomic>
#include <sstream> #include <sstream>
@ -570,7 +571,8 @@ bool ContextualCheckTransaction(const CTransaction& tx, CValidationState &state,
if (fDIP0003Active_context) { if (fDIP0003Active_context) {
// check version 3 transaction types // check version 3 transaction types
if (tx.nVersion >= 3) { if (tx.nVersion >= 3) {
if (tx.nType != TRANSACTION_NORMAL) { if (tx.nType != TRANSACTION_NORMAL &&
tx.nType != TRANSACTION_PROVIDER_REGISTER) {
return state.DoS(100, false, REJECT_INVALID, "bad-txns-type"); return state.DoS(100, false, REJECT_INVALID, "bad-txns-type");
} }
if (tx.IsCoinBase() && tx.nType != TRANSACTION_NORMAL) if (tx.IsCoinBase() && tx.nType != TRANSACTION_NORMAL)

View File

@ -44,4 +44,10 @@ static const int DIP0001_PROTOCOL_VERSION = 70208;
//! short-id-based block download starts with this version //! short-id-based block download starts with this version
static const int SHORT_IDS_BLOCKS_VERSION = 70209; static const int SHORT_IDS_BLOCKS_VERSION = 70209;
//! minimum ProTx proto version
static const int MIN_PROTX_PROTO_VERSION = 70211;
//! maximum ProTx proto version (slightly higher then current PROTOCOL_VERSION to ensure masternodes can upgrade)
static const int MAX_PROTX_PROTO_VERSION = PROTOCOL_VERSION + 2;
#endif // BITCOIN_VERSION_H #endif // BITCOIN_VERSION_H