This commit refactors the Actor implementation to use the new Mailbox
interface instead of directly managing a channel. This change
significantly simplifies the actor's message processing loop and
improves separation of concerns.
The main changes include replacing the direct channel field with a
Mailbox interface, updating NewActor to create a ChannelMailbox
instance, and refactoring the process method to use the iterator
pattern provided by mailbox.Receive. The new implementation uses a
clean for-range loop over the mailbox's message iterator, eliminating
the complex select statement that previously handled both message
reception and context cancellation.
The Tell and Ask methods in actorRefImpl have been simplified to use
the mailbox's Send method, which internally handles both the caller's
context and the actor's context. This eliminates the need for complex
select statements in these methods and ensures consistent context
handling throughout the actor system.
Message draining during shutdown is now handled through the mailbox's
Drain method, providing a cleaner separation between normal message
processing and cleanup operations. The actor still properly sends
unprocessed messages to the Dead Letter Office and completes pending
promises with appropriate errors during shutdown.
This commit adds thorough test coverage for the new Mailbox interface
and ChannelMailbox implementation. The tests verify correct behavior
across various scenarios including successful sends, context
cancellation, mailbox closure, and concurrent operations.
The test suite specifically validates that the mailbox respects both
the caller's context and the actor's context during send and receive
operations. This ensures that actors properly shut down when their
context is cancelled, and that callers can cancel operations without
affecting the actor's lifecycle.
Additional tests cover edge cases such as zero-capacity mailboxes
(which default to a capacity of 1), draining messages after closure,
and concurrent sends from multiple goroutines. The concurrent test
uses 10 senders each sending 100 messages to verify thread-safety
and proper message ordering.
All tests pass with the race detector enabled, confirming the
implementation is free from data races.
This commit introduces a new Mailbox interface that abstracts the
message queue implementation for actors. Previously, actors used a
direct channel for their mailbox, which limited flexibility and made
it difficult to implement alternative mailbox strategies.
The new Mailbox interface provides methods for sending, receiving, and
draining messages, with full context support for cancellation. The
Receive method leverages Go 1.23's iter.Seq pattern, providing a clean
iterator-based API that allows natural for-range loops over messages.
The ChannelMailbox implementation maintains the existing channel-based
behavior while conforming to the new interface. It stores the actor's
context internally, ensuring both caller and actor contexts are
properly respected during send and receive operations. This simplifies
context handling compared to complex context merging approaches.
This abstraction enables future implementations such as priority
mailboxes, persistent mailboxes, or bounded mailboxes with overflow
strategies, without requiring changes to the actor implementation.
In this commit, we add a readme which serves as a general introduction
to the pacakge, and also the motivation of the package. It serves as a
manual for developers that may wish to interact with the package.
In this commit, we add the actor system (along with the receiptionist)
and the router.
An actor can be registered with the system, which allows other callers
to locate it to send message to it via the receptionist. Custom routers
can be created for when there're actors that rely on the same service
key and also req+resp type. This can be used to implement something
similar to a worker pool.
In this commit, we add the actual Actor implementation. We define a
series of types and interfaces, that in concert, describe our actor. An
actor has some ID, a reference (used to send messages to it), and also a
set of defined messages that it'll accept.
An actor can be implemented using a simple function if it's stateless.
Otherwise, a struct can implement the Receive method, and handle its
internal message passing and state that way.
In this commit, we add two new fundamental data structures: Future[T]
and Promise[T].
A future is a response that might be ready at some point in the future.
This is already a common pattern in Go, we just make a type safe wrapper
around the typical operations: block w/ a timeout, add a call back for
execution, pipeline the response to a new future.
A promise is an intent to complete a future. Typically the caller
receives the future, and the callee is able to complete the future using
a promise.
In this commit, we add an integration test that verifies the
wallet_synced field in GetInfoResponse correctly reflects the wallet's
sync state.
The test creates a node, verifies wallet_synced becomes true after
initial sync, then stops the node and mines blocks while it's offline.
After restart, the test polls GetInfo to observe the wallet catching up,
ideally capturing the transition from wallet_synced=false to true.
The test is registered in the "wallet sync" test case group.
In this commit, we extend the chainSyncInfo struct with a new
isWalletSynced field that tracks the wallet's sync state independently
from the composite isSynced field. The GetInfo RPC handler now populates
the WalletSynced response field from this new struct field.
A debug log line is added to GetInfo to help diagnose sync state issues,
showing both the composite sync status and the wallet-specific sync
status.
Currently isWalletSynced mirrors isSynced since both ultimately derive
from the same underlying wallet sync check. This prepares the plumbing
for future differentiation where wallet sync state could be tracked
separately from router and blockbeat dispatcher states.
In this commit, we add a new `wallet_synced` boolean field to the
GetInfoResponse message. This field exposes the wallet's internal sync
state with the backing chain source, providing visibility into whether
the wallet has caught up to the current chain tip.
This is distinct from the existing `synced_to_chain` field, which
represents a composite sync state that also considers the router and
blockbeat dispatcher. The new field allows callers to distinguish
between wallet sync delays and other subsystem sync states.
Use the StateService stream to wait for LOCKED before sending the unlock
request, then wait for UNLOCKED/RPC_ACTIVE before reporting success.
If the state shows the wallet is already unlocked, skip sending the
unlock request and return an error immediately.
This avoids lost unlocks during slow startup.
Fix https://github.com/lightningnetwork/lnd/issues/7749
Guard access to remoteUpdateHorizon to prevent a race when
the gossiper is flushing a pending batch of announcements
while concurrently processing a GossipTimestampRange message
from a peer.
Signed-off-by: Nishant Bansal <nishant.bansal.282003@gmail.com>
Only post a severity classification comment when the bot hasn't
commented before or when the severity actually changed. Previously
every push (synchronize event) would post a new comment even if the
classification was identical.
The prompt now instructs the classifier to:
- Check for existing bot comments via the pr-severity-bot marker
- Compare the new severity against the existing severity label
- Skip commenting if both match, while still ensuring labels are correct
- Include a severity changed banner when re-commenting due to a change
When running `make lint` in a git worktree, the diff processor fails
with "no version control repository found" because the Docker container
only mounts the worktree directory, not the main git directory that the
worktree's .git file references.
This causes golangci-lint's `new-from-rev` filter to not work, resulting
in all ~32k existing lint issues being reported instead of only newly
introduced ones.
Fix by detecting when we're in a worktree (.git is a file, not a
directory) and mounting the main .git directory into the container so
revgrep can access the git history.
Claude keeps trying to use `gh api` to add severity labels, which gets
denied by the allowed tools restriction. Instead of retrying with the
permitted `gh pr edit --add-label` command, it silently gives up and
only posts the comment. The result is that severity comments appear on
PRs but the actual labels are never applied.
Add an explicit tool constraints section at the top of the prompt so
Claude knows upfront that only `gh pr view`, `gh pr edit`, and
`gh pr comment` are available.
This commit fixes a backwards compatibility issue that prevented nodes
from upgrading from v0.19.x to v0.20.x.
In v0.19.x, channel edge features were serialized as raw feature bytes
without a length prefix. In v0.20.x (commit 2f2845dfc), the serialization
changed to use Features.Encode() which adds a 2-byte big-endian length
prefix before the feature bits. The deserialization code was updated to
use Features.Decode() which expects this length prefix.
When v0.20.x reads a database created by v0.19.x, Decode() tries to read
a length prefix that doesn't exist, causing an EOF error:
unable to decode features: EOF
The fix adds a deserializeChanEdgeFeatures() helper that detects which
format is being read and decodes accordingly:
- New format (v0.20+): First 2 bytes encode the length of the remaining
bytes. Detected when uint16(bytes[0:2]) == len(bytes)-2.
- Legacy format (pre-v0.20): Raw feature bits without length prefix.
Uses DecodeBase256 with the known length.
The format detection is safe because in the legacy format, the first byte
always has at least one bit set (the serialization uses minimum bytes),
so the first two bytes can never encode a value equal to len-2.
Fixes#10528.
When processing a remote network announcement, it is possible for two
error messages to be sent back on the errChan. Since Brontide doesn't
actually read from errChan, and since errChan only buffered one error
message, the sending goroutine would deadlock forever. This would only
become apparent when the gossiper attempted to shut down and got hung
up.
For now, we can fix this simply by buffering up to two error messages on
errChan. There is an existing TODO to restructure this logic entirely
to use the actor model, and we can do a more thorough fix as part of
that work.
This bug was discovered while doing full node fuzz testing and was
triggered by sending a specific channel_announcement message and then
shutting down LND.
The PR severity classifier was failing for external contributors because
the claude-code-action checks that the actor has write permissions. Since
this workflow only reads PR metadata via the API and doesn't execute any
code from the PR (and has restricted tool permissions), it's safe to allow
any user to trigger classification.
When a PR originates from a fork, the PR branch doesn't exist in the
origin remote. This adds a step that uses `gh pr checkout` before
running the Claude action, which properly handles fork PRs by adding
the fork as a remote and fetching the branch from there.
Switch from pull_request to pull_request_target to allow the workflow
to run on PRs from forks. The pull_request trigger runs in the fork's
context which cannot access repository secrets.
This is safe because the workflow only reads PR metadata via the GitHub
API (changed files, labels) and doesn't checkout or execute any code
from the PR itself.
Add a GitHub Actions workflow that uses Claude Code to automatically
classify PRs by severity based on the files changed. This helps
reviewers prioritize and understand PR complexity at a glance.
The workflow:
- Triggers on PR open and synchronize events
- Uses Claude Code to analyze changed files against severity mapping
- Applies one of four severity labels (critical/high/medium/low)
- Posts a detailed comment explaining the classification
- Supports manual override via severity-override-* labels
Severity mapping:
- CRITICAL: lnwallet, htlcswitch, contractcourt, peer, keychain, input,
channeldb, funding, lnwire, server.go, rpcserver.go
- HIGH: routing, invoices, sweep, discovery, graph, watchtower, feature,
lnrpc, macaroons, chainntnfs, etc.
- MEDIUM: payments, autopilot, lncfg, kvdb, proto files, etc.
- LOW: docs, tests, scripts, CI/CD config