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