update code

fix state processing

read only db
This commit is contained in:
Roy Crihfield 2024-04-23 18:25:52 +08:00
parent 9593c7bde0
commit 6b65a54d1c
2 changed files with 51 additions and 122 deletions

View File

@ -25,120 +25,19 @@ import (
var errNotSupported = errors.New("this operation is not supported") var errNotSupported = errors.New("this operation is not supported")
type database struct { type database struct {
ethDB ethdb.Database ethdb.Database
} }
func newDatabase(db ethdb.Database) *database { func newDatabase(db ethdb.Database) *database {
return &database{ return &database{
ethDB: db, Database: db,
} }
} }
func (d *database) NewIterator(prefix []byte, start []byte) ethdb.Iterator {
return d.ethDB.NewIterator(prefix, start)
}
func (d *database) Has(key []byte) (bool, error) {
return d.ethDB.Has(key)
}
func (d *database) Get(key []byte) ([]byte, error) {
return d.ethDB.Get(key)
}
func (d *database) Put(key []byte, value []byte) error { func (d *database) Put(key []byte, value []byte) error {
return nil return errNotSupported
} }
func (d *database) Delete(key []byte) error { func (d *database) Delete(key []byte) error {
return nil return errNotSupported
}
func (d *database) Stat(property string) (string, error) {
return d.ethDB.Stat(property)
}
func (d *database) Compact(start []byte, limit []byte) error {
return d.ethDB.Compact(start, limit)
}
// HasAncient returns an error as we don't have a backing chain freezer.
func (d *database) HasAncient(kind string, number uint64) (bool, error) {
return d.ethDB.HasAncient(kind, number)
}
// Ancient returns an error as we don't have a backing chain freezer.
func (d *database) Ancient(kind string, number uint64) ([]byte, error) {
return d.ethDB.Ancient(kind, number)
}
// AncientRange returns an error as we don't have a backing chain freezer.
func (d *database) AncientRange(kind string, start, max, maxByteSize uint64) ([][]byte, error) {
return d.ethDB.AncientRange(kind, start, max, maxByteSize)
}
// Ancients returns an error as we don't have a backing chain freezer.
func (d *database) Ancients() (uint64, error) {
return d.ethDB.Ancients()
}
// AncientSize returns an error as we don't have a backing chain freezer.
func (d *database) AncientSize(kind string) (uint64, error) {
return d.ethDB.AncientSize(kind)
}
// Tail returns the number of first stored item in the freezer.
func (d *database) Tail() (uint64, error) {
return d.Tail()
}
// ModifyAncients is not supported.
func (d *database) ModifyAncients(fn func(ethdb.AncientWriteOp) error) (int64, error) {
return 0, nil
}
// TruncateHead discards all but the first n ancient data from the ancient store.
func (d *database) TruncateHead(n uint64) error {
return nil
}
// TruncateTail discards the first n ancient data from the ancient store.
func (d *database) TruncateTail(n uint64) error {
return nil
}
func (d *database) Sync() error {
return d.ethDB.Sync()
}
// MigrateTable processes and migrates entries of a given table to a new format.
func (d *database) MigrateTable(string, func([]byte) ([]byte, error)) error {
return nil
}
func (d *database) NewBatch() ethdb.Batch {
return d.ethDB.NewBatch()
}
// NewBatchWithSize creates a write-only database batch with pre-allocated buffer.
func (d *database) NewBatchWithSize(size int) ethdb.Batch {
return d.ethDB.NewBatchWithSize(size)
}
func (d *database) ReadAncients(fn func(ethdb.AncientReaderOp) error) (err error) {
return d.ethDB.ReadAncients(fn)
}
func (d *database) Close() error {
return d.ethDB.Close()
}
// NewSnapshot creates a database snapshot based on the current state.
func (d *database) NewSnapshot() (ethdb.Snapshot, error) {
return d.NewSnapshot()
}
// NewSnapshot creates a database snapshot based on the current state.
func (d *database) AncientDatadir() (string, error) {
return "", errNotSupported
} }

View File

@ -25,7 +25,7 @@ import (
"sync" "sync"
"time" "time"
"github.com/cerc-io/plugeth-statediff" statediff "github.com/cerc-io/plugeth-statediff"
"github.com/cerc-io/plugeth-statediff/indexer/database/sql/postgres" "github.com/cerc-io/plugeth-statediff/indexer/database/sql/postgres"
"github.com/ethereum/go-ethereum/common" "github.com/ethereum/go-ethereum/common"
"github.com/ethereum/go-ethereum/consensus" "github.com/ethereum/go-ethereum/consensus"
@ -36,6 +36,7 @@ import (
"github.com/ethereum/go-ethereum/core/vm" "github.com/ethereum/go-ethereum/core/vm"
"github.com/ethereum/go-ethereum/params" "github.com/ethereum/go-ethereum/params"
"github.com/ethereum/go-ethereum/rpc" "github.com/ethereum/go-ethereum/rpc"
"github.com/holiman/uint256"
"github.com/jmoiron/sqlx" "github.com/jmoiron/sqlx"
log "github.com/sirupsen/logrus" log "github.com/sirupsen/logrus"
@ -246,13 +247,13 @@ func ethBackend(db *sqlx.DB, c *ipldeth.Config) (*ipldeth.Backend, error) {
ExpiryDuration: time.Minute * time.Duration(gcc.StateDB.CacheExpiryInMins), ExpiryDuration: time.Minute * time.Duration(gcc.StateDB.CacheExpiryInMins),
}) })
// Read only wrapper around ipfs-ethdb eth.Database implementation // Read only wrapper around ipfs-ethdb eth.Database implementation
customEthDB := newDatabase(ethDB) ethDB = newDatabase(ethDB)
return &ipldeth.Backend{ return &ipldeth.Backend{
DB: db, DB: db,
Retriever: r, Retriever: r,
EthDB: customEthDB, EthDB: ethDB,
IpldTrieStateDatabase: ipldstate.NewDatabase(customEthDB), IpldTrieStateDatabase: ipldstate.NewDatabase(ethDB),
Config: c, Config: c,
}, nil }, nil
} }
@ -294,10 +295,13 @@ func (s *Service) writeStateDiffAt(height uint64) error {
// applyTransaction attempts to apply block transactions to the given state database // applyTransaction attempts to apply block transactions to the given state database
// and uses the input parameters for its environment. It returns the stateDB of parent with applied txs. // and uses the input parameters for its environment. It returns the stateDB of parent with applied txs.
//
// Note: this skips the DAO hard fork refund
func applyTransactions(block *types.Block, backend *ipldeth.Backend) (*ipldstate.StateDB, error) { func applyTransactions(block *types.Block, backend *ipldeth.Backend) (*ipldstate.StateDB, error) {
if block.NumberU64() == 0 { if block.NumberU64() == 0 {
return nil, errors.New("no transaction in genesis") return nil, errors.New("no transaction in genesis")
} }
config := backend.Config.ChainConfig
// Create the parent state database // Create the parent state database
parentHash := block.ParentHash() parentHash := block.ParentHash()
@ -310,10 +314,13 @@ func applyTransactions(block *types.Block, backend *ipldeth.Backend) (*ipldstate
var gp core.GasPool var gp core.GasPool
gp.AddGas(block.GasLimit()) gp.AddGas(block.GasLimit())
signer := types.MakeSigner(backend.Config.ChainConfig, block.Number())
blockContext := core.NewEVMBlockContext(block.Header(), backend, getAuthor(backend, block.Header())) blockContext := core.NewEVMBlockContext(block.Header(), backend, getAuthor(backend, block.Header()))
evm := vm.NewEVM(blockContext, vm.TxContext{}, statedb, backend.Config.ChainConfig, vm.Config{}) evm := vm.NewEVM(blockContext, vm.TxContext{}, statedb, config, vm.Config{})
rules := backend.Config.ChainConfig.Rules(block.Number(), true, block.Time()) signer := types.MakeSigner(config, block.Number(), block.Time())
if beaconRoot := block.BeaconRoot(); beaconRoot != nil {
ProcessBeaconBlockRoot(*beaconRoot, evm, statedb)
}
// Iterate over and process the individual transactions // Iterate over and process the individual transactions
for i, tx := range block.Transactions() { for i, tx := range block.Transactions() {
@ -322,7 +329,6 @@ func applyTransactions(block *types.Block, backend *ipldeth.Backend) (*ipldstate
return nil, fmt.Errorf("error converting transaction to message: %w", err) return nil, fmt.Errorf("error converting transaction to message: %w", err)
} }
statedb.SetTxContext(tx.Hash(), i) statedb.SetTxContext(tx.Hash(), i)
statedb.Prepare(rules, msg.From, block.Coinbase(), msg.To, nil, nil)
// Create a new context to be used in the EVM environment. // Create a new context to be used in the EVM environment.
evm.Reset(core.NewEVMTxContext(msg), statedb) evm.Reset(core.NewEVMTxContext(msg), statedb)
@ -330,10 +336,16 @@ func applyTransactions(block *types.Block, backend *ipldeth.Backend) (*ipldstate
if _, err := core.ApplyMessage(evm, msg, &gp); err != nil { if _, err := core.ApplyMessage(evm, msg, &gp); err != nil {
return nil, fmt.Errorf("transaction %#x failed: %w", tx.Hash(), err) return nil, fmt.Errorf("transaction %#x failed: %w", tx.Hash(), err)
} }
if config.IsByzantium(block.Number()) {
statedb.Finalise(true)
} else {
statedb.IntermediateRoot(config.IsEIP158(block.Number())).Bytes()
}
} }
if backend.Config.ChainConfig.Ethash != nil { if config.Ethash != nil {
accumulateRewards(backend.Config.ChainConfig, statedb, block.Header(), block.Uncles()) accumulateRewards(config, statedb, block.Header(), block.Uncles())
} }
return statedb, nil return statedb, nil
@ -354,20 +366,40 @@ func accumulateRewards(config *params.ChainConfig, state *ipldstate.StateDB, hea
} }
// Accumulate the rewards for the miner and any included uncles // Accumulate the rewards for the miner and any included uncles
reward := new(big.Int).Set(blockReward) reward := new(big.Int).Set(blockReward.ToBig())
r := new(big.Int) r := new(big.Int)
for _, uncle := range uncles { for _, uncle := range uncles {
r.Add(uncle.Number, big8) r.Add(uncle.Number, big8)
r.Sub(r, header.Number) r.Sub(r, header.Number)
r.Mul(r, blockReward) r.Mul(r, blockReward.ToBig())
r.Div(r, big8) r.Div(r, big8)
state.AddBalance(uncle.Coinbase, r) state.AddBalance(uncle.Coinbase, uint256.MustFromBig(r))
r.Div(blockReward, big32) r.Div(blockReward.ToBig(), big32)
reward.Add(reward, r) reward.Add(reward, r)
} }
state.AddBalance(header.Coinbase, reward) state.AddBalance(header.Coinbase, uint256.MustFromBig(reward))
}
// ProcessBeaconBlockRoot applies the EIP-4788 system call to the beacon block root
// contract. This method is exported to be used in tests.
func ProcessBeaconBlockRoot(beaconRoot common.Hash, vmenv *vm.EVM, statedb *ipldstate.StateDB) {
// If EIP-4788 is enabled, we need to invoke the beaconroot storage contract with
// the new root
msg := &core.Message{
From: params.SystemAddress,
GasLimit: 30_000_000,
GasPrice: common.Big0,
GasFeeCap: common.Big0,
GasTipCap: common.Big0,
To: &params.BeaconRootsStorageAddress,
Data: beaconRoot[:],
}
vmenv.Reset(core.NewEVMTxContext(msg), statedb)
statedb.AddAddressToAccessList(params.BeaconRootsStorageAddress)
_, _, _ = vmenv.Call(vm.AccountRef(msg.From), *msg.To, msg.Data, 30_000_000, common.U2560)
statedb.Finalise(true)
} }
func setChainConfig(ghash common.Hash) *params.ChainConfig { func setChainConfig(ghash common.Hash) *params.ChainConfig {
@ -376,8 +408,6 @@ func setChainConfig(ghash common.Hash) *params.ChainConfig {
return params.MainnetChainConfig return params.MainnetChainConfig
case ghash == params.SepoliaGenesisHash: case ghash == params.SepoliaGenesisHash:
return params.SepoliaChainConfig return params.SepoliaChainConfig
case ghash == params.RinkebyGenesisHash:
return params.RinkebyChainConfig
case ghash == params.GoerliGenesisHash: case ghash == params.GoerliGenesisHash:
return params.GoerliChainConfig return params.GoerliChainConfig
default: default: