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 ( import (
"context" "context"
"fmt" "fmt"
"github.com/ethereum/go-ethereum/miner"
"io/ioutil" "io/ioutil"
"math/big" "math/big"
"os" "os"
@ -27,10 +26,13 @@ import (
"strings" "strings"
"time" "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/cmd/utils"
"github.com/ethereum/go-ethereum/common" "github.com/ethereum/go-ethereum/common"
"github.com/ethereum/go-ethereum/common/hexutil" "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/consensus/ethash"
"github.com/ethereum/go-ethereum/core" "github.com/ethereum/go-ethereum/core"
"github.com/ethereum/go-ethereum/core/rawdb" "github.com/ethereum/go-ethereum/core/rawdb"
@ -41,7 +43,6 @@ import (
"github.com/ethereum/go-ethereum/internal/ethapi" "github.com/ethereum/go-ethereum/internal/ethapi"
"github.com/ethereum/go-ethereum/log" "github.com/ethereum/go-ethereum/log"
"github.com/ethereum/go-ethereum/node" "github.com/ethereum/go-ethereum/node"
"github.com/ethereum/go-ethereum/params"
"github.com/ethereum/go-ethereum/rlp" "github.com/ethereum/go-ethereum/rlp"
"github.com/ethereum/go-ethereum/rpc" "github.com/ethereum/go-ethereum/rpc"
@ -65,20 +66,37 @@ var (
} }
) )
// Main test api
type RetestethTestAPI interface { type RetestethTestAPI interface {
SetChainParams(ctx context.Context, chainParams ChainParams) (bool, error) SetChainParams(ctx context.Context, chainParams ChainParams) (bool, error)
MineBlocks(ctx context.Context, number uint64) (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) ImportRawBlock(ctx context.Context, rawBlock hexutil.Bytes) (common.Hash, error)
RewindToBlock(ctx context.Context, number uint64) (bool, error) RewindToBlock(ctx context.Context, number uint64) (bool, error)
GetLogHash(ctx context.Context, txHash common.Hash) (common.Hash, 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 { type RetestethAPI struct {
testclient *tester testclient *tester
rpchandler *rpc.Server rpchandler *rpc.Server
engine *NoRewardEngine // Mining without block reward for state tests support
blockInterval uint64 blockInterval uint64
} }
@ -95,89 +113,8 @@ type ChainParams struct {
Genesis core.Genesis `json:"genesis"` Genesis core.Genesis `json:"genesis"`
} }
type NoRewardEngine struct { // Restart the client with new genesis. Reset txPool and blockchain info
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()
}
func (api *RetestethAPI) SetChainParams(ctx context.Context, chainParams ChainParams) (bool, error) { func (api *RetestethAPI) SetChainParams(ctx context.Context, chainParams ChainParams) (bool, error) {
if api.testclient != nil { if api.testclient != nil {
api.testclient.Close() 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("eth", ethapi.NewPublicTransactionPoolAPI(api.testclient.ethereum.APIBackend, nonceLock))
api.rpchandler.RegisterName("debug", eth.NewPrivateDebugAPI(api.testclient.ethereum)) api.rpchandler.RegisterName("debug", eth.NewPrivateDebugAPI(api.testclient.ethereum))
api.rpchandler.RegisterName("web3", node.NewPublicWeb3API(api.testclient.stack)) api.rpchandler.RegisterName("web3", node.NewPublicWeb3API(api.testclient.stack))
return true, nil 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) { func (api *RetestethAPI) MineBlocks(ctx context.Context, number uint64) (bool, error) {
currentNumber := api.testclient.ethereum.BlockChain().CurrentBlock().Number().Uint64() currentNumber := api.testclient.ethereum.BlockChain().CurrentBlock().Number().Uint64()
startBlock := currentNumber startBlock := currentNumber
upToBlock := currentNumber + number 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.StartMining(1)
api.testclient.ethereum.Miner().SetRecommitInterval(time.Second * 10)
fakeBlockRemoved := false
for currentNumber < upToBlock { for currentNumber < upToBlock {
currentNumber = api.testclient.ethereum.BlockChain().CurrentBlock().Number().Uint64() currentNumber = api.testclient.ethereum.BlockChain().CurrentBlock().Number().Uint64()
if currentNumber == startBlock + 1 && fakeBlockRemoved == false { if currentNumber == startBlock + 1 && fakeBlockRemoved == false {
api.testclient.ethereum.BlockChain().SetHead(startBlock) api.testclient.ethereum.BlockChain().Reset()
currentNumber = startBlock currentNumber = startBlock
fakeBlockRemoved = true fakeBlockRemoved = true
} }
} }
api.testclient.ethereum.StopMining() api.testclient.ethereum.StopMining()
//time.Sleep(time.Second * 10)
api.testclient.ethereum.BlockChain().SetHead(upToBlock) 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 return true, nil
} }
func (api *RetestethAPI) currentNumber() uint64 { // Original storage range implementation. Geth StorageRangeAt has no consensus
if current := api.testclient.ethereum.BlockChain().CurrentBlock(); current != nil { func (api *RetestethAPI) StorageRangeAt2(ctx context.Context,
return current.NumberU64() 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 parentHeader := api.testclient.ethereum.BlockChain().GetHeaderByHash(header.ParentHash)
} var root common.Hash
var statedb *state.StateDB
var err error
func (api *RetestethAPI) importBlock(block *types.Block) error { if parentHeader == nil || int(txIndex) >= len(block.Transactions()) {
if _, err := api.testclient.ethereum.BlockChain().InsertChain([]*types.Block{block}); err != nil { root = header.Root
return err statedb, err = api.testclient.ethereum.BlockChain().StateAt(root)
} if err != nil {
fmt.Printf("Imported block %d, head is %d\n", block.NumberU64(), api.testclient.ethereum.BlockChain().CurrentBlock().Number()) return StorageRangeResult{}, err
return nil }
} 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) { func (api *RetestethAPI) ModifyTimestamp(ctx context.Context, interval uint64) (bool, error) {
api.blockInterval = interval api.blockInterval = interval
return true, nil return true, nil
@ -276,6 +264,14 @@ func (api *RetestethAPI) ImportRawBlock(ctx context.Context, rawBlock hexutil.By
return block.Hash(), nil 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) { func (api *RetestethAPI) RewindToBlock(ctx context.Context, newHead uint64) (bool, error) {
if err := api.testclient.ethereum.BlockChain().SetHead(newHead); err != nil { if err := api.testclient.ethereum.BlockChain().SetHead(newHead); err != nil {
return false, err return false, err
@ -384,6 +380,12 @@ func retesteth(ctx *cli.Context) error {
Service: apiImpl, Service: apiImpl,
Version: "1.0", Version: "1.0",
}, },
{
Namespace: "debug",
Public: true,
Service: apiImpl,
Version: "1.0",
},
} }
vhosts := splitAndTrim(ctx.GlobalString(utils.RPCVirtualHostsFlag.Name)) 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)) 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 { if err != nil {
utils.Fatalf("Could not start RPC api: %v", err) utils.Fatalf("Could not start RPC api: %v", err)
} }