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
19 changes: 19 additions & 0 deletions giga/deps/xevm/state/state.go
Original file line number Diff line number Diff line change
Expand Up @@ -119,6 +119,10 @@ func (s *DBImpl) RevertToSnapshot(rev int) {
panic("invalid revision number")
}

// Save references to contexts being discarded before updating state
discardedCtx := s.ctx
discardedSnapshots := s.snapshottedCtxs[rev+1:]

s.ctx = s.snapshottedCtxs[rev]
s.snapshottedCtxs = s.snapshottedCtxs[:rev]

Expand All @@ -137,6 +141,12 @@ func (s *DBImpl) RevertToSnapshot(rev int) {
if watermarkIndex >= 0 {
s.journal = s.journal[:watermarkIndex]
}

// Release resources from discarded contexts after all state updates
s.releaseCtxResources(discardedCtx)
for i := len(discardedSnapshots) - 1; i >= 0; i-- {
s.releaseCtxResources(discardedSnapshots[i])
}
}

func (s *DBImpl) handleResidualFundsInDestructedAccounts(st *TemporaryState) {
Expand Down Expand Up @@ -217,6 +227,15 @@ func (s *DBImpl) getTransientState(acc common.Address, key common.Hash) (common.
return val, found
}

// releaseCtxResources returns poolable resources (EventManager, CMS stores) from
// a snapshot context back to their respective sync.Pools.
func (s *DBImpl) releaseCtxResources(ctx sdk.Context) {
sdk.ReleaseEventManager(ctx.EventManager())
if cms, ok := ctx.MultiStore().(interface{ Release() }); ok {
cms.Release()
}
}

func deleteIfExists(store storetypes.KVStore, key []byte) bool {
if store.Has(key) {
store.Delete(key)
Expand Down
19 changes: 13 additions & 6 deletions sei-cosmos/store/multiversion/mvkv.go
Original file line number Diff line number Diff line change
Expand Up @@ -110,13 +110,20 @@ func NewVersionIndexedStore(parent types.KVStore, multiVersionStore MultiVersion
}

// Reset reinitializes the store for reuse from a pool.
// We allocate fresh maps and slices instead of clearing/reusing because the old
// data may have been handed off to the multiversion store (via SetReadset/
// SetWriteset/SetIterateset) and is still referenced for validation.
// SetReadset/SetWriteset/SetIterateset now clone data before storing, so we can
// safely clear and reuse the maps/slices here instead of allocating fresh ones.
func (store *VersionIndexedStore) Reset(parent types.KVStore, mvs MultiVersionStore, index, incarnation int, abortCh chan scheduler.Abort) {
store.readset = make(ReadSet)
store.writeset = make(map[string][]byte)
store.iterateset = nil
if store.readset != nil {
clear(store.readset)
} else {
store.readset = make(ReadSet)
}
if store.writeset != nil {
clear(store.writeset)
} else {
store.writeset = make(map[string][]byte)
}
store.iterateset = store.iterateset[:0]
store.parent = parent
store.multiVersionStore = mvs
store.transactionIndex = index
Expand Down
12 changes: 10 additions & 2 deletions sei-cosmos/store/multiversion/store.go
Original file line number Diff line number Diff line change
Expand Up @@ -249,9 +249,14 @@ func (s *Store) GetAllWritesetKeys() map[int][]string {
}

func (s *Store) SetReadset(index int, readset ReadSet) {
// Clone the readset so the caller (VIS) can reuse its map via clear().
clone := make(ReadSet, len(readset))
for k, v := range readset {
clone[k] = v
}
sl := s.slot(index)
sl.mu.Lock()
sl.readset = readset
sl.readset = clone
sl.mu.Unlock()
}

Expand All @@ -264,9 +269,12 @@ func (s *Store) GetReadset(index int) ReadSet {
}

func (s *Store) SetIterateset(index int, iterateset Iterateset) {
// Clone the iterateset so the caller (VIS) can reuse its slice via [:0].
clone := make(Iterateset, len(iterateset))
copy(clone, iterateset)
sl := s.slot(index)
sl.mu.Lock()
sl.iterateset = iterateset
sl.iterateset = clone
sl.mu.Unlock()
}

Expand Down
64 changes: 33 additions & 31 deletions sei-cosmos/types/events.go
Original file line number Diff line number Diff line change
Expand Up @@ -45,14 +45,28 @@ const (
AttributeKeyAccessTypeRead = "read"
)

var eventManagerPool = sync.Pool{
New: func() any {
return &EventManager{
events: make(Events, 0, 8),
}
},
}

func NewEventManager() *EventManager {
em := EventManager{
mtx: sync.RWMutex{},
em := eventManagerPool.Get().(*EventManager)
em.events = em.events[:0]
return em
}

// ReleaseEventManager returns an EventManager to the pool for reuse.
// The caller must not use the EventManager after calling this.
func ReleaseEventManager(em *EventManager) {
if em == nil {
return
}
em.mtx.Lock()
defer em.mtx.Unlock()
em.events = EmptyEvents()
return &em
em.events = em.events[:0]
eventManagerPool.Put(em)
}

func (em *EventManager) Events() Events { return em.events }
Expand Down Expand Up @@ -191,12 +205,10 @@ type (
// NewEvent creates a new Event object with a given type and slice of one or more
// attributes.
func NewEvent(ty string, attrs ...Attribute) Event {
e := Event{Type: ty}

for _, attr := range attrs {
e.Attributes = append(e.Attributes, attr.ToKVPair())
e := Event{Type: ty, Attributes: make([]abci.EventAttribute, len(attrs))}
for i, attr := range attrs {
e.Attributes[i] = attr.ToKVPair()
}

return e
}

Expand Down Expand Up @@ -344,33 +356,23 @@ func StringifyEvents(events []abci.Event) StringEvents {
return res.Flatten()
}

// MarkEventsToIndex returns the set of ABCI events, where each event's attribute
// has it's index value marked based on the provided set of events to index.
// MarkEventsToIndex modifies the ABCI events in-place, setting each attribute's
// Index field based on the provided set of events to index.
func MarkEventsToIndex(events []abci.Event, indexSet map[string]struct{}) []abci.Event {
indexAll := len(indexSet) == 0
updatedEvents := make([]abci.Event, len(events))

for i, e := range events {
updatedEvent := abci.Event{
Type: e.Type,
Attributes: make([]abci.EventAttribute, len(e.Attributes)),
}

for j, attr := range e.Attributes {
_, index := indexSet[fmt.Sprintf("%s.%s", e.Type, attr.Key)]
updatedAttr := abci.EventAttribute{
Key: attr.Key,
Value: attr.Value,
Index: index || indexAll,
for i := range events {
e := &events[i]
for j := range e.Attributes {
if indexAll {
e.Attributes[j].Index = true
} else {
_, e.Attributes[j].Index = indexSet[fmt.Sprintf("%s.%s", e.Type, e.Attributes[j].Key)]
}

updatedEvent.Attributes[j] = updatedAttr
}

updatedEvents[i] = updatedEvent
}

return updatedEvents
return events
}

type EVMEventManager struct {
Expand Down
36 changes: 18 additions & 18 deletions sei-cosmos/types/events_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -131,30 +131,31 @@ func (s *eventsTestSuite) TestStringifyEvents() {
}

func (s *eventsTestSuite) TestMarkEventsToIndex() {
events := []abci.Event{
{
Type: "message",
Attributes: []abci.EventAttribute{
{Key: []byte("sender"), Value: []byte("foo")},
{Key: []byte("recipient"), Value: []byte("bar")},
// Helper to create fresh events for each subtest since MarkEventsToIndex modifies in-place.
newEvents := func() []abci.Event {
return []abci.Event{
{
Type: "message",
Attributes: []abci.EventAttribute{
{Key: []byte("sender"), Value: []byte("foo")},
{Key: []byte("recipient"), Value: []byte("bar")},
},
},
},
{
Type: "staking",
Attributes: []abci.EventAttribute{
{Key: []byte("deposit"), Value: []byte("5")},
{Key: []byte("unbond"), Value: []byte("10")},
{
Type: "staking",
Attributes: []abci.EventAttribute{
{Key: []byte("deposit"), Value: []byte("5")},
{Key: []byte("unbond"), Value: []byte("10")},
},
},
},
}
}

testCases := map[string]struct {
events []abci.Event
indexSet map[string]struct{}
expected []abci.Event
}{
"empty index set": {
events: events,
expected: []abci.Event{
{
Type: "message",
Expand All @@ -174,7 +175,6 @@ func (s *eventsTestSuite) TestMarkEventsToIndex() {
indexSet: map[string]struct{}{},
},
"index some events": {
events: events,
expected: []abci.Event{
{
Type: "message",
Expand All @@ -197,7 +197,6 @@ func (s *eventsTestSuite) TestMarkEventsToIndex() {
},
},
"index all events": {
events: events,
expected: []abci.Event{
{
Type: "message",
Expand Down Expand Up @@ -226,7 +225,8 @@ func (s *eventsTestSuite) TestMarkEventsToIndex() {
for name, tc := range testCases {
tc := tc
s.T().Run(name, func(_ *testing.T) {
legacyEvents := sdk.MarkEventsToIndex(tc.events, tc.indexSet)
events := newEvents()
legacyEvents := sdk.MarkEventsToIndex(events, tc.indexSet)
s.Require().Equal(tc.expected, legacyEvents)
})
}
Expand Down
Loading