github.com/zhiqiangxu/go-ethereum@v1.9.16-0.20210824055606-be91cfdebc48/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/zhiqiangxu/go-ethereum/cmd/utils" 30 "github.com/zhiqiangxu/go-ethereum/common" 31 "github.com/zhiqiangxu/go-ethereum/common/hexutil" 32 "github.com/zhiqiangxu/go-ethereum/common/math" 33 "github.com/zhiqiangxu/go-ethereum/consensus" 34 "github.com/zhiqiangxu/go-ethereum/consensus/ethash" 35 "github.com/zhiqiangxu/go-ethereum/consensus/misc" 36 "github.com/zhiqiangxu/go-ethereum/core" 37 "github.com/zhiqiangxu/go-ethereum/core/rawdb" 38 "github.com/zhiqiangxu/go-ethereum/core/state" 39 "github.com/zhiqiangxu/go-ethereum/core/types" 40 "github.com/zhiqiangxu/go-ethereum/core/vm" 41 "github.com/zhiqiangxu/go-ethereum/crypto" 42 "github.com/zhiqiangxu/go-ethereum/ethdb" 43 "github.com/zhiqiangxu/go-ethereum/log" 44 "github.com/zhiqiangxu/go-ethereum/node" 45 "github.com/zhiqiangxu/go-ethereum/params" 46 "github.com/zhiqiangxu/go-ethereum/rlp" 47 "github.com/zhiqiangxu/go-ethereum/rpc" 48 "github.com/zhiqiangxu/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 GetBlockByHash(ctx context.Context, blockHash common.Hash, fullTx bool) (map[string]interface{}, error) 84 GetBalance(ctx context.Context, address common.Address, blockNr math.HexOrDecimal64) (*math.HexOrDecimal256, error) 85 GetCode(ctx context.Context, address common.Address, blockNr math.HexOrDecimal64) (hexutil.Bytes, error) 86 GetTransactionCount(ctx context.Context, address common.Address, blockNr math.HexOrDecimal64) (uint64, error) 87 } 88 89 type RetestethDebugAPI interface { 90 AccountRange(ctx context.Context, 91 blockHashOrNumber *math.HexOrDecimal256, txIndex uint64, 92 addressHash *math.HexOrDecimal256, maxResults uint64, 93 ) (AccountRangeResult, error) 94 StorageRangeAt(ctx context.Context, 95 blockHashOrNumber *math.HexOrDecimal256, txIndex uint64, 96 address common.Address, 97 begin *math.HexOrDecimal256, maxResults uint64, 98 ) (StorageRangeResult, error) 99 } 100 101 type RetestWeb3API interface { 102 ClientVersion(ctx context.Context) (string, error) 103 } 104 105 type RetestethAPI struct { 106 ethDb ethdb.Database 107 db state.Database 108 chainConfig *params.ChainConfig 109 author common.Address 110 extraData []byte 111 genesisHash common.Hash 112 engine *NoRewardEngine 113 blockchain *core.BlockChain 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: ¶ms.ChainConfig{ 356 ChainID: chainId, 357 HomesteadBlock: homesteadBlock, 358 DAOForkBlock: daoForkBlock, 359 DAOForkSupport: true, 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 CachesLockMmap: false, 394 DatasetsInMem: 1, 395 DatasetsOnDisk: 2, 396 DatasetsLockMmap: false, 397 }, nil, false) 398 default: 399 return false, fmt.Errorf("unrecognised seal engine: %s", chainParams.SealEngine) 400 } 401 engine := &NoRewardEngine{inner: inner, rewardsOn: chainParams.SealEngine != "NoReward"} 402 403 blockchain, err := core.NewBlockChain(ethDb, nil, chainConfig, engine, vm.Config{}, nil, nil) 404 if err != nil { 405 return false, err 406 } 407 408 api.chainConfig = chainConfig 409 api.genesisHash = genesisHash 410 api.author = chainParams.Genesis.Author 411 api.extraData = chainParams.Genesis.ExtraData 412 api.ethDb = ethDb 413 api.engine = engine 414 api.blockchain = blockchain 415 api.db = state.NewDatabase(api.ethDb) 416 api.txMap = make(map[common.Address]map[uint64]*types.Transaction) 417 api.txSenders = make(map[common.Address]struct{}) 418 api.blockInterval = 0 419 return true, nil 420 } 421 422 func (api *RetestethAPI) SendRawTransaction(ctx context.Context, rawTx hexutil.Bytes) (common.Hash, error) { 423 tx := new(types.Transaction) 424 if err := rlp.DecodeBytes(rawTx, tx); err != nil { 425 // Return nil is not by mistake - some tests include sending transaction where gasLimit overflows uint64 426 return common.Hash{}, nil 427 } 428 signer := types.MakeSigner(api.chainConfig, big.NewInt(int64(api.currentNumber()))) 429 sender, err := types.Sender(signer, tx) 430 if err != nil { 431 return common.Hash{}, err 432 } 433 if nonceMap, ok := api.txMap[sender]; ok { 434 nonceMap[tx.Nonce()] = tx 435 } else { 436 nonceMap = make(map[uint64]*types.Transaction) 437 nonceMap[tx.Nonce()] = tx 438 api.txMap[sender] = nonceMap 439 } 440 api.txSenders[sender] = struct{}{} 441 return tx.Hash(), nil 442 } 443 444 func (api *RetestethAPI) MineBlocks(ctx context.Context, number uint64) (bool, error) { 445 for i := 0; i < int(number); i++ { 446 if err := api.mineBlock(); err != nil { 447 return false, err 448 } 449 } 450 fmt.Printf("Mined %d blocks\n", number) 451 return true, nil 452 } 453 454 func (api *RetestethAPI) currentNumber() uint64 { 455 if current := api.blockchain.CurrentBlock(); current != nil { 456 return current.NumberU64() 457 } 458 return 0 459 } 460 461 func (api *RetestethAPI) mineBlock() error { 462 number := api.currentNumber() 463 parentHash := rawdb.ReadCanonicalHash(api.ethDb, number) 464 parent := rawdb.ReadBlock(api.ethDb, parentHash, number) 465 var timestamp uint64 466 if api.blockInterval == 0 { 467 timestamp = uint64(time.Now().Unix()) 468 } else { 469 timestamp = parent.Time() + api.blockInterval 470 } 471 gasLimit := core.CalcGasLimit(parent, 9223372036854775807, 9223372036854775807) 472 header := &types.Header{ 473 ParentHash: parent.Hash(), 474 Number: big.NewInt(int64(number + 1)), 475 GasLimit: gasLimit, 476 Extra: api.extraData, 477 Time: timestamp, 478 } 479 header.Coinbase = api.author 480 if api.engine != nil { 481 api.engine.Prepare(api.blockchain, header) 482 } 483 // If we are care about TheDAO hard-fork check whether to override the extra-data or not 484 if daoBlock := api.chainConfig.DAOForkBlock; daoBlock != nil { 485 // Check whether the block is among the fork extra-override range 486 limit := new(big.Int).Add(daoBlock, params.DAOForkExtraRange) 487 if header.Number.Cmp(daoBlock) >= 0 && header.Number.Cmp(limit) < 0 { 488 // Depending whether we support or oppose the fork, override differently 489 if api.chainConfig.DAOForkSupport { 490 header.Extra = common.CopyBytes(params.DAOForkBlockExtra) 491 } else if bytes.Equal(header.Extra, params.DAOForkBlockExtra) { 492 header.Extra = []byte{} // If miner opposes, don't let it use the reserved extra-data 493 } 494 } 495 } 496 statedb, err := api.blockchain.StateAt(parent.Root()) 497 if err != nil { 498 return err 499 } 500 if api.chainConfig.DAOForkSupport && api.chainConfig.DAOForkBlock != nil && api.chainConfig.DAOForkBlock.Cmp(header.Number) == 0 { 501 misc.ApplyDAOHardFork(statedb) 502 } 503 gasPool := new(core.GasPool).AddGas(header.GasLimit) 504 txCount := 0 505 var txs []*types.Transaction 506 var receipts []*types.Receipt 507 var blockFull = gasPool.Gas() < params.TxGas 508 for address := range api.txSenders { 509 if blockFull { 510 break 511 } 512 m := api.txMap[address] 513 for nonce := statedb.GetNonce(address); ; nonce++ { 514 if tx, ok := m[nonce]; ok { 515 // Try to apply transactions to the state 516 statedb.Prepare(tx.Hash(), common.Hash{}, txCount) 517 snap := statedb.Snapshot() 518 519 receipt, err := core.ApplyTransaction( 520 api.chainConfig, 521 api.blockchain, 522 &api.author, 523 gasPool, 524 statedb, 525 header, tx, &header.GasUsed, *api.blockchain.GetVMConfig(), 526 ) 527 if err != nil { 528 statedb.RevertToSnapshot(snap) 529 break 530 } 531 txs = append(txs, tx) 532 receipts = append(receipts, receipt) 533 delete(m, nonce) 534 if len(m) == 0 { 535 // Last tx for the sender 536 delete(api.txMap, address) 537 delete(api.txSenders, address) 538 } 539 txCount++ 540 if gasPool.Gas() < params.TxGas { 541 blockFull = true 542 break 543 } 544 } else { 545 break // Gap in the nonces 546 } 547 } 548 } 549 block, err := api.engine.FinalizeAndAssemble(api.blockchain, header, statedb, txs, []*types.Header{}, receipts) 550 if err != nil { 551 return err 552 } 553 return api.importBlock(block) 554 } 555 556 func (api *RetestethAPI) importBlock(block *types.Block) error { 557 if _, err := api.blockchain.InsertChain([]*types.Block{block}); err != nil { 558 return err 559 } 560 fmt.Printf("Imported block %d, head is %d\n", block.NumberU64(), api.currentNumber()) 561 return nil 562 } 563 564 func (api *RetestethAPI) ModifyTimestamp(ctx context.Context, interval uint64) (bool, error) { 565 api.blockInterval = interval 566 return true, nil 567 } 568 569 func (api *RetestethAPI) ImportRawBlock(ctx context.Context, rawBlock hexutil.Bytes) (common.Hash, error) { 570 block := new(types.Block) 571 if err := rlp.DecodeBytes(rawBlock, block); err != nil { 572 return common.Hash{}, err 573 } 574 fmt.Printf("Importing block %d with parent hash: %x, genesisHash: %x\n", block.NumberU64(), block.ParentHash(), api.genesisHash) 575 if err := api.importBlock(block); err != nil { 576 return common.Hash{}, err 577 } 578 return block.Hash(), nil 579 } 580 581 func (api *RetestethAPI) RewindToBlock(ctx context.Context, newHead uint64) (bool, error) { 582 if err := api.blockchain.SetHead(newHead); err != nil { 583 return false, err 584 } 585 // When we rewind, the transaction pool should be cleaned out. 586 api.txMap = make(map[common.Address]map[uint64]*types.Transaction) 587 api.txSenders = make(map[common.Address]struct{}) 588 return true, nil 589 } 590 591 var emptyListHash common.Hash = common.HexToHash("0x1dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d49347") 592 593 func (api *RetestethAPI) GetLogHash(ctx context.Context, txHash common.Hash) (common.Hash, error) { 594 receipt, _, _, _ := rawdb.ReadReceipt(api.ethDb, txHash, api.chainConfig) 595 if receipt == nil { 596 return emptyListHash, nil 597 } else { 598 if logListRlp, err := rlp.EncodeToBytes(receipt.Logs); err != nil { 599 return common.Hash{}, err 600 } else { 601 return common.BytesToHash(crypto.Keccak256(logListRlp)), nil 602 } 603 } 604 } 605 606 func (api *RetestethAPI) BlockNumber(ctx context.Context) (uint64, error) { 607 return api.currentNumber(), nil 608 } 609 610 func (api *RetestethAPI) GetBlockByNumber(ctx context.Context, blockNr math.HexOrDecimal64, fullTx bool) (map[string]interface{}, error) { 611 block := api.blockchain.GetBlockByNumber(uint64(blockNr)) 612 if block != nil { 613 response, err := RPCMarshalBlock(block, true, fullTx) 614 if err != nil { 615 return nil, err 616 } 617 response["author"] = response["miner"] 618 response["totalDifficulty"] = (*hexutil.Big)(api.blockchain.GetTd(block.Hash(), uint64(blockNr))) 619 return response, err 620 } 621 return nil, fmt.Errorf("block %d not found", blockNr) 622 } 623 624 func (api *RetestethAPI) GetBlockByHash(ctx context.Context, blockHash common.Hash, fullTx bool) (map[string]interface{}, error) { 625 block := api.blockchain.GetBlockByHash(blockHash) 626 if block != nil { 627 response, err := RPCMarshalBlock(block, true, fullTx) 628 if err != nil { 629 return nil, err 630 } 631 response["author"] = response["miner"] 632 response["totalDifficulty"] = (*hexutil.Big)(api.blockchain.GetTd(block.Hash(), block.Number().Uint64())) 633 return response, err 634 } 635 return nil, fmt.Errorf("block 0x%x not found", blockHash) 636 } 637 638 func (api *RetestethAPI) AccountRange(ctx context.Context, 639 blockHashOrNumber *math.HexOrDecimal256, txIndex uint64, 640 addressHash *math.HexOrDecimal256, maxResults uint64, 641 ) (AccountRangeResult, error) { 642 var ( 643 header *types.Header 644 block *types.Block 645 ) 646 if (*big.Int)(blockHashOrNumber).Cmp(big.NewInt(math.MaxInt64)) > 0 { 647 blockHash := common.BigToHash((*big.Int)(blockHashOrNumber)) 648 header = api.blockchain.GetHeaderByHash(blockHash) 649 block = api.blockchain.GetBlockByHash(blockHash) 650 //fmt.Printf("Account range: %x, txIndex %d, start: %x, maxResults: %d\n", blockHash, txIndex, common.BigToHash((*big.Int)(addressHash)), maxResults) 651 } else { 652 blockNumber := (*big.Int)(blockHashOrNumber).Uint64() 653 header = api.blockchain.GetHeaderByNumber(blockNumber) 654 block = api.blockchain.GetBlockByNumber(blockNumber) 655 //fmt.Printf("Account range: %d, txIndex %d, start: %x, maxResults: %d\n", blockNumber, txIndex, common.BigToHash((*big.Int)(addressHash)), maxResults) 656 } 657 parentHeader := api.blockchain.GetHeaderByHash(header.ParentHash) 658 var root common.Hash 659 var statedb *state.StateDB 660 var err error 661 if parentHeader == nil || int(txIndex) >= len(block.Transactions()) { 662 root = header.Root 663 statedb, err = api.blockchain.StateAt(root) 664 if err != nil { 665 return AccountRangeResult{}, err 666 } 667 } else { 668 root = parentHeader.Root 669 statedb, err = api.blockchain.StateAt(root) 670 if err != nil { 671 return AccountRangeResult{}, err 672 } 673 // Recompute transactions up to the target index. 674 signer := types.MakeSigner(api.blockchain.Config(), block.Number()) 675 for idx, tx := range block.Transactions() { 676 // Assemble the transaction call message and return if the requested offset 677 msg, _ := tx.AsMessage(signer) 678 context := core.NewEVMContext(msg, block.Header(), api.blockchain, nil) 679 // Not yet the searched for transaction, execute on top of the current state 680 vmenv := vm.NewEVM(context, statedb, api.blockchain.Config(), vm.Config{}) 681 if _, err := core.ApplyMessage(vmenv, msg, new(core.GasPool).AddGas(tx.Gas())); err != nil { 682 return AccountRangeResult{}, fmt.Errorf("transaction %#x failed: %v", tx.Hash(), err) 683 } 684 // Ensure any modifications are committed to the state 685 // Only delete empty objects if EIP158/161 (a.k.a Spurious Dragon) is in effect 686 root = statedb.IntermediateRoot(vmenv.ChainConfig().IsEIP158(block.Number())) 687 if idx == int(txIndex) { 688 // This is to make sure root can be opened by OpenTrie 689 root, err = statedb.Commit(api.chainConfig.IsEIP158(block.Number())) 690 if err != nil { 691 return AccountRangeResult{}, err 692 } 693 break 694 } 695 } 696 } 697 accountTrie, err := statedb.Database().OpenTrie(root) 698 if err != nil { 699 return AccountRangeResult{}, err 700 } 701 it := trie.NewIterator(accountTrie.NodeIterator(common.BigToHash((*big.Int)(addressHash)).Bytes())) 702 result := AccountRangeResult{AddressMap: make(map[common.Hash]common.Address)} 703 for i := 0; i < int(maxResults) && it.Next(); i++ { 704 if preimage := accountTrie.GetKey(it.Key); preimage != nil { 705 result.AddressMap[common.BytesToHash(it.Key)] = common.BytesToAddress(preimage) 706 } 707 } 708 //fmt.Printf("Number of entries returned: %d\n", len(result.AddressMap)) 709 // Add the 'next key' so clients can continue downloading. 710 if it.Next() { 711 next := common.BytesToHash(it.Key) 712 result.NextKey = next 713 } 714 return result, nil 715 } 716 717 func (api *RetestethAPI) GetBalance(ctx context.Context, address common.Address, blockNr math.HexOrDecimal64) (*math.HexOrDecimal256, error) { 718 //fmt.Printf("GetBalance %x, block %d\n", address, blockNr) 719 header := api.blockchain.GetHeaderByNumber(uint64(blockNr)) 720 statedb, err := api.blockchain.StateAt(header.Root) 721 if err != nil { 722 return nil, err 723 } 724 return (*math.HexOrDecimal256)(statedb.GetBalance(address)), nil 725 } 726 727 func (api *RetestethAPI) GetCode(ctx context.Context, address common.Address, blockNr math.HexOrDecimal64) (hexutil.Bytes, error) { 728 header := api.blockchain.GetHeaderByNumber(uint64(blockNr)) 729 statedb, err := api.blockchain.StateAt(header.Root) 730 if err != nil { 731 return nil, err 732 } 733 return statedb.GetCode(address), nil 734 } 735 736 func (api *RetestethAPI) GetTransactionCount(ctx context.Context, address common.Address, blockNr math.HexOrDecimal64) (uint64, error) { 737 header := api.blockchain.GetHeaderByNumber(uint64(blockNr)) 738 statedb, err := api.blockchain.StateAt(header.Root) 739 if err != nil { 740 return 0, err 741 } 742 return statedb.GetNonce(address), nil 743 } 744 745 func (api *RetestethAPI) StorageRangeAt(ctx context.Context, 746 blockHashOrNumber *math.HexOrDecimal256, txIndex uint64, 747 address common.Address, 748 begin *math.HexOrDecimal256, maxResults uint64, 749 ) (StorageRangeResult, error) { 750 var ( 751 header *types.Header 752 block *types.Block 753 ) 754 if (*big.Int)(blockHashOrNumber).Cmp(big.NewInt(math.MaxInt64)) > 0 { 755 blockHash := common.BigToHash((*big.Int)(blockHashOrNumber)) 756 header = api.blockchain.GetHeaderByHash(blockHash) 757 block = api.blockchain.GetBlockByHash(blockHash) 758 //fmt.Printf("Storage range: %x, txIndex %d, addr: %x, start: %x, maxResults: %d\n", 759 // blockHash, txIndex, address, common.BigToHash((*big.Int)(begin)), maxResults) 760 } else { 761 blockNumber := (*big.Int)(blockHashOrNumber).Uint64() 762 header = api.blockchain.GetHeaderByNumber(blockNumber) 763 block = api.blockchain.GetBlockByNumber(blockNumber) 764 //fmt.Printf("Storage range: %d, txIndex %d, addr: %x, start: %x, maxResults: %d\n", 765 // blockNumber, txIndex, address, common.BigToHash((*big.Int)(begin)), maxResults) 766 } 767 parentHeader := api.blockchain.GetHeaderByHash(header.ParentHash) 768 var root common.Hash 769 var statedb *state.StateDB 770 var err error 771 if parentHeader == nil || int(txIndex) >= len(block.Transactions()) { 772 root = header.Root 773 statedb, err = api.blockchain.StateAt(root) 774 if err != nil { 775 return StorageRangeResult{}, err 776 } 777 } else { 778 root = parentHeader.Root 779 statedb, err = api.blockchain.StateAt(root) 780 if err != nil { 781 return StorageRangeResult{}, err 782 } 783 // Recompute transactions up to the target index. 784 signer := types.MakeSigner(api.blockchain.Config(), block.Number()) 785 for idx, tx := range block.Transactions() { 786 // Assemble the transaction call message and return if the requested offset 787 msg, _ := tx.AsMessage(signer) 788 context := core.NewEVMContext(msg, block.Header(), api.blockchain, nil) 789 // Not yet the searched for transaction, execute on top of the current state 790 vmenv := vm.NewEVM(context, statedb, api.blockchain.Config(), vm.Config{}) 791 if _, err := core.ApplyMessage(vmenv, msg, new(core.GasPool).AddGas(tx.Gas())); err != nil { 792 return StorageRangeResult{}, fmt.Errorf("transaction %#x failed: %v", tx.Hash(), err) 793 } 794 // Ensure any modifications are committed to the state 795 // Only delete empty objects if EIP158/161 (a.k.a Spurious Dragon) is in effect 796 _ = statedb.IntermediateRoot(vmenv.ChainConfig().IsEIP158(block.Number())) 797 if idx == int(txIndex) { 798 // This is to make sure root can be opened by OpenTrie 799 _, err = statedb.Commit(vmenv.ChainConfig().IsEIP158(block.Number())) 800 if err != nil { 801 return StorageRangeResult{}, err 802 } 803 } 804 } 805 } 806 storageTrie := statedb.StorageTrie(address) 807 it := trie.NewIterator(storageTrie.NodeIterator(common.BigToHash((*big.Int)(begin)).Bytes())) 808 result := StorageRangeResult{Storage: make(map[common.Hash]SRItem)} 809 for i := 0; /*i < int(maxResults) && */ it.Next(); i++ { 810 if preimage := storageTrie.GetKey(it.Key); preimage != nil { 811 key := (*math.HexOrDecimal256)(big.NewInt(0).SetBytes(preimage)) 812 v, _, err := rlp.SplitString(it.Value) 813 if err != nil { 814 return StorageRangeResult{}, err 815 } 816 value := (*math.HexOrDecimal256)(big.NewInt(0).SetBytes(v)) 817 ks, _ := key.MarshalText() 818 vs, _ := value.MarshalText() 819 if len(ks)%2 != 0 { 820 ks = append(append(append([]byte{}, ks[:2]...), byte('0')), ks[2:]...) 821 } 822 if len(vs)%2 != 0 { 823 vs = append(append(append([]byte{}, vs[:2]...), byte('0')), vs[2:]...) 824 } 825 result.Storage[common.BytesToHash(it.Key)] = SRItem{ 826 Key: string(ks), 827 Value: string(vs), 828 } 829 } 830 } 831 if it.Next() { 832 result.Complete = false 833 } else { 834 result.Complete = true 835 } 836 return result, nil 837 } 838 839 func (api *RetestethAPI) ClientVersion(ctx context.Context) (string, error) { 840 return "Geth-" + params.VersionWithCommit(gitCommit, gitDate), nil 841 } 842 843 // splitAndTrim splits input separated by a comma 844 // and trims excessive white space from the substrings. 845 func splitAndTrim(input string) []string { 846 result := strings.Split(input, ",") 847 for i, r := range result { 848 result[i] = strings.TrimSpace(r) 849 } 850 return result 851 } 852 853 func retesteth(ctx *cli.Context) error { 854 log.Info("Welcome to retesteth!") 855 // register signer API with server 856 var ( 857 extapiURL string 858 ) 859 apiImpl := &RetestethAPI{} 860 var testApi RetestethTestAPI = apiImpl 861 var ethApi RetestethEthAPI = apiImpl 862 var debugApi RetestethDebugAPI = apiImpl 863 var web3Api RetestWeb3API = apiImpl 864 rpcAPI := []rpc.API{ 865 { 866 Namespace: "test", 867 Public: true, 868 Service: testApi, 869 Version: "1.0", 870 }, 871 { 872 Namespace: "eth", 873 Public: true, 874 Service: ethApi, 875 Version: "1.0", 876 }, 877 { 878 Namespace: "debug", 879 Public: true, 880 Service: debugApi, 881 Version: "1.0", 882 }, 883 { 884 Namespace: "web3", 885 Public: true, 886 Service: web3Api, 887 Version: "1.0", 888 }, 889 } 890 vhosts := splitAndTrim(ctx.GlobalString(utils.HTTPVirtualHostsFlag.Name)) 891 cors := splitAndTrim(ctx.GlobalString(utils.HTTPCORSDomainFlag.Name)) 892 893 // register apis and create handler stack 894 srv := rpc.NewServer() 895 err := node.RegisterApisFromWhitelist(rpcAPI, []string{"test", "eth", "debug", "web3"}, srv, false) 896 if err != nil { 897 utils.Fatalf("Could not register RPC apis: %w", err) 898 } 899 handler := node.NewHTTPHandlerStack(srv, cors, vhosts) 900 901 // start http server 902 var RetestethHTTPTimeouts = rpc.HTTPTimeouts{ 903 ReadTimeout: 120 * time.Second, 904 WriteTimeout: 120 * time.Second, 905 IdleTimeout: 120 * time.Second, 906 } 907 httpEndpoint := fmt.Sprintf("%s:%d", ctx.GlobalString(utils.HTTPListenAddrFlag.Name), ctx.Int(rpcPortFlag.Name)) 908 httpServer, _, err := node.StartHTTPEndpoint(httpEndpoint, RetestethHTTPTimeouts, handler) 909 if err != nil { 910 utils.Fatalf("Could not start RPC api: %v", err) 911 } 912 extapiURL = fmt.Sprintf("http://%s", httpEndpoint) 913 log.Info("HTTP endpoint opened", "url", extapiURL) 914 915 defer func() { 916 // Don't bother imposing a timeout here. 917 httpServer.Shutdown(context.Background()) 918 log.Info("HTTP endpoint closed", "url", httpEndpoint) 919 }() 920 921 abortChan := make(chan os.Signal, 11) 922 signal.Notify(abortChan, os.Interrupt) 923 924 sig := <-abortChan 925 log.Info("Exiting...", "signal", sig) 926 return nil 927 }