@@ -19,6 +19,7 @@ package core
1919import  (
2020	"crypto/ecdsa" 
2121	"encoding/binary" 
22+ 	"hash" 
2223	"math/big" 
2324	"testing" 
2425
@@ -516,9 +517,142 @@ func TestProcessParentBlockHash(t *testing.T) {
516517	})
517518}
518519
520+ func  TestFeynmanBlockhashOpcode (t  * testing.T ) {
521+ 	var  (
522+ 		feynmanTime  uint64  =  100 
523+ 
524+ 		// pragma solidity =0.8.24; 
525+ 		// 
526+ 		// contract GetBlockHash { 
527+ 		// 	function get(uint256 blockNumber) external view returns (bytes32) { 
528+ 		// 		return blockhash(blockNumber); 
529+ 		// 	} 
530+ 		// } 
531+ 		GetBlockHashAddress  =  common .HexToAddress ("0x1230000000000000000000000000000000000001" )
532+ 		GetBlockHashCode     =  common .FromHex ("0x6080604052348015600e575f80fd5b50600436106026575f3560e01c80639507d39a14602a575b5f80fd5b60396035366004604b565b4090565b60405190815260200160405180910390f35b5f60208284031215605a575f80fd5b503591905056fea26469706673582212200a417c99978abf73843291e0f284ce65b3ac99baa31abe6a43952308f3161ca864736f6c63430008180033" )
533+ 	)
534+ 
535+ 	getBlockHash  :=  func (evm  * vm.EVM , statedb  * state.StateDB , blockNumber  uint64 ) common.Hash  {
536+ 		// construct contract call calldata 
537+ 		blockNumberBuf  :=  make ([]byte , 32 )
538+ 		binary .BigEndian .PutUint64 (blockNumberBuf [24 :], blockNumber )
539+ 		calldata  :=  common .Hex2Bytes ("9507d39a" ) // "get(uint256 blockNumber)" selector 
540+ 		calldata  =  append (calldata , blockNumberBuf ... )
541+ 
542+ 		msg  :=  types .NewMessage (
543+ 			params .SystemAddress , // from 
544+ 			& GetBlockHashAddress , // to 
545+ 			0 ,                    // nonce 
546+ 			common .Big0 ,          // amount 
547+ 			30_000_000 ,           // gasLimit 
548+ 			common .Big0 ,          // gasPrice 
549+ 			common .Big0 ,          // gasFeeCap 
550+ 			common .Big0 ,          // gasTipCap 
551+ 			calldata ,             // data 
552+ 			nil ,                  // accessList 
553+ 			false ,                // isFake 
554+ 			nil ,                  // setCodeAuthorizations 
555+ 		)
556+ 
557+ 		evm .Reset (NewEVMTxContext (msg ), statedb )
558+ 		ret , _ , _  :=  evm .Call (vm .AccountRef (msg .From ()), * msg .To (), msg .Data (), 30_000_000 , common .Big0 , nil )
559+ 		return  common .BytesToHash (ret )
560+ 	}
561+ 
562+ 	var  (
563+ 		chainConfig  =  & params.ChainConfig {
564+ 			ChainID :             big .NewInt (1 ),
565+ 			HomesteadBlock :      big .NewInt (0 ),
566+ 			EIP150Block :         big .NewInt (0 ),
567+ 			EIP155Block :         big .NewInt (0 ),
568+ 			EIP158Block :         big .NewInt (0 ),
569+ 			ByzantiumBlock :      big .NewInt (0 ),
570+ 			ConstantinopleBlock : big .NewInt (0 ),
571+ 			PetersburgBlock :     big .NewInt (0 ),
572+ 			IstanbulBlock :       big .NewInt (0 ),
573+ 			MuirGlacierBlock :    big .NewInt (0 ),
574+ 			BerlinBlock :         big .NewInt (0 ),
575+ 			LondonBlock :         big .NewInt (0 ),
576+ 			ShanghaiBlock :       big .NewInt (0 ),
577+ 			BernoulliBlock :      big .NewInt (0 ),
578+ 			CurieBlock :          big .NewInt (0 ),
579+ 			DarwinTime :          new (uint64 ),
580+ 			DarwinV2Time :        new (uint64 ),
581+ 			EuclidTime :          new (uint64 ),
582+ 			EuclidV2Time :        new (uint64 ),
583+ 			FeynmanTime :         & feynmanTime ,
584+ 			Ethash :              new (params.EthashConfig ),
585+ 		}
586+ 
587+ 		block1Hash  =  common.Hash {0x01 }
588+ 		block2      =  & types.Header {ParentHash : block1Hash , Number : big .NewInt (2 ), Time : 0 , Difficulty : big .NewInt (0 )}
589+ 		block2Hash  =  block2 .Hash ()
590+ 		block3      =  & types.Header {ParentHash : block2Hash , Number : big .NewInt (3 ), Time : feynmanTime , Difficulty : big .NewInt (0 )}
591+ 
592+ 		coinbase  =  common.Address {}
593+ 	)
594+ 	test  :=  func (statedb  * state.StateDB ) {
595+ 		statedb .SetNonce (params .HistoryStorageAddress , 1 )
596+ 		statedb .SetCode (params .HistoryStorageAddress , params .HistoryStorageCode )
597+ 		statedb .SetCode (GetBlockHashAddress , GetBlockHashCode )
598+ 		statedb .IntermediateRoot (true )
599+ 
600+ 		// pre-Feynman 
601+ 		vmContext  :=  NewEVMBlockContext (block2 , nil , chainConfig , & coinbase )
602+ 		evm  :=  vm .NewEVM (vmContext , vm.TxContext {}, statedb , chainConfig , vm.Config {})
603+ 		// note: parent hash (block1Hash) is not stored 
604+ 
605+ 		// query 2 ancestors (block1, block0) of current block (block2) 
606+ 		if  have , want  :=  getBlockHash (evm , statedb , 1 ), getBlockHashPreFeynman (chainConfig .ChainID , 1 ); have  !=  want  {
607+ 			t .Errorf ("want block hash %v, have %v" , want , have )
608+ 		}
609+ 		if  have , want  :=  getBlockHash (evm , statedb , 0 ), getBlockHashPreFeynman (chainConfig .ChainID , 0 ); have  !=  want  {
610+ 			t .Errorf ("want block hash %v, have %v" , want , have )
611+ 		}
612+ 
613+ 		// post-Feynman 
614+ 		vmContext  =  NewEVMBlockContext (block3 , nil , chainConfig , & coinbase )
615+ 		evm  =  vm .NewEVM (vmContext , vm.TxContext {}, statedb , chainConfig , vm.Config {})
616+ 		ProcessParentBlockHash (block3 .ParentHash , evm , statedb ) // store parent hash (block2Hash) 
617+ 
618+ 		// query 2 ancestors (block2, block1) of current block (block3) 
619+ 		if  have , want  :=  getBlockHash (evm , statedb , 2 ), block2Hash ; have  !=  want  {
620+ 			t .Errorf ("want block hash %v, have %v" , want , have )
621+ 		}
622+ 		// querying before the Feynman fork boundary returns the empty hash 
623+ 		if  have , want  :=  getBlockHash (evm , statedb , 1 ), (common.Hash {}); have  !=  want  {
624+ 			t .Errorf ("want block hash %v, have %v" , want , have )
625+ 		}
626+ 	}
627+ 	t .Run ("MPT" , func (t  * testing.T ) {
628+ 		statedb , _  :=  state .New (types .EmptyRootHash , state .NewDatabase (rawdb .NewDatabase (memorydb .New ())), nil )
629+ 		test (statedb )
630+ 	})
631+ }
632+ 
519633func  getParentBlockHash (statedb  * state.StateDB , number  uint64 ) common.Hash  {
520634	ringIndex  :=  number  %  params .HistoryServeWindow 
521635	var  key  common.Hash 
522636	binary .BigEndian .PutUint64 (key [24 :], ringIndex )
523637	return  statedb .GetState (params .HistoryStorageAddress , key )
524638}
639+ 
640+ type  keccakState  interface  {
641+ 	hash.Hash 
642+ 	Read ([]byte ) (int , error )
643+ }
644+ 
645+ func  getBlockHashPreFeynman (chainId  * big.Int , blockNumber  uint64 ) common.Hash  {
646+ 	chainIdBuf  :=  make ([]byte , 8 )
647+ 	binary .BigEndian .PutUint64 (chainIdBuf , chainId .Uint64 ())
648+ 	num64Buf  :=  make ([]byte , 8 )
649+ 	binary .BigEndian .PutUint64 (num64Buf , blockNumber )
650+ 
651+ 	hasher  :=  sha3 .NewLegacyKeccak256 ().(keccakState )
652+ 	hasher .Write (chainIdBuf )
653+ 	hasher .Write (num64Buf )
654+ 
655+ 	var  hasherBuf  common.Hash 
656+ 	hasher .Read (hasherBuf [:])
657+ 	return  hasherBuf 
658+ }
0 commit comments