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