diff --git a/cmd/utils/cmd.go b/cmd/utils/cmd.go index de25fd1a146d..9e8f5ffaa5f4 100644 --- a/cmd/utils/cmd.go +++ b/cmd/utils/cmd.go @@ -170,6 +170,10 @@ func ImportChain(chain *core.BlockChain, fn string) error { } defer fh.Close() + if _, err := fh.Seek(18224628422, 0); err != nil { + panic(err) + } + var reader io.Reader = fh if strings.HasSuffix(fn, ".gz") { if reader, err = gzip.NewReader(reader); err != nil { diff --git a/cmd/utils/flags.go b/cmd/utils/flags.go index 3395eebca866..bc930215bcf6 100644 --- a/cmd/utils/flags.go +++ b/cmd/utils/flags.go @@ -2156,8 +2156,30 @@ func MakeChain(ctx *cli.Context, stack *node.Node, readonly bool) (*core.BlockCh } vmcfg := vm.Config{EnablePreimageRecording: ctx.Bool(VMEnableDebugFlag.Name)} + // Override the chain config with provided settings. + var overrides core.ChainOverrides + if ctx.IsSet(OverrideCancun.Name) { + v := ctx.Uint64(OverrideCancun.Name) + overrides.OverrideCancun = &v + } + if ctx.IsSet(OverridePrague.Name) { + v := ctx.Uint64(OverridePrague.Name) + overrides.OverridePrague = &v + } + if ctx.IsSet(OverrideProofInBlock.Name) { + v := ctx.Bool(OverrideProofInBlock.Name) + overrides.OverrideProofInBlock = &v + } + if ctx.IsSet(OverrideOverlayStride.Name) { + v := ctx.Uint64(OverrideOverlayStride.Name) + overrides.OverrideOverlayStride = &v + } + if ctx.IsSet(ClearVerkleCosts.Name) { + params.ClearVerkleWitnessCosts() + } + // Disable transaction indexing/unindexing by default. - chain, err := core.NewBlockChain(chainDb, cache, gspec, nil, engine, vmcfg, nil, nil) + chain, err := core.NewBlockChain(chainDb, cache, gspec, &overrides, engine, vmcfg, nil, nil) if err != nil { Fatalf("Can't create BlockChain: %v", err) } diff --git a/consensus/beacon/consensus.go b/consensus/beacon/consensus.go index 62d9f48feb2a..d4cd9d432b8a 100644 --- a/consensus/beacon/consensus.go +++ b/consensus/beacon/consensus.go @@ -347,10 +347,6 @@ func (beacon *Beacon) Prepare(chain consensus.ChainHeaderReader, header *types.H // Finalize implements consensus.Engine and processes withdrawals on top. func (beacon *Beacon) Finalize(chain consensus.ChainHeaderReader, header *types.Header, state *state.StateDB, txs []*types.Transaction, uncles []*types.Header, withdrawals []*types.Withdrawal) { - if !beacon.IsPoSHeader(header) { - beacon.ethone.Finalize(chain, header, state, txs, uncles, nil) - return - } // Withdrawals processing. for _, w := range withdrawals { // Convert amount from gwei to wei. @@ -373,6 +369,11 @@ func (beacon *Beacon) Finalize(chain consensus.ChainHeaderReader, header *types. log.Error("error performing the transition", "err", err) } } + + if !beacon.IsPoSHeader(header) { + beacon.ethone.Finalize(chain, header, state, txs, uncles, nil) + return + } } // FinalizeAndAssemble implements consensus.Engine, setting the final state and diff --git a/core/block_validator.go b/core/block_validator.go index d977c1d63d96..d84363e926ea 100644 --- a/core/block_validator.go +++ b/core/block_validator.go @@ -98,13 +98,13 @@ func (v *BlockValidator) ValidateBody(block *types.Block) error { return errors.New("data blobs present in block body") } } - if !v.bc.HasBlockAndState(block.ParentHash(), block.NumberU64()-1) { - if !v.bc.HasBlock(block.ParentHash(), block.NumberU64()-1) { - return consensus.ErrUnknownAncestor - } - fmt.Println("failure here") - return consensus.ErrPrunedAncestor - } + // if !v.bc.HasBlockAndState(block.ParentHash(), block.NumberU64()-1) { + // if !v.bc.HasBlock(block.ParentHash(), block.NumberU64()-1) { + // return consensus.ErrUnknownAncestor + // } + // fmt.Println("failure here") + // return consensus.ErrPrunedAncestor + // } return nil } @@ -121,16 +121,16 @@ func (v *BlockValidator) ValidateState(block *types.Block, statedb *state.StateD if rbloom != header.Bloom { return fmt.Errorf("invalid bloom (remote: %x local: %x)", header.Bloom, rbloom) } - // Tre receipt Trie's root (R = (Tr [[H1, R1], ... [Hn, Rn]])) - receiptSha := types.DeriveSha(receipts, trie.NewStackTrie(nil)) - if receiptSha != header.ReceiptHash { - return fmt.Errorf("invalid receipt root hash (remote: %x local: %x)", header.ReceiptHash, receiptSha) - } - // Validate the state root against the received state root and throw - // an error if they don't match. - if root := statedb.IntermediateRoot(v.config.IsEIP158(header.Number)); header.Root != root { - return fmt.Errorf("invalid merkle root (remote: %x local: %x) dberr: %w", header.Root, root, statedb.Error()) - } + // // Tre receipt Trie's root (R = (Tr [[H1, R1], ... [Hn, Rn]])) + // receiptSha := types.DeriveSha(receipts, trie.NewStackTrie(nil)) + // if receiptSha != header.ReceiptHash { + // return fmt.Errorf("invalid receipt root hash (remote: %x local: %x)", header.ReceiptHash, receiptSha) + // } + // // Validate the state root against the received state root and throw + // // an error if they don't match. + // if root := statedb.IntermediateRoot(v.config.IsEIP158(header.Number)); header.Root != root { + // return fmt.Errorf("invalid merkle root (remote: %x local: %x) dberr: %w", header.Root, root, statedb.Error()) + // } statedb.Database().SaveTransitionState(header.Root) return nil } diff --git a/core/blockchain.go b/core/blockchain.go index 36e58ca8df57..b6202f33eedd 100644 --- a/core/blockchain.go +++ b/core/blockchain.go @@ -18,15 +18,11 @@ package core import ( - "bufio" "errors" "fmt" "io" - "math" "math/big" - "os" "runtime" - "strconv" "strings" "sync" "sync/atomic" @@ -326,11 +322,10 @@ func NewBlockChain(db ethdb.Database, cacheConfig *CacheConfig, genesis *Genesis // for it to be able to recover if interrupted during the transition // but that's left out to a later PR since there's not really a need // right now. - bc.stateCache.InitTransitionStatus(true, true) - bc.stateCache.EndVerkleTransition() + bc.stateCache.InitTransitionStatus(false, false) } - if !bc.HasState(head.Root) { + if !bc.stateCache.Transitioned() && !bc.HasState(head.Root) { // Head state is missing, before the state recovery, find out the // disk layer point of snapshot(if it's enabled). Make sure the // rewound point is lower than disk layer. @@ -1535,30 +1530,6 @@ func (bc *BlockChain) InsertChain(chain types.Blocks) (int, error) { return bc.insertChain(chain, true) } -func findVerkleConversionBlock() (uint64, error) { - if _, err := os.Stat("conversion.txt"); os.IsNotExist(err) { - return math.MaxUint64, nil - } - - f, err := os.Open("conversion.txt") - if err != nil { - log.Error("Failed to open conversion.txt", "err", err) - return 0, err - } - defer f.Close() - - scanner := bufio.NewScanner(f) - scanner.Scan() - conversionBlock, err := strconv.ParseUint(scanner.Text(), 10, 64) - if err != nil { - log.Error("Failed to parse conversionBlock", "err", err) - return 0, err - } - log.Info("Found conversion block info", "conversionBlock", conversionBlock) - - return conversionBlock, nil -} - // insertChain is the internal implementation of InsertChain, which assumes that // 1) chains are contiguous, and 2) The chain mutex is held. // @@ -1573,11 +1544,6 @@ func (bc *BlockChain) insertChain(chain types.Blocks, setHead bool) (int, error) return 0, nil } - conversionBlock, err := findVerkleConversionBlock() - if err != nil { - return 0, err - } - // Start a parallel signature recovery (signer will fluke on fork transition, minimal perf loss) SenderCacher.RecoverFromBlocks(types.MakeSigner(bc.chainConfig, chain[0].Number(), chain[0].Time()), chain) @@ -1701,7 +1667,6 @@ func (bc *BlockChain) insertChain(chain types.Blocks, setHead bool) (int, error) activeState.StopPrefetcher() } }() - for ; block != nil && err == nil || errors.Is(err, ErrKnownBlock); block, err = it.next() { // If the chain is terminating, stop processing blocks if bc.insertStopped() { @@ -1767,13 +1732,15 @@ func (bc *BlockChain) insertChain(chain types.Blocks, setHead bool) (int, error) // is the fork block and that the conversion needs to be marked at started. if !bc.stateCache.InTransition() && !bc.stateCache.Transitioned() { bc.stateCache.StartVerkleTransition(parent.Root, emptyVerkleRoot, bc.Config(), bc.Config().PragueTime, parent.Root) + bc.stateCache.SetLastMerkleRoot(parent.Root) } } - if parent.Number.Uint64() == conversionBlock { - bc.StartVerkleTransition(parent.Root, emptyVerkleRoot, bc.Config(), &parent.Time, parent.Root) - bc.stateCache.SetLastMerkleRoot(parent.Root) + rootz := parent.Root + if block.Header().Number.Uint64() == 4702178 { + // Force first block to fallback to the tree. + rootz = common.HexToHash("0x00") } - statedb, err := state.New(parent.Root, bc.stateCache, bc.snaps) + statedb, err := state.New(rootz, bc.stateCache, bc.snaps) if err != nil { return it.index, err } diff --git a/core/state/database.go b/core/state/database.go index cca65bb6f993..d7ac62f36931 100644 --- a/core/state/database.go +++ b/core/state/database.go @@ -21,7 +21,6 @@ import ( "encoding/gob" "errors" "fmt" - "runtime/debug" "sync" "github.com/ethereum/go-ethereum/common" @@ -350,7 +349,6 @@ func (db *cachingDB) OpenTrie(root common.Hash) (Trie, error) { mpt Trie err error ) - fmt.Printf("opening trie with root %x, %v %v\n", root, db.InTransition(), db.Transitioned()) // TODO separate both cases when I can be certain that it won't // find a Verkle trie where is expects a Transitoion trie. @@ -416,7 +414,6 @@ func (db *cachingDB) OpenStorageTrie(stateRoot common.Hash, address common.Addre } } if db.InTransition() { - fmt.Printf("OpenStorageTrie during transition, state root=%x root=%x\n", stateRoot, root) mpt, err := db.openStorageMPTrie(db.LastMerkleRoot, address, root, nil) if err != nil { return nil, err @@ -590,7 +587,7 @@ func (db *cachingDB) LoadTransitionState(root common.Hash) { return } - // if a state could be read from the db, attempt to decode it + // if a state could be read from the db, attempt to decode it if len(data) > 0 { var ( newts TransitionState @@ -622,7 +619,6 @@ func (db *cachingDB) LoadTransitionState(root common.Hash) { db.CurrentTransitionState = ts.Copy() log.Debug("loaded transition state", "storage processed", db.CurrentTransitionState.StorageProcessed, "addr", db.CurrentTransitionState.CurrentAccountAddress, "slot hash", db.CurrentTransitionState.CurrentSlotHash, "root", root, "ended", db.CurrentTransitionState.ended, "started", db.CurrentTransitionState.started) - debug.PrintStack() } func (db *cachingDB) LockCurrentTransitionState() { diff --git a/core/vm/contracts.go b/core/vm/contracts.go index 036d18a078fe..3b65b813e492 100644 --- a/core/vm/contracts.go +++ b/core/vm/contracts.go @@ -151,7 +151,7 @@ func init() { func ActivePrecompiles(rules params.Rules) []common.Address { switch { case rules.IsPrague: - return PrecompiledAddressesBerlin + return PrecompiledAddressesByzantium case rules.IsCancun: return PrecompiledAddressesCancun case rules.IsBerlin: diff --git a/core/vm/evm.go b/core/vm/evm.go index 782fc6d56740..d15de2ab0bfe 100644 --- a/core/vm/evm.go +++ b/core/vm/evm.go @@ -41,14 +41,14 @@ type ( func (evm *EVM) precompile(addr common.Address) (PrecompiledContract, bool) { var precompiles map[common.Address]PrecompiledContract switch { - case evm.chainRules.IsPrague: - precompiles = PrecompiledContractsBerlin case evm.chainRules.IsCancun: precompiles = PrecompiledContractsCancun case evm.chainRules.IsBerlin: precompiles = PrecompiledContractsBerlin case evm.chainRules.IsIstanbul: precompiles = PrecompiledContractsIstanbul + case evm.chainRules.IsPrague: + precompiles = PrecompiledContractsByzantium case evm.chainRules.IsByzantium: precompiles = PrecompiledContractsByzantium default: diff --git a/core/vm/gas_table.go b/core/vm/gas_table.go index f367c3c92978..50ebf8c05b64 100644 --- a/core/vm/gas_table.go +++ b/core/vm/gas_table.go @@ -101,8 +101,9 @@ var ( func gasExtCodeSize(evm *EVM, contract *Contract, stack *Stack, mem *Memory, memorySize uint64) (uint64, error) { usedGas := uint64(0) slot := stack.Back(0) + address := slot.Bytes20() if evm.chainRules.IsPrague { - usedGas += evm.TxContext.Accesses.TouchAddressOnReadAndComputeGas(slot.Bytes(), uint256.Int{}, trieUtils.CodeSizeLeafKey) + usedGas += evm.TxContext.Accesses.TouchAddressOnReadAndComputeGas(address[:], uint256.Int{}, trieUtils.CodeSizeLeafKey) } return usedGas, nil diff --git a/core/vm/instructions.go b/core/vm/instructions.go index 6c40ff83a272..81c0e80ad58a 100644 --- a/core/vm/instructions.go +++ b/core/vm/instructions.go @@ -265,7 +265,7 @@ func opBalance(pc *uint64, interpreter *EVMInterpreter, scope *ScopeContext) ([] slot := scope.Stack.peek() address := common.Address(slot.Bytes20()) if interpreter.evm.chainRules.IsPrague { - statelessGas := interpreter.evm.Accesses.TouchAddressOnReadAndComputeGas(slot.Bytes(), uint256.Int{}, trieUtils.BalanceLeafKey) + statelessGas := interpreter.evm.Accesses.TouchAddressOnReadAndComputeGas(address[:], uint256.Int{}, trieUtils.BalanceLeafKey) if !scope.Contract.UseGas(statelessGas) { scope.Contract.Gas = 0 return nil, ErrOutOfGas @@ -353,9 +353,10 @@ func opReturnDataCopy(pc *uint64, interpreter *EVMInterpreter, scope *ScopeConte func opExtCodeSize(pc *uint64, interpreter *EVMInterpreter, scope *ScopeContext) ([]byte, error) { slot := scope.Stack.peek() - cs := uint64(interpreter.evm.StateDB.GetCodeSize(slot.Bytes20())) + address := slot.Bytes20() + cs := uint64(interpreter.evm.StateDB.GetCodeSize(address)) if interpreter.evm.chainRules.IsPrague { - statelessGas := interpreter.evm.Accesses.TouchAddressOnReadAndComputeGas(slot.Bytes(), uint256.Int{}, trieUtils.CodeSizeLeafKey) + statelessGas := interpreter.evm.Accesses.TouchAddressOnReadAndComputeGas(address[:], uint256.Int{}, trieUtils.CodeSizeLeafKey) if !scope.Contract.UseGas(statelessGas) { scope.Contract.Gas = 0 return nil, ErrOutOfGas @@ -495,7 +496,7 @@ func opExtCodeHash(pc *uint64, interpreter *EVMInterpreter, scope *ScopeContext) slot := scope.Stack.peek() address := common.Address(slot.Bytes20()) if interpreter.evm.chainRules.IsPrague { - statelessGas := interpreter.evm.Accesses.TouchAddressOnReadAndComputeGas(slot.Bytes(), uint256.Int{}, trieUtils.CodeKeccakLeafKey) + statelessGas := interpreter.evm.Accesses.TouchAddressOnReadAndComputeGas(address[:], uint256.Int{}, trieUtils.CodeKeccakLeafKey) if !scope.Contract.UseGas(statelessGas) { scope.Contract.Gas = 0 return nil, ErrOutOfGas @@ -531,12 +532,6 @@ func opBlockhash(pc *uint64, interpreter *EVMInterpreter, scope *ScopeContext) ( } evm := interpreter.evm - // if Prague is active, read it from the history contract (EIP 2935). - if evm.chainRules.IsPrague { - num.SetBytes(getBlockHashFromContract(num64, evm.StateDB, evm.Accesses).Bytes()) - return nil, nil - } - var upper, lower uint64 upper = interpreter.evm.Context.BlockNumber.Uint64() if upper < 257 { @@ -544,8 +539,14 @@ func opBlockhash(pc *uint64, interpreter *EVMInterpreter, scope *ScopeContext) ( } else { lower = upper - 256 } + if num64 >= lower && num64 < upper { - num.SetBytes(interpreter.evm.Context.GetHash(num64).Bytes()) + // if Prague is active, read it from the history contract (EIP 2935). + if evm.chainRules.IsPrague { + num.SetBytes(getBlockHashFromContract(num64, evm.StateDB, evm.Accesses).Bytes()) + } else { + num.SetBytes(interpreter.evm.Context.GetHash(num64).Bytes()) + } } else { num.Clear() } diff --git a/core/vm/interpreter.go b/core/vm/interpreter.go index 17b30fae1203..2dbb8005dfc5 100644 --- a/core/vm/interpreter.go +++ b/core/vm/interpreter.go @@ -56,9 +56,6 @@ func NewEVMInterpreter(evm *EVM) *EVMInterpreter { // If jump table was not initialised we set the default one. var table *JumpTable switch { - case evm.chainRules.IsPrague: - // TODO replace with prooper instruction set when fork is specified - table = &pragueInstructionSet case evm.chainRules.IsCancun: table = &cancunInstructionSet case evm.chainRules.IsShanghai: @@ -73,6 +70,9 @@ func NewEVMInterpreter(evm *EVM) *EVMInterpreter { table = &istanbulInstructionSet case evm.chainRules.IsConstantinople: table = &constantinopleInstructionSet + case evm.chainRules.IsPrague: + // TODO replace with prooper instruction set when fork is specified + table = &byzantiumInstructionSet case evm.chainRules.IsByzantium: table = &byzantiumInstructionSet case evm.chainRules.IsEIP158: diff --git a/params/config.go b/params/config.go index a2df06893a22..1dc807042a8e 100644 --- a/params/config.go +++ b/params/config.go @@ -505,7 +505,7 @@ func (c *ChainConfig) IsCancun(num *big.Int, time uint64) bool { // IsPrague returns whether num is either equal to the Prague fork time or greater. func (c *ChainConfig) IsPrague(num *big.Int, time uint64) bool { - return c.IsLondon(num) && isTimestampForked(c.PragueTime, time) + return c.IsByzantium(num) && isTimestampForked(c.PragueTime, time) } // CheckCompatible checks whether scheduled fork transitions have been imported @@ -550,6 +550,7 @@ func (c *ChainConfig) CheckConfigForkOrder() error { {name: "eip155Block", block: c.EIP155Block}, {name: "eip158Block", block: c.EIP158Block}, {name: "byzantiumBlock", block: c.ByzantiumBlock}, + {name: "pragueTime", timestamp: c.PragueTime, optional: true}, {name: "constantinopleBlock", block: c.ConstantinopleBlock}, {name: "petersburgBlock", block: c.PetersburgBlock}, {name: "istanbulBlock", block: c.IstanbulBlock}, @@ -561,7 +562,6 @@ func (c *ChainConfig) CheckConfigForkOrder() error { {name: "mergeNetsplitBlock", block: c.MergeNetsplitBlock, optional: true}, {name: "shanghaiTime", timestamp: c.ShanghaiTime}, {name: "cancunTime", timestamp: c.CancunTime, optional: true}, - {name: "pragueTime", timestamp: c.PragueTime, optional: true}, } { if lastFork.name != "" { switch { diff --git a/trie/verkle.go b/trie/verkle.go index 760e30c8cdaa..630e0b0a5b6d 100644 --- a/trie/verkle.go +++ b/trie/verkle.go @@ -213,6 +213,25 @@ func (trie *VerkleTrie) UpdateStorage(address common.Address, key, value []byte) } func (t *VerkleTrie) DeleteAccount(addr common.Address) error { + var ( + err error + values = make([][]byte, verkle.NodeWidth) + stem = t.pointCache.GetTreeKeyVersionCached(addr[:]) + ) + + for i := 0; i < verkle.NodeWidth; i++ { + values[i] = zero[:] + } + switch root := t.root.(type) { + case *verkle.InternalNode: + err = root.InsertValuesAtStem(stem, values, t.FlatdbNodeResolver) + default: + return errInvalidRootType + } + if err != nil { + return fmt.Errorf("DeleteAccount (%x) error: %v", addr, err) + } + return nil }