Skip to content

Feature/protocol workflow#267

Merged
jonasmartin merged 75 commits intodevfrom
feature/protocol-workflow
Feb 26, 2026
Merged

Feature/protocol workflow#267
jonasmartin merged 75 commits intodevfrom
feature/protocol-workflow

Conversation

@hperezrodal
Copy link
Contributor

Protocol Workflow Feature

Overview

This PR introduces a major refactoring of the protocol setup and execution workflow in BitVMX, introducing a new SetupEngine orchestration system and ProgramV2 implementation that provides better separation of concerns, improved testability, and more robust protocol initialization.

Key Features

1. SetupEngine - Protocol Setup Orchestration

Introduces a new SetupEngine that orchestrates multi-step protocol setup processes:

  • Step-based setup: Protocols define their setup steps via ProtocolHandler::setup_steps()
  • State management: Tracks step completion state across participants
  • Leader broadcast pattern: Non-leaders send data to leader, leader broadcasts to all
  • Automatic progression: Advances to next step when all participants complete current step
  • Persistent state: Setup state is saved and restored across program loads

2. ProgramV2 - Next Generation Program Implementation

New ProgramV2 implementation that:

  • Uses SetupEngine for orchestrating setup steps
  • Delegates aggregation responsibility to protocols themselves
  • Provides cleaner separation of concerns
  • Implements a cleaner state machine (New → SettingUpV2 → Monitoring → Ready)
  • Removes protocol-specific setup logic from Program layer

Key differences from Program (Legacy):

  • No prepare_aggregated_keys() - protocols handle their own aggregation
  • Uses SetupEngine to orchestrate setup steps
  • Cleaner state transitions
  • Protocol-specific setup logic lives in the protocol itself

3. AggregatedKeyProtocol

Replaces the old Collaboration flow with a new AggregatedKeyProtocol:

  • Unified approach: Single protocol for aggregated key generation (MuSig2)
  • Single participant support: Handles both single and multi-participant scenarios naturally
  • Storage in globals: Final aggregated key stored in globals under final_aggregated_key
  • No special cases: Removed single-participant bypass logic

Breaking Changes

Removed Features

  • Collaboration flow: The old Collaboration class and related methods have been removed
    • process_collaboration_message()
    • process_collaboration()
    • get_collaboration()
    • save_collaboration()
    • mark_collaboration_as_complete()
  • src/collaborate.rs: File removed

Migration Path

  • Existing programs using the legacy Program implementation continue to work
  • New programs should use setup_v2() API to leverage ProgramV2
  • Aggregated key generation now uses AggregatedKeyProtocol instead of Collaboration

Technical Details

SetupEngine Architecture

SetupEngine
├── Steps: Defined by ProtocolHandler::setup_steps()
├── State: Pending → ReadyToSend → WaitingForParticipants → Complete
├── Data Storage: Stored in globals with step-specific keys
└── Progression: Automatic when all participants complete current step

ProgramV2 State Machine

New
  ↓
SettingUpV2 (SetupEngine orchestrates setup steps)
  ↓
Monitoring (Blockchain monitoring setup)
  ↓
Ready (Protocol ready for execution)

Leader Broadcast Flow

Participant 1 (Non-leader) ──┐
                             ├──> Leader ──> Broadcast ──> All Participants
Participant 2 (Non-leader) ──┘

Testing

New Tests

  • test_aggregated_key: Multi-participant aggregated key generation test
  • test_aggregated_key_single_participant: Single-participant scenario test

Test Improvements

  • Improved Docker container cleanup to prevent conflicts between sequential test runs
  • Better error handling in test infrastructure
  • Tests validate that all participants compute the same aggregated key

Files Changed

New Files

  • src/program/setup/setup_engine.rs - SetupEngine implementation
  • src/program/setup/setup_step.rs - Setup step definitions
  • src/program/program_v2.rs - ProgramV2 implementation
  • src/program/protocols/aggregated_key.rs - AggregatedKeyProtocol
  • tests/aggregated_key.rs - Aggregated key tests

Modified Files

  • src/bitvmx.rs - Updated to support ProgramV2, removed Collaboration flow
  • src/types.rs - Updated message types, added ProgramVersion enum
  • src/api.rs - Added setup_v2() method
  • src/client.rs - Updated API calls to match new signatures
  • src/main.rs - Updated tick() return type handling
  • tests/common/mod.rs - Improved Docker container cleanup

Removed Files

  • src/collaborate.rs - Replaced by AggregatedKeyProtocol

Performance Considerations

  • Reduced message overhead: Leader broadcast pattern reduces total messages
  • Better state management: SetupEngine prevents duplicate state saves
  • Cleaner code paths: Removed special-case handling improves maintainability

Backward Compatibility

  • Legacy Program implementation remains available
  • Existing programs continue to work unchanged
  • New programs can opt into ProgramV2 via setup_v2() API
  • Both implementations can coexist in the same BitVMX instance

Future Work

  • Migrate more protocols to use SetupEngine
  • Deprecate legacy Program implementation
  • Add more comprehensive tests for edge cases

Checklist

  • Code compiles without errors
  • All tests pass (when run sequentially)
  • Documentation updated where necessary
  • Breaking changes documented
  • Migration path provided
  • Backward compatibility maintained

Related Issues

This PR addresses the need for:

  • Better protocol setup orchestration
  • Cleaner separation of concerns
  • More robust multi-participant coordination
  • Improved testability of protocol setup flows

Add a new setup module providing a framework for managing multi-party
protocol setup steps. Includes SetupStep trait for step lifecycle
management, StepPhase enum for state tracking, ExchangeConfig for
exchange configuration, and template implementations for keys, nonces,
and signatures steps
Add a new setup orchestration system with SetupEngine that provides a
state machine-based approach to managing multi-party protocol setup steps.
This enables cleaner separation of concerns and allows protocols to opt-in
gradually to the new system.
This is the next generation Program implementation that:
- Uses SetupEngine for orchestrating setup steps
- Delegates aggregation responsibility to protocols
- Provides cleaner separation of concerns
- Allows protocols to opt-in gradually via UsesSetupSteps trait
…ndler

Remove the UsesSetupSteps trait and integrate setup steps functionality directly into the ProtocolHandler trait. This simplifies the architecture
by eliminating an extra trait layer
- Removed use_broadcasting from ExchangeConfig struct and Default impl
- Updated exchange_config() in KeysStep, NoncesStep, and SignaturesStep
Rename the collaboration protocol to aggregated key protocol to better reflect its purpose of generating aggregated MuSig2 keys.
Rename the template_steps directory to steps for better clarity and consistency.
Add default implementations for optional protocol methods in the ProtocolHandler trait to reduce boilerplate code in simple protocols like AggregatedKeyProtocol.
Replace manual impl Default implementations with #[derive(Default)] for KeysStep, NoncesStep, and SignaturesStep. These are unit structs where the manual implementation was redundant, as it only called new().
…on.rs structure

- Remove unused UTXO funding section that was not being used in the test
- Remove unused wallet funding initialization
- Replace manual bitcoin/bitcoind setup with prepare_bitcoin() helper
- Add bitcoind cleanup at test end (matching integration.rs pattern)
- Clean up unused imports (Bitcoind, BitcoinClient, Wallet, etc.)
- Remove unused MIN_TX_FEE constant
…_steps()

- Replace Option<Vec<Box<dyn SetupStep>>> with Option<Vec<SetupStepName>> in ProtocolHandler::setup_steps()
- Add SetupStepName enum (Keys, Nonces, Signatures) for type-safe step names
- Implement factory function create_setup_step() to create steps from enum
- Update SetupEngine::new() to accept Vec<SetupStepName> instead of Vec<Box<dyn SetupStep>>
- Remove trait object allocations at protocol definition time
- Update all protocol implementations (AggregatedKeyProtocol, default implementation)
- Update tests to use enum variants instead of string literals
Move all setup-related logic from ProgramV2 to SetupEngine to improve
separation of concerns. ProgramV2 should only care about whether setup
is complete or not, not the internal details of setup steps.
…control

- Remove duplicate save() call in BitVMX after receive_setup_data() to prevent
  state overwrites that caused tick() to re-enter build() and send duplicate
  messages. ProgramV2 now handles saving internally.

- Write state to legacy key in ProgramV2::save() so is_active_program() can
  correctly identify Ready programs and skip them in process_programs().

- Add send_setup_completed() trait method to ProtocolHandler to allow protocols
  to suppress SetupCompleted messages. AggregatedKeyProtocol returns false to
  maintain backward compatibility with SetupKey callers that only expect
  AggregatedPubkey responses.

- Clean up aggregated_key test by removing unused helper struct and setup
  completion assertions that are no longer relevant.
- Remove special-case handling for single-participant protocols in ProgramV2::setup()
  This allows SetupEngine to handle all cases uniformly through the normal setup flow

- Add single-participant handling in AggregatedKeyProtocol::build_protocol()
  When only one participant exists, use their own key directly instead of
  attempting MuSig2 aggregation (which requires at least 2 participants)

- Add test_aggregated_key_single_participant() test
  Verifies that single-participant protocols work correctly through SetupEngine
  without any special-case bypass logic
- Remove deprecated `collaborate` module and all collaboration processing/storage paths
- Read aggregated pubkey/keypair derivation from globals (`final_aggregated_key`)
- Update aggregated-key single participant test to use `SetupKey` and assert globals match API response
- Remove confirmation_threshold parameter from SubscribeToTransaction and SubscribeToRskPegin API messages
- Simplify tick() return type from Result<bool> to Result<()>
- Remove unused GracefulShutdown trait implementation
- Update imports: use PubKeyHash from bitvmx_broker instead of bitvmx_operator_comms
- Add None parameters to TypesToMonitor calls for consistency
- Improve test infrastructure:
  - Add existence checks before removing directories
  - Add Docker container cleanup logic to prevent conflicts
  - Update shutdown policy tests to match new tick() signature
- Code formatting and cleanup (remove unused imports, improve formatting)
Resolved conflict in tests/common/mod.rs by combining imports:
- Added Path from std::path (needed for check_bitvmx_cpu_built)
- Kept Command from std::process (needed for Docker cleanup)
- Added warn to tracing imports (used in helper functions)
@hperezrodal hperezrodal marked this pull request as ready for review February 3, 2026 17:30
@hperezrodal hperezrodal force-pushed the feature/protocol-workflow branch from 99aa681 to 1e27abc Compare February 3, 2026 17:58
Copy link
Contributor

@jonasmartin jonasmartin left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

comments on aggregated_key

Comment on lines +129 to +132
let aggregated_key = if aggregated_pub_keys.len() == 1 {
tracing::info!("AggregatedKeyProtocol: Single participant, using own key directly");
*my_key
} else {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

this case is not valid. just resturn error if there is not enough participants

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Fixed: Removed the invalid single-participant case and added validation to require at least 2 participants. The protocol now returns an error if there are not enough participants for MuSig2 aggregation.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Not sure if exchange_config is needed, but if it's, remove the custom implementations from keys_steps, nonces_step and signatures_step so the base impl in the steupStep trait is used

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

At some point on this step something similar to this needs to be done:
https://github.com/FairgateLabs/rust-bitvmx-client/blob/main/src/program/program.rs#L520-L525

hperezrodal and others added 2 commits February 20, 2026 16:53
Replace manual match-based trait delegation with enum_dispatch macro,
consistent with the existing ProtocolHandler/ProtocolType pattern.
src/bitvmx.rs Outdated
Comment on lines +1020 to +893
participants_keys: Option<Vec<PublicKey>>,
_participants_keys: Option<Vec<PublicKey>>,
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

There was a usecase used by union where the public keys where provided externally instead of generated, we need to support that case

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

partially solved

Copy link
Contributor

@jonasmartin jonasmartin left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LGTM

@jonasmartin jonasmartin merged commit ebc46e6 into dev Feb 26, 2026
1 check passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants