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 &params, 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  }