diff --git a/pkg/validator/database.go b/pkg/validator/database.go index 1b609fa..df5d2c0 100644 --- a/pkg/validator/database.go +++ b/pkg/validator/database.go @@ -25,120 +25,19 @@ import ( var errNotSupported = errors.New("this operation is not supported") type database struct { - ethDB ethdb.Database + ethdb.Database } func newDatabase(db ethdb.Database) *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 { - return nil + return errNotSupported } func (d *database) Delete(key []byte) error { - return nil -} - -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 + return errNotSupported } diff --git a/pkg/validator/validator.go b/pkg/validator/validator.go index b08d124..1a201a9 100644 --- a/pkg/validator/validator.go +++ b/pkg/validator/validator.go @@ -25,7 +25,7 @@ import ( "sync" "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/ethereum/go-ethereum/common" "github.com/ethereum/go-ethereum/consensus" @@ -36,6 +36,7 @@ import ( "github.com/ethereum/go-ethereum/core/vm" "github.com/ethereum/go-ethereum/params" "github.com/ethereum/go-ethereum/rpc" + "github.com/holiman/uint256" "github.com/jmoiron/sqlx" 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), }) // Read only wrapper around ipfs-ethdb eth.Database implementation - customEthDB := newDatabase(ethDB) + ethDB = newDatabase(ethDB) return &ipldeth.Backend{ DB: db, Retriever: r, - EthDB: customEthDB, - IpldTrieStateDatabase: ipldstate.NewDatabase(customEthDB), + EthDB: ethDB, + IpldTrieStateDatabase: ipldstate.NewDatabase(ethDB), Config: c, }, nil } @@ -294,10 +295,13 @@ func (s *Service) writeStateDiffAt(height uint64) error { // 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. +// +// Note: this skips the DAO hard fork refund func applyTransactions(block *types.Block, backend *ipldeth.Backend) (*ipldstate.StateDB, error) { if block.NumberU64() == 0 { return nil, errors.New("no transaction in genesis") } + config := backend.Config.ChainConfig // Create the parent state database parentHash := block.ParentHash() @@ -310,10 +314,13 @@ func applyTransactions(block *types.Block, backend *ipldeth.Backend) (*ipldstate var gp core.GasPool gp.AddGas(block.GasLimit()) - signer := types.MakeSigner(backend.Config.ChainConfig, block.Number()) blockContext := core.NewEVMBlockContext(block.Header(), backend, getAuthor(backend, block.Header())) - evm := vm.NewEVM(blockContext, vm.TxContext{}, statedb, backend.Config.ChainConfig, vm.Config{}) - rules := backend.Config.ChainConfig.Rules(block.Number(), true, block.Time()) + evm := vm.NewEVM(blockContext, vm.TxContext{}, statedb, config, vm.Config{}) + 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 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) } 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. 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 { 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 { - accumulateRewards(backend.Config.ChainConfig, statedb, block.Header(), block.Uncles()) + if config.Ethash != nil { + accumulateRewards(config, statedb, block.Header(), block.Uncles()) } 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 - reward := new(big.Int).Set(blockReward) + reward := new(big.Int).Set(blockReward.ToBig()) r := new(big.Int) for _, uncle := range uncles { r.Add(uncle.Number, big8) r.Sub(r, header.Number) - r.Mul(r, blockReward) + r.Mul(r, blockReward.ToBig()) 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) } - 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: ¶ms.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 { @@ -376,8 +408,6 @@ func setChainConfig(ghash common.Hash) *params.ChainConfig { return params.MainnetChainConfig case ghash == params.SepoliaGenesisHash: return params.SepoliaChainConfig - case ghash == params.RinkebyGenesisHash: - return params.RinkebyChainConfig case ghash == params.GoerliGenesisHash: return params.GoerliChainConfig default: