shadow

package
v0.0.30 Latest Latest
Warning

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

Go to latest
Published: Apr 2, 2026 License: Apache-2.0 Imports: 13 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.

func FetchReport added in v0.0.30

func FetchReport(ctx context.Context, downloader seis3.Downloader, bucket, key string) (*DivergenceReport, error)

FetchReport downloads and decodes a DivergenceReport from S3.

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