Skip to content

roundpb+round: add proto defs and serialization for round mailbox transport - #144

Merged
Roasbeef merged 19 commits into
mainfrom
round-actor-protos
Mar 7, 2026
Merged

roundpb+round: add proto defs and serialization for round mailbox transport#144
Roasbeef merged 19 commits into
mainfrom
round-actor-protos

Conversation

@Roasbeef

@Roasbeef Roasbeef commented Mar 6, 2026

Copy link
Copy Markdown
Member

In this PR, we add the protobuf definitions and wire serialization needed for
the round protocol's mailbox transport layer. Up until now, the systest bridge
used direct in-memory type switches to shuttle messages between client and
server actors. With this change, we define a proper proto schema for all round
protocol messages and wire up ToProto/FromProto on the client-side types so
the production clientconn/serverconn transport can serialize them as
TLV-wrapped proto envelopes through the mailbox.

Fixes https://github.com/lightninglabs/darepo/issues/109

Proto Schema (rpc/roundpb)

We define the full set of messages for both directions of the round protocol:

Server-to-client (S2C) events: ClientSuccessResp, ClientBatchInfo,
ClientAwaitingInputSigsResp, ClientVTXOAggNonces, ClientVTXOAggSigs,
ClientRoundFailedResp, ClientErrorResp. These map 1:1 to the domain event
types the round FSM consumes.

Client-to-server (C2S) requests: JoinRoundRequest, SubmitNoncesRequest,
SubmitPartialSigRequest, SubmitForfeitSigRequest,
SubmitVTXOForfeitSigsRequest. These are the outbox messages the round actor
produces during its state transitions.

A companion convert.go provides shared helpers for converting between wire
types (outpoints, tx outputs, PSBT bytes, schnorr sigs, musig2 nonces, tree
paths) and their proto representations. Both ToProto and FromProto in the
round package rely on these helpers.

Egress: ToProto on Outbox Messages

We wire up ToProto on all C2S outbox message types so the serverconn egress
path can serialize them into mailbox envelopes. Covered types include
JoinRoundRequest (with boarding, VTXO, forfeit, and leave request variants
plus the auth payload), SubmitNoncesRequest, SubmitPartialSigRequest,
SubmitForfeitSigRequest, and SubmitVTXOForfeitSigsToServer.

Ingress: FromProto on Server Event Types

We add FromProto methods to all S2C event types so the serverconn ingress can
deserialize mailbox envelopes back into domain objects. Each method validates
the proto message variant, converts wire representations back to their Go
equivalents, and populates the event struct. Compile-time assertions verify all
S2C types satisfy the inboundServerMessage interface.

See each commit message for a detailed description w.r.t the incremental
changes.

@gemini-code-assist

Copy link
Copy Markdown

Summary of Changes

Hello, I'm Gemini Code Assist1! I'm currently reviewing this pull request and will post my feedback shortly. In the meantime, here's a summary to help you and other reviewers quickly get up to speed!

This pull request significantly refactors the internal messaging and state management within the application by introducing a durable actor model. This foundational change moves critical communication and state persistence from volatile in-memory structures to a robust, database-backed system. The primary impact is enhanced reliability and crash-recovery capabilities for core protocol operations, ensuring that messages are processed exactly once and actor states are consistently maintained across restarts. This lays the groundwork for more resilient and scalable distributed components.

Highlights

  • Durable Actor Model Infrastructure: Introduced a comprehensive durable actor model infrastructure, including AskResponse, Delivery, DeliveryStore, DurableActor, DurableMailbox, OutboxPublisher, RestartMessage, TLVMessage, and TxContext to enable crash-resilient message processing and state management.
  • Protobuf Definitions for Round Protocol: Added new protobuf definitions and generated Go code (arkrpc/ark_mailboxrpc.pb.go, arkrpc/indexer.pb.go, arkrpc/indexer.proto, arkrpc/indexer_grpc.pb.go, arkrpc/indexer_mailboxrpc.pb.go) for the round protocol's mailbox transport layer, defining messages for server-to-client events and client-to-server requests.
  • Expanded ArkService GetInfo Response: Extended the GetInfoResponse in arkrpc/ark.proto and arkrpc/ark.pb.go to include numerous new operator configuration parameters such as exit delays, forfeit scripts, sweep keys, dust limits, boarding amounts, fee rates, and minimum operator fees.
  • Transactional Outbox and Deduplication: Implemented a transactional outbox pattern with OutboxPublisher and processed_messages table for Change Data Capture (CDC), ensuring exactly-once message delivery semantics and robust deduplication for inter-actor communication.
  • Daemon RPC Service: Introduced a new daemonrpc package with protobuf definitions (daemon.proto, daemon.pb.go, daemon_grpc.pb.go, daemon_mailboxrpc.pb.go) and an RPCServer implementation for the daemon's own gRPC API, providing basic status information.
  • Robust Transaction Broadcast Handling: Enhanced the chainsource actor's BroadcastTx logic to gracefully handle ignorable broadcast errors (e.g., already known/confirmed transactions) and fall back to TestMempoolAccept for more robust transaction propagation.
  • Database Migration for Actor Delivery: Added a dedicated database migration (db/actordelivery/migrations/000001_durable_mailbox.up.sql) and associated tooling (cmd/merge-sql-schemas/main.go, db/actordelivery/migrations/runner.go) to manage the schema for durable actor mailboxes, outboxes, and checkpoints.

🧠 New Feature in Public Preview: You can now enable Memory to help Gemini Code Assist learn from your team's feedback. This makes future code reviews more consistent and personalized to your project's style. Click here to enable Memory in your admin console.

Changelog
  • .golangci.yml
    • Added ll linter exclusion for generated template files to prevent line length warnings.
  • AGENTS.md
    • Updated documentation to include make tidy-module-check target.
    • Refined guidelines for function and method comments, GoDoc for exported identifiers, and comments for non-trivial code.
    • Added specific rules for wrapping function definitions.
  • CLAUDE.md
    • Updated documentation to include make tidy-module-check target.
    • Refined guidelines for function and method comments, GoDoc for exported identifiers, and comments for non-trivial code.
    • Added specific rules for wrapping function definitions.
  • Makefile
    • Added new phony targets: commitmsg-lint, commitmsg-fmt, commitmsg-reword for commit message tooling.
    • Updated lint target to include check-migration-version.
    • Increased lint-source timeout to 15 minutes.
    • Added darepod binary build and install targets.
  • arkrpc/ark.pb.go
    • Updated protoc-gen-go version to v1.36.6.
    • Imported unsafe package.
    • Expanded GetInfoResponse message with 11 new fields for operator configuration parameters.
  • arkrpc/ark.proto
    • Extended GetInfoResponse message with new fields for operator configuration parameters, including exit delays, forfeit scripts, sweep keys, dust limits, boarding amounts, fee rates, and minimum operator fees.
  • arkrpc/ark_mailboxrpc.pb.go
    • Added new generated file for mailbox RPC client and server stubs for ArkService.
  • arkrpc/indexer.pb.go
    • Added new generated file for protobuf definitions related to the IndexerService, including VTXO status, event types, script registration, VTXO listing, and tree traversal.
  • arkrpc/indexer.proto
    • Added new file defining the IndexerService with RPCs for registering/unregistering receive scripts, listing scripts, listing OOR recipient events, listing VTXOs, getting VTXO subtrees, and listing VTXO events.
    • Defined new message types and enums for VTXO status, event types, proofs (TaprootSchnorrProof, BIP322Proof), outpoints, script scopes, VTXOs, tree nodes, and tree edges.
  • arkrpc/indexer_grpc.pb.go
    • Added new generated file for gRPC client and server stubs for IndexerService.
  • arkrpc/indexer_mailboxrpc.pb.go
    • Added new generated file for mailbox RPC client and server stubs for IndexerService.
  • baselib/actor/actor.go
    • Modified envelope struct to include callbackActorID, correlationID, and delivery fields to support durable ask/tell patterns.
    • Updated Tell method to return an error, providing more explicit feedback on message enqueue failures.
  • baselib/actor/ask_response.go
    • Added new file defining the AskResponse message, its TLV type, encoding/decoding, and helper functions for creating success/error responses. This enables durable RPC responses.
  • baselib/actor/ask_response_test.go
    • Added new file with unit and property-based tests for AskResponse encoding/decoding, IsError checks, and NewAskResponseWithResult functionality.
  • baselib/actor/delivery.go
    • Added new file defining the Delivery struct, which wraps messages with lease-based acknowledgment semantics, and its methods (Ack, Nack, Extend) for exactly-once processing.
  • baselib/actor/delivery_store.go
    • Added new file defining the DeliveryStore interface and associated parameter structs (EnqueueParams, LeasedMessage, AskResultParams, OutboxParams, OutboxClaimParams, CheckpointParams, DeadLetter) for persistent actor mailbox operations.
  • baselib/actor/delivery_test.go
    • Added new file with unit and property-based tests for Delivery functionality, including Ack/Nack, lease management, poison pill handling, and concurrent access safety.
  • baselib/actor/durable_actor.go
    • Added new file defining the DurableActor for crash-resilient message processing using a durable mailbox, including panic recovery, lease heartbeating, deduplication, and transaction wrapping.
    • Defined DurableActorRef and DurableAskParams for durable Ask semantics.
  • baselib/actor/durable_actor_test.go
    • Added new file with comprehensive tests for DurableActor creation, lifecycle, message processing (Tell/Ask), deduplication, panic recovery, transaction integration, and concurrent operations.
  • baselib/actor/durable_mailbox.go
    • Added new file defining the DurableMailbox for persistent message storage and lease-based delivery, including Send, TrySend, Receive, and Close methods.
  • baselib/actor/durable_mailbox_test.go
    • Added new file with unit and property-based tests for DurableMailbox send/receive, context cancellation, closure, wake signals, concurrent sends, and poison message handling.
  • baselib/actor/interface.go
    • Modified TellOnlyRef interface to return an error for Tell operations, providing feedback on enqueue failures.
    • Added ErrMailboxFull error constant.
  • baselib/actor/map_input_ref.go
    • Modified Tell method to return an error, propagating potential enqueue failures.
  • baselib/actor/map_ref.go
    • Added new file defining MapRef, a message-transforming wrapper around an ActorRef, enabling type-erased lookups and message adaptation.
  • baselib/actor/outbox_publisher.go
    • Added new file defining the OutboxPublisher, a background service that drains the transactional outbox and delivers messages to target actors, implementing the CDC pattern.
  • baselib/actor/outbox_publisher_test.go
    • Added new file with unit and property-based tests for OutboxPublisher delivery, decode error handling, delivery errors, batch processing, and concurrent operations.
  • baselib/actor/restart.go
    • Added new file defining the RestartMessage for FSM state recovery, including its TLV type, priority, encoding/decoding, and the PrependRestartMessage utility function.
  • baselib/actor/restart_test.go
    • Added new file with unit and property-based tests for RestartMessage encoding/decoding with and without checkpoints, priority, and IsRestartMessage helper.
  • baselib/actor/router.go
    • Modified Tell method to return an error, propagating enqueue failures, and updated DLO forwarding to ignore its return error.
  • baselib/actor/tell_only_ref_test_helper.go
    • Modified Tell method to return an error if the context is cancelled.
  • baselib/actor/tlv_message.go
    • Added new file defining the TLVMessage interface for messages supporting TLV serialization, and MessageCodec for managing message type registration and encoding/decoding.
  • baselib/actor/tlv_message_test.go
    • Added new file with unit and property-based tests for MessageCodec registration, encoding/decoding, handling of empty/corrupted data, and concurrent access.
  • baselib/actor/tx_context.go
    • Added new file defining TxContext utilities (WithTx, TxFromContext, RequireTx, WithoutTx, HasTx) for managing database transactions within actor contexts.
  • baselib/actor/tx_context_test.go
    • Added new file with unit tests for TxContext utilities, verifying transaction stripping and preservation of other context values.
  • baselib/actor/tx_environment.go
    • Added new file defining TxEnvironment and OutboxWriter interfaces for transaction-scoped operations within FSM states.
  • baselib/example/example_actors.go
    • Modified ReviewServiceBehavior to include a startProcessing channel, allowing controlled execution in examples.
  • baselib/example/example_test.go
    • Modified ExampleActorStateMachine to use the startProcessing channel to synchronize ReviewService processing, ensuring example output order.
  • baselib/go.mod
    • Updated Go module dependencies to include github.com/google/uuid, github.com/lightningnetwork/lnd/clock, github.com/lightningnetwork/lnd/tlv, and golang.org/x/sys.
  • baselib/go.sum
    • Updated Go module checksums for new and updated dependencies.
  • chainbackends/lndclient_adapters.go
    • Added InfoS logging for RegisterConfirmationsNtfn calls, including pkscript_len, num_confs, and height_hint.
  • chainsource/block_epoch_actor.go
    • Modified block epoch delivery to handle potential errors from Tell method, logging warnings if delivery fails.
  • chainsource/broadcast_errors.go
    • Added new file defining IsIgnorableBroadcastError and IsIgnorableMempoolRejectReason functions to classify expected transaction broadcast errors (e.g., already known/confirmed) and mempool reject reasons.
  • chainsource/broadcast_errors_test.go
    • Added new file with unit tests for IsIgnorableBroadcastError and IsIgnorableMempoolRejectReason functions, covering various ignorable and non-ignorable error cases.
  • chainsource/chainsource.go
    • Modified handleBroadcastTx to incorporate IsIgnorableBroadcastError and TestMempoolAccept for more robust transaction broadcast handling, treating ignorable errors as success.
    • Added InfoS logging for RegisterConfRequest calls, including caller_id, pkscript_len, target_confs, and height_hint.
  • chainsource/chainsource_test.go
    • Added new test cases for BroadcastTx to verify correct handling of ignorable errors and fallback to TestMempoolAccept results.
  • chainsource/conf_actor.go
    • Added logger helper method for consistent logging.
    • Added InfoS logging for ConfActor monitoring start/stop and confirmation events.
    • Modified deliverConfirmation to handle potential errors from Tell method, logging warnings if delivery fails.
  • chainsource/spend_actor.go
    • Added logger helper method for consistent logging.
    • Modified deliverSpend to handle potential errors from Tell method, logging warnings if delivery fails.
  • chainsource/transform_test.go
    • Updated Tell calls in TestMapConfirmationEvent, TestMapSpendEvent, TestMapBlockEpoch, TestMapConfirmationEventTypeSafety, and TestMapSpendEventMultipleMessages to check for and assert no errors, reflecting the updated Tell interface.
  • cmd/darepod/main.go
    • Added new file for the darepod daemon entry point, including Cobra CLI setup, configuration parsing with Viper, and signal interception for graceful shutdown.
  • cmd/merge-sql-schemas/main.go
    • Modified main function to apply migrations from both db/sqlc/migrations and db/actordelivery/migrations directories.
    • Extracted migration logic into a reusable applyMigrationDir function.
  • cmd/protoc-gen-mailboxrpc/internal/gen/config.go
    • Added new file defining Config struct for protoc-gen-mailboxrpc to allow excluding specific services from generation.
  • cmd/protoc-gen-mailboxrpc/internal/gen/generator.go
    • Added new file for the core logic of the protoc-gen-mailboxrpc plugin, responsible for generating Go stubs for mailbox RPC clients and servers based on protobuf service definitions.
  • cmd/protoc-gen-mailboxrpc/internal/gen/generator_test.go
    • Added new file with tests for the protoc-gen-mailboxrpc generator, verifying routing key emission and exclude_service functionality.
  • cmd/protoc-gen-mailboxrpc/internal/gen/templates.go
    • Added new file containing Go templates (serviceRawTemplate) for generating mailbox RPC client and server stubs, including client structs, server interfaces, and router registration helpers.
  • cmd/protoc-gen-mailboxrpc/main.go
    • Added new file for the protoc-gen-mailboxrpc plugin entry point, parsing command-line flags for configuration.
  • daemonrpc/daemon.pb.go
    • Added new generated file for protobuf definitions for the DaemonService, including GetInfoRequest and GetInfoResponse.
  • daemonrpc/daemon.proto
    • Added new file defining the DaemonService with a GetInfo RPC, providing basic daemon status information.
  • daemonrpc/daemon_grpc.pb.go
    • Added new generated file for gRPC client and server stubs for DaemonService.
  • daemonrpc/daemon_mailboxrpc.pb.go
    • Added new generated file for mailbox RPC client and server stubs for DaemonService.
  • darepod/config.go
    • Added new file defining the daemon's configuration structure (Config, LndConfig, ServerConfig, RPCConfig), including default values and validation logic.
  • darepod/log.go
    • Added new file for daemon-specific logging setup, defining the DRPD subsystem and UseLogger function.
  • darepod/rpc_server.go
    • Added new file implementing the DaemonService gRPC server, providing GetInfo functionality.
  • darepod/server.go
    • Added new file for the main daemon server orchestration logic, including LND connection, mailbox transport setup, actor system initialization, chain source actor registration, database management, RPC server setup, Ark/indexer RPC client creation, and wallet/round/OOR actor initialization.
  • db/actordelivery/doc.go
    • Added new file with documentation for the actordelivery package, explaining its purpose for isolated actor-delivery persistence.
  • db/actordelivery/migrations.go
    • Added new file for running isolated actor-delivery database migrations, including MigrationOption for custom table names and database names.
  • db/actordelivery/migrations/000001_durable_mailbox.down.sql
    • Added new file for the downgrade SQL script to remove all tables and indexes created for durable actor mailboxes.
  • db/actordelivery/migrations/000001_durable_mailbox.up.sql
    • Added new file for the initial SQL migration script, creating mailbox_messages, ask_results, outbox_messages, processed_messages, fsm_checkpoints, and dead_letters tables with their respective indexes.
  • db/actordelivery/migrations/runner.go
    • Added new file for the migration runner for the actor-delivery schema, using go:embed for SQL files and dbmigrate for execution.
  • db/actordelivery/migrations_test.go
    • Added new file with unit tests for actor-delivery migrations, verifying table creation and re-run idempotency.
  • db/actordelivery/queries/mailbox.sql
    • Added new file containing SQL queries for managing mailbox messages (enqueue, lease, ack, nack, extend, delete, expire leases, move to dead letter), ask results (insert, get, delete, cleanup expired), outbox messages (enqueue, claim batch, complete, fail, get, count, list pending, move to dead letter), processed messages (mark, check, cleanup expired), FSM checkpoints (save, get, delete, list), and dead letters (get, list, delete, count, cleanup old).
  • db/actordelivery/sqlc/db.go
    • Added new generated file for SQLC database access code, including DBTX interface and Queries struct with WithTx method.
  • db/actordelivery/sqlc/mailbox.sql.go
    • Added new generated file for SQLC Go code implementing all mailbox-related queries defined in queries/mailbox.sql.
  • db/actordelivery/sqlc/models.go
    • Added new generated file for SQLC Go models representing the tables in the actor delivery schema, including AskResult, DeadLetter, FsmCheckpoint, MailboxMessage, OutboxMessage, and ProcessedMessage.
  • db/actordelivery/sqlc/querier.go
    • Added new generated file for the SQLC Go Querier interface, defining all available actor delivery database operations.
