Skip to content

Commit

Permalink
Move logs to ephemeral store, add tests
Browse files Browse the repository at this point in the history
  • Loading branch information
drklee3 committed Jan 30, 2024
1 parent 09616de commit 5ef345d
Show file tree
Hide file tree
Showing 5 changed files with 389 additions and 38 deletions.
5 changes: 1 addition & 4 deletions x/evm/statedb/ctx.go
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,7 @@ func NewSnapshotCtx(initialCtx sdk.Context) *SnapshotCommitCtx {

// Create an initial snapshot of the initialCtx so no state is written until
// Commit() is called.
_ = sCtx.Snapshot(0, 0, StoreRevertKey{0, 0})
_ = sCtx.Snapshot(0, StoreRevertKey{0, 0, 0})

return sCtx
}
Expand Down Expand Up @@ -56,7 +56,6 @@ func (c *SnapshotCommitCtx) CurrentSnapshot() (CtxSnapshot, bool) {
// Snapshot creates a new branched context and returns the revision id.
func (c *SnapshotCommitCtx) Snapshot(
journalIndex int,
logsIndex int,
storeRevertKey StoreRevertKey,
) int {
id := c.nextSnapshotID
Expand All @@ -72,7 +71,6 @@ func (c *SnapshotCommitCtx) Snapshot(
write: newWrite,

journalIndex: journalIndex,
logsIndex: logsIndex,
storeRevertKey: storeRevertKey,
})

Expand Down Expand Up @@ -120,6 +118,5 @@ type CtxSnapshot struct {

// In-memory things like logs, access list
journalIndex int
logsIndex int
storeRevertKey StoreRevertKey
}
4 changes: 2 additions & 2 deletions x/evm/statedb/ctx_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,7 @@ func TestSnapshotCommitCtx(t *testing.T) {

// Make a snapshot
previousCtx := snapshotCtx.CurrentCtx()
snapshotID := snapshotCtx.Snapshot(0, 0, statedb.StoreRevertKey{})
snapshotID := snapshotCtx.Snapshot(0, statedb.StoreRevertKey{})
require.Equal(t, 0, snapshotID, "initial snapshot id should be 0")
require.NotEqual(t, previousCtx, snapshotCtx.CurrentCtx(), "CurrentCtx should be branched")

Expand All @@ -52,7 +52,7 @@ func TestRevert(t *testing.T) {
snapshotCtx := statedb.NewSnapshotCtx(initialCtx)

// Make a snapshot
snapshotID := snapshotCtx.Snapshot(0, 0, statedb.StoreRevertKey{0, 0})
snapshotID := snapshotCtx.Snapshot(0, statedb.StoreRevertKey{})

// Revert to the snapshot
snapshotCtx.Revert(snapshotID)
Expand Down
18 changes: 9 additions & 9 deletions x/evm/statedb/statedb.go
Original file line number Diff line number Diff line change
Expand Up @@ -47,7 +47,6 @@ type StateDB struct {
journal *journal
accessList *accessList

logs []*ethtypes.Log
sdkError error
}

Expand All @@ -65,7 +64,6 @@ func New(ctx sdk.Context, keeper evm.StateDBKeeper, txConfig types.TxConfig) evm
journal: newJournal(),
accessList: newAccessList(),

logs: nil,
sdkError: nil,
}
}
Expand All @@ -80,14 +78,14 @@ func (s *StateDB) AddLog(log *ethtypes.Log) {
log.TxHash = s.txConfig.TxHash
log.BlockHash = s.txConfig.BlockHash
log.TxIndex = s.txConfig.TxIndex
log.Index = s.txConfig.LogIndex + uint(len(s.logs))
log.Index = s.txConfig.LogIndex + uint(s.ephemeralStore.GetLogsCount())

Check failure

Code scanning / gosec

Potential integer overflow by integer type conversion Error

Potential integer overflow by integer type conversion

s.logs = append(s.logs, log)
s.ephemeralStore.AddLog(log)
}

// Logs returns the logs of current transaction.
func (s *StateDB) Logs() []*ethtypes.Log {
return s.logs
return s.ephemeralStore.GetLogs()
}

// AddRefund adds gas to the refund counter
Expand Down Expand Up @@ -396,7 +394,10 @@ func (s *StateDB) SlotInAccessList(addr common.Address, slot common.Hash) (addre

// Snapshot returns an identifier for the current revision of the state.
func (s *StateDB) Snapshot() int {
return s.ctx.Snapshot(s.journal.length(), len(s.logs), s.ephemeralStore.GetRevertKey())
return s.ctx.Snapshot(
s.journal.length(),
s.ephemeralStore.GetRevertKey(),
)
}

// RevertToSnapshot reverts all state changes made since the given revision.
Expand All @@ -410,10 +411,9 @@ func (s *StateDB) RevertToSnapshot(revid int) {

// Revert journal to the latest snapshot's journal index
s.journal.Revert(s, currentSnapshot.journalIndex)
s.ephemeralStore.Revert(currentSnapshot.storeRevertKey)

// Revert logs to the latest snapshot's logs index
s.logs = s.logs[:currentSnapshot.logsIndex]
// Revert ephemeral store: refunds, logs, suicided accounts
s.ephemeralStore.Revert(currentSnapshot.storeRevertKey)
}

// the StateDB object should be discarded after committed.
Expand Down
85 changes: 62 additions & 23 deletions x/evm/statedb/store.go
Original file line number Diff line number Diff line change
Expand Up @@ -4,73 +4,112 @@ import (
"fmt"

"github.com/ethereum/go-ethereum/common"
ethtypes "github.com/ethereum/go-ethereum/core/types"
)

// StoreRevertKey defines the required information to revert to a previous state.
type StoreRevertKey struct {
RefundIndex int
SuicidedAccountsIndex int
LogsIndex int
}

// EphemeralStore provides in-memory state of the refund and suicided accounts
// state with the ability to revert to a previous state.
type EphemeralStore struct {
refundStates []uint64
suicidedAccountStates []common.Address
RefundStates []uint64
SuicidedAccountStates []common.Address
Logs []*ethtypes.Log
}

// NewEphemeralStore creates a new EphemeralStore.
func NewEphemeralStore() *EphemeralStore {
return &EphemeralStore{
refundStates: []uint64{},
suicidedAccountStates: []common.Address{},
RefundStates: nil,
SuicidedAccountStates: nil,
Logs: nil,
}
}

// GetRevertKey returns the identifier of the current state of the store.
func (es *EphemeralStore) GetRevertKey() StoreRevertKey {
return StoreRevertKey{
RefundIndex: len(es.refundStates),
SuicidedAccountsIndex: len(es.suicidedAccountStates),
RefundIndex: len(es.RefundStates),
SuicidedAccountsIndex: len(es.SuicidedAccountStates),
LogsIndex: len(es.Logs),
}
}

// Revert reverts the state to the given key.
func (es *EphemeralStore) Revert(key StoreRevertKey) {
if key.RefundIndex > len(es.refundStates) {
panic(fmt.Errorf(
if err := es.ValidateRevertKey(key); err != nil {
panic(err)
}

es.RefundStates = es.RefundStates[:key.RefundIndex]
es.SuicidedAccountStates = es.SuicidedAccountStates[:key.SuicidedAccountsIndex]
es.Logs = es.Logs[:key.LogsIndex]
}

func (es *EphemeralStore) ValidateRevertKey(key StoreRevertKey) error {
if key.RefundIndex > len(es.RefundStates) {
return fmt.Errorf(
"invalid RefundIndex, %d is greater than the length of the refund states (%d)",
key.RefundIndex, len(es.refundStates),
))
key.RefundIndex, len(es.RefundStates),
)
}

if key.SuicidedAccountsIndex > len(es.suicidedAccountStates) {
panic(fmt.Errorf(
if key.SuicidedAccountsIndex > len(es.SuicidedAccountStates) {
return fmt.Errorf(
"invalid SuicidedAccountsIndex, %d is greater than the length of the suicided accounts (%d)",
key.SuicidedAccountsIndex, len(es.suicidedAccountStates),
))
key.SuicidedAccountsIndex, len(es.SuicidedAccountStates),
)
}

es.refundStates = es.refundStates[:key.RefundIndex]
es.suicidedAccountStates = es.suicidedAccountStates[:key.SuicidedAccountsIndex]
if key.LogsIndex > len(es.Logs) {
return fmt.Errorf(
"invalid LogsIndex, %d is greater than the length of the logs (%d)",
key.LogsIndex, len(es.Logs),
)
}

return nil
}

// -----------------------------------------------------------------------------
// Logs

// AddLog adds a log to the store.
func (es *EphemeralStore) AddLog(log *ethtypes.Log) {
es.Logs = append(es.Logs, log)
}

// GetLogsCount returns the number of logs.
func (es *EphemeralStore) GetLogsCount() int {
return len(es.Logs)
}

// GetLogs returns all logs.
func (es *EphemeralStore) GetLogs() []*ethtypes.Log {
return es.Logs
}

// -----------------------------------------------------------------------------
// Refund

// GetRefund returns the current refund value, which is the last element.
func (es *EphemeralStore) GetRefund() uint64 {
if len(es.refundStates) == 0 {
if len(es.RefundStates) == 0 {
return 0
}

return es.refundStates[len(es.refundStates)-1]
return es.RefundStates[len(es.RefundStates)-1]
}

// AddRefund adds a refund to the store.
func (es *EphemeralStore) AddRefund(gas uint64) {
newRefund := es.GetRefund() + gas
es.refundStates = append(es.refundStates, newRefund)
es.RefundStates = append(es.RefundStates, newRefund)
}

// SubRefund subtracts a refund from the store.
Expand All @@ -82,7 +121,7 @@ func (es *EphemeralStore) SubRefund(gas uint64) {
}

newRefund := currentRefund - gas
es.refundStates = append(es.refundStates, newRefund)
es.RefundStates = append(es.RefundStates, newRefund)
}

// -----------------------------------------------------------------------------
Expand All @@ -95,12 +134,12 @@ func (es *EphemeralStore) SetAccountSuicided(addr common.Address) {
return
}

es.suicidedAccountStates = append(es.suicidedAccountStates, addr)
es.SuicidedAccountStates = append(es.SuicidedAccountStates, addr)
}

// GetAccountSuicided returns true if the given account is suicided.
func (es *EphemeralStore) GetAccountSuicided(addr common.Address) bool {
for _, a := range es.suicidedAccountStates {
for _, a := range es.SuicidedAccountStates {
if a == addr {
return true
}
Expand All @@ -111,5 +150,5 @@ func (es *EphemeralStore) GetAccountSuicided(addr common.Address) bool {

// GetAllSuicided returns all suicided accounts.
func (es *EphemeralStore) GetAllSuicided() []common.Address {
return es.suicidedAccountStates
return es.SuicidedAccountStates
}
Loading

0 comments on commit 5ef345d

Please sign in to comment.