Bitcoin ABC 0.33.3
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{HelpExampleRpc("getavalanchekey", "")},
42 [&](const RPCHelpMan &self, const Config &config,
43 const JSONRPCRequest &request) -> UniValue {
44 NodeContext &node = EnsureAnyNodeContext(request.context);
46 return HexStr(avalanche.getSessionPubKey());
47 },
48 };
49}
50
51static CPubKey ParsePubKey(const UniValue &param) {
52 const std::string &keyHex = param.get_str();
53 if ((keyHex.length() != 2 * CPubKey::COMPRESSED_SIZE &&
54 keyHex.length() != 2 * CPubKey::SIZE) ||
55 !IsHex(keyHex)) {
57 strprintf("Invalid public key: %s\n", keyHex));
58 }
59
60 return HexToPubKey(keyHex);
61}
62
66 auto localProof = avalanche.getLocalProof();
67 if (localProof && localProof->getId() == proof->getId()) {
68 return true;
69 }
70
71 return avalanche.withPeerManager([&](avalanche::PeerManager &pm) {
72 return pm.getProof(proof->getId()) || pm.registerProof(proof, state);
73 });
74}
75
77 avalanche::ProofRef proof) {
79 return registerProofIfNeeded(avalanche, std::move(proof), state);
80}
81
83 const std::string &dgHex, CPubKey &auth) {
84 bilingual_str error;
85 if (!avalanche::Delegation::FromHex(dg, dgHex, error)) {
87 }
88
90 if (!dg.verify(state, auth)) {
92 "The delegation is invalid: " + state.ToString());
93 }
94}
95
97 const std::string &proofHex) {
98 bilingual_str error;
99 if (!avalanche::Proof::FromHex(proof, proofHex, error)) {
101 }
102
103 Amount stakeUtxoDustThreshold = avalanche::PROOF_DUST_THRESHOLD;
104 if (node.avalanche) {
105 // If Avalanche is enabled, use the configured dust threshold
106 node.avalanche->withPeerManager([&](avalanche::PeerManager &pm) {
107 stakeUtxoDustThreshold = pm.getStakeUtxoDustThreshold();
108 });
109 }
110
112 {
113 LOCK(cs_main);
114 if (!proof.verify(stakeUtxoDustThreshold, *Assert(node.chainman),
115 state)) {
117 "The proof is invalid: " + state.ToString());
118 }
119 }
120}
121
123 return RPCHelpMan{
124 "addavalanchenode",
125 "Add a node in the set of peers to poll for avalanche.\n",
126 {
128 "Node to be added to avalanche."},
130 "The public key of the node."},
132 "Proof that the node is not a sybil."},
134 "The proof delegation the the node public key"},
135 },
137 "Whether the addition succeeded or not."},
139 HelpExampleRpc("addavalanchenode", "5, \"<pubkey>\", \"<proof>\"")},
140 [&](const RPCHelpMan &self, const Config &config,
141 const JSONRPCRequest &request) -> UniValue {
142 const NodeId nodeid = request.params[0].getInt<int64_t>();
143 CPubKey key = ParsePubKey(request.params[1]);
144
145 auto proof = RCUPtr<avalanche::Proof>::make();
146 NodeContext &node = EnsureAnyNodeContext(request.context);
148
149 verifyProofOrThrow(node, *proof, request.params[2].get_str());
150
151 const avalanche::ProofId &proofid = proof->getId();
152 if (key != proof->getMaster()) {
153 if (request.params.size() < 4 || request.params[3].isNull()) {
154 throw JSONRPCError(
156 "The public key does not match the proof");
157 }
158
160 CPubKey auth;
161 verifyDelegationOrThrow(dg, request.params[3].get_str(), auth);
162
163 if (dg.getProofId() != proofid) {
164 throw JSONRPCError(
166 "The delegation does not match the proof");
167 }
168
169 if (key != auth) {
170 throw JSONRPCError(
172 "The public key does not match the delegation");
173 }
174 }
175
176 if (!registerProofIfNeeded(avalanche, proof)) {
178 "The proof has conflicting utxos");
179 }
180
181 if (!node.connman->ForNode(nodeid, [&](CNode *pnode) {
182 LOCK(pnode->cs_avalanche_pubkey);
183 bool expected = false;
184 if (pnode->m_avalanche_enabled.compare_exchange_strong(
185 expected, true)) {
186 pnode->m_avalanche_pubkey = std::move(key);
187 }
188 return true;
189 })) {
190 throw JSONRPCError(
192 strprintf("The node does not exist: %d", nodeid));
193 }
194
195 return avalanche.withPeerManager([&](avalanche::PeerManager &pm) {
196 // We don't know what this node supports as number of elements,
197 // so we assume the minimum for now
198 if (!pm.addNode(nodeid, proofid,
200 return false;
201 }
202
203 pm.addUnbroadcastProof(proofid);
204 return true;
205 });
206 },
207 };
208}
209
211 return RPCHelpMan{
212 "buildavalancheproof",
213 "Build a proof for avalanche's sybil resistance.\n",
214 {
216 "The proof's sequence"},
218 "A timestamp indicating when the proof expire"},
220 "The master private key in base58-encoding"},
221 {
222 "stakes",
225 "The stakes to be signed and associated private keys",
226 {
227 {
228 "stake",
231 "A stake to be attached to this proof",
232 {
233 {"txid", RPCArg::Type::STR_HEX,
234 RPCArg::Optional::NO, "The transaction id"},
236 "The output number"},
237 {"amount", RPCArg::Type::AMOUNT,
238 RPCArg::Optional::NO, "The amount in this UTXO"},
240 "The height at which this UTXO was mined"},
241 {"iscoinbase", RPCArg::Type::BOOL,
242 RPCArg::Default{false},
243 "Indicate wether the UTXO is a coinbase"},
244 {"privatekey", RPCArg::Type::STR,
246 "private key in base58-encoding"},
247 },
248 },
249 },
250 },
251 {"payoutAddress", RPCArg::Type::STR, RPCArg::Optional::NO,
252 "A payout address"},
253 },
255 "A string that is a serialized, hex-encoded proof data."},
256 RPCExamples{HelpExampleRpc("buildavalancheproof",
257 "0 1234567800 \"<master>\" []")},
258 [&](const RPCHelpMan &self, const Config &config,
259 const JSONRPCRequest &request) -> UniValue {
260 const uint64_t sequence = request.params[0].getInt<int64_t>();
261 const int64_t expiration = request.params[1].getInt<int64_t>();
262
263 CKey masterKey = DecodeSecret(request.params[2].get_str());
264 if (!masterKey.IsValid()) {
265 throw JSONRPCError(RPC_INVALID_PARAMETER, "Invalid master key");
266 }
267
268 CTxDestination payoutAddress = DecodeDestination(
269 request.params[4].get_str(), config.GetChainParams());
270
271 if (!IsValidDestination(payoutAddress)) {
273 "Invalid payout address");
274 }
275
276 avalanche::ProofBuilder pb(sequence, expiration, masterKey,
277 GetScriptForDestination(payoutAddress));
278
279 const UniValue &stakes = request.params[3].get_array();
280 for (size_t i = 0; i < stakes.size(); i++) {
281 const UniValue &stake = stakes[i];
283 stake,
284 {
285 {"txid", UniValue::VSTR},
286 {"vout", UniValue::VNUM},
287 // "amount" is also required but check is done below
288 // due to UniValue::VNUM erroneously not accepting
289 // quoted numerics (which are valid JSON)
290 {"height", UniValue::VNUM},
291 {"privatekey", UniValue::VSTR},
292 });
293
294 int nOut = stake.find_value("vout").getInt<int>();
295 if (nOut < 0) {
297 "vout cannot be negative");
298 }
299
300 const int height = stake.find_value("height").getInt<int>();
301 if (height < 1) {
303 "height must be positive");
304 }
305
306 const TxId txid(ParseHashO(stake, "txid"));
307 const COutPoint utxo(txid, nOut);
308
309 if (!stake.exists("amount")) {
310 throw JSONRPCError(RPC_INVALID_PARAMETER, "Missing amount");
311 }
312
313 const Amount amount =
314 AmountFromValue(stake.find_value("amount"));
315
316 const UniValue &iscbparam = stake.find_value("iscoinbase");
317 const bool iscoinbase =
318 iscbparam.isNull() ? false : iscbparam.get_bool();
319 CKey key =
320 DecodeSecret(stake.find_value("privatekey").get_str());
321
322 if (!key.IsValid()) {
324 "Invalid private key");
325 }
326
327 if (!pb.addUTXO(utxo, amount, uint32_t(height), iscoinbase,
328 std::move(key))) {
330 "Duplicated stake");
331 }
332 }
333
334 const avalanche::ProofRef proof = pb.build();
335
336 return proof->ToHex();
337 },
338 };
339}
340
342 return RPCHelpMan{
343 "decodeavalancheproof",
344 "Convert a serialized, hex-encoded proof, into JSON object. "
345 "The validity of the proof is not verified.\n",
346 {
348 "The proof hex string"},
349 },
350 RPCResult{
352 "",
353 "",
354 {
355 {RPCResult::Type::NUM, "sequence",
356 "The proof's sequential number"},
357 {RPCResult::Type::NUM, "expiration",
358 "A timestamp indicating when the proof expires"},
359 {RPCResult::Type::STR_HEX, "master", "The master public key"},
360 {RPCResult::Type::STR, "signature",
361 "The proof signature (base64 encoded)"},
363 "payoutscript",
364 "The proof payout script",
365 {
366 {RPCResult::Type::STR, "asm", "Decoded payout script"},
368 "Raw payout script in hex format"},
369 {RPCResult::Type::STR, "type",
370 "The output type (e.g. " + GetAllOutputTypes() + ")"},
371 {RPCResult::Type::NUM, "reqSigs",
372 "The required signatures"},
374 "addresses",
375 "",
376 {
377 {RPCResult::Type::STR, "address", "eCash address"},
378 }},
379 }},
380 {RPCResult::Type::STR_HEX, "limitedid",
381 "A hash of the proof data excluding the master key."},
382 {RPCResult::Type::STR_HEX, "proofid",
383 "A hash of the limitedid and master key."},
384 {RPCResult::Type::STR_AMOUNT, "staked_amount",
385 "The total staked amount of this proof in " +
386 Currency::get().ticker + "."},
387 {RPCResult::Type::NUM, "score", "The score of this proof."},
389 "stakes",
390 "",
391 {
393 "",
394 "",
395 {
397 "The transaction id"},
398 {RPCResult::Type::NUM, "vout", "The output number"},
400 "The amount in this UTXO"},
401 {RPCResult::Type::NUM, "height",
402 "The height at which this UTXO was mined"},
403 {RPCResult::Type::BOOL, "iscoinbase",
404 "Indicate whether the UTXO is a coinbase"},
405 {RPCResult::Type::STR_HEX, "pubkey",
406 "This UTXO's public key"},
407 {RPCResult::Type::STR, "signature",
408 "Signature of the proofid with this UTXO's private "
409 "key (base64 encoded)"},
410 }},
411 }},
412 }},
413 RPCExamples{HelpExampleCli("decodeavalancheproof", "\"<hex proof>\"") +
414 HelpExampleRpc("decodeavalancheproof", "\"<hex proof>\"")},
415 [&](const RPCHelpMan &self, const Config &config,
416 const JSONRPCRequest &request) -> UniValue {
417 avalanche::Proof proof;
418 bilingual_str error;
419 if (!avalanche::Proof::FromHex(proof, request.params[0].get_str(),
420 error)) {
422 }
423
424 UniValue result(UniValue::VOBJ);
425 result.pushKV("sequence", proof.getSequence());
426 result.pushKV("expiration", proof.getExpirationTime());
427 result.pushKV("master", HexStr(proof.getMaster()));
428 result.pushKV("signature", EncodeBase64(proof.getSignature()));
429
430 const auto payoutScript = proof.getPayoutScript();
431 UniValue payoutScriptObj(UniValue::VOBJ);
432 ScriptPubKeyToUniv(payoutScript, payoutScriptObj,
433 /* fIncludeHex */ true);
434 result.pushKV("payoutscript", payoutScriptObj);
435
436 result.pushKV("limitedid", proof.getLimitedId().ToString());
437 result.pushKV("proofid", proof.getId().ToString());
438
439 result.pushKV("staked_amount", proof.getStakedAmount());
440 result.pushKV("score", uint64_t(proof.getScore()));
441
442 UniValue stakes(UniValue::VARR);
443 for (const avalanche::SignedStake &s : proof.getStakes()) {
444 const COutPoint &utxo = s.getStake().getUTXO();
446 stake.pushKV("txid", utxo.GetTxId().ToString());
447 stake.pushKV("vout", uint64_t(utxo.GetN()));
448 stake.pushKV("amount", s.getStake().getAmount());
449 stake.pushKV("height", uint64_t(s.getStake().getHeight()));
450 stake.pushKV("iscoinbase", s.getStake().isCoinbase());
451 stake.pushKV("pubkey", HexStr(s.getStake().getPubkey()));
452 // Only PKHash destination is supported, so this is safe
453 stake.pushKV("address",
454 EncodeDestination(PKHash(s.getStake().getPubkey()),
455 config));
456 stake.pushKV("signature", EncodeBase64(s.getSignature()));
457 stakes.push_back(stake);
458 }
459 result.pushKV("stakes", stakes);
460
461 return result;
462 },
463 };
464}
465
467 return RPCHelpMan{
468 "delegateavalancheproof",
469 "Delegate the avalanche proof to another public key.\n",
470 {
472 "The limited id of the proof to be delegated."},
474 "The private key in base58-encoding. Must match the proof master "
475 "public key or the upper level parent delegation public key if "
476 " supplied."},
478 "The public key to delegate the proof to."},
480 "A string that is the serialized, hex-encoded delegation for the "
481 "proof and which is a parent for the delegation to build."},
482 },
484 "A string that is a serialized, hex-encoded delegation."},
486 HelpExampleRpc("delegateavalancheproof",
487 "\"<limitedproofid>\" \"<privkey>\" \"<pubkey>\"")},
488 [&](const RPCHelpMan &self, const Config &config,
489 const JSONRPCRequest &request) -> UniValue {
490 avalanche::LimitedProofId limitedProofId{
491 ParseHashV(request.params[0], "limitedproofid")};
492
493 const CKey privkey = DecodeSecret(request.params[1].get_str());
494 if (!privkey.IsValid()) {
496 "The private key is invalid");
497 }
498
499 const CPubKey pubkey = ParsePubKey(request.params[2]);
500
501 std::unique_ptr<avalanche::DelegationBuilder> dgb;
502 if (request.params.size() >= 4 && !request.params[3].isNull()) {
504 CPubKey auth;
505 verifyDelegationOrThrow(dg, request.params[3].get_str(), auth);
506
507 if (dg.getProofId() !=
508 limitedProofId.computeProofId(dg.getProofMaster())) {
509 throw JSONRPCError(
511 "The delegation does not match the proof");
512 }
513
514 if (privkey.GetPubKey() != auth) {
515 throw JSONRPCError(
517 "The private key does not match the delegation");
518 }
519
520 dgb = std::make_unique<avalanche::DelegationBuilder>(dg);
521 } else {
522 dgb = std::make_unique<avalanche::DelegationBuilder>(
523 limitedProofId, privkey.GetPubKey());
524 }
525
526 if (!dgb->addLevel(privkey, pubkey)) {
528 "Unable to build the delegation");
529 }
530
531 DataStream ss{};
532 ss << dgb->build();
533 return HexStr(ss);
534 },
535 };
536}
537
539 return RPCHelpMan{
540 "decodeavalanchedelegation",
541 "Convert a serialized, hex-encoded avalanche proof delegation, into "
542 "JSON object. \n"
543 "The validity of the delegation is not verified.\n",
544 {
546 "The delegation hex string"},
547 },
548 RPCResult{
550 "",
551 "",
552 {
553 {RPCResult::Type::STR_HEX, "pubkey",
554 "The public key the proof is delegated to."},
555 {RPCResult::Type::STR_HEX, "proofmaster",
556 "The delegated proof master public key."},
557 {RPCResult::Type::STR_HEX, "delegationid",
558 "The identifier of this delegation."},
559 {RPCResult::Type::STR_HEX, "limitedid",
560 "A delegated proof data hash excluding the master key."},
561 {RPCResult::Type::STR_HEX, "proofid",
562 "A hash of the delegated proof limitedid and master key."},
563 {RPCResult::Type::NUM, "depth",
564 "The number of delegation levels."},
566 "levels",
567 "",
568 {
570 "",
571 "",
572 {
573 {RPCResult::Type::NUM, "index",
574 "The index of this delegation level."},
575 {RPCResult::Type::STR_HEX, "pubkey",
576 "This delegated public key for this level"},
577 {RPCResult::Type::STR, "signature",
578 "Signature of this delegation level (base64 "
579 "encoded)"},
580 }},
581 }},
582 }},
583 RPCExamples{HelpExampleCli("decodeavalanchedelegation",
584 "\"<hex delegation>\"") +
585 HelpExampleRpc("decodeavalanchedelegation",
586 "\"<hex delegation>\"")},
587 [&](const RPCHelpMan &self, const Config &config,
588 const JSONRPCRequest &request) -> UniValue {
589 avalanche::Delegation delegation;
590 bilingual_str error;
592 delegation, request.params[0].get_str(), error)) {
594 }
595
596 UniValue result(UniValue::VOBJ);
597 result.pushKV("pubkey", HexStr(delegation.getDelegatedPubkey()));
598 result.pushKV("proofmaster", HexStr(delegation.getProofMaster()));
599 result.pushKV("delegationid", delegation.getId().ToString());
600 result.pushKV("limitedid",
601 delegation.getLimitedProofId().ToString());
602 result.pushKV("proofid", delegation.getProofId().ToString());
603
604 auto levels = delegation.getLevels();
605 result.pushKV("depth", uint64_t(levels.size()));
606
607 UniValue levelsArray(UniValue::VARR);
608 for (auto &level : levels) {
610 obj.pushKV("pubkey", HexStr(level.pubkey));
611 obj.pushKV("signature", EncodeBase64(level.sig));
612 levelsArray.push_back(std::move(obj));
613 }
614 result.pushKV("levels", levelsArray);
615
616 return result;
617 },
618 };
619}
620
622 return RPCHelpMan{
623 "getavalancheinfo",
624 "Returns an object containing various state info regarding avalanche "
625 "networking.\n",
626 {},
627 RPCResult{
629 "",
630 "",
631 {
632 {RPCResult::Type::BOOL, "ready_to_poll",
633 "Whether the node is ready to start polling and voting."},
635 "local",
636 "Only available if -avaproof has been supplied to the node",
637 {
638 {RPCResult::Type::BOOL, "verified",
639 "Whether the node local proof has been locally verified "
640 "or not."},
641 {RPCResult::Type::STR, "verification_status",
642 "The proof verification status. Only available if the "
643 "\"verified\" flag is false."},
644 {RPCResult::Type::STR_HEX, "proofid",
645 "The node local proof id."},
646 {RPCResult::Type::STR_HEX, "limited_proofid",
647 "The node local limited proof id."},
648 {RPCResult::Type::STR_HEX, "master",
649 "The node local proof master public key."},
650 {RPCResult::Type::STR, "payout_address",
651 "The node local proof payout address. This might be "
652 "omitted if the payout script is not one of P2PK, P2PKH "
653 "or P2SH, in which case decodeavalancheproof can be used "
654 "to get more details."},
655 {RPCResult::Type::STR_AMOUNT, "stake_amount",
656 "The node local proof staked amount."},
657 }},
659 "network",
660 "",
661 {
662 {RPCResult::Type::NUM, "proof_count",
663 "The number of valid avalanche proofs we know exist "
664 "(including this node's local proof if applicable)."},
665 {RPCResult::Type::NUM, "connected_proof_count",
666 "The number of avalanche proofs with at least one node "
667 "we are connected to (including this node's local proof "
668 "if applicable)."},
669 {RPCResult::Type::NUM, "dangling_proof_count",
670 "The number of avalanche proofs with no node attached."},
671 {RPCResult::Type::NUM, "finalized_proof_count",
672 "The number of known avalanche proofs that have been "
673 "finalized by avalanche."},
674 {RPCResult::Type::NUM, "conflicting_proof_count",
675 "The number of known avalanche proofs that conflict with "
676 "valid proofs."},
677 {RPCResult::Type::NUM, "immature_proof_count",
678 "The number of known avalanche proofs that have immature "
679 "utxos."},
680 {RPCResult::Type::STR_AMOUNT, "total_stake_amount",
681 "The total staked amount over all the valid proofs in " +
683 " (including this node's local proof if "
684 "applicable)."},
685 {RPCResult::Type::STR_AMOUNT, "connected_stake_amount",
686 "The total staked amount over all the connected proofs "
687 "in " +
689 " (including this node's local proof if "
690 "applicable)."},
691 {RPCResult::Type::STR_AMOUNT, "dangling_stake_amount",
692 "The total staked amount over all the dangling proofs "
693 "in " +
695 " (including this node's local proof if "
696 "applicable)."},
697 {RPCResult::Type::STR_AMOUNT, "immature_stake_amount",
698 "The total staked amount over all the immature proofs "
699 "in " +
701 " (including this node's local proof if "
702 "applicable)."},
703 {RPCResult::Type::NUM, "node_count",
704 "The number of avalanche nodes we are connected to "
705 "(including this node if a local proof is set)."},
706 {RPCResult::Type::NUM, "connected_node_count",
707 "The number of avalanche nodes associated with an "
708 "avalanche proof (including this node if a local proof "
709 "is set)."},
710 {RPCResult::Type::NUM, "pending_node_count",
711 "The number of avalanche nodes pending for a proof."},
712 }},
713 },
714 },
715 RPCExamples{HelpExampleCli("getavalancheinfo", "") +
716 HelpExampleRpc("getavalancheinfo", "")},
717 [&](const RPCHelpMan &self, const Config &config,
718 const JSONRPCRequest &request) -> UniValue {
719 NodeContext &node = EnsureAnyNodeContext(request.context);
721
723 ret.pushKV("ready_to_poll", avalanche.isQuorumEstablished());
724
725 auto localProof = avalanche.getLocalProof();
726 if (localProof != nullptr) {
728 const bool verified = avalanche.withPeerManager(
729 [&](const avalanche::PeerManager &pm) {
730 const avalanche::ProofId &proofid = localProof->getId();
731 return pm.isBoundToPeer(proofid);
732 });
733 local.pushKV("verified", verified);
734 const bool sharing = avalanche.canShareLocalProof();
735 if (!verified) {
737 avalanche.getLocalProofRegistrationState();
738 // If the local proof is not registered but the state is
739 // valid, no registration attempt occurred yet.
740 local.pushKV("verification_status",
741 state.IsValid()
742 ? (sharing ? "pending verification"
743 : "pending inbound connections")
744 : state.GetRejectReason());
745 }
746 local.pushKV("proofid", localProof->getId().ToString());
747 local.pushKV("limited_proofid",
748 localProof->getLimitedId().ToString());
749 local.pushKV("master", HexStr(localProof->getMaster()));
750 CTxDestination destination;
751 if (ExtractDestination(localProof->getPayoutScript(),
752 destination)) {
753 local.pushKV("payout_address",
754 EncodeDestination(destination, config));
755 }
756 local.pushKV("stake_amount", localProof->getStakedAmount());
757 ret.pushKV("local", local);
758 }
759
760 avalanche.withPeerManager([&](avalanche::PeerManager &pm) {
761 UniValue network(UniValue::VOBJ);
762
763 uint64_t proofCount{0};
764 uint64_t connectedProofCount{0};
765 uint64_t finalizedProofCount{0};
766 uint64_t connectedNodeCount{0};
767 Amount totalStakes = Amount::zero();
768 Amount connectedStakes = Amount::zero();
769
770 pm.forEachPeer([&](const avalanche::Peer &peer) {
771 CHECK_NONFATAL(peer.proof != nullptr);
772
773 const bool isLocalProof =
774 localProof &&
775 peer.proof->getId() == localProof->getId();
776
777 ++proofCount;
778 const Amount proofStake = peer.proof->getStakedAmount();
779
780 totalStakes += proofStake;
781
782 if (peer.hasFinalized) {
783 ++finalizedProofCount;
784 }
785
786 if (peer.node_count > 0 || isLocalProof) {
787 ++connectedProofCount;
788 connectedStakes += proofStake;
789 }
790
791 connectedNodeCount += peer.node_count + isLocalProof;
792 });
793
794 Amount immatureStakes = Amount::zero();
796 [&](const avalanche::ProofRef &proof) {
797 immatureStakes += proof->getStakedAmount();
798 });
799
800 network.pushKV("proof_count", proofCount);
801 network.pushKV("connected_proof_count", connectedProofCount);
802 network.pushKV("dangling_proof_count",
803 proofCount - connectedProofCount);
804
805 network.pushKV("finalized_proof_count", finalizedProofCount);
806 network.pushKV(
807 "conflicting_proof_count",
808 uint64_t(pm.getConflictingProofPool().countProofs()));
809 network.pushKV(
810 "immature_proof_count",
811 uint64_t(pm.getImmatureProofPool().countProofs()));
812
813 network.pushKV("total_stake_amount", totalStakes);
814 network.pushKV("connected_stake_amount", connectedStakes);
815 network.pushKV("dangling_stake_amount",
816 totalStakes - connectedStakes);
817 network.pushKV("immature_stake_amount", immatureStakes);
818
819 const uint64_t pendingNodes = pm.getPendingNodeCount();
820 network.pushKV("node_count", connectedNodeCount + pendingNodes);
821 network.pushKV("connected_node_count", connectedNodeCount);
822 network.pushKV("pending_node_count", pendingNodes);
823
824 ret.pushKV("network", network);
825 });
826
827 return ret;
828 },
829 };
830}
831
833 return RPCHelpMan{
834 "getavalanchepeerinfo",
835 "Returns data about an avalanche peer as a json array of objects. If "
836 "no proofid is provided, returns data about all the peers.\n",
837 {
839 "The hex encoded avalanche proof identifier."},
840 },
841 RPCResult{
843 "",
844 "",
845 {{
847 "",
848 "",
849 {{
850 {RPCResult::Type::NUM, "avalanche_peerid",
851 "The avalanche internal peer identifier"},
852 {RPCResult::Type::STR_HEX, "proofid",
853 "The avalanche proof id used by this peer"},
854 {RPCResult::Type::STR_HEX, "proof",
855 "The avalanche proof used by this peer"},
856 {RPCResult::Type::NUM, "nodecount",
857 "The number of nodes for this peer"},
859 "node_list",
860 "",
861 {
862 {RPCResult::Type::NUM, "nodeid",
863 "Node id, as returned by getpeerinfo"},
864 }},
865 }},
866 }},
867 },
868 RPCExamples{HelpExampleCli("getavalanchepeerinfo", "") +
869 HelpExampleCli("getavalanchepeerinfo", "\"proofid\"") +
870 HelpExampleRpc("getavalanchepeerinfo", "") +
871 HelpExampleRpc("getavalanchepeerinfo", "\"proofid\"")},
872 [&](const RPCHelpMan &self, const Config &config,
873 const JSONRPCRequest &request) -> UniValue {
874 NodeContext &node = EnsureAnyNodeContext(request.context);
876
877 auto peerToUniv = [](const avalanche::PeerManager &pm,
878 const avalanche::Peer &peer) {
880
881 obj.pushKV("avalanche_peerid", uint64_t(peer.peerid));
882 obj.pushKV("proofid", peer.getProofId().ToString());
883 obj.pushKV("proof", peer.proof->ToHex());
884
886 pm.forEachNode(peer, [&](const avalanche::Node &n) {
887 nodes.push_back(n.nodeid);
888 });
889
890 obj.pushKV("nodecount", uint64_t(peer.node_count));
891 obj.pushKV("node_list", nodes);
892
893 return obj;
894 };
895
897
898 avalanche.withPeerManager([&](const avalanche::PeerManager &pm) {
899 // If a proofid is provided, only return the associated peer
900 if (!request.params[0].isNull()) {
901 const avalanche::ProofId proofid =
902 avalanche::ProofId::fromHex(
903 request.params[0].get_str());
904 if (!pm.isBoundToPeer(proofid)) {
905 throw JSONRPCError(RPC_INVALID_PARAMETER,
906 "Proofid not found");
907 }
908
909 pm.forPeer(proofid, [&](const avalanche::Peer &peer) {
910 ret.push_back(peerToUniv(pm, peer));
911 return true;
912 });
913
914 return;
915 }
916
917 // If no proofid is provided, return all the peers
918 pm.forEachPeer([&](const avalanche::Peer &peer) {
919 ret.push_back(peerToUniv(pm, peer));
920 });
921 });
922
923 return ret;
924 },
925 };
926}
927
929 return RPCHelpMan{
930 "getavalancheproofs",
931 "Returns an object containing all tracked proofids.\n",
932 {},
933 RPCResult{
935 "",
936 "",
937 {
939 "valid",
940 "",
941 {
942 {RPCResult::Type::STR_HEX, "proofid",
943 "Avalanche proof id"},
944 }},
946 "conflicting",
947 "",
948 {
949 {RPCResult::Type::STR_HEX, "proofid",
950 "Avalanche proof id"},
951 }},
953 "immature",
954 "",
955 {
956 {RPCResult::Type::STR_HEX, "proofid",
957 "Avalanche proof id"},
958 }},
959 },
960 },
961 RPCExamples{HelpExampleCli("getavalancheproofs", "") +
962 HelpExampleRpc("getavalancheproofs", "")},
963 [&](const RPCHelpMan &self, const Config &config,
964 const JSONRPCRequest &request) -> UniValue {
965 NodeContext &node = EnsureAnyNodeContext(request.context);
967
969 avalanche.withPeerManager([&](avalanche::PeerManager &pm) {
970 auto appendProofIds = [&ret](const avalanche::ProofPool &pool,
971 const std::string &key) {
972 UniValue arrOut(UniValue::VARR);
973 for (const avalanche::ProofId &proofid :
974 pool.getProofIds()) {
975 arrOut.push_back(proofid.ToString());
976 }
977 ret.pushKV(key, arrOut);
978 };
979
980 appendProofIds(pm.getValidProofPool(), "valid");
981 appendProofIds(pm.getConflictingProofPool(), "conflicting");
982 appendProofIds(pm.getImmatureProofPool(), "immature");
983 });
984
985 return ret;
986 },
987 };
988}
989
991 return RPCHelpMan{
992 "getstakingreward",
993 "Return a list of possible staking reward winners based on the "
994 "previous "
995 "block hash.\n",
996 {
998 "The previous block hash, hex encoded."},
999 {"recompute", RPCArg::Type::BOOL, RPCArg::Default{false},
1000 "Whether to recompute the staking reward winner if there is a "
1001 "cached value."},
1002 },
1003 RPCResult{
1005 "",
1006 "",
1007 {
1009 "winner",
1010 "The winning proof",
1011 {
1012 {RPCResult::Type::STR_HEX, "proofid",
1013 "The winning proofid"},
1014 {RPCResult::Type::STR, "asm", "Decoded payout script"},
1016 "Raw payout script in hex format"},
1017 {RPCResult::Type::STR, "type",
1018 "The output type (e.g. " + GetAllOutputTypes() + ")"},
1019 {RPCResult::Type::NUM, "reqSigs",
1020 "The required signatures"},
1022 "addresses",
1023 "",
1024 {
1025 {RPCResult::Type::STR, "address", "eCash address"},
1026 }},
1027 }},
1028 }},
1029 RPCExamples{HelpExampleRpc("getstakingreward", "<blockhash>")},
1030 [&](const RPCHelpMan &self, const Config &config,
1031 const JSONRPCRequest &request) -> UniValue {
1032 const NodeContext &node = EnsureAnyNodeContext(request.context);
1035
1036 const BlockHash blockhash(
1037 ParseHashV(request.params[0], "blockhash"));
1038
1039 const CBlockIndex *pprev;
1040 {
1041 LOCK(cs_main);
1042 pprev = chainman.m_blockman.LookupBlockIndex(blockhash);
1043 }
1044
1045 if (!pprev) {
1046 throw JSONRPCError(
1048 strprintf("Block not found: %s\n", blockhash.ToString()));
1049 }
1050
1052 config.GetChainParams().GetConsensus(), pprev)) {
1053 throw JSONRPCError(
1055 strprintf(
1056 "Staking rewards are not activated for block %s\n",
1057 blockhash.ToString()));
1058 }
1059
1060 if (!request.params[1].isNull() && request.params[1].get_bool()) {
1061 // Force recompute the staking reward winner by first erasing
1062 // the cached entry if any
1063 avalanche.eraseStakingRewardWinner(blockhash);
1064 }
1065
1066 if (!avalanche.computeStakingReward(pprev)) {
1067 throw JSONRPCError(
1069 strprintf("Unable to determine a staking reward winner "
1070 "for block %s\n",
1071 blockhash.ToString()));
1072 }
1073
1074 std::vector<std::pair<avalanche::ProofId, CScript>> winners;
1075 if (!avalanche.getStakingRewardWinners(blockhash, winners)) {
1076 throw JSONRPCError(
1078 strprintf("Unable to retrieve the staking reward winner "
1079 "for block %s\n",
1080 blockhash.ToString()));
1081 }
1082
1083 UniValue winnersArr(UniValue::VARR);
1084 for (auto &winner : winners) {
1085 UniValue stakingRewardsObj(UniValue::VOBJ);
1086 ScriptPubKeyToUniv(winner.second, stakingRewardsObj,
1087 /*fIncludeHex=*/true);
1088 stakingRewardsObj.pushKV("proofid", winner.first.GetHex());
1089 winnersArr.push_back(stakingRewardsObj);
1090 }
1091
1092 return winnersArr;
1093 },
1094 };
1095}
1096
1098 return RPCHelpMan{
1099 "hasstakingreward",
1100 "Return true if a staking reward winner exists based on the previous "
1101 "block hash.\n",
1102 {
1104 "The previous block hash, hex encoded."},
1105 },
1107 "Whether staking reward winner has been computed for "
1108 "previous block hash or not."},
1109 RPCExamples{HelpExampleRpc("hasstakingreward", "<blockhash>")},
1110 [&](const RPCHelpMan &self, const Config &config,
1111 const JSONRPCRequest &request) -> UniValue {
1112 const NodeContext &node = EnsureAnyNodeContext(request.context);
1115
1116 const BlockHash blockhash(
1117 ParseHashV(request.params[0], "blockhash"));
1118
1119 const CBlockIndex *pprev;
1120 {
1121 LOCK(cs_main);
1122 pprev = chainman.m_blockman.LookupBlockIndex(blockhash);
1123 }
1124
1125 if (!pprev) {
1126 throw JSONRPCError(
1128 strprintf("Block not found: %s\n", blockhash.ToString()));
1129 }
1130
1132 config.GetChainParams().GetConsensus(), pprev)) {
1133 throw JSONRPCError(
1135 strprintf(
1136 "Staking rewards are not activated for block %s\n",
1137 blockhash.ToString()));
1138 }
1139
1140 std::vector<std::pair<avalanche::ProofId, CScript>> winners;
1141 if (!avalanche.getStakingRewardWinners(blockhash, winners)) {
1142 return false;
1143 }
1144 return winners.size() > 0;
1145 },
1146 };
1147}
1148
1150 return RPCHelpMan{
1151 "setstakingreward",
1152 "Set the staking reward winner for the given previous block hash.\n",
1153 {
1155 "The previous block hash, hex encoded."},
1157 "The payout script for the staking reward, hex encoded."},
1158 {"append", RPCArg::Type::BOOL, RPCArg::Default{false},
1159 "Append to the list of possible winners instead of replacing."},
1160 },
1162 "Whether the payout script was set or not"},
1164 HelpExampleRpc("setstakingreward", "<blockhash> <payout script>")},
1165 [&](const RPCHelpMan &self, const Config &config,
1166 const JSONRPCRequest &request) -> UniValue {
1167 const NodeContext &node = EnsureAnyNodeContext(request.context);
1170
1171 const BlockHash blockhash(
1172 ParseHashV(request.params[0], "blockhash"));
1173
1174 const CBlockIndex *pprev;
1175 {
1176 LOCK(cs_main);
1177 pprev = chainman.m_blockman.LookupBlockIndex(blockhash);
1178 }
1179
1180 if (!pprev) {
1181 throw JSONRPCError(
1183 strprintf("Block not found: %s\n", blockhash.ToString()));
1184 }
1185
1187 config.GetChainParams().GetConsensus(), pprev)) {
1188 throw JSONRPCError(
1190 strprintf(
1191 "Staking rewards are not activated for block %s\n",
1192 blockhash.ToString()));
1193 }
1194
1195 const std::vector<uint8_t> data =
1196 ParseHex(request.params[1].get_str());
1197 CScript payoutScript(data.begin(), data.end());
1198
1199 std::vector<CScript> payoutScripts;
1200
1201 if (!request.params[2].isNull() && request.params[2].get_bool()) {
1202 // Append mode, initialize our list with the current winners
1203 // and the new one will be added to the back of that list. If
1204 // there is no winner the list will remain empty.
1205 avalanche.getStakingRewardWinners(blockhash, payoutScripts);
1206 }
1207
1208 if (std::find(payoutScripts.begin(), payoutScripts.end(),
1209 payoutScript) != payoutScripts.end()) {
1210 throw JSONRPCError(
1212 strprintf(
1213 "Staking rewards winner is already set for block %s\n",
1214 blockhash.ToString()));
1215 }
1216
1217 payoutScripts.push_back(std::move(payoutScript));
1218
1219 // This will return true upon insertion or false upon replacement.
1220 // We want to convey the success of the RPC, so we always return
1221 // true.
1222 avalanche.setStakingRewardWinners(pprev, payoutScripts);
1223 return true;
1224 },
1225 };
1226}
1227
1229 return RPCHelpMan{
1230 "getremoteproofs",
1231 "Get the list of remote proofs for the given node id.\n",
1232 {
1234 "The node identifier."},
1235 },
1236 RPCResult{
1238 "proofs",
1239 "",
1240 {{
1242 "proof",
1243 "",
1244 {{
1245 {RPCResult::Type::STR_HEX, "proofid",
1246 "The hex encoded proof identifier."},
1247 {RPCResult::Type::BOOL, "present",
1248 "Whether the node has the proof."},
1249 {RPCResult::Type::NUM, "last_update",
1250 "The last time this proof status was updated."},
1251 }},
1252 }},
1253 },
1254 RPCExamples{HelpExampleRpc("getremoteproofs", "<nodeid>")},
1255 [&](const RPCHelpMan &self, const Config &config,
1256 const JSONRPCRequest &request) -> UniValue {
1257 NodeContext &node = EnsureAnyNodeContext(request.context);
1259
1260 const NodeId nodeid = request.params[0].getInt<int64_t>();
1261 auto remoteProofs = avalanche.withPeerManager(
1262 [nodeid](const avalanche::PeerManager &pm) {
1263 return pm.getRemoteProofs(nodeid);
1264 });
1265
1266 UniValue arrOut(UniValue::VARR);
1267
1268 for (const auto &remoteProof : remoteProofs) {
1270 obj.pushKV("proofid", remoteProof.proofid.ToString());
1271 obj.pushKV("present", remoteProof.present);
1272 obj.pushKV("last_update", remoteProof.lastUpdate.count());
1273
1274 arrOut.push_back(obj);
1275 }
1276
1277 return arrOut;
1278 },
1279 };
1280}
1281
1283 return RPCHelpMan{
1284 "getrawavalancheproof",
1285 "Lookup for a known avalanche proof by id.\n",
1286 {
1288 "The hex encoded avalanche proof identifier."},
1289 },
1290 RPCResult{
1292 "",
1293 "",
1294 {{
1295 {RPCResult::Type::STR_HEX, "proof",
1296 "The hex encoded proof matching the identifier."},
1297 {RPCResult::Type::BOOL, "immature",
1298 "Whether the proof has immature utxos."},
1299 {RPCResult::Type::BOOL, "boundToPeer",
1300 "Whether the proof is bound to an avalanche peer."},
1301 {RPCResult::Type::BOOL, "conflicting",
1302 "Whether the proof has a conflicting UTXO with an avalanche "
1303 "peer."},
1304 {RPCResult::Type::BOOL, "finalized",
1305 "Whether the proof is finalized by vote."},
1306 }},
1307 },
1308 RPCExamples{HelpExampleRpc("getrawavalancheproof", "<proofid>")},
1309 [&](const RPCHelpMan &self, const Config &config,
1310 const JSONRPCRequest &request) -> UniValue {
1311 NodeContext &node = EnsureAnyNodeContext(request.context);
1313
1314 const avalanche::ProofId proofid =
1315 avalanche::ProofId::fromHex(request.params[0].get_str());
1316
1317 bool isImmature = false;
1318 bool isBoundToPeer = false;
1319 bool conflicting = false;
1320 bool finalized = false;
1321 auto proof = avalanche.withPeerManager(
1322 [&](const avalanche::PeerManager &pm) {
1323 isImmature = pm.isImmature(proofid);
1324 isBoundToPeer = pm.isBoundToPeer(proofid);
1325 conflicting = pm.isInConflictingPool(proofid);
1326 finalized =
1327 pm.forPeer(proofid, [&](const avalanche::Peer &p) {
1328 return p.hasFinalized;
1329 });
1330 return pm.getProof(proofid);
1331 });
1332
1333 if (!proof) {
1334 throw JSONRPCError(RPC_INVALID_PARAMETER, "Proof not found");
1335 }
1336
1338
1339 DataStream ss{};
1340 ss << *proof;
1341 ret.pushKV("proof", HexStr(ss));
1342 ret.pushKV("immature", isImmature);
1343 ret.pushKV("boundToPeer", isBoundToPeer);
1344 ret.pushKV("conflicting", conflicting);
1345 ret.pushKV("finalized", finalized);
1346
1347 return ret;
1348 },
1349 };
1350}
1351
1353 return RPCHelpMan{
1354 "invalidateavalancheproof",
1355 "Reject a known avalanche proof by id.\n",
1356 {
1358 "The hex encoded avalanche proof identifier."},
1359 },
1360 RPCResult{
1362 "success",
1363 "",
1364 },
1365 RPCExamples{HelpExampleRpc("invalidateavalancheproof", "<proofid>")},
1366 [&](const RPCHelpMan &self, const Config &config,
1367 const JSONRPCRequest &request) -> UniValue {
1368 NodeContext &node = EnsureAnyNodeContext(request.context);
1370
1371 const avalanche::ProofId proofid =
1372 avalanche::ProofId::fromHex(request.params[0].get_str());
1373
1374 avalanche.withPeerManager([&](avalanche::PeerManager &pm) {
1375 if (!pm.exists(proofid) && !pm.isDangling(proofid)) {
1376 throw JSONRPCError(RPC_INVALID_PARAMETER,
1377 "Proof not found");
1378 }
1379
1380 if (!pm.rejectProof(
1381 proofid,
1383 throw JSONRPCError(RPC_INTERNAL_ERROR,
1384 "Failed to reject the proof");
1385 }
1386
1387 pm.setInvalid(proofid);
1388 });
1389
1390 if (avalanche.isRecentlyFinalized(proofid)) {
1391 // If the proof was previously finalized, clear the status.
1392 // Because there is no way to selectively delete an entry from a
1393 // Bloom filter, we have to clear the whole filter which could
1394 // cause extra voting rounds.
1395 avalanche.clearFinalizedItems();
1396 }
1397
1398 return true;
1399 },
1400 };
1401}
1402
1404 return RPCHelpMan{
1405 "isfinalblock",
1406 "Check if a block has been finalized by avalanche votes.\n",
1407 {
1409 "The hash of the block."},
1410 },
1412 "Whether the block has been finalized by avalanche votes."},
1413 RPCExamples{HelpExampleRpc("isfinalblock", "<block hash>") +
1414 HelpExampleCli("isfinalblock", "<block hash>")},
1415 [&](const RPCHelpMan &self, const Config &config,
1416 const JSONRPCRequest &request) -> UniValue {
1417 NodeContext &node = EnsureAnyNodeContext(request.context);
1419
1420 if (!avalanche.isQuorumEstablished()) {
1422 "Avalanche is not ready to poll yet.");
1423 }
1424
1425 ChainstateManager &chainman = EnsureAnyChainman(request.context);
1426 const BlockHash blockhash(
1427 ParseHashV(request.params[0], "blockhash"));
1428 const CBlockIndex *pindex;
1429
1430 {
1431 LOCK(cs_main);
1432 pindex = chainman.m_blockman.LookupBlockIndex(blockhash);
1433
1434 if (!pindex) {
1436 "Block not found");
1437 }
1438 }
1439
1440 return chainman.ActiveChainstate().IsBlockAvalancheFinalized(
1441 pindex);
1442 },
1443 };
1444}
1445
1447 return RPCHelpMan{
1448 "isfinaltransaction",
1449 "Check if a transaction has been finalized by avalanche votes.\n",
1450 {
1452 "The id of the transaction."},
1454 "The block in which to look for the transaction"},
1455 },
1456 RPCResult{
1457 RPCResult::Type::BOOL, "success",
1458 "Whether the transaction has been finalized by avalanche votes."},
1459 RPCExamples{HelpExampleRpc("isfinaltransaction", "<txid> <blockhash>") +
1460 HelpExampleCli("isfinaltransaction", "<txid> <blockhash>")},
1461 [&](const RPCHelpMan &self, const Config &config,
1462 const JSONRPCRequest &request) -> UniValue {
1463 const NodeContext &node = EnsureAnyNodeContext(request.context);
1465 const CTxMemPool &mempool = EnsureMemPool(node);
1467
1468 const TxId txid = TxId(ParseHashV(request.params[0], "txid"));
1469 CBlockIndex *pindex = nullptr;
1470
1471 if (!request.params[1].isNull()) {
1472 const BlockHash blockhash(
1473 ParseHashV(request.params[1], "blockhash"));
1474
1475 LOCK(cs_main);
1476 pindex = chainman.m_blockman.LookupBlockIndex(blockhash);
1477 if (!pindex) {
1479 "Block not found");
1480 }
1481 }
1482
1483 bool f_txindex_ready = false;
1484 if (g_txindex && !pindex) {
1485 f_txindex_ready = g_txindex->BlockUntilSyncedToCurrentChain();
1486 }
1487
1488 BlockHash hash_block;
1490 pindex, &mempool, txid, hash_block, chainman.m_blockman);
1491
1492 if (!avalanche.isQuorumEstablished()) {
1494 "Avalanche is not ready to poll yet.");
1495 }
1496
1497 if (!tx) {
1498 std::string errmsg;
1499 if (pindex) {
1500 if (WITH_LOCK(::cs_main,
1501 return !pindex->nStatus.hasData())) {
1503 "Block data not downloaded yet.");
1504 }
1505 errmsg = "No such transaction found in the provided block.";
1506 } else if (!g_txindex) {
1507 errmsg = "No such transaction. Use -txindex or provide a "
1508 "block hash to enable blockchain transaction "
1509 "queries.";
1510 } else if (!f_txindex_ready) {
1511 errmsg = "No such transaction. Blockchain transactions are "
1512 "still in the process of being indexed.";
1513 } else {
1514 errmsg = "No such mempool or blockchain transaction.";
1515 }
1517 }
1518
1519 if (!pindex) {
1520 LOCK(cs_main);
1521 pindex = chainman.m_blockman.LookupBlockIndex(hash_block);
1522 }
1523
1524 if (!tx) {
1525 // Tx not found, we should have raised an error at this stage
1526 return false;
1527 }
1528
1529 if (WITH_LOCK(
1530 mempool.cs,
1531 return mempool.isAvalancheFinalizedPreConsensus(txid))) {
1532 // The transaction is finalized
1533 return true;
1534 }
1535
1536 // Return true if the tx is in a finalized block
1537 return !node.mempool->exists(txid) &&
1538 chainman.ActiveChainstate().IsBlockAvalancheFinalized(
1539 pindex);
1540 },
1541 };
1542}
1543
1545 return RPCHelpMan{
1546 "reconsideravalancheproof",
1547 "Reconsider a known avalanche proof.\n",
1548 {
1550 "The hex encoded avalanche proof."},
1551 },
1552 RPCResult{
1554 "success",
1555 "Whether the proof has been successfully registered.",
1556 },
1557 RPCExamples{HelpExampleRpc("reconsideravalancheproof", "<proof hex>")},
1558 [&](const RPCHelpMan &self, const Config &config,
1559 const JSONRPCRequest &request) -> UniValue {
1560 auto proof = RCUPtr<avalanche::Proof>::make();
1561
1562 NodeContext &node = EnsureAnyNodeContext(request.context);
1564
1565 // Verify the proof. Note that this is redundant with the
1566 // verification done when adding the proof to the pool, but we get a
1567 // chance to give a better error message.
1568 verifyProofOrThrow(node, *proof, request.params[0].get_str());
1569
1570 // There is no way to selectively clear the invalidation status of
1571 // a single proof, so we clear the whole Bloom filter. This could
1572 // cause extra voting rounds.
1573 avalanche.withPeerManager([&](avalanche::PeerManager &pm) {
1574 if (pm.isInvalid(proof->getId())) {
1575 pm.clearAllInvalid();
1576 }
1577 });
1578
1579 // Add the proof to the pool if we don't have it already. Since the
1580 // proof verification has already been done, a failure likely
1581 // indicates that there already is a proof with conflicting utxos.
1583 if (!registerProofIfNeeded(avalanche, proof, state)) {
1585 strprintf("%s (%s)\n",
1586 state.GetRejectReason(),
1587 state.GetDebugMessage()));
1588 }
1589
1590 return avalanche.withPeerManager(
1591 [&](const avalanche::PeerManager &pm) {
1592 return pm.isBoundToPeer(proof->getId());
1593 });
1594 },
1595 };
1596}
1597
1599 return RPCHelpMan{
1600 "sendavalancheproof",
1601 "Broadcast an avalanche proof.\n",
1602 {
1604 "The avalanche proof to broadcast."},
1605 },
1607 "Whether the proof was sent successfully or not."},
1608 RPCExamples{HelpExampleRpc("sendavalancheproof", "<proof>")},
1609 [&](const RPCHelpMan &self, const Config &config,
1610 const JSONRPCRequest &request) -> UniValue {
1611 auto proof = RCUPtr<avalanche::Proof>::make();
1612
1613 NodeContext &node = EnsureAnyNodeContext(request.context);
1615
1616 // Verify the proof. Note that this is redundant with the
1617 // verification done when adding the proof to the pool, but we get a
1618 // chance to give a better error message.
1619 verifyProofOrThrow(node, *proof, request.params[0].get_str());
1620
1621 // Add the proof to the pool if we don't have it already. Since the
1622 // proof verification has already been done, a failure likely
1623 // indicates that there already is a proof with conflicting utxos.
1624 const avalanche::ProofId &proofid = proof->getId();
1626 if (!registerProofIfNeeded(avalanche, proof, state)) {
1628 strprintf("%s (%s)\n",
1629 state.GetRejectReason(),
1630 state.GetDebugMessage()));
1631 }
1632
1633 avalanche.withPeerManager([&](avalanche::PeerManager &pm) {
1634 pm.addUnbroadcastProof(proofid);
1635 });
1636
1637 if (node.peerman) {
1638 node.peerman->RelayProof(proofid);
1639 }
1640
1641 return true;
1642 },
1643 };
1644}
1645
1647 return RPCHelpMan{
1648 "verifyavalancheproof",
1649 "Verify an avalanche proof is valid and return the error otherwise.\n",
1650 {
1652 "Proof to verify."},
1653 },
1655 "Whether the proof is valid or not."},
1656 RPCExamples{HelpExampleRpc("verifyavalancheproof", "\"<proof>\"")},
1657 [&](const RPCHelpMan &self, const Config &config,
1658 const JSONRPCRequest &request) -> UniValue {
1659 avalanche::Proof proof;
1660 verifyProofOrThrow(EnsureAnyNodeContext(request.context), proof,
1661 request.params[0].get_str());
1662
1663 return true;
1664 },
1665 };
1666}
1667
1669 return RPCHelpMan{
1670 "verifyavalanchedelegation",
1671 "Verify an avalanche delegation is valid and return the error "
1672 "otherwise.\n",
1673 {
1675 "The avalanche proof delegation to verify."},
1676 },
1678 "Whether the delegation is valid or not."},
1679 RPCExamples{HelpExampleRpc("verifyavalanchedelegation", "\"<proof>\"")},
1680 [&](const RPCHelpMan &self, const Config &config,
1681 const JSONRPCRequest &request) -> UniValue {
1682 avalanche::Delegation delegation;
1683 CPubKey dummy;
1684 verifyDelegationOrThrow(delegation, request.params[0].get_str(),
1685 dummy);
1686
1687 return true;
1688 },
1689 };
1690}
1691
1693 return RPCHelpMan{
1694 "setflakyproof",
1695 "Add or remove a proofid from the flaky list. This means that an "
1696 "additional staking reward winner will be accepted if this proof is "
1697 "the selected one.\n",
1698 {
1700 "The avalanche proof id."},
1702 "Whether to add (true) or remove (false) the proof from the flaky "
1703 "list"},
1704 },
1706 "Whether the addition/removal is successful."},
1707 RPCExamples{HelpExampleRpc("setflakyproof", "\"<proofid>\" true")},
1708 [&](const RPCHelpMan &self, const Config &config,
1709 const JSONRPCRequest &request) -> UniValue {
1710 NodeContext &node = EnsureAnyNodeContext(request.context);
1713
1714 const auto proofid =
1715 avalanche::ProofId::fromHex(request.params[0].get_str());
1716 const bool addNotRemove = request.params[1].get_bool();
1717
1718 if (avalanche.withPeerManager(
1719 [&proofid, addNotRemove](avalanche::PeerManager &pm) {
1720 if (addNotRemove) {
1721 return pm.setFlaky(proofid);
1722 }
1723 return pm.unsetFlaky(proofid);
1724 })) {
1725 const CBlockIndex *pprev =
1726 WITH_LOCK(cs_main, return chainman.ActiveTip());
1727 // Force recompute the staking reward winner by first erasing
1728 // the cached entry if any
1729 avalanche.eraseStakingRewardWinner(pprev->GetBlockHash());
1730 return avalanche.computeStakingReward(pprev);
1731 }
1732
1733 return false;
1734 }};
1735}
1736
1738 return RPCHelpMan{
1739 "getflakyproofs",
1740 "List the flaky proofs (set via setflakyproof).\n",
1741 {},
1742 RPCResult{
1744 "flaky_proofs",
1745 "",
1746 {{
1748 "proof",
1749 "",
1750 {{
1751 {RPCResult::Type::STR_HEX, "proofid",
1752 "The hex encoded proof identifier."},
1753 {RPCResult::Type::STR_AMOUNT, "staked_amount",
1754 "The proof stake amount, only present if the proof is "
1755 "known."},
1757 "payout",
1758 "The proof payout script, only present if the proof is "
1759 "known.",
1760 {
1761 {RPCResult::Type::STR, "asm", "Decoded payout script"},
1763 "Raw payout script in hex format"},
1764 {RPCResult::Type::STR, "type",
1765 "The output type (e.g. " + GetAllOutputTypes() + ")"},
1766 {RPCResult::Type::NUM, "reqSigs",
1767 "The required signatures"},
1769 "addresses",
1770 "",
1771 {
1772 {RPCResult::Type::STR, "address",
1773 "eCash address"},
1774 }},
1775 }},
1776 }},
1777 }},
1778 },
1779 RPCExamples{HelpExampleRpc("getflakyproofs", "")},
1780 [&](const RPCHelpMan &self, const Config &config,
1781 const JSONRPCRequest &request) -> UniValue {
1782 NodeContext &node = EnsureAnyNodeContext(request.context);
1784
1785 UniValue flakyProofs(UniValue::VARR);
1786 avalanche.withPeerManager([&flakyProofs](
1788 pm.forEachFlakyProof([&](const avalanche::ProofId &proofid) {
1789 UniValue flakyProof(UniValue::VOBJ);
1790 flakyProof.pushKV("proofid", proofid.GetHex());
1791
1792 const auto proof = pm.getProof(proofid);
1793 if (proof) {
1794 flakyProof.pushKV("staked_amount",
1795 proof->getStakedAmount());
1796 UniValue payout(UniValue::VOBJ);
1797 ScriptPubKeyToUniv(proof->getPayoutScript(), payout,
1798 /*fIncludeHex=*/true);
1799 flakyProof.pushKV("payout", payout);
1800 }
1801
1802 flakyProofs.push_back(flakyProof);
1803 });
1804 });
1805
1806 return flakyProofs;
1807 }};
1808}
1809
1811 return RPCHelpMan{
1812 "getavailabilityscore",
1813 "Return the node availability score.\n",
1814 {
1815 {"nodeid", RPCArg::Type::NUM, RPCArg::Optional::NO, "The node id."},
1816 },
1817 RPCResult{RPCResult::Type::NUM, "availability_score",
1818 "The node availability score (if any)."},
1819 RPCExamples{HelpExampleRpc("getavailabilityscore", "<nodeid>")},
1820 [&](const RPCHelpMan &self, const Config &config,
1821 const JSONRPCRequest &request) -> UniValue {
1822 const NodeContext &node = EnsureAnyNodeContext(request.context);
1823 const CConnman &connman = EnsureConnman(node);
1824
1825 const NodeId nodeid(request.params[0].getInt<int64_t>());
1826
1827 CNodeStats nodeStats;
1828 if (connman.GetNodeStats(nodeid, nodeStats) &&
1829 nodeStats.m_availabilityScore) {
1830 return *nodeStats.m_availabilityScore;
1831 }
1832
1833 return UniValue::VNULL;
1834 },
1835 };
1836}
1837
1839 return RPCHelpMan{
1840 "getstakecontendervote",
1841 "Return the stake contender avalanche vote.\n",
1842 {
1844 "The prevblockhash used to compute the stake contender ID, hex "
1845 "encoded."},
1847 "The proofid used to compute the stake contender ID, hex "
1848 "encoded."},
1849 },
1851 "The vote that would be returned if polled."},
1852 RPCExamples{HelpExampleRpc("getstakecontendervote",
1853 "<prevblockhash> <proofid>")},
1854 [&](const RPCHelpMan &self, const Config &config,
1855 const JSONRPCRequest &request) -> UniValue {
1856 const NodeContext &node = EnsureAnyNodeContext(request.context);
1858
1859 const BlockHash prevblockhash(
1860 ParseHashV(request.params[0], "prevblockhash"));
1861 const avalanche::ProofId proofid(
1862 ParseHashV(request.params[1], "proofid"));
1863 const avalanche::StakeContenderId contenderId(prevblockhash,
1864 proofid);
1865 return avalanche.getStakeContenderStatus(contenderId);
1866 },
1867 };
1868}
1869
1871 return RPCHelpMan{
1872 "finalizetransaction",
1873 "Force finalize a mempool transaction. No attempt is made to poll for "
1874 "this transaction and this could cause the node to disagree with the "
1875 "network. This can fail if the transaction to be finalized would "
1876 "overflow the block size. Upon success it will be included in the "
1877 "block template.\n",
1878 {
1880 "The id of the transaction to be finalized."},
1881 },
1883 "finalized_txids",
1884 "The list of the successfully finalized txids if any (it can "
1885 "include ancestors of the target txid).",
1886 {{
1888 "txid",
1889 "The finalized transaction id.",
1890 }}},
1891 RPCExamples{HelpExampleRpc("finalizetransaction", "<txid>")},
1892 [&](const RPCHelpMan &self, const Config &config,
1893 const JSONRPCRequest &request) -> UniValue {
1894 const NodeContext &node = EnsureAnyNodeContext(request.context);
1895 CTxMemPool &mempool = EnsureAnyMemPool(request.context);
1896 const ChainstateManager &chainman = EnsureChainman(node);
1897
1898 const TxId txid(ParseHashV(request.params[0], "txid"));
1899
1900 LOCK2(cs_main, mempool.cs);
1901 auto entry = mempool.GetIter(txid);
1902 if (!entry) {
1904 "The transaction is not in the mempool.");
1905 }
1906
1907 const CBlockIndex *tip = chainman.ActiveTip();
1908 if (!tip) {
1910 "There is no active chain tip.");
1911 }
1912
1914
1915 std::vector<TxId> finalizedTxids;
1916 if (!mempool.setAvalancheFinalized(**entry, chainman.GetConsensus(),
1917 *tip, finalizedTxids)) {
1918 // If the function returned false, the finalizedTxids vector
1919 // should not be relied upon
1920 return ret;
1921 }
1922
1923 for (TxId &finalizedTxid : finalizedTxids) {
1924 ret.push_back(finalizedTxid.ToString());
1925
1926 // FIXME we might want to remove from the recent rejects as well
1927 // if it exists so we don't vote against this tx anymore. For
1928 // now this is a private data from the PeerManager and can only
1929 // be cleared entirely. Also a rejected transaction is not
1930 // expected to be in the mempool in the first place so this is
1931 // probably safe.
1932 }
1933
1934 return ret;
1935 },
1936 };
1937}
1938
1940 return RPCHelpMan{
1941 "removetransaction",
1942 "Remove a transaction and all its descendants from the mempool. If the "
1943 "transaction is final it is removed anyway. No attempt is made to poll "
1944 "for this transaction and this could cause the node to disagree with "
1945 "the network.\n",
1946 {
1948 "The id of the transaction to be removed."},
1949 },
1951 "removed_txids",
1952 "The list of the removed txids if any (it can include "
1953 "descendants of the target txid).",
1954 {{
1956 "txid",
1957 "The removed transaction id.",
1958 }}},
1959 RPCExamples{HelpExampleRpc("removetransaction", "<txid>")},
1960 [&](const RPCHelpMan &self, const Config &config,
1961 const JSONRPCRequest &request) -> UniValue {
1962 CTxMemPool &mempool = EnsureAnyMemPool(request.context);
1963
1964 const TxId txid(ParseHashV(request.params[0], "txid"));
1965
1966 LOCK(mempool.cs);
1967 auto iter = mempool.GetIter(txid);
1968 if (!iter) {
1970 "The transaction is not in the mempool.");
1971 }
1972
1973 // This mostly mimics the CTxMemPool::removeRecursive function so we
1974 // can return the list of removed txids
1975 CTxMemPool::setEntries setDescendants;
1976 mempool.CalculateDescendants(*iter, setDescendants);
1977
1979 for (auto &it : setDescendants) {
1980 ret.push_back((*it)->GetSharedTx()->GetId().ToString());
1981 }
1982
1983 mempool.RemoveStaged(setDescendants, MemPoolRemovalReason::MANUAL);
1984
1985 return ret;
1986 },
1987 };
1988}
1989
1991 return RPCHelpMan{
1992 "getfinaltransactions",
1993 "Returns all finalized transactions that have not been included in a "
1994 "finalized block yet.",
1995 {
1996 {"verbose", RPCArg::Type::BOOL, RPCArg::Default{false},
1997 "True for a json object, false for an array of transaction ids"},
1998 },
1999 {
2000 RPCResult{"for verbose = false",
2002 "",
2003 "",
2004 {
2005 {RPCResult::Type::STR_HEX, "", "The transaction id"},
2006 }},
2007 RPCResult{"for verbose = true",
2009 "",
2010 "",
2011 {{
2013 "",
2014 "",
2015 DecodeTxDoc(/*txid_field_doc=*/"The transaction id",
2016 /*wallet=*/false),
2017 }}},
2018 },
2019 RPCExamples{HelpExampleCli("getfinaltransactions", "true") +
2020 HelpExampleRpc("getfinaltransactions", "true")},
2021 [&](const RPCHelpMan &self, const Config &config,
2022 const JSONRPCRequest &request) -> UniValue {
2023 const bool fVerbose =
2024 !request.params[0].isNull() && request.params[0].get_bool();
2025
2026 const CTxMemPool &mempool = EnsureAnyMemPool(request.context);
2027
2028 UniValue finalTxs(UniValue::VARR);
2029 {
2030 LOCK(mempool.cs);
2031 mempool.finalizedTxs.forEachLeaf(
2032 [fVerbose, &finalTxs](const CTxMemPoolEntryRef &entryRef) {
2033 if (!fVerbose) {
2034 finalTxs.push_back(
2035 entryRef->GetTx().GetId().GetHex());
2036 } else {
2038 TxToUniv(entryRef->GetTx(), BlockHash(), tx,
2039 /*include_hex=*/true);
2040 finalTxs.push_back(std::move(tx));
2041 }
2042 return true;
2043 });
2044 }
2045
2046 return finalTxs;
2047 },
2048 };
2049}
2050
2052 // clang-format off
2053 static const CRPCCommand commands[] = {
2054 // category actor (function)
2055 // ----------------- --------------------
2056 { "avalanche", getavalanchekey, },
2057 { "avalanche", addavalanchenode, },
2058 { "avalanche", buildavalancheproof, },
2059 { "avalanche", decodeavalancheproof, },
2060 { "avalanche", delegateavalancheproof, },
2061 { "avalanche", decodeavalanchedelegation, },
2062 { "avalanche", getavalancheinfo, },
2063 { "avalanche", getavalanchepeerinfo, },
2064 { "avalanche", getavalancheproofs, },
2065 { "avalanche", getstakingreward, },
2066 { "hidden", hasstakingreward, },
2067 { "avalanche", setstakingreward, },
2068 { "avalanche", getremoteproofs, },
2069 { "avalanche", getrawavalancheproof, },
2070 { "avalanche", invalidateavalancheproof, },
2071 { "avalanche", isfinalblock, },
2072 { "avalanche", isfinaltransaction, },
2073 { "avalanche", reconsideravalancheproof, },
2074 { "avalanche", sendavalancheproof, },
2075 { "avalanche", verifyavalancheproof, },
2076 { "avalanche", verifyavalanchedelegation, },
2077 { "avalanche", setflakyproof, },
2078 { "avalanche", getflakyproofs, },
2079 { "avalanche", finalizetransaction, },
2080 { "avalanche", removetransaction, },
2081 { "avalanche", getfinaltransactions, },
2082 { "hidden", getavailabilityscore, },
2083 { "hidden", getstakecontendervote, },
2084 };
2085 // clang-format on
2086
2087 for (const auto &c : commands) {
2088 t.appendCommand(c.name, &c);
2089 }
2090}
static RPCHelpMan buildavalancheproof()
Definition: avalanche.cpp:210
static RPCHelpMan invalidateavalancheproof()
Definition: avalanche.cpp:1352
static RPCHelpMan delegateavalancheproof()
Definition: avalanche.cpp:466
static RPCHelpMan getremoteproofs()
Definition: avalanche.cpp:1228
static RPCHelpMan decodeavalanchedelegation()
Definition: avalanche.cpp:538
static RPCHelpMan sendavalancheproof()
Definition: avalanche.cpp:1598
static RPCHelpMan getavalancheproofs()
Definition: avalanche.cpp:928
static void verifyDelegationOrThrow(avalanche::Delegation &dg, const std::string &dgHex, CPubKey &auth)
Definition: avalanche.cpp:82
static RPCHelpMan getrawavalancheproof()
Definition: avalanche.cpp:1282
static void verifyProofOrThrow(const NodeContext &node, avalanche::Proof &proof, const std::string &proofHex)
Definition: avalanche.cpp:96
void RegisterAvalancheRPCCommands(CRPCTable &t)
Definition: avalanche.cpp:2051
static RPCHelpMan getavalanchekey()
Definition: avalanche.cpp:35
static RPCHelpMan hasstakingreward()
Definition: avalanche.cpp:1097
static RPCHelpMan addavalanchenode()
Definition: avalanche.cpp:122
static CPubKey ParsePubKey(const UniValue &param)
Definition: avalanche.cpp:51
static RPCHelpMan finalizetransaction()
Definition: avalanche.cpp:1870
static RPCHelpMan getavailabilityscore()
Definition: avalanche.cpp:1810
static RPCHelpMan getstakecontendervote()
Definition: avalanche.cpp:1838
static RPCHelpMan verifyavalanchedelegation()
Definition: avalanche.cpp:1668
static RPCHelpMan setflakyproof()
Definition: avalanche.cpp:1692
static RPCHelpMan getfinaltransactions()
Definition: avalanche.cpp:1990
static RPCHelpMan removetransaction()
Definition: avalanche.cpp:1939
static RPCHelpMan setstakingreward()
Definition: avalanche.cpp:1149
static RPCHelpMan getflakyproofs()
Definition: avalanche.cpp:1737
static RPCHelpMan isfinalblock()
Definition: avalanche.cpp:1403
static RPCHelpMan reconsideravalancheproof()
Definition: avalanche.cpp:1544
static RPCHelpMan isfinaltransaction()
Definition: avalanche.cpp:1446
static RPCHelpMan getstakingreward()
Definition: avalanche.cpp:990
static bool registerProofIfNeeded(const avalanche::Processor &avalanche, avalanche::ProofRef proof, avalanche::ProofRegistrationState &state)
Definition: avalanche.cpp:63
static RPCHelpMan getavalanchepeerinfo()
Definition: avalanche.cpp:832
static RPCHelpMan verifyavalancheproof()
Definition: avalanche.cpp:1646
static RPCHelpMan getavalancheinfo()
Definition: avalanche.cpp:621
static RPCHelpMan decodeavalancheproof()
Definition: avalanche.cpp:341
#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:830
void GetNodeStats(std::vector< CNodeStats > &vstats) const
Definition: net.cpp:2789
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:389
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:64
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:62
const DelegationId & getId() const
Definition: delegation.h:60
const CPubKey & getDelegatedPubkey() const
Definition: delegation.cpp:60
const LimitedProofId & getLimitedProofId() const
Definition: delegation.h:61
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:415
const ProofPool & getValidProofPool() const
Definition: peermanager.h:514
bool forPeer(const ProofId &proofid, Callable &&func) const
Definition: peermanager.h:423
void addUnbroadcastProof(const ProofId &proofid)
Proof broadcast API.
bool isBoundToPeer(const ProofId &proofid) const
size_t getPendingNodeCount() const
Definition: peermanager.h:320
const ProofPool & getImmatureProofPool() const
Definition: peermanager.h:518
void forEachPeer(Callable &&func) const
Definition: peermanager.h:429
void setInvalid(const ProofId &proofid)
void forEachNode(const Peer &peer, Callable &&func) const
Definition: peermanager.h:349
const Amount & getStakeUtxoDustThreshold() const
Definition: peermanager.h:534
void forEachFlakyProof(Callable &&func) const
Definition: peermanager.h:461
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:515
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:164
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:165
uint64_t getSequence() const
Definition: proof.h:163
const LimitedProofId & getLimitedId() const
Definition: proof.h:171
const SchnorrSig & getSignature() const
Definition: proof.h:168
const CScript & getPayoutScript() const
Definition: proof.h:167
uint32_t getScore() const
Definition: proof.h:175
const ProofId & getId() const
Definition: proof.h:170
const std::vector< SignedStake > & getStakes() const
Definition: proof.h:166
Map a proof to each utxo.
Definition: proofpool.h:57
size_t countProofs() const
Definition: proofpool.cpp:129
void forEachProof(Callable &&func) const
Definition: proofpool.h:118
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:41
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:144
A TxId is the identifier of a transaction.
Definition: txid.h:14
NodeId nodeid
Definition: node.h:21
uint32_t node_count
Definition: peermanager.h:89
ProofRef proof
Definition: peermanager.h:91
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.