diff --git a/src/validation.cpp b/src/validation.cpp index 9b5ecfe0c0..83b369ba65 100644 --- a/src/validation.cpp +++ b/src/validation.cpp @@ -3342,6 +3342,75 @@ std::vector GenerateCoinbaseCommitment(CBlock& block, const CBloc return commitment; } +// ELEMENTS +boost::optional GetPAKKeysFromCommitment(const CTransaction& coinbase) +{ + std::vector > offline_keys; + std::vector > online_keys; + bool is_reject = false; + for (unsigned int i = 0; i < coinbase.vout.size(); i++) { + const CScript& scriptPubKey = coinbase.vout[i].scriptPubKey; + + // OP + push + 4 bytes + push + 33 bytes + push + 33 bytes + // or + // OP + push + 4 bytes + push + 6 bytes (REJECT) + + CScript::const_iterator pc = scriptPubKey.begin(); + std::vector data; + opcodetype opcode; + + if (!scriptPubKey.GetOp(pc, opcode, data) || opcode != OP_RETURN){ + continue; + } + + if (!scriptPubKey.GetOp(pc, opcode, data) || data.size() != 4 || + data[0] != 0xab || data[1] != 0x22 || data[2] != 0xaa || data[3] != 0xee) { + continue; + } + + if (!scriptPubKey.GetOp(pc, opcode, data)){ + continue; + } + + // Check for pak list reject signal + // Returns an empty list regardless of other commitments + if (data.size() == 6 && data[0] == 'R' && data[1] == 'E' && data[2] == 'J' && data[3] == 'E' && data[4] == 'C' && data[5] == 'T') { + is_reject = true; + continue; + } + + // Check for offline key + if (data.size() != 33) { + continue; + } + + // Check for online key + std::vector data_online; + if (!scriptPubKey.GetOp(pc, opcode, data_online) || data_online.size() != 33) { + continue; + } + + offline_keys.push_back(data); + online_keys.push_back(data_online); + } + if (is_reject) { + offline_keys.clear(); + online_keys.clear(); + } + if (!is_reject && offline_keys.size() == 0) { + return boost::none; + } + CPAKList paklist; + if (!CPAKList::FromBytes(paklist, offline_keys, online_keys, is_reject)) { + return boost::none; + } else { + return paklist; + } +} + + + + /** Context-dependent validity checks. * By "context", we mean only the previous block headers, but not the UTXO * set; UTXO-related validity checks are done in ConnectBlock(). diff --git a/src/validation.h b/src/validation.h index 98c4f28a55..afa6db42c8 100644 --- a/src/validation.h +++ b/src/validation.h @@ -31,6 +31,9 @@ #include +#include // GetPAKKeysFromCommitment +#include // CPAKList + class CBlockIndex; class CBlockTreeDB; class CChainParams; @@ -426,6 +429,10 @@ void UpdateUncommittedBlockStructures(CBlock& block, const CBlockIndex* pindexPr /** Produce the necessary coinbase commitment for a block (modifies the hash, don't call for mined blocks). */ std::vector GenerateCoinbaseCommitment(CBlock& block, const CBlockIndex* pindexPrev, const Consensus::Params& consensusParams); +// ELEMENTS +/** Extract pak commitment from coinbase, if it exists. List must be ordered, but not necessarily consecutive in output index */ +boost::optional GetPAKKeysFromCommitment(const CTransaction& coinbase); + /** RAII wrapper for VerifyDB: Verify consistency of the block and coin databases */ class CVerifyDB { public: