mirror of
https://github.com/luxfi/explorer.git
synced 2026-09-24 00:25:12 +00:00
Make the explorer ONE binary that runs the Rust Blockscout-rs services in-process via FFI — not by rewriting them in Go and not by exec'ing subprocesses. The real Rust service entrypoints run on their own Tokio runtime threads inside the Go binary. - ffi/ — one C-ABI staticlib (crate-type=["staticlib"]) wrapping the service crates by path (../../explorer-rs/<svc>). One staticlib = one Rust std/panic runtime, no duplicate-symbol conflicts. A `service!` macro is the single place that bridges a service: parse Settings JSON, spawn a dedicated OS thread with a multi-thread Tokio runtime, run the service's real entrypoint. Exports lux_explorer_start_<svc>() + lux_explorer_start_all(). Disabled services still export their symbol and return LUX_FFI_ERR_DISABLED so the Go side links identically. sig-provider is wired and proven first (stateless, fastest to build); the other four services' deps/features/service! blocks are written out commented with confirmed entrypoint signatures for mechanical scale-out. - ffi_on.go (//go:build ffi) — cgo preamble (-llux_explorer_ffi + the darwin/linux system libs the Rust graph needs) + extern decls; startFFIServices() launches the services at startup from main(). - ffi_off.go (//go:build !ffi) — no-op fallback so plain `go build ./...` compiles WITHOUT the staticlib present. - Makefile `make single` = cargo build --release in ffi/ then go build -tags ffi. ffi/README.md documents the C ABI, the protoc / protoc-gen-openapiv2 build-tool prereqs, the seeded Cargo.lock, and the one-service-at-a-time scale-out recipe. Verified: default `go build ./...` exits 0; ffi/ staticlib compiles with sig-provider linked (.a 7.9MB shim -> 58MB with service); cgo -tags ffi links it into the binary (symbols present via nm); the single binary boots and logs `[ffi] start sig-provider -> ok (0)` with the service running in-process. go vet clean under both build tags.
71 lines
3.6 KiB
TOML
71 lines
3.6 KiB
TOML
[package]
|
|
name = "lux_explorer_ffi"
|
|
version = "0.1.0"
|
|
edition = "2021"
|
|
publish = false
|
|
description = "C-ABI staticlib that runs the Blockscout-rs explorer services in-process inside the Lux explorer Go binary (cgo). One Rust std copy wraps every needed service so the Go binary links a single .a."
|
|
|
|
# staticlib => a single self-contained `liblux_explorer_ffi.a` that cgo links
|
|
# directly into the explorer Go binary. We deliberately use ONE staticlib for
|
|
# ALL wrapped services (not one .a per service) so there is exactly one copy of
|
|
# the Rust std / panic runtime and no duplicate-symbol conflicts at link time.
|
|
[lib]
|
|
name = "lux_explorer_ffi"
|
|
crate-type = ["staticlib"]
|
|
|
|
[dependencies]
|
|
# Shared runtime glue. Tokio is built per-service-thread (see src/lib.rs); these
|
|
# are the only crates the FFI shim itself needs. anyhow is the common error type
|
|
# every wrapped service entrypoint returns; tokio drives the per-service runtime.
|
|
libc = "0.2"
|
|
serde_json = "1"
|
|
once_cell = "1"
|
|
anyhow = "1"
|
|
tokio = { version = "1", features = ["rt-multi-thread"] }
|
|
|
|
# --- Wrapped services (path deps into the sibling explorer-rs checkout) -------
|
|
# explorer-rs lives at ../../explorer-rs relative to this crate
|
|
# (/Users/a/work/lux/explorer/ffi -> /Users/a/work/lux/luxfi/explorer-rs).
|
|
# Each service is its OWN cargo workspace with no root workspace, so a plain
|
|
# path dep on the `*-server` crate pulls exactly that service's dependency
|
|
# graph. Each is feature-gated so a default `cargo build` (no --features) builds
|
|
# only the FFI shim + stubs and stays fast; turn services on individually.
|
|
#
|
|
# sig-provider is wired and proven first: it is stateless (no DB, no
|
|
# migrations), so it links and runs with the least build cost. Adding another
|
|
# service is a two-line change: (1) add its path dep below under a matching
|
|
# feature, (2) add a `service!{...}` entry in src/lib.rs. See README.md.
|
|
sig-provider-server = { path = "../../explorer-rs/sig-provider/sig-provider-server", optional = true }
|
|
|
|
# The remaining services are listed (commented) with their exact paths so
|
|
# scaling out is mechanical. They are NOT enabled by default because each pins a
|
|
# DIFFERENT major of blockscout-service-launcher (0.13/0.17/0.19/0.21) and pulls
|
|
# DB/migration stacks (sea-orm) — combining all of them inflates build time and
|
|
# must be done one at a time, verifying the link after each. See README.md
|
|
# "Scaling out" for the exact recipe.
|
|
#
|
|
# smart-contract-verifier-server = { path = "../../explorer-rs/smart-contract-verifier/smart-contract-verifier-server", optional = true }
|
|
# stats-server = { path = "../../explorer-rs/stats/stats-server", optional = true }
|
|
# multichain-aggregator-server = { path = "../../explorer-rs/multichain-aggregator/multichain-aggregator-server", optional = true }
|
|
# visualizer-server = { path = "../../explorer-rs/visualizer/visualizer-server", optional = true }
|
|
|
|
[features]
|
|
# Default = no service compiled in: the staticlib still builds (fast) and every
|
|
# entrypoint returns LUX_FFI_ERR_DISABLED so the Go side links and degrades
|
|
# gracefully. `make single` turns on the services it wants.
|
|
default = []
|
|
sig-provider = ["dep:sig-provider-server"]
|
|
# smart-contract-verifier = ["dep:smart-contract-verifier-server"]
|
|
# stats = ["dep:stats-server"]
|
|
# multichain-aggregator = ["dep:multichain-aggregator-server"]
|
|
# visualizer = ["dep:visualizer-server"]
|
|
|
|
# Convenience: every wired service at once.
|
|
all = ["sig-provider"]
|
|
|
|
[profile.release]
|
|
# Smaller, faster-linking staticlib. LTO off keeps incremental builds sane while
|
|
# scaling services out; flip to "thin" for a production single binary.
|
|
lto = false
|
|
codegen-units = 16
|