Lnd Emulator Utility Work
def AddInvoice(self, request, context): # Emulate utility work: Simulate a hash collision if request.value == 100000: context.set_code(grpc.StatusCode.ALREADY_EXISTS) context.set_details("Invoice with same hash already exists") return lnd_pb2.AddInvoiceResponse() # Normal emulation invoice = lnd_pb2.Invoice() invoice.r_hash = b"fakehash123" self.invoices[invoice.r_hash] = request return lnd_pb2.AddInvoiceResponse(r_hash=invoice.r_hash)
You can inject edge cases that occur once every 10,000 transactions on mainnet, but force them to happen on every test run. Part 6: Integrating LND Emulators into CI/CD Workflows The end goal of LND emulator utility work is automation . You want your GitHub Actions or GitLab CI to run Lightning tests without a real node. Sample GitHub Action Using lnd-sim name: LND Emulator Tests on: [push] jobs: test: runs-on: ubuntu-latest steps: - uses: actions/checkout@v3 - name: Run LND Emulator Mock Server run: | pip install lnd-sim lnd-sim --port 10009 --mock-data ./test/fixtures/mock_responses.json & - name: Run Application Tests Against Emulator env: LND_RPC_HOST: localhost:10009 LND_TLS_CERT: ./test/fake_cert.pem run: pytest tests/test_lightning_integration.py In this workflow, the emulator replaces the need for a Dockerized LND node, slashing test runtime from 5 minutes to 15 seconds. Part 7: Common Pitfalls in LND Emulator Work Even experienced developers make mistakes when doing emulator work. Pitfall 1: The "Mocking Reality" Gap Emulators are only as good as their fidelity. If your emulator always returns a successful payment, you will miss bugs related to partial payments or stuck HTLCs. Solution: Use a parameterized emulator that randomly injects TEMPORARY_CHANNEL_FAILURE codes. Pitfall 2: Ignoring Macaroon Authentication Real LND uses macaroons for auth. Forgetting to emulate macaroon validation means your tests will pass locally but fail in staging. Solution: Your emulator must check for the presence of admin.macaroon bytes in the metadata. Pitfall 3: State Drift Unlike a real LND node, simple emulators are often stateless. A payment that settles should update the channel balance. If your emulator doesn't track balance, you won't catch "insufficient local balance" errors. Solution: Use a stateful emulator like Polar, which maintains a simulated ledger. Part 8: The Future of LND Emulation As the Lightning Network introduces more complex features (Taproot Assets, Simple Taproot Channels, Atomic Multi-Path Payments), the need for sophisticated emulators grows. lnd emulator utility work
def LookupInvoice(self, request, context): # Emulate expiry: If the invoice was "created" more than 2 seconds ago, fail. # (In a real emulator, you'd store timestamps) if request.r_hash in self.invoices: return lnd_pb2.Invoice(settled=False, state=lnd_pb2.Invoice.UNPAID) else: context.set_code(grpc.StatusCode.NOT_FOUND) return lnd_pb2.Invoice() Sample GitHub Action Using lnd-sim name: LND Emulator
Simulating a "failure to find route" error to see how your wallet GUI reacts. 3.2. Polar (Lightning Labs’ GUI Emulator) Polar is a desktop application (Windows, Mac, Linux) that uses Docker to spin up entire fake Lightning networks. It is not a pure code-level emulator but rather a network emulator . You can drag, drop, and connect LND, c-lightning, and Eclair nodes on a virtual graph. If your emulator always returns a successful payment,
Creating a 10-node ring topology to test MPP (Multi-Path Payments) in zero real-world time. 3.3. regtest + btcd (The Blockchain Emulator) While not strictly "LND" emulation, running LND on Bitcoin’s RegTest (regression test mode) mode is the most authentic form of emulation. RegTest allows you to generate blocks instantly via RPC. Tools like bitcoind in RegTest act as the blockchain emulator, while LND runs as a real binary—but on a fake chain.
Using Python’s grpcio and unittest.mock , you can create a fake LND server in under 50 lines. import grpc from unittest.mock import MagicMock import lnd_pb2 # Generated from LND proto files class MockLNDServer: def init (self): self.invoices = {}
Testing channel force-close recovery by generating 100 fake blocks instantly. 3.4. mockery & gomock for LND (Unit Test Level) For developers writing Go-based applications that interface with LND, mockery can auto-generate emulated LND clients. This is the deepest form of utility work, where you emulate the interface of LND without running any network stack at all.
