JIT Evidence Reconstruction
Implemented — BackwardLabs/daejang-jit-engine @ 8cb725d
This is the most fully implemented component in the system. It restores only the transaction evidence needed for a requested subject, and emits Observation-level evidence.
Why restoration is just-in-time
Continuously storing detailed execution data for an entire chain makes trace and state collection prohibitively expensive. But a minimal reverse index — a block number, a transaction index, and a set of match bits — cannot by itself establish:
- whether that position is the same canonical block the index snapshot pointed at
- what the actual transaction hash and inclusion are
- whether a coarse match is real account participation or a false positive
- the exact
logIndex,traceAddress, orauthorizationIndexinvolved - whether execution succeeded, reverted, or was reorged
- the asset quantity sign and Observation origin from the account's perspective
- whether the result is incomplete because evidence is missing or because the schema cannot express it
So a replay layer sits between the reverse index and canonical Observations. It is reproducible, idempotent, and does not hide failure.
A reverse-index hit is never accepted as proof of relevance on its own. The engine re-resolves the block and transaction from the provider and records the observed block hash.
JIT processing at a glance
The solid path is the normal evidence path. Dashed paths show cases that cannot produce a complete Observation. They do not disappear: every selected candidate reaches a stored terminal outcome with the available evidence and limitation.
| Stage | Responsibility |
|---|---|
| Candidate selection | Limit expensive reconstruction to transactions that may involve the requested accounts |
| Context checks | Reconfirm chain identity, canonical inclusion, account scope, and request consistency |
| Evidence reconstruction | Collect and normalize the transaction, receipt, log, trace, and relevant state evidence |
| Observation | State only the account-scoped facts supported by committed execution effects |
| Validation and persistence | Validate the evidence contract and commit artifacts, revisions, and the terminal outcome |
The JIT path deliberately stops at Observation. Swap, bridge, self-transfer, valuation, cost basis, and tax meaning belong to later layers.
Input contract
interface StartJitRun {
generationId: string;
subjectId: string;
indexSnapshotId: string;
evidenceProfile: 'EVM_ACCOUNT_FULL';
accounts: Array<{
accountId: string;
chainId: string;
address: string;
ownershipFrom: string;
ownershipTo?: string;
}>;
candidates: Array<{
accountId: string;
chainId: string;
blockNumber: string;
transactionIndex?: number;
blockEventIndex?: number;
matchBits: number;
}>;
}
Both accounts and candidates must be non-empty, and every candidate must reference an account from the same request.
Normalization and validation
| Field | Rule |
|---|---|
| IDs | Letters, digits, ., _, :, - |
chainId | CAIP-2 EVM form eip155:<decimal chain id>; a candidate's chain must equal its account's chain |
address | 20-byte 0x EVM address, normalized to lowercase; EIP-55 checksum not required |
| Ownership window | RFC 3339 timestamps as [ownershipFrom, ownershipTo); the end is optional and must not precede the start |
blockNumber | Non-negative canonical decimal string without leading zeroes, except 0 |
| Candidate coordinate | Exactly one of transactionIndex or blockEventIndex |
matchBits | Non-zero bitwise OR of known bits in 0x01..0x80 |
| Evidence profile | Fixed to EVM_ACCOUNT_FULL; no reduced per-request profile |
| Duplicate candidates | The first identical locator in a snapshot is canonical; later occurrences terminate as DUPLICATE |
| Unknown fields | Stripped during normalization |
Match bits
| Bit | Meaning |
|---|---|
0x01 | TX_FROM |
0x02 | TX_TO |
0x04 | ASSET_FROM |
0x08 | ASSET_TO |
0x10 | ERC4337_ACCOUNT |
0x20 | EIP7702_AUTHORITY_CANDIDATE |
0x40 | NATIVE_INTERNAL_FROM |
0x80 | NATIVE_INTERNAL_TO |
Match bits are discovery hints. Exact-hit reconstruction can still return NOT_RELEVANT. Internal call, log, and authorization coordinates are reconstructed from execution evidence — they are not accepted as external candidate coordinates.
Implemented capabilities
- Immutable selection snapshot and selection digest
- Exact-hit and bounded-closure selection for candidate transactions
- Provider retry, failover, chain identity confirmation, and provider divergence detection
- Evidence collection from canonical transaction, receipt, log, and trace
- ERC-20, ERC-721, and ERC-1155 transfer Observations
- ERC-4337
UserOperationEvent, EIP-7702 authorization, and withdrawal observation - Reorg and inclusion revision handling
- Execution result cache, singleflight, and bounded concurrency
- CUE schema validation
- A Go gRPC daemon,
jitd, exposingCandidateQueryServiceandJitEngineService - Access control by Unix peer UID or mTLS subject
- Storage adapter with artifact staging and terminal commit
- Graceful shutdown, health endpoint, and secret redaction
Wallet and protocol assumptions
- An input address is not assumed to be an EOA. EOA, contract wallet, and ERC-4337 smart-account addresses are all emitted as
WALLETaccounts. - EIP-7702 candidates are verified against recovered authorization and before/after account state. The candidate bit alone does not create an Observation.
- ERC-4337
userOpHashanduserOpIndexare retained as native execution evidence. The pinned schema has no first-classUSER_OPERATIONcoordinate, so affected work terminates as partial or unsupported rather than being mapped onto a fabricated transaction coordinate. - The current
ERC4337_ACCOUNTexact match is the user-operationsender. Paymaster and actual gas-payer roles need separate discovery semantics before they can become wallet hits. - Transaction-less block credits and withdrawals use
blockEventIndex. The pinned schema has no transaction-less Observation origin, so these candidates currently terminate asUNSUPPORTEDwith native coordinates preserved.
Deliberate boundaries
The engine does not do the following, and this is by design rather than by omission:
- Determine economic events such as swap, bridge, or self-transfer
- Produce Postings, KRW valuation, cost basis, or tax policy application
- Generate a final report or submit a GIWA commitment
- Infer an ERC-4337 paymaster or actual gas payer as a wallet ownership relation
- Invent schema coordinates that do not exist
- Modify an already-published generation in place
Two further scope notes:
- The output discovery range is derived from the minimum and maximum resolved candidate blocks per account. It is not a claim that the engine independently scanned every block in that interval.
- Artifact retention, eviction, and an
EVICTEDlifecycle require a durable production store and are not implemented by the in-memory reference store.
Pinned schema contract
| Field | Value |
|---|---|
| Repository | BackwardLabs/schema |
| Module digest | d08257dbf7f22a381540cc1331ca6047a53bf0863eaa42d28d8db65bde371303 |
Verification
go test ./..., go vet ./..., and go build ./... pass on the base branch.
These tests cover fixture, mock-provider, transport, and storage-adapter boundaries. They do not demonstrate behavior against production RPC providers or a full product path.