diff --git a/src/avalanche/processor.h b/src/avalanche/processor.h --- a/src/avalanche/processor.h +++ b/src/avalanche/processor.h @@ -294,12 +294,9 @@ uint256 buildRemoteSighash(CNode *pfrom) const; /** - * Get the local proof used by this node. - * - * @returns Proof for this node. - * @throws a std::runtime_error if there is no proof set for this node + * Return true if a proof was set for this node. */ - const Proof getProof() const; + bool hasLocalProof() const; std::vector getPeers() const; std::vector getNodeIdsForPeer(PeerId peerId) const; diff --git a/src/avalanche/processor.cpp b/src/avalanche/processor.cpp --- a/src/avalanche/processor.cpp +++ b/src/avalanche/processor.cpp @@ -173,19 +173,48 @@ sessionKey.MakeNewKey(true); } + // If avalanche is enabled and a proof is supplied, make sure it does + // not contain garbage. At this point the validity of the utxos cannot + // be checked, so only basic verification is performed. if (gArgs.IsArgSet("-avaproof")) { peerData = std::make_unique(); - { - // The proof. - CDataStream stream(ParseHex(gArgs.GetArg("-avaproof", "")), - SER_NETWORK, 0); - stream >> peerData->proof; - - // Schedule proof registration at the first new block after IBD. - mustRegisterProof = true; + // The proof. + CDataStream stream(ParseHex(gArgs.GetArg("-avaproof", "")), SER_NETWORK, + 0); + stream >> peerData->proof; + + ProofValidationState proof_state; + if (!peerData->proof.verify(proof_state)) { + LogPrintfToBeContinued("Failed basic avaproof verification: "); + switch (proof_state.GetResult()) { + case avalanche::ProofValidationResult::NO_STAKE: + LogPrintf("the avalanche proof has no stake\n"); + break; + case avalanche::ProofValidationResult::DUST_THRESOLD: + LogPrintf("the avalanche proof stake is too low\n"); + break; + case avalanche::ProofValidationResult::DUPLICATE_STAKE: + LogPrintf("the avalanche proof has duplicated stake\n"); + break; + case avalanche::ProofValidationResult::INVALID_SIGNATURE: + LogPrintf("the avalanche proof has invalid stake " + "signatures\n"); + break; + case avalanche::ProofValidationResult::TOO_MANY_UTXOS: + LogPrintf("the avalanche proof has too many utxos " + "(max: %u)\n", + AVALANCHE_MAX_PROOF_STAKES); + break; + default: + LogPrintf("the avalanche proof is invalid\n"); + } + throw std::runtime_error("Failed basic avaproof verification"); } + // Schedule proof registration at first new block after IBD. + mustRegisterProof = true; + // Generate the delegation to the session key. DelegationBuilder dgb(peerData->proof); if (sessionKey.GetPubKey() != peerData->proof.getMaster()) { @@ -444,11 +473,8 @@ return true; } -const Proof Processor::getProof() const { - if (!peerData) { - throw std::runtime_error("proof not set"); - } - return peerData->proof; +bool Processor::hasLocalProof() const { + return peerData ? true : false; } bool Processor::startEventLoop(CScheduler &scheduler) { diff --git a/src/init.cpp b/src/init.cpp --- a/src/init.cpp +++ b/src/init.cpp @@ -2432,46 +2432,17 @@ } // Step 6.5 (I guess ?): Initialize Avalanche. - g_avalanche = std::make_unique( - *node.chain, node.connman.get(), node.peerman.get()); + try { + g_avalanche = std::make_unique( + *node.chain, node.connman.get(), node.peerman.get()); + } catch (const std::runtime_error &e) { + InitError(_("Failed to initialize avalanche")); + return false; + } if (args.GetBoolArg("-enableavalanche", AVALANCHE_DEFAULT_ENABLED)) { nLocalServices = ServiceFlags(nLocalServices | NODE_AVALANCHE); - // If avalanche is enabled and a proof is supplied, make sure it does - // not contain garbage. At this point the validity of the utxos cannot - // be checked, so only basic verification is performed. - try { - avalanche::Proof proof; - proof = g_avalanche->getProof(); - - avalanche::ProofValidationState proof_state; - if (!proof.verify(proof_state)) { - switch (proof_state.GetResult()) { - case avalanche::ProofValidationResult::NO_STAKE: - InitError(_("the avalanche proof has no stake")); - return false; - case avalanche::ProofValidationResult::DUST_THRESOLD: - InitError(_("the avalanche proof stake is too low")); - return false; - case avalanche::ProofValidationResult::DUPLICATE_STAKE: - InitError( - _("the avalanche proof has duplicated stake")); - return false; - case avalanche::ProofValidationResult::INVALID_SIGNATURE: - InitError(_("the avalanche proof has invalid stake " - "signatures")); - return false; - case avalanche::ProofValidationResult::TOO_MANY_UTXOS: - InitError(strprintf(_("the avalanche proof has too " - "many utxos (max: %u)"), - AVALANCHE_MAX_PROOF_STAKES)); - return false; - default: - InitError(_("the avalanche proof is invalid")); - return false; - } - } - } catch (const std::runtime_error &e) { + if (!g_avalanche->hasLocalProof()) { LogPrintf("Avalanche is enabled but no proof supplied, the node " "will not be able to vote\n"); } diff --git a/test/functional/abc_rpc_avalancheproof.py b/test/functional/abc_rpc_avalancheproof.py --- a/test/functional/abc_rpc_avalancheproof.py +++ b/test/functional/abc_rpc_avalancheproof.py @@ -187,14 +187,18 @@ self.stop_node(0) + init_error_msg = "Error: Failed to initialize avalanche" + debug_msg_head = "Failed basic avaproof verification: " + def check_proof_init_error(proof, message): - node.assert_start_raises_init_error( - self.extra_args[0] + [ - "-avaproof={}".format(proof), - "-avamasterkey=cND2ZvtabDbJ1gucx9GWH6XT9kgTAqfb6cotPt5Q5CyxVDhid2EN", - ], - expected_msg="Error: " + message, - ) + with node.assert_debug_log([debug_msg_head + message]): + node.assert_start_raises_init_error( + self.extra_args[0] + [ + "-avaproof={}".format(proof), + "-avamasterkey=cND2ZvtabDbJ1gucx9GWH6XT9kgTAqfb6cotPt5Q5CyxVDhid2EN", + ], + expected_msg=init_error_msg, + ) check_proof_init_error(no_stake, "the avalanche proof has no stake") @@ -207,13 +211,15 @@ # The too many utxos case creates a proof which is that large that it # cannot fit on the command line append_config(node.datadir, ["avaproof={}".format(too_many_utxos)]) - node.assert_start_raises_init_error( - self.extra_args[0] + [ - "-avamasterkey=cND2ZvtabDbJ1gucx9GWH6XT9kgTAqfb6cotPt5Q5CyxVDhid2EN", - ], - expected_msg="Error: the avalanche proof has too many utxos", - match=ErrorMatch.PARTIAL_REGEX, - ) + with node.assert_debug_log( + [debug_msg_head + "the avalanche proof has too many utxos"]): + node.assert_start_raises_init_error( + self.extra_args[0] + [ + "-avamasterkey=cND2ZvtabDbJ1gucx9GWH6XT9kgTAqfb6cotPt5Q5CyxVDhid2EN", + ], + expected_msg=init_error_msg, + match=ErrorMatch.PARTIAL_REGEX, + ) if __name__ == '__main__':