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