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