diff --git a/.editorconfig b/.editorconfig new file mode 100644 index 00000000..2048f1d1 --- /dev/null +++ b/.editorconfig @@ -0,0 +1,10 @@ +root = true + +[*.md] +indent_style = space +indent_size = 4 +trim_trailing_whitespace = false +max_line_length = 80 +insert_final_newline = true +charset = utf-8 +end_of_line = lf diff --git a/Makefile b/Makefile index dfe5b5f3..9c015504 100644 --- a/Makefile +++ b/Makefile @@ -1,9 +1,10 @@ BIN_IMAGE = blockbook-build DEB_IMAGE = blockbook-build-deb PACKAGER = $(shell id -u):$(shell id -g) +DOCKER_VERSION = $(shell docker version --format '{{.Client.Version}}') BASE_IMAGE = $$(awk -F= '$$1=="ID" { print $$2 ;}' /etc/os-release):$$(awk -F= '$$1=="VERSION_ID" { print $$2 ;}' /etc/os-release | tr -d '"') NO_CACHE = false -TCMALLOC = +TCMALLOC = PORTABLE = 0 ARGS ?= @@ -27,7 +28,7 @@ test-all: .bin-image docker run -t --rm -e PACKAGER=$(PACKAGER) -v "$(CURDIR):/src" --network="host" $(BIN_IMAGE) make test-all ARGS="$(ARGS)" deb-backend-%: .deb-image - docker run -t --rm -e PACKAGER=$(PACKAGER) -v "$(CURDIR):/src" -v "$(CURDIR)/build:/out" $(DEB_IMAGE) /build/build-deb.sh backend $* $(ARGS) + docker run -t --rm -e PACKAGER=$(PACKAGER) -v /var/run/docker.sock:/var/run/docker.sock -v "$(CURDIR):/src" -v "$(CURDIR)/build:/out" $(DEB_IMAGE) /build/build-deb.sh backend $* $(ARGS) deb-blockbook-%: .deb-image docker run -t --rm -e PACKAGER=$(PACKAGER) -v "$(CURDIR):/src" -v "$(CURDIR)/build:/out" $(DEB_IMAGE) /build/build-deb.sh blockbook $* $(ARGS) @@ -55,7 +56,7 @@ build-images: clean-images .deb-image: .bin-image @if [ $$(build/tools/image_status.sh $(DEB_IMAGE):latest build/docker) != "ok" ]; then \ echo "Building image $(DEB_IMAGE)..."; \ - docker build --no-cache=$(NO_CACHE) -t $(DEB_IMAGE) build/docker/deb; \ + docker build --no-cache=$(NO_CACHE) --build-arg DOCKER_VERSION=$(DOCKER_VERSION) -t $(DEB_IMAGE) build/docker/deb; \ else \ echo "Image $(DEB_IMAGE) is up to date"; \ fi @@ -79,3 +80,6 @@ clean-bin-image: clean-deb-image: - docker rmi $(DEB_IMAGE) + +style: + find . -name "*.go" -exec gofmt -w {} \; diff --git a/README.md b/README.md index 7f764eca..79774889 100644 --- a/README.md +++ b/README.md @@ -220,3 +220,7 @@ Blockbook stores data the key-value store RocksDB. Database format is described ## API Blockbook API is described [here](/docs/api.md). + +## Environment variables + +List of environment variables that affect Blockbook's behavior is [here](/docs/env.md). diff --git a/api/ethereumtype.go b/api/ethereumtype.go index b4aa9446..1f98f2ee 100644 --- a/api/ethereumtype.go +++ b/api/ethereumtype.go @@ -62,7 +62,7 @@ func (w *Worker) RefetchInternalDataRoutine() { if block != nil { blockSpecificData, _ = block.CoinSpecificData.(*bchain.EthereumBlockSpecificData) } - if err != nil || block == nil || blockSpecificData == nil || blockSpecificData.InternalDataError != "" { + if err != nil || block == nil || (blockSpecificData != nil && blockSpecificData.InternalDataError != "") { glog.Errorf("Refetching internal data for %d %s, error %v, retrying", ie.Height, ie.Hash, err) // try for second time to fetch the data - the 2nd attempt after the first unsuccessful has many times higher probability of success // probably something to do with data preloaded to cache on the backend diff --git a/api/types.go b/api/types.go index 0bc2f53a..c2839893 100644 --- a/api/types.go +++ b/api/types.go @@ -232,6 +232,10 @@ type EthereumSpecific struct { GasLimit *big.Int `json:"gasLimit"` GasUsed *big.Int `json:"gasUsed,omitempty"` GasPrice *Amount `json:"gasPrice,omitempty"` + L1Fee *big.Int `json:"l1Fee,omitempty"` + L1FeeScalar string `json:"l1FeeScalar,omitempty"` + L1GasPrice *Amount `json:"l1GasPrice,omitempty"` + L1GasUsed *big.Int `json:"l1GasUsed,omitempty"` Data string `json:"data,omitempty"` ParsedData *bchain.EthereumParsedInputData `json:"parsedData,omitempty"` InternalTransfers []EthereumInternalTransfer `json:"internalTransfers,omitempty"` @@ -499,6 +503,7 @@ type BlockRaw struct { // BlockbookInfo contains information about the running blockbook instance type BlockbookInfo struct { Coin string `json:"coin"` + Network string `json:"network"` Host string `json:"host"` Version string `json:"version"` GitCommit string `json:"gitCommit"` diff --git a/api/worker.go b/api/worker.go index 88f63b98..c75486e5 100644 --- a/api/worker.go +++ b/api/worker.go @@ -172,9 +172,18 @@ func (w *Worker) getAddressAliases(addresses map[string]struct{}) AddressAliases } for a := range addresses { if w.chainType == bchain.ChainEthereumType { - ci, err := w.db.GetContractInfoForAddress(a) - if err == nil && ci != nil && ci.Name != "" { - aliases[a] = AddressAlias{Type: "Contract", Alias: ci.Name} + addrDesc, err := w.chainParser.GetAddrDescFromAddress(a) + if err != nil || addrDesc == nil { + continue + } + ci, err := w.db.GetContractInfo(addrDesc, bchain.UnknownTokenType) + if err == nil && ci != nil { + if ci.Type == bchain.UnhandledTokenType { + ci, _, err = w.getContractDescriptorInfo(addrDesc, bchain.UnknownTokenType) + } + if err == nil && ci != nil && ci.Name != "" { + aliases[a] = AddressAlias{Type: "Contract", Alias: ci.Name} + } } } n := w.db.GetAddressAlias(a) @@ -198,6 +207,11 @@ func (w *Worker) GetTransaction(txid string, spendingTxs bool, specificJSON bool return tx, nil } +// GetRawTransaction gets raw transaction data in hex format from txid +func (w *Worker) GetRawTransaction(txid string) (string, error) { + return w.chain.EthereumTypeGetRawTransaction(txid) +} + // getTransaction reads transaction data from txid func (w *Worker) getTransaction(txid string, spendingTxs bool, specificJSON bool, addresses map[string]struct{}) (*Tx, error) { bchainTx, height, err := w.txCache.GetTransaction(txid) @@ -429,18 +443,25 @@ func (w *Worker) getTransactionFromBchainTx(bchainTx *bchain.Tx, height int, spe // mempool txs do not have fees yet if ethTxData.GasUsed != nil { feesSat.Mul(ethTxData.GasPrice, ethTxData.GasUsed) + if ethTxData.L1Fee != nil { + feesSat.Add(&feesSat, ethTxData.L1Fee) + } } if len(bchainTx.Vout) > 0 { valOutSat = bchainTx.Vout[0].ValueSat } ethSpecific = &EthereumSpecific{ - GasLimit: ethTxData.GasLimit, - GasPrice: (*Amount)(ethTxData.GasPrice), - GasUsed: ethTxData.GasUsed, - Nonce: ethTxData.Nonce, - Status: ethTxData.Status, - Data: ethTxData.Data, - ParsedData: parsedInputData, + GasLimit: ethTxData.GasLimit, + GasPrice: (*Amount)(ethTxData.GasPrice), + GasUsed: ethTxData.GasUsed, + L1Fee: ethTxData.L1Fee, + L1FeeScalar: ethTxData.L1FeeScalar, + L1GasPrice: (*Amount)(ethTxData.L1GasPrice), + L1GasUsed: ethTxData.L1GasUsed, + Nonce: ethTxData.Nonce, + Status: ethTxData.Status, + Data: ethTxData.Data, + ParsedData: parsedInputData, } if internalData != nil { ethSpecific.Type = internalData.Type @@ -601,7 +622,7 @@ func (w *Worker) GetTransactionFromMempoolTx(mempoolTx *bchain.MempoolTx) (*Tx, return r, nil } -func (w *Worker) getContractInfo(contract string, typeFromContext bchain.TokenTypeName) (*bchain.ContractInfo, bool, error) { +func (w *Worker) GetContractInfo(contract string, typeFromContext bchain.TokenTypeName) (*bchain.ContractInfo, bool, error) { cd, err := w.chainParser.GetAddrDescFromAddress(contract) if err != nil { return nil, false, err @@ -641,7 +662,7 @@ func (w *Worker) getContractDescriptorInfo(cd bchain.AddressDescriptor, typeFrom glog.Errorf("StoreContractInfo error %v, contract %v", err, cd) } } - } else if (len(contractInfo.Name) > 0 && contractInfo.Name[0] == 0) || (len(contractInfo.Symbol) > 0 && contractInfo.Symbol[0] == 0) { + } else if (contractInfo.Type == bchain.UnhandledTokenType || len(contractInfo.Name) > 0 && contractInfo.Name[0] == 0) || (len(contractInfo.Symbol) > 0 && contractInfo.Symbol[0] == 0) { // fix contract name/symbol that was parsed as a string consisting of zeroes blockchainContractInfo, err := w.chain.GetContractInfo(cd) if err != nil { @@ -660,6 +681,10 @@ func (w *Worker) getContractDescriptorInfo(cd bchain.AddressDescriptor, typeFrom if blockchainContractInfo != nil { contractInfo.Decimals = blockchainContractInfo.Decimals } + if contractInfo.Type == bchain.UnhandledTokenType { + glog.Infof("Contract %v %v [%s] handled", cd, typeFromContext, contractInfo.Name) + contractInfo.Type = typeFromContext + } if err = w.db.StoreContractInfo(contractInfo); err != nil { glog.Errorf("StoreContractInfo error %v, contract %v", err, cd) } @@ -680,7 +705,7 @@ func (w *Worker) getEthereumTokensTransfers(transfers bchain.TokenTransfers, add if info, ok := contractCache[t.Contract]; ok { contractInfo = info } else { - info, _, err := w.getContractInfo(t.Contract, typeName) + info, _, err := w.GetContractInfo(t.Contract, typeName) if err != nil { glog.Errorf("getContractInfo error %v, contract %v", err, t.Contract) continue @@ -1117,10 +1142,16 @@ func (w *Worker) getEthereumTypeAddressBalances(addrDesc bchain.AddressDescripto d.tokens = d.tokens[:j] sort.Sort(d.tokens) } - d.contractInfo, err = w.db.GetContractInfo(addrDesc, "") + d.contractInfo, err = w.db.GetContractInfo(addrDesc, bchain.UnknownTokenType) if err != nil { return nil, nil, err } + if d.contractInfo != nil && d.contractInfo.Type == bchain.UnhandledTokenType { + d.contractInfo, _, err = w.getContractDescriptorInfo(addrDesc, bchain.UnknownTokenType) + if err != nil { + return nil, nil, err + } + } if filter.FromHeight == 0 && filter.ToHeight == 0 { // compute total results for paging if filter.Vout == AddressFilterVoutOff { @@ -2406,6 +2437,7 @@ func (w *Worker) GetSystemInfo(internal bool) (*SystemInfo, error) { } blockbookInfo := &BlockbookInfo{ Coin: w.is.Coin, + Network: w.is.GetNetwork(), Host: w.is.Host, Version: vi.Version, GitCommit: vi.GitCommit, diff --git a/bchain/basechain.go b/bchain/basechain.go index cecd2954..5618c1d7 100644 --- a/bchain/basechain.go +++ b/bchain/basechain.go @@ -64,7 +64,7 @@ func (b *BaseChain) EthereumTypeGetErc20ContractBalance(addrDesc, contractDesc A return nil, errors.New("not supported") } -// GetContractInfo returns URI of non fungible or multi token defined by token id +// GetTokenURI returns URI of non fungible or multi token defined by token id func (p *BaseChain) GetTokenURI(contractDesc AddressDescriptor, tokenID *big.Int) (string, error) { return "", errors.New("not supported") } @@ -76,3 +76,12 @@ func (b *BaseChain) EthereumTypeGetSupportedStakingPools() []string { func (b *BaseChain) EthereumTypeGetStakingPoolsData(addrDesc AddressDescriptor) ([]StakingPoolData, error) { return nil, errors.New("not supported") } + +// EthereumTypeRpcCall calls eth_call with given data and to address +func (b *BaseChain) EthereumTypeRpcCall(data, to, from string) (string, error) { + return "", errors.New("not supported") +} + +func (b *BaseChain) EthereumTypeGetRawTransaction(txid string) (string, error) { + return "", errors.New("not supported") +} diff --git a/bchain/coins/arbitrum/arbitrumrpc.go b/bchain/coins/arbitrum/arbitrumrpc.go new file mode 100644 index 00000000..e8c25354 --- /dev/null +++ b/bchain/coins/arbitrum/arbitrumrpc.go @@ -0,0 +1,77 @@ +package arbitrum + +import ( + "context" + "encoding/json" + + "github.com/golang/glog" + "github.com/juju/errors" + "github.com/trezor/blockbook/bchain" + "github.com/trezor/blockbook/bchain/coins/eth" +) + +const ( + ArbitrumOneMainNet eth.Network = 42161 + ArbitrumNovaMainNet eth.Network = 42170 +) + +// ArbitrumRPC is an interface to JSON-RPC arbitrum service. +type ArbitrumRPC struct { + *eth.EthereumRPC +} + +// NewArbitrumRPC returns new ArbitrumRPC instance. +func NewArbitrumRPC(config json.RawMessage, pushHandler func(bchain.NotificationType)) (bchain.BlockChain, error) { + c, err := eth.NewEthereumRPC(config, pushHandler) + if err != nil { + return nil, err + } + + s := &ArbitrumRPC{ + EthereumRPC: c.(*eth.EthereumRPC), + } + + return s, nil +} + +// Initialize arbitrum rpc interface +func (b *ArbitrumRPC) Initialize() error { + b.OpenRPC = eth.OpenRPC + + rc, ec, err := b.OpenRPC(b.ChainConfig.RPCURL) + if err != nil { + return err + } + + // set chain specific + b.Client = ec + b.RPC = rc + b.NewBlock = eth.NewEthereumNewBlock() + b.NewTx = eth.NewEthereumNewTx() + + ctx, cancel := context.WithTimeout(context.Background(), b.Timeout) + defer cancel() + + id, err := b.Client.NetworkID(ctx) + if err != nil { + return err + } + + // parameters for getInfo request + switch eth.Network(id.Uint64()) { + case ArbitrumOneMainNet: + b.MainNetChainID = ArbitrumOneMainNet + b.Testnet = false + b.Network = "livenet" + case ArbitrumNovaMainNet: + b.MainNetChainID = ArbitrumNovaMainNet + b.Testnet = false + b.Network = "livenet" + default: + return errors.Errorf("Unknown network id %v", id) + } + + glog.Info("rpc: block chain ", b.Network) + + return nil +} diff --git a/bchain/coins/blockchain.go b/bchain/coins/blockchain.go index b456f0d0..ff596fa3 100644 --- a/bchain/coins/blockchain.go +++ b/bchain/coins/blockchain.go @@ -11,6 +11,7 @@ import ( "github.com/juju/errors" "github.com/trezor/blockbook/bchain" + "github.com/trezor/blockbook/bchain/coins/arbitrum" "github.com/trezor/blockbook/bchain/coins/avalanche" "github.com/trezor/blockbook/bchain/coins/bch" "github.com/trezor/blockbook/bchain/coins/bellcoin" @@ -42,6 +43,7 @@ import ( "github.com/trezor/blockbook/bchain/coins/namecoin" "github.com/trezor/blockbook/bchain/coins/nuls" "github.com/trezor/blockbook/bchain/coins/omotenashicoin" + "github.com/trezor/blockbook/bchain/coins/optimism" "github.com/trezor/blockbook/bchain/coins/pivx" "github.com/trezor/blockbook/bchain/coins/polis" "github.com/trezor/blockbook/bchain/coins/polygon" @@ -66,6 +68,7 @@ var BlockChainFactories = make(map[string]blockChainFactory) func init() { BlockChainFactories["Bitcoin"] = btc.NewBitcoinRPC BlockChainFactories["Testnet"] = btc.NewBitcoinRPC + BlockChainFactories["Testnet4"] = btc.NewBitcoinRPC BlockChainFactories["Signet"] = btc.NewBitcoinRPC BlockChainFactories["Regtest"] = btc.NewBitcoinRPC BlockChainFactories["Zcash"] = zec.NewZCashRPC @@ -139,6 +142,12 @@ func init() { BlockChainFactories["BNB Smart Chain Archive"] = bsc.NewBNBSmartChainRPC BlockChainFactories["Polygon"] = polygon.NewPolygonRPC BlockChainFactories["Polygon Archive"] = polygon.NewPolygonRPC + BlockChainFactories["Optimism"] = optimism.NewOptimismRPC + BlockChainFactories["Optimism Archive"] = optimism.NewOptimismRPC + BlockChainFactories["Arbitrum"] = arbitrum.NewArbitrumRPC + BlockChainFactories["Arbitrum Archive"] = arbitrum.NewArbitrumRPC + BlockChainFactories["Arbitrum Nova"] = arbitrum.NewArbitrumRPC + BlockChainFactories["Arbitrum Nova Archive"] = arbitrum.NewArbitrumRPC } // NewBlockChain creates bchain.BlockChain and bchain.Mempool for the coin passed by the parameter coin @@ -325,7 +334,7 @@ func (c *blockChainWithMetrics) EthereumTypeGetErc20ContractBalance(addrDesc, co return c.b.EthereumTypeGetErc20ContractBalance(addrDesc, contractDesc) } -// GetContractInfo returns URI of non fungible or multi token defined by token id +// GetTokenURI returns URI of non fungible or multi token defined by token id func (c *blockChainWithMetrics) GetTokenURI(contractDesc bchain.AddressDescriptor, tokenID *big.Int) (v string, err error) { defer func(s time.Time) { c.observeRPCLatency("GetTokenURI", s, err) }(time.Now()) return c.b.GetTokenURI(contractDesc, tokenID) @@ -340,6 +349,17 @@ func (c *blockChainWithMetrics) EthereumTypeGetStakingPoolsData(addrDesc bchain. return c.b.EthereumTypeGetStakingPoolsData(addrDesc) } +// EthereumTypeRpcCall calls eth_call with given data and to address +func (c *blockChainWithMetrics) EthereumTypeRpcCall(data, to, from string) (v string, err error) { + defer func(s time.Time) { c.observeRPCLatency("EthereumTypeRpcCall", s, err) }(time.Now()) + return c.b.EthereumTypeRpcCall(data, to, from) +} + +func (c *blockChainWithMetrics) EthereumTypeGetRawTransaction(txid string) (v string, err error) { + defer func(s time.Time) { c.observeRPCLatency("EthereumTypeGetRawTransaction", s, err) }(time.Now()) + return c.b.EthereumTypeGetRawTransaction(txid) +} + type mempoolWithMetrics struct { mempool bchain.Mempool m *common.Metrics diff --git a/bchain/coins/btc/bitcoinparser.go b/bchain/coins/btc/bitcoinparser.go index 77cbcf26..a022c18e 100644 --- a/bchain/coins/btc/bitcoinparser.go +++ b/bchain/coins/btc/bitcoinparser.go @@ -4,11 +4,28 @@ import ( "encoding/json" "math/big" + "github.com/martinboehm/btcd/wire" "github.com/martinboehm/btcutil/chaincfg" "github.com/trezor/blockbook/bchain" "github.com/trezor/blockbook/common" ) +// temp params for signet(wait btcd commit) +// magic numbers +const ( + Testnet4Magic wire.BitcoinNet = 0x283f161c +) + +// chain parameters +var ( + TestNet4Params chaincfg.Params +) + +func init() { + TestNet4Params = chaincfg.TestNet3Params + TestNet4Params.Net = Testnet4Magic +} + // BitcoinParser handle type BitcoinParser struct { *BitcoinLikeParser @@ -33,6 +50,8 @@ func GetChainParams(chain string) *chaincfg.Params { switch chain { case "test": return &chaincfg.TestNet3Params + case "testnet4": + return &TestNet4Params case "regtest": return &chaincfg.RegressionNetParams case "signet": diff --git a/bchain/coins/btc/bitcoinparser_test.go b/bchain/coins/btc/bitcoinparser_test.go index 1ca0d4ec..a697cbfd 100644 --- a/bchain/coins/btc/bitcoinparser_test.go +++ b/bchain/coins/btc/bitcoinparser_test.go @@ -467,11 +467,12 @@ func TestGetAddressesFromAddrDescTestnet(t *testing.T) { } var ( - testTx1, testTx2, testTx3 bchain.Tx + testTx1, testTx2, testTx3, testTx4 bchain.Tx testTxPacked1 = "0001e2408ba8d7af5401000000017f9a22c9cbf54bd902400df746f138f37bcf5b4d93eb755820e974ba43ed5f42040000006a4730440220037f4ed5427cde81d55b9b6a2fd08c8a25090c2c2fff3a75c1a57625ca8a7118022076c702fe55969fa08137f71afd4851c48e31082dd3c40c919c92cdbc826758d30121029f6da5623c9f9b68a9baf9c1bc7511df88fa34c6c2f71f7c62f2f03ff48dca80feffffff019c9700000000000017a9146144d57c8aff48492c9dfb914e120b20bad72d6f8773d00700" testTxPacked2 = "0007c91a899ab7da6a010000000001019d64f0c72a0d206001decbffaa722eb1044534c74eee7a5df8318e42a4323ec10000000017160014550da1f5d25a9dae2eafd6902b4194c4c6500af6ffffffff02809698000000000017a914cd668d781ece600efa4b2404dc91fd26b8b8aed8870553d7360000000017a914246655bdbd54c7e477d0ea2375e86e0db2b8f80a8702473044022076aba4ad559616905fa51d4ddd357fc1fdb428d40cb388e042cdd1da4a1b7357022011916f90c712ead9a66d5f058252efd280439ad8956a967e95d437d246710bc9012102a80a5964c5612bb769ef73147b2cf3c149bc0fd4ecb02f8097629c94ab013ffd00000000" testTxPacked3 = "00003d818bfda9aa3e02000000000102deb1999a857ab0a13d6b12fbd95ea75b409edde5f2ff747507ce42d9986a8b9d0000000000fdffffff9fd2d3361e203b2375eba6438efbef5b3075531e7e583c7cc76b7294fe7f22980000000000fdffffff02a0860100000000001600148091746745464e7555c31e9a5afceac14a02978ae7fc1c0000000000160014565ea9ff4589d3e05ba149ae6e257752bfdc2a1e0247304402207d67d320a8e813f986b35e9791935fcb736754812b7038686f5de6cfdcda99cd02201c3bb2c178e0056016437ecfe365a7eef84aa9d293ebdc566177af82e22fcdd3012103abb30c1bbe878b07b58dc169b1d061d48c60be8107f632a59778b38bf7ceea5a02473044022044f54a478cfe086e870cb026c9dcd4e14e63778bef569a4d55a6332725cd9a9802202f0e94c04e6f328fc64ad9efe552888c299750d1b8d033324825a3ff29920e030121036fcd433428aa7dc65c4f5408fa31f208c54fe4b4c6c1ae9c39a825ed4f1ac039813d0000" + testTxPacked4 = "0000a2b98ced82b6400300000000010148f8f93ebb12407809920d2ab9cc1bf01289b314eb23028c83fdab21e5fefa690100000000fdffffff0150c3000000000000160014cb888de3c89670a3061fb6ef6590f187649cca060247304402206a9db8d7157e4b0a06a1f090b9de88cdc616028b431b80617a055117877e479a02202937d6d1658d4a8afde86b245325c3bb0e769a87cb09d802bcefaa21550065e201210374aa8f312de4ebccbef55609700a39764387aa4ff5d76f1ccb4d2382e454f05b00000000" ) func init() { @@ -595,6 +596,37 @@ func init() { }, }, } + + testTx4 = bchain.Tx{ + Hex: "0300000000010148f8f93ebb12407809920d2ab9cc1bf01289b314eb23028c83fdab21e5fefa690100000000fdffffff0150c3000000000000160014cb888de3c89670a3061fb6ef6590f187649cca060247304402206a9db8d7157e4b0a06a1f090b9de88cdc616028b431b80617a055117877e479a02202937d6d1658d4a8afde86b245325c3bb0e769a87cb09d802bcefaa21550065e201210374aa8f312de4ebccbef55609700a39764387aa4ff5d76f1ccb4d2382e454f05b00000000", + Blocktime: 1724927392, + Txid: "8e3f38bf6854dd3c358be8d4f9a40a6dccc50de49616125d27af9fdbe65287eb", + LockTime: 0, + VSize: 110, + Version: 3, + Vin: []bchain.Vin{ + { + ScriptSig: bchain.ScriptSig{ + Hex: "", + }, + Txid: "69fafee521abfd838c0223eb14b38912f01bccb92a0d9209784012bb3ef9f848", + Vout: 1, + Sequence: 4294967293, + }, + }, + Vout: []bchain.Vout{ + { + ValueSat: *big.NewInt(50000), + N: 0, + ScriptPubKey: bchain.ScriptPubKey{ + Hex: "0014cb888de3c89670a3061fb6ef6590f187649cca06", + Addresses: []string{ + "tb1qewygmc7gjec2xpslkmhkty83sajfejsxqmy5dq", + }, + }, + }, + }, + } } func TestPackTx(t *testing.T) { @@ -643,6 +675,17 @@ func TestPackTx(t *testing.T) { want: testTxPacked3, wantErr: false, }, + { + name: "testnet4-1", + args: args{ + tx: testTx4, + height: 41657, + blockTime: 1724927392, + parser: NewBitcoinParser(GetChainParams("testnet4"), &Configuration{}), + }, + want: testTxPacked4, + wantErr: false, + }, } for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { @@ -701,6 +744,16 @@ func TestUnpackTx(t *testing.T) { want1: 15745, wantErr: false, }, + { + name: "testnet4-1", + args: args{ + packedTx: testTxPacked4, + parser: NewBitcoinParser(GetChainParams("testnet4"), &Configuration{}), + }, + want: &testTx4, + want1: 41657, + wantErr: false, + }, } for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { diff --git a/bchain/coins/ecash/ecashparser.go b/bchain/coins/ecash/ecashparser.go index e4547ae8..2b4ef881 100644 --- a/bchain/coins/ecash/ecashparser.go +++ b/bchain/coins/ecash/ecashparser.go @@ -3,11 +3,11 @@ package ecash import ( "fmt" - "github.com/pirk/ecashutil" "github.com/martinboehm/btcutil" "github.com/martinboehm/btcutil/chaincfg" "github.com/martinboehm/btcutil/txscript" "github.com/pirk/ecashaddr-converter/address" + "github.com/pirk/ecashutil" "github.com/trezor/blockbook/bchain" "github.com/trezor/blockbook/bchain/coins/btc" ) diff --git a/bchain/coins/eth/contract.go b/bchain/coins/eth/contract.go index 34916346..6dbca33e 100644 --- a/bchain/coins/eth/contract.go +++ b/bchain/coins/eth/contract.go @@ -273,14 +273,19 @@ func contractGetTransfersFromTx(tx *bchain.RpcTransaction) (bchain.TokenTransfer return r, nil } -func (b *EthereumRPC) ethCall(data, to string) (string, error) { +// EthereumTypeRpcCall calls eth_call with given data and to address +func (b *EthereumRPC) EthereumTypeRpcCall(data, to, from string) (string, error) { ctx, cancel := context.WithTimeout(context.Background(), b.Timeout) defer cancel() var r string - err := b.RPC.CallContext(ctx, &r, "eth_call", map[string]interface{}{ + args := map[string]interface{}{ "data": data, "to": to, - }, "latest") + } + if from != "" { + args["from"] = from + } + err := b.RPC.CallContext(ctx, &r, "eth_call", args, "latest") if err != nil { return "", err } @@ -289,7 +294,7 @@ func (b *EthereumRPC) ethCall(data, to string) (string, error) { func (b *EthereumRPC) fetchContractInfo(address string) (*bchain.ContractInfo, error) { var contract bchain.ContractInfo - data, err := b.ethCall(contractNameSignature, address) + data, err := b.EthereumTypeRpcCall(contractNameSignature, address, "") if err != nil { // ignore the error from the eth_call - since geth v1.9.15 they changed the behavior // and returning error "execution reverted" for some non contract addresses @@ -300,14 +305,14 @@ func (b *EthereumRPC) fetchContractInfo(address string) (*bchain.ContractInfo, e } name := strings.TrimSpace(parseSimpleStringProperty(data)) if name != "" { - data, err = b.ethCall(contractSymbolSignature, address) + data, err = b.EthereumTypeRpcCall(contractSymbolSignature, address, "") if err != nil { // glog.Warning(errors.Annotatef(err, "Contract SymbolSignature %v", address)) return nil, nil // return nil, errors.Annotatef(err, "erc20SymbolSignature %v", address) } symbol := strings.TrimSpace(parseSimpleStringProperty(data)) - data, _ = b.ethCall(contractDecimalsSignature, address) + data, _ = b.EthereumTypeRpcCall(contractDecimalsSignature, address, "") // if err != nil { // glog.Warning(errors.Annotatef(err, "Contract DecimalsSignature %v", address)) // // return nil, errors.Annotatef(err, "erc20DecimalsSignature %v", address) @@ -340,7 +345,7 @@ func (b *EthereumRPC) EthereumTypeGetErc20ContractBalance(addrDesc, contractDesc addr := hexutil.Encode(addrDesc)[2:] contract := hexutil.Encode(contractDesc) req := contractBalanceOfSignature + "0000000000000000000000000000000000000000000000000000000000000000"[len(addr):] + addr - data, err := b.ethCall(req, contract) + data, err := b.EthereumTypeRpcCall(req, contract, "") if err != nil { return nil, err } @@ -351,7 +356,7 @@ func (b *EthereumRPC) EthereumTypeGetErc20ContractBalance(addrDesc, contractDesc return r, nil } -// GetContractInfo returns URI of non fungible or multi token defined by token id +// GetTokenURI returns URI of non fungible or multi token defined by token id func (b *EthereumRPC) GetTokenURI(contractDesc bchain.AddressDescriptor, tokenID *big.Int) (string, error) { address := hexutil.Encode(contractDesc) // CryptoKitties do not fully support ERC721 standard, do not have tokenURI method @@ -364,7 +369,7 @@ func (b *EthereumRPC) GetTokenURI(contractDesc bchain.AddressDescriptor, tokenID } // try ERC721 tokenURI method and ERC1155 uri method for _, method := range []string{erc721TokenURIMethodSignature, erc1155URIMethodSignature} { - data, err := b.ethCall(method+id, address) + data, err := b.EthereumTypeRpcCall(method+id, address, "") if err == nil && data != "" { uri := parseSimpleStringProperty(data) // try to sanitize the URI returned from the contract diff --git a/bchain/coins/eth/ethparser.go b/bchain/coins/eth/ethparser.go index 975b8374..161c14ad 100644 --- a/bchain/coins/eth/ethparser.go +++ b/bchain/coins/eth/ethparser.go @@ -7,10 +7,10 @@ import ( "strings" "github.com/ethereum/go-ethereum/common/hexutil" - "github.com/golang/protobuf/proto" "github.com/juju/errors" "github.com/trezor/blockbook/bchain" "golang.org/x/crypto/sha3" + "google.golang.org/protobuf/proto" ) // EthereumTypeAddressDescriptorLen - the AddressDescriptor of EthereumType has fixed length @@ -331,6 +331,24 @@ func (p *EthereumParser) PackTx(tx *bchain.Tx, height uint32, blockTime int64) ( } pt.Receipt.Log = ptLogs + if r.Receipt.L1Fee != "" { + if pt.Receipt.L1Fee, err = hexDecodeBig(r.Receipt.L1Fee); err != nil { + return nil, errors.Annotatef(err, "L1Fee %v", r.Receipt.L1Fee) + } + } + if r.Receipt.L1FeeScalar != "" { + pt.Receipt.L1FeeScalar = []byte(r.Receipt.L1FeeScalar) + } + if r.Receipt.L1GasPrice != "" { + if pt.Receipt.L1GasPrice, err = hexDecodeBig(r.Receipt.L1GasPrice); err != nil { + return nil, errors.Annotatef(err, "L1GasPrice %v", r.Receipt.L1GasPrice) + } + } + if r.Receipt.L1GasUsed != "" { + if pt.Receipt.L1GasUsed, err = hexDecodeBig(r.Receipt.L1GasUsed); err != nil { + return nil, errors.Annotatef(err, "L1GasUsed %v", r.Receipt.L1GasUsed) + } + } } return proto.Marshal(pt) } @@ -359,27 +377,37 @@ func (p *EthereumParser) UnpackTx(buf []byte) (*bchain.Tx, uint32, error) { } var rr *bchain.RpcReceipt if pt.Receipt != nil { - logs := make([]*bchain.RpcLog, len(pt.Receipt.Log)) + rr = &bchain.RpcReceipt{ + GasUsed: hexEncodeBig(pt.Receipt.GasUsed), + Status: "", + Logs: make([]*bchain.RpcLog, len(pt.Receipt.Log)), + } for i, l := range pt.Receipt.Log { topics := make([]string, len(l.Topics)) for j, t := range l.Topics { topics[j] = hexutil.Encode(t) } - logs[i] = &bchain.RpcLog{ + rr.Logs[i] = &bchain.RpcLog{ Address: EIP55Address(l.Address), Data: hexutil.Encode(l.Data), Topics: topics, } } - status := "" // handle a special value []byte{'U'} as unknown state if len(pt.Receipt.Status) != 1 || pt.Receipt.Status[0] != 'U' { - status = hexEncodeBig(pt.Receipt.Status) + rr.Status = hexEncodeBig(pt.Receipt.Status) } - rr = &bchain.RpcReceipt{ - GasUsed: hexEncodeBig(pt.Receipt.GasUsed), - Status: status, - Logs: logs, + if len(pt.Receipt.L1Fee) > 0 { + rr.L1Fee = hexEncodeBig(pt.Receipt.L1Fee) + } + if len(pt.Receipt.L1FeeScalar) > 0 { + rr.L1FeeScalar = string(pt.Receipt.L1FeeScalar) + } + if len(pt.Receipt.L1GasPrice) > 0 { + rr.L1GasPrice = hexEncodeBig(pt.Receipt.L1GasPrice) + } + if len(pt.Receipt.L1GasUsed) > 0 { + rr.L1GasUsed = hexEncodeBig(pt.Receipt.L1GasUsed) } } // TODO handle internal transactions @@ -477,12 +505,16 @@ const ( // EthereumTxData contains ethereum specific transaction data type EthereumTxData struct { - Status TxStatus `json:"status"` // 1 OK, 0 Fail, -1 pending, -2 unknown - Nonce uint64 `json:"nonce"` - GasLimit *big.Int `json:"gaslimit"` - GasUsed *big.Int `json:"gasused"` - GasPrice *big.Int `json:"gasprice"` - Data string `json:"data"` + Status TxStatus `json:"status"` // 1 OK, 0 Fail, -1 pending, -2 unknown + Nonce uint64 `json:"nonce"` + GasLimit *big.Int `json:"gaslimit"` + GasUsed *big.Int `json:"gasused"` + GasPrice *big.Int `json:"gasprice"` + L1Fee *big.Int `json:"l1Fee,omitempty"` + L1FeeScalar string `json:"l1FeeScalar,omitempty"` + L1GasPrice *big.Int `json:"l1GasPrice,omitempty"` + L1GasUsed *big.Int `json:"L1GasUsed,omitempty"` + Data string `json:"data"` } // GetEthereumTxData returns EthereumTxData from bchain.Tx @@ -511,6 +543,10 @@ func GetEthereumTxDataFromSpecificData(coinSpecificData interface{}) *EthereumTx etd.Status = TxStatusFailure } etd.GasUsed, _ = hexutil.DecodeBig(csd.Receipt.GasUsed) + etd.L1Fee, _ = hexutil.DecodeBig(csd.Receipt.L1Fee) + etd.L1GasPrice, _ = hexutil.DecodeBig(csd.Receipt.L1GasPrice) + etd.L1GasUsed, _ = hexutil.DecodeBig(csd.Receipt.L1GasUsed) + etd.L1FeeScalar = csd.Receipt.L1FeeScalar } } return &etd diff --git a/bchain/coins/eth/ethrpc.go b/bchain/coins/eth/ethrpc.go index 1405ea3b..67b9a289 100644 --- a/bchain/coins/eth/ethrpc.go +++ b/bchain/coins/eth/ethrpc.go @@ -4,7 +4,7 @@ import ( "context" "encoding/json" "fmt" - "io/ioutil" + "io" "math/big" "net/http" "strconv" @@ -40,6 +40,7 @@ const ( type Configuration struct { CoinName string `json:"coin_name"` CoinShortcut string `json:"coin_shortcut"` + Network string `json:"network"` RPCURL string `json:"rpc_url"` RPCTimeout int `json:"rpc_timeout"` BlockAddressesToKeep int `json:"block_addresses_to_keep"` @@ -49,6 +50,7 @@ type Configuration struct { ProcessInternalTransactions bool `json:"processInternalTransactions"` ProcessZeroInternalTransactions bool `json:"processZeroInternalTransactions"` ConsensusNodeVersionURL string `json:"consensusNodeVersion"` + DisableMempoolSync bool `json:"disableMempoolSync,omitempty"` } // EthereumRPC is an interface to JSON-RPC eth service. @@ -159,7 +161,7 @@ func (b *EthereumRPC) Initialize() error { return errors.Errorf("Unknown network id %v", id) } - err = b.initStakingPools(b.ChainConfig.CoinShortcut) + err = b.initStakingPools() if err != nil { return err } @@ -173,7 +175,7 @@ func (b *EthereumRPC) Initialize() error { func (b *EthereumRPC) CreateMempool(chain bchain.BlockChain) (bchain.Mempool, error) { if b.Mempool == nil { b.Mempool = bchain.NewMempoolEthereumType(chain, b.ChainConfig.MempoolTxTimeoutHours, b.ChainConfig.QueryBackendOnMempoolResync) - glog.Info("mempool created, MempoolTxTimeoutHours=", b.ChainConfig.MempoolTxTimeoutHours, ", QueryBackendOnMempoolResync=", b.ChainConfig.QueryBackendOnMempoolResync) + glog.Info("mempool created, MempoolTxTimeoutHours=", b.ChainConfig.MempoolTxTimeoutHours, ", QueryBackendOnMempoolResync=", b.ChainConfig.QueryBackendOnMempoolResync, ", DisableMempoolSync=", b.ChainConfig.DisableMempoolSync) } return b.Mempool, nil } @@ -262,21 +264,23 @@ func (b *EthereumRPC) subscribeEvents() error { } }() - // new mempool transaction subscription - if err := b.subscribe(func() (bchain.EVMClientSubscription, error) { - // invalidate the previous subscription - it is either the first one or there was an error - b.newTxSubscription = nil - ctx, cancel := context.WithTimeout(context.Background(), b.Timeout) - defer cancel() - sub, err := b.RPC.EthSubscribe(ctx, b.NewTx.Channel(), "newPendingTransactions") - if err != nil { - return nil, errors.Annotatef(err, "EthSubscribe newPendingTransactions") + if !b.ChainConfig.DisableMempoolSync { + // new mempool transaction subscription + if err := b.subscribe(func() (bchain.EVMClientSubscription, error) { + // invalidate the previous subscription - it is either the first one or there was an error + b.newTxSubscription = nil + ctx, cancel := context.WithTimeout(context.Background(), b.Timeout) + defer cancel() + sub, err := b.RPC.EthSubscribe(ctx, b.NewTx.Channel(), "newPendingTransactions") + if err != nil { + return nil, errors.Annotatef(err, "EthSubscribe newPendingTransactions") + } + b.newTxSubscription = sub + glog.Info("Subscribed to newPendingTransactions") + return sub, nil + }); err != nil { + return err } - b.newTxSubscription = sub - glog.Info("Subscribed to newPendingTransactions") - return sub, nil - }); err != nil { - return err } return nil @@ -377,7 +381,7 @@ func (b *EthereumRPC) getConsensusVersion() string { glog.Error("getConsensusVersion ", err) return "" } - body, err := ioutil.ReadAll(resp.Body) + body, err := io.ReadAll(resp.Body) if err != nil { glog.Error("getConsensusVersion ", err) return "" @@ -610,19 +614,24 @@ type rpcTraceResult struct { } func (b *EthereumRPC) getCreationContractInfo(contract string, height uint32) *bchain.ContractInfo { - ci, err := b.fetchContractInfo(contract) - if ci == nil || err != nil { - ci = &bchain.ContractInfo{ - Contract: contract, - } + // do not fetch fetchContractInfo in sync, it slows it down + // the contract will be fetched only when asked by a client + // ci, err := b.fetchContractInfo(contract) + // if ci == nil || err != nil { + ci := &bchain.ContractInfo{ + Contract: contract, } - ci.Type = bchain.UnknownTokenType + // } + ci.Type = bchain.UnhandledTokenType ci.CreatedInBlock = height return ci } func (b *EthereumRPC) processCallTrace(call *rpcCallTrace, d *bchain.EthereumInternalData, contracts []bchain.ContractInfo, blockHeight uint32) []bchain.ContractInfo { value, err := hexutil.DecodeBig(call.Value) + if err != nil { + value = new(big.Int) + } if call.Type == "CREATE" || call.Type == "CREATE2" { d.Transfers = append(d.Transfers, bchain.EthereumInternalTransfer{ Type: bchain.CREATE, @@ -834,12 +843,13 @@ func (b *EthereumRPC) GetTransactionForMempool(txid string) (*bchain.Tx, error) func (b *EthereumRPC) GetTransaction(txid string) (*bchain.Tx, error) { ctx, cancel := context.WithTimeout(context.Background(), b.Timeout) defer cancel() - var tx *bchain.RpcTransaction + tx := &bchain.RpcTransaction{} hash := ethcommon.HexToHash(txid) - err := b.RPC.CallContext(ctx, &tx, "eth_getTransactionByHash", hash) + err := b.RPC.CallContext(ctx, tx, "eth_getTransactionByHash", hash) if err != nil { return nil, err - } else if tx == nil { + } + if *tx == (bchain.RpcTransaction{}) { if b.mempoolInitialized { b.Mempool.RemoveTransactionFromMempool(txid) } @@ -982,21 +992,31 @@ func (b *EthereumRPC) EthereumTypeEstimateGas(params map[string]interface{}) (ui // SendRawTransaction sends raw transaction func (b *EthereumRPC) SendRawTransaction(hex string) (string, error) { + return b.callRpcStringResult("eth_sendRawTransaction", hex) +} + +// EthereumTypeGetRawTransaction gets raw transaction in hex format +func (b *EthereumRPC) EthereumTypeGetRawTransaction(txid string) (string, error) { + return b.callRpcStringResult("eth_getRawTransactionByHash", txid) +} + +// Helper function for calling ETH RPC with parameters and getting string result +func (b *EthereumRPC) callRpcStringResult(rpcMethod string, args ...interface{}) (string, error) { ctx, cancel := context.WithTimeout(context.Background(), b.Timeout) defer cancel() var raw json.RawMessage - err := b.RPC.CallContext(ctx, &raw, "eth_sendRawTransaction", hex) + err := b.RPC.CallContext(ctx, &raw, rpcMethod, args...) if err != nil { return "", err } else if len(raw) == 0 { - return "", errors.New("SendRawTransaction: failed") + return "", errors.New(rpcMethod + " : failed") } var result string if err := json.Unmarshal(raw, &result); err != nil { return "", errors.Annotatef(err, "raw result %v", raw) } if result == "" { - return "", errors.New("SendRawTransaction: failed, empty result") + return "", errors.New(rpcMethod + " : failed, empty result") } return result, nil } diff --git a/bchain/coins/eth/ethtx.pb.go b/bchain/coins/eth/ethtx.pb.go index 6023a259..0174ab9b 100644 --- a/bchain/coins/eth/ethtx.pb.go +++ b/bchain/coins/eth/ethtx.pb.go @@ -1,261 +1,530 @@ // Code generated by protoc-gen-go. DO NOT EDIT. +// versions: +// protoc-gen-go v1.28.1 +// protoc v3.21.12 // source: bchain/coins/eth/ethtx.proto -/* -Package eth is a generated protocol buffer package. - -It is generated from these files: - bchain/coins/eth/ethtx.proto - -It has these top-level messages: - ProtoCompleteTransaction -*/ package eth -import proto "github.com/golang/protobuf/proto" -import fmt "fmt" -import math "math" +import ( + protoreflect "google.golang.org/protobuf/reflect/protoreflect" + protoimpl "google.golang.org/protobuf/runtime/protoimpl" + reflect "reflect" + sync "sync" +) -// Reference imports to suppress errors if they are not otherwise used. -var _ = proto.Marshal -var _ = fmt.Errorf -var _ = math.Inf - -// This is a compile-time assertion to ensure that this generated file -// is compatible with the proto package it is being compiled against. -// A compilation error at this line likely means your copy of the -// proto package needs to be updated. -const _ = proto.ProtoPackageIsVersion2 // please upgrade the proto package +const ( + // Verify that this generated code is sufficiently up-to-date. + _ = protoimpl.EnforceVersion(20 - protoimpl.MinVersion) + // Verify that runtime/protoimpl is sufficiently up-to-date. + _ = protoimpl.EnforceVersion(protoimpl.MaxVersion - 20) +) type ProtoCompleteTransaction struct { - BlockNumber uint32 `protobuf:"varint,1,opt,name=BlockNumber" json:"BlockNumber,omitempty"` - BlockTime uint64 `protobuf:"varint,2,opt,name=BlockTime" json:"BlockTime,omitempty"` - Tx *ProtoCompleteTransaction_TxType `protobuf:"bytes,3,opt,name=Tx" json:"Tx,omitempty"` - Receipt *ProtoCompleteTransaction_ReceiptType `protobuf:"bytes,4,opt,name=Receipt" json:"Receipt,omitempty"` + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + BlockNumber uint32 `protobuf:"varint,1,opt,name=BlockNumber,proto3" json:"BlockNumber,omitempty"` + BlockTime uint64 `protobuf:"varint,2,opt,name=BlockTime,proto3" json:"BlockTime,omitempty"` + Tx *ProtoCompleteTransaction_TxType `protobuf:"bytes,3,opt,name=Tx,proto3" json:"Tx,omitempty"` + Receipt *ProtoCompleteTransaction_ReceiptType `protobuf:"bytes,4,opt,name=Receipt,proto3" json:"Receipt,omitempty"` } -func (m *ProtoCompleteTransaction) Reset() { *m = ProtoCompleteTransaction{} } -func (m *ProtoCompleteTransaction) String() string { return proto.CompactTextString(m) } -func (*ProtoCompleteTransaction) ProtoMessage() {} -func (*ProtoCompleteTransaction) Descriptor() ([]byte, []int) { return fileDescriptor0, []int{0} } +func (x *ProtoCompleteTransaction) Reset() { + *x = ProtoCompleteTransaction{} + if protoimpl.UnsafeEnabled { + mi := &file_bchain_coins_eth_ethtx_proto_msgTypes[0] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} -func (m *ProtoCompleteTransaction) GetBlockNumber() uint32 { - if m != nil { - return m.BlockNumber +func (x *ProtoCompleteTransaction) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*ProtoCompleteTransaction) ProtoMessage() {} + +func (x *ProtoCompleteTransaction) ProtoReflect() protoreflect.Message { + mi := &file_bchain_coins_eth_ethtx_proto_msgTypes[0] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use ProtoCompleteTransaction.ProtoReflect.Descriptor instead. +func (*ProtoCompleteTransaction) Descriptor() ([]byte, []int) { + return file_bchain_coins_eth_ethtx_proto_rawDescGZIP(), []int{0} +} + +func (x *ProtoCompleteTransaction) GetBlockNumber() uint32 { + if x != nil { + return x.BlockNumber } return 0 } -func (m *ProtoCompleteTransaction) GetBlockTime() uint64 { - if m != nil { - return m.BlockTime +func (x *ProtoCompleteTransaction) GetBlockTime() uint64 { + if x != nil { + return x.BlockTime } return 0 } -func (m *ProtoCompleteTransaction) GetTx() *ProtoCompleteTransaction_TxType { - if m != nil { - return m.Tx +func (x *ProtoCompleteTransaction) GetTx() *ProtoCompleteTransaction_TxType { + if x != nil { + return x.Tx } return nil } -func (m *ProtoCompleteTransaction) GetReceipt() *ProtoCompleteTransaction_ReceiptType { - if m != nil { - return m.Receipt +func (x *ProtoCompleteTransaction) GetReceipt() *ProtoCompleteTransaction_ReceiptType { + if x != nil { + return x.Receipt } return nil } type ProtoCompleteTransaction_TxType struct { - AccountNonce uint64 `protobuf:"varint,1,opt,name=AccountNonce" json:"AccountNonce,omitempty"` + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + AccountNonce uint64 `protobuf:"varint,1,opt,name=AccountNonce,proto3" json:"AccountNonce,omitempty"` GasPrice []byte `protobuf:"bytes,2,opt,name=GasPrice,proto3" json:"GasPrice,omitempty"` - GasLimit uint64 `protobuf:"varint,3,opt,name=GasLimit" json:"GasLimit,omitempty"` + GasLimit uint64 `protobuf:"varint,3,opt,name=GasLimit,proto3" json:"GasLimit,omitempty"` Value []byte `protobuf:"bytes,4,opt,name=Value,proto3" json:"Value,omitempty"` Payload []byte `protobuf:"bytes,5,opt,name=Payload,proto3" json:"Payload,omitempty"` Hash []byte `protobuf:"bytes,6,opt,name=Hash,proto3" json:"Hash,omitempty"` To []byte `protobuf:"bytes,7,opt,name=To,proto3" json:"To,omitempty"` From []byte `protobuf:"bytes,8,opt,name=From,proto3" json:"From,omitempty"` - TransactionIndex uint32 `protobuf:"varint,9,opt,name=TransactionIndex" json:"TransactionIndex,omitempty"` + TransactionIndex uint32 `protobuf:"varint,9,opt,name=TransactionIndex,proto3" json:"TransactionIndex,omitempty"` } -func (m *ProtoCompleteTransaction_TxType) Reset() { *m = ProtoCompleteTransaction_TxType{} } -func (m *ProtoCompleteTransaction_TxType) String() string { return proto.CompactTextString(m) } -func (*ProtoCompleteTransaction_TxType) ProtoMessage() {} +func (x *ProtoCompleteTransaction_TxType) Reset() { + *x = ProtoCompleteTransaction_TxType{} + if protoimpl.UnsafeEnabled { + mi := &file_bchain_coins_eth_ethtx_proto_msgTypes[1] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *ProtoCompleteTransaction_TxType) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*ProtoCompleteTransaction_TxType) ProtoMessage() {} + +func (x *ProtoCompleteTransaction_TxType) ProtoReflect() protoreflect.Message { + mi := &file_bchain_coins_eth_ethtx_proto_msgTypes[1] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use ProtoCompleteTransaction_TxType.ProtoReflect.Descriptor instead. func (*ProtoCompleteTransaction_TxType) Descriptor() ([]byte, []int) { - return fileDescriptor0, []int{0, 0} + return file_bchain_coins_eth_ethtx_proto_rawDescGZIP(), []int{0, 0} } -func (m *ProtoCompleteTransaction_TxType) GetAccountNonce() uint64 { - if m != nil { - return m.AccountNonce +func (x *ProtoCompleteTransaction_TxType) GetAccountNonce() uint64 { + if x != nil { + return x.AccountNonce } return 0 } -func (m *ProtoCompleteTransaction_TxType) GetGasPrice() []byte { - if m != nil { - return m.GasPrice +func (x *ProtoCompleteTransaction_TxType) GetGasPrice() []byte { + if x != nil { + return x.GasPrice } return nil } -func (m *ProtoCompleteTransaction_TxType) GetGasLimit() uint64 { - if m != nil { - return m.GasLimit +func (x *ProtoCompleteTransaction_TxType) GetGasLimit() uint64 { + if x != nil { + return x.GasLimit } return 0 } -func (m *ProtoCompleteTransaction_TxType) GetValue() []byte { - if m != nil { - return m.Value +func (x *ProtoCompleteTransaction_TxType) GetValue() []byte { + if x != nil { + return x.Value } return nil } -func (m *ProtoCompleteTransaction_TxType) GetPayload() []byte { - if m != nil { - return m.Payload +func (x *ProtoCompleteTransaction_TxType) GetPayload() []byte { + if x != nil { + return x.Payload } return nil } -func (m *ProtoCompleteTransaction_TxType) GetHash() []byte { - if m != nil { - return m.Hash +func (x *ProtoCompleteTransaction_TxType) GetHash() []byte { + if x != nil { + return x.Hash } return nil } -func (m *ProtoCompleteTransaction_TxType) GetTo() []byte { - if m != nil { - return m.To +func (x *ProtoCompleteTransaction_TxType) GetTo() []byte { + if x != nil { + return x.To } return nil } -func (m *ProtoCompleteTransaction_TxType) GetFrom() []byte { - if m != nil { - return m.From +func (x *ProtoCompleteTransaction_TxType) GetFrom() []byte { + if x != nil { + return x.From } return nil } -func (m *ProtoCompleteTransaction_TxType) GetTransactionIndex() uint32 { - if m != nil { - return m.TransactionIndex +func (x *ProtoCompleteTransaction_TxType) GetTransactionIndex() uint32 { + if x != nil { + return x.TransactionIndex } return 0 } type ProtoCompleteTransaction_ReceiptType struct { - GasUsed []byte `protobuf:"bytes,1,opt,name=GasUsed,proto3" json:"GasUsed,omitempty"` - Status []byte `protobuf:"bytes,2,opt,name=Status,proto3" json:"Status,omitempty"` - Log []*ProtoCompleteTransaction_ReceiptType_LogType `protobuf:"bytes,3,rep,name=Log" json:"Log,omitempty"` + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + GasUsed []byte `protobuf:"bytes,1,opt,name=GasUsed,proto3" json:"GasUsed,omitempty"` + Status []byte `protobuf:"bytes,2,opt,name=Status,proto3" json:"Status,omitempty"` + Log []*ProtoCompleteTransaction_ReceiptType_LogType `protobuf:"bytes,3,rep,name=Log,proto3" json:"Log,omitempty"` + L1Fee []byte `protobuf:"bytes,4,opt,name=L1Fee,proto3,oneof" json:"L1Fee,omitempty"` + L1FeeScalar []byte `protobuf:"bytes,5,opt,name=L1FeeScalar,proto3,oneof" json:"L1FeeScalar,omitempty"` + L1GasPrice []byte `protobuf:"bytes,6,opt,name=L1GasPrice,proto3,oneof" json:"L1GasPrice,omitempty"` + L1GasUsed []byte `protobuf:"bytes,7,opt,name=L1GasUsed,proto3,oneof" json:"L1GasUsed,omitempty"` } -func (m *ProtoCompleteTransaction_ReceiptType) Reset() { *m = ProtoCompleteTransaction_ReceiptType{} } -func (m *ProtoCompleteTransaction_ReceiptType) String() string { return proto.CompactTextString(m) } -func (*ProtoCompleteTransaction_ReceiptType) ProtoMessage() {} +func (x *ProtoCompleteTransaction_ReceiptType) Reset() { + *x = ProtoCompleteTransaction_ReceiptType{} + if protoimpl.UnsafeEnabled { + mi := &file_bchain_coins_eth_ethtx_proto_msgTypes[2] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *ProtoCompleteTransaction_ReceiptType) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*ProtoCompleteTransaction_ReceiptType) ProtoMessage() {} + +func (x *ProtoCompleteTransaction_ReceiptType) ProtoReflect() protoreflect.Message { + mi := &file_bchain_coins_eth_ethtx_proto_msgTypes[2] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use ProtoCompleteTransaction_ReceiptType.ProtoReflect.Descriptor instead. func (*ProtoCompleteTransaction_ReceiptType) Descriptor() ([]byte, []int) { - return fileDescriptor0, []int{0, 1} + return file_bchain_coins_eth_ethtx_proto_rawDescGZIP(), []int{0, 1} } -func (m *ProtoCompleteTransaction_ReceiptType) GetGasUsed() []byte { - if m != nil { - return m.GasUsed +func (x *ProtoCompleteTransaction_ReceiptType) GetGasUsed() []byte { + if x != nil { + return x.GasUsed } return nil } -func (m *ProtoCompleteTransaction_ReceiptType) GetStatus() []byte { - if m != nil { - return m.Status +func (x *ProtoCompleteTransaction_ReceiptType) GetStatus() []byte { + if x != nil { + return x.Status } return nil } -func (m *ProtoCompleteTransaction_ReceiptType) GetLog() []*ProtoCompleteTransaction_ReceiptType_LogType { - if m != nil { - return m.Log +func (x *ProtoCompleteTransaction_ReceiptType) GetLog() []*ProtoCompleteTransaction_ReceiptType_LogType { + if x != nil { + return x.Log + } + return nil +} + +func (x *ProtoCompleteTransaction_ReceiptType) GetL1Fee() []byte { + if x != nil { + return x.L1Fee + } + return nil +} + +func (x *ProtoCompleteTransaction_ReceiptType) GetL1FeeScalar() []byte { + if x != nil { + return x.L1FeeScalar + } + return nil +} + +func (x *ProtoCompleteTransaction_ReceiptType) GetL1GasPrice() []byte { + if x != nil { + return x.L1GasPrice + } + return nil +} + +func (x *ProtoCompleteTransaction_ReceiptType) GetL1GasUsed() []byte { + if x != nil { + return x.L1GasUsed } return nil } type ProtoCompleteTransaction_ReceiptType_LogType struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + Address []byte `protobuf:"bytes,1,opt,name=Address,proto3" json:"Address,omitempty"` Data []byte `protobuf:"bytes,2,opt,name=Data,proto3" json:"Data,omitempty"` Topics [][]byte `protobuf:"bytes,3,rep,name=Topics,proto3" json:"Topics,omitempty"` } -func (m *ProtoCompleteTransaction_ReceiptType_LogType) Reset() { - *m = ProtoCompleteTransaction_ReceiptType_LogType{} +func (x *ProtoCompleteTransaction_ReceiptType_LogType) Reset() { + *x = ProtoCompleteTransaction_ReceiptType_LogType{} + if protoimpl.UnsafeEnabled { + mi := &file_bchain_coins_eth_ethtx_proto_msgTypes[3] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } } -func (m *ProtoCompleteTransaction_ReceiptType_LogType) String() string { - return proto.CompactTextString(m) + +func (x *ProtoCompleteTransaction_ReceiptType_LogType) String() string { + return protoimpl.X.MessageStringOf(x) } + func (*ProtoCompleteTransaction_ReceiptType_LogType) ProtoMessage() {} + +func (x *ProtoCompleteTransaction_ReceiptType_LogType) ProtoReflect() protoreflect.Message { + mi := &file_bchain_coins_eth_ethtx_proto_msgTypes[3] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use ProtoCompleteTransaction_ReceiptType_LogType.ProtoReflect.Descriptor instead. func (*ProtoCompleteTransaction_ReceiptType_LogType) Descriptor() ([]byte, []int) { - return fileDescriptor0, []int{0, 1, 0} + return file_bchain_coins_eth_ethtx_proto_rawDescGZIP(), []int{0, 1, 0} } -func (m *ProtoCompleteTransaction_ReceiptType_LogType) GetAddress() []byte { - if m != nil { - return m.Address +func (x *ProtoCompleteTransaction_ReceiptType_LogType) GetAddress() []byte { + if x != nil { + return x.Address } return nil } -func (m *ProtoCompleteTransaction_ReceiptType_LogType) GetData() []byte { - if m != nil { - return m.Data +func (x *ProtoCompleteTransaction_ReceiptType_LogType) GetData() []byte { + if x != nil { + return x.Data } return nil } -func (m *ProtoCompleteTransaction_ReceiptType_LogType) GetTopics() [][]byte { - if m != nil { - return m.Topics +func (x *ProtoCompleteTransaction_ReceiptType_LogType) GetTopics() [][]byte { + if x != nil { + return x.Topics } return nil } -func init() { - proto.RegisterType((*ProtoCompleteTransaction)(nil), "eth.ProtoCompleteTransaction") - proto.RegisterType((*ProtoCompleteTransaction_TxType)(nil), "eth.ProtoCompleteTransaction.TxType") - proto.RegisterType((*ProtoCompleteTransaction_ReceiptType)(nil), "eth.ProtoCompleteTransaction.ReceiptType") - proto.RegisterType((*ProtoCompleteTransaction_ReceiptType_LogType)(nil), "eth.ProtoCompleteTransaction.ReceiptType.LogType") +var File_bchain_coins_eth_ethtx_proto protoreflect.FileDescriptor + +var file_bchain_coins_eth_ethtx_proto_rawDesc = []byte{ + 0x0a, 0x1c, 0x62, 0x63, 0x68, 0x61, 0x69, 0x6e, 0x2f, 0x63, 0x6f, 0x69, 0x6e, 0x73, 0x2f, 0x65, + 0x74, 0x68, 0x2f, 0x65, 0x74, 0x68, 0x74, 0x78, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x22, 0xdd, + 0x06, 0x0a, 0x18, 0x50, 0x72, 0x6f, 0x74, 0x6f, 0x43, 0x6f, 0x6d, 0x70, 0x6c, 0x65, 0x74, 0x65, + 0x54, 0x72, 0x61, 0x6e, 0x73, 0x61, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x12, 0x20, 0x0a, 0x0b, 0x42, + 0x6c, 0x6f, 0x63, 0x6b, 0x4e, 0x75, 0x6d, 0x62, 0x65, 0x72, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0d, + 0x52, 0x0b, 0x42, 0x6c, 0x6f, 0x63, 0x6b, 0x4e, 0x75, 0x6d, 0x62, 0x65, 0x72, 0x12, 0x1c, 0x0a, + 0x09, 0x42, 0x6c, 0x6f, 0x63, 0x6b, 0x54, 0x69, 0x6d, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x04, + 0x52, 0x09, 0x42, 0x6c, 0x6f, 0x63, 0x6b, 0x54, 0x69, 0x6d, 0x65, 0x12, 0x30, 0x0a, 0x02, 0x54, + 0x78, 0x18, 0x03, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x20, 0x2e, 0x50, 0x72, 0x6f, 0x74, 0x6f, 0x43, + 0x6f, 0x6d, 0x70, 0x6c, 0x65, 0x74, 0x65, 0x54, 0x72, 0x61, 0x6e, 0x73, 0x61, 0x63, 0x74, 0x69, + 0x6f, 0x6e, 0x2e, 0x54, 0x78, 0x54, 0x79, 0x70, 0x65, 0x52, 0x02, 0x54, 0x78, 0x12, 0x3f, 0x0a, + 0x07, 0x52, 0x65, 0x63, 0x65, 0x69, 0x70, 0x74, 0x18, 0x04, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x25, + 0x2e, 0x50, 0x72, 0x6f, 0x74, 0x6f, 0x43, 0x6f, 0x6d, 0x70, 0x6c, 0x65, 0x74, 0x65, 0x54, 0x72, + 0x61, 0x6e, 0x73, 0x61, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x2e, 0x52, 0x65, 0x63, 0x65, 0x69, 0x70, + 0x74, 0x54, 0x79, 0x70, 0x65, 0x52, 0x07, 0x52, 0x65, 0x63, 0x65, 0x69, 0x70, 0x74, 0x1a, 0xf8, + 0x01, 0x0a, 0x06, 0x54, 0x78, 0x54, 0x79, 0x70, 0x65, 0x12, 0x22, 0x0a, 0x0c, 0x41, 0x63, 0x63, + 0x6f, 0x75, 0x6e, 0x74, 0x4e, 0x6f, 0x6e, 0x63, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x04, 0x52, + 0x0c, 0x41, 0x63, 0x63, 0x6f, 0x75, 0x6e, 0x74, 0x4e, 0x6f, 0x6e, 0x63, 0x65, 0x12, 0x1a, 0x0a, + 0x08, 0x47, 0x61, 0x73, 0x50, 0x72, 0x69, 0x63, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0c, 0x52, + 0x08, 0x47, 0x61, 0x73, 0x50, 0x72, 0x69, 0x63, 0x65, 0x12, 0x1a, 0x0a, 0x08, 0x47, 0x61, 0x73, + 0x4c, 0x69, 0x6d, 0x69, 0x74, 0x18, 0x03, 0x20, 0x01, 0x28, 0x04, 0x52, 0x08, 0x47, 0x61, 0x73, + 0x4c, 0x69, 0x6d, 0x69, 0x74, 0x12, 0x14, 0x0a, 0x05, 0x56, 0x61, 0x6c, 0x75, 0x65, 0x18, 0x04, + 0x20, 0x01, 0x28, 0x0c, 0x52, 0x05, 0x56, 0x61, 0x6c, 0x75, 0x65, 0x12, 0x18, 0x0a, 0x07, 0x50, + 0x61, 0x79, 0x6c, 0x6f, 0x61, 0x64, 0x18, 0x05, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x07, 0x50, 0x61, + 0x79, 0x6c, 0x6f, 0x61, 0x64, 0x12, 0x12, 0x0a, 0x04, 0x48, 0x61, 0x73, 0x68, 0x18, 0x06, 0x20, + 0x01, 0x28, 0x0c, 0x52, 0x04, 0x48, 0x61, 0x73, 0x68, 0x12, 0x0e, 0x0a, 0x02, 0x54, 0x6f, 0x18, + 0x07, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x02, 0x54, 0x6f, 0x12, 0x12, 0x0a, 0x04, 0x46, 0x72, 0x6f, + 0x6d, 0x18, 0x08, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x04, 0x46, 0x72, 0x6f, 0x6d, 0x12, 0x2a, 0x0a, + 0x10, 0x54, 0x72, 0x61, 0x6e, 0x73, 0x61, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x49, 0x6e, 0x64, 0x65, + 0x78, 0x18, 0x09, 0x20, 0x01, 0x28, 0x0d, 0x52, 0x10, 0x54, 0x72, 0x61, 0x6e, 0x73, 0x61, 0x63, + 0x74, 0x69, 0x6f, 0x6e, 0x49, 0x6e, 0x64, 0x65, 0x78, 0x1a, 0x92, 0x03, 0x0a, 0x0b, 0x52, 0x65, + 0x63, 0x65, 0x69, 0x70, 0x74, 0x54, 0x79, 0x70, 0x65, 0x12, 0x18, 0x0a, 0x07, 0x47, 0x61, 0x73, + 0x55, 0x73, 0x65, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x07, 0x47, 0x61, 0x73, 0x55, + 0x73, 0x65, 0x64, 0x12, 0x16, 0x0a, 0x06, 0x53, 0x74, 0x61, 0x74, 0x75, 0x73, 0x18, 0x02, 0x20, + 0x01, 0x28, 0x0c, 0x52, 0x06, 0x53, 0x74, 0x61, 0x74, 0x75, 0x73, 0x12, 0x3f, 0x0a, 0x03, 0x4c, + 0x6f, 0x67, 0x18, 0x03, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x2d, 0x2e, 0x50, 0x72, 0x6f, 0x74, 0x6f, + 0x43, 0x6f, 0x6d, 0x70, 0x6c, 0x65, 0x74, 0x65, 0x54, 0x72, 0x61, 0x6e, 0x73, 0x61, 0x63, 0x74, + 0x69, 0x6f, 0x6e, 0x2e, 0x52, 0x65, 0x63, 0x65, 0x69, 0x70, 0x74, 0x54, 0x79, 0x70, 0x65, 0x2e, + 0x4c, 0x6f, 0x67, 0x54, 0x79, 0x70, 0x65, 0x52, 0x03, 0x4c, 0x6f, 0x67, 0x12, 0x19, 0x0a, 0x05, + 0x4c, 0x31, 0x46, 0x65, 0x65, 0x18, 0x04, 0x20, 0x01, 0x28, 0x0c, 0x48, 0x00, 0x52, 0x05, 0x4c, + 0x31, 0x46, 0x65, 0x65, 0x88, 0x01, 0x01, 0x12, 0x25, 0x0a, 0x0b, 0x4c, 0x31, 0x46, 0x65, 0x65, + 0x53, 0x63, 0x61, 0x6c, 0x61, 0x72, 0x18, 0x05, 0x20, 0x01, 0x28, 0x0c, 0x48, 0x01, 0x52, 0x0b, + 0x4c, 0x31, 0x46, 0x65, 0x65, 0x53, 0x63, 0x61, 0x6c, 0x61, 0x72, 0x88, 0x01, 0x01, 0x12, 0x23, + 0x0a, 0x0a, 0x4c, 0x31, 0x47, 0x61, 0x73, 0x50, 0x72, 0x69, 0x63, 0x65, 0x18, 0x06, 0x20, 0x01, + 0x28, 0x0c, 0x48, 0x02, 0x52, 0x0a, 0x4c, 0x31, 0x47, 0x61, 0x73, 0x50, 0x72, 0x69, 0x63, 0x65, + 0x88, 0x01, 0x01, 0x12, 0x21, 0x0a, 0x09, 0x4c, 0x31, 0x47, 0x61, 0x73, 0x55, 0x73, 0x65, 0x64, + 0x18, 0x07, 0x20, 0x01, 0x28, 0x0c, 0x48, 0x03, 0x52, 0x09, 0x4c, 0x31, 0x47, 0x61, 0x73, 0x55, + 0x73, 0x65, 0x64, 0x88, 0x01, 0x01, 0x1a, 0x4f, 0x0a, 0x07, 0x4c, 0x6f, 0x67, 0x54, 0x79, 0x70, + 0x65, 0x12, 0x18, 0x0a, 0x07, 0x41, 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, 0x18, 0x01, 0x20, 0x01, + 0x28, 0x0c, 0x52, 0x07, 0x41, 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, 0x12, 0x12, 0x0a, 0x04, 0x44, + 0x61, 0x74, 0x61, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x04, 0x44, 0x61, 0x74, 0x61, 0x12, + 0x16, 0x0a, 0x06, 0x54, 0x6f, 0x70, 0x69, 0x63, 0x73, 0x18, 0x03, 0x20, 0x03, 0x28, 0x0c, 0x52, + 0x06, 0x54, 0x6f, 0x70, 0x69, 0x63, 0x73, 0x42, 0x08, 0x0a, 0x06, 0x5f, 0x4c, 0x31, 0x46, 0x65, + 0x65, 0x42, 0x0e, 0x0a, 0x0c, 0x5f, 0x4c, 0x31, 0x46, 0x65, 0x65, 0x53, 0x63, 0x61, 0x6c, 0x61, + 0x72, 0x42, 0x0d, 0x0a, 0x0b, 0x5f, 0x4c, 0x31, 0x47, 0x61, 0x73, 0x50, 0x72, 0x69, 0x63, 0x65, + 0x42, 0x0c, 0x0a, 0x0a, 0x5f, 0x4c, 0x31, 0x47, 0x61, 0x73, 0x55, 0x73, 0x65, 0x64, 0x42, 0x12, + 0x5a, 0x10, 0x62, 0x63, 0x68, 0x61, 0x69, 0x6e, 0x2f, 0x63, 0x6f, 0x69, 0x6e, 0x73, 0x2f, 0x65, + 0x74, 0x68, 0x62, 0x06, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x33, } -func init() { proto.RegisterFile("bchain/coins/eth/ethtx.proto", fileDescriptor0) } +var ( + file_bchain_coins_eth_ethtx_proto_rawDescOnce sync.Once + file_bchain_coins_eth_ethtx_proto_rawDescData = file_bchain_coins_eth_ethtx_proto_rawDesc +) -var fileDescriptor0 = []byte{ - // 409 bytes of a gzipped FileDescriptorProto - 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0x8c, 0x92, 0xdf, 0x8a, 0xd4, 0x30, - 0x18, 0xc5, 0xe9, 0x9f, 0x99, 0xd9, 0xfd, 0xa6, 0x8a, 0x04, 0x91, 0x30, 0xec, 0x45, 0x59, 0xbc, - 0x18, 0xbd, 0xe8, 0xe2, 0xea, 0x0b, 0xac, 0x23, 0xae, 0xc2, 0xb0, 0x0e, 0x31, 0x7a, 0x9f, 0x49, - 0xc3, 0x36, 0x38, 0x6d, 0x4a, 0x93, 0x42, 0xf7, 0x8d, 0x7c, 0x21, 0xdf, 0xc5, 0x4b, 0xc9, 0xd7, - 0x74, 0x1d, 0x11, 0x65, 0x2f, 0x0a, 0xf9, 0x9d, 0x7e, 0xa7, 0x39, 0x27, 0x29, 0x9c, 0xed, 0x65, - 0x25, 0x74, 0x73, 0x21, 0x8d, 0x6e, 0xec, 0x85, 0x72, 0x95, 0x7f, 0xdc, 0x50, 0xb4, 0x9d, 0x71, - 0x86, 0x24, 0xca, 0x55, 0xe7, 0xdf, 0x67, 0x40, 0x77, 0x1e, 0x37, 0xa6, 0x6e, 0x0f, 0xca, 0x29, - 0xde, 0x89, 0xc6, 0x0a, 0xe9, 0xb4, 0x69, 0x48, 0x0e, 0xcb, 0xb7, 0x07, 0x23, 0xbf, 0xdd, 0xf4, - 0xf5, 0x5e, 0x75, 0x34, 0xca, 0xa3, 0xf5, 0x23, 0x76, 0x2c, 0x91, 0x33, 0x38, 0x45, 0xe4, 0xba, - 0x56, 0x34, 0xce, 0xa3, 0x75, 0xca, 0x7e, 0x0b, 0xe4, 0x0d, 0xc4, 0x7c, 0xa0, 0x49, 0x1e, 0xad, - 0x97, 0x97, 0xcf, 0x0b, 0xe5, 0xaa, 0xe2, 0x5f, 0x5b, 0x15, 0x7c, 0xe0, 0x77, 0xad, 0x62, 0x31, - 0x1f, 0xc8, 0x06, 0x16, 0x4c, 0x49, 0xa5, 0x5b, 0x47, 0x53, 0xb4, 0xbe, 0xf8, 0xbf, 0x35, 0x0c, - 0xa3, 0x7f, 0x72, 0xae, 0x7e, 0x46, 0x30, 0x1f, 0xbf, 0x49, 0xce, 0x21, 0xbb, 0x92, 0xd2, 0xf4, - 0x8d, 0xbb, 0x31, 0x8d, 0x54, 0x58, 0x23, 0x65, 0x7f, 0x68, 0x64, 0x05, 0x27, 0xd7, 0xc2, 0xee, - 0x3a, 0x2d, 0xc7, 0x1a, 0x19, 0xbb, 0xe7, 0xf0, 0x6e, 0xab, 0x6b, 0xed, 0xb0, 0x4b, 0xca, 0xee, - 0x99, 0x3c, 0x85, 0xd9, 0x57, 0x71, 0xe8, 0x15, 0x26, 0xcd, 0xd8, 0x08, 0x84, 0xc2, 0x62, 0x27, - 0xee, 0x0e, 0x46, 0x94, 0x74, 0x86, 0xfa, 0x84, 0x84, 0x40, 0xfa, 0x41, 0xd8, 0x8a, 0xce, 0x51, - 0xc6, 0x35, 0x79, 0x0c, 0x31, 0x37, 0x74, 0x81, 0x4a, 0xcc, 0x8d, 0x9f, 0x79, 0xdf, 0x99, 0x9a, - 0x9e, 0x8c, 0x33, 0x7e, 0x4d, 0x5e, 0xc2, 0x93, 0xa3, 0xca, 0x1f, 0x9b, 0x52, 0x0d, 0xf4, 0x14, - 0xaf, 0xe3, 0x2f, 0x7d, 0xf5, 0x23, 0x82, 0xe5, 0xd1, 0x99, 0xf8, 0x34, 0xd7, 0xc2, 0x7e, 0xb1, - 0xaa, 0xc4, 0xea, 0x19, 0x9b, 0x90, 0x3c, 0x83, 0xf9, 0x67, 0x27, 0x5c, 0x6f, 0x43, 0xe7, 0x40, - 0x64, 0x03, 0xc9, 0xd6, 0xdc, 0xd2, 0x24, 0x4f, 0xd6, 0xcb, 0xcb, 0x57, 0x0f, 0x3e, 0xfd, 0x62, - 0x6b, 0x6e, 0xf1, 0x16, 0xbc, 0x7b, 0xf5, 0x09, 0x16, 0x81, 0x7d, 0x82, 0xab, 0xb2, 0xec, 0x94, - 0xb5, 0x53, 0x82, 0x80, 0xbe, 0xeb, 0x3b, 0xe1, 0x44, 0xd8, 0x1f, 0xd7, 0x3e, 0x15, 0x37, 0xad, - 0x96, 0x16, 0x03, 0x64, 0x2c, 0xd0, 0x7e, 0x8e, 0xbf, 0xed, 0xeb, 0x5f, 0x01, 0x00, 0x00, 0xff, - 0xff, 0xc2, 0x69, 0x8d, 0xdf, 0xd6, 0x02, 0x00, 0x00, +func file_bchain_coins_eth_ethtx_proto_rawDescGZIP() []byte { + file_bchain_coins_eth_ethtx_proto_rawDescOnce.Do(func() { + file_bchain_coins_eth_ethtx_proto_rawDescData = protoimpl.X.CompressGZIP(file_bchain_coins_eth_ethtx_proto_rawDescData) + }) + return file_bchain_coins_eth_ethtx_proto_rawDescData +} + +var file_bchain_coins_eth_ethtx_proto_msgTypes = make([]protoimpl.MessageInfo, 4) +var file_bchain_coins_eth_ethtx_proto_goTypes = []interface{}{ + (*ProtoCompleteTransaction)(nil), // 0: ProtoCompleteTransaction + (*ProtoCompleteTransaction_TxType)(nil), // 1: ProtoCompleteTransaction.TxType + (*ProtoCompleteTransaction_ReceiptType)(nil), // 2: ProtoCompleteTransaction.ReceiptType + (*ProtoCompleteTransaction_ReceiptType_LogType)(nil), // 3: ProtoCompleteTransaction.ReceiptType.LogType +} +var file_bchain_coins_eth_ethtx_proto_depIdxs = []int32{ + 1, // 0: ProtoCompleteTransaction.Tx:type_name -> ProtoCompleteTransaction.TxType + 2, // 1: ProtoCompleteTransaction.Receipt:type_name -> ProtoCompleteTransaction.ReceiptType + 3, // 2: ProtoCompleteTransaction.ReceiptType.Log:type_name -> ProtoCompleteTransaction.ReceiptType.LogType + 3, // [3:3] is the sub-list for method output_type + 3, // [3:3] is the sub-list for method input_type + 3, // [3:3] is the sub-list for extension type_name + 3, // [3:3] is the sub-list for extension extendee + 0, // [0:3] is the sub-list for field type_name +} + +func init() { file_bchain_coins_eth_ethtx_proto_init() } +func file_bchain_coins_eth_ethtx_proto_init() { + if File_bchain_coins_eth_ethtx_proto != nil { + return + } + if !protoimpl.UnsafeEnabled { + file_bchain_coins_eth_ethtx_proto_msgTypes[0].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*ProtoCompleteTransaction); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_bchain_coins_eth_ethtx_proto_msgTypes[1].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*ProtoCompleteTransaction_TxType); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_bchain_coins_eth_ethtx_proto_msgTypes[2].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*ProtoCompleteTransaction_ReceiptType); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_bchain_coins_eth_ethtx_proto_msgTypes[3].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*ProtoCompleteTransaction_ReceiptType_LogType); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + } + file_bchain_coins_eth_ethtx_proto_msgTypes[2].OneofWrappers = []interface{}{} + type x struct{} + out := protoimpl.TypeBuilder{ + File: protoimpl.DescBuilder{ + GoPackagePath: reflect.TypeOf(x{}).PkgPath(), + RawDescriptor: file_bchain_coins_eth_ethtx_proto_rawDesc, + NumEnums: 0, + NumMessages: 4, + NumExtensions: 0, + NumServices: 0, + }, + GoTypes: file_bchain_coins_eth_ethtx_proto_goTypes, + DependencyIndexes: file_bchain_coins_eth_ethtx_proto_depIdxs, + MessageInfos: file_bchain_coins_eth_ethtx_proto_msgTypes, + }.Build() + File_bchain_coins_eth_ethtx_proto = out.File + file_bchain_coins_eth_ethtx_proto_rawDesc = nil + file_bchain_coins_eth_ethtx_proto_goTypes = nil + file_bchain_coins_eth_ethtx_proto_depIdxs = nil } diff --git a/bchain/coins/eth/ethtx.proto b/bchain/coins/eth/ethtx.proto index ef7c4ce0..f53e0e39 100644 --- a/bchain/coins/eth/ethtx.proto +++ b/bchain/coins/eth/ethtx.proto @@ -1,30 +1,34 @@ syntax = "proto3"; - package eth; - - message ProtoCompleteTransaction { - message TxType { - uint64 AccountNonce = 1; - bytes GasPrice = 2; - uint64 GasLimit = 3; - bytes Value = 4; - bytes Payload = 5; - bytes Hash = 6; - bytes To = 7; - bytes From = 8; - uint32 TransactionIndex = 9; - } - message ReceiptType { - message LogType { - bytes Address = 1; - bytes Data = 2; - repeated bytes Topics = 3; - } - bytes GasUsed = 1; - bytes Status = 2; - repeated LogType Log = 3; - } - uint32 BlockNumber = 1; - uint64 BlockTime = 2; - TxType Tx = 3; - ReceiptType Receipt = 4; - } \ No newline at end of file +option go_package = "bchain/coins/eth"; + +message ProtoCompleteTransaction { + message TxType { + uint64 AccountNonce = 1; + bytes GasPrice = 2; + uint64 GasLimit = 3; + bytes Value = 4; + bytes Payload = 5; + bytes Hash = 6; + bytes To = 7; + bytes From = 8; + uint32 TransactionIndex = 9; + } + message ReceiptType { + message LogType { + bytes Address = 1; + bytes Data = 2; + repeated bytes Topics = 3; + } + bytes GasUsed = 1; + bytes Status = 2; + repeated LogType Log = 3; + optional bytes L1Fee = 4; + optional bytes L1FeeScalar = 5; + optional bytes L1GasPrice = 6; + optional bytes L1GasUsed = 7; + } + uint32 BlockNumber = 1; + uint64 BlockTime = 2; + TxType Tx = 3; + ReceiptType Receipt = 4; +} \ No newline at end of file diff --git a/bchain/coins/eth/stakingpool.go b/bchain/coins/eth/stakingpool.go index 30820390..659307c8 100644 --- a/bchain/coins/eth/stakingpool.go +++ b/bchain/coins/eth/stakingpool.go @@ -11,9 +11,13 @@ import ( "github.com/trezor/blockbook/bchain" ) -func (b *EthereumRPC) initStakingPools(coinShortcut string) error { +func (b *EthereumRPC) initStakingPools() error { + network := b.ChainConfig.Network + if network == "" { + network = b.ChainConfig.CoinShortcut + } // for now only single staking pool - envVar := strings.ToUpper(coinShortcut) + "_STAKING_POOL_CONTRACT" + envVar := strings.ToUpper(network) + "_STAKING_POOL_CONTRACT" envValue := os.Getenv(envVar) if envValue != "" { parts := strings.Split(envValue, "/") @@ -61,7 +65,7 @@ func isZeroBigInt(b *big.Int) bool { func (b *EthereumRPC) everstakeBalanceTypeContractCall(signature, addr, contract string) (string, error) { req := signature + "0000000000000000000000000000000000000000000000000000000000000000"[len(addr):] + addr - return b.ethCall(req, contract) + return b.EthereumTypeRpcCall(req, contract, "") } func (b *EthereumRPC) everstakeContractCallSimpleNumeric(signature, addr, contract string) (*big.Int, error) { diff --git a/bchain/coins/firo/firoparser.go b/bchain/coins/firo/firoparser.go index d2b9e1f0..cfdf9c4a 100644 --- a/bchain/coins/firo/firoparser.go +++ b/bchain/coins/firo/firoparser.go @@ -14,13 +14,13 @@ import ( ) const ( - OpZeroCoinMint = 0xc1 - OpZeroCoinSpend = 0xc2 - OpSigmaMint = 0xc3 - OpSigmaSpend = 0xc4 - OpLelantusMint = 0xc5 - OpLelantusJMint = 0xc6 - OpLelantusJoinSplit = 0xc7 + OpZeroCoinMint = 0xc1 + OpZeroCoinSpend = 0xc2 + OpSigmaMint = 0xc3 + OpSigmaSpend = 0xc4 + OpLelantusMint = 0xc5 + OpLelantusJMint = 0xc6 + OpLelantusJoinSplit = 0xc7 OpLelantusJoinSplitPayload = 0xc9 MainnetMagic wire.BitcoinNet = 0xe3d9fef1 @@ -194,7 +194,6 @@ func (p *FiroParser) ParseBlock(b []byte) (*bchain.Block, error) { break } } - if !isAllZero { // hash data @@ -344,7 +343,7 @@ type MTPHashDataRoot struct { } type MTPHashData struct { - BlockMTP [128][128]uint64 + BlockMTP [128][128]uint64 } type MTPBlockHeader struct { diff --git a/bchain/coins/optimism/evm.go b/bchain/coins/optimism/evm.go new file mode 100644 index 00000000..e1f7e51e --- /dev/null +++ b/bchain/coins/optimism/evm.go @@ -0,0 +1,45 @@ +package optimism + +import ( + "context" + + "github.com/ethereum/go-ethereum/rpc" + "github.com/trezor/blockbook/bchain" +) + +// OptimismRPCClient wraps an rpc client to implement the EVMRPCClient interface +type OptimismRPCClient struct { + *rpc.Client +} + +// EthSubscribe subscribes to events and returns a client subscription that implements the EVMClientSubscription interface +func (c *OptimismRPCClient) EthSubscribe(ctx context.Context, channel interface{}, args ...interface{}) (bchain.EVMClientSubscription, error) { + sub, err := c.Client.EthSubscribe(ctx, channel, args...) + if err != nil { + return nil, err + } + + return &OptimismClientSubscription{ClientSubscription: sub}, nil +} + +// CallContext performs a JSON-RPC call with the given arguments +func (c *OptimismRPCClient) CallContext(ctx context.Context, result interface{}, method string, args ...interface{}) error { + if err := c.Client.CallContext(ctx, result, method, args...); err != nil { + return err + } + + // special case to handle empty gas price for a valid rpc transaction + // (https://goerli-optimism.etherscan.io/tx/0x9b62094073147508471e3371920b68070979beea32100acdc49c721350b69cb9) + if r, ok := result.(*bchain.RpcTransaction); ok { + if *r != (bchain.RpcTransaction{}) && r.GasPrice == "" { + r.GasPrice = "0x0" + } + } + + return nil +} + +// OptimismClientSubscription wraps a client subcription to implement the EVMClientSubscription interface +type OptimismClientSubscription struct { + *rpc.ClientSubscription +} diff --git a/bchain/coins/optimism/optimismrpc.go b/bchain/coins/optimism/optimismrpc.go new file mode 100644 index 00000000..b28ae9ef --- /dev/null +++ b/bchain/coins/optimism/optimismrpc.go @@ -0,0 +1,73 @@ +package optimism + +import ( + "context" + "encoding/json" + + "github.com/golang/glog" + "github.com/juju/errors" + "github.com/trezor/blockbook/bchain" + "github.com/trezor/blockbook/bchain/coins/eth" +) + +const ( + // MainNet is production network + MainNet eth.Network = 10 +) + +// OptimismRPC is an interface to JSON-RPC optimism service. +type OptimismRPC struct { + *eth.EthereumRPC +} + +// NewOptimismRPC returns new OptimismRPC instance. +func NewOptimismRPC(config json.RawMessage, pushHandler func(bchain.NotificationType)) (bchain.BlockChain, error) { + c, err := eth.NewEthereumRPC(config, pushHandler) + if err != nil { + return nil, err + } + + s := &OptimismRPC{ + EthereumRPC: c.(*eth.EthereumRPC), + } + + return s, nil +} + +// Initialize bnb smart chain rpc interface +func (b *OptimismRPC) Initialize() error { + b.OpenRPC = eth.OpenRPC + + rc, ec, err := b.OpenRPC(b.ChainConfig.RPCURL) + if err != nil { + return err + } + + // set chain specific + b.Client = ec + b.RPC = rc + b.MainNetChainID = MainNet + b.NewBlock = eth.NewEthereumNewBlock() + b.NewTx = eth.NewEthereumNewTx() + + ctx, cancel := context.WithTimeout(context.Background(), b.Timeout) + defer cancel() + + id, err := b.Client.NetworkID(ctx) + if err != nil { + return err + } + + // parameters for getInfo request + switch eth.Network(id.Uint64()) { + case MainNet: + b.Testnet = false + b.Network = "livenet" + default: + return errors.Errorf("Unknown network id %v", id) + } + + glog.Info("rpc: block chain ", b.Network) + + return nil +} diff --git a/bchain/types.go b/bchain/types.go index a27431ab..8f1c2543 100644 --- a/bchain/types.go +++ b/bchain/types.go @@ -131,7 +131,8 @@ type TokenTypeName string // Token types const ( - UnknownTokenType TokenTypeName = "" + UnknownTokenType TokenTypeName = "" + UnhandledTokenType TokenTypeName = "-" // XPUBAddressTokenType is address derived from xpub XPUBAddressTokenType TokenTypeName = "XPUBAddress" @@ -335,6 +336,8 @@ type BlockChain interface { EthereumTypeGetErc20ContractBalance(addrDesc, contractDesc AddressDescriptor) (*big.Int, error) EthereumTypeGetSupportedStakingPools() []string EthereumTypeGetStakingPoolsData(addrDesc AddressDescriptor) ([]StakingPoolData, error) + EthereumTypeRpcCall(data, to, from string) (string, error) + EthereumTypeGetRawTransaction(txid string) (string, error) GetTokenURI(contractDesc AddressDescriptor, tokenID *big.Int) (string, error) } diff --git a/bchain/types_ethereum_type.go b/bchain/types_ethereum_type.go index 6ee54c2f..652a9edd 100644 --- a/bchain/types_ethereum_type.go +++ b/bchain/types_ethereum_type.go @@ -122,9 +122,13 @@ type RpcLog struct { // RpcLog is returned by eth_getTransactionReceipt type RpcReceipt struct { - GasUsed string `json:"gasUsed"` - Status string `json:"status"` - Logs []*RpcLog `json:"logs"` + GasUsed string `json:"gasUsed"` + Status string `json:"status"` + Logs []*RpcLog `json:"logs"` + L1Fee string `json:"l1Fee,omitempty"` + L1FeeScalar string `json:"l1FeeScalar,omitempty"` + L1GasPrice string `json:"l1GasPrice,omitempty"` + L1GasUsed string `json:"l1GasUsed,omitempty"` } // EthereumSpecificData contains data specific to Ethereum transactions diff --git a/blockbook-api.ts b/blockbook-api.ts index b69be708..295acff9 100644 --- a/blockbook-api.ts +++ b/blockbook-api.ts @@ -33,6 +33,10 @@ export interface EthereumSpecific { gasLimit: number; gasUsed?: number; gasPrice?: string; + l1Fee?: number; + l1FeeScalar?: string; + l1GasPrice?: string; + l1GasUsed?: number; data?: string; parsedData?: EthereumParsedInputData; internalTransfers?: EthereumInternalTransfer[]; @@ -257,6 +261,7 @@ export interface InternalStateColumn { } export interface BlockbookInfo { coin: string; + network: string; host: string; version: string; gitCommit: string; @@ -351,6 +356,7 @@ export interface WsBackendInfo { export interface WsInfoRes { name: string; shortcut: string; + network: string; decimals: number; version: string; bestHeight: number; @@ -442,6 +448,14 @@ export interface WsMempoolFiltersReq { fromTimestamp: number; M?: number; } +export interface WsRpcCallReq { + from?: string; + to: string; + data: string; +} +export interface WsRpcCallRes { + data: string; +} export interface MempoolTxidFilterEntries { entries?: { [key: string]: string }; usedZeroedKey?: boolean; diff --git a/blockbook.go b/blockbook.go index a0065ec6..6675aec3 100644 --- a/blockbook.go +++ b/blockbook.go @@ -507,7 +507,7 @@ func newInternalState(config *common.Config, d *db.RocksDB, enableSubNewTx bool) is.Host = name } - is.WsGetAccountInfoLimit, _ = strconv.Atoi(os.Getenv(strings.ToUpper(is.CoinShortcut) + "_WS_GETACCOUNTINFO_LIMIT")) + is.WsGetAccountInfoLimit, _ = strconv.Atoi(os.Getenv(strings.ToUpper(is.GetNetwork()) + "_WS_GETACCOUNTINFO_LIMIT")) if is.WsGetAccountInfoLimit > 0 { glog.Info("WsGetAccountInfoLimit enabled with limit ", is.WsGetAccountInfoLimit) is.WsLimitExceedingIPs = make(map[string]int) diff --git a/build/docker/deb/Dockerfile b/build/docker/deb/Dockerfile index 55989099..fd8fa114 100644 --- a/build/docker/deb/Dockerfile +++ b/build/docker/deb/Dockerfile @@ -6,9 +6,19 @@ ENV DEBIAN_FRONTEND=noninteractive RUN apt-get update && \ apt-get upgrade -y && \ - apt-get install -y devscripts debhelper make dh-exec && \ + apt-get install -y devscripts debhelper make dh-exec zstd && \ apt-get clean +# install docker cli +ARG DOCKER_VERSION + +RUN if [ -z "$DOCKER_VERSION" ]; then echo "DOCKER_VERSION is a required build arg" && exit 1; fi + +RUN wget -O docker.tgz "https://download.docker.com/linux/static/stable/x86_64/docker-${DOCKER_VERSION}.tgz" && \ + tar -xzf docker.tgz --strip 1 -C /usr/local/bin/ && \ + rm docker.tgz && \ + docker --version + ADD gpg-keys /tmp/gpg-keys RUN gpg --batch --import /tmp/gpg-keys/* diff --git a/build/templates/backend/Makefile b/build/templates/backend/Makefile index 5b9e0bd4..de5440aa 100644 --- a/build/templates/backend/Makefile +++ b/build/templates/backend/Makefile @@ -2,6 +2,16 @@ ARCHIVE := $(shell basename {{.Backend.BinaryURL}}) all: + mkdir backend +{{- if ne .Backend.DockerImage "" }} + docker container inspect extract > /dev/null 2>&1 && docker rm extract || true + docker create --name extract {{.Backend.DockerImage}} +{{- if eq .Backend.VerificationType "docker"}} + [ "$$(docker inspect --format='{{`{{index .RepoDigests 0}}`}}' {{.Backend.DockerImage}} | sed 's/.*@sha256://')" = "{{.Backend.VerificationSource}}" ] +{{- end}} + {{.Backend.ExtractCommand}} + docker rm extract +{{- else }} wget {{.Backend.BinaryURL}} {{- if eq .Backend.VerificationType "gpg"}} wget {{.Backend.VerificationSource}} -O checksum @@ -13,8 +23,8 @@ all: {{- else if eq .Backend.VerificationType "sha256"}} [ "$$(sha256sum ${ARCHIVE} | cut -d ' ' -f 1)" = "{{.Backend.VerificationSource}}" ] {{- end}} - mkdir backend {{.Backend.ExtractCommand}} ${ARCHIVE} +{{- end}} {{- if .Backend.ExcludeFiles}} # generated from exclude_files {{- range $index, $name := .Backend.ExcludeFiles}} diff --git a/build/templates/backend/config/bitcoin.conf b/build/templates/backend/config/bitcoin.conf index c6f94c73..619f6785 100644 --- a/build/templates/backend/config/bitcoin.conf +++ b/build/templates/backend/config/bitcoin.conf @@ -16,6 +16,8 @@ mempoolfullrbf=1 dbcache=1000 +deprecatedrpc=warnings + {{- if .Backend.AdditionalParams}} # generated from additional_params {{- range $name, $value := .Backend.AdditionalParams}} diff --git a/build/templates/backend/config/bitcoin_regtest.conf b/build/templates/backend/config/bitcoin_regtest.conf index 0fb7aef2..3bdfc3dc 100644 --- a/build/templates/backend/config/bitcoin_regtest.conf +++ b/build/templates/backend/config/bitcoin_regtest.conf @@ -12,6 +12,8 @@ rpcworkqueue=1100 maxmempool=2000 dbcache=1000 +deprecatedrpc=warnings + {{- if .Backend.AdditionalParams}} # generated from additional_params {{- range $name, $value := .Backend.AdditionalParams}} diff --git a/build/templates/backend/config/bitcoin-signet.conf b/build/templates/backend/config/bitcoin_signet.conf similarity index 96% rename from build/templates/backend/config/bitcoin-signet.conf rename to build/templates/backend/config/bitcoin_signet.conf index c26fa574..e88a0fd5 100644 --- a/build/templates/backend/config/bitcoin-signet.conf +++ b/build/templates/backend/config/bitcoin_signet.conf @@ -13,6 +13,8 @@ rpcworkqueue=1100 maxmempool=2000 dbcache=1000 +deprecatedrpc=warnings + {{- if .Backend.AdditionalParams}} # generated from additional_params {{- range $name, $value := .Backend.AdditionalParams}} diff --git a/build/templates/backend/config/bitcoin_testnet4.conf b/build/templates/backend/config/bitcoin_testnet4.conf new file mode 100644 index 00000000..46a5370b --- /dev/null +++ b/build/templates/backend/config/bitcoin_testnet4.conf @@ -0,0 +1,38 @@ +{{define "main" -}} +daemon=1 +server=1 +{{if .Backend.Mainnet}}mainnet=1{{else}}testnet4=1{{end}} +nolisten=1 +txindex=1 +disablewallet=1 + +zmqpubhashtx={{template "IPC.MessageQueueBindingTemplate" .}} +zmqpubhashblock={{template "IPC.MessageQueueBindingTemplate" .}} + +rpcworkqueue=1100 +maxmempool=4096 +mempoolexpiry=8760 +mempoolfullrbf=1 + +dbcache=1000 + +deprecatedrpc=warnings + +{{- if .Backend.AdditionalParams}} +# generated from additional_params +{{- range $name, $value := .Backend.AdditionalParams}} +{{- if eq $name "addnode"}} +{{- range $index, $node := $value}} +addnode={{$node}} +{{- end}} +{{- else}} +{{$name}}={{$value}} +{{- end}} +{{- end}} +{{- end}} + +{{if .Backend.Mainnet}}[main]{{else}}[testnet4]{{end}} +{{generateRPCAuth .IPC.RPCUser .IPC.RPCPass -}} +rpcport={{.Ports.BackendRPC}} + +{{end}} diff --git a/build/templates/backend/scripts/arbitrum.sh b/build/templates/backend/scripts/arbitrum.sh new file mode 100755 index 00000000..0872739c --- /dev/null +++ b/build/templates/backend/scripts/arbitrum.sh @@ -0,0 +1,34 @@ +#!/bin/sh + +{{define "main" -}} + +set -e + +INSTALL_DIR={{.Env.BackendInstallPath}}/{{.Coin.Alias}} +DATA_DIR={{.Env.BackendDataPath}}/{{.Coin.Alias}}/backend + +NITRO_BIN=$INSTALL_DIR/nitro + +$NITRO_BIN \ + --chain.name arb1 \ + --init.latest pruned \ + --init.download-path $DATA_DIR/tmp \ + --auth.jwtsecret $DATA_DIR/jwtsecret \ + --persistent.chain $DATA_DIR \ + --parent-chain.connection.url http://127.0.0.1:8136 \ + --parent-chain.blob-client.beacon-url http://127.0.0.1:7536 \ + --http.addr 127.0.0.1 \ + --http.port {{.Ports.BackendHttp}} \ + --http.api eth,net,web3,debug,txpool,arb \ + --http.vhosts '*' \ + --http.corsdomain '*' \ + --ws.addr 127.0.0.1 \ + --ws.api eth,net,web3,debug,txpool,arb \ + --ws.port {{.Ports.BackendRPC}} \ + --ws.origins '*' \ + --file-logging.enable='false' \ + --node.staker.enable='false' \ + --execution.tx-lookup-limit 0 \ + --validation.wasm.allowed-wasm-module-roots "$INSTALL_DIR/nitro-legacy/machines,$INSTALL_DIR/target/machines" + +{{end}} \ No newline at end of file diff --git a/build/templates/backend/scripts/arbitrum_archive.sh b/build/templates/backend/scripts/arbitrum_archive.sh new file mode 100755 index 00000000..27c7d6da --- /dev/null +++ b/build/templates/backend/scripts/arbitrum_archive.sh @@ -0,0 +1,35 @@ +#!/bin/sh + +{{define "main" -}} + +set -e + +INSTALL_DIR={{.Env.BackendInstallPath}}/{{.Coin.Alias}} +DATA_DIR={{.Env.BackendDataPath}}/{{.Coin.Alias}}/backend + +NITRO_BIN=$INSTALL_DIR/nitro + +$NITRO_BIN \ + --chain.name arb1 \ + --init.latest archive \ + --init.download-path $DATA_DIR/tmp \ + --auth.jwtsecret $DATA_DIR/jwtsecret \ + --persistent.chain $DATA_DIR \ + --parent-chain.connection.url http://127.0.0.1:8116 \ + --parent-chain.blob-client.beacon-url http://127.0.0.1:7516 \ + --http.addr 127.0.0.1 \ + --http.port {{.Ports.BackendHttp}} \ + --http.api eth,net,web3,debug,txpool,arb \ + --http.vhosts '*' \ + --http.corsdomain '*' \ + --ws.addr 127.0.0.1 \ + --ws.api eth,net,web3,debug,txpool,arb \ + --ws.port {{.Ports.BackendRPC}} \ + --ws.origins '*' \ + --file-logging.enable='false' \ + --node.staker.enable='false' \ + --execution.caching.archive \ + --execution.tx-lookup-limit 0 \ + --validation.wasm.allowed-wasm-module-roots "$INSTALL_DIR/nitro-legacy/machines,$INSTALL_DIR/target/machines" + +{{end}} \ No newline at end of file diff --git a/build/templates/backend/scripts/arbitrum_nova.sh b/build/templates/backend/scripts/arbitrum_nova.sh new file mode 100755 index 00000000..3f15e4ef --- /dev/null +++ b/build/templates/backend/scripts/arbitrum_nova.sh @@ -0,0 +1,34 @@ +#!/bin/sh + +{{define "main" -}} + +set -e + +INSTALL_DIR={{.Env.BackendInstallPath}}/{{.Coin.Alias}} +DATA_DIR={{.Env.BackendDataPath}}/{{.Coin.Alias}}/backend + +NITRO_BIN=$INSTALL_DIR/nitro + +$NITRO_BIN \ + --chain.name nova \ + --init.latest pruned \ + --init.download-path $DATA_DIR/tmp \ + --auth.jwtsecret $DATA_DIR/jwtsecret \ + --persistent.chain $DATA_DIR \ + --parent-chain.connection.url http://127.0.0.1:8136 \ + --parent-chain.blob-client.beacon-url http://127.0.0.1:7536 \ + --http.addr 127.0.0.1 \ + --http.port {{.Ports.BackendHttp}} \ + --http.api eth,net,web3,debug,txpool,arb \ + --http.vhosts '*' \ + --http.corsdomain '*' \ + --ws.addr 127.0.0.1 \ + --ws.api eth,net,web3,debug,txpool,arb \ + --ws.port {{.Ports.BackendRPC}} \ + --ws.origins '*' \ + --file-logging.enable='false' \ + --node.staker.enable='false' \ + --execution.tx-lookup-limit 0 \ + --validation.wasm.allowed-wasm-module-roots "$INSTALL_DIR/nitro-legacy/machines,$INSTALL_DIR/target/machines" + +{{end}} \ No newline at end of file diff --git a/build/templates/backend/scripts/arbitrum_nova_archive.sh b/build/templates/backend/scripts/arbitrum_nova_archive.sh new file mode 100755 index 00000000..eb150f79 --- /dev/null +++ b/build/templates/backend/scripts/arbitrum_nova_archive.sh @@ -0,0 +1,35 @@ +#!/bin/sh + +{{define "main" -}} + +set -e + +INSTALL_DIR={{.Env.BackendInstallPath}}/{{.Coin.Alias}} +DATA_DIR={{.Env.BackendDataPath}}/{{.Coin.Alias}}/backend + +NITRO_BIN=$INSTALL_DIR/nitro + +$NITRO_BIN \ + --chain.name nova \ + --init.latest archive \ + --init.download-path $DATA_DIR/tmp \ + --auth.jwtsecret $DATA_DIR/jwtsecret \ + --persistent.chain $DATA_DIR \ + --parent-chain.connection.url http://127.0.0.1:8116 \ + --parent-chain.blob-client.beacon-url http://127.0.0.1:7516 \ + --http.addr 127.0.0.1 \ + --http.port {{.Ports.BackendHttp}} \ + --http.api eth,net,web3,debug,txpool,arb \ + --http.vhosts '*' \ + --http.corsdomain '*' \ + --ws.addr 127.0.0.1 \ + --ws.api eth,net,web3,debug,txpool,arb \ + --ws.port {{.Ports.BackendRPC}} \ + --ws.origins '*' \ + --file-logging.enable='false' \ + --node.staker.enable='false' \ + --execution.caching.archive \ + --execution.tx-lookup-limit 0 \ + --validation.wasm.allowed-wasm-module-roots "$INSTALL_DIR/nitro-legacy/machines,$INSTALL_DIR/target/machines" + +{{end}} \ No newline at end of file diff --git a/build/templates/backend/scripts/optimism.sh b/build/templates/backend/scripts/optimism.sh new file mode 100644 index 00000000..faccfe80 --- /dev/null +++ b/build/templates/backend/scripts/optimism.sh @@ -0,0 +1,44 @@ +#!/bin/sh + +{{define "main" -}} + +set -e + +GETH_BIN={{.Env.BackendInstallPath}}/{{.Coin.Alias}}/geth +DATA_DIR={{.Env.BackendDataPath}}/{{.Coin.Alias}}/backend + +CHAINDATA_DIR=$DATA_DIR/geth/chaindata +SNAPSHOT=https://r2-snapshots.fastnode.io/op/$(curl -s https://r2-snapshots.fastnode.io/op/latest-mainnet) + +if [ ! -d "$CHAINDATA_DIR" ]; then + wget -c $SNAPSHOT -O - | lz4 -cd | tar xf - -C $DATA_DIR +fi + +$GETH_BIN \ + --op-network op-mainnet \ + --datadir $DATA_DIR \ + --authrpc.jwtsecret $DATA_DIR/jwtsecret \ + --authrpc.addr 127.0.0.1 \ + --authrpc.port {{.Ports.BackendAuthRpc}} \ + --authrpc.vhosts "*" \ + --port {{.Ports.BackendP2P}} \ + --http \ + --http.port {{.Ports.BackendHttp}} \ + --http.addr 127.0.0.1 \ + --http.api eth,net,web3,debug,txpool,engine \ + --http.vhosts "*" \ + --http.corsdomain "*" \ + --ws \ + --ws.port {{.Ports.BackendRPC}} \ + --ws.addr 127.0.0.1 \ + --ws.api eth,net,web3,debug,txpool,engine \ + --ws.origins "*" \ + --rollup.disabletxpoolgossip=true \ + --rollup.sequencerhttp https://mainnet-sequencer.optimism.io \ + --txlookuplimit 0 \ + --cache 4096 \ + --syncmode full \ + --maxpeers 0 \ + --nodiscover + +{{end}} diff --git a/build/templates/backend/scripts/optimism_archive.sh b/build/templates/backend/scripts/optimism_archive.sh new file mode 100644 index 00000000..78025884 --- /dev/null +++ b/build/templates/backend/scripts/optimism_archive.sh @@ -0,0 +1,48 @@ +#!/bin/sh + +{{define "main" -}} + +set -e + +GETH_BIN={{.Env.BackendInstallPath}}/{{.Coin.Alias}}/geth +DATA_DIR={{.Env.BackendDataPath}}/{{.Coin.Alias}}/backend + +CHAINDATA_DIR=$DATA_DIR/geth/chaindata +SNAPSHOT=https://datadirs.optimism.io/latest + +if [ ! -d "$CHAINDATA_DIR" ]; then + wget -c $(curl -sL $SNAPSHOT | grep -oP '(?<=url=)[^"]*') -O - | zstd -cd | tar xf - -C $DATA_DIR +fi + +$GETH_BIN \ + --op-network op-mainnet \ + --datadir $DATA_DIR \ + --authrpc.jwtsecret $DATA_DIR/jwtsecret \ + --authrpc.addr 127.0.0.1 \ + --authrpc.port {{.Ports.BackendAuthRpc}} \ + --authrpc.vhosts "*" \ + --port {{.Ports.BackendP2P}} \ + --http \ + --http.port {{.Ports.BackendHttp}} \ + --http.addr 127.0.0.1 \ + --http.api eth,net,web3,debug,txpool,engine \ + --http.vhosts "*" \ + --http.corsdomain "*" \ + --ws \ + --ws.port {{.Ports.BackendRPC}} \ + --ws.addr 127.0.0.1 \ + --ws.api eth,net,web3,debug,txpool,engine \ + --ws.origins "*" \ + --rollup.disabletxpoolgossip=true \ + --rollup.historicalrpc http://127.0.0.1:8304 \ + --rollup.sequencerhttp https://mainnet.sequencer.optimism.io \ + --cache 4096 \ + --cache.gc 0 \ + --cache.trie 30 \ + --cache.snapshot 20 \ + --syncmode full \ + --gcmode archive \ + --maxpeers 0 \ + --nodiscover + +{{end}} diff --git a/build/templates/backend/scripts/optimism_archive_legacy_geth.sh b/build/templates/backend/scripts/optimism_archive_legacy_geth.sh new file mode 100644 index 00000000..641da1fe --- /dev/null +++ b/build/templates/backend/scripts/optimism_archive_legacy_geth.sh @@ -0,0 +1,40 @@ +#!/bin/sh + +{{define "main" -}} + +set -e + +export USING_OVM=true +export ETH1_SYNC_SERVICE_ENABLE=false + +GETH_BIN={{.Env.BackendInstallPath}}/{{.Coin.Alias}}/geth +DATA_DIR={{.Env.BackendDataPath}}/{{.Coin.Alias}}/backend + +CHAINDATA_DIR=$DATA_DIR/geth/chaindata +SNAPSHOT=https://datadirs.optimism.io/mainnet-legacy-archival.tar.zst + +if [ ! -d "$CHAINDATA_DIR" ]; then + wget -c $SNAPSHOT -O - | zstd -cd | tar xf - -C $DATA_DIR +fi + +$GETH_BIN \ + --networkid 10 \ + --datadir $DATA_DIR \ + --port {{.Ports.BackendP2P}} \ + --rpc \ + --rpcport {{.Ports.BackendHttp}} \ + --rpcaddr 127.0.0.1 \ + --rpcapi eth,rollup,net,web3,debug \ + --rpcvhosts "*" \ + --rpccorsdomain "*" \ + --ws \ + --wsport {{.Ports.BackendRPC}} \ + --wsaddr 0.0.0.0 \ + --wsapi eth,rollup,net,web3,debug \ + --wsorigins "*" \ + --nousb \ + --ipcdisable \ + --nat=none \ + --nodiscover + +{{end}} \ No newline at end of file diff --git a/build/templates/backend/scripts/optimism_archive_op_node.sh b/build/templates/backend/scripts/optimism_archive_op_node.sh new file mode 100644 index 00000000..46375703 --- /dev/null +++ b/build/templates/backend/scripts/optimism_archive_op_node.sh @@ -0,0 +1,24 @@ +#!/bin/sh + +{{define "main" -}} + +set -e + +BIN={{.Env.BackendInstallPath}}/{{.Coin.Alias}}/op-node +PATH={{.Env.BackendDataPath}}/{{.Coin.Alias}}/backend + +$BIN \ + --network op-mainnet \ + --l1 http://127.0.0.1:8116 \ + --l1.beacon http://127.0.0.1:7516 \ + --l1.trustrpc \ + --l1.rpckind=debug_geth \ + --l2 http://127.0.0.1:8402 \ + --rpc.addr 127.0.0.1 \ + --rpc.port {{.Ports.BackendRPC}} \ + --l2.jwt-secret {{.Env.BackendDataPath}}/optimism_archive/backend/jwtsecret \ + --p2p.priv.path $PATH/opnode_p2p_priv.txt \ + --p2p.peerstore.path $PATH/opnode_peerstore_db \ + --p2p.discovery.path $PATH/opnode_discovery_db + +{{end}} diff --git a/build/templates/backend/scripts/optimism_op_node.sh b/build/templates/backend/scripts/optimism_op_node.sh new file mode 100644 index 00000000..200c04b6 --- /dev/null +++ b/build/templates/backend/scripts/optimism_op_node.sh @@ -0,0 +1,24 @@ +#!/bin/sh + +{{define "main" -}} + +set -e + +BIN={{.Env.BackendInstallPath}}/{{.Coin.Alias}}/op-node +PATH={{.Env.BackendDataPath}}/{{.Coin.Alias}}/backend + +$BIN \ + --network op-mainnet \ + --l1 http://127.0.0.1:8136 \ + --l1.beacon http://127.0.0.1:7536 \ + --l1.trustrpc \ + --l1.rpckind=debug_geth \ + --l2 http://127.0.0.1:8400 \ + --rpc.addr 127.0.0.1 \ + --rpc.port {{.Ports.BackendRPC}} \ + --l2.jwt-secret {{.Env.BackendDataPath}}/optimism/backend/jwtsecret \ + --p2p.priv.path $PATH/opnode_p2p_priv.txt \ + --p2p.peerstore.path $PATH/opnode_peerstore_db \ + --p2p.discovery.path $PATH/opnode_discovery_db + +{{end}} diff --git a/build/templates/blockbook/blockchaincfg.json b/build/templates/blockbook/blockchaincfg.json index 525937c5..7d8fe75c 100644 --- a/build/templates/blockbook/blockchaincfg.json +++ b/build/templates/blockbook/blockchaincfg.json @@ -7,6 +7,8 @@ {{end}} "coin_name": "{{.Coin.Name}}", "coin_shortcut": "{{.Coin.Shortcut}}", +{{- if .Coin.Network}} + "network": "{{.Coin.Network}}",{{end}} "coin_label": "{{.Coin.Label}}", "rpc_url": "{{template "IPC.RPCURLTemplate" .}}", "rpc_user": "{{.IPC.RPCUser}}", diff --git a/build/tools/templates.go b/build/tools/templates.go index f414e5e1..03113d2a 100644 --- a/build/tools/templates.go +++ b/build/tools/templates.go @@ -21,6 +21,7 @@ type Backend struct { SystemUser string `json:"system_user"` Version string `json:"version"` BinaryURL string `json:"binary_url"` + DockerImage string `json:"docker_image"` VerificationType string `json:"verification_type"` VerificationSource string `json:"verification_source"` ExtractCommand string `json:"extract_command"` @@ -44,6 +45,7 @@ type Config struct { Coin struct { Name string `json:"name"` Shortcut string `json:"shortcut"` + Network string `json:"network,omitempty"` Label string `json:"label"` Alias string `json:"alias"` } `json:"coin"` @@ -203,6 +205,7 @@ func LoadConfig(configsDir, coin string) (*Config, error) { case "gpg": case "sha256": case "gpg-sha256": + case "docker": default: return nil, fmt.Errorf("Invalid verification type: %s", config.Backend.VerificationType) } diff --git a/build/tools/trezor-common/sync-coins.go b/build/tools/trezor-common/sync-coins.go index f4e90ba1..acb5518e 100644 --- a/build/tools/trezor-common/sync-coins.go +++ b/build/tools/trezor-common/sync-coins.go @@ -1,4 +1,4 @@ -//usr/bin/go run $0 $@ ; exit +// usr/bin/go run $0 $@ ; exit package main import ( diff --git a/build/tools/typescriptify/typescriptify.go b/build/tools/typescriptify/typescriptify.go index 4b19d4a2..069572cb 100644 --- a/build/tools/typescriptify/typescriptify.go +++ b/build/tools/typescriptify/typescriptify.go @@ -60,6 +60,8 @@ func main() { t.Add(server.WsFiatRatesForTimestampsReq{}) t.Add(server.WsFiatRatesTickersListReq{}) t.Add(server.WsMempoolFiltersReq{}) + t.Add(server.WsRpcCallReq{}) + t.Add(server.WsRpcCallRes{}) t.Add(bchain.MempoolTxidFilterEntries{}) err := t.ConvertToFile("blockbook-api.ts") diff --git a/common/config.go b/common/config.go index a0429805..2252b602 100644 --- a/common/config.go +++ b/common/config.go @@ -12,6 +12,7 @@ type Config struct { CoinName string `json:"coin_name"` CoinShortcut string `json:"coin_shortcut"` CoinLabel string `json:"coin_label"` + Network string `json:"network"` FourByteSignatures string `json:"fourByteSignatures"` FiatRates string `json:"fiat_rates"` FiatRatesParams string `json:"fiat_rates_params"` diff --git a/common/internalstate.go b/common/internalstate.go index 7c5c95ae..29a7a333 100644 --- a/common/internalstate.go +++ b/common/internalstate.go @@ -57,6 +57,7 @@ type InternalState struct { CoinShortcut string `json:"coinShortcut"` CoinLabel string `json:"coinLabel"` Host string `json:"host"` + Network string `json:"network,omitempty"` DbState uint32 `json:"dbState"` ExtendedIndex bool `json:"extendedIndex"` @@ -305,6 +306,15 @@ func (is *InternalState) computeAvgBlockPeriod() { is.AvgBlockPeriod = (is.BlockTimes[last] - is.BlockTimes[first]) / avgBlockPeriodSample } +// GetNetwork returns network. If not set returns the same value as CoinShortcut +func (is *InternalState) GetNetwork() string { + network := is.Network + if network == "" { + return is.CoinShortcut + } + return network +} + // SetBackendInfo sets new BackendInfo func (is *InternalState) SetBackendInfo(bi *BackendInfo) { is.mux.Lock() diff --git a/common/jsonnumber.go b/common/jsonnumber.go index d209fbe2..d6eab76c 100644 --- a/common/jsonnumber.go +++ b/common/jsonnumber.go @@ -6,7 +6,9 @@ import ( ) // JSONNumber is used instead of json.Number after upgrade to go 1.14 -// to handle data which can be numbers in double quotes or possibly not numbers at all +// +// to handle data which can be numbers in double quotes or possibly not numbers at all +// // see https://github.com/golang/go/issues/37308 type JSONNumber string diff --git a/configs/coins/arbitrum.json b/configs/coins/arbitrum.json new file mode 100644 index 00000000..26cf9351 --- /dev/null +++ b/configs/coins/arbitrum.json @@ -0,0 +1,66 @@ +{ + "coin": { + "name": "Arbitrum", + "shortcut": "ETH", + "network": "ARB", + "label": "Arbitrum", + "alias": "arbitrum" + }, + "ports": { + "backend_rpc": 8205, + "backend_p2p": 38405, + "backend_http": 8305, + "blockbook_internal": 9205, + "blockbook_public": 9305 + }, + "ipc": { + "rpc_url_template": "ws://127.0.0.1:{{.Ports.BackendRPC}}", + "rpc_timeout": 25 + }, + "backend": { + "package_name": "backend-arbitrum", + "package_revision": "satoshilabs-1", + "system_user": "arbitrum", + "version": "3.2.1", + "docker_image": "offchainlabs/nitro-node:v3.2.1-d81324d", + "verification_type": "docker", + "verification_source": "724ebdcca39cd0c28ffd025ecea8d1622a376f41344201b729afb60352cbc306", + "extract_command": "docker cp extract:/home/user/target backend/target; docker cp extract:/home/user/nitro-legacy backend/nitro-legacy; docker cp extract:/usr/local/bin/nitro backend/nitro", + "exclude_files": [], + "exec_command_template": "/bin/sh -c '{{.Env.BackendInstallPath}}/{{.Coin.Alias}}/arbitrum_exec.sh 2>> {{.Env.BackendDataPath}}/{{.Coin.Alias}}/backend/{{.Coin.Alias}}.log'", + "exec_script": "arbitrum.sh", + "logrotate_files_template": "{{.Env.BackendDataPath}}/{{.Coin.Alias}}/backend/{{.Coin.Alias}}.log", + "postinst_script_template": "openssl rand -hex 32 > {{.Env.BackendDataPath}}/{{.Coin.Alias}}/backend/jwtsecret", + "service_type": "simple", + "service_additional_params_template": "", + "protect_memory": true, + "mainnet": true, + "server_config_file": "", + "client_config_file": "" + }, + "blockbook": { + "package_name": "blockbook-arbitrum", + "system_user": "blockbook-arbitrum", + "internal_binding_template": ":{{.Ports.BlockbookInternal}}", + "public_binding_template": ":{{.Ports.BlockbookPublic}}", + "explorer_url": "", + "additional_params": "", + "block_chain": { + "parse": true, + "mempool_workers": 8, + "mempool_sub_workers": 2, + "block_addresses_to_keep": 300, + "additional_params": { + "mempoolTxTimeoutHours": 48, + "queryBackendOnMempoolResync": false, + "fiat_rates": "coingecko", + "fiat_rates_vs_currencies": "AED,ARS,AUD,BDT,BHD,BMD,BRL,CAD,CHF,CLP,CNY,CZK,DKK,EUR,GBP,HKD,HUF,IDR,ILS,INR,JPY,KRW,KWD,LKR,MMK,MXN,MYR,NGN,NOK,NZD,PHP,PKR,PLN,RUB,SAR,SEK,SGD,THB,TRY,TWD,UAH,USD,VEF,VND,ZAR,BTC,ETH", + "fiat_rates_params": "{\"coin\": \"ethereum\",\"platformIdentifier\": \"arbitrum-one\",\"platformVsCurrency\": \"eth\",\"periodSeconds\": 900}" + } + } + }, + "meta": { + "package_maintainer": "IT", + "package_maintainer_email": "it@satoshilabs.com" + } +} diff --git a/configs/coins/arbitrum_archive.json b/configs/coins/arbitrum_archive.json new file mode 100644 index 00000000..c85bb4cb --- /dev/null +++ b/configs/coins/arbitrum_archive.json @@ -0,0 +1,68 @@ +{ + "coin": { + "name": "Arbitrum Archive", + "shortcut": "ETH", + "network": "ARB", + "label": "Arbitrum", + "alias": "arbitrum_archive" + }, + "ports": { + "backend_rpc": 8306, + "backend_p2p": 38406, + "blockbook_internal": 9206, + "blockbook_public": 9306 + }, + "ipc": { + "rpc_url_template": "ws://127.0.0.1:{{.Ports.BackendRPC}}", + "rpc_timeout": 25 + }, + "backend": { + "package_name": "backend-arbitrum-archive", + "package_revision": "satoshilabs-1", + "system_user": "arbitrum", + "version": "3.2.1", + "docker_image": "offchainlabs/nitro-node:v3.2.1-d81324d", + "verification_type": "docker", + "verification_source": "724ebdcca39cd0c28ffd025ecea8d1622a376f41344201b729afb60352cbc306", + "extract_command": "docker cp extract:/home/user/target backend/target; docker cp extract:/home/user/nitro-legacy backend/nitro-legacy; docker cp extract:/usr/local/bin/nitro backend/nitro", + "exclude_files": [], + "exec_command_template": "/bin/sh -c '{{.Env.BackendInstallPath}}/{{.Coin.Alias}}/arbitrum_archive_exec.sh 2>> {{.Env.BackendDataPath}}/{{.Coin.Alias}}/backend/{{.Coin.Alias}}.log'", + "exec_script": "arbitrum_archive.sh", + "logrotate_files_template": "{{.Env.BackendDataPath}}/{{.Coin.Alias}}/backend/{{.Coin.Alias}}.log", + "postinst_script_template": "openssl rand -hex 32 > {{.Env.BackendDataPath}}/{{.Coin.Alias}}/backend/jwtsecret", + "service_type": "simple", + "service_additional_params_template": "", + "protect_memory": true, + "mainnet": true, + "server_config_file": "", + "client_config_file": "" + }, + "blockbook": { + "package_name": "blockbook-arbitrum-archive", + "system_user": "blockbook-arbitrum", + "internal_binding_template": ":{{.Ports.BlockbookInternal}}", + "public_binding_template": ":{{.Ports.BlockbookPublic}}", + "explorer_url": "", + "additional_params": "-workers=16", + "block_chain": { + "parse": true, + "mempool_workers": 8, + "mempool_sub_workers": 2, + "block_addresses_to_keep": 600, + "additional_params": { + "address_aliases": true, + "mempoolTxTimeoutHours": 48, + "processInternalTransactions": true, + "queryBackendOnMempoolResync": false, + "fiat_rates": "coingecko", + "fiat_rates_vs_currencies": "AED,ARS,AUD,BDT,BHD,BMD,BRL,CAD,CHF,CLP,CNY,CZK,DKK,EUR,GBP,HKD,HUF,IDR,ILS,INR,JPY,KRW,KWD,LKR,MMK,MXN,MYR,NGN,NOK,NZD,PHP,PKR,PLN,RUB,SAR,SEK,SGD,THB,TRY,TWD,UAH,USD,VEF,VND,ZAR,BTC,ETH", + "fiat_rates_params": "{\"coin\": \"ethereum\",\"platformIdentifier\": \"arbitrum-one\",\"platformVsCurrency\": \"eth\",\"periodSeconds\": 900}", + "fourByteSignatures": "https://www.4byte.directory/api/v1/signatures/" + } + } + }, + "meta": { + "package_maintainer": "IT", + "package_maintainer_email": "it@satoshilabs.com" + } +} diff --git a/configs/coins/arbitrum_nova.json b/configs/coins/arbitrum_nova.json new file mode 100644 index 00000000..55d20d7d --- /dev/null +++ b/configs/coins/arbitrum_nova.json @@ -0,0 +1,65 @@ +{ + "coin": { + "name": "Arbitrum Nova", + "shortcut": "ETH", + "label": "Arbitrum Nova", + "alias": "arbitrum_nova" + }, + "ports": { + "backend_rpc": 8207, + "backend_p2p": 38407, + "backend_http": 8307, + "blockbook_internal": 9207, + "blockbook_public": 9307 + }, + "ipc": { + "rpc_url_template": "ws://127.0.0.1:{{.Ports.BackendRPC}}", + "rpc_timeout": 25 + }, + "backend": { + "package_name": "backend-arbitrum-nova", + "package_revision": "satoshilabs-1", + "system_user": "arbitrum", + "version": "3.2.1", + "docker_image": "offchainlabs/nitro-node:v3.2.1-d81324d", + "verification_type": "docker", + "verification_source": "724ebdcca39cd0c28ffd025ecea8d1622a376f41344201b729afb60352cbc306", + "extract_command": "docker cp extract:/home/user/target backend/target; docker cp extract:/home/user/nitro-legacy backend/nitro-legacy; docker cp extract:/usr/local/bin/nitro backend/nitro", + "exclude_files": [], + "exec_command_template": "/bin/sh -c '{{.Env.BackendInstallPath}}/{{.Coin.Alias}}/arbitrum_nova_exec.sh 2>> {{.Env.BackendDataPath}}/{{.Coin.Alias}}/backend/{{.Coin.Alias}}.log'", + "exec_script": "arbitrum_nova.sh", + "logrotate_files_template": "{{.Env.BackendDataPath}}/{{.Coin.Alias}}/backend/{{.Coin.Alias}}.log", + "postinst_script_template": "openssl rand -hex 32 > {{.Env.BackendDataPath}}/{{.Coin.Alias}}/backend/jwtsecret", + "service_type": "simple", + "service_additional_params_template": "", + "protect_memory": true, + "mainnet": true, + "server_config_file": "", + "client_config_file": "" + }, + "blockbook": { + "package_name": "blockbook-arbitrum-nova", + "system_user": "blockbook-arbitrum", + "internal_binding_template": ":{{.Ports.BlockbookInternal}}", + "public_binding_template": ":{{.Ports.BlockbookPublic}}", + "explorer_url": "", + "additional_params": "", + "block_chain": { + "parse": true, + "mempool_workers": 8, + "mempool_sub_workers": 2, + "block_addresses_to_keep": 300, + "additional_params": { + "mempoolTxTimeoutHours": 48, + "queryBackendOnMempoolResync": false, + "fiat_rates": "coingecko", + "fiat_rates_vs_currencies": "AED,ARS,AUD,BDT,BHD,BMD,BRL,CAD,CHF,CLP,CNY,CZK,DKK,EUR,GBP,HKD,HUF,IDR,ILS,INR,JPY,KRW,KWD,LKR,MMK,MXN,MYR,NGN,NOK,NZD,PHP,PKR,PLN,RUB,SAR,SEK,SGD,THB,TRY,TWD,UAH,USD,VEF,VND,ZAR,BTC,ETH", + "fiat_rates_params": "{\"coin\": \"ethereum\",\"platformIdentifier\": \"ethereum\",\"platformVsCurrency\": \"eth\",\"periodSeconds\": 900}" + } + } + }, + "meta": { + "package_maintainer": "IT", + "package_maintainer_email": "it@satoshilabs.com" + } +} diff --git a/configs/coins/arbitrum_nova_archive.json b/configs/coins/arbitrum_nova_archive.json new file mode 100644 index 00000000..d0833e45 --- /dev/null +++ b/configs/coins/arbitrum_nova_archive.json @@ -0,0 +1,67 @@ +{ + "coin": { + "name": "Arbitrum Nova Archive", + "shortcut": "ETH", + "label": "Arbitrum Nova", + "alias": "arbitrum_nova_archive" + }, + "ports": { + "backend_rpc": 8308, + "backend_p2p": 38408, + "blockbook_internal": 9208, + "blockbook_public": 9308 + }, + "ipc": { + "rpc_url_template": "ws://127.0.0.1:{{.Ports.BackendRPC}}", + "rpc_timeout": 25 + }, + "backend": { + "package_name": "backend-arbitrum-nova-archive", + "package_revision": "satoshilabs-1", + "system_user": "arbitrum", + "version": "3.2.1", + "docker_image": "offchainlabs/nitro-node:v3.2.1-d81324d", + "verification_type": "docker", + "verification_source": "724ebdcca39cd0c28ffd025ecea8d1622a376f41344201b729afb60352cbc306", + "extract_command": "docker cp extract:/home/user/target backend/target; docker cp extract:/home/user/nitro-legacy backend/nitro-legacy; docker cp extract:/usr/local/bin/nitro backend/nitro", + "exclude_files": [], + "exec_command_template": "/bin/sh -c '{{.Env.BackendInstallPath}}/{{.Coin.Alias}}/arbitrum_nova_archive_exec.sh 2>> {{.Env.BackendDataPath}}/{{.Coin.Alias}}/backend/{{.Coin.Alias}}.log'", + "exec_script": "arbitrum_nova_archive.sh", + "logrotate_files_template": "{{.Env.BackendDataPath}}/{{.Coin.Alias}}/backend/{{.Coin.Alias}}.log", + "postinst_script_template": "openssl rand -hex 32 > {{.Env.BackendDataPath}}/{{.Coin.Alias}}/backend/jwtsecret", + "service_type": "simple", + "service_additional_params_template": "", + "protect_memory": true, + "mainnet": true, + "server_config_file": "", + "client_config_file": "" + }, + "blockbook": { + "package_name": "blockbook-arbitrum-nova-archive", + "system_user": "blockbook-arbitrum", + "internal_binding_template": ":{{.Ports.BlockbookInternal}}", + "public_binding_template": ":{{.Ports.BlockbookPublic}}", + "explorer_url": "", + "additional_params": "-workers=16", + "block_chain": { + "parse": true, + "mempool_workers": 8, + "mempool_sub_workers": 2, + "block_addresses_to_keep": 600, + "additional_params": { + "address_aliases": true, + "mempoolTxTimeoutHours": 48, + "processInternalTransactions": true, + "queryBackendOnMempoolResync": false, + "fiat_rates": "coingecko", + "fiat_rates_vs_currencies": "AED,ARS,AUD,BDT,BHD,BMD,BRL,CAD,CHF,CLP,CNY,CZK,DKK,EUR,GBP,HKD,HUF,IDR,ILS,INR,JPY,KRW,KWD,LKR,MMK,MXN,MYR,NGN,NOK,NZD,PHP,PKR,PLN,RUB,SAR,SEK,SGD,THB,TRY,TWD,UAH,USD,VEF,VND,ZAR,BTC,ETH", + "fiat_rates_params": "{\"coin\": \"ethereum\",\"platformIdentifier\": \"ethereum\",\"platformVsCurrency\": \"eth\",\"periodSeconds\": 900}", + "fourByteSignatures": "https://www.4byte.directory/api/v1/signatures/" + } + } + }, + "meta": { + "package_maintainer": "IT", + "package_maintainer_email": "it@satoshilabs.com" + } +} diff --git a/configs/coins/bcash.json b/configs/coins/bcash.json index 1d2043ea..1a6a4e5d 100644 --- a/configs/coins/bcash.json +++ b/configs/coins/bcash.json @@ -22,10 +22,10 @@ "package_name": "backend-bcash", "package_revision": "satoshilabs-1", "system_user": "bcash", - "version": "27.0.0", - "binary_url": "https://github.com/bitcoin-cash-node/bitcoin-cash-node/releases/download/v27.0.0/bitcoin-cash-node-27.0.0-x86_64-linux-gnu.tar.gz", + "version": "28.0.1", + "binary_url": "https://github.com/bitcoin-cash-node/bitcoin-cash-node/releases/download/v28.0.1/bitcoin-cash-node-28.0.1-x86_64-linux-gnu.tar.gz", "verification_type": "sha256", - "verification_source": "2ab81515a763162435f7ea28bb1f10f69b6143f469278fc52c0b8cbaec6cf238", + "verification_source": "d69ee632147f886ca540cecdff5b1b85512612b4c005e86b09083a63c35b64fa", "extract_command": "tar -C backend --strip 1 -xf", "exclude_files": ["bin/bitcoin-qt"], "exec_command_template": "{{.Env.BackendInstallPath}}/{{.Coin.Alias}}/bin/bitcoind -datadir={{.Env.BackendDataPath}}/{{.Coin.Alias}}/backend -conf={{.Env.BackendInstallPath}}/{{.Coin.Alias}}/{{.Coin.Alias}}.conf -pid=/run/{{.Coin.Alias}}/{{.Coin.Alias}}.pid", diff --git a/configs/coins/bcash_testnet.json b/configs/coins/bcash_testnet.json index 0571743a..fb98530c 100644 --- a/configs/coins/bcash_testnet.json +++ b/configs/coins/bcash_testnet.json @@ -22,10 +22,10 @@ "package_name": "backend-bcash-testnet", "package_revision": "satoshilabs-1", "system_user": "bcash", - "version": "27.0.0", - "binary_url": "https://github.com/bitcoin-cash-node/bitcoin-cash-node/releases/download/v27.0.0/bitcoin-cash-node-27.0.0-x86_64-linux-gnu.tar.gz", + "version": "28.0.1", + "binary_url": "https://github.com/bitcoin-cash-node/bitcoin-cash-node/releases/download/v28.0.1/bitcoin-cash-node-28.0.1-x86_64-linux-gnu.tar.gz", "verification_type": "sha256", - "verification_source": "2ab81515a763162435f7ea28bb1f10f69b6143f469278fc52c0b8cbaec6cf238", + "verification_source": "d69ee632147f886ca540cecdff5b1b85512612b4c005e86b09083a63c35b64fa", "extract_command": "tar -C backend --strip 1 -xf", "exclude_files": ["bin/bitcoin-qt"], "exec_command_template": "{{.Env.BackendInstallPath}}/{{.Coin.Alias}}/bin/bitcoind -datadir={{.Env.BackendDataPath}}/{{.Coin.Alias}}/backend -conf={{.Env.BackendInstallPath}}/{{.Coin.Alias}}/{{.Coin.Alias}}.conf -pid=/run/{{.Coin.Alias}}/{{.Coin.Alias}}.pid", diff --git a/configs/coins/bitcoin.json b/configs/coins/bitcoin.json index 61fbb924..9e4b09ec 100644 --- a/configs/coins/bitcoin.json +++ b/configs/coins/bitcoin.json @@ -22,10 +22,10 @@ "package_name": "backend-bitcoin", "package_revision": "satoshilabs-1", "system_user": "bitcoin", - "version": "27.1", - "binary_url": "https://bitcoincore.org/bin/bitcoin-core-27.1/bitcoin-27.1-x86_64-linux-gnu.tar.gz", + "version": "28.0", + "binary_url": "https://bitcoincore.org/bin/bitcoin-core-28.0/bitcoin-28.0-x86_64-linux-gnu.tar.gz", "verification_type": "sha256", - "verification_source": "c9840607d230d65f6938b81deaec0b98fe9cb14c3a41a5b13b2c05d044a48422", + "verification_source": "7fe294b02b25b51acb8e8e0a0eb5af6bbafa7cd0c5b0e5fcbb61263104a82fbc", "extract_command": "tar -C backend --strip 1 -xf", "exclude_files": ["bin/bitcoin-qt"], "exec_command_template": "{{.Env.BackendInstallPath}}/{{.Coin.Alias}}/bin/bitcoind -datadir={{.Env.BackendDataPath}}/{{.Coin.Alias}}/backend -conf={{.Env.BackendInstallPath}}/{{.Coin.Alias}}/{{.Coin.Alias}}.conf -pid=/run/{{.Coin.Alias}}/{{.Coin.Alias}}.pid", @@ -43,8 +43,8 @@ }, "platforms": { "arm64": { - "binary_url": "https://bitcoincore.org/bin/bitcoin-core-27.1/bitcoin-27.1-aarch64-linux-gnu.tar.gz", - "verification_source": "bb878df4f8ff8fb8acfb94207c50f959c462c39e652f507c2a2db20acc6a1eee" + "binary_url": "https://bitcoincore.org/bin/bitcoin-core-28.0/bitcoin-28.0-aarch64-linux-gnu.tar.gz", + "verification_source": "7fa582d99a25c354d23e371a5848bd9e6a79702870f9cbbf1292b86e647d0f4e" } } }, diff --git a/configs/coins/bitcoin_regtest.json b/configs/coins/bitcoin_regtest.json index 96a6c898..42f94833 100644 --- a/configs/coins/bitcoin_regtest.json +++ b/configs/coins/bitcoin_regtest.json @@ -22,10 +22,10 @@ "package_name": "backend-bitcoin-regtest", "package_revision": "satoshilabs-1", "system_user": "bitcoin", - "version": "27.1", - "binary_url": "https://bitcoincore.org/bin/bitcoin-core-27.1/bitcoin-27.1-x86_64-linux-gnu.tar.gz", + "version": "28.0", + "binary_url": "https://bitcoincore.org/bin/bitcoin-core-28.0/bitcoin-28.0-x86_64-linux-gnu.tar.gz", "verification_type": "sha256", - "verification_source": "c9840607d230d65f6938b81deaec0b98fe9cb14c3a41a5b13b2c05d044a48422", + "verification_source": "7fe294b02b25b51acb8e8e0a0eb5af6bbafa7cd0c5b0e5fcbb61263104a82fbc", "extract_command": "tar -C backend --strip 1 -xf", "exclude_files": ["bin/bitcoin-qt"], "exec_command_template": "{{.Env.BackendInstallPath}}/{{.Coin.Alias}}/bin/bitcoind -datadir={{.Env.BackendDataPath}}/{{.Coin.Alias}}/backend -conf={{.Env.BackendInstallPath}}/{{.Coin.Alias}}/{{.Coin.Alias}}.conf -pid=/run/{{.Coin.Alias}}/{{.Coin.Alias}}.pid", @@ -42,8 +42,8 @@ }, "platforms": { "arm64": { - "binary_url": "https://bitcoincore.org/bin/bitcoin-core-27.1/bitcoin-27.1-aarch64-linux-gnu.tar.gz", - "verification_source": "bb878df4f8ff8fb8acfb94207c50f959c462c39e652f507c2a2db20acc6a1eee" + "binary_url": "https://bitcoincore.org/bin/bitcoin-core-28.0/bitcoin-28.0-aarch64-linux-gnu.tar.gz", + "verification_source": "7fa582d99a25c354d23e371a5848bd9e6a79702870f9cbbf1292b86e647d0f4e" } } }, diff --git a/configs/coins/bitcoin_signet.json b/configs/coins/bitcoin_signet.json index 7a94587f..c18e71cc 100644 --- a/configs/coins/bitcoin_signet.json +++ b/configs/coins/bitcoin_signet.json @@ -22,10 +22,10 @@ "package_name": "backend-bitcoin-signet", "package_revision": "satoshilabs-1", "system_user": "bitcoin", - "version": "27.1", - "binary_url": "https://bitcoincore.org/bin/bitcoin-core-27.1/bitcoin-27.1-x86_64-linux-gnu.tar.gz", + "version": "28.0", + "binary_url": "https://bitcoincore.org/bin/bitcoin-core-28.0/bitcoin-28.0-x86_64-linux-gnu.tar.gz", "verification_type": "sha256", - "verification_source": "c9840607d230d65f6938b81deaec0b98fe9cb14c3a41a5b13b2c05d044a48422", + "verification_source": "7fe294b02b25b51acb8e8e0a0eb5af6bbafa7cd0c5b0e5fcbb61263104a82fbc", "extract_command": "tar -C backend --strip 1 -xf", "exclude_files": ["bin/bitcoin-qt"], "exec_command_template": "{{.Env.BackendInstallPath}}/{{.Coin.Alias}}/bin/bitcoind -datadir={{.Env.BackendDataPath}}/{{.Coin.Alias}}/backend -conf={{.Env.BackendInstallPath}}/{{.Coin.Alias}}/{{.Coin.Alias}}.conf -pid=/run/{{.Coin.Alias}}/{{.Coin.Alias}}.pid", @@ -35,15 +35,15 @@ "service_additional_params_template": "", "protect_memory": true, "mainnet": false, - "server_config_file": "bitcoin-signet.conf", + "server_config_file": "bitcoin_signet.conf", "client_config_file": "bitcoin_client.conf", "additional_params": { "deprecatedrpc": "estimatefee" }, "platforms": { "arm64": { - "binary_url": "https://bitcoincore.org/bin/bitcoin-core-27.1/bitcoin-27.1-aarch64-linux-gnu.tar.gz", - "verification_source": "bb878df4f8ff8fb8acfb94207c50f959c462c39e652f507c2a2db20acc6a1eee" + "binary_url": "https://bitcoincore.org/bin/bitcoin-core-28.0/bitcoin-28.0-aarch64-linux-gnu.tar.gz", + "verification_source": "7fa582d99a25c354d23e371a5848bd9e6a79702870f9cbbf1292b86e647d0f4e" } } }, diff --git a/configs/coins/bitcoin_testnet.json b/configs/coins/bitcoin_testnet.json index 3b6741e1..dc6048f6 100644 --- a/configs/coins/bitcoin_testnet.json +++ b/configs/coins/bitcoin_testnet.json @@ -22,10 +22,10 @@ "package_name": "backend-bitcoin-testnet", "package_revision": "satoshilabs-1", "system_user": "bitcoin", - "version": "27.1", - "binary_url": "https://bitcoincore.org/bin/bitcoin-core-27.1/bitcoin-27.1-x86_64-linux-gnu.tar.gz", + "version": "28.0", + "binary_url": "https://bitcoincore.org/bin/bitcoin-core-28.0/bitcoin-28.0-x86_64-linux-gnu.tar.gz", "verification_type": "sha256", - "verification_source": "c9840607d230d65f6938b81deaec0b98fe9cb14c3a41a5b13b2c05d044a48422", + "verification_source": "7fe294b02b25b51acb8e8e0a0eb5af6bbafa7cd0c5b0e5fcbb61263104a82fbc", "extract_command": "tar -C backend --strip 1 -xf", "exclude_files": ["bin/bitcoin-qt"], "exec_command_template": "{{.Env.BackendInstallPath}}/{{.Coin.Alias}}/bin/bitcoind -datadir={{.Env.BackendDataPath}}/{{.Coin.Alias}}/backend -conf={{.Env.BackendInstallPath}}/{{.Coin.Alias}}/{{.Coin.Alias}}.conf -pid=/run/{{.Coin.Alias}}/{{.Coin.Alias}}.pid", @@ -42,8 +42,8 @@ }, "platforms": { "arm64": { - "binary_url": "https://bitcoincore.org/bin/bitcoin-core-27.1/bitcoin-27.1-aarch64-linux-gnu.tar.gz", - "verification_source": "bb878df4f8ff8fb8acfb94207c50f959c462c39e652f507c2a2db20acc6a1eee" + "binary_url": "https://bitcoincore.org/bin/bitcoin-core-28.0/bitcoin-28.0-aarch64-linux-gnu.tar.gz", + "verification_source": "7fa582d99a25c354d23e371a5848bd9e6a79702870f9cbbf1292b86e647d0f4e" } } }, diff --git a/configs/coins/bitcoin_testnet4.json b/configs/coins/bitcoin_testnet4.json new file mode 100644 index 00000000..75bf73e8 --- /dev/null +++ b/configs/coins/bitcoin_testnet4.json @@ -0,0 +1,80 @@ +{ + "coin": { + "name": "Testnet4", + "shortcut": "TEST", + "label": "Bitcoin Testnet4", + "alias": "bitcoin_testnet4" + }, + "ports": { + "backend_rpc": 18029, + "backend_message_queue": 48329, + "blockbook_internal": 19029, + "blockbook_public": 19129 + }, + "ipc": { + "rpc_url_template": "http://127.0.0.1:{{.Ports.BackendRPC}}", + "rpc_user": "rpc", + "rpc_pass": "rpc", + "rpc_timeout": 25, + "message_queue_binding_template": "tcp://127.0.0.1:{{.Ports.BackendMessageQueue}}" + }, + "backend": { + "package_name": "backend-bitcoin-testnet4", + "package_revision": "satoshilabs-1", + "system_user": "bitcoin", + "version": "28.0", + "binary_url": "https://bitcoincore.org/bin/bitcoin-core-28.0/bitcoin-28.0-x86_64-linux-gnu.tar.gz", + "verification_type": "sha256", + "verification_source": "7fe294b02b25b51acb8e8e0a0eb5af6bbafa7cd0c5b0e5fcbb61263104a82fbc", + "extract_command": "tar -C backend --strip 1 -xf", + "exclude_files": ["bin/bitcoin-qt"], + "exec_command_template": "{{.Env.BackendInstallPath}}/{{.Coin.Alias}}/bin/bitcoind -datadir={{.Env.BackendDataPath}}/{{.Coin.Alias}}/backend -conf={{.Env.BackendInstallPath}}/{{.Coin.Alias}}/{{.Coin.Alias}}.conf -pid=/run/{{.Coin.Alias}}/{{.Coin.Alias}}.pid", + "logrotate_files_template": "{{.Env.BackendDataPath}}/{{.Coin.Alias}}/backend/testnet4/*.log", + "postinst_script_template": "", + "service_type": "forking", + "service_additional_params_template": "", + "protect_memory": true, + "mainnet": false, + "server_config_file": "bitcoin_testnet4.conf", + "client_config_file": "bitcoin_client.conf", + "additional_params": { + "deprecatedrpc": "estimatefee" + }, + "platforms": { + "arm64": { + "binary_url": "https://bitcoincore.org/bin/bitcoin-core-28.0/bitcoin-28.0-aarch64-linux-gnu.tar.gz", + "verification_source": "7fa582d99a25c354d23e371a5848bd9e6a79702870f9cbbf1292b86e647d0f4e" + } + } + }, + "blockbook": { + "package_name": "blockbook-bitcoin-testnet4", + "system_user": "blockbook-bitcoin", + "internal_binding_template": ":{{.Ports.BlockbookInternal}}", + "public_binding_template": ":{{.Ports.BlockbookPublic}}", + "explorer_url": "", + "additional_params": "-enablesubnewtx -extendedindex", + "block_chain": { + "parse": true, + "mempool_workers": 8, + "mempool_sub_workers": 2, + "block_addresses_to_keep": 10000, + "xpub_magic": 70617039, + "xpub_magic_segwit_p2sh": 71979618, + "xpub_magic_segwit_native": 73342198, + "slip44": 1, + "additional_params": { + "block_golomb_filter_p": 20, + "block_filter_scripts": "taproot-noordinals", + "block_filter_use_zeroed_key": true, + "mempool_golomb_filter_p": 20, + "mempool_filter_scripts": "taproot", + "mempool_filter_use_zeroed_key": false + } + } + }, + "meta": { + "package_maintainer": "IT", + "package_maintainer_email": "it@satoshilabs.com" + } +} diff --git a/configs/coins/bsc.json b/configs/coins/bsc.json index a22923d8..db599b3a 100644 --- a/configs/coins/bsc.json +++ b/configs/coins/bsc.json @@ -2,6 +2,7 @@ "coin": { "name": "BNB Smart Chain", "shortcut": "BNB", + "network": "BSC", "label": "BNB Smart Chain", "alias": "bsc" }, diff --git a/configs/coins/bsc_archive.json b/configs/coins/bsc_archive.json index b40584ea..0b460876 100644 --- a/configs/coins/bsc_archive.json +++ b/configs/coins/bsc_archive.json @@ -2,6 +2,7 @@ "coin": { "name": "BNB Smart Chain Archive", "shortcut": "BNB", + "network": "BSC", "label": "BNB Smart Chain", "alias": "bsc_archive" }, diff --git a/configs/coins/dash.json b/configs/coins/dash.json index b77e6732..255325ef 100644 --- a/configs/coins/dash.json +++ b/configs/coins/dash.json @@ -22,10 +22,10 @@ "package_name": "backend-dash", "package_revision": "satoshilabs-1", "system_user": "dash", - "version": "20.1.1", - "binary_url": "https://github.com/dashpay/dash/releases/download/v20.1.1/dashcore-20.1.1-x86_64-linux-gnu.tar.gz", + "version": "22.0.0", + "binary_url": "https://github.com/dashpay/dash/releases/download/v22.0.0/dashcore-22.0.0-x86_64-linux-gnu.tar.gz", "verification_type": "gpg-sha256", - "verification_source": "https://github.com/dashpay/dash/releases/download/v20.1.1/SHA256SUMS.asc", + "verification_source": "https://github.com/dashpay/dash/releases/download/v22.0.0/SHA256SUMS.asc", "extract_command": "tar -C backend --strip 1 -xf", "exclude_files": ["bin/dash-qt"], "exec_command_template": "{{.Env.BackendInstallPath}}/{{.Coin.Alias}}/bin/dashd -deprecatedrpc=estimatefee -datadir={{.Env.BackendDataPath}}/{{.Coin.Alias}}/backend -conf={{.Env.BackendInstallPath}}/{{.Coin.Alias}}/{{.Coin.Alias}}.conf -pid=/run/{{.Coin.Alias}}/{{.Coin.Alias}}.pid", diff --git a/configs/coins/dash_testnet.json b/configs/coins/dash_testnet.json index 86925e0a..081381a6 100644 --- a/configs/coins/dash_testnet.json +++ b/configs/coins/dash_testnet.json @@ -22,10 +22,10 @@ "package_name": "backend-dash-testnet", "package_revision": "satoshilabs-1", "system_user": "dash", - "version": "20.1.1", - "binary_url": "https://github.com/dashpay/dash/releases/download/v20.1.1/dashcore-20.1.1-x86_64-linux-gnu.tar.gz", + "version": "22.0.0", + "binary_url": "https://github.com/dashpay/dash/releases/download/v22.0.0/dashcore-22.0.0-x86_64-linux-gnu.tar.gz", "verification_type": "gpg-sha256", - "verification_source": "https://github.com/dashpay/dash/releases/download/v20.1.1/SHA256SUMS.asc", + "verification_source": "https://github.com/dashpay/dash/releases/download/v22.0.0/SHA256SUMS.asc", "extract_command": "tar -C backend --strip 1 -xf", "exclude_files": [ "bin/dash-qt" diff --git a/configs/coins/dogecoin.json b/configs/coins/dogecoin.json index 4f3d4d59..f1200432 100644 --- a/configs/coins/dogecoin.json +++ b/configs/coins/dogecoin.json @@ -22,10 +22,10 @@ "package_name": "backend-dogecoin", "package_revision": "satoshilabs-1", "system_user": "dogecoin", - "version": "1.14.7", - "binary_url": "https://github.com/dogecoin/dogecoin/releases/download/v1.14.7/dogecoin-1.14.7-x86_64-linux-gnu.tar.gz", + "version": "1.14.9", + "binary_url": "https://github.com/dogecoin/dogecoin/releases/download/v1.14.9/dogecoin-1.14.9-x86_64-linux-gnu.tar.gz", "verification_type": "sha256", - "verification_source": "9cd22fb3ebba4d407c2947f4241b9e78c759f29cdf32de8863aea6aeed21cf8b", + "verification_source": "4f227117b411a7c98622c970986e27bcfc3f547a72bef65e7d9e82989175d4f8", "extract_command": "tar -C backend --strip 1 -xf", "exclude_files": ["bin/dogecoin-qt"], "exec_command_template": "{{.Env.BackendInstallPath}}/{{.Coin.Alias}}/bin/dogecoind -datadir={{.Env.BackendDataPath}}/{{.Coin.Alias}}/backend -conf={{.Env.BackendInstallPath}}/{{.Coin.Alias}}/{{.Coin.Alias}}.conf -pid=/run/{{.Coin.Alias}}/{{.Coin.Alias}}.pid", @@ -45,8 +45,8 @@ }, "platforms": { "arm64": { - "binary_url": "https://github.com/dogecoin/dogecoin/releases/download/v1.14.7/dogecoin-1.14.7-aarch64-linux-gnu.tar.gz", - "verification_source": "b8fb8050b19283d1ab3c261aaca96d84f2a17f93b52fcff9e252f390b0564f31", + "binary_url": "https://github.com/dogecoin/dogecoin/releases/download/v1.14.9/dogecoin-1.14.9-aarch64-linux-gnu.tar.gz", + "verification_source": "6928c895a20d0bcb6d5c7dcec753d35c884a471aaf8ad4242a89a96acb4f2985", "exclude_files": [] } } diff --git a/configs/coins/dogecoin_testnet.json b/configs/coins/dogecoin_testnet.json index d16ab587..8103ba70 100644 --- a/configs/coins/dogecoin_testnet.json +++ b/configs/coins/dogecoin_testnet.json @@ -22,10 +22,10 @@ "package_name": "backend-dogecoin-testnet", "package_revision": "satoshilabs-1", "system_user": "dogecoin", - "version": "1.14.7", - "binary_url": "https://github.com/dogecoin/dogecoin/releases/download/v1.14.7/dogecoin-1.14.7-x86_64-linux-gnu.tar.gz", + "version": "1.14.9", + "binary_url": "https://github.com/dogecoin/dogecoin/releases/download/v1.14.9/dogecoin-1.14.9-x86_64-linux-gnu.tar.gz", "verification_type": "sha256", - "verification_source": "9cd22fb3ebba4d407c2947f4241b9e78c759f29cdf32de8863aea6aeed21cf8b", + "verification_source": "4f227117b411a7c98622c970986e27bcfc3f547a72bef65e7d9e82989175d4f8", "extract_command": "tar -C backend --strip 1 -xf", "exclude_files": [ "bin/dogecoin-qt" @@ -47,8 +47,8 @@ }, "platforms": { "arm64": { - "binary_url": "https://github.com/dogecoin/dogecoin/releases/download/v1.14.7/dogecoin-1.14.7-aarch64-linux-gnu.tar.gz", - "verification_source": "b8fb8050b19283d1ab3c261aaca96d84f2a17f93b52fcff9e252f390b0564f31", + "binary_url": "https://github.com/dogecoin/dogecoin/releases/download/v1.14.9/dogecoin-1.14.9-aarch64-linux-gnu.tar.gz", + "verification_source": "6928c895a20d0bcb6d5c7dcec753d35c884a471aaf8ad4242a89a96acb4f2985", "exclude_files": [] } } diff --git a/configs/coins/ethereum.json b/configs/coins/ethereum.json index 79e607a9..c81e8660 100644 --- a/configs/coins/ethereum.json +++ b/configs/coins/ethereum.json @@ -22,11 +22,11 @@ "package_name": "backend-ethereum", "package_revision": "satoshilabs-1", "system_user": "ethereum", - "version": "2.59.1", - "binary_url": "https://github.com/ledgerwatch/erigon/releases/download/v2.59.1/erigon_2.59.1_linux_amd64.tar.gz", + "version": "2.60.10", + "binary_url": "https://github.com/ledgerwatch/erigon/releases/download/v2.60.10/erigon_v2.60.10_linux_amd64.tar.gz", "verification_type": "sha256", - "verification_source": "5800f0da3ec52f8abc414860f4b3c9ac8c46d07c5044b5458820c71fd4b95b38", - "extract_command": "tar -C backend -xf", + "verification_source": "e22dc039846f2aee3d180b1dfb7d1b8282377d76ab4654137ed4abfec5d8e2af", + "extract_command": "tar -C backend --strip-components=1 -xf", "exclude_files": [], "exec_command_template": "/bin/sh -c '{{.Env.BackendInstallPath}}/{{.Coin.Alias}}/erigon --chain mainnet --snap.keepblocks --db.size.limit 15TB --prune c --prune.c.older 1000000 -torrent.download.rate 32mb --nat none --datadir {{.Env.BackendDataPath}}/{{.Coin.Alias}}/backend/erigon --port {{.Ports.BackendP2P}} --ws --ws.port {{.Ports.BackendRPC}} --http --http.port {{.Ports.BackendRPC}} --http.addr 127.0.0.1 --http.corsdomain \"*\" --http.vhosts \"*\" --http.api \"eth,net,web3,debug,txpool\" --authrpc.port {{.Ports.BackendAuthRpc}} --private.api.addr \"\" --torrent.port {{.Ports.BackendHttp}} --log.dir.path {{.Env.BackendDataPath}}/{{.Coin.Alias}}/backend --log.dir.prefix {{.Coin.Alias}}'", "logrotate_files_template": "{{.Env.BackendDataPath}}/{{.Coin.Alias}}/backend/{{.Coin.Alias}}.log", @@ -39,8 +39,8 @@ "client_config_file": "", "platforms": { "arm64": { - "binary_url": "https://github.com/ledgerwatch/erigon/releases/download/v2.59.1/erigon_2.59.1_linux_arm64.tar.gz", - "verification_source": "9d29e04f600111971c56a9c48aa5c7c9e81cd61ad8bb042c240505e4bd93bf88" + "binary_url": "https://github.com/ledgerwatch/erigon/releases/download/v2.60.10/erigon_v2.60.10_linux_arm64.tar.gz", + "verification_source": "68cb9baf937d19446de91bc1efccf389b4a2452233b3a5ef1cf5cd8a91b9ce95" } } }, diff --git a/configs/coins/ethereum_archive.json b/configs/coins/ethereum_archive.json index 18103432..6bab2239 100644 --- a/configs/coins/ethereum_archive.json +++ b/configs/coins/ethereum_archive.json @@ -22,11 +22,11 @@ "package_name": "backend-ethereum-archive", "package_revision": "satoshilabs-1", "system_user": "ethereum", - "version": "2.59.1", - "binary_url": "https://github.com/ledgerwatch/erigon/releases/download/v2.59.1/erigon_2.59.1_linux_amd64.tar.gz", + "version": "2.60.10", + "binary_url": "https://github.com/ledgerwatch/erigon/releases/download/v2.60.10/erigon_v2.60.10_linux_amd64.tar.gz", "verification_type": "sha256", - "verification_source": "5800f0da3ec52f8abc414860f4b3c9ac8c46d07c5044b5458820c71fd4b95b38", - "extract_command": "tar -C backend -xf", + "verification_source": "e22dc039846f2aee3d180b1dfb7d1b8282377d76ab4654137ed4abfec5d8e2af", + "extract_command": "tar -C backend --strip-components=1 -xf", "exclude_files": [], "exec_command_template": "/bin/sh -c '{{.Env.BackendInstallPath}}/{{.Coin.Alias}}/erigon --chain mainnet --snap.keepblocks --db.size.limit 15TB --prune c --prune.c.older 1000000 -torrent.download.rate 32mb --nat none --datadir {{.Env.BackendDataPath}}/{{.Coin.Alias}}/backend/erigon --port {{.Ports.BackendP2P}} --ws --ws.port {{.Ports.BackendRPC}} --http --http.port {{.Ports.BackendRPC}} --http.addr 127.0.0.1 --http.corsdomain \"*\" --http.vhosts \"*\" --http.api \"eth,net,web3,debug,txpool\" --authrpc.port {{.Ports.BackendAuthRpc}} --private.api.addr \"\" --torrent.port {{.Ports.BackendHttp}} --log.dir.path {{.Env.BackendDataPath}}/{{.Coin.Alias}}/backend --log.dir.prefix {{.Coin.Alias}}'", "logrotate_files_template": "{{.Env.BackendDataPath}}/{{.Coin.Alias}}/backend/{{.Coin.Alias}}.log", @@ -39,8 +39,8 @@ "client_config_file": "", "platforms": { "arm64": { - "binary_url": "https://github.com/ledgerwatch/erigon/releases/download/v2.59.1/erigon_2.59.1_linux_arm64.tar.gz", - "verification_source": "9d29e04f600111971c56a9c48aa5c7c9e81cd61ad8bb042c240505e4bd93bf88" + "binary_url": "https://github.com/ledgerwatch/erigon/releases/download/v2.60.10/erigon_v2.60.10_linux_arm64.tar.gz", + "verification_source": "68cb9baf937d19446de91bc1efccf389b4a2452233b3a5ef1cf5cd8a91b9ce95" } } }, diff --git a/configs/coins/ethereum_archive_consensus.json b/configs/coins/ethereum_archive_consensus.json index c57f2207..51f757ad 100644 --- a/configs/coins/ethereum_archive_consensus.json +++ b/configs/coins/ethereum_archive_consensus.json @@ -19,10 +19,10 @@ "package_name": "backend-ethereum-archive-consensus", "package_revision": "satoshilabs-1", "system_user": "ethereum", - "version": "5.0.2", - "binary_url": "https://github.com/prysmaticlabs/prysm/releases/download/v5.0.2/beacon-chain-v5.0.2-linux-amd64", + "version": "5.2.0", + "binary_url": "https://github.com/prysmaticlabs/prysm/releases/download/v5.2.0/beacon-chain-v5.2.0-linux-amd64", "verification_type": "sha256", - "verification_source": "f3515bdd216a34e54b178d03ced311e4c86cee1a1d0f84fb8bffa682244916b4", + "verification_source": "bd8c8756943a75f4b6d120b5a9b215a56d071a4fc986ff91af2a4b01e1ac6aea", "extract_command": "mv ${ARCHIVE} backend/beacon-chain && chmod +x backend/beacon-chain && echo", "exclude_files": [], "exec_command_template": "/bin/sh -c '{{.Env.BackendInstallPath}}/{{.Coin.Alias}}/beacon-chain --mainnet --accept-terms-of-use --execution-endpoint=http://localhost:{{.Ports.BackendAuthRpc}} --grpc-gateway-port=7516 --rpc-port=7517 --monitoring-port=7518 --p2p-tcp-port=3516 --p2p-udp-port=2516 --datadir={{.Env.BackendDataPath}}/{{.Coin.Alias}}/backend --jwt-secret={{.Env.BackendDataPath}}/ethereum_archive/backend/erigon/jwt.hex 2>>{{.Env.BackendDataPath}}/{{.Coin.Alias}}/backend/{{.Coin.Alias}}.log'", @@ -36,8 +36,8 @@ "client_config_file": "", "platforms": { "arm64": { - "binary_url": "https://github.com/prysmaticlabs/prysm/releases/download/v5.0.2/beacon-chain-v5.0.2-linux-arm64", - "verification_source": "dcabf9ecd9e6835f04d81d8317d640fdb3a223cb462c8764f0ea167a3ff3230e" + "binary_url": "https://github.com/prysmaticlabs/prysm/releases/download/v5.2.0/beacon-chain-v5.2.0-linux-arm64", + "verification_source": "fb5b46749abe8ebfd8cd074215b350a8db305bceda624e70d7ee9e432e480dac" } } }, diff --git a/configs/coins/ethereum_consensus.json b/configs/coins/ethereum_consensus.json index 971e2635..c6213955 100644 --- a/configs/coins/ethereum_consensus.json +++ b/configs/coins/ethereum_consensus.json @@ -19,10 +19,10 @@ "package_name": "backend-ethereum-consensus", "package_revision": "satoshilabs-1", "system_user": "ethereum", - "version": "5.0.2", - "binary_url": "https://github.com/prysmaticlabs/prysm/releases/download/v5.0.2/beacon-chain-v5.0.2-linux-amd64", + "version": "5.2.0", + "binary_url": "https://github.com/prysmaticlabs/prysm/releases/download/v5.2.0/beacon-chain-v5.2.0-linux-amd64", "verification_type": "sha256", - "verification_source": "f3515bdd216a34e54b178d03ced311e4c86cee1a1d0f84fb8bffa682244916b4", + "verification_source": "bd8c8756943a75f4b6d120b5a9b215a56d071a4fc986ff91af2a4b01e1ac6aea", "extract_command": "mv ${ARCHIVE} backend/beacon-chain && chmod +x backend/beacon-chain && echo", "exclude_files": [], "exec_command_template": "/bin/sh -c '{{.Env.BackendInstallPath}}/{{.Coin.Alias}}/beacon-chain --mainnet --accept-terms-of-use --execution-endpoint=http://localhost:{{.Ports.BackendAuthRpc}} --grpc-gateway-port=7536 --rpc-port=7537 --monitoring-port=7538 --p2p-tcp-port=3536 --p2p-udp-port=2536 --datadir={{.Env.BackendDataPath}}/{{.Coin.Alias}}/backend --jwt-secret={{.Env.BackendDataPath}}/ethereum/backend/erigon/jwt.hex 2>>{{.Env.BackendDataPath}}/{{.Coin.Alias}}/backend/{{.Coin.Alias}}.log'", @@ -36,8 +36,8 @@ "client_config_file": "", "platforms": { "arm64": { - "binary_url": "https://github.com/prysmaticlabs/prysm/releases/download/v5.0.2/beacon-chain-v5.0.2-linux-arm64", - "verification_source": "dcabf9ecd9e6835f04d81d8317d640fdb3a223cb462c8764f0ea167a3ff3230e" + "binary_url": "https://github.com/prysmaticlabs/prysm/releases/download/v5.2.0/beacon-chain-v5.2.0-linux-arm64", + "verification_source": "fb5b46749abe8ebfd8cd074215b350a8db305bceda624e70d7ee9e432e480dac" } } }, diff --git a/configs/coins/ethereum_testnet_holesky.json b/configs/coins/ethereum_testnet_holesky.json index 91e6e9b7..7dceab36 100644 --- a/configs/coins/ethereum_testnet_holesky.json +++ b/configs/coins/ethereum_testnet_holesky.json @@ -22,11 +22,11 @@ "package_name": "backend-ethereum-testnet-holesky", "package_revision": "satoshilabs-1", "system_user": "ethereum", - "version": "2.59.1", - "binary_url": "https://github.com/ledgerwatch/erigon/releases/download/v2.59.1/erigon_2.59.1_linux_amd64.tar.gz", + "version": "2.60.10", + "binary_url": "https://github.com/ledgerwatch/erigon/releases/download/v2.60.10/erigon_v2.60.10_linux_amd64.tar.gz", "verification_type": "sha256", - "verification_source": "5800f0da3ec52f8abc414860f4b3c9ac8c46d07c5044b5458820c71fd4b95b38", - "extract_command": "tar -C backend -xf", + "verification_source": "e22dc039846f2aee3d180b1dfb7d1b8282377d76ab4654137ed4abfec5d8e2af", + "extract_command": "tar -C backend --strip-components=1 -xf", "exclude_files": [], "exec_command_template": "/bin/sh -c '{{.Env.BackendInstallPath}}/{{.Coin.Alias}}/erigon --chain holesky --snap.keepblocks --db.size.limit 15TB --prune c --prune.c.older 1000000 -torrent.download.rate 32mb --nat none --datadir {{.Env.BackendDataPath}}/{{.Coin.Alias}}/backend/erigon --port {{.Ports.BackendP2P}} --ws --ws.port {{.Ports.BackendRPC}} --http --http.port {{.Ports.BackendRPC}} --http.addr 127.0.0.1 --http.corsdomain \"*\" --http.vhosts \"*\" --http.api \"eth,net,web3,debug,txpool\" --authrpc.port {{.Ports.BackendAuthRpc}} --private.api.addr \"\" --torrent.port {{.Ports.BackendHttp}} --log.dir.path {{.Env.BackendDataPath}}/{{.Coin.Alias}}/backend --log.dir.prefix {{.Coin.Alias}}'", "logrotate_files_template": "{{.Env.BackendDataPath}}/{{.Coin.Alias}}/backend/{{.Coin.Alias}}.log", @@ -39,8 +39,8 @@ "client_config_file": "", "platforms": { "arm64": { - "binary_url": "https://github.com/ledgerwatch/erigon/releases/download/v2.59.1/erigon_2.59.1_linux_arm64.tar.gz", - "verification_source": "9d29e04f600111971c56a9c48aa5c7c9e81cd61ad8bb042c240505e4bd93bf88" + "binary_url": "https://github.com/ledgerwatch/erigon/releases/download/v2.60.10/erigon_v2.60.10_linux_arm64.tar.gz", + "verification_source": "68cb9baf937d19446de91bc1efccf389b4a2452233b3a5ef1cf5cd8a91b9ce95" } } }, diff --git a/configs/coins/ethereum_testnet_holesky_archive.json b/configs/coins/ethereum_testnet_holesky_archive.json index aa7c3f77..3474b63a 100644 --- a/configs/coins/ethereum_testnet_holesky_archive.json +++ b/configs/coins/ethereum_testnet_holesky_archive.json @@ -23,11 +23,11 @@ "package_name": "backend-ethereum-testnet-holesky-archive", "package_revision": "satoshilabs-1", "system_user": "ethereum", - "version": "2.59.1", - "binary_url": "https://github.com/ledgerwatch/erigon/releases/download/v2.59.1/erigon_2.59.1_linux_amd64.tar.gz", + "version": "2.60.10", + "binary_url": "https://github.com/ledgerwatch/erigon/releases/download/v2.60.10/erigon_v2.60.10_linux_amd64.tar.gz", "verification_type": "sha256", - "verification_source": "5800f0da3ec52f8abc414860f4b3c9ac8c46d07c5044b5458820c71fd4b95b38", - "extract_command": "tar -C backend -xf", + "verification_source": "e22dc039846f2aee3d180b1dfb7d1b8282377d76ab4654137ed4abfec5d8e2af", + "extract_command": "tar -C backend --strip-components=1 -xf", "exclude_files": [], "exec_command_template": "/bin/sh -c '{{.Env.BackendInstallPath}}/{{.Coin.Alias}}/erigon --chain holesky --snap.keepblocks --db.size.limit 15TB --prune c --prune.c.older 1000000 -torrent.download.rate 32mb --nat none --datadir {{.Env.BackendDataPath}}/{{.Coin.Alias}}/backend/erigon --port {{.Ports.BackendP2P}} --ws --ws.port {{.Ports.BackendRPC}} --http --http.port {{.Ports.BackendRPC}} --http.addr 127.0.0.1 --http.corsdomain \"*\" --http.vhosts \"*\" --http.api \"eth,net,web3,debug,txpool\" --authrpc.port {{.Ports.BackendAuthRpc}} --private.api.addr \"\" --torrent.port {{.Ports.BackendHttp}} --log.dir.path {{.Env.BackendDataPath}}/{{.Coin.Alias}}/backend --log.dir.prefix {{.Coin.Alias}}'", "logrotate_files_template": "{{.Env.BackendDataPath}}/{{.Coin.Alias}}/backend/{{.Coin.Alias}}.log", @@ -40,8 +40,8 @@ "client_config_file": "", "platforms": { "arm64": { - "binary_url": "https://github.com/ledgerwatch/erigon/releases/download/v2.59.1/erigon_2.59.1_linux_arm64.tar.gz", - "verification_source": "9d29e04f600111971c56a9c48aa5c7c9e81cd61ad8bb042c240505e4bd93bf88" + "binary_url": "https://github.com/ledgerwatch/erigon/releases/download/v2.60.10/erigon_v2.60.10_linux_arm64.tar.gz", + "verification_source": "68cb9baf937d19446de91bc1efccf389b4a2452233b3a5ef1cf5cd8a91b9ce95" } } }, diff --git a/configs/coins/ethereum_testnet_holesky_archive_consensus.json b/configs/coins/ethereum_testnet_holesky_archive_consensus.json index e2db51d5..848775b2 100644 --- a/configs/coins/ethereum_testnet_holesky_archive_consensus.json +++ b/configs/coins/ethereum_testnet_holesky_archive_consensus.json @@ -23,15 +23,15 @@ "package_name": "backend-ethereum-testnet-holesky-archive-consensus", "package_revision": "satoshilabs-1", "system_user": "ethereum", - "version": "5.0.2", - "binary_url": "https://github.com/prysmaticlabs/prysm/releases/download/v5.0.2/beacon-chain-v5.0.2-linux-amd64", + "version": "5.2.0", + "binary_url": "https://github.com/prysmaticlabs/prysm/releases/download/v5.2.0/beacon-chain-v5.2.0-linux-amd64", "verification_type": "sha256", - "verification_source": "f3515bdd216a34e54b178d03ced311e4c86cee1a1d0f84fb8bffa682244916b4", + "verification_source": "bd8c8756943a75f4b6d120b5a9b215a56d071a4fc986ff91af2a4b01e1ac6aea", "extract_command": "mv ${ARCHIVE} backend/beacon-chain && chmod +x backend/beacon-chain && echo", "exclude_files": [], "exec_command_template": "/bin/sh -c '{{.Env.BackendInstallPath}}/{{.Coin.Alias}}/beacon-chain --holesky --accept-terms-of-use --execution-endpoint=http://localhost:{{.Ports.BackendAuthRpc}} --grpc-gateway-port=17536 --rpc-port=17537 --monitoring-port=17538 --p2p-tcp-port=13636 --p2p-udp-port=12636 --datadir={{.Env.BackendDataPath}}/{{.Coin.Alias}}/backend --jwt-secret={{.Env.BackendDataPath}}/ethereum_testnet_holesky_archive/backend/erigon/jwt.hex --genesis-state={{.Env.BackendDataPath}}/{{.Coin.Alias}}/backend/genesis.ssz 2>>{{.Env.BackendDataPath}}/{{.Coin.Alias}}/backend/{{.Coin.Alias}}.log'", "logrotate_files_template": "{{.Env.BackendDataPath}}/{{.Coin.Alias}}/backend/{{.Coin.Alias}}.log", - "postinst_script_template": "wget https://github.com/eth-clients/holesky/raw/main/custom_config_data/genesis.ssz -O {{.Env.BackendDataPath}}/{{.Coin.Alias}}/backend/genesis.ssz", + "postinst_script_template": "wget https://github.com/eth-clients/holesky/raw/main/metadata/genesis.ssz -O {{.Env.BackendDataPath}}/{{.Coin.Alias}}/backend/genesis.ssz", "service_type": "simple", "service_additional_params_template": "", "protect_memory": true, @@ -40,8 +40,8 @@ "client_config_file": "", "platforms": { "arm64": { - "binary_url": "https://github.com/prysmaticlabs/prysm/releases/download/v5.0.2/beacon-chain-v5.0.2-linux-arm64", - "verification_source": "dcabf9ecd9e6835f04d81d8317d640fdb3a223cb462c8764f0ea167a3ff3230e" + "binary_url": "https://github.com/prysmaticlabs/prysm/releases/download/v5.2.0/beacon-chain-v5.2.0-linux-arm64", + "verification_source": "fb5b46749abe8ebfd8cd074215b350a8db305bceda624e70d7ee9e432e480dac" } } }, diff --git a/configs/coins/ethereum_testnet_holesky_consensus.json b/configs/coins/ethereum_testnet_holesky_consensus.json index 461d4172..69583957 100644 --- a/configs/coins/ethereum_testnet_holesky_consensus.json +++ b/configs/coins/ethereum_testnet_holesky_consensus.json @@ -23,15 +23,15 @@ "package_name": "backend-ethereum-testnet-holesky-consensus", "package_revision": "satoshilabs-1", "system_user": "ethereum", - "version": "5.0.2", - "binary_url": "https://github.com/prysmaticlabs/prysm/releases/download/v5.0.2/beacon-chain-v5.0.2-linux-amd64", + "version": "5.2.0", + "binary_url": "https://github.com/prysmaticlabs/prysm/releases/download/v5.2.0/beacon-chain-v5.2.0-linux-amd64", "verification_type": "sha256", - "verification_source": "f3515bdd216a34e54b178d03ced311e4c86cee1a1d0f84fb8bffa682244916b4", + "verification_source": "bd8c8756943a75f4b6d120b5a9b215a56d071a4fc986ff91af2a4b01e1ac6aea", "extract_command": "mv ${ARCHIVE} backend/beacon-chain && chmod +x backend/beacon-chain && echo", "exclude_files": [], "exec_command_template": "/bin/sh -c '{{.Env.BackendInstallPath}}/{{.Coin.Alias}}/beacon-chain --holesky --accept-terms-of-use --execution-endpoint=http://localhost:{{.Ports.BackendAuthRpc}} --grpc-gateway-port=17516 --rpc-port=17517 --monitoring-port=17518 --p2p-tcp-port=13516 --p2p-udp-port=12516 --datadir={{.Env.BackendDataPath}}/{{.Coin.Alias}}/backend --jwt-secret={{.Env.BackendDataPath}}/ethereum_testnet_holesky/backend/erigon/jwt.hex --genesis-state={{.Env.BackendDataPath}}/{{.Coin.Alias}}/backend/genesis.ssz 2>>{{.Env.BackendDataPath}}/{{.Coin.Alias}}/backend/{{.Coin.Alias}}.log'", "logrotate_files_template": "{{.Env.BackendDataPath}}/{{.Coin.Alias}}/backend/{{.Coin.Alias}}.log", - "postinst_script_template": "wget https://github.com/eth-clients/holesky/raw/main/custom_config_data/genesis.ssz -O {{.Env.BackendDataPath}}/{{.Coin.Alias}}/backend/genesis.ssz", + "postinst_script_template": "wget https://github.com/eth-clients/holesky/raw/main/metadata/genesis.ssz -O {{.Env.BackendDataPath}}/{{.Coin.Alias}}/backend/genesis.ssz", "service_type": "simple", "service_additional_params_template": "", "protect_memory": true, @@ -40,8 +40,8 @@ "client_config_file": "", "platforms": { "arm64": { - "binary_url": "https://github.com/prysmaticlabs/prysm/releases/download/v5.0.2/beacon-chain-v5.0.2-linux-arm64", - "verification_source": "dcabf9ecd9e6835f04d81d8317d640fdb3a223cb462c8764f0ea167a3ff3230e" + "binary_url": "https://github.com/prysmaticlabs/prysm/releases/download/v5.2.0/beacon-chain-v5.2.0-linux-arm64", + "verification_source": "fb5b46749abe8ebfd8cd074215b350a8db305bceda624e70d7ee9e432e480dac" } } }, diff --git a/configs/coins/ethereum_testnet_sepolia.json b/configs/coins/ethereum_testnet_sepolia.json index a39e6cc3..dfca9bf9 100644 --- a/configs/coins/ethereum_testnet_sepolia.json +++ b/configs/coins/ethereum_testnet_sepolia.json @@ -22,11 +22,11 @@ "package_name": "backend-ethereum-testnet-sepolia", "package_revision": "satoshilabs-1", "system_user": "ethereum", - "version": "2.59.1", - "binary_url": "https://github.com/ledgerwatch/erigon/releases/download/v2.59.1/erigon_2.59.1_linux_amd64.tar.gz", + "version": "2.60.10", + "binary_url": "https://github.com/ledgerwatch/erigon/releases/download/v2.60.10/erigon_v2.60.10_linux_amd64.tar.gz", "verification_type": "sha256", - "verification_source": "5800f0da3ec52f8abc414860f4b3c9ac8c46d07c5044b5458820c71fd4b95b38", - "extract_command": "tar -C backend -xf", + "verification_source": "e22dc039846f2aee3d180b1dfb7d1b8282377d76ab4654137ed4abfec5d8e2af", + "extract_command": "tar -C backend --strip-components=1 -xf", "exclude_files": [], "exec_command_template": "/bin/sh -c '{{.Env.BackendInstallPath}}/{{.Coin.Alias}}/erigon --chain sepolia --snap.keepblocks --db.size.limit 15TB --prune c --prune.c.older 1000000 -torrent.download.rate 32mb --nat none --datadir {{.Env.BackendDataPath}}/{{.Coin.Alias}}/backend/erigon --port {{.Ports.BackendP2P}} --ws --ws.port {{.Ports.BackendRPC}} --http --http.port {{.Ports.BackendRPC}} --http.addr 127.0.0.1 --http.corsdomain \"*\" --http.vhosts \"*\" --http.api \"eth,net,web3,debug,txpool\" --authrpc.port {{.Ports.BackendAuthRpc}} --private.api.addr \"\" --torrent.port {{.Ports.BackendHttp}} --log.dir.path {{.Env.BackendDataPath}}/{{.Coin.Alias}}/backend --log.dir.prefix {{.Coin.Alias}}'", "logrotate_files_template": "{{.Env.BackendDataPath}}/{{.Coin.Alias}}/backend/{{.Coin.Alias}}.log", @@ -39,8 +39,8 @@ "client_config_file": "", "platforms": { "arm64": { - "binary_url": "https://github.com/ledgerwatch/erigon/releases/download/v2.59.1/erigon_2.59.1_linux_arm64.tar.gz", - "verification_source": "9d29e04f600111971c56a9c48aa5c7c9e81cd61ad8bb042c240505e4bd93bf88" + "binary_url": "https://github.com/ledgerwatch/erigon/releases/download/v2.60.10/erigon_v2.60.10_linux_arm64.tar.gz", + "verification_source": "68cb9baf937d19446de91bc1efccf389b4a2452233b3a5ef1cf5cd8a91b9ce95" } } }, diff --git a/configs/coins/ethereum_testnet_sepolia_archive.json b/configs/coins/ethereum_testnet_sepolia_archive.json index 90e40f7c..35926e52 100644 --- a/configs/coins/ethereum_testnet_sepolia_archive.json +++ b/configs/coins/ethereum_testnet_sepolia_archive.json @@ -23,11 +23,11 @@ "package_name": "backend-ethereum-testnet-sepolia-archive", "package_revision": "satoshilabs-1", "system_user": "ethereum", - "version": "2.59.1", - "binary_url": "https://github.com/ledgerwatch/erigon/releases/download/v2.59.1/erigon_2.59.1_linux_amd64.tar.gz", + "version": "2.60.10", + "binary_url": "https://github.com/ledgerwatch/erigon/releases/download/v2.60.10/erigon_v2.60.10_linux_amd64.tar.gz", "verification_type": "sha256", - "verification_source": "5800f0da3ec52f8abc414860f4b3c9ac8c46d07c5044b5458820c71fd4b95b38", - "extract_command": "tar -C backend -xf", + "verification_source": "e22dc039846f2aee3d180b1dfb7d1b8282377d76ab4654137ed4abfec5d8e2af", + "extract_command": "tar -C backend --strip-components=1 -xf", "exclude_files": [], "exec_command_template": "/bin/sh -c '{{.Env.BackendInstallPath}}/{{.Coin.Alias}}/erigon --chain sepolia --snap.keepblocks --db.size.limit 15TB --prune c --prune.c.older 1000000 -torrent.download.rate 32mb --nat none --datadir {{.Env.BackendDataPath}}/{{.Coin.Alias}}/backend/erigon --port {{.Ports.BackendP2P}} --ws --ws.port {{.Ports.BackendRPC}} --http --http.port {{.Ports.BackendRPC}} --http.addr 127.0.0.1 --http.corsdomain \"*\" --http.vhosts \"*\" --http.api \"eth,net,web3,debug,txpool\" --authrpc.port {{.Ports.BackendAuthRpc}} --private.api.addr \"\" --torrent.port {{.Ports.BackendHttp}} --log.dir.path {{.Env.BackendDataPath}}/{{.Coin.Alias}}/backend --log.dir.prefix {{.Coin.Alias}}'", "logrotate_files_template": "{{.Env.BackendDataPath}}/{{.Coin.Alias}}/backend/{{.Coin.Alias}}.log", @@ -40,8 +40,8 @@ "client_config_file": "", "platforms": { "arm64": { - "binary_url": "https://github.com/ledgerwatch/erigon/releases/download/v2.59.1/erigon_2.59.1_linux_arm64.tar.gz", - "verification_source": "9d29e04f600111971c56a9c48aa5c7c9e81cd61ad8bb042c240505e4bd93bf88" + "binary_url": "https://github.com/ledgerwatch/erigon/releases/download/v2.60.10/erigon_v2.60.10_linux_arm64.tar.gz", + "verification_source": "68cb9baf937d19446de91bc1efccf389b4a2452233b3a5ef1cf5cd8a91b9ce95" } } }, diff --git a/configs/coins/ethereum_testnet_sepolia_archive_consensus.json b/configs/coins/ethereum_testnet_sepolia_archive_consensus.json index c18afa41..8563a8e9 100644 --- a/configs/coins/ethereum_testnet_sepolia_archive_consensus.json +++ b/configs/coins/ethereum_testnet_sepolia_archive_consensus.json @@ -23,15 +23,15 @@ "package_name": "backend-ethereum-testnet-sepolia-archive-consensus", "package_revision": "satoshilabs-1", "system_user": "ethereum", - "version": "5.0.2", - "binary_url": "https://github.com/prysmaticlabs/prysm/releases/download/v5.0.2/beacon-chain-v5.0.2-linux-amd64", + "version": "5.2.0", + "binary_url": "https://github.com/prysmaticlabs/prysm/releases/download/v5.2.0/beacon-chain-v5.2.0-linux-amd64", "verification_type": "sha256", - "verification_source": "f3515bdd216a34e54b178d03ced311e4c86cee1a1d0f84fb8bffa682244916b4", + "verification_source": "bd8c8756943a75f4b6d120b5a9b215a56d071a4fc986ff91af2a4b01e1ac6aea", "extract_command": "mv ${ARCHIVE} backend/beacon-chain && chmod +x backend/beacon-chain && echo", "exclude_files": [], "exec_command_template": "/bin/sh -c '{{.Env.BackendInstallPath}}/{{.Coin.Alias}}/beacon-chain --sepolia --accept-terms-of-use --execution-endpoint=http://localhost:{{.Ports.BackendAuthRpc}} --grpc-gateway-port=17586 --rpc-port=17587 --monitoring-port=17548 --p2p-tcp-port=13676 --p2p-udp-port=12676 --datadir={{.Env.BackendDataPath}}/{{.Coin.Alias}}/backend --jwt-secret={{.Env.BackendDataPath}}/ethereum_testnet_sepolia_archive/backend/erigon/jwt.hex --genesis-state={{.Env.BackendDataPath}}/{{.Coin.Alias}}/backend/genesis.ssz 2>>{{.Env.BackendDataPath}}/{{.Coin.Alias}}/backend/{{.Coin.Alias}}.log'", "logrotate_files_template": "{{.Env.BackendDataPath}}/{{.Coin.Alias}}/backend/{{.Coin.Alias}}.log", - "postinst_script_template": "wget https://github.com/eth-clients/merge-testnets/raw/302fe27afdc7a9d15b1766a0c0a9d64319140255/sepolia/genesis.ssz -O {{.Env.BackendDataPath}}/{{.Coin.Alias}}/backend/genesis.ssz", + "postinst_script_template": "wget https://github.com/eth-clients/sepolia/raw/main/metadata/genesis.ssz -O {{.Env.BackendDataPath}}/{{.Coin.Alias}}/backend/genesis.ssz", "service_type": "simple", "service_additional_params_template": "", "protect_memory": true, @@ -40,8 +40,8 @@ "client_config_file": "", "platforms": { "arm64": { - "binary_url": "https://github.com/prysmaticlabs/prysm/releases/download/v5.0.2/beacon-chain-v5.0.2-linux-arm64", - "verification_source": "dcabf9ecd9e6835f04d81d8317d640fdb3a223cb462c8764f0ea167a3ff3230e" + "binary_url": "https://github.com/prysmaticlabs/prysm/releases/download/v5.2.0/beacon-chain-v5.2.0-linux-arm64", + "verification_source": "fb5b46749abe8ebfd8cd074215b350a8db305bceda624e70d7ee9e432e480dac" } } }, diff --git a/configs/coins/ethereum_testnet_sepolia_consensus.json b/configs/coins/ethereum_testnet_sepolia_consensus.json index 03e82589..1a700fe7 100644 --- a/configs/coins/ethereum_testnet_sepolia_consensus.json +++ b/configs/coins/ethereum_testnet_sepolia_consensus.json @@ -23,15 +23,15 @@ "package_name": "backend-ethereum-testnet-sepolia-consensus", "package_revision": "satoshilabs-1", "system_user": "ethereum", - "version": "5.0.2", - "binary_url": "https://github.com/prysmaticlabs/prysm/releases/download/v5.0.2/beacon-chain-v5.0.2-linux-amd64", + "version": "5.2.0", + "binary_url": "https://github.com/prysmaticlabs/prysm/releases/download/v5.2.0/beacon-chain-v5.2.0-linux-amd64", "verification_type": "sha256", - "verification_source": "f3515bdd216a34e54b178d03ced311e4c86cee1a1d0f84fb8bffa682244916b4", + "verification_source": "bd8c8756943a75f4b6d120b5a9b215a56d071a4fc986ff91af2a4b01e1ac6aea", "extract_command": "mv ${ARCHIVE} backend/beacon-chain && chmod +x backend/beacon-chain && echo", "exclude_files": [], "exec_command_template": "/bin/sh -c '{{.Env.BackendInstallPath}}/{{.Coin.Alias}}/beacon-chain --sepolia --accept-terms-of-use --execution-endpoint=http://localhost:{{.Ports.BackendAuthRpc}} --grpc-gateway-port=17576 --rpc-port=17577 --monitoring-port=17578 --p2p-tcp-port=13576 --p2p-udp-port=12576 --datadir={{.Env.BackendDataPath}}/{{.Coin.Alias}}/backend --jwt-secret={{.Env.BackendDataPath}}/ethereum_testnet_sepolia/backend/erigon/jwt.hex --genesis-state={{.Env.BackendDataPath}}/{{.Coin.Alias}}/backend/genesis.ssz 2>>{{.Env.BackendDataPath}}/{{.Coin.Alias}}/backend/{{.Coin.Alias}}.log'", "logrotate_files_template": "{{.Env.BackendDataPath}}/{{.Coin.Alias}}/backend/{{.Coin.Alias}}.log", - "postinst_script_template": "wget https://github.com/eth-clients/merge-testnets/raw/302fe27afdc7a9d15b1766a0c0a9d64319140255/sepolia/genesis.ssz -O {{.Env.BackendDataPath}}/{{.Coin.Alias}}/backend/genesis.ssz", + "postinst_script_template": "wget https://github.com/eth-clients/holesky/raw/main/metadata/genesis.ssz -O {{.Env.BackendDataPath}}/{{.Coin.Alias}}/backend/genesis.ssz", "service_type": "simple", "service_additional_params_template": "", "protect_memory": true, @@ -40,8 +40,8 @@ "client_config_file": "", "platforms": { "arm64": { - "binary_url": "https://github.com/prysmaticlabs/prysm/releases/download/v5.0.2/beacon-chain-v5.0.2-linux-arm64", - "verification_source": "dcabf9ecd9e6835f04d81d8317d640fdb3a223cb462c8764f0ea167a3ff3230e" + "binary_url": "https://github.com/prysmaticlabs/prysm/releases/download/v5.2.0/beacon-chain-v5.2.0-linux-arm64", + "verification_source": "fb5b46749abe8ebfd8cd074215b350a8db305bceda624e70d7ee9e432e480dac" } } }, diff --git a/configs/coins/firo.json b/configs/coins/firo.json index 102733fc..14a0f65b 100644 --- a/configs/coins/firo.json +++ b/configs/coins/firo.json @@ -22,10 +22,10 @@ "package_name": "backend-firo", "package_revision": "satoshilabs-1", "system_user": "firo", - "version": "0.14.13.3", - "binary_url": "https://github.com/firoorg/firo/releases/download/v0.14.13.3/firo-0.14.13.3-linux64.tar.gz", + "version": "0.14.14.0", + "binary_url": "https://github.com/firoorg/firo/releases/download/v0.14.14.0/firo-0.14.14.0-linux64.tar.gz", "verification_type": "sha256", - "verification_source": "39a4729fe9ab95cf3a236b95aadd53c3a18ac8737b7bfdd8934dd5524e19d2e8", + "verification_source": "0f8c914286031830d8c9eb1ab86b3e21f349917aea7bc2ab12229ab4c638cbe8", "extract_command": "tar -C backend --strip 1 -xf", "exclude_files": [ "bin/firo-qt", diff --git a/configs/coins/flux.json b/configs/coins/flux.json index 24116c44..ec850124 100644 --- a/configs/coins/flux.json +++ b/configs/coins/flux.json @@ -22,10 +22,10 @@ "package_name": "backend-flux", "package_revision": "satoshilabs-1", "system_user": "flux", - "version": "7.1.0", - "binary_url": "https://github.com/RunOnFlux/fluxd/releases/download/v7.1.0/Flux-amd64-v7.1.0.tar.gz", + "version": "7.2.0", + "binary_url": "https://github.com/RunOnFlux/fluxd/releases/download/v7.2.0/Flux-amd64-v7.2.0.tar.gz", "verification_type": "sha256", - "verification_source": "832fe0d7700cf74430f4b464f07706a78ec39b2ec309d3d8230b0dffe9993296", + "verification_source": "aac3a9581fb8e8f3215ddd3de9721fdb6e9d90ef65d3fa73a495d7451dd480ef", "extract_command": "tar -C backend -xf", "exclude_files": [], "exec_command_template": "{{.Env.BackendInstallPath}}/{{.Coin.Alias}}/fluxd -datadir={{.Env.BackendDataPath}}/{{.Coin.Alias}}/backend -conf={{.Env.BackendInstallPath}}/{{.Coin.Alias}}/{{.Coin.Alias}}.conf -pid=/run/{{.Coin.Alias}}/{{.Coin.Alias}}.pid", diff --git a/configs/coins/groestlcoin.json b/configs/coins/groestlcoin.json index c8ae6342..18b8f5cc 100644 --- a/configs/coins/groestlcoin.json +++ b/configs/coins/groestlcoin.json @@ -22,10 +22,10 @@ "package_name": "backend-groestlcoin", "package_revision": "satoshilabs-1", "system_user": "groestlcoin", - "version": "27.0", - "binary_url": "https://github.com/Groestlcoin/groestlcoin/releases/download/v27.0/groestlcoin-27.0-x86_64-linux-gnu.tar.gz", + "version": "28.0", + "binary_url": "https://github.com/Groestlcoin/groestlcoin/releases/download/v28.0/groestlcoin-28.0-x86_64-linux-gnu.tar.gz", "verification_type": "sha256", - "verification_source": "5189f036913e2033b5fe95ba8f3fc027e9c5bd286d2150e9133cd4a2fd69a7a0", + "verification_source": "540d5d7c6bb0449763567ea7c2559e124d61b82a6b2798701d5759458d9c21d7", "extract_command": "tar -C backend --strip 1 -xf", "exclude_files": ["bin/groestlcoin-qt"], "exec_command_template": "{{.Env.BackendInstallPath}}/{{.Coin.Alias}}/bin/groestlcoind -datadir={{.Env.BackendDataPath}}/{{.Coin.Alias}}/backend -conf={{.Env.BackendInstallPath}}/{{.Coin.Alias}}/{{.Coin.Alias}}.conf -pid=/run/{{.Coin.Alias}}/{{.Coin.Alias}}.pid", @@ -42,8 +42,8 @@ }, "platforms": { "arm64": { - "binary_url": "https://github.com/Groestlcoin/groestlcoin/releases/download/v27.0/groestlcoin-27.0-aarch64-linux-gnu.tar.gz", - "verification_source": "95e1a4c4f4d50709df40e2d86c4b578db053d1cb475a3384862192c1298f9de6" + "binary_url": "https://github.com/Groestlcoin/groestlcoin/releases/download/v28.0/groestlcoin-28.0-aarch64-linux-gnu.tar.gz", + "verification_source": "092c6ff333a3defe2603b91c55aea6415e554a2bbc6abb3ad43ac712fa9b63b1" } } }, diff --git a/configs/coins/groestlcoin_regtest.json b/configs/coins/groestlcoin_regtest.json index 0a62a9bf..aaa4ba27 100644 --- a/configs/coins/groestlcoin_regtest.json +++ b/configs/coins/groestlcoin_regtest.json @@ -22,10 +22,10 @@ "package_name": "backend-groestlcoin-regtest", "package_revision": "satoshilabs-1", "system_user": "groestlcoin", - "version": "27.0", - "binary_url": "https://github.com/Groestlcoin/groestlcoin/releases/download/v27.0/groestlcoin-27.0-x86_64-linux-gnu.tar.gz", + "version": "28.0", + "binary_url": "https://github.com/Groestlcoin/groestlcoin/releases/download/v28.0/groestlcoin-28.0-x86_64-linux-gnu.tar.gz", "verification_type": "sha256", - "verification_source": "5189f036913e2033b5fe95ba8f3fc027e9c5bd286d2150e9133cd4a2fd69a7a0", + "verification_source": "540d5d7c6bb0449763567ea7c2559e124d61b82a6b2798701d5759458d9c21d7", "extract_command": "tar -C backend --strip 1 -xf", "exclude_files": ["bin/groestlcoin-qt"], "exec_command_template": "{{.Env.BackendInstallPath}}/{{.Coin.Alias}}/bin/groestlcoind -datadir={{.Env.BackendDataPath}}/{{.Coin.Alias}}/backend -conf={{.Env.BackendInstallPath}}/{{.Coin.Alias}}/{{.Coin.Alias}}.conf -pid=/run/{{.Coin.Alias}}/{{.Coin.Alias}}.pid", @@ -42,8 +42,8 @@ }, "platforms": { "arm64": { - "binary_url": "https://github.com/Groestlcoin/groestlcoin/releases/download/v27.0/groestlcoin-27.0-aarch64-linux-gnu.tar.gz", - "verification_source": "95e1a4c4f4d50709df40e2d86c4b578db053d1cb475a3384862192c1298f9de6" + "binary_url": "https://github.com/Groestlcoin/groestlcoin/releases/download/v28.0/groestlcoin-28.0-aarch64-linux-gnu.tar.gz", + "verification_source": "092c6ff333a3defe2603b91c55aea6415e554a2bbc6abb3ad43ac712fa9b63b1" } } }, diff --git a/configs/coins/groestlcoin_signet.json b/configs/coins/groestlcoin_signet.json index 2fd281a2..53df59f7 100644 --- a/configs/coins/groestlcoin_signet.json +++ b/configs/coins/groestlcoin_signet.json @@ -22,10 +22,10 @@ "package_name": "backend-groestlcoin-signet", "package_revision": "satoshilabs-1", "system_user": "groestlcoin", - "version": "27.0", - "binary_url": "https://github.com/Groestlcoin/groestlcoin/releases/download/v27.0/groestlcoin-27.0-x86_64-linux-gnu.tar.gz", + "version": "28.0", + "binary_url": "https://github.com/Groestlcoin/groestlcoin/releases/download/v28.0/groestlcoin-28.0-x86_64-linux-gnu.tar.gz", "verification_type": "sha256", - "verification_source": "5189f036913e2033b5fe95ba8f3fc027e9c5bd286d2150e9133cd4a2fd69a7a0", + "verification_source": "540d5d7c6bb0449763567ea7c2559e124d61b82a6b2798701d5759458d9c21d7", "extract_command": "tar -C backend --strip 1 -xf", "exclude_files": ["bin/groestlcoin-qt"], "exec_command_template": "{{.Env.BackendInstallPath}}/{{.Coin.Alias}}/bin/groestlcoind -datadir={{.Env.BackendDataPath}}/{{.Coin.Alias}}/backend -conf={{.Env.BackendInstallPath}}/{{.Coin.Alias}}/{{.Coin.Alias}}.conf -pid=/run/{{.Coin.Alias}}/{{.Coin.Alias}}.pid", @@ -35,16 +35,16 @@ "service_additional_params_template": "", "protect_memory": true, "mainnet": false, - "server_config_file": "bitcoin-signet.conf", + "server_config_file": "bitcoin_signet.conf", "client_config_file": "bitcoin_client.conf", "additional_params": { "deprecatedrpc": "estimatefee" }, "platforms": { - "arm64": { - "binary_url": "https://github.com/Groestlcoin/groestlcoin/releases/download/v27.0/groestlcoin-27.0-aarch64-linux-gnu.tar.gz", - "verification_source": "95e1a4c4f4d50709df40e2d86c4b578db053d1cb475a3384862192c1298f9de6" - } + "arm64": { + "binary_url": "https://github.com/Groestlcoin/groestlcoin/releases/download/v28.0/groestlcoin-28.0-aarch64-linux-gnu.tar.gz", + "verification_source": "092c6ff333a3defe2603b91c55aea6415e554a2bbc6abb3ad43ac712fa9b63b1" + } } }, "blockbook": { diff --git a/configs/coins/groestlcoin_testnet.json b/configs/coins/groestlcoin_testnet.json index 435fc1f3..7106edef 100644 --- a/configs/coins/groestlcoin_testnet.json +++ b/configs/coins/groestlcoin_testnet.json @@ -22,10 +22,10 @@ "package_name": "backend-groestlcoin-testnet", "package_revision": "satoshilabs-1", "system_user": "groestlcoin", - "version": "27.0", - "binary_url": "https://github.com/Groestlcoin/groestlcoin/releases/download/v27.0/groestlcoin-27.0-x86_64-linux-gnu.tar.gz", + "version": "28.0", + "binary_url": "https://github.com/Groestlcoin/groestlcoin/releases/download/v28.0/groestlcoin-28.0-x86_64-linux-gnu.tar.gz", "verification_type": "sha256", - "verification_source": "5189f036913e2033b5fe95ba8f3fc027e9c5bd286d2150e9133cd4a2fd69a7a0", + "verification_source": "540d5d7c6bb0449763567ea7c2559e124d61b82a6b2798701d5759458d9c21d7", "extract_command": "tar -C backend --strip 1 -xf", "exclude_files": ["bin/groestlcoin-qt"], "exec_command_template": "{{.Env.BackendInstallPath}}/{{.Coin.Alias}}/bin/groestlcoind -datadir={{.Env.BackendDataPath}}/{{.Coin.Alias}}/backend -conf={{.Env.BackendInstallPath}}/{{.Coin.Alias}}/{{.Coin.Alias}}.conf -pid=/run/{{.Coin.Alias}}/{{.Coin.Alias}}.pid", @@ -42,8 +42,8 @@ }, "platforms": { "arm64": { - "binary_url": "https://github.com/Groestlcoin/groestlcoin/releases/download/v27.0/groestlcoin-27.0-aarch64-linux-gnu.tar.gz", - "verification_source": "95e1a4c4f4d50709df40e2d86c4b578db053d1cb475a3384862192c1298f9de6" + "binary_url": "https://github.com/Groestlcoin/groestlcoin/releases/download/v28.0/groestlcoin-28.0-aarch64-linux-gnu.tar.gz", + "verification_source": "092c6ff333a3defe2603b91c55aea6415e554a2bbc6abb3ad43ac712fa9b63b1" } } }, diff --git a/configs/coins/litecoin.json b/configs/coins/litecoin.json index 6b212245..026665c1 100644 --- a/configs/coins/litecoin.json +++ b/configs/coins/litecoin.json @@ -22,10 +22,10 @@ "package_name": "backend-litecoin", "package_revision": "satoshilabs-1", "system_user": "litecoin", - "version": "0.21.3", - "binary_url": "https://download.litecoin.org/litecoin-0.21.3/linux/litecoin-0.21.3-x86_64-linux-gnu.tar.gz", + "version": "0.21.4", + "binary_url": "https://download.litecoin.org/litecoin-0.21.4/linux/litecoin-0.21.4-x86_64-linux-gnu.tar.gz", "verification_type": "gpg", - "verification_source": "https://download.litecoin.org/litecoin-0.21.3/linux/litecoin-0.21.3-x86_64-linux-gnu.tar.gz.asc", + "verification_source": "https://download.litecoin.org/litecoin-0.21.4/linux/litecoin-0.21.4-x86_64-linux-gnu.tar.gz.asc", "extract_command": "tar -C backend --strip 1 -xf", "exclude_files": ["bin/litecoin-qt"], "exec_command_template": "{{.Env.BackendInstallPath}}/{{.Coin.Alias}}/bin/litecoind -datadir={{.Env.BackendDataPath}}/{{.Coin.Alias}}/backend -conf={{.Env.BackendInstallPath}}/{{.Coin.Alias}}/{{.Coin.Alias}}.conf -pid=/run/{{.Coin.Alias}}/{{.Coin.Alias}}.pid", @@ -42,8 +42,8 @@ }, "platforms": { "arm64": { - "binary_url": "https://download.litecoin.org/litecoin-0.21.3/linux/litecoin-0.21.3-aarch64-linux-gnu.tar.gz", - "verification_source": "https://download.litecoin.org/litecoin-0.21.3/linux/litecoin-0.21.3-aarch64-linux-gnu.tar.gz.asc" + "binary_url": "https://download.litecoin.org/litecoin-0.21.4/linux/litecoin-0.21.4-aarch64-linux-gnu.tar.gz", + "verification_source": "https://download.litecoin.org/litecoin-0.21.4/linux/litecoin-0.21.4-aarch64-linux-gnu.tar.gz.asc" } } }, diff --git a/configs/coins/litecoin_testnet.json b/configs/coins/litecoin_testnet.json index 25d2ce57..0d0962b3 100644 --- a/configs/coins/litecoin_testnet.json +++ b/configs/coins/litecoin_testnet.json @@ -22,10 +22,10 @@ "package_name": "backend-litecoin-testnet", "package_revision": "satoshilabs-1", "system_user": "litecoin", - "version": "0.21.3", - "binary_url": "https://download.litecoin.org/litecoin-0.21.3/linux/litecoin-0.21.3-x86_64-linux-gnu.tar.gz", + "version": "0.21.4", + "binary_url": "https://download.litecoin.org/litecoin-0.21.4/linux/litecoin-0.21.4-x86_64-linux-gnu.tar.gz", "verification_type": "gpg", - "verification_source": "https://download.litecoin.org/litecoin-0.21.3/linux/litecoin-0.21.3-x86_64-linux-gnu.tar.gz.asc", + "verification_source": "https://download.litecoin.org/litecoin-0.21.4/linux/litecoin-0.21.4-x86_64-linux-gnu.tar.gz.asc", "extract_command": "tar -C backend --strip 1 -xf", "exclude_files": [ "bin/litecoin-qt" @@ -44,8 +44,8 @@ }, "platforms": { "arm64": { - "binary_url": "https://download.litecoin.org/litecoin-0.21.3/linux/litecoin-0.21.3-aarch64-linux-gnu.tar.gz", - "verification_source": "https://download.litecoin.org/litecoin-0.21.3/linux/litecoin-0.21.3-aarch64-linux-gnu.tar.gz.asc" + "binary_url": "https://download.litecoin.org/litecoin-0.21.4/linux/litecoin-0.21.4-aarch64-linux-gnu.tar.gz", + "verification_source": "https://download.litecoin.org/litecoin-0.21.4/linux/litecoin-0.21.4-aarch64-linux-gnu.tar.gz.asc" } } }, diff --git a/configs/coins/optimism.json b/configs/coins/optimism.json new file mode 100644 index 00000000..bc7cc886 --- /dev/null +++ b/configs/coins/optimism.json @@ -0,0 +1,67 @@ +{ + "coin": { + "name": "Optimism", + "shortcut": "ETH", + "network": "OP", + "label": "Optimism", + "alias": "optimism" + }, + "ports": { + "backend_rpc": 8200, + "backend_p2p": 38400, + "backend_http": 8300, + "backend_authrpc": 8400, + "blockbook_internal": 9200, + "blockbook_public": 9300 + }, + "ipc": { + "rpc_url_template": "ws://127.0.0.1:{{.Ports.BackendRPC}}", + "rpc_timeout": 25 + }, + "backend": { + "package_name": "backend-optimism", + "package_revision": "satoshilabs-1", + "system_user": "optimism", + "version": "1.101315.1", + "binary_url": "https://github.com/ethereum-optimism/op-geth/archive/refs/tags/v1.101315.1.tar.gz", + "verification_type": "sha256", + "verification_source": "f0f31ef2982f87f9e3eb90f2b603f5fcd9d680e487d35f5bdcf5aeba290b153f", + "extract_command": "mkdir backend/source && tar -C backend/source --strip 1 -xf v1.101315.1.tar.gz && cd backend/source && make geth && mv build/bin/geth ../ && rm -rf ../source && echo", + "exclude_files": [], + "exec_command_template": "/bin/sh -c '{{.Env.BackendInstallPath}}/{{.Coin.Alias}}/optimism_exec.sh 2>> {{.Env.BackendDataPath}}/{{.Coin.Alias}}/backend/{{.Coin.Alias}}.log'", + "exec_script": "optimism.sh", + "logrotate_files_template": "{{.Env.BackendDataPath}}/{{.Coin.Alias}}/backend/{{.Coin.Alias}}.log", + "postinst_script_template": "openssl rand -hex 32 > {{.Env.BackendDataPath}}/{{.Coin.Alias}}/backend/jwtsecret", + "service_type": "simple", + "service_additional_params_template": "", + "protect_memory": true, + "mainnet": true, + "server_config_file": "", + "client_config_file": "" + }, + "blockbook": { + "package_name": "blockbook-optimism", + "system_user": "blockbook-optimism", + "internal_binding_template": ":{{.Ports.BlockbookInternal}}", + "public_binding_template": ":{{.Ports.BlockbookPublic}}", + "explorer_url": "", + "additional_params": "", + "block_chain": { + "parse": true, + "mempool_workers": 8, + "mempool_sub_workers": 2, + "block_addresses_to_keep": 300, + "additional_params": { + "mempoolTxTimeoutHours": 48, + "queryBackendOnMempoolResync": false, + "fiat_rates": "coingecko", + "fiat_rates_vs_currencies": "AED,ARS,AUD,BDT,BHD,BMD,BRL,CAD,CHF,CLP,CNY,CZK,DKK,EUR,GBP,HKD,HUF,IDR,ILS,INR,JPY,KRW,KWD,LKR,MMK,MXN,MYR,NGN,NOK,NZD,PHP,PKR,PLN,RUB,SAR,SEK,SGD,THB,TRY,TWD,UAH,USD,VEF,VND,ZAR,BTC,ETH", + "fiat_rates_params": "{\"coin\": \"ethereum\",\"platformIdentifier\": \"optimistic-ethereum\",\"platformVsCurrency\": \"eth\",\"periodSeconds\": 900}" + } + } + }, + "meta": { + "package_maintainer": "IT", + "package_maintainer_email": "it@satoshilabs.com" + } +} diff --git a/configs/coins/optimism_archive.json b/configs/coins/optimism_archive.json new file mode 100644 index 00000000..1a642f11 --- /dev/null +++ b/configs/coins/optimism_archive.json @@ -0,0 +1,70 @@ +{ + "coin": { + "name": "Optimism Archive", + "shortcut": "ETH", + "network": "OP", + "label": "Optimism", + "alias": "optimism_archive" + }, + "ports": { + "backend_rpc": 8202, + "backend_p2p": 38402, + "backend_http": 8302, + "backend_authrpc": 8402, + "blockbook_internal": 9202, + "blockbook_public": 9302 + }, + "ipc": { + "rpc_url_template": "ws://127.0.0.1:{{.Ports.BackendRPC}}", + "rpc_timeout": 25 + }, + "backend": { + "package_name": "backend-optimism-archive", + "package_revision": "satoshilabs-1", + "system_user": "optimism", + "version": "1.101315.1", + "binary_url": "https://github.com/ethereum-optimism/op-geth/archive/refs/tags/v1.101315.1.tar.gz", + "verification_type": "sha256", + "verification_source": "f0f31ef2982f87f9e3eb90f2b603f5fcd9d680e487d35f5bdcf5aeba290b153f", + "extract_command": "mkdir backend/source && tar -C backend/source --strip 1 -xf v1.101315.1.tar.gz && cd backend/source && make geth && mv build/bin/geth ../ && rm -rf ../source && echo", + "exclude_files": [], + "exec_command_template": "/bin/sh -c '{{.Env.BackendInstallPath}}/{{.Coin.Alias}}/optimism_archive_exec.sh 2>> {{.Env.BackendDataPath}}/{{.Coin.Alias}}/backend/{{.Coin.Alias}}.log'", + "exec_script": "optimism_archive.sh", + "logrotate_files_template": "{{.Env.BackendDataPath}}/{{.Coin.Alias}}/backend/{{.Coin.Alias}}.log", + "postinst_script_template": "openssl rand -hex 32 > {{.Env.BackendDataPath}}/{{.Coin.Alias}}/backend/jwtsecret", + "service_type": "simple", + "service_additional_params_template": "", + "protect_memory": true, + "mainnet": true, + "server_config_file": "", + "client_config_file": "" + }, + "blockbook": { + "package_name": "blockbook-optimism-archive", + "system_user": "blockbook-optimism", + "internal_binding_template": ":{{.Ports.BlockbookInternal}}", + "public_binding_template": ":{{.Ports.BlockbookPublic}}", + "explorer_url": "", + "additional_params": "-workers=16", + "block_chain": { + "parse": true, + "mempool_workers": 8, + "mempool_sub_workers": 2, + "block_addresses_to_keep": 600, + "additional_params": { + "address_aliases": true, + "mempoolTxTimeoutHours": 48, + "processInternalTransactions": true, + "queryBackendOnMempoolResync": false, + "fiat_rates": "coingecko", + "fiat_rates_vs_currencies": "AED,ARS,AUD,BDT,BHD,BMD,BRL,CAD,CHF,CLP,CNY,CZK,DKK,EUR,GBP,HKD,HUF,IDR,ILS,INR,JPY,KRW,KWD,LKR,MMK,MXN,MYR,NGN,NOK,NZD,PHP,PKR,PLN,RUB,SAR,SEK,SGD,THB,TRY,TWD,UAH,USD,VEF,VND,ZAR,BTC,ETH", + "fiat_rates_params": "{\"coin\": \"ethereum\",\"platformIdentifier\": \"optimistic-ethereum\",\"platformVsCurrency\": \"eth\",\"periodSeconds\": 900}", + "fourByteSignatures": "https://www.4byte.directory/api/v1/signatures/" + } + } + }, + "meta": { + "package_maintainer": "IT", + "package_maintainer_email": "it@satoshilabs.com" + } +} diff --git a/configs/coins/optimism_archive_legacy_geth.json b/configs/coins/optimism_archive_legacy_geth.json new file mode 100644 index 00000000..7a9379d9 --- /dev/null +++ b/configs/coins/optimism_archive_legacy_geth.json @@ -0,0 +1,40 @@ +{ + "coin": { + "name": "Optimism Archive Legacy Geth", + "shortcut": "ETH", + "label": "Optimism", + "alias": "optimism_archive_legacy_geth" + }, + "ports": { + "backend_rpc": 8204, + "backend_http": 8304, + "backend_p2p": 38404, + "blockbook_internal": 9204, + "blockbook_public": 9304 + }, + "backend": { + "package_name": "backend-optimism-archive-legacy-geth", + "package_revision": "satoshilabs-1", + "system_user": "optimism", + "version": "0.5.31", + "binary_url": "https://github.com/ethereum-optimism/optimism-legacy/archive/refs/heads/develop.zip", + "verification_type": "sha256", + "verification_source": "367b32b3f4c1450a57fa57650a0abdfb74ae58c09123d94b161aaec90fd6b883", + "extract_command": "mkdir backend/source && unzip -d backend/source", + "exclude_files": [], + "exec_command_template": "/bin/sh -c '{{.Env.BackendInstallPath}}/{{.Coin.Alias}}/optimism_archive_legacy_geth_exec.sh 2>> {{.Env.BackendDataPath}}/{{.Coin.Alias}}/backend/{{.Coin.Alias}}.log'", + "exec_script": "optimism_archive_legacy_geth.sh", + "logrotate_files_template": "{{.Env.BackendDataPath}}/{{.Coin.Alias}}/backend/{{.Coin.Alias}}.log", + "postinst_script_template": "cd {{.Env.BackendInstallPath}}/{{.Coin.Alias}}/source/optimism-legacy-devlop/l2geth && make geth && mv build/bin/geth {{.Env.BackendInstallPath}}/{{.Coin.Alias}} && rm -rf {{.Env.BackendInstallPath}}/{{.Coin.Alias}}/source", + "service_type": "simple", + "service_additional_params_template": "", + "protect_memory": true, + "mainnet": true, + "server_config_file": "", + "client_config_file": "" + }, + "meta": { + "package_maintainer": "IT", + "package_maintainer_email": "it@satoshilabs.com" + } +} \ No newline at end of file diff --git a/configs/coins/optimism_archive_op_node.json b/configs/coins/optimism_archive_op_node.json new file mode 100644 index 00000000..a16c4122 --- /dev/null +++ b/configs/coins/optimism_archive_op_node.json @@ -0,0 +1,38 @@ +{ + "coin": { + "name": "Optimism Archive Op-Node", + "shortcut": "ETH", + "label": "Optimism", + "alias": "optimism_archive_op_node" + }, + "ports": { + "backend_rpc": 8203, + "blockbook_internal": 9203, + "blockbook_public": 9303 + }, + "backend": { + "package_name": "backend-optimism-archive-op-node", + "package_revision": "satoshilabs-1", + "system_user": "optimism", + "version": "1.7.6", + "binary_url": "https://github.com/ethereum-optimism/optimism/archive/refs/tags/op-node/v1.7.6.tar.gz", + "verification_type": "sha256", + "verification_source": "91384e4834f0d0776d1c3e19613b5c50a904f6e5814349e444d42d9e8be5a7ab", + "extract_command": "mkdir backend/source && tar -C backend/source --strip 1 -xf v1.7.6.tar.gz && cd backend/source/op-node && go build -o ../../op-node ./cmd && rm -rf ../../source && echo", + "exclude_files": [], + "exec_command_template": "/bin/sh -c '{{.Env.BackendInstallPath}}/{{.Coin.Alias}}/optimism_archive_op_node_exec.sh 2>&1 >> {{.Env.BackendDataPath}}/{{.Coin.Alias}}/backend/{{.Coin.Alias}}.log'", + "exec_script": "optimism_archive_op_node.sh", + "logrotate_files_template": "{{.Env.BackendDataPath}}/{{.Coin.Alias}}/backend/{{.Coin.Alias}}.log", + "postinst_script_template": "", + "service_type": "simple", + "service_additional_params_template": "", + "protect_memory": true, + "mainnet": true, + "server_config_file": "", + "client_config_file": "" + }, + "meta": { + "package_maintainer": "IT", + "package_maintainer_email": "it@satoshilabs.com" + } +} \ No newline at end of file diff --git a/configs/coins/optimism_op_node.json b/configs/coins/optimism_op_node.json new file mode 100644 index 00000000..e2b6cc17 --- /dev/null +++ b/configs/coins/optimism_op_node.json @@ -0,0 +1,38 @@ +{ + "coin": { + "name": "Optimism Op-Node", + "shortcut": "ETH", + "label": "Optimism", + "alias": "optimism_op_node" + }, + "ports": { + "backend_rpc": 8201, + "blockbook_internal": 9201, + "blockbook_public": 9301 + }, + "backend": { + "package_name": "backend-optimism-op-node", + "package_revision": "satoshilabs-1", + "system_user": "optimism", + "version": "1.7.6", + "binary_url": "https://github.com/ethereum-optimism/optimism/archive/refs/tags/op-node/v1.7.6.tar.gz", + "verification_type": "sha256", + "verification_source": "91384e4834f0d0776d1c3e19613b5c50a904f6e5814349e444d42d9e8be5a7ab", + "extract_command": "mkdir backend/source && tar -C backend/source --strip 1 -xf v1.7.6.tar.gz && cd backend/source/op-node && go build -o ../../op-node ./cmd && rm -rf ../../source && echo", + "exclude_files": [], + "exec_command_template": "/bin/sh -c '{{.Env.BackendInstallPath}}/{{.Coin.Alias}}/optimism_op_node_exec.sh 2>&1 >> {{.Env.BackendDataPath}}/{{.Coin.Alias}}/backend/{{.Coin.Alias}}.log'", + "exec_script": "optimism_op_node.sh", + "logrotate_files_template": "{{.Env.BackendDataPath}}/{{.Coin.Alias}}/backend/{{.Coin.Alias}}.log", + "postinst_script_template": "", + "service_type": "simple", + "service_additional_params_template": "", + "protect_memory": true, + "mainnet": true, + "server_config_file": "", + "client_config_file": "" + }, + "meta": { + "package_maintainer": "IT", + "package_maintainer_email": "it@satoshilabs.com" + } +} \ No newline at end of file diff --git a/configs/coins/polygon.json b/configs/coins/polygon.json index 1044b1e3..71e0c143 100644 --- a/configs/coins/polygon.json +++ b/configs/coins/polygon.json @@ -1,7 +1,8 @@ { "coin": { "name": "Polygon", - "shortcut": "MATIC", + "shortcut": "POL", + "network": "POL", "label": "Polygon", "alias": "polygon_bor" }, @@ -20,16 +21,16 @@ "package_name": "backend-polygon-bor", "package_revision": "satoshilabs-1", "system_user": "polygon", - "version": "1.3.2", - "binary_url": "https://github.com/maticnetwork/bor/archive/refs/tags/v1.3.2.tar.gz", + "version": "1.5.3", + "binary_url": "https://github.com/maticnetwork/bor/archive/refs/tags/v1.5.3.tar.gz", "verification_type": "sha256", - "verification_source": "bcd662d003a3aaa704b0226afcf0dac040de5f054de09e3ef1f5a0c494cdbc0f", - "extract_command": "mkdir backend/source && tar -C backend/source --strip 1 -xf v1.3.2.tar.gz && cd backend/source && make bor && mv build/bin/bor ../ && rm -rf ../source && echo", + "verification_source": "6dabc3306aa628f86232e96e5ec1a970bbebe38ace09447a0d2e5421dd77e4bd", + "extract_command": "mkdir backend/source && tar -C backend/source --strip 1 -xf v1.5.3.tar.gz && cd backend/source && make bor && mv build/bin/bor ../ && rm -rf ../source && echo", "exclude_files": [], "exec_command_template": "/bin/sh -c '{{.Env.BackendInstallPath}}/{{.Coin.Alias}}/polygon_bor_exec.sh 2>> {{.Env.BackendDataPath}}/{{.Coin.Alias}}/backend/{{.Coin.Alias}}.log'", "exec_script": "polygon_bor.sh", "logrotate_files_template": "{{.Env.BackendDataPath}}/{{.Coin.Alias}}/backend/{{.Coin.Alias}}.log", - "postinst_script_template": "wget https://raw.githubusercontent.com/maticnetwork/bor/v1.3.2/builder/files/genesis-mainnet-v1.json -O {{.Env.BackendInstallPath}}/{{.Coin.Alias}}/genesis.json", + "postinst_script_template": "wget https://raw.githubusercontent.com/maticnetwork/bor/v1.5.3/builder/files/genesis-mainnet-v1.json -O {{.Env.BackendInstallPath}}/{{.Coin.Alias}}/genesis.json", "service_type": "simple", "service_additional_params_template": "", "protect_memory": true, @@ -54,7 +55,7 @@ "queryBackendOnMempoolResync": false, "fiat_rates": "coingecko", "fiat_rates_vs_currencies": "AED,ARS,AUD,BDT,BHD,BMD,BRL,CAD,CHF,CLP,CNY,CZK,DKK,EUR,GBP,HKD,HUF,IDR,ILS,INR,JPY,KRW,KWD,LKR,MMK,MXN,MYR,NGN,NOK,NZD,PHP,PKR,PLN,RUB,SAR,SEK,SGD,THB,TRY,TWD,UAH,USD,VEF,VND,ZAR,BTC,ETH", - "fiat_rates_params": "{\"url\": \"https://api.coingecko.com/api/v3\", \"coin\": \"matic-network\",\"platformIdentifier\": \"polygon-pos\",\"platformVsCurrency\": \"usd\",\"periodSeconds\": 900}" + "fiat_rates_params": "{\"coin\": \"matic-network\",\"platformIdentifier\": \"polygon-pos\",\"platformVsCurrency\": \"usd\",\"periodSeconds\": 900}" } } }, diff --git a/configs/coins/polygon_archive.json b/configs/coins/polygon_archive.json index 860dd01b..6898e89c 100644 --- a/configs/coins/polygon_archive.json +++ b/configs/coins/polygon_archive.json @@ -1,7 +1,8 @@ { "coin": { "name": "Polygon Archive", - "shortcut": "MATIC", + "shortcut": "POL", + "network": "POL", "label": "Polygon", "alias": "polygon_archive_bor" }, @@ -20,16 +21,16 @@ "package_name": "backend-polygon-archive-bor", "package_revision": "satoshilabs-1", "system_user": "polygon", - "version": "1.3.2", - "binary_url": "https://github.com/maticnetwork/bor/archive/refs/tags/v1.3.2.tar.gz", + "version": "1.5.3", + "binary_url": "https://github.com/maticnetwork/bor/archive/refs/tags/v1.5.3.tar.gz", "verification_type": "sha256", - "verification_source": "bcd662d003a3aaa704b0226afcf0dac040de5f054de09e3ef1f5a0c494cdbc0f", - "extract_command": "mkdir backend/source && tar -C backend/source --strip 1 -xf v1.3.2.tar.gz && cd backend/source && make bor && mv build/bin/bor ../ && rm -rf ../source && echo", + "verification_source": "6dabc3306aa628f86232e96e5ec1a970bbebe38ace09447a0d2e5421dd77e4bd", + "extract_command": "mkdir backend/source && tar -C backend/source --strip 1 -xf v1.5.3.tar.gz && cd backend/source && make bor && mv build/bin/bor ../ && rm -rf ../source && echo", "exclude_files": [], "exec_command_template": "/bin/sh -c '{{.Env.BackendInstallPath}}/{{.Coin.Alias}}/polygon_archive_bor_exec.sh 2>> {{.Env.BackendDataPath}}/{{.Coin.Alias}}/backend/{{.Coin.Alias}}.log'", "exec_script": "polygon_archive_bor.sh", "logrotate_files_template": "{{.Env.BackendDataPath}}/{{.Coin.Alias}}/backend/{{.Coin.Alias}}.log", - "postinst_script_template": "wget https://raw.githubusercontent.com/maticnetwork/bor/v1.3.2/builder/files/genesis-mainnet-v1.json -O {{.Env.BackendInstallPath}}/{{.Coin.Alias}}/genesis.json", + "postinst_script_template": "wget https://raw.githubusercontent.com/maticnetwork/bor/v1.5.3/builder/files/genesis-mainnet-v1.json -O {{.Env.BackendInstallPath}}/{{.Coin.Alias}}/genesis.json", "service_type": "simple", "service_additional_params_template": "", "protect_memory": true, @@ -56,7 +57,7 @@ "queryBackendOnMempoolResync": false, "fiat_rates": "coingecko", "fiat_rates_vs_currencies": "AED,ARS,AUD,BDT,BHD,BMD,BRL,CAD,CHF,CLP,CNY,CZK,DKK,EUR,GBP,HKD,HUF,IDR,ILS,INR,JPY,KRW,KWD,LKR,MMK,MXN,MYR,NGN,NOK,NZD,PHP,PKR,PLN,RUB,SAR,SEK,SGD,THB,TRY,TWD,UAH,USD,VEF,VND,ZAR,BTC,ETH", - "fiat_rates_params": "{\"url\": \"https://api.coingecko.com/api/v3\", \"coin\": \"matic-network\",\"platformIdentifier\": \"polygon-pos\",\"platformVsCurrency\": \"usd\",\"periodSeconds\": 900}", + "fiat_rates_params": "{\"coin\": \"matic-network\",\"platformIdentifier\": \"polygon-pos\",\"platformVsCurrency\": \"usd\",\"periodSeconds\": 900}", "fourByteSignatures": "https://www.4byte.directory/api/v1/signatures/" } } diff --git a/configs/coins/polygon_heimdall.json b/configs/coins/polygon_heimdall.json index 6a57ea81..1486deeb 100644 --- a/configs/coins/polygon_heimdall.json +++ b/configs/coins/polygon_heimdall.json @@ -16,16 +16,16 @@ "package_name": "backend-polygon-heimdall", "package_revision": "satoshilabs-1", "system_user": "polygon", - "version": "1.0.5", - "binary_url": "https://github.com/maticnetwork/heimdall/archive/refs/tags/v1.0.5.tar.gz", + "version": "1.0.10", + "binary_url": "https://github.com/maticnetwork/heimdall/archive/refs/tags/v1.0.10.tar.gz", "verification_type": "sha256", - "verification_source": "59727263cb3927dd47e5c00dc3c5754f0cd7680af6e1ae019b4b540b3442197c", - "extract_command": "mkdir backend/source && tar -C backend/source --strip 1 -xf v1.0.5.tar.gz && cd backend/source && make build && mv build/heimdalld ../ && rm -rf ../source && echo", + "verification_source": "9058e054de2a0090e0a8400aa23d6144d7432ac31c6b4e4b6cff684a834e612f", + "extract_command": "mkdir backend/source && tar -C backend/source --strip 1 -xf v1.0.10.tar.gz && cd backend/source && make build && mv build/heimdalld ../ && rm -rf ../source && echo", "exclude_files": [], "exec_command_template": "/bin/sh -c '{{.Env.BackendInstallPath}}/{{.Coin.Alias}}/polygon_heimdall_exec.sh 2>&1 >> {{.Env.BackendDataPath}}/{{.Coin.Alias}}/backend/{{.Coin.Alias}}.log'", "exec_script": "polygon_heimdall.sh", "logrotate_files_template": "{{.Env.BackendDataPath}}/{{.Coin.Alias}}/backend/{{.Coin.Alias}}.log", - "postinst_script_template": "wget https://raw.githubusercontent.com/maticnetwork/heimdall/v1.0.5/builder/files/genesis-mainnet-v1.json -O {{.Env.BackendInstallPath}}/{{.Coin.Alias}}/genesis.json", + "postinst_script_template": "wget https://raw.githubusercontent.com/maticnetwork/heimdall/v1.0.10/builder/files/genesis-mainnet-v1.json -O {{.Env.BackendInstallPath}}/{{.Coin.Alias}}/genesis.json", "service_type": "simple", "service_additional_params_template": "", "protect_memory": true, diff --git a/configs/coins/polygon_heimdall_archive.json b/configs/coins/polygon_heimdall_archive.json index 82114a9c..228f42d0 100644 --- a/configs/coins/polygon_heimdall_archive.json +++ b/configs/coins/polygon_heimdall_archive.json @@ -16,16 +16,16 @@ "package_name": "backend-polygon-archive-heimdall", "package_revision": "satoshilabs-1", "system_user": "polygon", - "version": "1.0.5", - "binary_url": "https://github.com/maticnetwork/heimdall/archive/refs/tags/v1.0.5.tar.gz", + "version": "1.0.10", + "binary_url": "https://github.com/maticnetwork/heimdall/archive/refs/tags/v1.0.10.tar.gz", "verification_type": "sha256", - "verification_source": "59727263cb3927dd47e5c00dc3c5754f0cd7680af6e1ae019b4b540b3442197c", - "extract_command": "mkdir backend/source && tar -C backend/source --strip 1 -xf v1.0.5.tar.gz && cd backend/source && make build && mv build/heimdalld ../ && rm -rf ../source && echo", + "verification_source": "9058e054de2a0090e0a8400aa23d6144d7432ac31c6b4e4b6cff684a834e612f", + "extract_command": "mkdir backend/source && tar -C backend/source --strip 1 -xf v1.0.10.tar.gz && cd backend/source && make build && mv build/heimdalld ../ && rm -rf ../source && echo", "exclude_files": [], "exec_command_template": "/bin/sh -c '{{.Env.BackendInstallPath}}/{{.Coin.Alias}}/polygon_archive_heimdall_exec.sh 2>&1 >> {{.Env.BackendDataPath}}/{{.Coin.Alias}}/backend/{{.Coin.Alias}}.log'", "exec_script": "polygon_archive_heimdall.sh", "logrotate_files_template": "{{.Env.BackendDataPath}}/{{.Coin.Alias}}/backend/{{.Coin.Alias}}.log", - "postinst_script_template": "wget https://raw.githubusercontent.com/maticnetwork/heimdall/v1.0.5/builder/files/genesis-mainnet-v1.json -O {{.Env.BackendInstallPath}}/{{.Coin.Alias}}/genesis.json", + "postinst_script_template": "wget https://raw.githubusercontent.com/maticnetwork/heimdall/v1.0.10/builder/files/genesis-mainnet-v1.json -O {{.Env.BackendInstallPath}}/{{.Coin.Alias}}/genesis.json", "service_type": "simple", "service_additional_params_template": "", "protect_memory": true, diff --git a/configs/coins/qtum.json b/configs/coins/qtum.json index 5bfbae99..7699106a 100644 --- a/configs/coins/qtum.json +++ b/configs/coins/qtum.json @@ -22,10 +22,10 @@ "package_name": "backend-qtum", "package_revision": "satoshilabs-1", "system_user": "qtum", - "version": "24.1", - "binary_url": "https://github.com/qtumproject/qtum/releases/download/v24.1/qtum-24.1-x86_64-linux-gnu.tar.gz", + "version": "27.1", + "binary_url": "https://github.com/qtumproject/qtum/releases/download/v27.1/qtum-27.1-x86_64-linux-gnu.tar.gz", "verification_type": "sha256", - "verification_source": "13f7ca5c352732772e924bd07db0e8327e0a850edd9c89e7d191e0734990621c", + "verification_source": "0b1f612f0762184240c785c66b548f2dab8eed5e25481c635806ddf81807aa86", "extract_command": "tar -C backend --strip 1 -xf", "exclude_files": [ "bin/qtum-qt" diff --git a/configs/coins/qtum_testnet.json b/configs/coins/qtum_testnet.json index 1ceeef11..ed1218de 100644 --- a/configs/coins/qtum_testnet.json +++ b/configs/coins/qtum_testnet.json @@ -22,10 +22,10 @@ "package_name": "backend-qtum-testnet", "package_revision": "satoshilabs-1", "system_user": "qtum", - "version": "24.1", - "binary_url": "https://github.com/qtumproject/qtum/releases/download/v24.1/qtum-24.1-x86_64-linux-gnu.tar.gz", + "version": "27.1", + "binary_url": "https://github.com/qtumproject/qtum/releases/download/v27.1/qtum-27.1-x86_64-linux-gnu.tar.gz", "verification_type": "sha256", - "verification_source": "13f7ca5c352732772e924bd07db0e8327e0a850edd9c89e7d191e0734990621c", + "verification_source": "0b1f612f0762184240c785c66b548f2dab8eed5e25481c635806ddf81807aa86", "extract_command": "tar -C backend --strip 1 -xf", "exclude_files": [ "bin/qtum-qt" diff --git a/configs/coins/zcash.json b/configs/coins/zcash.json index fdf43d3d..be640783 100644 --- a/configs/coins/zcash.json +++ b/configs/coins/zcash.json @@ -22,10 +22,10 @@ "package_name": "backend-zcash", "package_revision": "satoshilabs-1", "system_user": "zcash", - "version": "5.9.1", - "binary_url": "https://github.com/zcash/artifacts/raw/master/v5.9.1/bullseye/zcash-5.9.1-linux64-debian-bullseye.tar.gz", + "version": "6.1.0", + "binary_url": "https://download.z.cash/downloads/zcash-6.1.0-linux64-debian-bullseye.tar.gz", "verification_type": "sha256", - "verification_source": "1911d4da83781dfe9d50fb4e0e5bab14fddca6e648f861563a629583182f478e", + "verification_source": "1d17ceacb265599bb4ee690baaf2b335cfe9825df5198359c771ee1834fd4358", "extract_command": "tar -C backend --strip 1 -xf", "exclude_files": [], "exec_command_template": "{{.Env.BackendInstallPath}}/{{.Coin.Alias}}/bin/zcashd -datadir={{.Env.BackendDataPath}}/{{.Coin.Alias}}/backend -conf={{.Env.BackendInstallPath}}/{{.Coin.Alias}}/{{.Coin.Alias}}.conf -pid=/run/{{.Coin.Alias}}/{{.Coin.Alias}}.pid", diff --git a/configs/coins/zcash_testnet.json b/configs/coins/zcash_testnet.json index 89125fe3..f2a1c388 100644 --- a/configs/coins/zcash_testnet.json +++ b/configs/coins/zcash_testnet.json @@ -21,10 +21,10 @@ "backend": { "package_name": "backend-zcash-testnet", "package_revision": "satoshilabs-1", - "version": "5.9.1", - "binary_url": "https://github.com/zcash/artifacts/raw/master/v5.9.1/bullseye/zcash-5.9.1-linux64-debian-bullseye.tar.gz", + "version": "6.1.0", + "binary_url": "https://download.z.cash/downloads/zcash-6.1.0-linux64-debian-bullseye.tar.gz", "verification_type": "sha256", - "verification_source": "1911d4da83781dfe9d50fb4e0e5bab14fddca6e648f861563a629583182f478e", + "verification_source": "1d17ceacb265599bb4ee690baaf2b335cfe9825df5198359c771ee1834fd4358", "extract_command": "tar -C backend --strip 1 -xf", "exclude_files": [], "exec_command_template": "{{.Env.BackendInstallPath}}/{{.Coin.Alias}}/bin/zcashd -datadir={{.Env.BackendDataPath}}/{{.Coin.Alias}}/backend -conf={{.Env.BackendInstallPath}}/{{.Coin.Alias}}/{{.Coin.Alias}}.conf -pid=/run/{{.Coin.Alias}}/{{.Coin.Alias}}.pid", diff --git a/configs/contract-fix/ethereum.json b/configs/contract-fix/ethereum.json new file mode 100644 index 00000000..5b6dc03e --- /dev/null +++ b/configs/contract-fix/ethereum.json @@ -0,0 +1 @@ +[{"type":"ERC20","contract":"0xC19B6A4Ac7C7Cc24459F08984Bbd09664af17bD1","name":"Sensorium","symbol":"SENSO","decimals":0,"createdInBlock":11098997}] diff --git a/db/bulkconnect.go b/db/bulkconnect.go index 2a044bc1..8c2095bf 100644 --- a/db/bulkconnect.go +++ b/db/bulkconnect.go @@ -438,6 +438,11 @@ func (b *BulkConnect) Close() error { return err } } + if err := b.d.SetInconsistentState(false); err != nil { + return err + } + glog.Info("rocksdb: bulk connect closed, db set to open state") + bt, err := b.d.loadBlockTimes() if err != nil { return err @@ -446,11 +451,7 @@ func (b *BulkConnect) Close() error { if b.d.metrics != nil { b.d.metrics.AvgBlockPeriod.Set(float64(avg)) } - - if err := b.d.SetInconsistentState(false); err != nil { - return err - } - glog.Info("rocksdb: bulk connect closed, db set to open state") + glog.Info("rocksdb: processed block times") b.d = nil return nil } diff --git a/db/rocksdb.go b/db/rocksdb.go index 9c5a3b2f..58e269d7 100644 --- a/db/rocksdb.go +++ b/db/rocksdb.go @@ -1962,6 +1962,7 @@ func (d *RocksDB) LoadInternalState(config *common.Config) (*common.InternalStat } else { is.CoinLabel = config.CoinLabel } + is.Network = config.Network return is, nil } diff --git a/db/rocksdb_ethereumtype.go b/db/rocksdb_ethereumtype.go index 29bff516..11371a79 100644 --- a/db/rocksdb_ethereumtype.go +++ b/db/rocksdb_ethereumtype.go @@ -124,7 +124,7 @@ type AddrContracts struct { Contracts []AddrContract } -// packAddrContract packs AddrContracts into a byte buffer +// packAddrContracts packs AddrContracts into a byte buffer func packAddrContracts(acs *AddrContracts) []byte { buf := make([]byte, 0, 128) varBuf := make([]byte, maxPackedBigintBytes) diff --git a/docs/api.md b/docs/api.md index 69ac4579..811a5c40 100644 --- a/docs/api.md +++ b/docs/api.md @@ -8,68 +8,74 @@ API V2 is the current version of API. It can be used with all coin types that Bl Common principles used in API V2: -- all crypto amounts are transferred as strings, in the lowest denomination (satoshis, wei, ...), without decimal point -- empty fields are omitted. Empty field is a string of value _null_ or _""_, a number of value _0_, an object of value _null_ or an array without elements. The reason for this is that the interface serves many different coins which use only subset of the fields. Sometimes this principle can lead to slightly confusing results, for example when transaction version is 0, the field _version_ is omitted. +- all crypto amounts are transferred as strings, in the lowest denomination (satoshis, wei, ...), without decimal point +- empty fields are omitted. Empty field is a string of value _null_ or _""_, a number of value _0_, an object of value _null_ or an array without elements. The reason for this is that the interface serves many different coins which use only subset of the fields. Sometimes this principle can lead to slightly confusing results, for example when transaction version is 0, the field _version_ is omitted. + +See all the referred types (`typescript` interfaces) in the [blockbook-api.ts](../blockbook-api.ts) file. ### REST API The following methods are supported: -- [Status](#status) -- [Get block hash](#get-block-hash) -- [Get transaction](#get-transaction) -- [Get transaction specific](#get-transaction-specific) -- [Get address](#get-address) -- [Get xpub](#get-xpub) -- [Get utxo](#get-utxo) -- [Get block](#get-block) -- [Send transaction](#send-transaction) -- [Tickers list](#tickers-list) -- [Tickers](#tickers) -- [Balance history](#balance-history) +- [Status](#status) +- [Get block hash](#get-block-hash) +- [Get transaction](#get-transaction) +- [Get transaction specific](#get-transaction-specific) +- [Get address](#get-address) +- [Get xpub](#get-xpub) +- [Get utxo](#get-utxo) +- [Get block](#get-block) +- [Send transaction](#send-transaction) +- [Tickers list](#tickers-list) +- [Tickers](#tickers) +- [Balance history](#balance-history) #### Status page Status page returns current status of Blockbook and connected backend. ``` -GET /api +GET /api/status ``` -Response: +Response (`SystemInfo` type): + + ```javascript { "blockbook": { "coin": "Bitcoin", - "host": "blockbook", + "network": "BTC", + "host": "backend5", "version": "0.4.0", - "gitCommit": "3d9ad91", - "buildTime": "2019-05-17T14:34:00+00:00", + "gitCommit": "a0960c8e", + "buildTime": "2024-08-08T12:32:50+00:00", "syncMode": true, "initialSync": false, "inSync": true, - "bestHeight": 577261, - "lastBlockTime": "2019-05-22T18:03:33.547762973+02:00", + "bestHeight": 860730, + "lastBlockTime": "2024-09-10T08:19:04.471017534Z", "inSyncMempool": true, - "lastMempoolTime": "2019-05-22T18:10:10.27929383+02:00", - "mempoolSize": 17348, + "lastMempoolTime": "2024-09-10T08:42:39.38871351Z", + "mempoolSize": 232021, "decimals": 8, - "dbSize": 191887866502, - "about": "Blockbook - blockchain indexer for Trezor wallet https://trezor.io/. Do not use for any other purpose." + "dbSize": 761283489075, + "hasFiatRates": true, + "currentFiatRatesTime": "2024-09-10T08:42:00.898792419Z", + "historicalFiatRatesTime": "2024-09-10T00:00:00Z", + "about": "Blockbook - blockchain indexer for Trezor Suite https://trezor.io/trezor-suite. Do not use for any other purpose." }, "backend": { "chain": "main", - "blocks": 577261, - "headers": 577261, - "bestBlockHash": "0000000000000000000ca8c902aa58b3118a7f35d093e25a07f17bcacd91cabf", - "difficulty": "6704632680587.417", - "sizeOnDisk": 250504188580, - "version": "180000", - "subversion": "/Satoshi:0.18.0/", - "protocolVersion": "70015", - "timeOffset": 0, - "warnings": "" + "blocks": 860730, + "headers": 860730, + "bestBlockHash": "00000000000000000000effeb0c4460480e6a347deab95332c63007a68646ee5", + "difficulty": "89471664776970.77", + "sizeOnDisk": 681584532221, + "version": "270100", + "subversion": "/Satoshi:27.1.0/", + "protocolVersion": "70016" } } ``` @@ -82,9 +88,11 @@ GET /api/v2/block-index/ Response: + + ```javascript { - "blockHash": "ed8f3af8c10ca70a136901c6dd3adf037f0aea8a93fbe9e80939214034300f1e" + "blockHash": "0000000000000000000b7b8574bc6fd285825ec2dbcbeca149121fc05b0c828c" } ``` @@ -98,117 +106,183 @@ Get transaction returns "normalized" data about transaction, which has the same GET /api/v2/tx/ ``` -Response for Bitcoin-type coins, confirmed transaction: +Response for Bitcoin-type coins, confirmed transaction (`Tx` type): + + ```javascript { - "txid": "9e2bc8fbd40af17a6564831f84aef0cab2046d4bad19e91c09d21bff2c851851", - "version": 1, + "txid": "8c1e3dec662d1f2a5e322ccef5eca263f98eb16723c6f990be0c88c1db113fb1", + "version": 2, + "lockTime": 860729, "vin": [ { - "txid": "f124e6999bf67e710b9e8a8ac4dbb08a64aa9c264120cf98793455e36a531615", - "vout": 2, - "sequence": 4294967295, + "txid": "0eb7b574373de2c88d0dc1444f49947c681d0437d21361f9ebb4dd09c62f2a66", + "vout": 1, + "sequence": 4294967293, "n": 0, "addresses": [ - "DDhUv8JZGmSxKYV95NLnbRTUKni9cDZD3S" + "bc1qmgwnfjlda4ns3g6g3yz74w6scnn9yu2ts82yyc" ], "isAddress": true, - "value": "55795108999999", - "hex": "473...2c7ec77bb982" + "value": "10106300" } ], "vout": [ { - "value": "55585679000000", + "value": "175000", "n": 0, - "hex": "76a914feaca9d9fa7120c7c587c00c639bb18d40faadd388ac", + "hex": "76a914ecc999d554eaa3efa5e871c28f58b549c36ec51788ac", "addresses": [ - "DUMh1rPrXTrCN2Z9EHsLPg7b78rACHB2h7" + "1Nb1ykSD7J5k4RFjJQGsrD9gxBE6jzfNa9" ], "isAddress": true }, { - "value": "209329999999", + "value": "9888100", "n": 1, - "hex": "76a914ea8984be785868391d92f49c14933f47c152ea0a88ac", + "hex": "001496f152a0919487624bf4f13f46f0d20fa10d9acc", "addresses": [ - "DSXDQ6rnwLX47WFRnemctoXPHA9pLMxqXn" + "bc1qjmc49gy3jjrkyjl57yl5duxjp7ssmxkvh5t2q5" ], "isAddress": true } ], - "blockHash": "78d1f3de899a10dd2e580704226ebf9508e95e1706f177fc9c31c47f245d2502", - "blockHeight": 2647927, + "blockHash": "00000000000000000000effeb0c4460480e6a347deab95332c63007a68646ee5", + "blockHeight": 860730, "confirmations": 1, - "blockTime": 1553088212, - "size": 234, - "vsize": 153, - "value": "55795008999999", - "valueIn": "55795108999999", - "fees": "100000000", - "hex": "0100000...0011000" + "blockTime": 1725956288, + "size": 225, + "vsize": 144, + "value": "10063100", + "valueIn": "10106300", + "fees": "43200", + "hex": "02000000000101662a2fc609ddb4ebf96113d237041d687c94494f44c10d8dc8e23d3774b5b70e0100000000fdffffff0298ab0200000000001976a914ecc999d554eaa3efa5e871c28f58b549c36ec51788ac64e196000000000016001496f152a0919487624bf4f13f46f0d20fa10d9acc0247304402202bb0591180cdbbe0f639af6eb21abdb993fc5a667b09e6392d5c11b025a9187102201ef2e84fc91a5d2c6fbbc9f943482d230256a3640f8ecb83c1f3f17242cf011001210314f03889e1667feb696ee280625943195189cfabe46d54204d987f631fe6892739220d00" } ``` -Response for Bitcoin-type coins, unconfirmed transaction (_blockHeight_: -1, _confirmations_: 0, mining estimates _confirmationETABlocks_ and _confirmationETASeconds_): +Response for Bitcoin-type coins, unconfirmed transaction: + +Special fields: + +- _blockHeight_: -1 +- _confirmations_: 0 +- _confirmationETABlocks_: number +- _confirmationETASeconds_: number + + ```javascript { - "txid": "cd8ec77174e426070d0a50779232bba7312b712e2c6843d82d963d7076c61366", + "txid": "73b1ad97194e426031e5c692869de2d83dc2ff6033fc6f0ab5514345f92eaf0d", "version": 2, "vin": [ { - "txid": "47687cc4abb58d815168686465a38113a0608b2568a6d6480129d197e653f6dc", - "sequence": 4294967295, + "txid": "bccbebb64b1613ada74eefa96753088a80fefa53a10e42c66eef1899371bc096", "n": 0, - "addresses": ["bc1qka0gpenex558g8gpxmpx247mwhw695k6a7yhs4"], + "addresses": [ + "bc1q9lh77es6m8ztr7muwcec00ewn8fxakpl9jwv8y" + ], "isAddress": true, - "value": "1983687" + "value": "371042" } ], "vout": [ { - "value": "3106", + "value": "293135", "n": 0, - "hex": "0020d7da4868055fde790a8581637ab81c216e17a3f8a099283da6c4a27419ffa539", + "hex": "0014aafd7386f99f4b508ec05ee8f7edc2e07126620a", "addresses": [ - "bc1q6ldys6q9tl08jz59s93h4wquy9hp0glc5zvjs0dxcj38gx0l55uspu8x86" + "bc1q4t7h8phena94prkqtm500mwzupcjvcs2akcdy9" ], "isAddress": true }, { - "value": "1979101", + "value": "74022", "n": 1, - "hex": "0014381be30ca46ddf378ef69ebc4a601bd6ff30b754", - "addresses": ["bc1q8qd7xr9ydh0n0rhkn67y5cqm6mlnpd65dcyeeg"], + "hex": "0014a3de0fbba89c17d43093164ea955bad65bc260bf", + "addresses": [ + "bc1q500qlwagnstagvynze82j4d66eduyc9lf64ksh" + ], "isAddress": true } ], "blockHeight": -1, "confirmations": 0, - "confirmationETABlocks": 3, - "confirmationETASeconds": 2055, - "blockTime": 1675270935, - "size": 234, - "vsize": 153, - "value": "1982207", - "valueIn": "1983687", - "fees": "1480", - "hex": "020000000001...b18f00000000" + "confirmationETABlocks": 1, + "confirmationETASeconds": 619, + "blockTime": 1725959035, + "size": 222, + "vsize": 141, + "value": "367157", + "valueIn": "371042", + "fees": "3885", + "hex": "0200000000010196c01b379918ef6ec6420ea153fafe808a085367a9ef4ea7ad13164bb6ebcbbc000000000000000000020f79040000000000160014aafd7386f99f4b508ec05ee8f7edc2e07126620a2621010000000000160014a3de0fbba89c17d43093164ea955bad65bc260bf0247304402204a5bdf8a8d19b0a19044b0c0de3ced92b92e8d0c629ffca83178c85a608f719e02203841d40dd92db48715f9f41a732e139ac3cc7696a23adc87136bd8037a594e9f012102824a5e7b878f8d63887bdcb1b0982cdb0b375068b3798c4c96799476a19a389e00000000", + "rbf": true, + "coinSpecificData": { + "txid": "73b1ad97194e426031e5c692869de2d83dc2ff6033fc6f0ab5514345f92eaf0d", + "hash": "91deb6a9d0f5a37e2e83d1e602ba14cd9811fd3605f582154c9bd1337f7f4c8a", + "version": 2, + "size": 222, + "vsize": 141, + "weight": 561, + "locktime": 0, + "vin": [ + { + "txid": "bccbebb64b1613ada74eefa96753088a80fefa53a10e42c66eef1899371bc096", + "vout": 0, + "scriptSig": { + "asm": "", + "hex": "" + }, + "txinwitness": [ + "304402204a5bdf8a8d19b0a19044b0c0de3ced92b92e8d0c629ffca83178c85a608f719e02203841d40dd92db48715f9f41a732e139ac3cc7696a23adc87136bd8037a594e9f01", + "02824a5e7b878f8d63887bdcb1b0982cdb0b375068b3798c4c96799476a19a389e" + ], + "sequence": 0 + } + ], + "vout": [ + { + "value": 0.00293135, + "n": 0, + "scriptPubKey": { + "asm": "0 aafd7386f99f4b508ec05ee8f7edc2e07126620a", + "desc": "addr(bc1q4t7h8phena94prkqtm500mwzupcjvcs2akcdy9)#qmxeweuu", + "hex": "0014aafd7386f99f4b508ec05ee8f7edc2e07126620a", + "address": "bc1q4t7h8phena94prkqtm500mwzupcjvcs2akcdy9", + "type": "witness_v0_keyhash" + } + }, + { + "value": 0.00074022, + "n": 1, + "scriptPubKey": { + "asm": "0 a3de0fbba89c17d43093164ea955bad65bc260bf", + "desc": "addr(bc1q500qlwagnstagvynze82j4d66eduyc9lf64ksh)#mynfp6xy", + "hex": "0014a3de0fbba89c17d43093164ea955bad65bc260bf", + "address": "bc1q500qlwagnstagvynze82j4d66eduyc9lf64ksh", + "type": "witness_v0_keyhash" + } + } + ], + "hex": "0200000000010196c01b379918ef6ec6420ea153fafe808a085367a9ef4ea7ad13164bb6ebcbbc000000000000000000020f79040000000000160014aafd7386f99f4b508ec05ee8f7edc2e07126620a2621010000000000160014a3de0fbba89c17d43093164ea955bad65bc260bf0247304402204a5bdf8a8d19b0a19044b0c0de3ced92b92e8d0c629ffca83178c85a608f719e02203841d40dd92db48715f9f41a732e139ac3cc7696a23adc87136bd8037a594e9f012102824a5e7b878f8d63887bdcb1b0982cdb0b375068b3798c4c96799476a19a389e00000000" + } } ``` Response for Ethereum-type coins. Data of the transaction consist of: -- always only one _vin_, only one _vout_ -- an array of _tokenTransfers_ (ERC20, ERC721 or ERC1155) -- _ethereumSpecific_ data - - _type_ (returned only for contract creation - value `1` and destruction value `2`) - - _status_ (`1` OK, `0` Failure, `-1` pending), potential _error_ message, _gasLimit_, _gasUsed_, _gasPrice_, _nonce_, input _data_ - - parsed input data in the field _parsedData_, if a match with the 4byte directory was found - - internal transfers (type `0` transfer, type `1` contract creation, type `2` contract destruction) -- _addressAliases_ - maps addresses in the transaction to names from contract or ENS. Only addresses with known names are returned. +- always only one _vin_, only one _vout_ +- an array of _tokenTransfers_ (ERC20, ERC721 or ERC1155) +- _ethereumSpecific_ data + - _type_ (returned only for contract creation - value `1` and destruction value `2`) + - _status_ (`1` OK, `0` Failure, `-1` pending), potential _error_ message, _gasLimit_, _gasUsed_, _gasPrice_, _nonce_, input _data_ + - parsed input data in the field _parsedData_, if a match with the 4byte directory was found + - internal transfers (type `0` transfer, type `1` contract creation, type `2` contract destruction) +- _addressAliases_ - maps addresses in the transaction to names from contract or ENS. Only addresses with known names are returned. + + ```javascript { @@ -311,8 +385,8 @@ Response for Ethereum-type coins. Data of the transaction consist of: A note about the `blockTime` field: -- for already mined transaction (`confirmations > 0`), the field `blockTime` contains time of the block -- for transactions in mempool (`confirmations == 0`), the field contains time when the running instance of Blockbook was first time notified about the transaction. This time may be different in different instances of Blockbook. +- for already mined transaction (`confirmations > 0`), the field `blockTime` contains time of the block +- for transactions in mempool (`confirmations == 0`), the field contains time when the running instance of Blockbook was first time notified about the transaction. This time may be different in different instances of Blockbook. #### Get transaction specific @@ -324,10 +398,14 @@ GET /api/v2/tx-specific/ Example response: + + ```javascript { "hex": "040000808...8e6e73cb009", "txid": "7a0a0ff6f67bac2a856c7296382b69151949878de6fb0d01a8efa197182b2913", + "authdigest": "ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff", + "size": 1809, "overwintered": true, "version": 4, "versiongroupid": "892f2085", @@ -337,6 +415,7 @@ Example response: "vout": [], "vjoinsplit": [], "valueBalance": 0, + "valueBalanceZat": 0, "vShieldedSpend": [ { "cv": "50258bfa65caa9f42f4448b9194840c7da73afc8159faf7358140bfd0f237962", @@ -367,7 +446,8 @@ Example response: ], "bindingSig": "bc018af8808387...5130bb382ad8e6e73cb009", "blockhash": "0000000001c4aa394e796dd1b82e358f114535204f6f5b6cf4ad58dc439c47af", - "confirmations": 5222, + "height": 495665, + "confirmations": 2145803, "time": 1552301566, "blocktime": 1552301566 } @@ -383,43 +463,46 @@ GET /api/v2/address/
[?page=&pageSize=&from=&t The optional query parameters: -- _page_: specifies page of returned transactions, starting from 1. If out of range, Blockbook returns the closest possible page. -- _pageSize_: number of transactions returned by call (default and maximum 1000) -- _from_, _to_: filter of the returned transactions _from_ block height _to_ block height (default no filter) -- _details_: specifies level of details returned by request (default _txids_) - - _basic_: return only address balances, without any transactions - - _tokens_: _basic_ + tokens belonging to the address (applicable only to some coins) - - _tokenBalances_: _basic_ + tokens with balances + belonging to the address (applicable only to some coins) - - _txids_: _tokenBalances_ + list of txids, subject to _from_, _to_ filter and paging - - _txslight_: _tokenBalances_ + list of transaction with limited details (only data from index), subject to _from_, _to_ filter and paging - - _txs_: _tokenBalances_ + list of transaction with details, subject to _from_, _to_ filter and paging -- _contract_: return only transactions which affect specified contract (applicable only to coins which support contracts) -- _secondary_: specifies secondary (fiat) currency in which the token and total balances are returned in addition to crypto values +- _page_: specifies page of returned transactions, starting from 1. If out of range, Blockbook returns the closest possible page. +- _pageSize_: number of transactions returned by call (default and maximum 1000) +- _from_, _to_: filter of the returned transactions _from_ block height _to_ block height (default no filter) +- _details_: specifies level of details returned by request (default _txids_) + - _basic_: return only address balances, without any transactions + - _tokens_: _basic_ + tokens belonging to the address (applicable only to some coins) + - _tokenBalances_: _basic_ + tokens with balances + belonging to the address (applicable only to some coins) + - _txids_: _tokenBalances_ + list of txids, subject to _from_, _to_ filter and paging + - _txslight_: _tokenBalances_ + list of transaction with limited details (only data from index), subject to _from_, _to_ filter and paging + - _txs_: _tokenBalances_ + list of transaction with details, subject to _from_, _to_ filter and paging +- _contract_: return only transactions which affect specified contract (applicable only to coins which support contracts) +- _secondary_: specifies secondary (fiat) currency in which the token and total balances are returned in addition to crypto values -Example response for bitcoin type coin, _details_ set to _txids_: +Example response for bitcoin type coin, _details_ set to _txids_ (`Address` type): + + ```javascript { "page": 1, "totalPages": 1, "itemsOnPage": 1000, - "address": "D5Z7XrtJNg7hAtznSDMXvfiFmMYphwuWz7", - "balance": "2432468097999991", - "totalReceived": "3992283916999979", - "totalSent": "1559815818999988", + "address": "bc1q0wd209cv5k9pd9mhk7nspacywcj038xxdhnt5u", + "balance": "4225100", + "totalReceived": "4225100", + "totalSent": "0", "unconfirmedBalance": "0", "unconfirmedTxs": 0, - "txs": 3, + "txs": 2, "txids": [ - "461dd46d5d6f56d765f82e60e6bf0727a3a1d1cb8c4144373d805b152a21d308", - "bdb5b47603c5d174eae3384c368068c8e9d2183b398ed0e31d125defa4447a10", - "5c1d2686d70d82bd8e84b5d3dc4bd0e8485e28cdc865336db6a5e40b2098277d" + "0db6010dc0815a4bdaa505bd1ccc851056b0d53c7e4ea7af39c4d648a2c0c019", + "7532920ddc506218337cceac978cce9c7f98e27ad3226dee55f3e934e0b32e80" ] } ``` Example response for ethereum type coin, _details_ set to _tokenBalances_ and _secondary_ set to _usd_. The _baseValue_ is value of the token in the base currency (ETH), _secondaryValue_ is value of the token in specified _secondary_ currency: + + ```javascript { "address": "0x2df3951b2037bA620C20Ed0B73CCF45Ea473e83B", @@ -457,25 +540,25 @@ Returns balances and transactions of an xpub or output descriptor, applicable on Blockbook supports BIP44, BIP49, BIP84 and BIP86 (Taproot) derivation schemes, using either xpubs or output descriptors (see https://github.com/bitcoin/bitcoin/blob/master/doc/descriptors.md) -- Xpubs +- Xpubs - Blockbook expects xpub at level 3 derivation path, i.e. _m/purpose'/coin_type'/account'/_. Blockbook completes the _change/address_index_ part of the path when deriving addresses. - The BIP version is determined by the prefix of the xpub. The prefixes for each coin are defined by fields `xpub_magic`, `xpub_magic_segwit_p2sh`, `xpub_magic_segwit_native` in the [trezor-common](https://github.com/trezor/trezor-common/tree/master/defs/bitcoin) library. If the prefix is not recognized, Blockbook defaults to BIP44 derivation scheme. + Blockbook expects xpub at level 3 derivation path, i.e. _m/purpose'/coin_type'/account'/_. Blockbook completes the _change/address_index_ part of the path when deriving addresses. + The BIP version is determined by the prefix of the xpub. The prefixes for each coin are defined by fields `xpub_magic`, `xpub_magic_segwit_p2sh`, `xpub_magic_segwit_native` in the [trezor-common](https://github.com/trezor/trezor-common/tree/master/defs/bitcoin) library. If the prefix is not recognized, Blockbook defaults to BIP44 derivation scheme. -- Output descriptors +- Output descriptors - Output descriptors are in the form `([][//*])[#checksum]`, for example `pkh([5c9e228d/44'/0'/0']xpub6BgBgses...Mj92pReUsQ/<0;1>/*)#abcd` + Output descriptors are in the form `([][//*])[#checksum]`, for example `pkh([5c9e228d/44'/0'/0']xpub6BgBgses...Mj92pReUsQ/<0;1>/*)#abcd` - Parameters `type` and `xpub` are mandatory, the rest is optional + Parameters `type` and `xpub` are mandatory, the rest is optional - Blockbook supports a limited set of `type`s: + Blockbook supports a limited set of `type`s: - - BIP44: `pkh(xpub)` - - BIP49: `sh(wpkh(xpub))` - - BIP84: `wpkh(xpub)` - - BIP86 (Taproot single key): `tr(xpub)` + - BIP44: `pkh(xpub)` + - BIP49: `sh(wpkh(xpub))` + - BIP84: `wpkh(xpub)` + - BIP86 (Taproot single key): `tr(xpub)` - Parameter `change` can be a single number or a list of change indexes, specified either in the format `` or `{index1,index2,...}`. If the parameter `change` is not specified, Blockbook defaults to `<0;1>`. + Parameter `change` can be a single number or a list of change indexes, specified either in the format `` or `{index1,index2,...}`. If the parameter `change` is not specified, Blockbook defaults to `<0;1>`. The returned transactions are sorted by block height, newest blocks first. @@ -485,22 +568,22 @@ GET /api/v2/xpub/[?page=&pageSize=&from=[?confirmed=true] ``` -Response: +Response (`Utxo[]` type): ```javascript [ - { - txid: "13d26cd939bf5d155b1c60054e02d9c9b832a85e6ec4f2411be44b6b5a2842e9", - vout: 0, - value: "1422303206539", - confirmations: 0, - lockTime: 2648100, - }, - { - txid: "a79e396a32e10856c97b95f43da7e9d2b9a11d446f7638dbd75e5e7603128cac", - vout: 1, - value: "39748685", - height: 2648043, - confirmations: 47, - coinbase: true, - }, - { - txid: "de4f379fdc3ea9be063e60340461a014f372a018d70c3db35701654e7066b3ef", - vout: 0, - value: "122492339065", - height: 2646043, - confirmations: 2047, - }, - { - txid: "9e8eb9b3d2e8e4b5d6af4c43a9196dfc55a05945c8675904d8c61f404ea7b1e9", - vout: 0, - value: "142771322208", - height: 2644885, - confirmations: 3205, - }, + { + txid: '13d26cd939bf5d155b1c60054e02d9c9b832a85e6ec4f2411be44b6b5a2842e9', + vout: 0, + value: '1422303206539', + confirmations: 0, + lockTime: 2648100, + }, + { + txid: 'a79e396a32e10856c97b95f43da7e9d2b9a11d446f7638dbd75e5e7603128cac', + vout: 1, + value: '39748685', + height: 2648043, + confirmations: 47, + coinbase: true, + }, + { + txid: 'de4f379fdc3ea9be063e60340461a014f372a018d70c3db35701654e7066b3ef', + vout: 0, + value: '122492339065', + height: 2646043, + confirmations: 2047, + }, + { + txid: '9e8eb9b3d2e8e4b5d6af4c43a9196dfc55a05945c8675904d8c61f404ea7b1e9', + vout: 0, + value: '142771322208', + height: 2644885, + confirmations: 3205, + }, ]; ``` @@ -606,7 +689,7 @@ Returns information about block with transactions, subject to paging. GET /api/v2/block/ ``` -Response: +Response (`Block` type): ```javascript { @@ -735,9 +818,9 @@ GET /api/v2/tickers-list/?timestamp= The query parameters: -- _timestamp_: specifies a Unix timestamp to return available tickers for. +- _timestamp_: specifies a Unix timestamp to return available tickers for. -Example response: +Example response (`AvailableVsCurrencies` type): ```javascript { @@ -760,10 +843,10 @@ GET /api/v2/tickers/[?currency=×tamp=] The optional query parameters: -- _currency_: specifies a currency of returned rate ("usd", "eur", "eth"...). If not specified, all available currencies will be returned. -- _timestamp_: a Unix timestamp that specifies a date to return currency rates for. If not specified, the last available rate will be returned. +- _currency_: specifies a currency of returned rate ("usd", "eur", "eth"...). If not specified, all available currencies will be returned. +- _timestamp_: a Unix timestamp that specifies a date to return currency rates for. If not specified, the last available rate will be returned. -Example response (no parameters): +Example response (no parameters, `FiatTicker` type): ```javascript { @@ -807,15 +890,15 @@ GET /api/v2/balancehistory/?from=&to=[&fiatcur Query parameters: -- _from_: specifies a start date as a Unix timestamp -- _to_: specifies an end date as a Unix timestamp +- _from_: specifies a start date as a Unix timestamp +- _to_: specifies an end date as a Unix timestamp The optional query parameters: -- _fiatcurrency_: if specified, the response will contain secondary (fiat) rate at the time of transaction. If not, all available currencies will be returned. -- _groupBy_: an interval in seconds, to group results by. Default is 3600 seconds. +- _fiatcurrency_: if specified, the response will contain secondary (fiat) rate at the time of transaction. If not, all available currencies will be returned. +- _groupBy_: an interval in seconds, to group results by. Default is 3600 seconds. -Example response (_fiatcurrency_ not specified): +Example response (_fiatcurrency_ not specified, `BalanceHistory[]` type): ```javascript [ @@ -850,26 +933,26 @@ Example response (fiatcurrency=usd): ```javascript [ - { - time: 1578391200, - txs: 5, - received: "5000000", - sent: "0", - sentToSelf: "0", - rates: { - usd: 7855.9, + { + time: 1578391200, + txs: 5, + received: '5000000', + sent: '0', + sentToSelf: '0', + rates: { + usd: 7855.9, + }, }, - }, - { - time: 1578488400, - txs: 1, - received: "0", - sent: "5000000", - sentToSelf: "0", - rates: { - usd: 8283.11, + { + time: 1578488400, + txs: 1, + received: '0', + sent: '5000000', + sentToSelf: '0', + rates: { + usd: 8283.11, + }, }, - }, ]; ``` @@ -877,16 +960,16 @@ Example response (fiatcurrency=usd&groupBy=172800): ```javascript [ - { - time: 1578355200, - txs: 6, - received: "5000000", - sent: "5000000", - sentToSelf: "0", - rates: { - usd: 7734.45, + { + time: 1578355200, + txs: 6, + received: '5000000', + sent: '5000000', + sentToSelf: '0', + rates: { + usd: 7734.45, + }, }, - }, ]; ``` @@ -898,28 +981,28 @@ Websocket interface is provided at `/websocket/`. The interface can be explored The websocket interface provides the following requests: -- getInfo -- getBlockHash -- getAccountInfo -- getAccountUtxo -- getTransaction -- getTransactionSpecific -- getBalanceHistory -- getCurrentFiatRates -- getFiatRatesTickersList -- getFiatRatesForTimestamps -- getMempoolFilters -- getBlockFilter -- estimateFee -- sendTransaction -- ping +- getInfo +- getBlockHash +- getAccountInfo +- getAccountUtxo +- getTransaction +- getTransactionSpecific +- getBalanceHistory +- getCurrentFiatRates +- getFiatRatesTickersList +- getFiatRatesForTimestamps +- getMempoolFilters +- getBlockFilter +- estimateFee +- sendTransaction +- ping The client can subscribe to the following events: -- `subscribeNewBlock` - new block added to blockchain -- `subscribeNewTransaction` - new transaction added to blockchain (all addresses) -- `subscribeAddresses` - new transaction for a given address (list of addresses) added to mempool -- `subscribeFiatRates` - new currency rate ticker +- `subscribeNewBlock` - new block added to blockchain +- `subscribeNewTransaction` - new transaction added to blockchain (all addresses) +- `subscribeAddresses` - new transaction for a given address (list of addresses) added to mempool +- `subscribeFiatRates` - new currency rate ticker There can be always only one subscription of given event per connection, i.e. new list of addresses replaces previous list of addresses. @@ -927,7 +1010,7 @@ The subscribeNewTransaction event is not enabled by default. To enable support, _Note: If there is reorg on the backend (blockchain), you will get a new block hash with the same or even smaller height if the reorg is deeper_ -Websocket communication format +Websocket communication format (`WsReq` type) ```javascript { @@ -951,7 +1034,7 @@ Example for subscribing to an address (or multiple addresses) ## Legacy API V1 -The legacy API is a compatible subset of API provided by **Bitcore Insight**. It is supported only Bitcoin-type coins. The details of the REST/socket.io requests can be found in the Insight's documentation. +The legacy API is a compatible subset of API provided by **Bitcore Insight**. It is supported only for Bitcoin-type coins. The details of the REST/socket.io requests can be found in the Insight's documentation. ### REST API @@ -972,4 +1055,4 @@ Socket.io interface is provided at `/socket.io/`. The interface also can be expl The legacy API is provided as is and will not be further developed. -The legacy API is currently (as of Blockbook v0.4.0) also accessible without the _/v1/_ prefix, however in the future versions the version less access will be removed. +The legacy API is currently (as of Blockbook v0.4.0) also accessible without the _/v1/_ prefix, however in the future versions the version-less access will be removed. diff --git a/docs/env.md b/docs/env.md new file mode 100644 index 00000000..8d95dc98 --- /dev/null +++ b/docs/env.md @@ -0,0 +1,11 @@ +# Environment variables + +Some behavior of Blockbook can be modified by environment variables. The variables usually start with a coin shortcut to allow to run multiple Blockbooks on a single server. + +- `_WS_GETACCOUNTINFO_LIMIT` - Limits the number of `getAccountInfo` requests per websocket connection to reduce server abuse. Accepts number as input. + +- `_STAKING_POOL_CONTRACT` - The pool name and contract used for Ethereum staking. The format of the variable is `/`. If missing, staking support is disabled. + +- `COINGECKO_API_KEY` or `_COINGECKO_API_KEY` - API key for making requests to CoinGecko in the paid tier. + +- `_ALLOWED_RPC_CALL_TO` - Addresses to which `rpcCall` websocket requests can be made, as a comma-separated list. If omitted, `rpcCall` is enabled for all addresses. diff --git a/docs/ports.md b/docs/ports.md index 212d4ace..fe51bbb8 100644 --- a/docs/ports.md +++ b/docs/ports.md @@ -1,82 +1,89 @@ # Registry of ports -| coin | blockbook public | blockbook internal | backend rpc | backend service ports (zmq) | -|----------------------------------|------------------|--------------------|-------------|--------------------------------------| -| Ethereum Archive | 9116 | 9016 | 8016 | 38316 p2p, 8116 http, 8516 authrpc | -| Bitcoin | 9130 | 9030 | 8030 | 38330 | -| Bitcoin Cash | 9131 | 9031 | 8031 | 38331 | -| Zcash | 9132 | 9032 | 8032 | 38332 | -| Dash | 9133 | 9033 | 8033 | 38333 | -| Litecoin | 9134 | 9034 | 8034 | 38334 | -| Bitcoin Gold | 9135 | 9035 | 8035 | 38335 | -| Ethereum | 9136 | 9036 | 8036 | 38336 p2p, 8136 http, 8536 authrpc | -| Ethereum Classic | 9137 | 9037 | 8037 | 38337 p2p, 8137 http | -| Dogecoin | 9138 | 9038 | 8038 | 38338 | -| Namecoin | 9139 | 9039 | 8039 | 38339 | -| Vertcoin | 9140 | 9040 | 8040 | 38340 | -| Monacoin | 9141 | 9041 | 8041 | 38341 | -| DigiByte | 9142 | 9042 | 8042 | 38342 | -| Myriad | 9143 | 9043 | 8043 | 38343 | -| GameCredits | 9144 | 9044 | 8044 | 38344 | -| Groestlcoin | 9145 | 9045 | 8045 | 38345 | -| Bitcoin Cash SV | 9146 | 9046 | 8046 | 38346 | -| Liquid | 9147 | 9047 | 8047 | 38347 | -| Fujicoin | 9148 | 9048 | 8048 | 38348 | -| PIVX | 9149 | 9049 | 8049 | 38349 | -| Firo | 9150 | 9050 | 8050 | 38350 | -| Koto | 9151 | 9051 | 8051 | 38351 | -| Bellcoin | 9152 | 9052 | 8052 | 38352 | -| NULS | 9153 | 9053 | 8053 | 38353 | -| Bitcore | 9154 | 9054 | 8054 | 38354 | -| Viacoin | 9155 | 9055 | 8055 | 38355 | -| VIPSTARCOIN | 9156 | 9056 | 8056 | 38356 | -| MonetaryUnit | 9157 | 9057 | 8057 | 38357 | -| Flux | 9158 | 9058 | 8058 | 38358 | -| Ravencoin | 9159 | 9059 | 8059 | 38359 | -| Ritocoin | 9160 | 9060 | 8060 | 38360 | -| Decred | 9161 | 9061 | 8061 | 38361 | -| SnowGem | 9162 | 9062 | 8062 | 38362 | -| BNB Smart Chain | 9164 | 9064 | 8064 | 38364 p2p, 8164 http | -| BNB Smart Chain Archive | 9165 | 9065 | 8065 | 38365 p2p, 8165 http | -| Flo | 9166 | 9066 | 8066 | 38366 | -| Polis | 9167 | 9067 | 8067 | 38367 | -| Polygon | 9170 | 9070 | 8070 | 38370 p2p, 8170 http | -| Polygon Archive | 9172 | 9072 | 8072 | 38372 p2p, 8172 http | -| Qtum | 9188 | 9088 | 8088 | 38388 | -| Divi Project | 9189 | 9089 | 8089 | 38389 | -| CPUchain | 9190 | 9090 | 8090 | 38390 | -| DeepOnion | 9191 | 9091 | 8091 | 38391 | -| Unobtanium | 9192 | 9092 | 65535 | 38392 | -| Omotenashicoin | 9194 | 9094 | 8094 | 38394 | -| BitZeny | 9195 | 9095 | 8095 | 38395 | -| Trezarcoin | 9196 | 9096 | 8096 | 38396 | -| eCash | 9197 | 9097 | 8097 | 38397 | -| Avalanche | 9198 | 9098 | 8098 | 38398 p2p | -| Avalanche Archive | 9199 | 9099 | 8099 | 38399 p2p | -| Ethereum Testnet Holesky | 19116 | 19016 | 18016 | 18116 http, 18516 authrpc, 48316 p2p | -| Bitcoin Signet | 19120 | 19020 | 18020 | 48320 | -| Bitcoin Regtest | 19121 | 19021 | 18021 | 48321 | -| Bitcoin Testnet | 19130 | 19030 | 18030 | 48330 | -| Bitcoin Cash Testnet | 19131 | 19031 | 18031 | 48331 | -| Zcash Testnet | 19132 | 19032 | 18032 | 48332 | -| Dash Testnet | 19133 | 19033 | 18033 | 48333 | -| Litecoin Testnet | 19134 | 19034 | 18034 | 48334 | -| Bitcoin Gold Testnet | 19135 | 19035 | 18035 | 48335 | -| Ethereum Testnet Holesky Archive | 19136 | 19036 | 18036 | 18136 http, 18536 authrpc, 48336 p2p | -| Dogecoin Testnet | 19138 | 19038 | 18038 | 48338 | -| Vertcoin Testnet | 19140 | 19040 | 18040 | 48340 | -| Monacoin Testnet | 19141 | 19041 | 18041 | 48341 | -| DigiByte Testnet | 19142 | 19042 | 18042 | 48342 | -| Groestlcoin Testnet | 19145 | 19045 | 18045 | 48345 | -| Groestlcoin Regtest | 19146 | 19046 | 18046 | 48346 | -| Groestlcoin Signet | 19147 | 19047 | 18047 | 48347 | -| PIVX Testnet | 19149 | 19049 | 18049 | 48349 | -| Koto Testnet | 19151 | 19051 | 18051 | 48351 | -| Decred Testnet | 19161 | 19061 | 18061 | 48361 | -| Flo Testnet | 19166 | 19066 | 18066 | 48366 | -| Ethereum Testnet Sepolia | 19176 | 19076 | 18076 | 18176 http, 18576 authrpc, 48376 p2p | -| Ethereum Testnet Sepolia Archive | 19186 | 19086 | 18086 | 18186 http, 18586 authrpc, 48386 p2p | -| Qtum Testnet | 19188 | 19088 | 18088 | 48388 | -| Omotenashicoin Testnet | 19189 | 19089 | 18089 | 48389 | +| coin | blockbook public | blockbook internal | backend rpc | backend service ports (zmq) | +| -------------------------------- | ---------------- | ------------------ | ----------- | --------------------------------------------------- | +| Ethereum Archive | 9116 | 9016 | 8016 | 38316 p2p, 8116 http, 8516 authrpc | +| Bitcoin | 9130 | 9030 | 8030 | 38330 | +| Bitcoin Cash | 9131 | 9031 | 8031 | 38331 | +| Zcash | 9132 | 9032 | 8032 | 38332 | +| Dash | 9133 | 9033 | 8033 | 38333 | +| Litecoin | 9134 | 9034 | 8034 | 38334 | +| Bitcoin Gold | 9135 | 9035 | 8035 | 38335 | +| Ethereum | 9136 | 9036 | 8036 | 38336 p2p, 8136 http, 8536 authrpc | +| Ethereum Classic | 9137 | 9037 | 8037 | 38337 p2p, 8137 http | +| Dogecoin | 9138 | 9038 | 8038 | 38338 | +| Namecoin | 9139 | 9039 | 8039 | 38339 | +| Vertcoin | 9140 | 9040 | 8040 | 38340 | +| Monacoin | 9141 | 9041 | 8041 | 38341 | +| DigiByte | 9142 | 9042 | 8042 | 38342 | +| Myriad | 9143 | 9043 | 8043 | 38343 | +| GameCredits | 9144 | 9044 | 8044 | 38344 | +| Groestlcoin | 9145 | 9045 | 8045 | 38345 | +| Bitcoin Cash SV | 9146 | 9046 | 8046 | 38346 | +| Liquid | 9147 | 9047 | 8047 | 38347 | +| Fujicoin | 9148 | 9048 | 8048 | 38348 | +| PIVX | 9149 | 9049 | 8049 | 38349 | +| Firo | 9150 | 9050 | 8050 | 38350 | +| Koto | 9151 | 9051 | 8051 | 38351 | +| Bellcoin | 9152 | 9052 | 8052 | 38352 | +| NULS | 9153 | 9053 | 8053 | 38353 | +| Bitcore | 9154 | 9054 | 8054 | 38354 | +| Viacoin | 9155 | 9055 | 8055 | 38355 | +| VIPSTARCOIN | 9156 | 9056 | 8056 | 38356 | +| MonetaryUnit | 9157 | 9057 | 8057 | 38357 | +| Flux | 9158 | 9058 | 8058 | 38358 | +| Ravencoin | 9159 | 9059 | 8059 | 38359 | +| Ritocoin | 9160 | 9060 | 8060 | 38360 | +| Decred | 9161 | 9061 | 8061 | 38361 | +| SnowGem | 9162 | 9062 | 8062 | 38362 | +| BNB Smart Chain | 9164 | 9064 | 8064 | 38364 p2p, 8164 http | +| BNB Smart Chain Archive | 9165 | 9065 | 8065 | 38365 p2p, 8165 http | +| Flo | 9166 | 9066 | 8066 | 38366 | +| Polis | 9167 | 9067 | 8067 | 38367 | +| Polygon | 9170 | 9070 | 8070 | 38370 p2p, 8170 http | +| Polygon Archive | 9172 | 9072 | 8072 | 38372 p2p, 8172 http | +| Qtum | 9188 | 9088 | 8088 | 38388 | +| Divi Project | 9189 | 9089 | 8089 | 38389 | +| CPUchain | 9190 | 9090 | 8090 | 38390 | +| DeepOnion | 9191 | 9091 | 8091 | 38391 | +| Unobtanium | 9192 | 9092 | 65535 | 38392 | +| Omotenashicoin | 9194 | 9094 | 8094 | 38394 | +| BitZeny | 9195 | 9095 | 8095 | 38395 | +| Trezarcoin | 9196 | 9096 | 8096 | 38396 | +| eCash | 9197 | 9097 | 8097 | 38397 | +| Avalanche | 9198 | 9098 | 8098 | 38398 p2p | +| Avalanche Archive | 9199 | 9099 | 8099 | 38399 p2p | +| Optimism | 9300 | 9200 | 8200 | 38400 p2p, 8300 http, 8400 authrpc | +| Optimism Archive | 9302 | 9202 | 8202 | 38402 p2p, 8302 http, 8402 authrpc | +| Arbitrum | 9305 | 9205 | 8205 | 38405 p2p, 8305 http | +| Arbitrum Archive | 9306 | 9206 | 8306 | 38406 p2p | +| Arbitrum Nova | 9307 | 9207 | 8207 | 38407 p2p, 8307 http | +| Arbitrum Nova Archive | 9308 | 9208 | 8308 | 38408 p2p | +| Ethereum Testnet Holesky | 19116 | 19016 | 18016 | 18116 http, 18516 authrpc, 48316 p2p | +| Bitcoin Signet | 19120 | 19020 | 18020 | 48320 | +| Bitcoin Regtest | 19121 | 19021 | 18021 | 48321 | +| Bitcoin Testnet4 | 19129 | 19029 | 18029 | 48329 | +| Bitcoin Testnet | 19130 | 19030 | 18030 | 48330 | +| Bitcoin Cash Testnet | 19131 | 19031 | 18031 | 48331 | +| Zcash Testnet | 19132 | 19032 | 18032 | 48332 | +| Dash Testnet | 19133 | 19033 | 18033 | 48333 | +| Litecoin Testnet | 19134 | 19034 | 18034 | 48334 | +| Bitcoin Gold Testnet | 19135 | 19035 | 18035 | 48335 | +| Ethereum Testnet Holesky Archive | 19136 | 19036 | 18036 | 18136 http, 18136 torrent, 18536 authrpc, 48336 p2p | +| Dogecoin Testnet | 19138 | 19038 | 18038 | 48338 | +| Vertcoin Testnet | 19140 | 19040 | 18040 | 48340 | +| Monacoin Testnet | 19141 | 19041 | 18041 | 48341 | +| DigiByte Testnet | 19142 | 19042 | 18042 | 48342 | +| Groestlcoin Testnet | 19145 | 19045 | 18045 | 48345 | +| Groestlcoin Regtest | 19146 | 19046 | 18046 | 48346 | +| Groestlcoin Signet | 19147 | 19047 | 18047 | 48347 | +| PIVX Testnet | 19149 | 19049 | 18049 | 48349 | +| Koto Testnet | 19151 | 19051 | 18051 | 48351 | +| Decred Testnet | 19161 | 19061 | 18061 | 48361 | +| Flo Testnet | 19166 | 19066 | 18066 | 48366 | +| Ethereum Testnet Sepolia | 19176 | 19076 | 18076 | 18176 http, 18576 authrpc, 48376 p2p | +| Ethereum Testnet Sepolia Archive | 19186 | 19086 | 18086 | 18186 http, 18186 torrent, 18586 authrpc, 48386 p2p | +| Qtum Testnet | 19188 | 19088 | 18088 | 48388 | +| Omotenashicoin Testnet | 19189 | 19089 | 18089 | 48389 | > NOTE: This document is generated from coin definitions in `configs/coins` using command `go run contrib/scripts/check-and-generate-port-registry.go -w`. diff --git a/fiat/coingecko.go b/fiat/coingecko.go index b7e89708..68c7722c 100644 --- a/fiat/coingecko.go +++ b/fiat/coingecko.go @@ -59,7 +59,7 @@ type marketChartPrices struct { } // NewCoinGeckoDownloader creates a coingecko structure that implements the RatesDownloaderInterface -func NewCoinGeckoDownloader(db *db.RocksDB, coinShortcut string, url string, coin string, platformIdentifier string, platformVsCurrency string, allowedVsCurrencies string, timeFormat string, metrics *common.Metrics, throttleDown bool) RatesDownloaderInterface { +func NewCoinGeckoDownloader(db *db.RocksDB, network string, url string, coin string, platformIdentifier string, platformVsCurrency string, allowedVsCurrencies string, timeFormat string, metrics *common.Metrics, throttleDown bool) RatesDownloaderInterface { throttlingDelayMs := 0 // No delay by default if throttleDown { throttlingDelayMs = DefaultThrottleDelayMs @@ -67,7 +67,7 @@ func NewCoinGeckoDownloader(db *db.RocksDB, coinShortcut string, url string, coi allowedVsCurrenciesMap := getAllowedVsCurrenciesMap(allowedVsCurrencies) - apiKey := os.Getenv(strings.ToUpper(coinShortcut) + "_COINGECKO_API_KEY") + apiKey := os.Getenv(strings.ToUpper(network) + "_COINGECKO_API_KEY") if apiKey == "" { apiKey = os.Getenv("COINGECKO_API_KEY") } diff --git a/fiat/fiat_rates.go b/fiat/fiat_rates.go index a9a37979..d6ead4bb 100644 --- a/fiat/fiat_rates.go +++ b/fiat/fiat_rates.go @@ -108,7 +108,7 @@ func NewFiatRates(db *db.RocksDB, config *common.Config, metrics *common.Metrics // a small hack - in tests the callback is not used, therefore there is no delay slowing down the test throttle = false } - fr.downloader = NewCoinGeckoDownloader(db, db.GetInternalState().CoinShortcut, rdParams.URL, rdParams.Coin, rdParams.PlatformIdentifier, rdParams.PlatformVsCurrency, fr.allowedVsCurrencies, fr.timeFormat, metrics, throttle) + fr.downloader = NewCoinGeckoDownloader(db, db.GetInternalState().GetNetwork(), rdParams.URL, rdParams.Coin, rdParams.PlatformIdentifier, rdParams.PlatformVsCurrency, fr.allowedVsCurrencies, fr.timeFormat, metrics, throttle) if is != nil { is.HasFiatRates = true is.HasTokenFiatRates = fr.downloadTokens @@ -419,8 +419,8 @@ func (fr *FiatRates) RunDownloader() error { } } - // load hourly tickers, give about 30 minutes to prepare the tickers - if time.Now().UTC().Unix() >= fr.hourlyTickersTo+secondsInHour+secondsInHour/2 { + // load hourly tickers, it is necessary to wait about 1 hour to prepare the tickers + if time.Now().UTC().Unix() >= fr.hourlyTickersTo+secondsInHour+secondsInHour { hourlyTickers, err := fr.downloader.HourlyTickers() if err != nil || hourlyTickers == nil { glog.Error("FiatRatesDownloader: HourlyTickers error ", err) @@ -430,8 +430,8 @@ func (fr *FiatRates) RunDownloader() error { } } - // load five minute tickers, give about 5 minutes to prepare the tickers - if time.Now().UTC().Unix() >= fr.fiveMinutesTickersTo+2*secondsInFiveMinutes { + // load five minute tickers, it is necessary to wait about 10 minutes to prepare the tickers + if time.Now().UTC().Unix() >= fr.fiveMinutesTickersTo+3*secondsInFiveMinutes { fiveMinutesTickers, err := fr.downloader.FiveMinutesTickers() if err != nil || fiveMinutesTickers == nil { glog.Error("FiatRatesDownloader: FiveMinutesTickers error ", err) diff --git a/server/html_templates.go b/server/html_templates.go index a06ff0e6..470134c1 100644 --- a/server/html_templates.go +++ b/server/html_templates.go @@ -35,6 +35,66 @@ type htmlTemplates[TD any] struct { postHtmlTemplateHandler func(data *TD, w http.ResponseWriter, r *http.Request) } +func (s *htmlTemplates[TD]) jsonHandler(handler func(r *http.Request, apiVersion int) (interface{}, error), apiVersion int) func(w http.ResponseWriter, r *http.Request) { + type jsonError struct { + Text string `json:"error"` + HTTPStatus int `json:"-"` + } + handlerName := getFunctionName(handler) + return func(w http.ResponseWriter, r *http.Request) { + var data interface{} + var err error + defer func() { + if e := recover(); e != nil { + glog.Error(handlerName, " recovered from panic: ", e) + debug.PrintStack() + if s.debug { + data = jsonError{fmt.Sprint("Internal server error: recovered from panic ", e), http.StatusInternalServerError} + } else { + data = jsonError{"Internal server error", http.StatusInternalServerError} + } + } + w.Header().Set("Content-Type", "application/json; charset=utf-8") + if e, isError := data.(jsonError); isError { + w.WriteHeader(e.HTTPStatus) + } + err = json.NewEncoder(w).Encode(data) + if err != nil { + glog.Warning("json encode ", err) + } + if s.metrics != nil { + s.metrics.ExplorerPendingRequests.With((common.Labels{"method": handlerName})).Dec() + } + }() + if s.metrics != nil { + s.metrics.ExplorerPendingRequests.With((common.Labels{"method": handlerName})).Inc() + } + data, err = handler(r, apiVersion) + if err != nil || data == nil { + if apiErr, ok := err.(*api.APIError); ok { + if apiErr.Public { + data = jsonError{apiErr.Error(), http.StatusBadRequest} + } else { + data = jsonError{apiErr.Error(), http.StatusInternalServerError} + } + } else { + if err != nil { + glog.Error(handlerName, " error: ", err) + } + if s.debug { + if data != nil { + data = jsonError{fmt.Sprintf("Internal server error: %v, data %+v", err, data), http.StatusInternalServerError} + } else { + data = jsonError{fmt.Sprintf("Internal server error: %v", err), http.StatusInternalServerError} + } + } else { + data = jsonError{"Internal server error", http.StatusInternalServerError} + } + } + } + } +} + func (s *htmlTemplates[TD]) htmlTemplateHandler(handler func(w http.ResponseWriter, r *http.Request) (tpl, *TD, error)) func(w http.ResponseWriter, r *http.Request) { handlerName := getFunctionName(handler) return func(w http.ResponseWriter, r *http.Request) { diff --git a/server/internal.go b/server/internal.go index 3560f0fa..2544c05b 100644 --- a/server/internal.go +++ b/server/internal.go @@ -5,11 +5,15 @@ import ( "encoding/json" "fmt" "html/template" + "io" "net/http" "path/filepath" "sort" + "strconv" + "strings" "github.com/golang/glog" + "github.com/juju/errors" "github.com/prometheus/client_golang/prometheus/promhttp" "github.com/trezor/blockbook/api" "github.com/trezor/blockbook/bchain" @@ -72,6 +76,8 @@ func NewInternalServer(binding, certFiles string, db *db.RocksDB, chain bchain.B serveMux.HandleFunc(path+"admin/ws-limit-exceeding-ips", s.htmlTemplateHandler(s.wsLimitExceedingIPs)) if s.chainParser.GetChainType() == bchain.ChainEthereumType { serveMux.HandleFunc(path+"admin/internal-data-errors", s.htmlTemplateHandler(s.internalDataErrors)) + serveMux.HandleFunc(path+"admin/contract-info", s.htmlTemplateHandler(s.contractInfoPage)) + serveMux.HandleFunc(path+"admin/contract-info/", s.jsonHandler(s.apiContractInfo, 0)) } return s, nil } @@ -118,7 +124,8 @@ func (s *InternalServer) index(w http.ResponseWriter, r *http.Request) { const ( adminIndexTpl = iota + errorInternalTpl + 1 adminInternalErrorsTpl - adminLimitExceedingIPS + adminLimitExceedingIPSTpl + adminContractInfoTpl internalTplCount ) @@ -173,7 +180,8 @@ func (s *InternalServer) parseTemplates() []*template.Template { t[errorInternalTpl] = createTemplate("./static/internal_templates/error.html", "./static/internal_templates/base.html") t[adminIndexTpl] = createTemplate("./static/internal_templates/index.html", "./static/internal_templates/base.html") t[adminInternalErrorsTpl] = createTemplate("./static/internal_templates/block_internal_data_errors.html", "./static/internal_templates/base.html") - t[adminLimitExceedingIPS] = createTemplate("./static/internal_templates/ws_limit_exceeding_ips.html", "./static/internal_templates/base.html") + t[adminLimitExceedingIPSTpl] = createTemplate("./static/internal_templates/ws_limit_exceeding_ips.html", "./static/internal_templates/base.html") + t[adminContractInfoTpl] = createTemplate("./static/internal_templates/contract_info.html", "./static/internal_templates/base.html") return t } @@ -213,5 +221,54 @@ func (s *InternalServer) wsLimitExceedingIPs(w http.ResponseWriter, r *http.Requ }) data.WsLimitExceedingIPs = ips data.WsGetAccountInfoLimit = s.is.WsGetAccountInfoLimit - return adminLimitExceedingIPS, data, nil + return adminLimitExceedingIPSTpl, data, nil +} + +func (s *InternalServer) contractInfoPage(w http.ResponseWriter, r *http.Request) (tpl, *InternalTemplateData, error) { + data := s.newTemplateData(r) + return adminContractInfoTpl, data, nil +} + +func (s *InternalServer) apiContractInfo(r *http.Request, apiVersion int) (interface{}, error) { + if r.Method == http.MethodPost { + return s.updateContracts(r) + } + var contractAddress string + i := strings.LastIndexByte(r.URL.Path, '/') + if i > 0 { + contractAddress = r.URL.Path[i+1:] + } + if len(contractAddress) == 0 { + return nil, api.NewAPIError("Missing contract address", true) + } + + contractInfo, valid, err := s.api.GetContractInfo(contractAddress, bchain.UnknownTokenType) + if err != nil { + return nil, api.NewAPIError(err.Error(), true) + } + if !valid { + return nil, api.NewAPIError("Not a contract", true) + } + return contractInfo, nil +} + +func (s *InternalServer) updateContracts(r *http.Request) (interface{}, error) { + data, err := io.ReadAll(r.Body) + if err != nil { + return nil, api.NewAPIError("Cannot get request body", true) + } + var contractInfos []bchain.ContractInfo + err = json.Unmarshal(data, &contractInfos) + if err != nil { + return nil, errors.Annotatef(err, "Cannot unmarshal body to array of ContractInfo objects") + } + for i := range contractInfos { + c := &contractInfos[i] + err := s.db.StoreContractInfo(c) + if err != nil { + return nil, api.NewAPIError("Error updating contract "+c.Contract+" "+err.Error(), true) + } + + } + return "{\"success\":\"Updated " + strconv.Itoa(len(contractInfos)) + " contracts\"}", nil } diff --git a/server/public.go b/server/public.go index 55286b59..6baca22a 100644 --- a/server/public.go +++ b/server/public.go @@ -14,7 +14,6 @@ import ( "reflect" "regexp" "runtime" - "runtime/debug" "sort" "strconv" "strings" @@ -188,6 +187,7 @@ func (s *PublicServer) ConnectFullPublicInterface() { serveMux.HandleFunc(path+"api/block-filters/", s.jsonHandler(s.apiBlockFilters, apiDefault)) serveMux.HandleFunc(path+"api/tx-specific/", s.jsonHandler(s.apiTxSpecific, apiDefault)) serveMux.HandleFunc(path+"api/tx/", s.jsonHandler(s.apiTx, apiDefault)) + serveMux.HandleFunc(path+"api/rawtx/", s.jsonHandler(s.apiRawTx, apiDefault)) serveMux.HandleFunc(path+"api/address/", s.jsonHandler(s.apiAddress, apiDefault)) serveMux.HandleFunc(path+"api/xpub/", s.jsonHandler(s.apiXpub, apiDefault)) serveMux.HandleFunc(path+"api/utxo/", s.jsonHandler(s.apiUtxo, apiDefault)) @@ -290,63 +290,6 @@ func getFunctionName(i interface{}) string { return name } -func (s *PublicServer) jsonHandler(handler func(r *http.Request, apiVersion int) (interface{}, error), apiVersion int) func(w http.ResponseWriter, r *http.Request) { - type jsonError struct { - Text string `json:"error"` - HTTPStatus int `json:"-"` - } - handlerName := getFunctionName(handler) - return func(w http.ResponseWriter, r *http.Request) { - var data interface{} - var err error - defer func() { - if e := recover(); e != nil { - glog.Error(handlerName, " recovered from panic: ", e) - debug.PrintStack() - if s.debug { - data = jsonError{fmt.Sprint("Internal server error: recovered from panic ", e), http.StatusInternalServerError} - } else { - data = jsonError{"Internal server error", http.StatusInternalServerError} - } - } - w.Header().Set("Access-Control-Allow-Origin", "*") - w.Header().Set("Content-Type", "application/json; charset=utf-8") - if e, isError := data.(jsonError); isError { - w.WriteHeader(e.HTTPStatus) - } - err = json.NewEncoder(w).Encode(data) - if err != nil { - glog.Warning("json encode ", err) - } - s.metrics.ExplorerPendingRequests.With((common.Labels{"method": handlerName})).Dec() - }() - s.metrics.ExplorerPendingRequests.With((common.Labels{"method": handlerName})).Inc() - data, err = handler(r, apiVersion) - if err != nil || data == nil { - if apiErr, ok := err.(*api.APIError); ok { - if apiErr.Public { - data = jsonError{apiErr.Error(), http.StatusBadRequest} - } else { - data = jsonError{apiErr.Error(), http.StatusInternalServerError} - } - } else { - if err != nil { - glog.Error(handlerName, " error: ", err) - } - if s.debug { - if data != nil { - data = jsonError{fmt.Sprintf("Internal server error: %v, data %+v", err, data), http.StatusInternalServerError} - } else { - data = jsonError{fmt.Sprintf("Internal server error: %v", err), http.StatusInternalServerError} - } - } else { - data = jsonError{"Internal server error", http.StatusInternalServerError} - } - } - } - } -} - func (s *PublicServer) newTemplateData(r *http.Request) *TemplateData { t := &TemplateData{ CoinName: s.is.Coin, @@ -362,7 +305,7 @@ func (s *PublicServer) newTemplateData(r *http.Request) *TemplateData { t.MultiTokenName = bchain.EthereumTokenTypeMap[bchain.MultiToken] } if !s.debug { - t.Minified = ".min.3" + t.Minified = ".min.4" } if s.is.HasFiatRates { // get the secondary coin and if it should be shown either from query parameters "secondary" and "use_secondary" @@ -1347,6 +1290,19 @@ func (s *PublicServer) apiTx(r *http.Request, apiVersion int) (interface{}, erro return tx, err } +func (s *PublicServer) apiRawTx(r *http.Request, apiVersion int) (interface{}, error) { + var txid string + i := strings.LastIndexByte(r.URL.Path, '/') + if i > 0 { + txid = r.URL.Path[i+1:] + } + if len(txid) == 0 { + return "", api.NewAPIError("Missing txid", true) + } + s.metrics.ExplorerViews.With(common.Labels{"action": "api-raw-tx"}).Inc() + return s.api.GetRawTransaction(txid) +} + func (s *PublicServer) apiTxSpecific(r *http.Request, apiVersion int) (interface{}, error) { var txid string i := strings.LastIndexByte(r.URL.Path, '/') diff --git a/server/public_ethereumtype_test.go b/server/public_ethereumtype_test.go new file mode 100644 index 00000000..a0714f47 --- /dev/null +++ b/server/public_ethereumtype_test.go @@ -0,0 +1,263 @@ +//go:build unittest +// +build unittest + +package server + +import ( + "net/http" + "net/http/httptest" + "testing" + "time" + + "github.com/golang/glog" + "github.com/linxGnu/grocksdb" + "github.com/trezor/blockbook/bchain" + "github.com/trezor/blockbook/bchain/coins/eth" + "github.com/trezor/blockbook/common" + "github.com/trezor/blockbook/db" + "github.com/trezor/blockbook/tests/dbtestdata" +) + +func httpTestsEthereumType(t *testing.T, ts *httptest.Server) { + tests := []httpTests{ + { + name: "explorerAddress " + dbtestdata.EthAddr7b, + r: newGetRequest(ts.URL + "/address/" + dbtestdata.EthAddr7b), + status: http.StatusOK, + contentType: "text/html; charset=utf-8", + body: []string{ + `Trezor Fake Coin Explorer

Address address7b.eth

0x7B62EB7fe80350DC7EC945C0B73242cb9877FB1b

0.000000000123450123 FAKE
0.00 USD

Confirmed
Balance0.000000000123450123 FAKE0.00 USD
Transactions2
Non-contract Transactions0
Internal Transactions0
Nonce123
ContractQuantityValueTransfers#
Contract 130.000000001000123013 S13-1
Contract 740.001000123074 S74-1
ContractTokensTransfers#
Contract 20511

Transactions

ERC721 Token Transfers
ERC20 Token Transfers
address7b.eth
 
871.180000950184 S74-
 
address7b.eth
7.674999999999991915 S13-
`, + }, + }, + { + name: "explorerAddress " + dbtestdata.EthAddr5d, + r: newGetRequest(ts.URL + "/address/" + dbtestdata.EthAddr5d), + status: http.StatusOK, + contentType: "text/html; charset=utf-8", + body: []string{ + `Trezor Fake Coin Explorer

Address

0x5Dc6288b35E0807A3d6fEB89b3a2Ff4aB773168e

0.000000000123450093 FAKE
0.00 USD

Confirmed
Balance0.000000000123450093 FAKE0.00 USD
Transactions1
Non-contract Transactions1
Internal Transactions0
Nonce93
ContractTokensTransfers#
Contract 1111 S111 of ID 1776, 10 S111 of ID 18981

Transactions

0x5Dc6288b35E0807A3d6fEB89b3a2Ff4aB773168e
 
0 FAKE0.00 USD0.00 USD
ERC1155 Token Transfers
 
0x5Dc6288b35E0807A3d6fEB89b3a2Ff4aB773168e
1 S111 of ID 1776, 10 S111 of ID 1898
`, + }, + }, + { + name: "explorerTx " + dbtestdata.EthTxidB1T2, + r: newGetRequest(ts.URL + "/tx/0x" + dbtestdata.EthTxidB1T2), + status: http.StatusOK, + contentType: "text/html; charset=utf-8", + body: []string{ + `Trezor Fake Coin Explorer

Transaction

0xa9cd088aba2131000da6f38a33c20169baee476218deea6b78720700b895b101
In BlockUnconfirmed
StatusSuccess
Value0 FAKE0.00 USD0.00 USD
Gas Used / Limit52025 / 78037
Gas Price0.00000004 FAKE0.00 USD0.00 USD (40 Gwei)
Fees0.002081 FAKE4.16 USD18.55 USD
RBFON
Nonce208
 
0 FAKE0.00 USD0.00 USD
ERC20 Token Transfers
Input Data

0xa9059cbb000000000000000000000000555ee11fbddc0e49a9bab358a8941ad95ffdb48f00000000000000000000000000000000000000000000021e19e0c9bab2400000
transfer(address, uint256)
#TypeData
0address0x555Ee11FBDDc0E49A9bAB358A8941AD95fFDB48f
1uint25610000000000000000000000
`, + }, + }, { + name: "explorerTokenDetail " + dbtestdata.EthAddr7b, + r: newGetRequest(ts.URL + "/nft/" + dbtestdata.EthAddrContractCd + "/" + "1"), + status: http.StatusOK, + contentType: "text/html; charset=utf-8", + body: []string{`Trezor Fake Coin Explorer

NFT Token Detail

Token ID1
Contract0xcdA9FC258358EcaA88845f19Af595e908bb7EfE9
Contract 205
Contract typeERC20
`}, + }, + { + name: "apiIndex", + r: newGetRequest(ts.URL + "/api"), + status: http.StatusOK, + contentType: "application/json; charset=utf-8", + body: []string{ + `{"blockbook":{"coin":"Fakecoin"`, + `"bestHeight":4321001`, + `"decimals":18`, + `"backend":{"chain":"fakecoin","blocks":2,"headers":2,"bestBlockHash":"0x2b57e15e93a0ed197417a34c2498b7187df79099572c04a6b6e6ff418f74e6ee"`, + `"version":"001001","subversion":"/Fakecoin:0.0.1/"`, + }, + }, + { + name: "apiAddress EthAddr4b", + r: newGetRequest(ts.URL + "/api/v2/address/" + dbtestdata.EthAddr4b), + status: http.StatusOK, + contentType: "application/json; charset=utf-8", + body: []string{ + `{"page":1,"totalPages":1,"itemsOnPage":1000,"address":"0x4Bda106325C335dF99eab7fE363cAC8A0ba2a24D","balance":"123450075","unconfirmedBalance":"0","unconfirmedTxs":0,"txs":1,"nonTokenTxs":1,"internalTxs":1,"txids":["0xc92919ad24ffd58f760b18df7949f06e1190cf54a50a0e3745a385608ed3cbf2"],"nonce":"75","tokens":[{"type":"ERC20","name":"Contract 13","contract":"0x0d0F936Ee4c93e25944694D6C121de94D9760F11","transfers":2,"symbol":"S13","decimals":18,"balance":"1000075013"},{"type":"ERC20","name":"Contract 74","contract":"0x4af4114F73d1c1C903aC9E0361b379D1291808A2","transfers":2,"symbol":"S74","decimals":12,"balance":"1000075074"}]}`, + }, + }, + { + name: "apiAddress EthAddr7b details=txs", + r: newGetRequest(ts.URL + "/api/v2/address/" + dbtestdata.EthAddr7b + "?details=txs"), + status: http.StatusOK, + contentType: "application/json; charset=utf-8", + body: []string{ + `{"page":1,"totalPages":1,"itemsOnPage":1000,"address":"0x7B62EB7fe80350DC7EC945C0B73242cb9877FB1b","balance":"123450123","unconfirmedBalance":"0","unconfirmedTxs":0,"txs":2,"transactions":[{"txid":"0xca7628be5c80cda77163729ec63d218ee868a399d827a4682a478c6f48a6e22a","vin":[{"n":0,"addresses":["0x837E3f699d85a4b0B99894567e9233dFB1DcB081"],"isAddress":true}],"vout":[{"value":"0","n":0,"addresses":["0xcdA9FC258358EcaA88845f19Af595e908bb7EfE9"],"isAddress":true}],"blockHeight":-1,"confirmations":0,"blockTime":0,"value":"0","fees":"87945000410410","rbf":true,"coinSpecificData":{"tx":{"nonce":"0x2","gasPrice":"0x59682f07","gas":"0x173a9","to":"0xcdA9FC258358EcaA88845f19Af595e908bb7EfE9","value":"0x0","input":"0x23b872dd000000000000000000000000837e3f699d85a4b0b99894567e9233dfb1dcb0810000000000000000000000007b62eb7fe80350dc7ec945c0b73242cb9877fb1b0000000000000000000000000000000000000000000000000000000000000001","hash":"0xca7628be5c80cda77163729ec63d218ee868a399d827a4682a478c6f48a6e22a","blockNumber":"0xb33b9f","from":"0x837E3f699d85a4b0B99894567e9233dFB1DcB081","transactionIndex":"0x1"},"receipt":{"gasUsed":"0xe506","status":"0x1","logs":[{"address":"0xcdA9FC258358EcaA88845f19Af595e908bb7EfE9","topics":["0x8c5be1e5ebec7d5bd14f71427d1e84f3dd0314c0f7b2291e5b200ac8c7c3b925","0x000000000000000000000000837e3f699d85a4b0b99894567e9233dfb1dcb081","0x0000000000000000000000000000000000000000000000000000000000000000","0x0000000000000000000000000000000000000000000000000000000000000001"],"data":"0x"},{"address":"0xcdA9FC258358EcaA88845f19Af595e908bb7EfE9","topics":["0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef","0x000000000000000000000000837e3f699d85a4b0b99894567e9233dfb1dcb081","0x0000000000000000000000007b62eb7fe80350dc7ec945c0b73242cb9877fb1b","0x0000000000000000000000000000000000000000000000000000000000000001"],"data":"0x"}]}},"tokenTransfers":[{"type":"ERC721","from":"0x837E3f699d85a4b0B99894567e9233dFB1DcB081","to":"0x7B62EB7fe80350DC7EC945C0B73242cb9877FB1b","contract":"0xcdA9FC258358EcaA88845f19Af595e908bb7EfE9","name":"Contract 205","symbol":"S205","decimals":18,"value":"1"}],"ethereumSpecific":{"status":1,"nonce":2,"gasLimit":95145,"gasUsed":58630,"gasPrice":"1500000007","data":"0x23b872dd000000000000000000000000837e3f699d85a4b0b99894567e9233dfb1dcb0810000000000000000000000007b62eb7fe80350dc7ec945c0b73242cb9877fb1b0000000000000000000000000000000000000000000000000000000000000001","parsedData":{"methodId":"0x23b872dd","name":""}}},{"txid":"0xc92919ad24ffd58f760b18df7949f06e1190cf54a50a0e3745a385608ed3cbf2","vin":[{"n":0,"addresses":["0x4Bda106325C335dF99eab7fE363cAC8A0ba2a24D"],"isAddress":true}],"vout":[{"value":"0","n":0,"addresses":["0x479CC461fEcd078F766eCc58533D6F69580CF3AC"],"isAddress":true}],"blockHeight":-1,"confirmations":0,"blockTime":0,"value":"0","fees":"216368000000000","rbf":true,"coinSpecificData":{"tx":{"nonce":"0x1df76","gasPrice":"0x3b9aca00","gas":"0x3d090","to":"0x479CC461fEcd078F766eCc58533D6F69580CF3AC","value":"0x0","input":"0x4f15078700000000000000000000000000000000000000000000000000000000000000c0000000000000000000000000000000000000000000000000000000000000022000000000000000000000000000000000000000000000000000000000000003c00000000000000000000000000000000000000000000000000000000000000420000000000000000000000000000000000000000000000000000000000000048000000000000000000000000000000000000000000000000000000000000004e00000000000000000000000000000000000000000000000000000000000000002000000000000000000000000555ee11fbddc0e49a9bab358a8941ad95ffdb48f0000000000000000000000004bda106325c335df99eab7fe363cac8a0ba2a24d0000000000000000000000000d0f936ee4c93e25944694d6c121de94d9760f110000000000000000000000004af4114f73d1c1c903ac9e0361b379d1291808a200000000000000000000000000000000000000000000000000000000000000000000000000000000000000007b62eb7fe80350dc7ec945c0b73242cb9877fb1b0000000000000000000000004bda106325c335df99eab7fe363cac8a0ba2a24d0000000000000000000000004af4114f73d1c1c903ac9e0361b379d1291808a20000000000000000000000000d0f936ee4c93e25944694d6c121de94d9760f110000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000a5ef5a7656bfb0000000000000000000000000000000000000000000000000000004ba78398d5c5000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000166cfe0b9579b4ecf7a2801880f644009a324671a79754ea57c3a103c6e70d3dbef6ba69a08000000000000000000000000000000000000000000000000004f937d86afb90000000000000000000000000000000000000000000000000ab280fd8037d500000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000166cfb784b7c1f3fbe8b75484603ab8adc58aaee3a46245a6579fac7077b5570018b4e0d4eb0000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000308fd0e798ac00000000000000000000000000000000000000000000000006a8313d60b1f606b0000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000001b000000000000000000000000000000000000000000000000000000000000001b00000000000000000000000000000000000000000000000000000000000000029de0ccec59e8948e3d905b40e5542335ebc1eb4674db517d2f6392ec7fdeb3d45f3449d313ee2589819c6c79eb1c1b047adae68565c1608e3a1d1d70823febb0000000000000000000000000000000000000000000000000000000000000000234d06fe17f1202e8b07177a30eb64d14adc08cdb3fa1b3e3e0bea0f9672c02175b77c01c51d3c7e460723b27ecbc7801fd6482559a8c9999593f9a4d149c7384","hash":"0xc92919ad24ffd58f760b18df7949f06e1190cf54a50a0e3745a385608ed3cbf2","blockNumber":"0x41eee9","from":"0x4Bda106325C335dF99eab7fE363cAC8A0ba2a24D","transactionIndex":"0x24"},"internalData":{"type":1,"contract":"0d0f936ee4c93e25944694d6c121de94d9760f11","transfers":[{"type":0,"from":"4bda106325c335df99eab7fe363cac8a0ba2a24d","to":"9f4981531fda132e83c44680787dfa7ee31e4f8d","value":1000010},{"type":2,"from":"4af4114f73d1c1c903ac9e0361b379d1291808a2","to":"9f4981531fda132e83c44680787dfa7ee31e4f8d","value":1000011}],"Error":""},"receipt":{"gasUsed":"0x34d30","status":"0x1","logs":[{"address":"0x0d0F936Ee4c93e25944694D6C121de94D9760F11","topics":["0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef","0x000000000000000000000000555ee11fbddc0e49a9bab358a8941ad95ffdb48f","0x0000000000000000000000004bda106325c335df99eab7fe363cac8a0ba2a24d"],"data":"0x0000000000000000000000000000000000000000000000006a8313d60b1f8001"},{"address":"0x4af4114F73d1c1C903aC9E0361b379D1291808A2","topics":["0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef","0x0000000000000000000000004bda106325c335df99eab7fe363cac8a0ba2a24d","0x000000000000000000000000555ee11fbddc0e49a9bab358a8941ad95ffdb48f"],"data":"0x000000000000000000000000000000000000000000000000000308fd0e798ac0"},{"address":"0x479CC461fEcd078F766eCc58533D6F69580CF3AC","topics":["0x0d0b9391970d9a25552f37d436d2aae2925e2bfe1b2a923754bada030c498cb3","0x000000000000000000000000555ee11fbddc0e49a9bab358a8941ad95ffdb48f","0x0000000000000000000000000000000000000000000000000000000000000000","0x5af266c0a89a07c1917deaa024414577e6c3c31c8907d079e13eb448c082594f"],"data":"0x0000000000000000000000004bda106325c335df99eab7fe363cac8a0ba2a24d0000000000000000000000000d0f936ee4c93e25944694d6c121de94d9760f110000000000000000000000004af4114f73d1c1c903ac9e0361b379d1291808a20000000000000000000000000000000000000000000000006a8313d60b1f8001000000000000000000000000000000000000000000000000000308fd0e798ac0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000005e083a16f4b092c5729a49f9c3ed3cc171bb3d3d0c22e20b1de6063c32f399ac"},{"address":"0x4af4114F73d1c1C903aC9E0361b379D1291808A2","topics":["0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef","0x0000000000000000000000007b62eb7fe80350dc7ec945c0b73242cb9877fb1b","0x0000000000000000000000004bda106325c335df99eab7fe363cac8a0ba2a24d"],"data":"0x00000000000000000000000000000000000000000000000000031855667df7a8"},{"address":"0x0d0F936Ee4c93e25944694D6C121de94D9760F11","topics":["0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef","0x0000000000000000000000004bda106325c335df99eab7fe363cac8a0ba2a24d","0x0000000000000000000000007b62eb7fe80350dc7ec945c0b73242cb9877fb1b"],"data":"0x0000000000000000000000000000000000000000000000006a8313d60b1f606b"},{"address":"0x479CC461fEcd078F766eCc58533D6F69580CF3AC","topics":["0x0d0b9391970d9a25552f37d436d2aae2925e2bfe1b2a923754bada030c498cb3","0x0000000000000000000000007b62eb7fe80350dc7ec945c0b73242cb9877fb1b","0x0000000000000000000000000000000000000000000000000000000000000000","0xb0b69dad58df6032c3b266e19b1045b19c87acd2c06fb0c598090f44b8e263aa"],"data":"0x0000000000000000000000004bda106325c335df99eab7fe363cac8a0ba2a24d0000000000000000000000004af4114f73d1c1c903ac9e0361b379d1291808a20000000000000000000000000d0f936ee4c93e25944694d6c121de94d9760f1100000000000000000000000000000000000000000000000000031855667df7a80000000000000000000000000000000000000000000000006a8313d60b1f606b00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000f2b0d62c44ed08f2a5adef40c875d20310a42a9d4f488bd26323256fe01c7f48"}]}},"tokenTransfers":[{"type":"ERC20","from":"0x555Ee11FBDDc0E49A9bAB358A8941AD95fFDB48f","to":"0x4Bda106325C335dF99eab7fE363cAC8A0ba2a24D","contract":"0x0d0F936Ee4c93e25944694D6C121de94D9760F11","name":"Contract 13","symbol":"S13","decimals":18,"value":"7675000000000000001"},{"type":"ERC20","from":"0x4Bda106325C335dF99eab7fE363cAC8A0ba2a24D","to":"0x555Ee11FBDDc0E49A9bAB358A8941AD95fFDB48f","contract":"0x4af4114F73d1c1C903aC9E0361b379D1291808A2","name":"Contract 74","symbol":"S74","decimals":12,"value":"854307892726464"},{"type":"ERC20","from":"0x7B62EB7fe80350DC7EC945C0B73242cb9877FB1b","to":"0x4Bda106325C335dF99eab7fE363cAC8A0ba2a24D","contract":"0x4af4114F73d1c1C903aC9E0361b379D1291808A2","name":"Contract 74","symbol":"S74","decimals":12,"value":"871180000950184"},{"type":"ERC20","from":"0x4Bda106325C335dF99eab7fE363cAC8A0ba2a24D","to":"0x7B62EB7fe80350DC7EC945C0B73242cb9877FB1b","contract":"0x0d0F936Ee4c93e25944694D6C121de94D9760F11","name":"Contract 13","symbol":"S13","decimals":18,"value":"7674999999999991915"}],"ethereumSpecific":{"status":1,"nonce":122742,"gasLimit":250000,"gasUsed":216368,"gasPrice":"1000000000","data":"0x4f15078700000000000000000000000000000000000000000000000000000000000000c0000000000000000000000000000000000000000000000000000000000000022000000000000000000000000000000000000000000000000000000000000003c00000000000000000000000000000000000000000000000000000000000000420000000000000000000000000000000000000000000000000000000000000048000000000000000000000000000000000000000000000000000000000000004e00000000000000000000000000000000000000000000000000000000000000002000000000000000000000000555ee11fbddc0e49a9bab358a8941ad95ffdb48f0000000000000000000000004bda106325c335df99eab7fe363cac8a0ba2a24d0000000000000000000000000d0f936ee4c93e25944694d6c121de94d9760f110000000000000000000000004af4114f73d1c1c903ac9e0361b379d1291808a200000000000000000000000000000000000000000000000000000000000000000000000000000000000000007b62eb7fe80350dc7ec945c0b73242cb9877fb1b0000000000000000000000004bda106325c335df99eab7fe363cac8a0ba2a24d0000000000000000000000004af4114f73d1c1c903ac9e0361b379d1291808a20000000000000000000000000d0f936ee4c93e25944694d6c121de94d9760f110000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000a5ef5a7656bfb0000000000000000000000000000000000000000000000000000004ba78398d5c5000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000166cfe0b9579b4ecf7a2801880f644009a324671a79754ea57c3a103c6e70d3dbef6ba69a08000000000000000000000000000000000000000000000000004f937d86afb90000000000000000000000000000000000000000000000000ab280fd8037d500000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000166cfb784b7c1f3fbe8b75484603ab8adc58aaee3a46245a6579fac7077b5570018b4e0d4eb0000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000308fd0e798ac00000000000000000000000000000000000000000000000006a8313d60b1f606b0000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000001b000000000000000000000000000000000000000000000000000000000000001b00000000000000000000000000000000000000000000000000000000000000029de0ccec59e8948e3d905b40e5542335ebc1eb4674db517d2f6392ec7fdeb3d45f3449d313ee2589819c6c79eb1c1b047adae68565c1608e3a1d1d70823febb0000000000000000000000000000000000000000000000000000000000000000234d06fe17f1202e8b07177a30eb64d14adc08cdb3fa1b3e3e0bea0f9672c02175b77c01c51d3c7e460723b27ecbc7801fd6482559a8c9999593f9a4d149c7384","parsedData":{"methodId":"0x4f150787","name":""}}}],"nonce":"123","tokens":[{"type":"ERC20","name":"Contract 13","contract":"0x0d0F936Ee4c93e25944694D6C121de94D9760F11","transfers":1,"symbol":"S13","decimals":18,"balance":"1000123013"},{"type":"ERC721","name":"Contract 205","contract":"0xcdA9FC258358EcaA88845f19Af595e908bb7EfE9","transfers":1,"symbol":"S205","decimals":18,"ids":["1"]},{"type":"ERC20","name":"Contract 74","contract":"0x4af4114F73d1c1C903aC9E0361b379D1291808A2","transfers":1,"symbol":"S74","decimals":12,"balance":"1000123074"}],"addressAliases":{"0x7B62EB7fe80350DC7EC945C0B73242cb9877FB1b":{"Type":"ENS","Alias":"address7b.eth"},"0xcdA9FC258358EcaA88845f19Af595e908bb7EfE9":{"Type":"Contract","Alias":"Contract 205"}}}`, + }, + }, + { + name: "apiTx EthTxidB1T2", + r: newGetRequest(ts.URL + "/api/v2/tx/0x" + dbtestdata.EthTxidB1T2), + status: http.StatusOK, + contentType: "application/json; charset=utf-8", + body: []string{ + `{"txid":"0xa9cd088aba2131000da6f38a33c20169baee476218deea6b78720700b895b101","vin":[{"n":0,"addresses":["0x20cD153de35D469BA46127A0C8F18626b59a256A"],"isAddress":true}],"vout":[{"value":"0","n":0,"addresses":["0x4af4114F73d1c1C903aC9E0361b379D1291808A2"],"isAddress":true}],"blockHeight":-1,"confirmations":0,"blockTime":0,"value":"0","fees":"2081000000000000","rbf":true,"coinSpecificData":{"tx":{"nonce":"0xd0","gasPrice":"0x9502f9000","gas":"0x130d5","to":"0x4af4114F73d1c1C903aC9E0361b379D1291808A2","value":"0x0","input":"0xa9059cbb000000000000000000000000555ee11fbddc0e49a9bab358a8941ad95ffdb48f00000000000000000000000000000000000000000000021e19e0c9bab2400000","hash":"0xa9cd088aba2131000da6f38a33c20169baee476218deea6b78720700b895b101","blockNumber":"0x41eee8","from":"0x20cD153de35D469BA46127A0C8F18626b59a256A","transactionIndex":"0x0"},"internalData":{"type":0,"transfers":[{"type":1,"from":"9f4981531fda132e83c44680787dfa7ee31e4f8d","to":"4af4114f73d1c1c903ac9e0361b379d1291808a2","value":1000000},{"type":0,"from":"3e3a3d69dc66ba10737f531ed088954a9ec89d97","to":"9f4981531fda132e83c44680787dfa7ee31e4f8d","value":1000001},{"type":0,"from":"3e3a3d69dc66ba10737f531ed088954a9ec89d97","to":"3e3a3d69dc66ba10737f531ed088954a9ec89d97","value":1000002}],"Error":""},"receipt":{"gasUsed":"0xcb39","status":"0x1","logs":[{"address":"0x4af4114F73d1c1C903aC9E0361b379D1291808A2","topics":["0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef","0x00000000000000000000000020cd153de35d469ba46127a0c8f18626b59a256a","0x000000000000000000000000555ee11fbddc0e49a9bab358a8941ad95ffdb48f"],"data":"0x00000000000000000000000000000000000000000000021e19e0c9bab2400000"}]}},"tokenTransfers":[{"type":"ERC20","from":"0x20cD153de35D469BA46127A0C8F18626b59a256A","to":"0x555Ee11FBDDc0E49A9bAB358A8941AD95fFDB48f","contract":"0x4af4114F73d1c1C903aC9E0361b379D1291808A2","name":"Contract 74","symbol":"S74","decimals":12,"value":"10000000000000000000000"}],"ethereumSpecific":{"status":1,"nonce":208,"gasLimit":78037,"gasUsed":52025,"gasPrice":"40000000000","data":"0xa9059cbb000000000000000000000000555ee11fbddc0e49a9bab358a8941ad95ffdb48f00000000000000000000000000000000000000000000021e19e0c9bab2400000","parsedData":{"methodId":"0xa9059cbb","name":"Transfer","function":"transfer(address, uint256)","params":[{"type":"address","values":["0x555Ee11FBDDc0E49A9bAB358A8941AD95fFDB48f"]},{"type":"uint256","values":["10000000000000000000000"]}]}},"addressAliases":{"0x20cD153de35D469BA46127A0C8F18626b59a256A":{"Type":"ENS","Alias":"address20.eth"},"0x4af4114F73d1c1C903aC9E0361b379D1291808A2":{"Type":"Contract","Alias":"Contract 74"}}}`, + }, + }, + { + name: "apiFiatRates get rate by timestamp", + r: newGetRequest(ts.URL + "/api/v2/tickers?currency=usd×tamp=1574340000"), + status: http.StatusOK, + contentType: "application/json; charset=utf-8", + body: []string{ + `{"ts":1574380800,"rates":{"usd":7914.5}}`, + }, + }, + { + name: "apiFiatRates get token rate by timestamp", + r: newGetRequest(ts.URL + "/api/v2/tickers?currency=usd×tamp=1574340000&token=0xA4DD6Bc15Be95Af55f0447555c8b6aA3088562f3"), + status: http.StatusOK, + contentType: "application/json; charset=utf-8", + body: []string{ + `{"ts":1574380800,"rates":{"usd":1.2}}`, + }, + }, + { + name: "apiFiatRates get token rate by timestamp for all currencies", + r: newGetRequest(ts.URL + "/api/v2/tickers?timestamp=1574340000&token=0xA4DD6Bc15Be95Af55f0447555c8b6aA3088562f3"), + status: http.StatusOK, + contentType: "application/json; charset=utf-8", + body: []string{ + `{"ts":1574380800,"rates":{"eur":1.0816754,"usd":1.2}}`, + }, + }, + { + name: "apiFiatRates get token rate for unknown token by timestamp", + r: newGetRequest(ts.URL + "/api/v2/tickers?currency=usd×tamp=1574340000&token=0xFFFFFFFFFFe95Af55f0447555c8b6aA3088562f3"), + status: http.StatusOK, + contentType: "application/json; charset=utf-8", + body: []string{ + `{"ts":1574340000,"rates":{"usd":-1}}`, + }, + }, + } + + performHttpTests(tests, t, ts) +} + +var websocketTestsEthereumType = []websocketTest{ + { + name: "websocket getInfo", + req: websocketReq{ + Method: "getInfo", + }, + want: `{"id":"0","data":{"name":"Fakecoin","shortcut":"FAKE","network":"FAKE","decimals":18,"version":"unknown","bestHeight":4321001,"bestHash":"0x2b57e15e93a0ed197417a34c2498b7187df79099572c04a6b6e6ff418f74e6ee","block0Hash":"","testnet":true,"backend":{"version":"001001","subversion":"/Fakecoin:0.0.1/"}}}`, + }, + { + name: "websocket rpcCall", + req: websocketReq{ + Method: "rpcCall", + Params: WsRpcCallReq{ + To: "0xcdA9FC258358EcaA88845f19Af595e908bb7EfE9", + Data: "0x4567", + }, + }, + want: `{"id":"1","data":{"data":"0x4567abcd"}}`, + }, +} + +func initEthereumTypeDB(d *db.RocksDB) error { + // add 0xa9059cbb transfer(address,uint256) signature + wb := grocksdb.NewWriteBatch() + defer wb.Destroy() + if err := d.StoreFourByteSignature(wb, 2835717307, 145, &bchain.FourByteSignature{ + Name: "transfer", + Parameters: []string{"address", "uint256"}, + }); err != nil { + return err + } + return d.WriteBatch(wb) +} + +// initTestFiatRatesEthereumType initializes test data for /api/v2/tickers endpoint +func initTestFiatRatesEthereumType(d *db.RocksDB) error { + if err := insertFiatRate("20180320000000", map[string]float32{ + "usd": 2000.0, + "eur": 1300.0, + }, map[string]float32{ + "0xdac17f958d2ee523a2206206994597c13d831ec7": 2000.1, + "0x2260fac5e5542a773aa44fbcfedf7c193bc2c599": 123.0, + }, d); err != nil { + return err + } + if err := insertFiatRate("20180321000000", map[string]float32{ + "usd": 2001.0, + "eur": 1301.0, + }, map[string]float32{ + "0xdac17f958d2ee523a2206206994597c13d831ec7": 2001.1, + "0x2260fac5e5542a773aa44fbcfedf7c193bc2c599": 199.0, + }, d); err != nil { + return err + } + if err := insertFiatRate("20180322000000", map[string]float32{ + "usd": 2002.0, + "eur": 1302.0, + }, map[string]float32{ + "0xdac17f958d2ee523a2206206994597c13d831ec7": 2002.1, + "0x2260fac5e5542a773aa44fbcfedf7c193bc2c599": 99.0, + }, d); err != nil { + return err + } + if err := insertFiatRate("20180323000000", map[string]float32{ + "usd": 2003.0, + "eur": 1303.0, + }, map[string]float32{ + "0xdac17f958d2ee523a2206206994597c13d831ec7": 2003.1, + "0x2260fac5e5542a773aa44fbcfedf7c193bc2c599": 101.0, + }, d); err != nil { + return err + } + if err := insertFiatRate("20190321000000", map[string]float32{ + "usd": 7814.5, + "eur": 7100.0, + }, map[string]float32{ + "0xdac17f958d2ee523a2206206994597c13d831ec7": 7814.1, + "0x2260fac5e5542a773aa44fbcfedf7c193bc2c599": 499.0, + "0xa4dd6bc15be95af55f0447555c8b6aa3088562f3": 0.8, + }, d); err != nil { + return err + } + if err := insertFiatRate("20191122000000", map[string]float32{ + "usd": 7914.5, + "eur": 7134.1, + }, map[string]float32{ + "0xdac17f958d2ee523a2206206994597c13d831ec7": 7914.1, + "0x2260fac5e5542a773aa44fbcfedf7c193bc2c599": 599.0, + "0xa4dd6bc15be95af55f0447555c8b6aa3088562f3": 1.2, + }, d); err != nil { + return err + } + + return d.FiatRatesStoreSpecialTickers("CurrentTickers", &[]common.CurrencyRatesTicker{ + { + Timestamp: time.Unix(1592821931, 0), + Rates: map[string]float32{ + "usd": 8914.5, + "eur": 8134.1, + }, + TokenRates: map[string]float32{ + "0xdac17f958d2ee523a2206206994597c13d831ec7": 8914.1, + "0x2260fac5e5542a773aa44fbcfedf7c193bc2c599": 899.0, + "0xa4dd6bc15be95af55f0447555c8b6aa3088562f3": 8.2, + }, + }, + }) +} + +func Test_PublicServer_EthereumType(t *testing.T) { + timeNow = fixedTimeNow + parser := eth.NewEthereumParser(1, true) + chain, err := dbtestdata.NewFakeBlockChainEthereumType(parser) + if err != nil { + glog.Fatal("fakechain: ", err) + } + + s, dbpath := setupPublicHTTPServer(parser, chain, t, false) + defer closeAndDestroyPublicServer(t, s, dbpath) + s.ConnectFullPublicInterface() + // take the handler of the public server and pass it to the test server + ts := httptest.NewServer(s.https.Handler) + defer ts.Close() + + httpTestsEthereumType(t, ts) + runWebsocketTests(t, ts, websocketTestsEthereumType) +} diff --git a/server/public_test.go b/server/public_test.go new file mode 100644 index 00000000..550afefe --- /dev/null +++ b/server/public_test.go @@ -0,0 +1,1773 @@ +//go:build unittest + +package server + +import ( + "encoding/json" + "io" + "net/http" + "net/http/httptest" + "net/url" + "os" + "strconv" + "strings" + "testing" + "time" + + "github.com/golang/glog" + "github.com/gorilla/websocket" + "github.com/linxGnu/grocksdb" + "github.com/martinboehm/btcutil/chaincfg" + gosocketio "github.com/martinboehm/golang-socketio" + "github.com/martinboehm/golang-socketio/transport" + "github.com/trezor/blockbook/bchain" + "github.com/trezor/blockbook/bchain/coins/btc" + "github.com/trezor/blockbook/common" + "github.com/trezor/blockbook/db" + "github.com/trezor/blockbook/fiat" + "github.com/trezor/blockbook/tests/dbtestdata" +) + +func TestMain(m *testing.M) { + // set the current directory to blockbook root so that ./static/ works + if err := os.Chdir(".."); err != nil { + glog.Fatal("Chdir error:", err) + } + c := m.Run() + chaincfg.ResetParams() + os.Exit(c) +} + +func setupRocksDB(parser bchain.BlockChainParser, chain bchain.BlockChain, t *testing.T, extendedIndex bool, config *common.Config) (*db.RocksDB, *common.InternalState, string) { + tmp, err := os.MkdirTemp("", "testdb") + if err != nil { + t.Fatal(err) + } + d, err := db.NewRocksDB(tmp, 100000, -1, parser, nil, extendedIndex) + if err != nil { + t.Fatal(err) + } + is, err := d.LoadInternalState(config) + if err != nil { + t.Fatal(err) + } + d.SetInternalState(is) + // there are 2 simulated block, of height bestBlockHeight-1 and bestBlockHeight + bestHeight, err := chain.GetBestBlockHeight() + if err != nil { + t.Fatal(err) + } + block1, err := chain.GetBlock("", bestHeight-1) + if err != nil { + t.Fatal(err) + } + // setup internal state BlockTimes + for i := uint32(0); i < block1.Height; i++ { + is.BlockTimes = append(is.BlockTimes, 0) + } + // import data + if err := d.ConnectBlock(block1); err != nil { + t.Fatal(err) + } + block2, err := chain.GetBlock("", bestHeight) + if err != nil { + t.Fatal(err) + } + if err := d.ConnectBlock(block2); err != nil { + t.Fatal(err) + } + is.FinishedSync(block2.Height) + if parser.GetChainType() == bchain.ChainEthereumType { + if err := initTestFiatRatesEthereumType(d); err != nil { + t.Fatal(err) + } + if err := initEthereumTypeDB(d); err != nil { + t.Fatal(err) + } + } else { + if err := initTestFiatRates(d); err != nil { + t.Fatal(err) + } + } + return d, is, tmp +} + +var metrics *common.Metrics + +func setupPublicHTTPServer(parser bchain.BlockChainParser, chain bchain.BlockChain, t *testing.T, extendedIndex bool) (*PublicServer, string) { + // config with mocked CoinGecko API + config := common.Config{ + CoinName: "Fakecoin", + CoinLabel: "Fake Coin", + CoinShortcut: "FAKE", + FiatRates: "coingecko", + FiatRatesParams: `{"url": "none", "coin": "ethereum","platformIdentifier": "ethereum","platformVsCurrency": "usd","periodSeconds": 60}`, + } + + // add block golomb filters with extended index + if extendedIndex { + config.BlockGolombFilterP = 20 + } + + d, is, path := setupRocksDB(parser, chain, t, extendedIndex, &config) + + var err error + // metrics can be setup only once + if metrics == nil { + metrics, err = common.GetMetrics("Fakecoin" + strconv.FormatBool(extendedIndex)) + if err != nil { + glog.Fatal("metrics: ", err) + } + } + + mempool, err := chain.CreateMempool(chain) + if err != nil { + glog.Fatal("mempool: ", err) + } + + // caching is switched off because test transactions do not have hex data + txCache, err := db.NewTxCache(d, chain, metrics, is, false) + if err != nil { + glog.Fatal("txCache: ", err) + } + + fiatRates, err := fiat.NewFiatRates(d, &config, nil, nil) + if err != nil { + glog.Fatal("fiatRates ", err) + } + + // s.Run is never called, binding can be to any port + s, err := NewPublicServer("localhost:12345", "", d, chain, mempool, txCache, "", metrics, is, fiatRates, false) + if err != nil { + t.Fatal(err) + } + return s, path +} + +func closeAndDestroyPublicServer(t *testing.T, s *PublicServer, dbpath string) { + // destroy db + if err := s.db.Close(); err != nil { + t.Fatal(err) + } + os.RemoveAll(dbpath) +} + +func newGetRequest(u string) *http.Request { + r, err := http.NewRequest("GET", u, nil) + if err != nil { + glog.Fatal(err) + } + return r +} + +func newPostFormRequest(u string, formdata ...string) *http.Request { + form := url.Values{} + for i := 0; i < len(formdata)-1; i += 2 { + form.Add(formdata[i], formdata[i+1]) + } + r, err := http.NewRequest("POST", u, strings.NewReader(form.Encode())) + if err != nil { + glog.Fatal(err) + } + r.Header.Add("Content-Type", "application/x-www-form-urlencoded") + return r +} + +func newPostRequest(u string, body string) *http.Request { + r, err := http.NewRequest("POST", u, strings.NewReader(body)) + if err != nil { + glog.Fatal(err) + } + r.Header.Add("Content-Type", "application/octet-stream") + return r +} + +func insertFiatRate(date string, rates map[string]float32, tokenRates map[string]float32, d *db.RocksDB) error { + convertedDate, err := time.Parse("20060102150405", date) + if err != nil { + return err + } + ticker := &common.CurrencyRatesTicker{ + Timestamp: convertedDate, + Rates: rates, + TokenRates: tokenRates, + } + wb := grocksdb.NewWriteBatch() + defer wb.Destroy() + if err := d.FiatRatesStoreTicker(wb, ticker); err != nil { + return err + } + return d.WriteBatch(wb) +} + +// initTestFiatRates initializes test data for /api/v2/tickers endpoint +func initTestFiatRates(d *db.RocksDB) error { + if err := insertFiatRate("20180320000000", map[string]float32{ + "usd": 2000.0, + "eur": 1300.0, + }, nil, d); err != nil { + return err + } + if err := insertFiatRate("20180321000000", map[string]float32{ + "usd": 2001.0, + "eur": 1301.0, + }, nil, d); err != nil { + return err + } + if err := insertFiatRate("20180322000000", map[string]float32{ + "usd": 2002.0, + "eur": 1302.0, + }, nil, d); err != nil { + return err + } + if err := insertFiatRate("20180324000000", map[string]float32{ + "usd": 2003.0, + "eur": 1303.0, + }, nil, d); err != nil { + return err + } + if err := insertFiatRate("20191121000000", map[string]float32{ + "usd": 7814.5, + "eur": 7100.0, + }, nil, d); err != nil { + return err + } + return insertFiatRate("20191122000000", map[string]float32{ + "usd": 7914.5, + "eur": 7134.1, + }, nil, d) +} + +type httpTests struct { + name string + r *http.Request + status int + contentType string + body []string +} + +func performHttpTests(tests []httpTests, t *testing.T, ts *httptest.Server) { + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + resp, err := http.DefaultClient.Do(tt.r) + if err != nil { + t.Fatal(err) + } + defer resp.Body.Close() + if resp.StatusCode != tt.status { + t.Errorf("StatusCode = %v, want %v", resp.StatusCode, tt.status) + } + if resp.Header["Content-Type"][0] != tt.contentType { + t.Errorf("Content-Type = %v, want %v", resp.Header["Content-Type"][0], tt.contentType) + } + bb, err := io.ReadAll(resp.Body) + if err != nil { + t.Fatal(err) + } + b := string(bb) + for _, c := range tt.body { + if !strings.Contains(b, c) { + t.Errorf("got\n%v\nwant to contain %v", b, c) + break + } + } + }) + } +} + +func httpTestsBitcoinType(t *testing.T, ts *httptest.Server) { + tests := []httpTests{ + { + name: "explorerTx", + r: newGetRequest(ts.URL + "/tx/fdd824a780cbb718eeb766eb05d83fdefc793a27082cd5e67f856d69798cf7db"), + status: http.StatusOK, + contentType: "text/html; charset=utf-8", + body: []string{ + `Trezor Fake Coin Explorer

Transaction

fdd824a780cbb718eeb766eb05d83fdefc793a27082cd5e67f856d69798cf7db
Mined Time1639 days 11 hours ago
In Block00000000eb0443fd7dc4a1ed5c686a8e995057805f9a161d9a5a77a95e72b7b6
In Block Height225494
Total Input0 FAKE
Total Output13.60030331 FAKE
Fees0 FAKE
No Inputs (Newly Generated Coins)
 
Unparsed address0 FAKE×
`, + }, + }, + { + name: "explorerAddress", + r: newGetRequest(ts.URL + "/address/mtGXQvBowMkBpnhLckhxhbwYK44Gs9eEtz"), + status: http.StatusOK, + contentType: "text/html; charset=utf-8", + body: []string{ + `Trezor Fake Coin Explorer

Address

mtGXQvBowMkBpnhLckhxhbwYK44Gs9eEtz

0.00012345 FAKE

Confirmed
Total Received0.00024690 FAKE
Total Sent0.00012345 FAKE
Final Balance0.00012345 FAKE
No. Transactions2

Transactions

mtGXQvBowMkBpnhLckhxhbwYK44Gs9eEtz0.00012345 FAKE
 
OP_RETURN 2020f1686f6a200 FAKE×
No Inputs
 
mtGXQvBowMkBpnhLckhxhbwYK44Gs9eEtz0.00012345 FAKE
mtGXQvBowMkBpnhLckhxhbwYK44Gs9eEtz0.00012345 FAKE×
`, + }, + }, + { + name: "explorerSpendingTx", + r: newGetRequest(ts.URL + "/spending/7c3be24063f268aaa1ed81b64776798f56088757641a34fb156c4f51ed2e9d25/0"), + status: http.StatusOK, + contentType: "text/html; charset=utf-8", + body: []string{ + `Trezor Fake Coin Explorer

Transaction

3d90d15ed026dc45e19ffb52875ed18fa9e8012ad123d7f7212176e2b0ebdb71
Mined Time1639 days 11 hours ago
In Block00000000eb0443fd7dc4a1ed5c686a8e995057805f9a161d9a5a77a95e72b7b6
In Block Height225494
Total Input3172.83951062 FAKE
Total Output3172.83951000 FAKE
Fees0.00000062 FAKE
`, + }, + }, + { + name: "explorerSpendingTx - not found", + r: newGetRequest(ts.URL + "/spending/123be24063f268aaa1ed81b64776798f56088757641a34fb156c4f51ed2e9d25/0"), + status: http.StatusOK, + contentType: "text/html; charset=utf-8", + body: []string{ + `Trezor Fake Coin Explorer

Error

Transaction not found

`, + }, + }, + { + name: "explorerBlocks", + r: newGetRequest(ts.URL + "/blocks"), + status: http.StatusOK, + contentType: "text/html; charset=utf-8", + body: []string{ + `Trezor Fake Coin Explorer

Blocks

HeightHashTimestampTransactionsSize
22549400000000eb0443fd7dc4a1ed5c686a8e995057805f9a161d9a5a77a95e72b7b61639 days 11 hours ago42345678
2254930000000076fbbed90fd75b0e18856aa35baa984e9c9d444cf746ad85e94e29971640 days 9 hours ago21234567
`, + }, + }, + { + name: "explorerBlock", + r: newGetRequest(ts.URL + "/block/225494"), + status: http.StatusOK, + contentType: "text/html; charset=utf-8", + body: []string{ + `Trezor Fake Coin Explorer

Block

225494
00000000eb0443fd7dc4a1ed5c686a8e995057805f9a161d9a5a77a95e72b7b6
Transactions4
Height225494
Confirmations1
Timestamp1639 days 11 hours ago
Size (bytes)2345678
Version
Merkle Root
Nonce
Bits
Difficulty

Transactions

 
OP_RETURN 2020f1686f6a200 FAKE×
No Inputs (Newly Generated Coins)
 
Unparsed address0 FAKE×
`, + }, + }, + { + name: "explorerIndex", + r: newGetRequest(ts.URL + "/"), + status: http.StatusOK, + contentType: "text/html; charset=utf-8", + body: []string{ + `Trezor Fake Coin Explorer

Application status

Synchronization with backend is disabled, the state of index is not up to date.

`, + `

Blockbook

CoinFakecoin
Host
Version / Commit / Buildunknown / unknown / unknown
Synchronized
true
Last Block225494
Last Block Update`, + `
Mempool in Sync
false
Last Mempool Update
Transactions in Mempool0
Current Fiat rates

Backend

Chainfakecoin
Version001001
Subversion/Fakecoin:0.0.1/
Last Block2
Difficulty
Blockbook - blockchain indexer for Trezor Suite https://trezor.io/trezor-suite. Do not use for any other purpose.
`, + }, + }, + { + name: "explorerSearch block height", + r: newGetRequest(ts.URL + "/search?q=225494"), + status: http.StatusOK, + contentType: "text/html; charset=utf-8", + body: []string{ + `Trezor Fake Coin Explorer

Block

225494
00000000eb0443fd7dc4a1ed5c686a8e995057805f9a161d9a5a77a95e72b7b6
Transactions4
Height225494
Confirmations1
Timestamp1639 days 11 hours ago
Size (bytes)2345678
Version
Merkle Root
Nonce
Bits
Difficulty

Transactions

 
OP_RETURN 2020f1686f6a200 FAKE×
No Inputs (Newly Generated Coins)
 
Unparsed address0 FAKE×
`, + }, + }, + { + name: "explorerSearch block hash", + r: newGetRequest(ts.URL + "/search?q=00000000eb0443fd7dc4a1ed5c686a8e995057805f9a161d9a5a77a95e72b7b6"), + status: http.StatusOK, + contentType: "text/html; charset=utf-8", + body: []string{ + `Trezor Fake Coin Explorer

Block

225494
00000000eb0443fd7dc4a1ed5c686a8e995057805f9a161d9a5a77a95e72b7b6
Transactions4
Height225494
Confirmations1
Timestamp1639 days 11 hours ago
Size (bytes)2345678
Version
Merkle Root
Nonce
Bits
Difficulty

Transactions

 
OP_RETURN 2020f1686f6a200 FAKE×
No Inputs (Newly Generated Coins)
 
Unparsed address0 FAKE×
`, + }, + }, + { + name: "explorerSearch tx", + r: newGetRequest(ts.URL + "/search?q=fdd824a780cbb718eeb766eb05d83fdefc793a27082cd5e67f856d69798cf7db"), + status: http.StatusOK, + contentType: "text/html; charset=utf-8", + body: []string{ + `Trezor Fake Coin Explorer

Transaction

fdd824a780cbb718eeb766eb05d83fdefc793a27082cd5e67f856d69798cf7db
Mined Time1639 days 11 hours ago
In Block00000000eb0443fd7dc4a1ed5c686a8e995057805f9a161d9a5a77a95e72b7b6
In Block Height225494
Total Input0 FAKE
Total Output13.60030331 FAKE
Fees0 FAKE
No Inputs (Newly Generated Coins)
 
Unparsed address0 FAKE×
`, + }, + }, + { + name: "explorerSearch address", + r: newGetRequest(ts.URL + "/search?q=mtGXQvBowMkBpnhLckhxhbwYK44Gs9eEtz"), + status: http.StatusOK, + contentType: "text/html; charset=utf-8", + body: []string{ + `Trezor Fake Coin Explorer

Address

mtGXQvBowMkBpnhLckhxhbwYK44Gs9eEtz

0.00012345 FAKE

Confirmed
Total Received0.00024690 FAKE
Total Sent0.00012345 FAKE
Final Balance0.00012345 FAKE
No. Transactions2

Transactions

mtGXQvBowMkBpnhLckhxhbwYK44Gs9eEtz0.00012345 FAKE
 
OP_RETURN 2020f1686f6a200 FAKE×
No Inputs
 
mtGXQvBowMkBpnhLckhxhbwYK44Gs9eEtz0.00012345 FAKE
mtGXQvBowMkBpnhLckhxhbwYK44Gs9eEtz0.00012345 FAKE×
`, + }, + }, + { + name: "explorerSearch xpub", + r: newGetRequest(ts.URL + "/search?q=" + dbtestdata.Xpub), + status: http.StatusOK, + contentType: "text/html; charset=utf-8", + body: []string{ + `Trezor Fake Coin Explorer

XPUB

upub5E1xjDmZ7Hhej6LPpS8duATdKXnRYui7bDYj6ehfFGzWDZtmCmQkZhc3Zb7kgRLtHWd16QFxyP86JKL3ShZEBFX88aciJ3xyocuyhZZ8g6q

1186.419755 FAKE

Confirmed
Total Received1186.41975501 FAKE
Total Sent0.00000001 FAKE
Final Balance1186.41975500 FAKE
No. Transactions2
Used XPUB Addresses2
XPUB Addresses with Balance
AddressBalanceTxsPath
2N6utyMZfPNUb1Bk8oz7p2JqJrXkq83gegu1186.41975500 FAKE1m/49'/1'/33'/1/3

Transactions

`, + }, + }, + { + name: "explorerSearch taproot descriptor", + r: newGetRequest(ts.URL + "/search?q=" + url.QueryEscape(dbtestdata.TaprootDescriptor)), + status: http.StatusOK, + contentType: "text/html; charset=utf-8", + body: []string{ + `Trezor Fake Coin Explorer

XPUB

tr([5c9e228d/86'/1'/0']tpubDC88gkaZi5HvJGxGDNLADkvtdpni3mLmx6vr2KnXmWMG8zfkBRggsxHVBkUpgcwPe2KKpkyvTJCdXHb1UHEWE64vczyyPQfHr1skBcsRedN/{0,1}/*)#4rqwxvej

0 FAKE

Confirmed
Total Received0 FAKE
Total Sent0 FAKE
Final Balance0 FAKE
No. Transactions0
Used XPUB Addresses0
XPUB Addresses with Balance
No addresses
`, + }, + }, + { + name: "explorerSearch not found", + r: newGetRequest(ts.URL + "/search?q=1234"), + status: http.StatusOK, + contentType: "text/html; charset=utf-8", + body: []string{ + `Trezor Fake Coin Explorer

Error

No matching records found for '1234'

`, + }, + }, + { + name: "explorerSendTx", + r: newGetRequest(ts.URL + "/sendtx"), + status: http.StatusOK, + contentType: "text/html; charset=utf-8", + body: []string{ + `Trezor Fake Coin Explorer

Send Raw Transaction

`, + }, + }, + { + name: "explorerSendTx POST", + r: newPostFormRequest(ts.URL+"/sendtx", "hex", "12341234"), + status: http.StatusOK, + contentType: "text/html; charset=utf-8", + body: []string{ + `Trezor Fake Coin Explorer

Send Raw Transaction

Invalid data
`, + }, + }, + { + name: "apiIndex", + r: newGetRequest(ts.URL + "/api"), + status: http.StatusOK, + contentType: "application/json; charset=utf-8", + body: []string{ + `{"blockbook":{"coin":"Fakecoin"`, + `"bestHeight":225494`, + `"decimals":8`, + `"backend":{"chain":"fakecoin","blocks":2,"headers":2,"bestBlockHash":"00000000eb0443fd7dc4a1ed5c686a8e995057805f9a161d9a5a77a95e72b7b6"`, + `"version":"001001","subversion":"/Fakecoin:0.0.1/"`, + }, + }, + { + name: "apiBlockIndex", + r: newGetRequest(ts.URL + "/api/block-index/"), + status: http.StatusOK, + contentType: "application/json; charset=utf-8", + body: []string{ + `{"blockHash":"00000000eb0443fd7dc4a1ed5c686a8e995057805f9a161d9a5a77a95e72b7b6"}`, + }, + }, + { + name: "apiTx v1", + r: newGetRequest(ts.URL + "/api/v1/tx/05e2e48aeabdd9b75def7b48d756ba304713c2aba7b522bf9dbc893fc4231b07"), + status: http.StatusOK, + contentType: "application/json; charset=utf-8", + body: []string{ + `{"txid":"05e2e48aeabdd9b75def7b48d756ba304713c2aba7b522bf9dbc893fc4231b07","vin":[{"txid":"effd9ef509383d536b1c8af5bf434c8efbf521a4f2befd4022bbd68694b4ac75","vout":2,"n":0,"scriptSig":{},"addresses":["2NEVv9LJmAnY99W1pFoc5UJjVdypBqdnvu1"],"value":"0.00009876"}],"vout":[{"value":"0.00009","n":0,"scriptPubKey":{"hex":"a914e921fc4912a315078f370d959f2c4f7b6d2a683c87","addresses":["2NEVv9LJmAnY99W1pFoc5UJjVdypBqdnvu1"]},"spent":false}],"blockhash":"00000000eb0443fd7dc4a1ed5c686a8e995057805f9a161d9a5a77a95e72b7b6","blockheight":225494,"confirmations":1,"time":1521595678,"blocktime":1521595678,"valueOut":"0.00009","valueIn":"0.00009876","fees":"0.00000876","hex":""}`, + }, + }, + { + name: "apiTx - not found v1", + r: newGetRequest(ts.URL + "/api/v1/tx/1232e48aeabdd9b75def7b48d756ba304713c2aba7b522bf9dbc893fc4231b07"), + status: http.StatusBadRequest, + contentType: "application/json; charset=utf-8", + body: []string{ + `{"error":"Transaction '1232e48aeabdd9b75def7b48d756ba304713c2aba7b522bf9dbc893fc4231b07' not found"}`, + }, + }, + { + name: "apiTx v2", + r: newGetRequest(ts.URL + "/api/v2/tx/05e2e48aeabdd9b75def7b48d756ba304713c2aba7b522bf9dbc893fc4231b07"), + status: http.StatusOK, + contentType: "application/json; charset=utf-8", + body: []string{ + `{"txid":"05e2e48aeabdd9b75def7b48d756ba304713c2aba7b522bf9dbc893fc4231b07","vin":[{"txid":"effd9ef509383d536b1c8af5bf434c8efbf521a4f2befd4022bbd68694b4ac75","vout":2,"n":0,"addresses":["2NEVv9LJmAnY99W1pFoc5UJjVdypBqdnvu1"],"isAddress":true,"value":"9876"}],"vout":[{"value":"9000","n":0,"hex":"a914e921fc4912a315078f370d959f2c4f7b6d2a683c87","addresses":["2NEVv9LJmAnY99W1pFoc5UJjVdypBqdnvu1"],"isAddress":true}],"blockHash":"00000000eb0443fd7dc4a1ed5c686a8e995057805f9a161d9a5a77a95e72b7b6","blockHeight":225494,"confirmations":1,"blockTime":1521595678,"value":"9000","valueIn":"9876","fees":"876"}`, + }, + }, + { + name: "apiTx - not found v2", + r: newGetRequest(ts.URL + "/api/v2/tx/1232e48aeabdd9b75def7b48d756ba304713c2aba7b522bf9dbc893fc4231b07"), + status: http.StatusBadRequest, + contentType: "application/json; charset=utf-8", + body: []string{ + `{"error":"Transaction '1232e48aeabdd9b75def7b48d756ba304713c2aba7b522bf9dbc893fc4231b07' not found"}`, + }, + }, + { + name: "apiTxSpecific", + r: newGetRequest(ts.URL + "/api/tx-specific/00b2c06055e5e90e9c82bd4181fde310104391a7fa4f289b1704e5d90caa3840"), + status: http.StatusOK, + contentType: "application/json; charset=utf-8", + body: []string{ + `{"hex":"","txid":"00b2c06055e5e90e9c82bd4181fde310104391a7fa4f289b1704e5d90caa3840","version":0,"locktime":0,"vin":[],"vout":[{"ValueSat":100000000,"value":0,"n":0,"scriptPubKey":{"hex":"76a914010d39800f86122416e28f485029acf77507169288ac","addresses":null}},{"ValueSat":12345,"value":0,"n":1,"scriptPubKey":{"hex":"76a9148bdf0aa3c567aa5975c2e61321b8bebbe7293df688ac","addresses":null}},{"ValueSat":12345,"value":0,"n":2,"scriptPubKey":{"hex":"76a9148bdf0aa3c567aa5975c2e61321b8bebbe7293df688ac","addresses":null}}],"confirmations":2,"time":1521515026,"blocktime":1521515026}`, + }, + }, + { + name: "apiFeeStats", + r: newGetRequest(ts.URL + "/api/v2/feestats/225494"), + status: http.StatusOK, + contentType: "application/json; charset=utf-8", + body: []string{ + `{"txCount":3,"totalFeesSat":"1284","averageFeePerKb":1398,"decilesFeePerKb":[155,155,155,155,1679,1679,1679,2361,2361,2361,2361]}`, + }, + }, + { + name: "apiFiatRates all currencies", + r: newGetRequest(ts.URL + "/api/v2/tickers"), + status: http.StatusOK, + contentType: "application/json; charset=utf-8", + body: []string{ + `{"ts":1574380800,"rates":{"eur":7134.1,"usd":7914.5}}`, + }, + }, + { + name: "apiFiatRates get last rate", + r: newGetRequest(ts.URL + "/api/v2/tickers?currency=usd"), + status: http.StatusOK, + contentType: "application/json; charset=utf-8", + body: []string{ + `{"ts":1574380800,"rates":{"usd":7914.5}}`, + }, + }, + { + name: "apiFiatRates get rate by exact timestamp", + r: newGetRequest(ts.URL + "/api/v2/tickers?currency=usd×tamp=1521545531"), + status: http.StatusOK, + contentType: "application/json; charset=utf-8", + body: []string{ + `{"ts":1521590400,"rates":{"usd":2001}}`, + }, + }, + { + name: "apiFiatRates incorrect timestamp", + r: newGetRequest(ts.URL + "/api/v2/tickers?currency=usd×tamp=yesterday"), + status: http.StatusBadRequest, + contentType: "application/json; charset=utf-8", + body: []string{ + `{"error":"Parameter 'timestamp' is not a valid Unix timestamp."}`, + }, + }, + { + name: "apiFiatRates future timestamp", + r: newGetRequest(ts.URL + "/api/v2/tickers?currency=usd×tamp=7980386400"), + status: http.StatusOK, + contentType: "application/json; charset=utf-8", + body: []string{ + `{"ts":7980386400,"rates":{"usd":-1}}`, + }, + }, + { + name: "apiFiatRates future timestamp, all currencies", + r: newGetRequest(ts.URL + "/api/v2/tickers?timestamp=7980386400"), + status: http.StatusOK, + contentType: "application/json; charset=utf-8", + body: []string{ + `{"ts":7980386400,"rates":{}}`, + }, + }, + { + name: "apiFiatRates get EUR rate (exact timestamp)", + r: newGetRequest(ts.URL + "/api/v2/tickers?timestamp=1574344800¤cy=eur"), + status: http.StatusOK, + contentType: "application/json; charset=utf-8", + body: []string{ + `{"ts":1574380800,"rates":{"eur":7134.1}`, + }, + }, + { + name: "apiMultiFiatRates all currencies", + r: newGetRequest(ts.URL + "/api/v2/multi-tickers?timestamp=1574344800,1521677000"), + status: http.StatusOK, + contentType: "application/json; charset=utf-8", + body: []string{ + `[{"ts":1574380800,"rates":{"eur":7134.1,"usd":7914.5}},{"ts":1521849600,"rates":{"eur":1303,"usd":2003}}]`, + }, + }, + { + name: "apiMultiFiatRates get EUR rate", + r: newGetRequest(ts.URL + "/api/v2/multi-tickers?timestamp=1521545531,1574346615¤cy=eur"), + status: http.StatusOK, + contentType: "application/json; charset=utf-8", + body: []string{ + `[{"ts":1521590400,"rates":{"eur":1301}},{"ts":1574380800,"rates":{"eur":7134.1}}]`, + }, + }, + { + name: "apiFiatRates get closest rate", + r: newGetRequest(ts.URL + "/api/v2/tickers?timestamp=1357045200¤cy=usd"), + status: http.StatusOK, + contentType: "application/json; charset=utf-8", + body: []string{ + `{"ts":1521504000,"rates":{"usd":2000}}`, + }, + }, + { + name: "apiFiatRates get rate by block height", + r: newGetRequest(ts.URL + "/api/v2/tickers?block=225494¤cy=usd"), + status: http.StatusOK, + contentType: "application/json; charset=utf-8", + body: []string{ + `{"ts":1521676800,"rates":{"usd":2002}}`, + }, + }, + { + name: "apiFiatRates get rate for EUR", + r: newGetRequest(ts.URL + "/api/v2/tickers?timestamp=1574346615¤cy=eur"), + status: http.StatusOK, + contentType: "application/json; charset=utf-8", + body: []string{ + `{"ts":1574380800,"rates":{"eur":7134.1}}`, + }, + }, + { + name: "apiFiatRates get exact rate for an incorrect currency", + r: newGetRequest(ts.URL + "/api/v2/tickers?timestamp=1574346615¤cy=does_not_exist"), + status: http.StatusOK, + contentType: "application/json; charset=utf-8", + body: []string{ + `{"ts":1574346615,"rates":{"does_not_exist":-1}}`, + }, + }, + { + name: "apiTickerList", + r: newGetRequest(ts.URL + "/api/v2/tickers-list?timestamp=1574346615"), + status: http.StatusOK, + contentType: "application/json; charset=utf-8", + body: []string{ + `{"ts":1574380800,"available_currencies":["eur","usd"]}`, + }, + }, + { + name: "apiAddress v1", + r: newGetRequest(ts.URL + "/api/v1/address/mv9uLThosiEnGRbVPS7Vhyw6VssbVRsiAw"), + status: http.StatusOK, + contentType: "application/json; charset=utf-8", + body: []string{ + `{"page":1,"totalPages":1,"itemsOnPage":1000,"addrStr":"mv9uLThosiEnGRbVPS7Vhyw6VssbVRsiAw","balance":"0","totalReceived":"12345.67890123","totalSent":"12345.67890123","unconfirmedBalance":"0","unconfirmedTxApperances":0,"txApperances":2,"transactions":["7c3be24063f268aaa1ed81b64776798f56088757641a34fb156c4f51ed2e9d25","effd9ef509383d536b1c8af5bf434c8efbf521a4f2befd4022bbd68694b4ac75"]}`, + }, + }, + { + name: "apiAddress v2", + r: newGetRequest(ts.URL + "/api/v2/address/mv9uLThosiEnGRbVPS7Vhyw6VssbVRsiAw"), + status: http.StatusOK, + contentType: "application/json; charset=utf-8", + body: []string{ + `{"page":1,"totalPages":1,"itemsOnPage":1000,"address":"mv9uLThosiEnGRbVPS7Vhyw6VssbVRsiAw","balance":"0","totalReceived":"1234567890123","totalSent":"1234567890123","unconfirmedBalance":"0","unconfirmedTxs":0,"txs":2,"txids":["7c3be24063f268aaa1ed81b64776798f56088757641a34fb156c4f51ed2e9d25","effd9ef509383d536b1c8af5bf434c8efbf521a4f2befd4022bbd68694b4ac75"]}`, + }, + }, + { + name: "apiAddress v2 details=basic", + r: newGetRequest(ts.URL + "/api/v2/address/mv9uLThosiEnGRbVPS7Vhyw6VssbVRsiAw?details=basic"), + status: http.StatusOK, + contentType: "application/json; charset=utf-8", + body: []string{ + `{"address":"mv9uLThosiEnGRbVPS7Vhyw6VssbVRsiAw","balance":"0","totalReceived":"1234567890123","totalSent":"1234567890123","unconfirmedBalance":"0","unconfirmedTxs":0,"txs":2}`, + }, + }, + { + name: "apiAddress v2 details=txs", + r: newGetRequest(ts.URL + "/api/v2/address/mv9uLThosiEnGRbVPS7Vhyw6VssbVRsiAw?details=txs"), + status: http.StatusOK, + contentType: "application/json; charset=utf-8", + body: []string{ + `{"page":1,"totalPages":1,"itemsOnPage":1000,"address":"mv9uLThosiEnGRbVPS7Vhyw6VssbVRsiAw","balance":"0","totalReceived":"1234567890123","totalSent":"1234567890123","unconfirmedBalance":"0","unconfirmedTxs":0,"txs":2,"transactions":[{"txid":"7c3be24063f268aaa1ed81b64776798f56088757641a34fb156c4f51ed2e9d25","vin":[{"txid":"effd9ef509383d536b1c8af5bf434c8efbf521a4f2befd4022bbd68694b4ac75","n":0,"addresses":["mv9uLThosiEnGRbVPS7Vhyw6VssbVRsiAw"],"isAddress":true,"isOwn":true,"value":"1234567890123"},{"txid":"00b2c06055e5e90e9c82bd4181fde310104391a7fa4f289b1704e5d90caa3840","vout":1,"n":1,"addresses":["mtGXQvBowMkBpnhLckhxhbwYK44Gs9eEtz"],"isAddress":true,"value":"12345"}],"vout":[{"value":"317283951061","n":0,"spent":true,"hex":"76a914ccaaaf374e1b06cb83118453d102587b4273d09588ac","addresses":["mzB8cYrfRwFRFAGTDzV8LkUQy5BQicxGhX"],"isAddress":true},{"value":"917283951061","n":1,"hex":"76a9148d802c045445df49613f6a70ddd2e48526f3701f88ac","addresses":["mtR97eM2HPWVM6c8FGLGcukgaHHQv7THoL"],"isAddress":true},{"value":"0","n":2,"hex":"6a072020f1686f6a20","addresses":["OP_RETURN 2020f1686f6a20"],"isAddress":false}],"blockHash":"00000000eb0443fd7dc4a1ed5c686a8e995057805f9a161d9a5a77a95e72b7b6","blockHeight":225494,"confirmations":1,"blockTime":1521595678,"value":"1234567902122","valueIn":"1234567902468","fees":"346"},{"txid":"effd9ef509383d536b1c8af5bf434c8efbf521a4f2befd4022bbd68694b4ac75","vin":[],"vout":[{"value":"1234567890123","n":0,"spent":true,"hex":"76a914a08eae93007f22668ab5e4a9c83c8cd1c325e3e088ac","addresses":["mv9uLThosiEnGRbVPS7Vhyw6VssbVRsiAw"],"isAddress":true,"isOwn":true},{"value":"1","n":1,"spent":true,"hex":"a91452724c5178682f70e0ba31c6ec0633755a3b41d987","addresses":["2MzmAKayJmja784jyHvRUW1bXPget1csRRG"],"isAddress":true},{"value":"9876","n":2,"spent":true,"hex":"a914e921fc4912a315078f370d959f2c4f7b6d2a683c87","addresses":["2NEVv9LJmAnY99W1pFoc5UJjVdypBqdnvu1"],"isAddress":true}],"blockHash":"0000000076fbbed90fd75b0e18856aa35baa984e9c9d444cf746ad85e94e2997","blockHeight":225493,"confirmations":2,"blockTime":1521515026,"value":"1234567900000","valueIn":"0","fees":"0"}]}`, + }, + }, + { + name: "apiAddress v2 missing address", + r: newGetRequest(ts.URL + "/api/v2/address/"), + status: http.StatusBadRequest, + contentType: "application/json; charset=utf-8", + body: []string{ + `{"error":"Missing address"}`, + }, + }, + { + name: "apiXpub v2 default", + r: newGetRequest(ts.URL + "/api/v2/xpub/" + dbtestdata.Xpub), + status: http.StatusOK, + contentType: "application/json; charset=utf-8", + body: []string{ + `{"page":1,"totalPages":1,"itemsOnPage":1000,"address":"upub5E1xjDmZ7Hhej6LPpS8duATdKXnRYui7bDYj6ehfFGzWDZtmCmQkZhc3Zb7kgRLtHWd16QFxyP86JKL3ShZEBFX88aciJ3xyocuyhZZ8g6q","balance":"118641975500","totalReceived":"118641975501","totalSent":"1","unconfirmedBalance":"0","unconfirmedTxs":0,"txs":2,"addrTxCount":3,"txids":["3d90d15ed026dc45e19ffb52875ed18fa9e8012ad123d7f7212176e2b0ebdb71","effd9ef509383d536b1c8af5bf434c8efbf521a4f2befd4022bbd68694b4ac75"],"usedTokens":2,"tokens":[{"type":"XPUBAddress","name":"2N6utyMZfPNUb1Bk8oz7p2JqJrXkq83gegu","path":"m/49'/1'/33'/1/3","transfers":1,"decimals":8,"balance":"118641975500","totalReceived":"118641975500","totalSent":"0"}]}`, + }, + }, + { + name: "apiXpub v2 tokens=used", + r: newGetRequest(ts.URL + "/api/v2/xpub/" + dbtestdata.Xpub + "?tokens=used"), + status: http.StatusOK, + contentType: "application/json; charset=utf-8", + body: []string{ + `{"page":1,"totalPages":1,"itemsOnPage":1000,"address":"upub5E1xjDmZ7Hhej6LPpS8duATdKXnRYui7bDYj6ehfFGzWDZtmCmQkZhc3Zb7kgRLtHWd16QFxyP86JKL3ShZEBFX88aciJ3xyocuyhZZ8g6q","balance":"118641975500","totalReceived":"118641975501","totalSent":"1","unconfirmedBalance":"0","unconfirmedTxs":0,"txs":2,"addrTxCount":3,"txids":["3d90d15ed026dc45e19ffb52875ed18fa9e8012ad123d7f7212176e2b0ebdb71","effd9ef509383d536b1c8af5bf434c8efbf521a4f2befd4022bbd68694b4ac75"],"usedTokens":2,"tokens":[{"type":"XPUBAddress","name":"2MzmAKayJmja784jyHvRUW1bXPget1csRRG","path":"m/49'/1'/33'/0/0","transfers":2,"decimals":8,"balance":"0","totalReceived":"1","totalSent":"1"},{"type":"XPUBAddress","name":"2N6utyMZfPNUb1Bk8oz7p2JqJrXkq83gegu","path":"m/49'/1'/33'/1/3","transfers":1,"decimals":8,"balance":"118641975500","totalReceived":"118641975500","totalSent":"0"}]}`, + }, + }, + { + name: "apiXpub v2 tokens=derived", + r: newGetRequest(ts.URL + "/api/v2/xpub/" + dbtestdata.Xpub + "?tokens=derived"), + status: http.StatusOK, + contentType: "application/json; charset=utf-8", + body: []string{ + `{"page":1,"totalPages":1,"itemsOnPage":1000,"address":"upub5E1xjDmZ7Hhej6LPpS8duATdKXnRYui7bDYj6ehfFGzWDZtmCmQkZhc3Zb7kgRLtHWd16QFxyP86JKL3ShZEBFX88aciJ3xyocuyhZZ8g6q","balance":"118641975500","totalReceived":"118641975501","totalSent":"1","unconfirmedBalance":"0","unconfirmedTxs":0,"txs":2,"addrTxCount":3,"txids":["3d90d15ed026dc45e19ffb52875ed18fa9e8012ad123d7f7212176e2b0ebdb71","effd9ef509383d536b1c8af5bf434c8efbf521a4f2befd4022bbd68694b4ac75"],"usedTokens":2,"tokens":[{"type":"XPUBAddress","name":"2MzmAKayJmja784jyHvRUW1bXPget1csRRG","path":"m/49'/1'/33'/0/0","transfers":2,"decimals":8,"balance":"0","totalReceived":"1","totalSent":"1"},{"type":"XPUBAddress","name":"2MsYfbi6ZdVXLDNrYAQ11ja9Sd3otMk4Pmj","path":"m/49'/1'/33'/0/1","transfers":0,"decimals":8},{"type":"XPUBAddress","name":"2MuAZNAjLSo6RLFad2fvHSfgqBD7BoEVy4T","path":"m/49'/1'/33'/0/2","transfers":0,"decimals":8},{"type":"XPUBAddress","name":"2NEqKzw3BosGnBE9by5uaDy5QgwjHac4Zbg","path":"m/49'/1'/33'/0/3","transfers":0,"decimals":8},{"type":"XPUBAddress","name":"2Mw7vJNC8zUK6VNN4CEjtoTYmuNPLewxZzV","path":"m/49'/1'/33'/0/4","transfers":0,"decimals":8},{"type":"XPUBAddress","name":"2N1kvo97NFASPXiwephZUxE9PRXunjTxEc4","path":"m/49'/1'/33'/0/5","transfers":0,"decimals":8},{"type":"XPUBAddress","name":"2MuWrWMzoBt8VDFNvPmpJf42M1GTUs85fPx","path":"m/49'/1'/33'/0/6","transfers":0,"decimals":8},{"type":"XPUBAddress","name":"2MuVZ2Ca6Da9zmYynt49Rx7uikAgubGcymF","path":"m/49'/1'/33'/0/7","transfers":0,"decimals":8},{"type":"XPUBAddress","name":"2MzRGWDUmrPP9HwYu4B43QGCTLwoop5cExa","path":"m/49'/1'/33'/0/8","transfers":0,"decimals":8},{"type":"XPUBAddress","name":"2N5C9EEWJzyBXhpyPHqa3UNed73Amsi5b3L","path":"m/49'/1'/33'/0/9","transfers":0,"decimals":8},{"type":"XPUBAddress","name":"2MzNawz2zjwq1L85GDE3YydEJGJYfXxaWkk","path":"m/49'/1'/33'/0/10","transfers":0,"decimals":8},{"type":"XPUBAddress","name":"2N7NdeuAMgL57WE7QCeV2gTWi2Um8iAu5dA","path":"m/49'/1'/33'/0/11","transfers":0,"decimals":8},{"type":"XPUBAddress","name":"2N8JQEP6DSHEZHNsSDPA1gHMUq9YFndhkfV","path":"m/49'/1'/33'/0/12","transfers":0,"decimals":8},{"type":"XPUBAddress","name":"2Mvbn3YXqKZVpQKugaoQrfjSYPvz76RwZkC","path":"m/49'/1'/33'/0/13","transfers":0,"decimals":8},{"type":"XPUBAddress","name":"2N8MRNxCfwUY9TSW27X9ooGYtqgrGCfLRHx","path":"m/49'/1'/33'/0/14","transfers":0,"decimals":8},{"type":"XPUBAddress","name":"2N6HvwrHC113KYZAmCtJ9XJNWgaTcnFunCM","path":"m/49'/1'/33'/0/15","transfers":0,"decimals":8},{"type":"XPUBAddress","name":"2NEo3oNyHUoi7rmRWee7wki37jxPWsWCopJ","path":"m/49'/1'/33'/0/16","transfers":0,"decimals":8},{"type":"XPUBAddress","name":"2Mzm5KY8qdFbDHsQfy4akXbFvbR3FAwDuVo","path":"m/49'/1'/33'/0/17","transfers":0,"decimals":8},{"type":"XPUBAddress","name":"2NGMwftmQCogp6XZNGvgiybz3WZysvsJzqC","path":"m/49'/1'/33'/0/18","transfers":0,"decimals":8},{"type":"XPUBAddress","name":"2N3fJrrefndYjLGycvFFfYgevpZtcRKCkRD","path":"m/49'/1'/33'/0/19","transfers":0,"decimals":8},{"type":"XPUBAddress","name":"2N1T7TnHBwfdpBoyw53EGUL7vuJmb2mU6jF","path":"m/49'/1'/33'/0/20","transfers":0,"decimals":8},{"type":"XPUBAddress","name":"2MzSBtRWHbBjeUcu3H5VRDqkvz5sfmDxJKo","path":"m/49'/1'/33'/1/0","transfers":0,"decimals":8},{"type":"XPUBAddress","name":"2MtShtAJYb1afWduUTwF1SixJjan7urZKke","path":"m/49'/1'/33'/1/1","transfers":0,"decimals":8},{"type":"XPUBAddress","name":"2N3cP668SeqyBEr9gnB4yQEmU3VyxeRYith","path":"m/49'/1'/33'/1/2","transfers":0,"decimals":8},{"type":"XPUBAddress","name":"2N6utyMZfPNUb1Bk8oz7p2JqJrXkq83gegu","path":"m/49'/1'/33'/1/3","transfers":1,"decimals":8,"balance":"118641975500","totalReceived":"118641975500","totalSent":"0"},{"type":"XPUBAddress","name":"2NEzatauNhf9kPTwwj6ZfYKjUdy52j4hVUL","path":"m/49'/1'/33'/1/4","transfers":0,"decimals":8},{"type":"XPUBAddress","name":"2N4RjsDp4LBpkNqyF91aNjgpF9CwDwBkJZq","path":"m/49'/1'/33'/1/5","transfers":0,"decimals":8},{"type":"XPUBAddress","name":"2N8XygTmQc4NoBBPEy3yybnfCYhsxFtzPDY","path":"m/49'/1'/33'/1/6","transfers":0,"decimals":8},{"type":"XPUBAddress","name":"2N5BjBomZvb48sccK2vwLMiQ5ETKp1fdPVn","path":"m/49'/1'/33'/1/7","transfers":0,"decimals":8},{"type":"XPUBAddress","name":"2MybMwbZRPCGU3SMWPwQCpDkbcQFw5Hbwen","path":"m/49'/1'/33'/1/8","transfers":0,"decimals":8},{"type":"XPUBAddress","name":"2N7HexL4dyAQc7Th4iqcCW4hZuyiZsLWf74","path":"m/49'/1'/33'/1/9","transfers":0,"decimals":8},{"type":"XPUBAddress","name":"2NF6X5FDGWrQj4nQrfP6hA77zB5WAc1DGup","path":"m/49'/1'/33'/1/10","transfers":0,"decimals":8},{"type":"XPUBAddress","name":"2N4ZRPdvc7BVioBTohy4F6QtxreqcjNj26b","path":"m/49'/1'/33'/1/11","transfers":0,"decimals":8},{"type":"XPUBAddress","name":"2Mtfho1rLmevh4qTnkYWxZEFCWteDMtTcUF","path":"m/49'/1'/33'/1/12","transfers":0,"decimals":8},{"type":"XPUBAddress","name":"2NFUCphKYvmMcNZRZrF261mRX6iADVB9Qms","path":"m/49'/1'/33'/1/13","transfers":0,"decimals":8},{"type":"XPUBAddress","name":"2N5kBNMB8qgxE4Y4f8J19fScsE49J4aNvoJ","path":"m/49'/1'/33'/1/14","transfers":0,"decimals":8},{"type":"XPUBAddress","name":"2NANWCaefhCKdXMcW8NbZnnrFRDvhJN2wPy","path":"m/49'/1'/33'/1/15","transfers":0,"decimals":8},{"type":"XPUBAddress","name":"2NFHw7Yo2Bz8D2wGAYHW9qidbZFLpfJ72qB","path":"m/49'/1'/33'/1/16","transfers":0,"decimals":8},{"type":"XPUBAddress","name":"2NBDSsBgy5PpFniLCb1eAFHcSxgxwPSDsZa","path":"m/49'/1'/33'/1/17","transfers":0,"decimals":8},{"type":"XPUBAddress","name":"2NDWCSQHogc7sCuc2WoYt9PX2i2i6a5k6dX","path":"m/49'/1'/33'/1/18","transfers":0,"decimals":8},{"type":"XPUBAddress","name":"2N8vNyDP7iSDjm3BKpXrbDjAxyphqfvnJz8","path":"m/49'/1'/33'/1/19","transfers":0,"decimals":8},{"type":"XPUBAddress","name":"2N4tFKLurSbMusAyq1tv4tzymVjveAFV1Vb","path":"m/49'/1'/33'/1/20","transfers":0,"decimals":8},{"type":"XPUBAddress","name":"2NBx5WwjAr2cH6Yqrp3Vsf957HtRKwDUVdX","path":"m/49'/1'/33'/1/21","transfers":0,"decimals":8},{"type":"XPUBAddress","name":"2NBu1seHTaFhQxbcW5L5BkZzqFLGmZqpxsa","path":"m/49'/1'/33'/1/22","transfers":0,"decimals":8},{"type":"XPUBAddress","name":"2NCDLoea22jGsXuarfT1n2QyCUh6RFhAPnT","path":"m/49'/1'/33'/1/23","transfers":0,"decimals":8}]}`, + }, + }, + { + name: "apiXpub v2 taproot descriptor tokens=derived", + r: newGetRequest(ts.URL + "/api/v2/xpub/" + url.QueryEscape(dbtestdata.TaprootDescriptor) + "?tokens=derived&gap=2"), + status: http.StatusOK, + contentType: "application/json; charset=utf-8", + body: []string{ + `{"page":1,"totalPages":1,"itemsOnPage":1000,"address":"tr([5c9e228d/86'/1'/0']tpubDC88gkaZi5HvJGxGDNLADkvtdpni3mLmx6vr2KnXmWMG8zfkBRggsxHVBkUpgcwPe2KKpkyvTJCdXHb1UHEWE64vczyyPQfHr1skBcsRedN/{0,1}/*)#4rqwxvej","balance":"0","totalReceived":"0","totalSent":"0","unconfirmedBalance":"0","unconfirmedTxs":0,"txs":0,"tokens":[{"type":"XPUBAddress","name":"tb1pswrqtykue8r89t9u4rprjs0gt4qzkdfuursfnvqaa3f2yql07zmq8s8a5u","path":"m/86'/1'/0'/0/0","transfers":0,"decimals":8},{"type":"XPUBAddress","name":"tb1p8tvmvsvhsee73rhym86wt435qrqm92psfsyhy6a3n5gw455znnpqm8wald","path":"m/86'/1'/0'/0/1","transfers":0,"decimals":8},{"type":"XPUBAddress","name":"tb1p537ddhyuydg5c2v75xxmn6ac64yz4xns2x0gpdcwj5vzzzgrywlqlqwk43","path":"m/86'/1'/0'/0/2","transfers":0,"decimals":8},{"type":"XPUBAddress","name":"tb1pn2d0yjeedavnkd8z8lhm566p0f2utm3lgvxrsdehnl94y34txmts5s7t4c","path":"m/86'/1'/0'/1/0","transfers":0,"decimals":8},{"type":"XPUBAddress","name":"tb1p0pnd6ue5vryymvd28aeq3kdz6rmsdjqrq6eespgtg8wdgnxjzjksujhq4u","path":"m/86'/1'/0'/1/1","transfers":0,"decimals":8},{"type":"XPUBAddress","name":"tb1p29gpmd96hhgf7wj2vs03ca7x2xx39g8t6e0p55h2d5ssqs4fsj8qtx00wc","path":"m/86'/1'/0'/1/2","transfers":0,"decimals":8}]}`, + }, + }, + { + name: "apiXpub v2 details=basic", + r: newGetRequest(ts.URL + "/api/v2/xpub/" + dbtestdata.Xpub + "?details=basic"), + status: http.StatusOK, + contentType: "application/json; charset=utf-8", + body: []string{ + `{"address":"upub5E1xjDmZ7Hhej6LPpS8duATdKXnRYui7bDYj6ehfFGzWDZtmCmQkZhc3Zb7kgRLtHWd16QFxyP86JKL3ShZEBFX88aciJ3xyocuyhZZ8g6q","balance":"118641975500","totalReceived":"118641975501","totalSent":"1","unconfirmedBalance":"0","unconfirmedTxs":0,"txs":3,"addrTxCount":3,"usedTokens":2}`, + }, + }, + { + name: "apiXpub v2 details=tokens?tokens=used", + r: newGetRequest(ts.URL + "/api/v2/xpub/" + dbtestdata.Xpub + "?details=tokens&tokens=used"), + status: http.StatusOK, + contentType: "application/json; charset=utf-8", + body: []string{ + `{"address":"upub5E1xjDmZ7Hhej6LPpS8duATdKXnRYui7bDYj6ehfFGzWDZtmCmQkZhc3Zb7kgRLtHWd16QFxyP86JKL3ShZEBFX88aciJ3xyocuyhZZ8g6q","balance":"118641975500","totalReceived":"118641975501","totalSent":"1","unconfirmedBalance":"0","unconfirmedTxs":0,"txs":3,"addrTxCount":3,"usedTokens":2,"tokens":[{"type":"XPUBAddress","name":"2MzmAKayJmja784jyHvRUW1bXPget1csRRG","path":"m/49'/1'/33'/0/0","transfers":2,"decimals":8},{"type":"XPUBAddress","name":"2N6utyMZfPNUb1Bk8oz7p2JqJrXkq83gegu","path":"m/49'/1'/33'/1/3","transfers":1,"decimals":8}]}`, + }, + }, + { + name: "apiXpub v2 details=tokenBalances", + r: newGetRequest(ts.URL + "/api/v2/xpub/" + dbtestdata.Xpub + "?details=tokenBalances"), + status: http.StatusOK, + contentType: "application/json; charset=utf-8", + body: []string{ + `{"address":"upub5E1xjDmZ7Hhej6LPpS8duATdKXnRYui7bDYj6ehfFGzWDZtmCmQkZhc3Zb7kgRLtHWd16QFxyP86JKL3ShZEBFX88aciJ3xyocuyhZZ8g6q","balance":"118641975500","totalReceived":"118641975501","totalSent":"1","unconfirmedBalance":"0","unconfirmedTxs":0,"txs":3,"addrTxCount":3,"usedTokens":2,"tokens":[{"type":"XPUBAddress","name":"2N6utyMZfPNUb1Bk8oz7p2JqJrXkq83gegu","path":"m/49'/1'/33'/1/3","transfers":1,"decimals":8,"balance":"118641975500","totalReceived":"118641975500","totalSent":"0"}]}`, + }, + }, + { + name: "apiXpub v2 details=txs&tokens=derived&gap=5&from=225494&to=225494&pageSize=3", + r: newGetRequest(ts.URL + "/api/v2/xpub/" + dbtestdata.Xpub + "?details=txs&tokens=derived&gap=5&from=225494&to=225494&pageSize=3"), + status: http.StatusOK, + contentType: "application/json; charset=utf-8", + body: []string{ + `{"page":1,"totalPages":1,"itemsOnPage":3,"address":"upub5E1xjDmZ7Hhej6LPpS8duATdKXnRYui7bDYj6ehfFGzWDZtmCmQkZhc3Zb7kgRLtHWd16QFxyP86JKL3ShZEBFX88aciJ3xyocuyhZZ8g6q","balance":"118641975500","totalReceived":"118641975501","totalSent":"1","unconfirmedBalance":"0","unconfirmedTxs":0,"txs":2,"addrTxCount":3,"transactions":[{"txid":"3d90d15ed026dc45e19ffb52875ed18fa9e8012ad123d7f7212176e2b0ebdb71","vin":[{"txid":"7c3be24063f268aaa1ed81b64776798f56088757641a34fb156c4f51ed2e9d25","n":0,"addresses":["mzB8cYrfRwFRFAGTDzV8LkUQy5BQicxGhX"],"isAddress":true,"value":"317283951061"},{"txid":"effd9ef509383d536b1c8af5bf434c8efbf521a4f2befd4022bbd68694b4ac75","vout":1,"n":1,"addresses":["2MzmAKayJmja784jyHvRUW1bXPget1csRRG"],"isAddress":true,"isOwn":true,"value":"1"}],"vout":[{"value":"118641975500","n":0,"hex":"a91495e9fbe306449c991d314afe3c3567d5bf78efd287","addresses":["2N6utyMZfPNUb1Bk8oz7p2JqJrXkq83gegu"],"isAddress":true,"isOwn":true},{"value":"198641975500","n":1,"hex":"76a9143f8ba3fda3ba7b69f5818086e12223c6dd25e3c888ac","addresses":["mmJx9Y8ayz9h14yd9fgCW1bUKoEpkBAquP"],"isAddress":true}],"blockHash":"00000000eb0443fd7dc4a1ed5c686a8e995057805f9a161d9a5a77a95e72b7b6","blockHeight":225494,"confirmations":1,"blockTime":1521595678,"value":"317283951000","valueIn":"317283951062","fees":"62"}],"usedTokens":2,"tokens":[{"type":"XPUBAddress","name":"2MzmAKayJmja784jyHvRUW1bXPget1csRRG","path":"m/49'/1'/33'/0/0","transfers":2,"decimals":8,"balance":"0","totalReceived":"1","totalSent":"1"},{"type":"XPUBAddress","name":"2MsYfbi6ZdVXLDNrYAQ11ja9Sd3otMk4Pmj","path":"m/49'/1'/33'/0/1","transfers":0,"decimals":8},{"type":"XPUBAddress","name":"2MuAZNAjLSo6RLFad2fvHSfgqBD7BoEVy4T","path":"m/49'/1'/33'/0/2","transfers":0,"decimals":8},{"type":"XPUBAddress","name":"2NEqKzw3BosGnBE9by5uaDy5QgwjHac4Zbg","path":"m/49'/1'/33'/0/3","transfers":0,"decimals":8},{"type":"XPUBAddress","name":"2Mw7vJNC8zUK6VNN4CEjtoTYmuNPLewxZzV","path":"m/49'/1'/33'/0/4","transfers":0,"decimals":8},{"type":"XPUBAddress","name":"2N1kvo97NFASPXiwephZUxE9PRXunjTxEc4","path":"m/49'/1'/33'/0/5","transfers":0,"decimals":8},{"type":"XPUBAddress","name":"2MzSBtRWHbBjeUcu3H5VRDqkvz5sfmDxJKo","path":"m/49'/1'/33'/1/0","transfers":0,"decimals":8},{"type":"XPUBAddress","name":"2MtShtAJYb1afWduUTwF1SixJjan7urZKke","path":"m/49'/1'/33'/1/1","transfers":0,"decimals":8},{"type":"XPUBAddress","name":"2N3cP668SeqyBEr9gnB4yQEmU3VyxeRYith","path":"m/49'/1'/33'/1/2","transfers":0,"decimals":8},{"type":"XPUBAddress","name":"2N6utyMZfPNUb1Bk8oz7p2JqJrXkq83gegu","path":"m/49'/1'/33'/1/3","transfers":1,"decimals":8,"balance":"118641975500","totalReceived":"118641975500","totalSent":"0"},{"type":"XPUBAddress","name":"2NEzatauNhf9kPTwwj6ZfYKjUdy52j4hVUL","path":"m/49'/1'/33'/1/4","transfers":0,"decimals":8},{"type":"XPUBAddress","name":"2N4RjsDp4LBpkNqyF91aNjgpF9CwDwBkJZq","path":"m/49'/1'/33'/1/5","transfers":0,"decimals":8},{"type":"XPUBAddress","name":"2N8XygTmQc4NoBBPEy3yybnfCYhsxFtzPDY","path":"m/49'/1'/33'/1/6","transfers":0,"decimals":8},{"type":"XPUBAddress","name":"2N5BjBomZvb48sccK2vwLMiQ5ETKp1fdPVn","path":"m/49'/1'/33'/1/7","transfers":0,"decimals":8},{"type":"XPUBAddress","name":"2MybMwbZRPCGU3SMWPwQCpDkbcQFw5Hbwen","path":"m/49'/1'/33'/1/8","transfers":0,"decimals":8}]}`, + }, + }, + { + name: "apiXpub v2 missing xpub", + r: newGetRequest(ts.URL + "/api/v2/xpub/"), + status: http.StatusBadRequest, + contentType: "application/json; charset=utf-8", + body: []string{ + `{"error":"Missing xpub"}`, + }, + }, + { + name: "apiUtxo v1", + r: newGetRequest(ts.URL + "/api/v1/utxo/mtR97eM2HPWVM6c8FGLGcukgaHHQv7THoL"), + status: http.StatusOK, + contentType: "application/json; charset=utf-8", + body: []string{ + `[{"txid":"7c3be24063f268aaa1ed81b64776798f56088757641a34fb156c4f51ed2e9d25","vout":1,"amount":"9172.83951061","satoshis":917283951061,"height":225494,"confirmations":1}]`, + }, + }, + { + name: "apiUtxo v2", + r: newGetRequest(ts.URL + "/api/v2/utxo/mtR97eM2HPWVM6c8FGLGcukgaHHQv7THoL"), + status: http.StatusOK, + contentType: "application/json; charset=utf-8", + body: []string{ + `[{"txid":"7c3be24063f268aaa1ed81b64776798f56088757641a34fb156c4f51ed2e9d25","vout":1,"value":"917283951061","height":225494,"confirmations":1}]`, + }, + }, + { + name: "apiUtxo v2 xpub", + r: newGetRequest(ts.URL + "/api/v2/utxo/" + dbtestdata.Xpub), + status: http.StatusOK, + contentType: "application/json; charset=utf-8", + body: []string{ + `[{"txid":"3d90d15ed026dc45e19ffb52875ed18fa9e8012ad123d7f7212176e2b0ebdb71","vout":0,"value":"118641975500","height":225494,"confirmations":1,"address":"2N6utyMZfPNUb1Bk8oz7p2JqJrXkq83gegu","path":"m/49'/1'/33'/1/3"}]`, + }, + }, + { + name: "apiUtxo v2 xpub", + r: newGetRequest(ts.URL + "/api/v2/utxo/" + url.QueryEscape(dbtestdata.TaprootDescriptor)), + status: http.StatusOK, + contentType: "application/json; charset=utf-8", + body: []string{ + `[]`, + }, + }, + { + name: "apiBalanceHistory Addr2 v2", + r: newGetRequest(ts.URL + "/api/v2/balancehistory/mtGXQvBowMkBpnhLckhxhbwYK44Gs9eEtz"), + status: http.StatusOK, + contentType: "application/json; charset=utf-8", + body: []string{ + `[{"time":1521514800,"txs":1,"received":"24690","sent":"0","sentToSelf":"0","rates":{"eur":1301,"usd":2001}},{"time":1521594000,"txs":1,"received":"0","sent":"12345","sentToSelf":"0","rates":{"eur":1302,"usd":2002}}]`, + }, + }, + { + name: "apiBalanceHistory Addr5 v2", + r: newGetRequest(ts.URL + "/api/v2/balancehistory/2NEVv9LJmAnY99W1pFoc5UJjVdypBqdnvu1"), + status: http.StatusOK, + contentType: "application/json; charset=utf-8", + body: []string{ + `[{"time":1521514800,"txs":1,"received":"9876","sent":"0","sentToSelf":"0","rates":{"eur":1301,"usd":2001}},{"time":1521594000,"txs":1,"received":"9000","sent":"9876","sentToSelf":"9000","rates":{"eur":1302,"usd":2002}}]`, + }, + }, + { + name: "apiBalanceHistory Addr5 v2 fiatcurrency=eur", + r: newGetRequest(ts.URL + "/api/v2/balancehistory/2NEVv9LJmAnY99W1pFoc5UJjVdypBqdnvu1?fiatcurrency=eur"), + status: http.StatusOK, + contentType: "application/json; charset=utf-8", + body: []string{ + `[{"time":1521514800,"txs":1,"received":"9876","sent":"0","sentToSelf":"0","rates":{"eur":1301}},{"time":1521594000,"txs":1,"received":"9000","sent":"9876","sentToSelf":"9000","rates":{"eur":1302}}]`, + }, + }, + { + name: "apiBalanceHistory Addr2 v2 from=1521504000&to=1521590400", + r: newGetRequest(ts.URL + "/api/v2/balancehistory/mtGXQvBowMkBpnhLckhxhbwYK44Gs9eEtz?from=1521504000&to=1521590400"), + status: http.StatusOK, + contentType: "application/json; charset=utf-8", + body: []string{ + `[{"time":1521514800,"txs":1,"received":"24690","sent":"0","sentToSelf":"0","rates":{"eur":1301,"usd":2001}}]`, + }, + }, + { + name: "apiBalanceHistory xpub v2", + r: newGetRequest(ts.URL + "/api/v2/balancehistory/" + dbtestdata.Xpub), + status: http.StatusOK, + contentType: "application/json; charset=utf-8", + body: []string{ + `[{"time":1521514800,"txs":1,"received":"1","sent":"0","sentToSelf":"0","rates":{"eur":1301,"usd":2001}},{"time":1521594000,"txs":1,"received":"118641975500","sent":"1","sentToSelf":"118641975500","rates":{"eur":1302,"usd":2002}}]`, + }, + }, + { + name: "apiBalanceHistory xpub v2 from=1521504000&to=1521590400", + r: newGetRequest(ts.URL + "/api/v2/balancehistory/" + dbtestdata.Xpub + "?from=1521504000&to=1521590400"), + status: http.StatusOK, + contentType: "application/json; charset=utf-8", + body: []string{ + `[{"time":1521514800,"txs":1,"received":"1","sent":"0","sentToSelf":"0","rates":{"eur":1301,"usd":2001}}]`, + }, + }, + { + name: "apiBalanceHistory xpub v2 from=1521504000&to=1521590400&fiatcurrency=usd", + r: newGetRequest(ts.URL + "/api/v2/balancehistory/" + dbtestdata.Xpub + "?from=1521504000&to=1521590400&fiatcurrency=usd"), + status: http.StatusOK, + contentType: "application/json; charset=utf-8", + body: []string{ + `[{"time":1521514800,"txs":1,"received":"1","sent":"0","sentToSelf":"0","rates":{"usd":2001}}]`, + }, + }, + { + name: "apiBalanceHistory xpub v2 from=1521590400", + r: newGetRequest(ts.URL + "/api/v2/balancehistory/" + dbtestdata.Xpub + "?from=1521590400"), + status: http.StatusOK, + contentType: "application/json; charset=utf-8", + body: []string{ + `[{"time":1521594000,"txs":1,"received":"118641975500","sent":"1","sentToSelf":"118641975500","rates":{"eur":1302,"usd":2002}}]`, + }, + }, + { + name: "apiSendTx", + r: newGetRequest(ts.URL + "/api/v2/sendtx/1234567890"), + status: http.StatusBadRequest, + contentType: "application/json; charset=utf-8", + body: []string{ + `{"error":"Invalid data"}`, + }, + }, + { + name: "apiSendTx POST", + r: newPostRequest(ts.URL+"/api/v2/sendtx/", "123456"), + status: http.StatusOK, + contentType: "application/json; charset=utf-8", + body: []string{ + `{"result":"9876"}`, + }, + }, + { + name: "apiSendTx POST empty", + r: newPostRequest(ts.URL+"/api/v2/sendtx", ""), + status: http.StatusBadRequest, + contentType: "application/json; charset=utf-8", + body: []string{ + `{"error":"Missing tx blob"}`, + }, + }, + { + name: "apiEstimateFee", + r: newGetRequest(ts.URL + "/api/estimatefee/123?conservative=false"), + status: http.StatusOK, + contentType: "application/json; charset=utf-8", + body: []string{ + `{"result":"0.00012299"}`, + }, + }, + { + name: "apiGetBlock", + r: newGetRequest(ts.URL + "/api/v2/block/225493"), + status: http.StatusOK, + contentType: "application/json; charset=utf-8", + body: []string{ + `{"page":1,"totalPages":1,"itemsOnPage":1000,"hash":"0000000076fbbed90fd75b0e18856aa35baa984e9c9d444cf746ad85e94e2997","nextBlockHash":"00000000eb0443fd7dc4a1ed5c686a8e995057805f9a161d9a5a77a95e72b7b6","height":225493,"confirmations":2,"size":1234567,"time":1521515026,"version":0,"merkleRoot":"","nonce":"","bits":"","difficulty":"","txCount":2,"txs":[{"txid":"00b2c06055e5e90e9c82bd4181fde310104391a7fa4f289b1704e5d90caa3840","vin":[],"vout":[{"value":"100000000","n":0,"addresses":["mfcWp7DB6NuaZsExybTTXpVgWz559Np4Ti"],"isAddress":true},{"value":"12345","n":1,"spent":true,"addresses":["mtGXQvBowMkBpnhLckhxhbwYK44Gs9eEtz"],"isAddress":true},{"value":"12345","n":2,"addresses":["mtGXQvBowMkBpnhLckhxhbwYK44Gs9eEtz"],"isAddress":true}],"blockHash":"0000000076fbbed90fd75b0e18856aa35baa984e9c9d444cf746ad85e94e2997","blockHeight":225493,"confirmations":2,"blockTime":1521515026,"value":"100024690","valueIn":"0","fees":"0"},{"txid":"effd9ef509383d536b1c8af5bf434c8efbf521a4f2befd4022bbd68694b4ac75","vin":[],"vout":[{"value":"1234567890123","n":0,"spent":true,"addresses":["mv9uLThosiEnGRbVPS7Vhyw6VssbVRsiAw"],"isAddress":true},{"value":"1","n":1,"spent":true,"addresses":["2MzmAKayJmja784jyHvRUW1bXPget1csRRG"],"isAddress":true},{"value":"9876","n":2,"spent":true,"addresses":["2NEVv9LJmAnY99W1pFoc5UJjVdypBqdnvu1"],"isAddress":true}],"blockHash":"0000000076fbbed90fd75b0e18856aa35baa984e9c9d444cf746ad85e94e2997","blockHeight":225493,"confirmations":2,"blockTime":1521515026,"value":"1234567900000","valueIn":"0","fees":"0"}]}`, + }, + }, + { + name: "apiGetRawBlock", + r: newGetRequest(ts.URL + "/api/v2/rawblock/225493"), + status: http.StatusOK, + contentType: "application/json; charset=utf-8", + body: []string{ + `{"hex":"00e0ff3fd42677a86f1515bafcf9802c1765e02226655a9b97fd44132602000000000000"}`, + }, + }, + } + performHttpTests(tests, t, ts) +} + +func socketioTestsBitcoinType(t *testing.T, ts *httptest.Server) { + type socketioReq struct { + Method string `json:"method"` + Params []interface{} `json:"params"` + } + + url := strings.Replace(ts.URL, "http://", "ws://", 1) + "/socket.io/" + s, err := gosocketio.Dial(url, transport.GetDefaultWebsocketTransport()) + if err != nil { + t.Fatal(err) + } + defer s.Close() + + tests := []struct { + name string + req socketioReq + want string + }{ + { + name: "socketio getInfo", + req: socketioReq{"getInfo", []interface{}{}}, + want: `{"result":{"blocks":225494,"testnet":true,"network":"fakecoin","subversion":"/Fakecoin:0.0.1/","coin_name":"Fakecoin","about":"Blockbook - blockchain indexer for Trezor Suite https://trezor.io/trezor-suite. Do not use for any other purpose."}}`, + }, + { + name: "socketio estimateFee", + req: socketioReq{"estimateFee", []interface{}{17}}, + want: `{"result":0.000034}`, + }, + { + name: "socketio estimateSmartFee", + req: socketioReq{"estimateSmartFee", []interface{}{19, true}}, + want: `{"result":0.000019}`, + }, + { + name: "socketio getAddressTxids", + req: socketioReq{"getAddressTxids", []interface{}{ + []string{"mtGXQvBowMkBpnhLckhxhbwYK44Gs9eEtz"}, + map[string]interface{}{ + "start": 2000000, + "end": 0, + "queryMempool": false, + }, + }}, + want: `{"result":["7c3be24063f268aaa1ed81b64776798f56088757641a34fb156c4f51ed2e9d25","00b2c06055e5e90e9c82bd4181fde310104391a7fa4f289b1704e5d90caa3840"]}`, + }, + { + name: "socketio getAddressTxids limited range", + req: socketioReq{"getAddressTxids", []interface{}{ + []string{"mtGXQvBowMkBpnhLckhxhbwYK44Gs9eEtz"}, + map[string]interface{}{ + "start": 225494, + "end": 225494, + "queryMempool": false, + }, + }}, + want: `{"result":["7c3be24063f268aaa1ed81b64776798f56088757641a34fb156c4f51ed2e9d25"]}`, + }, + { + name: "socketio getAddressHistory", + req: socketioReq{"getAddressHistory", []interface{}{ + []string{"mtGXQvBowMkBpnhLckhxhbwYK44Gs9eEtz"}, + map[string]interface{}{ + "start": 2000000, + "end": 0, + "queryMempool": false, + "from": 0, + "to": 5, + }, + }}, + want: `{"result":{"totalCount":2,"items":[{"addresses":{"mtGXQvBowMkBpnhLckhxhbwYK44Gs9eEtz":{"inputIndexes":[1],"outputIndexes":[]}},"satoshis":-12345,"confirmations":1,"tx":{"hex":"","height":225494,"blockTimestamp":1521595678,"version":0,"hash":"7c3be24063f268aaa1ed81b64776798f56088757641a34fb156c4f51ed2e9d25","inputs":[{"txid":"effd9ef509383d536b1c8af5bf434c8efbf521a4f2befd4022bbd68694b4ac75","outputIndex":0,"script":"","sequence":0,"address":"mv9uLThosiEnGRbVPS7Vhyw6VssbVRsiAw","satoshis":1234567890123},{"txid":"00b2c06055e5e90e9c82bd4181fde310104391a7fa4f289b1704e5d90caa3840","outputIndex":1,"script":"","sequence":0,"address":"mtGXQvBowMkBpnhLckhxhbwYK44Gs9eEtz","satoshis":12345}],"inputSatoshis":1234567902468,"outputs":[{"satoshis":317283951061,"script":"76a914ccaaaf374e1b06cb83118453d102587b4273d09588ac","address":"mzB8cYrfRwFRFAGTDzV8LkUQy5BQicxGhX"},{"satoshis":917283951061,"script":"76a9148d802c045445df49613f6a70ddd2e48526f3701f88ac","address":"mtR97eM2HPWVM6c8FGLGcukgaHHQv7THoL"},{"satoshis":0,"script":"6a072020f1686f6a20","address":"OP_RETURN 2020f1686f6a20"}],"outputSatoshis":1234567902122,"feeSatoshis":346}},{"addresses":{"mtGXQvBowMkBpnhLckhxhbwYK44Gs9eEtz":{"inputIndexes":[],"outputIndexes":[1,2]}},"satoshis":24690,"confirmations":2,"tx":{"hex":"","height":225493,"blockTimestamp":1521515026,"version":0,"hash":"00b2c06055e5e90e9c82bd4181fde310104391a7fa4f289b1704e5d90caa3840","inputs":[],"outputs":[{"satoshis":100000000,"script":"76a914010d39800f86122416e28f485029acf77507169288ac","address":"mfcWp7DB6NuaZsExybTTXpVgWz559Np4Ti"},{"satoshis":12345,"script":"76a9148bdf0aa3c567aa5975c2e61321b8bebbe7293df688ac","address":"mtGXQvBowMkBpnhLckhxhbwYK44Gs9eEtz"},{"satoshis":12345,"script":"76a9148bdf0aa3c567aa5975c2e61321b8bebbe7293df688ac","address":"mtGXQvBowMkBpnhLckhxhbwYK44Gs9eEtz"}],"outputSatoshis":100024690}}]}}`, + }, + { + name: "socketio getBlockHeader", + req: socketioReq{"getBlockHeader", []interface{}{225493}}, + want: `{"result":{"hash":"0000000076fbbed90fd75b0e18856aa35baa984e9c9d444cf746ad85e94e2997","version":0,"confirmations":0,"height":0,"chainWork":"","nextHash":"","merkleRoot":"","time":0,"medianTime":0,"nonce":0,"bits":"","difficulty":0}}`, + }, + { + name: "socketio getDetailedTransaction", + req: socketioReq{"getDetailedTransaction", []interface{}{"3d90d15ed026dc45e19ffb52875ed18fa9e8012ad123d7f7212176e2b0ebdb71"}}, + want: `{"result":{"hex":"","height":225494,"blockTimestamp":1521595678,"version":0,"hash":"3d90d15ed026dc45e19ffb52875ed18fa9e8012ad123d7f7212176e2b0ebdb71","inputs":[{"txid":"7c3be24063f268aaa1ed81b64776798f56088757641a34fb156c4f51ed2e9d25","outputIndex":0,"script":"","sequence":0,"address":"mzB8cYrfRwFRFAGTDzV8LkUQy5BQicxGhX","satoshis":317283951061},{"txid":"effd9ef509383d536b1c8af5bf434c8efbf521a4f2befd4022bbd68694b4ac75","outputIndex":1,"script":"","sequence":0,"address":"2MzmAKayJmja784jyHvRUW1bXPget1csRRG","satoshis":1}],"inputSatoshis":317283951062,"outputs":[{"satoshis":118641975500,"script":"a91495e9fbe306449c991d314afe3c3567d5bf78efd287","address":"2N6utyMZfPNUb1Bk8oz7p2JqJrXkq83gegu"},{"satoshis":198641975500,"script":"76a9143f8ba3fda3ba7b69f5818086e12223c6dd25e3c888ac","address":"mmJx9Y8ayz9h14yd9fgCW1bUKoEpkBAquP"}],"outputSatoshis":317283951000,"feeSatoshis":62}}`, + }, + { + name: "socketio sendTransaction", + req: socketioReq{"sendTransaction", []interface{}{"010000000001019d64f0c72a0d206001decbffaa722eb1044534c"}}, + want: `{"error":{"message":"Invalid data"}}`, + }, + } + + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + resp, err := s.Ack("message", tt.req, time.Second*3) + if err != nil { + t.Errorf("Socketio error %v", err) + } + if resp != tt.want { + t.Errorf("got %v, want %v", resp, tt.want) + } + }) + } +} + +type websocketReq struct { + ID string `json:"id"` + Method string `json:"method"` + Params interface{} `json:"params,omitempty"` +} +type websocketResp struct { + ID string `json:"id"` +} + +type websocketTest struct { + name string + req websocketReq + want string +} + +var websocketTestsBitcoinType = []websocketTest{ + { + name: "websocket getInfo", + req: websocketReq{ + Method: "getInfo", + }, + want: `{"id":"0","data":{"name":"Fakecoin","shortcut":"FAKE","network":"FAKE","decimals":8,"version":"unknown","bestHeight":225494,"bestHash":"00000000eb0443fd7dc4a1ed5c686a8e995057805f9a161d9a5a77a95e72b7b6","block0Hash":"","testnet":true,"backend":{"version":"001001","subversion":"/Fakecoin:0.0.1/"}}}`, + }, + { + name: "websocket getBlockHash", + req: websocketReq{ + Method: "getBlockHash", + Params: map[string]interface{}{ + "height": 225494, + }, + }, + want: `{"id":"1","data":{"hash":"00000000eb0443fd7dc4a1ed5c686a8e995057805f9a161d9a5a77a95e72b7b6"}}`, + }, + { + name: "websocket getAccountInfo xpub txs", + req: websocketReq{ + Method: "getAccountInfo", + Params: map[string]interface{}{ + "descriptor": dbtestdata.Xpub, + "details": "txs", + }, + }, + want: `{"id":"2","data":{"page":1,"totalPages":1,"itemsOnPage":25,"address":"upub5E1xjDmZ7Hhej6LPpS8duATdKXnRYui7bDYj6ehfFGzWDZtmCmQkZhc3Zb7kgRLtHWd16QFxyP86JKL3ShZEBFX88aciJ3xyocuyhZZ8g6q","balance":"118641975500","totalReceived":"118641975501","totalSent":"1","unconfirmedBalance":"0","unconfirmedTxs":0,"txs":2,"addrTxCount":3,"transactions":[{"txid":"3d90d15ed026dc45e19ffb52875ed18fa9e8012ad123d7f7212176e2b0ebdb71","vin":[{"txid":"7c3be24063f268aaa1ed81b64776798f56088757641a34fb156c4f51ed2e9d25","n":0,"addresses":["mzB8cYrfRwFRFAGTDzV8LkUQy5BQicxGhX"],"isAddress":true,"value":"317283951061"},{"txid":"effd9ef509383d536b1c8af5bf434c8efbf521a4f2befd4022bbd68694b4ac75","vout":1,"n":1,"addresses":["2MzmAKayJmja784jyHvRUW1bXPget1csRRG"],"isAddress":true,"isOwn":true,"value":"1"}],"vout":[{"value":"118641975500","n":0,"hex":"a91495e9fbe306449c991d314afe3c3567d5bf78efd287","addresses":["2N6utyMZfPNUb1Bk8oz7p2JqJrXkq83gegu"],"isAddress":true,"isOwn":true},{"value":"198641975500","n":1,"hex":"76a9143f8ba3fda3ba7b69f5818086e12223c6dd25e3c888ac","addresses":["mmJx9Y8ayz9h14yd9fgCW1bUKoEpkBAquP"],"isAddress":true}],"blockHash":"00000000eb0443fd7dc4a1ed5c686a8e995057805f9a161d9a5a77a95e72b7b6","blockHeight":225494,"confirmations":1,"blockTime":1521595678,"value":"317283951000","valueIn":"317283951062","fees":"62"},{"txid":"effd9ef509383d536b1c8af5bf434c8efbf521a4f2befd4022bbd68694b4ac75","vin":[],"vout":[{"value":"1234567890123","n":0,"spent":true,"hex":"76a914a08eae93007f22668ab5e4a9c83c8cd1c325e3e088ac","addresses":["mv9uLThosiEnGRbVPS7Vhyw6VssbVRsiAw"],"isAddress":true},{"value":"1","n":1,"spent":true,"hex":"a91452724c5178682f70e0ba31c6ec0633755a3b41d987","addresses":["2MzmAKayJmja784jyHvRUW1bXPget1csRRG"],"isAddress":true,"isOwn":true},{"value":"9876","n":2,"spent":true,"hex":"a914e921fc4912a315078f370d959f2c4f7b6d2a683c87","addresses":["2NEVv9LJmAnY99W1pFoc5UJjVdypBqdnvu1"],"isAddress":true}],"blockHash":"0000000076fbbed90fd75b0e18856aa35baa984e9c9d444cf746ad85e94e2997","blockHeight":225493,"confirmations":2,"blockTime":1521515026,"value":"1234567900000","valueIn":"0","fees":"0"}],"usedTokens":2,"tokens":[{"type":"XPUBAddress","name":"2MzmAKayJmja784jyHvRUW1bXPget1csRRG","path":"m/49'/1'/33'/0/0","transfers":2,"decimals":8,"balance":"0","totalReceived":"1","totalSent":"1"},{"type":"XPUBAddress","name":"2MsYfbi6ZdVXLDNrYAQ11ja9Sd3otMk4Pmj","path":"m/49'/1'/33'/0/1","transfers":0,"decimals":8},{"type":"XPUBAddress","name":"2MuAZNAjLSo6RLFad2fvHSfgqBD7BoEVy4T","path":"m/49'/1'/33'/0/2","transfers":0,"decimals":8},{"type":"XPUBAddress","name":"2NEqKzw3BosGnBE9by5uaDy5QgwjHac4Zbg","path":"m/49'/1'/33'/0/3","transfers":0,"decimals":8},{"type":"XPUBAddress","name":"2Mw7vJNC8zUK6VNN4CEjtoTYmuNPLewxZzV","path":"m/49'/1'/33'/0/4","transfers":0,"decimals":8},{"type":"XPUBAddress","name":"2N1kvo97NFASPXiwephZUxE9PRXunjTxEc4","path":"m/49'/1'/33'/0/5","transfers":0,"decimals":8},{"type":"XPUBAddress","name":"2MuWrWMzoBt8VDFNvPmpJf42M1GTUs85fPx","path":"m/49'/1'/33'/0/6","transfers":0,"decimals":8},{"type":"XPUBAddress","name":"2MuVZ2Ca6Da9zmYynt49Rx7uikAgubGcymF","path":"m/49'/1'/33'/0/7","transfers":0,"decimals":8},{"type":"XPUBAddress","name":"2MzRGWDUmrPP9HwYu4B43QGCTLwoop5cExa","path":"m/49'/1'/33'/0/8","transfers":0,"decimals":8},{"type":"XPUBAddress","name":"2N5C9EEWJzyBXhpyPHqa3UNed73Amsi5b3L","path":"m/49'/1'/33'/0/9","transfers":0,"decimals":8},{"type":"XPUBAddress","name":"2MzNawz2zjwq1L85GDE3YydEJGJYfXxaWkk","path":"m/49'/1'/33'/0/10","transfers":0,"decimals":8},{"type":"XPUBAddress","name":"2N7NdeuAMgL57WE7QCeV2gTWi2Um8iAu5dA","path":"m/49'/1'/33'/0/11","transfers":0,"decimals":8},{"type":"XPUBAddress","name":"2N8JQEP6DSHEZHNsSDPA1gHMUq9YFndhkfV","path":"m/49'/1'/33'/0/12","transfers":0,"decimals":8},{"type":"XPUBAddress","name":"2Mvbn3YXqKZVpQKugaoQrfjSYPvz76RwZkC","path":"m/49'/1'/33'/0/13","transfers":0,"decimals":8},{"type":"XPUBAddress","name":"2N8MRNxCfwUY9TSW27X9ooGYtqgrGCfLRHx","path":"m/49'/1'/33'/0/14","transfers":0,"decimals":8},{"type":"XPUBAddress","name":"2N6HvwrHC113KYZAmCtJ9XJNWgaTcnFunCM","path":"m/49'/1'/33'/0/15","transfers":0,"decimals":8},{"type":"XPUBAddress","name":"2NEo3oNyHUoi7rmRWee7wki37jxPWsWCopJ","path":"m/49'/1'/33'/0/16","transfers":0,"decimals":8},{"type":"XPUBAddress","name":"2Mzm5KY8qdFbDHsQfy4akXbFvbR3FAwDuVo","path":"m/49'/1'/33'/0/17","transfers":0,"decimals":8},{"type":"XPUBAddress","name":"2NGMwftmQCogp6XZNGvgiybz3WZysvsJzqC","path":"m/49'/1'/33'/0/18","transfers":0,"decimals":8},{"type":"XPUBAddress","name":"2N3fJrrefndYjLGycvFFfYgevpZtcRKCkRD","path":"m/49'/1'/33'/0/19","transfers":0,"decimals":8},{"type":"XPUBAddress","name":"2N1T7TnHBwfdpBoyw53EGUL7vuJmb2mU6jF","path":"m/49'/1'/33'/0/20","transfers":0,"decimals":8},{"type":"XPUBAddress","name":"2MzSBtRWHbBjeUcu3H5VRDqkvz5sfmDxJKo","path":"m/49'/1'/33'/1/0","transfers":0,"decimals":8},{"type":"XPUBAddress","name":"2MtShtAJYb1afWduUTwF1SixJjan7urZKke","path":"m/49'/1'/33'/1/1","transfers":0,"decimals":8},{"type":"XPUBAddress","name":"2N3cP668SeqyBEr9gnB4yQEmU3VyxeRYith","path":"m/49'/1'/33'/1/2","transfers":0,"decimals":8},{"type":"XPUBAddress","name":"2N6utyMZfPNUb1Bk8oz7p2JqJrXkq83gegu","path":"m/49'/1'/33'/1/3","transfers":1,"decimals":8,"balance":"118641975500","totalReceived":"118641975500","totalSent":"0"},{"type":"XPUBAddress","name":"2NEzatauNhf9kPTwwj6ZfYKjUdy52j4hVUL","path":"m/49'/1'/33'/1/4","transfers":0,"decimals":8},{"type":"XPUBAddress","name":"2N4RjsDp4LBpkNqyF91aNjgpF9CwDwBkJZq","path":"m/49'/1'/33'/1/5","transfers":0,"decimals":8},{"type":"XPUBAddress","name":"2N8XygTmQc4NoBBPEy3yybnfCYhsxFtzPDY","path":"m/49'/1'/33'/1/6","transfers":0,"decimals":8},{"type":"XPUBAddress","name":"2N5BjBomZvb48sccK2vwLMiQ5ETKp1fdPVn","path":"m/49'/1'/33'/1/7","transfers":0,"decimals":8},{"type":"XPUBAddress","name":"2MybMwbZRPCGU3SMWPwQCpDkbcQFw5Hbwen","path":"m/49'/1'/33'/1/8","transfers":0,"decimals":8},{"type":"XPUBAddress","name":"2N7HexL4dyAQc7Th4iqcCW4hZuyiZsLWf74","path":"m/49'/1'/33'/1/9","transfers":0,"decimals":8},{"type":"XPUBAddress","name":"2NF6X5FDGWrQj4nQrfP6hA77zB5WAc1DGup","path":"m/49'/1'/33'/1/10","transfers":0,"decimals":8},{"type":"XPUBAddress","name":"2N4ZRPdvc7BVioBTohy4F6QtxreqcjNj26b","path":"m/49'/1'/33'/1/11","transfers":0,"decimals":8},{"type":"XPUBAddress","name":"2Mtfho1rLmevh4qTnkYWxZEFCWteDMtTcUF","path":"m/49'/1'/33'/1/12","transfers":0,"decimals":8},{"type":"XPUBAddress","name":"2NFUCphKYvmMcNZRZrF261mRX6iADVB9Qms","path":"m/49'/1'/33'/1/13","transfers":0,"decimals":8},{"type":"XPUBAddress","name":"2N5kBNMB8qgxE4Y4f8J19fScsE49J4aNvoJ","path":"m/49'/1'/33'/1/14","transfers":0,"decimals":8},{"type":"XPUBAddress","name":"2NANWCaefhCKdXMcW8NbZnnrFRDvhJN2wPy","path":"m/49'/1'/33'/1/15","transfers":0,"decimals":8},{"type":"XPUBAddress","name":"2NFHw7Yo2Bz8D2wGAYHW9qidbZFLpfJ72qB","path":"m/49'/1'/33'/1/16","transfers":0,"decimals":8},{"type":"XPUBAddress","name":"2NBDSsBgy5PpFniLCb1eAFHcSxgxwPSDsZa","path":"m/49'/1'/33'/1/17","transfers":0,"decimals":8},{"type":"XPUBAddress","name":"2NDWCSQHogc7sCuc2WoYt9PX2i2i6a5k6dX","path":"m/49'/1'/33'/1/18","transfers":0,"decimals":8},{"type":"XPUBAddress","name":"2N8vNyDP7iSDjm3BKpXrbDjAxyphqfvnJz8","path":"m/49'/1'/33'/1/19","transfers":0,"decimals":8},{"type":"XPUBAddress","name":"2N4tFKLurSbMusAyq1tv4tzymVjveAFV1Vb","path":"m/49'/1'/33'/1/20","transfers":0,"decimals":8},{"type":"XPUBAddress","name":"2NBx5WwjAr2cH6Yqrp3Vsf957HtRKwDUVdX","path":"m/49'/1'/33'/1/21","transfers":0,"decimals":8},{"type":"XPUBAddress","name":"2NBu1seHTaFhQxbcW5L5BkZzqFLGmZqpxsa","path":"m/49'/1'/33'/1/22","transfers":0,"decimals":8},{"type":"XPUBAddress","name":"2NCDLoea22jGsXuarfT1n2QyCUh6RFhAPnT","path":"m/49'/1'/33'/1/23","transfers":0,"decimals":8}]}}`, + }, + { + name: "websocket getAccountInfo address", + req: websocketReq{ + Method: "getAccountInfo", + Params: map[string]interface{}{ + "descriptor": dbtestdata.Addr4, + "details": "txids", + }, + }, + want: `{"id":"3","data":{"page":1,"totalPages":1,"itemsOnPage":25,"address":"2MzmAKayJmja784jyHvRUW1bXPget1csRRG","balance":"0","totalReceived":"1","totalSent":"1","unconfirmedBalance":"0","unconfirmedTxs":0,"txs":2,"txids":["3d90d15ed026dc45e19ffb52875ed18fa9e8012ad123d7f7212176e2b0ebdb71","effd9ef509383d536b1c8af5bf434c8efbf521a4f2befd4022bbd68694b4ac75"]}}`, + }, + { + name: "websocket getAccountInfo xpub gap", + req: websocketReq{ + Method: "getAccountInfo", + Params: map[string]interface{}{ + "descriptor": dbtestdata.Xpub, + "details": "tokens", + "tokens": "derived", + "gap": 10, + }, + }, + want: `{"id":"4","data":{"address":"upub5E1xjDmZ7Hhej6LPpS8duATdKXnRYui7bDYj6ehfFGzWDZtmCmQkZhc3Zb7kgRLtHWd16QFxyP86JKL3ShZEBFX88aciJ3xyocuyhZZ8g6q","balance":"118641975500","totalReceived":"118641975501","totalSent":"1","unconfirmedBalance":"0","unconfirmedTxs":0,"txs":3,"addrTxCount":3,"usedTokens":2,"tokens":[{"type":"XPUBAddress","name":"2MzmAKayJmja784jyHvRUW1bXPget1csRRG","path":"m/49'/1'/33'/0/0","transfers":2,"decimals":8},{"type":"XPUBAddress","name":"2MsYfbi6ZdVXLDNrYAQ11ja9Sd3otMk4Pmj","path":"m/49'/1'/33'/0/1","transfers":0,"decimals":8},{"type":"XPUBAddress","name":"2MuAZNAjLSo6RLFad2fvHSfgqBD7BoEVy4T","path":"m/49'/1'/33'/0/2","transfers":0,"decimals":8},{"type":"XPUBAddress","name":"2NEqKzw3BosGnBE9by5uaDy5QgwjHac4Zbg","path":"m/49'/1'/33'/0/3","transfers":0,"decimals":8},{"type":"XPUBAddress","name":"2Mw7vJNC8zUK6VNN4CEjtoTYmuNPLewxZzV","path":"m/49'/1'/33'/0/4","transfers":0,"decimals":8},{"type":"XPUBAddress","name":"2N1kvo97NFASPXiwephZUxE9PRXunjTxEc4","path":"m/49'/1'/33'/0/5","transfers":0,"decimals":8},{"type":"XPUBAddress","name":"2MuWrWMzoBt8VDFNvPmpJf42M1GTUs85fPx","path":"m/49'/1'/33'/0/6","transfers":0,"decimals":8},{"type":"XPUBAddress","name":"2MuVZ2Ca6Da9zmYynt49Rx7uikAgubGcymF","path":"m/49'/1'/33'/0/7","transfers":0,"decimals":8},{"type":"XPUBAddress","name":"2MzRGWDUmrPP9HwYu4B43QGCTLwoop5cExa","path":"m/49'/1'/33'/0/8","transfers":0,"decimals":8},{"type":"XPUBAddress","name":"2N5C9EEWJzyBXhpyPHqa3UNed73Amsi5b3L","path":"m/49'/1'/33'/0/9","transfers":0,"decimals":8},{"type":"XPUBAddress","name":"2MzNawz2zjwq1L85GDE3YydEJGJYfXxaWkk","path":"m/49'/1'/33'/0/10","transfers":0,"decimals":8},{"type":"XPUBAddress","name":"2MzSBtRWHbBjeUcu3H5VRDqkvz5sfmDxJKo","path":"m/49'/1'/33'/1/0","transfers":0,"decimals":8},{"type":"XPUBAddress","name":"2MtShtAJYb1afWduUTwF1SixJjan7urZKke","path":"m/49'/1'/33'/1/1","transfers":0,"decimals":8},{"type":"XPUBAddress","name":"2N3cP668SeqyBEr9gnB4yQEmU3VyxeRYith","path":"m/49'/1'/33'/1/2","transfers":0,"decimals":8},{"type":"XPUBAddress","name":"2N6utyMZfPNUb1Bk8oz7p2JqJrXkq83gegu","path":"m/49'/1'/33'/1/3","transfers":1,"decimals":8},{"type":"XPUBAddress","name":"2NEzatauNhf9kPTwwj6ZfYKjUdy52j4hVUL","path":"m/49'/1'/33'/1/4","transfers":0,"decimals":8},{"type":"XPUBAddress","name":"2N4RjsDp4LBpkNqyF91aNjgpF9CwDwBkJZq","path":"m/49'/1'/33'/1/5","transfers":0,"decimals":8},{"type":"XPUBAddress","name":"2N8XygTmQc4NoBBPEy3yybnfCYhsxFtzPDY","path":"m/49'/1'/33'/1/6","transfers":0,"decimals":8},{"type":"XPUBAddress","name":"2N5BjBomZvb48sccK2vwLMiQ5ETKp1fdPVn","path":"m/49'/1'/33'/1/7","transfers":0,"decimals":8},{"type":"XPUBAddress","name":"2MybMwbZRPCGU3SMWPwQCpDkbcQFw5Hbwen","path":"m/49'/1'/33'/1/8","transfers":0,"decimals":8},{"type":"XPUBAddress","name":"2N7HexL4dyAQc7Th4iqcCW4hZuyiZsLWf74","path":"m/49'/1'/33'/1/9","transfers":0,"decimals":8},{"type":"XPUBAddress","name":"2NF6X5FDGWrQj4nQrfP6hA77zB5WAc1DGup","path":"m/49'/1'/33'/1/10","transfers":0,"decimals":8},{"type":"XPUBAddress","name":"2N4ZRPdvc7BVioBTohy4F6QtxreqcjNj26b","path":"m/49'/1'/33'/1/11","transfers":0,"decimals":8},{"type":"XPUBAddress","name":"2Mtfho1rLmevh4qTnkYWxZEFCWteDMtTcUF","path":"m/49'/1'/33'/1/12","transfers":0,"decimals":8},{"type":"XPUBAddress","name":"2NFUCphKYvmMcNZRZrF261mRX6iADVB9Qms","path":"m/49'/1'/33'/1/13","transfers":0,"decimals":8}]}}`, + }, + { + name: "websocket getAccountUtxo", + req: websocketReq{ + Method: "getAccountUtxo", + Params: map[string]interface{}{ + "descriptor": dbtestdata.Addr1, + }, + }, + want: `{"id":"5","data":[{"txid":"00b2c06055e5e90e9c82bd4181fde310104391a7fa4f289b1704e5d90caa3840","vout":0,"value":"100000000","height":225493,"confirmations":2}]}`, + }, + { + name: "websocket getAccountUtxo", + req: websocketReq{ + Method: "getAccountUtxo", + Params: map[string]interface{}{ + "descriptor": dbtestdata.Addr4, + }, + }, + want: `{"id":"6","data":[]}`, + }, + { + name: "websocket getTransaction", + req: websocketReq{ + Method: "getTransaction", + Params: map[string]interface{}{ + "txid": dbtestdata.TxidB2T2, + }, + }, + want: `{"id":"7","data":{"txid":"3d90d15ed026dc45e19ffb52875ed18fa9e8012ad123d7f7212176e2b0ebdb71","vin":[{"txid":"7c3be24063f268aaa1ed81b64776798f56088757641a34fb156c4f51ed2e9d25","n":0,"addresses":["mzB8cYrfRwFRFAGTDzV8LkUQy5BQicxGhX"],"isAddress":true,"value":"317283951061"},{"txid":"effd9ef509383d536b1c8af5bf434c8efbf521a4f2befd4022bbd68694b4ac75","vout":1,"n":1,"addresses":["2MzmAKayJmja784jyHvRUW1bXPget1csRRG"],"isAddress":true,"value":"1"}],"vout":[{"value":"118641975500","n":0,"hex":"a91495e9fbe306449c991d314afe3c3567d5bf78efd287","addresses":["2N6utyMZfPNUb1Bk8oz7p2JqJrXkq83gegu"],"isAddress":true},{"value":"198641975500","n":1,"hex":"76a9143f8ba3fda3ba7b69f5818086e12223c6dd25e3c888ac","addresses":["mmJx9Y8ayz9h14yd9fgCW1bUKoEpkBAquP"],"isAddress":true}],"blockHash":"00000000eb0443fd7dc4a1ed5c686a8e995057805f9a161d9a5a77a95e72b7b6","blockHeight":225494,"confirmations":1,"blockTime":1521595678,"value":"317283951000","valueIn":"317283951062","fees":"62"}}`, + }, + { + name: "websocket getTransaction", + req: websocketReq{ + Method: "getTransaction", + Params: map[string]interface{}{ + "txid": "not a tx", + }, + }, + want: `{"id":"8","data":{"error":{"message":"Transaction 'not a tx' not found"}}}`, + }, + { + name: "websocket getTransactionSpecific", + req: websocketReq{ + Method: "getTransactionSpecific", + Params: map[string]interface{}{ + "txid": dbtestdata.TxidB2T2, + }, + }, + want: `{"id":"9","data":{"hex":"","txid":"3d90d15ed026dc45e19ffb52875ed18fa9e8012ad123d7f7212176e2b0ebdb71","version":0,"locktime":0,"vin":[{"coinbase":"","txid":"7c3be24063f268aaa1ed81b64776798f56088757641a34fb156c4f51ed2e9d25","vout":0,"scriptSig":{"hex":""},"sequence":0,"addresses":null},{"coinbase":"","txid":"effd9ef509383d536b1c8af5bf434c8efbf521a4f2befd4022bbd68694b4ac75","vout":1,"scriptSig":{"hex":""},"sequence":0,"addresses":null}],"vout":[{"ValueSat":118641975500,"value":0,"n":0,"scriptPubKey":{"hex":"a91495e9fbe306449c991d314afe3c3567d5bf78efd287","addresses":null}},{"ValueSat":198641975500,"value":0,"n":1,"scriptPubKey":{"hex":"76a9143f8ba3fda3ba7b69f5818086e12223c6dd25e3c888ac","addresses":null}}],"confirmations":1,"time":1521595678,"blocktime":1521595678,"vsize":400}}`, + }, + { + name: "websocket estimateFee", + req: websocketReq{ + Method: "estimateFee", + Params: map[string]interface{}{ + "blocks": []int{2, 5, 10, 20}, + "specific": map[string]interface{}{ + "conservative": false, + "txsize": 1234, + }, + }, + }, + want: `{"id":"10","data":[{"feePerTx":"246","feePerUnit":"199"},{"feePerTx":"616","feePerUnit":"499"},{"feePerTx":"1233","feePerUnit":"999"},{"feePerTx":"2467","feePerUnit":"1999"}]}`, + }, + { + name: "websocket estimateFee second time, from cache", + req: websocketReq{ + Method: "estimateFee", + Params: map[string]interface{}{ + "blocks": []int{2, 5, 10, 20}, + "specific": map[string]interface{}{ + "conservative": false, + "txsize": 1234, + }, + }, + }, + want: `{"id":"11","data":[{"feePerTx":"246","feePerUnit":"199"},{"feePerTx":"616","feePerUnit":"499"},{"feePerTx":"1233","feePerUnit":"999"},{"feePerTx":"2467","feePerUnit":"1999"}]}`, + }, + { + name: "websocket sendTransaction", + req: websocketReq{ + Method: "sendTransaction", + Params: map[string]interface{}{ + "hex": "123456", + }, + }, + want: `{"id":"12","data":{"result":"9876"}}`, + }, + { + name: "websocket subscribeNewBlock", + req: websocketReq{ + Method: "subscribeNewBlock", + }, + want: `{"id":"13","data":{"subscribed":true}}`, + }, + { + name: "websocket unsubscribeNewBlock", + req: websocketReq{ + Method: "unsubscribeNewBlock", + }, + want: `{"id":"14","data":{"subscribed":false}}`, + }, + { + name: "websocket subscribeAddresses", + req: websocketReq{ + Method: "subscribeAddresses", + Params: map[string]interface{}{ + "addresses": []string{dbtestdata.Addr1, dbtestdata.Addr2}, + }, + }, + want: `{"id":"15","data":{"subscribed":true}}`, + }, + { + name: "websocket unsubscribeAddresses", + req: websocketReq{ + Method: "unsubscribeAddresses", + }, + want: `{"id":"16","data":{"subscribed":false}}`, + }, + { + name: "websocket ping", + req: websocketReq{ + Method: "ping", + }, + want: `{"id":"17","data":{}}`, + }, + { + name: "websocket getCurrentFiatRates all currencies", + req: websocketReq{ + Method: "getCurrentFiatRates", + Params: map[string]interface{}{ + "currencies": []string{}, + }, + }, + want: `{"id":"18","data":{"ts":1574380800,"rates":{"eur":7134.1,"usd":7914.5}}}`, + }, + { + name: "websocket getCurrentFiatRates usd", + req: websocketReq{ + Method: "getCurrentFiatRates", + Params: map[string]interface{}{ + "currencies": []string{"usd"}, + }, + }, + want: `{"id":"19","data":{"ts":1574380800,"rates":{"usd":7914.5}}}`, + }, + { + name: "websocket getCurrentFiatRates eur", + req: websocketReq{ + Method: "getCurrentFiatRates", + Params: map[string]interface{}{ + "currencies": []string{"eur"}, + }, + }, + want: `{"id":"20","data":{"ts":1574380800,"rates":{"eur":7134.1}}}`, + }, + { + name: "websocket getCurrentFiatRates incorrect currency", + req: websocketReq{ + Method: "getCurrentFiatRates", + Params: map[string]interface{}{ + "currencies": []string{"does-not-exist"}, + }, + }, + want: `{"id":"21","data":{"error":{"message":"No tickers found!"}}}`, + }, + { + name: "websocket getFiatRatesForTimestamps missing date", + req: websocketReq{ + Method: "getFiatRatesForTimestamps", + Params: map[string]interface{}{ + "currencies": []string{"usd"}, + }, + }, + want: `{"id":"22","data":{"error":{"message":"No timestamps provided"}}}`, + }, + { + name: "websocket getFiatRatesForTimestamps incorrect date", + req: websocketReq{ + Method: "getFiatRatesForTimestamps", + Params: map[string]interface{}{ + "currencies": []string{"usd"}, + "timestamps": []string{"yesterday"}, + }, + }, + want: `{"id":"23","data":{"error":{"message":"json: cannot unmarshal string into Go struct field WsFiatRatesForTimestampsReq.timestamps of type int64"}}}`, + }, + { + name: "websocket getFiatRatesForTimestamps empty currency", + req: websocketReq{ + Method: "getFiatRatesForTimestamps", + Params: map[string]interface{}{ + "timestamps": []int64{7885693815}, + "currencies": []string{""}, + }, + }, + want: `{"id":"24","data":{"tickers":[{"ts":7885693815,"rates":{}}]}}`, + }, + { + name: "websocket getFiatRatesForTimestamps incorrect (future) date", + req: websocketReq{ + Method: "getFiatRatesForTimestamps", + Params: map[string]interface{}{ + "currencies": []string{"usd"}, + "timestamps": []int64{7885693815}, + }, + }, + want: `{"id":"25","data":{"tickers":[{"ts":7885693815,"rates":{"usd":-1}}]}}`, + }, + { + name: "websocket getFiatRatesForTimestamps exact date", + req: websocketReq{ + Method: "getFiatRatesForTimestamps", + Params: map[string]interface{}{ + "currencies": []string{"usd"}, + "timestamps": []int64{1574380800}, + }, + }, + want: `{"id":"26","data":{"tickers":[{"ts":1574380800,"rates":{"usd":7914.5}}]}}`, + }, + { + name: "websocket getFiatRatesForTimestamps closest date, eur", + req: websocketReq{ + Method: "getFiatRatesForTimestamps", + Params: map[string]interface{}{ + "currencies": []string{"eur"}, + "timestamps": []int64{1521507600}, + }, + }, + want: `{"id":"27","data":{"tickers":[{"ts":1521590400,"rates":{"eur":1301}}]}}`, + }, + { + name: "websocket getFiatRatesForTimestamps multiple timestamps usd", + req: websocketReq{ + Method: "getFiatRatesForTimestamps", + Params: map[string]interface{}{ + "currencies": []string{"usd"}, + "timestamps": []int64{1570346615, 1574346615}, + }, + }, + want: `{"id":"28","data":{"tickers":[{"ts":1574294400,"rates":{"usd":7814.5}},{"ts":1574380800,"rates":{"usd":7914.5}}]}}`, + }, + { + name: "websocket getFiatRatesForTimestamps multiple timestamps eur", + req: websocketReq{ + Method: "getFiatRatesForTimestamps", + Params: map[string]interface{}{ + "currencies": []string{"eur"}, + "timestamps": []int64{1570346615, 1574346615}, + }, + }, + want: `{"id":"29","data":{"tickers":[{"ts":1574294400,"rates":{"eur":7100}},{"ts":1574380800,"rates":{"eur":7134.1}}]}}`, + }, + { + name: "websocket getFiatRatesForTimestamps multiple timestamps with an error", + req: websocketReq{ + Method: "getFiatRatesForTimestamps", + Params: map[string]interface{}{ + "currencies": []string{"usd"}, + "timestamps": []int64{1570346615, 1574346615, 2000000000}, + }, + }, + want: `{"id":"30","data":{"tickers":[{"ts":1574294400,"rates":{"usd":7814.5}},{"ts":1574380800,"rates":{"usd":7914.5}},{"ts":2000000000,"rates":{"usd":-1}}]}}`, + }, + { + name: "websocket getFiatRatesForTimestamps multiple errors", + req: websocketReq{ + Method: "getFiatRatesForTimestamps", + Params: map[string]interface{}{ + "currencies": []string{"usd"}, + "timestamps": []int64{7832854800, 2000000000}, + }, + }, + want: `{"id":"31","data":{"tickers":[{"ts":7832854800,"rates":{"usd":-1}},{"ts":2000000000,"rates":{"usd":-1}}]}}`, + }, + { + name: "websocket getTickersList", + req: websocketReq{ + Method: "getFiatRatesTickersList", + Params: map[string]interface{}{ + "timestamp": 1570346615, + }, + }, + want: `{"id":"32","data":{"ts":1574294400,"available_currencies":["eur","usd"]}}`, + }, + { + name: "websocket getBalanceHistory Addr2", + req: websocketReq{ + Method: "getBalanceHistory", + Params: map[string]interface{}{ + "descriptor": "mtGXQvBowMkBpnhLckhxhbwYK44Gs9eEtz", + }, + }, + want: `{"id":"33","data":[{"time":1521514800,"txs":1,"received":"24690","sent":"0","sentToSelf":"0","rates":{"eur":1301,"usd":2001}},{"time":1521594000,"txs":1,"received":"0","sent":"12345","sentToSelf":"0","rates":{"eur":1302,"usd":2002}}]}`, + }, + { + name: "websocket getBalanceHistory xpub", + req: websocketReq{ + Method: "getBalanceHistory", + Params: map[string]interface{}{ + "descriptor": dbtestdata.Xpub, + }, + }, + want: `{"id":"34","data":[{"time":1521514800,"txs":1,"received":"1","sent":"0","sentToSelf":"0","rates":{"eur":1301,"usd":2001}},{"time":1521594000,"txs":1,"received":"118641975500","sent":"1","sentToSelf":"118641975500","rates":{"eur":1302,"usd":2002}}]}`, + }, + { + name: "websocket getBalanceHistory xpub from=1521504000&to=1521590400 currencies=[usd]", + req: websocketReq{ + Method: "getBalanceHistory", + Params: map[string]interface{}{ + "descriptor": dbtestdata.Xpub, + "from": 1521504000, + "to": 1521590400, + "currencies": []string{"usd"}, + }, + }, + want: `{"id":"35","data":[{"time":1521514800,"txs":1,"received":"1","sent":"0","sentToSelf":"0","rates":{"usd":2001}}]}`, + }, + { + name: "websocket getBalanceHistory xpub from=1521504000&to=1521590400 currencies=[usd, eur, incorrect]", + req: websocketReq{ + Method: "getBalanceHistory", + Params: map[string]interface{}{ + "descriptor": dbtestdata.Xpub, + "from": 1521504000, + "to": 1521590400, + "currencies": []string{"usd", "eur", "incorrect"}, + }, + }, + want: `{"id":"36","data":[{"time":1521514800,"txs":1,"received":"1","sent":"0","sentToSelf":"0","rates":{"eur":1301,"incorrect":-1,"usd":2001}}]}`, + }, + { + name: "websocket getBalanceHistory xpub from=1521504000&to=1521590400 currencies=[]", + req: websocketReq{ + Method: "getBalanceHistory", + Params: map[string]interface{}{ + "descriptor": dbtestdata.Xpub, + "from": 1521504000, + "to": 1521590400, + "currencies": []string{}, + }, + }, + want: `{"id":"37","data":[{"time":1521514800,"txs":1,"received":"1","sent":"0","sentToSelf":"0","rates":{"eur":1301,"usd":2001}}]}`, + }, + { + name: "websocket subscribeNewTransaction", + req: websocketReq{ + Method: "subscribeNewTransaction", + }, + want: `{"id":"38","data":{"subscribed":false,"message":"subscribeNewTransaction not enabled, use -enablesubnewtx flag to enable."}}`, + }, + { + name: "websocket unsubscribeNewTransaction", + req: websocketReq{ + Method: "unsubscribeNewTransaction", + }, + want: `{"id":"39","data":{"subscribed":false,"message":"unsubscribeNewTransaction not enabled, use -enablesubnewtx flag to enable."}}`, + }, + { + name: "websocket getBlock", + req: websocketReq{ + Method: "getBlock", + Params: map[string]interface{}{ + "id": "00000000eb0443fd7dc4a1ed5c686a8e995057805f9a161d9a5a77a95e72b7b6", + }, + }, + want: `{"id":"40","data":{"error":{"message":"Not supported"}}}`, + }, + { + name: "websocket getMempoolFilters", + req: websocketReq{ + Method: "getMempoolFilters", + Params: map[string]interface{}{ + "scriptType": "", + }, + }, + want: `{"id":"41","data":{"P":0,"M":1,"zeroedKey":false,"entries":{}}}`, + }, + { + name: "websocket getMempoolFilters invalid type", + req: websocketReq{ + Method: "getMempoolFilters", + Params: map[string]interface{}{ + "scriptType": "invalid", + }, + }, + want: `{"id":"42","data":{"error":{"message":"Unsupported script filter invalid"}}}`, + }, + { + name: "websocket getBlockFilter", + req: websocketReq{ + Method: "getBlockFilter", + Params: map[string]interface{}{ + "blockHash": "abcd", + }, + }, + want: `{"id":"43","data":{"P":0,"M":1,"zeroedKey":false,"blockFilter":""}}`, + }, + { + name: "websocket rpcCall", + req: websocketReq{ + Method: "rpcCall", + Params: WsRpcCallReq{ + To: "0x123", + Data: "0x456", + }, + }, + want: `{"id":"44","data":{"error":{"message":"not supported"}}}`, + }, +} + +func runWebsocketTests(t *testing.T, ts *httptest.Server, tests []websocketTest) { + url := strings.Replace(ts.URL, "http://", "ws://", 1) + "/websocket" + s, _, err := websocket.DefaultDialer.Dial(url, nil) + if err != nil { + t.Fatal(err) + } + defer s.Close() + + // send all requests at once + for i, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + tt.req.ID = strconv.Itoa(i) + err = s.WriteJSON(tt.req) + if err != nil { + t.Fatal(err) + } + }) + } + + // wait for all responses + done := make(chan struct{}) + + go func() { + defer close(done) + for i := 0; i < len(tests); i++ { + _, message, err := s.ReadMessage() + if err != nil { + t.Fatal(err) + } + var resp websocketResp + err = json.Unmarshal(message, &resp) + if err != nil { + t.Fatal(err) + } + id, err := strconv.Atoi(resp.ID) + if err != nil { + t.Fatal(err) + } + got := strings.TrimSpace(string(message)) + if got != tests[id].want { + t.Errorf("%s: got %v, want %v", tests[id].name, got, tests[id].want) + } else { + tests[id].want = "already checked, should not check twice" + } + } + }() + + select { + case <-done: + break + case <-time.After(time.Second * 10): + t.Error("Timeout while waiting for websocket responses") + } +} + +// fixedTimeNow returns always 2022-09-15 12:43:56 UTC +func fixedTimeNow() time.Time { + return time.Date(2022, 9, 15, 12, 43, 56, 0, time.UTC) +} + +func setupChain(t *testing.T) (bchain.BlockChainParser, bchain.BlockChain) { + timeNow = fixedTimeNow + parser := btc.NewBitcoinParser( + btc.GetChainParams("test"), + &btc.Configuration{ + BlockAddressesToKeep: 1, + XPubMagic: 70617039, + XPubMagicSegwitP2sh: 71979618, + XPubMagicSegwitNative: 73342198, + Slip44: 1, + }) + + chain, err := dbtestdata.NewFakeBlockChain(parser) + if err != nil { + glog.Fatal("fakechain: ", err) + } + return parser, chain +} + +func Test_PublicServer_BitcoinType(t *testing.T) { + parser, chain := setupChain(t) + + s, dbpath := setupPublicHTTPServer(parser, chain, t, false) + defer closeAndDestroyPublicServer(t, s, dbpath) + s.ConnectFullPublicInterface() + // take the handler of the public server and pass it to the test server + ts := httptest.NewServer(s.https.Handler) + defer ts.Close() + + httpTestsBitcoinType(t, ts) + socketioTestsBitcoinType(t, ts) + runWebsocketTests(t, ts, websocketTestsBitcoinType) +} + +func httpTestsBitcoinTypeExtendedIndex(t *testing.T, ts *httptest.Server) { + tests := []struct { + name string + r *http.Request + status int + contentType string + body []string + }{ + { + name: "apiIndex", + r: newGetRequest(ts.URL + "/api"), + status: http.StatusOK, + contentType: "application/json; charset=utf-8", + body: []string{ + `{"blockbook":{"coin":"Fakecoin"`, + `"bestHeight":225494`, + `"decimals":8`, + `"backend":{"chain":"fakecoin","blocks":2,"headers":2,"bestBlockHash":"00000000eb0443fd7dc4a1ed5c686a8e995057805f9a161d9a5a77a95e72b7b6"`, + `"version":"001001","subversion":"/Fakecoin:0.0.1/"`, + }, + }, + { + name: "apiTx v2", + r: newGetRequest(ts.URL + "/api/v2/tx/7c3be24063f268aaa1ed81b64776798f56088757641a34fb156c4f51ed2e9d25"), + status: http.StatusOK, + contentType: "application/json; charset=utf-8", + body: []string{ + `{"txid":"7c3be24063f268aaa1ed81b64776798f56088757641a34fb156c4f51ed2e9d25","vin":[{"txid":"effd9ef509383d536b1c8af5bf434c8efbf521a4f2befd4022bbd68694b4ac75","n":0,"addresses":["mv9uLThosiEnGRbVPS7Vhyw6VssbVRsiAw"],"isAddress":true,"value":"1234567890123"},{"txid":"00b2c06055e5e90e9c82bd4181fde310104391a7fa4f289b1704e5d90caa3840","vout":1,"n":1,"addresses":["mtGXQvBowMkBpnhLckhxhbwYK44Gs9eEtz"],"isAddress":true,"value":"12345"}],"vout":[{"value":"317283951061","n":0,"spent":true,"spentTxId":"3d90d15ed026dc45e19ffb52875ed18fa9e8012ad123d7f7212176e2b0ebdb71","spentHeight":225494,"hex":"76a914ccaaaf374e1b06cb83118453d102587b4273d09588ac","addresses":["mzB8cYrfRwFRFAGTDzV8LkUQy5BQicxGhX"],"isAddress":true},{"value":"917283951061","n":1,"hex":"76a9148d802c045445df49613f6a70ddd2e48526f3701f88ac","addresses":["mtR97eM2HPWVM6c8FGLGcukgaHHQv7THoL"],"isAddress":true},{"value":"0","n":2,"hex":"6a072020f1686f6a20","addresses":["OP_RETURN 2020f1686f6a20"],"isAddress":false}],"blockHash":"00000000eb0443fd7dc4a1ed5c686a8e995057805f9a161d9a5a77a95e72b7b6","blockHeight":225494,"confirmations":1,"blockTime":1521595678,"value":"1234567902122","valueIn":"1234567902468","fees":"346"}`, + }, + }, + { + name: "apiAddress v2 details=txs", + r: newGetRequest(ts.URL + "/api/v2/address/mv9uLThosiEnGRbVPS7Vhyw6VssbVRsiAw?details=txs"), + status: http.StatusOK, + contentType: "application/json; charset=utf-8", + body: []string{ + `{"page":1,"totalPages":1,"itemsOnPage":1000,"address":"mv9uLThosiEnGRbVPS7Vhyw6VssbVRsiAw","balance":"0","totalReceived":"1234567890123","totalSent":"1234567890123","unconfirmedBalance":"0","unconfirmedTxs":0,"txs":2,"transactions":[{"txid":"7c3be24063f268aaa1ed81b64776798f56088757641a34fb156c4f51ed2e9d25","vin":[{"txid":"effd9ef509383d536b1c8af5bf434c8efbf521a4f2befd4022bbd68694b4ac75","n":0,"addresses":["mv9uLThosiEnGRbVPS7Vhyw6VssbVRsiAw"],"isAddress":true,"isOwn":true,"value":"1234567890123"},{"txid":"00b2c06055e5e90e9c82bd4181fde310104391a7fa4f289b1704e5d90caa3840","vout":1,"n":1,"addresses":["mtGXQvBowMkBpnhLckhxhbwYK44Gs9eEtz"],"isAddress":true,"value":"12345"}],"vout":[{"value":"317283951061","n":0,"spent":true,"spentTxId":"3d90d15ed026dc45e19ffb52875ed18fa9e8012ad123d7f7212176e2b0ebdb71","spentHeight":225494,"hex":"76a914ccaaaf374e1b06cb83118453d102587b4273d09588ac","addresses":["mzB8cYrfRwFRFAGTDzV8LkUQy5BQicxGhX"],"isAddress":true},{"value":"917283951061","n":1,"hex":"76a9148d802c045445df49613f6a70ddd2e48526f3701f88ac","addresses":["mtR97eM2HPWVM6c8FGLGcukgaHHQv7THoL"],"isAddress":true},{"value":"0","n":2,"hex":"6a072020f1686f6a20","addresses":["OP_RETURN 2020f1686f6a20"],"isAddress":false}],"blockHash":"00000000eb0443fd7dc4a1ed5c686a8e995057805f9a161d9a5a77a95e72b7b6","blockHeight":225494,"confirmations":1,"blockTime":1521595678,"value":"1234567902122","valueIn":"1234567902468","fees":"346"},{"txid":"effd9ef509383d536b1c8af5bf434c8efbf521a4f2befd4022bbd68694b4ac75","vin":[],"vout":[{"value":"1234567890123","n":0,"spent":true,"spentTxId":"7c3be24063f268aaa1ed81b64776798f56088757641a34fb156c4f51ed2e9d25","spentHeight":225494,"hex":"76a914a08eae93007f22668ab5e4a9c83c8cd1c325e3e088ac","addresses":["mv9uLThosiEnGRbVPS7Vhyw6VssbVRsiAw"],"isAddress":true,"isOwn":true},{"value":"1","n":1,"spent":true,"spentTxId":"3d90d15ed026dc45e19ffb52875ed18fa9e8012ad123d7f7212176e2b0ebdb71","spentIndex":1,"spentHeight":225494,"hex":"a91452724c5178682f70e0ba31c6ec0633755a3b41d987","addresses":["2MzmAKayJmja784jyHvRUW1bXPget1csRRG"],"isAddress":true},{"value":"9876","n":2,"spent":true,"spentTxId":"05e2e48aeabdd9b75def7b48d756ba304713c2aba7b522bf9dbc893fc4231b07","spentHeight":225494,"hex":"a914e921fc4912a315078f370d959f2c4f7b6d2a683c87","addresses":["2NEVv9LJmAnY99W1pFoc5UJjVdypBqdnvu1"],"isAddress":true}],"blockHash":"0000000076fbbed90fd75b0e18856aa35baa984e9c9d444cf746ad85e94e2997","blockHeight":225493,"confirmations":2,"blockTime":1521515026,"value":"1234567900000","valueIn":"0","fees":"0"}]}`, + }, + }, + { + name: "apiGetBlock", + r: newGetRequest(ts.URL + "/api/v2/block/225493"), + status: http.StatusOK, + contentType: "application/json; charset=utf-8", + body: []string{ + `{"page":1,"totalPages":1,"itemsOnPage":1000,"hash":"0000000076fbbed90fd75b0e18856aa35baa984e9c9d444cf746ad85e94e2997","nextBlockHash":"00000000eb0443fd7dc4a1ed5c686a8e995057805f9a161d9a5a77a95e72b7b6","height":225493,"confirmations":2,"size":1234567,"time":1521515026,"version":0,"merkleRoot":"","nonce":"","bits":"","difficulty":"","txCount":2,"txs":[{"txid":"00b2c06055e5e90e9c82bd4181fde310104391a7fa4f289b1704e5d90caa3840","vin":[],"vout":[{"value":"100000000","n":0,"addresses":["mfcWp7DB6NuaZsExybTTXpVgWz559Np4Ti"],"isAddress":true},{"value":"12345","n":1,"spent":true,"spentTxId":"7c3be24063f268aaa1ed81b64776798f56088757641a34fb156c4f51ed2e9d25","spentIndex":1,"spentHeight":225494,"addresses":["mtGXQvBowMkBpnhLckhxhbwYK44Gs9eEtz"],"isAddress":true},{"value":"12345","n":2,"addresses":["mtGXQvBowMkBpnhLckhxhbwYK44Gs9eEtz"],"isAddress":true}],"blockHash":"0000000076fbbed90fd75b0e18856aa35baa984e9c9d444cf746ad85e94e2997","blockHeight":225493,"confirmations":2,"blockTime":1521515026,"value":"100024690","valueIn":"0","fees":"0"},{"txid":"effd9ef509383d536b1c8af5bf434c8efbf521a4f2befd4022bbd68694b4ac75","vin":[],"vout":[{"value":"1234567890123","n":0,"spent":true,"spentTxId":"7c3be24063f268aaa1ed81b64776798f56088757641a34fb156c4f51ed2e9d25","spentHeight":225494,"addresses":["mv9uLThosiEnGRbVPS7Vhyw6VssbVRsiAw"],"isAddress":true},{"value":"1","n":1,"spent":true,"spentTxId":"3d90d15ed026dc45e19ffb52875ed18fa9e8012ad123d7f7212176e2b0ebdb71","spentIndex":1,"spentHeight":225494,"addresses":["2MzmAKayJmja784jyHvRUW1bXPget1csRRG"],"isAddress":true},{"value":"9876","n":2,"spent":true,"spentTxId":"05e2e48aeabdd9b75def7b48d756ba304713c2aba7b522bf9dbc893fc4231b07","spentHeight":225494,"addresses":["2NEVv9LJmAnY99W1pFoc5UJjVdypBqdnvu1"],"isAddress":true}],"blockHash":"0000000076fbbed90fd75b0e18856aa35baa984e9c9d444cf746ad85e94e2997","blockHeight":225493,"confirmations":2,"blockTime":1521515026,"value":"1234567900000","valueIn":"0","fees":"0"}]}`, + }, + }, + { + name: "apiBlockFilters", + r: newGetRequest(ts.URL + "/api/v2/block-filters?lastN=2"), + status: http.StatusOK, + contentType: "application/json; charset=utf-8", + body: []string{ + `{"P":20,"M":1048576,"zeroedKey":false,"blockFilters":{"225493":{"blockHash":"0000000076fbbed90fd75b0e18856aa35baa984e9c9d444cf746ad85e94e2997","filter":"050079b0d468a27502af2ac08f2fc0"},"225494":{"blockHash":"00000000eb0443fd7dc4a1ed5c686a8e995057805f9a161d9a5a77a95e72b7b6","filter":"0a0195bc0a550129e827a9ba4aa44287840cc73d0c27d16832059690"}}}`, + }, + }, + { + name: "apiBlockFilters scriptType=taproot", + r: newGetRequest(ts.URL + "/api/v2/block-filters?lastN=2&scriptType=taproot"), + status: http.StatusBadRequest, + contentType: "application/json; charset=utf-8", + body: []string{ + `{"error":"Invalid scriptType taproot. Use "}`, + }, + }, + } + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + resp, err := http.DefaultClient.Do(tt.r) + if err != nil { + t.Fatal(err) + } + defer resp.Body.Close() + if resp.StatusCode != tt.status { + t.Errorf("StatusCode = %v, want %v", resp.StatusCode, tt.status) + } + if resp.Header["Content-Type"][0] != tt.contentType { + t.Errorf("Content-Type = %v, want %v", resp.Header["Content-Type"][0], tt.contentType) + } + bb, err := io.ReadAll(resp.Body) + if err != nil { + t.Fatal(err) + } + b := string(bb) + for _, c := range tt.body { + if !strings.Contains(b, c) { + t.Errorf("got %v, want to contain %v", b, c) + break + } + } + }) + } +} + +var websocketTestsBitcoinTypeExtendedIndex = []websocketTest{ + { + name: "websocket getInfo", + req: websocketReq{ + Method: "getInfo", + }, + want: `{"id":"0","data":{"name":"Fakecoin","shortcut":"FAKE","network":"FAKE","decimals":8,"version":"unknown","bestHeight":225494,"bestHash":"00000000eb0443fd7dc4a1ed5c686a8e995057805f9a161d9a5a77a95e72b7b6","block0Hash":"","testnet":true,"backend":{"version":"001001","subversion":"/Fakecoin:0.0.1/"}}}`, + }, + { + name: "websocket getBlockHash", + req: websocketReq{ + Method: "getBlockHash", + Params: map[string]interface{}{ + "height": 225494, + }, + }, + want: `{"id":"1","data":{"hash":"00000000eb0443fd7dc4a1ed5c686a8e995057805f9a161d9a5a77a95e72b7b6"}}`, + }, + { + name: "websocket getAccountInfo xpub txs", + req: websocketReq{ + Method: "getAccountInfo", + Params: map[string]interface{}{ + "descriptor": dbtestdata.Xpub, + "details": "txs", + }, + }, + want: `{"id":"2","data":{"page":1,"totalPages":1,"itemsOnPage":25,"address":"upub5E1xjDmZ7Hhej6LPpS8duATdKXnRYui7bDYj6ehfFGzWDZtmCmQkZhc3Zb7kgRLtHWd16QFxyP86JKL3ShZEBFX88aciJ3xyocuyhZZ8g6q","balance":"118641975500","totalReceived":"118641975501","totalSent":"1","unconfirmedBalance":"0","unconfirmedTxs":0,"txs":2,"addrTxCount":3,"transactions":[{"txid":"3d90d15ed026dc45e19ffb52875ed18fa9e8012ad123d7f7212176e2b0ebdb71","vin":[{"txid":"7c3be24063f268aaa1ed81b64776798f56088757641a34fb156c4f51ed2e9d25","n":0,"addresses":["mzB8cYrfRwFRFAGTDzV8LkUQy5BQicxGhX"],"isAddress":true,"value":"317283951061"},{"txid":"effd9ef509383d536b1c8af5bf434c8efbf521a4f2befd4022bbd68694b4ac75","vout":1,"n":1,"addresses":["2MzmAKayJmja784jyHvRUW1bXPget1csRRG"],"isAddress":true,"isOwn":true,"value":"1"}],"vout":[{"value":"118641975500","n":0,"hex":"a91495e9fbe306449c991d314afe3c3567d5bf78efd287","addresses":["2N6utyMZfPNUb1Bk8oz7p2JqJrXkq83gegu"],"isAddress":true,"isOwn":true},{"value":"198641975500","n":1,"hex":"76a9143f8ba3fda3ba7b69f5818086e12223c6dd25e3c888ac","addresses":["mmJx9Y8ayz9h14yd9fgCW1bUKoEpkBAquP"],"isAddress":true}],"blockHash":"00000000eb0443fd7dc4a1ed5c686a8e995057805f9a161d9a5a77a95e72b7b6","blockHeight":225494,"confirmations":1,"blockTime":1521595678,"value":"317283951000","valueIn":"317283951062","fees":"62"},{"txid":"effd9ef509383d536b1c8af5bf434c8efbf521a4f2befd4022bbd68694b4ac75","vin":[],"vout":[{"value":"1234567890123","n":0,"spent":true,"spentTxId":"7c3be24063f268aaa1ed81b64776798f56088757641a34fb156c4f51ed2e9d25","spentHeight":225494,"hex":"76a914a08eae93007f22668ab5e4a9c83c8cd1c325e3e088ac","addresses":["mv9uLThosiEnGRbVPS7Vhyw6VssbVRsiAw"],"isAddress":true},{"value":"1","n":1,"spent":true,"spentTxId":"3d90d15ed026dc45e19ffb52875ed18fa9e8012ad123d7f7212176e2b0ebdb71","spentIndex":1,"spentHeight":225494,"hex":"a91452724c5178682f70e0ba31c6ec0633755a3b41d987","addresses":["2MzmAKayJmja784jyHvRUW1bXPget1csRRG"],"isAddress":true,"isOwn":true},{"value":"9876","n":2,"spent":true,"spentTxId":"05e2e48aeabdd9b75def7b48d756ba304713c2aba7b522bf9dbc893fc4231b07","spentHeight":225494,"hex":"a914e921fc4912a315078f370d959f2c4f7b6d2a683c87","addresses":["2NEVv9LJmAnY99W1pFoc5UJjVdypBqdnvu1"],"isAddress":true}],"blockHash":"0000000076fbbed90fd75b0e18856aa35baa984e9c9d444cf746ad85e94e2997","blockHeight":225493,"confirmations":2,"blockTime":1521515026,"value":"1234567900000","valueIn":"0","fees":"0"}],"usedTokens":2,"tokens":[{"type":"XPUBAddress","name":"2MzmAKayJmja784jyHvRUW1bXPget1csRRG","path":"m/49'/1'/33'/0/0","transfers":2,"decimals":8,"balance":"0","totalReceived":"1","totalSent":"1"},{"type":"XPUBAddress","name":"2MsYfbi6ZdVXLDNrYAQ11ja9Sd3otMk4Pmj","path":"m/49'/1'/33'/0/1","transfers":0,"decimals":8},{"type":"XPUBAddress","name":"2MuAZNAjLSo6RLFad2fvHSfgqBD7BoEVy4T","path":"m/49'/1'/33'/0/2","transfers":0,"decimals":8},{"type":"XPUBAddress","name":"2NEqKzw3BosGnBE9by5uaDy5QgwjHac4Zbg","path":"m/49'/1'/33'/0/3","transfers":0,"decimals":8},{"type":"XPUBAddress","name":"2Mw7vJNC8zUK6VNN4CEjtoTYmuNPLewxZzV","path":"m/49'/1'/33'/0/4","transfers":0,"decimals":8},{"type":"XPUBAddress","name":"2N1kvo97NFASPXiwephZUxE9PRXunjTxEc4","path":"m/49'/1'/33'/0/5","transfers":0,"decimals":8},{"type":"XPUBAddress","name":"2MuWrWMzoBt8VDFNvPmpJf42M1GTUs85fPx","path":"m/49'/1'/33'/0/6","transfers":0,"decimals":8},{"type":"XPUBAddress","name":"2MuVZ2Ca6Da9zmYynt49Rx7uikAgubGcymF","path":"m/49'/1'/33'/0/7","transfers":0,"decimals":8},{"type":"XPUBAddress","name":"2MzRGWDUmrPP9HwYu4B43QGCTLwoop5cExa","path":"m/49'/1'/33'/0/8","transfers":0,"decimals":8},{"type":"XPUBAddress","name":"2N5C9EEWJzyBXhpyPHqa3UNed73Amsi5b3L","path":"m/49'/1'/33'/0/9","transfers":0,"decimals":8},{"type":"XPUBAddress","name":"2MzNawz2zjwq1L85GDE3YydEJGJYfXxaWkk","path":"m/49'/1'/33'/0/10","transfers":0,"decimals":8},{"type":"XPUBAddress","name":"2N7NdeuAMgL57WE7QCeV2gTWi2Um8iAu5dA","path":"m/49'/1'/33'/0/11","transfers":0,"decimals":8},{"type":"XPUBAddress","name":"2N8JQEP6DSHEZHNsSDPA1gHMUq9YFndhkfV","path":"m/49'/1'/33'/0/12","transfers":0,"decimals":8},{"type":"XPUBAddress","name":"2Mvbn3YXqKZVpQKugaoQrfjSYPvz76RwZkC","path":"m/49'/1'/33'/0/13","transfers":0,"decimals":8},{"type":"XPUBAddress","name":"2N8MRNxCfwUY9TSW27X9ooGYtqgrGCfLRHx","path":"m/49'/1'/33'/0/14","transfers":0,"decimals":8},{"type":"XPUBAddress","name":"2N6HvwrHC113KYZAmCtJ9XJNWgaTcnFunCM","path":"m/49'/1'/33'/0/15","transfers":0,"decimals":8},{"type":"XPUBAddress","name":"2NEo3oNyHUoi7rmRWee7wki37jxPWsWCopJ","path":"m/49'/1'/33'/0/16","transfers":0,"decimals":8},{"type":"XPUBAddress","name":"2Mzm5KY8qdFbDHsQfy4akXbFvbR3FAwDuVo","path":"m/49'/1'/33'/0/17","transfers":0,"decimals":8},{"type":"XPUBAddress","name":"2NGMwftmQCogp6XZNGvgiybz3WZysvsJzqC","path":"m/49'/1'/33'/0/18","transfers":0,"decimals":8},{"type":"XPUBAddress","name":"2N3fJrrefndYjLGycvFFfYgevpZtcRKCkRD","path":"m/49'/1'/33'/0/19","transfers":0,"decimals":8},{"type":"XPUBAddress","name":"2N1T7TnHBwfdpBoyw53EGUL7vuJmb2mU6jF","path":"m/49'/1'/33'/0/20","transfers":0,"decimals":8},{"type":"XPUBAddress","name":"2MzSBtRWHbBjeUcu3H5VRDqkvz5sfmDxJKo","path":"m/49'/1'/33'/1/0","transfers":0,"decimals":8},{"type":"XPUBAddress","name":"2MtShtAJYb1afWduUTwF1SixJjan7urZKke","path":"m/49'/1'/33'/1/1","transfers":0,"decimals":8},{"type":"XPUBAddress","name":"2N3cP668SeqyBEr9gnB4yQEmU3VyxeRYith","path":"m/49'/1'/33'/1/2","transfers":0,"decimals":8},{"type":"XPUBAddress","name":"2N6utyMZfPNUb1Bk8oz7p2JqJrXkq83gegu","path":"m/49'/1'/33'/1/3","transfers":1,"decimals":8,"balance":"118641975500","totalReceived":"118641975500","totalSent":"0"},{"type":"XPUBAddress","name":"2NEzatauNhf9kPTwwj6ZfYKjUdy52j4hVUL","path":"m/49'/1'/33'/1/4","transfers":0,"decimals":8},{"type":"XPUBAddress","name":"2N4RjsDp4LBpkNqyF91aNjgpF9CwDwBkJZq","path":"m/49'/1'/33'/1/5","transfers":0,"decimals":8},{"type":"XPUBAddress","name":"2N8XygTmQc4NoBBPEy3yybnfCYhsxFtzPDY","path":"m/49'/1'/33'/1/6","transfers":0,"decimals":8},{"type":"XPUBAddress","name":"2N5BjBomZvb48sccK2vwLMiQ5ETKp1fdPVn","path":"m/49'/1'/33'/1/7","transfers":0,"decimals":8},{"type":"XPUBAddress","name":"2MybMwbZRPCGU3SMWPwQCpDkbcQFw5Hbwen","path":"m/49'/1'/33'/1/8","transfers":0,"decimals":8},{"type":"XPUBAddress","name":"2N7HexL4dyAQc7Th4iqcCW4hZuyiZsLWf74","path":"m/49'/1'/33'/1/9","transfers":0,"decimals":8},{"type":"XPUBAddress","name":"2NF6X5FDGWrQj4nQrfP6hA77zB5WAc1DGup","path":"m/49'/1'/33'/1/10","transfers":0,"decimals":8},{"type":"XPUBAddress","name":"2N4ZRPdvc7BVioBTohy4F6QtxreqcjNj26b","path":"m/49'/1'/33'/1/11","transfers":0,"decimals":8},{"type":"XPUBAddress","name":"2Mtfho1rLmevh4qTnkYWxZEFCWteDMtTcUF","path":"m/49'/1'/33'/1/12","transfers":0,"decimals":8},{"type":"XPUBAddress","name":"2NFUCphKYvmMcNZRZrF261mRX6iADVB9Qms","path":"m/49'/1'/33'/1/13","transfers":0,"decimals":8},{"type":"XPUBAddress","name":"2N5kBNMB8qgxE4Y4f8J19fScsE49J4aNvoJ","path":"m/49'/1'/33'/1/14","transfers":0,"decimals":8},{"type":"XPUBAddress","name":"2NANWCaefhCKdXMcW8NbZnnrFRDvhJN2wPy","path":"m/49'/1'/33'/1/15","transfers":0,"decimals":8},{"type":"XPUBAddress","name":"2NFHw7Yo2Bz8D2wGAYHW9qidbZFLpfJ72qB","path":"m/49'/1'/33'/1/16","transfers":0,"decimals":8},{"type":"XPUBAddress","name":"2NBDSsBgy5PpFniLCb1eAFHcSxgxwPSDsZa","path":"m/49'/1'/33'/1/17","transfers":0,"decimals":8},{"type":"XPUBAddress","name":"2NDWCSQHogc7sCuc2WoYt9PX2i2i6a5k6dX","path":"m/49'/1'/33'/1/18","transfers":0,"decimals":8},{"type":"XPUBAddress","name":"2N8vNyDP7iSDjm3BKpXrbDjAxyphqfvnJz8","path":"m/49'/1'/33'/1/19","transfers":0,"decimals":8},{"type":"XPUBAddress","name":"2N4tFKLurSbMusAyq1tv4tzymVjveAFV1Vb","path":"m/49'/1'/33'/1/20","transfers":0,"decimals":8},{"type":"XPUBAddress","name":"2NBx5WwjAr2cH6Yqrp3Vsf957HtRKwDUVdX","path":"m/49'/1'/33'/1/21","transfers":0,"decimals":8},{"type":"XPUBAddress","name":"2NBu1seHTaFhQxbcW5L5BkZzqFLGmZqpxsa","path":"m/49'/1'/33'/1/22","transfers":0,"decimals":8},{"type":"XPUBAddress","name":"2NCDLoea22jGsXuarfT1n2QyCUh6RFhAPnT","path":"m/49'/1'/33'/1/23","transfers":0,"decimals":8}]}}`, + }, + { + name: "websocket getBlockFilter", + req: websocketReq{ + Method: "getBlockFilter", + Params: map[string]interface{}{ + "blockHash": "0000000076fbbed90fd75b0e18856aa35baa984e9c9d444cf746ad85e94e2997", + }, + }, + want: `{"id":"3","data":{"P":20,"M":1048576,"zeroedKey":false,"blockFilter":"050079b0d468a27502af2ac08f2fc0"}}`, + }, + { + name: "websocket getBlockFiltersBatch bestKnownBlockHash 1st block", + req: websocketReq{ + Method: "getBlockFiltersBatch", + Params: map[string]interface{}{ + "bestKnownBlockHash": "0000000076fbbed90fd75b0e18856aa35baa984e9c9d444cf746ad85e94e2997", + }, + }, + want: `{"id":"4","data":{"P":20,"M":1048576,"zeroedKey":false,"blockFiltersBatch":["225494:00000000eb0443fd7dc4a1ed5c686a8e995057805f9a161d9a5a77a95e72b7b6:0a0195bc0a550129e827a9ba4aa44287840cc73d0c27d16832059690"]}}`, + }, + { + name: "websocket getBlockFiltersBatch bestKnownBlockHash 2nd block", + req: websocketReq{ + Method: "getBlockFiltersBatch", + Params: map[string]interface{}{ + "bestKnownBlockHash": "00000000eb0443fd7dc4a1ed5c686a8e995057805f9a161d9a5a77a95e72b7b6", + }, + }, + want: `{"id":"5","data":{"P":20,"M":1048576,"zeroedKey":false,"blockFiltersBatch":[]}}`, + }, + { + name: "websocket getBlockFiltersBatch bestKnownBlockHash 1st block, unsupported script type", + req: websocketReq{ + Method: "getBlockFiltersBatch", + Params: map[string]interface{}{ + "bestKnownBlockHash": "0000000076fbbed90fd75b0e18856aa35baa984e9c9d444cf746ad85e94e2997", + "scriptType": "unsupported", + }, + }, + want: `{"id":"6","data":{"error":{"message":"Unsupported script type unsupported"}}}`, + }, +} + +func Test_PublicServer_BitcoinType_ExtendedIndex(t *testing.T) { + parser, chain := setupChain(t) + + s, dbpath := setupPublicHTTPServer(parser, chain, t, true) + defer closeAndDestroyPublicServer(t, s, dbpath) + s.ConnectFullPublicInterface() + // take the handler of the public server and pass it to the test server + ts := httptest.NewServer(s.https.Handler) + defer ts.Close() + + httpTestsBitcoinTypeExtendedIndex(t, ts) + runWebsocketTests(t, ts, websocketTestsBitcoinTypeExtendedIndex) +} diff --git a/server/websocket.go b/server/websocket.go index cba5f27d..c782adea 100644 --- a/server/websocket.go +++ b/server/websocket.go @@ -4,6 +4,7 @@ import ( "encoding/json" "math/big" "net/http" + "os" "runtime/debug" "strconv" "strings" @@ -70,6 +71,7 @@ type WebsocketServer struct { fiatRatesSubscriptions map[string]map[*websocketChannel]string fiatRatesTokenSubscriptions map[*websocketChannel][]string fiatRatesSubscriptionsLock sync.Mutex + allowedRpcCallTo map[string]struct{} } // NewWebsocketServer creates new websocket interface to blockbook and returns its handle @@ -105,6 +107,14 @@ func NewWebsocketServer(db *db.RocksDB, chain bchain.BlockChain, mempool bchain. fiatRatesSubscriptions: make(map[string]map[*websocketChannel]string), fiatRatesTokenSubscriptions: make(map[*websocketChannel][]string), } + envRpcCall := os.Getenv(strings.ToUpper(is.GetNetwork()) + "_ALLOWED_RPC_CALL_TO") + if envRpcCall != "" { + s.allowedRpcCallTo = make(map[string]struct{}) + for _, c := range strings.Split(envRpcCall, ",") { + s.allowedRpcCallTo[strings.ToLower(c)] = struct{}{} + } + glog.Info("Support of rpcCall for these contracts: ", envRpcCall) + } return s, nil } @@ -277,8 +287,8 @@ var requestHandlers = map[string]func(*WebsocketServer, *websocketChannel, *WsRe c.getAddressInfoDescriptorsMux.Unlock() if l > s.is.WsGetAccountInfoLimit { if s.closeChannel(c) { - glog.Info("Client ", c.id, " exceeded getAddressInfo limit, ", c.ip) - s.is.AddWsLimitExceedingIP(c.ip) + glog.Info("Client ", c.id, " exceeded getAddressInfo limit, ", c.ip) + s.is.AddWsLimitExceedingIP(c.ip) } return } @@ -391,6 +401,14 @@ var requestHandlers = map[string]func(*WebsocketServer, *websocketChannel, *WsRe } return }, + "rpcCall": func(s *WebsocketServer, c *websocketChannel, req *WsReq) (rv interface{}, err error) { + r := WsRpcCallReq{} + err = json.Unmarshal(req.Params, &r) + if err == nil { + rv, err = s.rpcCall(&r) + } + return + }, "subscribeNewBlock": func(s *WebsocketServer, c *websocketChannel, req *WsReq) (rv interface{}, err error) { return s.subscribeNewBlock(c, req) }, @@ -580,6 +598,7 @@ func (s *WebsocketServer) getInfo() (*WsInfoRes, error) { return &WsInfoRes{ Name: s.is.Coin, Shortcut: s.is.CoinShortcut, + Network: s.is.GetNetwork(), Decimals: s.chainParser.AmountDecimals(), BestHeight: int(height), BestHash: hash, @@ -746,6 +765,20 @@ func (s *WebsocketServer) getBlockFiltersBatch(r *WsBlockFiltersBatchReq) (res i }, nil } +func (s *WebsocketServer) rpcCall(r *WsRpcCallReq) (*WsRpcCallRes, error) { + if s.allowedRpcCallTo != nil { + _, ok := s.allowedRpcCallTo[strings.ToLower(r.To)] + if !ok { + return nil, errors.New("Not supported") + } + } + data, err := s.chain.EthereumTypeRpcCall(r.Data, r.To, r.From) + if err != nil { + return nil, err + } + return &WsRpcCallRes{Data: data}, nil +} + type subscriptionResponse struct { Subscribed bool `json:"subscribed"` } diff --git a/server/ws_types.go b/server/ws_types.go index d91a2a56..f49f02ad 100644 --- a/server/ws_types.go +++ b/server/ws_types.go @@ -36,6 +36,7 @@ type WsBackendInfo struct { type WsInfoRes struct { Name string `json:"name"` Shortcut string `json:"shortcut"` + Network string `json:"network"` Decimals int `json:"decimals"` Version string `json:"version"` BestHeight int `json:"bestHeight"` @@ -137,3 +138,13 @@ type WsFiatRatesTickersListReq struct { Timestamp int64 `json:"timestamp,omitempty"` Token string `json:"token,omitempty"` } + +type WsRpcCallReq struct { + From string `json:"from,omitempty"` + To string `json:"to"` + Data string `json:"data"` +} + +type WsRpcCallRes struct { + Data string `json:"data"` +} diff --git a/static/css/main.css b/static/css/main.css index b02f915c..e708ac18 100644 --- a/static/css/main.css +++ b/static/css/main.css @@ -200,6 +200,10 @@ span.btn-paging:hover { color: #757575; } +.btn-paging.active:hover { + background-color: white; +} + .paging-group { border: 1px solid #e2e2e2; border-radius: 0.5rem; @@ -694,4 +698,4 @@ span.btn-paging:hover { .btn { --bs-btn-font-size: 1rem; } -} \ No newline at end of file +} diff --git a/static/css/main.min.3.css b/static/css/main.min.3.css deleted file mode 100644 index dbafe084..00000000 --- a/static/css/main.min.3.css +++ /dev/null @@ -1 +0,0 @@ -@import "TTHoves/TTHoves.css";* {margin: 0;padding: 0;outline: none;font-family: "TT Hoves", -apple-system, "Segoe UI", "Helvetica Neue", Arial, sans-serif;}html, body {height: 100%;}body {min-height: 100%;margin: 0;background: linear-gradient(to bottom, #f6f6f6 360px, #e5e5e5 0), #e5e5e5;background-repeat: no-repeat;}a {color: #00854d;text-decoration: none;}a:hover {color: #00854d;text-decoration: underline;}select {border-radius: 0.5rem;padding-left: 0.5rem;border: 1px solid #ced4da;color: var(--bs-body-color);min-height: 45px;}#header {position: fixed;top: 0;left: 0;width: 100%;margin: 0;padding-bottom: 0;padding-top: 0;background-color: white;border-bottom: 1px solid #f6f6f6;z-index: 10;}#header a {color: var(--bs-navbar-brand-color);}#header a:hover {color: var(--bs-navbar-brand-hover-color);}#header .navbar {--bs-navbar-padding-y: 0.7rem;}#header .form-control-lg {font-size: 1rem;padding: 0.75rem 1rem;}#header .container {min-height: 50px;}#header .btn.dropdown-toggle {padding-right: 0;}#header .dropdown-menu {--bs-dropdown-min-width: 13rem;}#header .dropdown-menu[data-bs-popper] {left: initial;right: 0;}#header .dropdown-menu.show {display: flex;}.form-control:focus {outline: 0;box-shadow: none;border-color: #00854d;}.base-value {color: #757575 !important;padding-left: 0.5rem;font-weight: normal;}.badge {vertical-align: middle;text-transform: uppercase;letter-spacing: 0.15em;--bs-badge-padding-x: 0.8rem;--bs-badge-font-weight: normal;--bs-badge-border-radius: 0.6rem;}.bg-secondary {background-color: #757575 !important;}.accordion {--bs-accordion-border-radius: 10px;--bs-accordion-inner-border-radius: calc(10px - 1px);--bs-accordion-color: var(--bs-body-color);--bs-accordion-active-color: var(--bs-body-color);--bs-accordion-active-bg: white;--bs-accordion-btn-active-icon: url("data:image/svg+xml,");}.accordion-button:focus {outline: 0;box-shadow: none;}.accordion-body {letter-spacing: -0.01em;}.bb-group {border: 0.6rem solid #f6f6f6;background-color: #f6f6f6;border-radius: 0.5rem;position: relative;display: inline-flex;vertical-align: middle;}.bb-group>.btn {--bs-btn-padding-x: 0.5rem;--bs-btn-padding-y: 0.22rem;--bs-btn-border-radius: 0.3rem;--bs-btn-border-width: 0;color: #545454;}.bb-group>.btn-check:checked+.btn, .bb-group .btn.active {color: black;font-weight: bold;background-color: white;}.paging {display: flex;}.paging .bb-group>.btn {min-width: 2rem;margin-left: 0.1rem;margin-right: 0.1rem;}.paging .bb-group>.btn:hover {background-color: white;}.paging a {text-decoration: none;}.btn-paging {--bs-btn-color: #757575;--bs-btn-border-color: #e2e2e2;--bs-btn-hover-color: black;--bs-btn-hover-bg: #f6f6f6;--bs-btn-hover-border-color: #e2e2e2;--bs-btn-focus-shadow-rgb: 108, 117, 125;--bs-btn-active-color: #fff;--bs-btn-active-bg: #e2e2e2;--bs-btn-active-border-color: #e2e2e2;--bs-btn-active-shadow: inset 0 3px 5px rgba(0, 0, 0, 0.125);--bs-gradient: none;--bs-btn-padding-y: 0.75rem;--bs-btn-padding-x: 1.1rem;--bs-btn-border-radius: 0.5rem;--bs-btn-font-weight: bold;background-color: #f6f6f6;}span.btn-paging {cursor: initial;}span.btn-paging:hover {color: #757575;}.paging-group {border: 1px solid #e2e2e2;border-radius: 0.5rem;}.paging-group>.bb-group {border: 0.53rem solid #f6f6f6;}#wrap {min-height: 100%;height: auto;padding: 112px 0 75px 0;margin: 0 auto -56px;}#footer {background-color: black;color: #757575;height: 56px;overflow: hidden;}.navbar-form {width: 60%;}.navbar-form button {margin-left: -50px;position: relative;}.search-icon {width: 16px;height: 16px;position: absolute;top: 16px;background-size: cover;background-image: url("data:image/svg+xml, %3Csvg width='16' height='16' viewBox='0 0 16 16' fill='none' xmlns='http://www.w3.org/2000/svg'%3E%3Cpath d='M7.24976 12.5C10.1493 12.5 12.4998 10.1495 12.4998 7.25C12.4998 4.35051 10.1493 2 7.24976 2C4.35026 2 1.99976 4.35051 1.99976 7.25C1.99976 10.1495 4.35026 12.5 7.24976 12.5Z' stroke='black' stroke-width='1.5' stroke-linecap='round' stroke-linejoin='round' /%3E%3Cpath d='M10.962 10.9625L13.9996 14.0001' stroke='black' stroke-width='1.5' stroke-linecap='round' stroke-linejoin='round' /%3E%3C/svg%3E");}.navbar-form ::placeholder {color: #e2e2e2;}.ellipsis {overflow: hidden;text-overflow: ellipsis;white-space: nowrap;}.data-table {table-layout: fixed;overflow-wrap: anywhere;margin-left: 8px;margin-top: 2rem;margin-bottom: 2rem;width: calc(100% - 16px);}.data-table thead {padding-bottom: 20px;}.table.data-table> :not(caption)>*>* {padding: 0.8rem 0.8rem;background-color: var(--bs-table-bg);border-bottom-width: 1px;box-shadow: inset 0 0 0 9999px var(--bs-table-accent-bg);}.table.data-table>thead>*>* {padding-bottom: 1.5rem;}.table.data-table>*>*:last-child>* {border-bottom: none;}.data-table thead, .data-table thead tr, .data-table thead th {color: #757575;border: none;font-weight: normal;}.data-table tbody th {color: #757575;font-weight: normal;}.data-table tbody {background: white;border-radius: 8px;box-shadow: 0 0 0 8px white;}.data-table h3, .data-table h5, .data-table h6 {margin-bottom: 0;}.data-table h3, .data-table h5 {color: var(--bs-body-color);}.accordion .table.data-table>thead>*>* {padding-bottom: 0;}.info-table tbody {display: inline-table;width: 100%;}.info-table td {font-weight: bold;}.info-table tr>td:first-child {font-weight: normal;color: #757575;}.ns:before {content: " ";}.nc:before {content: ",";}.trezor-logo {width: 128px;height: 32px;position: absolute;top: 16px;background-size: cover;background-image: url("data:image/svg+xml,%3Csvg style='width: 128px%3B' version='1.1' xmlns='http://www.w3.org/2000/svg' x='0px' y='0px' viewBox='0 0 163.7 41.9' space='preserve'%3E%3Cpolygon points='101.1 12.8 118.2 12.8 118.2 17.3 108.9 29.9 118.2 29.9 118.2 35.2 101.1 35.2 101.1 30.7 110.4 18.1 101.1 18.1'%3E%3C/polygon%3E%3Cpath d='M158.8 26.9c2.1-0.8 4.3-2.9 4.3-6.6c0-4.5-3.1-7.4-7.7-7.4h-10.5v22.3h5.8v-7.5h2.2l4.1 7.5h6.7L158.8 26.9z M154.7 22.5h-4V18h4c1.5 0 2.5 0.9 2.5 2.2C157.2 21.6 156.2 22.5 154.7 22.5z'%3E%3C/path%3E%3Cpath d='M130.8 12.5c-6.8 0-11.6 4.9-11.6 11.5s4.9 11.5 11.6 11.5s11.7-4.9 11.7-11.5S137.6 12.5 130.8 12.5z M130.8 30.3c-3.4 0-5.7-2.6-5.7-6.3c0-3.8 2.3-6.3 5.7-6.3c3.4 0 5.8 2.6 5.8 6.3C136.6 27.7 134.2 30.3 130.8 30.3z'%3E%3C/path%3E%3Cpolygon points='82.1 12.8 98.3 12.8 98.3 18 87.9 18 87.9 21.3 98 21.3 98 26.4 87.9 26.4 87.9 30 98.3 30 98.3 35.2 82.1 35.2'%3E%3C/polygon%3E%3Cpath d='M24.6 9.7C24.6 4.4 20 0 14.4 0S4.2 4.4 4.2 9.7v3.1H0v22.3h0l14.4 6.7l14.4-6.7h0V12.9h-4.2V9.7z M9.4 9.7c0-2.5 2.2-4.5 5-4.5s5 2 5 4.5v3.1H9.4V9.7z M23 31.5l-8.6 4l-8.6-4V18.1H23V31.5z'%3E%3C/path%3E%3Cpath d='M79.4 20.3c0-4.5-3.1-7.4-7.7-7.4H61.2v22.3H67v-7.5h2.2l4.1 7.5H80l-4.9-8.3C77.2 26.1 79.4 24 79.4 20.3z M71 22.5h-4V18h4c1.5 0 2.5 0.9 2.5 2.2C73.5 21.6 72.5 22.5 71 22.5z'%3E%3C/path%3E%3Cpolygon points='40.5 12.8 58.6 12.8 58.6 18.1 52.4 18.1 52.4 35.2 46.6 35.2 46.6 18.1 40.5 18.1'%3E%3C/polygon%3E%3C/svg%3E");}.copyable::before, .copied::before {width: 18px;height: 16px;margin: 3px -18px;content: "";position: absolute;background-size: cover;}.copyable::before {display: none;cursor: copy;background-image: url("data:image/svg+xml,%3Csvg width='18' height='16' viewBox='0 0 18 16' fill='none' xmlns='http://www.w3.org/2000/svg'%3E%3Cpath d='M10.5 10.4996H13.5V2.49963H5.5V5.49963' stroke='%2300854D' stroke-width='1.5' stroke-linecap='round' stroke-linejoin='round'/%3E%3Cpath d='M10.4998 5.49976H2.49976V13.4998H10.4998V5.49976Z' stroke='%2300854D' stroke-width='1.5' stroke-linecap='round' stroke-linejoin='round'/%3E%3C/svg%3E");}.copyable:hover::before {display: inline-block;}.copied::before {transition: all 0.4s ease;transform: scale(1.2);background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='18' height='16' viewBox='-30 -30 330 330'%3E%3Cpath d='M 30,180 90,240 240,30' style='stroke:%2300854D;stroke-width:32;fill:none'/%3E%3C/svg%3E");}.h-data {letter-spacing: 0.12em;font-weight: normal !important;}.tx-detail {background: #f6f6f6;color: #757575;border-radius: 10px;box-shadow: 0 0 0 10px white;width: calc(100% - 20px);margin-left: 10px;margin-top: 3rem;overflow-wrap: break-word;}.tx-detail:first-child {margin-top: 1rem;}.tx-detail:last-child {margin-bottom: 2rem;}.tx-detail span.ellipsis, .tx-detail a.ellipsis {display: block;float: left;max-width: 100%;}.tx-detail>.head, .tx-detail>.footer {padding: 1.5rem;--bs-gutter-x: 0;}.tx-detail>.head {border-radius: 10px 10px 0 0;}.tx-detail .txid {font-size: 106%;letter-spacing: -0.01em;}.tx-detail>.body {padding: 0 1.5rem;--bs-gutter-x: 0;letter-spacing: -0.01em;}.tx-detail>.subhead {padding: 1.5rem 1.5rem 0.4rem 1.5rem;--bs-gutter-x: 0;letter-spacing: 0.1em;text-transform: uppercase;color: var(--bs-body-color);}.tx-detail>.subhead-2 {padding: 0.3rem 1.5rem 0 1.5rem;--bs-gutter-x: 0;font-size: .875em;color: var(--bs-body-color);}.tx-in .col-12, .tx-out .col-12, .tx-addr .col-12 {background-color: white;padding: 1.2rem 1.3rem;border-bottom: 1px solid #f6f6f6;}.amt-out {padding: 1.2rem 0 1.2rem 1rem;text-align: right;overflow-wrap: break-word;}.tx-in .col-12:last-child, .tx-out .col-12:last-child {border-bottom: none;}.tx-own {background-color: #fff9e3 !important;}.tx-amt {float: right !important;}.spent {color: #dc3545 !important;}.unspent {color: #28a745 !important;}.outpoint {color: #757575 !important;}.spent, .unspent, .outpoint {display: inline-block;text-align: right;min-width: 18px;text-decoration: none !important;}.octicon {height: 24px;width: 24px;margin-left: -12px;margin-top: 19px;position: absolute;background-size: cover;background-image: url("data:image/svg+xml,%3Csvg width='24' height='24' viewBox='0 0 24 24' fill='none' xmlns='http://www.w3.org/2000/svg'%3E%3Cpath d='M9 4.5L16.5 12L9 19.5' stroke='%23AFAFAF' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'/%3E%3C/svg%3E%0A");}.txvalue {color: var(--bs-body-color);font-weight: bold;}.txerror {color: #c51f13;}.txerror a, .txerror .txvalue {color: #c51f13;}.txerror .copyable::before, .txerror .copied::before {filter: invert(86%) sepia(43%) saturate(732%) hue-rotate(367deg) brightness(84%);}.tx-amt .amt:hover, .tx-amt.amt:hover, .amt-out>.amt:hover {color: var(--bs-body-color);}.prim-amt {display: initial;}.sec-amt {display: none;}.csec-amt {display: none;}.base-amt {display: none;}.cbase-amt {display: none;}.tooltip {--bs-tooltip-opacity: 1;--bs-tooltip-max-width: 380px;--bs-tooltip-bg: #fff;--bs-tooltip-color: var(--bs-body-color);--bs-tooltip-padding-x: 1rem;--bs-tooltip-padding-y: 0.8rem;filter: drop-shadow(0px 24px 64px rgba(22, 27, 45, 0.25));}.l-tooltip {text-align: start;display: inline-block;}.l-tooltip .prim-amt, .l-tooltip .sec-amt, .l-tooltip .csec-amt, .l-tooltip .base-amt, .l-tooltip .cbase-amt {display: initial;float: right;}.l-tooltip .amt-time {padding-right: 3rem;float: left;}.amt-dec {font-size: 95%;}.unconfirmed {color: white;background-color: #c51e13;padding: 0.7rem 1.2rem;border-radius: 1.4rem;}.json {word-wrap: break-word;font-size: smaller;background: #002b31;border-radius: 8px;}#raw {padding: 1.5rem 2rem;color: #ffffff;letter-spacing: 0.02em;}#raw .string {color: #2bca87;}#raw .number, #raw .boolean {color: #efc941;}#raw .null {color: red;}@media (max-width: 768px) {body {font-size: 0.8rem;background: linear-gradient(to bottom, #f6f6f6 500px, #e5e5e5 0), #e5e5e5;}.container {padding-left: 2px;padding-right: 2px;}.accordion-body {padding: var(--bs-accordion-body-padding-y) 0;}.octicon {scale: 60% !important;margin-top: -2px;}.unconfirmed {padding: 0.1rem 0.8rem;}.btn {--bs-btn-font-size: 0.8rem;}}@media (max-width: 991px) {#header .container {min-height: 40px;}#header .dropdown-menu[data-bs-popper] {left: 0;right: initial;}.trezor-logo {top: 10px;}.octicon {scale: 80%;}.table.data-table>:not(caption)>*>* {padding: 0.8rem 0.4rem;}.tx-in .col-12, .tx-out .col-12, .tx-addr .col-12 {padding: 0.7rem 1.1rem;}.amt-out {padding: 0.7rem 0 0.7rem 1rem }}@media (min-width: 769px) {body {font-size: 0.9rem;}.btn {--bs-btn-font-size: 0.9rem;}}@media (min-width: 1200px) {.h1, h1 {font-size: 2.4rem;}body {font-size: 1rem;}.btn {--bs-btn-font-size: 1rem;}} \ No newline at end of file diff --git a/static/css/main.min.4.css b/static/css/main.min.4.css new file mode 100644 index 00000000..54dd88a2 --- /dev/null +++ b/static/css/main.min.4.css @@ -0,0 +1 @@ +@import "TTHoves/TTHoves.css";* {margin: 0;padding: 0;outline: none;font-family: "TT Hoves", -apple-system, "Segoe UI", "Helvetica Neue", Arial, sans-serif;}html, body {height: 100%;}body {min-height: 100%;margin: 0;background: linear-gradient(to bottom, #f6f6f6 360px, #e5e5e5 0), #e5e5e5;background-repeat: no-repeat;}a {color: #00854d;text-decoration: none;}a:hover {color: #00854d;text-decoration: underline;}select {border-radius: 0.5rem;padding-left: 0.5rem;border: 1px solid #ced4da;color: var(--bs-body-color);min-height: 45px;}#header {position: fixed;top: 0;left: 0;width: 100%;margin: 0;padding-bottom: 0;padding-top: 0;background-color: white;border-bottom: 1px solid #f6f6f6;z-index: 10;}#header a {color: var(--bs-navbar-brand-color);}#header a:hover {color: var(--bs-navbar-brand-hover-color);}#header .navbar {--bs-navbar-padding-y: 0.7rem;}#header .form-control-lg {font-size: 1rem;padding: 0.75rem 1rem;}#header .container {min-height: 50px;}#header .btn.dropdown-toggle {padding-right: 0;}#header .dropdown-menu {--bs-dropdown-min-width: 13rem;}#header .dropdown-menu[data-bs-popper] {left: initial;right: 0;}#header .dropdown-menu.show {display: flex;}.form-control:focus {outline: 0;box-shadow: none;border-color: #00854d;}.base-value {color: #757575 !important;padding-left: 0.5rem;font-weight: normal;}.badge {vertical-align: middle;text-transform: uppercase;letter-spacing: 0.15em;--bs-badge-padding-x: 0.8rem;--bs-badge-font-weight: normal;--bs-badge-border-radius: 0.6rem;}.bg-secondary {background-color: #757575 !important;}.accordion {--bs-accordion-border-radius: 10px;--bs-accordion-inner-border-radius: calc(10px - 1px);--bs-accordion-color: var(--bs-body-color);--bs-accordion-active-color: var(--bs-body-color);--bs-accordion-active-bg: white;--bs-accordion-btn-active-icon: url("data:image/svg+xml,");}.accordion-button:focus {outline: 0;box-shadow: none;}.accordion-body {letter-spacing: -0.01em;}.bb-group {border: 0.6rem solid #f6f6f6;background-color: #f6f6f6;border-radius: 0.5rem;position: relative;display: inline-flex;vertical-align: middle;}.bb-group>.btn {--bs-btn-padding-x: 0.5rem;--bs-btn-padding-y: 0.22rem;--bs-btn-border-radius: 0.3rem;--bs-btn-border-width: 0;color: #545454;}.bb-group>.btn-check:checked+.btn, .bb-group .btn.active {color: black;font-weight: bold;background-color: white;}.paging {display: flex;}.paging .bb-group>.btn {min-width: 2rem;margin-left: 0.1rem;margin-right: 0.1rem;}.paging .bb-group>.btn:hover {background-color: white;}.paging a {text-decoration: none;}.btn-paging {--bs-btn-color: #757575;--bs-btn-border-color: #e2e2e2;--bs-btn-hover-color: black;--bs-btn-hover-bg: #f6f6f6;--bs-btn-hover-border-color: #e2e2e2;--bs-btn-focus-shadow-rgb: 108, 117, 125;--bs-btn-active-color: #fff;--bs-btn-active-bg: #e2e2e2;--bs-btn-active-border-color: #e2e2e2;--bs-btn-active-shadow: inset 0 3px 5px rgba(0, 0, 0, 0.125);--bs-gradient: none;--bs-btn-padding-y: 0.75rem;--bs-btn-padding-x: 1.1rem;--bs-btn-border-radius: 0.5rem;--bs-btn-font-weight: bold;background-color: #f6f6f6;}span.btn-paging {cursor: initial;}span.btn-paging:hover {color: #757575;}.btn-paging.active:hover {background-color: white;}.paging-group {border: 1px solid #e2e2e2;border-radius: 0.5rem;}.paging-group>.bb-group {border: 0.53rem solid #f6f6f6;}#wrap {min-height: 100%;height: auto;padding: 112px 0 75px 0;margin: 0 auto -56px;}#footer {background-color: black;color: #757575;height: 56px;overflow: hidden;}.navbar-form {width: 60%;}.navbar-form button {margin-left: -50px;position: relative;}.search-icon {width: 16px;height: 16px;position: absolute;top: 16px;background-size: cover;background-image: url("data:image/svg+xml, %3Csvg width='16' height='16' viewBox='0 0 16 16' fill='none' xmlns='http://www.w3.org/2000/svg'%3E%3Cpath d='M7.24976 12.5C10.1493 12.5 12.4998 10.1495 12.4998 7.25C12.4998 4.35051 10.1493 2 7.24976 2C4.35026 2 1.99976 4.35051 1.99976 7.25C1.99976 10.1495 4.35026 12.5 7.24976 12.5Z' stroke='black' stroke-width='1.5' stroke-linecap='round' stroke-linejoin='round' /%3E%3Cpath d='M10.962 10.9625L13.9996 14.0001' stroke='black' stroke-width='1.5' stroke-linecap='round' stroke-linejoin='round' /%3E%3C/svg%3E");}.navbar-form ::placeholder {color: #e2e2e2;}.ellipsis {overflow: hidden;text-overflow: ellipsis;white-space: nowrap;}.data-table {table-layout: fixed;overflow-wrap: anywhere;margin-left: 8px;margin-top: 2rem;margin-bottom: 2rem;width: calc(100% - 16px);}.data-table thead {padding-bottom: 20px;}.table.data-table> :not(caption)>*>* {padding: 0.8rem 0.8rem;background-color: var(--bs-table-bg);border-bottom-width: 1px;box-shadow: inset 0 0 0 9999px var(--bs-table-accent-bg);}.table.data-table>thead>*>* {padding-bottom: 1.5rem;}.table.data-table>*>*:last-child>* {border-bottom: none;}.data-table thead, .data-table thead tr, .data-table thead th {color: #757575;border: none;font-weight: normal;}.data-table tbody th {color: #757575;font-weight: normal;}.data-table tbody {background: white;border-radius: 8px;box-shadow: 0 0 0 8px white;}.data-table h3, .data-table h5, .data-table h6 {margin-bottom: 0;}.data-table h3, .data-table h5 {color: var(--bs-body-color);}.accordion .table.data-table>thead>*>* {padding-bottom: 0;}.info-table tbody {display: inline-table;width: 100%;}.info-table td {font-weight: bold;}.info-table tr>td:first-child {font-weight: normal;color: #757575;}.ns:before {content: " ";}.nc:before {content: ",";}.trezor-logo {width: 128px;height: 32px;position: absolute;top: 16px;background-size: cover;background-image: url("data:image/svg+xml,%3Csvg style='width: 128px%3B' version='1.1' xmlns='http://www.w3.org/2000/svg' x='0px' y='0px' viewBox='0 0 163.7 41.9' space='preserve'%3E%3Cpolygon points='101.1 12.8 118.2 12.8 118.2 17.3 108.9 29.9 118.2 29.9 118.2 35.2 101.1 35.2 101.1 30.7 110.4 18.1 101.1 18.1'%3E%3C/polygon%3E%3Cpath d='M158.8 26.9c2.1-0.8 4.3-2.9 4.3-6.6c0-4.5-3.1-7.4-7.7-7.4h-10.5v22.3h5.8v-7.5h2.2l4.1 7.5h6.7L158.8 26.9z M154.7 22.5h-4V18h4c1.5 0 2.5 0.9 2.5 2.2C157.2 21.6 156.2 22.5 154.7 22.5z'%3E%3C/path%3E%3Cpath d='M130.8 12.5c-6.8 0-11.6 4.9-11.6 11.5s4.9 11.5 11.6 11.5s11.7-4.9 11.7-11.5S137.6 12.5 130.8 12.5z M130.8 30.3c-3.4 0-5.7-2.6-5.7-6.3c0-3.8 2.3-6.3 5.7-6.3c3.4 0 5.8 2.6 5.8 6.3C136.6 27.7 134.2 30.3 130.8 30.3z'%3E%3C/path%3E%3Cpolygon points='82.1 12.8 98.3 12.8 98.3 18 87.9 18 87.9 21.3 98 21.3 98 26.4 87.9 26.4 87.9 30 98.3 30 98.3 35.2 82.1 35.2'%3E%3C/polygon%3E%3Cpath d='M24.6 9.7C24.6 4.4 20 0 14.4 0S4.2 4.4 4.2 9.7v3.1H0v22.3h0l14.4 6.7l14.4-6.7h0V12.9h-4.2V9.7z M9.4 9.7c0-2.5 2.2-4.5 5-4.5s5 2 5 4.5v3.1H9.4V9.7z M23 31.5l-8.6 4l-8.6-4V18.1H23V31.5z'%3E%3C/path%3E%3Cpath d='M79.4 20.3c0-4.5-3.1-7.4-7.7-7.4H61.2v22.3H67v-7.5h2.2l4.1 7.5H80l-4.9-8.3C77.2 26.1 79.4 24 79.4 20.3z M71 22.5h-4V18h4c1.5 0 2.5 0.9 2.5 2.2C73.5 21.6 72.5 22.5 71 22.5z'%3E%3C/path%3E%3Cpolygon points='40.5 12.8 58.6 12.8 58.6 18.1 52.4 18.1 52.4 35.2 46.6 35.2 46.6 18.1 40.5 18.1'%3E%3C/polygon%3E%3C/svg%3E");}.copyable::before, .copied::before {width: 18px;height: 16px;margin: 3px -18px;content: "";position: absolute;background-size: cover;}.copyable::before {display: none;cursor: copy;background-image: url("data:image/svg+xml,%3Csvg width='18' height='16' viewBox='0 0 18 16' fill='none' xmlns='http://www.w3.org/2000/svg'%3E%3Cpath d='M10.5 10.4996H13.5V2.49963H5.5V5.49963' stroke='%2300854D' stroke-width='1.5' stroke-linecap='round' stroke-linejoin='round'/%3E%3Cpath d='M10.4998 5.49976H2.49976V13.4998H10.4998V5.49976Z' stroke='%2300854D' stroke-width='1.5' stroke-linecap='round' stroke-linejoin='round'/%3E%3C/svg%3E");}.copyable:hover::before {display: inline-block;}.copied::before {transition: all 0.4s ease;transform: scale(1.2);background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='18' height='16' viewBox='-30 -30 330 330'%3E%3Cpath d='M 30,180 90,240 240,30' style='stroke:%2300854D;stroke-width:32;fill:none'/%3E%3C/svg%3E");}.h-data {letter-spacing: 0.12em;font-weight: normal !important;}.tx-detail {background: #f6f6f6;color: #757575;border-radius: 10px;box-shadow: 0 0 0 10px white;width: calc(100% - 20px);margin-left: 10px;margin-top: 3rem;overflow-wrap: break-word;}.tx-detail:first-child {margin-top: 1rem;}.tx-detail:last-child {margin-bottom: 2rem;}.tx-detail span.ellipsis, .tx-detail a.ellipsis {display: block;float: left;max-width: 100%;}.tx-detail>.head, .tx-detail>.footer {padding: 1.5rem;--bs-gutter-x: 0;}.tx-detail>.head {border-radius: 10px 10px 0 0;}.tx-detail .txid {font-size: 106%;letter-spacing: -0.01em;}.tx-detail>.body {padding: 0 1.5rem;--bs-gutter-x: 0;letter-spacing: -0.01em;}.tx-detail>.subhead {padding: 1.5rem 1.5rem 0.4rem 1.5rem;--bs-gutter-x: 0;letter-spacing: 0.1em;text-transform: uppercase;color: var(--bs-body-color);}.tx-detail>.subhead-2 {padding: 0.3rem 1.5rem 0 1.5rem;--bs-gutter-x: 0;font-size: .875em;color: var(--bs-body-color);}.tx-in .col-12, .tx-out .col-12, .tx-addr .col-12 {background-color: white;padding: 1.2rem 1.3rem;border-bottom: 1px solid #f6f6f6;}.amt-out {padding: 1.2rem 0 1.2rem 1rem;text-align: right;overflow-wrap: break-word;}.tx-in .col-12:last-child, .tx-out .col-12:last-child {border-bottom: none;}.tx-own {background-color: #fff9e3 !important;}.tx-amt {float: right !important;}.spent {color: #dc3545 !important;}.unspent {color: #28a745 !important;}.outpoint {color: #757575 !important;}.spent, .unspent, .outpoint {display: inline-block;text-align: right;min-width: 18px;text-decoration: none !important;}.octicon {height: 24px;width: 24px;margin-left: -12px;margin-top: 19px;position: absolute;background-size: cover;background-image: url("data:image/svg+xml,%3Csvg width='24' height='24' viewBox='0 0 24 24' fill='none' xmlns='http://www.w3.org/2000/svg'%3E%3Cpath d='M9 4.5L16.5 12L9 19.5' stroke='%23AFAFAF' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'/%3E%3C/svg%3E%0A");}.txvalue {color: var(--bs-body-color);font-weight: bold;}.txerror {color: #c51f13;}.txerror a, .txerror .txvalue {color: #c51f13;}.txerror .copyable::before, .txerror .copied::before {filter: invert(86%) sepia(43%) saturate(732%) hue-rotate(367deg) brightness(84%);}.tx-amt .amt:hover, .tx-amt.amt:hover, .amt-out>.amt:hover {color: var(--bs-body-color);}.prim-amt {display: initial;}.sec-amt {display: none;}.csec-amt {display: none;}.base-amt {display: none;}.cbase-amt {display: none;}.tooltip {--bs-tooltip-opacity: 1;--bs-tooltip-max-width: 380px;--bs-tooltip-bg: #fff;--bs-tooltip-color: var(--bs-body-color);--bs-tooltip-padding-x: 1rem;--bs-tooltip-padding-y: 0.8rem;filter: drop-shadow(0px 24px 64px rgba(22, 27, 45, 0.25));}.l-tooltip {text-align: start;display: inline-block;}.l-tooltip .prim-amt, .l-tooltip .sec-amt, .l-tooltip .csec-amt, .l-tooltip .base-amt, .l-tooltip .cbase-amt {display: initial;float: right;}.l-tooltip .amt-time {padding-right: 3rem;float: left;}.amt-dec {font-size: 95%;}.unconfirmed {color: white;background-color: #c51e13;padding: 0.7rem 1.2rem;border-radius: 1.4rem;}.json {word-wrap: break-word;font-size: smaller;background: #002b31;border-radius: 8px;}#raw {padding: 1.5rem 2rem;color: #ffffff;letter-spacing: 0.02em;}#raw .string {color: #2bca87;}#raw .number, #raw .boolean {color: #efc941;}#raw .null {color: red;}@media (max-width: 768px) {body {font-size: 0.8rem;background: linear-gradient(to bottom, #f6f6f6 500px, #e5e5e5 0), #e5e5e5;}.container {padding-left: 2px;padding-right: 2px;}.accordion-body {padding: var(--bs-accordion-body-padding-y) 0;}.octicon {scale: 60% !important;margin-top: -2px;}.unconfirmed {padding: 0.1rem 0.8rem;}.btn {--bs-btn-font-size: 0.8rem;}}@media (max-width: 991px) {#header .container {min-height: 40px;}#header .dropdown-menu[data-bs-popper] {left: 0;right: initial;}.trezor-logo {top: 10px;}.octicon {scale: 80%;}.table.data-table>:not(caption)>*>* {padding: 0.8rem 0.4rem;}.tx-in .col-12, .tx-out .col-12, .tx-addr .col-12 {padding: 0.7rem 1.1rem;}.amt-out {padding: 0.7rem 0 0.7rem 1rem }}@media (min-width: 769px) {body {font-size: 0.9rem;}.btn {--bs-btn-font-size: 0.9rem;}}@media (min-width: 1200px) {.h1, h1 {font-size: 2.4rem;}body {font-size: 1rem;}.btn {--bs-btn-font-size: 1rem;}} \ No newline at end of file diff --git a/static/internal_templates/contract_info.html b/static/internal_templates/contract_info.html new file mode 100644 index 00000000..57cbfece --- /dev/null +++ b/static/internal_templates/contract_info.html @@ -0,0 +1,39 @@ +{{define "specific"}} {{if eq .ChainType 1}} + +
+
+
+ +
+
+ +
+
+
+
+ To update contract, use POST request to /admin/contract-info/ endpoint. Example: +
+
+            curl -k -v  \
+            'https://<internaladdress>/admin/contract-info/' \
+            -H 'Content-Type: application/json' \
+            --data '[{ContractInfo},{ContractInfo},...]'        
+        
+
+
+{{else}} Not supported {{end}}{{end}} diff --git a/static/internal_templates/index.html b/static/internal_templates/index.html index 5fef7011..7a94bce8 100644 --- a/static/internal_templates/index.html +++ b/static/internal_templates/index.html @@ -1,10 +1,14 @@ {{define "specific"}} {{if eq .ChainType 1}} -{{end}} -{{end}} \ No newline at end of file + +{{end}}{{end}} diff --git a/static/js/main.js b/static/js/main.js index d729efc9..b1d31408 100644 --- a/static/js/main.js +++ b/static/js/main.js @@ -85,6 +85,79 @@ function addressAliasTooltip() { return `${type}
${address}
`; } +function handleTxPage(rawData, txId) { + const rawOutput = document.getElementById('raw'); + const rawButton = document.getElementById('raw-button'); + const rawHexButton = document.getElementById('raw-hex-button'); + + rawOutput.innerHTML = syntaxHighlight(rawData); + + let isShowingHexData = false; + + const memoizedResponses = {}; + + async function getTransactionHex(txId) { + // BTC-like coins have a 'hex' field in the raw data + if (rawData['hex']) { + return rawData['hex']; + } + if (memoizedResponses[txId]) { + return memoizedResponses[txId]; + } + const fetchedData = await fetchTransactionHex(txId); + memoizedResponses[txId] = fetchedData; + return fetchedData; + } + + async function fetchTransactionHex(txId) { + const response = await fetch(`/api/rawtx/${txId}`); + if (!response.ok) { + throw new Error(`Error fetching data: ${response.status}`); + } + const txHex = await response.text(); + const hexWithoutQuotes = txHex.replace(/"/g, ''); + return hexWithoutQuotes; + } + + function updateButtonStyles() { + if (isShowingHexData) { + rawButton.classList.add('active'); + rawButton.style.fontWeight = 'normal'; + rawHexButton.classList.remove('active'); + rawHexButton.style.fontWeight = 'bold'; + } else { + rawButton.classList.remove('active'); + rawButton.style.fontWeight = 'bold'; + rawHexButton.classList.add('active'); + rawHexButton.style.fontWeight = 'normal'; + } + } + + updateButtonStyles(); + + rawHexButton.addEventListener('click', async () => { + if (!isShowingHexData) { + try { + const txHex = await getTransactionHex(txId); + rawOutput.textContent = txHex; + } catch (error) { + console.error('Error fetching raw transaction hex:', error); + rawOutput.textContent = `Error fetching raw transaction hex: ${error.message}`; + } + isShowingHexData = true; + updateButtonStyles(); + } + }); + + rawButton.addEventListener('click', () => { + if (isShowingHexData) { + rawOutput.innerHTML = syntaxHighlight(rawData); + isShowingHexData = false; + updateButtonStyles(); + } + }); +} + window.addEventListener("DOMContentLoaded", () => { const a = getCoinCookie(); if (a?.length === 3) { @@ -127,7 +200,8 @@ window.addEventListener("DOMContentLoaded", () => { if (e.clientX < e.target.getBoundingClientRect().x) { let t = e.target.getAttribute("cc"); if (!t) t = e.target.innerText; - navigator.clipboard.writeText(t); + const textToCopy = t.trim(); + navigator.clipboard.writeText(textToCopy); e.target.className = e.target.className.replace("copyable", "copied"); setTimeout( () => diff --git a/static/js/main.min.3.js b/static/js/main.min.3.js deleted file mode 100644 index 72a9ffe0..00000000 --- a/static/js/main.min.3.js +++ /dev/null @@ -1 +0,0 @@ -function syntaxHighlight(t){return(t=(t=JSON.stringify(t,void 0,2)).replace(/&/g,"&").replace(//g,">")).length>1e6?`${t}`:t.replace(/("(\\u[a-zA-Z0-9]{4}|\\[^u]|[^\\"])*"(\s*:)?|\b(true|false|null)\b|-?\d+(?:\.\d*)?(?:[eE][+\-]?\d+)?)/g,t=>{let e="number";return/^"/.test(t)?e=/:$/.test(t)?"key":"string":/true|false/.test(t)?e="boolean":/null/.test(t)&&(e="null"),`${t}`})}function getCoinCookie(){if(hasSecondary)return document.cookie.split("; ").find(t=>t.startsWith("secondary_coin="))?.split("=")}function changeCSSStyle(t,e,l){let a=document.all?"rules":"cssRules";for(i=0,len=document.styleSheets[1][a].length;i`;if(a){let n=a.getAttribute("tm");n||(n="now"),r+=`${n}${a.outerHTML}
`}if(s&&(r+=`now${s.outerHTML}
`),e){let o=e.getAttribute("tm");o||(o="now"),r+=`${o}${e.outerHTML}
`}return l&&(r+=`now${l.outerHTML}
`),`${r}`}function addressAliasTooltip(){let t=this.getAttribute("alias-type"),e=this.getAttribute("cc");return`${t}
${e}
`}window.addEventListener("DOMContentLoaded",()=>{let t=getCoinCookie();t?.length===3&&("true"===t[2]&&(changeCSSStyle(".prim-amt","display","none"),changeCSSStyle(".sec-amt","display","initial")),document.querySelectorAll(".amt").forEach(t=>new bootstrap.Tooltip(t,{title:amountTooltip,html:!0}))),document.querySelectorAll("[alias-type]").forEach(t=>new bootstrap.Tooltip(t,{title:addressAliasTooltip,html:!0})),document.querySelectorAll("[tt]").forEach(t=>new bootstrap.Tooltip(t,{title:t.getAttribute("tt")})),document.querySelectorAll("#header .bb-group>.btn-check").forEach(t=>t.addEventListener("click",t=>{let e=getCoinCookie(),l="secondary-coin"===t.target.id;e?.length===3&&"true"===e[2]!==l&&(document.cookie=`${e[0]}=${e[1]}=${l}; Path=/`,changeCSSStyle(".prim-amt","display",l?"none":"initial"),changeCSSStyle(".sec-amt","display",l?"initial":"none"))})),document.querySelectorAll(".copyable").forEach(t=>t.addEventListener("click",t=>{if(t.clientXt.target.className=t.target.className.replace("copied","copyable"),1e3),t.preventDefault()}}))}); \ No newline at end of file diff --git a/static/js/main.min.4.js b/static/js/main.min.4.js new file mode 100644 index 00000000..5e237185 --- /dev/null +++ b/static/js/main.min.4.js @@ -0,0 +1 @@ +function syntaxHighlight(t){return(t=(t=JSON.stringify(t,void 0,2)).replace(/&/g,"&").replace(//g,">")).length>1e6?`${t}`:t.replace(/("(\\u[a-zA-Z0-9]{4}|\\[^u]|[^\\"])*"(\s*:)?|\b(true|false|null)\b|-?\d+(?:\.\d*)?(?:[eE][+\-]?\d+)?)/g,(t=>{let e="number";return/^"/.test(t)?e=/:$/.test(t)?"key":"string":/true|false/.test(t)?e="boolean":/null/.test(t)&&(e="null"),`${t}`}))}function getCoinCookie(){if(hasSecondary)return document.cookie.split("; ").find((t=>t.startsWith("secondary_coin=")))?.split("=")}function changeCSSStyle(t,e,n){const a=document.all?"rules":"cssRules";for(i=0,len=document.styleSheets[1][a].length;i`;if(a){let t=a.getAttribute("tm");t||(t="now"),i+=`${t}${a.outerHTML}
`}if(o&&(i+=`now${o.outerHTML}
`),e){let t=e.getAttribute("tm");t||(t="now"),i+=`${t}${e.outerHTML}
`}return n&&(i+=`now${n.outerHTML}
`),`${i}`}function addressAliasTooltip(){return`${this.getAttribute("alias-type")}
${this.getAttribute("cc")}
`}function handleTxPage(t,e){const n=document.getElementById("raw"),a=document.getElementById("raw-button"),o=document.getElementById("raw-hex-button");n.innerHTML=syntaxHighlight(t);let i=!1;const r={};async function s(e){if(t.hex)return t.hex;if(r[e])return r[e];const n=await async function(t){const e=await fetch(`/api/rawtx/${t}`);if(!e.ok)throw new Error(`Error fetching data: ${e.status}`);const n=await e.text();return n.replace(/"/g,"")}(e);return r[e]=n,n}function l(){i?(a.classList.add("active"),a.style.fontWeight="normal",o.classList.remove("active"),o.style.fontWeight="bold"):(a.classList.remove("active"),a.style.fontWeight="bold",o.classList.add("active"),o.style.fontWeight="normal")}l(),o.addEventListener("click",(async()=>{if(!i){try{const t=await s(e);n.textContent=t}catch(t){console.error("Error fetching raw transaction hex:",t),n.textContent=`Error fetching raw transaction hex: ${t.message}`}i=!0,l()}})),a.addEventListener("click",(()=>{i&&(n.innerHTML=syntaxHighlight(t),i=!1,l())}))}window.addEventListener("DOMContentLoaded",(()=>{const t=getCoinCookie();3===t?.length&&("true"===t[2]&&(changeCSSStyle(".prim-amt","display","none"),changeCSSStyle(".sec-amt","display","initial")),document.querySelectorAll(".amt").forEach((t=>new bootstrap.Tooltip(t,{title:amountTooltip,html:!0})))),document.querySelectorAll("[alias-type]").forEach((t=>new bootstrap.Tooltip(t,{title:addressAliasTooltip,html:!0}))),document.querySelectorAll("[tt]").forEach((t=>new bootstrap.Tooltip(t,{title:t.getAttribute("tt")}))),document.querySelectorAll("#header .bb-group>.btn-check").forEach((t=>t.addEventListener("click",(t=>{const e=getCoinCookie(),n="secondary-coin"===t.target.id;3===e?.length&&"true"===e[2]!==n&&(document.cookie=`${e[0]}=${e[1]}=${n}; Path=/`,changeCSSStyle(".prim-amt","display",n?"none":"initial"),changeCSSStyle(".sec-amt","display",n?"initial":"none"))})))),document.querySelectorAll(".copyable").forEach((t=>t.addEventListener("click",(t=>{if(t.clientXt.target.className=t.target.className.replace("copied","copyable")),1e3),t.preventDefault()}}))))})); \ No newline at end of file diff --git a/static/templates/tx.html b/static/templates/tx.html index 86b03071..1b94682d 100644 --- a/static/templates/tx.html +++ b/static/templates/tx.html @@ -51,6 +51,24 @@ Gas Price {{amountSpan $tx.EthereumSpecific.GasPrice $data "copyable"}} ({{amountSatsSpan $tx.EthereumSpecific.GasPrice $data "copyable"}} Gwei) + {{if $tx.EthereumSpecific.L1GasUsed}} + + L1 Gas Used + {{formatBigInt $tx.EthereumSpecific.L1GasUsed}} + + {{end}} + {{if $tx.EthereumSpecific.L1GasPrice}} + + L1 Gas Price + {{amountSpan $tx.EthereumSpecific.L1GasPrice $data "copyable"}} ({{amountSatsSpan $tx.EthereumSpecific.L1GasPrice $data "copyable"}} Gwei) + + {{end}} + {{if $tx.EthereumSpecific.L1FeeScalar}} + + L1 Fee Scalar + {{$tx.EthereumSpecific.L1FeeScalar}} + + {{end}} {{else}} Total Input @@ -99,6 +117,12 @@ {{end}} + {{if $tx.EthereumSpecific}} + + Nonce + {{$tx.EthereumSpecific.Nonce}} + + {{end}}
@@ -158,13 +182,19 @@ {{end}} {{end}}
-
Raw Transaction
-
-

+    
+    
+    
+

     
-
{{end}} diff --git a/static/test-websocket.html b/static/test-websocket.html index 3972aa53..e4e2b22b 100644 --- a/static/test-websocket.html +++ b/static/test-websocket.html @@ -1,823 +1,1293 @@ - + - - - - - - - Blockbook Websocket Test Page - + + + +
+
+

Blockbook Websocket Test Page

+
+
+
+ +
+
+ +
+
+ +
+
+
+
+ +
+
+
+
+
+ +
+
+
+
+
+ +
+
+ +
+
+
+
+
+
+
+
+ +
+
+
+ + + +
+
+
+
+
+
+
+
+
+ +
+
+
+ + +
+
+ + + + + +
+
+
+
+
+
+
+
+
+ +
+
+
+ +
+
+
+
+
+
+
+
+
+ +
+
+
+ +
+
+ + + + +
+
+
+
+
+
+
+
+
+ +
+
+
+ +
+
+
+
+
+
+
+
+
+ +
+
+
+ +
+
+
+
+
+
+
+
+
+ +
+
+
+ +
+
+ +
+
+
+
+
+
+
+
+
+ +
+
+ +
+
+
+
+
+
+
+
+ +
+
+ +
+
+ +
+
+ +
+
+
+
+
+
+
+ +
+
+ +
+
+ +
+
+
+
+
+
+
+ +
+
+ +
+
+ +
+
+
+
+
+
+
+ +
+
+ +
+
+ +
+
+
+
+
+
+
+ +
+
+ + +
+
+
+
+
+
+
+ +
+
+
+ + + +
+
+
+
+
+
+
+
+ +
+
+
+ + + +
+
+
+
+
+
+
+
+ +
+
+ +
+
+ +
+
+
+
+
+
+
+ +
+
+ +
+
+ +
+
+
+
+
+
+
+ +
+
+ +
+
+ +
+
+ +
+
+
+
+
+
+
+ +
+
+ +
+
+ +
+
+ +
+
+ +
+
+
+
+
+
+

+ + - - - -
-
-

Blockbook Websocket Test Page

-
-
-
- -
-
- -
-
- -
-
-
-
- -
-
-
-
-
-
- -
-
-
-
-
-
- -
-
- -
-
-
-
-
-
-
-
-
- -
-
-
- - - -
-
-
-
-
-
-
-
-
-
- -
-
-
- - -
-
- - - - - -
-
-
-
-
-
-
-
-
-
- -
-
-
- -
-
-
-
-
-
-
-
-
-
- -
-
-
- -
-
- - - - -
-
-
-
-
-
-
-
-
-
- -
-
-
- -
-
-
-
-
-
-
-
-
-
- -
-
-
- -
-
-
-
-
-
-
-
-
-
- -
-
-
- -
-
- -
-
-
-
-
-
-
-
-
-
- -
-
- -
-
-
-
-
-
-
-
-
- -
-
- -
-
- -
-
- -
-
-
-
-
-
-
- -
-
- -
-
- -
-
-
-
-
-
-
- -
-
- -
-
- -
-
-
-
-
-
-
- -
-
- -
-
- -
-
-
-
-
-
-
- -
-
- - -
-
-
-
-
-
-
- -
-
-
- - - -
-
-
-
-
-
-
-
- -
-
- -
-
- -
-
-
-
-
-
-
- -
-
- -
-
- -
-
-
-
-
-
-
- -
-
- -
-
- -
-
- -
-
-
-
-
-
-
- -
-
- -
-
- -
-
- -
-
- -
-
-
-
-
-
-

- - - diff --git a/tests/dbtestdata/fakechain_ethereumtype.go b/tests/dbtestdata/fakechain_ethereumtype.go new file mode 100644 index 00000000..3722ef41 --- /dev/null +++ b/tests/dbtestdata/fakechain_ethereumtype.go @@ -0,0 +1,150 @@ +package dbtestdata + +import ( + "encoding/json" + "math/big" + "strconv" + + "github.com/trezor/blockbook/bchain" +) + +type fakeBlockChainEthereumType struct { + *fakeBlockChain +} + +// NewFakeBlockChainEthereumType returns mocked blockchain RPC interface used for tests +func NewFakeBlockChainEthereumType(parser bchain.BlockChainParser) (bchain.BlockChain, error) { + return &fakeBlockChainEthereumType{&fakeBlockChain{&bchain.BaseChain{Parser: parser}}}, nil +} + +func (c *fakeBlockChainEthereumType) CreateMempool(chain bchain.BlockChain) (bchain.Mempool, error) { + return bchain.NewMempoolEthereumType(chain, 1, false), nil +} + +func (c *fakeBlockChainEthereumType) GetChainInfo() (v *bchain.ChainInfo, err error) { + return &bchain.ChainInfo{ + Chain: c.GetNetworkName(), + Blocks: 2, + Headers: 2, + Bestblockhash: GetTestEthereumTypeBlock2(c.Parser).BlockHeader.Hash, + Version: "001001", + Subversion: c.GetSubversion(), + }, nil +} + +func (c *fakeBlockChainEthereumType) GetBestBlockHash() (v string, err error) { + return GetTestEthereumTypeBlock2(c.Parser).BlockHeader.Hash, nil +} + +func (c *fakeBlockChainEthereumType) GetBestBlockHeight() (v uint32, err error) { + return GetTestEthereumTypeBlock2(c.Parser).BlockHeader.Height, nil +} + +func (c *fakeBlockChainEthereumType) GetBlockHash(height uint32) (v string, err error) { + b1 := GetTestEthereumTypeBlock1(c.Parser) + if height == b1.BlockHeader.Height { + return b1.BlockHeader.Hash, nil + } + b2 := GetTestEthereumTypeBlock2(c.Parser) + if height == b2.BlockHeader.Height { + return b2.BlockHeader.Hash, nil + } + return "", bchain.ErrBlockNotFound +} + +func (c *fakeBlockChainEthereumType) GetBlockHeader(hash string) (v *bchain.BlockHeader, err error) { + b1 := GetTestEthereumTypeBlock1(c.Parser) + if hash == b1.BlockHeader.Hash { + return &b1.BlockHeader, nil + } + b2 := GetTestEthereumTypeBlock2(c.Parser) + if hash == b2.BlockHeader.Hash { + return &b2.BlockHeader, nil + } + return nil, bchain.ErrBlockNotFound +} + +func (c *fakeBlockChainEthereumType) GetBlock(hash string, height uint32) (v *bchain.Block, err error) { + b1 := GetTestEthereumTypeBlock1(c.Parser) + if hash == b1.BlockHeader.Hash || height == b1.BlockHeader.Height { + return b1, nil + } + b2 := GetTestEthereumTypeBlock2(c.Parser) + if hash == b2.BlockHeader.Hash || height == b2.BlockHeader.Height { + return b2, nil + } + return nil, bchain.ErrBlockNotFound +} + +func (c *fakeBlockChainEthereumType) GetBlockInfo(hash string) (v *bchain.BlockInfo, err error) { + b1 := GetTestEthereumTypeBlock1(c.Parser) + if hash == b1.BlockHeader.Hash { + return getBlockInfo(b1), nil + } + b2 := GetTestEthereumTypeBlock2(c.Parser) + if hash == b2.BlockHeader.Hash { + return getBlockInfo(b2), nil + } + return nil, bchain.ErrBlockNotFound +} + +func (c *fakeBlockChainEthereumType) GetTransaction(txid string) (v *bchain.Tx, err error) { + v = getTxInBlock(GetTestEthereumTypeBlock1(c.Parser), txid) + if v == nil { + v = getTxInBlock(GetTestEthereumTypeBlock2(c.Parser), txid) + } + if v != nil { + return v, nil + } + return nil, bchain.ErrTxNotFound +} + +func (c *fakeBlockChainEthereumType) GetTransactionSpecific(tx *bchain.Tx) (v json.RawMessage, err error) { + txS, _ := tx.CoinSpecificData.(bchain.EthereumSpecificData) + + rm, err := json.Marshal(txS) + if err != nil { + return nil, err + } + return json.RawMessage(rm), nil +} + +func (c *fakeBlockChainEthereumType) EthereumTypeGetBalance(addrDesc bchain.AddressDescriptor) (*big.Int, error) { + return big.NewInt(123450000 + int64(addrDesc[0])), nil +} + +func (c *fakeBlockChainEthereumType) EthereumTypeGetNonce(addrDesc bchain.AddressDescriptor) (uint64, error) { + return uint64(addrDesc[0]), nil +} + +func (c *fakeBlockChainEthereumType) GetContractInfo(contractDesc bchain.AddressDescriptor) (*bchain.ContractInfo, error) { + addresses, _, _ := c.Parser.GetAddressesFromAddrDesc(contractDesc) + return &bchain.ContractInfo{ + Type: bchain.ERC20TokenType, + Contract: addresses[0], + Name: "Contract " + strconv.Itoa(int(contractDesc[0])), + Symbol: "S" + strconv.Itoa(int(contractDesc[0])), + Decimals: 18, + CreatedInBlock: 12345, + }, nil +} + +// EthereumTypeGetErc20ContractBalance returns simulated balance +func (c *fakeBlockChainEthereumType) EthereumTypeGetErc20ContractBalance(addrDesc, contractDesc bchain.AddressDescriptor) (*big.Int, error) { + return big.NewInt(1000000000 + int64(addrDesc[0])*1000 + int64(contractDesc[0])), nil +} + +// EthereumTypeRpcCall calls eth_call with given data and to address +func (c *fakeBlockChainEthereumType) EthereumTypeRpcCall(data, to, from string) (string, error) { + return data + "abcd", nil +} + +// EthereumTypeGetRawTransaction returns simulated transaction hex data +func (c *fakeBlockChainEthereumType) EthereumTypeGetRawTransaction(txid string) (string, error) { + return txid + "abcd", nil +} + +// GetTokenURI returns URI derived from the input contractDesc +func (c *fakeBlockChainEthereumType) GetTokenURI(contractDesc bchain.AddressDescriptor, tokenID *big.Int) (string, error) { + return "https://ipfs.io/ipfs/" + contractDesc.String()[3:] + ".json", nil +} diff --git a/tests/rpc/testdata/bitcoin_testnet4.json b/tests/rpc/testdata/bitcoin_testnet4.json new file mode 100644 index 00000000..e61c5d87 --- /dev/null +++ b/tests/rpc/testdata/bitcoin_testnet4.json @@ -0,0 +1,105 @@ +{ + "blockHeight": 41500, + "blockHash": "000000000000000466119d6e5eb24802dcc14605f4050ac586f45eaa61da2719", + "blockTime": 1724848265, + "blockTxs": [ + "3d40148138492c4c0b91207acc2ec1cb3942e1cb51713e6851f01450452314d1", + "38924e01871d5fb25dca1bc9d17ae8cb65155fcb12a70984fc65ec85d48efd2a", + "8b77d1e7b5d7c528a59917c13f42787fa1988db744c1e9bc58f024f15fbb2ebb", + "06a9373ca11293ec51d15c5c142118fd46ceec33c0a46a865448f9916337b2ef" + ], + "txDetails": { + "38924e01871d5fb25dca1bc9d17ae8cb65155fcb12a70984fc65ec85d48efd2a": { + "hex": "0200000002a6a8a1e0e89cc206f40efc707863510b866cd0f20487446f6373c5b136ea9ab3010000006a4730440220053c7b24201514691f67154cbfd1e2ba917b3813b44b6ed81afd75bd11f16c4f022075c24b3fc21e88071148c6daa1ca4075e55da1f3f403ceb943268016744b10d1012102d1b7b25ab15f33fc693ba6c9b80b4c35fca1708008c8afac171b33f1fef4bd59fdffffffcd227a67d359ad8aaf99d9a56fdb0604a18804d40e046d21607f95a0c263e6d1000000006a473044022029297263b9b49c5652bf2179f5c94968788dc8d63d42a268980b8b9d0bda480602206c5cae1eb7b23872e02e2967eb229d8ed9cc73331dbadbd0354b82f80937a23e012103e959e8ad180e0323105e95ceea131debdbe0d77bfd54289bad77d15164942acdfdffffff03c3b0090000000000160014de4e79ce2048a42698e04e079e94c97fd6e012cf9f770e000000000017a914d9e303986df109b001b97b45f3a00d84b6c9d7278788760200000000001600144a6a08ffbb16515133284e385b0ea29812ce99251ba20000", + "txid": "38924e01871d5fb25dca1bc9d17ae8cb65155fcb12a70984fc65ec85d48efd2a", + "blocktime": 1724848265, + "time": 1724848265, + "locktime": 41499, + "vsize": 398, + "version": 2, + "vin": [ + { + "txid": "b39aea36b1c573636f448704f2d06c860b51637870fc0ef406c29ce8e0a1a8a6", + "vout": 1, + "sequence": 4294967293, + "scriptSig": { + "hex": "4730440220053c7b24201514691f67154cbfd1e2ba917b3813b44b6ed81afd75bd11f16c4f022075c24b3fc21e88071148c6daa1ca4075e55da1f3f403ceb943268016744b10d1012102d1b7b25ab15f33fc693ba6c9b80b4c35fca1708008c8afac171b33f1fef4bd59" + } + }, + { + "txid": "d1e663c2a0957f60216d040ed40488a10406db6fa5d999af8aad59d3677a22cd", + "vout": 0, + "sequence": 4294967293, + "scriptSig": { + "hex": "473044022029297263b9b49c5652bf2179f5c94968788dc8d63d42a268980b8b9d0bda480602206c5cae1eb7b23872e02e2967eb229d8ed9cc73331dbadbd0354b82f80937a23e012103e959e8ad180e0323105e95ceea131debdbe0d77bfd54289bad77d15164942acd" + } + } + ], + "vout": [ + { + "value": 0.00635075, + "n": 0, + "scriptPubKey": { + "hex": "0014de4e79ce2048a42698e04e079e94c97fd6e012cf" + } + }, + { + "value": 0.00948127, + "n": 1, + "scriptPubKey": { + "hex": "a914c9e67d2b78a38857c786ea9a2fc3e64cb6e7756487" + } + }, + { + "value": 0.00161416, + "n": 2, + "scriptPubKey": { + "hex": "00144a6a08ffbb16515133284e385b0ea29812ce9925" + } + } + ] + }, + "8b77d1e7b5d7c528a59917c13f42787fa1988db744c1e9bc58f024f15fbb2ebb": { + "hex": "0200000001cd227a67d359ad8aaf99d9a56fdb0604a18804d40e046d21607f95a0c263e6d1020000006a473044022027687d38378d1e6c991f68815217e309f1e290a8c706159455a680457ec1545002202dd0d9fc7251a5a4f7d4b76d824981b97a4c5121ec46fee4786a283debde544501210223a0cd87e2f1958998684f6c75771a95727d310cc4d30ed34ca427affe89d4c2fdffffff038876020000000000160014f6a58ba8a373263dddcb82bd6202a1157270cb4de8b00400000000001600144237fc8335d817b911332fc9df26744215266b1794d204000000000017a914e5bd951e8d6b10fab8cea5b103c71ae3a37b95bf871ba20000", + "txid": "8b77d1e7b5d7c528a59917c13f42787fa1988db744c1e9bc58f024f15fbb2ebb", + "blocktime": 1724848265, + "time": 1724848265, + "locktime": 41499, + "vsize": 251, + "version": 2, + "vin": [ + { + "txid": "d1e663c2a0957f60216d040ed40488a10406db6fa5d999af8aad59d3677a22cd", + "vout": 2, + "sequence": 4294967293, + "scriptSig": { + "hex": "473044022027687d38378d1e6c991f68815217e309f1e290a8c706159455a680457ec1545002202dd0d9fc7251a5a4f7d4b76d824981b97a4c5121ec46fee4786a283debde544501210223a0cd87e2f1958998684f6c75771a95727d310cc4d30ed34ca427affe89d4c2" + } + } + ], + "vout": [ + { + "value": 0.00161416, + "n": 0, + "scriptPubKey": { + "hex": "0014f6a58ba8a373263dddcb82bd6202a1157270cb4d" + } + }, + { + "value": 0.00307432, + "n": 1, + "scriptPubKey": { + "hex": "00144237fc8335d817b911332fc9df26744215266b17" + } + }, + { + "value": 0.00316052, + "n": 2, + "scriptPubKey": { + "hex": "a914e5bd951e8d6b10fab8cea5b103c71ae3a37b95bf87" + } + } + ] + } + } +} diff --git a/tests/sync/testdata/bitcoin_testnet4.json b/tests/sync/testdata/bitcoin_testnet4.json new file mode 100644 index 00000000..5bd3c8e2 --- /dev/null +++ b/tests/sync/testdata/bitcoin_testnet4.json @@ -0,0 +1,266 @@ +{ + "connectBlocks": { + "syncRanges": [ + {"lower": 41500, "upper": 41514} + ], + "blocks": { + "41500": { + "height": 41500, + "hash": "000000000000000466119d6e5eb24802dcc14605f4050ac586f45eaa61da2719", + "noTxs": 4, + "txDetails": [ + { + "hex": "0200000001cd227a67d359ad8aaf99d9a56fdb0604a18804d40e046d21607f95a0c263e6d1020000006a473044022027687d38378d1e6c991f68815217e309f1e290a8c706159455a680457ec1545002202dd0d9fc7251a5a4f7d4b76d824981b97a4c5121ec46fee4786a283debde544501210223a0cd87e2f1958998684f6c75771a95727d310cc4d30ed34ca427affe89d4c2fdffffff038876020000000000160014f6a58ba8a373263dddcb82bd6202a1157270cb4de8b00400000000001600144237fc8335d817b911332fc9df26744215266b1794d204000000000017a914e5bd951e8d6b10fab8cea5b103c71ae3a37b95bf871ba20000", + "txid": "8b77d1e7b5d7c528a59917c13f42787fa1988db744c1e9bc58f024f15fbb2ebb", + "time": 1724848265, + "blocktime": 1724848265, + "version": 2, + "vin": [ + { + "txid": "d1e663c2a0957f60216d040ed40488a10406db6fa5d999af8aad59d3677a22cd", + "vout": 2, + "scriptSig": { + "hex": "473044022027687d38378d1e6c991f68815217e309f1e290a8c706159455a680457ec1545002202dd0d9fc7251a5a4f7d4b76d824981b97a4c5121ec46fee4786a283debde544501210223a0cd87e2f1958998684f6c75771a95727d310cc4d30ed34ca427affe89d4c2" + }, + "sequence": 4294967293 + } + ], + "vout": [ + { + "value": 0.00161416, + "n": 0, + "scriptPubKey": { + "hex": "0014f6a58ba8a373263dddcb82bd6202a1157270cb4d" + } + }, + { + "value": 0.00307432, + "n": 1, + "scriptPubKey": { + "hex": "00144237fc8335d817b911332fc9df26744215266b17" + } + } + ] + }, + { + "hex": "02000000030a33417aa2c909c65225b024e4988b46810202a7a57da1505a4ac79405ac4da4020000006a47304402204da60448cf946bc3ac839df244eef7eb5b04f6707be70382647c1fe4443936e102201fa6b33200b4835c6b67f2c31e63a76d2a6b962cc576f1b1b5cf09b4ba8f452c0121030a15ad4bbb816e75e733c12666af2a04bb55b7108f9c075e12104ac2a82fa326fdffffffcd227a67d359ad8aaf99d9a56fdb0604a18804d40e046d21607f95a0c263e6d1010000006a47304402207875d1ec865e2fdff50e6923b97a19f86597077685cc6d9c3b6af255dbd5e8bc022026177e9010f43b62bf1aab96b7a02ea639ad63b3cb2231603d9b0573d6a0049d012102373d8f65f846d07e07f74057b77bd81b4531cf95fc45040802a4f160271b47ddfdffffff7e848dbf9c2911fb316c47d5da66009836cd21a7d282dc3d9f2f993bec88c5d7000000006a47304402202a5dbdef43698a1027514585e1198e5d6ffcfbc60792ee48d979bfb40cfe6840022004d5819608fda4d16c5920f7f7ed5b4eb6eb90aa1fb3f21153055b83e89dd57d012102d6dd02728abb6829736d1cb14758361a15fd848db4283df310dc2084151c3908fdffffff039f770e00000000001600146a18cc237247b14c7b8bcb23c504a60b6c073bdf9db90d0000000000160014dda8363d492ccc33ef8c2ad02de0632bde0111aadd9202000000000017a914fa793409354d909ceaf168b7b7f91a92e0b4ba85871ba20000", + "txid": "06a9373ca11293ec51d15c5c142118fd46ceec33c0a46a865448f9916337b2ef", + "time": 1724848265, + "blocktime": 1724848265, + "version": 2, + "vin": [ + { + "txid": "a44dac0594c74a5a50a17da5a7020281468b98e424b02552c609c9a27a41330a", + "vout": 2, + "scriptSig": { + "hex": "47304402204da60448cf946bc3ac839df244eef7eb5b04f6707be70382647c1fe4443936e102201fa6b33200b4835c6b67f2c31e63a76d2a6b962cc576f1b1b5cf09b4ba8f452c0121030a15ad4bbb816e75e733c12666af2a04bb55b7108f9c075e12104ac2a82fa326" + }, + "sequence": 4294967293 + }, + { + "txid": "d1e663c2a0957f60216d040ed40488a10406db6fa5d999af8aad59d3677a22cd", + "vout": 1, + "scriptSig": { + "hex": "47304402207875d1ec865e2fdff50e6923b97a19f86597077685cc6d9c3b6af255dbd5e8bc022026177e9010f43b62bf1aab96b7a02ea639ad63b3cb2231603d9b0573d6a0049d012102373d8f65f846d07e07f74057b77bd81b4531cf95fc45040802a4f160271b47dd" + }, + "sequence": 4294967293 + }, + { + "txid": "d7c588ec3b992f9f3ddc82d2a721cd36980066dad5476c31fb11299cbf8d847e", + "vout": 0, + "scriptSig": { + "hex": "47304402202a5dbdef43698a1027514585e1198e5d6ffcfbc60792ee48d979bfb40cfe6840022004d5819608fda4d16c5920f7f7ed5b4eb6eb90aa1fb3f21153055b83e89dd57d012102d6dd02728abb6829736d1cb14758361a15fd848db4283df310dc2084151c3908" + }, + "sequence": 4294967293 + } + ], + "vout": [ + { + "value": 0.00948127, + "n": 0, + "scriptPubKey": { + "hex": "00146a18cc237247b14c7b8bcb23c504a60b6c073bdf" + } + }, + { + "value": 0.00899485, + "n": 1, + "scriptPubKey": { + "hex": "0014dda8363d492ccc33ef8c2ad02de0632bde0111aa" + } + }, + { + "value": 0.00168669, + "n": 1, + "scriptPubKey": { + "hex": "a914fa793409354d909ceaf168b7b7f91a92e0b4ba8587" + } + } + ] + } + ] + }, + "41514": { + "height": 41514, + "hash": "0000000000000002b7bdc99aec6aa3637ed2bfda355a1124b55c6e73362d20e3", + "noTxs": 4, + "txDetails": [ + { + "txid": "dc733fabf5035aaae5e006ed18007a0017945800a934df4ec3ce39a91575b8e8", + "version": 2, + "vin": [ + { + "txid": "989a37280f12b604db89ada924157118988e786bd962e57b77c08382da404cb8", + "vout": 1, + "scriptSig": { + "hex": "473044022061df7eaac833f84457a3636f017c25a3718570071fad06488a1f2558f270e1d3022028cf6a7964d91b16af7a5b3d45d334865857b3ffeb963b03aec57c1605f9e88201210347db551a1dddc6b9e33514b617e5f0d1a877d289438a3c2b660eade0b2167bb7" + }, + "sequence": 4294967293 + }, + { + "txid": "87311755ace5410b892a84319a721058a004a160484c672d74efe49b84fba877", + "vout": 2, + "scriptSig": { + "hex": "473044022061e33861ff14d7578b8bf5e0acbe411c23c245cb66867fec4a00d4da1d79886b02205363bca58a7419b63afcb5242e129ca049b39260706bcdc5d812217bb8549734012102fb95500bc0cfc2989caf311093d81bf4fbeac8fd6d7595e634a665062da27ece" + }, + "sequence": 4294967293 + }, + { + "txid": "841b8c2713db90d8b6f299c5f5ace825f7a2a1b85314c3c556b6a60888257e84", + "vout": 0, + "scriptSig": { + "hex": "47304402202a975b7766809be1cb6b3639a7ae19939c7ca65d9e52fef9c0fac974c50ab6c402204e3bd3df8e229a76a4e18ddb5bbcc57f3edb17e275e5a720eff87264fca6e6540121039d7a392480bcddc3b5ae486e8f42928aea3db0b29960a6eba2a74535d3666e5f" + }, + "sequence": 4294967293 + } + ], + "vout": [ + { + "value": 0.00590901, + "n": 0, + "scriptPubKey": { + "hex": "76a914a385f9839ca1052e69add674e34a86b5e2fee49488ac" + } + }, + { + "value": 0.00169446, + "n": 1, + "scriptPubKey": { + "hex": "0014064c311089eee424ba61ad731dd2b2a24b634920" + } + }, + { + "value": 0.00955888, + "n": 2, + "scriptPubKey": { + "hex": "0014b0bc24934c98b2eb46dcf3dea49adb6d689bf640" + } + } + ], + "hex": "0200000003b84c40da8283c0777be562d96b788e9818711524a9ad89db04b6120f28379a98010000006a473044022061df7eaac833f84457a3636f017c25a3718570071fad06488a1f2558f270e1d3022028cf6a7964d91b16af7a5b3d45d334865857b3ffeb963b03aec57c1605f9e88201210347db551a1dddc6b9e33514b617e5f0d1a877d289438a3c2b660eade0b2167bb7fdffffff77a8fb849be4ef742d674c4860a104a05810729a31842a890b41e5ac55173187020000006a473044022061e33861ff14d7578b8bf5e0acbe411c23c245cb66867fec4a00d4da1d79886b02205363bca58a7419b63afcb5242e129ca049b39260706bcdc5d812217bb8549734012102fb95500bc0cfc2989caf311093d81bf4fbeac8fd6d7595e634a665062da27ecefdffffff847e258808a6b656c5c31453b8a1a2f725e8acf5c599f2b6d890db13278c1b84000000006a47304402202a975b7766809be1cb6b3639a7ae19939c7ca65d9e52fef9c0fac974c50ab6c402204e3bd3df8e229a76a4e18ddb5bbcc57f3edb17e275e5a720eff87264fca6e6540121039d7a392480bcddc3b5ae486e8f42928aea3db0b29960a6eba2a74535d3666e5ffdffffff0335040900000000001976a914a385f9839ca1052e69add674e34a86b5e2fee49488ace695020000000000160014064c311089eee424ba61ad731dd2b2a24b634920f0950e0000000000160014b0bc24934c98b2eb46dcf3dea49adb6d689bf64029a20000", + "time": 1724854426, + "blocktime": 1724854426 + }, + { + "txid": "83e4e72359aad484639376259de9ea0dab88aa7b9b2d0a8ab654fe151cb10cbb", + "version": 2, + "vin": [ + { + "txid": "a6384c1718c87b699b11e0aa7e7ff5806c6053146f530de59989695b4a770957", + "vout": 1, + "scriptSig": { + "hex": "" + }, + "sequence": 4294967293 + }, + { + "txid": "64d1c85d3a0f4dc94d280a63d08ff4cae640f504b7e65d4d07afd8aa6e56127f", + "vout": 1, + "scriptSig": { + "hex": "" + }, + "sequence": 4294967293 + }, + { + "txid": "9ad596bbe3bff49476127cdada75ba54e269cabb8fa8bf83c4ea78037998ba32", + "vout": 2, + "scriptSig": { + "hex": "" + }, + "sequence": 4294967293 + }, + { + "txid": "6cbe7386a8085f440a25c8b5eafaf251e29b5d9894d0b78f1a058155e3cbb64a", + "vout": 1, + "scriptSig": { + "hex": "" + }, + "sequence": 4294967293 + }, + { + "txid": "44a3af6673cfc9bd746ba5f8183b5ffb48259cf2473fd300daf803125ba19576", + "vout": 0, + "scriptSig": { + "hex": "" + }, + "sequence": 4294967293 + } + ], + "vout": [ + { + "value": 0.00590901, + "n": 0, + "scriptPubKey": { + "hex": "a914a42e6b2b8198b25bdeb2bb45677ab2180d4847ae87" + } + }, + { + "value": 0.00774515, + "n": 1, + "scriptPubKey": { + "hex": "0014601770808f0168c4dc0d927759407047f079a0f9" + } + } + ], + "hex": "020000000001055709774a5b698999e50d536f1453606c80f57f7eaae0119b697bc818174c38a60100000000fdffffff7f12566eaad8af074d5de6b704f540e6caf48fd0630a284dc94d0f3a5dc8d1640100000000fdffffff32ba98790378eac483bfa88fbbca69e254ba75dada7c127694f4bfe3bb96d59a0200000000fdffffff4ab6cbe35581051a8fb7d094985d9be251f2faeab5c8250a445f08a88673be6c0100000000fdffffff7695a15b1203f8da00d33f47f29c2548fb5f3b18f8a56b74bdc9cf7366afa3440000000000fdffffff02350409000000000017a914a42e6b2b8198b25bdeb2bb45677ab2180d4847ae8773d10b0000000000160014601770808f0168c4dc0d927759407047f079a0f9024730440220703d8e59902e1f2e06b343588d88e84433cea072b5004c5c4dff0dd9787b3d2f022070924c133eba86760eebc91e09dad2d0db08f684b1976ca1b4d1f3421f2c084d012103f4bf0506968dd6eb701d0e40ab6ea02d5179a6550a761801684bd4384c0e79eb02473044022057bf3d62109758c6bc278ab54c15d43c95aa9c0f11548e76a5e1ca8ae103508002201d9f503b33d930d128fe102f5b1622dc15c32ef00268e58980e2b61ce77c33200121024f8884e9ebe6bf9c6492a662bf4bb3d30a55072cee98c82b8a17a22111ef4cf602473044022072788e6901a2d27b2db22ebef67aec7704aacbe003d96f0b8bf118c6ae5c0040022029dacac606daa4017e6e8e78efb139de5fb846599b67d501ef5851c302dee3fc012102718eb94089203414331e1291f30ebc139b087fde31dde1cfad7db22327bc69f40247304402202c927e0ccb0ec9cb8ad76206ad5ed95572df8c600bb1eb03de0f101d287cb121022050ddb0e7768dfe16788f1a1b835a8ad3b5be6fef0a2093781977aebf6e5d8a9f0121027e18fe1411ba7a2296c47ff8397e92986ce0836897bb42270b6dd86b2814ea1302473044022028d03205ca7736a78feb0c0b507df77952dd3c2a6947cdd9f9be58ef9094f9a20220768e22de86fc6683cec1c12d72f8ea5d6d0583ba171a69e1791bb46b399eff22012102d24813d067d189c0d15bfe62a24ef4295100cd0f80b0286de1dfae66540dfc4b29a20000", + "time": 1724854426, + "blocktime": 1724854426 + } + ] + } + } + }, + "handleFork": { + "syncRanges": [ + {"lower": 41480, "upper": 41499} + ], + "fakeBlocks": { + "41497": { + "height": 41497, + "hash": "0000000000000016204d49115b14be42a5022d0b4fd3e955ebd93e0933e6c6a1" + }, + "41498": { + "height": 41498, + "hash": "00000000000000064cebdc2a2fdcc74810325b4de8b4297e6cdd4fbdda221192" + }, + "41499": { + "height": 41499, + "hash": "00000000a4da915dca73162b98b671dd60b5a52208abf159f2ea7b11f08b1989" + } + }, + "realBlocks": { + "41497": { + "height": 41497, + "hash": "00000000000000098b5976b60433bbbf44b73681282e2bf7ee6186e9767c2ced" + }, + "41498": { + "height": 41498, + "hash": "000000000af275137c4183636a8c3fbe1ed9f8b30345daa89dc09be08822efd6" + }, + "41499": { + "height": 41499, + "hash": "00000000da2db0a996113cf34bdaacb9ce31ebc6a172f640601d3aec6936f8b5" + } + } + } +} diff --git a/tests/tests.json b/tests/tests.json new file mode 100644 index 00000000..f99a222d --- /dev/null +++ b/tests/tests.json @@ -0,0 +1,253 @@ +{ + "avalanche": { + "rpc": ["GetBlock", "GetBlockHash", "GetTransaction", "EstimateFee", "GetBlockHeader"] + }, + "bcash": { + "rpc": ["GetBlock", "GetBlockHash", "GetTransaction", "GetTransactionForMempool", "MempoolSync", + "EstimateFee", "GetBestBlockHash", "GetBestBlockHeight", "GetBlockHeader"], + "sync": ["ConnectBlocksParallel", "ConnectBlocks", "HandleFork"] + }, + "bcash_testnet": { + "rpc": ["GetBlock", "GetBlockHash", "GetTransaction", "GetTransactionForMempool", "MempoolSync", + "EstimateFee", "GetBestBlockHash", "GetBestBlockHeight", "GetBlockHeader"], + "sync": ["ConnectBlocksParallel", "ConnectBlocks", "HandleFork"] + }, + "bellcoin": { + "rpc": ["GetBlock", "GetBlockHash", "GetTransaction", "GetTransactionForMempool", "MempoolSync", + "EstimateSmartFee", "EstimateFee"], + "sync": ["ConnectBlocksParallel", "ConnectBlocks", "HandleFork"] + }, + "bgold": { + "sync": ["ConnectBlocksParallel", "ConnectBlocks", "HandleFork"] + }, + "bitcoin": { + "rpc": ["GetBlock", "GetBlockHash", "GetTransaction", "GetTransactionForMempool", "MempoolSync", + "EstimateSmartFee", "EstimateFee", "GetBestBlockHash", "GetBestBlockHeight", "GetBlockHeader"], + "sync": ["ConnectBlocksParallel", "ConnectBlocks", "HandleFork"] + }, + "bitcoin_testnet": { + "rpc": ["GetBlock", "GetBlockHash", "GetTransaction", "GetTransactionForMempool", "MempoolSync", + "EstimateSmartFee", "EstimateFee", "GetBestBlockHash", "GetBestBlockHeight", "GetBlockHeader"], + "sync": ["ConnectBlocksParallel", "ConnectBlocks", "HandleFork"] + }, + "bitcoin_testnet4": { + "rpc": ["GetBlock", "GetBlockHash", "GetTransaction", "GetTransactionForMempool", "MempoolSync", + "EstimateSmartFee", "EstimateFee", "GetBestBlockHash", "GetBestBlockHeight", "GetBlockHeader"], + "sync": ["ConnectBlocksParallel", "ConnectBlocks", "HandleFork"] + }, + "bitcoin_signet": { + "rpc": ["GetBlock", "GetBlockHash", "GetTransaction", "GetTransactionForMempool", "MempoolSync", + "EstimateSmartFee", "EstimateFee", "GetBestBlockHash", "GetBestBlockHeight", "GetBlockHeader"], + "sync": ["ConnectBlocksParallel", "ConnectBlocks", "HandleFork"] + }, + "bitcore": { + "rpc": ["GetBlock", "GetBlockHash", "GetTransaction", "GetTransactionForMempool", "MempoolSync", + "EstimateSmartFee", "EstimateFee", "GetBestBlockHash", "GetBestBlockHeight", "GetBlockHeader"], + "sync": ["ConnectBlocksParallel", "ConnectBlocks", "HandleFork"] + }, + "bitzeny": { + "rpc": ["GetBlock", "GetBlockHash", "GetTransaction", "GetTransactionForMempool", "MempoolSync", + "EstimateSmartFee", "EstimateFee", "GetBestBlockHash", "GetBestBlockHeight", "GetBlockHeader"], + "sync": ["ConnectBlocksParallel", "ConnectBlocks", "HandleFork"] + }, + "bsc": { + "rpc": ["GetBlock", "GetBlockHash", "GetTransaction", "EstimateFee", "GetBlockHeader"] + }, + "bsc_archive": { + "rpc": ["GetBlock", "GetBlockHash", "GetTransaction", "EstimateFee", "GetBlockHeader"] + }, + "cpuchain": { + "rpc": ["GetBlock", "GetBlockHash", "GetTransaction", "GetTransactionForMempool", "MempoolSync", + "EstimateSmartFee", "EstimateFee"], + "sync": ["ConnectBlocksParallel", "ConnectBlocks"] + }, + "dash": { + "rpc": ["GetBlock", "GetBlockHash", "GetTransaction", "GetTransactionForMempool", "MempoolSync", + "EstimateSmartFee", "GetBestBlockHash", "GetBestBlockHeight", "GetBlockHeader"], + "sync": ["ConnectBlocksParallel", "ConnectBlocks", "HandleFork"] + }, + "dash_testnet": { + "rpc": ["GetBlock", "GetBlockHash", "GetTransaction", "GetTransactionForMempool", "MempoolSync", + "EstimateSmartFee", "GetBestBlockHash", "GetBestBlockHeight", "GetBlockHeader"], + "sync": ["ConnectBlocksParallel", "ConnectBlocks", "HandleFork"] + }, + "decred": { + "rpc": ["GetBlock", "GetBlockHash", "GetTransaction", "MempoolSync", + "EstimateFee", "GetBestBlockHash", "GetBestBlockHeight", "GetBlockHeader"], + "sync": ["ConnectBlocksParallel", "ConnectBlocks"] + }, + "decred_testnet": { + "rpc": ["GetBlock", "GetBlockHash", "GetTransaction", "MempoolSync", + "EstimateFee", "GetBestBlockHash", "GetBestBlockHeight", "GetBlockHeader"], + "sync": ["ConnectBlocksParallel", "ConnectBlocks"] + }, + "deeponion": { + "rpc": ["GetBlock", "GetBlockHash", "GetTransaction", "GetTransactionForMempool", "MempoolSync", + "EstimateSmartFee", "EstimateFee"], + "sync": ["ConnectBlocksParallel", "ConnectBlocks"] + }, + "digibyte": { + "rpc": ["GetBlock", "GetBlockHash", "GetTransaction", "GetTransactionForMempool", "MempoolSync", + "EstimateSmartFee", "EstimateFee", "GetBestBlockHash", "GetBestBlockHeight", "GetBlockHeader"] + }, + "divi": { + "rpc": ["GetBlock", "GetBlockHash", "GetTransaction", "GetTransactionForMempool", "MempoolSync", + "EstimateSmartFee", "EstimateFee", "GetBestBlockHash", "GetBestBlockHeight"], + "sync": ["ConnectBlocksParallel", "ConnectBlocks"] + }, + "dogecoin": { + "rpc": ["GetBlock", "GetBlockHash", "GetTransaction", "MempoolSync"], + "sync": ["ConnectBlocksParallel", "ConnectBlocks"] + }, + "dogecoin_testnet": { + "rpc": ["GetBlock", "GetBlockHash", "GetTransaction", "GetTransactionForMempool", "MempoolSync"], + "sync": ["ConnectBlocksParallel", "ConnectBlocks"] + }, + "ecash": { + "rpc": ["GetBlock", "GetBlockHash", "GetTransaction", "GetTransactionForMempool", "MempoolSync", + "GetBestBlockHash", "GetBestBlockHeight", "GetBlockHeader"], + "sync": ["ConnectBlocksParallel", "ConnectBlocks", "HandleFork"] + }, + "flo": { + "rpc": ["GetBlock", "GetBlockHash", "GetTransaction", "GetTransactionForMempool", "MempoolSync", + "EstimateSmartFee", "EstimateFee", "GetBestBlockHash", "GetBestBlockHeight", "GetBlockHeader"], + "sync": ["ConnectBlocksParallel", "ConnectBlocks", "HandleFork"] + }, + "fujicoin": { + "rpc": ["GetBlock", "GetBlockHash", "GetTransaction", "GetTransactionForMempool", "MempoolSync", + "EstimateSmartFee", "EstimateFee", "GetBestBlockHash", "GetBestBlockHeight", "GetBlockHeader"], + "sync": ["ConnectBlocksParallel", "ConnectBlocks", "HandleFork"] + }, + "gamecredits": { + "rpc": ["GetBlock", "GetBlockHash", "GetTransaction", "GetTransactionForMempool", "MempoolSync", + "EstimateSmartFee", "EstimateFee"], + "sync": ["ConnectBlocksParallel", "ConnectBlocks", "HandleFork"] + }, + "groestlcoin": { + "rpc": ["GetBlock", "GetBlockHash", "GetTransaction", "GetTransactionForMempool", "MempoolSync", + "EstimateSmartFee", "EstimateFee", "GetBestBlockHash", "GetBestBlockHeight", "GetBlockHeader"], + "sync": ["ConnectBlocksParallel", "ConnectBlocks", "HandleFork"] + }, + "koto": { + "rpc": ["GetBlock", "GetBlockHash", "GetTransaction", "GetTransactionForMempool", "MempoolSync", + "EstimateSmartFee", "EstimateFee", "GetBestBlockHash", "GetBestBlockHeight", "GetBlockHeader"], + "sync": ["ConnectBlocksParallel", "ConnectBlocks", "HandleFork"] + }, + "koto_testnet": { + "rpc": ["GetBlock", "GetBlockHash", "GetTransaction", "GetTransactionForMempool", "MempoolSync", + "EstimateSmartFee", "EstimateFee", "GetBestBlockHash", "GetBestBlockHeight", "GetBlockHeader"], + "sync": ["ConnectBlocksParallel", "ConnectBlocks", "HandleFork"] + }, + "litecoin": { + "rpc": ["GetBlock", "GetBlockHash", "GetTransaction", "GetTransactionForMempool", "MempoolSync", + "EstimateSmartFee", "EstimateFee"], + "sync": ["ConnectBlocksParallel", "ConnectBlocks", "HandleFork"] + }, + "monacoin": { + "rpc": ["GetBlock", "GetBlockHash", "GetTransaction", "GetTransactionForMempool", "MempoolSync", + "EstimateSmartFee", "EstimateFee", "GetBestBlockHash", "GetBestBlockHeight", "GetBlockHeader"], + "sync": ["ConnectBlocksParallel", "ConnectBlocks", "HandleFork"] + }, + "myriad": { + "rpc": ["GetBlock", "GetBlockHash", "GetTransaction", "GetTransactionForMempool", "MempoolSync", + "EstimateSmartFee", "EstimateFee", "GetBestBlockHash", "GetBestBlockHeight", "GetBlockHeader"] + }, + "namecoin": { + "rpc": ["GetBlock", "GetBlockHash", "GetTransaction", "MempoolSync", "EstimateSmartFee", + "EstimateFee", "GetBestBlockHash", "GetBestBlockHeight", "GetBlockHeader"] + }, + "vertcoin": { + "rpc": ["GetBlock", "GetBlockHash", "GetTransaction", "GetTransactionForMempool", "MempoolSync", + "EstimateSmartFee", "EstimateFee", "GetBestBlockHash", "GetBestBlockHeight", "GetBlockHeader"], + "sync": ["ConnectBlocksParallel", "ConnectBlocks", "HandleFork"] + }, + "zcash": { + "rpc": ["GetBlock", "GetBlockHash", "GetTransaction", "GetTransactionForMempool", "MempoolSync", + "GetBestBlockHash", "GetBestBlockHeight", "GetBlockHeader"], + "sync": ["ConnectBlocksParallel", "ConnectBlocks", "HandleFork"] + }, + "zcash_testnet": { + "rpc": ["GetBlock", "GetBlockHash", "GetTransaction", "GetTransactionForMempool", "MempoolSync", + "GetBestBlockHash", "GetBestBlockHeight", "GetBlockHeader"], + "sync": ["ConnectBlocksParallel", "ConnectBlocks", "HandleFork"] + }, + "pivx": { + "rpc": ["GetBlock", "GetBlockHash", "GetTransaction", "GetTransactionForMempool", "MempoolSync", + "EstimateSmartFee", "EstimateFee", "GetBestBlockHash", "GetBestBlockHeight", "GetBlockHeader"], + "sync": ["ConnectBlocksParallel", "ConnectBlocks", "HandleFork"] + }, + "polis": { + "rpc": ["GetBlock", "GetBlockHash", "GetTransaction", "GetTransactionForMempool", "MempoolSync", + "EstimateSmartFee", "EstimateFee", "GetBestBlockHash", "GetBestBlockHeight", "GetBlockHeader"], + "sync": ["ConnectBlocksParallel", "ConnectBlocks"] + }, + "firo": { + "rpc": ["GetBlock", "GetBlockHash", "GetTransaction", "GetTransactionForMempool", "MempoolSync", + "EstimateFee", "GetBestBlockHash", "GetBestBlockHeight", "GetBlockHeader"], + "sync": ["ConnectBlocksParallel", "ConnectBlocks", "HandleFork"] + }, + "qtum": { + "rpc": ["GetBlock", "GetBlockHash", "GetTransaction", "GetTransactionForMempool", "MempoolSync", + "EstimateSmartFee", "GetBestBlockHash", "GetBestBlockHeight", "GetBlockHeader"], + "sync": ["ConnectBlocksParallel", "ConnectBlocks", "HandleFork"] + }, + "viacoin": { + "rpc": ["GetBlock", "GetBlockHash", "GetTransaction", "GetTransactionForMempool", "MempoolSync", + "EstimateSmartFee", "GetBestBlockHash", "GetBestBlockHeight", "GetBlockHeader"], + "sync": ["ConnectBlocksParallel", "ConnectBlocks", "HandleFork"] + }, + "nuls": { + "rpc": ["GetBlock", "GetBlockHash", "GetTransaction", "GetBestBlockHash", "GetBestBlockHeight", "GetBlockHeader"], + "sync": ["ConnectBlocksParallel", "ConnectBlocks", "HandleFork"] + }, + "vipstarcoin": { + "rpc": ["GetBlock", "GetBlockHash", "GetTransaction", "GetTransactionForMempool", "MempoolSync", + "EstimateFee", "GetBestBlockHash", "GetBestBlockHeight", "GetBlockHeader"], + "sync": ["ConnectBlocksParallel", "ConnectBlocks", "HandleFork"] + }, + "monetaryunit": { + "rpc": ["GetBlock", "GetBlockHash", "GetTransaction", "GetTransactionForMempool", "MempoolSync", + "EstimateSmartFee", "EstimateFee", "GetBestBlockHash", "GetBestBlockHeight", "GetBlockHeader"], + "sync": ["ConnectBlocksParallel", "ConnectBlocks", "HandleFork"] + }, + "zelcash": { + "rpc": ["GetBlock", "GetBlockHash", "GetTransaction", "GetTransactionForMempool", "MempoolSync", + "EstimateSmartFee", "EstimateFee", "GetBestBlockHash", "GetBestBlockHeight", "GetBlockHeader"], + "sync": ["ConnectBlocksParallel", "ConnectBlocks", "HandleFork"] + }, + "ravencoin": { + "rpc": ["GetBlock", "GetBlockHash", "GetTransaction", "GetTransactionForMempool", "MempoolSync", + "EstimateSmartFee", "GetBestBlockHash", "GetBestBlockHeight", "GetBlockHeader"], + "sync": ["ConnectBlocksParallel", "ConnectBlocks", "HandleFork"] + }, + "ritocoin": { + "rpc": ["GetBlock", "GetBlockHash", "GetTransaction", "GetTransactionForMempool", "MempoolSync", + "EstimateSmartFee", "GetBestBlockHash", "GetBestBlockHeight", "GetBlockHeader"], + "sync": ["ConnectBlocksParallel", "ConnectBlocks", "HandleFork"] + }, + "unobtanium": { + "rpc": ["GetBlock", "GetBlockHash", "GetTransaction", "GetTransactionForMempool", "MempoolSync", + "GetBestBlockHash", "GetBestBlockHeight"], + "sync": ["ConnectBlocksParallel", "ConnectBlocks"] + }, + "snowgem": { + "rpc": ["GetBlock", "GetBlockHash", "GetTransaction", "GetTransactionForMempool", "MempoolSync", + "EstimateSmartFee", "EstimateFee", "GetBestBlockHash", "GetBestBlockHeight", "GetBlockHeader"], + "sync": ["ConnectBlocksParallel", "ConnectBlocks", "HandleFork"] + }, + "omotenashicoin": { + "rpc": ["GetBlock", "GetBlockHash", "GetTransaction", "GetTransactionForMempool", "MempoolSync", + "EstimateSmartFee", "EstimateFee", "GetBestBlockHash", "GetBestBlockHeight"], + "sync": ["ConnectBlocksParallel", "ConnectBlocks"] + }, + "omotenashicoin_testnet": { + "rpc": ["GetBlock", "GetBlockHash", "GetTransaction", "GetTransactionForMempool", "MempoolSync", + "EstimateSmartFee", "EstimateFee", "GetBestBlockHash", "GetBestBlockHeight"], + "sync": ["ConnectBlocksParallel", "ConnectBlocks"] + }, + "trezarcoin": { + "rpc": ["GetBlock", "GetBlockHash", "GetTransaction", "GetTransactionForMempool", "MempoolSync", + "EstimateFee", "GetBestBlockHash", "GetBestBlockHeight", "GetBlockHeader"], + "sync": ["ConnectBlocksParallel", "ConnectBlocks", "HandleFork"] + } +}