github.com/fibonacci-chain/fbc@v0.0.0-20231124064014-c7636198c1e9/x/evm/watcher/querier.go (about) 1 package watcher 2 3 import ( 4 "encoding/hex" 5 "encoding/json" 6 "errors" 7 "github.com/ethereum/go-ethereum/common/hexutil" 8 clientcontext "github.com/fibonacci-chain/fbc/libs/cosmos-sdk/client/context" 9 "strconv" 10 "sync" 11 12 prototypes "github.com/fibonacci-chain/fbc/x/evm/watcher/proto" 13 "github.com/gogo/protobuf/proto" 14 15 "github.com/ethereum/go-ethereum/common" 16 ethtypes "github.com/ethereum/go-ethereum/core/types" 17 "github.com/fibonacci-chain/fbc/app/rpc/namespaces/eth/state" 18 "github.com/fibonacci-chain/fbc/app/types" 19 sdk "github.com/fibonacci-chain/fbc/libs/cosmos-sdk/types" 20 evmtypes "github.com/fibonacci-chain/fbc/x/evm/types" 21 lru "github.com/hashicorp/golang-lru" 22 ) 23 24 const MsgFunctionDisable = "fast query function has been disabled" 25 26 var errNotFound = errors.New("leveldb: not found") 27 var errDisable = errors.New(MsgFunctionDisable) 28 29 const hashPrefixKeyLen = 33 30 31 var hashPrefixKeyPool = &sync.Pool{ 32 New: func() interface{} { 33 return &[hashPrefixKeyLen]byte{} 34 }, 35 } 36 37 func getHashPrefixKey(prefix []byte, hash []byte) ([]byte, error) { 38 if len(prefix)+len(hash) > hashPrefixKeyLen { 39 return nil, errors.New("invalid prefix or hash len") 40 } 41 key := hashPrefixKeyPool.Get().(*[hashPrefixKeyLen]byte) 42 copy(key[:], prefix) 43 copy(key[len(prefix):], hash) 44 return key[:len(prefix)+len(hash)], nil 45 } 46 47 func putHashPrefixKey(key []byte) { 48 hashPrefixKeyPool.Put((*[hashPrefixKeyLen]byte)(key[:hashPrefixKeyLen])) 49 } 50 51 type Querier struct { 52 store *WatchStore 53 sw bool 54 lru *lru.Cache 55 } 56 57 func (q Querier) enabled() bool { 58 return q.sw 59 } 60 61 func (q *Querier) Enable(sw bool) { 62 q.sw = sw 63 } 64 65 func NewQuerier() *Querier { 66 lru, e := lru.New(GetWatchLruSize()) 67 if e != nil { 68 panic(errors.New("Failed to init LRU Cause " + e.Error())) 69 } 70 return &Querier{store: InstanceOfWatchStore(), sw: IsWatcherEnabled(), lru: lru} 71 } 72 73 func (q Querier) GetTransactionReceipt(hash common.Hash) (*TransactionReceipt, error) { 74 if !q.enabled() { 75 return nil, errDisable 76 } 77 var protoReceipt prototypes.TransactionReceipt 78 b, e := q.store.Get(append(prefixReceipt, hash.Bytes()...)) 79 if e != nil { 80 return nil, e 81 } 82 if b == nil { 83 return nil, errNotFound 84 } 85 e = proto.Unmarshal(b, &protoReceipt) 86 if e != nil { 87 return nil, e 88 } 89 receipt := protoToReceipt(&protoReceipt) 90 return receipt, nil 91 } 92 93 func (q Querier) GetTransactionResponse(hash common.Hash) (*TransactionResponse, error) { 94 if !q.enabled() { 95 return nil, errors.New(MsgFunctionDisable) 96 } 97 var response TransactionResponse 98 b, e := q.store.Get(append(prefixTxResponse, hash.Bytes()...)) 99 if e != nil { 100 return nil, e 101 } 102 if b == nil { 103 return nil, errNotFound 104 } 105 e = json.Unmarshal(b, &response) 106 if e != nil { 107 return nil, e 108 } 109 110 return &response, nil 111 } 112 113 func (q Querier) GetBlockByHash(hash common.Hash, fullTx bool) (*Block, error) { 114 if !q.enabled() { 115 return nil, errDisable 116 } 117 var block Block 118 var err error 119 var blockHashKey []byte 120 if blockHashKey, err = getHashPrefixKey(prefixBlock, hash.Bytes()); err != nil { 121 blockHashKey = append(prefixBlock, hash.Bytes()...) 122 } else { 123 defer putHashPrefixKey(blockHashKey) 124 } 125 126 _, err = q.store.GetUnsafe(blockHashKey, func(value []byte) (interface{}, error) { 127 if value == nil { 128 return nil, errNotFound 129 } 130 e := json.Unmarshal(value, &block) 131 if e != nil { 132 return nil, e 133 } 134 return nil, nil 135 }) 136 if err != nil { 137 return nil, err 138 } 139 140 if fullTx && block.Transactions != nil { 141 txsHash := block.Transactions.([]interface{}) 142 txList := make([]*Transaction, 0, len(txsHash)) 143 for _, tx := range txsHash { 144 transaction, e := q.GetTransactionByHash(common.HexToHash(tx.(string))) 145 if e == nil && transaction != nil { 146 txList = append(txList, transaction) 147 } 148 } 149 block.Transactions = txList 150 } 151 block.UncleHash = ethtypes.EmptyUncleHash 152 block.ReceiptsRoot = ethtypes.EmptyRootHash 153 154 return &block, nil 155 } 156 157 func (q Querier) GetBlockHashByNumber(number uint64) (common.Hash, error) { 158 if !q.enabled() { 159 return common.Hash{}, errDisable 160 } 161 var height = number 162 var err error 163 if height == 0 { 164 height, err = q.GetLatestBlockNumber() 165 if err != nil { 166 return common.Hash{}, err 167 } 168 } 169 hash, e := q.store.Get(append(prefixBlockInfo, []byte(strconv.Itoa(int(height)))...)) 170 if e != nil { 171 return common.Hash{}, e 172 } 173 if hash == nil { 174 return common.Hash{}, errNotFound 175 } 176 return common.HexToHash(string(hash)), e 177 } 178 179 func (q Querier) GetBlockByNumber(number uint64, fullTx bool) (*Block, error) { 180 if !q.enabled() { 181 return nil, errDisable 182 } 183 var height = number 184 var err error 185 if height == 0 { 186 height, err = q.GetLatestBlockNumber() 187 if err != nil { 188 return nil, err 189 } 190 } 191 hash, e := q.store.Get(append(prefixBlockInfo, []byte(strconv.Itoa(int(height)))...)) 192 if e != nil { 193 return nil, e 194 } 195 if hash == nil { 196 return nil, errNotFound 197 } 198 199 return q.GetBlockByHash(common.HexToHash(string(hash)), fullTx) 200 } 201 202 func (q Querier) GetCode(contractAddr common.Address, height uint64) ([]byte, error) { 203 if !q.enabled() { 204 return nil, errDisable 205 } 206 var codeInfo CodeInfo 207 info, e := q.store.Get(append(prefixCode, contractAddr.Bytes()...)) 208 if e != nil { 209 return nil, e 210 } 211 if info == nil { 212 return nil, errNotFound 213 } 214 215 e = json.Unmarshal(info, &codeInfo) 216 if e != nil { 217 return nil, e 218 } 219 if height < codeInfo.Height && height > 0 { 220 return nil, errors.New("the target height has not deploy this contract yet") 221 } 222 return hex.DecodeString(codeInfo.Code) 223 } 224 225 func (q Querier) GetCodeByHash(codeHash []byte) ([]byte, error) { 226 if !q.enabled() { 227 return nil, errDisable 228 } 229 cacheCode, ok := q.lru.Get(common.BytesToHash(codeHash)) 230 if ok { 231 data, ok := cacheCode.([]byte) 232 if ok { 233 return data, nil 234 } 235 } 236 code, e := q.store.Get(append(prefixCodeHash, codeHash...)) 237 if e != nil { 238 return nil, e 239 } 240 if code == nil { 241 return nil, errNotFound 242 } 243 q.lru.Add(common.BytesToHash(codeHash), code) 244 return code, nil 245 } 246 247 func (q Querier) GetLatestBlockNumber() (uint64, error) { 248 if !q.enabled() { 249 return 0, errDisable 250 } 251 height, e := q.store.Get(keyLatestBlockHeight) 252 if e != nil { 253 return 0, e 254 } 255 if height == nil { 256 return 0, errNotFound 257 } 258 h, e := strconv.Atoi(string(height)) 259 return uint64(h), e 260 } 261 262 func (q Querier) GetTransactionByHash(hash common.Hash) (*Transaction, error) { 263 if !q.enabled() { 264 return nil, errDisable 265 } 266 var protoTx prototypes.Transaction 267 var txHashKey []byte 268 var err error 269 if txHashKey, err = getHashPrefixKey(prefixTx, hash.Bytes()); err != nil { 270 txHashKey = append(prefixTx, hash.Bytes()...) 271 } else { 272 defer putHashPrefixKey(txHashKey) 273 } 274 275 _, err = q.store.GetUnsafe(txHashKey, func(value []byte) (interface{}, error) { 276 if value == nil { 277 return nil, errNotFound 278 } 279 e := proto.Unmarshal(value, &protoTx) 280 if e != nil { 281 return nil, e 282 } 283 return nil, nil 284 }) 285 if err != nil { 286 return nil, err 287 } 288 tx := protoToTransaction(&protoTx) 289 return tx, nil 290 } 291 292 func (q Querier) GetTransactionByBlockNumberAndIndex(number uint64, idx uint) (*Transaction, error) { 293 if !q.enabled() { 294 return nil, errDisable 295 } 296 block, e := q.GetBlockByNumber(number, true) 297 if e != nil { 298 return nil, e 299 } 300 return q.getTransactionByBlockAndIndex(block, idx) 301 } 302 303 func (q Querier) GetTransactionByBlockHashAndIndex(hash common.Hash, idx uint) (*Transaction, error) { 304 if !q.enabled() { 305 return nil, errDisable 306 } 307 block, e := q.GetBlockByHash(hash, true) 308 if e != nil { 309 return nil, e 310 } 311 return q.getTransactionByBlockAndIndex(block, idx) 312 } 313 314 func (q Querier) getTransactionByBlockAndIndex(block *Block, idx uint) (*Transaction, error) { 315 if block.Transactions == nil { 316 return nil, errors.New("no such transaction in target block") 317 } 318 txs, ok := block.Transactions.([]*Transaction) 319 if ok { 320 for _, tx := range txs { 321 rawTx := *tx 322 if idx == uint(*rawTx.TransactionIndex) { 323 return &rawTx, nil 324 } 325 } 326 } 327 return nil, errors.New("no such transaction in target block") 328 } 329 330 func (q Querier) GetTransactionsByBlockNumber(number, offset, limit uint64) ([]*Transaction, error) { 331 if !q.enabled() { 332 return nil, errDisable 333 } 334 block, err := q.GetBlockByNumber(number, true) 335 if err != nil { 336 return nil, err 337 } 338 if block.Transactions == nil { 339 return nil, errors.New("no such transaction in target block") 340 } 341 342 rawTxs, ok := block.Transactions.([]*Transaction) 343 if ok { 344 var txs []*Transaction 345 for idx := offset; idx < offset+limit && int(idx) < len(rawTxs); idx++ { 346 rawTx := *rawTxs[idx] 347 txs = append(txs, &rawTx) 348 } 349 return txs, nil 350 } 351 return nil, errors.New("no such transaction in target block") 352 } 353 354 func (q Querier) GetTxResultByBlock(clientCtx clientcontext.CLIContext, 355 height, offset, limit uint64) ([]*TransactionResult, error) { 356 if !q.enabled() { 357 return nil, errors.New(MsgFunctionDisable) 358 } 359 360 // get block hash 361 rawBlockHash, err := q.store.Get(append(prefixBlockInfo, []byte(strconv.Itoa(int(height)))...)) 362 if err != nil { 363 return nil, err 364 } 365 if rawBlockHash == nil { 366 return nil, errNotFound 367 } 368 369 blockHash := common.HexToHash(string(rawBlockHash)) 370 371 // get block by hash 372 var block Block 373 var blockHashKey []byte 374 if blockHashKey, err = getHashPrefixKey(prefixBlock, blockHash.Bytes()); err != nil { 375 blockHashKey = append(prefixBlock, blockHash.Bytes()...) 376 } else { 377 defer putHashPrefixKey(blockHashKey) 378 } 379 380 _, err = q.store.GetUnsafe(blockHashKey, func(value []byte) (interface{}, error) { 381 if value == nil { 382 return nil, errNotFound 383 } 384 e := json.Unmarshal(value, &block) 385 if e != nil { 386 return nil, e 387 } 388 return nil, nil 389 }) 390 if err != nil { 391 return nil, err 392 } 393 394 results := make([]*TransactionResult, 0, limit) 395 var ethStart, ethEnd, ethTxLen uint64 396 397 // get result from eth tx 398 if block.Transactions != nil { 399 txsHash := block.Transactions.([]interface{}) 400 ethTxLen = uint64(len(txsHash)) 401 402 if offset < ethTxLen { 403 ethStart = offset 404 if ethEnd = ethStart + limit; ethEnd > ethTxLen { 405 ethEnd = ethTxLen 406 } 407 } 408 409 for i := ethStart; i < ethEnd; i++ { 410 txHash := common.HexToHash(txsHash[i].(string)) 411 //Get Eth Tx 412 tx, err := q.GetTransactionByHash(txHash) 413 if err != nil { 414 return nil, err 415 } 416 //Get Eth Receipt 417 receipt, err := q.GetTransactionReceipt(txHash) 418 if err != nil { 419 return nil, err 420 } 421 422 var txLog string 423 txResult, err := q.GetTransactionResponse(txHash) 424 if err == nil { 425 txLog = txResult.TxResult.Log 426 } 427 428 r := &TransactionResult{TxType: hexutil.Uint64(EthReceipt), EthTx: tx, Receipt: receipt, 429 EthTxLog: txLog} 430 results = append(results, r) 431 } 432 } 433 434 // enough Tx by Eth 435 ethTxNums := ethEnd - ethStart 436 if ethTxNums == limit { 437 return results, nil 438 } 439 // calc remain std txs 440 remainTxs := limit - ethTxNums 441 // get result from Std tx 442 var stdTxsHash []common.Hash 443 b, err := q.store.Get(append(prefixStdTxHash, blockHash.Bytes()...)) 444 if err != nil { 445 return nil, err 446 } 447 448 if b == nil { 449 return results, nil 450 451 } 452 err = json.Unmarshal(b, &stdTxsHash) 453 if err != nil { 454 return nil, err 455 } 456 457 if stdTxsHash != nil && len(stdTxsHash) != 0 { 458 stdTxsLen := uint64(len(stdTxsHash)) 459 var stdStart, stdEnd uint64 460 stdStart = offset + ethTxNums - ethTxLen 461 if stdEnd = stdStart + remainTxs; stdEnd > stdTxsLen { 462 stdEnd = stdTxsLen 463 } 464 465 for i := stdStart; i < stdEnd; i++ { 466 stdResponse, err := q.GetTransactionResponse(stdTxsHash[i]) 467 if err != nil { 468 return nil, err 469 } 470 471 res, err := RawTxResultToStdResponse(clientCtx, stdResponse.ResultTx, nil, stdResponse.Timestamp) 472 if err != nil { 473 return nil, err 474 } 475 results = append(results, res) 476 } 477 } 478 479 return results, nil 480 } 481 482 func (q Querier) MustGetAccount(addr sdk.AccAddress) (*types.EthAccount, error) { 483 acc, e := q.GetAccount(addr) 484 //todo delete account from rdb if we get Account from H db successfully 485 if e != nil { 486 acc, e = q.GetAccountFromRdb(addr) 487 } else { 488 q.DeleteAccountFromRdb(addr) 489 } 490 return acc, e 491 } 492 493 func (q Querier) GetAccount(addr sdk.AccAddress) (*types.EthAccount, error) { 494 if !q.enabled() { 495 return nil, errDisable 496 } 497 b, e := q.store.Get([]byte(GetMsgAccountKey(addr.Bytes()))) 498 if e != nil { 499 return nil, e 500 } 501 if b == nil { 502 return nil, errNotFound 503 } 504 acc, err := DecodeAccount(b) 505 if err != nil { 506 return nil, e 507 } 508 return acc, nil 509 } 510 511 func (q Querier) GetAccountFromRdb(addr sdk.AccAddress) (*types.EthAccount, error) { 512 if !q.enabled() { 513 return nil, errDisable 514 } 515 key := append(prefixRpcDb, GetMsgAccountKey(addr.Bytes())...) 516 517 b, e := q.store.Get(key) 518 if e != nil { 519 return nil, e 520 } 521 if b == nil { 522 return nil, errNotFound 523 } 524 acc, err := DecodeAccount(b) 525 if err != nil { 526 return nil, e 527 } 528 return acc, nil 529 } 530 531 func (q Querier) DeleteAccountFromRdb(addr sdk.AccAddress) { 532 if !q.enabled() { 533 return 534 } 535 q.store.Delete(append(prefixRpcDb, GetMsgAccountKey(addr.Bytes())...)) 536 } 537 538 func (q Querier) MustGetState(addr common.Address, key []byte) ([]byte, error) { 539 orgKey := GetMsgStateKey(addr, key) 540 data := state.GetStateFromLru(orgKey) 541 if data != nil { 542 return data, nil 543 } 544 b, e := q.GetState(orgKey) 545 if e != nil { 546 b, e = q.GetStateFromRdb(orgKey) 547 } else { 548 q.DeleteStateFromRdb(addr, key) 549 } 550 if e == nil { 551 state.SetStateToLru(orgKey, b) 552 } 553 return b, e 554 } 555 556 func (q Querier) GetState(key []byte) ([]byte, error) { 557 if !q.enabled() { 558 return nil, errDisable 559 } 560 b, e := q.store.Get(key) 561 if e != nil { 562 return nil, e 563 } 564 if b == nil { 565 return nil, errNotFound 566 } 567 return b, nil 568 } 569 570 func (q Querier) GetStateFromRdb(key []byte) ([]byte, error) { 571 if !q.enabled() { 572 return nil, errDisable 573 } 574 b, e := q.store.Get(append(prefixRpcDb, key...)) 575 if e != nil { 576 return nil, e 577 } 578 if b == nil { 579 return nil, errNotFound 580 } 581 582 return b, nil 583 } 584 585 func (q Querier) DeleteStateFromRdb(addr common.Address, key []byte) { 586 if !q.enabled() { 587 return 588 } 589 q.store.Delete(append(prefixRpcDb, GetMsgStateKey(addr, key)...)) 590 } 591 592 func (q Querier) GetParams() (*evmtypes.Params, error) { 593 if !q.enabled() { 594 return nil, errDisable 595 } 596 params := q.store.GetEvmParams() 597 return ¶ms, nil 598 } 599 600 func (q Querier) HasContractBlockedList(key []byte) bool { 601 if !q.enabled() { 602 return false 603 } 604 return q.store.Has(append(prefixBlackList, key...)) 605 } 606 func (q Querier) GetContractMethodBlockedList(key []byte) ([]byte, error) { 607 if !q.enabled() { 608 return nil, errDisable 609 } 610 return q.store.Get(append(prefixBlackList, key...)) 611 } 612 613 func (q Querier) HasContractDeploymentWhitelist(key []byte) bool { 614 if !q.enabled() { 615 return false 616 } 617 return q.store.Has(append(prefixWhiteList, key...)) 618 } 619 620 func (q Querier) GetStdTxHashByBlockHash(hash common.Hash) ([]common.Hash, error) { 621 if !q.enabled() { 622 return nil, errors.New(MsgFunctionDisable) 623 } 624 var stdTxHash []common.Hash 625 b, e := q.store.Get(append(prefixStdTxHash, hash.Bytes()...)) 626 if e != nil { 627 return nil, e 628 } 629 if b == nil { 630 return nil, errNotFound 631 } 632 e = json.Unmarshal(b, &stdTxHash) 633 if e != nil { 634 return nil, e 635 } 636 637 return stdTxHash, nil 638 }