Skip to content

Commit 804cd9f

Browse files
committed
Update PAK internals, helper functions
1 parent 16b87ba commit 804cd9f

File tree

5 files changed

+76
-187
lines changed

5 files changed

+76
-187
lines changed

src/primitives/pak.cpp

Lines changed: 57 additions & 69 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@
44

55
#include <primitives/pak.h>
66
#include <pubkey.h>
7+
#include <dynafed.h>
78

89
// ELEMENTS
910

@@ -33,73 +34,9 @@ class CSecp256k1Init {
3334
static CSecp256k1Init instance_of_csecp256k1;
3435
}
3536

36-
CScript CPAKList::Magic()
37-
{
38-
CScript scriptPubKey;
39-
scriptPubKey.resize(6);
40-
scriptPubKey[0] = OP_RETURN;
41-
scriptPubKey[1] = 0x04;
42-
scriptPubKey[2] = 0xab;
43-
scriptPubKey[3] = 0x22;
44-
scriptPubKey[4] = 0xaa;
45-
scriptPubKey[5] = 0xee;
46-
return scriptPubKey;
47-
}
48-
49-
std::vector<CScript> CPAKList::GenerateCoinbasePAKCommitments() const
50-
{
51-
std::vector<CScript> commitments;
52-
CScript scriptPubKey = CPAKList::Magic();
53-
54-
for (unsigned int i = 0; i < m_offline_keys.size(); i++) {
55-
CScript scriptCommitment(scriptPubKey);
56-
unsigned char pubkey[33];
57-
size_t outputlen = 33;
58-
secp256k1_ec_pubkey_serialize(secp256k1_ctx_pak, pubkey, &outputlen, &m_offline_keys[i], SECP256K1_EC_COMPRESSED);
59-
assert(outputlen == 33);
60-
scriptCommitment << std::vector<unsigned char>(pubkey, pubkey+outputlen);
61-
secp256k1_ec_pubkey_serialize(secp256k1_ctx_pak, pubkey, &outputlen, &m_online_keys[i], SECP256K1_EC_COMPRESSED);
62-
assert(outputlen == 33);
63-
scriptCommitment << std::vector<unsigned char>(pubkey, pubkey+outputlen);
64-
commitments.push_back(scriptCommitment);
65-
}
66-
67-
return commitments;
68-
}
69-
70-
std::vector<CScript> CPAKList::GenerateCoinbasePAKReject() const
71-
{
72-
CScript scriptPubKey = CPAKList::Magic();
73-
74-
std::vector<unsigned char> reject;
75-
reject.push_back('R');
76-
reject.push_back('E');
77-
reject.push_back('J');
78-
reject.push_back('E');
79-
reject.push_back('C');
80-
reject.push_back('T');
81-
82-
scriptPubKey << reject;
83-
84-
std::vector<CScript> commitment;
85-
commitment.push_back(scriptPubKey);
86-
return commitment;
87-
}
88-
89-
void CPAKList::CreateCommitments(std::vector<CScript> &commitments) const
90-
{
91-
if(reject) {
92-
commitments = GenerateCoinbasePAKReject();
93-
} else {
94-
commitments = GenerateCoinbasePAKCommitments();
95-
}
96-
}
97-
9837
bool CPAKList::operator==(const CPAKList &other) const
9938
{
100-
if (this->reject != other.reject) {
101-
return false;
102-
} else if (this->m_offline_keys.size() != other.m_offline_keys.size()) {
39+
if (this->m_offline_keys.size() != other.m_offline_keys.size()) {
10340
return false;
10441
} else {
10542
for (unsigned int i = 0; i < this->m_offline_keys.size(); i++) {
@@ -112,7 +49,7 @@ bool CPAKList::operator==(const CPAKList &other) const
11249
return true;
11350
}
11451

115-
bool CPAKList::FromBytes(CPAKList &paklist, std::vector<std::vector<unsigned char> >& offline_keys_bytes, std::vector<std::vector<unsigned char> >& online_keys_bytes, bool is_reject)
52+
bool CPAKList::FromBytes(CPAKList &paklist, const std::vector<std::vector<unsigned char> >& offline_keys_bytes, const std::vector<std::vector<unsigned char> >& online_keys_bytes)
11653
{
11754
if(offline_keys_bytes.size() != online_keys_bytes.size()
11855
|| offline_keys_bytes.size() > SECP256K1_WHITELIST_MAX_N_KEYS) {
@@ -134,11 +71,11 @@ bool CPAKList::FromBytes(CPAKList &paklist, std::vector<std::vector<unsigned cha
13471
online_keys.push_back(pubkey2);
13572
}
13673

137-
paklist = CPAKList(offline_keys, online_keys, is_reject);
74+
paklist = CPAKList(offline_keys, online_keys);
13875
return true;
13976
}
14077

141-
void CPAKList::ToBytes(std::vector<std::vector<unsigned char> >& offline_keys, std::vector<std::vector<unsigned char> >& online_keys, bool &is_reject) const
78+
void CPAKList::ToBytes(std::vector<std::vector<unsigned char> >& offline_keys, std::vector<std::vector<unsigned char> >& online_keys) const
14279
{
14380
offline_keys.resize(0);
14481
online_keys.resize(0);
@@ -151,7 +88,6 @@ void CPAKList::ToBytes(std::vector<std::vector<unsigned char> >& offline_keys, s
15188
secp256k1_ec_pubkey_serialize(secp256k1_ctx_pak, pubkey, &outputlen, &m_online_keys[i], SECP256K1_EC_COMPRESSED);
15289
online_keys.push_back(std::vector<unsigned char>(pubkey, pubkey+outputlen));
15390
}
154-
is_reject = reject;
15591
}
15692

15793
// Proof follows the OP_RETURN <genesis_block_hash> <destination_scriptpubkey>
@@ -243,3 +179,55 @@ bool ScriptHasValidPAKProof(const CScript& script, const uint256& genesis_hash)
243179

244180
return true;
245181
}
182+
183+
CPAKList CreatePAKListFromExtensionSpace(const std::vector<std::vector<unsigned char>>& extension_space)
184+
{
185+
std::vector<std::vector<unsigned char>> offline_keys;
186+
std::vector<std::vector<unsigned char>> online_keys;
187+
for (const auto& entry : extension_space) {
188+
// As soon as we find something that is possibly not 2 serialized pubkeys
189+
// we stop looking. CPAKList::FromBytes does pubkey validation itself.
190+
if (entry.size() != 66) {
191+
break;
192+
}
193+
offline_keys.emplace_back(entry.begin(), entry.begin()+33);
194+
online_keys.emplace_back(entry.begin()+33, entry.end());
195+
// Allow additional data, just ignore
196+
if (offline_keys.size() == SECP256K1_WHITELIST_MAX_N_KEYS) {
197+
break;
198+
}
199+
}
200+
CPAKList paklist;
201+
if (!CPAKList::FromBytes(paklist, offline_keys, online_keys)) {
202+
return CPAKList();
203+
}
204+
return paklist;
205+
}
206+
207+
CPAKList GetActivePAKList(const CBlockIndex* pblockindex, const Consensus::Params& params)
208+
{
209+
assert(pblockindex);
210+
211+
return CreatePAKListFromExtensionSpace(ComputeNextBlockFullCurrentParameters(pblockindex, params).m_extension_space);
212+
}
213+
214+
bool IsPAKValidOutput(const CTxOut& txout, const CPAKList& paklist)
215+
{
216+
const CChainParams& params = Params();
217+
if (txout.scriptPubKey.IsPegoutScript(params.ParentGenesisBlockHash()) &&
218+
txout.nAsset.IsExplicit() && txout.nAsset.GetAsset() == params.GetConsensus().pegged_asset &&
219+
(!ScriptHasValidPAKProof(txout.scriptPubKey, params.ParentGenesisBlockHash(), paklist))) {
220+
return false;
221+
}
222+
return true;
223+
}
224+
225+
bool IsPAKValidTx(const CTransaction& tx, const CPAKList& paklist)
226+
{
227+
for (const auto& txout : tx.vout) {
228+
if (!IsPAKValidOutput(txout, paklist)) {
229+
return false;
230+
}
231+
}
232+
return true;
233+
}

src/primitives/pak.h

Lines changed: 13 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -8,28 +8,22 @@
88
#include <script/script.h>
99
#include <secp256k1/include/secp256k1_whitelist.h>
1010
#include <boost/optional.hpp>
11+
#include <chain.h>
1112

1213
class CPAKList
1314
{
1415
private:
1516
std::vector<secp256k1_pubkey> m_offline_keys;
1617
std::vector<secp256k1_pubkey> m_online_keys;
17-
bool reject;
18-
19-
std::vector<CScript> GenerateCoinbasePAKCommitments() const;
20-
std::vector<CScript> GenerateCoinbasePAKReject() const;
2118

2219
public:
23-
CPAKList()
24-
{
25-
reject = true;
26-
}
20+
CPAKList() {}
2721
/**
2822
* Creates a new CPAKList. Requires that the number of offline keys is the same as the number of online keys
2923
* and that this number is not larger than SECP256K1_WHITELIST_MAX_N_KEYS.
3024
*/
31-
CPAKList(std::vector<secp256k1_pubkey> offline_keys, std::vector<secp256k1_pubkey> online_keys, bool reject) :
32-
m_offline_keys(offline_keys), m_online_keys(online_keys), reject(reject) {
25+
CPAKList(std::vector<secp256k1_pubkey> offline_keys, std::vector<secp256k1_pubkey> online_keys) :
26+
m_offline_keys(offline_keys), m_online_keys(online_keys) {
3327
assert(m_offline_keys.size() == m_online_keys.size());
3428
assert(m_offline_keys.size() <= SECP256K1_WHITELIST_MAX_N_KEYS);
3529
}
@@ -41,11 +35,7 @@ class CPAKList
4135
}
4236
bool IsReject() const
4337
{
44-
return reject;
45-
}
46-
bool IsEmpty() const
47-
{
48-
return !reject && this->size() == 0;
38+
return size()==0;
4939
}
5040
std::vector<secp256k1_pubkey> OnlineKeys() const
5141
{
@@ -60,24 +50,21 @@ class CPAKList
6050
return m_offline_keys.size();
6151
}
6252

63-
static CScript Magic();
64-
/** Produce a list of scripts to add to the coinbase to signal changes in PAK list or rejection of any pak proofs to nodes */
65-
void CreateCommitments(std::vector<CScript> &commitments) const;
66-
67-
static bool FromBytes(CPAKList &paklist, std::vector<std::vector<unsigned char> >& offline_keys, std::vector<std::vector<unsigned char> >& online_keys, bool is_reject);
68-
void ToBytes(std::vector<std::vector<unsigned char> >& offline_keys, std::vector<std::vector<unsigned char> >& online_keys, bool &is_reject) const;
53+
static bool FromBytes(CPAKList &paklist, const std::vector<std::vector<unsigned char> >& offline_keys, const std::vector<std::vector<unsigned char> >& online_keys);
54+
void ToBytes(std::vector<std::vector<unsigned char> >& offline_keys, std::vector<std::vector<unsigned char> >& online_keys) const;
6955
};
7056

7157
/**
7258
** Returns true if the script includes valid pegout proof
73-
** given the PAK list loaded. Two pushes after regular pegout script:
59+
** given the PAK list. Two pushes after regular pegout script:
7460
** <full_pubkey> <proof>
7561
**/
7662
bool ScriptHasValidPAKProof(const CScript& script, const uint256& genesis_hash);
7763

78-
// ELEMENTS:
79-
extern boost::optional<CPAKList> g_paklist_config;
80-
extern CPAKList g_paklist_blockchain;
81-
///////////
64+
CPAKList GetActivePAKList(const CBlockIndex* pblockindex, const Consensus::Params& params);
65+
66+
bool IsPAKValidOutput(const CTxOut& txout, const CPAKList& paklist);
67+
68+
bool IsPAKValidTx(const CTransaction& tx, const CPAKList& paklist);
8269

8370
#endif // BITCOIN_PRIMITIVES_PAK_H

src/rpc/misc.cpp

Lines changed: 6 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -667,8 +667,7 @@ UniValue FormatPAKList(CPAKList &paklist) {
667667
UniValue paklist_value(UniValue::VOBJ);
668668
std::vector<std::vector<unsigned char> > offline_keys;
669669
std::vector<std::vector<unsigned char> > online_keys;
670-
bool is_reject;
671-
paklist.ToBytes(offline_keys, online_keys, is_reject);
670+
paklist.ToBytes(offline_keys, online_keys);
672671

673672
UniValue retOnline(UniValue::VARR);
674673
UniValue retOffline(UniValue::VARR);
@@ -679,7 +678,7 @@ UniValue FormatPAKList(CPAKList &paklist) {
679678
}
680679
paklist_value.pushKV("online", retOnline);
681680
paklist_value.pushKV("offline", retOffline);
682-
paklist_value.pushKV("reject", is_reject);
681+
paklist_value.pushKV("reject", retOffline.empty());
683682
return paklist_value;
684683
}
685684

@@ -688,26 +687,21 @@ UniValue getpakinfo(const JSONRPCRequest& request)
688687
if (request.fHelp || request.params.size() != 0)
689688
throw std::runtime_error(
690689
RPCHelpMan{"getpakinfo",
691-
"\nReturns relevant pegout authorization key (PAK) information about this node, both from command line arguments and blockchain data.\n",
690+
"\nReturns relevant pegout authorization key (PAK) information about this node, both from blockchain data.\n",
692691
{},
693692
RPCResult{
694693
"{\n"
695-
"\"config_paklist\" (array) The PAK list loaded from beta.conf at startup\n"
696-
"\"block_paklist\" (array) The PAK list loaded from latest block commitment\n"
694+
"\"block_paklist\" (array) The PAK list loaded from latest epoch\n"
697695
"}\n"
698696
},
699697
RPCExamples{""},
700698
}.ToString());
701699

702700
LOCK(cs_main);
703701

704-
UniValue paklist_value(UniValue::VOBJ);
705-
if (g_paklist_config) {
706-
paklist_value = FormatPAKList(*g_paklist_config);
707-
}
708702
UniValue ret(UniValue::VOBJ);
709-
ret.pushKV("config_paklist", paklist_value);
710-
ret.pushKV("block_paklist", FormatPAKList(g_paklist_blockchain));
703+
CPAKList paklist = GetActivePAKList(chainActive.Tip(), Params().GetConsensus());
704+
ret.pushKV("block_paklist", FormatPAKList(paklist));
711705

712706
return ret;
713707
}

src/validation.cpp

Lines changed: 0 additions & 77 deletions
Original file line numberDiff line numberDiff line change
@@ -2628,17 +2628,6 @@ bool CChainState::ConnectTip(CValidationState& state, const CChainParams& chainp
26282628
if (!FlushStateToDisk(chainparams, state, FlushStateMode::IF_NEEDED))
26292629
return false;
26302630

2631-
// Get PAK commitment from coinbase, if it exists
2632-
boost::optional<CPAKList> paklist = GetPAKKeysFromCommitment(*blockConnecting.vtx[0]);
2633-
if (paklist) {
2634-
std::vector<std::vector<unsigned char> > offline_keys;
2635-
std::vector<std::vector<unsigned char> > online_keys;
2636-
bool is_reject;
2637-
paklist->ToBytes(offline_keys, online_keys, is_reject);
2638-
pblocktree->WritePAKList(offline_keys, online_keys, is_reject);
2639-
g_paklist_blockchain = *paklist;
2640-
}
2641-
26422631
int64_t nTime5 = GetTimeMicros(); nTimeChainState += nTime5 - nTime4;
26432632
LogPrint(BCLog::BENCH, " - Writing chainstate: %.2fms [%.2fs (%.2fms/blk)]\n", (nTime5 - nTime4) * MILLI, nTimeChainState * MICRO, nTimeChainState * MILLI / nBlocksTotal);
26442633
// Remove conflicting transactions from the mempool.;
@@ -3448,72 +3437,6 @@ std::vector<unsigned char> GenerateCoinbaseCommitment(CBlock& block, const CBloc
34483437
}
34493438

34503439
// ELEMENTS
3451-
boost::optional<CPAKList> GetPAKKeysFromCommitment(const CTransaction& coinbase)
3452-
{
3453-
std::vector<std::vector<unsigned char> > offline_keys;
3454-
std::vector<std::vector<unsigned char> > online_keys;
3455-
bool is_reject = false;
3456-
for (unsigned int i = 0; i < coinbase.vout.size(); i++) {
3457-
const CScript& scriptPubKey = coinbase.vout[i].scriptPubKey;
3458-
3459-
// OP + push + 4 bytes + push + 33 bytes + push + 33 bytes
3460-
// or
3461-
// OP + push + 4 bytes + push + 6 bytes (REJECT)
3462-
3463-
CScript::const_iterator pc = scriptPubKey.begin();
3464-
std::vector<unsigned char> data;
3465-
opcodetype opcode;
3466-
3467-
if (!scriptPubKey.GetOp(pc, opcode, data) || opcode != OP_RETURN){
3468-
continue;
3469-
}
3470-
3471-
if (!scriptPubKey.GetOp(pc, opcode, data) || data.size() != 4 ||
3472-
data[0] != 0xab || data[1] != 0x22 || data[2] != 0xaa || data[3] != 0xee) {
3473-
continue;
3474-
}
3475-
3476-
if (!scriptPubKey.GetOp(pc, opcode, data)){
3477-
continue;
3478-
}
3479-
3480-
// Check for pak list reject signal
3481-
// Returns an empty list regardless of other commitments
3482-
if (data.size() == 6 && data[0] == 'R' && data[1] == 'E' && data[2] == 'J' && data[3] == 'E' && data[4] == 'C' && data[5] == 'T') {
3483-
is_reject = true;
3484-
continue;
3485-
}
3486-
3487-
// Check for offline key
3488-
if (data.size() != 33) {
3489-
continue;
3490-
}
3491-
3492-
// Check for online key
3493-
std::vector<unsigned char> data_online;
3494-
if (!scriptPubKey.GetOp(pc, opcode, data_online) || data_online.size() != 33) {
3495-
continue;
3496-
}
3497-
3498-
offline_keys.push_back(data);
3499-
online_keys.push_back(data_online);
3500-
}
3501-
if (is_reject) {
3502-
offline_keys.clear();
3503-
online_keys.clear();
3504-
}
3505-
if (!is_reject && offline_keys.size() == 0) {
3506-
return boost::none;
3507-
}
3508-
CPAKList paklist;
3509-
if (!CPAKList::FromBytes(paklist, offline_keys, online_keys, is_reject)) {
3510-
return boost::none;
3511-
} else {
3512-
return paklist;
3513-
}
3514-
}
3515-
3516-
35173440

35183441

35193442
/** Context-dependent validity checks.

0 commit comments

Comments
 (0)