152 Commits
Author SHA1 Message Date
zeekay 2c62ec960f SQLite without shared cache, so the explorer's reads cannot fail the indexer's writes
In shared-cache mode SQLite locks per table and answers a blocked write with
SQLITE_LOCKED, which busy_timeout does not wait out. The block write then
failed outright and every other write in indexBlock was dropped unseen.
v1.5.11
2026-09-23 05:39:28 -07:00
zeekayandHanzo Dev 7c86195752 Report average block time in milliseconds, as the explorer page reads it
The page divides average_block_time by 1000, per Blockscout's /stats contract.
Seconds made every explorer show 0.0s.

Co-authored-by: Hanzo Dev <[email protected]>
v1.5.10
2026-09-22 23:38:43 -07:00
zeekayandHanzo Dev f28079bd70 Build on Go 1.27
Moved the go directive to 1.27.1. go build ./... and go vet ./... are clean.
The e2e suite still fails in BeforeSuite because no local node is reachable; it
fails identically with this change reverted.

Co-authored-by: Hanzo Dev <[email protected]>
v1.5.9
2026-09-17 13:34:58 -07:00
zeekayandHanzo Dev 05fdd58377 Typecheck on the native compiler, keep 6 for the tools
typescript 7.0.2 is the native compiler and exports no JavaScript API, and
next below 16.3 wants typescript/lib/typescript.js, which the native compiler
does not ship: the check fails and next shells out to `pnpm add typescript`
mid-build, which a frozen lockfile or an offline runner turns into a failed
build. So 7.0.2 comes in aliased as tsgo and does the typechecking, and
typescript stays on the 6 line for next. The docs site: 10 diagnostics before and after.

Co-authored-by: Hanzo Dev <[email protected]>
2026-09-17 00:39:33 -07:00
zeekayandHanzo Dev 5e4e7ae274 Ignore node_modules
The explorer app and the docs site install into the tree and nothing ignored
them, so an install left them stageable.

Co-authored-by: Hanzo Dev <[email protected]>
2026-09-17 00:27:01 -07:00
zeekayandHanzo Dev bda095be28 Compile the explorer app with TypeScript 7
typescript 7.0.2 is the native compiler, so this is a pin and not a second
toolchain. explorer/app (@luxfi/explorer-app, new typecheck script, tsc
--noEmit): 0 diagnostics before and after. Its lockfile was missing and is
committed with the pin.

Co-authored-by: Hanzo Dev <[email protected]>
2026-09-17 00:25:44 -07:00
zeekayandHanzo Dev 77e3759c2f Compile with TypeScript 7
typescript 7.0.2 is the native compiler, so this is a pin and not a second
toolchain. The docs site typecheck (new script, tsc --noEmit): 10 diagnostics
before and after. TS7 no longer resolves a bare CSS side-effect import, so
css.d.ts declares '*.css'; that is free on the old compiler.

Co-authored-by: Hanzo Dev <[email protected]>
2026-09-17 00:19:50 -07:00
zeekayandHanzo Dev 2d0c1c229f docs: describe hanzoai/base as an application framework
Co-authored-by: Hanzo Dev <[email protected]>
2026-09-11 00:31:17 -07:00
zeekayandHanzo Dev f0ef4624cc go 1.26.8
One toolchain across the estate. The tree carried 1.26.0, .1, .3, .4 and .5
at once, so which compiler built a binary depended on which repo it came
from.

Co-authored-by: Hanzo Dev <[email protected]>
2026-09-08 23:58:21 -07:00
zeekayandHanzo Dev f8907ec5de run on nothing but the binary
alpine carried a shell, a package manager, libc and sqlite-libs so that a
dynamically linked binary could find them. Linking statically removes the
reason for all four: the image is the binary and the TLS roots, on
distroless static, as nonroot.

The explorer serves its frontend from //go:embed, so nothing else was ever
needed at runtime.

Co-authored-by: Hanzo Dev <[email protected]>
2026-09-08 23:21:59 -07:00
zeekayandHanzo Dev 7a4566d4b3 chain letters are lowercase
The primary-network chains answer to either case; one spelling beats two.
/v1/chain/c/rpc, /v1/chain/p, /v1/chain/x across the estate.

