github.com/ethereum-optimism/optimism/l2geth@v0.0.0-20230612200230-50b04ade19e3/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-optimism/optimism/l2geth/cmd/utils" 30 "github.com/ethereum-optimism/optimism/l2geth/common" 31 "github.com/ethereum-optimism/optimism/l2geth/common/hexutil" 32 "github.com/ethereum-optimism/optimism/l2geth/common/math" 33 "github.com/ethereum-optimism/optimism/l2geth/consensus" 34 "github.com/ethereum-optimism/optimism/l2geth/consensus/ethash" 35 "github.com/ethereum-optimism/optimism/l2geth/consensus/misc" 36 "github.com/ethereum-optimism/optimism/l2geth/core" 37 "github.com/ethereum-optimism/optimism/l2geth/core/rawdb" 38 "github.com/ethereum-optimism/optimism/l2geth/core/state" 39 "github.com/ethereum-optimism/optimism/l2geth/core/types" 40 "github.com/ethereum-optimism/optimism/l2geth/core/vm" 41 "github.com/ethereum-optimism/optimism/l2geth/crypto" 42 "github.com/ethereum-optimism/optimism/l2geth/ethdb" 43 "github.com/ethereum-optimism/optimism/l2geth/log" 44 "github.com/ethereum-optimism/optimism/l2geth/node" 45 "github.com/ethereum-optimism/optimism/l2geth/params" 46 "github.com/ethereum-optimism/optimism/l2geth/rlp" 47 "github.com/ethereum-optimism/optimism/l2geth/rpc" 48 "github.com/ethereum-optimism/optimism/l2geth/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: ¶ms.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 blockFull = gasPool.Gas() < params.TxGas 499 for address := range api.txSenders { 500 if blockFull { 501 break 502 } 503 m := api.txMap[address] 504 for nonce := statedb.GetNonce(address); ; nonce++ { 505 if tx, ok := m[nonce]; ok { 506 // Try to apply transactions to the state 507 statedb.Prepare(tx.Hash(), common.Hash{}, txCount) 508 snap := statedb.Snapshot() 509 510 receipt, err := core.ApplyTransaction( 511 api.chainConfig, 512 api.blockchain, 513 &api.author, 514 gasPool, 515 statedb, 516 header, tx, &header.GasUsed, *api.blockchain.GetVMConfig(), 517 ) 518 if err != nil { 519 statedb.RevertToSnapshot(snap) 520 break 521 } 522 txs = append(txs, tx) 523 receipts = append(receipts, receipt) 524 delete(m, nonce) 525 if len(m) == 0 { 526 // Last tx for the sender 527 delete(api.txMap, address) 528 delete(api.txSenders, address) 529 } 530 txCount++ 531 if gasPool.Gas() < params.TxGas { 532 blockFull = true 533 break 534 } 535 } else { 536 break // Gap in the nonces 537 } 538 } 539 } 540 block, err := api.engine.FinalizeAndAssemble(api.blockchain, header, statedb, txs, []*types.Header{}, receipts) 541 if err != nil { 542 return err 543 } 544 return api.importBlock(block) 545 } 546 547 func (api *RetestethAPI) importBlock(block *types.Block) error { 548 if _, err := api.blockchain.InsertChain([]*types.Block{block}); err != nil { 549 return err 550 } 551 api.blockNumber = block.NumberU64() 552 fmt.Printf("Imported block %d\n", block.NumberU64()) 553 return nil 554 } 555 556 func (api *RetestethAPI) ModifyTimestamp(ctx context.Context, interval uint64) (bool, error) { 557 api.blockInterval = interval 558 return true, nil 559 } 560 561 func (api *RetestethAPI) ImportRawBlock(ctx context.Context, rawBlock hexutil.Bytes) (common.Hash, error) { 562 block := new(types.Block) 563 if err := rlp.DecodeBytes(rawBlock, block); err != nil { 564 return common.Hash{}, err 565 } 566 fmt.Printf("Importing block %d with parent hash: %x, genesisHash: %x\n", block.NumberU64(), block.ParentHash(), api.genesisHash) 567 if err := api.importBlock(block); err != nil { 568 return common.Hash{}, err 569 } 570 return block.Hash(), nil 571 } 572 573 func (api *RetestethAPI) RewindToBlock(ctx context.Context, newHead uint64) (bool, error) { 574 if err := api.blockchain.SetHead(newHead); err != nil { 575 return false, err 576 } 577 api.blockNumber = newHead 578 return true, nil 579 } 580 581 var emptyListHash common.Hash = common.HexToHash("0x1dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d49347") 582 583 func (api *RetestethAPI) GetLogHash(ctx context.Context, txHash common.Hash) (common.Hash, error) { 584 receipt, _, _, _ := rawdb.ReadReceipt(api.ethDb, txHash, api.chainConfig) 585 if receipt == nil { 586 return emptyListHash, nil 587 } else { 588 if logListRlp, err := rlp.EncodeToBytes(receipt.Logs); err != nil { 589 return common.Hash{}, err 590 } else { 591 return common.BytesToHash(crypto.Keccak256(logListRlp)), nil 592 } 593 } 594 } 595 596 func (api *RetestethAPI) BlockNumber(ctx context.Context) (uint64, error) { 597 //fmt.Printf("BlockNumber, response: %d\n", api.blockNumber) 598 return api.blockNumber, nil 599 } 600 601 func (api *RetestethAPI) GetBlockByNumber(ctx context.Context, blockNr math.HexOrDecimal64, fullTx bool) (map[string]interface{}, error) { 602 block := api.blockchain.GetBlockByNumber(uint64(blockNr)) 603 if block != nil { 604 response, err := RPCMarshalBlock(block, true, fullTx) 605 if err != nil { 606 return nil, err 607 } 608 response["author"] = response["miner"] 609 response["totalDifficulty"] = (*hexutil.Big)(api.blockchain.GetTd(block.Hash(), uint64(blockNr))) 610 return response, err 611 } 612 return nil, fmt.Errorf("block %d not found", blockNr) 613 } 614 615 func (api *RetestethAPI) AccountRange(ctx context.Context, 616 blockHashOrNumber *math.HexOrDecimal256, txIndex uint64, 617 addressHash *math.HexOrDecimal256, maxResults uint64, 618 ) (AccountRangeResult, error) { 619 var ( 620 header *types.Header 621 block *types.Block 622 ) 623 if (*big.Int)(blockHashOrNumber).Cmp(big.NewInt(math.MaxInt64)) > 0 { 624 blockHash := common.BigToHash((*big.Int)(blockHashOrNumber)) 625 header = api.blockchain.GetHeaderByHash(blockHash) 626 block = api.blockchain.GetBlockByHash(blockHash) 627 //fmt.Printf("Account range: %x, txIndex %d, start: %x, maxResults: %d\n", blockHash, txIndex, common.BigToHash((*big.Int)(addressHash)), maxResults) 628 } else { 629 blockNumber := (*big.Int)(blockHashOrNumber).Uint64() 630 header = api.blockchain.GetHeaderByNumber(blockNumber) 631 block = api.blockchain.GetBlockByNumber(blockNumber) 632 //fmt.Printf("Account range: %d, txIndex %d, start: %x, maxResults: %d\n", blockNumber, txIndex, common.BigToHash((*big.Int)(addressHash)), maxResults) 633 } 634 parentHeader := api.blockchain.GetHeaderByHash(header.ParentHash) 635 var root common.Hash 636 var statedb *state.StateDB 637 var err error 638 if parentHeader == nil || int(txIndex) >= len(block.Transactions()) { 639 root = header.Root 640 statedb, err = api.blockchain.StateAt(root) 641 if err != nil { 642 return AccountRangeResult{}, err 643 } 644 } else { 645 root = parentHeader.Root 646 statedb, err = api.blockchain.StateAt(root) 647 if err != nil { 648 return AccountRangeResult{}, err 649 } 650 // Recompute transactions up to the target index. 651 signer := types.MakeSigner(api.blockchain.Config(), block.Number()) 652 for idx, tx := range block.Transactions() { 653 // Assemble the transaction call message and return if the requested offset 654 msg, _ := tx.AsMessage(signer) 655 context := core.NewEVMContext(msg, block.Header(), api.blockchain, nil) 656 // Not yet the searched for transaction, execute on top of the current state 657 vmenv := vm.NewEVM(context, statedb, api.blockchain.Config(), vm.Config{}) 658 if _, _, _, err := core.ApplyMessage(vmenv, msg, new(core.GasPool).AddGas(tx.Gas())); err != nil { 659 return AccountRangeResult{}, fmt.Errorf("transaction %#x failed: %v", tx.Hash(), err) 660 } 661 // Ensure any modifications are committed to the state 662 // Only delete empty objects if EIP158/161 (a.k.a Spurious Dragon) is in effect 663 root = statedb.IntermediateRoot(vmenv.ChainConfig().IsEIP158(block.Number())) 664 if idx == int(txIndex) { 665 // This is to make sure root can be opened by OpenTrie 666 root, err = statedb.Commit(api.chainConfig.IsEIP158(block.Number())) 667 if err != nil { 668 return AccountRangeResult{}, err 669 } 670 break 671 } 672 } 673 } 674 accountTrie, err := statedb.Database().OpenTrie(root) 675 if err != nil { 676 return AccountRangeResult{}, err 677 } 678 it := trie.NewIterator(accountTrie.NodeIterator(common.BigToHash((*big.Int)(addressHash)).Bytes())) 679 result := AccountRangeResult{AddressMap: make(map[common.Hash]common.Address)} 680 for i := 0; i < int(maxResults) && it.Next(); i++ { 681 if preimage := accountTrie.GetKey(it.Key); preimage != nil { 682 result.AddressMap[common.BytesToHash(it.Key)] = common.BytesToAddress(preimage) 683 } 684 } 685 //fmt.Printf("Number of entries returned: %d\n", len(result.AddressMap)) 686 // Add the 'next key' so clients can continue downloading. 687 if it.Next() { 688 next := common.BytesToHash(it.Key) 689 result.NextKey = next 690 } 691 return result, nil 692 } 693 694 func (api *RetestethAPI) GetBalance(ctx context.Context, address common.Address, blockNr math.HexOrDecimal64) (*math.HexOrDecimal256, error) { 695 //fmt.Printf("GetBalance %x, block %d\n", address, blockNr) 696 header := api.blockchain.GetHeaderByNumber(uint64(blockNr)) 697 statedb, err := api.blockchain.StateAt(header.Root) 698 if err != nil { 699 return nil, err 700 } 701 return (*math.HexOrDecimal256)(statedb.GetBalance(address)), nil 702 } 703 704 func (api *RetestethAPI) GetCode(ctx context.Context, address common.Address, blockNr math.HexOrDecimal64) (hexutil.Bytes, error) { 705 header := api.blockchain.GetHeaderByNumber(uint64(blockNr)) 706 statedb, err := api.blockchain.StateAt(header.Root) 707 if err != nil { 708 return nil, err 709 } 710 return statedb.GetCode(address), nil 711 } 712 713 func (api *RetestethAPI) GetTransactionCount(ctx context.Context, address common.Address, blockNr math.HexOrDecimal64) (uint64, error) { 714 header := api.blockchain.GetHeaderByNumber(uint64(blockNr)) 715 statedb, err := api.blockchain.StateAt(header.Root) 716 if err != nil { 717 return 0, err 718 } 719 return statedb.GetNonce(address), nil 720 } 721 722 func (api *RetestethAPI) StorageRangeAt(ctx context.Context, 723 blockHashOrNumber *math.HexOrDecimal256, txIndex uint64, 724 address common.Address, 725 begin *math.HexOrDecimal256, maxResults uint64, 726 ) (StorageRangeResult, error) { 727 var ( 728 header *types.Header 729 block *types.Block 730 ) 731 if (*big.Int)(blockHashOrNumber).Cmp(big.NewInt(math.MaxInt64)) > 0 { 732 blockHash := common.BigToHash((*big.Int)(blockHashOrNumber)) 733 header = api.blockchain.GetHeaderByHash(blockHash) 734 block = api.blockchain.GetBlockByHash(blockHash) 735 //fmt.Printf("Storage range: %x, txIndex %d, addr: %x, start: %x, maxResults: %d\n", 736 // blockHash, txIndex, address, common.BigToHash((*big.Int)(begin)), maxResults) 737 } else { 738 blockNumber := (*big.Int)(blockHashOrNumber).Uint64() 739 header = api.blockchain.GetHeaderByNumber(blockNumber) 740 block = api.blockchain.GetBlockByNumber(blockNumber) 741 //fmt.Printf("Storage range: %d, txIndex %d, addr: %x, start: %x, maxResults: %d\n", 742 // blockNumber, txIndex, address, common.BigToHash((*big.Int)(begin)), maxResults) 743 } 744 parentHeader := api.blockchain.GetHeaderByHash(header.ParentHash) 745 var root common.Hash 746 var statedb *state.StateDB 747 var err error 748 if parentHeader == nil || int(txIndex) >= len(block.Transactions()) { 749 root = header.Root 750 statedb, err = api.blockchain.StateAt(root) 751 if err != nil { 752 return StorageRangeResult{}, err 753 } 754 } else { 755 root = parentHeader.Root 756 statedb, err = api.blockchain.StateAt(root) 757 if err != nil { 758 return StorageRangeResult{}, err 759 } 760 // Recompute transactions up to the target index. 761 signer := types.MakeSigner(api.blockchain.Config(), block.Number()) 762 for idx, tx := range block.Transactions() { 763 // Assemble the transaction call message and return if the requested offset 764 msg, _ := tx.AsMessage(signer) 765 context := core.NewEVMContext(msg, block.Header(), api.blockchain, nil) 766 // Not yet the searched for transaction, execute on top of the current state 767 vmenv := vm.NewEVM(context, statedb, api.blockchain.Config(), vm.Config{}) 768 if _, _, _, err := core.ApplyMessage(vmenv, msg, new(core.GasPool).AddGas(tx.Gas())); err != nil { 769 return StorageRangeResult{}, fmt.Errorf("transaction %#x failed: %v", tx.Hash(), err) 770 } 771 // Ensure any modifications are committed to the state 772 // Only delete empty objects if EIP158/161 (a.k.a Spurious Dragon) is in effect 773 _ = statedb.IntermediateRoot(vmenv.ChainConfig().IsEIP158(block.Number())) 774 if idx == int(txIndex) { 775 // This is to make sure root can be opened by OpenTrie 776 _, err = statedb.Commit(vmenv.ChainConfig().IsEIP158(block.Number())) 777 if err != nil { 778 return StorageRangeResult{}, err 779 } 780 } 781 } 782 } 783 storageTrie := statedb.StorageTrie(address) 784 it := trie.NewIterator(storageTrie.NodeIterator(common.BigToHash((*big.Int)(begin)).Bytes())) 785 result := StorageRangeResult{Storage: make(map[common.Hash]SRItem)} 786 for i := 0; /*i < int(maxResults) && */ it.Next(); i++ { 787 if preimage := storageTrie.GetKey(it.Key); preimage != nil { 788 key := (*math.HexOrDecimal256)(big.NewInt(0).SetBytes(preimage)) 789 v, _, err := rlp.SplitString(it.Value) 790 if err != nil { 791 return StorageRangeResult{}, err 792 } 793 value := (*math.HexOrDecimal256)(big.NewInt(0).SetBytes(v)) 794 ks, _ := key.MarshalText() 795 vs, _ := value.MarshalText() 796 if len(ks)%2 != 0 { 797 ks = append(append(append([]byte{}, ks[:2]...), byte('0')), ks[2:]...) 798 } 799 if len(vs)%2 != 0 { 800 vs = append(append(append([]byte{}, vs[:2]...), byte('0')), vs[2:]...) 801 } 802 result.Storage[common.BytesToHash(it.Key)] = SRItem{ 803 Key: string(ks), 804 Value: string(vs), 805 } 806 } 807 } 808 if it.Next() { 809 result.Complete = false 810 } else { 811 result.Complete = true 812 } 813 return result, nil 814 } 815 816 func (api *RetestethAPI) ClientVersion(ctx context.Context) (string, error) { 817 return "Geth-" + params.VersionWithCommit(gitCommit, gitDate), nil 818 } 819 820 // splitAndTrim splits input separated by a comma 821 // and trims excessive white space from the substrings. 822 func splitAndTrim(input string) []string { 823 result := strings.Split(input, ",") 824 for i, r := range result { 825 result[i] = strings.TrimSpace(r) 826 } 827 return result 828 } 829 830 func retesteth(ctx *cli.Context) error { 831 log.Info("Welcome to retesteth!") 832 // register signer API with server 833 var ( 834 extapiURL string 835 ) 836 apiImpl := &RetestethAPI{} 837 var testApi RetestethTestAPI = apiImpl 838 var ethApi RetestethEthAPI = apiImpl 839 var debugApi RetestethDebugAPI = apiImpl 840 var web3Api RetestWeb3API = apiImpl 841 rpcAPI := []rpc.API{ 842 { 843 Namespace: "test", 844 Public: true, 845 Service: testApi, 846 Version: "1.0", 847 }, 848 { 849 Namespace: "eth", 850 Public: true, 851 Service: ethApi, 852 Version: "1.0", 853 }, 854 { 855 Namespace: "debug", 856 Public: true, 857 Service: debugApi, 858 Version: "1.0", 859 }, 860 { 861 Namespace: "web3", 862 Public: true, 863 Service: web3Api, 864 Version: "1.0", 865 }, 866 } 867 vhosts := splitAndTrim(ctx.GlobalString(utils.RPCVirtualHostsFlag.Name)) 868 cors := splitAndTrim(ctx.GlobalString(utils.RPCCORSDomainFlag.Name)) 869 870 // start http server 871 httpEndpoint := fmt.Sprintf("%s:%d", ctx.GlobalString(utils.RPCListenAddrFlag.Name), ctx.Int(rpcPortFlag.Name)) 872 listener, _, err := rpc.StartHTTPEndpoint(httpEndpoint, rpcAPI, []string{"test", "eth", "debug", "web3"}, cors, vhosts, rpc.DefaultHTTPTimeouts) 873 if err != nil { 874 utils.Fatalf("Could not start RPC api: %v", err) 875 } 876 extapiURL = fmt.Sprintf("http://%s", httpEndpoint) 877 log.Info("HTTP endpoint opened", "url", extapiURL) 878 879 defer func() { 880 listener.Close() 881 log.Info("HTTP endpoint closed", "url", httpEndpoint) 882 }() 883 884 abortChan := make(chan os.Signal, 11) 885 signal.Notify(abortChan, os.Interrupt) 886 887 sig := <-abortChan 888 log.Info("Exiting...", "signal", sig) 889 return nil 890 }