mirror of
https://gitlab.com/pulsechaincom/erigon-pulse.git
synced 2025-01-05 18:42:19 +00:00
94f4ea805d
the root cause is that when `inMemoryExecution` lambda gets created in the `eth/backend.go`, it captures the reference of `backend.notifications`, and so the execution of side-forks actually adds notifications to there, and it all gets sent out to tx pool (and RPC daemon) at the end of the stage loop (regardless of whether there was forkchoice update or not) so we can create a separate notification, but then somehow flush it to the "main" nofitications when the in-memory exec state is flushed Co-authored-by: Alexey Sharp <alexeysharp@Alexeys-iMac.local> Co-authored-by: Alex Sharp <alexsharp@Alexs-MacBook-Pro.local>
172 lines
6.1 KiB
Go
172 lines
6.1 KiB
Go
package shards
|
|
|
|
import (
|
|
"context"
|
|
|
|
libcommon "github.com/ledgerwatch/erigon-lib/common"
|
|
"github.com/ledgerwatch/erigon-lib/gointerfaces"
|
|
"github.com/ledgerwatch/erigon-lib/gointerfaces/remote"
|
|
"github.com/ledgerwatch/erigon/common"
|
|
)
|
|
|
|
// Accumulator collects state changes in a form that can then be delivered to the RPC daemon
|
|
type Accumulator struct {
|
|
viewID uint64 // mdbx's txID
|
|
changes []*remote.StateChange
|
|
latestChange *remote.StateChange
|
|
accountChangeIndex map[common.Address]int // For the latest changes, allows finding account change by account's address
|
|
storageChangeIndex map[common.Address]map[common.Hash]int
|
|
}
|
|
|
|
func NewAccumulator() *Accumulator {
|
|
return &Accumulator{}
|
|
}
|
|
|
|
type StateChangeConsumer interface {
|
|
SendStateChanges(ctx context.Context, sc *remote.StateChangeBatch)
|
|
}
|
|
|
|
func (a *Accumulator) Reset(viewID uint64) {
|
|
a.changes = nil
|
|
a.latestChange = nil
|
|
a.accountChangeIndex = nil
|
|
a.storageChangeIndex = nil
|
|
a.viewID = viewID
|
|
}
|
|
func (a *Accumulator) SendAndReset(ctx context.Context, c StateChangeConsumer, pendingBaseFee uint64, blockGasLimit uint64) {
|
|
if a == nil || c == nil || len(a.changes) == 0 {
|
|
return
|
|
}
|
|
sc := &remote.StateChangeBatch{DatabaseViewID: a.viewID, ChangeBatch: a.changes, PendingBlockBaseFee: pendingBaseFee, BlockGasLimit: blockGasLimit}
|
|
c.SendStateChanges(ctx, sc)
|
|
a.Reset(0) // reset here for GC, but there will be another Reset with correct viewID
|
|
}
|
|
|
|
// StartChange begins accumulation of changes for a new block
|
|
func (a *Accumulator) StartChange(blockHeight uint64, blockHash common.Hash, txs [][]byte, unwind bool) {
|
|
a.changes = append(a.changes, &remote.StateChange{})
|
|
a.latestChange = a.changes[len(a.changes)-1]
|
|
a.latestChange.BlockHeight = blockHeight
|
|
a.latestChange.BlockHash = gointerfaces.ConvertHashToH256(blockHash)
|
|
if unwind {
|
|
a.latestChange.Direction = remote.Direction_UNWIND
|
|
} else {
|
|
a.latestChange.Direction = remote.Direction_FORWARD
|
|
}
|
|
a.accountChangeIndex = make(map[common.Address]int)
|
|
a.storageChangeIndex = make(map[common.Address]map[common.Hash]int)
|
|
if txs != nil {
|
|
a.latestChange.Txs = make([][]byte, len(txs))
|
|
for i := range txs {
|
|
a.latestChange.Txs[i] = libcommon.Copy(txs[i])
|
|
}
|
|
}
|
|
}
|
|
|
|
// ChangeAccount adds modification of account balance or nonce (or both) to the latest change
|
|
func (a *Accumulator) ChangeAccount(address common.Address, incarnation uint64, data []byte) {
|
|
i, ok := a.accountChangeIndex[address]
|
|
if !ok || incarnation > a.latestChange.Changes[i].Incarnation {
|
|
// Account has not been changed in the latest block yet
|
|
i = len(a.latestChange.Changes)
|
|
a.latestChange.Changes = append(a.latestChange.Changes, &remote.AccountChange{Address: gointerfaces.ConvertAddressToH160(address)})
|
|
a.accountChangeIndex[address] = i
|
|
delete(a.storageChangeIndex, address)
|
|
}
|
|
accountChange := a.latestChange.Changes[i]
|
|
switch accountChange.Action {
|
|
case remote.Action_STORAGE:
|
|
accountChange.Action = remote.Action_UPSERT
|
|
case remote.Action_CODE:
|
|
accountChange.Action = remote.Action_UPSERT_CODE
|
|
case remote.Action_REMOVE:
|
|
panic("")
|
|
}
|
|
accountChange.Incarnation = incarnation
|
|
accountChange.Data = data
|
|
}
|
|
|
|
// DeleteAccount marks account as deleted
|
|
func (a *Accumulator) DeleteAccount(address common.Address) {
|
|
i, ok := a.accountChangeIndex[address]
|
|
if !ok {
|
|
// Account has not been changed in the latest block yet
|
|
i = len(a.latestChange.Changes)
|
|
a.latestChange.Changes = append(a.latestChange.Changes, &remote.AccountChange{Address: gointerfaces.ConvertAddressToH160(address)})
|
|
a.accountChangeIndex[address] = i
|
|
}
|
|
accountChange := a.latestChange.Changes[i]
|
|
if accountChange.Action != remote.Action_STORAGE {
|
|
panic("")
|
|
}
|
|
accountChange.Data = nil
|
|
accountChange.Code = nil
|
|
accountChange.StorageChanges = nil
|
|
accountChange.Action = remote.Action_REMOVE
|
|
delete(a.storageChangeIndex, address)
|
|
}
|
|
|
|
// ChangeCode adds code to the latest change
|
|
func (a *Accumulator) ChangeCode(address common.Address, incarnation uint64, code []byte) {
|
|
i, ok := a.accountChangeIndex[address]
|
|
if !ok || incarnation > a.latestChange.Changes[i].Incarnation {
|
|
// Account has not been changed in the latest block yet
|
|
i = len(a.latestChange.Changes)
|
|
a.latestChange.Changes = append(a.latestChange.Changes, &remote.AccountChange{Address: gointerfaces.ConvertAddressToH160(address), Action: remote.Action_CODE})
|
|
a.accountChangeIndex[address] = i
|
|
delete(a.storageChangeIndex, address)
|
|
}
|
|
accountChange := a.latestChange.Changes[i]
|
|
switch accountChange.Action {
|
|
case remote.Action_STORAGE:
|
|
accountChange.Action = remote.Action_CODE
|
|
case remote.Action_UPSERT:
|
|
accountChange.Action = remote.Action_UPSERT_CODE
|
|
case remote.Action_REMOVE:
|
|
panic("")
|
|
}
|
|
accountChange.Incarnation = incarnation
|
|
accountChange.Code = code
|
|
}
|
|
|
|
func (a *Accumulator) ChangeStorage(address common.Address, incarnation uint64, location common.Hash, data []byte) {
|
|
i, ok := a.accountChangeIndex[address]
|
|
if !ok || incarnation > a.latestChange.Changes[i].Incarnation {
|
|
// Account has not been changed in the latest block yet
|
|
i = len(a.latestChange.Changes)
|
|
a.latestChange.Changes = append(a.latestChange.Changes, &remote.AccountChange{Address: gointerfaces.ConvertAddressToH160(address), Action: remote.Action_STORAGE})
|
|
a.accountChangeIndex[address] = i
|
|
delete(a.storageChangeIndex, address)
|
|
}
|
|
accountChange := a.latestChange.Changes[i]
|
|
if accountChange.Action == remote.Action_REMOVE {
|
|
panic("")
|
|
}
|
|
accountChange.Incarnation = incarnation
|
|
si, ok1 := a.storageChangeIndex[address]
|
|
if !ok1 {
|
|
si = make(map[common.Hash]int)
|
|
a.storageChangeIndex[address] = si
|
|
}
|
|
j, ok2 := si[location]
|
|
if !ok2 {
|
|
j = len(accountChange.StorageChanges)
|
|
accountChange.StorageChanges = append(accountChange.StorageChanges, &remote.StorageChange{})
|
|
si[location] = j
|
|
}
|
|
storageChange := accountChange.StorageChanges[j]
|
|
storageChange.Location = gointerfaces.ConvertHashToH256(location)
|
|
storageChange.Data = data
|
|
}
|
|
|
|
func (a *Accumulator) CopyAndReset(target *Accumulator) {
|
|
target.changes = a.changes
|
|
a.changes = nil
|
|
target.latestChange = a.latestChange
|
|
a.latestChange = nil
|
|
target.accountChangeIndex = a.accountChangeIndex
|
|
a.accountChangeIndex = nil
|
|
target.storageChangeIndex = a.storageChangeIndex
|
|
a.storageChangeIndex = nil
|
|
}
|