Implement and enforce CbTx with correct block height and deprecate BIP34

This commit is contained in:
Alexander Block 2018-04-06 11:00:10 +02:00
parent 11df4f24de
commit 0a086898f5
8 changed files with 146 additions and 5 deletions

View File

@ -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
View 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
View 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

View File

@ -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;

View File

@ -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

View File

@ -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 */

View File

@ -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()) {

View File

@ -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;
}