[ create a new paste ] login | about

Link: http://codepad.org/F8Kata4K    [ raw code | fork ]

Plain Text, pasted on Jul 10:
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*)&block;
+    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


Create a new paste based on this one


Comments: