LCOV - code coverage report
Current view: top level - src - signet.cpp (source / functions) Hit Total Coverage
Test: coverage.lcov Lines: 93 93 100.0 %
Date: 2021-06-29 14:35:33 Functions: 4 4 100.0 %
Legend: Modified by patch:
Lines: hit not hit | Branches: + taken - not taken # not executed

Not modified by patch:
Lines: hit not hit | Branches: + taken - not taken # not executed
Branches: 31 34 91.2 %

           Branch data     Line data    Source code
#       1                 :            : // Copyright (c) 2019-2020 The Bitcoin Core developers
#       2                 :            : // Distributed under the MIT software license, see the accompanying
#       3                 :            : // file COPYING or http://www.opensource.org/licenses/mit-license.php.
#       4                 :            : 
#       5                 :            : #include <signet.h>
#       6                 :            : 
#       7                 :            : #include <array>
#       8                 :            : #include <cstdint>
#       9                 :            : #include <vector>
#      10                 :            : 
#      11                 :            : #include <consensus/merkle.h>
#      12                 :            : #include <consensus/params.h>
#      13                 :            : #include <consensus/validation.h>
#      14                 :            : #include <core_io.h>
#      15                 :            : #include <hash.h>
#      16                 :            : #include <primitives/block.h>
#      17                 :            : #include <primitives/transaction.h>
#      18                 :            : #include <span.h>
#      19                 :            : #include <script/interpreter.h>
#      20                 :            : #include <script/standard.h>
#      21                 :            : #include <streams.h>
#      22                 :            : #include <util/strencodings.h>
#      23                 :            : #include <util/system.h>
#      24                 :            : #include <uint256.h>
#      25                 :            : 
#      26                 :            : static constexpr uint8_t SIGNET_HEADER[4] = {0xec, 0xc7, 0xda, 0xa2};
#      27                 :            : 
#      28                 :            : static constexpr unsigned int BLOCK_SCRIPT_VERIFY_FLAGS = SCRIPT_VERIFY_P2SH | SCRIPT_VERIFY_WITNESS | SCRIPT_VERIFY_DERSIG | SCRIPT_VERIFY_NULLDUMMY;
#      29                 :            : 
#      30                 :            : static bool FetchAndClearCommitmentSection(const Span<const uint8_t> header, CScript& witness_commitment, std::vector<uint8_t>& result)
#      31                 :         35 : {
#      32                 :         35 :     CScript replacement;
#      33                 :         35 :     bool found_header = false;
#      34                 :         35 :     result.clear();
#      35                 :            : 
#      36                 :         35 :     opcodetype opcode;
#      37                 :         35 :     CScript::const_iterator pc = witness_commitment.begin();
#      38                 :         35 :     std::vector<uint8_t> pushdata;
#      39         [ +  + ]:        132 :     while (witness_commitment.GetOp(pc, opcode, pushdata)) {
#      40         [ +  + ]:         97 :         if (pushdata.size() > 0) {
#      41 [ +  - ][ +  + ]:         62 :             if (!found_header && pushdata.size() > (size_t) header.size() && Span<const uint8_t>(pushdata.data(), header.size()) == header) {
#         [ +  + ][ +  + ]
#      42                 :            :                 // pushdata only counts if it has the header _and_ some data
#      43                 :         23 :                 result.insert(result.end(), pushdata.begin() + header.size(), pushdata.end());
#      44                 :         23 :                 pushdata.erase(pushdata.begin() + header.size(), pushdata.end());
#      45                 :         23 :                 found_header = true;
#      46                 :         23 :             }
#      47                 :         62 :             replacement << pushdata;
#      48                 :         62 :         } else {
#      49                 :         35 :             replacement << opcode;
#      50                 :         35 :         }
#      51                 :         97 :     }
#      52                 :            : 
#      53         [ +  + ]:         35 :     if (found_header) witness_commitment = replacement;
#      54                 :         35 :     return found_header;
#      55                 :         35 : }
#      56                 :            : 
#      57                 :            : static uint256 ComputeModifiedMerkleRoot(const CMutableTransaction& cb, const CBlock& block)
#      58                 :         27 : {
#      59                 :         27 :     std::vector<uint256> leaves;
#      60                 :         27 :     leaves.resize(block.vtx.size());
#      61                 :         27 :     leaves[0] = cb.GetHash();
#      62         [ +  + ]:         39 :     for (size_t s = 1; s < block.vtx.size(); ++s) {
#      63                 :         12 :         leaves[s] = block.vtx[s]->GetHash();
#      64                 :         12 :     }
#      65                 :         27 :     return ComputeMerkleRoot(std::move(leaves));
#      66                 :         27 : }
#      67                 :            : 
#      68                 :            : std::optional<SignetTxs> SignetTxs::Create(const CBlock& block, const CScript& challenge)
#      69                 :         43 : {
#      70                 :         43 :     CMutableTransaction tx_to_spend;
#      71                 :         43 :     tx_to_spend.nVersion = 0;
#      72                 :         43 :     tx_to_spend.nLockTime = 0;
#      73                 :         43 :     tx_to_spend.vin.emplace_back(COutPoint(), CScript(OP_0), 0);
#      74                 :         43 :     tx_to_spend.vout.emplace_back(0, challenge);
#      75                 :            : 
#      76                 :         43 :     CMutableTransaction tx_spending;
#      77                 :         43 :     tx_spending.nVersion = 0;
#      78                 :         43 :     tx_spending.nLockTime = 0;
#      79                 :         43 :     tx_spending.vin.emplace_back(COutPoint(), CScript(), 0);
#      80                 :         43 :     tx_spending.vout.emplace_back(0, CScript(OP_RETURN));
#      81                 :            : 
#      82                 :            :     // can't fill any other fields before extracting signet
#      83                 :            :     // responses from block coinbase tx
#      84                 :            : 
#      85                 :            :     // find and delete signet signature
#      86         [ +  + ]:         43 :     if (block.vtx.empty()) return std::nullopt; // no coinbase tx in block; invalid
#      87                 :         39 :     CMutableTransaction modified_cb(*block.vtx.at(0));
#      88                 :            : 
#      89                 :         39 :     const int cidx = GetWitnessCommitmentIndex(block);
#      90         [ +  + ]:         39 :     if (cidx == NO_WITNESS_COMMITMENT) {
#      91                 :          4 :         return std::nullopt; // require a witness commitment
#      92                 :          4 :     }
#      93                 :            : 
#      94                 :         35 :     CScript& witness_commitment = modified_cb.vout.at(cidx).scriptPubKey;
#      95                 :            : 
#      96                 :         35 :     std::vector<uint8_t> signet_solution;
#      97         [ +  + ]:         35 :     if (!FetchAndClearCommitmentSection(SIGNET_HEADER, witness_commitment, signet_solution)) {
#      98                 :            :         // no signet solution -- allow this to support OP_TRUE as trivial block challenge
#      99                 :         23 :     } else {
#     100                 :         23 :         try {
#     101                 :         23 :             VectorReader v(SER_NETWORK, INIT_PROTO_VERSION, signet_solution, 0);
#     102                 :         23 :             v >> tx_spending.vin[0].scriptSig;
#     103                 :         23 :             v >> tx_spending.vin[0].scriptWitness.stack;
#     104         [ +  + ]:         23 :             if (!v.empty()) return std::nullopt; // extraneous data encountered
#     105                 :          4 :         } catch (const std::exception&) {
#     106                 :          4 :             return std::nullopt; // parsing error
#     107                 :          4 :         }
#     108                 :         27 :     }
#     109                 :         27 :     uint256 signet_merkle = ComputeModifiedMerkleRoot(modified_cb, block);
#     110                 :            : 
#     111                 :         27 :     std::vector<uint8_t> block_data;
#     112                 :         27 :     CVectorWriter writer(SER_NETWORK, INIT_PROTO_VERSION, block_data, 0);
#     113                 :         27 :     writer << block.nVersion;
#     114                 :         27 :     writer << block.hashPrevBlock;
#     115                 :         27 :     writer << signet_merkle;
#     116                 :         27 :     writer << block.nTime;
#     117                 :         27 :     tx_to_spend.vin[0].scriptSig << block_data;
#     118                 :         27 :     tx_spending.vin[0].prevout = COutPoint(tx_to_spend.GetHash(), 0);
#     119                 :            : 
#     120                 :         27 :     return SignetTxs{tx_to_spend, tx_spending};
#     121                 :         27 : }
#     122                 :            : 
#     123                 :            : // Signet block solution checker
#     124                 :            : bool CheckSignetBlockSolution(const CBlock& block, const Consensus::Params& consensusParams)
#     125                 :         41 : {
#     126         [ +  + ]:         41 :     if (block.GetHash() == consensusParams.hashGenesisBlock) {
#     127                 :            :         // genesis block solution is always valid
#     128                 :         12 :         return true;
#     129                 :         12 :     }
#     130                 :            : 
#     131                 :         29 :     const CScript challenge(consensusParams.signet_challenge.begin(), consensusParams.signet_challenge.end());
#     132                 :         29 :     const std::optional<SignetTxs> signet_txs = SignetTxs::Create(block, challenge);
#     133                 :            : 
#     134         [ +  + ]:         29 :     if (!signet_txs) {
#     135         [ +  - ]:          8 :         LogPrint(BCLog::VALIDATION, "CheckSignetBlockSolution: Errors in block (block solution parse failure)\n");
#     136                 :          8 :         return false;
#     137                 :          8 :     }
#     138                 :            : 
#     139                 :         21 :     const CScript& scriptSig = signet_txs->m_to_sign.vin[0].scriptSig;
#     140                 :         21 :     const CScriptWitness& witness = signet_txs->m_to_sign.vin[0].scriptWitness;
#     141                 :            : 
#     142                 :         21 :     PrecomputedTransactionData txdata;
#     143                 :         21 :     txdata.Init(signet_txs->m_to_sign, {signet_txs->m_to_spend.vout[0]});
#     144                 :         21 :     TransactionSignatureChecker sigcheck(&signet_txs->m_to_sign, /*nIn=*/ 0, /*amount=*/ signet_txs->m_to_spend.vout[0].nValue, txdata, MissingDataBehavior::ASSERT_FAIL);
#     145                 :            : 
#     146         [ +  + ]:         21 :     if (!VerifyScript(scriptSig, signet_txs->m_to_spend.vout[0].scriptPubKey, &witness, BLOCK_SCRIPT_VERIFY_FLAGS, sigcheck)) {
#     147         [ +  - ]:          1 :         LogPrint(BCLog::VALIDATION, "CheckSignetBlockSolution: Errors in block (block solution invalid)\n");
#     148                 :          1 :         return false;
#     149                 :          1 :     }
#     150                 :         20 :     return true;
#     151                 :         20 : }

Generated by: LCOV version 1.14