Ignored Files
  • Ignored by pattern: .github/workflows/** (1)
    • .github/workflows/main.yml
Using Gemini Code Assist

The full guide for Gemini Code Assist can be found on our documentation page, here are some quick tips.

Invoking Gemini

You can request assistance from Gemini at any point by creating a comment using either /gemini <command> or @gemini-code-assist <command>. Below is a summary of the supported commands on the current page.

Feature Command Description
Code Review /gemini review Performs a code review for the current pull request in its current state.
Pull Request Summary /gemini summary Provides a summary of the current pull request in its current state.
Comment @gemini-code-assist Responds in comments when explicitly tagged, both in pull request comments and review comments.
Help /gemini help Displays a list of available commands.

Customization

To customize Gemini Code Assist for GitHub experience, repository maintainers can create a configuration file and/or provide a custom code review style guide (such as PEP-8 for Python) by creating and adding files to a .gemini/ folder in the base of the repository. Detailed instructions can be found here.

Limitations & Feedback

Gemini Code Assist may make mistakes. Please leave feedback on any instances where its feedback is incorrect or counter productive. You can react with 👍 and 👎 on @gemini-code-assist comments. If you're interested in giving your feedback about your experience with Gemini Code Assist for Github and other Google products, sign up here.

You can also get AI-powered code generation, chat, as well as code reviews directly in the IDE at no cost with the Gemini Code Assist IDE Extension.

Footnotes

  1. Review the Privacy Notices, Generative AI Prohibited Use Policy, Terms of Service, and learn how to configure Gemini Code Assist in GitHub here. Gemini can make mistakes, so double check it and use code with caution.

@gemini-code-assist gemini-code-assist Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Code Review

This pull request introduces a significant and well-architected durable actor framework, complete with persistent mailboxes and a transactional outbox pattern for crash-resilient message processing. The new darepod daemon provides a solid foundation for the client application, and the protobuf definitions for the round protocol are a crucial step towards a production-ready transport layer. The changes are extensive but appear to be of high quality, with thorough test coverage for the new components. The enhanced error handling in the Tell methods and the robust transaction broadcast logic in the chainsource actor are notable improvements.

Note: Security Review did not run due to the size of the PR.

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 6439160226

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment thread rpc/roundpb/convert.go Outdated
Comment thread round/from_proto.go
@Roasbeef
Roasbeef force-pushed the round-actor-protos branch 3 times, most recently from a0f2f6d to 08fbbcd Compare March 6, 2026 06:38
@Roasbeef
Roasbeef changed the base branch from master to main March 6, 2026 06:39
@Roasbeef
Roasbeef force-pushed the round-actor-protos branch from 08fbbcd to d0f8824 Compare March 7, 2026 01:54
Roasbeef and others added 3 commits March 6, 2026 20:02
Define the protobuf schema for all round protocol messages that
flow between client and server through the mailbox transport. The
proto file covers both directions:

Server-to-client (S2C) events: ClientSuccessResp,
ClientBatchInfo, ClientAwaitingInputSigsResp, ClientVTXOAggNonces,
ClientVTXOAggSigs, ClientRoundFailedResp, ClientErrorResp.

Client-to-server (C2S) requests: JoinRoundRequest,
SubmitNoncesRequest, SubmitPartialSigRequest,
SubmitForfeitSigRequest, SubmitVTXOForfeitSigsRequest.

A companion convert.go file provides helpers for converting
between wire types (outpoints, tx outputs, PSBT, schnorr
signatures, musig2 nonces, tree paths) and their proto
representations. These helpers are shared by both the ToProto
and FromProto implementations in the round package.

The gen_protos.sh script is updated to include the new roundpb
package in the generation pipeline.

Co-authored-by: András Bánki-Horváth <554360+bhandras@users.noreply.github.com>
Wire up the ToProto methods on all client-to-server outbox
message types so they produce real proto messages instead of
returning nil stubs. This enables the serverconn egress to
serialize these messages into mailbox envelopes for transport.

Covered types: JoinRoundRequest (boarding requests, VTXO
requests, forfeit requests, leave requests, auth payload),
SubmitNoncesRequest (per-signer nonce maps), SubmitPartialSigRequest
(per-signer partial signature maps), SubmitForfeitSigRequest
(boarding input signatures), and SubmitVTXOForfeitSigsToServer
(forfeit tx + client VTXO signatures).

The corresponding test is updated from asserting nil (stub
behavior) to asserting non-nil (real proto output).

Co-authored-by: András Bánki-Horváth <554360+bhandras@users.noreply.github.com>
Add FromProto methods to all server-to-client event types so the
serverconn ingress can deserialize mailbox envelopes back into
domain objects. Each method validates the proto message type,
converts wire representations (outpoints, PSBT, tree paths,
nonces, signatures) to their Go equivalents, and populates the
event struct.

Covered S2C types: RoundJoined (from ClientSuccessResp),
CommitmentTxBuilt (from ClientBatchInfo), AwaitingBoardingSigs
(from ClientAwaitingInputSigsResp), NoncesAggregated (from
ClientVTXOAggNonces), OperatorSigned (from ClientVTXOAggSigs),
BoardingFailed (from ClientRoundFailedResp or ClientErrorResp).

Also adds FromProto on JoinRoundRequest for test code that needs
to deserialize captured mailbox envelopes back to the client
domain type (used by join auth forgery tests).

Compile-time assertions verify all S2C types implement the
inboundServerMessage interface.
@Roasbeef
Roasbeef force-pushed the round-actor-protos branch from d0f8824 to 287c129 Compare March 7, 2026 02:04
Roasbeef and others added 16 commits March 6, 2026 20:47
Move the OOR mailbox wire protocol package from the top-level oorwire/
directory into rpc/oorpb/ to colocate it with the other RPC proto
packages (roundpb, etc.) under the rpc/ tree. This rename also changes
the Go package name from oorwire to oorpb for consistency with the
naming convention used by roundpb.

All proto stubs are regenerated via make rpc with the updated
go_package option pointing to rpc/oorpb, and all import sites are
updated accordingly.

Co-Authored-By: bhandras <bhandras@users.noreply.github.com>
Replace the broken fmt.Sscanf-based parser with
chainhash.NewHashFromStr + strconv.ParseUint. The old
implementation scanned hex bytes in forward order, but
OutpointToMapKey (via wire.OutPoint.String) produces
byte-reversed hex. This caused a round-trip mismatch that
would break connector leaf map deserialization.

Also update the ConnectorLeafMap proto comment to describe
the actual "hash:index" string key format instead of the
36-byte binary encoding, and remove the dead
OutpointKeyBytes function that implemented the old format.
Schnorr signatures are 64 bytes (32-byte R.x + 32-byte s), not
32 bytes as previously documented. Fix all proto field comments
and Go doc comments that incorrectly stated "32 bytes" for
schnorr signatures.
Change the ServerMessage.ToProto() interface from returning a bare
proto.Message to returning fn.Result[proto.Message]. This surfaces
serialization errors that were previously silently swallowed:

- SubmitPartialSigRequest: partial sig encode error was discarded
  with `_ = sig.Encode(&buf)`.
- SubmitVTXOForfeitSigsToServer: missing forfeit tx map entries and
  MsgTx serialization failures were silently skipped with `continue`.

All callers in serverconn (Encode, handleSendClientEvent) and the
oor outbox messages are updated to use .Unpack() for the (T, error)
pattern. Test assertions use .UnwrapOrFail(t) for concise success
checks.

Also adds a nil guard for LeafOutput in CommitmentTxBuilt.FromProto
to prevent nil pointer dereference when the server sends a
ConnectorLeafInfo with a missing leaf_output.
Add doc comments clarifying three edge cases identified during review:

- TreeFromProto: note that FinalKey is nil after deserialization and
  callers must run Materialize to recompute it from CoSigners.

- ConnectorLeafInfo.LeafIndex: document that this field is not
  populated by FromProto since the server's ConnectorLeafInfo proto
  does not carry it; only local tree-building code sets it.

- ClientConnectorLeafInfo proto: note it is currently unused in wire
  protocol messages and reserved for future client-to-server forfeit
  flows.
Add rapid-based property tests covering round-trip correctness for all
conversion helpers in roundpb/convert.go:

- OutpointToProto/FromProto and OutpointsToProto/FromProto
- OutpointToMapKey/FromMapKey (byte-reversed hex format)
- TxOutToProto/FromProto
- SchnorrSigToBytes/FromBytes
- TxIDToHex/FromHex
- TreeToProto/FromProto (recursive node structure)
- MsgTxToBytes/FromBytes
- PSBTToBytes/FromBytes

Each property test generates random inputs via rapid generators and
verifies the value survives a full encode→decode round-trip unchanged.
Also includes nil-handling tests and negative tests for malformed
map keys and hex strings.
Add registerRoundEventRoutes to wire up server-push round protocol
events to the round actor via the EventRouter. Each push event is
deserialized from its roundpb proto, populated via FromProto, and
wrapped in a ServerMessageNotification for delivery to the round
actor's durable mailbox.

The following push event routes are registered:
- BatchInfo (ClientBatchInfo → CommitmentTxBuilt)
- AwaitingInputSigs (ClientAwaitingInputSigsResp → AwaitingBoardingSigs)
- AggNonces (ClientVTXOAggNonces → NoncesAggregated)
- AggSigs (ClientVTXOAggSigs → OperatorSigned)
- RoundFailed (ClientRoundFailedResp → BoardingFailed)
- Error (ClientErrorResp → BoardingFailed)

Also adds roundpb/service.go with ServiceName and push event method
name constants following the same pattern as oorpb.

Co-Authored-By: bhandras <bhandras@users.noreply.github.com>
Add rapid-based property tests covering round-trip correctness for
all OOR proto conversion helpers:

- encodeOutPoint/decodeOutPoint
- encodeSigningDescriptor/decodeSigningDescriptor
- NewSubmitPackageRequest/ParseSubmitPackageRequest
- NewSubmitPackageResponse/ParseSubmitPackageResponse
- NewFinalizePackageRequest/ParseFinalizePackageRequest
- NewFinalizePackageResponse/ParseFinalizePackageResponse
- decodeSessionID invalid length rejection

Each property test generates random inputs via rapid generators and
verifies the value survives a full encode→decode round-trip unchanged.
Move lib/actormsg import to correct alphabetical position per gci
linter. Extract inline Adapt closure to standalone roundEventAdapt
function to stay under the 80-char line limit.

Co-Authored-By: bhandras <bhandras@users.noreply.github.com>
This function became unused after the fn.Result[proto.Message]
migration replaced error-envelope returns with fn.Err.
Fix gci import ordering and split long hex string literals across
lines to stay under the 80-char line limit.
malicious server input

Address several security findings from code review:

C1/M1: Add pre-order invariant check (childIdx > i) in
TreeFromProto to prevent cycle injection and diamond DAGs
in deserialized VTXO trees. A malicious server could
previously craft self-referential or mutually-referential
node graphs that cause stack overflow on any recursive tree
traversal (signing, verification, unrolling).

M2: Add output index bounds check in TreeFromProto child
wiring. Previously, a child could reference an output index
that doesn't exist in the parent node, causing downstream
OOB panics.

M3: Add configurable max node count (DefaultMaxTreeNodes =
50,000) with WithMaxTreeNodes functional option to prevent
OOM DoS from unbounded tree allocations.

H1: Reject nil PSBT in CommitmentTxBuilt.FromProto. An
omitted batch_psbt field previously produced a nil Tx that
would panic on dereference during sighash computation.

H2: Validate non-negative values in TxOutFromProto. The
proto int64 value field could carry negative values that
corrupt fee calculations and tree node amounts. Change
TxOutFromProto signature to return error.

M4: Reject negative tree path indices in
CommitmentTxBuilt.FromProto since they are semantically
invalid as commitment tx output indices.
deserialization

Add comprehensive regression tests that verify the security
hardening from the previous commit. Tests cover:

- TreeFromProto cycle rejection (self-reference, mutual
  cycle, back-edge exploit chain)
- TreeFromProto large node count rejection (OOM DoS)
- TreeFromProto output index bounds checking
- TreeFromProto negative node amount rejection
- CommitmentTxBuilt.FromProto nil PSBT rejection
- CommitmentTxBuilt.FromProto negative tree path index
  rejection
- CommitmentTxBuilt.FromProto negative connector amount
  rejection
- Diamond DAG behavior documentation (accepted but noted)
- Byte order consistency verification
- Nil passthrough behavior for PSBT, schnorr sigs, MsgTx
- Outpoint map key edge cases

Tests that previously demonstrated vulnerabilities (assert
NoError on malicious input) are converted to regression
tests that verify the new validation rejects the input.
Add a BoardingInputSigToProto conversion helper that validates the
domain InputIndex (int) fits within int32 range before casting to
the proto field. Without this check, indices exceeding MaxInt32
would silently truncate, potentially causing the server to sign the
wrong input in a forfeit transaction.

Also fix two pre-existing lint issues: rename the WithMaxTreeNodes
parameter from `max` to `maxNodes` to avoid shadowing the builtin,
and add the required blank line after the multi-line TreeFromProto
function signature.
Wire the new BoardingInputSigToProto helper into
SubmitForfeitSigRequest.ToProto so that input index bounds checking
happens in the roundpb conversion layer rather than inline.

Add a TreeOpts field to CommitmentTxBuilt so that VTXO tree
deserialization options (e.g., max node count) can be injected by
the event router from daemon configuration and passed through to
roundpb.TreeFromProto during FromProto.

Document that map iteration in SubmitNoncesRequest.ToProto,
SubmitPartialSigRequest.ToProto, and
SubmitVTXOForfeitSigsToServer.ToProto is non-deterministic. This is
acceptable because proto map fields have no ordering semantics and
downstream code does not derive idempotency keys from raw proto
bytes.

Fix lint line-length violations in security test roundID literals.
Add a MaxTreeNodes field to ServerConfig that caps the number of
nodes accepted in a VTXO tree received from the server, preventing
memory exhaustion from oversized payloads. The default is set to
roundpb.DefaultMaxTreeNodes (50,000) in DefaultConfig.

In registerRoundEventRoutes, capture the configured value and build
a TreeFromProtoOption slice that is injected into
CommitmentTxBuilt via the newEvent closure. This threads the limit
through FromProto into roundpb.TreeFromProto without changing any
interface signatures.
@Roasbeef
Roasbeef force-pushed the round-actor-protos branch from 287c129 to cbd092f Compare March 7, 2026 03:30
@Roasbeef
Roasbeef merged commit de593b7 into main Mar 7, 2026
16 checks 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.

1 participant