feat(stf/branch): simplify merged iterator (#22131)

Co-authored-by: marbar3778 <marbar3778@yahoo.com>
This commit is contained in:
testinginprod 2024-11-07 15:50:26 +01:00 committed by GitHub
parent ffa74d17cb
commit 99b4858a95
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
14 changed files with 292 additions and 225 deletions

View File

@ -5,6 +5,7 @@ go 1.23
// server v2 integration
replace (
cosmossdk.io/api => ../../api
cosmossdk.io/core/testing => ../../core/testing
cosmossdk.io/server/v2/appmanager => ../../server/v2/appmanager
cosmossdk.io/server/v2/stf => ../../server/v2/stf
cosmossdk.io/store/v2 => ../../store/v2
@ -30,7 +31,7 @@ require (
require (
buf.build/gen/go/cometbft/cometbft/protocolbuffers/go v1.35.1-20240701160653-fedbb9acfd2f.1 // indirect
buf.build/gen/go/cosmos/gogo-proto/protocolbuffers/go v1.35.1-20240130113600-88ef6483f90f.1 // indirect
cosmossdk.io/core/testing v0.0.0-20240923163230-04da382a9f29 // indirect
cosmossdk.io/core/testing v0.0.0 // indirect
cosmossdk.io/errors/v2 v2.0.0-20240731132947-df72853b3ca5 // indirect
github.com/DataDog/zstd v1.5.5 // indirect
github.com/beorn7/perks v1.0.1 // indirect

View File

@ -4,8 +4,6 @@ buf.build/gen/go/cosmos/gogo-proto/protocolbuffers/go v1.35.1-20240130113600-88e
buf.build/gen/go/cosmos/gogo-proto/protocolbuffers/go v1.35.1-20240130113600-88ef6483f90f.1/go.mod h1:zqi/LZjZhyvjCMTEVIwAf5VRlkLduuCfqmZxgoormq0=
cosmossdk.io/core v1.0.0-alpha.5 h1:McjYXAQ6XcT20v2uHyH7PhoWH8V+mebzfVFqT3GinsI=
cosmossdk.io/core v1.0.0-alpha.5/go.mod h1:3u9cWq1FAVtiiCrDPpo4LhR+9V6k/ycSG4/Y/tREWCY=
cosmossdk.io/core/testing v0.0.0-20240923163230-04da382a9f29 h1:NxxUo0GMJUbIuVg0R70e3cbn9eFTEuMr7ev1AFvypdY=
cosmossdk.io/core/testing v0.0.0-20240923163230-04da382a9f29/go.mod h1:8s2tPeJtSiQuoyPmr2Ag7meikonISO4Fv4MoO8+ORrs=
cosmossdk.io/depinject v1.1.0 h1:wLan7LG35VM7Yo6ov0jId3RHWCGRhe8E8bsuARorl5E=
cosmossdk.io/depinject v1.1.0/go.mod h1:kkI5H9jCGHeKeYWXTqYdruogYrEeWvBQCw1Pj4/eCFI=
cosmossdk.io/errors/v2 v2.0.0-20240731132947-df72853b3ca5 h1:IQNdY2kB+k+1OM2DvqFG1+UgeU1JzZrWtwuWzI3ZfwA=

View File

@ -4,6 +4,7 @@ go 1.23.1
replace (
cosmossdk.io/api => ../../../api
cosmossdk.io/core/testing => ../../../core/testing
cosmossdk.io/server/v2 => ../
cosmossdk.io/server/v2/appmanager => ../appmanager
cosmossdk.io/server/v2/stf => ../stf
@ -43,7 +44,7 @@ require (
require (
buf.build/gen/go/cometbft/cometbft/protocolbuffers/go v1.35.1-20240701160653-fedbb9acfd2f.1 // indirect
buf.build/gen/go/cosmos/gogo-proto/protocolbuffers/go v1.35.1-20240130113600-88ef6483f90f.1 // indirect
cosmossdk.io/core/testing v0.0.0-20240923163230-04da382a9f29 // indirect
cosmossdk.io/core/testing v0.0.0 // indirect
cosmossdk.io/depinject v1.1.0 // indirect
cosmossdk.io/errors v1.0.1 // indirect
cosmossdk.io/math v1.3.0 // indirect

View File

@ -8,8 +8,6 @@ cosmossdk.io/collections v0.4.0 h1:PFmwj2W8szgpD5nOd8GWH6AbYNi1f2J6akWXJ7P5t9s=
cosmossdk.io/collections v0.4.0/go.mod h1:oa5lUING2dP+gdDquow+QjlF45eL1t4TJDypgGd+tv0=
cosmossdk.io/core v1.0.0-alpha.5 h1:McjYXAQ6XcT20v2uHyH7PhoWH8V+mebzfVFqT3GinsI=
cosmossdk.io/core v1.0.0-alpha.5/go.mod h1:3u9cWq1FAVtiiCrDPpo4LhR+9V6k/ycSG4/Y/tREWCY=
cosmossdk.io/core/testing v0.0.0-20240923163230-04da382a9f29 h1:NxxUo0GMJUbIuVg0R70e3cbn9eFTEuMr7ev1AFvypdY=
cosmossdk.io/core/testing v0.0.0-20240923163230-04da382a9f29/go.mod h1:8s2tPeJtSiQuoyPmr2Ag7meikonISO4Fv4MoO8+ORrs=
cosmossdk.io/depinject v1.1.0 h1:wLan7LG35VM7Yo6ov0jId3RHWCGRhe8E8bsuARorl5E=
cosmossdk.io/depinject v1.1.0/go.mod h1:kkI5H9jCGHeKeYWXTqYdruogYrEeWvBQCw1Pj4/eCFI=
cosmossdk.io/errors v1.0.1 h1:bzu+Kcr0kS/1DuPBtUFdWjzLqyUuCiyHjyJB6srBV/0=

View File

@ -0,0 +1,83 @@
package branch
import (
"fmt"
"testing"
"cosmossdk.io/core/store"
coretesting "cosmossdk.io/core/testing"
)
var (
stackSizes = []int{1, 10, 100}
elemsInStack = 10
)
func Benchmark_CacheStack_Set(b *testing.B) {
for _, stackSize := range stackSizes {
b.Run(fmt.Sprintf("StackSize%d", stackSize), func(b *testing.B) {
bs := makeBranchStack(b, stackSize)
b.ResetTimer()
b.ReportAllocs()
for i := 0; i < b.N; i++ {
_ = bs.Set([]byte{0}, []byte{0})
}
})
}
}
func Benchmark_Get(b *testing.B) {
for _, stackSize := range stackSizes {
b.Run(fmt.Sprintf("StackSize%d", stackSize), func(b *testing.B) {
bs := makeBranchStack(b, stackSize)
b.ResetTimer()
b.ReportAllocs()
for i := 0; i < b.N; i++ {
_, _ = bs.Get([]byte{0})
}
})
}
}
func Benchmark_Iterate(b *testing.B) {
var keySink, valueSink any
for _, stackSize := range stackSizes {
b.Run(fmt.Sprintf("StackSize%d", stackSize), func(b *testing.B) {
bs := makeBranchStack(b, stackSize)
b.ResetTimer()
b.ReportAllocs()
for i := 0; i < b.N; i++ {
iter, _ := bs.Iterator(nil, nil)
for iter.Valid() {
keySink = iter.Key()
valueSink = iter.Value()
iter.Next()
}
_ = iter.Close()
}
})
}
_ = keySink
_ = valueSink
}
// makeBranchStack creates a branch stack of the given size and initializes it with unique key-value pairs.
func makeBranchStack(b *testing.B, stackSize int) Store[store.KVStore] {
parent := coretesting.NewMemKV()
branch := NewStore[store.KVStore](parent)
for i := 1; i < stackSize; i++ {
branch = NewStore[store.KVStore](branch)
for j := 0; j < elemsInStack; j++ {
// create unique keys by including the branch index.
key := []byte{byte(i), byte(j)}
value := []byte{byte(j)}
err := branch.Set(key, value)
if err != nil {
b.Fatal(err)
}
}
}
return branch
}

View File

@ -15,7 +15,7 @@ const (
var errKeyEmpty = errors.New("key cannot be empty")
// changeSet implements the sorted cache for cachekv store,
// changeSet implements the sorted tree for cachekv store,
// we don't use MemDB here because cachekv is used extensively in sdk core path,
// we need it to be as fast as possible, while `MemDB` is mainly used as a mocking db in unit tests.
//

View File

@ -7,229 +7,162 @@ import (
corestore "cosmossdk.io/core/store"
)
// mergedIterator merges a parent Iterator and a cache Iterator.
// The cache iterator may return nil keys to signal that an item
// had been deleted (but not deleted in the parent).
// If the cache iterator has the same key as the parent, the
// cache shadows (overrides) the parent.
type mergedIterator struct {
parent corestore.Iterator
cache corestore.Iterator
ascending bool
var (
errInvalidIterator = errors.New("invalid iterator")
)
valid bool
// mergedIterator merges a parent Iterator and a child Iterator.
// The child iterator may contain items that shadow or override items in the parent iterator.
// If the child iterator has the same key as the parent, the child's value takes precedence.
// Deleted items in the child (indicated by nil values) are skipped.
type mergedIterator[Parent, Child corestore.Iterator] struct {
parent Parent // Iterator for the parent store
child Child // Iterator for the child store
ascending bool // Direction of iteration
valid bool // Indicates if the iterator is in a valid state
currKey []byte // Current key pointed by the iterator
currValue []byte // Current value corresponding to currKey
err error // Error encountered during iteration
}
var _ corestore.Iterator = (*mergedIterator)(nil)
// Ensure mergedIterator implements the corestore.Iterator interface.
var _ corestore.Iterator = (*mergedIterator[corestore.Iterator, corestore.Iterator])(nil)
// mergeIterators merges two iterators.
func mergeIterators(parent, cache corestore.Iterator, ascending bool) corestore.Iterator {
iter := &mergedIterator{
// mergeIterators creates a new merged iterator from parent and child iterators.
// The 'ascending' parameter determines the direction of iteration.
func mergeIterators[Parent, Child corestore.Iterator](parent Parent, child Child, ascending bool) *mergedIterator[Parent, Child] {
iter := &mergedIterator[Parent, Child]{
parent: parent,
cache: cache,
child: child,
ascending: ascending,
}
iter.valid = iter.skipUntilExistsOrInvalid()
iter.advance() // Initialize the iterator by advancing to the first valid item
return iter
}
// Domain implements Iterator.
// Returns parent domain because cache and parent domains are the same.
func (iter *mergedIterator) Domain() (start, end []byte) {
return iter.parent.Domain()
// Domain returns the start and end range of the iterator.
// It delegates to the parent iterator as both iterators share the same domain.
func (i *mergedIterator[Parent, Child]) Domain() (start, end []byte) {
return i.parent.Domain()
}
// Valid implements Iterator.
func (iter *mergedIterator) Valid() bool {
return iter.valid
// Valid checks if the iterator is in a valid state.
// It returns true if the iterator has not reached the end.
func (i *mergedIterator[Parent, Child]) Valid() bool {
return i.valid
}
// Next implements Iterator
func (iter *mergedIterator) Next() {
iter.assertValid()
// Next advances the iterator to the next valid item.
// It skips over deleted items (with nil values) and updates the current key and value.
func (i *mergedIterator[Parent, Child]) Next() {
if !i.valid {
i.err = errInvalidIterator
return
}
i.advance()
}
switch {
case !iter.parent.Valid():
// If parent is invalid, get the next cache item.
iter.cache.Next()
case !iter.cache.Valid():
// If cache is invalid, get the next parent item.
iter.parent.Next()
default:
// Both are valid. Compare keys.
keyP, keyC := iter.parent.Key(), iter.cache.Key()
switch iter.compare(keyP, keyC) {
case -1: // parent < cache
iter.parent.Next()
case 0: // parent == cache
iter.parent.Next()
iter.cache.Next()
case 1: // parent > cache
iter.cache.Next()
// Key returns the current key pointed by the iterator.
// If the iterator is invalid, it returns nil.
func (i *mergedIterator[Parent, Child]) Key() []byte {
if !i.valid {
panic("called key on invalid iterator")
}
return i.currKey
}
// Value returns the current value corresponding to the current key.
// If the iterator is invalid, it returns nil.
func (i *mergedIterator[Parent, Child]) Value() []byte {
if !i.valid {
panic("called value on invalid iterator")
}
return i.currValue
}
// Close closes both the parent and child iterators.
// It returns any error encountered during the closing of the iterators.
func (i *mergedIterator[Parent, Child]) Close() (err error) {
err = errors.Join(err, i.parent.Close())
err = errors.Join(err, i.child.Close())
i.valid = false
return err
}
// Error returns any error that occurred during iteration.
// If the iterator is valid, it returns nil.
func (i *mergedIterator[Parent, Child]) Error() error {
return i.err
}
// advance moves the iterator to the next valid (non-deleted) item.
// It handles merging logic between the parent and child iterators.
func (i *mergedIterator[Parent, Child]) advance() {
for {
// Check if both iterators have reached the end
if !i.parent.Valid() && !i.child.Valid() {
i.valid = false
return
}
}
iter.valid = iter.skipUntilExistsOrInvalid()
}
// Key implements Iterator
func (iter *mergedIterator) Key() []byte {
iter.assertValid()
var key, value []byte
// If parent is invalid, get the cache key.
if !iter.parent.Valid() {
return iter.cache.Key()
}
// If parent iterator is exhausted, use the child iterator
if !i.parent.Valid() {
key = i.child.Key()
value = i.child.Value()
i.child.Next()
} else if !i.child.Valid() {
// If child iterator is exhausted, use the parent iterator
key = i.parent.Key()
value = i.parent.Value()
i.parent.Next()
} else {
// Both iterators are valid; compare keys
keyP, keyC := i.parent.Key(), i.child.Key()
switch cmp := i.compare(keyP, keyC); {
case cmp < 0:
// Parent key is less than child key
key = keyP
value = i.parent.Value()
i.parent.Next()
case cmp == 0:
// Keys are equal; child overrides parent
key = keyC
value = i.child.Value()
i.parent.Next()
i.child.Next()
case cmp > 0:
// Child key is less than parent key
key = keyC
value = i.child.Value()
i.child.Next()
}
}
// If cache is invalid, get the parent key.
if !iter.cache.Valid() {
return iter.parent.Key()
}
// Skip deleted items (value is nil)
if value == nil {
continue
}
// Both are valid. Compare keys.
keyP, keyC := iter.parent.Key(), iter.cache.Key()
cmp := iter.compare(keyP, keyC)
switch cmp {
case -1: // parent < cache
return keyP
case 0: // parent == cache
return keyP
case 1: // parent > cache
return keyC
default:
panic("invalid compare result")
// Update the current key and value, and mark iterator as valid
i.currKey = key
i.currValue = value
i.valid = true
return
}
}
// Value implements Iterator
func (iter *mergedIterator) Value() []byte {
iter.assertValid()
// If parent is invalid, get the cache value.
if !iter.parent.Valid() {
return iter.cache.Value()
}
// If cache is invalid, get the parent value.
if !iter.cache.Valid() {
return iter.parent.Value()
}
// Both are valid. Compare keys.
keyP, keyC := iter.parent.Key(), iter.cache.Key()
cmp := iter.compare(keyP, keyC)
switch cmp {
case -1: // parent < cache
return iter.parent.Value()
case 0: // parent == cache
return iter.cache.Value()
case 1: // parent > cache
return iter.cache.Value()
default:
panic("invalid comparison result")
}
}
// Close implements Iterator
func (iter *mergedIterator) Close() error {
err1 := iter.cache.Close()
if err := iter.parent.Close(); err != nil {
return err
}
return err1
}
var errInvalidIterator = errors.New("invalid merged iterator")
// Error returns an error if the mergedIterator is invalid defined by the
// Valid method.
func (iter *mergedIterator) Error() error {
if !iter.Valid() {
return errInvalidIterator
}
return nil
}
// If not valid, panics.
// NOTE: May have side-effect of iterating over cache.
func (iter *mergedIterator) assertValid() {
if err := iter.Error(); err != nil {
panic(err)
}
}
// Like bytes.Compare but opposite if not ascending.
func (iter *mergedIterator) compare(a, b []byte) int {
if iter.ascending {
// compare compares two byte slices a and b.
// It returns an integer comparing a and b:
// - Negative if a < b
// - Zero if a == b
// - Positive if a > b
//
// The comparison respects the iterator's direction (ascending or descending).
func (i *mergedIterator[Parent, Child]) compare(a, b []byte) int {
if i.ascending {
return bytes.Compare(a, b)
}
return bytes.Compare(a, b) * -1
}
// Skip all delete-items from the cache w/ `key < until`. After this function,
// current cache item is a non-delete-item, or `until <= key`.
// If the current cache item is not a delete item, does nothing.
// If `until` is nil, there is no limit, and cache may end up invalid.
// CONTRACT: cache is valid.
func (iter *mergedIterator) skipCacheDeletes(until []byte) {
for iter.cache.Valid() &&
iter.cache.Value() == nil &&
(until == nil || iter.compare(iter.cache.Key(), until) < 0) {
iter.cache.Next()
}
}
// Fast forwards cache (or parent+cache in case of deleted items) until current
// item exists, or until iterator becomes invalid.
// Returns whether the iterator is valid.
func (iter *mergedIterator) skipUntilExistsOrInvalid() bool {
for {
// If parent is invalid, fast-forward cache.
if !iter.parent.Valid() {
iter.skipCacheDeletes(nil)
return iter.cache.Valid()
}
// Parent is valid.
if !iter.cache.Valid() {
return true
}
// Parent is valid, cache is valid.
// Compare parent and cache.
keyP := iter.parent.Key()
keyC := iter.cache.Key()
switch iter.compare(keyP, keyC) {
case -1: // parent < cache.
return true
case 0: // parent == cache.
// Skip over if cache item is a delete.
valueC := iter.cache.Value()
if valueC == nil {
iter.parent.Next()
iter.cache.Next()
continue
}
// Cache is not a delete.
return true // cache exists.
case 1: // cache < parent
// Skip over if cache item is a delete.
valueC := iter.cache.Value()
if valueC == nil {
iter.skipCacheDeletes(keyP)
continue
}
// Cache is not a delete.
return true // cache exists.
}
}
return bytes.Compare(b, a)
}

View File

@ -7,6 +7,52 @@ import (
corestore "cosmossdk.io/core/store"
)
func TestMergedIterator_Validity(t *testing.T) {
panics := func(f func()) {
defer func() {
r := recover()
if r == nil {
t.Error("panic expected")
}
}()
f()
}
t.Run("panics when calling key on invalid iter", func(t *testing.T) {
parent, err := newMemState().Iterator(nil, nil)
if err != nil {
t.Fatal(err)
}
cache, err := newMemState().Iterator(nil, nil)
if err != nil {
t.Fatal(err)
}
it := mergeIterators(parent, cache, true)
panics(func() {
it.Key()
})
})
t.Run("panics when calling value on invalid iter", func(t *testing.T) {
parent, err := newMemState().Iterator(nil, nil)
if err != nil {
t.Fatal(err)
}
cache, err := newMemState().Iterator(nil, nil)
if err != nil {
t.Fatal(err)
}
it := mergeIterators(parent, cache, true)
panics(func() {
it.Value()
})
})
}
func TestMergedIterator_Next(t *testing.T) {
specs := map[string]struct {
setup func() corestore.Iterator
@ -19,7 +65,7 @@ func TestMergedIterator_Next(t *testing.T) {
return mergeIterators(must(parent.Iterator(nil, nil)), must(cache.Iterator(nil, nil)), true)
},
},
"parent iterator has one item, cache is empty": {
"parent iterator has one item, child is empty": {
setup: func() corestore.Iterator {
parent := newMemState()
if err := parent.Set([]byte("k1"), []byte("1")); err != nil {
@ -30,7 +76,7 @@ func TestMergedIterator_Next(t *testing.T) {
},
exp: [][2]string{{"k1", "1"}},
},
"cache has one item, parent is empty": {
"child has one item, parent is empty": {
setup: func() corestore.Iterator {
parent := newMemState()
cache := newMemState()
@ -41,21 +87,21 @@ func TestMergedIterator_Next(t *testing.T) {
},
exp: [][2]string{{"k1", "1"}},
},
"both iterators have same key, cache preferred": {
"both iterators have same key, child preferred": {
setup: func() corestore.Iterator {
parent := newMemState()
if err := parent.Set([]byte("k1"), []byte("parent-val")); err != nil {
t.Fatal(err)
}
cache := newMemState()
if err := cache.Set([]byte("k1"), []byte("cache-val")); err != nil {
if err := cache.Set([]byte("k1"), []byte("child-val")); err != nil {
t.Fatal(err)
}
return mergeIterators(must(parent.Iterator(nil, nil)), must(cache.Iterator(nil, nil)), true)
},
exp: [][2]string{{"k1", "cache-val"}},
exp: [][2]string{{"k1", "child-val"}},
},
"both iterators have same key, but cache value is nil": {
"both iterators have same key, but child value is nil": {
setup: func() corestore.Iterator {
parent := newMemState()
if err := parent.Set([]byte("k1"), []byte("1")); err != nil {
@ -68,7 +114,7 @@ func TestMergedIterator_Next(t *testing.T) {
return mergeIterators(must(parent.Iterator(nil, nil)), must(cache.Iterator(nil, nil)), true)
},
},
"parent and cache are ascending": {
"parent and child are ascending": {
setup: func() corestore.Iterator {
parent := newMemState()
if err := parent.Set([]byte("k2"), []byte("v2")); err != nil {
@ -88,7 +134,7 @@ func TestMergedIterator_Next(t *testing.T) {
},
exp: [][2]string{{"k1", "v1"}, {"k2", "v2"}, {"k3", "v3"}, {"k4", "v4"}},
},
"parent and cache are descending": {
"parent and child are descending": {
setup: func() corestore.Iterator {
parent := newMemState()
if err := parent.Set([]byte("k3"), []byte("v3")); err != nil {

View File

@ -8,9 +8,9 @@ import (
var _ store.Writer = (*Store[store.Reader])(nil)
// Store wraps an in-memory cache around an underlying types.KVStore.
// Store wraps an in-memory child around an underlying types.KVStore.
type Store[T store.Reader] struct {
changeSet changeSet // always ascending sorted
changeSet changeSet // ordered changeset.
parent T
}
@ -24,11 +24,18 @@ func NewStore[T store.Reader](parent T) Store[T] {
// Get implements types.KVStore.
func (s Store[T]) Get(key []byte) (value []byte, err error) {
// if found in memory cache, immediately return.
value, found := s.changeSet.get(key)
if found {
return
}
return s.parent.Get(key)
// after we get it from parent store, we cache it.
// if it is not found in parent store, we still cache it as nil.
value, err = s.parent.Get(key)
if err != nil {
return nil, err
}
return value, nil
}
// Set implements types.KVStore.
@ -36,7 +43,6 @@ func (s Store[T]) Set(key, value []byte) error {
if value == nil {
return errors.New("cannot set a nil value")
}
s.changeSet.set(key, value)
return nil
}

View File

@ -4,6 +4,7 @@ go 1.23
require (
cosmossdk.io/core v1.0.0-alpha.5
cosmossdk.io/core/testing v0.0.0
cosmossdk.io/schema v0.3.0
github.com/cosmos/gogoproto v1.7.0
github.com/tidwall/btree v1.7.0
@ -13,3 +14,5 @@ require (
github.com/google/go-cmp v0.6.0 // indirect
google.golang.org/protobuf v1.35.1 // indirect
)
replace cosmossdk.io/core/testing => ../../../core/testing

View File

@ -58,7 +58,7 @@ require (
cloud.google.com/go/iam v1.1.13 // indirect
cloud.google.com/go/storage v1.43.0 // indirect
cosmossdk.io/collections v0.4.1-0.20241104084251-838f1557af0a // indirect
cosmossdk.io/core/testing v0.0.0-20240923163230-04da382a9f29 // indirect
cosmossdk.io/core/testing v0.0.0 // indirect
cosmossdk.io/errors v1.0.1 // indirect
cosmossdk.io/errors/v2 v2.0.0-20240731132947-df72853b3ca5 // indirect
cosmossdk.io/schema v0.3.1-0.20241010135032-192601639cac // indirect
@ -291,6 +291,7 @@ replace (
// server v2 integration
replace (
cosmossdk.io/api => ../../api
cosmossdk.io/core/testing => ../../core/testing
cosmossdk.io/runtime/v2 => ../../runtime/v2
cosmossdk.io/server/v2 => ../../server/v2
cosmossdk.io/server/v2/appmanager => ../../server/v2/appmanager

View File

@ -194,8 +194,6 @@ cloud.google.com/go/workflows v1.6.0/go.mod h1:6t9F5h/unJz41YqfBmqSASJSXccBLtD1V
cloud.google.com/go/workflows v1.7.0/go.mod h1:JhSrZuVZWuiDfKEFxU0/F1PQjmpnpcoISEXH2bcHC3M=
cosmossdk.io/core v1.0.0-alpha.5 h1:McjYXAQ6XcT20v2uHyH7PhoWH8V+mebzfVFqT3GinsI=
cosmossdk.io/core v1.0.0-alpha.5/go.mod h1:3u9cWq1FAVtiiCrDPpo4LhR+9V6k/ycSG4/Y/tREWCY=
cosmossdk.io/core/testing v0.0.0-20240923163230-04da382a9f29 h1:NxxUo0GMJUbIuVg0R70e3cbn9eFTEuMr7ev1AFvypdY=
cosmossdk.io/core/testing v0.0.0-20240923163230-04da382a9f29/go.mod h1:8s2tPeJtSiQuoyPmr2Ag7meikonISO4Fv4MoO8+ORrs=
cosmossdk.io/depinject v1.1.0 h1:wLan7LG35VM7Yo6ov0jId3RHWCGRhe8E8bsuARorl5E=
cosmossdk.io/depinject v1.1.0/go.mod h1:kkI5H9jCGHeKeYWXTqYdruogYrEeWvBQCw1Pj4/eCFI=
cosmossdk.io/errors v1.0.1 h1:bzu+Kcr0kS/1DuPBtUFdWjzLqyUuCiyHjyJB6srBV/0=

View File

@ -32,7 +32,7 @@ require (
)
require (
cosmossdk.io/core/testing v0.0.0-20240923163230-04da382a9f29
cosmossdk.io/core/testing v0.0.0
cosmossdk.io/runtime/v2 v2.0.0-20240911143651-72620a577660
cosmossdk.io/server/v2/stf v0.0.0-00010101000000-000000000000
cosmossdk.io/store/v2 v2.0.0-00010101000000-000000000000
@ -248,6 +248,7 @@ replace (
cosmossdk.io/api => ../api
cosmossdk.io/client/v2 => ../client/v2
cosmossdk.io/collections => ../collections
cosmossdk.io/core/testing => ../core/testing
cosmossdk.io/indexer/postgres => ../indexer/postgres
cosmossdk.io/runtime/v2 => ../runtime/v2
cosmossdk.io/server/v2/appmanager => ../server/v2/appmanager

View File

@ -194,8 +194,6 @@ cloud.google.com/go/workflows v1.6.0/go.mod h1:6t9F5h/unJz41YqfBmqSASJSXccBLtD1V
cloud.google.com/go/workflows v1.7.0/go.mod h1:JhSrZuVZWuiDfKEFxU0/F1PQjmpnpcoISEXH2bcHC3M=
cosmossdk.io/core v1.0.0-alpha.5 h1:McjYXAQ6XcT20v2uHyH7PhoWH8V+mebzfVFqT3GinsI=
cosmossdk.io/core v1.0.0-alpha.5/go.mod h1:3u9cWq1FAVtiiCrDPpo4LhR+9V6k/ycSG4/Y/tREWCY=
cosmossdk.io/core/testing v0.0.0-20240923163230-04da382a9f29 h1:NxxUo0GMJUbIuVg0R70e3cbn9eFTEuMr7ev1AFvypdY=
cosmossdk.io/core/testing v0.0.0-20240923163230-04da382a9f29/go.mod h1:8s2tPeJtSiQuoyPmr2Ag7meikonISO4Fv4MoO8+ORrs=
cosmossdk.io/depinject v1.1.0 h1:wLan7LG35VM7Yo6ov0jId3RHWCGRhe8E8bsuARorl5E=
cosmossdk.io/depinject v1.1.0/go.mod h1:kkI5H9jCGHeKeYWXTqYdruogYrEeWvBQCw1Pj4/eCFI=
cosmossdk.io/errors v1.0.1 h1:bzu+Kcr0kS/1DuPBtUFdWjzLqyUuCiyHjyJB6srBV/0=