Uma infraestrututa para construir uma nova internet
  • Go 99.1%
  • Shell 0.5%
  • Assembly 0.3%
Find a file
Ruben M. Damião 477b24dc40 node/swell+swell: authenticate block broadcasts and cut duplicate post-BFT fetches
Leader-to-validator block broadcasts travelled without an application-layer
  signature — only the hop-by-hop socket auth protected them, so any relay
  that forwarded a broadcast could have injected forged block content at the
  same height/hash. Carry the leader's Ed25519 signature over the block hash
  in the broadcast wire format and verify it against the round-0 leader token
  on receive. The receiver also caches the signature so, once BFT produces
  ProofOfConsensus, the sealed block can be assembled locally — skipping the
  round-trip FetchBlock the follower was doing on every height.

  HandleConsensusResult now prefers the cached broadcast, waits 50ms if it
  hasn't arrived yet, and only then falls back to FetchBlock. On localhost
  the BFT result and the leader's broadcast race in the microsecond range,
  so the wait lets the broadcast path win most heights. The short-circuit
  for `height <= LastCommitHeight` covers the observer-promotion window
  where the upstream-applied block and a concurrent BFT result would
  otherwise trip AddSealedBlock's InvalidHeight check.

  Also serialize Send+Read on peerConn via a new reqMu + sendAndRead helper:
  two concurrent Reads on the same BufferedChannel could strand one forever
  because the dispatcher only tracks a single waiter. This showed up as the
  proactive fetch and the consensus-result fetch fighting over the same
  leader connection. With the broadcast path carrying the seal, the fetch
  fallback is rarer but still races the proactive loop when it fires.

  Drops the double PutLargeByteArray wrap in the broadcast wire format that
  the receiver never unwrapped — the likely source of the intermittent
  "block broadcast hash mismatch" warning.

  TestEndToEnd_ObserverPromotion body now passes end-to-end. The remaining
  FAIL at timeout is the pre-existing Node.Stop() hang in wg.Wait (sync
  connection goroutines parked in conn.Read don't wake on stopChan close);
  that is a separate issue.
2026-04-22 22:14:30 -03:00
chain - [bft_observer_promotion_progress.md](bft_observer_promotion_progress.md) — Fix do TestEndToEnd_ObserverPromotion: 4 bugs corrigidos, ainda falha entre height 40 e 50 2026-04-18 08:32:52 -03:00
cmd chain+node: freeze checksum snapshot and pin port offsets 2026-04-15 22:37:09 -03:00
crypto Migrating existing votuporanga references to brisa. Filling the gap on overall documentation 2026-04-05 21:13:04 -03:00
docker swell/brisa: per-window network, brisa package, weighted BFT quorum 2026-04-09 14:53:18 -03:00
docs state+node/swell: credit/debit stake on deposit/withdraw and lock it while active 2026-04-16 14:41:48 -03:00
network chain+swell+network: persistent BFT listener and per-height validator dispatch 2026-04-17 20:50:15 -03:00
node node/swell+swell: authenticate block broadcasts and cut duplicate post-BFT fetches 2026-04-22 22:14:30 -03:00
papirus chain+state: stake-weighted lottery with unpredictable seed, FileStore tests, and state checksum docs 2026-04-13 16:54:54 -03:00
scripts Migrating existing votuporanga references to brisa. Filling the gap on overall documentation 2026-04-05 21:13:04 -03:00
state state+node/swell: credit/debit stake on deposit/withdraw and lock it while active 2026-04-16 14:41:48 -03:00
swell node/swell+swell: authenticate block broadcasts and cut duplicate post-BFT fetches 2026-04-22 22:14:30 -03:00
testnet This is a rewrite of the codebase at github.com/freehandle/breeze together with github.com/freehandle/papirus 2026-04-02 23:29:19 -03:00
util chain+swell+network: persistent BFT listener and per-height validator dispatch 2026-04-17 20:50:15 -03:00
.gitignore sync: ship validator pools and harden post-sync startup 2026-04-14 21:56:24 -03:00
brisa.go Migrating existing votuporanga references to brisa. Filling the gap on overall documentation 2026-04-05 21:13:04 -03:00
brisa_test.go Migrating existing votuporanga references to brisa. Filling the gap on overall documentation 2026-04-05 21:13:04 -03:00
docker-compose.poa.yml Migrating existing votuporanga references to brisa. Filling the gap on overall documentation 2026-04-05 21:13:04 -03:00
docker-compose.yml swell/brisa: per-window network, brisa package, weighted BFT quorum 2026-04-09 14:53:18 -03:00
Dockerfile swell/brisa: per-window network, brisa package, weighted BFT quorum 2026-04-09 14:53:18 -03:00
go.mod This is a rewrite of the codebase at github.com/freehandle/breeze together with github.com/freehandle/papirus 2026-04-02 23:29:19 -03:00
go.sum This is a rewrite of the codebase at github.com/freehandle/breeze together with github.com/freehandle/papirus 2026-04-02 23:29:19 -03:00
hqq chain+state: stake-weighted lottery with unpredictable seed, FileStore tests, and state checksum docs 2026-04-13 16:54:54 -03:00
LICENSE relay+social: window-aware checksum confirm, dynamic pool update, and automatic rollback 2026-04-12 16:57:45 -03:00
Makefile swell/brisa: per-window network, brisa package, weighted BFT quorum 2026-04-09 14:53:18 -03:00
README.md README.md instructions 2026-04-13 19:06:45 -03:00
TESTNET.md Migrating existing votuporanga references to brisa. Filling the gap on overall documentation 2026-04-05 21:13:04 -03:00

Brisa

Brisa is a Byzantine Fault Tolerant blockchain with stake-weighted validator selection, window-based checksum consensus, and coordinated disaster recovery.

Building

make build     # builds all binaries into the project root
make test      # runs all tests
make clean     # removes built binaries

Individual binaries:

make brisa-node
make relay-node
make gateway-node
make poa-server
make wallet

Node Types

Brisa networks consist of four node types. Each is a separate binary in cmd/.

Node Binary Role
Validator brisa-node Participates in BFT consensus, produces blocks
Relay relay-node Distributes blocks from validators to clients
Gateway gateway-node Accepts user actions, confirms them against validators
PoA poa-server Single-authority node (development / private chains)

A minimal production network needs 3+ validators (BFT requires 2/3+1) and at least 1 relay for block distribution.

Deploying a Validator Network

1. Generate keystores

On each validator machine:

./brisa-node -gen-keystore -keystore validator.json
# Enter a password, note the printed token (64-char hex)

2. Create configuration

Generate a sample config and edit it:

./brisa-node -gen-config   # writes brisa-node.example.yaml
cp brisa-node.example.yaml brisa-node.yaml

Each validator's config lists all other validators:

node:
  db_path: "./data"
  genesis: false               # true ONLY on the first node, first start

network:
  consensus_port: 9000
  sync_port: 9100              # defaults to consensus_port + 100
  action_gateway: ":9001"
  web_admin: ":8080"

credentials:
  keystore: "./validator.json"
  password_env: "BRISA_PASSWORD"

validators:
  - token: "<validator-2-token>"
    addr: "192.168.1.11:9000"
  - token: "<validator-3-token>"
    addr: "192.168.1.12:9000"

protocol:
  window_slots: 300            # 5 min windows @ 1 block/s
  num_validators: 15
  bft_pool_size: 10
  block_reward: 10
  minimum_stake: 1000

3. Start the genesis node

Exactly one node starts with genesis: true to create the genesis block. This records the genesis timestamp; all other nodes receive it via sync.

export BRISA_PASSWORD=<password>
./brisa-node -config brisa-node.yaml

After the first start, set genesis: false for all subsequent runs.

4. Start remaining validators

Each additional validator either:

  • Syncs from a peer (recommended for first start):
node:
  sync_peer: "192.168.1.10:9100"
  sync_peer_token: "<genesis-node-token>"
  • Or connects directly if the network is young enough that replay from genesis is fast.
export BRISA_PASSWORD=<password>
./brisa-node -config brisa-node.yaml

5. NTP clock correction

By default, validators query pool.ntp.org at startup for clock correction. All validators must agree on block slot times, so NTP is strongly recommended.

./brisa-node -ntp-server pool.ntp.org    # default
./brisa-node -no-ntp                      # use system clock (testing only)

Deploying a Relay Node

Relays distribute blocks from validators to downstream clients (gateways, social nodes, other relays). They do not participate in consensus.

./relay-node -example > relay.yaml
# Edit relay.yaml
export RELAY_PASSWORD=<password>
./relay-node -config relay.yaml

Minimal config:

relay:
  listen: ":9200"
  cache_size: 100

credentials:
  keystore: "./relay.json"
  password_env: "RELAY_PASSWORD"
  generate: true

upstreams:
  - token: "<validator-token>"
    addr: "192.168.1.10:9100"

History node mode

Set data_dir to persist blocks to disk. With bootstrap_history: true, the relay fetches missing history from upstreams at startup.

relay:
  listen: ":9200"
  cache_size: 200
  data_dir: "./relay-blocks"
  bootstrap_history: true

Size cache_size for at least 2 consensus windows (2 × window_slots) to ensure rollbacks never reach disk.

Deploying a Gateway Node

Gateways accept user actions (transactions), forward them to validators, and confirm them by watching the block stream. They are the entry point for application clients.

./gateway-node -example > gateway.yaml
# Edit gateway.yaml
export GW_PASSWORD=<password>
./gateway-node -config gateway.yaml
gateway:
  listen: ":9300"
  min_confirmations: 1
  confirmation_depth: 3

credentials:
  keystore: "./gateway.json"
  password_env: "GW_PASSWORD"
  generate: true

validators:
  - token: "<validator-token>"
    sync_addr: "192.168.1.10:9100"
    action_addr: "192.168.1.10:9001"

The gateway must be listed in each validator's authorized_nodes for action submission to be accepted.

Network Topology

                    ┌──────────┐
                    │ Validator│
              ┌────►│    1     │◄────┐
              │     └──────────┘     │
              │          ▲           │
         consensus    consensus   consensus
              │          │           │
              ▼          ▼           ▼
        ┌──────────┐ ┌──────────┐ ┌──────────┐
        │ Validator│ │ Validator│ │ Validator│
        │    2     │ │    3     │ │    ...   │
        └────┬─────┘ └────┬─────┘ └────┬─────┘
             │sync        │sync        │sync
             ▼            ▼            ▼
        ┌─────────────────────────────────┐
        │          Relay Node(s)          │
        └──────────┬──────────┬───────────┘
                   │          │
              ┌────▼───┐ ┌───▼────┐
              │Gateway │ │ Social │
              │  Node  │ │  Node  │
              └────────┘ └────────┘

Validators form a fully-connected BFT mesh on the consensus port. Each validator exposes a sync port for relay subscriptions. Relays fan out blocks to gateways, social nodes, and other relays.

Disaster Recovery

When the entire network stops (no BFT quorum can form), operators coordinate a restart out-of-band. Each operator agrees on:

  1. Snapshot hash — which snapshot to restart from
  2. Restart time — when consensus begins (RFC 3339)
  3. Validator pool — who participates in the new network

Add to each validator's config:

disaster_recovery:
  snapshot_hash: "a1b2c3..."
  restart_time: "2026-04-15T14:00:00Z"
  pool:
    - "<validator-1-token>"
    - "<validator-2-token>"
    - "<validator-3-token>"

Start each validator before restart_time. The node loads its local snapshot, validates the hash, and waits until the agreed time to begin consensus.

Relays do not need DR configuration — they receive a SyncMsgDRReset from validators on reconnect, clear their cache, and propagate the signal downstream automatically.

After successful restart, remove the disaster_recovery section from config for subsequent normal runs.

Recovery Levels

Outage Duration Mechanism Manual?
Single node down Any BFT tolerance (2/3+1 continue) No
Short network stall < 1 window Skip blocks + stagnation No
Medium outage > 1 window Auto clock recovery (maybeAddRecoveryEntry) No
Checksum divergence Window boundary Rollback to last checkpoint No
Full network stop Any Disaster recovery (coordinated restart) Yes

Further Reading