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