Co-authored-by: Hanzo Dev <[email protected]>
2026-09-08 15:21:19 -07:00
zeekayandHanzo Dev 7e198c5359 ci: a runner label names the platform, not the org
hanzo-build-linux-amd64, lux-build-linux-amd64, zoo-build-linux-amd64 and
every other org-prefixed spelling all meant the same machine. Which org a
job belongs to does not change which host can build it, so the org bought
one pool name per org per arch and each could go stale on its own -- the
evo host alone answered to fourteen names for one label.

One vocabulary now: linux-amd64, linux-arm64, macos-arm64, win-amd64. The
generic labels every plain workflow uses (ubuntu-latest, self-hosted) are
untouched, so naive CI keeps working.

Co-authored-by: Hanzo Dev <[email protected]>
2026-09-08 12:09:44 -07:00
zeekayandHanzo Dev 2177ed3a0f Read transactions by block, so an imported chain keeps its history
A transaction hash resolves through an index the node builds as it accepts
transactions, not as it replays them. A chain restored from an RLP import
therefore serves blocks and receipts while eth_getTransactionByHash and
eth_getTransactionReceipt answer null for all of it.

The ingest path asked by hash, so it lost every transaction it read. Worse,
a null receipt unmarshalled into an empty struct rather than a miss, and the
empty transaction that fell out was written as a row keyed by the empty
hash — which every later miss then merged into. 220 transactions and 379
logs became 3 rows and 2.

Ask by block number instead. A block carries what the sender submitted, and
eth_getBlockReceipts carries what running it produced; together they are the
whole transaction, and neither needs the hash index. It also costs two round
trips per block where the old path cost two per transaction.

One receipt parser now serves both the block-keyed and hash-keyed reads, and
the hash-keyed one reports a miss as a nil transaction.

Co-authored-by: Hanzo Dev <[email protected]>
v1.5.8
2026-09-05 19:31:05 -07:00
zeekay 54b7ff2563 ci(release): publish indexer for arm64 as well as amd64
The lab runs both architectures, so a tag carrying one of them deploys
on half the fleet. One job now builds both platforms under a single
manifest list, with binfmt registered for the arm64 leg: the Dockerfile
compiles indexerd with CGO against sqlite-dev, so that leg runs inside
the target-arch container rather than cross-compiling on TARGETARCH. The
timeout covers the emulated pass instead of aborting part-way through it.
2026-09-05 19:04:39 -07:00
zeekay e2c128f306 feat(indexer): update RPC endpoints to /v1/chain 2026-09-04 14:42:46 -07:00
zeekay 9483d71f42 every Hanzo dependency is the version npm serves
Ranges drift once nothing moves them: a caret that has not been rewritten
since it was written pins whatever was current that day, and an exact pin
cannot even take a patch. Both are updated here.

One line per package, so a surface reads the same components, the same
tokens and the same face as every other one.
2026-09-01 16:08:04 -07:00
zeekay 234f8e4110 reach chains at /v1/chain; the node deleted /v1/bc 2026-08-30 20:44:13 -07:00
zeekay 5f5211929a docs: chain routes are /v1/chain
luxd serves chain APIs under one segment from constants.ChainAliasPrefix
(constants v1.6.4, node v1.36.181):

  /v1/bc/<alias>/...   -> /v1/chain/<alias>/...
  /ext/bc/<alias>/...  -> /v1/chain/<alias>/...

Observations keep their original addresses: a dated note or a recorded status
code is a fact about when it was written, not an instruction to follow.
2026-08-30 16:41:57 -07:00
zeekayandHanzo Dev 3d6388d6ab An NFT transfer says which NFT
The indexer had the item id all along and threw it away at the edge.
formatTokenTransfer wrote every row in the ERC-20 shape — an amount and a
null decimals — so the three Lux Genesis mints, which moved ids 0, 1 and 2,
came back as three identical rows and no page could name what had moved.
The id now rides in `total`, whose shape follows the token type the way
luxfi/explore's Erc721TotalPayload / Erc1155TotalPayload already read it.

