github.com/mister-meeseeks/go-ethereum@v1.9.7/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: ¶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 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 }