ChainLaunch

Pro Feature

Pro Sharing — P2P Resource Exchange

Pro Sharing requires ChainLaunch Pro. Learn more about Pro features.

ChainLaunch Pro Feature

Pro Sharing requires ChainLaunch Pro. Learn more about Pro features.

Pro Sharing is a peer-to-peer protocol that lets two or more ChainLaunch Pro instances exchange resources directly — keys, networks, chaincode, and governance proposals — without a central authority. It's the foundation for true multi-organization consortiums where every party runs their own ChainLaunch.

For just sharing node connection metadata (IP/port/cert), see Node Sharing. This page covers the broader P2P system that builds on top of it.

What you can share

Resource Direction Use case
Keys A → B A generates an MSP signing key in their HSM and shares the public material so B can include them in a channel config.
Networks (Fabric & Besu) A → B A defines a network template; B receives an invitation, accepts it, and joins as a participating org.
Chaincode A → B Source code, package, or installed chaincode is shared so all orgs run identical bytecode.
Configuration proposals A → B (multi-sig) A drafts a channel-config update; signers in B and C approve before A submits.
Node metadata bidirectional IP/port/TLS-cert info — see Node Sharing.

What never leaves a host: private keys (only public material is exchanged), database contents, audit logs, and any data on chain.

Architecture

Pro Sharing rides on a WebSocket-based mesh between paired instances:

┌──────────────────┐         WSS (mTLS)        ┌──────────────────┐
│  ChainLaunch A   │ ◄─────────────────────────► │  ChainLaunch B   │
│  pkg/pro         │     pro_shares + dual-      │  pkg/pro         │
│  pkg/communica…  │     table receiver pattern  │  pkg/communica…  │
└──────────────────┘                              └──────────────────┘
        │                                                  │
        ▼                                                  ▼
   pro_shares ─────► connection_items ─────► connected_peers

Each paired peer is a row in connected_peers. Every shared resource gets a row in pro_shares plus a row in a resource-specific table (e.g. received_keys, received_networks). The connection_id column on every share links back to the originating peer for audit and revocation.

Step 1 — Pair two instances

Pairing creates a mutual-TLS WebSocket trust link. Use the CLI on either instance:

# Instance A — generate an invitation
chainlaunch nodesharing generate-node-invitation --bidirectional
# → Invitation JWT: eyJhbGciOi...
# Instance B — accept it
chainlaunch nodesharing accept-node-invitation \
  --invitation_jwt "eyJhbGciOi..."
# → Connected peer #1 ✓

Bidirectional pairings let both sides see each other's resources. One-way pairings restrict the flow to A → B only. The full mechanics — including external URL setup so the WebSocket callback works behind NAT — are in Node Sharing.

Verify the pair under Settings → Connected Peers or:

chainlaunch nodesharing list-connected-peers

Step 2 — Share keys

Pick a key (database-backed, AWS KMS, or HashiCorp Vault) and share it:

chainlaunch pro share-key --key_id 42 --peer_id 1 \
  --metadata 'Org2 MSP signing key'

The peer receives an entry in their Inbox → Shared Keys. They can:

  • Accept — the key is persisted as a received_keys row, with the public material visible everywhere a local key would be (network configs, chaincode endorsements, MSP definitions).
  • Reject — the share is marked rejected and an audit event is appended on both sides.

Inbox / actions:

# Keys shared with me
chainlaunch pro get-keys-shared-with-me
 
# Accept (or otherwise process) a shared key
chainlaunch pro receive-key --shareId 17

Only public key material crosses the wire. Private keys remain in the originating ChainLaunch (or the underlying HSM/Vault). See Vault and AWS KMS for HSM details.

Step 3 — Share a Fabric or Besu network

Share an entire network — including consortium definition, channel config, and orderer endpoints:

# Fabric
chainlaunch pro share-network --networkId 5 --recipients 1,2
 
# Besu
chainlaunch pro share-besu-network --networkId 7 --recipients 1

The receiver sees the share under Networks → Shared with me:

# List
chainlaunch pro list-shared-networks
 
# Inspect
chainlaunch pro get-shared-network --networkId 5
 
# Accept (joins the network with the proposed role)
chainlaunch pro accept-shared-network --shareId {shareId}
 
# Reject
chainlaunch pro reject-shared-network --shareId {shareId}
 
# Remove a previously accepted share
chainlaunch pro delete-shared-network --shareId {shareId}

