BIP141: Commitment structure and deployment
Includes a fix by Suhas Daftuar and LongShao007
This commit is contained in:
parent
449f9b8deb
commit
8b49040854
13 changed files with 225 additions and 13 deletions
|
@ -92,6 +92,11 @@ public:
|
||||||
consensus.vDeployments[Consensus::DEPLOYMENT_CSV].nStartTime = 1462060800; // May 1st, 2016
|
consensus.vDeployments[Consensus::DEPLOYMENT_CSV].nStartTime = 1462060800; // May 1st, 2016
|
||||||
consensus.vDeployments[Consensus::DEPLOYMENT_CSV].nTimeout = 1493596800; // May 1st, 2017
|
consensus.vDeployments[Consensus::DEPLOYMENT_CSV].nTimeout = 1493596800; // May 1st, 2017
|
||||||
|
|
||||||
|
// Deployment of SegWit (BIP141 and BIP143)
|
||||||
|
consensus.vDeployments[Consensus::DEPLOYMENT_SEGWIT].bit = 1;
|
||||||
|
consensus.vDeployments[Consensus::DEPLOYMENT_SEGWIT].nStartTime = 0;
|
||||||
|
consensus.vDeployments[Consensus::DEPLOYMENT_SEGWIT].nTimeout = 0; // Never / undefined
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* The message start string is designed to be unlikely to occur in normal data.
|
* The message start string is designed to be unlikely to occur in normal data.
|
||||||
* The characters are rarely used upper ASCII, not valid as UTF-8, and produce
|
* The characters are rarely used upper ASCII, not valid as UTF-8, and produce
|
||||||
|
@ -183,6 +188,11 @@ public:
|
||||||
consensus.vDeployments[Consensus::DEPLOYMENT_CSV].nStartTime = 1456790400; // March 1st, 2016
|
consensus.vDeployments[Consensus::DEPLOYMENT_CSV].nStartTime = 1456790400; // March 1st, 2016
|
||||||
consensus.vDeployments[Consensus::DEPLOYMENT_CSV].nTimeout = 1493596800; // May 1st, 2017
|
consensus.vDeployments[Consensus::DEPLOYMENT_CSV].nTimeout = 1493596800; // May 1st, 2017
|
||||||
|
|
||||||
|
// Deployment of SegWit (BIP141 and BIP143)
|
||||||
|
consensus.vDeployments[Consensus::DEPLOYMENT_SEGWIT].bit = 1;
|
||||||
|
consensus.vDeployments[Consensus::DEPLOYMENT_SEGWIT].nStartTime = 2000000000; // Far in the future
|
||||||
|
consensus.vDeployments[Consensus::DEPLOYMENT_SEGWIT].nTimeout = 2100000000;
|
||||||
|
|
||||||
pchMessageStart[0] = 0x0b;
|
pchMessageStart[0] = 0x0b;
|
||||||
pchMessageStart[1] = 0x11;
|
pchMessageStart[1] = 0x11;
|
||||||
pchMessageStart[2] = 0x09;
|
pchMessageStart[2] = 0x09;
|
||||||
|
@ -255,6 +265,9 @@ public:
|
||||||
consensus.vDeployments[Consensus::DEPLOYMENT_CSV].bit = 0;
|
consensus.vDeployments[Consensus::DEPLOYMENT_CSV].bit = 0;
|
||||||
consensus.vDeployments[Consensus::DEPLOYMENT_CSV].nStartTime = 0;
|
consensus.vDeployments[Consensus::DEPLOYMENT_CSV].nStartTime = 0;
|
||||||
consensus.vDeployments[Consensus::DEPLOYMENT_CSV].nTimeout = 999999999999ULL;
|
consensus.vDeployments[Consensus::DEPLOYMENT_CSV].nTimeout = 999999999999ULL;
|
||||||
|
consensus.vDeployments[Consensus::DEPLOYMENT_SEGWIT].bit = 1;
|
||||||
|
consensus.vDeployments[Consensus::DEPLOYMENT_SEGWIT].nStartTime = 0;
|
||||||
|
consensus.vDeployments[Consensus::DEPLOYMENT_SEGWIT].nTimeout = 999999999999ULL;
|
||||||
|
|
||||||
pchMessageStart[0] = 0xfa;
|
pchMessageStart[0] = 0xfa;
|
||||||
pchMessageStart[1] = 0xbf;
|
pchMessageStart[1] = 0xbf;
|
||||||
|
@ -317,3 +330,4 @@ void SelectParams(const std::string& network)
|
||||||
SelectBaseParams(network);
|
SelectBaseParams(network);
|
||||||
pCurrentParams = &Params(network);
|
pCurrentParams = &Params(network);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -165,6 +165,17 @@ uint256 BlockMerkleRoot(const CBlock& block, bool* mutated)
|
||||||
return ComputeMerkleRoot(leaves, mutated);
|
return ComputeMerkleRoot(leaves, mutated);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
uint256 BlockWitnessMerkleRoot(const CBlock& block, bool* mutated)
|
||||||
|
{
|
||||||
|
std::vector<uint256> leaves;
|
||||||
|
leaves.resize(block.vtx.size());
|
||||||
|
leaves[0].SetNull(); // The witness hash of the coinbase is 0.
|
||||||
|
for (size_t s = 1; s < block.vtx.size(); s++) {
|
||||||
|
leaves[s] = block.vtx[s].GetWitnessHash();
|
||||||
|
}
|
||||||
|
return ComputeMerkleRoot(leaves, mutated);
|
||||||
|
}
|
||||||
|
|
||||||
std::vector<uint256> BlockMerkleBranch(const CBlock& block, uint32_t position)
|
std::vector<uint256> BlockMerkleBranch(const CBlock& block, uint32_t position)
|
||||||
{
|
{
|
||||||
std::vector<uint256> leaves;
|
std::vector<uint256> leaves;
|
||||||
|
|
|
@ -22,6 +22,12 @@ uint256 ComputeMerkleRootFromBranch(const uint256& leaf, const std::vector<uint2
|
||||||
*/
|
*/
|
||||||
uint256 BlockMerkleRoot(const CBlock& block, bool* mutated = NULL);
|
uint256 BlockMerkleRoot(const CBlock& block, bool* mutated = NULL);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Compute the Merkle root of the witness transactions in a block.
|
||||||
|
* *mutated is set to true if a duplicated subtree was found.
|
||||||
|
*/
|
||||||
|
uint256 BlockWitnessMerkleRoot(const CBlock& block, bool* mutated = NULL);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Compute the Merkle branch for the tree of transactions in a block, for a
|
* Compute the Merkle branch for the tree of transactions in a block, for a
|
||||||
* given position.
|
* given position.
|
||||||
|
|
|
@ -16,6 +16,7 @@ enum DeploymentPos
|
||||||
{
|
{
|
||||||
DEPLOYMENT_TESTDUMMY,
|
DEPLOYMENT_TESTDUMMY,
|
||||||
DEPLOYMENT_CSV, // Deployment of BIP68, BIP112, and BIP113.
|
DEPLOYMENT_CSV, // Deployment of BIP68, BIP112, and BIP113.
|
||||||
|
DEPLOYMENT_SEGWIT, // Deployment of BIP141 and BIP143
|
||||||
// NOTE: Also add new deployments to VersionBitsDeploymentInfo in versionbits.cpp
|
// NOTE: Also add new deployments to VersionBitsDeploymentInfo in versionbits.cpp
|
||||||
MAX_VERSION_BITS_DEPLOYMENTS
|
MAX_VERSION_BITS_DEPLOYMENTS
|
||||||
};
|
};
|
||||||
|
|
|
@ -77,6 +77,9 @@ public:
|
||||||
bool CorruptionPossible() const {
|
bool CorruptionPossible() const {
|
||||||
return corruptionPossible;
|
return corruptionPossible;
|
||||||
}
|
}
|
||||||
|
void SetCorruptionPossible() {
|
||||||
|
corruptionPossible = true;
|
||||||
|
}
|
||||||
unsigned int GetRejectCode() const { return chRejectCode; }
|
unsigned int GetRejectCode() const { return chRejectCode; }
|
||||||
std::string GetRejectReason() const { return strRejectReason; }
|
std::string GetRejectReason() const { return strRejectReason; }
|
||||||
std::string GetDebugMessage() const { return strDebugMessage; }
|
std::string GetDebugMessage() const { return strDebugMessage; }
|
||||||
|
|
138
src/main.cpp
138
src/main.cpp
|
@ -293,6 +293,8 @@ struct CNodeState {
|
||||||
bool fPreferHeaderAndIDs;
|
bool fPreferHeaderAndIDs;
|
||||||
//! Whether this peer will send us cmpctblocks if we request them
|
//! Whether this peer will send us cmpctblocks if we request them
|
||||||
bool fProvidesHeaderAndIDs;
|
bool fProvidesHeaderAndIDs;
|
||||||
|
//! Whether this peer can give us witnesses
|
||||||
|
bool fHaveWitness;
|
||||||
|
|
||||||
CNodeState() {
|
CNodeState() {
|
||||||
fCurrentlyConnected = false;
|
fCurrentlyConnected = false;
|
||||||
|
@ -1119,6 +1121,11 @@ bool AcceptToMemoryPoolWorker(CTxMemPool& pool, CValidationState& state, const C
|
||||||
return state.DoS(0, false, REJECT_NONSTANDARD, "premature-version2-tx");
|
return state.DoS(0, false, REJECT_NONSTANDARD, "premature-version2-tx");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Don't accept witness transactions before the final threshold passes
|
||||||
|
if (!tx.wit.IsNull() && !IsWitnessEnabled(chainActive.Tip(), Params().GetConsensus())) {
|
||||||
|
return state.DoS(0, false, REJECT_NONSTANDARD, "no-witness-yet", true);
|
||||||
|
}
|
||||||
|
|
||||||
// Only accept nLockTime-using transactions that can be mined in the next
|
// Only accept nLockTime-using transactions that can be mined in the next
|
||||||
// block; we don't want our mempool filled up with transactions that can't
|
// block; we don't want our mempool filled up with transactions that can't
|
||||||
// be mined yet.
|
// be mined yet.
|
||||||
|
@ -1459,8 +1466,17 @@ bool AcceptToMemoryPoolWorker(CTxMemPool& pool, CValidationState& state, const C
|
||||||
|
|
||||||
// Check against previous transactions
|
// Check against previous transactions
|
||||||
// This is done last to help prevent CPU exhaustion denial-of-service attacks.
|
// This is done last to help prevent CPU exhaustion denial-of-service attacks.
|
||||||
if (!CheckInputs(tx, state, view, true, STANDARD_SCRIPT_VERIFY_FLAGS, true))
|
if (!CheckInputs(tx, state, view, true, STANDARD_SCRIPT_VERIFY_FLAGS, true)) {
|
||||||
return false; // state filled in by CheckInputs
|
// SCRIPT_VERIFY_CLEANSTACK requires SCRIPT_VERIFY_WITNESS, so we
|
||||||
|
// need to turn both off, and compare against just turning off CLEANSTACK
|
||||||
|
// to see if the failure is specifically due to witness validation.
|
||||||
|
if (CheckInputs(tx, state, view, true, STANDARD_SCRIPT_VERIFY_FLAGS & ~(SCRIPT_VERIFY_WITNESS | SCRIPT_VERIFY_CLEANSTACK), true) &&
|
||||||
|
!CheckInputs(tx, state, view, true, STANDARD_SCRIPT_VERIFY_FLAGS & ~SCRIPT_VERIFY_CLEANSTACK, true)) {
|
||||||
|
// Only the witness is wrong, so the transaction itself may be fine.
|
||||||
|
state.SetCorruptionPossible();
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
// Check again against just the consensus-critical mandatory script
|
// Check again against just the consensus-critical mandatory script
|
||||||
// verification flags, in case of bugs in the standard flags that cause
|
// verification flags, in case of bugs in the standard flags that cause
|
||||||
|
@ -2406,6 +2422,11 @@ bool ConnectBlock(const CBlock& block, CValidationState& state, CBlockIndex* pin
|
||||||
nLockTimeFlags |= LOCKTIME_VERIFY_SEQUENCE;
|
nLockTimeFlags |= LOCKTIME_VERIFY_SEQUENCE;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Start enforcing WITNESS rules using versionbits logic.
|
||||||
|
if (IsWitnessEnabled(pindex->pprev, chainparams.GetConsensus())) {
|
||||||
|
flags |= SCRIPT_VERIFY_WITNESS;
|
||||||
|
}
|
||||||
|
|
||||||
int64_t nTime2 = GetTimeMicros(); nTimeForks += nTime2 - nTime1;
|
int64_t nTime2 = GetTimeMicros(); nTimeForks += nTime2 - nTime1;
|
||||||
LogPrint("bench", " - Fork checks: %.2fms [%.2fs]\n", 0.001 * (nTime2 - nTime1), nTimeForks * 0.000001);
|
LogPrint("bench", " - Fork checks: %.2fms [%.2fs]\n", 0.001 * (nTime2 - nTime1), nTimeForks * 0.000001);
|
||||||
|
|
||||||
|
@ -3441,6 +3462,71 @@ static bool CheckIndexAgainstCheckpoint(const CBlockIndex* pindexPrev, CValidati
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool IsWitnessEnabled(const CBlockIndex* pindexPrev, const Consensus::Params& params)
|
||||||
|
{
|
||||||
|
LOCK(cs_main);
|
||||||
|
return (VersionBitsState(pindexPrev, params, Consensus::DEPLOYMENT_SEGWIT, versionbitscache) == THRESHOLD_ACTIVE);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Compute at which vout of the block's coinbase transaction the witness
|
||||||
|
// commitment occurs, or -1 if not found.
|
||||||
|
static int GetWitnessCommitmentIndex(const CBlock& block)
|
||||||
|
{
|
||||||
|
int commitpos = -1;
|
||||||
|
for (size_t o = 0; o < block.vtx[0].vout.size(); o++) {
|
||||||
|
if (block.vtx[0].vout[o].scriptPubKey.size() >= 38 && block.vtx[0].vout[o].scriptPubKey[0] == OP_RETURN && block.vtx[0].vout[o].scriptPubKey[1] == 0x24 && block.vtx[0].vout[o].scriptPubKey[2] == 0xaa && block.vtx[0].vout[o].scriptPubKey[3] == 0x21 && block.vtx[0].vout[o].scriptPubKey[4] == 0xa9 && block.vtx[0].vout[o].scriptPubKey[5] == 0xed) {
|
||||||
|
commitpos = o;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return commitpos;
|
||||||
|
}
|
||||||
|
|
||||||
|
void UpdateUncommittedBlockStructures(CBlock& block, const CBlockIndex* pindexPrev, const Consensus::Params& consensusParams)
|
||||||
|
{
|
||||||
|
int commitpos = GetWitnessCommitmentIndex(block);
|
||||||
|
static const std::vector<unsigned char> nonce(32, 0x00);
|
||||||
|
if (commitpos != -1 && IsWitnessEnabled(pindexPrev, consensusParams) && block.vtx[0].wit.IsEmpty()) {
|
||||||
|
block.vtx[0].wit.vtxinwit.resize(1);
|
||||||
|
block.vtx[0].wit.vtxinwit[0].scriptWitness.stack.resize(1);
|
||||||
|
block.vtx[0].wit.vtxinwit[0].scriptWitness.stack[0] = nonce;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
std::vector<unsigned char> GenerateCoinbaseCommitment(CBlock& block, const CBlockIndex* pindexPrev, const Consensus::Params& consensusParams)
|
||||||
|
{
|
||||||
|
std::vector<unsigned char> commitment;
|
||||||
|
int commitpos = GetWitnessCommitmentIndex(block);
|
||||||
|
bool fHaveWitness = false;
|
||||||
|
for (size_t t = 1; t < block.vtx.size(); t++) {
|
||||||
|
if (!block.vtx[t].wit.IsNull()) {
|
||||||
|
fHaveWitness = true;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
std::vector<unsigned char> ret(32, 0x00);
|
||||||
|
if (fHaveWitness && IsWitnessEnabled(pindexPrev, consensusParams)) {
|
||||||
|
if (commitpos == -1) {
|
||||||
|
uint256 witnessroot = BlockWitnessMerkleRoot(block, NULL);
|
||||||
|
CHash256().Write(witnessroot.begin(), 32).Write(&ret[0], 32).Finalize(witnessroot.begin());
|
||||||
|
CTxOut out;
|
||||||
|
out.nValue = 0;
|
||||||
|
out.scriptPubKey.resize(38);
|
||||||
|
out.scriptPubKey[0] = OP_RETURN;
|
||||||
|
out.scriptPubKey[1] = 0x24;
|
||||||
|
out.scriptPubKey[2] = 0xaa;
|
||||||
|
out.scriptPubKey[3] = 0x21;
|
||||||
|
out.scriptPubKey[4] = 0xa9;
|
||||||
|
out.scriptPubKey[5] = 0xed;
|
||||||
|
memcpy(&out.scriptPubKey[6], witnessroot.begin(), 32);
|
||||||
|
commitment = std::vector<unsigned char>(out.scriptPubKey.begin(), out.scriptPubKey.end());
|
||||||
|
const_cast<std::vector<CTxOut>*>(&block.vtx[0].vout)->push_back(out);
|
||||||
|
block.vtx[0].UpdateHash();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
UpdateUncommittedBlockStructures(block, pindexPrev, consensusParams);
|
||||||
|
return commitment;
|
||||||
|
}
|
||||||
|
|
||||||
bool ContextualCheckBlockHeader(const CBlockHeader& block, CValidationState& state, const Consensus::Params& consensusParams, CBlockIndex * const pindexPrev, int64_t nAdjustedTime)
|
bool ContextualCheckBlockHeader(const CBlockHeader& block, CValidationState& state, const Consensus::Params& consensusParams, CBlockIndex * const pindexPrev, int64_t nAdjustedTime)
|
||||||
{
|
{
|
||||||
// Check proof of work
|
// Check proof of work
|
||||||
|
@ -3497,6 +3583,43 @@ bool ContextualCheckBlock(const CBlock& block, CValidationState& state, CBlockIn
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Validation for witness commitments.
|
||||||
|
// * We compute the witness hash (which is the hash including witnesses) of all the block's transactions, except the
|
||||||
|
// coinbase (where 0x0000....0000 is used instead).
|
||||||
|
// * The coinbase scriptWitness is a stack of a single 32-byte vector, containing a witness nonce (unconstrained).
|
||||||
|
// * We build a merkle tree with all those witness hashes as leaves (similar to the hashMerkleRoot in the block header).
|
||||||
|
// * There must be at least one output whose scriptPubKey is a single 36-byte push, the first 4 bytes of which are
|
||||||
|
// {0xaa, 0x21, 0xa9, 0xed}, and the following 32 bytes are SHA256^2(witness root, witness nonce). In case there are
|
||||||
|
// multiple, the last one is used.
|
||||||
|
bool fHaveWitness = false;
|
||||||
|
if (IsWitnessEnabled(pindexPrev, consensusParams)) {
|
||||||
|
int commitpos = GetWitnessCommitmentIndex(block);
|
||||||
|
if (commitpos != -1) {
|
||||||
|
bool malleated = false;
|
||||||
|
uint256 hashWitness = BlockWitnessMerkleRoot(block, &malleated);
|
||||||
|
// The malleation check is ignored; as the transaction tree itself
|
||||||
|
// already does not permit it, it is impossible to trigger in the
|
||||||
|
// witness tree.
|
||||||
|
if (block.vtx[0].wit.vtxinwit.size() != 1 || block.vtx[0].wit.vtxinwit[0].scriptWitness.stack.size() != 1 || block.vtx[0].wit.vtxinwit[0].scriptWitness.stack[0].size() != 32) {
|
||||||
|
return state.DoS(100, error("%s : invalid witness nonce size", __func__), REJECT_INVALID, "bad-witness-nonce-size", true);
|
||||||
|
}
|
||||||
|
CHash256().Write(hashWitness.begin(), 32).Write(&block.vtx[0].wit.vtxinwit[0].scriptWitness.stack[0][0], 32).Finalize(hashWitness.begin());
|
||||||
|
if (memcmp(hashWitness.begin(), &block.vtx[0].vout[commitpos].scriptPubKey[6], 32)) {
|
||||||
|
return state.DoS(100, error("%s : witness merkle commitment mismatch", __func__), REJECT_INVALID, "bad-witness-merkle-match", true);
|
||||||
|
}
|
||||||
|
fHaveWitness = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// No witness data is allowed in blocks that don't commit to witness data, as this would otherwise leave room for spam
|
||||||
|
if (!fHaveWitness) {
|
||||||
|
for (size_t i = 0; i < block.vtx.size(); i++) {
|
||||||
|
if (!block.vtx[i].wit.IsNull()) {
|
||||||
|
return state.DoS(100, error("%s : unexpected witness data found", __func__), REJECT_INVALID, "unexpected-witness", true);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -5278,7 +5401,7 @@ bool static ProcessMessage(CNode* pfrom, string strCommand, CDataStream& vRecv,
|
||||||
else if (!fMissingInputs2)
|
else if (!fMissingInputs2)
|
||||||
{
|
{
|
||||||
int nDos = 0;
|
int nDos = 0;
|
||||||
if (stateDummy.IsInvalid(nDos) && nDos > 0)
|
if (stateDummy.IsInvalid(nDos) && nDos > 0 && (!state.CorruptionPossible() || State(fromPeer)->fHaveWitness))
|
||||||
{
|
{
|
||||||
// Punish peer that gave us an invalid orphan tx
|
// Punish peer that gave us an invalid orphan tx
|
||||||
Misbehaving(fromPeer, nDos);
|
Misbehaving(fromPeer, nDos);
|
||||||
|
@ -5289,9 +5412,11 @@ bool static ProcessMessage(CNode* pfrom, string strCommand, CDataStream& vRecv,
|
||||||
// Probably non-standard or insufficient fee/priority
|
// Probably non-standard or insufficient fee/priority
|
||||||
LogPrint("mempool", " removed orphan tx %s\n", orphanHash.ToString());
|
LogPrint("mempool", " removed orphan tx %s\n", orphanHash.ToString());
|
||||||
vEraseQueue.push_back(orphanHash);
|
vEraseQueue.push_back(orphanHash);
|
||||||
|
if (!stateDummy.CorruptionPossible()) {
|
||||||
assert(recentRejects);
|
assert(recentRejects);
|
||||||
recentRejects->insert(orphanHash);
|
recentRejects->insert(orphanHash);
|
||||||
}
|
}
|
||||||
|
}
|
||||||
mempool.check(pcoinsTip);
|
mempool.check(pcoinsTip);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -5325,8 +5450,10 @@ bool static ProcessMessage(CNode* pfrom, string strCommand, CDataStream& vRecv,
|
||||||
LogPrint("mempool", "not keeping orphan with rejected parents %s\n",tx.GetHash().ToString());
|
LogPrint("mempool", "not keeping orphan with rejected parents %s\n",tx.GetHash().ToString());
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
|
if (!state.CorruptionPossible()) {
|
||||||
assert(recentRejects);
|
assert(recentRejects);
|
||||||
recentRejects->insert(tx.GetHash());
|
recentRejects->insert(tx.GetHash());
|
||||||
|
}
|
||||||
|
|
||||||
if (pfrom->fWhitelisted && GetBoolArg("-whitelistforcerelay", DEFAULT_WHITELISTFORCERELAY)) {
|
if (pfrom->fWhitelisted && GetBoolArg("-whitelistforcerelay", DEFAULT_WHITELISTFORCERELAY)) {
|
||||||
// Always relay transactions received from whitelisted peers, even
|
// Always relay transactions received from whitelisted peers, even
|
||||||
|
@ -5355,9 +5482,12 @@ bool static ProcessMessage(CNode* pfrom, string strCommand, CDataStream& vRecv,
|
||||||
if (state.GetRejectCode() < REJECT_INTERNAL) // Never send AcceptToMemoryPool's internal codes over P2P
|
if (state.GetRejectCode() < REJECT_INTERNAL) // Never send AcceptToMemoryPool's internal codes over P2P
|
||||||
pfrom->PushMessage(NetMsgType::REJECT, strCommand, (unsigned char)state.GetRejectCode(),
|
pfrom->PushMessage(NetMsgType::REJECT, strCommand, (unsigned char)state.GetRejectCode(),
|
||||||
state.GetRejectReason().substr(0, MAX_REJECT_MESSAGE_LENGTH), inv.hash);
|
state.GetRejectReason().substr(0, MAX_REJECT_MESSAGE_LENGTH), inv.hash);
|
||||||
if (nDoS > 0)
|
if (nDoS > 0 && (!state.CorruptionPossible() || State(pfrom->id)->fHaveWitness)) {
|
||||||
|
// When a non-witness-supporting peer gives us a transaction that would
|
||||||
|
// be accepted if witness validation was off, we can't blame them for it.
|
||||||
Misbehaving(pfrom->GetId(), nDoS);
|
Misbehaving(pfrom->GetId(), nDoS);
|
||||||
}
|
}
|
||||||
|
}
|
||||||
FlushStateToDisk(state, FLUSH_STATE_PERIODIC);
|
FlushStateToDisk(state, FLUSH_STATE_PERIODIC);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -453,6 +453,15 @@ bool DisconnectBlock(const CBlock& block, CValidationState& state, const CBlockI
|
||||||
/** Check a block is completely valid from start to finish (only works on top of our current best block, with cs_main held) */
|
/** Check a block is completely valid from start to finish (only works on top of our current best block, with cs_main held) */
|
||||||
bool TestBlockValidity(CValidationState& state, const CChainParams& chainparams, const CBlock& block, CBlockIndex* pindexPrev, bool fCheckPOW = true, bool fCheckMerkleRoot = true);
|
bool TestBlockValidity(CValidationState& state, const CChainParams& chainparams, const CBlock& block, CBlockIndex* pindexPrev, bool fCheckPOW = true, bool fCheckMerkleRoot = true);
|
||||||
|
|
||||||
|
/** Check whether witness commitments are required for block. */
|
||||||
|
bool IsWitnessEnabled(const CBlockIndex* pindexPrev, const Consensus::Params& params);
|
||||||
|
|
||||||
|
/** Update uncommitted block structures (currently: only the witness nonce). This is safe for submitted blocks. */
|
||||||
|
void UpdateUncommittedBlockStructures(CBlock& block, const CBlockIndex* pindexPrev, const Consensus::Params& consensusParams);
|
||||||
|
|
||||||
|
/** Produce the necessary coinbase commitment for a block (modifies the hash, don't call for mined blocks). */
|
||||||
|
std::vector<unsigned char> GenerateCoinbaseCommitment(CBlock& block, const CBlockIndex* pindexPrev, const Consensus::Params& consensusParams);
|
||||||
|
|
||||||
/** RAII wrapper for VerifyDB: Verify consistency of the block and coin databases */
|
/** RAII wrapper for VerifyDB: Verify consistency of the block and coin databases */
|
||||||
class CVerifyDB {
|
class CVerifyDB {
|
||||||
public:
|
public:
|
||||||
|
|
|
@ -93,6 +93,7 @@ void BlockAssembler::resetBlock()
|
||||||
// Reserve space for coinbase tx
|
// Reserve space for coinbase tx
|
||||||
nBlockSize = 1000;
|
nBlockSize = 1000;
|
||||||
nBlockSigOps = 100;
|
nBlockSigOps = 100;
|
||||||
|
fIncludeWitness = false;
|
||||||
|
|
||||||
// These counters do not include coinbase tx
|
// These counters do not include coinbase tx
|
||||||
nBlockTx = 0;
|
nBlockTx = 0;
|
||||||
|
@ -134,6 +135,14 @@ CBlockTemplate* BlockAssembler::CreateNewBlock(const CScript& scriptPubKeyIn)
|
||||||
? nMedianTimePast
|
? nMedianTimePast
|
||||||
: pblock->GetBlockTime();
|
: pblock->GetBlockTime();
|
||||||
|
|
||||||
|
// Decide whether to include witness transactions
|
||||||
|
// This is only needed in case the witness softfork activation is reverted
|
||||||
|
// (which would require a very deep reorganization) or when
|
||||||
|
// -promiscuousmempoolflags is used.
|
||||||
|
// TODO: replace this with a call to main to assess validity of a mempool
|
||||||
|
// transaction (which in most cases can be a no-op).
|
||||||
|
fIncludeWitness = IsWitnessEnabled(pindexPrev, chainparams.GetConsensus());
|
||||||
|
|
||||||
addPriorityTxs();
|
addPriorityTxs();
|
||||||
addPackageTxs();
|
addPackageTxs();
|
||||||
|
|
||||||
|
@ -150,6 +159,7 @@ CBlockTemplate* BlockAssembler::CreateNewBlock(const CScript& scriptPubKeyIn)
|
||||||
coinbaseTx.vout[0].nValue = nFees + GetBlockSubsidy(nHeight, chainparams.GetConsensus());
|
coinbaseTx.vout[0].nValue = nFees + GetBlockSubsidy(nHeight, chainparams.GetConsensus());
|
||||||
coinbaseTx.vin[0].scriptSig = CScript() << nHeight << OP_0;
|
coinbaseTx.vin[0].scriptSig = CScript() << nHeight << OP_0;
|
||||||
pblock->vtx[0] = coinbaseTx;
|
pblock->vtx[0] = coinbaseTx;
|
||||||
|
pblocktemplate->vchCoinbaseCommitment = GenerateCoinbaseCommitment(*pblock, pindexPrev, chainparams.GetConsensus());
|
||||||
pblocktemplate->vTxFees[0] = -nFees;
|
pblocktemplate->vTxFees[0] = -nFees;
|
||||||
|
|
||||||
// Fill in header
|
// Fill in header
|
||||||
|
@ -299,6 +309,10 @@ void BlockAssembler::addScoreTxs()
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// cannot accept witness transactions into a non-witness block
|
||||||
|
if (!fIncludeWitness && !iter->GetTx().wit.IsNull())
|
||||||
|
continue;
|
||||||
|
|
||||||
// If tx is dependent on other mempool txs which haven't yet been included
|
// If tx is dependent on other mempool txs which haven't yet been included
|
||||||
// then put it in the waitSet
|
// then put it in the waitSet
|
||||||
if (isStillDependent(iter)) {
|
if (isStillDependent(iter)) {
|
||||||
|
@ -543,6 +557,10 @@ void BlockAssembler::addPriorityTxs()
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// cannot accept witness transactions into a non-witness block
|
||||||
|
if (!fIncludeWitness && !iter->GetTx().wit.IsNull())
|
||||||
|
continue;
|
||||||
|
|
||||||
// If tx is dependent on other mempool txs which haven't yet been included
|
// If tx is dependent on other mempool txs which haven't yet been included
|
||||||
// then put it in the waitSet
|
// then put it in the waitSet
|
||||||
if (isStillDependent(iter)) {
|
if (isStillDependent(iter)) {
|
||||||
|
|
|
@ -29,6 +29,7 @@ struct CBlockTemplate
|
||||||
CBlock block;
|
CBlock block;
|
||||||
std::vector<CAmount> vTxFees;
|
std::vector<CAmount> vTxFees;
|
||||||
std::vector<int64_t> vTxSigOps;
|
std::vector<int64_t> vTxSigOps;
|
||||||
|
std::vector<unsigned char> vchCoinbaseCommitment;
|
||||||
};
|
};
|
||||||
|
|
||||||
// Container for tracking updates to ancestor feerate as we include (parent)
|
// Container for tracking updates to ancestor feerate as we include (parent)
|
||||||
|
@ -139,6 +140,7 @@ private:
|
||||||
CBlock* pblock;
|
CBlock* pblock;
|
||||||
|
|
||||||
// Configuration parameters for the block size
|
// Configuration parameters for the block size
|
||||||
|
bool fIncludeWitness;
|
||||||
unsigned int nBlockMaxSize, nBlockMinSize;
|
unsigned int nBlockMaxSize, nBlockMinSize;
|
||||||
|
|
||||||
// Information on the current status of the block
|
// Information on the current status of the block
|
||||||
|
|
|
@ -335,7 +335,6 @@ class CTransaction
|
||||||
private:
|
private:
|
||||||
/** Memory only. */
|
/** Memory only. */
|
||||||
const uint256 hash;
|
const uint256 hash;
|
||||||
void UpdateHash() const;
|
|
||||||
|
|
||||||
public:
|
public:
|
||||||
// Default transaction version.
|
// Default transaction version.
|
||||||
|
@ -414,6 +413,8 @@ public:
|
||||||
}
|
}
|
||||||
|
|
||||||
std::string ToString() const;
|
std::string ToString() const;
|
||||||
|
|
||||||
|
void UpdateHash() const;
|
||||||
};
|
};
|
||||||
|
|
||||||
/** A mutable version of CTransaction. */
|
/** A mutable version of CTransaction. */
|
||||||
|
|
|
@ -930,6 +930,7 @@ UniValue getblockchaininfo(const UniValue& params, bool fHelp)
|
||||||
softforks.push_back(SoftForkDesc("bip66", 3, tip, consensusParams));
|
softforks.push_back(SoftForkDesc("bip66", 3, tip, consensusParams));
|
||||||
softforks.push_back(SoftForkDesc("bip65", 4, tip, consensusParams));
|
softforks.push_back(SoftForkDesc("bip65", 4, tip, consensusParams));
|
||||||
bip9_softforks.push_back(Pair("csv", BIP9SoftForkDesc(consensusParams, Consensus::DEPLOYMENT_CSV)));
|
bip9_softforks.push_back(Pair("csv", BIP9SoftForkDesc(consensusParams, Consensus::DEPLOYMENT_CSV)));
|
||||||
|
bip9_softforks.push_back(Pair("segwit", BIP9SoftForkDesc(consensusParams, Consensus::DEPLOYMENT_SEGWIT)));
|
||||||
obj.push_back(Pair("softforks", softforks));
|
obj.push_back(Pair("softforks", softforks));
|
||||||
obj.push_back(Pair("bip9_softforks", bip9_softforks));
|
obj.push_back(Pair("bip9_softforks", bip9_softforks));
|
||||||
|
|
||||||
|
|
|
@ -348,7 +348,8 @@ UniValue getblocktemplate(const UniValue& params, bool fHelp)
|
||||||
" \"transactions\" : [ (array) contents of non-coinbase transactions that should be included in the next block\n"
|
" \"transactions\" : [ (array) contents of non-coinbase transactions that should be included in the next block\n"
|
||||||
" {\n"
|
" {\n"
|
||||||
" \"data\" : \"xxxx\", (string) transaction data encoded in hexadecimal (byte-for-byte)\n"
|
" \"data\" : \"xxxx\", (string) transaction data encoded in hexadecimal (byte-for-byte)\n"
|
||||||
" \"hash\" : \"xxxx\", (string) hash/id encoded in little-endian hexadecimal\n"
|
" \"txid\" : \"xxxx\", (string) transaction id encoded in little-endian hexadecimal\n"
|
||||||
|
" \"hash\" : \"xxxx\", (string) hash encoded in little-endian hexadecimal\n"
|
||||||
" \"depends\" : [ (array) array of numbers \n"
|
" \"depends\" : [ (array) array of numbers \n"
|
||||||
" n (numeric) transactions before this one (by 1-based index in 'transactions' list) that must be present in the final block if this one is\n"
|
" n (numeric) transactions before this one (by 1-based index in 'transactions' list) that must be present in the final block if this one is\n"
|
||||||
" ,...\n"
|
" ,...\n"
|
||||||
|
@ -546,7 +547,7 @@ UniValue getblocktemplate(const UniValue& params, bool fHelp)
|
||||||
UniValue transactions(UniValue::VARR);
|
UniValue transactions(UniValue::VARR);
|
||||||
map<uint256, int64_t> setTxIndex;
|
map<uint256, int64_t> setTxIndex;
|
||||||
int i = 0;
|
int i = 0;
|
||||||
BOOST_FOREACH (const CTransaction& tx, pblock->vtx) {
|
BOOST_FOREACH (CTransaction& tx, pblock->vtx) {
|
||||||
uint256 txHash = tx.GetHash();
|
uint256 txHash = tx.GetHash();
|
||||||
setTxIndex[txHash] = i++;
|
setTxIndex[txHash] = i++;
|
||||||
|
|
||||||
|
@ -556,8 +557,8 @@ UniValue getblocktemplate(const UniValue& params, bool fHelp)
|
||||||
UniValue entry(UniValue::VOBJ);
|
UniValue entry(UniValue::VOBJ);
|
||||||
|
|
||||||
entry.push_back(Pair("data", EncodeHexTx(tx)));
|
entry.push_back(Pair("data", EncodeHexTx(tx)));
|
||||||
|
entry.push_back(Pair("txid", txHash.GetHex()));
|
||||||
entry.push_back(Pair("hash", txHash.GetHex()));
|
entry.push_back(Pair("hash", tx.GetWitnessHash().GetHex()));
|
||||||
|
|
||||||
UniValue deps(UniValue::VARR);
|
UniValue deps(UniValue::VARR);
|
||||||
BOOST_FOREACH (const CTxIn &in, tx.vin)
|
BOOST_FOREACH (const CTxIn &in, tx.vin)
|
||||||
|
@ -656,6 +657,9 @@ UniValue getblocktemplate(const UniValue& params, bool fHelp)
|
||||||
result.push_back(Pair("curtime", pblock->GetBlockTime()));
|
result.push_back(Pair("curtime", pblock->GetBlockTime()));
|
||||||
result.push_back(Pair("bits", strprintf("%08x", pblock->nBits)));
|
result.push_back(Pair("bits", strprintf("%08x", pblock->nBits)));
|
||||||
result.push_back(Pair("height", (int64_t)(pindexPrev->nHeight+1)));
|
result.push_back(Pair("height", (int64_t)(pindexPrev->nHeight+1)));
|
||||||
|
if (!pblocktemplate->vchCoinbaseCommitment.empty()) {
|
||||||
|
result.push_back(Pair("default_witness_commitment", HexStr(pblocktemplate->vchCoinbaseCommitment.begin(), pblocktemplate->vchCoinbaseCommitment.end())));
|
||||||
|
}
|
||||||
|
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
@ -719,6 +723,14 @@ UniValue submitblock(const UniValue& params, bool fHelp)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
{
|
||||||
|
LOCK(cs_main);
|
||||||
|
BlockMap::iterator mi = mapBlockIndex.find(block.hashPrevBlock);
|
||||||
|
if (mi != mapBlockIndex.end()) {
|
||||||
|
UpdateUncommittedBlockStructures(block, mi->second, Params().GetConsensus());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
CValidationState state;
|
CValidationState state;
|
||||||
submitblock_StateCatcher sc(block.GetHash());
|
submitblock_StateCatcher sc(block.GetHash());
|
||||||
RegisterValidationInterface(&sc);
|
RegisterValidationInterface(&sc);
|
||||||
|
|
|
@ -14,6 +14,10 @@ const struct BIP9DeploymentInfo VersionBitsDeploymentInfo[Consensus::MAX_VERSION
|
||||||
{
|
{
|
||||||
/*.name =*/ "csv",
|
/*.name =*/ "csv",
|
||||||
/*.gbt_force =*/ true,
|
/*.gbt_force =*/ true,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
/*.name =*/ "segwit",
|
||||||
|
/*.gbt_force =*/ false,
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
Loading…
Reference in a new issue