shadow

package
v0.0.26 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Mar 31, 2026 License: Apache-2.0 Imports: 10 Imported by: 0

Documentation

Overview

Package shadow provides block-by-block comparison between a shadow chain node and a canonical chain node. The comparison is layered:

  • Layer 0: Block header hashes (AppHash, LastResultsHash, gas). If these match, the block is identical and deeper layers are skipped.
  • Layer 1: Transaction receipt comparison (status, gas, logs, etc.). Run only when Layer 0 fails, to isolate which transactions diverged.
  • Layer 2: State diff comparison (future).
  • Layer 3: Execution trace comparison (future).

Index

Constants

This section is empty.

Variables

This section is empty.

Functions

func RenderMarkdown added in v0.0.25

func RenderMarkdown(r *DivergenceReport) string

RenderMarkdown produces a human-readable investigation report from a DivergenceReport. The output is designed to be consumed by engineers or LLM agents analyzing why a shadow node diverged from the canonical chain.

Types

type ChainSnapshot added in v0.0.25

type ChainSnapshot struct {
	Block        json.RawMessage `json:"block"`
	BlockResults json.RawMessage `json:"blockResults"`
}

ChainSnapshot captures the raw RPC responses from one chain at a specific height. The JSON is preserved verbatim for offline analysis.

type Comparator

type Comparator struct {
	// contains filtered or unexported fields
}

Comparator performs block-by-block comparison between a shadow node and a canonical chain node via their RPC endpoints.

func NewComparator

func NewComparator(shadowRPC, canonicalRPC string) *Comparator

NewComparator creates a Comparator that queries shadowRPC for the local shadow node and canonicalRPC for the reference chain.

func (*Comparator) BuildDivergenceReport added in v0.0.25

func (c *Comparator) BuildDivergenceReport(ctx context.Context, height int64, comparison CompareResult) (*DivergenceReport, error)

BuildDivergenceReport captures a complete investigation artifact at the given height. It pairs the comparison result with the full raw RPC responses from both chains so engineers can diagnose offline.

func (*Comparator) CompareBlock

func (c *Comparator) CompareBlock(ctx context.Context, height int64) (*CompareResult, error)

CompareBlock performs a layered comparison for the given block height. Layer 0 (block headers) always runs. If Layer 0 detects a divergence, Layer 1 (transaction receipts) is run to provide diagnostic detail.

type CompareResult

type CompareResult struct {
	// Height is the block height that was compared.
	Height int64 `json:"height"`

	// Timestamp is the UTC time the comparison was performed.
	Timestamp string `json:"timestamp"`

	// Match is true when all checked layers agree between shadow and canonical.
	Match bool `json:"match"`

	// DivergenceLayer is the first layer that detected a mismatch.
	// Nil when Match is true.
	DivergenceLayer *int `json:"divergenceLayer,omitempty"`

	// Layer0 holds the block-level hash comparison. Always populated.
	Layer0 Layer0Result `json:"layer0"`

	// Layer1 holds the transaction receipt comparison.
	// Only populated when Layer 0 detected a divergence.
	Layer1 *Layer1Result `json:"layer1,omitempty"`
}

CompareResult holds the comparison output for a single block.

func (*CompareResult) Diverged

func (r *CompareResult) Diverged() bool

Diverged returns true when the comparison detected a mismatch at any layer.

type DivergenceReport added in v0.0.25

type DivergenceReport struct {
	Height     int64         `json:"height"`
	Timestamp  string        `json:"timestamp"`
	Comparison CompareResult `json:"comparison"`
	Shadow     ChainSnapshot `json:"shadow"`
	Canonical  ChainSnapshot `json:"canonical"`
}

DivergenceReport is a self-contained investigation artifact for a single app-hash divergence event. It includes the layered comparison result plus the full block and block_results from both chains, giving engineers all the context needed to diagnose why the shadow node diverged without querying external systems.

type FieldDivergence

type FieldDivergence struct {
	Field     string `json:"field"`
	Shadow    any    `json:"shadow"`
	Canonical any    `json:"canonical"`
}

FieldDivergence records a single field-level mismatch in a tx receipt.

type Layer0Result

type Layer0Result struct {
	AppHashMatch         bool `json:"appHashMatch"`
	LastResultsHashMatch bool `json:"lastResultsHashMatch"`
	GasUsedMatch         bool `json:"gasUsedMatch"`

	// Raw values are included when there is a mismatch, for diagnostics.
	ShadowAppHash    string `json:"shadowAppHash,omitempty"`
	CanonicalAppHash string `json:"canonicalAppHash,omitempty"`

	ShadowLastResultsHash    string `json:"shadowLastResultsHash,omitempty"`
	CanonicalLastResultsHash string `json:"canonicalLastResultsHash,omitempty"`

	ShadowGasUsed    int64 `json:"shadowGasUsed,omitempty"`
	CanonicalGasUsed int64 `json:"canonicalGasUsed,omitempty"`
}

Layer0Result compares block-level hashes. This is the cheapest check; if all fields match, the block is identical and no further comparison is needed.

func (Layer0Result) Match

func (r Layer0Result) Match() bool

Match returns true when all Layer 0 fields agree.

type Layer1Result

type Layer1Result struct {
	// TotalTxs is the number of transactions in the block.
	TotalTxs int `json:"totalTxs"`

	// TxCountMatch is true when both chains have the same number of txs.
	TxCountMatch bool `json:"txCountMatch"`

	// Divergences lists the per-transaction differences found.
	Divergences []TxDivergence `json:"divergences,omitempty"`
}

Layer1Result compares individual transaction receipts within a block. Only populated when Layer 0 fails.

type TxDivergence

type TxDivergence struct {
	// TxIndex is the position of the transaction within the block.
	TxIndex int `json:"txIndex"`

	// Fields lists which receipt fields diverged.
	Fields []FieldDivergence `json:"fields"`
}

TxDivergence records a mismatch for a single transaction within a block.

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL