Network Module (hierachain/network/*)
Overview
The Network module handles communication between HieraChain nodes over ZeroMQ. SecureConnectionManager provides optional CurveZMQ transport encryption, an MSP handshake, and message-signature checks. The API server's NetworkClient creates ZmqNode directly, so that path does not automatically run the manager's handshake or signature checks.
Layered Security Architecture
SecureConnectionManager provides these security components when an application uses it; they are not automatically active on every NetworkClient connection:
-
Layer 1: CurveZMQ (Transport)
Technology: Curve25519
- Encrypts the transmission between ZeroMQ sockets when configured with local transport keys and peer public keys.
- Ensures privacy and prevents eavesdropping on Web2 networks.
SecureConnectionManagergenerates a CurveZMQ keypair for its transport; the API server's separateNetworkClientuses the transport keys configured for itsZmqNode.
-
Layer 2: MSP Handshake (Identity)
Technology: Ed25519 + Certificates
- Authenticates node identity through MSP (Membership Service Provider) certificates when the handshake is run.
- Only allows nodes from valid organizations to join the network.
- 2-step Handshake process:
INITandACK. - Binds the active certificate subject and signing key to the ZeroMQ routing ID and registered organization identity.
-
Layer 3: Integrity & Replay Protection
Technology: Ed25519 + Nonce + Timestamp
- Data-message signature checks are controlled by
require_signatures; they default toFalsein base, development, and test settings, andTrueinProductionSettings. - Prevents replay attacks by checking unique Nonce and Timestamp within the allowed window (60s).
- Handshake messages have separate signature checks and carry signed
timestampandnoncefields accepted by the transport replay gate.
- Data-message signature checks are controlled by
Core Components
1. ZMQ Transport (zmq_transport.py)
Implements the asynchronous P2P model using ROUTER (for receiving) and DEALER (for sending) sockets.
- Transport: Uses asynchronous sockets; broadcasts send to registered peers sequentially.
- Identity Management: Manages node identities at the socket level for accurate routing.
- Replay buffer: Retains at most 1,000 timestamp/nonce pairs with nonce strings of at most 128 characters. When all entries are still within the 60-second window, new messages are rejected until an entry expires.
NetworkClient tracks seed and manually registered peers in the same registry. Removing a peer also closes its outbound DEALER socket. A peer is initially healthy for 60 seconds after registration; each accepted inbound message from its registered socket identity renews that period. An idle peer becomes unhealthy when status or peers are read. This health indicator does not authenticate the peer or confirm delivery of outbound messages.
If ZmqNode.start() fails, it closes the transport sockets and context before raising NetworkError. NetworkClient.start() releases a partially initialized transport and returns False; after resolving the cause, calling start() again creates a fresh transport. NetworkClient.stop() also cleans up a transport that never reached the running state and can be called repeatedly.
2. Secure Connection Manager (secure_connection.py)
Orchestrates the secure connection establishment process:
- Establish a Curve25519 encrypted channel.
- Perform Handshake to exchange and verify MSP certificates.
- Manage the list of authenticated peers (
authenticated_peers).
The API server's NetworkClient does not currently wire this manager into its ZmqNode transport.
3. Peer Trust Manager (peer_trust_manager.py)
Manages the trust level of neighboring nodes:
- Policy Enforcement: Supports
openandstrict.opentrusts peers unless they are blocklisted;strictrequires an allowlisted peer. - Peer lists: Allowlist and blocklist entries are managed explicitly; the manager does not assign reputation scores or automatically disconnect peers for spam.
- Signed messages: Invalid data-message signatures are dropped by
SecureConnectionManagerwhen signature checks are enabled.
Secure Handshake Process
sequenceDiagram
participant NodeA as Node A (Initiator)
participant NodeB as Node B (Responder)
Note over NodeA, NodeB: 1. Curve25519 Encrypted Channel Established
NodeA->>NodeB: HANDSHAKE_INIT (MSP Cert + Ed25519 Sig)
Note right of NodeB: Verify Trust Policy<br/>Verify MSP Certificate<br/>Verify Handshake Signature
NodeB-->>NodeA: HANDSHAKE_ACK (Success + Ed25519 Sig)
Note left of NodeA: Verify ACK Signature
Note over NodeA, NodeB: 2. Authenticated P2P Channel Ready
The responder echoes the HANDSHAKE_INIT nonce in the signed ACK. The initiator
accepts an ACK only while a matching outbound handshake is pending, the peer
passes the configured trust policy, and the ACK certificate is active and bound
to that peer's routing ID and signing key. A missing or mismatched CA
certificate, identity record, organization, or key is rejected.
Usage Examples
1. Initialize a Secure Node
from hierachain.network.secure_connection import SecureConnectionManager
# Initialize manager with MSP integration
secure_node = SecureConnectionManager(
node_id="node_001",
port=5001,
msp=msp_instance,
identity_mgr=identity_instance
)
async def start_configured_node() -> None:
await secure_node.start()
2. Send a Signed Message
# Automatically signs and sends over the encrypted channel
async def send_proposal() -> bool:
payload = {"event": "block_proposal", "data": {"block_index": 1}}
return await secure_node.send_secure("peer_002", payload)
P2P Configuration (Environment Variables)
| Environment Variable | Function | Recommended Value (Prod) |
|---|---|---|
HRC_P2P_TRUST_POLICY |
Trust policy | strict |
HRC_P2P_REQUIRE_SIGNATURES |
Require Ed25519 signatures | true |
HRC_P2P_PEER_ALLOWLIST |
Trusted Peer ID list | (Specific ID list) |
Related
ZeroMQ accepts frames up to 1 MiB and exactly two application frames (sender identity and body); excess frames are drained without accumulating a Python multipart list. Secure connections validate identities and signatures before retaining replay entries, with a separate 1,000-entry cache per verified peer. Plain transport requires configured peer IDs and isolates their caches; it provides no cryptographic identity guarantee. These limits do not replace upstream connection and bandwidth controls.