codepad
[
create a new paste
]
login
|
about
Language:
C
C++
D
Haskell
Lua
OCaml
PHP
Perl
Plain Text
Python
Ruby
Scheme
Tcl
commit 961fce0cdc0aa03ccc6622414ecc16933946dc6e Author: Luke Dashjr <luke-jr+git@utopios.org> Date: Mon Jul 10 10:59:49 2017 +0000 Data-commitment softfork - Blocks must commit to the full block data linearly, followed by the full block data for the previous block (also linear) - The final hash is to be stored in the witness commitment's nonce (the commitment itself is masked for the block hashing) - If and only if the previous 100 blocks are generation-only, the segwit+data commitment may be skipped This solves two problems: - ASICBoost and anything similar should be unfeasible - SPV mining should be of minimal practical usability diff --git a/src/consensus/consensus.h b/src/consensus/consensus.h index 58b2ed4b3e..c0f45452c4 100644 --- a/src/consensus/consensus.h +++ b/src/consensus/consensus.h @@ -8,7 +8,7 @@ #include <stdint.h> -/** The maximum allowed size for a serialized block, in bytes (only for buffer size limits) */ +/** The maximum possible size for a serialized block, in bytes */ static const unsigned int MAX_BLOCK_SERIALIZED_SIZE = 4000000; /** The maximum allowed weight for a block, see BIP 141 (network rule) */ static const unsigned int MAX_BLOCK_WEIGHT = 4000000; diff --git a/src/consensus/params.h b/src/consensus/params.h index 6240e82857..84b1404c23 100644 --- a/src/consensus/params.h +++ b/src/consensus/params.h @@ -17,6 +17,7 @@ enum DeploymentPos DEPLOYMENT_TESTDUMMY, DEPLOYMENT_CSV, // Deployment of BIP68, BIP112, and BIP113. DEPLOYMENT_SEGWIT, // Deployment of BIP141, BIP143, and BIP147. + DEPLOYMENT_DATACOMMIT, // NOTE: Also add new deployments to VersionBitsDeploymentInfo in versionbits.cpp MAX_VERSION_BITS_DEPLOYMENTS }; diff --git a/src/hash.h b/src/hash.h index b9952d39fc..50052049fb 100644 --- a/src/hash.h +++ b/src/hash.h @@ -131,6 +131,7 @@ class CHashWriter { private: CHash256 ctx; + size_t len; const int nType; const int nVersion; @@ -143,6 +144,11 @@ public: void write(const char *pch, size_t size) { ctx.Write((const unsigned char*)pch, size); + len += size; + } + + size_t GetLength() { + return len; } // invalidates the object diff --git a/src/validation.cpp b/src/validation.cpp index 09288be1ca..75dbce2bd6 100644 --- a/src/validation.cpp +++ b/src/validation.cpp @@ -2882,15 +2882,56 @@ void UpdateUncommittedBlockStructures(CBlock& block, const CBlockIndex* pindexPr } } +static void PadHashWriter(CHashWriter& hasher, size_t padding_to_size) +{ + const size_t hasher_len = hasher.GetLength(); + if (hasher_len >= padding_to_size) { + return; + } + const size_t padding_size = padding_to_size - hasher_len; + std::vector<unsigned char> padding(padding_size, 0x00); + hasher.write(padding.data(), padding_size); +} + +static uint256 BlockDataCommitment(const CBlock& block, CMutableTransaction& modified_gentx, const int commitpos, const CBlock& prevblock) +{ + assert(block.vtx.size()); + assert(commitpos >= 0 && (size_t)commitpos < modified_gentx.vout.size()); + assert(modified_gentx.vout[commitpos].scriptPubKey.size() >= 38); + + CHashWriter hasher(SER_GETHASH, PROTOCOL_VERSION); + + hasher << *(CBlockHeader*)█ + WriteCompactSize(hasher, block.vtx.size()); + memset(&modified_gentx.vout[commitpos].scriptPubKey[6], 0xff, 32); + hasher << modified_gentx; + for (size_t i = 1; i < block.vtx.size(); ++i) { + hasher << block.vtx[i]; + } + PadHashWriter(MAX_BLOCK_SERIALIZED_SIZE); + + hasher << prevblock; + PadHashWriter(MAX_BLOCK_SERIALIZED_SIZE * 2); + + return hasher.GetHash(); +} + std::vector<unsigned char> GenerateCoinbaseCommitment(CBlock& block, const CBlockIndex* pindexPrev, const Consensus::Params& consensusParams) { std::vector<unsigned char> commitment; int commitpos = GetWitnessCommitmentIndex(block); - std::vector<unsigned char> ret(32, 0x00); if (consensusParams.vDeployments[Consensus::DEPLOYMENT_SEGWIT].nTimeout != 0) { if (commitpos == -1) { - uint256 witnessroot = BlockWitnessMerkleRoot(block, NULL); - CHash256().Write(witnessroot.begin(), 32).Write(&ret[0], 32).Finalize(witnessroot.begin()); + CBlock prevblock; + if (consensusParams.vDeployments[Consensus::DEPLOYMENT_DATACOMMIT].nTimeout != 0) { + if (!(pindexPrev->nStatus & BLOCK_HAVE_DATA) && pindexPrev->nTx > 0) { + // FIXME + } + if (!ReadBlockFromDisk(prevblock, pindexPrev, consensusParams)) { + // FIXME + } + } + CTxOut out; out.nValue = 0; out.scriptPubKey.resize(38); @@ -2900,10 +2941,17 @@ std::vector<unsigned char> GenerateCoinbaseCommitment(CBlock& block, const CBloc 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()); CMutableTransaction tx(*block.vtx[0]); tx.vout.push_back(out); + uint256 datacommit; + if (consensusParams.vDeployments[Consensus::DEPLOYMENT_DATACOMMIT].nTimeout != 0) { + datacommit = BlockDataCommitment(block, tx, tx.vout.size() - 1, prevblock); + } + + uint256 witnessroot = BlockWitnessMerkleRoot(block, NULL); + CHash256().Write(witnessroot.begin(), 32).Write(datacommit.begin(), 32).Finalize(witnessroot.begin()); + memcpy(&out.scriptPubKey[6], witnessroot.begin(), 32); + commitment = std::vector<unsigned char>(out.scriptPubKey.begin(), out.scriptPubKey.end()); block.vtx[0] = MakeTransactionRef(std::move(tx)); } } @@ -2983,6 +3031,12 @@ static bool ContextualCheckBlock(const CBlock& block, CValidationState& state, c bool fHaveWitness = false; if (VersionBitsState(pindexPrev, consensusParams, Consensus::DEPLOYMENT_SEGWIT, versionbitscache) == THRESHOLD_ACTIVE) { int commitpos = GetWitnessCommitmentIndex(block); + if (commitpos == -1) { + // TODO: Check this comparison isn't off by one + if (pindexPrev->GetAncestor(nHeight - COINBASE_MATURITY)->nChainTx != pindexPrev->nChainTx - COINBASE_MATURITY) { + return state.DoS(100, false, REJECT_INVALID, "missing-data-commitment", true, strprintf("%s : missing data commitment", __func__)); + } + } if (commitpos != -1) { bool malleated = false; uint256 hashWitness = BlockWitnessMerkleRoot(block, &malleated); @@ -2992,11 +3046,28 @@ static bool ContextualCheckBlock(const CBlock& block, CValidationState& state, c if (block.vtx[0]->vin[0].scriptWitness.stack.size() != 1 || block.vtx[0]->vin[0].scriptWitness.stack[0].size() != 32) { return state.DoS(100, false, REJECT_INVALID, "bad-witness-nonce-size", true, strprintf("%s : invalid witness nonce size", __func__)); } - CHash256().Write(hashWitness.begin(), 32).Write(&block.vtx[0]->vin[0].scriptWitness.stack[0][0], 32).Finalize(hashWitness.begin()); + uint256 witness_nonce; + memcpy(witness_nonce.begin(), &block.vtx[0]->vin[0].scriptWitness.stack[0][0], 32); + CHash256().Write(hashWitness.begin(), 32).Write(witness_nonce.begin(), 32).Finalize(hashWitness.begin()); if (memcmp(hashWitness.begin(), &block.vtx[0]->vout[commitpos].scriptPubKey[6], 32)) { return state.DoS(100, false, REJECT_INVALID, "bad-witness-merkle-match", true, strprintf("%s : witness merkle commitment mismatch", __func__)); } fHaveWitness = true; + + if (VersionBitsState(pindexPrev, consensusParams, Consensus::DEPLOYMENT_DATACOMMIT, versionbitscache) == THRESHOLD_ACTIVE) { + CBlock prevblock; + if (!(pindexPrev->nStatus & BLOCK_HAVE_DATA) && pindexPrev->nTx > 0) { + // FIXME + } + if (!ReadBlockFromDisk(prevblock, pindexPrev, consensusParams)) { + // FIXME + } + CMutableTransaction modified_gentx(*block.vtx[0]); + uint256 datacommit = BlockDataCommitment(block, modified_gentx, commitpos, prevblock); + if (witness_nonce != datacommit) { + return state.DoS(100, false, REJECT_INVALID, "bad-data-commitment-match", true, strprintf("%s : data commitment mismatch", __func__)); + } + } } } diff --git a/src/versionbits.cpp b/src/versionbits.cpp index 8047e17aa8..1439ab913f 100644 --- a/src/versionbits.cpp +++ b/src/versionbits.cpp @@ -17,7 +17,11 @@ const struct VBDeploymentInfo VersionBitsDeploymentInfo[Consensus::MAX_VERSION_B { /*.name =*/ "segwit", /*.gbt_force =*/ true, - } + }, + { + /*.name =*/ "datacommit", + /*.gbt_force =*/ false, + }, }; ThresholdState AbstractThresholdConditionChecker::GetStateFor(const CBlockIndex* pindexPrev, const Consensus::Params& params, ThresholdConditionCache& cache) const
Private
[
?
]
Run code
Submit