Changeset View
Changeset View
Standalone View
Standalone View
src/rpc/avalanche.cpp
Show First 20 Lines • Show All 67 Lines • ▼ Show 20 Lines | static void verifyDelegationOrThrow(avalanche::Delegation &dg, | ||||
avalanche::DelegationState state; | avalanche::DelegationState state; | ||||
if (!dg.verify(state, auth)) { | if (!dg.verify(state, auth)) { | ||||
throw JSONRPCError(RPC_INVALID_PARAMETER, | throw JSONRPCError(RPC_INVALID_PARAMETER, | ||||
"The delegation is invalid: " + state.ToString()); | "The delegation is invalid: " + state.ToString()); | ||||
} | } | ||||
} | } | ||||
static void verifyProofOrThrow(const NodeContext &node, avalanche::Proof &proof, | |||||
const std::string &proofHex) { | |||||
bilingual_str error; | |||||
if (!avalanche::Proof::FromHex(proof, proofHex, error)) { | |||||
throw JSONRPCError(RPC_DESERIALIZATION_ERROR, error.original); | |||||
} | |||||
avalanche::ProofValidationState state; | |||||
{ | |||||
LOCK(cs_main); | |||||
if (!proof.verify(state, | |||||
node.chainman->ActiveChainstate().CoinsTip())) { | |||||
throw JSONRPCError(RPC_INVALID_PARAMETER, | |||||
"The proof is invalid: " + state.ToString()); | |||||
} | |||||
} | |||||
} | |||||
static UniValue addavalanchenode(const Config &config, | static UniValue addavalanchenode(const Config &config, | ||||
const JSONRPCRequest &request) { | const JSONRPCRequest &request) { | ||||
RPCHelpMan{ | RPCHelpMan{ | ||||
"addavalanchenode", | "addavalanchenode", | ||||
"Add a node in the set of peers to poll for avalanche.\n", | "Add a node in the set of peers to poll for avalanche.\n", | ||||
{ | { | ||||
{"nodeid", RPCArg::Type::NUM, RPCArg::Optional::NO, | {"nodeid", RPCArg::Type::NUM, RPCArg::Optional::NO, | ||||
"Node to be added to avalanche."}, | "Node to be added to avalanche."}, | ||||
Show All 17 Lines | static UniValue addavalanchenode(const Config &config, | ||||
if (!g_avalanche) { | if (!g_avalanche) { | ||||
throw JSONRPCError(RPC_INTERNAL_ERROR, "Avalanche is not initialized"); | throw JSONRPCError(RPC_INTERNAL_ERROR, "Avalanche is not initialized"); | ||||
} | } | ||||
const NodeId nodeid = request.params[0].get_int64(); | const NodeId nodeid = request.params[0].get_int64(); | ||||
CPubKey key = ParsePubKey(request.params[1]); | CPubKey key = ParsePubKey(request.params[1]); | ||||
auto proof = std::make_shared<avalanche::Proof>(); | auto proof = std::make_shared<avalanche::Proof>(); | ||||
bilingual_str error; | NodeContext &node = EnsureNodeContext(request.context); | ||||
if (!avalanche::Proof::FromHex(*proof, request.params[2].get_str(), | verifyProofOrThrow(node, *proof, request.params[2].get_str()); | ||||
error)) { | |||||
throw JSONRPCError(RPC_DESERIALIZATION_ERROR, error.original); | |||||
} | |||||
const avalanche::ProofId &proofid = proof->getId(); | const avalanche::ProofId &proofid = proof->getId(); | ||||
if (key != proof->getMaster()) { | if (key != proof->getMaster()) { | ||||
if (request.params.size() < 4 || request.params[3].isNull()) { | if (request.params.size() < 4 || request.params[3].isNull()) { | ||||
throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, | throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, | ||||
"The public key does not match the proof"); | "The public key does not match the proof"); | ||||
} | } | ||||
avalanche::Delegation dg; | avalanche::Delegation dg; | ||||
CPubKey auth; | CPubKey auth; | ||||
verifyDelegationOrThrow(dg, request.params[3].get_str(), auth); | verifyDelegationOrThrow(dg, request.params[3].get_str(), auth); | ||||
if (dg.getProofId() != proofid) { | if (dg.getProofId() != proofid) { | ||||
throw JSONRPCError(RPC_INVALID_PARAMETER, | throw JSONRPCError(RPC_INVALID_PARAMETER, | ||||
"The delegation does not match the proof"); | "The delegation does not match the proof"); | ||||
} | } | ||||
if (key != auth) { | if (key != auth) { | ||||
throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, | throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, | ||||
"The public key does not match the delegation"); | "The public key does not match the delegation"); | ||||
} | } | ||||
} | } | ||||
if (!registerProofIfNeeded(proof)) { | if (!registerProofIfNeeded(proof)) { | ||||
return false; | throw JSONRPCError(RPC_INVALID_PARAMETER, | ||||
"The proof has conflicting utxos"); | |||||
} | } | ||||
NodeContext &node = EnsureNodeContext(request.context); | |||||
if (!node.connman->ForNode(nodeid, [&](CNode *pnode) { | if (!node.connman->ForNode(nodeid, [&](CNode *pnode) { | ||||
// FIXME This is not thread safe, and might cause issues if the | // FIXME This is not thread safe, and might cause issues if the | ||||
// unlikely event the peer sends an avahello message at the same | // unlikely event the peer sends an avahello message at the same | ||||
// time. | // time. | ||||
if (!pnode->m_avalanche_state) { | if (!pnode->m_avalanche_state) { | ||||
pnode->m_avalanche_state = | pnode->m_avalanche_state = | ||||
std::make_unique<CNode::AvalancheState>(); | std::make_unique<CNode::AvalancheState>(); | ||||
} | } | ||||
pnode->m_avalanche_state->pubkey = std::move(key); | pnode->m_avalanche_state->pubkey = std::move(key); | ||||
return true; | return true; | ||||
})) { | })) { | ||||
return false; | throw JSONRPCError(RPC_INVALID_PARAMETER, | ||||
strprintf("The node does not exist: %d", nodeid)); | |||||
; | |||||
} | } | ||||
return g_avalanche->withPeerManager([&](avalanche::PeerManager &pm) { | return g_avalanche->withPeerManager([&](avalanche::PeerManager &pm) { | ||||
if (!pm.addNode(nodeid, proofid)) { | if (!pm.addNode(nodeid, proofid)) { | ||||
return false; | return false; | ||||
} | } | ||||
pm.addUnbroadcastProof(proofid); | pm.addUnbroadcastProof(proofid); | ||||
▲ Show 20 Lines • Show All 390 Lines • ▼ Show 20 Lines | static UniValue getrawavalancheproof(const Config &config, | ||||
CDataStream ss(SER_NETWORK, PROTOCOL_VERSION); | CDataStream ss(SER_NETWORK, PROTOCOL_VERSION); | ||||
ss << *proof; | ss << *proof; | ||||
ret.pushKV("proof", HexStr(ss)); | ret.pushKV("proof", HexStr(ss)); | ||||
ret.pushKV("orphan", isOrphan); | ret.pushKV("orphan", isOrphan); | ||||
return ret; | return ret; | ||||
} | } | ||||
static void verifyProofOrThrow(const NodeContext &node, avalanche::Proof &proof, | |||||
const std::string &proofHex) { | |||||
bilingual_str error; | |||||
if (!avalanche::Proof::FromHex(proof, proofHex, error)) { | |||||
throw JSONRPCError(RPC_DESERIALIZATION_ERROR, error.original); | |||||
} | |||||
avalanche::ProofValidationState state; | |||||
{ | |||||
LOCK(cs_main); | |||||
if (!proof.verify(state, | |||||
node.chainman->ActiveChainstate().CoinsTip())) { | |||||
throw JSONRPCError(RPC_INVALID_PARAMETER, | |||||
"The proof is invalid: " + state.ToString()); | |||||
} | |||||
} | |||||
} | |||||
static UniValue sendavalancheproof(const Config &config, | static UniValue sendavalancheproof(const Config &config, | ||||
const JSONRPCRequest &request) { | const JSONRPCRequest &request) { | ||||
RPCHelpMan{ | RPCHelpMan{ | ||||
"sendavalancheproof", | "sendavalancheproof", | ||||
"Broadcast an avalanche proof.\n", | "Broadcast an avalanche proof.\n", | ||||
{ | { | ||||
{"proof", RPCArg::Type::STR_HEX, RPCArg::Optional::NO, | {"proof", RPCArg::Type::STR_HEX, RPCArg::Optional::NO, | ||||
"The avalanche proof to broadcast."}, | "The avalanche proof to broadcast."}, | ||||
▲ Show 20 Lines • Show All 82 Lines • Show Last 20 Lines |