On accept, the receiver's ChainLaunch:

  1. Imports the network definition into its local DB.
  2. Joins the channel(s) using local nodes (or external nodes — see Node Sharing).
  3. Subscribes to live events for that channel and starts indexing.

Step 4 — Share chaincode

Sharing chaincode keeps all orgs running identical bytecode. You can share at three levels:

Level What's exchanged
Source Original source tree — receiver builds locally
Package Pre-built .tar.gz chaincode package
Installed Reference to an already-installed chaincode for cross-instance discovery
chainlaunch pro share-chaincode \
  --chaincodeId 12 --recipients 1,2 \
  --version 1.0 --sequence 1 \
  --dockerImage kfsoftware/external-chaincode:v1.0

Receiver inbox:

chainlaunch pro list-shared-chaincodes
chainlaunch pro get-shared-chaincode --chaincodeId {chaincodeId}

After accept, the chaincode shows up in the receiver's chaincode list as Source: shared from Org A. Lifecycle events (install, approve, commit) for that chaincode are mirrored back to the source org via the audit channel.

Step 5 — Share configuration proposals (multi-sig governance)

For any change that requires multiple-org approval (Fabric channel-config updates, Besu validator rotation), use a shared configuration proposal:

chainlaunch pro share-config-proposal \
  --proposalId proposal-add-org3 \
  --channelName mychannel \
  --recipients 1,2 \
  --metadata 'Add Org3 to channel mychannel'

Each receiver:

  1. Reviews the proposed config in Governance → Pending Proposals.
  2. Signs (or rejects) under their own RBAC rules.
  3. Once the policy threshold is reached, the originator can submit the signed update.

For the full governance workflow, including reviewer assignment, expiration, and audit, see Governance and automating_governance.md.

Database model (for operators)

If you operate ChainLaunch and need to debug a share that "looks stuck":

Table Role
connected_peers One row per paired instance. Holds the cached external URL and pairing JWT material.
pro_shares The central log of every share event (resource type, status, timestamps). Use it to answer "did this share actually reach B?"
received_keys Keys received from other peers.
connection_items Peer nodes (Fabric peers/orderers, Besu validators) referenced by shares.
pro_share_status enum pending, accepted, rejected, revoked, expired.
-- All shares originating from this instance
SELECT id, resource_type, target_peer_id, status, created_at
FROM pro_shares
WHERE direction = 'outgoing'
ORDER BY created_at DESC LIMIT 50;

Troubleshooting

Symptom Likely cause Fix
"Peer offline" on share The other instance can't be reached on its external URL Verify each instance was started with --external-url https://... and that URL resolves & TLS-validates from the other side.
Share stuck in pending Receiver hasn't connected since share was issued Check connected_peers.last_seen_at — peers reconnect on a heartbeat.
Network share accepted but channel doesn't appear Receiver has no nodes assigned to that channel yet After accepting, run Networks → (the shared network) → Add Nodes on the receiver.
403 forbidden on share Caller lacks PRO_SHARE_CREATE permission Grant the user OPERATOR or ADMIN role. See RBAC.
Chaincode share at package level fails Package size exceeds the configured WS frame limit Either use source level (smaller) or raise the per-instance --max-share-size flag.
Receiver sees a key but can't endorse They accepted the share but the local MSP isn't using that key as signing identity Edit the local MSP definition to reference the received key by its share ID.

Security model

  • Pairing: Both sides hold each other's pinned TLS cert hash from the invitation JWT. A man-in-the-middle proxy can't insert itself after pairing.
  • Authorization: RBAC permissions gate every endpoint (PRO_SHARE_CREATE, PRO_SHARE_ACCEPT, PRO_SHARE_REVOKE).
  • Replay: Each share has a monotonic share_id per peer; receivers reject duplicates.
  • Audit: Every share, accept, reject, and revoke is recorded in Audit Logging on both sides.
  • Revocation: An originator can DELETE /pro/shared-networks/{shareId} (and equivalent for keys/chaincode) at any time. The receiver retains the resource if already accepted but is notified that the source org has revoked the link — useful for offboarding a partner without breaking active workloads.

Best practices

  • Pair bidirectionally for active partnerships, one-way for read-only observers.
  • Use one connected peer per partner org, not per environment — environment isolation should come from separate channels, not separate peers.
  • Encrypt the master key with Encryption at Rest so the pairing material on disk is safe from cold-storage attacks.
  • Audit pro_shares weekly during early consortium ramp-up — it's the fastest way to spot mis-shares before they become governance issues.
  • Tag shares with the change ticket in purpose so audit trails are self-explanatory months later.

Next steps