// Copyright 2026 The go-ethereum Authors // This file is part of the go-ethereum library. // // The go-ethereum library is free software: you can redistribute it and/or modify // it under the terms of the GNU Lesser General Public License as published by // the Free Software Foundation, either version 3 of the License, or // (at your option) any later version. // // The go-ethereum library is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // GNU Lesser General Public License for more details. // // You should have received a copy of the GNU Lesser General Public License // along with the go-ethereum library. If not, see . package core import ( "math/big" "testing" "github.com/ethereum/go-ethereum/common" "github.com/ethereum/go-ethereum/consensus/beacon" "github.com/ethereum/go-ethereum/consensus/ethash" "github.com/ethereum/go-ethereum/params" ) // TestBinaryTransitionRegistryBootstrap exercises the registry deployment on // the first UBT block: pre-fork blocks must leave the registry uninitialised, // the first UBT block must mark started=true and the base root must be // captured for every subsequent UBT block. func TestBinaryTransitionRegistryBootstrap(t *testing.T) { var ( ubtTime uint64 = 30 coinbase = common.HexToAddress("0x71562b71999873DB5b286dF957af199Ec94617F7") gspec = &Genesis{ Config: ¶ms.ChainConfig{ ChainID: big.NewInt(1), HomesteadBlock: big.NewInt(0), EIP150Block: big.NewInt(0), EIP155Block: big.NewInt(0), EIP158Block: big.NewInt(0), ByzantiumBlock: big.NewInt(0), ConstantinopleBlock: big.NewInt(0), PetersburgBlock: big.NewInt(0), IstanbulBlock: big.NewInt(0), MuirGlacierBlock: big.NewInt(0), BerlinBlock: big.NewInt(0), LondonBlock: big.NewInt(0), Ethash: new(params.EthashConfig), ShanghaiTime: u64(0), CancunTime: u64(0), PragueTime: u64(0), UBTTime: &ubtTime, TerminalTotalDifficulty: common.Big0, EnableUBTAtGenesis: false, BlobScheduleConfig: ¶ms.BlobScheduleConfig{ Cancun: params.DefaultCancunBlobConfig, Prague: params.DefaultPragueBlobConfig, UBT: params.DefaultPragueBlobConfig, }, }, Alloc: GenesisAlloc{ coinbase: { Balance: big.NewInt(1000000000000000000), }, params.BeaconRootsAddress: {Nonce: 1, Code: params.BeaconRootsCode, Balance: common.Big0}, params.HistoryStorageAddress: {Nonce: 1, Code: params.HistoryStorageCode, Balance: common.Big0}, params.WithdrawalQueueAddress: {Nonce: 1, Code: params.WithdrawalQueueCode, Balance: common.Big0}, params.ConsolidationQueueAddress: {Nonce: 1, Code: params.ConsolidationQueueCode, Balance: common.Big0}, }, } ) config := gspec.Config engine := beacon.New(ethash.NewFaker()) registryAddr := params.BinaryTransitionRegistryAddress slotStarted := common.Hash{} slotBaseRoot := common.BytesToHash([]byte{5}) GenerateChainWithGenesis(gspec, engine, 6, func(i int, gen *BlockGen) { gen.SetPoS() blockNum := gen.Number() blockTime := gen.Timestamp() isUBT := config.IsUBT(blockNum, blockTime) started := gen.GetState(registryAddr, slotStarted) baseRoot := gen.GetState(registryAddr, slotBaseRoot) t.Logf("block %d: num=%d time=%d isUBT=%v started=%x baseRoot=%x", i, blockNum.Uint64(), blockTime, isUBT, started, baseRoot) if !isUBT { if started != (common.Hash{}) { t.Errorf("block %d: pre-transition block should not have registry initialized", i) } return } if started == (common.Hash{}) { t.Errorf("block %d: UBT block should have registry slot 0 (started) set", i) } if baseRoot == (common.Hash{}) { t.Errorf("block %d: UBT block should have registry slot 5 (base root) set", i) } }) }