github.com/hhwill/poc-eth@v0.0.0-20240218063348-3bb107c90dbf/cmd/geth/retesteth.go (about)

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