gitlab.com/aquachain/aquachain@v1.17.16-rc3.0.20221018032414-e3ddf1e1c055/aqua/api.go (about) 1 // Copyright 2018 The aquachain Authors 2 // This file is part of the aquachain library. 3 // 4 // The aquachain library is free software: you can redistribute it and/or modify 5 // it under the terms of the GNU Lesser 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 // The aquachain library 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 Lesser General Public License for more details. 13 // 14 // You should have received a copy of the GNU Lesser General Public License 15 // along with the aquachain library. If not, see <http://www.gnu.org/licenses/>. 16 17 package aqua 18 19 import ( 20 "compress/gzip" 21 "context" 22 "fmt" 23 "io" 24 "math/big" 25 "os" 26 "sort" 27 "strings" 28 29 "gitlab.com/aquachain/aquachain/common" 30 "gitlab.com/aquachain/aquachain/common/hexutil" 31 "gitlab.com/aquachain/aquachain/common/log" 32 "gitlab.com/aquachain/aquachain/core" 33 "gitlab.com/aquachain/aquachain/core/state" 34 "gitlab.com/aquachain/aquachain/core/types" 35 "gitlab.com/aquachain/aquachain/opt/miner" 36 "gitlab.com/aquachain/aquachain/params" 37 "gitlab.com/aquachain/aquachain/rlp" 38 "gitlab.com/aquachain/aquachain/rpc" 39 ) 40 41 // PublicTestingAPI provides an API to access new features 42 type PublicTestingAPI struct { 43 cfg *params.ChainConfig 44 agent *miner.RemoteAgent 45 e *Aquachain 46 } 47 48 // NewPublicAquachainAPI creates a new Aquachain protocol API for full nodes. 49 func NewPublicTestingAPI(cfg *params.ChainConfig, e *Aquachain) *PublicTestingAPI { 50 agent := miner.NewRemoteAgent(e.BlockChain(), e.Engine()) 51 e.Miner().Register(agent) 52 return &PublicTestingAPI{cfg, agent, e} 53 } 54 55 // PublicAquachainAPI provides an API to access Aquachain full node-related 56 // information. 57 type PublicAquachainAPI struct { 58 e *Aquachain 59 } 60 61 // NewPublicAquachainAPI creates a new Aquachain protocol API for full nodes. 62 func NewPublicAquachainAPI(e *Aquachain) *PublicAquachainAPI { 63 return &PublicAquachainAPI{e} 64 } 65 66 // Aquabase is the address that mining rewards will be send to 67 func (api *PublicAquachainAPI) Aquabase() (common.Address, error) { 68 return api.e.Aquabase() 69 } 70 71 // Coinbase is the address that mining rewards will be send to (alias for Aquabase) 72 func (api *PublicAquachainAPI) Coinbase() (common.Address, error) { 73 return api.Aquabase() 74 } 75 76 // Hashrate returns the POW hashrate 77 func (api *PublicAquachainAPI) Hashrate() hexutil.Uint64 { 78 return hexutil.Uint64(api.e.Miner().HashRate()) 79 } 80 81 // ChainId is the EIP-155 replay-protection chain id for the current ethereum chain config. 82 func (api *PublicAquachainAPI) ChainId() hexutil.Uint64 { 83 chainID := new(big.Int) 84 if config := api.e.chainConfig; config.IsEIP155(api.e.blockchain.CurrentBlock().Number()) { 85 chainID = config.ChainId 86 } 87 return (hexutil.Uint64)(chainID.Uint64()) 88 } 89 90 // PublicMinerAPI provides an API to control the miner. 91 // It offers only methods that operate on data that pose no security risk when it is publicly accessible. 92 type PublicMinerAPI struct { 93 e *Aquachain 94 agent *miner.RemoteAgent 95 } 96 97 // NewPublicMinerAPI create a new PublicMinerAPI instance. 98 func NewPublicMinerAPI(e *Aquachain) *PublicMinerAPI { 99 agent := miner.NewRemoteAgent(e.BlockChain(), e.Engine()) 100 e.Miner().Register(agent) 101 102 return &PublicMinerAPI{e, agent} 103 } 104 105 // Mining returns an indication if this node is currently mining. 106 func (api *PublicMinerAPI) Mining() bool { 107 return api.e.IsMining() 108 } 109 110 // SubmitWork can be used by external miner to submit their POW solution. It returns an indication if the work was 111 // accepted. Note, this is not an indication if the provided work was valid! 112 func (api *PublicMinerAPI) SubmitWork(nonce types.BlockNonce, solution, digest common.Hash) bool { 113 return api.agent.SubmitWork(nonce, digest, solution) 114 } 115 116 // SubmitBlock can be used by external miner to submit their POW solution. It returns an indication if the work was 117 // accepted. Note, this is not an indication if the provided work was valid! 118 func (api *PublicTestingAPI) SubmitBlock(encodedBlock []byte) bool { 119 var block types.Block 120 if encodedBlock == nil { 121 log.Warn("submitblock rlp got nil") 122 return false 123 } 124 if err := rlp.DecodeBytes(encodedBlock, &block); err != nil { 125 log.Warn("submitblock rlp decode error", "err", err) 126 return false 127 } 128 if block.Nonce() == 0 { 129 log.Warn("submitblock got 0 nonce") 130 return false 131 } 132 block.SetVersion(api.e.chainConfig.GetBlockVersion(block.Number())) 133 log.Debug("RPC client submitted block:", "block", block.Header()) 134 return api.agent.SubmitBlock(&block) 135 } 136 137 func (api *PublicTestingAPI) GetBlockTemplate(addr common.Address) ([]byte, error) { 138 log.Debug("Got block template request:", "coinbase", addr) 139 if !api.e.IsMining() { 140 if err := api.e.StartMining(false); err != nil { 141 return nil, err 142 } 143 } 144 return api.agent.GetBlockTemplate(addr) 145 } 146 147 // GetWork returns a work package for external miner. The work package consists of 3 strings 148 // result[0], 32 bytes hex encoded current block header pow-hash 149 // result[1], 32 bytes hex encoded auxiliary chunk (pre hf5: dag seed, hf5: zeros, hf8: header version) 150 // result[2], 32 bytes hex encoded boundary condition ("target"), 2^256/difficulty 151 func (api *PublicMinerAPI) GetWork() ([3]string, error) { 152 if !api.e.IsMining() { 153 if err := api.e.StartMining(false); err != nil { 154 return [3]string{}, err 155 } 156 } 157 work, err := api.agent.GetWork() 158 if err != nil { 159 return work, fmt.Errorf("mining not ready: %v", err) 160 } 161 return work, nil 162 } 163 164 // SubmitHashrate can be used for remote miners to submit their hash rate. This enables the node to report the combined 165 // hash rate of all miners which submit work through this node. It accepts the miner hash rate and an identifier which 166 // must be unique between nodes. 167 func (api *PublicMinerAPI) SubmitHashrate(hashrate hexutil.Uint64, id common.Hash) bool { 168 // api.agent.SubmitHashrate(id, uint64(hashrate)) 169 return true 170 } 171 172 // PrivateMinerAPI provides private RPC methods to control the miner. 173 // These methods can be abused by external users and must be considered insecure for use by untrusted users. 174 type PrivateMinerAPI struct { 175 e *Aquachain 176 } 177 178 // NewPrivateMinerAPI create a new RPC service which controls the miner of this node. 179 func NewPrivateMinerAPI(e *Aquachain) *PrivateMinerAPI { 180 return &PrivateMinerAPI{e: e} 181 } 182 183 // Start the miner with the given number of threads. If threads is nil the number 184 // of workers started is equal to the number of logical CPUs that are usable by 185 // this process. If mining is already running, this method adjust the number of 186 // threads allowed to use. 187 func (api *PrivateMinerAPI) Start(threads *int) error { 188 // Set the number of threads if the seal engine supports it 189 if threads == nil { 190 threads = new(int) 191 } else if *threads == 0 { 192 *threads = -1 // Disable the miner from within 193 } 194 type threaded interface { 195 SetThreads(threads int) 196 } 197 if th, ok := api.e.engine.(threaded); ok { 198 log.Info("Updated mining threads", "threads", *threads) 199 th.SetThreads(*threads) 200 } 201 // Start the miner and return 202 if !api.e.IsMining() { 203 // Propagate the initial price point to the transaction pool 204 api.e.lock.RLock() 205 price := api.e.gasPrice 206 api.e.lock.RUnlock() 207 208 api.e.txPool.SetGasPrice(price) 209 return api.e.StartMining(true) 210 } 211 return nil 212 } 213 214 // Stop the miner 215 func (api *PrivateMinerAPI) Stop() bool { 216 type threaded interface { 217 SetThreads(threads int) 218 } 219 if th, ok := api.e.engine.(threaded); ok { 220 th.SetThreads(-1) 221 } 222 api.e.StopMining() 223 return true 224 } 225 226 // SetExtra sets the extra data string that is included when this miner mines a block. 227 func (api *PrivateMinerAPI) SetExtra(extra string) (bool, error) { 228 if err := api.e.Miner().SetExtra([]byte(extra)); err != nil { 229 return false, err 230 } 231 return true, nil 232 } 233 234 // SetGasPrice sets the minimum accepted gas price for the miner. 235 func (api *PrivateMinerAPI) SetGasPrice(gasPrice hexutil.Big) bool { 236 api.e.lock.Lock() 237 api.e.gasPrice = (*big.Int)(&gasPrice) 238 api.e.lock.Unlock() 239 240 api.e.txPool.SetGasPrice((*big.Int)(&gasPrice)) 241 return true 242 } 243 244 // SetAquabase sets the aquabase of the miner 245 func (api *PrivateMinerAPI) SetAquabase(aquabase common.Address) bool { 246 api.e.SetAquabase(aquabase) 247 return true 248 } 249 250 // GetHashrate returns the current hashrate of the miner. 251 func (api *PrivateMinerAPI) GetHashrate() uint64 { 252 return uint64(api.e.miner.HashRate()) 253 } 254 255 // PrivateAdminAPI is the collection of Aquachain full node-related APIs 256 // exposed over the private admin endpoint. 257 type PrivateAdminAPI struct { 258 aqua *Aquachain 259 } 260 261 // NewPrivateAdminAPI creates a new API definition for the full node private 262 // admin methods of the Aquachain service. 263 func NewPrivateAdminAPI(aqua *Aquachain) *PrivateAdminAPI { 264 return &PrivateAdminAPI{aqua: aqua} 265 } 266 267 // ExportState exports the current state database into a simplified json file. 268 func (api *PrivateAdminAPI) ExportState(file string) (bool, error) { 269 // Make sure we can create the file to export into 270 out, err := os.OpenFile(file, os.O_CREATE|os.O_WRONLY|os.O_TRUNC, os.ModePerm) 271 if err != nil { 272 return false, err 273 } 274 defer out.Close() 275 statedb, err := api.aqua.BlockChain().State() 276 if err != nil { 277 return false, err 278 } 279 var writer io.Writer = out 280 if strings.HasSuffix(file, ".gz") { 281 writer = gzip.NewWriter(writer) 282 defer writer.(*gzip.Writer).Close() 283 } 284 // Export the state 285 if err := statedb.TakeSnapshot(writer); err != nil { 286 return false, err 287 } 288 return true, nil 289 } 290 291 // GetDistribution returns a map of address->balance 292 func (api *PrivateAdminAPI) GetDistribution() (map[string]state.DumpAccount, error) { 293 statedb, err := api.aqua.BlockChain().State() 294 if err != nil { 295 return nil, err 296 } 297 // Export the state 298 dump := statedb.RawDump() 299 return dump.Accounts, nil 300 } 301 302 var BigAqua = new(big.Float).SetFloat64(params.Aqua) 303 304 func (api *PrivateAdminAPI) GetRichlist(n int) ([]string, error) { 305 if n == 0 { 306 n = 100 307 } 308 dist, err := api.GetDistribution() 309 if err != nil { 310 return nil, err 311 } 312 type distribResult struct { 313 a string 314 ss state.DumpAccount 315 } 316 var results = []distribResult{} 317 for addr, bal := range dist { 318 results = append(results, distribResult{addr, bal}) 319 } 320 sort.Slice(results, func(i, j int) bool { 321 ii, _ := new(big.Int).SetString(results[i].ss.Balance, 10) 322 jj, _ := new(big.Int).SetString(results[j].ss.Balance, 10) 323 return ii.Cmp(jj) > 0 324 }) 325 var balances []string 326 for i, v := range results { 327 if v.ss.Balance != "0" { 328 f, _ := new(big.Float).SetString(v.ss.Balance) 329 f = f.Quo(f, BigAqua) 330 balances = append(balances, fmt.Sprintf("%s: %2.8f", v.a, f)) 331 if i >= n-1 { 332 break 333 } 334 } 335 } 336 return balances, nil 337 } 338 339 // Supply returns a map of address->balance 340 func (api *PrivateAdminAPI) Supply() (*big.Int, error) { 341 dump, err := api.GetDistribution() 342 if err != nil { 343 return nil, err 344 } 345 total := new(big.Int) 346 347 if len(dump) > 100000 { 348 return nil, fmt.Errorf("number of accounts over 100000, bailing") 349 } 350 351 bal := make([]string, len(dump)) 352 n := 0 353 for i := range dump { 354 bal[n] = dump[i].Balance 355 n++ 356 } 357 358 for i := range bal { 359 if bal[i] == "" || bal[i] == "0" { 360 continue 361 } 362 balance, _ := new(big.Int).SetString(bal[i], 10) 363 total.Add(total, balance) 364 } 365 return total, nil 366 } 367 368 // ExportRealloc exports the current state database into a ready-to-import json file 369 func (api *PrivateAdminAPI) ExportRealloc(file string) (bool, error) { 370 // Make sure we can create the file to export into 371 out, err := os.OpenFile(file, os.O_CREATE|os.O_WRONLY|os.O_TRUNC, os.ModePerm) 372 if err != nil { 373 return false, err 374 } 375 defer out.Close() 376 statedb, err := api.aqua.BlockChain().State() 377 if err != nil { 378 return false, err 379 } 380 var writer io.Writer = out 381 if strings.HasSuffix(file, ".gz") { 382 writer = gzip.NewWriter(writer) 383 defer writer.(*gzip.Writer).Close() 384 } 385 writer.Write([]byte(`` + 386 `{ 387 "config":{ 388 "chainId":61717561, 389 "homesteadBlock":0, 390 "eip150Block":0, 391 "eip150Hash":"0x0000000000000000000000000000000000000000000000000000000000000000" 392 }, 393 "nonce":"0x2a", 394 "timestamp":"0x0", 395 "extraData":"0x", 396 "gasLimit":"0x401640", 397 "difficulty":"0x5f5e0ff", 398 "mixHash":"0x0000000000000000000000000000000000000000000000000000000000000000", 399 "coinbase":"0x0000000000000000000000000000000000000000", 400 "alloc": 401 `)) 402 // Export the state 403 if err := statedb.TakeSnapshot(writer); err != nil { 404 return false, err 405 } 406 writer.Write([]byte("}")) 407 return true, nil 408 } 409 410 // ExportChain exports the current blockchain into a local file. 411 func (api *PrivateAdminAPI) ExportChain(file string) (bool, error) { 412 // Make sure we can create the file to export into 413 out, err := os.OpenFile(file, os.O_CREATE|os.O_WRONLY|os.O_TRUNC, os.ModePerm) 414 if err != nil { 415 return false, err 416 } 417 defer out.Close() 418 419 var writer io.Writer = out 420 if strings.HasSuffix(file, ".gz") { 421 writer = gzip.NewWriter(writer) 422 defer writer.(*gzip.Writer).Close() 423 } 424 425 // Export the blockchain 426 if err := api.aqua.BlockChain().Export(writer); err != nil { 427 return false, err 428 } 429 return true, nil 430 } 431 432 func hasAllBlocks(chain *core.BlockChain, bs []*types.Block) bool { 433 getversion := chain.Config().GetBlockVersion 434 log.Debug("iterating blocks", "count", len(bs)) 435 for _, b := range bs { 436 if !chain.HasBlock(b.SetVersion(getversion(b.Number())), b.NumberU64()) { 437 return false 438 } 439 } 440 return true 441 } 442 443 // ImportChain imports a blockchain from a local file. 444 func (api *PrivateAdminAPI) ImportChain(file string) (bool, error) { 445 // Make sure the can access the file to import 446 in, err := os.Open(file) 447 if err != nil { 448 return false, err 449 } 450 defer in.Close() 451 452 var reader io.Reader = in 453 if strings.HasSuffix(file, ".gz") { 454 if reader, err = gzip.NewReader(reader); err != nil { 455 return false, err 456 } 457 } 458 459 // Run actual the import in pre-configured batches 460 stream := rlp.NewStream(reader, 0) 461 462 blocks, index := make([]*types.Block, 0, 2500), 0 463 for batch := 0; ; batch++ { 464 // Load a batch of blocks from the input file 465 for len(blocks) < cap(blocks) { 466 block := new(types.Block) 467 if err := stream.Decode(block); err == io.EOF { 468 break 469 } else if err != nil { 470 return false, fmt.Errorf("block %d: failed to parse: %v", index, err) 471 } 472 blocks = append(blocks, block) 473 index++ 474 } 475 if len(blocks) == 0 { 476 break 477 } 478 479 if hasAllBlocks(api.aqua.BlockChain(), blocks) { 480 blocks = blocks[:0] 481 continue 482 } 483 // Import the batch and reset the buffer 484 if _, err := api.aqua.BlockChain().InsertChain(blocks); err != nil { 485 return false, fmt.Errorf("batch %d: failed to insert: %v", batch, err) 486 } 487 blocks = blocks[:0] 488 } 489 return true, nil 490 } 491 492 // PublicDebugAPI is the collection of Aquachain full node APIs exposed 493 // over the public debugging endpoint. 494 type PublicDebugAPI struct { 495 aqua *Aquachain 496 } 497 498 // NewPublicDebugAPI creates a new API definition for the full node- 499 // related public debug methods of the Aquachain service. 500 func NewPublicDebugAPI(aqua *Aquachain) *PublicDebugAPI { 501 return &PublicDebugAPI{aqua: aqua} 502 } 503 504 // DumpBlock retrieves the entire state of the database at a given block. 505 func (api *PublicDebugAPI) DumpBlock(blockNr rpc.BlockNumber) (state.Dump, error) { 506 if blockNr == rpc.PendingBlockNumber { 507 // If we're dumping the pending state, we need to request 508 // both the pending block as well as the pending state from 509 // the miner and operate on those 510 _, stateDb := api.aqua.miner.Pending() 511 return stateDb.RawDump(), nil 512 } 513 var block *types.Block 514 if blockNr == rpc.LatestBlockNumber { 515 block = api.aqua.blockchain.CurrentBlock() 516 } else { 517 block = api.aqua.blockchain.GetBlockByNumber(uint64(blockNr)) 518 } 519 if block == nil { 520 return state.Dump{}, fmt.Errorf("block #%d not found", blockNr) 521 } 522 stateDb, err := api.aqua.BlockChain().StateAt(block.Root()) 523 if err != nil { 524 return state.Dump{}, err 525 } 526 return stateDb.RawDump(), nil 527 } 528 529 // PrivateDebugAPI is the collection of Aquachain full node APIs exposed over 530 // the private debugging endpoint. 531 type PrivateDebugAPI struct { 532 config *params.ChainConfig 533 aqua *Aquachain 534 } 535 536 // NewPrivateDebugAPI creates a new API definition for the full node-related 537 // private debug methods of the Aquachain service. 538 func NewPrivateDebugAPI(config *params.ChainConfig, aqua *Aquachain) *PrivateDebugAPI { 539 return &PrivateDebugAPI{config: config, aqua: aqua} 540 } 541 542 // Preimage is a debug API function that returns the preimage for a sha3 hash, if known. 543 func (api *PrivateDebugAPI) Preimage(ctx context.Context, hash common.Hash) (hexutil.Bytes, error) { 544 db := core.PreimageTable(api.aqua.ChainDb()) 545 return db.Get(hash.Bytes()) 546 } 547 548 // GetBadBlocks returns a list of the last 'bad blocks' that the client has seen on the network 549 // and returns them as a JSON list of block-hashes 550 func (api *PrivateDebugAPI) GetBadBlocks(ctx context.Context) ([]core.BadBlockArgs, error) { 551 return api.aqua.BlockChain().BadBlocks() 552 } 553 554 // StorageRangeResult is the result of a debug_storageRangeAt API call. 555 type StorageRangeResult struct { 556 Storage storageMap `json:"storage"` 557 NextKey *common.Hash `json:"nextKey"` // nil if Storage includes the last key in the trie. 558 } 559 560 type storageMap map[common.Hash]storageEntry 561 562 type storageEntry struct { 563 Key *common.Hash `json:"key"` 564 Value common.Hash `json:"value"` 565 }