@ -23,8 +23,11 @@ import (
"github.com/ethereum/go-ethereum/accounts/abi"
"github.com/ethereum/go-ethereum/common"
"github.com/ethereum/go-ethereum/consensus"
"github.com/ethereum/go-ethereum/core"
"github.com/ethereum/go-ethereum/core/rawdb"
"github.com/ethereum/go-ethereum/core/state"
"github.com/ethereum/go-ethereum/core/types"
"github.com/ethereum/go-ethereum/core/vm"
"github.com/ethereum/go-ethereum/params"
)
@ -203,3 +206,113 @@ func BenchmarkEVM_CREATE2_1200(bench *testing.B) {
// initcode size 1200K, repeatedly calls CREATE2 and then modifies the mem contents
benchmarkEVM_Create ( bench , "5b5862124f80600080f5600152600056" )
}
func fakeHeader ( n uint64 , parentHash common . Hash ) * types . Header {
header := types . Header {
Coinbase : common . HexToAddress ( "0x00000000000000000000000000000000deadbeef" ) ,
Number : big . NewInt ( int64 ( n ) ) ,
ParentHash : parentHash ,
Time : 1000 ,
Nonce : types . BlockNonce { 0x1 } ,
Extra : [ ] byte { } ,
Difficulty : big . NewInt ( 0 ) ,
GasLimit : 100000 ,
}
return & header
}
type dummyChain struct {
counter int
}
// Engine retrieves the chain's consensus engine.
func ( d * dummyChain ) Engine ( ) consensus . Engine {
return nil
}
// GetHeader returns the hash corresponding to their hash.
func ( d * dummyChain ) GetHeader ( h common . Hash , n uint64 ) * types . Header {
d . counter ++
parentHash := common . Hash { }
s := common . LeftPadBytes ( big . NewInt ( int64 ( n - 1 ) ) . Bytes ( ) , 32 )
copy ( parentHash [ : ] , s )
//parentHash := common.Hash{byte(n - 1)}
//fmt.Printf("GetHeader(%x, %d) => header with parent %x\n", h, n, parentHash)
return fakeHeader ( n , parentHash )
}
// TestBlockhash tests the blockhash operation. It's a bit special, since it internally
// requires access to a chain reader.
func TestBlockhash ( t * testing . T ) {
// Current head
n := uint64 ( 1000 )
parentHash := common . Hash { }
s := common . LeftPadBytes ( big . NewInt ( int64 ( n - 1 ) ) . Bytes ( ) , 32 )
copy ( parentHash [ : ] , s )
header := fakeHeader ( n , parentHash )
// This is the contract we're using. It requests the blockhash for current num (should be all zeroes),
// then iteratively fetches all blockhashes back to n-260.
// It returns
// 1. the first (should be zero)
// 2. the second (should be the parent hash)
// 3. the last non-zero hash
// By making the chain reader return hashes which correlate to the number, we can
// verify that it obtained the right hashes where it should
/ *
pragma solidity ^ 0.5 .3 ;
contract Hasher {
function test ( ) public view returns ( bytes32 , bytes32 , bytes32 ) {
uint256 x = block . number ;
bytes32 first ;
bytes32 last ;
bytes32 zero ;
zero = blockhash ( x ) ; // Should be zeroes
first = blockhash ( x - 1 ) ;
for ( uint256 i = 2 ; i < 260 ; i ++ ) {
bytes32 hash = blockhash ( x - i ) ;
if ( uint256 ( hash ) != 0 ) {
last = hash ;
}
}
return ( zero , first , last ) ;
}
}
* /
// The contract above
data := common . Hex2Bytes ( "6080604052348015600f57600080fd5b50600436106045576000357c010000000000000000000000000000000000000000000000000000000090048063f8a8fd6d14604a575b600080fd5b60506074565b60405180848152602001838152602001828152602001935050505060405180910390f35b600080600080439050600080600083409050600184034092506000600290505b61010481101560c35760008186034090506000816001900414151560b6578093505b5080806001019150506094565b508083839650965096505050505090919256fea165627a7a72305820462d71b510c1725ff35946c20b415b0d50b468ea157c8c77dff9466c9cb85f560029" )
// The method call to 'test()'
input := common . Hex2Bytes ( "f8a8fd6d" )
chain := & dummyChain { }
ret , _ , err := Execute ( data , input , & Config {
GetHashFn : core . GetHashFn ( header , chain ) ,
BlockNumber : new ( big . Int ) . Set ( header . Number ) ,
} )
if err != nil {
t . Fatalf ( "expected no error, got %v" , err )
}
if len ( ret ) != 96 {
t . Fatalf ( "expected returndata to be 96 bytes, got %d" , len ( ret ) )
}
zero := new ( big . Int ) . SetBytes ( ret [ 0 : 32 ] )
first := new ( big . Int ) . SetBytes ( ret [ 32 : 64 ] )
last := new ( big . Int ) . SetBytes ( ret [ 64 : 96 ] )
if zero . BitLen ( ) != 0 {
t . Fatalf ( "expected zeroes, got %x" , ret [ 0 : 32 ] )
}
if first . Uint64 ( ) != 999 {
t . Fatalf ( "second block should be 999, got %d (%x)" , first , ret [ 32 : 64 ] )
}
if last . Uint64 ( ) != 744 {
t . Fatalf ( "last block should be 744, got %d (%x)" , last , ret [ 64 : 96 ] )
}
if exp , got := 255 , chain . counter ; exp != got {
t . Errorf ( "suboptimal; too much chain iteration, expected %d, got %d" , exp , got )
}
}