2021-05-23 14:53:18 +00:00
|
|
|
package shards
|
|
|
|
|
|
|
|
import (
|
2021-08-17 08:52:55 +00:00
|
|
|
"context"
|
|
|
|
|
2021-09-12 07:50:17 +00:00
|
|
|
libcommon "github.com/ledgerwatch/erigon-lib/common"
|
2021-07-01 21:31:14 +00:00
|
|
|
"github.com/ledgerwatch/erigon-lib/gointerfaces"
|
|
|
|
"github.com/ledgerwatch/erigon-lib/gointerfaces/remote"
|
2021-05-23 14:53:18 +00:00
|
|
|
"github.com/ledgerwatch/erigon/common"
|
2021-09-26 16:09:36 +00:00
|
|
|
"github.com/ledgerwatch/erigon/params"
|
2021-05-23 14:53:18 +00:00
|
|
|
)
|
|
|
|
|
|
|
|
// Accumulator collects state changes in a form that can then be delivered to the RPC daemon
|
|
|
|
type Accumulator struct {
|
2021-09-17 03:31:20 +00:00
|
|
|
viewID uint64 // mdbx's txID
|
2021-09-26 16:09:36 +00:00
|
|
|
chainConfig *params.ChainConfig
|
2021-09-17 03:31:20 +00:00
|
|
|
changes []*remote.StateChange
|
2021-05-23 14:53:18 +00:00
|
|
|
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
|
|
|
|
}
|
|
|
|
|
2021-09-26 16:09:36 +00:00
|
|
|
func NewAccumulator(chainConfig *params.ChainConfig) *Accumulator {
|
|
|
|
return &Accumulator{chainConfig: chainConfig}
|
|
|
|
}
|
|
|
|
|
2021-08-17 08:52:55 +00:00
|
|
|
type StateChangeConsumer interface {
|
2021-09-17 03:31:20 +00:00
|
|
|
SendStateChanges(ctx context.Context, sc *remote.StateChangeBatch)
|
2021-08-17 08:52:55 +00:00
|
|
|
}
|
|
|
|
|
2021-09-17 03:31:20 +00:00
|
|
|
func (a *Accumulator) Reset(viewID uint64) {
|
2021-07-10 09:43:58 +00:00
|
|
|
a.changes = nil
|
|
|
|
a.latestChange = nil
|
|
|
|
a.accountChangeIndex = nil
|
|
|
|
a.storageChangeIndex = nil
|
2021-09-17 03:31:20 +00:00
|
|
|
a.viewID = viewID
|
2021-07-10 09:43:58 +00:00
|
|
|
}
|
2021-09-26 16:09:36 +00:00
|
|
|
func (a *Accumulator) ChainConfig() *params.ChainConfig { return a.chainConfig }
|
2022-01-25 10:49:28 +00:00
|
|
|
func (a *Accumulator) SendAndReset(ctx context.Context, c StateChangeConsumer, pendingBaseFee uint64, blockGasLimit uint64) {
|
2021-08-17 08:52:55 +00:00
|
|
|
if a == nil || c == nil || len(a.changes) == 0 {
|
|
|
|
return
|
|
|
|
}
|
2022-01-25 10:49:28 +00:00
|
|
|
sc := &remote.StateChangeBatch{DatabaseViewID: a.viewID, ChangeBatch: a.changes, PendingBlockBaseFee: pendingBaseFee, BlockGasLimit: blockGasLimit}
|
2021-09-26 16:09:36 +00:00
|
|
|
c.SendStateChanges(ctx, sc)
|
2021-09-17 03:31:20 +00:00
|
|
|
a.Reset(0) // reset here for GC, but there will be another Reset with correct viewID
|
2021-08-17 08:52:55 +00:00
|
|
|
}
|
2021-07-10 09:43:58 +00:00
|
|
|
|
2021-08-17 08:52:55 +00:00
|
|
|
// StartChange begins accumulation of changes for a new block
|
2021-09-26 16:09:36 +00:00
|
|
|
func (a *Accumulator) StartChange(blockHeight uint64, blockHash common.Hash, txs [][]byte, unwind bool) {
|
2021-09-17 03:31:20 +00:00
|
|
|
a.changes = append(a.changes, &remote.StateChange{})
|
|
|
|
a.latestChange = a.changes[len(a.changes)-1]
|
2021-05-23 14:53:18 +00:00
|
|
|
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)
|
2021-08-17 08:52:55 +00:00
|
|
|
if txs != nil {
|
|
|
|
a.latestChange.Txs = make([][]byte, len(txs))
|
|
|
|
for i := range txs {
|
2021-09-12 07:50:17 +00:00
|
|
|
a.latestChange.Txs[i] = libcommon.Copy(txs[i])
|
2021-08-17 08:52:55 +00:00
|
|
|
}
|
|
|
|
}
|
2021-05-23 14:53:18 +00:00
|
|
|
}
|
|
|
|
|
2021-08-17 08:52:55 +00:00
|
|
|
// ChangeAccount adds modification of account balance or nonce (or both) to the latest change
|
2021-08-18 02:41:07 +00:00
|
|
|
func (a *Accumulator) ChangeAccount(address common.Address, incarnation uint64, data []byte) {
|
2021-05-23 14:53:18 +00:00
|
|
|
i, ok := a.accountChangeIndex[address]
|
2021-08-18 02:41:07 +00:00
|
|
|
if !ok || incarnation > a.latestChange.Changes[i].Incarnation {
|
2021-05-23 14:53:18 +00:00
|
|
|
// Account has not been changed in the latest block yet
|
|
|
|
i = len(a.latestChange.Changes)
|
2021-08-17 08:52:55 +00:00
|
|
|
a.latestChange.Changes = append(a.latestChange.Changes, &remote.AccountChange{Address: gointerfaces.ConvertAddressToH160(address)})
|
2021-05-23 14:53:18 +00:00
|
|
|
a.accountChangeIndex[address] = i
|
|
|
|
}
|
|
|
|
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
|
2022-07-01 10:52:43 +00:00
|
|
|
case remote.Action_REMOVE:
|
2021-05-23 14:53:18 +00:00
|
|
|
panic("")
|
|
|
|
}
|
2021-08-18 02:41:07 +00:00
|
|
|
accountChange.Incarnation = incarnation
|
2021-05-23 14:53:18 +00:00
|
|
|
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)
|
2021-08-17 08:52:55 +00:00
|
|
|
a.latestChange.Changes = append(a.latestChange.Changes, &remote.AccountChange{Address: gointerfaces.ConvertAddressToH160(address)})
|
2021-05-23 14:53:18 +00:00
|
|
|
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
|
2022-07-01 10:52:43 +00:00
|
|
|
accountChange.Action = remote.Action_REMOVE
|
2021-05-23 14:53:18 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
// ChangeCode adds code to the latest change
|
|
|
|
func (a *Accumulator) ChangeCode(address common.Address, incarnation uint64, code []byte) {
|
|
|
|
i, ok := a.accountChangeIndex[address]
|
2021-08-18 02:41:07 +00:00
|
|
|
if !ok || incarnation > a.latestChange.Changes[i].Incarnation {
|
2021-05-23 14:53:18 +00:00
|
|
|
// Account has not been changed in the latest block yet
|
|
|
|
i = len(a.latestChange.Changes)
|
2021-08-18 02:41:07 +00:00
|
|
|
a.latestChange.Changes = append(a.latestChange.Changes, &remote.AccountChange{Address: gointerfaces.ConvertAddressToH160(address), Action: remote.Action_CODE})
|
2021-05-23 14:53:18 +00:00
|
|
|
a.accountChangeIndex[address] = i
|
|
|
|
}
|
|
|
|
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
|
2022-07-01 10:52:43 +00:00
|
|
|
case remote.Action_REMOVE:
|
2021-05-23 14:53:18 +00:00
|
|
|
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]
|
2021-08-18 02:41:07 +00:00
|
|
|
if !ok || incarnation > a.latestChange.Changes[i].Incarnation {
|
2021-05-23 14:53:18 +00:00
|
|
|
// Account has not been changed in the latest block yet
|
|
|
|
i = len(a.latestChange.Changes)
|
2021-08-18 02:41:07 +00:00
|
|
|
a.latestChange.Changes = append(a.latestChange.Changes, &remote.AccountChange{Address: gointerfaces.ConvertAddressToH160(address), Action: remote.Action_STORAGE})
|
2021-05-23 14:53:18 +00:00
|
|
|
a.accountChangeIndex[address] = i
|
|
|
|
}
|
|
|
|
accountChange := a.latestChange.Changes[i]
|
2022-07-01 10:52:43 +00:00
|
|
|
if accountChange.Action == remote.Action_REMOVE {
|
2021-05-23 14:53:18 +00:00
|
|
|
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
|
|
|
|
}
|