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