/tokens/{addr}/instances was a hardcoded empty list and /instances/{id} was
an unregistered route, so a collection had no items and an item had no page.
Both are real now. The item list comes from the transfer table rather than
the balance table: balances hold only what someone holds now, so a burned
item would vanish from a collection that still minted it, while its last
transfer always exists and names its current owner.

ERC-1155 was not indexed at all. It is now, single and batch — a batch log
yields one row per (id, amount) pair, so no id is folded away.

Underneath, one decoder. There were two, and they disagreed: the daemon's
path read ERC-20 and ERC-721 only, spelled types "ERC-721", and stored the
raw amount hex; the adapter's path also read ERC-1155 and ERC-404 but
spelled types "ERC721" and stored ids two different ways depending on which
event carried them. decodeTransfers is now the only place a log becomes a
transfer, with one spelling, decimal amounts, and one stored id shape.
applyERC20BalanceDelta and applyERC721BalanceDelta collapse into move(),
which is one function because the three token kinds differ only in what the
id column holds.

An item's tokenURI is read on chain and recorded; the document behind it is
not fetched. An indexer that waits on an IPFS gateway stops indexing, and
the document is not ours and can change. uri_state distinguishes the three
answers that were previously one blank: the chain gave a URI, the chain
names none, or we have not asked. image_url and metadata stay null rather
than assert media nobody read.

Verified against C-Chain 96369: Lux Genesis
(0x9e04fc57c20b2ee45627c4aa280eb471f2ca6ea5, totalSupply 3) indexed from the
live RPC now reports ids 0, 1, 2 on its transfers and lists three items with
their owners, matching eth_getLogs topics[3] and ownerOf.

migrations/004_nft_marketplace.sql stays unapplied and now says why: no
marketplace contract is deployed on any Lux chain, so its tables could only
ever be empty. LLM.md's EVM parity list claimed Seaport/LooksRare/Blur/
X2Y2/Rarible/Zora coverage for a package nothing imports; it now says what
runs.

Co-authored-by: Hanzo Dev <[email protected]>
2026-08-29 13:35:20 -07:00
zeekayandHanzo Dev abb63c79b4 An event topic is the hash of its signature, and now a test says so
Seventeen of the twenty-three marketplace topics in nft.go did not hash from
the signature written beside them. The wrong ones were not typos. Zora's
AskCreated and AskCancelled were the same sixty-three characters with a
different first byte. Foundation's settled topic was "e6" thirty-two times.
Blur's cancel matched the real hash for eighteen characters and then diverged —
a remembered prefix with the rest filled in. The six that were right were
Seaport's and LooksRare v1's, the ones anybody could have copied.

Fourteen are corrected by derivation. Three name a struct — LibPart.Part,
Item, Ask — and a topic hashes the canonical signature, where a struct is
written out as a tuple, so those cannot be derived from the text beside them.
They are marked unverified rather than guessed at, because replacing a
fabricated value with a confident one is the same mistake twice.

A wrong topic does not fail. It matches no log, so an indexer built on it
reports that a marketplace has never traded, and from outside that is
indistinguishable from a quiet market. The test derives every topic it can and
refuses the two shapes the bad ones had: a repeating unit, and a long head
shared with a sibling.

Nothing imports this package yet, which is the only reason it never showed.

Co-authored-by: Hanzo Dev <[email protected]>
2026-08-29 12:15:47 -07:00
zeekayandHanzo Dev 64519916bf the corporate name is Lux Industries Inc
Lux Partners Limited is not the entity behind this work. Every place the
old name stood — copyright lines, site footers, brand config, legal and
compliance text — now names the company that actually holds it.

lux.fund is the exception and is not renamed to match: that site belongs
to Lux Assets Management LLC, a different company, and it says so.

Two kinds of line were left for a person rather than rewritten. A dated
news item recording that Lux Partners Limited was established in the Isle
of Man is a historical fact, and renaming it would falsify the record. And
a sentence asserting that the company is domiciled in the Isle of Man is a
claim about a jurisdiction, not a name — an Inc or an LLC is not an Isle
of Man company, so swapping the name there would assert something untrue.

