github.com/bigzoro/my_simplechain@v0.0.0-20240315012955-8ad0a2a29bb9/cmd/sipe/retesteth.go (about)

     1  // Copyright 2019 The go-simplechain Authors
     2  // This file is part of go-simplechain.
     3  //
     4  // go-simplechain is free software: you can redistribute it and/or modify
     5  // it under the terms of the GNU General Public License as published by
     6  // the Free Software Foundation, either version 3 of the License, or
     7  // (at your option) any later version.
     8  //
     9  // go-simplechain is distributed in the hope that it will be useful,
    10  // but WITHOUT ANY WARRANTY; without even the implied warranty of
    11  // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
    12  // GNU General Public License for more details.
    13  //
    14  // You should have received a copy of the GNU General Public License
    15  // along with go-simplechain. If not, see <http://www.gnu.org/licenses/>.
    16  
    17  package main
    18  
    19  import (
    20  	"context"
    21  	"fmt"
    22  	"math/big"
    23  	"os"
    24  	"os/signal"
    25  	"strings"
    26  	"time"
    27  
    28  	"github.com/bigzoro/my_simplechain/cmd/utils"
    29  	"github.com/bigzoro/my_simplechain/common"
    30  	"github.com/bigzoro/my_simplechain/common/hexutil"
    31  	"github.com/bigzoro/my_simplechain/common/math"
    32  	"github.com/bigzoro/my_simplechain/consensus"
    33  	"github.com/bigzoro/my_simplechain/consensus/ethash"
    34  	"github.com/bigzoro/my_simplechain/core"
    35  	"github.com/bigzoro/my_simplechain/core/rawdb"
    36  	"github.com/bigzoro/my_simplechain/core/state"
    37  	"github.com/bigzoro/my_simplechain/core/types"
    38  	"github.com/bigzoro/my_simplechain/core/vm"
    39  	"github.com/bigzoro/my_simplechain/crypto"
    40  	"github.com/bigzoro/my_simplechain/ethdb"
    41  	"github.com/bigzoro/my_simplechain/log"
    42  	"github.com/bigzoro/my_simplechain/node"
    43  	"github.com/bigzoro/my_simplechain/params"
    44  	"github.com/bigzoro/my_simplechain/rlp"
    45  	"github.com/bigzoro/my_simplechain/rpc"
    46  	"github.com/bigzoro/my_simplechain/trie"
    47  
    48  	cli "gopkg.in/urfave/cli.v1"
    49  )
    50  
    51  var (
    52  	rpcPortFlag = cli.IntFlag{
    53  		Name:  "rpcport",
    54  		Usage: "HTTP-RPC server listening port",
    55  		Value: node.DefaultHTTPPort,
    56  	}
    57  	retestethCommand = cli.Command{
    58  		Action:      utils.MigrateFlags(retesteth),
    59  		Name:        "retesteth",
    60  		Usage:       "Launches geth in retesteth mode",
    61  		ArgsUsage:   "",
    62  		Flags:       []cli.Flag{rpcPortFlag},
    63  		Category:    "MISCELLANEOUS COMMANDS",
    64  		Description: `Launches geth in retesteth mode (no database, no network, only retesteth RPC interface)`,
    65  	}
    66  )
    67  
    68  type RetestethTestAPI interface {
    69  	SetChainParams(ctx context.Context, chainParams ChainParams) (bool, error)
    70  	MineBlocks(ctx context.Context, number uint64) (bool, error)
    71  	ModifyTimestamp(ctx context.Context, interval uint64) (bool, error)
    72  	ImportRawBlock(ctx context.Context, rawBlock hexutil.Bytes) (common.Hash, error)
    73  	RewindToBlock(ctx context.Context, number uint64) (bool, error)
    74  	GetLogHash(ctx context.Context, txHash common.Hash) (common.Hash, error)
    75  }
    76  
    77  type RetestethEthAPI interface {
    78  	SendRawTransaction(ctx context.Context, rawTx hexutil.Bytes) (common.Hash, error)
    79  	BlockNumber(ctx context.Context) (uint64, error)
    80  	GetBlockByNumber(ctx context.Context, blockNr math.HexOrDecimal64, fullTx bool) (map[string]interface{}, error)
    81  	GetBalance(ctx context.Context, address common.Address, blockNr math.HexOrDecimal64) (*math.HexOrDecimal256, error)
    82  	GetCode(ctx context.Context, address common.Address, blockNr math.HexOrDecimal64) (hexutil.Bytes, error)
    83  	GetTransactionCount(ctx context.Context, address common.Address, blockNr math.HexOrDecimal64) (uint64, error)
    84  }
    85  
    86  type RetestethDebugAPI interface {
    87  	AccountRange(ctx context.Context,
    88  		blockHashOrNumber *math.HexOrDecimal256, txIndex uint64,
    89  		addressHash *math.HexOrDecimal256, maxResults uint64,
    90  	) (AccountRangeResult, error)
    91  	StorageRangeAt(ctx context.Context,
    92  		blockHashOrNumber *math.HexOrDecimal256, txIndex uint64,
    93  		address common.Address,
    94  		begin *math.HexOrDecimal256, maxResults uint64,
    95  	) (StorageRangeResult, error)
    96  }
    97  
    98  type RetestWeb3API interface {
    99  	ClientVersion(ctx context.Context) (string, error)
   100  }
   101  
   102  type RetestethAPI struct {
   103  	ethDb         ethdb.Database
   104  	db            state.Database
   105  	chainConfig   *params.ChainConfig
   106  	author        common.Address
   107  	extraData     []byte
   108  	genesisHash   common.Hash
   109  	engine        *NoRewardEngine
   110  	blockchain    *core.BlockChain
   111  	blockNumber   uint64
   112  	txMap         map[common.Address]map[uint64]*types.Transaction // Sender -> Nonce -> Transaction
   113  	txSenders     map[common.Address]struct{}                      // Set of transaction senders
   114  	blockInterval uint64
   115  }
   116  
   117  type ChainParams struct {
   118  	SealEngine string                            `json:"sealEngine"`
   119  	Params     CParamsParams                     `json:"params"`
   120  	Genesis    CParamsGenesis                    `json:"genesis"`
   121  	Accounts   map[common.Address]CParamsAccount `json:"accounts"`
   122  }
   123  
   124  type CParamsParams struct {
   125  	AccountStartNonce      math.HexOrDecimal64   `json:"accountStartNonce"`
   126  	SingularityBlock       *math.HexOrDecimal64  `json:"singularityForkBlock"`
   127  	ChainID                *math.HexOrDecimal256 `json:"chainID"`
   128  	MaximumExtraDataSize   math.HexOrDecimal64   `json:"maximumExtraDataSize"`
   129  	TieBreakingGas         bool                  `json:"tieBreakingGas"`
   130  	MinGasLimit            math.HexOrDecimal64   `json:"minGasLimit"`
   131  	MaxGasLimit            math.HexOrDecimal64   `json:"maxGasLimit"`
   132  	GasLimitBoundDivisor   math.HexOrDecimal64   `json:"gasLimitBoundDivisor"`
   133  	MinimumDifficulty      math.HexOrDecimal256  `json:"minimumDifficulty"`
   134  	DifficultyBoundDivisor math.HexOrDecimal256  `json:"difficultyBoundDivisor"`
   135  	DurationLimit          math.HexOrDecimal256  `json:"durationLimit"`
   136  	BlockReward            math.HexOrDecimal256  `json:"blockReward"`
   137  	NetworkID              math.HexOrDecimal256  `json:"networkID"`
   138  }
   139  
   140  type CParamsGenesis struct {
   141  	Nonce      math.HexOrDecimal64   `json:"nonce"`
   142  	Difficulty *math.HexOrDecimal256 `json:"difficulty"`
   143  	MixHash    *math.HexOrDecimal256 `json:"mixHash"`
   144  	Author     common.Address        `json:"author"`
   145  	Timestamp  math.HexOrDecimal64   `json:"timestamp"`
   146  	ParentHash common.Hash           `json:"parentHash"`
   147  	ExtraData  hexutil.Bytes         `json:"extraData"`
   148  	GasLimit   math.HexOrDecimal64   `json:"gasLimit"`
   149  }
   150  
   151  type CParamsAccount struct {
   152  	Balance     *math.HexOrDecimal256 `json:"balance"`
   153  	Precompiled *CPAccountPrecompiled `json:"precompiled"`
   154  	Code        hexutil.Bytes         `json:"code"`
   155  	Storage     map[string]string     `json:"storage"`
   156  	Nonce       *math.HexOrDecimal64  `json:"nonce"`
   157  }
   158  
   159  type CPAccountPrecompiled struct {
   160  	Name          string                `json:"name"`
   161  	StartingBlock math.HexOrDecimal64   `json:"startingBlock"`
   162  	Linear        *CPAPrecompiledLinear `json:"linear"`
   163  }
   164  
   165  type CPAPrecompiledLinear struct {
   166  	Base uint64 `json:"base"`
   167  	Word uint64 `json:"word"`
   168  }
   169  
   170  type AccountRangeResult struct {
   171  	AddressMap map[common.Hash]common.Address `json:"addressMap"`
   172  	NextKey    common.Hash                    `json:"nextKey"`
   173  }
   174  
   175  type StorageRangeResult struct {
   176  	Complete bool                   `json:"complete"`
   177  	Storage  map[common.Hash]SRItem `json:"storage"`
   178  }
   179  
   180  type SRItem struct {
   181  	Key   string `json:"key"`
   182  	Value string `json:"value"`
   183  }
   184  
   185  type NoRewardEngine struct {
   186  	inner     consensus.Engine
   187  	rewardsOn bool
   188  }
   189  
   190  func (e *NoRewardEngine) Author(header *types.Header) (common.Address, error) {
   191  	return e.inner.Author(header)
   192  }
   193  
   194  func (e *NoRewardEngine) VerifyHeader(chain consensus.ChainReader, header *types.Header, seal bool) error {
   195  	return e.inner.VerifyHeader(chain, header, seal)
   196  }
   197  
   198  func (e *NoRewardEngine) VerifyHeaders(chain consensus.ChainReader, headers []*types.Header, seals []bool) (chan<- struct{}, <-chan error) {
   199  	return e.inner.VerifyHeaders(chain, headers, seals)
   200  }
   201  
   202  func (e *NoRewardEngine) VerifyUncles(chain consensus.ChainReader, block *types.Block) error {
   203  	return e.inner.VerifyUncles(chain, block)
   204  }
   205  
   206  func (e *NoRewardEngine) VerifySeal(chain consensus.ChainReader, header *types.Header) error {
   207  	return e.inner.VerifySeal(chain, header)
   208  }
   209  
   210  func (e *NoRewardEngine) Prepare(chain consensus.ChainReader, header *types.Header) error {
   211  	return e.inner.Prepare(chain, header)
   212  }
   213  
   214  func (e *NoRewardEngine) accumulateRewards(config *params.ChainConfig, state *state.StateDB, header *types.Header, uncles []*types.Header) {
   215  	// Simply touch miner and uncle coinbase accounts
   216  	reward := big.NewInt(0)
   217  	for _, uncle := range uncles {
   218  		state.AddBalance(uncle.Coinbase, reward)
   219  	}
   220  	state.AddBalance(header.Coinbase, reward)
   221  }
   222  
   223  func (e *NoRewardEngine) Finalize(chain consensus.ChainReader, header *types.Header, statedb *state.StateDB, txs []*types.Transaction,
   224  	uncles []*types.Header, _ []*types.Receipt) error {
   225  	if e.rewardsOn {
   226  		e.inner.Finalize(chain, header, statedb, txs, uncles, nil)
   227  	} else {
   228  		e.accumulateRewards(chain.Config(), statedb, header, uncles)
   229  		header.Root = statedb.IntermediateRoot(true)
   230  	}
   231  	return nil
   232  }
   233  
   234  func (e *NoRewardEngine) FinalizeAndAssemble(chain consensus.ChainReader, header *types.Header, statedb *state.StateDB, txs []*types.Transaction,
   235  	uncles []*types.Header, receipts []*types.Receipt) (*types.Block, error) {
   236  	if e.rewardsOn {
   237  		return e.inner.FinalizeAndAssemble(chain, header, statedb, txs, uncles, receipts)
   238  	} else {
   239  		e.accumulateRewards(chain.Config(), statedb, header, uncles)
   240  		header.Root = statedb.IntermediateRoot(true)
   241  
   242  		// Header seems complete, assemble into a block and return
   243  		return types.NewBlock(header, txs, uncles, receipts), nil
   244  	}
   245  }
   246  
   247  func (e *NoRewardEngine) Seal(chain consensus.ChainReader, block *types.Block, results chan<- *types.Block, stop <-chan struct{}) error {
   248  	return e.inner.Seal(chain, block, results, stop)
   249  }
   250  
   251  func (e *NoRewardEngine) SealHash(header *types.Header) common.Hash {
   252  	return e.inner.SealHash(header)
   253  }
   254  
   255  func (e *NoRewardEngine) CalcDifficulty(chain consensus.ChainReader, time uint64, parent *types.Header) *big.Int {
   256  	return e.inner.CalcDifficulty(chain, time, parent)
   257  }
   258  
   259  func (e *NoRewardEngine) APIs(chain consensus.ChainReader) []rpc.API {
   260  	return e.inner.APIs(chain)
   261  }
   262  
   263  func (e *NoRewardEngine) Close() error {
   264  	return e.inner.Close()
   265  }
   266  
   267  func (api *RetestethAPI) SetChainParams(ctx context.Context, chainParams ChainParams) (bool, error) {
   268  	// Clean up
   269  	if api.blockchain != nil {
   270  		api.blockchain.Stop()
   271  	}
   272  	if api.engine != nil {
   273  		api.engine.Close()
   274  	}
   275  	if api.ethDb != nil {
   276  		api.ethDb.Close()
   277  	}
   278  	ethDb := rawdb.NewMemoryDatabase()
   279  	accounts := make(core.GenesisAlloc)
   280  	for address, account := range chainParams.Accounts {
   281  		balance := big.NewInt(0)
   282  		if account.Balance != nil {
   283  			balance.Set((*big.Int)(account.Balance))
   284  		}
   285  		var nonce uint64
   286  		if account.Nonce != nil {
   287  			nonce = uint64(*account.Nonce)
   288  		}
   289  		if account.Precompiled == nil || account.Balance != nil {
   290  			storage := make(map[common.Hash]common.Hash)
   291  			for k, v := range account.Storage {
   292  				storage[common.HexToHash(k)] = common.HexToHash(v)
   293  			}
   294  			accounts[address] = core.GenesisAccount{
   295  				Balance: balance,
   296  				Code:    account.Code,
   297  				Nonce:   nonce,
   298  				Storage: storage,
   299  			}
   300  		}
   301  	}
   302  	chainId := big.NewInt(1)
   303  	if chainParams.Params.ChainID != nil {
   304  		chainId.Set((*big.Int)(chainParams.Params.ChainID))
   305  	}
   306  	var singularityBlock *big.Int
   307  
   308  	if chainParams.Params.SingularityBlock != nil {
   309  		singularityBlock = big.NewInt(int64(*chainParams.Params.SingularityBlock))
   310  	}
   311  
   312  	genesis := &core.Genesis{
   313  		Config: &params.ChainConfig{
   314  			ChainID:          chainId,
   315  			SingularityBlock: singularityBlock,
   316  			Scrypt:           new(params.ScryptConfig),
   317  		},
   318  		Nonce:      uint64(chainParams.Genesis.Nonce),
   319  		Timestamp:  uint64(chainParams.Genesis.Timestamp),
   320  		ExtraData:  chainParams.Genesis.ExtraData,
   321  		GasLimit:   uint64(chainParams.Genesis.GasLimit),
   322  		Difficulty: big.NewInt(0).Set((*big.Int)(chainParams.Genesis.Difficulty)),
   323  		Mixhash:    common.BigToHash((*big.Int)(chainParams.Genesis.MixHash)),
   324  		Coinbase:   chainParams.Genesis.Author,
   325  		ParentHash: chainParams.Genesis.ParentHash,
   326  		Alloc:      accounts,
   327  	}
   328  	chainConfig, genesisHash, err := core.SetupGenesisBlock(ethDb, genesis)
   329  	if err != nil {
   330  		return false, err
   331  	}
   332  	fmt.Printf("Chain config: %v\n", chainConfig)
   333  
   334  	var inner consensus.Engine
   335  	switch chainParams.SealEngine {
   336  	case "NoProof", "NoReward":
   337  		inner = ethash.NewFaker()
   338  	case "Ethash":
   339  		inner = ethash.New(ethash.Config{
   340  			CacheDir:       "ethash",
   341  			CachesInMem:    2,
   342  			CachesOnDisk:   3,
   343  			DatasetsInMem:  1,
   344  			DatasetsOnDisk: 2,
   345  		}, nil, false)
   346  	default:
   347  		return false, fmt.Errorf("unrecognised seal engine: %s", chainParams.SealEngine)
   348  	}
   349  	engine := &NoRewardEngine{inner: inner, rewardsOn: chainParams.SealEngine != "NoReward"}
   350  
   351  	blockchain, err := core.NewBlockChain(ethDb, nil, chainConfig, engine, vm.Config{}, nil)
   352  	if err != nil {
   353  		return false, err
   354  	}
   355  
   356  	api.chainConfig = chainConfig
   357  	api.genesisHash = genesisHash
   358  	api.author = chainParams.Genesis.Author
   359  	api.extraData = chainParams.Genesis.ExtraData
   360  	api.ethDb = ethDb
   361  	api.engine = engine
   362  	api.blockchain = blockchain
   363  	api.db = state.NewDatabase(api.ethDb)
   364  	api.blockNumber = 0
   365  	api.txMap = make(map[common.Address]map[uint64]*types.Transaction)
   366  	api.txSenders = make(map[common.Address]struct{})
   367  	api.blockInterval = 0
   368  	return true, nil
   369  }
   370  
   371  func (api *RetestethAPI) SendRawTransaction(ctx context.Context, rawTx hexutil.Bytes) (common.Hash, error) {
   372  	tx := new(types.Transaction)
   373  	if err := rlp.DecodeBytes(rawTx, tx); err != nil {
   374  		// Return nil is not by mistake - some tests include sending transaction where gasLimit overflows uint64
   375  		return common.Hash{}, nil
   376  	}
   377  	signer := types.MakeSigner(api.chainConfig)
   378  	sender, err := types.Sender(signer, tx)
   379  	if err != nil {
   380  		return common.Hash{}, err
   381  	}
   382  	if nonceMap, ok := api.txMap[sender]; ok {
   383  		nonceMap[tx.Nonce()] = tx
   384  	} else {
   385  		nonceMap = make(map[uint64]*types.Transaction)
   386  		nonceMap[tx.Nonce()] = tx
   387  		api.txMap[sender] = nonceMap
   388  	}
   389  	api.txSenders[sender] = struct{}{}
   390  	return tx.Hash(), nil
   391  }
   392  
   393  func (api *RetestethAPI) MineBlocks(ctx context.Context, number uint64) (bool, error) {
   394  	for i := 0; i < int(number); i++ {
   395  		if err := api.mineBlock(); err != nil {
   396  			return false, err
   397  		}
   398  	}
   399  	fmt.Printf("Mined %d blocks\n", number)
   400  	return true, nil
   401  }
   402  
   403  func (api *RetestethAPI) mineBlock() error {
   404  	parentHash := rawdb.ReadCanonicalHash(api.ethDb, api.blockNumber)
   405  	parent := rawdb.ReadBlock(api.ethDb, parentHash, api.blockNumber)
   406  	var timestamp uint64
   407  	if api.blockInterval == 0 {
   408  		timestamp = uint64(time.Now().Unix())
   409  	} else {
   410  		timestamp = parent.Time() + api.blockInterval
   411  	}
   412  	gasLimit := core.CalcGasLimit(parent, 9223372036854775807, 9223372036854775807)
   413  	header := &types.Header{
   414  		ParentHash: parent.Hash(),
   415  		Number:     big.NewInt(int64(api.blockNumber + 1)),
   416  		GasLimit:   gasLimit,
   417  		Extra:      api.extraData,
   418  		Time:       timestamp,
   419  	}
   420  	header.Coinbase = api.author
   421  	if api.engine != nil {
   422  		api.engine.Prepare(api.blockchain, header)
   423  	}
   424  	//// If we are care about TheDAO hard-fork check whether to override the extra-data or not
   425  	//if daoBlock := api.chainConfig.DAOForkBlock; daoBlock != nil {
   426  	//	// Check whether the block is among the fork extra-override range
   427  	//	limit := new(big.Int).Add(daoBlock, params.DAOForkExtraRange)
   428  	//	if header.Number.Cmp(daoBlock) >= 0 && header.Number.Cmp(limit) < 0 {
   429  	//		// Depending whether we support or oppose the fork, override differently
   430  	//		if api.chainConfig.DAOForkSupport {
   431  	//			header.Extra = common.CopyBytes(params.DAOForkBlockExtra)
   432  	//		} else if bytes.Equal(header.Extra, params.DAOForkBlockExtra) {
   433  	//			header.Extra = []byte{} // If miner opposes, don't let it use the reserved extra-data
   434  	//		}
   435  	//	}
   436  	//}
   437  	statedb, err := api.blockchain.StateAt(parent.Root())
   438  	if err != nil {
   439  		return err
   440  	}
   441  
   442  	gasPool := new(core.GasPool).AddGas(header.GasLimit)
   443  	txCount := 0
   444  	var txs []*types.Transaction
   445  	var receipts []*types.Receipt
   446  	var blockFull = gasPool.Gas() < params.TxGas
   447  	for address := range api.txSenders {
   448  		if blockFull {
   449  			break
   450  		}
   451  		m := api.txMap[address]
   452  		for nonce := statedb.GetNonce(address); ; nonce++ {
   453  			if tx, ok := m[nonce]; ok {
   454  				// Try to apply transactions to the state
   455  				statedb.Prepare(tx.Hash(), common.Hash{}, txCount)
   456  				snap := statedb.Snapshot()
   457  
   458  				receipt, err := core.ApplyTransaction(
   459  					api.chainConfig,
   460  					api.blockchain,
   461  					&api.author,
   462  					gasPool,
   463  					statedb,
   464  					header, tx, &header.GasUsed, *api.blockchain.GetVMConfig(),
   465  				)
   466  				if err != nil {
   467  					statedb.RevertToSnapshot(snap)
   468  					break
   469  				}
   470  				txs = append(txs, tx)
   471  				receipts = append(receipts, receipt)
   472  				delete(m, nonce)
   473  				if len(m) == 0 {
   474  					// Last tx for the sender
   475  					delete(api.txMap, address)
   476  					delete(api.txSenders, address)
   477  				}
   478  				txCount++
   479  				if gasPool.Gas() < params.TxGas {
   480  					blockFull = true
   481  					break
   482  				}
   483  			} else {
   484  				break // Gap in the nonces
   485  			}
   486  		}
   487  	}
   488  	block, err := api.engine.FinalizeAndAssemble(api.blockchain, header, statedb, txs, []*types.Header{}, receipts)
   489  	if err != nil {
   490  		return err
   491  	}
   492  	return api.importBlock(block)
   493  }
   494  
   495  func (api *RetestethAPI) importBlock(block *types.Block) error {
   496  	if _, err := api.blockchain.InsertChain([]*types.Block{block}); err != nil {
   497  		return err
   498  	}
   499  	api.blockNumber = block.NumberU64()
   500  	fmt.Printf("Imported block %d\n", block.NumberU64())
   501  	return nil
   502  }
   503  
   504  func (api *RetestethAPI) ModifyTimestamp(ctx context.Context, interval uint64) (bool, error) {
   505  	api.blockInterval = interval
   506  	return true, nil
   507  }
   508  
   509  func (api *RetestethAPI) ImportRawBlock(ctx context.Context, rawBlock hexutil.Bytes) (common.Hash, error) {
   510  	block := new(types.Block)
   511  	if err := rlp.DecodeBytes(rawBlock, block); err != nil {
   512  		return common.Hash{}, err
   513  	}
   514  	fmt.Printf("Importing block %d with parent hash: %x, genesisHash: %x\n", block.NumberU64(), block.ParentHash(), api.genesisHash)
   515  	if err := api.importBlock(block); err != nil {
   516  		return common.Hash{}, err
   517  	}
   518  	return block.Hash(), nil
   519  }
   520  
   521  func (api *RetestethAPI) RewindToBlock(ctx context.Context, newHead uint64) (bool, error) {
   522  	if err := api.blockchain.SetHead(newHead); err != nil {
   523  		return false, err
   524  	}
   525  	api.blockNumber = newHead
   526  	return true, nil
   527  }
   528  
   529  var emptyListHash common.Hash = common.HexToHash("0x1dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d49347")
   530  
   531  func (api *RetestethAPI) GetLogHash(ctx context.Context, txHash common.Hash) (common.Hash, error) {
   532  	receipt, _, _, _ := rawdb.ReadReceipt(api.ethDb, txHash, api.chainConfig)
   533  	if receipt == nil {
   534  		return emptyListHash, nil
   535  	} else {
   536  		if logListRlp, err := rlp.EncodeToBytes(receipt.Logs); err != nil {
   537  			return common.Hash{}, err
   538  		} else {
   539  			return common.BytesToHash(crypto.Keccak256(logListRlp)), nil
   540  		}
   541  	}
   542  }
   543  
   544  func (api *RetestethAPI) BlockNumber(ctx context.Context) (uint64, error) {
   545  	//fmt.Printf("BlockNumber, response: %d\n", api.blockNumber)
   546  	return api.blockNumber, nil
   547  }
   548  
   549  func (api *RetestethAPI) GetBlockByNumber(ctx context.Context, blockNr math.HexOrDecimal64, fullTx bool) (map[string]interface{}, error) {
   550  	block := api.blockchain.GetBlockByNumber(uint64(blockNr))
   551  	if block != nil {
   552  		response, err := RPCMarshalBlock(block, true, fullTx)
   553  		if err != nil {
   554  			return nil, err
   555  		}
   556  		response["author"] = response["miner"]
   557  		response["totalDifficulty"] = (*hexutil.Big)(api.blockchain.GetTd(block.Hash(), uint64(blockNr)))
   558  		return response, err
   559  	}
   560  	return nil, fmt.Errorf("block %d not found", blockNr)
   561  }
   562  
   563  func (api *RetestethAPI) AccountRange(ctx context.Context,
   564  	blockHashOrNumber *math.HexOrDecimal256, txIndex uint64,
   565  	addressHash *math.HexOrDecimal256, maxResults uint64,
   566  ) (AccountRangeResult, error) {
   567  	var (
   568  		header *types.Header
   569  		block  *types.Block
   570  	)
   571  	if (*big.Int)(blockHashOrNumber).Cmp(big.NewInt(math.MaxInt64)) > 0 {
   572  		blockHash := common.BigToHash((*big.Int)(blockHashOrNumber))
   573  		header = api.blockchain.GetHeaderByHash(blockHash)
   574  		block = api.blockchain.GetBlockByHash(blockHash)
   575  		//fmt.Printf("Account range: %x, txIndex %d, start: %x, maxResults: %d\n", blockHash, txIndex, common.BigToHash((*big.Int)(addressHash)), maxResults)
   576  	} else {
   577  		blockNumber := (*big.Int)(blockHashOrNumber).Uint64()
   578  		header = api.blockchain.GetHeaderByNumber(blockNumber)
   579  		block = api.blockchain.GetBlockByNumber(blockNumber)
   580  		//fmt.Printf("Account range: %d, txIndex %d, start: %x, maxResults: %d\n", blockNumber, txIndex, common.BigToHash((*big.Int)(addressHash)), maxResults)
   581  	}
   582  	parentHeader := api.blockchain.GetHeaderByHash(header.ParentHash)
   583  	var root common.Hash
   584  	var statedb *state.StateDB
   585  	var err error
   586  	if parentHeader == nil || int(txIndex) >= len(block.Transactions()) {
   587  		root = header.Root
   588  		statedb, err = api.blockchain.StateAt(root)
   589  		if err != nil {
   590  			return AccountRangeResult{}, err
   591  		}
   592  	} else {
   593  		root = parentHeader.Root
   594  		statedb, err = api.blockchain.StateAt(root)
   595  		if err != nil {
   596  			return AccountRangeResult{}, err
   597  		}
   598  		// Recompute transactions up to the target index.
   599  		signer := types.MakeSigner(api.blockchain.Config())
   600  		for idx, tx := range block.Transactions() {
   601  			// Assemble the transaction call message and return if the requested offset
   602  			msg, _ := tx.AsMessage(signer)
   603  			context := core.NewEVMContext(msg, block.Header(), api.blockchain, nil)
   604  			// Not yet the searched for transaction, execute on top of the current state
   605  			vmenv := vm.NewEVM(context, statedb, api.blockchain.Config(), vm.Config{})
   606  			if _, _, _, err := core.ApplyMessage(vmenv, msg, new(core.GasPool).AddGas(tx.Gas())); err != nil {
   607  				return AccountRangeResult{}, fmt.Errorf("transaction %#x failed: %v", tx.Hash(), err)
   608  			}
   609  			// Ensure any modifications are committed to the state
   610  			// Only delete empty objects if EIP158/161 (a.k.a Spurious Dragon) is in effect
   611  			root = statedb.IntermediateRoot(true)
   612  			if idx == int(txIndex) {
   613  				// This is to make sure root can be opened by OpenTrie
   614  				root, err = statedb.Commit(true)
   615  				if err != nil {
   616  					return AccountRangeResult{}, err
   617  				}
   618  				break
   619  			}
   620  		}
   621  	}
   622  	accountTrie, err := statedb.Database().OpenTrie(root)
   623  	if err != nil {
   624  		return AccountRangeResult{}, err
   625  	}
   626  	it := trie.NewIterator(accountTrie.NodeIterator(common.BigToHash((*big.Int)(addressHash)).Bytes()))
   627  	result := AccountRangeResult{AddressMap: make(map[common.Hash]common.Address)}
   628  	for i := 0; i < int(maxResults) && it.Next(); i++ {
   629  		if preimage := accountTrie.GetKey(it.Key); preimage != nil {
   630  			result.AddressMap[common.BytesToHash(it.Key)] = common.BytesToAddress(preimage)
   631  		}
   632  	}
   633  	//fmt.Printf("Number of entries returned: %d\n", len(result.AddressMap))
   634  	// Add the 'next key' so clients can continue downloading.
   635  	if it.Next() {
   636  		next := common.BytesToHash(it.Key)
   637  		result.NextKey = next
   638  	}
   639  	return result, nil
   640  }
   641  
   642  func (api *RetestethAPI) GetBalance(ctx context.Context, address common.Address, blockNr math.HexOrDecimal64) (*math.HexOrDecimal256, error) {
   643  	//fmt.Printf("GetBalance %x, block %d\n", address, blockNr)
   644  	header := api.blockchain.GetHeaderByNumber(uint64(blockNr))
   645  	statedb, err := api.blockchain.StateAt(header.Root)
   646  	if err != nil {
   647  		return nil, err
   648  	}
   649  	return (*math.HexOrDecimal256)(statedb.GetBalance(address)), nil
   650  }
   651  
   652  func (api *RetestethAPI) GetCode(ctx context.Context, address common.Address, blockNr math.HexOrDecimal64) (hexutil.Bytes, error) {
   653  	header := api.blockchain.GetHeaderByNumber(uint64(blockNr))
   654  	statedb, err := api.blockchain.StateAt(header.Root)
   655  	if err != nil {
   656  		return nil, err
   657  	}
   658  	return statedb.GetCode(address), nil
   659  }
   660  
   661  func (api *RetestethAPI) GetTransactionCount(ctx context.Context, address common.Address, blockNr math.HexOrDecimal64) (uint64, error) {
   662  	header := api.blockchain.GetHeaderByNumber(uint64(blockNr))
   663  	statedb, err := api.blockchain.StateAt(header.Root)
   664  	if err != nil {
   665  		return 0, err
   666  	}
   667  	return statedb.GetNonce(address), nil
   668  }
   669  
   670  func (api *RetestethAPI) StorageRangeAt(ctx context.Context,
   671  	blockHashOrNumber *math.HexOrDecimal256, txIndex uint64,
   672  	address common.Address,
   673  	begin *math.HexOrDecimal256, maxResults uint64,
   674  ) (StorageRangeResult, error) {
   675  	var (
   676  		header *types.Header
   677  		block  *types.Block
   678  	)
   679  	if (*big.Int)(blockHashOrNumber).Cmp(big.NewInt(math.MaxInt64)) > 0 {
   680  		blockHash := common.BigToHash((*big.Int)(blockHashOrNumber))
   681  		header = api.blockchain.GetHeaderByHash(blockHash)
   682  		block = api.blockchain.GetBlockByHash(blockHash)
   683  		//fmt.Printf("Storage range: %x, txIndex %d, addr: %x, start: %x, maxResults: %d\n",
   684  		//	blockHash, txIndex, address, common.BigToHash((*big.Int)(begin)), maxResults)
   685  	} else {
   686  		blockNumber := (*big.Int)(blockHashOrNumber).Uint64()
   687  		header = api.blockchain.GetHeaderByNumber(blockNumber)
   688  		block = api.blockchain.GetBlockByNumber(blockNumber)
   689  		//fmt.Printf("Storage range: %d, txIndex %d, addr: %x, start: %x, maxResults: %d\n",
   690  		//	blockNumber, txIndex, address, common.BigToHash((*big.Int)(begin)), maxResults)
   691  	}
   692  	parentHeader := api.blockchain.GetHeaderByHash(header.ParentHash)
   693  	var root common.Hash
   694  	var statedb *state.StateDB
   695  	var err error
   696  	if parentHeader == nil || int(txIndex) >= len(block.Transactions()) {
   697  		root = header.Root
   698  		statedb, err = api.blockchain.StateAt(root)
   699  		if err != nil {
   700  			return StorageRangeResult{}, err
   701  		}
   702  	} else {
   703  		root = parentHeader.Root
   704  		statedb, err = api.blockchain.StateAt(root)
   705  		if err != nil {
   706  			return StorageRangeResult{}, err
   707  		}
   708  		// Recompute transactions up to the target index.
   709  		signer := types.MakeSigner(api.blockchain.Config())
   710  		for idx, tx := range block.Transactions() {
   711  			// Assemble the transaction call message and return if the requested offset
   712  			msg, _ := tx.AsMessage(signer)
   713  			context := core.NewEVMContext(msg, block.Header(), api.blockchain, nil)
   714  			// Not yet the searched for transaction, execute on top of the current state
   715  			vmenv := vm.NewEVM(context, statedb, api.blockchain.Config(), vm.Config{})
   716  			if _, _, _, err := core.ApplyMessage(vmenv, msg, new(core.GasPool).AddGas(tx.Gas())); err != nil {
   717  				return StorageRangeResult{}, fmt.Errorf("transaction %#x failed: %v", tx.Hash(), err)
   718  			}
   719  			// Ensure any modifications are committed to the state
   720  			// Only delete empty objects if EIP158/161 (a.k.a Spurious Dragon) is in effect
   721  			_ = statedb.IntermediateRoot(true)
   722  			if idx == int(txIndex) {
   723  				// This is to make sure root can be opened by OpenTrie
   724  				_, err = statedb.Commit(true)
   725  				if err != nil {
   726  					return StorageRangeResult{}, err
   727  				}
   728  			}
   729  		}
   730  	}
   731  	storageTrie := statedb.StorageTrie(address)
   732  	it := trie.NewIterator(storageTrie.NodeIterator(common.BigToHash((*big.Int)(begin)).Bytes()))
   733  	result := StorageRangeResult{Storage: make(map[common.Hash]SRItem)}
   734  	for i := 0; /*i < int(maxResults) && */ it.Next(); i++ {
   735  		if preimage := storageTrie.GetKey(it.Key); preimage != nil {
   736  			key := (*math.HexOrDecimal256)(big.NewInt(0).SetBytes(preimage))
   737  			v, _, err := rlp.SplitString(it.Value)
   738  			if err != nil {
   739  				return StorageRangeResult{}, err
   740  			}
   741  			value := (*math.HexOrDecimal256)(big.NewInt(0).SetBytes(v))
   742  			ks, _ := key.MarshalText()
   743  			vs, _ := value.MarshalText()
   744  			if len(ks)%2 != 0 {
   745  				ks = append(append(append([]byte{}, ks[:2]...), byte('0')), ks[2:]...)
   746  			}
   747  			if len(vs)%2 != 0 {
   748  				vs = append(append(append([]byte{}, vs[:2]...), byte('0')), vs[2:]...)
   749  			}
   750  			result.Storage[common.BytesToHash(it.Key)] = SRItem{
   751  				Key:   string(ks),
   752  				Value: string(vs),
   753  			}
   754  		}
   755  	}
   756  	if it.Next() {
   757  		result.Complete = false
   758  	} else {
   759  		result.Complete = true
   760  	}
   761  	return result, nil
   762  }
   763  
   764  func (api *RetestethAPI) ClientVersion(ctx context.Context) (string, error) {
   765  	return "Geth-" + params.VersionWithCommit(gitCommit, gitDate), nil
   766  }
   767  
   768  // splitAndTrim splits input separated by a comma
   769  // and trims excessive white space from the substrings.
   770  func splitAndTrim(input string) []string {
   771  	result := strings.Split(input, ",")
   772  	for i, r := range result {
   773  		result[i] = strings.TrimSpace(r)
   774  	}
   775  	return result
   776  }
   777  
   778  func retesteth(ctx *cli.Context) error {
   779  	log.Info("Welcome to retesteth!")
   780  	// register signer API with server
   781  	var (
   782  		extapiURL string
   783  	)
   784  	apiImpl := &RetestethAPI{}
   785  	var testApi RetestethTestAPI = apiImpl
   786  	var ethApi RetestethEthAPI = apiImpl
   787  	var debugApi RetestethDebugAPI = apiImpl
   788  	var web3Api RetestWeb3API = apiImpl
   789  	rpcAPI := []rpc.API{
   790  		{
   791  			Namespace: "test",
   792  			Public:    true,
   793  			Service:   testApi,
   794  			Version:   "1.0",
   795  		},
   796  		{
   797  			Namespace: "eth",
   798  			Public:    true,
   799  			Service:   ethApi,
   800  			Version:   "1.0",
   801  		},
   802  		{
   803  			Namespace: "debug",
   804  			Public:    true,
   805  			Service:   debugApi,
   806  			Version:   "1.0",
   807  		},
   808  		{
   809  			Namespace: "web3",
   810  			Public:    true,
   811  			Service:   web3Api,
   812  			Version:   "1.0",
   813  		},
   814  	}
   815  	vhosts := splitAndTrim(ctx.GlobalString(utils.RPCVirtualHostsFlag.Name))
   816  	cors := splitAndTrim(ctx.GlobalString(utils.RPCCORSDomainFlag.Name))
   817  
   818  	// start http server
   819  	httpEndpoint := fmt.Sprintf("%s:%d", ctx.GlobalString(utils.RPCListenAddrFlag.Name), ctx.Int(rpcPortFlag.Name))
   820  	listener, _, err := rpc.StartHTTPEndpoint(httpEndpoint, rpcAPI, []string{"test", "eth", "debug", "web3"}, cors, vhosts, rpc.DefaultHTTPTimeouts)
   821  	if err != nil {
   822  		utils.Fatalf("Could not start RPC api: %v", err)
   823  	}
   824  	extapiURL = fmt.Sprintf("http://%s", httpEndpoint)
   825  	log.Info("HTTP endpoint opened", "url", extapiURL)
   826  
   827  	defer func() {
   828  		listener.Close()
   829  		log.Info("HTTP endpoint closed", "url", httpEndpoint)
   830  	}()
   831  
   832  	abortChan := make(chan os.Signal, 11)
   833  	signal.Notify(abortChan, os.Interrupt)
   834  
   835  	sig := <-abortChan
   836  	log.Info("Exiting...", "signal", sig)
   837  	return nil
   838  }