mirror of
https://github.com/ethereum/go-ethereum.git
synced 2026-08-20 10:52:25 +00:00
core/vm/runtime: add test for blockhash
This commit is contained in:
parent
f180981273
commit
c616dcf111
2 changed files with 119 additions and 2 deletions
|
|
@ -23,11 +23,15 @@ import (
|
|||
)
|
||||
|
||||
func NewEnv(cfg *Config) *vm.EVM {
|
||||
getHash := cfg.GetHashFn
|
||||
if getHash == nil {
|
||||
getHash = func(uint64) common.Hash { return common.Hash{} }
|
||||
}
|
||||
|
||||
context := vm.Context{
|
||||
CanTransfer: core.CanTransfer,
|
||||
Transfer: core.Transfer,
|
||||
GetHash: func(uint64) common.Hash { return common.Hash{} },
|
||||
|
||||
GetHash: getHash,
|
||||
Origin: cfg.Origin,
|
||||
Coinbase: cfg.Coinbase,
|
||||
BlockNumber: cfg.BlockNumber,
|
||||
|
|
|
|||
|
|
@ -17,6 +17,9 @@
|
|||
package runtime
|
||||
|
||||
import (
|
||||
"github.com/ethereum/go-ethereum/consensus"
|
||||
"github.com/ethereum/go-ethereum/core"
|
||||
"github.com/ethereum/go-ethereum/core/types"
|
||||
"math/big"
|
||||
"strings"
|
||||
"testing"
|
||||
|
|
@ -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: big.NewInt(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 chain.counter != 255 {
|
||||
t.Logf("Suboptimal; too much chain iteration, expected 255, got %d", chain.counter)
|
||||
}
|
||||
}
|
||||
|
|
|
|||
Loading…
Reference in a new issue