Implementation of ProRegTx with basic validation (no processing)
This commit is contained in:
parent
c9a72e8880
commit
958b84ace3
@ -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
122
src/evo/providertx.cpp
Normal 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
62
src/evo/providertx.h
Normal 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
|
@ -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;
|
||||||
|
@ -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 */
|
||||||
|
@ -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)
|
||||||
|
@ -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
|
||||||
|
Loading…
Reference in New Issue
Block a user