diff --git a/src/avalanche/processor.cpp b/src/avalanche/processor.cpp --- a/src/avalanche/processor.cpp +++ b/src/avalanche/processor.cpp @@ -249,8 +249,21 @@ } } - // Generate the delegation to the session key. DelegationBuilder dgb(peerData->proof); + + if (argsman.IsArgSet("-avadelegation")) { + Delegation dg; + CDataStream stream(ParseHex(argsman.GetArg("-avadelegation", "")), + SER_NETWORK, 0); + stream >> dg; + + if (!dgb.importDelegation(dg)) { + error = _("the supplied avalanche delegation is invalid"); + return nullptr; + } + } + + // Generate the delegation to the session key. if (sessionKey.GetPubKey() != peerData->proof.getMaster()) { dgb.addLevel(masterKey, sessionKey.GetPubKey()); } diff --git a/src/init.cpp b/src/init.cpp --- a/src/init.cpp +++ b/src/init.cpp @@ -1227,6 +1227,12 @@ strprintf("Mandatory cooldown between two avapoll (default: %u)", AVALANCHE_DEFAULT_COOLDOWN), ArgsManager::ALLOW_ANY, OptionsCategory::AVALANCHE); + argsman.AddArg( + "-avadelegation", + "Avalanche proof delegation to the master key used by this node " + "(default: none). Should be used in conjunction with -avaproof and " + "-avamasterkey", + ArgsManager::ALLOW_ANY, OptionsCategory::AVALANCHE); argsman.AddArg("-avaproof", "Avalanche proof to be used by this node (default: none)", ArgsManager::ALLOW_ANY, OptionsCategory::AVALANCHE); diff --git a/test/functional/abc_p2p_avalanche.py b/test/functional/abc_p2p_avalanche.py --- a/test/functional/abc_p2p_avalanche.py +++ b/test/functional/abc_p2p_avalanche.py @@ -7,6 +7,7 @@ from test_framework.avatools import get_stakes from test_framework.key import ( + bytes_to_wif, ECKey, ECPubKey, ) @@ -351,15 +352,40 @@ int(node.getnetworkinfo()['localservices'], 16) & NODE_AVALANCHE, NODE_AVALANCHE) - self.log.info("Test the avahello signature") - quorum = get_quorum() - poll_node = quorum[0] + def check_avahello(args): + # Restart the node with the given args + self.restart_node(0, self.extra_args[0] + args) - avahello = poll_node.wait_for_avahello().hello + quorum = get_quorum() + poll_node = quorum[0] - avakey.set(bytes.fromhex(node.getavalanchekey())) - assert avakey.verify_schnorr( - avahello.sig, avahello.get_sighash(poll_node)) + avahello = poll_node.wait_for_avahello().hello + + avakey.set(bytes.fromhex(node.getavalanchekey())) + assert avakey.verify_schnorr( + avahello.sig, avahello.get_sighash(poll_node)) + + self.log.info( + "Test the avahello signature with a generated delegation") + check_avahello([ + "-avaproof={}".format(proof), + "-avamasterkey=cND2ZvtabDbJ1gucx9GWH6XT9kgTAqfb6cotPt5Q5CyxVDhid2EN" + ]) + + master_key = ECKey() + master_key.generate() + delegation = node.delegateavalancheproof( + proof, + bytes_to_wif(privkey.get_bytes()), + master_key.get_pubkey().get_bytes().hex(), + ) + + self.log.info("Test the avahello signature with a supplied delegation") + check_avahello([ + "-avaproof={}".format(proof), + "-avadelegation={}".format(delegation), + "-avamasterkey={}".format(bytes_to_wif(master_key.get_bytes())), + ]) if __name__ == '__main__': 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 @@ -237,6 +237,23 @@ match=ErrorMatch.PARTIAL_REGEX, ) + self.log.info("Bad delegation should be rejected at startup") + + def check_delegation_init_error(delegation, message): + node.assert_start_raises_init_error( + self.extra_args[0] + [ + "-avadelegation={}".format(delegation), + "-avaproof={}".format(proof), + "-avamasterkey={}".format( + bytes_to_wif(privkey.get_bytes())), + ], + expected_msg="Error: " + message, + ) + + bad_proof_id = AvalancheDelegation() + check_delegation_init_error(bad_proof_id.serialize().hex(), + "the supplied avalanche delegation is invalid") + if __name__ == '__main__': AvalancheProofTest().main()