Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
23 commits
Select commit Hold shift + click to select a range
7781aaa
feat: add canonical state-diff rewriter
littlehand26 Jul 21, 2026
00fd2aa
chore: pin reviewed Ethermint state-diff commit
littlehand26 Jul 21, 2026
ca84bfa
build: preserve RocksDB layer across commits
littlehand26 Jul 21, 2026
19b6aed
build: refresh gomod2nix dependencies
littlehand26 Jul 21, 2026
ffb8820
feat(statediff): add read-only pilot plans
littlehand26 Jul 21, 2026
b11a848
feat(statediff): harden resumable historical rewriter
littlehand26 Jul 22, 2026
93a1409
chore(statediff): close remaining review gaps
littlehand26 Jul 22, 2026
dccae73
perf(statediff): streamline direct replacement apply
littlehand26 Jul 22, 2026
71592d0
chore(statediff): remove unused preflight wrapper
littlehand26 Jul 22, 2026
e89f833
style: satisfy repository import grouping
littlehand26 Jul 22, 2026
f42638e
feat(statediff): stage reusable legacy changesets
littlehand26 Jul 22, 2026
b897656
feat(statediff): plan directly from frozen IAVL
littlehand26 Jul 22, 2026
1ecb3ad
perf(statediff): parallelize direct IAVL reads
littlehand26 Jul 22, 2026
7d1eb33
fix(statediff): reserve maximum canonical plan input
littlehand26 Jul 22, 2026
cff2825
perf(statediff): preserve direct traversal locality
littlehand26 Jul 22, 2026
504dab2
perf(statediff): add trusted legacy scan mode
littlehand26 Jul 22, 2026
0b74b83
feat(statediff): add production refill segments
littlehand26 Jul 24, 2026
acfd0d1
docs: record production refill segments
littlehand26 Jul 24, 2026
2729e05
feat(statediff): add direct refill batches
littlehand26 Jul 24, 2026
909e59d
feat(statediff): stream full refill directories
littlehand26 Jul 24, 2026
f68cb69
docs: describe streaming refill directories
littlehand26 Jul 24, 2026
3c54744
feat(statediff): refill directly from frozen IAVL
littlehand26 Jul 25, 2026
292ebad
perf(statediff): preserve locality across direct runs
littlehand26 Jul 25, 2026
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
38 changes: 37 additions & 1 deletion .github/workflows/build-rocksdb.yml
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,42 @@ env:
DOCKERFILE: Dockerfile.debank-rocksdb

jobs:
build-statediff-rewriter:
if: github.event_name == 'pull_request'
runs-on: ubuntu-latest
permissions:
contents: read
steps:
- name: Free disk space
uses: jlumbroso/free-disk-space@54081f138730dfa15788a46383842cd2f914a1be # v1.3.1
with:
tool-cache: true
android: true
dotnet: true
haskell: true
large-packages: false
swap-storage: false
- uses: actions/checkout@v4
- uses: docker/setup-buildx-action@v3
- name: Build rewriter image without pushing
uses: docker/build-push-action@v6
with:
file: Dockerfile.statediff-rewriter
context: .
push: false
load: true
platforms: linux/amd64
tags: cronos-statediff-rewriter:pr-${{ github.event.pull_request.number }}
build-args: |
GIT_COMMIT=${{ github.sha }}
provenance: false
- name: Verify rewriter runtime and provenance
run: |
image="cronos-statediff-rewriter:pr-${{ github.event.pull_request.number }}"
test "$(docker image inspect --format '{{ index .Config.Labels "org.opencontainers.image.revision" }}' "${image}")" = "${{ github.sha }}"
test "$(docker run --rm "${image}" --version)" = "${{ github.sha }}"
docker run --rm "${image}" --help

build-rocksdb:
strategy:
fail-fast: false
Expand All @@ -33,7 +69,7 @@ jobs:
id-token: write
steps:
- name: Free disk space
uses: jlumbroso/free-disk-space@main
uses: jlumbroso/free-disk-space@54081f138730dfa15788a46383842cd2f914a1be # v1.3.1
with:
tool-cache: true
android: true
Expand Down
3 changes: 3 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,9 @@

### Improvements

