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