Co-authored-by: Hanzo Dev <[email protected]>
v1.5.7
2026-08-28 13:01:04 -07:00
zeekay 62a5d63bf6 Name Zen in the hero card's font stack
The social card asked for Inter first. That is not a face this estate
licenses, ships or ever drew, so a renderer with Inter installed painted
the wrong face and one without it silently fell through to system-ui.
Zen leads now; the same tail follows it.
2026-08-28 11:41:46 -07:00
zeekay 0d4a268c3a style(docs): swap the geist-named font tokens for Zen 2026-08-23 15:02:00 -07:00
zeekayandHanzo Dev 984494b3a8 Take the sqlite C under the name nothing else claims
The wrapper this reached for registers the driver as "sqlite", and so does
modernc.org/sqlite, which arrives here with hanzoai/replicate. Two packages
under one name is a panic in init, before main runs.

csqlite is the same house C under "sqlite3" — the name every sql.Open here
already names, and one nothing else in this graph takes.

Co-authored-by: Hanzo Dev <[email protected]>
v1.5.6
2026-08-13 15:12:22 -07:00
zeekayandHanzo Dev 6920479c85 One sqlite in the binary
Two packages compiled the same amalgamation: upstream mattn/go-sqlite3 here,
and hanzoai/csqlite by way of hanzoai/sqlite, which luxfi/graph moved to. A
binary linking both — the explorer links all three of us — defines every
sqlite3_* symbol and every cgo trampoline twice and fails at link. It fails on
darwin; linux is laxer about duplicates, which is the only reason a build ever
got through.

hanzoai/sqlite is the house driver and csqlite registers both "sqlite" and
"sqlite3", so nothing but the import line changes: every sql.Open here still
names the driver it always named.

Co-authored-by: Hanzo Dev <[email protected]>
v1.5.5
2026-08-13 15:08:06 -07:00
zeekayandHanzo Dev fe9cf8d4f7 evm: notice when the chain under us has been rebuilt from genesis
The zoo chain was relaunched and its index never followed. It is serving
24,607 blocks of a chain that no longer exists: at height 5000 the index
holds 0xd798ca91 where the chain now has 0xa6c56d04, and its newest block
is dated two days ago while the live chain sits at 9,564.

indexNewBlocks resumes from MAX(number)+1 and loops while that is <= the
head. A chain rebuilt from genesis reports a head far below everything
already stored, so the resume point lands past it, the loop body never
runs, and the cursor cannot move again. There is no recovery from this by
waiting: the further the new chain gets, the longer it stays behind a
cursor left on the old one.

Deciding this on height alone would be wrong in the other direction. One
backend of a load-balanced set lagging its peers reports the same shape as
a relaunch, and erasing a chain because a node was slow is worse than
being stale. So the height is only used to decide when to ask a question
that has a real answer: block 0's hash. Every node knows which chain it is
on however far behind it is, so a changed genesis means a different chain
and an unchanged one settles it. The streak before the probe keeps the
common case free of extra RPCs.

Each chain is indexed into its own database, so forgetting one reaches
nothing else. The hash is recorded on the first poll that can reach the
chain, because a relaunch cannot be recognised without knowing what came
before it, and an unreadable or unrecorded genesis is not evidence of
anything, so both keep the index.

The graph indexer has resolved this for its own cursor since v1.2.x. This
gives the block indexer the same footing.

Co-authored-by: Hanzo Dev <[email protected]>
v1.5.4
2026-08-11 12:46:30 -07:00
zeekayandHanzo Dev 7c85b79a62 explorer: name the block's transaction count what the SPA reads
Block rows and block details rendered the Txn label with nothing after it.
Lux block 1106999 has 4 transactions by RPC and the page showed no number.

formatBlock emitted the column's own name, tx_count. The SPA's Block type
declares transactions_count and every render site reads it — BlocksTableItem,
BlocksListItem, LatestBlocksItem, BlockDetails — so the value arrived under a
key nobody looked up and each cell fell back to undefined. Rows that arrived
over the realtime channel DID show a count, which is what made this look like a
data problem rather than a naming one: that path already renames the field
(lib/socket/sse.ts toApiBlock), so the same block read correctly when pushed
and blank when fetched.

Renamed rather than aliased: nothing reads a block's tx_count, so a second
spelling would only be a second thing to keep in step. formatPlatformBlock gets
the same name — P-Chain rows go through the same block widgets.

The suite asserted the old key by PRESENCE, in three places, which is why a
rename is what it takes to notice. TestBlockFieldValues now pins the value:
want 3, got <nil> on the old name.

Co-authored-by: Hanzo Dev <[email protected]>
v1.5.3
2026-08-08 06:17:16 -07:00
zeekayandHanzo Dev d8b8f8fa23 explorer: fold address case at the lookup boundary, and emit the token contract the SPA reads
Two defects that both fail silently, which is worse than erroring.

Every wallet emits EIP-55 checksummed addresses. The hex pattern accepts
mixed case, so a checksummed address passed validation and then matched no
row — the route answered 404, and the page rendered WLUX, a contract holding
149M LUX, as an empty EOA. The stored hash is lowercase, so the two spellings
have to fold to one key. That fold now happens once, in j()/csvHandler(),
which every route already passes through; handlers keep doing lookups and
stay in their lane. Only {hash} and {addr} fold — {id}, {pair}, {prefix} and
{item} are not hex and are case-significant.

formatToken emitted address/holders/trust_score while the SPA's TokenInfo
(luxfi/explore types/api/token.ts) reads address_hash/holders_count, so
TokensTable keyed every row on undefined and the page crashed. Renamed to
the contract rather than shimming the client, and fixed the second producer
of the same object in formatTokenTransfer, which had drifted to its own
spelling. trust_score had no consumer anywhere: TokenReputation is
'ok' | 'scam', a fraud flag, not the 0-100 completeness heuristic that
computed it — deriving one from the other would have called any token
lacking an icon a scam. reputation is null until there is a real oracle, and
the dead scorer is gone. Its toBool/toInt helpers were generic coercion
braided into a scoring file; they move to convert.go with their tests.

