Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
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
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@

### Improvements

* [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) stateChangeSource {
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