github.com/aergoio/aergo@v1.3.1/chain/chainservice.go (about) 1 /** 2 * @file 3 * @copyright defined in aergo/LICENSE.txt 4 */ 5 6 package chain 7 8 import ( 9 "encoding/json" 10 "errors" 11 "fmt" 12 "math/big" 13 "reflect" 14 "runtime" 15 "strings" 16 "sync/atomic" 17 18 "github.com/aergoio/aergo-actor/actor" 19 "github.com/aergoio/aergo-lib/log" 20 cfg "github.com/aergoio/aergo/config" 21 "github.com/aergoio/aergo/consensus" 22 "github.com/aergoio/aergo/contract" 23 "github.com/aergoio/aergo/contract/enterprise" 24 "github.com/aergoio/aergo/contract/name" 25 "github.com/aergoio/aergo/contract/system" 26 "github.com/aergoio/aergo/fee" 27 "github.com/aergoio/aergo/internal/enc" 28 "github.com/aergoio/aergo/message" 29 "github.com/aergoio/aergo/pkg/component" 30 "github.com/aergoio/aergo/state" 31 "github.com/aergoio/aergo/types" 32 lru "github.com/hashicorp/golang-lru" 33 ) 34 35 var ( 36 logger = log.NewLogger("chain") 37 38 dfltErrBlocks = 128 39 40 ErrNotSupportedConsensus = errors.New("not supported by this consensus") 41 ErrRecoNoBestStateRoot = errors.New("state root of best block is not exist") 42 ErrRecoInvalidSdbRoot = errors.New("state root of sdb is invalid") 43 44 TestDebugger *Debugger 45 ) 46 47 // Core represents a storage layer of a blockchain (chain & state DB). 48 type Core struct { 49 cdb *ChainDB 50 sdb *state.ChainStateDB 51 } 52 53 // NewCore returns an instance of Core. 54 func NewCore(dbType string, dataDir string, testModeOn bool, forceResetHeight types.BlockNo) (*Core, error) { 55 core := &Core{ 56 cdb: NewChainDB(), 57 sdb: state.NewChainStateDB(), 58 } 59 60 err := core.init(dbType, dataDir, testModeOn, forceResetHeight) 61 if err != nil { 62 return nil, err 63 } 64 65 return core, nil 66 } 67 68 // Init prepares Core (chain & state DB). 69 func (core *Core) init(dbType string, dataDir string, testModeOn bool, forceResetHeight types.BlockNo) error { 70 // init chaindb 71 if err := core.cdb.Init(dbType, dataDir); err != nil { 72 logger.Fatal().Err(err).Msg("failed to initialize chaindb") 73 return err 74 } 75 76 if forceResetHeight > 0 { 77 if err := core.cdb.ResetBest(forceResetHeight); err != nil { 78 logger.Fatal().Err(err).Uint64("height", forceResetHeight).Msg("failed to reset chaindb") 79 return err 80 } 81 } 82 83 // init statedb 84 bestBlock, err := core.cdb.GetBestBlock() 85 if err != nil { 86 return err 87 } 88 89 if err := core.sdb.Init(dbType, dataDir, bestBlock, testModeOn); err != nil { 90 logger.Fatal().Err(err).Msg("failed to initialize statedb") 91 return err 92 } 93 94 contract.LoadDatabase(dataDir) 95 96 return nil 97 } 98 99 func (core *Core) initGenesis(genesis *types.Genesis, mainnet bool, testmode bool) (*types.Block, error) { 100 101 gen := core.cdb.GetGenesisInfo() 102 if gen == nil { 103 logger.Info().Msg("generating genesis block..") 104 if testmode { 105 if !mainnet { 106 logger.Warn().Msg("--testnet opt will ignored due to testmode") 107 } 108 genesis = types.GetTestGenesis() 109 } else { 110 if genesis == nil { 111 if mainnet { 112 //return nil, errors.New("to use mainnet, create genesis manually (visit http://docs.aergo.io)") 113 genesis = types.GetMainNetGenesis() 114 } else { 115 genesis = types.GetTestNetGenesis() 116 } 117 } 118 } 119 120 err := core.sdb.SetGenesis(genesis, InitGenesisBPs) 121 if err != nil { 122 logger.Fatal().Err(err).Msg("cannot set statedb of genesisblock") 123 return nil, err 124 } 125 126 err = core.cdb.addGenesisBlock(genesis) 127 if err != nil { 128 logger.Fatal().Err(err).Msg("cannot add genesisblock") 129 return nil, err 130 } 131 gen = genesis 132 } else { 133 if !mainnet { 134 logger.Warn().Msg("--testnet option will be ignored") 135 } 136 if testmode && !gen.HasDevChainID() { 137 logger.Info().Str("chain id", gen.ID.ToJSON()).Msg("current genesis info") 138 return nil, errors.New("do not run testmode on non dev-chain") 139 } 140 } 141 142 initChainParams(gen) 143 144 genesisBlock, _ := core.cdb.GetBlockByNo(0) 145 146 logger.Info().Str("chain id", gen.ID.ToJSON()). 147 Str("hash", enc.ToString(genesisBlock.GetHash())).Msg("chain initialized") 148 return genesisBlock, nil 149 } 150 151 func (core *Core) GetGenesisInfo() *types.Genesis { 152 return core.cdb.GetGenesisInfo() 153 } 154 155 // Close closes chain & state DB. 156 func (core *Core) Close() { 157 if core.sdb != nil { 158 core.sdb.Close() 159 } 160 if core.cdb != nil { 161 core.cdb.Close() 162 } 163 contract.CloseDatabase() 164 } 165 166 // InitGenesisBlock initialize chain database and generate specified genesis block if necessary 167 func (core *Core) InitGenesisBlock(gb *types.Genesis, useTestnet bool) error { 168 _, err := core.initGenesis(gb, useTestnet, false) 169 if err != nil { 170 logger.Fatal().Err(err).Msg("cannot initialize genesis block") 171 return err 172 } 173 return nil 174 } 175 176 type IChainHandler interface { 177 getBlock(blockHash []byte) (*types.Block, error) 178 getBlockByNo(blockNo types.BlockNo) (*types.Block, error) 179 getTx(txHash []byte) (*types.Tx, *types.TxIdx, error) 180 getReceipt(txHash []byte) (*types.Receipt, error) 181 getAccountVote(id []string, addr []byte) (*types.AccountVoteInfo, error) 182 getVotes(id string, n uint32) (*types.VoteList, error) 183 getStaking(addr []byte) (*types.Staking, error) 184 getNameInfo(name string, blockNo types.BlockNo) (*types.NameInfo, error) 185 getEnterpriseConf(key string) (*types.EnterpriseConfig, error) 186 addBlock(newBlock *types.Block, usedBstate *state.BlockState, peerID types.PeerID) error 187 getAnchorsNew() (ChainAnchor, types.BlockNo, error) 188 findAncestor(Hashes [][]byte) (*types.BlockInfo, error) 189 setSkipMempool(val bool) 190 listEvents(filter *types.FilterInfo) ([]*types.Event, error) 191 verifyBlock(block *types.Block) error 192 } 193 194 // ChainService manage connectivity of blocks 195 type ChainService struct { 196 *component.BaseComponent 197 consensus.ChainConsensus 198 *Core 199 200 cfg *cfg.Config 201 op *OrphanPool 202 errBlocks *lru.Cache 203 204 validator *BlockValidator 205 206 chainWorker *ChainWorker 207 chainManager *ChainManager 208 chainVerifier *ChainVerifier 209 210 stat stats 211 212 recovered atomic.Value 213 debuggable bool 214 } 215 216 // NewChainService creates an instance of ChainService. 217 func NewChainService(cfg *cfg.Config) *ChainService { 218 cs := &ChainService{ 219 cfg: cfg, 220 op: NewOrphanPool(DfltOrphanPoolSize), 221 stat: newStats(), 222 } 223 224 cs.setRecovered(false) 225 226 var err error 227 if cs.Core, err = NewCore(cfg.DbType, cfg.DataDir, cfg.EnableTestmode, types.BlockNo(cfg.Blockchain.ForceResetHeight)); err != nil { 228 logger.Fatal().Err(err).Msg("failed to initialize DB") 229 panic(err) 230 } 231 232 if err = Init(cfg.Blockchain.MaxBlockSize, 233 cfg.Blockchain.CoinbaseAccount, 234 cfg.Consensus.EnableBp, 235 cfg.Blockchain.MaxAnchorCount, 236 cfg.Blockchain.VerifierCount); err != nil { 237 logger.Error().Err(err).Msg("failed to init chainservice") 238 panic("invalid config: blockchain") 239 } 240 241 cs.validator = NewBlockValidator(cs, cs.sdb) 242 cs.BaseComponent = component.NewBaseComponent(message.ChainSvc, cs, logger) 243 cs.chainManager = newChainManager(cs, cs.Core) 244 cs.chainWorker = newChainWorker(cs, defaultChainWorkerCount, cs.Core) 245 if cs.cfg.Blockchain.VerifyOnly { 246 if cs.cfg.Consensus.EnableBp { 247 logger.Fatal().Err(err).Msg("can't be enableBp at verifyOnly mode") 248 } 249 cs.chainVerifier = newChainVerifier(cs, cs.Core) 250 } 251 252 cs.errBlocks, err = lru.New(dfltErrBlocks) 253 if err != nil { 254 logger.Fatal().Err(err).Msg("failed to init lru") 255 return nil 256 } 257 258 // init genesis block 259 if _, err := cs.initGenesis(nil, !cfg.UseTestnet, cfg.EnableTestmode); err != nil { 260 logger.Fatal().Err(err).Msg("failed to create a genesis block") 261 panic("failed to init genesis block") 262 } 263 264 if ConsensusName() == consensus.ConsensusName[consensus.ConsensusDPOS] { 265 top, err := cs.getVotes(types.VoteBP[2:], 1) 266 if err != nil { 267 logger.Debug().Err(err).Msg("failed to get elected BPs") 268 } else { 269 for _, res := range top.Votes { 270 logger.Debug().Str("BP", enc.ToString(res.Candidate)). 271 Str("votes", new(big.Int).SetBytes(res.Amount).String()).Msgf("BP vote stat") 272 } 273 } 274 } 275 276 // init related modules 277 if !pubNet && cfg.Blockchain.ZeroFee { 278 fee.EnableZeroFee() 279 } 280 logger.Info().Bool("enablezerofee", fee.IsZeroFee()).Msg("fee") 281 contract.PubNet = pubNet 282 contract.TraceBlockNo = cfg.Blockchain.StateTrace 283 contract.SetStateSQLMaxDBSize(cfg.SQL.MaxDbSize) 284 contract.StartLStateFactory() 285 286 // For a strict governance transaction validation. 287 types.InitGovernance(cs.ConsensusType(), cs.IsPublic()) 288 system.InitGovernance(cs.ConsensusType()) 289 290 // init Debugger 291 cs.initDebugger() 292 293 cs.startChilds() 294 295 return cs 296 } 297 298 func (cs *ChainService) startChilds() { 299 if !cs.cfg.Blockchain.VerifyOnly { 300 cs.chainManager.Start() 301 cs.chainWorker.Start() 302 } else { 303 cs.chainVerifier.Start() 304 } 305 } 306 307 func (cs *ChainService) initDebugger() { 308 TestDebugger = newDebugger() 309 } 310 311 // SDB returns cs.sdb. 312 func (cs *ChainService) SDB() *state.ChainStateDB { 313 return cs.sdb 314 } 315 316 // CDB returns cs.sdb as a consensus.ChainDbReader. 317 func (cs *ChainService) CDB() consensus.ChainDB { 318 return cs.cdb 319 } 320 321 // CDB returns cs.sdb as a consensus.ChainDbReader. 322 func (cs *ChainService) WalDB() consensus.ChainWAL { 323 return cs.cdb 324 } 325 326 // GetConsensusInfo returns consensus-related information, which is different 327 // from consensus to consensus. 328 func (cs *ChainService) GetConsensusInfo() string { 329 if cs.ChainConsensus == nil { 330 return "" 331 } 332 333 return cs.Info() 334 } 335 336 func (cs *ChainService) GetChainStats() string { 337 return cs.stat.JSON() 338 } 339 340 //GetEnterpriseConfig return EnterpiseConfig. if the given key does not exist, fill EnterpriseConfig with only the key and return 341 func (cs *ChainService) GetEnterpriseConfig(key string) (*types.EnterpriseConfig, error) { 342 return cs.getEnterpriseConf(key) 343 } 344 345 func (cs *ChainService) GetSystemValue(key types.SystemValue) (*big.Int, error) { 346 return cs.getSystemValue(key) 347 } 348 349 // SetChainConsensus sets cs.cc to cc. 350 func (cs *ChainService) SetChainConsensus(cc consensus.ChainConsensus) { 351 cs.ChainConsensus = cc 352 cs.cdb.cc = cc 353 } 354 355 // BeforeStart initialize chain database and generate empty genesis block if necessary 356 func (cs *ChainService) BeforeStart() { 357 } 358 359 // AfterStart ... do nothing 360 func (cs *ChainService) AfterStart() { 361 } 362 363 // BeforeStop close chain database and stop BlockValidator 364 func (cs *ChainService) BeforeStop() { 365 cs.Close() 366 367 cs.chainManager.Stop() 368 cs.chainWorker.Stop() 369 370 cs.validator.Stop() 371 } 372 373 func (cs *ChainService) notifyBlock(block *types.Block, isByBP bool) { 374 cs.BaseComponent.RequestTo(message.P2PSvc, 375 &message.NotifyNewBlock{ 376 Produced: isByBP, 377 BlockNo: block.Header.BlockNo, 378 Block: block, 379 }) 380 } 381 382 func (cs *ChainService) setRecovered(val bool) { 383 cs.recovered.Store(val) 384 return 385 } 386 387 func (cs *ChainService) isRecovered() bool { 388 var val bool 389 aopv := cs.recovered.Load() 390 if aopv != nil { 391 val = aopv.(bool) 392 } else { 393 panic("ChainService: recovered is nil") 394 } 395 return val 396 } 397 398 // Receive actor message 399 func (cs *ChainService) Receive(context actor.Context) { 400 if !cs.isRecovered() { 401 err := cs.Recover() 402 if err != nil { 403 logger.Fatal().Err(err).Msg("CHAIN DATA IS CRASHED, BUT CAN'T BE RECOVERED") 404 } 405 406 cs.setRecovered(true) 407 } 408 409 switch msg := context.Message().(type) { 410 case *message.AddBlock, 411 *message.GetAnchors, //TODO move to ChainWorker (need chain lock) 412 *message.GetAncestor: 413 cs.chainManager.Request(msg, context.Sender()) 414 415 //pass to chainWorker 416 case *message.GetBlock, 417 *message.GetBlockByNo, 418 *message.GetState, 419 *message.GetStateAndProof, 420 *message.GetTx, 421 *message.GetReceipt, 422 *message.GetABI, 423 *message.GetQuery, 424 *message.GetStateQuery, 425 *message.GetElected, 426 *message.GetVote, 427 *message.GetStaking, 428 *message.GetNameInfo, 429 *message.GetEnterpriseConf, 430 *message.ListEvents: 431 cs.chainWorker.Request(msg, context.Sender()) 432 433 //handle directly 434 case *message.GetBestBlockNo: 435 context.Respond(message.GetBestBlockNoRsp{ 436 BlockNo: cs.getBestBlockNo(), 437 }) 438 case *message.GetBestBlock: 439 block, err := cs.GetBestBlock() 440 if err != nil { 441 logger.Error().Err(err).Msg("failed to get best block") 442 } 443 context.Respond(message.GetBestBlockRsp{ 444 Block: block, 445 Err: err, 446 }) 447 case *message.MemPoolDelRsp: 448 err := msg.Err 449 if err != nil { 450 logger.Error().Err(err).Msg("failed to remove txs from mempool") 451 } 452 case actor.SystemMessage, 453 actor.AutoReceiveMessage, 454 actor.NotInfluenceReceiveTimeout: 455 //logger.Debugf("Received message. (%v) %s", reflect.TypeOf(msg), msg) 456 457 default: 458 //logger.Debugf("Missed message. (%v) %s", reflect.TypeOf(msg), msg) 459 } 460 } 461 462 func (cs *ChainService) Statistics() *map[string]interface{} { 463 if cs.chainVerifier != nil { 464 return cs.chainVerifier.Statistics() 465 } 466 return &map[string]interface{}{ 467 "testmode": cs.cfg.EnableTestmode, 468 "testnet": cs.cfg.UseTestnet, 469 "orphan": cs.op.curCnt, 470 "config": cs.cfg.Blockchain, 471 } 472 } 473 474 func (cs *ChainService) GetChainTree() ([]byte, error) { 475 return cs.cdb.GetChainTree() 476 } 477 478 func (cs *ChainService) getVotes(id string, n uint32) (*types.VoteList, error) { 479 switch ConsensusName() { 480 case consensus.ConsensusName[consensus.ConsensusDPOS]: 481 return system.GetVoteResult(cs.sdb, []byte(id), int(n)) 482 case consensus.ConsensusName[consensus.ConsensusRAFT]: 483 //return cs.GetBPs() 484 return nil, ErrNotSupportedConsensus 485 default: 486 return nil, ErrNotSupportedConsensus 487 } 488 } 489 490 func (cs *ChainService) getAccountVote(ids []string, addr []byte) (*types.AccountVoteInfo, error) { 491 if cs.GetType() != consensus.ConsensusDPOS { 492 return nil, ErrNotSupportedConsensus 493 } 494 495 scs, err := cs.sdb.GetSystemAccountState() 496 if err != nil { 497 return nil, err 498 } 499 500 var voteInfo types.AccountVoteInfo 501 502 for _, id := range ids { 503 vote, err := system.GetVote(scs, addr, []byte(id)) 504 if err != nil { 505 return nil, err 506 } 507 var candidates []string 508 to := vote.GetCandidate() 509 if len(to) == 0 { 510 continue 511 } 512 if id == types.VoteBP[2:] { 513 for offset := 0; offset < len(to); offset += system.PeerIDLength { 514 candidates = append(candidates, types.EncodeB58(to[offset:offset+system.PeerIDLength])) 515 } 516 } else { 517 err := json.Unmarshal(to, &candidates) 518 if err != nil { 519 return nil, err 520 } 521 } 522 voteInfo.Voting = append(voteInfo.Voting, &types.VoteInfo{Id: id, Candidates: candidates}) 523 } 524 525 return &voteInfo, nil 526 } 527 528 func (cs *ChainService) getStaking(addr []byte) (*types.Staking, error) { 529 if cs.GetType() != consensus.ConsensusDPOS { 530 return nil, ErrNotSupportedConsensus 531 } 532 533 scs, err := cs.sdb.GetStateDB().OpenContractStateAccount(types.ToAccountID([]byte(types.AergoSystem))) 534 if err != nil { 535 return nil, err 536 } 537 namescs, err := cs.sdb.GetStateDB().OpenContractStateAccount(types.ToAccountID([]byte(types.AergoName))) 538 if err != nil { 539 return nil, err 540 } 541 staking, err := system.GetStaking(scs, name.GetAddress(namescs, addr)) 542 if err != nil { 543 return nil, err 544 } 545 return staking, nil 546 } 547 548 func (cs *ChainService) getNameInfo(qname string, blockNo types.BlockNo) (*types.NameInfo, error) { 549 var stateDB *state.StateDB 550 if blockNo != 0 { 551 block, err := cs.cdb.GetBlockByNo(blockNo) 552 if err != nil { 553 return nil, err 554 } 555 stateDB = cs.sdb.OpenNewStateDB(block.GetHeader().GetBlocksRootHash()) 556 } else { 557 stateDB = cs.sdb.GetStateDB() 558 } 559 return name.GetNameInfo(stateDB, qname) 560 } 561 562 func (cs *ChainService) getEnterpriseConf(key string) (*types.EnterpriseConfig, error) { 563 stateDB := cs.sdb.GetStateDB() 564 if strings.ToUpper(key) != enterprise.AdminsKey { 565 return enterprise.GetConf(stateDB, key) 566 } 567 return enterprise.GetAdmin(stateDB) 568 } 569 570 func (cs *ChainService) getSystemValue(key types.SystemValue) (*big.Int, error) { 571 stateDB := cs.sdb.GetStateDB() 572 switch key { 573 case types.StakingTotal: 574 return system.GetStakingTotal(stateDB) 575 } 576 return nil, fmt.Errorf("unsupported system value : %s", key) 577 } 578 579 type ChainManager struct { 580 *SubComponent 581 IChainHandler //to use chain APIs 582 *Core // TODO remove after moving GetQuery to ChainWorker 583 } 584 585 type ChainWorker struct { 586 *SubComponent 587 IChainHandler //to use chain APIs 588 *Core 589 } 590 591 var ( 592 chainManagerName = "Chain Manager" 593 chainWorkerName = "Chain Worker" 594 chainVerifierName = "Chain Verifier" 595 ) 596 597 func newChainManager(cs *ChainService, core *Core) *ChainManager { 598 chainManager := &ChainManager{IChainHandler: cs, Core: core} 599 chainManager.SubComponent = NewSubComponent(chainManager, cs.BaseComponent, chainManagerName, 1) 600 601 return chainManager 602 } 603 604 func newChainWorker(cs *ChainService, cntWorker int, core *Core) *ChainWorker { 605 chainWorker := &ChainWorker{IChainHandler: cs, Core: core} 606 chainWorker.SubComponent = NewSubComponent(chainWorker, cs.BaseComponent, chainWorkerName, cntWorker) 607 608 return chainWorker 609 } 610 611 func (cm *ChainManager) Receive(context actor.Context) { 612 defer RecoverExit() 613 614 switch msg := context.Message().(type) { 615 616 case *message.AddBlock: 617 runtime.LockOSThread() 618 defer runtime.UnlockOSThread() 619 620 block := msg.Block 621 logger.Info().Str("hash", block.ID()).Str("prev", block.PrevID()).Uint64("bestno", cm.cdb.getBestBlockNo()). 622 Uint64("no", block.GetHeader().GetBlockNo()).Bool("syncer", msg.IsSync).Msg("add block chainservice") 623 624 var bstate *state.BlockState 625 if msg.Bstate != nil { 626 bstate = msg.Bstate.(*state.BlockState) 627 } 628 err := cm.addBlock(block, bstate, msg.PeerID) 629 if err != nil { 630 logger.Error().Err(err).Uint64("no", block.GetHeader().BlockNo).Str("hash", block.ID()).Msg("failed to add block") 631 } 632 blkNo := block.GetHeader().GetBlockNo() 633 blkHash := block.BlockHash() 634 635 rsp := message.AddBlockRsp{ 636 BlockNo: blkNo, 637 BlockHash: blkHash, 638 Err: err, 639 } 640 641 context.Respond(&rsp) 642 case *message.GetAnchors: 643 anchor, lastNo, err := cm.getAnchorsNew() 644 context.Respond(message.GetAnchorsRsp{ 645 Seq: msg.Seq, 646 Hashes: anchor, 647 LastNo: lastNo, 648 Err: err, 649 }) 650 case *message.GetAncestor: 651 hashes := msg.Hashes 652 ancestor, err := cm.findAncestor(hashes) 653 context.Respond(message.GetAncestorRsp{ 654 Ancestor: ancestor, 655 Err: err, 656 }) 657 case *actor.Started, *actor.Stopping, *actor.Stopped, *component.CompStatReq: // donothing 658 default: 659 debug := fmt.Sprintf("[%s] Missed message. (%v) %s", cm.name, reflect.TypeOf(msg), msg) 660 logger.Debug().Msg(debug) 661 } 662 } 663 664 func getAddressNameResolved(sdb *state.ChainStateDB, account []byte) ([]byte, error) { 665 if len(account) == types.NameLength { 666 scs, err := sdb.GetStateDB().OpenContractStateAccount(types.ToAccountID([]byte(types.AergoName))) 667 if err != nil { 668 logger.Error().Str("hash", enc.ToString(account)).Err(err).Msg("failed to get state for account") 669 return nil, err 670 } 671 return name.GetAddress(scs, account), nil 672 } 673 return account, nil 674 } 675 676 func (cw *ChainWorker) Receive(context actor.Context) { 677 switch msg := context.Message().(type) { 678 case *message.GetBlock: 679 bid := types.ToBlockID(msg.BlockHash) 680 block, err := cw.getBlock(bid[:]) 681 if err != nil { 682 logger.Debug().Err(err).Str("hash", enc.ToString(msg.BlockHash)).Msg("block not found") 683 } 684 context.Respond(message.GetBlockRsp{ 685 Block: block, 686 Err: err, 687 }) 688 case *message.GetBlockByNo: 689 block, err := cw.getBlockByNo(msg.BlockNo) 690 if err != nil { 691 logger.Error().Err(err).Uint64("blockNo", msg.BlockNo).Msg("failed to get block by no") 692 } 693 context.Respond(message.GetBlockByNoRsp{ 694 Block: block, 695 Err: err, 696 }) 697 case *message.GetState: 698 address, err := getAddressNameResolved(cw.sdb, msg.Account) 699 if err != nil { 700 context.Respond(message.GetStateRsp{ 701 Account: msg.Account, 702 State: nil, 703 Err: err, 704 }) 705 return 706 } 707 id := types.ToAccountID(address) 708 accState, err := cw.sdb.GetStateDB().GetAccountState(id) 709 if err != nil { 710 logger.Error().Str("hash", enc.ToString(address)).Err(err).Msg("failed to get state for account") 711 } 712 context.Respond(message.GetStateRsp{ 713 Account: address, 714 State: accState, 715 Err: err, 716 }) 717 case *message.GetStateAndProof: 718 address, err := getAddressNameResolved(cw.sdb, msg.Account) 719 if err != nil { 720 context.Respond(message.GetStateAndProofRsp{ 721 StateProof: nil, 722 Err: err, 723 }) 724 break 725 } 726 id := types.ToAccountID(address) 727 stateProof, err := cw.sdb.GetStateDB().GetAccountAndProof(id[:], msg.Root, msg.Compressed) 728 if err != nil { 729 logger.Error().Str("hash", enc.ToString(address)).Err(err).Msg("failed to get state for account") 730 } 731 stateProof.Key = address 732 context.Respond(message.GetStateAndProofRsp{ 733 StateProof: stateProof, 734 Err: err, 735 }) 736 case *message.GetTx: 737 tx, txIdx, err := cw.getTx(msg.TxHash) 738 context.Respond(message.GetTxRsp{ 739 Tx: tx, 740 TxIds: txIdx, 741 Err: err, 742 }) 743 case *message.GetReceipt: 744 receipt, err := cw.getReceipt(msg.TxHash) 745 context.Respond(message.GetReceiptRsp{ 746 Receipt: receipt, 747 Err: err, 748 }) 749 case *message.GetABI: 750 address, err := getAddressNameResolved(cw.sdb, msg.Contract) 751 if err != nil { 752 context.Respond(message.GetABIRsp{ 753 ABI: nil, 754 Err: err, 755 }) 756 break 757 } 758 contractState, err := cw.sdb.GetStateDB().OpenContractStateAccount(types.ToAccountID(address)) 759 if err == nil { 760 abi, err := contract.GetABI(contractState) 761 context.Respond(message.GetABIRsp{ 762 ABI: abi, 763 Err: err, 764 }) 765 } else { 766 context.Respond(message.GetABIRsp{ 767 ABI: nil, 768 Err: err, 769 }) 770 } 771 case *message.GetQuery: 772 runtime.LockOSThread() 773 defer runtime.UnlockOSThread() 774 address, err := getAddressNameResolved(cw.sdb, msg.Contract) 775 if err != nil { 776 context.Respond(message.GetQueryRsp{Result: nil, Err: err}) 777 break 778 } 779 ctrState, err := cw.sdb.GetStateDB().OpenContractStateAccount(types.ToAccountID(address)) 780 if err != nil { 781 logger.Error().Str("hash", enc.ToString(address)).Err(err).Msg("failed to get state for contract") 782 context.Respond(message.GetQueryRsp{Result: nil, Err: err}) 783 } else { 784 bs := state.NewBlockState(cw.sdb.OpenNewStateDB(cw.sdb.GetRoot())) 785 ret, err := contract.Query(address, bs, cw.cdb, ctrState, msg.Queryinfo) 786 context.Respond(message.GetQueryRsp{Result: ret, Err: err}) 787 } 788 case *message.GetStateQuery: 789 var varProofs []*types.ContractVarProof 790 var contractProof *types.AccountProof 791 var err error 792 793 address, err := getAddressNameResolved(cw.sdb, msg.ContractAddress) 794 if err != nil { 795 context.Respond(message.GetStateQueryRsp{ 796 Result: nil, 797 Err: err, 798 }) 799 break 800 } 801 id := types.ToAccountID(address) 802 contractProof, err = cw.sdb.GetStateDB().GetAccountAndProof(id[:], msg.Root, msg.Compressed) 803 if err != nil { 804 logger.Error().Str("hash", enc.ToString(address)).Err(err).Msg("failed to get state for account") 805 } else if contractProof.Inclusion { 806 contractTrieRoot := contractProof.State.StorageRoot 807 for _, storageKey := range msg.StorageKeys { 808 varProof, err := cw.sdb.GetStateDB().GetVarAndProof(storageKey, contractTrieRoot, msg.Compressed) 809 varProof.Key = storageKey 810 varProofs = append(varProofs, varProof) 811 if err != nil { 812 logger.Error().Str("hash", enc.ToString(address)).Err(err).Msg("failed to get state variable in contract") 813 } 814 } 815 } 816 contractProof.Key = address 817 stateQuery := &types.StateQueryProof{ 818 ContractProof: contractProof, 819 VarProofs: varProofs, 820 } 821 context.Respond(message.GetStateQueryRsp{ 822 Result: stateQuery, 823 Err: err, 824 }) 825 case *message.GetElected: 826 top, err := cw.getVotes(msg.Id, msg.N) 827 context.Respond(&message.GetVoteRsp{ 828 Top: top, 829 Err: err, 830 }) 831 case *message.GetVote: 832 info, err := cw.getAccountVote(msg.Ids, msg.Addr) 833 context.Respond(&message.GetAccountVoteRsp{ 834 Info: info, 835 Err: err, 836 }) 837 case *message.GetStaking: 838 staking, err := cw.getStaking(msg.Addr) 839 context.Respond(&message.GetStakingRsp{ 840 Staking: staking, 841 Err: err, 842 }) 843 case *message.GetNameInfo: 844 owner, err := cw.getNameInfo(msg.Name, msg.BlockNo) 845 context.Respond(&message.GetNameInfoRsp{ 846 Owner: owner, 847 Err: err, 848 }) 849 case *message.GetEnterpriseConf: 850 conf, err := cw.getEnterpriseConf(msg.Key) 851 context.Respond(&message.GetEnterpriseConfRsp{ 852 Conf: conf, 853 Err: err, 854 }) 855 case *message.ListEvents: 856 events, err := cw.listEvents(msg.Filter) 857 context.Respond(&message.ListEventsRsp{ 858 Events: events, 859 Err: err, 860 }) 861 862 case *actor.Started, *actor.Stopping, *actor.Stopped, *component.CompStatReq: // donothing 863 default: 864 debug := fmt.Sprintf("[%s] Missed message. (%v) %s", cw.name, reflect.TypeOf(msg), msg) 865 logger.Debug().Msg(debug) 866 } 867 } 868 869 func (cs *ChainService) ConsensusType() string { 870 return cs.GetGenesisInfo().ConsensusType() 871 } 872 873 func (cs *ChainService) IsPublic() bool { 874 return cs.GetGenesisInfo().PublicNet() 875 }