This project explores how to consolidate PBFT-family consensus messages into a single canonical representation and then re-materialize them into the original wire format of each blockchain client. The current implementation centers on the CometBFT pipeline, and we are extending the same canonical model to cover Kaia IBFT and Hyperledger Besu (IBFT/QBFT) so that messages can be translated across engines without losing intent.
- Convert PBFT-style consensus messages from multiple engines into a common
CanonicalMessageformat. - Inspect, mutate, or simulate the canonical data for research and fault-injection experiments.
- Serialize the modified canonical messages back into chain-specific vote or proposal objects for validation or reinjection.
- Canonical message model: The
message/abstractionpackage defines the shared structure that captures proposal, vote, precommit, and related PBFT semantics. - Chain-specific mappers: Adapters in
cometbft/,kaia/, andhyperledger/besu/implement theMapperinterface (ToCanonical/FromCanonical) to bridge native data structures with the canonical model. - Raw message wrappers: On-chain WAL entries, RPC responses, or network packets can be wrapped into
RawConsensusMessagefor uniform processing. - Conversion simulators: Utilities under
cmd/demodemonstrate how real CometBFT messages round-trip through the canonical bridge. - Codec experiments: The
message/codecpackage contains JSON, Protobuf, RLP, and other serialization experiments that stress-test interoperability.
.
├── cmd/ # CLI tools and conversion demos
│ └── demo/ # CometBFT message simulator and round-trip checker
├── cometbft/ # CometBFT mapper and consensus adapters
├── hyperledger/besu/ # Besu IBFT/QBFT mapper (work in progress)
├── kaia/ # Kaia IBFT mapper (work in progress)
├── message/ # Canonical models, codecs, and protobuf definitions
└── examples/ # Sample WAL-derived consensus messages
go version # Go 1.21 or later is recommended
protoc --versiongit clone <repository-url>
cd Byzantine-simulate
go mod tidygo run cmd/byzproxy/main.go \
--listen tcp://0.0.0.0:26656 \
--upstream tcp://127.0.0.1:26657 \
--node-key /path/to/node_key.json \
--attack double_vote \
--trigger-height 100 \
--trigger-step prevote- Bridges external peers with an upstream CometBFT validator over a secure P2P connection.
- Decodes consensus messages into their canonical form, applies the configured byzantine mutation, and re-encodes them before forwarding.
- Supports hooks to delay, drop, or duplicate envelopes once the trigger height/round/step matches.
- Exposes structured JSON logs describing each forwarded or mutated message.
Additional useful flags:
--duplicateduplicates each triggered envelope after mutation.--delay=2sdelays forwarding of triggered envelopes by two seconds.--mutate-direction=downstreamapplies mutations to traffic heading towards external peers (default is upstream).--timestamp-skew=250ms,--round-offset=1, and other canonical offsets reshape forged consensus data.
go run cmd/demo/main.go- Lists the available scenarios (
simulation,vote-batch,byzantine). -scenario=simulationstreams synthetic CometBFT messages through the canonical mapper.-scenario=vote-batchreplays fixtures fromexamples/cometbft/Vote.jsonand validates the round-trip.-scenario=byzantineforges mutated payloads via the canonical → byz-canonical → byzcomet pipeline and prints each stage of the mutation.- Actions supported by the byzantine pipeline include
double_vote,double_proposal,alter_validator,drop_signature,timestamp_skew, andnone. - Tunable flags such as
-alternate-block,-alternate-prev,-alternate-signature,-alternate-validator,-round-offset,-height-offset, and-timestamp-skewcontrol the resulting forged payloads.
Example explorations:
# Emit a conflicting prevote that bumps height/round and swaps the validator
go run cmd/demo/main.go -scenario=byzantine -action=alter_validator -alternate-validator=validator-9 -round-offset=1 -height-offset=2
# Produce a timestamp-skewed proposal with custom hashes
go run cmd/demo/main.go -scenario=byzantine -action=timestamp_skew -timestamp-skew=250ms -alternate-block=0xDEADBEEF -alternate-prev=0xFEEDFACE
# Generate a double vote while forcing an explicit signature override
go run cmd/demo/main.go -scenario=byzantine -action=double_vote -alternate-signature=fake-signatureTo script the same pipeline, use cmd/byzantine which emits JSON containing both the byz-canonical mutations and their encoded CometBFT counterparts.
go test ./...- Validates transformation logic, verification helpers, and simulator behaviors.
protoc \
--proto_path=message/proto \
--descriptor_set_out=message/proto/abstraction.protoset \
--include_imports --include_source_info \
message/proto/abstraction.proto- Collect raw data: Read WAL entries, RPC responses, or network packets and wrap them as
RawConsensusMessageobjects. - Normalize: Use a chain-specific mapper to convert the raw data into
CanonicalMessageinstances. - Analyze or mutate: Apply filtering, field edits, or re-signing steps against the canonical representation.
- Rehydrate: Serialize the modified canonical messages back into the original chain-specific structures.
- Inject or simulate: Feed the resulting messages into the consensus engine or exercise them on a controlled test network.
The CometBFT pipeline is production-ready, while Kaia and Besu adapters are being aligned with the canonical schema, signature semantics, and codec expectations.
verify_vote_conversion.md: Walkthrough of the CometBFT vote conversion experiment.verify_conversion.md: Canonical conversion rules and testing strategy overview.message/README.md: Usage notes for the codec experimentation tools.
- Open an issue to discuss new ideas or report a bug.
- Create a feature branch for your changes.
- Run
go test ./...to ensure the core suites pass. - Submit a pull request summarizing the change and test results.
Refer to the repository's license file for detailed terms.