github.com/fibonacci-chain/fbc@v0.0.0-20231124064014-c7636198c1e9/app/rpc/backend/backend.go (about) 1 package backend 2 3 import ( 4 "context" 5 "errors" 6 "fmt" 7 "time" 8 9 "github.com/fibonacci-chain/fbc/libs/cosmos-sdk/server" 10 "github.com/fibonacci-chain/fbc/libs/cosmos-sdk/store/types" 11 12 "github.com/fibonacci-chain/fbc/libs/tendermint/global" 13 14 coretypes "github.com/fibonacci-chain/fbc/libs/tendermint/rpc/core/types" 15 lru "github.com/hashicorp/golang-lru" 16 17 "github.com/spf13/viper" 18 19 "github.com/fibonacci-chain/fbc/libs/tendermint/libs/log" 20 "github.com/fibonacci-chain/fbc/x/evm/watcher" 21 "golang.org/x/time/rate" 22 23 rpctypes "github.com/fibonacci-chain/fbc/app/rpc/types" 24 evmtypes "github.com/fibonacci-chain/fbc/x/evm/types" 25 26 clientcontext "github.com/fibonacci-chain/fbc/libs/cosmos-sdk/client/context" 27 28 "github.com/ethereum/go-ethereum/common" 29 "github.com/ethereum/go-ethereum/common/bitutil" 30 "github.com/ethereum/go-ethereum/common/hexutil" 31 "github.com/ethereum/go-ethereum/core/bloombits" 32 ethtypes "github.com/ethereum/go-ethereum/core/types" 33 tmtypes "github.com/fibonacci-chain/fbc/libs/tendermint/types" 34 dbm "github.com/fibonacci-chain/fbc/libs/tm-db" 35 ) 36 37 const ( 38 FlagLogsLimit = "rpc.logs-limit" 39 FlagLogsTimeout = "rpc.logs-timeout" 40 blockCacheSize = 1024 41 ) 42 43 var ErrTimeout = errors.New("query timeout exceeded") 44 45 // Backend implements the functionality needed to filter changes. 46 // Implemented by EthermintBackend. 47 type Backend interface { 48 // Used by block filter; also used for polling 49 BlockNumber() (hexutil.Uint64, error) 50 LatestBlockNumber() (int64, error) 51 HeaderByNumber(blockNum rpctypes.BlockNumber) (*ethtypes.Header, error) 52 HeaderByHash(blockHash common.Hash) (*ethtypes.Header, error) 53 GetBlockByNumber(blockNum rpctypes.BlockNumber, fullTx bool) (*watcher.Block, error) 54 GetBlockByHash(hash common.Hash, fullTx bool) (*watcher.Block, error) 55 56 GetTransactionByHash(hash common.Hash) (*watcher.Transaction, error) 57 58 // returns the logs of a given block 59 GetLogs(height int64) ([][]*ethtypes.Log, error) 60 61 // Used by pending transaction filter 62 PendingTransactions() ([]*watcher.Transaction, error) 63 PendingTransactionCnt() (int, error) 64 PendingTransactionsByHash(target common.Hash) (*watcher.Transaction, error) 65 UserPendingTransactionsCnt(address string) (int, error) 66 UserPendingTransactions(address string, limit int) ([]*watcher.Transaction, error) 67 PendingAddressList() ([]string, error) 68 GetPendingNonce(address string) (uint64, bool) 69 70 // Used by log filter 71 GetTransactionLogs(txHash common.Hash) ([]*ethtypes.Log, error) 72 BloomStatus() (uint64, uint64) 73 ServiceFilter(ctx context.Context, session *bloombits.MatcherSession) 74 75 // Used by eip-1898 76 ConvertToBlockNumber(rpctypes.BlockNumberOrHash) (rpctypes.BlockNumber, error) 77 // Block returns the block at the given block number, block data is readonly 78 Block(height *int64) (*coretypes.ResultBlock, error) 79 PruneEverything() bool 80 } 81 82 var _ Backend = (*EthermintBackend)(nil) 83 84 // EthermintBackend implements the Backend interface 85 type EthermintBackend struct { 86 ctx context.Context 87 clientCtx clientcontext.CLIContext 88 logger log.Logger 89 gasLimit int64 90 bloomRequests chan chan *bloombits.Retrieval 91 closeBloomHandler chan struct{} 92 wrappedBackend *watcher.Querier 93 rateLimiters map[string]*rate.Limiter 94 disableAPI map[string]bool 95 backendCache Cache 96 logsLimit int 97 logsTimeout int // timeout second 98 blockCache *lru.Cache 99 pruneEverything bool 100 } 101 102 // New creates a new EthermintBackend instance 103 func New(clientCtx clientcontext.CLIContext, log log.Logger, rateLimiters map[string]*rate.Limiter, disableAPI map[string]bool) *EthermintBackend { 104 b := &EthermintBackend{ 105 ctx: context.Background(), 106 clientCtx: clientCtx, 107 logger: log.With("module", "json-rpc"), 108 gasLimit: int64(^uint32(0)), 109 bloomRequests: make(chan chan *bloombits.Retrieval), 110 closeBloomHandler: make(chan struct{}), 111 wrappedBackend: watcher.NewQuerier(), 112 rateLimiters: rateLimiters, 113 disableAPI: disableAPI, 114 backendCache: NewLruCache(), 115 logsLimit: viper.GetInt(FlagLogsLimit), 116 logsTimeout: viper.GetInt(FlagLogsTimeout), 117 pruneEverything: viper.GetString(server.FlagPruning) == types.PruningOptionEverything, 118 } 119 b.blockCache, _ = lru.New(blockCacheSize) 120 return b 121 } 122 123 func (b *EthermintBackend) PruneEverything() bool { 124 return b.pruneEverything 125 } 126 127 func (b *EthermintBackend) LogsLimit() int { 128 return b.logsLimit 129 } 130 131 func (b *EthermintBackend) LogsTimeout() time.Duration { 132 return time.Duration(b.logsTimeout) * time.Second 133 } 134 135 // BlockNumber returns the current block number. 136 func (b *EthermintBackend) BlockNumber() (hexutil.Uint64, error) { 137 committedHeight := global.GetGlobalHeight() 138 return hexutil.Uint64(committedHeight), nil 139 } 140 141 // GetBlockByNumber returns the block identified by number. 142 func (b *EthermintBackend) GetBlockByNumber(blockNum rpctypes.BlockNumber, fullTx bool) (*watcher.Block, error) { 143 //query block in cache first 144 block, err := b.backendCache.GetBlockByNumber(uint64(blockNum), fullTx) 145 if err == nil { 146 return block, nil 147 } 148 //query block from watch db 149 block, err = b.wrappedBackend.GetBlockByNumber(uint64(blockNum), fullTx) 150 if err == nil { 151 b.backendCache.AddOrUpdateBlock(block.Hash, block, fullTx) 152 return block, nil 153 } 154 //query block from db 155 height := blockNum.Int64() 156 if height <= 0 { 157 // get latest block height 158 num, err := b.BlockNumber() 159 if err != nil { 160 return nil, err 161 } 162 height = int64(num) 163 } 164 165 resBlock, err := b.Block(&height) 166 if err != nil { 167 return nil, nil 168 } 169 170 block, err = rpctypes.RpcBlockFromTendermint(b.clientCtx, resBlock.Block, fullTx) 171 if err != nil { 172 return nil, err 173 } 174 b.backendCache.AddOrUpdateBlock(block.Hash, block, fullTx) 175 return block, nil 176 } 177 178 // GetBlockByHash returns the block identified by hash. 179 func (b *EthermintBackend) GetBlockByHash(hash common.Hash, fullTx bool) (*watcher.Block, error) { 180 //query block in cache first 181 block, err := b.backendCache.GetBlockByHash(hash, fullTx) 182 if err == nil { 183 return block, err 184 } 185 //query block from watch db 186 block, err = b.wrappedBackend.GetBlockByHash(hash, fullTx) 187 if err == nil { 188 b.backendCache.AddOrUpdateBlock(hash, block, fullTx) 189 return block, nil 190 } 191 //query block from tendermint 192 res, _, err := b.clientCtx.Query(fmt.Sprintf("custom/%s/%s/%s", evmtypes.ModuleName, evmtypes.QueryHashToHeight, hash.Hex())) 193 if err != nil { 194 return nil, err 195 } 196 197 var out evmtypes.QueryResBlockNumber 198 if err := b.clientCtx.Codec.UnmarshalJSON(res, &out); err != nil { 199 return nil, err 200 } 201 202 resBlock, err := b.Block(&out.Number) 203 if err != nil { 204 return nil, nil 205 } 206 207 block, err = rpctypes.RpcBlockFromTendermint(b.clientCtx, resBlock.Block, fullTx) 208 if err != nil { 209 return nil, err 210 } 211 b.backendCache.AddOrUpdateBlock(hash, block, fullTx) 212 return block, nil 213 } 214 215 // HeaderByNumber returns the block header identified by height. 216 func (b *EthermintBackend) HeaderByNumber(blockNum rpctypes.BlockNumber) (*ethtypes.Header, error) { 217 height := blockNum.Int64() 218 if height <= 0 { 219 // get latest block height 220 num, err := b.BlockNumber() 221 if err != nil { 222 return nil, err 223 } 224 225 height = int64(num) 226 } 227 228 resBlock, err := b.Block(&height) 229 if err != nil { 230 return nil, err 231 } 232 233 res, _, err := b.clientCtx.Query(fmt.Sprintf("custom/%s/%s/%d", evmtypes.ModuleName, evmtypes.QueryBloom, resBlock.Block.Height)) 234 if err != nil { 235 return nil, err 236 } 237 238 var bloomRes evmtypes.QueryBloomFilter 239 b.clientCtx.Codec.MustUnmarshalJSON(res, &bloomRes) 240 241 ethHeader := rpctypes.EthHeaderFromTendermint(resBlock.Block.Header) 242 ethHeader.Bloom = bloomRes.Bloom 243 return ethHeader, nil 244 } 245 246 // HeaderByHash returns the block header identified by hash. 247 func (b *EthermintBackend) HeaderByHash(blockHash common.Hash) (*ethtypes.Header, error) { 248 res, _, err := b.clientCtx.Query(fmt.Sprintf("custom/%s/%s/%s", evmtypes.ModuleName, evmtypes.QueryHashToHeight, blockHash.Hex())) 249 if err != nil { 250 return nil, err 251 } 252 253 var out evmtypes.QueryResBlockNumber 254 if err := b.clientCtx.Codec.UnmarshalJSON(res, &out); err != nil { 255 return nil, err 256 } 257 258 resBlock, err := b.Block(&out.Number) 259 if err != nil { 260 return nil, err 261 } 262 263 res, _, err = b.clientCtx.Query(fmt.Sprintf("custom/%s/%s/%d", evmtypes.ModuleName, evmtypes.QueryBloom, resBlock.Block.Height)) 264 if err != nil { 265 return nil, err 266 } 267 268 var bloomRes evmtypes.QueryBloomFilter 269 b.clientCtx.Codec.MustUnmarshalJSON(res, &bloomRes) 270 271 ethHeader := rpctypes.EthHeaderFromTendermint(resBlock.Block.Header) 272 ethHeader.Bloom = bloomRes.Bloom 273 return ethHeader, nil 274 } 275 276 // GetTransactionLogs returns the logs given a transaction hash. 277 // It returns an error if there's an encoding error. 278 // If no logs are found for the tx hash, the error is nil. 279 func (b *EthermintBackend) GetTransactionLogs(txHash common.Hash) ([]*ethtypes.Log, error) { 280 txRes, err := b.clientCtx.Client.Tx(txHash.Bytes(), !b.clientCtx.TrustNode) 281 if err != nil { 282 return nil, err 283 } 284 285 execRes, err := evmtypes.DecodeResultData(txRes.TxResult.Data) 286 if err != nil { 287 return nil, err 288 } 289 290 // Sometimes failed txs leave Logs which need to be cleared 291 if !txRes.TxResult.IsOK() && execRes.Logs != nil { 292 return []*ethtypes.Log{}, nil 293 } 294 295 return execRes.Logs, nil 296 } 297 298 // PendingTransactions returns the transactions that are in the transaction pool 299 // and have a from address that is one of the accounts this node manages. 300 func (b *EthermintBackend) PendingTransactions() ([]*watcher.Transaction, error) { 301 lastHeight, err := b.clientCtx.Client.LatestBlockNumber() 302 if err != nil { 303 return nil, err 304 } 305 pendingTxs, err := b.clientCtx.Client.UnconfirmedTxs(-1) 306 if err != nil { 307 return nil, err 308 } 309 310 transactions := make([]*watcher.Transaction, 0, len(pendingTxs.Txs)) 311 for _, tx := range pendingTxs.Txs { 312 ethTx, err := rpctypes.RawTxToEthTx(b.clientCtx, tx, lastHeight) 313 if err != nil { 314 // ignore non Ethermint EVM transactions 315 continue 316 } 317 318 // TODO: check signer and reference against accounts the node manages 319 rpcTx, err := watcher.NewTransaction(ethTx, common.BytesToHash(ethTx.Hash), common.Hash{}, 0, 0) 320 if err != nil { 321 return nil, err 322 } 323 324 transactions = append(transactions, rpcTx) 325 } 326 327 return transactions, nil 328 } 329 330 func (b *EthermintBackend) PendingTransactionCnt() (int, error) { 331 result, err := b.clientCtx.Client.NumUnconfirmedTxs() 332 if err != nil { 333 return 0, err 334 } 335 return result.Count, nil 336 } 337 338 func (b *EthermintBackend) UserPendingTransactionsCnt(address string) (int, error) { 339 result, err := b.clientCtx.Client.UserNumUnconfirmedTxs(address) 340 if err != nil { 341 return 0, err 342 } 343 return result.Count, nil 344 } 345 346 func (b *EthermintBackend) GetPendingNonce(address string) (uint64, bool) { 347 result, ok := b.clientCtx.Client.GetPendingNonce(address) 348 if !ok { 349 return 0, false 350 } 351 return result.Nonce, true 352 } 353 354 func (b *EthermintBackend) UserPendingTransactions(address string, limit int) ([]*watcher.Transaction, error) { 355 lastHeight, err := b.clientCtx.Client.LatestBlockNumber() 356 if err != nil { 357 return nil, err 358 } 359 result, err := b.clientCtx.Client.UserUnconfirmedTxs(address, limit) 360 if err != nil { 361 return nil, err 362 } 363 transactions := make([]*watcher.Transaction, 0, len(result.Txs)) 364 for _, tx := range result.Txs { 365 ethTx, err := rpctypes.RawTxToEthTx(b.clientCtx, tx, lastHeight) 366 if err != nil { 367 // ignore non Ethermint EVM transactions 368 continue 369 } 370 371 // TODO: check signer and reference against accounts the node manages 372 rpcTx, err := watcher.NewTransaction(ethTx, common.BytesToHash(ethTx.Hash), common.Hash{}, 0, 0) 373 if err != nil { 374 return nil, err 375 } 376 377 transactions = append(transactions, rpcTx) 378 } 379 380 return transactions, nil 381 } 382 383 func (b *EthermintBackend) PendingAddressList() ([]string, error) { 384 res, err := b.clientCtx.Client.GetAddressList() 385 if err != nil { 386 return nil, err 387 } 388 return res.Addresses, nil 389 } 390 391 // PendingTransactions returns the transaction that is in the transaction pool 392 // and have a from address that is one of the accounts this node manages. 393 func (b *EthermintBackend) PendingTransactionsByHash(target common.Hash) (*watcher.Transaction, error) { 394 lastHeight, err := b.clientCtx.Client.LatestBlockNumber() 395 if err != nil { 396 return nil, err 397 } 398 pendingTx, err := b.clientCtx.Client.GetUnconfirmedTxByHash(target) 399 if err != nil { 400 return nil, err 401 } 402 ethTx, err := rpctypes.RawTxToEthTx(b.clientCtx, pendingTx, lastHeight) 403 if err != nil { 404 // ignore non Ethermint EVM transactions 405 return nil, err 406 } 407 rpcTx, err := watcher.NewTransaction(ethTx, common.BytesToHash(ethTx.Hash), common.Hash{}, 0, 0) 408 if err != nil { 409 return nil, err 410 } 411 return rpcTx, nil 412 } 413 414 func (b *EthermintBackend) GetTransactionByHash(hash common.Hash) (tx *watcher.Transaction, err error) { 415 // query tx in cache first 416 tx, err = b.backendCache.GetTransaction(hash) 417 if err == nil { 418 return tx, err 419 } 420 // query tx in watch db 421 tx, err = b.wrappedBackend.GetTransactionByHash(hash) 422 if err == nil { 423 b.backendCache.AddOrUpdateTransaction(hash, tx) 424 return tx, nil 425 } 426 // query tx in tendermint 427 txRes, err := b.clientCtx.Client.Tx(hash.Bytes(), false) 428 if err != nil { 429 return nil, err 430 } 431 432 // Can either cache or just leave this out if not necessary 433 block, err := b.Block(&txRes.Height) 434 if err != nil { 435 return nil, err 436 } 437 438 blockHash := common.BytesToHash(block.Block.Hash()) 439 440 ethTx, err := rpctypes.RawTxToEthTx(b.clientCtx, txRes.Tx, txRes.Height) 441 if err != nil { 442 return nil, err 443 } 444 445 tx, err = watcher.NewTransaction(ethTx, common.BytesToHash(ethTx.Hash), blockHash, uint64(txRes.Height), uint64(txRes.Index)) 446 if err != nil { 447 return nil, err 448 } 449 b.backendCache.AddOrUpdateTransaction(hash, tx) 450 return tx, nil 451 } 452 453 // GetLogs returns all the logs from all the ethereum transactions in a block. 454 func (b *EthermintBackend) GetLogs(height int64) ([][]*ethtypes.Log, error) { 455 block, err := b.Block(&height) 456 if err != nil { 457 return nil, err 458 } 459 // return empty directly when block was produced during stress testing. 460 var blockLogs = [][]*ethtypes.Log{} 461 if b.logsLimit > 0 && len(block.Block.Txs) > b.logsLimit { 462 return blockLogs, nil 463 } 464 ctx, cancel := context.WithTimeout(context.Background(), time.Duration(b.logsTimeout)*time.Second) 465 defer cancel() 466 for _, tx := range block.Block.Txs { 467 select { 468 case <-ctx.Done(): 469 return nil, ErrTimeout 470 default: 471 // NOTE: we query the state in case the tx result logs are not persisted after an upgrade. 472 txRes, err := b.clientCtx.Client.Tx(tx.Hash(block.Block.Height), !b.clientCtx.TrustNode) 473 if err != nil { 474 continue 475 } 476 execRes, err := evmtypes.DecodeResultData(txRes.TxResult.Data) 477 if err != nil { 478 continue 479 } 480 var validLogs []*ethtypes.Log 481 for _, log := range execRes.Logs { 482 if int64(log.BlockNumber) == block.Block.Height { 483 validLogs = append(validLogs, log) 484 } 485 } 486 blockLogs = append(blockLogs, validLogs) 487 } 488 } 489 490 return blockLogs, nil 491 } 492 493 // BloomStatus returns the BloomBitsBlocks and the number of processed sections maintained 494 // by the chain indexer. 495 func (b *EthermintBackend) BloomStatus() (uint64, uint64) { 496 sections := evmtypes.GetIndexer().StoredSection() 497 return evmtypes.BloomBitsBlocks, sections 498 } 499 500 // LatestBlockNumber gets the latest block height in int64 format. 501 func (b *EthermintBackend) LatestBlockNumber() (int64, error) { 502 return b.clientCtx.Client.LatestBlockNumber() 503 } 504 505 func (b *EthermintBackend) ServiceFilter(ctx context.Context, session *bloombits.MatcherSession) { 506 for i := 0; i < evmtypes.BloomFilterThreads; i++ { 507 go session.Multiplex(evmtypes.BloomRetrievalBatch, evmtypes.BloomRetrievalWait, b.bloomRequests) 508 } 509 } 510 511 // startBloomHandlers starts a batch of goroutines to accept bloom bit database 512 // retrievals from possibly a range of filters and serving the data to satisfy. 513 func (b *EthermintBackend) StartBloomHandlers(sectionSize uint64, db dbm.DB) { 514 for i := 0; i < evmtypes.BloomServiceThreads; i++ { 515 go func() { 516 for { 517 select { 518 case <-b.closeBloomHandler: 519 return 520 521 case request := <-b.bloomRequests: 522 task := <-request 523 task.Bitsets = make([][]byte, len(task.Sections)) 524 for i, section := range task.Sections { 525 height := int64((section+1)*sectionSize-1) + tmtypes.GetStartBlockHeight() 526 hash, err := b.GetBlockHashByHeight(rpctypes.BlockNumber(height)) 527 if err != nil { 528 task.Error = err 529 } 530 if compVector, err := evmtypes.ReadBloomBits(db, task.Bit, section, hash); err == nil { 531 if blob, err := bitutil.DecompressBytes(compVector, int(sectionSize/8)); err == nil { 532 task.Bitsets[i] = blob 533 } else { 534 task.Error = err 535 } 536 } else { 537 task.Error = err 538 } 539 } 540 request <- task 541 } 542 } 543 }() 544 } 545 } 546 547 // GetBlockHashByHeight returns the block hash by height. 548 func (b *EthermintBackend) GetBlockHashByHeight(height rpctypes.BlockNumber) (common.Hash, error) { 549 res, _, err := b.clientCtx.Query(fmt.Sprintf("custom/%s/%s/%d", evmtypes.ModuleName, evmtypes.QueryHeightToHash, height)) 550 if err != nil { 551 return common.Hash{}, err 552 } 553 554 hash := common.BytesToHash(res) 555 return hash, nil 556 } 557 558 // Close 559 func (b *EthermintBackend) Close() { 560 close(b.closeBloomHandler) 561 } 562 563 func (b *EthermintBackend) GetRateLimiter(apiName string) *rate.Limiter { 564 if b.rateLimiters == nil { 565 return nil 566 } 567 return b.rateLimiters[apiName] 568 } 569 570 func (b *EthermintBackend) IsDisabled(apiName string) bool { 571 if b.disableAPI == nil { 572 return false 573 } 574 return b.disableAPI[apiName] 575 } 576 577 func (b *EthermintBackend) ConvertToBlockNumber(blockNumberOrHash rpctypes.BlockNumberOrHash) (rpctypes.BlockNumber, error) { 578 if blockNumber, ok := blockNumberOrHash.Number(); ok { 579 return blockNumber, nil 580 } 581 hash, ok := blockNumberOrHash.Hash() 582 if !ok { 583 return rpctypes.LatestBlockNumber, nil 584 } 585 ethBlock, err := b.wrappedBackend.GetBlockByHash(hash, false) 586 if err == nil { 587 return rpctypes.BlockNumber(ethBlock.Number), nil 588 } 589 590 res, _, err := b.clientCtx.Query(fmt.Sprintf("custom/%s/%s/%s", evmtypes.ModuleName, evmtypes.QueryHashToHeight, hash.Hex())) 591 if err != nil { 592 return rpctypes.LatestBlockNumber, rpctypes.ErrResourceNotFound 593 } 594 595 var out evmtypes.QueryResBlockNumber 596 if err := b.clientCtx.Codec.UnmarshalJSON(res, &out); err != nil { 597 return rpctypes.LatestBlockNumber, rpctypes.ErrResourceNotFound 598 } 599 return rpctypes.BlockNumber(out.Number), nil 600 } 601 602 func (b *EthermintBackend) cacheBlock(block *coretypes.ResultBlock) { 603 if b.blockCache != nil { 604 b.blockCache.Add(block.Block.Height, block) 605 } 606 } 607 608 func (b *EthermintBackend) getBlockFromCache(height int64) *coretypes.ResultBlock { 609 if b.blockCache != nil { 610 if v, ok := b.blockCache.Get(height); ok { 611 return v.(*coretypes.ResultBlock) 612 } 613 } 614 return nil 615 } 616 617 func (b *EthermintBackend) Block(height *int64) (block *coretypes.ResultBlock, err error) { 618 if height != nil { 619 block = b.getBlockFromCache(*height) 620 } 621 if block == nil { 622 block, err = b.clientCtx.Client.Block(height) 623 if err != nil { 624 return nil, err 625 } 626 b.cacheBlock(block) 627 } 628 return block, nil 629 }