Bitcoin ABC 0.33.5
P2P Digital Currency
avalanche.cpp
Go to the documentation of this file.
1// Copyright (c) 2020 The Bitcoin developers
2// Distributed under the MIT software license, see the accompanying
3// file COPYING or http://www.opensource.org/licenses/mit-license.php.
4
10#include <avalanche/proof.h>
14#include <common/args.h>
15#include <config.h>
16#include <core_io.h>
17#include <index/txindex.h>
18#include <key_io.h>
19#include <net_processing.h>
20#include <node/context.h>
22#include <rpc/blockchain.h>
24#include <rpc/server.h>
25#include <rpc/server_util.h>
26#include <rpc/util.h>
27#include <util/strencodings.h>
28#include <util/translation.h>
29
30#include <univalue.h>
31
34
36 return RPCHelpMan{
37 "getavalanchekey",
38 "Returns the key used to sign avalanche messages.\n",
39 {},
41 RPCExamples{HelpExampleCli("getavalanchekey", "") +
42 HelpExampleRpc("getavalanchekey", "")},
43 [&](const RPCHelpMan &self, const Config &config,
44 const JSONRPCRequest &request) -> UniValue {
45 NodeContext &node = EnsureAnyNodeContext(request.context);
47 return HexStr(avalanche.getSessionPubKey());
48 },
49 };
50}
51
52static CPubKey ParsePubKey(const UniValue &param) {
53 const std::string &keyHex = param.get_str();
54 if ((keyHex.length() != 2 * CPubKey::COMPRESSED_SIZE &&
55 keyHex.length() != 2 * CPubKey::SIZE) ||
56 !IsHex(keyHex)) {
58 strprintf("Invalid public key: %s\n", keyHex));
59 }
60
61 return HexToPubKey(keyHex);
62}
63
67 auto localProof = avalanche.getLocalProof();
68 if (localProof && localProof->getId() == proof->getId()) {
69 return true;
70 }
71
72 return avalanche.withPeerManager([&](avalanche::PeerManager &pm) {
73 return pm.getProof(proof->getId()) || pm.registerProof(proof, state);
74 });
75}
76
78 avalanche::ProofRef proof) {
80 return registerProofIfNeeded(avalanche, std::move(proof), state);
81}
82
84 const std::string &dgHex, CPubKey &auth) {
85 bilingual_str error;
86 if (!avalanche::Delegation::FromHex(dg, dgHex, error)) {
88 }
89
91 if (!dg.verify(state, auth)) {
93 "The delegation is invalid: " + state.ToString());
94 }
95}
96
98 const std::string &proofHex) {
99 bilingual_str error;
100 if (!avalanche::Proof::FromHex(proof, proofHex, error)) {
102 }
103
104 Amount stakeUtxoDustThreshold = avalanche::PROOF_DUST_THRESHOLD;
105 if (node.avalanche) {
106 // If Avalanche is enabled, use the configured dust threshold
107 node.avalanche->withPeerManager([&](avalanche::PeerManager &pm) {
108 stakeUtxoDustThreshold = pm.getStakeUtxoDustThreshold();
109 });
110 }
111
113 {
114 LOCK(cs_main);
115 if (!proof.verify(stakeUtxoDustThreshold, *Assert(node.chainman),
116 state)) {
118 "The proof is invalid: " + state.ToString());
119 }
120 }
121}
122
124 return RPCHelpMan{
125 "addavalanchenode",
126 "Add a node in the set of peers to poll for avalanche.\n",
127 {
129 "Node to be added to avalanche."},
131 "The public key of the node."},
133 "Proof that the node is not a sybil."},
135 "The proof delegation the the node public key"},
136 },
138 "Whether the addition succeeded or not."},
140 HelpExampleCli("addavalanchenode", "5, \"<pubkey>\", \"<proof>\"") +
141 HelpExampleRpc("addavalanchenode", "5, \"<pubkey>\", \"<proof>\"")},
142 [&](const RPCHelpMan &self, const Config &config,
143 const JSONRPCRequest &request) -> UniValue {
144 const NodeId nodeid = request.params[0].getInt<int64_t>();
145 CPubKey key = ParsePubKey(request.params[1]);
146
147 auto proof = RCUPtr<avalanche::Proof>::make();
148 NodeContext &node = EnsureAnyNodeContext(request.context);
150
151 verifyProofOrThrow(node, *proof, request.params[2].get_str());
152
153 const avalanche::ProofId &proofid = proof->getId();
154 if (key != proof->getMaster()) {
155 if (request.params.size() < 4 || request.params[3].isNull()) {
156 throw JSONRPCError(
158 "The public key does not match the proof");
159 }
160
162 CPubKey auth;
163 verifyDelegationOrThrow(dg, request.params[3].get_str(), auth);
164
165 if (dg.getProofId() != proofid) {
166 throw JSONRPCError(
168 "The delegation does not match the proof");
169 }
170
171 if (key != auth) {
172 throw JSONRPCError(
174 "The public key does not match the delegation");
175 }
176 }
177
178 if (!registerProofIfNeeded(avalanche, proof)) {
180 "The proof has conflicting utxos");
181 }
182
183 if (!node.connman->ForNode(nodeid, [&](CNode *pnode) {
184 LOCK(pnode->cs_avalanche_pubkey);
185 bool expected = false;
186 if (pnode->m_avalanche_enabled.compare_exchange_strong(
187 expected, true)) {
188 pnode->m_avalanche_pubkey = std::move(key);
189 }
190 return true;
191 })) {
192 throw JSONRPCError(
194 strprintf("The node does not exist: %d", nodeid));
195 }
196
197 return avalanche.withPeerManager([&](avalanche::PeerManager &pm) {
198 // We don't know what this node supports as number of elements,
199 // so we assume the minimum for now
200 if (!pm.addNode(nodeid, proofid,
202 return false;
203 }
204
205 pm.addUnbroadcastProof(proofid);
206 return true;
207 });
208 },
209 };
210}
211
213 return RPCHelpMan{
214 "buildavalancheproof",
215 "Build a proof for avalanche's sybil resistance.\n",
216 {
218 "The proof's sequence"},
220 "A timestamp indicating when the proof expires"},
222 "The master private key in base58-encoding"},
223 {
224 "stakes",
227 "The stakes to be signed and associated private keys",
228 {
229 {
230 "stake",
233 "A stake to be attached to this proof",
234 {
235 {"txid", RPCArg::Type::STR_HEX,
236 RPCArg::Optional::NO, "The transaction id"},
238 "The output number"},
239 {"amount", RPCArg::Type::AMOUNT,
240 RPCArg::Optional::NO, "The amount in this UTXO"},
242 "The height at which this UTXO was mined"},
243 {"iscoinbase", RPCArg::Type::BOOL,
244 RPCArg::Default{false},
245 "Indicate whether the UTXO is a coinbase"},
246 {"privatekey", RPCArg::Type::STR,
248 "private key in base58-encoding"},
249 },
250 },
251 },
252 },
253 {"payoutAddress", RPCArg::Type::STR, RPCArg::Optional::NO,
254 "A payout address"},
255 },
257 "A string that is a serialized, hex-encoded proof data."},
258 RPCExamples{HelpExampleCli("buildavalancheproof",
259 "0 1234567800 \"<master>\" []") +
260 HelpExampleRpc("buildavalancheproof",
261 "0 1234567800 \"<master>\" []")},
262 [&](const RPCHelpMan &self, const Config &config,
263 const JSONRPCRequest &request) -> UniValue {
264 const uint64_t sequence = request.params[0].getInt<int64_t>();
265 const int64_t expiration = request.params[1].getInt<int64_t>();
266
267 CKey masterKey = DecodeSecret(request.params[2].get_str());
268 if (!masterKey.IsValid()) {
269 throw JSONRPCError(RPC_INVALID_PARAMETER, "Invalid master key");
270 }
271
272 CTxDestination payoutAddress = DecodeDestination(
273 request.params[4].get_str(), config.GetChainParams());
274
275 if (!IsValidDestination(payoutAddress)) {
277 "Invalid payout address");
278 }
279
280 avalanche::ProofBuilder pb(sequence, expiration, masterKey,
281 GetScriptForDestination(payoutAddress));
282
283 const UniValue &stakes = request.params[3].get_array();
284 for (size_t i = 0; i < stakes.size(); i++) {
285 const UniValue &stake = stakes[i];
287 stake,
288 {
289 {"txid", UniValue::VSTR},
290 {"vout", UniValue::VNUM},
291 // "amount" is also required but check is done below
292 // due to UniValue::VNUM erroneously not accepting
293 // quoted numerics (which are valid JSON)
294 {"height", UniValue::VNUM},
295 {"privatekey", UniValue::VSTR},
296 });
297
298 int nOut = stake.find_value("vout").getInt<int>();
299 if (nOut < 0) {
301 "vout cannot be negative");
302 }
303
304 const int height = stake.find_value("height").getInt<int>();
305 if (height < 1) {
307 "height must be positive");
308 }
309
310 const TxId txid(ParseHashO(stake, "txid"));
311 const COutPoint utxo(txid, nOut);
312
313 if (!stake.exists("amount")) {
314 throw JSONRPCError(RPC_INVALID_PARAMETER, "Missing amount");
315 }
316
317 const Amount amount =
318 AmountFromValue(stake.find_value("amount"));
319
320 const UniValue &iscbparam = stake.find_value("iscoinbase");
321 const bool iscoinbase =
322 iscbparam.isNull() ? false : iscbparam.get_bool();
323 CKey key =
324 DecodeSecret(stake.find_value("privatekey").get_str());
325
326 if (!key.IsValid()) {
328 "Invalid private key");
329 }
330
331 if (!pb.addUTXO(utxo, amount, uint32_t(height), iscoinbase,
332 std::move(key))) {
334 "Duplicated stake");
335 }
336 }
337
338 const avalanche::ProofRef proof = pb.build();
339
340 return proof->ToHex();
341 },
342 };
343}
344
346 return RPCHelpMan{
347 "decodeavalancheproof",
348 "Convert a serialized, hex-encoded proof into a JSON object. "
349 "The validity of the proof is not verified.\n",
350 {
352 "The proof hex string"},
353 },
354 RPCResult{
356 "",
357 "",
358 {
359 {RPCResult::Type::NUM, "sequence",
360 "The proof's sequential number"},
361 {RPCResult::Type::NUM, "expiration",
362 "A timestamp indicating when the proof expires"},
363 {RPCResult::Type::STR_HEX, "master", "The master public key"},
364 {RPCResult::Type::STR, "signature",
365 "The proof signature (base64 encoded)"},
367 "payoutscript",
368 "The proof payout script",
369 {
370 {RPCResult::Type::STR, "asm", "Decoded payout script"},
372 "Raw payout script in hex format"},
373 {RPCResult::Type::STR, "type",
374 "The output type (e.g. " + GetAllOutputTypes() + ")"},
375 {RPCResult::Type::NUM, "reqSigs",
376 "The required signatures"},
378 "addresses",
379 "",
380 {
381 {RPCResult::Type::STR, "address", "eCash address"},
382 }},
383 }},
384 {RPCResult::Type::STR_HEX, "limitedid",
385 "A hash of the proof data excluding the master key."},
386 {RPCResult::Type::STR_HEX, "proofid",
387 "A hash of the limitedid and master key."},
388 {RPCResult::Type::STR_AMOUNT, "staked_amount",
389 "The total staked amount of this proof in " +
390 Currency::get().ticker + "."},
391 {RPCResult::Type::NUM, "score", "The score of this proof."},
393 "stakes",
394 "",
395 {
397 "",
398 "",
399 {
401 "The transaction id"},
402 {RPCResult::Type::NUM, "vout", "The output number"},
404 "The amount in this UTXO"},
405 {RPCResult::Type::NUM, "height",
406 "The height at which this UTXO was mined"},
407 {RPCResult::Type::BOOL, "iscoinbase",
408 "Indicate whether the UTXO is a coinbase"},
409 {RPCResult::Type::STR_HEX, "pubkey",
410 "This UTXO's public key"},
411 {RPCResult::Type::STR, "signature",
412 "Signature of the proofid with this UTXO's private "
413 "key (base64 encoded)"},
414 }},
415 }},
416 }},
417 RPCExamples{HelpExampleCli("decodeavalancheproof", "\"<hex proof>\"") +
418 HelpExampleRpc("decodeavalancheproof", "\"<hex proof>\"")},
419 [&](const RPCHelpMan &self, const Config &config,
420 const JSONRPCRequest &request) -> UniValue {
421 avalanche::Proof proof;
422 bilingual_str error;
423 if (!avalanche::Proof::FromHex(proof, request.params[0].get_str(),
424 error)) {
426 }
427
428 UniValue result(UniValue::VOBJ);
429 result.pushKV("sequence", proof.getSequence());
430 result.pushKV("expiration", proof.getExpirationTime());
431 result.pushKV("master", HexStr(proof.getMaster()));
432 result.pushKV("signature", EncodeBase64(proof.getSignature()));
433
434 const auto payoutScript = proof.getPayoutScript();
435 UniValue payoutScriptObj(UniValue::VOBJ);
436 ScriptPubKeyToUniv(payoutScript, payoutScriptObj,
437 /* fIncludeHex */ true);
438 result.pushKV("payoutscript", payoutScriptObj);
439
440 result.pushKV("limitedid", proof.getLimitedId().ToString());
441 result.pushKV("proofid", proof.getId().ToString());
442
443 result.pushKV("staked_amount", proof.getStakedAmount());
444 result.pushKV("score", uint64_t(proof.getScore()));
445
446 UniValue stakes(UniValue::VARR);
447 for (const avalanche::SignedStake &s : proof.getStakes()) {
448 const COutPoint &utxo = s.getStake().getUTXO();
450 stake.pushKV("txid", utxo.GetTxId().ToString());
451 stake.pushKV("vout", uint64_t(utxo.GetN()));
452 stake.pushKV("amount", s.getStake().getAmount());
453 stake.pushKV("height", uint64_t(s.getStake().getHeight()));
454 stake.pushKV("iscoinbase", s.getStake().isCoinbase());
455 stake.pushKV("pubkey", HexStr(s.getStake().getPubkey()));
456 // Only PKHash destination is supported, so this is safe
457 stake.pushKV("address",
458 EncodeDestination(PKHash(s.getStake().getPubkey()),
459 config));
460 stake.pushKV("signature", EncodeBase64(s.getSignature()));
461 stakes.push_back(stake);
462 }
463 result.pushKV("stakes", stakes);
464
465 return result;
466 },
467 };
468}
469
471 return RPCHelpMan{
472 "delegateavalancheproof",
473 "Delegate the avalanche proof to another public key.\n",
474 {
476 "The limited id of the proof to be delegated."},
478 "The private key in base58-encoding. Must match the proof master "
479 "public key or the upper level parent delegation public key if "
480 "supplied."},
482 "The public key to delegate the proof to."},
484 "A string that is the serialized, hex-encoded delegation for the "
485 "proof and which is a parent for the delegation to build."},
486 },
488 "A string that is a serialized, hex-encoded delegation."},
490 HelpExampleCli("delegateavalancheproof",
491 "\"<limitedproofid>\" \"<privkey>\" \"<pubkey>\"") +
492 HelpExampleRpc("delegateavalancheproof",
493 "\"<limitedproofid>\" \"<privkey>\" \"<pubkey>\"")},
494 [&](const RPCHelpMan &self, const Config &config,
495 const JSONRPCRequest &request) -> UniValue {
496 avalanche::LimitedProofId limitedProofId{
497 ParseHashV(request.params[0], "limitedproofid")};
498
499 const CKey privkey = DecodeSecret(request.params[1].get_str());
500 if (!privkey.IsValid()) {
502 "The private key is invalid");
503 }
504
505 const CPubKey pubkey = ParsePubKey(request.params[2]);
506
507 std::unique_ptr<avalanche::DelegationBuilder> dgb;
508 if (request.params.size() >= 4 && !request.params[3].isNull()) {
510 CPubKey auth;
511 verifyDelegationOrThrow(dg, request.params[3].get_str(), auth);
512
513 if (dg.getProofId() !=
514 limitedProofId.computeProofId(dg.getProofMaster())) {
515 throw JSONRPCError(
517 "The delegation does not match the proof");
518 }
519
520 if (privkey.GetPubKey() != auth) {
521 throw JSONRPCError(
523 "The private key does not match the delegation");
524 }
525
526 dgb = std::make_unique<avalanche::DelegationBuilder>(dg);
527 } else {
528 dgb = std::make_unique<avalanche::DelegationBuilder>(
529 limitedProofId, privkey.GetPubKey());
530 }
531
532 if (!dgb->addLevel(privkey, pubkey)) {
534 "Unable to build the delegation");
535 }
536
537 DataStream ss{};
538 ss << dgb->build();
539 return HexStr(ss);
540 },
541 };
542}
543
545 return RPCHelpMan{
546 "decodeavalanchedelegation",
547 "Convert a serialized, hex-encoded avalanche proof delegation into "
548 "a JSON object.\n"
549 "The validity of the delegation is not verified.\n",
550 {
552 "The delegation hex string"},
553 },
554 RPCResult{
556 "",
557 "",
558 {
559 {RPCResult::Type::STR_HEX, "pubkey",
560 "The public key the proof is delegated to."},
561 {RPCResult::Type::STR_HEX, "proofmaster",
562 "The delegated proof master public key."},
563 {RPCResult::Type::STR_HEX, "delegationid",
564 "The identifier of this delegation."},
565 {RPCResult::Type::STR_HEX, "limitedid",
566 "A delegated proof data hash excluding the master key."},
567 {RPCResult::Type::STR_HEX, "proofid",
568 "A hash of the delegated proof limitedid and master key."},
569 {RPCResult::Type::NUM, "depth",
570 "The number of delegation levels."},
572 "levels",
573 "",
574 {
576 "",
577 "",
578 {
579 {RPCResult::Type::NUM, "index",
580 "The index of this delegation level."},
581 {RPCResult::Type::STR_HEX, "pubkey",
582 "This delegated public key for this level"},
583 {RPCResult::Type::STR, "signature",
584 "Signature of this delegation level (base64 "
585 "encoded)"},
586 }},
587 }},
588 }},
589 RPCExamples{HelpExampleCli("decodeavalanchedelegation",
590 "\"<hex delegation>\"") +
591 HelpExampleRpc("decodeavalanchedelegation",
592 "\"<hex delegation>\"")},
593 [&](const RPCHelpMan &self, const Config &config,
594 const JSONRPCRequest &request) -> UniValue {
595 avalanche::Delegation delegation;
596 bilingual_str error;
598 delegation, request.params[0].get_str(), error)) {
600 }
601
602 UniValue result(UniValue::VOBJ);
603 result.pushKV("pubkey", HexStr(delegation.getDelegatedPubkey()));
604 result.pushKV("proofmaster", HexStr(delegation.getProofMaster()));
605 result.pushKV("delegationid", delegation.getId().ToString());
606 result.pushKV("limitedid",
607 delegation.getLimitedProofId().ToString());
608 result.pushKV("proofid", delegation.getProofId().ToString());
609
610 auto levels = delegation.getLevels();
611 result.pushKV("depth", uint64_t(levels.size()));
612
613 UniValue levelsArray(UniValue::VARR);
614 for (auto &level : levels) {
616 obj.pushKV("pubkey", HexStr(level.pubkey));
617 obj.pushKV("signature", EncodeBase64(level.sig));
618 levelsArray.push_back(std::move(obj));
619 }
620 result.pushKV("levels", levelsArray);
621
622 return result;
623 },
624 };
625}
626
628 return RPCHelpMan{
629 "getavalancheinfo",
630 "Returns an object containing various state info regarding avalanche "
631 "networking.\n",
632 {},
633 RPCResult{
635 "",
636 "",
637 {
638 {RPCResult::Type::BOOL, "ready_to_poll",
639 "Whether the node is ready to start polling and voting."},
641 "local",
642 "Only available if -avaproof has been supplied to the node",
643 {
644 {RPCResult::Type::BOOL, "verified",
645 "Whether the node local proof has been locally verified "
646 "or not."},
647 {RPCResult::Type::STR, "verification_status",
648 "The proof verification status. Only available if the "
649 "\"verified\" flag is false."},
650 {RPCResult::Type::STR_HEX, "proofid",
651 "The node local proof id."},
652 {RPCResult::Type::STR_HEX, "limited_proofid",
653 "The node local limited proof id."},
654 {RPCResult::Type::STR_HEX, "master",
655 "The node local proof master public key."},
656 {RPCResult::Type::STR, "payout_address",
657 "The node local proof payout address. This might be "
658 "omitted if the payout script is not one of P2PK, P2PKH "
659 "or P2SH, in which case decodeavalancheproof can be used "
660 "to get more details."},
661 {RPCResult::Type::STR_AMOUNT, "stake_amount",
662 "The node local proof staked amount."},
663 }},
665 "network",
666 "",
667 {
668 {RPCResult::Type::NUM, "proof_count",
669 "The number of valid avalanche proofs we know exist "
670 "(including this node's local proof if applicable)."},
671 {RPCResult::Type::NUM, "connected_proof_count",
672 "The number of avalanche proofs with at least one node "
673 "we are connected to (including this node's local proof "
674 "if applicable)."},
675 {RPCResult::Type::NUM, "dangling_proof_count",
676 "The number of avalanche proofs with no node attached."},
677 {RPCResult::Type::NUM, "finalized_proof_count",
678 "The number of known avalanche proofs that have been "
679 "finalized by avalanche."},
680 {RPCResult::Type::NUM, "conflicting_proof_count",
681 "The number of known avalanche proofs that conflict with "
682 "valid proofs."},
683 {RPCResult::Type::NUM, "immature_proof_count",
684 "The number of known avalanche proofs that have immature "
685 "utxos."},
686 {RPCResult::Type::STR_AMOUNT, "total_stake_amount",
687 "The total staked amount over all the valid proofs in " +
689 " (including this node's local proof if "
690 "applicable)."},
691 {RPCResult::Type::STR_AMOUNT, "connected_stake_amount",
692 "The total staked amount over all the connected proofs "
693 "in " +
695 " (including this node's local proof if "
696 "applicable)."},
697 {RPCResult::Type::STR_AMOUNT, "dangling_stake_amount",
698 "The total staked amount over all the dangling proofs "
699 "in " +
701 " (including this node's local proof if "
702 "applicable)."},
703 {RPCResult::Type::STR_AMOUNT, "immature_stake_amount",
704 "The total staked amount over all the immature proofs "
705 "in " +
707 " (including this node's local proof if "
708 "applicable)."},
709 {RPCResult::Type::NUM, "node_count",
710 "The number of avalanche nodes we are connected to "
711 "(including this node if a local proof is set)."},
712 {RPCResult::Type::NUM, "connected_node_count",
713 "The number of avalanche nodes associated with an "
714 "avalanche proof (including this node if a local proof "
715 "is set)."},
716 {RPCResult::Type::NUM, "pending_node_count",
717 "The number of avalanche nodes pending for a proof."},
718 }},
719 },
720 },
721 RPCExamples{HelpExampleCli("getavalancheinfo", "") +
722 HelpExampleRpc("getavalancheinfo", "")},
723 [&](const RPCHelpMan &self, const Config &config,
724 const JSONRPCRequest &request) -> UniValue {
725 NodeContext &node = EnsureAnyNodeContext(request.context);
727
729 ret.pushKV("ready_to_poll", avalanche.isQuorumEstablished());
730
731 auto localProof = avalanche.getLocalProof();
732 if (localProof != nullptr) {
734 const bool verified = avalanche.withPeerManager(
735 [&](const avalanche::PeerManager &pm) {
736 const avalanche::ProofId &proofid = localProof->getId();
737 return pm.isBoundToPeer(proofid);
738 });
739 local.pushKV("verified", verified);
740 const bool sharing = avalanche.canShareLocalProof();
741 if (!verified) {
743 avalanche.getLocalProofRegistrationState();
744 // If the local proof is not registered but the state is
745 // valid, no registration attempt occurred yet.
746 local.pushKV("verification_status",
747 state.IsValid()
748 ? (sharing ? "pending verification"
749 : "pending inbound connections")
750 : state.GetRejectReason());
751 }
752 local.pushKV("proofid", localProof->getId().ToString());
753 local.pushKV("limited_proofid",
754 localProof->getLimitedId().ToString());
755 local.pushKV("master", HexStr(localProof->getMaster()));
756 CTxDestination destination;
757 if (ExtractDestination(localProof->getPayoutScript(),
758 destination)) {
759 local.pushKV("payout_address",
760 EncodeDestination(destination, config));
761 }
762 local.pushKV("stake_amount", localProof->getStakedAmount());
763 ret.pushKV("local", local);
764 }
765
766 avalanche.withPeerManager([&](avalanche::PeerManager &pm) {
767 UniValue network(UniValue::VOBJ);
768
769 uint64_t proofCount{0};
770 uint64_t connectedProofCount{0};
771 uint64_t finalizedProofCount{0};
772 uint64_t connectedNodeCount{0};
773 Amount totalStakes = Amount::zero();
774 Amount connectedStakes = Amount::zero();
775
776 pm.forEachPeer([&](const avalanche::Peer &peer) {
777 CHECK_NONFATAL(peer.proof != nullptr);
778
779 const bool isLocalProof =
780 localProof &&
781 peer.proof->getId() == localProof->getId();
782
783 ++proofCount;
784 const Amount proofStake = peer.proof->getStakedAmount();
785
786 totalStakes += proofStake;
787
788 if (peer.hasFinalized) {
789 ++finalizedProofCount;
790 }
791
792 if (peer.node_count > 0 || isLocalProof) {
793 ++connectedProofCount;
794 connectedStakes += proofStake;
795 }
796
797 connectedNodeCount += peer.node_count + isLocalProof;
798 });
799
800 Amount immatureStakes = Amount::zero();
802 [&](const avalanche::ProofRef &proof) {
803 immatureStakes += proof->getStakedAmount();
804 });
805
806 network.pushKV("proof_count", proofCount);
807 network.pushKV("connected_proof_count", connectedProofCount);
808 network.pushKV("dangling_proof_count",
809 proofCount - connectedProofCount);
810
811 network.pushKV("finalized_proof_count", finalizedProofCount);
812 network.pushKV(
813 "conflicting_proof_count",
814 uint64_t(pm.getConflictingProofPool().countProofs()));
815 network.pushKV(
816 "immature_proof_count",
817 uint64_t(pm.getImmatureProofPool().countProofs()));
818
819 network.pushKV("total_stake_amount", totalStakes);
820 network.pushKV("connected_stake_amount", connectedStakes);
821 network.pushKV("dangling_stake_amount",
822 totalStakes - connectedStakes);
823 network.pushKV("immature_stake_amount", immatureStakes);
824
825 const uint64_t pendingNodes = pm.getPendingNodeCount();
826 network.pushKV("node_count", connectedNodeCount + pendingNodes);
827 network.pushKV("connected_node_count", connectedNodeCount);
828 network.pushKV("pending_node_count", pendingNodes);
829
830 ret.pushKV("network", network);
831 });
832
833 return ret;
834 },
835 };
836}
837
839 return RPCHelpMan{
840 "getavalanchepeerinfo",
841 "Returns data about an avalanche peer as a json array of objects. If "
842 "no proofid is provided, returns data about all the peers.\n",
843 {
845 "The hex encoded avalanche proof identifier."},
846 },
847 RPCResult{
849 "",
850 "",
851 {{
853 "",
854 "",
855 {{
856 {RPCResult::Type::NUM, "avalanche_peerid",
857 "The avalanche internal peer identifier"},
858 {RPCResult::Type::STR_HEX, "proofid",
859 "The avalanche proof id used by this peer"},
860 {RPCResult::Type::STR_HEX, "proof",
861 "The avalanche proof used by this peer"},
862 {RPCResult::Type::NUM, "nodecount",
863 "The number of nodes for this peer"},
865 "node_list",
866 "",
867 {
868 {RPCResult::Type::NUM, "nodeid",
869 "Node id, as returned by getpeerinfo"},
870 }},
871 }},
872 }},
873 },
874 RPCExamples{HelpExampleCli("getavalanchepeerinfo", "") +
875 HelpExampleCli("getavalanchepeerinfo", "\"proofid\"") +
876 HelpExampleRpc("getavalanchepeerinfo", "") +
877 HelpExampleRpc("getavalanchepeerinfo", "\"proofid\"")},
878 [&](const RPCHelpMan &self, const Config &config,
879 const JSONRPCRequest &request) -> UniValue {
880 NodeContext &node = EnsureAnyNodeContext(request.context);
882
883 auto peerToUniv = [](const avalanche::PeerManager &pm,
884 const avalanche::Peer &peer) {
886
887 obj.pushKV("avalanche_peerid", uint64_t(peer.peerid));
888 obj.pushKV("proofid", peer.getProofId().ToString());
889 obj.pushKV("proof", peer.proof->ToHex());
890
892 pm.forEachNode(peer, [&](const avalanche::Node &n) {
893 nodes.push_back(n.nodeid);
894 });
895
896 obj.pushKV("nodecount", uint64_t(peer.node_count));
897 obj.pushKV("node_list", nodes);
898
899 return obj;
900 };
901
903
904 avalanche.withPeerManager([&](const avalanche::PeerManager &pm) {
905 // If a proofid is provided, only return the associated peer
906 if (!request.params[0].isNull()) {
907 const avalanche::ProofId proofid =
908 avalanche::ProofId::fromHex(
909 request.params[0].get_str());
910 if (!pm.isBoundToPeer(proofid)) {
911 throw JSONRPCError(RPC_INVALID_PARAMETER,
912 "Proofid not found");
913 }
914
915 pm.forPeer(proofid, [&](const avalanche::Peer &peer) {
916 ret.push_back(peerToUniv(pm, peer));
917 return true;
918 });
919
920 return;
921 }
922
923 // If no proofid is provided, return all the peers
924 pm.forEachPeer([&](const avalanche::Peer &peer) {
925 ret.push_back(peerToUniv(pm, peer));
926 });
927 });
928
929 return ret;
930 },
931 };
932}
933
935 return RPCHelpMan{
936 "getavalancheproofs",
937 "Returns an object containing all tracked proofids.\n",
938 {},
939 RPCResult{
941 "",
942 "",
943 {
945 "valid",
946 "",
947 {
948 {RPCResult::Type::STR_HEX, "proofid",
949 "Avalanche proof id"},
950 }},
952 "conflicting",
953 "",
954 {
955 {RPCResult::Type::STR_HEX, "proofid",
956 "Avalanche proof id"},
957 }},
959 "immature",
960 "",
961 {
962 {RPCResult::Type::STR_HEX, "proofid",
963 "Avalanche proof id"},
964 }},
965 },
966 },
967 RPCExamples{HelpExampleCli("getavalancheproofs", "") +
968 HelpExampleRpc("getavalancheproofs", "")},
969 [&](const RPCHelpMan &self, const Config &config,
970 const JSONRPCRequest &request) -> UniValue {
971 NodeContext &node = EnsureAnyNodeContext(request.context);
973
975 avalanche.withPeerManager([&](avalanche::PeerManager &pm) {
976 auto appendProofIds = [&ret](const avalanche::ProofPool &pool,
977 const std::string &key) {
978 UniValue arrOut(UniValue::VARR);
979 for (const avalanche::ProofId &proofid :
980 pool.getProofIds()) {
981 arrOut.push_back(proofid.ToString());
982 }
983 ret.pushKV(key, arrOut);
984 };
985
986 appendProofIds(pm.getValidProofPool(), "valid");
987 appendProofIds(pm.getConflictingProofPool(), "conflicting");
988 appendProofIds(pm.getImmatureProofPool(), "immature");
989 });
990
991 return ret;
992 },
993 };
994}
995
997 return RPCHelpMan{
998 "getstakingreward",
999 "Return a list of possible staking reward winners based on the "
1000 "previous "
1001 "block hash.\n",
1002 {
1004 "The previous block hash, hex encoded."},
1005 {"recompute", RPCArg::Type::BOOL, RPCArg::Default{false},
1006 "Whether to recompute the staking reward winner if there is a "
1007 "cached value."},
1008 },
1009 RPCResult{
1011 "",
1012 "",
1013 {
1015 "winner",
1016 "The winning proof",
1017 {
1018 {RPCResult::Type::STR_HEX, "proofid",
1019 "The winning proofid"},
1020 {RPCResult::Type::STR, "asm", "Decoded payout script"},
1022 "Raw payout script in hex format"},
1023 {RPCResult::Type::STR, "type",
1024 "The output type (e.g. " + GetAllOutputTypes() + ")"},
1025 {RPCResult::Type::NUM, "reqSigs",
1026 "The required signatures"},
1028 "addresses",
1029 "",
1030 {
1031 {RPCResult::Type::STR, "address", "eCash address"},
1032 }},
1033 }},
1034 }},
1035 RPCExamples{HelpExampleCli("getstakingreward", "<blockhash>") +
1036 HelpExampleRpc("getstakingreward", "<blockhash>")},
1037 [&](const RPCHelpMan &self, const Config &config,
1038 const JSONRPCRequest &request) -> UniValue {
1039 const NodeContext &node = EnsureAnyNodeContext(request.context);
1042
1043 const BlockHash blockhash(
1044 ParseHashV(request.params[0], "blockhash"));
1045
1046 const CBlockIndex *pprev;
1047 {
1048 LOCK(cs_main);
1049 pprev = chainman.m_blockman.LookupBlockIndex(blockhash);
1050 }
1051
1052 if (!pprev) {
1053 throw JSONRPCError(
1055 strprintf("Block not found: %s\n", blockhash.ToString()));
1056 }
1057
1059 config.GetChainParams().GetConsensus(), pprev)) {
1060 throw JSONRPCError(
1062 strprintf(
1063 "Staking rewards are not activated for block %s\n",
1064 blockhash.ToString()));
1065 }
1066
1067 if (!request.params[1].isNull() && request.params[1].get_bool()) {
1068 // Force recompute the staking reward winner by first erasing
1069 // the cached entry if any
1070 avalanche.eraseStakingRewardWinner(blockhash);
1071 }
1072
1073 if (!avalanche.computeStakingReward(pprev)) {
1074 throw JSONRPCError(
1076 strprintf("Unable to determine a staking reward winner "
1077 "for block %s\n",
1078 blockhash.ToString()));
1079 }
1080
1081 std::vector<std::pair<avalanche::ProofId, CScript>> winners;
1082 if (!avalanche.getStakingRewardWinners(blockhash, winners)) {
1083 throw JSONRPCError(
1085 strprintf("Unable to retrieve the staking reward winner "
1086 "for block %s\n",
1087 blockhash.ToString()));
1088 }
1089
1090 UniValue winnersArr(UniValue::VARR);
1091 for (auto &winner : winners) {
1092 UniValue stakingRewardsObj(UniValue::VOBJ);
1093 ScriptPubKeyToUniv(winner.second, stakingRewardsObj,
1094 /*fIncludeHex=*/true);
1095 stakingRewardsObj.pushKV("proofid", winner.first.GetHex());
1096 winnersArr.push_back(stakingRewardsObj);
1097 }
1098
1099 return winnersArr;
1100 },
1101 };
1102}
1103
1105 return RPCHelpMan{
1106 "hasstakingreward",
1107 "Return true if a staking reward winner exists based on the previous "
1108 "block hash.\n",
1109 {
1111 "The previous block hash, hex encoded."},
1112 },
1114 "Whether staking reward winner has been computed for "
1115 "previous block hash or not."},
1116 RPCExamples{HelpExampleCli("hasstakingreward", "<blockhash>") +
1117 HelpExampleRpc("hasstakingreward", "<blockhash>")},
1118 [&](const RPCHelpMan &self, const Config &config,
1119 const JSONRPCRequest &request) -> UniValue {
1120 const NodeContext &node = EnsureAnyNodeContext(request.context);
1123
1124 const BlockHash blockhash(
1125 ParseHashV(request.params[0], "blockhash"));
1126
1127 const CBlockIndex *pprev;
1128 {
1129 LOCK(cs_main);
1130 pprev = chainman.m_blockman.LookupBlockIndex(blockhash);
1131 }
1132
1133 if (!pprev) {
1134 throw JSONRPCError(
1136 strprintf("Block not found: %s\n", blockhash.ToString()));
1137 }
1138
1140 config.GetChainParams().GetConsensus(), pprev)) {
1141 throw JSONRPCError(
1143 strprintf(
1144 "Staking rewards are not activated for block %s\n",
1145 blockhash.ToString()));
1146 }
1147
1148 std::vector<std::pair<avalanche::ProofId, CScript>> winners;
1149 if (!avalanche.getStakingRewardWinners(blockhash, winners)) {
1150 return false;
1151 }
1152 return winners.size() > 0;
1153 },
1154 };
1155}
1156
1158 return RPCHelpMan{
1159 "setstakingreward",
1160 "Set the staking reward winner for the given previous block hash.\n",
1161 {
1163 "The previous block hash, hex encoded."},
1165 "The payout script for the staking reward, hex encoded."},
1166 {"append", RPCArg::Type::BOOL, RPCArg::Default{false},
1167 "Append to the list of possible winners instead of replacing."},
1168 },
1170 "Whether the payout script was set or not"},
1172 HelpExampleCli("setstakingreward", "<blockhash> <payout script>") +
1173 HelpExampleRpc("setstakingreward", "<blockhash> <payout script>")},
1174 [&](const RPCHelpMan &self, const Config &config,
1175 const JSONRPCRequest &request) -> UniValue {
1176 const NodeContext &node = EnsureAnyNodeContext(request.context);
1179
1180 const BlockHash blockhash(
1181 ParseHashV(request.params[0], "blockhash"));
1182
1183 const CBlockIndex *pprev;
1184 {
1185 LOCK(cs_main);
1186 pprev = chainman.m_blockman.LookupBlockIndex(blockhash);
1187 }
1188
1189 if (!pprev) {
1190 throw JSONRPCError(
1192 strprintf("Block not found: %s\n", blockhash.ToString()));
1193 }
1194
1196 config.GetChainParams().GetConsensus(), pprev)) {
1197 throw JSONRPCError(
1199 strprintf(
1200 "Staking rewards are not activated for block %s\n",
1201 blockhash.ToString()));
1202 }
1203
1204 const std::vector<uint8_t> data =
1205 ParseHex(request.params[1].get_str());
1206 CScript payoutScript(data.begin(), data.end());
1207
1208 std::vector<CScript> payoutScripts;
1209
1210 if (!request.params[2].isNull() && request.params[2].get_bool()) {
1211 // Append mode, initialize our list with the current winners
1212 // and the new one will be added to the back of that list. If
1213 // there is no winner the list will remain empty.
1214 avalanche.getStakingRewardWinners(blockhash, payoutScripts);
1215 }
1216
1217 if (std::find(payoutScripts.begin(), payoutScripts.end(),
1218 payoutScript) != payoutScripts.end()) {
1219 throw JSONRPCError(
1221 strprintf(
1222 "Staking rewards winner is already set for block %s\n",
1223 blockhash.ToString()));
1224 }
1225
1226 payoutScripts.push_back(std::move(payoutScript));
1227
1228 // This will return true upon insertion or false upon replacement.
1229 // We want to convey the success of the RPC, so we always return
1230 // true.
1231 avalanche.setStakingRewardWinners(pprev, payoutScripts);
1232 return true;
1233 },
1234 };
1235}
1236
1238 return RPCHelpMan{
1239 "getremoteproofs",
1240 "Get the list of remote proofs for the given node id.\n",
1241 {
1243 "The node identifier."},
1244 },
1245 RPCResult{
1247 "proofs",
1248 "",
1249 {{
1251 "proof",
1252 "",
1253 {{
1254 {RPCResult::Type::STR_HEX, "proofid",
1255 "The hex encoded proof identifier."},
1256 {RPCResult::Type::BOOL, "present",
1257 "Whether the node has the proof."},
1258 {RPCResult::Type::NUM, "last_update",
1259 "The last time this proof status was updated."},
1260 }},
1261 }},
1262 },
1263 RPCExamples{HelpExampleCli("getremoteproofs", "<nodeid>") +
1264 HelpExampleRpc("getremoteproofs", "<nodeid>")},
1265 [&](const RPCHelpMan &self, const Config &config,
1266 const JSONRPCRequest &request) -> UniValue {
1267 NodeContext &node = EnsureAnyNodeContext(request.context);
1269
1270 const NodeId nodeid = request.params[0].getInt<int64_t>();
1271 auto remoteProofs = avalanche.withPeerManager(
1272 [nodeid](const avalanche::PeerManager &pm) {
1273 return pm.getRemoteProofs(nodeid);
1274 });
1275
1276 UniValue arrOut(UniValue::VARR);
1277
1278 for (const auto &remoteProof : remoteProofs) {
1280 obj.pushKV("proofid", remoteProof.proofid.ToString());
1281 obj.pushKV("present", remoteProof.present);
1282 obj.pushKV("last_update", remoteProof.lastUpdate.count());
1283
1284 arrOut.push_back(obj);
1285 }
1286
1287 return arrOut;
1288 },
1289 };
1290}
1291
1293 return RPCHelpMan{
1294 "getrawavalancheproof",
1295 "Lookup for a known avalanche proof by id.\n",
1296 {
1298 "The hex encoded avalanche proof identifier."},
1299 },
1300 RPCResult{
1302 "",
1303 "",
1304 {{
1305 {RPCResult::Type::STR_HEX, "proof",
1306 "The hex encoded proof matching the identifier."},
1307 {RPCResult::Type::BOOL, "immature",
1308 "Whether the proof has immature utxos."},
1309 {RPCResult::Type::BOOL, "boundToPeer",
1310 "Whether the proof is bound to an avalanche peer."},
1311 {RPCResult::Type::BOOL, "conflicting",
1312 "Whether the proof has a conflicting UTXO with an avalanche "
1313 "peer."},
1314 {RPCResult::Type::BOOL, "finalized",
1315 "Whether the proof is finalized by vote."},
1316 }},
1317 },
1318 RPCExamples{HelpExampleCli("getrawavalancheproof", "<proofid>") +
1319 HelpExampleRpc("getrawavalancheproof", "<proofid>")},
1320 [&](const RPCHelpMan &self, const Config &config,
1321 const JSONRPCRequest &request) -> UniValue {
1322 NodeContext &node = EnsureAnyNodeContext(request.context);
1324
1325 const avalanche::ProofId proofid =
1326 avalanche::ProofId::fromHex(request.params[0].get_str());
1327
1328 bool isImmature = false;
1329 bool isBoundToPeer = false;
1330 bool conflicting = false;
1331 bool finalized = false;
1332 auto proof = avalanche.withPeerManager(
1333 [&](const avalanche::PeerManager &pm) {
1334 isImmature = pm.isImmature(proofid);
1335 isBoundToPeer = pm.isBoundToPeer(proofid);
1336 conflicting = pm.isInConflictingPool(proofid);
1337 finalized =
1338 pm.forPeer(proofid, [&](const avalanche::Peer &p) {
1339 return p.hasFinalized;
1340 });
1341 return pm.getProof(proofid);
1342 });
1343
1344 if (!proof) {
1345 throw JSONRPCError(RPC_INVALID_PARAMETER, "Proof not found");
1346 }
1347
1349
1350 DataStream ss{};
1351 ss << *proof;
1352 ret.pushKV("proof", HexStr(ss));
1353 ret.pushKV("immature", isImmature);
1354 ret.pushKV("boundToPeer", isBoundToPeer);
1355 ret.pushKV("conflicting", conflicting);
1356 ret.pushKV("finalized", finalized);
1357
1358 return ret;
1359 },
1360 };
1361}
1362
1364 return RPCHelpMan{
1365 "invalidateavalancheproof",
1366 "Reject a known avalanche proof by id.\n",
1367 {
1369 "The hex encoded avalanche proof identifier."},
1370 },
1371 RPCResult{
1373 "success",
1374 "",
1375 },
1376 RPCExamples{HelpExampleCli("invalidateavalancheproof", "<proofid>") +
1377 HelpExampleRpc("invalidateavalancheproof", "<proofid>")},
1378 [&](const RPCHelpMan &self, const Config &config,
1379 const JSONRPCRequest &request) -> UniValue {
1380 NodeContext &node = EnsureAnyNodeContext(request.context);
1382
1383 const avalanche::ProofId proofid =
1384 avalanche::ProofId::fromHex(request.params[0].get_str());
1385
1386 avalanche.withPeerManager([&](avalanche::PeerManager &pm) {
1387 if (!pm.exists(proofid) && !pm.isDangling(proofid)) {
1388 throw JSONRPCError(RPC_INVALID_PARAMETER,
1389 "Proof not found");
1390 }
1391
1392 if (!pm.rejectProof(
1393 proofid,
1395 throw JSONRPCError(RPC_INTERNAL_ERROR,
1396 "Failed to reject the proof");
1397 }
1398
1399 pm.setInvalid(proofid);
1400 });
1401
1402 if (avalanche.isRecentlyFinalized(proofid)) {
1403 // If the proof was previously finalized, clear the status.
1404 // Because there is no way to selectively delete an entry from a
1405 // Bloom filter, we have to clear the whole filter which could
1406 // cause extra voting rounds.
1407 avalanche.clearFinalizedItems();
1408 }
1409
1410 return true;
1411 },
1412 };
1413}
1414
1416 return RPCHelpMan{
1417 "isfinalblock",
1418 "Check if a block has been finalized by avalanche votes.\n",
1419 {
1421 "The hash of the block."},
1422 },
1424 "Whether the block has been finalized by avalanche votes."},
1425 RPCExamples{HelpExampleCli("isfinalblock", "<block hash>") +
1426 HelpExampleRpc("isfinalblock", "<block hash>")},
1427 [&](const RPCHelpMan &self, const Config &config,
1428 const JSONRPCRequest &request) -> UniValue {
1429 NodeContext &node = EnsureAnyNodeContext(request.context);
1431
1432 if (!avalanche.isQuorumEstablished()) {
1434 "Avalanche is not ready to poll yet.");
1435 }
1436
1437 ChainstateManager &chainman = EnsureAnyChainman(request.context);
1438 const BlockHash blockhash(
1439 ParseHashV(request.params[0], "blockhash"));
1440 const CBlockIndex *pindex;
1441
1442 {
1443 LOCK(cs_main);
1444 pindex = chainman.m_blockman.LookupBlockIndex(blockhash);
1445
1446 if (!pindex) {
1448 "Block not found");
1449 }
1450 }
1451
1452 return chainman.ActiveChainstate().IsBlockAvalancheFinalized(
1453 pindex);
1454 },
1455 };
1456}
1457
1459 return RPCHelpMan{
1460 "isfinaltransaction",
1461 "Check if a transaction has been finalized by avalanche votes.\n",
1462 {
1464 "The id of the transaction."},
1466 "The block in which to look for the transaction"},
1467 },
1468 RPCResult{
1469 RPCResult::Type::BOOL, "success",
1470 "Whether the transaction has been finalized by avalanche votes."},
1471 RPCExamples{HelpExampleCli("isfinaltransaction", "<txid> <blockhash>") +
1472 HelpExampleRpc("isfinaltransaction", "<txid> <blockhash>")},
1473 [&](const RPCHelpMan &self, const Config &config,
1474 const JSONRPCRequest &request) -> UniValue {
1475 const NodeContext &node = EnsureAnyNodeContext(request.context);
1477 const CTxMemPool &mempool = EnsureMemPool(node);
1479
1480 const TxId txid = TxId(ParseHashV(request.params[0], "txid"));
1481 CBlockIndex *pindex = nullptr;
1482
1483 if (!request.params[1].isNull()) {
1484 const BlockHash blockhash(
1485 ParseHashV(request.params[1], "blockhash"));
1486
1487 LOCK(cs_main);
1488 pindex = chainman.m_blockman.LookupBlockIndex(blockhash);
1489 if (!pindex) {
1491 "Block not found");
1492 }
1493 }
1494
1495 bool f_txindex_ready = false;
1496 if (g_txindex && !pindex) {
1497 f_txindex_ready = g_txindex->BlockUntilSyncedToCurrentChain();
1498 }
1499
1500 BlockHash hash_block;
1502 pindex, &mempool, txid, hash_block, chainman.m_blockman);
1503
1504 if (!avalanche.isQuorumEstablished()) {
1506 "Avalanche is not ready to poll yet.");
1507 }
1508
1509 if (!tx) {
1510 std::string errmsg;
1511 if (pindex) {
1512 if (WITH_LOCK(::cs_main,
1513 return !pindex->nStatus.hasData())) {
1515 "Block data not downloaded yet.");
1516 }
1517 errmsg = "No such transaction found in the provided block.";
1518 } else if (!g_txindex) {
1519 errmsg = "No such transaction. Use -txindex or provide a "
1520 "block hash to enable blockchain transaction "
1521 "queries.";
1522 } else if (!f_txindex_ready) {
1523 errmsg = "No such transaction. Blockchain transactions are "
1524 "still in the process of being indexed.";
1525 } else {
1526 errmsg = "No such mempool or blockchain transaction.";
1527 }
1529 }
1530
1531 if (!pindex) {
1532 LOCK(cs_main);
1533 pindex = chainman.m_blockman.LookupBlockIndex(hash_block);
1534 }
1535
1536 if (!tx) {
1537 // Tx not found, we should have raised an error at this stage
1538 return false;
1539 }
1540
1541 if (WITH_LOCK(
1542 mempool.cs,
1543 return mempool.isAvalancheFinalizedPreConsensus(txid))) {
1544 // The transaction is finalized
1545 return true;
1546 }
1547
1548 // Return true if the tx is in a finalized block
1549 return !node.mempool->exists(txid) &&
1550 chainman.ActiveChainstate().IsBlockAvalancheFinalized(
1551 pindex);
1552 },
1553 };
1554}
1555
1557 return RPCHelpMan{
1558 "reconsideravalancheproof",
1559 "Reconsider a known avalanche proof.\n",
1560 {
1562 "The hex encoded avalanche proof."},
1563 },
1564 RPCResult{
1566 "success",
1567 "Whether the proof has been successfully registered.",
1568 },
1569 RPCExamples{HelpExampleCli("reconsideravalancheproof", "<proof hex>") +
1570 HelpExampleRpc("reconsideravalancheproof", "<proof hex>")},
1571 [&](const RPCHelpMan &self, const Config &config,
1572 const JSONRPCRequest &request) -> UniValue {
1573 auto proof = RCUPtr<avalanche::Proof>::make();
1574
1575 NodeContext &node = EnsureAnyNodeContext(request.context);
1577
1578 // Verify the proof. Note that this is redundant with the
1579 // verification done when adding the proof to the pool, but we get a
1580 // chance to give a better error message.
1581 verifyProofOrThrow(node, *proof, request.params[0].get_str());
1582
1583 // There is no way to selectively clear the invalidation status of
1584 // a single proof, so we clear the whole Bloom filter. This could
1585 // cause extra voting rounds.
1586 avalanche.withPeerManager([&](avalanche::PeerManager &pm) {
1587 if (pm.isInvalid(proof->getId())) {
1588 pm.clearAllInvalid();
1589 }
1590 });
1591
1592 // Add the proof to the pool if we don't have it already. Since the
1593 // proof verification has already been done, a failure likely
1594 // indicates that there already is a proof with conflicting utxos.
1596 if (!registerProofIfNeeded(avalanche, proof, state)) {
1598 strprintf("%s (%s)\n",
1599 state.GetRejectReason(),
1600 state.GetDebugMessage()));
1601 }
1602
1603 return avalanche.withPeerManager(
1604 [&](const avalanche::PeerManager &pm) {
1605 return pm.isBoundToPeer(proof->getId());
1606 });
1607 },
1608 };
1609}
1610
1612 return RPCHelpMan{
1613 "sendavalancheproof",
1614 "Broadcast an avalanche proof.\n",
1615 {
1617 "The avalanche proof to broadcast."},
1618 },
1620 "Whether the proof was sent successfully or not."},
1621 RPCExamples{HelpExampleCli("sendavalancheproof", "<proof>") +
1622 HelpExampleRpc("sendavalancheproof", "<proof>")},
1623 [&](const RPCHelpMan &self, const Config &config,
1624 const JSONRPCRequest &request) -> UniValue {
1625 auto proof = RCUPtr<avalanche::Proof>::make();
1626
1627 NodeContext &node = EnsureAnyNodeContext(request.context);
1629
1630 // Verify the proof. Note that this is redundant with the
1631 // verification done when adding the proof to the pool, but we get a
1632 // chance to give a better error message.
1633 verifyProofOrThrow(node, *proof, request.params[0].get_str());
1634
1635 // Add the proof to the pool if we don't have it already. Since the
1636 // proof verification has already been done, a failure likely
1637 // indicates that there already is a proof with conflicting utxos.
1638 const avalanche::ProofId &proofid = proof->getId();
1640 if (!registerProofIfNeeded(avalanche, proof, state)) {
1642 strprintf("%s (%s)\n",
1643 state.GetRejectReason(),
1644 state.GetDebugMessage()));
1645 }
1646
1647 avalanche.withPeerManager([&](avalanche::PeerManager &pm) {
1648 pm.addUnbroadcastProof(proofid);
1649 });
1650
1651 if (node.peerman) {
1652 node.peerman->RelayProof(proofid);
1653 }
1654
1655 return true;
1656 },
1657 };
1658}
1659
1661 return RPCHelpMan{
1662 "verifyavalancheproof",
1663 "Verify an avalanche proof is valid and return the error otherwise.\n",
1664 {
1666 "Proof to verify."},
1667 },
1669 "Whether the proof is valid or not."},
1670 RPCExamples{HelpExampleCli("verifyavalancheproof", "\"<proof>\"") +
1671 HelpExampleRpc("verifyavalancheproof", "\"<proof>\"")},
1672 [&](const RPCHelpMan &self, const Config &config,
1673 const JSONRPCRequest &request) -> UniValue {
1674 avalanche::Proof proof;
1675 verifyProofOrThrow(EnsureAnyNodeContext(request.context), proof,
1676 request.params[0].get_str());
1677
1678 return true;
1679 },
1680 };
1681}
1682
1684 return RPCHelpMan{
1685 "verifyavalanchedelegation",
1686 "Verify an avalanche delegation is valid and return the error "
1687 "otherwise.\n",
1688 {
1690 "The avalanche proof delegation to verify."},
1691 },
1693 "Whether the delegation is valid or not."},
1694 RPCExamples{HelpExampleCli("verifyavalanchedelegation", "\"<proof>\"") +
1695 HelpExampleRpc("verifyavalanchedelegation", "\"<proof>\"")},
1696 [&](const RPCHelpMan &self, const Config &config,
1697 const JSONRPCRequest &request) -> UniValue {
1698 avalanche::Delegation delegation;
1699 CPubKey dummy;
1700 verifyDelegationOrThrow(delegation, request.params[0].get_str(),
1701 dummy);
1702
1703 return true;
1704 },
1705 };
1706}
1707
1709 return RPCHelpMan{
1710 "setflakyproof",
1711 "Add or remove a proofid from the flaky list. This means that an "
1712 "additional staking reward winner will be accepted if this proof is "
1713 "the selected one.\n",
1714 {
1716 "The avalanche proof id."},
1718 "Whether to add (true) or remove (false) the proof from the flaky "
1719 "list"},
1720 },
1722 "Whether the addition/removal is successful."},
1723 RPCExamples{HelpExampleCli("setflakyproof", "\"<proofid>\" true") +
1724 HelpExampleRpc("setflakyproof", "\"<proofid>\" true")},
1725 [&](const RPCHelpMan &self, const Config &config,
1726 const JSONRPCRequest &request) -> UniValue {
1727 NodeContext &node = EnsureAnyNodeContext(request.context);
1730
1731 const auto proofid =
1732 avalanche::ProofId::fromHex(request.params[0].get_str());
1733 const bool addNotRemove = request.params[1].get_bool();
1734
1735 if (avalanche.withPeerManager(
1736 [&proofid, addNotRemove](avalanche::PeerManager &pm) {
1737 if (addNotRemove) {
1738 return pm.setFlaky(proofid);
1739 }
1740 return pm.unsetFlaky(proofid);
1741 })) {
1742 const CBlockIndex *pprev =
1743 WITH_LOCK(cs_main, return chainman.ActiveTip());
1744 // Force recompute the staking reward winner by first erasing
1745 // the cached entry if any
1746 avalanche.eraseStakingRewardWinner(pprev->GetBlockHash());
1747 return avalanche.computeStakingReward(pprev);
1748 }
1749
1750 return false;
1751 }};
1752}
1753
1755 return RPCHelpMan{
1756 "getflakyproofs",
1757 "List the flaky proofs (set via setflakyproof).\n",
1758 {},
1759 RPCResult{
1761 "flaky_proofs",
1762 "",
1763 {{
1765 "proof",
1766 "",
1767 {{
1768 {RPCResult::Type::STR_HEX, "proofid",
1769 "The hex encoded proof identifier."},
1770 {RPCResult::Type::STR_AMOUNT, "staked_amount",
1771 "The proof stake amount, only present if the proof is "
1772 "known."},
1774 "payout",
1775 "The proof payout script, only present if the proof is "
1776 "known.",
1777 {
1778 {RPCResult::Type::STR, "asm", "Decoded payout script"},
1780 "Raw payout script in hex format"},
1781 {RPCResult::Type::STR, "type",
1782 "The output type (e.g. " + GetAllOutputTypes() + ")"},
1783 {RPCResult::Type::NUM, "reqSigs",
1784 "The required signatures"},
1786 "addresses",
1787 "",
1788 {
1789 {RPCResult::Type::STR, "address",
1790 "eCash address"},
1791 }},
1792 }},
1793 }},
1794 }},
1795 },
1796 RPCExamples{HelpExampleCli("getflakyproofs", "") +
1797 HelpExampleRpc("getflakyproofs", "")},
1798 [&](const RPCHelpMan &self, const Config &config,
1799 const JSONRPCRequest &request) -> UniValue {
1800 NodeContext &node = EnsureAnyNodeContext(request.context);
1802
1803 UniValue flakyProofs(UniValue::VARR);
1804 avalanche.withPeerManager([&flakyProofs](
1806 pm.forEachFlakyProof([&](const avalanche::ProofId &proofid) {
1807 UniValue flakyProof(UniValue::VOBJ);
1808 flakyProof.pushKV("proofid", proofid.GetHex());
1809
1810 const auto proof = pm.getProof(proofid);
1811 if (proof) {
1812 flakyProof.pushKV("staked_amount",
1813 proof->getStakedAmount());
1814 UniValue payout(UniValue::VOBJ);
1815 ScriptPubKeyToUniv(proof->getPayoutScript(), payout,
1816 /*fIncludeHex=*/true);
1817 flakyProof.pushKV("payout", payout);
1818 }
1819
1820 flakyProofs.push_back(flakyProof);
1821 });
1822 });
1823
1824 return flakyProofs;
1825 }};
1826}
1827
1829 return RPCHelpMan{
1830 "getavailabilityscore",
1831 "Return the node availability score.\n",
1832 {
1833 {"nodeid", RPCArg::Type::NUM, RPCArg::Optional::NO, "The node id."},
1834 },
1835 RPCResult{RPCResult::Type::NUM, "availability_score",
1836 "The node availability score (if any)."},
1837 RPCExamples{HelpExampleCli("getavailabilityscore", "<nodeid>") +
1838 HelpExampleRpc("getavailabilityscore", "<nodeid>")},
1839 [&](const RPCHelpMan &self, const Config &config,
1840 const JSONRPCRequest &request) -> UniValue {
1841 const NodeContext &node = EnsureAnyNodeContext(request.context);
1842 const CConnman &connman = EnsureConnman(node);
1843
1844 const NodeId nodeid(request.params[0].getInt<int64_t>());
1845
1846 CNodeStats nodeStats;
1847 if (connman.GetNodeStats(nodeid, nodeStats) &&
1848 nodeStats.m_availabilityScore) {
1849 return *nodeStats.m_availabilityScore;
1850 }
1851
1852 return UniValue::VNULL;
1853 },
1854 };
1855}
1856
1858 return RPCHelpMan{
1859 "getstakecontendervote",
1860 "Return the stake contender avalanche vote.\n",
1861 {
1863 "The prevblockhash used to compute the stake contender ID, hex "
1864 "encoded."},
1866 "The proofid used to compute the stake contender ID, hex "
1867 "encoded."},
1868 },
1870 "The vote that would be returned if polled."},
1871 RPCExamples{HelpExampleCli("getstakecontendervote",
1872 "<prevblockhash> <proofid>") +
1873 HelpExampleRpc("getstakecontendervote",
1874 "<prevblockhash> <proofid>")},
1875 [&](const RPCHelpMan &self, const Config &config,
1876 const JSONRPCRequest &request) -> UniValue {
1877 const NodeContext &node = EnsureAnyNodeContext(request.context);
1879
1880 const BlockHash prevblockhash(
1881 ParseHashV(request.params[0], "prevblockhash"));
1882 const avalanche::ProofId proofid(
1883 ParseHashV(request.params[1], "proofid"));
1884 const avalanche::StakeContenderId contenderId(prevblockhash,
1885 proofid);
1886 return avalanche.getStakeContenderStatus(contenderId);
1887 },
1888 };
1889}
1890
1892 return RPCHelpMan{
1893 "finalizetransaction",
1894 "Force finalize a mempool transaction. No attempt is made to poll for "
1895 "this transaction and this could cause the node to disagree with the "
1896 "network. This can fail if the transaction to be finalized would "
1897 "overflow the block size. Upon success it will be included in the "
1898 "block template.\n",
1899 {
1901 "The id of the transaction to be finalized."},
1902 },
1904 "finalized_txids",
1905 "The list of the successfully finalized txids if any (it can "
1906 "include ancestors of the target txid).",
1907 {{
1909 "txid",
1910 "The finalized transaction id.",
1911 }}},
1912 RPCExamples{HelpExampleCli("finalizetransaction", "<txid>") +
1913 HelpExampleRpc("finalizetransaction", "<txid>")},
1914 [&](const RPCHelpMan &self, const Config &config,
1915 const JSONRPCRequest &request) -> UniValue {
1916 const NodeContext &node = EnsureAnyNodeContext(request.context);
1917 CTxMemPool &mempool = EnsureAnyMemPool(request.context);
1918 const ChainstateManager &chainman = EnsureChainman(node);
1919
1920 const TxId txid(ParseHashV(request.params[0], "txid"));
1921
1922 LOCK2(cs_main, mempool.cs);
1923 auto entry = mempool.GetIter(txid);
1924 if (!entry) {
1926 "The transaction is not in the mempool.");
1927 }
1928
1929 const CBlockIndex *tip = chainman.ActiveTip();
1930 if (!tip) {
1932 "There is no active chain tip.");
1933 }
1934
1936
1937 std::vector<TxId> finalizedTxids;
1938 if (!mempool.setAvalancheFinalized(**entry, chainman.GetConsensus(),
1939 *tip, finalizedTxids)) {
1940 // If the function returned false, the finalizedTxids vector
1941 // should not be relied upon
1942 return ret;
1943 }
1944
1945 for (TxId &finalizedTxid : finalizedTxids) {
1946 ret.push_back(finalizedTxid.ToString());
1947
1948 // FIXME we might want to remove from the recent rejects as well
1949 // if it exists so we don't vote against this tx anymore. For
1950 // now this is a private data from the PeerManager and can only
1951 // be cleared entirely. Also a rejected transaction is not
1952 // expected to be in the mempool in the first place so this is
1953 // probably safe.
1954 }
1955
1956 return ret;
1957 },
1958 };
1959}
1960
1962 return RPCHelpMan{
1963 "removetransaction",
1964 "Remove a transaction and all its descendants from the mempool. If the "
1965 "transaction is final it is removed anyway. No attempt is made to poll "
1966 "for this transaction and this could cause the node to disagree with "
1967 "the network.\n",
1968 {
1970 "The id of the transaction to be removed."},
1971 },
1973 "removed_txids",
1974 "The list of the removed txids if any (it can include "
1975 "descendants of the target txid).",
1976 {{
1978 "txid",
1979 "The removed transaction id.",
1980 }}},
1981 RPCExamples{HelpExampleCli("removetransaction", "<txid>") +
1982 HelpExampleRpc("removetransaction", "<txid>")},
1983 [&](const RPCHelpMan &self, const Config &config,
1984 const JSONRPCRequest &request) -> UniValue {
1985 CTxMemPool &mempool = EnsureAnyMemPool(request.context);
1986
1987 const TxId txid(ParseHashV(request.params[0], "txid"));
1988
1989 LOCK(mempool.cs);
1990 auto iter = mempool.GetIter(txid);
1991 if (!iter) {
1993 "The transaction is not in the mempool.");
1994 }
1995
1996 // This mostly mimics the CTxMemPool::removeRecursive function so we
1997 // can return the list of removed txids
1998 CTxMemPool::setEntries setDescendants;
1999 mempool.CalculateDescendants(*iter, setDescendants);
2000
2002 for (auto &it : setDescendants) {
2003 ret.push_back((*it)->GetSharedTx()->GetId().ToString());
2004 }
2005
2006 mempool.RemoveStaged(setDescendants, MemPoolRemovalReason::MANUAL);
2007
2008 return ret;
2009 },
2010 };
2011}
2012
2014 return RPCHelpMan{
2015 "getfinaltransactions",
2016 "Returns all finalized transactions that have not been included in a "
2017 "finalized block yet.",
2018 {
2019 {"verbose", RPCArg::Type::BOOL, RPCArg::Default{false},
2020 "True for a json object, false for an array of transaction ids"},
2021 },
2022 {
2023 RPCResult{"for verbose = false",
2025 "",
2026 "",
2027 {
2028 {RPCResult::Type::STR_HEX, "", "The transaction id"},
2029 }},
2030 RPCResult{"for verbose = true",
2032 "",
2033 "",
2034 {{
2036 "",
2037 "",
2038 DecodeTxDoc(/*txid_field_doc=*/"The transaction id",
2039 /*wallet=*/false),
2040 }}},
2041 },
2042 RPCExamples{HelpExampleCli("getfinaltransactions", "true") +
2043 HelpExampleRpc("getfinaltransactions", "true")},
2044 [&](const RPCHelpMan &self, const Config &config,
2045 const JSONRPCRequest &request) -> UniValue {
2046 const bool fVerbose =
2047 !request.params[0].isNull() && request.params[0].get_bool();
2048
2049 const CTxMemPool &mempool = EnsureAnyMemPool(request.context);
2050
2051 UniValue finalTxs(UniValue::VARR);
2052 {
2053 LOCK(mempool.cs);
2054 mempool.finalizedTxs.forEachLeaf(
2055 [fVerbose, &finalTxs](const CTxMemPoolEntryRef &entryRef) {
2056 if (!fVerbose) {
2057 finalTxs.push_back(
2058 entryRef->GetTx().GetId().GetHex());
2059 } else {
2061 TxToUniv(entryRef->GetTx(), BlockHash(), tx,
2062 /*include_hex=*/true);
2063 finalTxs.push_back(std::move(tx));
2064 }
2065 return true;
2066 });
2067 }
2068
2069 return finalTxs;
2070 },
2071 };
2072}
2073
2075 // clang-format off
2076 static const CRPCCommand commands[] = {
2077 // category actor (function)
2078 // ----------------- --------------------
2079 { "avalanche", getavalanchekey, },
2080 { "avalanche", addavalanchenode, },
2081 { "avalanche", buildavalancheproof, },
2082 { "avalanche", decodeavalancheproof, },
2083 { "avalanche", delegateavalancheproof, },
2084 { "avalanche", decodeavalanchedelegation, },
2085 { "avalanche", getavalancheinfo, },
2086 { "avalanche", getavalanchepeerinfo, },
2087 { "avalanche", getavalancheproofs, },
2088 { "avalanche", getstakingreward, },
2089 { "hidden", hasstakingreward, },
2090 { "avalanche", setstakingreward, },
2091 { "avalanche", getremoteproofs, },
2092 { "avalanche", getrawavalancheproof, },
2093 { "avalanche", invalidateavalancheproof, },
2094 { "avalanche", isfinalblock, },
2095 { "avalanche", isfinaltransaction, },
2096 { "avalanche", reconsideravalancheproof, },
2097 { "avalanche", sendavalancheproof, },
2098 { "avalanche", verifyavalancheproof, },
2099 { "avalanche", verifyavalanchedelegation, },
2100 { "avalanche", setflakyproof, },
2101 { "avalanche", getflakyproofs, },
2102 { "avalanche", finalizetransaction, },
2103 { "avalanche", removetransaction, },
2104 { "avalanche", getfinaltransactions, },
2105 { "hidden", getavailabilityscore, },
2106 { "hidden", getstakecontendervote, },
2107 };
2108 // clang-format on
2109
2110 for (const auto &c : commands) {
2111 t.appendCommand(c.name, &c);
2112 }
2113}
static RPCHelpMan buildavalancheproof()
Definition: avalanche.cpp:212
static RPCHelpMan invalidateavalancheproof()
Definition: avalanche.cpp:1363
static RPCHelpMan delegateavalancheproof()
Definition: avalanche.cpp:470
static RPCHelpMan getremoteproofs()
Definition: avalanche.cpp:1237
static RPCHelpMan decodeavalanchedelegation()
Definition: avalanche.cpp:544
static RPCHelpMan sendavalancheproof()
Definition: avalanche.cpp:1611
static RPCHelpMan getavalancheproofs()
Definition: avalanche.cpp:934
static void verifyDelegationOrThrow(avalanche::Delegation &dg, const std::string &dgHex, CPubKey &auth)
Definition: avalanche.cpp:83
static RPCHelpMan getrawavalancheproof()
Definition: avalanche.cpp:1292
static void verifyProofOrThrow(const NodeContext &node, avalanche::Proof &proof, const std::string &proofHex)
Definition: avalanche.cpp:97
void RegisterAvalancheRPCCommands(CRPCTable &t)
Definition: avalanche.cpp:2074
static RPCHelpMan getavalanchekey()
Definition: avalanche.cpp:35
static RPCHelpMan hasstakingreward()
Definition: avalanche.cpp:1104
static RPCHelpMan addavalanchenode()
Definition: avalanche.cpp:123
static CPubKey ParsePubKey(const UniValue &param)
Definition: avalanche.cpp:52
static RPCHelpMan finalizetransaction()
Definition: avalanche.cpp:1891
static RPCHelpMan getavailabilityscore()
Definition: avalanche.cpp:1828
static RPCHelpMan getstakecontendervote()
Definition: avalanche.cpp:1857
static RPCHelpMan verifyavalanchedelegation()
Definition: avalanche.cpp:1683
static RPCHelpMan setflakyproof()
Definition: avalanche.cpp:1708
static RPCHelpMan getfinaltransactions()
Definition: avalanche.cpp:2013
static RPCHelpMan removetransaction()
Definition: avalanche.cpp:1961
static RPCHelpMan setstakingreward()
Definition: avalanche.cpp:1157
static RPCHelpMan getflakyproofs()
Definition: avalanche.cpp:1754
static RPCHelpMan isfinalblock()
Definition: avalanche.cpp:1415
static RPCHelpMan reconsideravalancheproof()
Definition: avalanche.cpp:1556
static RPCHelpMan isfinaltransaction()
Definition: avalanche.cpp:1458
static RPCHelpMan getstakingreward()
Definition: avalanche.cpp:996
static bool registerProofIfNeeded(const avalanche::Processor &avalanche, avalanche::ProofRef proof, avalanche::ProofRegistrationState &state)
Definition: avalanche.cpp:64
static RPCHelpMan getavalanchepeerinfo()
Definition: avalanche.cpp:838
static RPCHelpMan verifyavalancheproof()
Definition: avalanche.cpp:1660
static RPCHelpMan getavalancheinfo()
Definition: avalanche.cpp:627
static RPCHelpMan decodeavalancheproof()
Definition: avalanche.cpp:345
#define CHECK_NONFATAL(condition)
Identity function.
Definition: check.h:53
#define Assert(val)
Identity function.
Definition: check.h:84
The block chain is a tree shaped structure starting with the genesis block at the root,...
Definition: blockindex.h:25
BlockHash GetBlockHash() const
Definition: blockindex.h:130
Definition: net.h:829
void GetNodeStats(std::vector< CNodeStats > &vstats) const
Definition: net.cpp:2816
An encapsulated secp256k1 private key.
Definition: key.h:28
bool IsValid() const
Check whether this private key is valid.
Definition: key.h:97
CPubKey GetPubKey() const
Compute the public key from a private key.
Definition: key.cpp:209
Information about a peer.
Definition: net.h:388
An encapsulated public key.
Definition: pubkey.h:31
static constexpr unsigned int COMPRESSED_SIZE
Definition: pubkey.h:37
static constexpr unsigned int SIZE
secp256k1:
Definition: pubkey.h:36
RPC command dispatcher.
Definition: server.h:194
void appendCommand(const std::string &name, const CRPCCommand *pcmd)
Appends a CRPCCommand to the dispatch table.
Definition: server.cpp:330
CTxMemPool stores valid-according-to-the-current-best-chain transactions that may be included in the ...
Definition: txmempool.h:221
std::set< txiter, CompareIteratorById > setEntries
Definition: txmempool.h:321
RecursiveMutex cs
This mutex needs to be locked when accessing mapTx or other members that are guarded by it.
Definition: txmempool.h:317
bool setAvalancheFinalized(const CTxMemPoolEntryRef &tx, const Consensus::Params &params, const CBlockIndex &active_chain_tip, std::vector< TxId > &finalizedTxIds) EXCLUSIVE_LOCKS_REQUIRED(bool isAvalancheFinalizedPreConsensus(const TxId &txid) const EXCLUSIVE_LOCKS_REQUIRED(cs)
Definition: txmempool.h:546
RadixTree< CTxMemPoolEntry, MemPoolEntryRadixTreeAdapter > finalizedTxs
Definition: txmempool.h:324
void CalculateDescendants(txiter it, setEntries &setDescendants) const EXCLUSIVE_LOCKS_REQUIRED(cs)
Populate setDescendants with all in-mempool descendants of hash.
Definition: txmempool.cpp:242
void RemoveStaged(const setEntries &stage, MemPoolRemovalReason reason) EXCLUSIVE_LOCKS_REQUIRED(cs)
Remove a set of transactions from the mempool.
Definition: txmempool.cpp:836
std::optional< txiter > GetIter(const TxId &txid) const EXCLUSIVE_LOCKS_REQUIRED(cs)
Returns an iterator to the given txid, if found.
Definition: txmempool.cpp:744
Provides an interface for creating and interacting with one or two chainstates: an IBD chainstate gen...
Definition: validation.h:1185
SnapshotCompletionResult MaybeCompleteSnapshotValidation() EXCLUSIVE_LOCKS_REQUIRED(const CBlockIndex *GetSnapshotBaseBlock() const EXCLUSIVE_LOCKS_REQUIRED(Chainstate ActiveChainstate)() const
Once the background validation chainstate has reached the height which is the base of the UTXO snapsh...
Definition: validation.h:1436
CBlockIndex * ActiveTip() const EXCLUSIVE_LOCKS_REQUIRED(GetMutex())
Definition: validation.h:1443
const Consensus::Params & GetConsensus() const
Definition: validation.h:1281
node::BlockManager m_blockman
A single BlockManager instance is shared across each constructed chainstate to avoid duplicating bloc...
Definition: validation.h:1326
Definition: config.h:19
Double ended buffer combining vector and stream-like interfaces.
Definition: streams.h:118
static RCUPtr make(Args &&...args)
Construct a new object that is owned by the pointer.
Definition: rcu.h:112
void push_back(UniValue val)
Definition: univalue.cpp:96
const std::string & get_str() const
const UniValue & find_value(std::string_view key) const
Definition: univalue.cpp:229
@ VNULL
Definition: univalue.h:30
@ VOBJ
Definition: univalue.h:31
@ VSTR
Definition: univalue.h:33
@ VARR
Definition: univalue.h:32
@ VNUM
Definition: univalue.h:34
bool isNull() const
Definition: univalue.h:104
size_t size() const
Definition: univalue.h:92
Int getInt() const
Definition: univalue.h:157
const UniValue & get_array() const
bool exists(const std::string &key) const
Definition: univalue.h:99
void pushKV(std::string key, UniValue val)
Definition: univalue.cpp:115
bool get_bool() const
bool IsValid() const
Definition: validation.h:119
std::string GetRejectReason() const
Definition: validation.h:123
std::string GetDebugMessage() const
Definition: validation.h:124
std::string ToString() const
Definition: validation.h:125
ProofId getProofId() const
Definition: delegation.cpp:56
const std::vector< Level > & getLevels() const
Definition: delegation.h:63
static bool FromHex(Delegation &dg, const std::string &dgHex, bilingual_str &errorOut)
Definition: delegation.cpp:16
bool verify(DelegationState &state, CPubKey &auth) const
Definition: delegation.cpp:73
const CPubKey & getProofMaster() const
Definition: delegation.h:61
const DelegationId & getId() const
Definition: delegation.h:59
const CPubKey & getDelegatedPubkey() const
Definition: delegation.cpp:60
const LimitedProofId & getLimitedProofId() const
Definition: delegation.h:60
std::vector< RemoteProof > getRemoteProofs(const NodeId nodeid) const
bool isDangling(const ProofId &proofid) const
bool addNode(NodeId nodeid, const ProofId &proofid, size_t max_elements)
Node API.
Definition: peermanager.cpp:33
bool unsetFlaky(const ProofId &proofid)
bool exists(const ProofId &proofid) const
Return true if the (valid) proof exists, but only for non-dangling proofs.
Definition: peermanager.h:413
const ProofPool & getValidProofPool() const
Definition: peermanager.h:512
bool forPeer(const ProofId &proofid, Callable &&func) const
Definition: peermanager.h:421
void addUnbroadcastProof(const ProofId &proofid)
Proof broadcast API.
bool isBoundToPeer(const ProofId &proofid) const
size_t getPendingNodeCount() const
Definition: peermanager.h:318
const ProofPool & getImmatureProofPool() const
Definition: peermanager.h:516
void forEachPeer(Callable &&func) const
Definition: peermanager.h:427
void setInvalid(const ProofId &proofid)
void forEachNode(const Peer &peer, Callable &&func) const
Definition: peermanager.h:347
const Amount & getStakeUtxoDustThreshold() const
Definition: peermanager.h:532
void forEachFlakyProof(Callable &&func) const
Definition: peermanager.h:459
bool isInvalid(const ProofId &proofid) const
bool isImmature(const ProofId &proofid) const
bool rejectProof(const ProofId &proofid, RejectionMode mode=RejectionMode::DEFAULT)
const ProofPool & getConflictingProofPool() const
Definition: peermanager.h:513
bool isInConflictingPool(const ProofId &proofid) const
ProofRef getProof(const ProofId &proofid) const
bool registerProof(const ProofRef &proof, ProofRegistrationState &registrationState, RegistrationMode mode=RegistrationMode::DEFAULT)
bool addUTXO(COutPoint utxo, Amount amount, uint32_t height, bool is_coinbase, CKey key)
int64_t getExpirationTime() const
Definition: proof.h:161
static bool FromHex(Proof &proof, const std::string &hexProof, bilingual_str &errorOut)
Definition: proof.cpp:52
bool verify(const Amount &stakeUtxoDustThreshold, ProofValidationState &state) const
Definition: proof.cpp:120
Amount getStakedAmount() const
Definition: proof.cpp:105
const CPubKey & getMaster() const
Definition: proof.h:162
uint64_t getSequence() const
Definition: proof.h:160
const LimitedProofId & getLimitedId() const
Definition: proof.h:168
const SchnorrSig & getSignature() const
Definition: proof.h:165
const CScript & getPayoutScript() const
Definition: proof.h:164
uint32_t getScore() const
Definition: proof.h:172
const ProofId & getId() const
Definition: proof.h:167
const std::vector< SignedStake > & getStakes() const
Definition: proof.h:163
Map a proof to each utxo.
Definition: proofpool.h:56
size_t countProofs() const
Definition: proofpool.cpp:129
void forEachProof(Callable &&func) const
Definition: proofpool.h:117
ProofIdSet getProofIds() const
Definition: proofpool.cpp:101
std::string ToString() const
Definition: uint256.h:80
std::string GetHex() const
Definition: uint256.cpp:16
CBlockIndex * LookupBlockIndex(const BlockHash &hash) EXCLUSIVE_LOCKS_REQUIRED(cs_main)
void ScriptPubKeyToUniv(const CScript &scriptPubKey, UniValue &out, bool fIncludeHex)
Definition: core_write.cpp:194
void TxToUniv(const CTransaction &tx, const BlockHash &hashBlock, UniValue &entry, bool include_hex=true, const CTxUndo *txundo=nullptr, TxVerbosity verbosity=TxVerbosity::SHOW_DETAILS, std::function< bool(const CTxOut &)> is_change_func={})
Definition: core_write.cpp:221
RecursiveMutex cs_main
Mutex to guard access to validation specific variables, such as reading or changing the chainstate.
Definition: cs_main.cpp:7
int64_t NodeId
Definition: eviction.h:16
std::string HexStr(const Span< const uint8_t > s)
Convert a span of bytes to a lower-case hexadecimal string.
Definition: hex_base.cpp:30
std::string EncodeDestination(const CTxDestination &dest, const Config &config)
Definition: key_io.cpp:167
CTxDestination DecodeDestination(const std::string &addr, const CChainParams &params)
Definition: key_io.cpp:174
CKey DecodeSecret(const std::string &str)
Definition: key_io.cpp:77
static constexpr Amount PROOF_DUST_THRESHOLD
Minimum amount per utxo.
Definition: proof.h:38
Definition: messages.h:12
CTransactionRef GetTransaction(const CBlockIndex *const block_index, const CTxMemPool *const mempool, const TxId &txid, BlockHash &hashBlock, const BlockManager &blockman)
Return transaction with a given txid.
std::shared_ptr< const CTransaction > CTransactionRef
Definition: transaction.h:315
static constexpr size_t AVALANCHE_MAX_ELEMENT_POLL_LEGACY
Legacy maximum element poll.
Definition: processor.h:63
std::vector< RPCResult > DecodeTxDoc(const std::string &txid_field_doc, bool wallet)
Explain the UniValue "decoded" transaction object, may include extra fields if processed by wallet.
UniValue JSONRPCError(int code, const std::string &message)
Definition: request.cpp:58
@ RPC_MISC_ERROR
General application defined errors std::exception thrown in command handling.
Definition: protocol.h:38
@ RPC_INVALID_PARAMETER
Invalid, missing or duplicate parameter.
Definition: protocol.h:46
@ RPC_INTERNAL_ERROR
Definition: protocol.h:33
@ RPC_DESERIALIZATION_ERROR
Error parsing or validating structure in raw format.
Definition: protocol.h:50
@ RPC_INVALID_ADDRESS_OR_KEY
Invalid address or key.
Definition: protocol.h:42
std::string HelpExampleCli(const std::string &methodname, const std::string &args)
Definition: util.cpp:163
Amount AmountFromValue(const UniValue &value)
Definition: util.cpp:68
std::string HelpExampleRpc(const std::string &methodname, const std::string &args)
Definition: util.cpp:180
std::string GetAllOutputTypes()
Definition: util.cpp:318
CPubKey HexToPubKey(const std::string &hex_in)
Definition: util.cpp:204
uint256 ParseHashO(const UniValue &o, std::string strKey)
Definition: util.cpp:103
uint256 ParseHashV(const UniValue &v, std::string strName)
Utilities: convert hex-encoded values (throws error if not hex).
Definition: util.cpp:86
void RPCTypeCheckObj(const UniValue &o, const std::map< std::string, UniValueType > &typesExpected, bool fAllowNull, bool fStrict)
Check for expected keys/value types in an Object.
Definition: util.cpp:39
ChainstateManager & EnsureAnyChainman(const std::any &context)
Definition: server_util.cpp:59
NodeContext & EnsureAnyNodeContext(const std::any &context)
Definition: server_util.cpp:21
CTxMemPool & EnsureMemPool(const NodeContext &node)
Definition: server_util.cpp:29
ChainstateManager & EnsureChainman(const NodeContext &node)
Definition: server_util.cpp:52
CTxMemPool & EnsureAnyMemPool(const std::any &context)
Definition: server_util.cpp:37
avalanche::Processor & EnsureAvalanche(const NodeContext &node)
Definition: server_util.cpp:81
CConnman & EnsureConnman(const NodeContext &node)
Definition: server_util.cpp:63
bool IsStakingRewardsActivated(const Consensus::Params &params, const CBlockIndex *pprev)
bool ExtractDestination(const CScript &scriptPubKey, CTxDestination &addressRet)
Parse a standard scriptPubKey for the destination address.
Definition: standard.cpp:158
bool IsValidDestination(const CTxDestination &dest)
Check whether a CTxDestination is a CNoDestination.
Definition: standard.cpp:260
CScript GetScriptForDestination(const CTxDestination &dest)
Generate a Bitcoin scriptPubKey for the given CTxDestination.
Definition: standard.cpp:240
std::variant< CNoDestination, PKHash, ScriptHash > CTxDestination
A txout script template with a specific destination.
Definition: standard.h:85
Definition: amount.h:21
static constexpr Amount zero() noexcept
Definition: amount.h:34
A BlockHash is a unqiue identifier for a block.
Definition: blockhash.h:13
POD that contains various stats about a node.
Definition: net.h:216
std::optional< double > m_availabilityScore
Definition: net.h:251
static const Currency & get()
Definition: amount.cpp:18
std::string ticker
Definition: amount.h:155
@ STR_HEX
Special type that is a STR with only hex chars.
@ AMOUNT
Special type representing a floating point amount (can be either NUM or STR)
@ OMITTED
Optional argument for which the default value is omitted from help text for one of two reasons:
@ NO
Required arg.
@ STR_HEX
Special string with only hex chars.
@ STR_AMOUNT
Special string to represent a floating point amount.
bool forEachLeaf(Callable &&func) const
Definition: radix.h:143
A TxId is the identifier of a transaction.
Definition: txid.h:14
NodeId nodeid
Definition: node.h:20
uint32_t node_count
Definition: peermanager.h:87
ProofRef proof
Definition: peermanager.h:89
static ProofId fromHex(const std::string &str)
Definition: proofid.h:21
StakeContenderIds are unique for each block to ensure that the peer polling for their acceptance has ...
Bilingual messages:
Definition: translation.h:17
std::string original
Definition: translation.h:18
NodeContext struct containing references to chain state and connection state.
Definition: context.h:48
#define LOCK2(cs1, cs2)
Definition: sync.h:309
#define LOCK(cs)
Definition: sync.h:306
#define WITH_LOCK(cs, code)
Run code while locking a mutex.
Definition: sync.h:357
#define strprintf
Format arguments and return the string or write to given std::ostream (see tinyformat::format doc for...
Definition: tinyformat.h:1202
std::unique_ptr< TxIndex > g_txindex
The global transaction index, used in GetTransaction. May be null.
Definition: txindex.cpp:17
@ MANUAL
Manual removal via RPC.
std::string EncodeBase64(Span< const uint8_t > input)
template std::vector< std::byte > ParseHex(std::string_view)
bool IsHex(std::string_view str)
Returns true if each character in str is a hex character, and has an even number of hex digits.