Implement and enforce CbTx with correct block height and deprecate BIP34
This commit is contained in:
parent
11df4f24de
commit
0a086898f5
@ -110,6 +110,7 @@ BITCOIN_CORE_H = \
|
||||
evo/specialtx.h \
|
||||
evo/providertx.h \
|
||||
evo/deterministicmns.h \
|
||||
evo/cbtx.h \
|
||||
privatesend.h \
|
||||
privatesend-client.h \
|
||||
privatesend-server.h \
|
||||
@ -224,6 +225,7 @@ libdash_server_a_SOURCES = \
|
||||
evo/specialtx.cpp \
|
||||
evo/providertx.cpp \
|
||||
evo/deterministicmns.cpp \
|
||||
evo/cbtx.cpp \
|
||||
httprpc.cpp \
|
||||
httpserver.cpp \
|
||||
init.cpp \
|
||||
|
47
src/evo/cbtx.cpp
Normal file
47
src/evo/cbtx.cpp
Normal file
@ -0,0 +1,47 @@
|
||||
// Copyright (c) 2017 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 "cbtx.h"
|
||||
#include "specialtx.h"
|
||||
#include "deterministicmns.h"
|
||||
|
||||
#include "validation.h"
|
||||
#include "univalue.h"
|
||||
|
||||
bool CheckCbTx(const CTransaction& tx, const CBlockIndex* pindexPrev, CValidationState& state)
|
||||
{
|
||||
AssertLockHeld(cs_main);
|
||||
|
||||
if (!tx.IsCoinBase())
|
||||
return state.DoS(100, false, REJECT_INVALID, "bad-cbtx-invalid");
|
||||
|
||||
CCbTx cbTx;
|
||||
if (!GetTxPayload(tx, cbTx))
|
||||
return state.DoS(100, false, REJECT_INVALID, "bad-tx-payload");
|
||||
|
||||
if (cbTx.nVersion > CCbTx::CURRENT_VERSION)
|
||||
return state.DoS(100, false, REJECT_INVALID, "bad-cbtx-version");
|
||||
|
||||
if (pindexPrev) {
|
||||
if (pindexPrev->nHeight + 1 != cbTx.nHeight)
|
||||
return state.DoS(100, false, REJECT_INVALID, "bad-cbtx-height");
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
std::string CCbTx::ToString() const
|
||||
{
|
||||
return strprintf("CCbTx(nHeight=%d, nVersion=%d, merkleRootMNList=%s)",
|
||||
nVersion, nHeight, merkleRootMNList.ToString());
|
||||
}
|
||||
|
||||
void CCbTx::ToJson(UniValue& obj) const
|
||||
{
|
||||
obj.clear();
|
||||
obj.setObject();
|
||||
obj.push_back(Pair("version", (int)nVersion));
|
||||
obj.push_back(Pair("height", (int)nHeight));
|
||||
obj.push_back(Pair("merkleRootMNList", merkleRootMNList.ToString()));
|
||||
}
|
42
src/evo/cbtx.h
Normal file
42
src/evo/cbtx.h
Normal file
@ -0,0 +1,42 @@
|
||||
// Copyright (c) 2017 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_CBTX_H
|
||||
#define DASH_CBTX_H
|
||||
|
||||
#include "primitives/transaction.h"
|
||||
#include "consensus/validation.h"
|
||||
|
||||
class CBlockIndex;
|
||||
class UniValue;
|
||||
|
||||
// coinbase transaction
|
||||
class CCbTx
|
||||
{
|
||||
public:
|
||||
static const uint16_t CURRENT_VERSION = 1;
|
||||
|
||||
public:
|
||||
uint16_t nVersion{CURRENT_VERSION};
|
||||
int32_t nHeight{0};
|
||||
uint256 merkleRootMNList;
|
||||
|
||||
public:
|
||||
ADD_SERIALIZE_METHODS;
|
||||
|
||||
template <typename Stream, typename Operation>
|
||||
inline void SerializationOp(Stream& s, Operation ser_action)
|
||||
{
|
||||
READWRITE(nVersion);
|
||||
READWRITE(nHeight);
|
||||
READWRITE(merkleRootMNList);
|
||||
}
|
||||
|
||||
std::string ToString() const;
|
||||
void ToJson(UniValue& obj) const;
|
||||
};
|
||||
|
||||
bool CheckCbTx(const CTransaction& tx, const CBlockIndex* pindexPrev, CValidationState& state);
|
||||
|
||||
#endif//DASH_CBTX_H
|
@ -12,6 +12,7 @@
|
||||
|
||||
#include "specialtx.h"
|
||||
#include "deterministicmns.h"
|
||||
#include "cbtx.h"
|
||||
|
||||
bool CheckSpecialTx(const CTransaction& tx, const CBlockIndex* pindexPrev, CValidationState& state)
|
||||
{
|
||||
@ -33,6 +34,8 @@ bool CheckSpecialTx(const CTransaction& tx, const CBlockIndex* pindexPrev, CVali
|
||||
return CheckProUpRegTx(tx, pindexPrev, state);
|
||||
case TRANSACTION_PROVIDER_UPDATE_REVOKE:
|
||||
return CheckProUpRevTx(tx, pindexPrev, state);
|
||||
case TRANSACTION_COINBASE:
|
||||
return CheckCbTx(tx, pindexPrev, state);
|
||||
}
|
||||
|
||||
return state.DoS(10, false, REJECT_INVALID, "bad-tx-type");
|
||||
@ -49,6 +52,8 @@ bool ProcessSpecialTx(const CTransaction& tx, const CBlockIndex* pindex, CValida
|
||||
case TRANSACTION_PROVIDER_UPDATE_REGISTRAR:
|
||||
case TRANSACTION_PROVIDER_UPDATE_REVOKE:
|
||||
return true; // handled in batches per block
|
||||
case TRANSACTION_COINBASE:
|
||||
return true; // nothing to do
|
||||
}
|
||||
|
||||
return state.DoS(100, false, REJECT_INVALID, "bad-tx-type");
|
||||
@ -65,6 +70,8 @@ bool UndoSpecialTx(const CTransaction& tx, const CBlockIndex* pindex)
|
||||
case TRANSACTION_PROVIDER_UPDATE_REGISTRAR:
|
||||
case TRANSACTION_PROVIDER_UPDATE_REVOKE:
|
||||
return true; // handled in batches per block
|
||||
case TRANSACTION_COINBASE:
|
||||
return true; // nothing to do
|
||||
}
|
||||
|
||||
return false;
|
||||
|
@ -28,6 +28,9 @@
|
||||
#include "masternode-sync.h"
|
||||
#include "validationinterface.h"
|
||||
|
||||
#include "evo/specialtx.h"
|
||||
#include "evo/cbtx.h"
|
||||
|
||||
#include <algorithm>
|
||||
#include <boost/thread.hpp>
|
||||
#include <boost/tuple/tuple.hpp>
|
||||
@ -126,6 +129,9 @@ std::unique_ptr<CBlockTemplate> BlockAssembler::CreateNewBlock(const CScript& sc
|
||||
pblocktemplate->vTxSigOps.push_back(-1); // updated at end
|
||||
|
||||
LOCK2(cs_main, mempool.cs);
|
||||
|
||||
bool fDIP0003Active_context = VersionBitsState(chainActive.Tip(), chainparams.GetConsensus(), Consensus::DEPLOYMENT_DIP0003, versionbitscache) == THRESHOLD_ACTIVE;
|
||||
|
||||
CBlockIndex* pindexPrev = chainActive.Tip();
|
||||
nHeight = pindexPrev->nHeight + 1;
|
||||
|
||||
@ -166,7 +172,19 @@ std::unique_ptr<CBlockTemplate> BlockAssembler::CreateNewBlock(const CScript& sc
|
||||
|
||||
// Compute regular coinbase transaction.
|
||||
coinbaseTx.vout[0].nValue = blockReward;
|
||||
coinbaseTx.vin[0].scriptSig = CScript() << nHeight << OP_0;
|
||||
|
||||
if (!fDIP0003Active_context) {
|
||||
coinbaseTx.vin[0].scriptSig = CScript() << nHeight << OP_0;
|
||||
} else {
|
||||
coinbaseTx.vin[0].scriptSig = CScript() << OP_RETURN;
|
||||
|
||||
coinbaseTx.nVersion = 3;
|
||||
coinbaseTx.nType = TRANSACTION_COINBASE;
|
||||
|
||||
CCbTx cbTx;
|
||||
cbTx.nHeight = nHeight;
|
||||
SetTxPayload(coinbaseTx, cbTx);
|
||||
}
|
||||
|
||||
// Update coinbase transaction with additional info about masternode and governance payments,
|
||||
// get some info back to pass to getblocktemplate
|
||||
|
@ -18,6 +18,7 @@ enum {
|
||||
TRANSACTION_PROVIDER_UPDATE_SERVICE = 2,
|
||||
TRANSACTION_PROVIDER_UPDATE_REGISTRAR = 3,
|
||||
TRANSACTION_PROVIDER_UPDATE_REVOKE = 4,
|
||||
TRANSACTION_COINBASE = 5,
|
||||
};
|
||||
|
||||
/** An outpoint - a combination of a transaction hash and an index n into its vout */
|
||||
|
@ -31,6 +31,7 @@
|
||||
|
||||
#include "evo/specialtx.h"
|
||||
#include "evo/providertx.h"
|
||||
#include "evo/cbtx.h"
|
||||
|
||||
#include <stdint.h>
|
||||
|
||||
@ -158,6 +159,13 @@ void TxToJSON(const CTransaction& tx, const uint256 hashBlock, UniValue& entry)
|
||||
proTx.ToJson(proTxObj);
|
||||
entry.push_back(Pair("proUpRevTx", proTxObj));
|
||||
}
|
||||
} else if (tx.nType == TRANSACTION_COINBASE) {
|
||||
CCbTx cbTx;
|
||||
if (GetTxPayload(tx, cbTx)) {
|
||||
UniValue proTxObj;
|
||||
cbTx.ToJson(proTxObj);
|
||||
entry.push_back(Pair("cbTx", proTxObj));
|
||||
}
|
||||
}
|
||||
|
||||
if (!hashBlock.IsNull()) {
|
||||
|
@ -45,6 +45,7 @@
|
||||
#include "evo/specialtx.h"
|
||||
#include "evo/providertx.h"
|
||||
#include "evo/deterministicmns.h"
|
||||
#include "evo/cbtx.h"
|
||||
|
||||
#include <atomic>
|
||||
#include <sstream>
|
||||
@ -550,7 +551,12 @@ bool CheckTransaction(const CTransaction& tx, CValidationState &state, bool fChe
|
||||
|
||||
if (tx.IsCoinBase())
|
||||
{
|
||||
if (tx.vin[0].scriptSig.size() < 2 || tx.vin[0].scriptSig.size() > 100)
|
||||
int minCbSize = 2;
|
||||
if (tx.nType == TRANSACTION_COINBASE) {
|
||||
// With the introduction of CbTx, coinbase scripts are not required anymore to hold a valid block height
|
||||
minCbSize = 1;
|
||||
}
|
||||
if (tx.vin[0].scriptSig.size() < minCbSize || tx.vin[0].scriptSig.size() > 100)
|
||||
return state.DoS(100, false, REJECT_INVALID, "bad-cb-length");
|
||||
}
|
||||
else
|
||||
@ -576,10 +582,11 @@ bool ContextualCheckTransaction(const CTransaction& tx, CValidationState &state,
|
||||
tx.nType != TRANSACTION_PROVIDER_REGISTER &&
|
||||
tx.nType != TRANSACTION_PROVIDER_UPDATE_SERVICE &&
|
||||
tx.nType != TRANSACTION_PROVIDER_UPDATE_REGISTRAR &&
|
||||
tx.nType != TRANSACTION_PROVIDER_UPDATE_REVOKE) {
|
||||
tx.nType != TRANSACTION_PROVIDER_UPDATE_REVOKE &&
|
||||
tx.nType != TRANSACTION_COINBASE) {
|
||||
return state.DoS(100, false, REJECT_INVALID, "bad-txns-type");
|
||||
}
|
||||
if (tx.IsCoinBase() && tx.nType != TRANSACTION_NORMAL)
|
||||
if (tx.IsCoinBase() && tx.nType != TRANSACTION_COINBASE)
|
||||
return state.DoS(100, false, REJECT_INVALID, "bad-txns-cb-type");
|
||||
} else if (tx.nType != TRANSACTION_NORMAL) {
|
||||
return state.DoS(100, false, REJECT_INVALID, "bad-txns-type");
|
||||
@ -3513,6 +3520,7 @@ bool ContextualCheckBlock(const CBlock& block, CValidationState& state, const Co
|
||||
: block.GetBlockTime();
|
||||
|
||||
bool fDIP0001Active_context = nHeight >= Params().GetConsensus().DIP0001Height;
|
||||
bool fDIP0003Active_context = VersionBitsState(pindexPrev, consensusParams, Consensus::DEPLOYMENT_DIP0003, versionbitscache) == THRESHOLD_ACTIVE;
|
||||
|
||||
// Size limits
|
||||
unsigned int nMaxBlockSize = MaxBlockSize(fDIP0001Active_context);
|
||||
@ -3537,7 +3545,9 @@ bool ContextualCheckBlock(const CBlock& block, CValidationState& state, const Co
|
||||
return state.DoS(10, false, REJECT_INVALID, "bad-blk-sigops", false, "out-of-bounds SigOpCount");
|
||||
|
||||
// Enforce rule that the coinbase starts with serialized block height
|
||||
if (nHeight >= consensusParams.BIP34Height)
|
||||
// After DIP3/DIP4 activation, we don't enforce the height in the input script anymore.
|
||||
// The CbTx special transaction payload will then contain the height, which is checked in CheckCbTx
|
||||
if (nHeight >= consensusParams.BIP34Height && !fDIP0003Active_context)
|
||||
{
|
||||
CScript expect = CScript() << nHeight;
|
||||
if (block.vtx[0]->vin[0].scriptSig.size() < expect.size() ||
|
||||
@ -3546,6 +3556,12 @@ bool ContextualCheckBlock(const CBlock& block, CValidationState& state, const Co
|
||||
}
|
||||
}
|
||||
|
||||
if (fDIP0003Active_context) {
|
||||
if (block.vtx[0]->nType != TRANSACTION_COINBASE) {
|
||||
return state.DoS(100, false, REJECT_INVALID, "bad-cb-type", false, "coinbase is not a CbTx");
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user