Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
65 commits
Select commit Hold shift + click to select a range
cc6c67b
Support object store (#206)
Mar 25, 2024
17043e4
cleanup
mmsqe Mar 27, 2025
78e3a48
Merge remote-tracking branch 'origin/release/v0.53.x' into release/v0…
mmsqe Mar 28, 2025
f44f06b
fix test
mmsqe Mar 28, 2025
e1ee61f
lint
mmsqe Mar 28, 2025
b75bb98
Merge remote-tracking branch 'origin/main' into release/v0.53.x_obj_s…
mmsqe Apr 9, 2025
e64ccc0
resolve
mmsqe Apr 9, 2025
d2c1c3b
fix test
mmsqe Apr 9, 2025
8892029
fix test
mmsqe Apr 9, 2025
83f4859
Problem: store key type assertion is incorrect (#244)
mmsqe Apr 9, 2025
d97d3d1
Merge remote-tracking branch 'origin/main' into release/v0.53.x_obj_s…
mmsqe Apr 11, 2025
3c03b87
Merge remote-tracking branch 'origin/main' into release/v0.53.x_obj_s…
mmsqe Apr 25, 2025
a06944f
Merge remote-tracking branch 'origin/main' into release/v0.53.x_obj_s…
mmsqe Sep 2, 2025
f2fcf30
fix clientv2
mmsqe Sep 2, 2025
e328edf
init
technicallyty Sep 12, 2025
58b6c43
Merge remote-tracking branch 'origin' into technicallyty/object-stores
Eric-Warehime Oct 14, 2025
a8655d6
Fix gofumpt
Eric-Warehime Oct 14, 2025
78e339e
Add codecov
Eric-Warehime Oct 14, 2025
6dd547c
Remove flags from codecov upload
Eric-Warehime Oct 14, 2025
c19b17b
Fix e2e, integration paths
Eric-Warehime Oct 15, 2025
47eac84
Merge remote-tracking branch 'origin' into technicallyty/object-stores
Eric-Warehime Oct 15, 2025
6e24572
Tidy client v2
Eric-Warehime Oct 15, 2025
d285145
Add validity test
Eric-Warehime Oct 15, 2025
12a2cc8
Add length validity test
Eric-Warehime Oct 15, 2025
613a3fa
Add baseapp stores test
Eric-Warehime Oct 15, 2025
ba1607b
Update codecov to ignore mock dirs
Eric-Warehime Oct 15, 2025
9baec7f
Add rootmulti obj store getter test
Eric-Warehime Oct 16, 2025
1a3f99e
Add prefix objstore test
Eric-Warehime Oct 16, 2025
3cfcbab
Add domain to prefix iter test
Eric-Warehime Oct 16, 2025
a1f2db1
Add general prefix obj store tests
Eric-Warehime Oct 16, 2025
f90ccd5
Merge remote-tracking branch 'origin' into technicallyty/object-stores
Eric-Warehime Oct 16, 2025
98df6d1
Fix test
Eric-Warehime Oct 16, 2025
269226d
Fix hashing
Eric-Warehime Oct 16, 2025
e955c32
Upload all test coverage data
Eric-Warehime Oct 16, 2025
2850c8f
Extend baseapp testing
Eric-Warehime Oct 16, 2025
52a92b1
Add context test
Eric-Warehime Oct 16, 2025
f1969b5
Fix lint
Eric-Warehime Oct 16, 2025
b37ab1f
Test store types
Eric-Warehime Oct 16, 2025
3859325
Update changelog entry
Eric-Warehime Oct 16, 2025
96dff47
Use var for zeroValue
Eric-Warehime Oct 21, 2025
bdb5e3d
Cleanup
Eric-Warehime Oct 21, 2025
f39718f
Merge branch 'main' into technicallyty/object-stores
Eric-Warehime Oct 21, 2025
905e1e4
Go mod tidy
Eric-Warehime Oct 21, 2025
a450cff
Port blockstm
Eric-Warehime Oct 21, 2025
a4c8d30
Add constructor changes
Eric-Warehime Oct 21, 2025
9eeae04
Merge branch 'technicallyty/object-stores' into eric/bstm-upstream
Eric-Warehime Oct 21, 2025
4ddb03a
Lint fix
Eric-Warehime Oct 21, 2025
f60a9a0
Go mod tidy
Eric-Warehime Oct 21, 2025
b2e29dd
Add blockstm coverage
Eric-Warehime Oct 21, 2025
bdd5a60
Add txnrunner test
Eric-Warehime Oct 21, 2025
a82c725
Go mod tidy all
Eric-Warehime Oct 21, 2025
e0dc364
Remove blockstm separate package, use common store types
Eric-Warehime Oct 22, 2025
fad7177
Add comments for type assertion in trace store branching
Eric-Warehime Oct 23, 2025
c47a40a
Merge branch 'technicallyty/object-stores' into eric/bstm-upstream
Eric-Warehime Oct 23, 2025
604402a
Merge branch 'main' into technicallyty/object-stores
Eric-Warehime Oct 23, 2025
40059a8
Merge branch 'technicallyty/object-stores' into eric/bstm-upstream
Eric-Warehime Oct 23, 2025
3438141
PR comments
Eric-Warehime Oct 23, 2025
3c81c6c
Fix lint
Eric-Warehime Oct 23, 2025
f0bfe48
Refactor
Eric-Warehime Oct 23, 2025
fe98b78
Change executor to use errgroup
Eric-Warehime Oct 23, 2025
47d2388
Add comments
Eric-Warehime Oct 23, 2025
ed74d82
Fix lints
Eric-Warehime Oct 23, 2025
8565005
Merge remote-tracking branch 'origin' into eric/bstm-upstream
Eric-Warehime Oct 23, 2025
e694322
Fix race condition
Eric-Warehime Oct 24, 2025
55cb76b
Add coverage data back for new package
Eric-Warehime Oct 24, 2025
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
34 changes: 33 additions & 1 deletion .github/workflows/test.yml
Original file line number Diff line number Diff line change
Expand Up @@ -234,6 +234,11 @@ jobs:
with:
name: "${{ github.sha }}-store-coverage"
continue-on-error: true
- uses: actions/download-artifact@v4
if: env.GIT_DIFF
with:
name: "${{ github.sha }}-blockstm-coverage"
continue-on-error: true
- uses: actions/download-artifact@v4
if: env.GIT_DIFF
with:
Expand All @@ -253,7 +258,7 @@ jobs:
if: env.GIT_DIFF
uses: codecov/codecov-action@v5
with:
files: ./00profile.out,./01profile.out,./02profile.out,./03profile.out,./integration-profile.out,./e2e-profile.out,./client/v2/coverage.out,./core/coverage.out,./depinject/coverage.out,./errors/coverage.out,./math/coverage.out,./schema/coverage.out,./collections/coverage.out,./tools/cosmovisor/coverage.out,./tools/confix/coverage.out,./store/coverage.out,./log/coverage.out,./x/tx/coverage.out,./tools/benchmark/coverage.out
files: ./00profile.out,./01profile.out,./02profile.out,./03profile.out,./integration-profile.out,./e2e-profile.out,./client/v2/coverage.out,./core/coverage.out,./depinject/coverage.out,./errors/coverage.out,./math/coverage.out,./schema/coverage.out,./collections/coverage.out,./tools/cosmovisor/coverage.out,./tools/confix/coverage.out,./store/coverage.out,./log/coverage.out,./x/tx/coverage.out,./tools/benchmark/coverage.out,./blockstm/coverage.out
fail_ci_if_error: false
verbose: true
token: ${{ secrets.CODECOV_TOKEN }}
Expand Down Expand Up @@ -570,6 +575,33 @@ jobs:
with:
name: "${{ github.sha }}-store-coverage"
path: ./store/coverage.out
test-blockstm:
runs-on: depot-ubuntu-22.04-4
steps:
- uses: actions/checkout@v5
- uses: actions/setup-go@v6
with:
go-version: "1.25"
check-latest: true
cache: true
cache-dependency-path: store/go.sum
- uses: technote-space/[email protected]
id: git_diff
with:
PATTERNS: |
blockstm/**/*.go
blockstm/go.mod
blockstm/go.sum
- name: tests
if: env.GIT_DIFF
run: |
cd blockstm
go test -mod=readonly -timeout 30m -coverprofile=coverage.out -covermode=atomic -coverpkg=./,./tree -tags='norace ledger test_ledger_mock' ./...
- uses: actions/upload-artifact@v4
if: env.GIT_DIFF
with:
name: "${{ github.sha }}-blockstm-coverage"
path: ./blockstm/coverage.out

test-log:
runs-on: depot-ubuntu-22.04-4
Expand Down
41 changes: 41 additions & 0 deletions blockstm/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
`blockstm` implements the [block-stm algorithm](https://arxiv.org/abs/2203.06871), it follows the paper pseudocode pretty closely.

The main API is a simple function call `ExecuteBlock`:

```golang
type ExecuteFn func(TxnIndex, MultiStore)
func ExecuteBlock(
ctx context.Context, // context for cancellation
blockSize int, // the number of the transactions to be executed
stores []storetypes.StoreKey, // the list of store keys to support
storage MultiStore, // the parent storage, after all transactions are executed, the whole change sets are written into parent storage at once
executors int, // how many concurrent executors to spawn
executeFn ExecuteFn, // callback function to actually execute a transaction with a wrapped `MultiStore`.
) error
```

The main deviations from the paper are:

### Optimisation

We applied the optimization described in section 4 of the paper:

```
Block-STM calls add_dependency from the VM itself, and can thus re-read and continue execution when false is returned.
```

When the VM execution reads an `ESTIMATE` mark, it'll hang on a `CondVar`, so it can resume execution after the dependency is resolved,
much more efficient than abortion and rerun.

### Support Deletion, Iteration, and MultiStore

These features are necessary for integration with cosmos-sdk.

The multi-version data structure is implemented with nested btree for easier iteration support,
the `WriteSet` is also implemented with a btree, and it takes advantage of ordered property to optimize some logic.

The internal data structures are also adapted with multiple stores in mind.

### Attribution

This package was originally authored in [go-block-stm](https://github.com/crypto-org-chain/go-block-stm). We have brought the full source tree into the SDK so that we can natively incorporate the library and required changes into the SDK. Over time we expect to incoporate optimizations and deviations from the upstream implementation.
54 changes: 54 additions & 0 deletions blockstm/bench_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,54 @@
package blockstm

import (
"context"
"strconv"
"testing"

"github.com/test-go/testify/require"

storetypes "cosmossdk.io/store/types"
)

func BenchmarkBlockSTM(b *testing.B) {
stores := map[storetypes.StoreKey]int{StoreKeyAuth: 0, StoreKeyBank: 1}
for i := 0; i < 26; i++ {
key := storetypes.NewKVStoreKey(strconv.FormatInt(int64(i), 10))
stores[key] = i + 2
}
storage := NewMultiMemDB(stores)
testCases := []struct {
name string
block *MockBlock
}{
{"random-10000/100", testBlock(10000, 100)},
{"no-conflict-10000", noConflictBlock(10000)},
{"worst-case-10000", worstCaseBlock(10000)},
{"iterate-10000/100", iterateBlock(10000, 100)},
}
for _, tc := range testCases {
b.Run(tc.name+"-sequential", func(b *testing.B) {
b.ResetTimer()
for i := 0; i < b.N; i++ {
runSequential(storage, tc.block)
}
})
for _, worker := range []int{1, 5, 10, 15, 20} {
b.Run(tc.name+"-worker-"+strconv.Itoa(worker), func(b *testing.B) {
b.ResetTimer()
for i := 0; i < b.N; i++ {
require.NoError(
b,
ExecuteBlock(context.Background(), tc.block.Size(), stores, storage, worker, tc.block.ExecuteTx),
)
}
})
}
}
}

func runSequential(storage MultiStore, block *MockBlock) {
for i, tx := range block.Txs {
block.Results[i] = tx(storage)
}
}
30 changes: 30 additions & 0 deletions blockstm/condvar.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
package blockstm

import "sync"

type Condvar struct {
sync.Mutex
notified bool
cond sync.Cond
}

func NewCondvar() *Condvar {
c := &Condvar{}
c.cond = *sync.NewCond(c)
return c
}

func (cv *Condvar) Wait() {
cv.Lock()
for !cv.notified {
cv.cond.Wait()
}
cv.Unlock()
}

func (cv *Condvar) Notify() {
cv.Lock()
cv.notified = true
cv.Unlock()
cv.cond.Signal()
}
89 changes: 89 additions & 0 deletions blockstm/executor.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,89 @@
package blockstm

import (
"context"
"fmt"
)

// Executor fields are not mutated during execution.
type Executor struct {
ctx context.Context // context for cancellation
scheduler *Scheduler // scheduler for task management
txExecutor TxExecutor // callback to actually execute a transaction
mvMemory *MVMemory // multi-version memory for the executor

// index of the executor, used for debugging output
i int
}

func NewExecutor(
ctx context.Context,
scheduler *Scheduler,
txExecutor TxExecutor,
mvMemory *MVMemory,
i int,
) *Executor {
return &Executor{
ctx: ctx,
scheduler: scheduler,
txExecutor: txExecutor,
mvMemory: mvMemory,
i: i,
}
}

// Run executes all tasks until completion
// Invariant `num_active_tasks`:
// - `NextTask` increases it if returns a valid task.
// - `TryExecute` and `NeedsReexecution` don't change it if it returns a new valid task to run,
// otherwise it decreases it.
func (e *Executor) Run() error {
var kind TaskKind
version := InvalidTxnVersion
for !e.scheduler.Done() {
if !version.Valid() {
// check for cancellation
select {
case <-e.ctx.Done():
return nil
default:
}

version, kind = e.scheduler.NextTask()
continue
}

switch kind {
case TaskKindExecution:
version, kind = e.TryExecute(version)
case TaskKindValidation:
version, kind = e.NeedsReexecution(version)
default:
return fmt.Errorf("unknown task kind %v", kind)
}
}
return nil
}

func (e *Executor) TryExecute(version TxnVersion) (TxnVersion, TaskKind) {
e.scheduler.executedTxns.Add(1)
view := e.execute(version.Index)
wroteNewLocation := e.mvMemory.Record(version, view)
return e.scheduler.FinishExecution(version, wroteNewLocation)
}

func (e *Executor) NeedsReexecution(version TxnVersion) (TxnVersion, TaskKind) {
e.scheduler.validatedTxns.Add(1)
valid := e.mvMemory.ValidateReadSet(version.Index)
aborted := !valid && e.scheduler.TryValidationAbort(version)
if aborted {
e.mvMemory.ConvertWritesToEstimates(version.Index)
}
return e.scheduler.FinishValidation(version.Index, aborted)
}

func (e *Executor) execute(txn TxnIndex) *MultiMVMemoryView {
view := e.mvMemory.View(txn)
e.txExecutor(txn, view)
return view
}
Loading
Loading