* [Chaintable/cronos#6](https://github.com/Chaintable/cronos/pull/6) feat: add state-diff refill from frozen IAVL, bounded changeset batches, and streaming changeset directories.
* [Chaintable/cronos#6](https://github.com/Chaintable/cronos/pull/6) feat: add bounded production segments for historical state-diff recovery.
* [Chaintable/cronos#3](https://github.com/Chaintable/cronos/pull/3) feat: add fail-closed tooling for canonical historical state-diff recovery.
* [#2095](https://github.com/crypto-org-chain/cronos/pull/2095) feat: add hardcoded unblockable address list that is filtered out of both the mempool and consensus blocklists.

### Bug fixes
Expand Down
35 changes: 35 additions & 0 deletions Dockerfile.statediff-rewriter
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
FROM golang:1.25-bookworm AS go-builder

RUN apt-get update && \
apt-get install -y libgflags-dev libsnappy-dev zlib1g-dev libbz2-dev liblz4-dev libzstd-dev && \
rm -rf /var/lib/apt/lists/*

RUN git clone https://github.com/facebook/rocksdb.git /tmp/rocksdb && \
cd /tmp/rocksdb && \
git checkout v10.5.1 && \
PORTABLE=1 DISABLE_WARNING_AS_ERROR=1 make -j$(nproc) install-shared && \
ldconfig && \
rm -rf /tmp/rocksdb

WORKDIR /code
COPY . /code/
ARG GIT_COMMIT
RUN test -n "${GIT_COMMIT}" && \
GOPRIVATE='github.com/Chaintable/*' make build-statediff-rewriter COMMIT="${GIT_COMMIT}"

FROM ubuntu:22.04

ARG GIT_COMMIT
LABEL org.opencontainers.image.revision="${GIT_COMMIT}"

RUN apt-get update && \
apt-get install -y libsnappy1v5 libgflags2.2 zlib1g libbz2-1.0 liblz4-1 libzstd1 ca-certificates && \
rm -rf /var/lib/apt/lists/*

COPY --from=go-builder /usr/local/lib/ /usr/local/lib/
RUN ldconfig
COPY --from=go-builder /code/build/statediff-rewriter /usr/bin/statediff-rewriter

WORKDIR /work
ENTRYPOINT ["/usr/bin/statediff-rewriter"]
CMD ["--help"]
14 changes: 10 additions & 4 deletions Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -93,26 +93,32 @@ build_tags_comma_sep := $(subst $(whitespace),$(comma),$(build_tags))
ldflags += -X github.com/cosmos/cosmos-sdk/version.Name=cronos \
-X github.com/cosmos/cosmos-sdk/version.AppName=cronosd \
-X github.com/cosmos/cosmos-sdk/version.Version=$(VERSION) \
-X github.com/cosmos/cosmos-sdk/version.Commit=$(COMMIT) \
-X github.com/cosmos/cosmos-sdk/version.BuildTags=$(build_tags_comma_sep)
-X github.com/cosmos/cosmos-sdk/version.Commit=$(COMMIT)

BUILD_FLAGS := -tags "$(build_tags)" -ldflags '$(ldflags)'
BUILD_FLAGS := -tags "$(build_tags)" -ldflags '$(ldflags) -X github.com/cosmos/cosmos-sdk/version.BuildTags=$(build_tags_comma_sep)'
statediff_rewriter_build_tags := $(strip $(filter-out rocksdb grocksdb_clean_link,$(build_tags)) rocksdb grocksdb_clean_link)
statediff_rewriter_build_tags_comma_sep := $(subst $(whitespace),$(comma),$(statediff_rewriter_build_tags))
STATEDIFF_REWRITER_BUILD_FLAGS := -tags "$(statediff_rewriter_build_tags)" -ldflags '$(ldflags) -X github.com/cosmos/cosmos-sdk/version.BuildTags=$(statediff_rewriter_build_tags_comma_sep)'
# check for nostrip option
ifeq (,$(findstring nostrip,$(COSMOS_BUILD_OPTIONS)))
BUILD_FLAGS += -trimpath
STATEDIFF_REWRITER_BUILD_FLAGS += -trimpath
endif

all: build
build: check-network print-ledger go.sum
@go build -mod=readonly $(BUILD_FLAGS) -o $(BUILDDIR)/cronosd ./cmd/cronosd

build-statediff-rewriter: check-network go.sum
@CGO_ENABLED=1 go build -mod=readonly $(STATEDIFF_REWRITER_BUILD_FLAGS) -o $(BUILDDIR)/statediff-rewriter ./cmd/statediff-rewriter

install: check-network print-ledger go.sum
@go install -mod=readonly $(BUILD_FLAGS) ./cmd/cronosd

test:
@go test -tags=objstore -v -mod=readonly $(PACKAGES) -coverprofile=$(COVERAGE) -covermode=atomic

.PHONY: all clean build install test
.PHONY: all clean build build-statediff-rewriter install test

clean:
rm -rf $(BUILDDIR)/
Expand Down
6 changes: 3 additions & 3 deletions cmd/cronosd/cmd/rollback_to_version.go
Original file line number Diff line number Diff line change
Expand Up @@ -5,11 +5,11 @@ import (
"strconv"

dbm "github.com/cosmos/cosmos-db"
"github.com/cosmos/cosmos-sdk/server"
"github.com/spf13/cobra"

"github.com/crypto-org-chain/cronos/app"
"github.com/crypto-org-chain/cronos/cmd/cronosd/opendb"
"github.com/spf13/cobra"

"github.com/cosmos/cosmos-sdk/server"
)

// RollbackToVersionCmd force-rolls the application multistore back to an explicit
Expand Down
98 changes: 98 additions & 0 deletions cmd/statediff-rewriter/archive.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,98 @@
package main

import (
"fmt"
"os"
"path/filepath"
"strings"

dbm "github.com/cosmos/cosmos-db"
"github.com/cosmos/iavl"
iavldb "github.com/cosmos/iavl/db"
"github.com/crypto-org-chain/cronos/cmd/cronosd/opendb"

"cosmossdk.io/log"
"cosmossdk.io/store/metrics"
"cosmossdk.io/store/rootmulti"
storetypes "cosmossdk.io/store/types"
"cosmossdk.io/store/wrapper"
)

type archiveReader struct {
home string
db dbm.DB
store *rootmulti.Store
}

func openArchive(home string) (*archiveReader, error) {
if !rocksDBBuild {
return nil, fmt.Errorf("statediff-rewriter requires build tags rocksdb and grocksdb_clean_link")
}
databasePath := filepath.Join(home, "data", "application.db")
if _, err := requireReadOnlyFilesystem(databasePath, "archive database"); err != nil {
return nil, err
}
db, err := opendb.OpenReadOnlyDB(home, dbm.RocksDBBackend)
if err != nil {
return nil, err
}
return &archiveReader{home: home, db: db, store: rootmulti.NewStore(db, log.NewNopLogger(), metrics.NewNoOpMetrics())}, nil
}

func (a *archiveReader) Close() error { return a.db.Close() }

func (a *archiveReader) evmIAVLDB() iavldb.DB {
return wrapper.NewDBWrapper(dbm.NewPrefixDB(a.db, []byte(evmIAVLPrefix)))
}

func (a *archiveReader) evmStateChangeSource(cacheSize int) keyRangeStateChangeSource {
return iavl.NewImmutableTree(a.evmIAVLDB(), cacheSize, true, log.NewNopLogger())
}

func (a *archiveReader) evmLegacyLatestVersion() (int64, error) {
return legacyLatestRootVersion(a.evmIAVLDB())
}

func (a *archiveReader) commitInfo(version int64) (*storetypes.CommitInfo, error) {
info, err := a.store.GetCommitInfo(version)
if err != nil {
return nil, fmt.Errorf("read commit info %d: %w", version, err)
}
if info.Version != version {
return nil, fmt.Errorf("commit info %d has version %d", version, info.Version)
}
return info, nil
}

func (a *archiveReader) identity() (archiveIdentity, error) {
databaseIdentity, err := readRocksDBIdentity(a.home)
if err != nil {
return archiveIdentity{}, err
}
latest := rootmulti.GetLatestVersion(a.db)
info, err := a.commitInfo(latest)
if err != nil {
return archiveIdentity{}, err
}
return archiveIdentity{
Home: a.home, DatabaseIdentity: databaseIdentity,
LatestVersion: latest, FinalCommitHash: commonHash(info.Hash()),
}, nil
}

func readRocksDBIdentity(home string) (string, error) {
path := filepath.Join(home, "data", "application.db", "IDENTITY")
body, err := os.ReadFile(path)
if err != nil {
return "", fmt.Errorf("read RocksDB identity %s: %w", path, err)
}
fields := strings.Fields(string(body))
if len(fields) != 1 {
return "", fmt.Errorf("RocksDB identity %s must contain exactly one value", path)
}
return fields[0], nil
}

func commonHash(body []byte) string {
return fmt.Sprintf("0x%x", body)
}
24 changes: 24 additions & 0 deletions cmd/statediff-rewriter/archive_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
package main

import (
"os"
"path/filepath"
"testing"

"github.com/stretchr/testify/require"
)

func TestReadRocksDBIdentity(t *testing.T) {
home := t.TempDir()
dir := filepath.Join(home, "data", "application.db")
require.NoError(t, os.MkdirAll(dir, 0o755))
require.NoError(t, os.WriteFile(filepath.Join(dir, "IDENTITY"), []byte("db-123\n"), 0o600))

identity, err := readRocksDBIdentity(home)
require.NoError(t, err)
require.Equal(t, "db-123", identity)

require.NoError(t, os.WriteFile(filepath.Join(dir, "IDENTITY"), []byte("db-123\ndb-456\n"), 0o600))
_, err = readRocksDBIdentity(home)
require.ErrorContains(t, err, "exactly one value")
}
Loading
Loading