Page MenuHomePhabricator

D9364.diff
No OneTemporary

D9364.diff

diff --git a/src/net.h b/src/net.h
--- a/src/net.h
+++ b/src/net.h
@@ -1000,6 +1000,7 @@
AvalancheState() {}
avalanche::Delegation delegation;
+ SchnorrSig sig;
};
// m_avalanche_state == nullptr if we're not using avalanche with this peer
diff --git a/src/net_processing.cpp b/src/net_processing.cpp
--- a/src/net_processing.cpp
+++ b/src/net_processing.cpp
@@ -3979,11 +3979,30 @@
pfrom.m_avalanche_state = std::make_unique<CNode::AvalancheState>();
}
+ // Store the delegation and signature for later verification.
CHashVerifier<CDataStream> verifier(&vRecv);
- avalanche::Delegation &delegation = pfrom.m_avalanche_state->delegation;
- verifier >> delegation;
+ verifier >> pfrom.m_avalanche_state->delegation;
+ SchnorrSig &sig = pfrom.m_avalanche_state->sig;
+ verifier >> sig;
+ return;
+ }
+
+ if (msg_type == NetMsgType::AVAPROOF) {
+ if (!pfrom.m_avalanche_state) {
+ // We don't support the case of a AVAPROOF received before
+ // the AVAHELLO for now. Ideally we should store all the data
+ // received, and process it after both messages were received,
+ // no matter which order they reach us.
+ return;
+ }
+ // Read the proof.
avalanche::Proof proof;
+ vRecv >> proof;
+
+ // Verify the delegation
+ const avalanche::Delegation &delegation =
+ pfrom.m_avalanche_state->delegation;
avalanche::DelegationState state;
CPubKey pubkey;
if (!delegation.verify(state, proof, pubkey)) {
@@ -3991,8 +4010,20 @@
return;
}
- SchnorrSig sig;
- verifier >> sig;
+ // Use the delegated pubkey to verify the signature received
+ // in the avahello message.
+ const uint256 hash = g_avalanche->buildRemoteSighash(&pfrom);
+
+ if (!pubkey.VerifySchnorr(hash, pfrom.m_avalanche_state->sig)) {
+ Misbehaving(pfrom, 100, "invalid-avalanche-handshake");
+ return;
+ }
+
+ // TODO:
+ // - store the proof in a proofpool
+ // - if IBD is finished, add the node
+ // - if IBD, add the node later, when we can check its proof
+ return;
}
if (msg_type == NetMsgType::AVAPOLL) {
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
@@ -3,6 +3,7 @@
# Distributed under the MIT software license, see the accompanying
# file COPYING or http://www.opensource.org/licenses/mit-license.php.
"""Test the resolution of forks via avalanche."""
+from io import BytesIO
import random
from test_framework.avatools import get_stakes
@@ -12,10 +13,13 @@
)
from test_framework.mininode import P2PInterface, mininode_lock
from test_framework.messages import (
+ AvalancheProof,
AvalancheResponse,
AvalancheVote,
CInv,
+ msg_avahello,
msg_avapoll,
+ msg_avaproof,
msg_tcpavaresponse,
NODE_AVALANCHE,
NODE_NETWORK,
@@ -104,6 +108,11 @@
with mininode_lock:
return self.avapolls.pop(0) if len(self.avapolls) > 0 else None
+ def send_avahello(self, hello):
+ msg = msg_avahello()
+ msg.hello = hello
+ self.send_message(msg)
+
def wait_for_avahello(self, timeout=5):
wait_until(
lambda: self.avahello is not None,
@@ -113,6 +122,11 @@
with mininode_lock:
return self.avahello
+ def send_avaproof(self, proof):
+ msg = msg_avaproof()
+ msg.proof = proof
+ self.send_message(msg)
+
class AvalancheTest(BitcoinTestFramework):
def set_test_params(self):
@@ -350,8 +364,7 @@
])
self.log.info("Test the avahello signature")
- quorum = get_quorum()
- poll_node = quorum[0]
+ poll_node = get_node()
avahello = poll_node.wait_for_avahello().hello
@@ -359,6 +372,21 @@
assert avakey.verify_schnorr(
avahello.sig, avahello.get_sighash(poll_node))
+ self.log.info("Test banning behavior on invalid avahello signature")
+ poll_node = get_node()
+ with self.nodes[0].assert_debug_log(
+ ['Misbehaving',
+ '(0 -> 100) BAN THRESHOLD EXCEEDED: invalid-avalanche-handshake']):
+ # We use the same avahello that the node previously sent to
+ # another p2p interface. The signature will not correspond to
+ # the expected message for this peer.
+ poll_node.send_avahello(avahello)
+ # The signature is checked when the delegation can be checked,
+ # after receiving a proof.
+ proof_obj = AvalancheProof()
+ proof_obj.deserialize(BytesIO(bytes.fromhex(proof)))
+ poll_node.send_avaproof(proof_obj)
+
if __name__ == '__main__':
AvalancheTest().main()

File Metadata

Mime Type
text/plain
Expires
Thu, Feb 6, 15:44 (16 h, 41 m)
Storage Engine
blob
Storage Format
Raw Data
Storage Handle
5082635
Default Alt Text
D9364.diff (4 KB)

Event Timeline