Files
zeekayandHanzo Dev 57d5786f67 The O-chain answers the differential, in all three languages
chains/oraclevm is 213 lines and is not the chain. It re-exports
github.com/luxfi/oracle/vm, which is 1628; chains/relayvm is 161 lines
over luxfi/relay/vm's 2077. Of the eight chains the node runs that the
differential did not cover, the two that looked smallest by an order of
magnitude were the two that were not there.

The O-chain's wire is not a codec frame. ParseBlock is json.Unmarshal
and Bytes is json.Marshal, so the wire is whatever encoding/json writes
for the chain's structs, and computeID hashes the block marshalled
AGAIN rather than the bytes it was handed. So a block does not
round-trip its own id, and a member the reader accepts and omitempty
then drops does not change it. Both are vectors now.

Its genesis block is built with time.Unix, which is local time, and
MarshalJSON writes the offset: one genesis file gives block id
6cf00752 with TZ unset on a -08:00 box and f4970a27 under
Asia/Kolkata. Two validators in two timezones are on different chains
from block zero. No vector can carry that id, so O_GENESIS pins the
genesis through a re-marshal instead and conformance/README.md says why
rather than letting the workaround hide the bug.

153 O vectors: the JSON wire and the id over it, the request id that
gives a request its name, the Merkle root a request's records commit
to, and the three refusals the observation plane has. The Rust and C++
ports answer every one of them and decline nothing, and all three
implementations agree on all six compared fields.

The C++ port compiles chains/cpp/fhevm's id.cpp and json.cpp rather
than carrying a second opinion about what encoding/json accepts. Those
two files are chain-neutral and their name is a debt: the right home is
a shared one, and moving them is a rename across fifteen F-chain files.

Co-authored-by: Hanzo Dev <[email protected]>
2026-09-07 20:07:02 -07:00

71 lines
2.7 KiB
Go

// SPDX-License-Identifier: BSD-3-Clause-Eco
// The chain identity each evaluator was configured with, asked as a vector.
//
// Three of the chains hash something that is NOT on the wire into every id they
// derive: the Z-chain opens its block id with sha256(ChainID ‖ NetworkID), the
// F-chain does the same and binds its signing preimage to the chain id besides,
// and the Q-chain carries the pair in the block but refuses a block whose pair
// is not the one the node serves. So the identity is part of the corpus's
// contract, and an evaluator that picked its own numbers derives a different id
// for every well-formed vector on that chain.
//
// That is not a hypothetical. The first run of this differential disagreed on
// the id of all twenty-five Z vectors, and on none of the malformed ones, for
// exactly one reason: the Go evaluator was configured for chain 40 and the C++
// one for chain 4. Twenty-five identical-looking rows said "the two chains
// derive different ids", which is what a genuine hash fork looks like, and none
// of them said which number was wrong.
//
// One vector per affected chain fixes that. It carries no bytes: each
// evaluator prints the identity IT was built with, so a mismatch is one row
// naming both numbers, and the rows underneath can be read for what they
// actually are.
package main
import "fmt"
// identities is the contract, in one place. Everything that reads a chain
// identity in this generator reads it from here.
var identities = []struct {
Chain string
VectorI string
ChainID byte
Network uint32
}{
{"Q", "Q_CHAIN_IDENTITY", qChain, networkID},
{"Z", "Z_CHAIN_IDENTITY", zChain, networkID},
{"F", "F_CHAIN_IDENTITY", fChain, networkID},
{"O", "O_CHAIN_IDENTITY", oChain, networkID},
}
func identityVectors() []Vector {
v := make([]Vector, 0, len(identities))
for _, in := range identities {
v = append(v, Vector{ID: in.VectorI, Chain: in.Chain, Op: "identity", Wire: none})
}
return v
}
// evalIdentity answers with the numbers THIS evaluator holds, never with the
// ones the corpus asked about — a row that echoed the question would agree with
// every implementation, including one configured for another chain entirely.
func evalIdentity(v Vector) Result {
for _, in := range identities {
if in.Chain != v.Chain {
continue
}
return Result{
ID: v.ID,
Parse: "ok",
Kind: "ChainIdentity",
Hash: hexID(id(in.ChainID)),
Syntactic: fmt.Sprintf("network=%d", in.Network),
Exec: VOK,
Note: "the identity this evaluator derives ids under",
}
}
return Result{ID: v.ID, Parse: VInternal, Kind: none, Hash: none,
Syntactic: VInternal, Exec: VInternal, Note: "no identity for chain " + v.Chain}
}