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