Co-authored-by: Hanzo Dev <[email protected]>
v1.5.2
2026-08-07 09:00:19 -07:00
zeekayandHanzo Dev a6fa1e8268 Merge remote-tracking branch 'origin/main'
Co-authored-by: Hanzo Dev <[email protected]>
2026-08-06 18:37:52 -07:00
zeekayandHanzo Dev f4d8b7a114 rpc: finish the /v1/ sweep, and stop sending Avalanche to /v1/
luxd serves exactly one HTTP prefix -- server/http/server.go:33 sets
baseURL = "/v1" and every route derives from it -- so /ext/* 404s on any
luxd. Avalanche is the mirror image: api.avax.network really does serve
/ext/bc/C/rpc, and pointing it at /v1/ breaks it.

31a1ee7 converted README.md only. This finishes the job and corrects the
overshoot in the same pass:

  config/chains.yaml     sparklepony, testnet.sparklepony, pars,
                         testnet.pars  ->  /v1/   (luxd hosts)
                         avax stays on /ext/
  chains.example.yaml    avax stays on /ext/
  docs/configuration.mdx LUX_{C,P,X}_RPC and the c/p/x_chain block, all
                         127.0.0.1:9630 and :9650 luxd  ->  /v1/
  docs/index.mdx         localhost:9650 and api.lux.network  ->  /v1/

Measured, positive and negative control per host:
  api.lux.network/v1/bc/C/rpc  -> 200 0x17871    /ext -> 404
  api.pars.network/v1/bc/C/rpc -> 200 0x78d65    /ext -> 404
  api.lux-test.network/v1/...  -> 200 0x17870    /ext -> 404

evm/transport/transport_test.go is deliberately left at HEAD. Its
isLuxdEndpoint gate is literally strings.Contains(endpoint, "/v1/"), so
the table is /v1/ throughout by design.

go test ./evm/transport/... ok 15.429s. Both YAML files parse. This repo
does NOT build before this change -- cmd/indexerd fails at link with
duplicate sqlite3 symbols, verified identical with these changes stashed
-- so nothing here is tagged.

Co-authored-by: Hanzo Dev <[email protected]>
2026-08-06 18:35:56 -07:00
zeekayandHanzo Dev 31a1ee7d6e rpc: /ext/ -> /v1/ on our own hosts
luxd serves /v1/*; /ext/* 404s. Third-party chains keep their own paths.

Co-authored-by: Hanzo Dev <[email protected]>
2026-08-03 21:02:00 -07:00
zeekayandHanzo Dev f816a9e7fa build: bump Go builder images to 1.26.5, set GOTOOLCHAIN=auto
Currency bump: golang builder images -> 1.26.5 (latest stable).

Adds ENV GOTOOLCHAIN=auto to each Go builder stage. The official golang
images set GOTOOLCHAIN=local, so a builder image older than the module's
go directive is a hard mid-build failure. The pin stays the hermetic fast
path; auto is the safety net for the next go.mod bump.

No go.mod go directive was changed. Builder images move; directives stay.

Co-authored-by: Hanzo Dev <[email protected]>
2026-08-01 16:26:31 -07:00
zooqueenandHanzo Dev de500be239 ci: one CI path — .hanzo/workflows
Both workflows here named labels no runner on this forge carries. docker.yml
used the bare `[self-hosted, linux, amd64]` triple and docs.yml the same; the
pool is named `lux-build-linux-amd64`, nothing answers to the triple, and a job
naming a label nothing carries does not fail — it waits. Note that
.github/actionlint.yaml in this repo has registered `lux-build-linux-amd64` as
the self-hosted label for some time; the workflows had simply never followed it.

The image build moves to .hanzo/workflows/release.yml. Two further things had
to change or it would have failed on the first runner that claimed it:

  * ghcr login used the instance GITHUB_TOKEN, which on this forge is a Hanzo
    Git token with no rights at ghcr.io. It now uses GHCR_USER and GHCR_TOKEN,
    the org Actions secrets sourced from KMS.

  * the layer cache was `type=gha`, the GitHub-hosted Actions cache service,
    now the backend-independent registry cache.

Dropped with it: the linux/arm64 half of the image. It was produced by QEMU
emulation on an amd64 runner, which is hours rather than minutes. This image is
amd64-only until we own an arm64 runner and it can return as a native matrix
entry.

docs.yml's build survives as .hanzo/workflows/docs.yml; its publish does not.
configure-pages, upload-pages-artifact and deploy-pages all speak to the GitHub
Pages API, which this forge does not have. Building still fails on the commit
that breaks the docs, and it stays path-filtered to docs/**, but the site is no
longer published from CI — that returns when it is served from the PaaS.

Co-authored-by: Hanzo Dev <[email protected]>
2026-07-30 17:14:21 -07:00
zeekayandHanzo Dev e9498c93fb deps: drop go.sum lines that disagree with the checksum log
These hashes were recorded from direct VCS fetches made while GOPRIVATE covered
github.com/luxfi/*, which switches off the module proxy and checksum
verification together. Tags moved afterwards, so what is written down here no
longer matches what sum.golang.org holds and the build refuses to verify.

proxy.golang.org still serves the originally-published bytes and those verify
against the log, so dropping only the disagreeing lines and re-tidying restores
a verified module graph with no version change. Lines that agree are untouched;
this is not a regenerated go.sum.

The failure followed the machine rather than the repository — the same commit
built wherever the module cache was clean. Any machine or CI runner that
fetched luxfi modules under the old GOPRIVATE holds the same poisoned entries.

Co-authored-by: Hanzo Dev <[email protected]>
2026-07-28 09:38:27 -07:00
zeekayandHanzo Dev 5ce7dca138 fix(explorer): a zero that means "unavailable" is a lie
Every figure below was rendered as 0 on explore.lux.network while the
chain said otherwise. None of them was missing data — the queries asked
for columns that are not there, or read columns nothing writes.

  /addresses answered {"items":[]} while /stats reported 72 addresses:
  the ORDER BY named `transactions_count`, which is the Blockscout-legacy
  spelling; luxfi/indexer's evm_addresses spells it `tx_count`. SQLite
  raised "no such column", the handler swallowed it into an empty page,
  and it stayed empty forever. Same guess broke evm_tokens' address
  column. detectColumn now asks the database instead.

  Token "Holders 0" sat directly above a populated holder list:
  evm_tokens.holder_count is never written by the indexer. Holders and
  transfers are now counted from evm_token_balances / evm_token_transfers
  in the same statement that selects the token — one query, not N+1 — and
  the token list is ranked by that count instead of by a column of zeros.

  Address balance read 0 for every address, WLUX's 159,126,795.518 LUX
  included: evm_addresses.balance is written as the literal '0' on first
  sight and never updated. Current state belongs to the chain, not to an
  index of it, so balances now come from the node — one batched
  eth_getBalance per page. No node configured, or no answer, means the
  balance is unavailable, and unavailable is null.

  "Burnt fees 100%" on every block: burnt_fees was gas_used x base_fee,
  which is the Ethereum EIP-1559 burn. Lux does not burn it. creditTxFee
  credits the whole fee to the coinbase (0x0100..0000, no code, no key)
  unless the fee split is active, and it has never fired on mainnet.

  average_block_time was structurally 0 — subtracting two TEXT datetimes
  in SQLite yields 0 — and gas_used_today compared those TEXT timestamps
  lexically against datetime('now'), matching nothing. Both go through
  strftime('%s') now, and transactions_today is counted rather than
  hardcoded nil.

Co-authored-by: Hanzo Dev <[email protected]>
v1.4.7
2026-07-27 14:25:21 -07:00
zeekay 69cc8f9adf chore: sync working tree
Commits 1 outstanding change(s) that were sitting uncommitted.
No build artifacts and no secrets in the changeset (both checked).
2026-07-26 10:13:40 -07:00
zeekay 0b0a861363 fix(deps): reconcile go.sum against what the registry actually serves
Chasing these one at a time was whack-a-mole — every repair surfaced the next
moved tag (age, pq, threshold, zap, consensus, constants, sdk, keys…). This is
the systematic pass instead: every distinct luxfi/hanzoai module@version in the
workspace (692 of them) was resolved against proxy.golang.org + a direct fetch,
and any go.sum line disagreeing with what is actually served was corrected.

Not an attack, and checked rather than assumed: for each case the proxy and a
direct fetch AGREE with each other and differ from the recorded hash. Two
independent transports agreeing means nothing is rewriting bytes in flight —
the tags moved at source. sum.golang.org still holds the original, but
GOPRIVATE covers github.com/luxfi/* with GOSUMDB=off, so our own modules never
consult the checksum DB and a moved tag splits consumers silently instead of
failing at publish time.

Only the recorded hash changes. No selected version moves, and `go mod tidy`
was deliberately NOT run, so nothing is upgraded as a side effect.

Verified: `go list -m all` resolves with no checksum error.

The durable fix is upstream: treat a published version as immutable. Cut
x.y.z+1 instead of moving a tag — with GOSUMDB off, no consumer can detect it.
2026-07-26 04:16:27 -07:00
zeekay 01d674241a fix(deps): correct moved-tag hashes for luxfi modules in go.sum
Several luxfi versions carry TWO different contents across this workspace,
because published tags were moved instead of a new patch being cut:
[email protected], [email protected], [email protected], [email protected], [email protected].

Adjudicated before editing, since "checksum mismatch / SECURITY ERROR" is also
what a real supply-chain attack looks like. It is not one here: sum.golang.org
holds the OLD hash while proxy.golang.org and a direct fetch BOTH serve the same
NEW bytes. Two independent transports agreeing means nothing is rewriting
content in flight — the tag moved at source. The sumdb entry is a fossil:
GOPRIVATE covers github.com/luxfi/* with GOSUMDB=off, so our own modules never
consult the checksum DB and a moved tag splits consumers silently.

The old bytes are served by nothing now, so a stale pin can never build.
Corrected to the only content that exists, in BOTH line forms (h1: and
/go.mod h1:) — Go reports these one at a time, so a partial fix just relocates
the error.

Deliberately no `go mod tidy`: this changes no selected version, only the
recorded hash of versions already chosen.

Verified: `go list -m all` resolves with no checksum error.

The durable fix is upstream: never move a published tag, cut x.y.z+1 instead.
2026-07-26 02:42:49 -07:00
zeekayandHanzo Dev 755319c47c feat(platform): wire P-Chain block + validator indexing (additive)
Standalone explorer API now serves a P-Chain variant when a pchain_blocks
table is present: GET /blocks, /blocks/{id}, /main-page/blocks read the
linear block table, and a new GET /validators returns the synced validator
set (weight/stake, start/end time, uptime, delegation fee, BLS signer
pubkey+PoP, potential reward, connected, per-node delegator_count).

Adapter fixes required for the default SQLite query backend:
- SyncValidators no longer uses Postgres-only to_timestamp(); timestamps are
  bound as time.Time, which both the SQLite and Postgres drivers accept for a
  TIMESTAMP column (regression covered by a real RPC->SQLite test).
- Capture the validator BLS signer (publicKey + proofOfPossession); new
  bls_public_key / bls_proof_of_possession columns on pchain_validators.
- Fall back to weight when the RPC omits the deprecated stakeAmount.

EVM path untouched: block/main-page routes branch on the platform flag; all
other routes are unchanged.

Co-authored-by: Hanzo Dev <[email protected]>
2026-07-08 07:12:16 -07:00
zeekayandHanzo Dev e616aa286e chore: migrate luxd HTTP routes /ext -> /v1
Drop the Avalanche-heritage /ext prefix; /v1 is the single canonical route
surface (one way, no backward compat). The node's baseURL is the source of
truth; clients, SDKs, CLI, indexer, maker, genesis, netrunner, and the
k8s/compose/gateway/explorer configs are updated to match.

Co-authored-by: Hanzo Dev <[email protected]>
2026-07-01 11:40:21 -07:00
zeekayandHanzo Dev 8d5a0db0eb fix(evm/defi): rename duplicate TestEmptyLogs to subject-scoped names
Two distinct tests (ParseGovernanceEvents vs ParseTeleportEvents empty-log
handling) collided on the name TestEmptyLogs, breaking compilation of the
evm/defi test package. Rename to TestGovernanceEmptyLogs / TestTeleportEmptyLogs
— no coverage change, package compiles + both pass.

Co-authored-by: Hanzo Dev <[email protected]>
v1.5.1
2026-06-30 16:01:01 -07:00
zeekayandHanzo Dev 984a761b64 fix(deps): repair vanished pins / go.sum drift ( core-bump@latest [email protected]) + build green
Co-authored-by: Hanzo Dev <[email protected]>
v1.5.0
2026-06-30 14:11:06 -07:00
zeekay 2303cb398a Merge branch 'bump/luxdb-v1.19.3' 2026-06-30 14:10:29 -07:00
zeekay bd887f0e2a docs(brand): add hero banner 2026-06-28 20:37:40 -07:00
zeekay 535a3f89dd chore(brand): dynamic hero banner 2026-06-28 20:37:39 -07:00
zeekayandGitHub 637b5c65db chore: bump luxfi/database v1.19.3 (#21)
Co-authored-by: zeekay <[email protected]>
2026-06-25 15:24:11 -07:00
zeekay d909d7f168 chore: bump luxfi/database v1.19.3 2026-06-25 13:06:36 -07:00
zooqueen 5f7a20b00c fix(explorer): real tx fee + block burnt_fees/rewards; value as decimal string (fixes SPA NaN/null on fee-less txs) v1.4.6 2026-06-23 14:41:27 -07:00
zeekay a534262058 scrub branding + corona→corona (OSS brand hygiene) v1.4.5 2026-06-10 23:41:10 -07:00
zeekay 22723298b0 ci: route to canonical native arcd labels [self-hosted, linux, <arch>]
Replaces non-canonical scale-set / org-prefixed labels with the
existing labels every arcd host registers with. Matches evo for
amd64 and spark for arm64. No new labels added.
2026-06-10 20:22:29 -07:00