github.com/cryptohub-digital/blockbook@v0.3.5-0.20240403155730-99ab40b9104c/bchain/coins/blockchain.go (about)

     1  package coins
     2  
     3  import (
     4  	"context"
     5  	"encoding/json"
     6  	"fmt"
     7  	"io/ioutil"
     8  	"math/big"
     9  	"reflect"
    10  	"time"
    11  
    12  	"github.com/cryptohub-digital/blockbook/bchain"
    13  	"github.com/cryptohub-digital/blockbook/bchain/coins/avalanche"
    14  	"github.com/cryptohub-digital/blockbook/bchain/coins/bch"
    15  	"github.com/cryptohub-digital/blockbook/bchain/coins/bellcoin"
    16  	"github.com/cryptohub-digital/blockbook/bchain/coins/bitcore"
    17  	"github.com/cryptohub-digital/blockbook/bchain/coins/bitzeny"
    18  	"github.com/cryptohub-digital/blockbook/bchain/coins/bsc"
    19  	"github.com/cryptohub-digital/blockbook/bchain/coins/btc"
    20  	"github.com/cryptohub-digital/blockbook/bchain/coins/btg"
    21  	"github.com/cryptohub-digital/blockbook/bchain/coins/cpuchain"
    22  	"github.com/cryptohub-digital/blockbook/bchain/coins/dash"
    23  	"github.com/cryptohub-digital/blockbook/bchain/coins/dcr"
    24  	"github.com/cryptohub-digital/blockbook/bchain/coins/deeponion"
    25  	"github.com/cryptohub-digital/blockbook/bchain/coins/digibyte"
    26  	"github.com/cryptohub-digital/blockbook/bchain/coins/divi"
    27  	"github.com/cryptohub-digital/blockbook/bchain/coins/dogecoin"
    28  	"github.com/cryptohub-digital/blockbook/bchain/coins/ecash"
    29  	"github.com/cryptohub-digital/blockbook/bchain/coins/eth"
    30  	"github.com/cryptohub-digital/blockbook/bchain/coins/firo"
    31  	"github.com/cryptohub-digital/blockbook/bchain/coins/flo"
    32  	"github.com/cryptohub-digital/blockbook/bchain/coins/fujicoin"
    33  	"github.com/cryptohub-digital/blockbook/bchain/coins/gamecredits"
    34  	"github.com/cryptohub-digital/blockbook/bchain/coins/grs"
    35  	"github.com/cryptohub-digital/blockbook/bchain/coins/koto"
    36  	"github.com/cryptohub-digital/blockbook/bchain/coins/liquid"
    37  	"github.com/cryptohub-digital/blockbook/bchain/coins/litecoin"
    38  	"github.com/cryptohub-digital/blockbook/bchain/coins/monacoin"
    39  	"github.com/cryptohub-digital/blockbook/bchain/coins/monetaryunit"
    40  	"github.com/cryptohub-digital/blockbook/bchain/coins/myriad"
    41  	"github.com/cryptohub-digital/blockbook/bchain/coins/namecoin"
    42  	"github.com/cryptohub-digital/blockbook/bchain/coins/nuls"
    43  	"github.com/cryptohub-digital/blockbook/bchain/coins/omotenashicoin"
    44  	"github.com/cryptohub-digital/blockbook/bchain/coins/pivx"
    45  	"github.com/cryptohub-digital/blockbook/bchain/coins/polis"
    46  	"github.com/cryptohub-digital/blockbook/bchain/coins/qtum"
    47  	"github.com/cryptohub-digital/blockbook/bchain/coins/ravencoin"
    48  	"github.com/cryptohub-digital/blockbook/bchain/coins/ritocoin"
    49  	"github.com/cryptohub-digital/blockbook/bchain/coins/snowgem"
    50  	"github.com/cryptohub-digital/blockbook/bchain/coins/trezarcoin"
    51  	"github.com/cryptohub-digital/blockbook/bchain/coins/unobtanium"
    52  	"github.com/cryptohub-digital/blockbook/bchain/coins/vertcoin"
    53  	"github.com/cryptohub-digital/blockbook/bchain/coins/viacoin"
    54  	"github.com/cryptohub-digital/blockbook/bchain/coins/vipstarcoin"
    55  	"github.com/cryptohub-digital/blockbook/bchain/coins/xcb"
    56  	"github.com/cryptohub-digital/blockbook/bchain/coins/zec"
    57  
    58  	"github.com/cryptohub-digital/blockbook/common"
    59  	"github.com/juju/errors"
    60  )
    61  
    62  type blockChainFactory func(config json.RawMessage, pushHandler func(bchain.NotificationType)) (bchain.BlockChain, error)
    63  
    64  // BlockChainFactories is a map of constructors of coin RPC interfaces
    65  var BlockChainFactories = make(map[string]blockChainFactory)
    66  
    67  func init() {
    68  	BlockChainFactories["Bitcoin"] = btc.NewBitcoinRPC
    69  	BlockChainFactories["Testnet"] = btc.NewBitcoinRPC
    70  	BlockChainFactories["Signet"] = btc.NewBitcoinRPC
    71  	BlockChainFactories["Regtest"] = btc.NewBitcoinRPC
    72  	BlockChainFactories["Zcash"] = zec.NewZCashRPC
    73  	BlockChainFactories["Zcash Testnet"] = zec.NewZCashRPC
    74  	BlockChainFactories["Ethereum"] = eth.NewEthereumRPC
    75  	BlockChainFactories["Ethereum Archive"] = eth.NewEthereumRPC
    76  	BlockChainFactories["Ethereum Classic"] = eth.NewEthereumRPC
    77  	BlockChainFactories["Ethereum Testnet Ropsten"] = eth.NewEthereumRPC
    78  	BlockChainFactories["Ethereum Testnet Ropsten Archive"] = eth.NewEthereumRPC
    79  	BlockChainFactories["Ethereum Testnet Goerli"] = eth.NewEthereumRPC
    80  	BlockChainFactories["Ethereum Testnet Goerli Archive"] = eth.NewEthereumRPC
    81  	BlockChainFactories["Ethereum Testnet Sepolia"] = eth.NewEthereumRPC
    82  	BlockChainFactories["Ethereum Testnet Sepolia Archive"] = eth.NewEthereumRPC
    83  	BlockChainFactories["Bcash"] = bch.NewBCashRPC
    84  	BlockChainFactories["Bcash Testnet"] = bch.NewBCashRPC
    85  	BlockChainFactories["Bgold"] = btg.NewBGoldRPC
    86  	BlockChainFactories["Bgold Testnet"] = btg.NewBGoldRPC
    87  	BlockChainFactories["Dash"] = dash.NewDashRPC
    88  	BlockChainFactories["Dash Testnet"] = dash.NewDashRPC
    89  	BlockChainFactories["Decred"] = dcr.NewDecredRPC
    90  	BlockChainFactories["Decred Testnet"] = dcr.NewDecredRPC
    91  	BlockChainFactories["GameCredits"] = gamecredits.NewGameCreditsRPC
    92  	BlockChainFactories["Koto"] = koto.NewKotoRPC
    93  	BlockChainFactories["Koto Testnet"] = koto.NewKotoRPC
    94  	BlockChainFactories["Litecoin"] = litecoin.NewLitecoinRPC
    95  	BlockChainFactories["Litecoin Testnet"] = litecoin.NewLitecoinRPC
    96  	BlockChainFactories["Dogecoin"] = dogecoin.NewDogecoinRPC
    97  	BlockChainFactories["Dogecoin Testnet"] = dogecoin.NewDogecoinRPC
    98  	BlockChainFactories["Vertcoin"] = vertcoin.NewVertcoinRPC
    99  	BlockChainFactories["Vertcoin Testnet"] = vertcoin.NewVertcoinRPC
   100  	BlockChainFactories["Namecoin"] = namecoin.NewNamecoinRPC
   101  	BlockChainFactories["Monacoin"] = monacoin.NewMonacoinRPC
   102  	BlockChainFactories["Monacoin Testnet"] = monacoin.NewMonacoinRPC
   103  	BlockChainFactories["MonetaryUnit"] = monetaryunit.NewMonetaryUnitRPC
   104  	BlockChainFactories["DigiByte"] = digibyte.NewDigiByteRPC
   105  	BlockChainFactories["DigiByte Testnet"] = digibyte.NewDigiByteRPC
   106  	BlockChainFactories["Myriad"] = myriad.NewMyriadRPC
   107  	BlockChainFactories["Liquid"] = liquid.NewLiquidRPC
   108  	BlockChainFactories["Groestlcoin"] = grs.NewGroestlcoinRPC
   109  	BlockChainFactories["Groestlcoin Testnet"] = grs.NewGroestlcoinRPC
   110  	BlockChainFactories["Groestlcoin Signet"] = grs.NewGroestlcoinRPC
   111  	BlockChainFactories["Groestlcoin Regtest"] = grs.NewGroestlcoinRPC
   112  	BlockChainFactories["PIVX"] = pivx.NewPivXRPC
   113  	BlockChainFactories["PIVX Testnet"] = pivx.NewPivXRPC
   114  	BlockChainFactories["Polis"] = polis.NewPolisRPC
   115  	BlockChainFactories["Firo"] = firo.NewFiroRPC
   116  	BlockChainFactories["Fujicoin"] = fujicoin.NewFujicoinRPC
   117  	BlockChainFactories["Flo"] = flo.NewFloRPC
   118  	BlockChainFactories["Bellcoin"] = bellcoin.NewBellcoinRPC
   119  	BlockChainFactories["Qtum"] = qtum.NewQtumRPC
   120  	BlockChainFactories["Viacoin"] = viacoin.NewViacoinRPC
   121  	BlockChainFactories["Qtum Testnet"] = qtum.NewQtumRPC
   122  	BlockChainFactories["NULS"] = nuls.NewNulsRPC
   123  	BlockChainFactories["VIPSTARCOIN"] = vipstarcoin.NewVIPSTARCOINRPC
   124  	BlockChainFactories["Flux"] = zec.NewZCashRPC
   125  	BlockChainFactories["Ravencoin"] = ravencoin.NewRavencoinRPC
   126  	BlockChainFactories["Ritocoin"] = ritocoin.NewRitocoinRPC
   127  	BlockChainFactories["Divi"] = divi.NewDiviRPC
   128  	BlockChainFactories["CPUchain"] = cpuchain.NewCPUchainRPC
   129  	BlockChainFactories["Unobtanium"] = unobtanium.NewUnobtaniumRPC
   130  	BlockChainFactories["DeepOnion"] = deeponion.NewDeepOnionRPC
   131  	BlockChainFactories["SnowGem"] = snowgem.NewSnowGemRPC
   132  	BlockChainFactories["Bitcore"] = bitcore.NewBitcoreRPC
   133  	BlockChainFactories["Omotenashicoin"] = omotenashicoin.NewOmotenashiCoinRPC
   134  	BlockChainFactories["Omotenashicoin Testnet"] = omotenashicoin.NewOmotenashiCoinRPC
   135  	BlockChainFactories["BitZeny"] = bitzeny.NewBitZenyRPC
   136  	BlockChainFactories["Trezarcoin"] = trezarcoin.NewTrezarcoinRPC
   137  	BlockChainFactories["ECash"] = ecash.NewECashRPC
   138  	BlockChainFactories["Avalanche"] = avalanche.NewAvalancheRPC
   139  	BlockChainFactories["Avalanche Archive"] = avalanche.NewAvalancheRPC
   140  	BlockChainFactories["BNB Smart Chain"] = bsc.NewBNBSmartChainRPC
   141  	BlockChainFactories["BNB Smart Chain Archive"] = bsc.NewBNBSmartChainRPC
   142  	BlockChainFactories["Core Coin"] = xcb.NewCoreblockchainRPC
   143  	BlockChainFactories["Core Coin Testnet"] = xcb.NewCoreblockchainRPC
   144  
   145  }
   146  
   147  // GetCoinNameFromConfig gets coin name and coin shortcut from config file
   148  func GetCoinNameFromConfig(configFileContent []byte) (string, string, string, error) {
   149  	var cn struct {
   150  		CoinName     string `json:"coin_name"`
   151  		CoinShortcut string `json:"coin_shortcut"`
   152  		CoinLabel    string `json:"coin_label"`
   153  	}
   154  	err := json.Unmarshal(configFileContent, &cn)
   155  	if err != nil {
   156  		return "", "", "", errors.Annotatef(err, "Error parsing config file ")
   157  	}
   158  	return cn.CoinName, cn.CoinShortcut, cn.CoinLabel, nil
   159  }
   160  
   161  // NewBlockChain creates bchain.BlockChain and bchain.Mempool for the coin passed by the parameter coin
   162  func NewBlockChain(coin string, configfile string, pushHandler func(bchain.NotificationType), metrics *common.Metrics) (bchain.BlockChain, bchain.Mempool, error) {
   163  	data, err := ioutil.ReadFile(configfile)
   164  	if err != nil {
   165  		return nil, nil, errors.Annotatef(err, "Error reading file %v", configfile)
   166  	}
   167  	var config json.RawMessage
   168  	err = json.Unmarshal(data, &config)
   169  	if err != nil {
   170  		return nil, nil, errors.Annotatef(err, "Error parsing file %v", configfile)
   171  	}
   172  	bcf, ok := BlockChainFactories[coin]
   173  	if !ok {
   174  		return nil, nil, errors.New(fmt.Sprint("Unsupported coin '", coin, "'. Must be one of ", reflect.ValueOf(BlockChainFactories).MapKeys()))
   175  	}
   176  	bc, err := bcf(config, pushHandler)
   177  	if err != nil {
   178  		return nil, nil, err
   179  	}
   180  	err = bc.Initialize()
   181  	if err != nil {
   182  		return nil, nil, err
   183  	}
   184  	mempool, err := bc.CreateMempool(bc)
   185  	if err != nil {
   186  		return nil, nil, err
   187  	}
   188  	return &blockChainWithMetrics{b: bc, m: metrics}, &mempoolWithMetrics{mempool: mempool, m: metrics}, nil
   189  }
   190  
   191  type blockChainWithMetrics struct {
   192  	b bchain.BlockChain
   193  	m *common.Metrics
   194  }
   195  
   196  func (c *blockChainWithMetrics) observeRPCLatency(method string, start time.Time, err error) {
   197  	var e string
   198  	if err != nil {
   199  		e = "failure"
   200  	}
   201  	c.m.RPCLatency.With(common.Labels{"method": method, "error": e}).Observe(float64(time.Since(start)) / 1e6) // in milliseconds
   202  }
   203  
   204  func (c *blockChainWithMetrics) AddVerifiedSCData(contract *bchain.ContractInfo) *bchain.ContractInfo {
   205  	return c.b.AddVerifiedSCData(contract)
   206  }
   207  
   208  func (c *blockChainWithMetrics) FindVerifiedByName(query string) *bchain.AddressDescriptor {
   209  	return c.b.FindVerifiedByName(query)
   210  }
   211  
   212  func (c *blockChainWithMetrics) AddVerifiedAddressData(address bchain.AddressDescriptor) *bchain.VerifiedAddress {
   213  	return c.b.AddVerifiedAddressData(address)
   214  }
   215  
   216  func (c *blockChainWithMetrics) Initialize() error {
   217  	return c.b.Initialize()
   218  }
   219  
   220  func (c *blockChainWithMetrics) CreateMempool(chain bchain.BlockChain) (bchain.Mempool, error) {
   221  	return c.b.CreateMempool(chain)
   222  }
   223  
   224  func (c *blockChainWithMetrics) InitializeMempool(addrDescForOutpoint bchain.AddrDescForOutpointFunc, onNewTxAddr bchain.OnNewTxAddrFunc, onNewTx bchain.OnNewTxFunc) error {
   225  	return c.b.InitializeMempool(addrDescForOutpoint, onNewTxAddr, onNewTx)
   226  }
   227  
   228  func (c *blockChainWithMetrics) Shutdown(ctx context.Context) error {
   229  	return c.b.Shutdown(ctx)
   230  }
   231  
   232  func (c *blockChainWithMetrics) IsTestnet() bool {
   233  	return c.b.IsTestnet()
   234  }
   235  
   236  func (c *blockChainWithMetrics) GetNetworkName() string {
   237  	return c.b.GetNetworkName()
   238  }
   239  
   240  func (c *blockChainWithMetrics) GetCoinName() string {
   241  	return c.b.GetCoinName()
   242  }
   243  
   244  func (c *blockChainWithMetrics) GetSubversion() string {
   245  	return c.b.GetSubversion()
   246  }
   247  
   248  func (c *blockChainWithMetrics) GetChainInfo() (v *bchain.ChainInfo, err error) {
   249  	defer func(s time.Time) { c.observeRPCLatency("GetChainInfo", s, err) }(time.Now())
   250  	return c.b.GetChainInfo()
   251  }
   252  
   253  func (c *blockChainWithMetrics) GetBestBlockHash() (v string, err error) {
   254  	defer func(s time.Time) { c.observeRPCLatency("GetBestBlockHash", s, err) }(time.Now())
   255  	return c.b.GetBestBlockHash()
   256  }
   257  
   258  func (c *blockChainWithMetrics) GetBestBlockHeight() (v uint32, err error) {
   259  	defer func(s time.Time) { c.observeRPCLatency("GetBestBlockHeight", s, err) }(time.Now())
   260  	return c.b.GetBestBlockHeight()
   261  }
   262  
   263  func (c *blockChainWithMetrics) GetBlockHash(height uint32) (v string, err error) {
   264  	defer func(s time.Time) { c.observeRPCLatency("GetBlockHash", s, err) }(time.Now())
   265  	return c.b.GetBlockHash(height)
   266  }
   267  
   268  func (c *blockChainWithMetrics) GetBlockHeader(hash string) (v *bchain.BlockHeader, err error) {
   269  	defer func(s time.Time) { c.observeRPCLatency("GetBlockHeader", s, err) }(time.Now())
   270  	return c.b.GetBlockHeader(hash)
   271  }
   272  
   273  func (c *blockChainWithMetrics) GetBlock(hash string, height uint32) (v *bchain.Block, err error) {
   274  	defer func(s time.Time) { c.observeRPCLatency("GetBlock", s, err) }(time.Now())
   275  	return c.b.GetBlock(hash, height)
   276  }
   277  
   278  func (c *blockChainWithMetrics) GetBlockInfo(hash string) (v *bchain.BlockInfo, err error) {
   279  	defer func(s time.Time) { c.observeRPCLatency("GetBlockInfo", s, err) }(time.Now())
   280  	return c.b.GetBlockInfo(hash)
   281  }
   282  
   283  func (c *blockChainWithMetrics) GetBlockRaw(hash string) (v string, err error) {
   284  	defer func(s time.Time) { c.observeRPCLatency("GetBlockRaw", s, err) }(time.Now())
   285  	return c.b.GetBlockRaw(hash)
   286  }
   287  
   288  func (c *blockChainWithMetrics) GetMempoolTransactions() (v []string, err error) {
   289  	defer func(s time.Time) { c.observeRPCLatency("GetMempoolTransactions", s, err) }(time.Now())
   290  	return c.b.GetMempoolTransactions()
   291  }
   292  
   293  func (c *blockChainWithMetrics) GetTransaction(txid string) (v *bchain.Tx, err error) {
   294  	defer func(s time.Time) { c.observeRPCLatency("GetTransaction", s, err) }(time.Now())
   295  	return c.b.GetTransaction(txid)
   296  }
   297  
   298  func (c *blockChainWithMetrics) GetTransactionSpecific(tx *bchain.Tx) (v json.RawMessage, err error) {
   299  	defer func(s time.Time) { c.observeRPCLatency("GetTransactionSpecific", s, err) }(time.Now())
   300  	return c.b.GetTransactionSpecific(tx)
   301  }
   302  
   303  func (c *blockChainWithMetrics) GetTransactionForMempool(txid string) (v *bchain.Tx, err error) {
   304  	defer func(s time.Time) { c.observeRPCLatency("GetTransactionForMempool", s, err) }(time.Now())
   305  	return c.b.GetTransactionForMempool(txid)
   306  }
   307  
   308  func (c *blockChainWithMetrics) EstimateSmartFee(blocks int, conservative bool) (v big.Int, err error) {
   309  	defer func(s time.Time) { c.observeRPCLatency("EstimateSmartFee", s, err) }(time.Now())
   310  	return c.b.EstimateSmartFee(blocks, conservative)
   311  }
   312  
   313  func (c *blockChainWithMetrics) EstimateFee(blocks int) (v big.Int, err error) {
   314  	defer func(s time.Time) { c.observeRPCLatency("EstimateFee", s, err) }(time.Now())
   315  	return c.b.EstimateFee(blocks)
   316  }
   317  
   318  func (c *blockChainWithMetrics) SendRawTransaction(tx string) (v string, err error) {
   319  	defer func(s time.Time) { c.observeRPCLatency("SendRawTransaction", s, err) }(time.Now())
   320  	return c.b.SendRawTransaction(tx)
   321  }
   322  
   323  func (c *blockChainWithMetrics) GetMempoolEntry(txid string) (v *bchain.MempoolEntry, err error) {
   324  	defer func(s time.Time) { c.observeRPCLatency("GetMempoolEntry", s, err) }(time.Now())
   325  	return c.b.GetMempoolEntry(txid)
   326  }
   327  
   328  func (c *blockChainWithMetrics) GetChainParser() bchain.BlockChainParser {
   329  	return c.b.GetChainParser()
   330  }
   331  
   332  func (c *blockChainWithMetrics) EthereumTypeGetBalance(addrDesc bchain.AddressDescriptor) (v *big.Int, err error) {
   333  	defer func(s time.Time) { c.observeRPCLatency("EthereumTypeGetBalance", s, err) }(time.Now())
   334  	return c.b.EthereumTypeGetBalance(addrDesc)
   335  }
   336  
   337  func (c *blockChainWithMetrics) EthereumTypeGetNonce(addrDesc bchain.AddressDescriptor) (v uint64, err error) {
   338  	defer func(s time.Time) { c.observeRPCLatency("EthereumTypeGetNonce", s, err) }(time.Now())
   339  	return c.b.EthereumTypeGetNonce(addrDesc)
   340  }
   341  
   342  func (c *blockChainWithMetrics) EthereumTypeEstimateGas(params map[string]interface{}) (v uint64, err error) {
   343  	defer func(s time.Time) { c.observeRPCLatency("EthereumTypeEstimateGas", s, err) }(time.Now())
   344  	return c.b.EthereumTypeEstimateGas(params)
   345  }
   346  
   347  func (c *blockChainWithMetrics) GetContractInfo(contractDesc bchain.AddressDescriptor) (v *bchain.ContractInfo, err error) {
   348  	defer func(s time.Time) { c.observeRPCLatency("GetContractInfo", s, err) }(time.Now())
   349  	return c.b.GetContractInfo(contractDesc)
   350  }
   351  
   352  func (c *blockChainWithMetrics) EthereumTypeGetErc20ContractBalance(addrDesc, contractDesc bchain.AddressDescriptor) (v *big.Int, err error) {
   353  	defer func(s time.Time) { c.observeRPCLatency("EthereumTypeGetErc20ContractBalance", s, err) }(time.Now())
   354  	return c.b.EthereumTypeGetErc20ContractBalance(addrDesc, contractDesc)
   355  }
   356  
   357  // GetTokenURI returns URI of non fungible or multi token defined by token id
   358  func (c *blockChainWithMetrics) GetTokenURI(contractDesc bchain.AddressDescriptor, tokenID *big.Int) (v string, err error) {
   359  	defer func(s time.Time) { c.observeRPCLatency("GetTokenURI", s, err) }(time.Now())
   360  	return c.b.GetTokenURI(contractDesc, tokenID)
   361  }
   362  
   363  func (c *blockChainWithMetrics) CoreCoinTypeGetBalance(addrDesc bchain.AddressDescriptor) (v *big.Int, err error) {
   364  	defer func(s time.Time) { c.observeRPCLatency("CoreCoinTypeGetBalance", s, err) }(time.Now())
   365  	return c.b.CoreCoinTypeGetBalance(addrDesc)
   366  }
   367  
   368  func (c *blockChainWithMetrics) CoreCoinTypeGetNonce(addrDesc bchain.AddressDescriptor) (v uint64, err error) {
   369  	defer func(s time.Time) { c.observeRPCLatency("CoreCoinTypeGetNonce", s, err) }(time.Now())
   370  	return c.b.CoreCoinTypeGetNonce(addrDesc)
   371  }
   372  
   373  func (c *blockChainWithMetrics) CoreCoinTypeEstimateEnergy(params map[string]interface{}) (v uint64, err error) {
   374  	defer func(s time.Time) { c.observeRPCLatency("CoreCoinTypeEstimateEnergy", s, err) }(time.Now())
   375  	return c.b.CoreCoinTypeEstimateEnergy(params)
   376  }
   377  
   378  func (c *blockChainWithMetrics) CoreCoinTypeGetCbc20ContractBalance(addrDesc, contractDesc bchain.AddressDescriptor) (v *big.Int, err error) {
   379  	defer func(s time.Time) { c.observeRPCLatency("CoreCoinTypeGetCbc20ContractBalance", s, err) }(time.Now())
   380  	return c.b.CoreCoinTypeGetCbc20ContractBalance(addrDesc, contractDesc)
   381  }
   382  
   383  type mempoolWithMetrics struct {
   384  	mempool bchain.Mempool
   385  	m       *common.Metrics
   386  }
   387  
   388  func (c *mempoolWithMetrics) observeRPCLatency(method string, start time.Time, err error) {
   389  	var e string
   390  	if err != nil {
   391  		e = "failure"
   392  	}
   393  	c.m.RPCLatency.With(common.Labels{"method": method, "error": e}).Observe(float64(time.Since(start)) / 1e6) // in milliseconds
   394  }
   395  
   396  func (c *mempoolWithMetrics) Resync() (count int, err error) {
   397  	defer func(s time.Time) { c.observeRPCLatency("ResyncMempool", s, err) }(time.Now())
   398  	count, err = c.mempool.Resync()
   399  	if err == nil {
   400  		c.m.MempoolSize.Set(float64(count))
   401  	}
   402  	return count, err
   403  }
   404  
   405  func (c *mempoolWithMetrics) GetTransactions(address string) (v []bchain.Outpoint, err error) {
   406  	defer func(s time.Time) { c.observeRPCLatency("GetMempoolTransactions", s, err) }(time.Now())
   407  	return c.mempool.GetTransactions(address)
   408  }
   409  
   410  func (c *mempoolWithMetrics) GetAddrDescTransactions(addrDesc bchain.AddressDescriptor) (v []bchain.Outpoint, err error) {
   411  	defer func(s time.Time) { c.observeRPCLatency("GetMempoolTransactionsForAddrDesc", s, err) }(time.Now())
   412  	return c.mempool.GetAddrDescTransactions(addrDesc)
   413  }
   414  
   415  func (c *mempoolWithMetrics) GetAllEntries() (v bchain.MempoolTxidEntries) {
   416  	defer func(s time.Time) { c.observeRPCLatency("GetAllEntries", s, nil) }(time.Now())
   417  	return c.mempool.GetAllEntries()
   418  }
   419  
   420  func (c *mempoolWithMetrics) GetTransactionTime(txid string) uint32 {
   421  	return c.mempool.GetTransactionTime(txid)
   422  }
   423  
   424  func (c *mempoolWithMetrics) GetTxidFilterEntries(filterScripts string, fromTimestamp uint32) (bchain.MempoolTxidFilterEntries, error) {
   425  	return c.mempool.GetTxidFilterEntries(filterScripts, fromTimestamp)
   426  }