remove noReward

add debugStorageRangeAt normal implementaion
This commit is contained in:
Dimitry Kh 2020-04-16 03:01:12 +03:00
parent 73e6d96041
commit 03f0013c9c

View file

@ -19,7 +19,6 @@ package main
import (
"context"
"fmt"
"github.com/ethereum/go-ethereum/miner"
"io/ioutil"
"math/big"
"os"
@ -27,10 +26,13 @@ import (
"strings"
"time"
"github.com/ethereum/go-ethereum/common/math"
"github.com/ethereum/go-ethereum/core/vm"
"github.com/ethereum/go-ethereum/miner"
"github.com/ethereum/go-ethereum/trie"
"github.com/ethereum/go-ethereum/cmd/utils"
"github.com/ethereum/go-ethereum/common"
"github.com/ethereum/go-ethereum/common/hexutil"
"github.com/ethereum/go-ethereum/consensus"
"github.com/ethereum/go-ethereum/consensus/ethash"
"github.com/ethereum/go-ethereum/core"
"github.com/ethereum/go-ethereum/core/rawdb"
@ -41,7 +43,6 @@ import (
"github.com/ethereum/go-ethereum/internal/ethapi"
"github.com/ethereum/go-ethereum/log"
"github.com/ethereum/go-ethereum/node"
"github.com/ethereum/go-ethereum/params"
"github.com/ethereum/go-ethereum/rlp"
"github.com/ethereum/go-ethereum/rpc"
@ -65,20 +66,37 @@ var (
}
)
// Main test api
type RetestethTestAPI interface {
SetChainParams(ctx context.Context, chainParams ChainParams) (bool, error)
MineBlocks(ctx context.Context, number uint64) (bool, error)
ModifyTimestamp(ctx context.Context, interval uint64) (bool, error)
ModifyTimestamp(ctx context.Context, interval uint64) (bool, error) //Subject to remove
ImportRawBlock(ctx context.Context, rawBlock hexutil.Bytes) (common.Hash, error)
RewindToBlock(ctx context.Context, number uint64) (bool, error)
GetLogHash(ctx context.Context, txHash common.Hash) (common.Hash, error)
}
type RetestethDebugAPI interface {
StorageRangeAt(ctx context.Context,
blockHashOrNumber *math.HexOrDecimal256, txIndex uint64,
address common.Address,
begin *math.HexOrDecimal256, maxResults uint64,
) (StorageRangeResult, error)
}
type StorageRangeResult struct {
Complete bool `json:"complete"`
Storage map[common.Hash]SRItem `json:"storage"`
}
type SRItem struct {
Key string `json:"key"`
Value string `json:"value"`
}
type RetestethAPI struct {
testclient *tester
rpchandler *rpc.Server
engine *NoRewardEngine // Mining without block reward for state tests support
blockInterval uint64
}
@ -95,89 +113,8 @@ type ChainParams struct {
Genesis core.Genesis `json:"genesis"`
}
type NoRewardEngine struct {
inner consensus.Engine
rewardsOn bool
}
func (e *NoRewardEngine) Author(header *types.Header) (common.Address, error) {
return e.inner.Author(header)
}
func (e *NoRewardEngine) VerifyHeader(chain consensus.ChainReader, header *types.Header, seal bool) error {
return e.inner.VerifyHeader(chain, header, seal)
}
func (e *NoRewardEngine) VerifyHeaders(chain consensus.ChainReader, headers []*types.Header, seals []bool) (chan<- struct{}, <-chan error) {
return e.inner.VerifyHeaders(chain, headers, seals)
}
func (e *NoRewardEngine) VerifyUncles(chain consensus.ChainReader, block *types.Block) error {
return e.inner.VerifyUncles(chain, block)
}
func (e *NoRewardEngine) VerifySeal(chain consensus.ChainReader, header *types.Header) error {
return e.inner.VerifySeal(chain, header)
}
func (e *NoRewardEngine) Prepare(chain consensus.ChainReader, header *types.Header) error {
return e.inner.Prepare(chain, header)
}
func (e *NoRewardEngine) accumulateRewards(config *params.ChainConfig, state *state.StateDB, header *types.Header, uncles []*types.Header) {
// Simply touch miner and uncle coinbase accounts
reward := big.NewInt(0)
for _, uncle := range uncles {
state.AddBalance(uncle.Coinbase, reward)
}
state.AddBalance(header.Coinbase, reward)
}
func (e *NoRewardEngine) Finalize(chain consensus.ChainReader, header *types.Header, statedb *state.StateDB, txs []*types.Transaction,
uncles []*types.Header) {
if e.rewardsOn {
e.inner.Finalize(chain, header, statedb, txs, uncles)
} else {
e.accumulateRewards(chain.Config(), statedb, header, uncles)
header.Root = statedb.IntermediateRoot(chain.Config().IsEIP158(header.Number))
}
}
func (e *NoRewardEngine) FinalizeAndAssemble(chain consensus.ChainReader, header *types.Header, statedb *state.StateDB, txs []*types.Transaction,
uncles []*types.Header, receipts []*types.Receipt) (*types.Block, error) {
if e.rewardsOn {
return e.inner.FinalizeAndAssemble(chain, header, statedb, txs, uncles, receipts)
} else {
e.accumulateRewards(chain.Config(), statedb, header, uncles)
header.Root = statedb.IntermediateRoot(chain.Config().IsEIP158(header.Number))
// Header seems complete, assemble into a block and return
return types.NewBlock(header, txs, uncles, receipts), nil
}
}
func (e *NoRewardEngine) Seal(chain consensus.ChainReader, block *types.Block, results chan<- *types.Block, stop <-chan struct{}) error {
return e.inner.Seal(chain, block, results, stop)
}
func (e *NoRewardEngine) SealHash(header *types.Header) common.Hash {
return e.inner.SealHash(header)
}
func (e *NoRewardEngine) CalcDifficulty(chain consensus.ChainReader, time uint64, parent *types.Header) *big.Int {
return e.inner.CalcDifficulty(chain, time, parent)
}
func (e *NoRewardEngine) APIs(chain consensus.ChainReader) []rpc.API {
return e.inner.APIs(chain)
}
func (e *NoRewardEngine) Close() error {
return e.inner.Close()
}
// Restart the client with new genesis. Reset txPool and blockchain info
func (api *RetestethAPI) SetChainParams(ctx context.Context, chainParams ChainParams) (bool, error) {
if api.testclient != nil {
api.testclient.Close()
}
@ -191,74 +128,125 @@ func (api *RetestethAPI) SetChainParams(ctx context.Context, chainParams ChainPa
api.rpchandler.RegisterName("eth", ethapi.NewPublicTransactionPoolAPI(api.testclient.ethereum.APIBackend, nonceLock))
api.rpchandler.RegisterName("debug", eth.NewPrivateDebugAPI(api.testclient.ethereum))
api.rpchandler.RegisterName("web3", node.NewPublicWeb3API(api.testclient.stack))
return true, nil
}
// Seal transactions from txPool, imported by eth_sendRawTransaction, into a block
func (api *RetestethAPI) MineBlocks(ctx context.Context, number uint64) (bool, error) {
currentNumber := api.testclient.ethereum.BlockChain().CurrentBlock().Number().Uint64()
startBlock := currentNumber
upToBlock := currentNumber + number
fakeBlockRemoved := false // Geth adds empty block immediately with StartMining. need to remove
// NOT THREAD SAFE!!!
api.testclient.ethereum.StartMining(1)
api.testclient.ethereum.Miner().SetRecommitInterval(time.Second * 10)
fakeBlockRemoved := false
for currentNumber < upToBlock {
currentNumber = api.testclient.ethereum.BlockChain().CurrentBlock().Number().Uint64()
if currentNumber == startBlock + 1 && fakeBlockRemoved == false {
api.testclient.ethereum.BlockChain().SetHead(startBlock)
api.testclient.ethereum.BlockChain().Reset()
currentNumber = startBlock
fakeBlockRemoved = true
}
}
api.testclient.ethereum.StopMining()
//time.Sleep(time.Second * 10)
api.testclient.ethereum.BlockChain().SetHead(upToBlock)
//time.Sleep(time.Second * 10)
//var origin types.Block
//origin = *api.testclient.ethereum.BlockChain().CurrentBlock()
//api.testclient.ethereum.BlockChain().InsertChain([]*types.Block{&origin})
// Override timestamp ??
/*
var block types.Block
var origin *types.Block
var header types.Header
origin = api.testclient.ethereum.BlockChain().CurrentBlock()
header = *origin.Header()
header.Time = 1000
log.Warn(fmt.Sprintf("Hash %x", origin.Header().Hash()))
block = *types.NewBlockWithHeader(&header).WithBody(origin.Transactions(), origin.Uncles())
api.testclient.ethereum.BlockChain().SetHead(0)
if _, err := api.testclient.ethereum.BlockChain().InsertChain([]*types.Block{&block}); err != nil {
return false, err
}
fmt.Printf("Imported block %d, head is %d\n", block.NumberU64(), api.testclient.ethereum.BlockChain().CurrentBlock().Header().Number)
log.Warn(fmt.Sprintf("Hash %x", api.testclient.ethereum.BlockChain().CurrentBlock().Hash()
*/
return true, nil
}
func (api *RetestethAPI) currentNumber() uint64 {
if current := api.testclient.ethereum.BlockChain().CurrentBlock(); current != nil {
return current.NumberU64()
// Original storage range implementation. Geth StorageRangeAt has no consensus
func (api *RetestethAPI) StorageRangeAt2(ctx context.Context,
blockHashOrNumber *math.HexOrDecimal256, txIndex uint64,
address common.Address,
begin *math.HexOrDecimal256, maxResults uint64,
) (StorageRangeResult, error) {
var (
header *types.Header
block *types.Block
)
if (*big.Int)(blockHashOrNumber).Cmp(big.NewInt(math.MaxInt64)) > 0 {
blockHash := common.BigToHash((*big.Int)(blockHashOrNumber))
header = api.testclient.ethereum.BlockChain().GetHeaderByHash(blockHash)
block = api.testclient.ethereum.BlockChain().GetBlockByHash(blockHash)
} else {
blockNumber := (*big.Int)(blockHashOrNumber).Uint64()
header = api.testclient.ethereum.BlockChain().GetHeaderByNumber(blockNumber)
block = api.testclient.ethereum.BlockChain().GetBlockByNumber(blockNumber)
}
return 0
}
func (api *RetestethAPI) importBlock(block *types.Block) error {
if _, err := api.testclient.ethereum.BlockChain().InsertChain([]*types.Block{block}); err != nil {
return err
}
fmt.Printf("Imported block %d, head is %d\n", block.NumberU64(), api.testclient.ethereum.BlockChain().CurrentBlock().Number())
return nil
parentHeader := api.testclient.ethereum.BlockChain().GetHeaderByHash(header.ParentHash)
var root common.Hash
var statedb *state.StateDB
var err error
if parentHeader == nil || int(txIndex) >= len(block.Transactions()) {
root = header.Root
statedb, err = api.testclient.ethereum.BlockChain().StateAt(root)
if err != nil {
return StorageRangeResult{}, err
}
} else {
root = parentHeader.Root
statedb, err = api.testclient.ethereum.BlockChain().StateAt(root)
if err != nil {
return StorageRangeResult{}, err
}
// Recompute transactions up to the target index.
signer := types.MakeSigner(api.testclient.ethereum.BlockChain().Config(), block.Number())
for idx, tx := range block.Transactions() {
// Assemble the transaction call message and return if the requested offset
msg, _ := tx.AsMessage(signer)
context := core.NewEVMContext(msg, block.Header(), api.testclient.ethereum.BlockChain(), nil)
// Not yet the searched for transaction, execute on top of the current state
vmenv := vm.NewEVM(context, statedb, api.testclient.ethereum.BlockChain().Config(), vm.Config{})
if _, _, _, err := core.ApplyMessage(vmenv, msg, new(core.GasPool).AddGas(tx.Gas())); err != nil {
return StorageRangeResult{}, fmt.Errorf("transaction %#x failed: %v", tx.Hash(), err)
}
// Ensure any modifications are committed to the state
// Only delete empty objects if EIP158/161 (a.k.a Spurious Dragon) is in effect
_ = statedb.IntermediateRoot(vmenv.ChainConfig().IsEIP158(block.Number()))
if idx == int(txIndex) {
// This is to make sure root can be opened by OpenTrie
_, err = statedb.Commit(vmenv.ChainConfig().IsEIP158(block.Number()))
if err != nil {
return StorageRangeResult{}, err
}
}
}
}
storageTrie := statedb.StorageTrie(address)
it := trie.NewIterator(storageTrie.NodeIterator(common.BigToHash((*big.Int)(begin)).Bytes()))
result := StorageRangeResult{Storage: make(map[common.Hash]SRItem)}
for i := 0; /*i < int(maxResults) && */ it.Next(); i++ {
if preimage := storageTrie.GetKey(it.Key); preimage != nil {
key := (*math.HexOrDecimal256)(big.NewInt(0).SetBytes(preimage))
v, _, err := rlp.SplitString(it.Value)
if err != nil {
return StorageRangeResult{}, err
}
value := (*math.HexOrDecimal256)(big.NewInt(0).SetBytes(v))
ks, _ := key.MarshalText()
vs, _ := value.MarshalText()
if len(ks)%2 != 0 {
ks = append(append(append([]byte{}, ks[:2]...), byte('0')), ks[2:]...)
}
if len(vs)%2 != 0 {
vs = append(append(append([]byte{}, vs[:2]...), byte('0')), vs[2:]...)
}
result.Storage[common.BytesToHash(it.Key)] = SRItem{
Key: string(ks),
Value: string(vs),
}
}
}
if it.Next() {
result.Complete = false
} else {
result.Complete = true
}
return result, nil
}
// Subject to remove
func (api *RetestethAPI) ModifyTimestamp(ctx context.Context, interval uint64) (bool, error) {
api.blockInterval = interval
return true, nil
@ -276,6 +264,14 @@ func (api *RetestethAPI) ImportRawBlock(ctx context.Context, rawBlock hexutil.By
return block.Hash(), nil
}
func (api *RetestethAPI) importBlock(block *types.Block) error {
if _, err := api.testclient.ethereum.BlockChain().InsertChain([]*types.Block{block}); err != nil {
return err
}
fmt.Printf("Imported block %d, head is %d\n", block.NumberU64(), api.testclient.ethereum.BlockChain().CurrentBlock().Number())
return nil
}
func (api *RetestethAPI) RewindToBlock(ctx context.Context, newHead uint64) (bool, error) {
if err := api.testclient.ethereum.BlockChain().SetHead(newHead); err != nil {
return false, err
@ -384,6 +380,12 @@ func retesteth(ctx *cli.Context) error {
Service: apiImpl,
Version: "1.0",
},
{
Namespace: "debug",
Public: true,
Service: apiImpl,
Version: "1.0",
},
}
vhosts := splitAndTrim(ctx.GlobalString(utils.RPCVirtualHostsFlag.Name))
@ -397,7 +399,7 @@ func retesteth(ctx *cli.Context) error {
}
httpEndpoint := fmt.Sprintf("%s:%d", ctx.GlobalString(utils.RPCListenAddrFlag.Name), ctx.Int(rpcPortFlag.Name))
listener, rpcHandler, err := rpc.StartHTTPEndpoint(httpEndpoint, rpcAPI, []string{"test"}, cors, vhosts, RetestethHTTPTimeouts)
listener, rpcHandler, err := rpc.StartHTTPEndpoint(httpEndpoint, rpcAPI, []string{"test", "debug"}, cors, vhosts, RetestethHTTPTimeouts)
if err != nil {
utils.Fatalf("Could not start RPC api: %v", err)
}