2023-03-14 21:26:20 +01:00
|
|
|
package ethapi
|
|
|
|
|
|
|
|
import (
|
|
|
|
"bytes"
|
|
|
|
"encoding/json"
|
|
|
|
"errors"
|
|
|
|
|
|
|
|
"github.com/ethereum/go-ethereum/common"
|
|
|
|
"github.com/ethereum/go-ethereum/common/hexutil"
|
|
|
|
"github.com/ethereum/go-ethereum/core/state"
|
|
|
|
)
|
|
|
|
|
|
|
|
type AccountStorage struct {
|
2023-03-29 21:55:41 +02:00
|
|
|
StorageRoot *common.Hash
|
|
|
|
StorageSlots map[common.Hash]common.Hash
|
2023-03-14 21:26:20 +01:00
|
|
|
}
|
|
|
|
|
2023-03-29 21:55:41 +02:00
|
|
|
func (a *AccountStorage) UnmarshalJSON(data []byte) error {
|
2023-03-14 21:26:20 +01:00
|
|
|
var hash common.Hash
|
|
|
|
if err := json.Unmarshal(data, &hash); err == nil {
|
2023-03-29 21:55:41 +02:00
|
|
|
a.StorageRoot = &hash
|
2023-03-14 21:26:20 +01:00
|
|
|
return nil
|
|
|
|
}
|
2023-03-29 21:55:41 +02:00
|
|
|
return json.Unmarshal(data, &a.StorageSlots)
|
2023-03-14 21:26:20 +01:00
|
|
|
}
|
|
|
|
|
2023-03-29 21:55:41 +02:00
|
|
|
func (a AccountStorage) MarshalJSON() ([]byte, error) {
|
|
|
|
if a.StorageRoot != nil {
|
|
|
|
return json.Marshal(*a.StorageRoot)
|
2023-03-14 21:26:20 +01:00
|
|
|
}
|
2023-03-29 21:55:41 +02:00
|
|
|
return json.Marshal(a.StorageSlots)
|
2023-03-14 21:26:20 +01:00
|
|
|
}
|
|
|
|
|
2023-03-29 21:55:41 +02:00
|
|
|
type KnownAccounts map[common.Address]AccountStorage
|
|
|
|
|
|
|
|
// It is known that marshaling is broken
|
|
|
|
// https://github.com/golang/go/issues/55890
|
|
|
|
|
|
|
|
//go:generate go run github.com/fjl/gencodec -type TransactionOpts -out gen_tx_opts_json.go
|
2023-03-14 21:26:20 +01:00
|
|
|
type TransactionOpts struct {
|
2023-03-29 21:55:41 +02:00
|
|
|
KnownAccounts KnownAccounts `json:"knownAccounts"`
|
|
|
|
BlockNumberMin *hexutil.Uint64 `json:"blockNumberMin,omitempty"`
|
|
|
|
BlockNumberMax *hexutil.Uint64 `json:"blockNumberMax,omitempty"`
|
|
|
|
TimestampMin *hexutil.Uint64 `json:"timestampMin,omitempty"`
|
|
|
|
TimestampMax *hexutil.Uint64 `json:"timestampMax,omitempty"`
|
2023-03-14 21:26:20 +01:00
|
|
|
}
|
|
|
|
|
2023-03-31 08:34:47 +02:00
|
|
|
const MaxNumberOfEntries = 1000
|
|
|
|
|
2023-03-14 21:26:20 +01:00
|
|
|
func (o *TransactionOpts) Check(blockNumber uint64, timeStamp uint64, statedb *state.StateDB) error {
|
|
|
|
if o.BlockNumberMin != nil && blockNumber < uint64(*o.BlockNumberMin) {
|
|
|
|
return errors.New("BlockNumberMin condition not met")
|
|
|
|
}
|
|
|
|
if o.BlockNumberMax != nil && blockNumber > uint64(*o.BlockNumberMax) {
|
|
|
|
return errors.New("BlockNumberMax condition not met")
|
|
|
|
}
|
|
|
|
if o.TimestampMin != nil && timeStamp < uint64(*o.TimestampMin) {
|
|
|
|
return errors.New("TimestampMin condition not met")
|
|
|
|
}
|
|
|
|
if o.TimestampMax != nil && timeStamp > uint64(*o.TimestampMax) {
|
|
|
|
return errors.New("TimestampMax condition not met")
|
|
|
|
}
|
2023-03-22 08:23:26 +01:00
|
|
|
counter := 0
|
|
|
|
for _, account := range o.KnownAccounts {
|
2023-03-29 21:55:41 +02:00
|
|
|
if account.StorageRoot != nil {
|
2023-03-22 08:23:26 +01:00
|
|
|
counter += 1
|
2023-03-29 21:55:41 +02:00
|
|
|
} else if account.StorageSlots != nil {
|
|
|
|
counter += len(account.StorageSlots)
|
2023-03-22 08:23:26 +01:00
|
|
|
}
|
|
|
|
}
|
2023-03-31 08:34:47 +02:00
|
|
|
if counter > MaxNumberOfEntries {
|
2023-03-14 21:26:20 +01:00
|
|
|
return errors.New("knownAccounts too large")
|
|
|
|
}
|
2023-03-29 21:55:41 +02:00
|
|
|
return o.CheckStorage(statedb)
|
2023-03-14 21:26:20 +01:00
|
|
|
}
|
|
|
|
|
2023-03-29 21:55:41 +02:00
|
|
|
func (o *TransactionOpts) CheckStorage(statedb *state.StateDB) error {
|
2023-03-14 21:26:20 +01:00
|
|
|
for address, accountStorage := range o.KnownAccounts {
|
2023-03-29 21:55:41 +02:00
|
|
|
if accountStorage.StorageRoot != nil {
|
2023-03-31 08:34:47 +02:00
|
|
|
rootHash := statedb.GetRoot(address)
|
|
|
|
if rootHash != *accountStorage.StorageRoot {
|
2023-03-14 21:26:20 +01:00
|
|
|
return errors.New("storage root hash condition not met")
|
|
|
|
}
|
2023-03-29 21:55:41 +02:00
|
|
|
} else if len(accountStorage.StorageSlots) > 0 {
|
|
|
|
for slot, value := range accountStorage.StorageSlots {
|
2023-03-14 21:26:20 +01:00
|
|
|
stored := statedb.GetState(address, slot)
|
|
|
|
if !bytes.Equal(stored.Bytes(), value.Bytes()) {
|
|
|
|
return errors.New("storage slot value condition not met")
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return nil
|
|
|
|
}
|