forked from cerc-io/plugeth
		
	core/forkid: correctly compute forkid when timestamp fork is activated in genesis (#27895)
This changes the forkID calculation to ignore time-based forks that occurred before the genesis block. It's supposed to be done this way because the spec says: > If a chain is configured to start with a non-Frontier ruleset already in its genesis, that is NOT considered a fork.
This commit is contained in:
		
							parent
							
								
									a3e35414b7
								
							
						
					
					
						commit
						32fde3f838
					
				| @ -77,7 +77,7 @@ func (c *Chain) RootAt(height int) common.Hash { | ||||
| 
 | ||||
| // ForkID gets the fork id of the chain.
 | ||||
| func (c *Chain) ForkID() forkid.ID { | ||||
| 	return forkid.NewID(c.chainConfig, c.blocks[0].Hash(), uint64(c.Len()), c.blocks[0].Time()) | ||||
| 	return forkid.NewID(c.chainConfig, c.blocks[0], uint64(c.Len()), c.blocks[0].Time()) | ||||
| } | ||||
| 
 | ||||
| // Shorten returns a copy chain of a desired height from the imported
 | ||||
|  | ||||
| @ -73,9 +73,9 @@ type ID struct { | ||||
| type Filter func(id ID) error | ||||
| 
 | ||||
| // NewID calculates the Ethereum fork ID from the chain config, genesis hash, head and time.
 | ||||
| func NewID(config *params.ChainConfig, genesis common.Hash, head, time uint64) ID { | ||||
| func NewID(config *params.ChainConfig, genesis *types.Block, head, time uint64) ID { | ||||
| 	// Calculate the starting checksum from the genesis hash
 | ||||
| 	hash := crc32.ChecksumIEEE(genesis[:]) | ||||
| 	hash := crc32.ChecksumIEEE(genesis.Hash().Bytes()) | ||||
| 
 | ||||
| 	// Calculate the current fork checksum and the next fork block
 | ||||
| 	forksByBlock, forksByTime := gatherForks(config) | ||||
| @ -88,6 +88,10 @@ func NewID(config *params.ChainConfig, genesis common.Hash, head, time uint64) I | ||||
| 		return ID{Hash: checksumToBytes(hash), Next: fork} | ||||
| 	} | ||||
| 	for _, fork := range forksByTime { | ||||
| 		if fork <= genesis.Time() { | ||||
| 			// Fork active in genesis, skip in forkid calculation
 | ||||
| 			continue | ||||
| 		} | ||||
| 		if fork <= time { | ||||
| 			// Fork already passed, checksum the previous hash and fork timestamp
 | ||||
| 			hash = checksumUpdate(hash, fork) | ||||
| @ -104,7 +108,7 @@ func NewIDWithChain(chain Blockchain) ID { | ||||
| 
 | ||||
| 	return NewID( | ||||
| 		chain.Config(), | ||||
| 		chain.Genesis().Hash(), | ||||
| 		chain.Genesis(), | ||||
| 		head.Number.Uint64(), | ||||
| 		head.Time, | ||||
| 	) | ||||
|  | ||||
| @ -18,10 +18,14 @@ package forkid | ||||
| 
 | ||||
| import ( | ||||
| 	"bytes" | ||||
| 	"hash/crc32" | ||||
| 	"math" | ||||
| 	"math/big" | ||||
| 	"testing" | ||||
| 
 | ||||
| 	"github.com/ethereum/go-ethereum/common" | ||||
| 	"github.com/ethereum/go-ethereum/core" | ||||
| 	"github.com/ethereum/go-ethereum/core/types" | ||||
| 	"github.com/ethereum/go-ethereum/params" | ||||
| 	"github.com/ethereum/go-ethereum/rlp" | ||||
| ) | ||||
| @ -36,13 +40,13 @@ func TestCreation(t *testing.T) { | ||||
| 	} | ||||
| 	tests := []struct { | ||||
| 		config  *params.ChainConfig | ||||
| 		genesis common.Hash | ||||
| 		genesis *types.Block | ||||
| 		cases   []testcase | ||||
| 	}{ | ||||
| 		// Mainnet test cases
 | ||||
| 		{ | ||||
| 			params.MainnetChainConfig, | ||||
| 			params.MainnetGenesisHash, | ||||
| 			core.DefaultGenesisBlock().ToBlock(), | ||||
| 			[]testcase{ | ||||
| 				{0, 0, ID{Hash: checksumToBytes(0xfc64ec04), Next: 1150000}},                    // Unsynced
 | ||||
| 				{1149999, 0, ID{Hash: checksumToBytes(0xfc64ec04), Next: 1150000}},              // Last Frontier block
 | ||||
| @ -77,7 +81,7 @@ func TestCreation(t *testing.T) { | ||||
| 		// Goerli test cases
 | ||||
| 		{ | ||||
| 			params.GoerliChainConfig, | ||||
| 			params.GoerliGenesisHash, | ||||
| 			core.DefaultGoerliGenesisBlock().ToBlock(), | ||||
| 			[]testcase{ | ||||
| 				{0, 0, ID{Hash: checksumToBytes(0xa3f5ab08), Next: 1561651}},                   // Unsynced, last Frontier, Homestead, Tangerine, Spurious, Byzantium, Constantinople and first Petersburg block
 | ||||
| 				{1561650, 0, ID{Hash: checksumToBytes(0xa3f5ab08), Next: 1561651}},             // Last Petersburg block
 | ||||
| @ -94,7 +98,7 @@ func TestCreation(t *testing.T) { | ||||
| 		// Sepolia test cases
 | ||||
| 		{ | ||||
| 			params.SepoliaChainConfig, | ||||
| 			params.SepoliaGenesisHash, | ||||
| 			core.DefaultSepoliaGenesisBlock().ToBlock(), | ||||
| 			[]testcase{ | ||||
| 				{0, 0, ID{Hash: checksumToBytes(0xfe3366e7), Next: 1735371}},                   // Unsynced, last Frontier, Homestead, Tangerine, Spurious, Byzantium, Constantinople, Petersburg, Istanbul, Berlin and first London block
 | ||||
| 				{1735370, 0, ID{Hash: checksumToBytes(0xfe3366e7), Next: 1735371}},             // Last London block
 | ||||
| @ -382,3 +386,55 @@ func TestEncoding(t *testing.T) { | ||||
| 		} | ||||
| 	} | ||||
| } | ||||
| 
 | ||||
| // Tests that time-based forks which are active at genesis are not included in
 | ||||
| // forkid hash.
 | ||||
| func TestTimeBasedForkInGenesis(t *testing.T) { | ||||
| 	var ( | ||||
| 		time       = uint64(1690475657) | ||||
| 		genesis    = types.NewBlockWithHeader(&types.Header{Time: time}) | ||||
| 		forkidHash = checksumToBytes(crc32.ChecksumIEEE(genesis.Hash().Bytes())) | ||||
| 		config     = func(shanghai, cancun uint64) *params.ChainConfig { | ||||
| 			return ¶ms.ChainConfig{ | ||||
| 				ChainID:                       big.NewInt(1337), | ||||
| 				HomesteadBlock:                big.NewInt(0), | ||||
| 				DAOForkBlock:                  nil, | ||||
| 				DAOForkSupport:                true, | ||||
| 				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), | ||||
| 				TerminalTotalDifficulty:       big.NewInt(0), | ||||
| 				TerminalTotalDifficultyPassed: true, | ||||
| 				MergeNetsplitBlock:            big.NewInt(0), | ||||
| 				ShanghaiTime:                  &shanghai, | ||||
| 				CancunTime:                    &cancun, | ||||
| 				Ethash:                        new(params.EthashConfig), | ||||
| 			} | ||||
| 		} | ||||
| 	) | ||||
| 	tests := []struct { | ||||
| 		config *params.ChainConfig | ||||
| 		want   ID | ||||
| 	}{ | ||||
| 		// Shanghai active before genesis, skip
 | ||||
| 		{config(time-1, time+1), ID{Hash: forkidHash, Next: time + 1}}, | ||||
| 
 | ||||
| 		// Shanghai active at genesis, skip
 | ||||
| 		{config(time, time+1), ID{Hash: forkidHash, Next: time + 1}}, | ||||
| 
 | ||||
| 		// Shanghai not active, skip
 | ||||
| 		{config(time+1, time+2), ID{Hash: forkidHash, Next: time + 1}}, | ||||
| 	} | ||||
| 	for _, tt := range tests { | ||||
| 		if have := NewID(tt.config, genesis, 0, time); have != tt.want { | ||||
| 			t.Fatalf("incorrect forkid hash: have %x, want %x", have, tt.want) | ||||
| 		} | ||||
| 	} | ||||
| } | ||||
|  | ||||
| @ -355,7 +355,7 @@ func (h *handler) runEthPeer(peer *eth.Peer, handler eth.Handler) error { | ||||
| 		number  = head.Number.Uint64() | ||||
| 		td      = h.chain.GetTd(hash, number) | ||||
| 	) | ||||
| 	forkID := forkid.NewID(h.chain.Config(), genesis.Hash(), number, head.Time) | ||||
| 	forkID := forkid.NewID(h.chain.Config(), genesis, number, head.Time) | ||||
| 	if err := peer.Handshake(h.networkID, td, hash, genesis.Hash(), forkID, h.forkFilter); err != nil { | ||||
| 		peer.Log().Debug("Ethereum handshake failed", "err", err) | ||||
| 		return err | ||||
|  | ||||
| @ -61,6 +61,6 @@ func StartENRUpdater(chain *core.BlockChain, ln *enode.LocalNode) { | ||||
| func currentENREntry(chain *core.BlockChain) *enrEntry { | ||||
| 	head := chain.CurrentHeader() | ||||
| 	return &enrEntry{ | ||||
| 		ForkID: forkid.NewID(chain.Config(), chain.Genesis().Hash(), head.Number.Uint64(), head.Time), | ||||
| 		ForkID: forkid.NewID(chain.Config(), chain.Genesis(), head.Number.Uint64(), head.Time), | ||||
| 	} | ||||
| } | ||||
|  | ||||
| @ -40,7 +40,7 @@ func testHandshake(t *testing.T, protocol uint) { | ||||
| 		genesis = backend.chain.Genesis() | ||||
| 		head    = backend.chain.CurrentBlock() | ||||
| 		td      = backend.chain.GetTd(head.Hash(), head.Number.Uint64()) | ||||
| 		forkID  = forkid.NewID(backend.chain.Config(), backend.chain.Genesis().Hash(), backend.chain.CurrentHeader().Number.Uint64(), backend.chain.CurrentHeader().Time) | ||||
| 		forkID  = forkid.NewID(backend.chain.Config(), backend.chain.Genesis(), backend.chain.CurrentHeader().Number.Uint64(), backend.chain.CurrentHeader().Time) | ||||
| 	) | ||||
| 	tests := []struct { | ||||
| 		code uint64 | ||||
|  | ||||
| @ -69,7 +69,7 @@ func (h *clientHandler) handle(p *serverPeer, noInitAnnounce bool) error { | ||||
| 	p.Log().Debug("Light Ethereum peer connected", "name", p.Name()) | ||||
| 
 | ||||
| 	// Execute the LES handshake
 | ||||
| 	forkid := forkid.NewID(h.backend.blockchain.Config(), h.backend.genesis, h.backend.blockchain.CurrentHeader().Number.Uint64(), h.backend.blockchain.CurrentHeader().Time) | ||||
| 	forkid := forkid.NewID(h.backend.blockchain.Config(), h.backend.BlockChain().Genesis(), h.backend.blockchain.CurrentHeader().Number.Uint64(), h.backend.blockchain.CurrentHeader().Time) | ||||
| 	if err := p.Handshake(h.backend.blockchain.Genesis().Hash(), forkid, h.forkFilter); err != nil { | ||||
| 		p.Log().Debug("Light Ethereum handshake failed", "err", err) | ||||
| 		return err | ||||
|  | ||||
| @ -124,8 +124,8 @@ func TestHandshake(t *testing.T) { | ||||
| 		genesis = common.HexToHash("cafebabe") | ||||
| 
 | ||||
| 		chain1, chain2   = &fakeChain{}, &fakeChain{} | ||||
| 		forkID1          = forkid.NewID(chain1.Config(), chain1.Genesis().Hash(), chain1.CurrentHeader().Number.Uint64(), chain1.CurrentHeader().Time) | ||||
| 		forkID2          = forkid.NewID(chain2.Config(), chain2.Genesis().Hash(), chain2.CurrentHeader().Number.Uint64(), chain2.CurrentHeader().Time) | ||||
| 		forkID1          = forkid.NewID(chain1.Config(), chain1.Genesis(), chain1.CurrentHeader().Number.Uint64(), chain1.CurrentHeader().Time) | ||||
| 		forkID2          = forkid.NewID(chain2.Config(), chain2.Genesis(), chain2.CurrentHeader().Number.Uint64(), chain2.CurrentHeader().Time) | ||||
| 		filter1, filter2 = forkid.NewFilter(chain1), forkid.NewFilter(chain2) | ||||
| 	) | ||||
| 
 | ||||
|  | ||||
| @ -116,7 +116,7 @@ func (h *serverHandler) handle(p *clientPeer) error { | ||||
| 		hash   = head.Hash() | ||||
| 		number = head.Number.Uint64() | ||||
| 		td     = h.blockchain.GetTd(hash, number) | ||||
| 		forkID = forkid.NewID(h.blockchain.Config(), h.blockchain.Genesis().Hash(), number, head.Time) | ||||
| 		forkID = forkid.NewID(h.blockchain.Config(), h.blockchain.Genesis(), number, head.Time) | ||||
| 	) | ||||
| 	if err := p.Handshake(td, hash, number, h.blockchain.Genesis().Hash(), forkID, h.forkFilter, h.server); err != nil { | ||||
| 		p.Log().Debug("Light Ethereum handshake failed", "err", err) | ||||
|  | ||||
| @ -499,7 +499,7 @@ func (server *testServer) newRawPeer(t *testing.T, name string, version int) (*t | ||||
| 		head    = server.handler.blockchain.CurrentHeader() | ||||
| 		td      = server.handler.blockchain.GetTd(head.Hash(), head.Number.Uint64()) | ||||
| 	) | ||||
| 	forkID := forkid.NewID(server.handler.blockchain.Config(), genesis.Hash(), head.Number.Uint64(), head.Time) | ||||
| 	forkID := forkid.NewID(server.handler.blockchain.Config(), genesis, head.Number.Uint64(), head.Time) | ||||
| 	tp.handshakeWithServer(t, td, head.Hash(), head.Number.Uint64(), genesis.Hash(), forkID) | ||||
| 
 | ||||
| 	// Ensure the connection is established or exits when any error occurs
 | ||||
|  | ||||
		Loading…
	
		Reference in New Issue
	
	Block a user