Compare commits

..

15 Commits

Author SHA1 Message Date
Martin Boehm b6e3f26eb2 Insert utxos in fixUtxo in the growing order 2020-02-23 00:24:05 +01:00
Martin Boehm 72e48ce658 Automatically check for UTXO inconsitencies 2020-02-16 23:07:50 +01:00
Martin Boehm 9cfe1f3d25 Fix order of utxos 2020-02-14 16:54:51 +01:00
Martin Boehm 839f67f6eb Fix incorrect order of utxos 2020-02-14 16:33:36 +01:00
Martin Boehm 267c2b22c1 Check the order of utxos 2020-02-14 10:04:12 +01:00
Martin Boehm 5a801ed038 Insert utxos in the right order in disconnect block 2020-02-09 11:46:13 +01:00
Martin Boehm 3c90059994 Alter disconnect block procedure to avoid possible utxo db inconsistency 2020-01-31 09:29:54 +01:00
Martin Boehm b4d0e2e819 Alter logging of a possible db inconsitency in addresses column 2020-01-29 23:54:20 +01:00
Martin Boehm a5a5edef9d Optimize and sort correctly fixed utxos 2020-01-29 20:46:58 +01:00
Martin Boehm 923234e97d Improve storing/loading of block info to db 2020-01-29 20:45:22 +01:00
Vladyslav Burzakovskyy 466d89a670 balanceHistory: remove empty currencies from the list, fix typo 2020-01-28 21:04:19 +01:00
Martin Boehm 358858b418 Fix errors in utxo db 2020-01-27 14:33:58 +01:00
Martin Boehm f903a1d6f9 Handle possible address descriptor mismatch in db column addresses 2020-01-27 14:33:13 +01:00
Martin Boehm 7df8f05b31 Check for error in utxo DB 2020-01-26 20:12:12 +01:00
Martin Boehm af1d3fceaa Add load address by serialized address descriptor 2020-01-25 22:17:17 +01:00
273 changed files with 3648 additions and 7892 deletions

1
.gitignore vendored
View File

@ -8,7 +8,6 @@ debug*
docker/blockbook
build/pkg-defs
build/blockbook
build/blockchaincfg.json
build/ldb
build/sst_dump
build/*.deb

View File

@ -3,8 +3,8 @@
Blockbook is back-end service for Trezor wallet. Although it is open source, the design and development of the core packages
is done by Trezor developers in order to keep Blockbook compatible with Trezor.
Bug fixes and support for new coins are welcome. **Please take note that non-fixing pull requests that change base
packages or another coin code will not be accepted.** If you have a need to change some of the existing code, please file
Bug fixes and support for new coins are welcome. Please take note that non-fixing pull requests that change base
packages or another coin code will not be accepted. If you have a need to change some of the existing code, please file
an issue and discuss your request with Blockbook maintainers.
## Development environment

298
Gopkg.lock generated 100644
View File

@ -0,0 +1,298 @@
# This file is autogenerated, do not edit; changes may be undone by the next 'dep ensure'.
[[projects]]
branch = "master"
name = "github.com/Groestlcoin/go-groestl-hash"
packages = ["groestl","hash"]
revision = "790653ac190c4029ee200e82a8f21b5d1afaf7d6"
[[projects]]
digest = "1:8b13694e3e7b33c6f389f367b6a001a1184b051e34880fdd9e58a2207d9f6573"
name = "github.com/allegro/bigcache"
packages = [
".",
"queue",
]
pruneopts = ""
revision = "69ea0af04088faa57adb9ac683934277141e92a5"
version = "v2.0.0"
[[projects]]
branch = "master"
digest = "1:10f6df61e4d3de150f3c11c3c6791c5702382c7f4aa983bcab9f49a73fea44a3"
name = "github.com/aristanetworks/goarista"
packages = ["monotime"]
pruneopts = ""
revision = "8e7d5b18fe7ad671e07097d5445dbc70422663b2"
[[projects]]
branch = "master"
name = "github.com/agl/ed25519"
packages = [".","edwards25519"]
revision = "5312a61534124124185d41f09206b9fef1d88403"
[[projects]]
branch = "master"
name = "github.com/beorn7/perks"
packages = ["quantile"]
revision = "3a771d992973f24aa725d07868b467d1ddfceafb"
[[projects]]
branch = "master"
name = "github.com/bsm/go-vlq"
packages = ["."]
revision = "ec6e8d4f5f4ec0f6e808ffc7f4dcc7516d4d7d49"
[[projects]]
branch = "master"
name = "github.com/martinboehm/btcd"
packages = ["blockchain","btcec","chaincfg","chaincfg/chainhash","database","txscript","wire"]
revision = "8e7c0427fee5d4778c5d4eb987150369e3ca1d0e"
[[projects]]
branch = "master"
name = "github.com/btcsuite/btclog"
packages = ["."]
revision = "84c8d2346e9fc8c7b947e243b9c24e6df9fd206a"
[[projects]]
branch = "master"
name = "github.com/dchest/blake256"
packages = ["."]
revision = "dee3fe6eb0e98dc774a94fc231f85baf7c29d360"
[[projects]]
name = "github.com/deckarep/golang-set"
packages = ["."]
revision = "1d4478f51bed434f1dadf96dcd9b43aabac66795"
version = "v1.7"
[[projects]]
branch = "master"
name = "github.com/decred/base58"
packages = ["."]
revision = "dbeddd8aab76c31eb2ea98351a63fa2c6bf46888"
[[projects]]
name = "github.com/decred/dcrd"
packages = ["chaincfg","chaincfg/chainec","chaincfg/chainhash","dcrec","dcrec/edwards","dcrec/secp256k1","dcrec/secp256k1/schnorr","dcrjson","dcrutil","txscript","wire"]
revision = "e3e8c47c68b010dbddeb783ebad32a3a4993dd71"
version = "v1.4.0"
[[projects]]
name = "github.com/decred/slog"
packages = ["."]
revision = "fbd821ef791ba2b8ae945f5d44f4e49396d230c5"
version = "v1.0.0"
[[projects]]
name = "github.com/ethereum/go-ethereum"
packages = [".","common","common/hexutil","common/math","core/types","crypto","crypto/secp256k1","crypto/sha3","ethclient","ethdb","log","metrics","p2p/netutil","params","rlp","rpc","trie"]
revision = "24d727b6d6e2c0cde222fa12155c4a6db5caaf2e"
version = "v1.8.20"
[[projects]]
name = "github.com/go-stack/stack"
packages = ["."]
revision = "259ab82a6cad3992b4e21ff5cac294ccb06474bc"
version = "v1.7.0"
[[projects]]
name = "github.com/gobuffalo/packr"
packages = ["."]
revision = "5a2cbb54c4e7d482e3f518c56f1f86f133d5204f"
version = "v1.13.7"
[[projects]]
name = "github.com/gogo/protobuf"
packages = ["proto"]
revision = "1adfc126b41513cc696b209667c8656ea7aac67c"
version = "v1.0.0"
[[projects]]
branch = "master"
name = "github.com/golang/glog"
packages = ["."]
revision = "23def4e6c14b4da8ac2ed8007337bc5eb5007998"
[[projects]]
name = "github.com/golang/protobuf"
packages = ["proto"]
revision = "925541529c1fa6821df4e44ce2723319eb2be768"
version = "v1.0.0"
[[projects]]
branch = "master"
name = "github.com/golang/snappy"
packages = ["."]
revision = "553a641470496b2327abcac10b36396bd98e45c9"
[[projects]]
name = "github.com/gorilla/websocket"
packages = ["."]
revision = "ea4d1f681babbce9545c9c5f3d5194a789c89f5b"
version = "v1.2.0"
[[projects]]
branch = "master"
name = "github.com/martinboehm/bchutil"
packages = ["."]
revision = "6373f11b6efe1ea81e8713b8788a695b2c144d38"
[[projects]]
branch = "master"
name = "github.com/martinboehm/btcutil"
packages = [".","base58","bech32","chaincfg","hdkeychain","txscript"]
revision = "a3d2b8457b77d37c3813742d4030e199b6e09111"
[[projects]]
branch = "master"
name = "github.com/juju/errors"
packages = ["."]
revision = "c7d06af17c68cd34c835053720b21f6549d9b0ee"
[[projects]]
branch = "master"
name = "github.com/martinboehm/golang-socketio"
packages = [".","protocol","transport"]
revision = "f60b0a8befde091474a624a8ffd81ee9912957b3"
[[projects]]
name = "github.com/matttproud/golang_protobuf_extensions"
packages = ["pbutil"]
revision = "3247c84500bff8d9fb6d579d800f20b3e091582c"
version = "v1.0.0"
[[projects]]
branch = "master"
name = "github.com/mr-tron/base58"
packages = ["base58"]
revision = "c1bdf7c52f59d6685ca597b9955a443ff95eeee6"
[[projects]]
branch = "master"
name = "github.com/pebbe/zmq4"
packages = ["."]
revision = "5b443b6471cea4b4f9f85025530c04c93233f76a"
[[projects]]
name = "github.com/pkg/errors"
packages = ["."]
revision = "645ef00459ed84a119197bfb8d8205042c6df63d"
version = "v0.8.0"
[[projects]]
name = "github.com/prometheus/client_golang"
packages = ["prometheus","prometheus/promhttp"]
revision = "c5b7fccd204277076155f10851dad72b76a49317"
version = "v0.8.0"
[[projects]]
branch = "master"
name = "github.com/prometheus/client_model"
packages = ["go"]
revision = "99fa1f4be8e564e8a6b613da7fa6f46c9edafc6c"
[[projects]]
branch = "master"
name = "github.com/prometheus/common"
packages = ["expfmt","internal/bitbucket.org/ww/goautoneg","model"]
revision = "d0f7cd64bda49e08b22ae8a730aa57aa0db125d6"
[[projects]]
branch = "master"
name = "github.com/prometheus/procfs"
packages = [".","internal/util","nfs","xfs"]
revision = "8b1c2da0d56deffdbb9e48d4414b4e674bd8083e"
[[projects]]
name = "github.com/rs/cors"
packages = ["."]
revision = "feef513b9575b32f84bafa580aad89b011259019"
version = "v1.3.0"
[[projects]]
name = "github.com/schancel/cashaddr-converter"
packages = ["address","baseconv","cashaddress","legacy"]
revision = "0a38f5822f795dc3727b4caacc298e02938d9eb1"
version = "v9"
[[projects]]
branch = "master"
name = "github.com/syndtr/goleveldb"
packages = ["leveldb","leveldb/cache","leveldb/comparer","leveldb/errors","leveldb/filter","leveldb/iterator","leveldb/journal","leveldb/memdb","leveldb/opt","leveldb/storage","leveldb/table","leveldb/util"]
revision = "714f901b98fdb3aa954b4193d8cbd64a28d80cad"
[[projects]]
branch = "master"
name = "github.com/tecbot/gorocksdb"
packages = ["."]
revision = "214b6b7bc0f06812ab5602fdc502a3e619916f38"
[[projects]]
branch = "master"
name = "golang.org/x/crypto"
packages = ["ripemd160", "sha3"]
revision = "a832865fa7ada6126f4c6124ac49f71be71bff2a"
[[projects]]
branch = "master"
name = "golang.org/x/net"
packages = ["websocket"]
revision = "61147c48b25b599e5b561d2e9c4f3e1ef489ca41"
[[projects]]
branch = "v2"
name = "gopkg.in/karalabe/cookiejar.v2"
packages = ["collections/prque"]
revision = "8dcd6a7f4951f6ff3ee9cbb919a06d8925822e57"
[[projects]]
branch = "v2"
name = "gopkg.in/natefinch/npipe.v2"
packages = ["."]
revision = "c1b8fa8bdccecb0b8db834ee0b92fdbcfa606dd6"
[solve-meta]
analyzer-name = "dep"
analyzer-version = 1
input-imports = [
"github.com/bsm/go-vlq",
"github.com/deckarep/golang-set",
"github.com/decred/dcrd/chaincfg",
"github.com/decred/dcrd/dcrjson",
"github.com/decred/dcrd/txscript",
"github.com/ethereum/go-ethereum",
"github.com/ethereum/go-ethereum/common",
"github.com/ethereum/go-ethereum/common/hexutil",
"github.com/ethereum/go-ethereum/core/types",
"github.com/ethereum/go-ethereum/ethclient",
"github.com/ethereum/go-ethereum/rpc",
"github.com/gobuffalo/packr",
"github.com/gogo/protobuf/proto",
"github.com/golang/glog",
"github.com/golang/protobuf/proto",
"github.com/gorilla/websocket",
"github.com/juju/errors",
"github.com/martinboehm/bchutil",
"github.com/martinboehm/btcd/blockchain",
"github.com/martinboehm/btcd/chaincfg/chainhash",
"github.com/martinboehm/btcd/txscript",
"github.com/martinboehm/btcd/wire",
"github.com/martinboehm/btcutil",
"github.com/martinboehm/btcutil/base58",
"github.com/martinboehm/btcutil/chaincfg",
"github.com/martinboehm/btcutil/hdkeychain",
"github.com/martinboehm/btcutil/txscript",
"github.com/martinboehm/golang-socketio",
"github.com/martinboehm/golang-socketio/transport",
"github.com/pebbe/zmq4",
"github.com/prometheus/client_golang/prometheus",
"github.com/prometheus/client_golang/prometheus/promhttp",
"github.com/schancel/cashaddr-converter/address",
"github.com/tecbot/gorocksdb",
]
solver-name = "gps-cdcl"
solver-version = 1

74
Gopkg.toml 100644
View File

@ -0,0 +1,74 @@
# Gopkg.toml example
#
# Refer to https://github.com/golang/dep/blob/master/docs/Gopkg.toml.md
# for detailed Gopkg.toml documentation.
#
# required = ["github.com/user/thing/cmd/thing"]
# ignored = ["github.com/user/project/pkgX", "bitbucket.org/user/project/pkgA/pkgY"]
#
# [[constraint]]
# name = "github.com/user/project"
# version = "1.0.0"
#
# [[constraint]]
# name = "github.com/user/project2"
# branch = "dev"
# source = "github.com/myfork/project2"
#
# [[override]]
# name = "github.com/x/y"
# version = "2.4.0"
[[constraint]]
branch = "master"
name = "github.com/bsm/go-vlq"
[[constraint]]
branch = "master"
name = "github.com/martinboehm/btcd"
[[constraint]]
branch = "master"
name = "github.com/martinboehm/btcutil"
[[constraint]]
branch = "master"
name = "github.com/golang/glog"
[[constraint]]
name = "github.com/gorilla/mux"
version = "1.6.1"
[[constraint]]
branch = "master"
name = "github.com/juju/errors"
[[constraint]]
branch = "master"
name = "github.com/martinboehm/golang-socketio"
[[constraint]]
branch = "master"
name = "github.com/pebbe/zmq4"
[[constraint]]
name = "github.com/prometheus/client_golang"
version = "0.8.0"
[[constraint]]
branch = "master"
name = "github.com/tecbot/gorocksdb"
[[constraint]]
name = "github.com/ethereum/go-ethereum"
version = "1.8.2"
[[constraint]]
name = "github.com/golang/protobuf"
version = "1.0.0"
[[constraint]]
branch = "master"
name = "github.com/martinboehm/bchutil"

View File

@ -1,9 +1,8 @@
BIN_IMAGE = blockbook-build
DEB_IMAGE = blockbook-build-deb
PACKAGER = $(shell id -u):$(shell id -g)
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 =
UPDATE_VENDOR = 1
ARGS ?=
TARGETS=$(subst .json,, $(shell ls configs/coins))
@ -11,28 +10,28 @@ TARGETS=$(subst .json,, $(shell ls configs/coins))
.PHONY: build build-debug test deb
build: .bin-image
docker run -t --rm -e PACKAGER=$(PACKAGER) -v "$(CURDIR):/src" -v "$(CURDIR)/build:/out" $(BIN_IMAGE) make build ARGS="$(ARGS)"
docker run -t --rm -e PACKAGER=$(PACKAGER) -e UPDATE_VENDOR=$(UPDATE_VENDOR) -v $(CURDIR):/src -v $(CURDIR)/build:/out $(BIN_IMAGE) make build ARGS="$(ARGS)"
build-debug: .bin-image
docker run -t --rm -e PACKAGER=$(PACKAGER) -v "$(CURDIR):/src" -v "$(CURDIR)/build:/out" $(BIN_IMAGE) make build-debug ARGS="$(ARGS)"
docker run -t --rm -e PACKAGER=$(PACKAGER) -e UPDATE_VENDOR=$(UPDATE_VENDOR) -v $(CURDIR):/src -v $(CURDIR)/build:/out $(BIN_IMAGE) make build-debug ARGS="$(ARGS)"
test: .bin-image
docker run -t --rm -e PACKAGER=$(PACKAGER) -v "$(CURDIR):/src" --network="host" $(BIN_IMAGE) make test ARGS="$(ARGS)"
docker run -t --rm -e PACKAGER=$(PACKAGER) -e UPDATE_VENDOR=$(UPDATE_VENDOR) -v $(CURDIR):/src --network="host" $(BIN_IMAGE) make test ARGS="$(ARGS)"
test-integration: .bin-image
docker run -t --rm -e PACKAGER=$(PACKAGER) -v "$(CURDIR):/src" --network="host" $(BIN_IMAGE) make test-integration ARGS="$(ARGS)"
docker run -t --rm -e PACKAGER=$(PACKAGER) -e UPDATE_VENDOR=$(UPDATE_VENDOR) -v $(CURDIR):/src --network="host" $(BIN_IMAGE) make test-integration ARGS="$(ARGS)"
test-all: .bin-image
docker run -t --rm -e PACKAGER=$(PACKAGER) -v "$(CURDIR):/src" --network="host" $(BIN_IMAGE) make test-all ARGS="$(ARGS)"
docker run -t --rm -e PACKAGER=$(PACKAGER) -e UPDATE_VENDOR=$(UPDATE_VENDOR) -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) -e UPDATE_VENDOR=$(UPDATE_VENDOR) -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)
docker run -t --rm -e PACKAGER=$(PACKAGER) -e UPDATE_VENDOR=$(UPDATE_VENDOR) -v $(CURDIR):/src -v $(CURDIR)/build:/out $(DEB_IMAGE) /build/build-deb.sh blockbook $* $(ARGS)
deb-%: .deb-image
docker run -t --rm -e PACKAGER=$(PACKAGER) -v "$(CURDIR):/src" -v "$(CURDIR)/build:/out" $(DEB_IMAGE) /build/build-deb.sh all $* $(ARGS)
docker run -t --rm -e PACKAGER=$(PACKAGER) -e UPDATE_VENDOR=$(UPDATE_VENDOR) -v $(CURDIR):/src -v $(CURDIR)/build:/out $(DEB_IMAGE) /build/build-deb.sh all $* $(ARGS)
deb-blockbook-all: clean-deb $(addprefix deb-blockbook-, $(TARGETS))
@ -45,8 +44,8 @@ build-images: clean-images
.bin-image:
@if [ $$(build/tools/image_status.sh $(BIN_IMAGE):latest build/docker) != "ok" ]; then \
echo "Building image $(BIN_IMAGE) from $(BASE_IMAGE)"; \
docker build --no-cache=$(NO_CACHE) --build-arg TCMALLOC=$(TCMALLOC) --build-arg BASE_IMAGE=$(BASE_IMAGE) -t $(BIN_IMAGE) build/docker/bin; \
echo "Building image $(BIN_IMAGE)..."; \
docker build --no-cache=$(NO_CACHE) -t $(BIN_IMAGE) build/docker/bin; \
else \
echo "Image $(BIN_IMAGE) is up to date"; \
fi

View File

@ -1,74 +0,0 @@
[![Go Report Card](https://goreportcard.com/badge/trezor/blockbook)](https://goreportcard.com/report/trezor/blockbook)
# Blockbook
**Blockbook** is back-end service for Trezor wallet. Main features of **Blockbook** are:
- index of addresses and address balances of the connected block chain
- fast searches in the indexes
- simple blockchain explorer
- websocket, API and legacy Bitcore Insight compatible socket.io interfaces
- support of multiple coins (Bitcoin and Ethereum type), with easy extensibility for other coins
- scripts for easy creation of debian packages for backend and blockbook
## Build and installation instructions
Officially supported platform is **Debian Linux** and **AMD64** architecture.
Memory and disk requirements for initial synchronization of **Bitcoin mainnet** are around 32 GB RAM and over 180 GB of disk space. After initial synchronization, fully synchronized instance uses about 10 GB RAM.
Other coins should have lower requirements, depending on the size of their block chain. Note that fast SSD disks are highly
recommended.
User installation guide is [here](https://wiki.trezor.io/User_manual:Running_a_local_instance_of_Trezor_Wallet_backend_(Blockbook)).
Developer build guide is [here](/docs/build.md).
Contribution guide is [here](CONTRIBUTING.md).
## Implemented coins
Blockbook currently supports over 30 coins. The Trezor team implemented
- Bitcoin, Bitcoin Cash, Zcash, Dash, Litecoin, Bitcoin Gold, Ethereum, Ethereum Classic, Dogecoin, Namecoin, Vertcoin, DigiByte, Liquid
the rest of coins were implemented by the community.
Testnets for some coins are also supported, for example:
- Bitcoin Testnet, Bitcoin Cash Testnet, ZCash Testnet, Ethereum Testnet Ropsten
List of all implemented coins is in [the registry of ports](/docs/ports.md).
## Common issues when running Blockbook or implementing additional coins
#### Out of memory when doing initial synchronization
How to reduce memory footprint of the initial sync:
- disable rocksdb cache by parameter `-dbcache=0`, the default size is 500MB
- run blockbook with parameter `-workers=1`. This disables bulk import mode, which caches a lot of data in memory (not in rocksdb cache). It will run about twice as slowly but especially for smaller blockchains it is no problem at all.
Please add your experience to this [issue](https://github.com/trezor/blockbook/issues/43).
#### Error `internalState: database is in inconsistent state and cannot be used`
Blockbook was killed during the initial import, most commonly by OOM killer. By default, Blockbook performs the initial import in bulk import mode, which for performance reasons does not store all the data immediately to the database. If Blockbook is killed during this phase, the database is left in an inconsistent state.
See above how to reduce the memory footprint, delete the database files and run the import again.
Check [this](https://github.com/trezor/blockbook/issues/89) or [this](https://github.com/trezor/blockbook/issues/147) issue for more info.
#### Running on Ubuntu
[This issue](https://github.com/trezor/blockbook/issues/45) discusses how to run Blockbook on Ubuntu. If you have some additional experience with Blockbook on Ubuntu, please add it to [this issue](https://github.com/trezor/blockbook/issues/45).
#### My coin implementation is reporting parse errors when importing blockchain
Your coin's block/transaction data may not be compatible with `BitcoinParser` `ParseBlock`/`ParseTx`, which is used by default. In that case, implement your coin in a similar way we used in case of [zcash](https://github.com/trezor/blockbook/tree/master/bchain/coins/zec) and some other coins. The principle is not to parse the block/transaction data in Blockbook but instead to get parsed transactions as json from the backend.
## Data storage in RocksDB
Blockbook stores data the key-value store RocksDB. Database format is described [here](/docs/rocksdb.md).
## API
Blockbook API is described [here](/docs/api.md).

View File

@ -1,57 +1,74 @@
# Fork
Fork of Trezor Blockbook.
[![Go Report Card](https://goreportcard.com/badge/trezor/blockbook)](https://goreportcard.com/report/trezor/blockbook)
# Blockbook
The differences:
**Blockbook** is back-end service for Trezor wallet. Main features of **Blockbook** are:
* Just for Ethereum.
- index of addresses and address balances of the connected block chain
- fast searches in the indexes
- simple blockchain explorer
- websocket, API and legacy Bitcore Insight compatible socket.io interfaces
- support of multiple coins (Bitcoin and Ethereum type), with easy extensibility for other coins
- scripts for easy creation of debian packages for backend and blockbook
* Use existing `geth --full` server.
## Build and installation instructions
* Don't require `backend-*` package.
Officially supported platform is **Debian Linux** and **AMD64** architecture.
* Minimal UI, dark theme.
Memory and disk requirements for initial synchronization of **Bitcoin mainnet** are around 32 GB RAM and over 180 GB of disk space. After initial synchronization, fully synchronized instance uses about 10 GB RAM.
Other coins should have lower requirements, depending on the size of their block chain. Note that fast SSD disks are highly
recommended.
* Listen only on localhost, no SSL.
User installation guide is [here](https://wiki.trezor.io/User_manual:Running_a_local_instance_of_Trezor_Wallet_backend_(Blockbook)).
* Use spacecruft repos, not github.
Developer build guide is [here](/docs/build.md).
* Don't use CDN.
Contribution guide is [here](CONTRIBUTING.md).
# Install
## Implemented coins
```
# Install docker, etc.
git clone https://spacecruft.org/spacecruft/blockbook
cd blockbook
make deb-blockbook-ethereum
dpkg -i build/blockbook-ethereum_0.3.4_amd64.deb
```
Blockbook currently supports over 30 coins. The Trezor team implemented
Edit config:
```
vim /opt/coins/blockbook/ethereum/config/blockchaincfg.json
```
- Bitcoin, Bitcoin Cash, Zcash, Dash, Litecoin, Bitcoin Gold, Ethereum, Ethereum Classic, Dogecoin, Namecoin, Vertcoin, DigiByte, Liquid
XXX Hardcoded into systemd script, set `geth` node:
the rest of coins were implemented by the community.
```
vim /lib/systemd/system/blockbook-ethereum.service
systemctl daemon-reload
```
Testnets for some coins are also supported, for example:
- Bitcoin Testnet, Bitcoin Cash Testnet, ZCash Testnet, Ethereum Testnet Ropsten
Start:
```
systemctl start blockbook-ethereum.service
```
List of all implemented coins is in [the registry of ports](/docs/ports.md).
Logs:
```
tail -f /opt/coins/blockbook/ethereum/logs/blockbook.INFO
```
## Common issues when running Blockbook or implementing additional coins
# Upstream
Fork of Trezor Blockbook. See `README-upstream.md`.
#### Out of memory when doing initial synchronization
* https://github.com/trezor/blockbook
How to reduce memory footprint of the initial sync:
- disable rocksdb cache by parameter `-dbcache=0`, the default size is 500MB
- run blockbook with parameter `-workers=1`. This disables bulk import mode, which caches a lot of data in memory (not in rocksdb cache). It will run about twice as slowly but especially for smaller blockchains it is no problem at all.
Please add your experience to this [issue](https://github.com/trezor/blockbook/issues/43).
#### Error `internalState: database is in inconsistent state and cannot be used`
Blockbook was killed during the initial import, most commonly by OOM killer. By default, Blockbook performs the initial import in bulk import mode, which for performance reasons does not store all the data immediately to the database. If Blockbook is killed during this phase, the database is left in an inconsistent state.
See above how to reduce the memory footprint, delete the database files and run the import again.
Check [this](https://github.com/trezor/blockbook/issues/89) or [this](https://github.com/trezor/blockbook/issues/147) issue for more info.
#### Running on Ubuntu
[This issue](https://github.com/trezor/blockbook/issues/45) discusses how to run Blockbook on Ubuntu. If you have some additional experience with Blockbook on Ubuntu, please add it to [this issue](https://github.com/trezor/blockbook/issues/45).
#### My coin implementation is reporting parse errors when importing blockchain
Your coin's block/transaction data may not be compatible with `BitcoinParser` `ParseBlock`/`ParseTx`, which is used by default. In that case, implement your coin in a similar way we used in case of [zcash](https://github.com/trezor/blockbook/tree/master/bchain/coins/zec) and some other coins. The principle is not to parse the block/transaction data in Blockbook but instead to get parsed transactions as json from the backend.
## Data storage in RocksDB
Blockbook stores data the key-value store RocksDB. Database format is described [here](/docs/rocksdb.md).
## API
Blockbook API is described [here](/docs/api.md).

View File

@ -1,16 +1,14 @@
package api
import (
"blockbook/bchain"
"blockbook/common"
"blockbook/db"
"encoding/json"
"errors"
"math/big"
"sort"
"time"
"spacecruft.org/spacecruft/blockbook/bchain"
"spacecruft.org/spacecruft/blockbook/bchain/coins/eth"
"spacecruft.org/spacecruft/blockbook/common"
"spacecruft.org/spacecruft/blockbook/db"
)
const maxUint32 = ^uint32(0)
@ -171,12 +169,11 @@ type TokenTransfer struct {
// EthereumSpecific contains ethereum specific transaction data
type EthereumSpecific struct {
Status eth.TxStatus `json:"status"` // 1 OK, 0 Fail, -1 pending
Nonce uint64 `json:"nonce"`
GasLimit *big.Int `json:"gasLimit"`
GasUsed *big.Int `json:"gasUsed"`
GasPrice *Amount `json:"gasPrice"`
Data string `json:"data,omitempty"`
Status int `json:"status"` // 1 OK, 0 Fail, -1 pending
Nonce uint64 `json:"nonce"`
GasLimit *big.Int `json:"gasLimit"`
GasUsed *big.Int `json:"gasUsed"`
GasPrice *Amount `json:"gasPrice"`
}
// Tx holds information about a transaction
@ -196,7 +193,8 @@ type Tx struct {
FeesSat *Amount `json:"fees,omitempty"`
Hex string `json:"hex,omitempty"`
Rbf bool `json:"rbf,omitempty"`
CoinSpecificData json.RawMessage `json:"coinSpecificData,omitempty"`
CoinSpecificData interface{} `json:"-"`
CoinSpecificJSON json.RawMessage `json:"-"`
TokenTransfers []TokenTransfer `json:"tokenTransfers,omitempty"`
EthereumSpecific *EthereumSpecific `json:"ethereumSpecific,omitempty"`
}
@ -226,8 +224,6 @@ const (
AddressFilterVoutInputs = -2
// AddressFilterVoutOutputs specifies that only txs where the address is as output are returned
AddressFilterVoutOutputs = -3
// AddressFilterVoutQueryNotNecessary signals that query for transactions is not necessary as there are no transactions for specified contract filter
AddressFilterVoutQueryNotNecessary = -4
// TokensToReturnNonzeroBalance - return only tokens with nonzero balance
TokensToReturnNonzeroBalance TokensToReturn = 0
@ -303,13 +299,12 @@ func (a Utxos) Less(i, j int) bool {
// BalanceHistory contains info about one point in time of balance history
type BalanceHistory struct {
Time uint32 `json:"time"`
Txs uint32 `json:"txs"`
ReceivedSat *Amount `json:"received"`
SentSat *Amount `json:"sent"`
SentToSelfSat *Amount `json:"sentToSelf"`
FiatRates map[string]float64 `json:"rates,omitempty"`
Txid string `json:"txid,omitempty"`
Time uint32 `json:"time"`
Txs uint32 `json:"txs"`
ReceivedSat *Amount `json:"received"`
SentSat *Amount `json:"sent"`
FiatRates map[string]float64 `json:"rates,omitempty"`
Txid string `json:"txid,omitempty"`
}
// BalanceHistories is array of BalanceHistory
@ -331,9 +326,8 @@ func (a BalanceHistories) SortAndAggregate(groupByTime uint32) BalanceHistories
bhs := make(BalanceHistories, 0)
if len(a) > 0 {
bha := BalanceHistory{
ReceivedSat: &Amount{},
SentSat: &Amount{},
SentToSelfSat: &Amount{},
SentSat: &Amount{},
ReceivedSat: &Amount{},
}
sort.Sort(a)
for i := range a {
@ -346,19 +340,17 @@ func (a BalanceHistories) SortAndAggregate(groupByTime uint32) BalanceHistories
bhs = append(bhs, bha)
}
bha = BalanceHistory{
Time: time,
ReceivedSat: &Amount{},
SentSat: &Amount{},
SentToSelfSat: &Amount{},
Time: time,
SentSat: &Amount{},
ReceivedSat: &Amount{},
}
}
if bha.Txid != bh.Txid {
bha.Txs += bh.Txs
bha.Txid = bh.Txid
}
(*big.Int)(bha.ReceivedSat).Add((*big.Int)(bha.ReceivedSat), (*big.Int)(bh.ReceivedSat))
(*big.Int)(bha.SentSat).Add((*big.Int)(bha.SentSat), (*big.Int)(bh.SentSat))
(*big.Int)(bha.SentToSelfSat).Add((*big.Int)(bha.SentToSelfSat), (*big.Int)(bh.SentToSelfSat))
(*big.Int)(bha.ReceivedSat).Add((*big.Int)(bha.ReceivedSat), (*big.Int)(bh.ReceivedSat))
}
if bha.Txs > 0 {
bha.Txid = ""
@ -376,19 +368,19 @@ type Blocks struct {
// BlockInfo contains extended block header data and a list of block txids
type BlockInfo struct {
Hash string `json:"hash"`
Prev string `json:"previousBlockHash,omitempty"`
Next string `json:"nextBlockHash,omitempty"`
Height uint32 `json:"height"`
Confirmations int `json:"confirmations"`
Size int `json:"size"`
Time int64 `json:"time,omitempty"`
Version common.JSONNumber `json:"version"`
MerkleRoot string `json:"merkleRoot"`
Nonce string `json:"nonce"`
Bits string `json:"bits"`
Difficulty string `json:"difficulty"`
Txids []string `json:"tx,omitempty"`
Hash string `json:"hash"`
Prev string `json:"previousBlockHash,omitempty"`
Next string `json:"nextBlockHash,omitempty"`
Height uint32 `json:"height"`
Confirmations int `json:"confirmations"`
Size int `json:"size"`
Time int64 `json:"time,omitempty"`
Version json.Number `json:"version"`
MerkleRoot string `json:"merkleRoot"`
Nonce string `json:"nonce"`
Bits string `json:"bits"`
Difficulty string `json:"difficulty"`
Txids []string `json:"tx,omitempty"`
}
// Block contains information about block
@ -421,10 +413,26 @@ type BlockbookInfo struct {
About string `json:"about"`
}
// BackendInfo is used to get information about blockchain
type BackendInfo struct {
BackendError string `json:"error,omitempty"`
Chain string `json:"chain,omitempty"`
Blocks int `json:"blocks,omitempty"`
Headers int `json:"headers,omitempty"`
BestBlockHash string `json:"bestBlockHash,omitempty"`
Difficulty string `json:"difficulty,omitempty"`
SizeOnDisk int64 `json:"sizeOnDisk,omitempty"`
Version string `json:"version,omitempty"`
Subversion string `json:"subversion,omitempty"`
ProtocolVersion string `json:"protocolVersion,omitempty"`
Timeoffset float64 `json:"timeOffset,omitempty"`
Warnings string `json:"warnings,omitempty"`
}
// SystemInfo contains information about the running blockbook and backend instance
type SystemInfo struct {
Blockbook *BlockbookInfo `json:"blockbook"`
Backend *common.BackendInfo `json:"backend"`
Blockbook *BlockbookInfo `json:"blockbook"`
Backend *BackendInfo `json:"backend"`
}
// MempoolTxid contains information about a transaction in mempool

View File

@ -67,22 +67,20 @@ func TestBalanceHistories_SortAndAggregate(t *testing.T) {
name: "one",
a: []BalanceHistory{
{
ReceivedSat: (*Amount)(big.NewInt(1)),
SentSat: (*Amount)(big.NewInt(2)),
SentToSelfSat: (*Amount)(big.NewInt(1)),
Time: 1521514812,
Txid: "00b2c06055e5e90e9c82bd4181fde310104391a7fa4f289b1704e5d90caa3840",
Txs: 1,
ReceivedSat: (*Amount)(big.NewInt(1)),
SentSat: (*Amount)(big.NewInt(2)),
Time: 1521514812,
Txid: "00b2c06055e5e90e9c82bd4181fde310104391a7fa4f289b1704e5d90caa3840",
Txs: 1,
},
},
groupByTime: 3600,
want: []BalanceHistory{
{
ReceivedSat: (*Amount)(big.NewInt(1)),
SentSat: (*Amount)(big.NewInt(2)),
SentToSelfSat: (*Amount)(big.NewInt(1)),
Time: 1521514800,
Txs: 1,
ReceivedSat: (*Amount)(big.NewInt(1)),
SentSat: (*Amount)(big.NewInt(2)),
Time: 1521514800,
Txs: 1,
},
},
},
@ -90,76 +88,67 @@ func TestBalanceHistories_SortAndAggregate(t *testing.T) {
name: "aggregate",
a: []BalanceHistory{
{
ReceivedSat: (*Amount)(big.NewInt(1)),
SentSat: (*Amount)(big.NewInt(2)),
SentToSelfSat: (*Amount)(big.NewInt(0)),
Time: 1521504812,
Txid: "0011223344556677889900112233445566778899001122334455667788990011",
Txs: 1,
ReceivedSat: (*Amount)(big.NewInt(1)),
SentSat: (*Amount)(big.NewInt(2)),
Time: 1521504812,
Txid: "0011223344556677889900112233445566778899001122334455667788990011",
Txs: 1,
},
{
ReceivedSat: (*Amount)(big.NewInt(3)),
SentSat: (*Amount)(big.NewInt(4)),
SentToSelfSat: (*Amount)(big.NewInt(2)),
Time: 1521504812,
Txid: "00b2c06055e5e90e9c82bd4181fde310104391a7fa4f289b1704e5d90caa3840",
Txs: 1,
ReceivedSat: (*Amount)(big.NewInt(3)),
SentSat: (*Amount)(big.NewInt(4)),
Time: 1521504812,
Txid: "00b2c06055e5e90e9c82bd4181fde310104391a7fa4f289b1704e5d90caa3840",
Txs: 1,
},
{
ReceivedSat: (*Amount)(big.NewInt(5)),
SentSat: (*Amount)(big.NewInt(6)),
SentToSelfSat: (*Amount)(big.NewInt(3)),
Time: 1521514812,
Txid: "00b2c06055e5e90e9c82bd4181fde310104391a7fa4f289b1704e5d90caa3840",
Txs: 1,
ReceivedSat: (*Amount)(big.NewInt(5)),
SentSat: (*Amount)(big.NewInt(6)),
Time: 1521514812,
Txid: "00b2c06055e5e90e9c82bd4181fde310104391a7fa4f289b1704e5d90caa3840",
Txs: 1,
},
{
ReceivedSat: (*Amount)(big.NewInt(7)),
SentSat: (*Amount)(big.NewInt(8)),
SentToSelfSat: (*Amount)(big.NewInt(3)),
Time: 1521504812,
Txid: "00b2c06055e5e90e9c82bd4181fde310104391a7fa4f289b1704e5d90caa3840",
Txs: 1,
ReceivedSat: (*Amount)(big.NewInt(7)),
SentSat: (*Amount)(big.NewInt(8)),
Time: 1521504812,
Txid: "00b2c06055e5e90e9c82bd4181fde310104391a7fa4f289b1704e5d90caa3840",
Txs: 1,
},
{
ReceivedSat: (*Amount)(big.NewInt(9)),
SentSat: (*Amount)(big.NewInt(10)),
SentToSelfSat: (*Amount)(big.NewInt(5)),
Time: 1521534812,
Txid: "0011223344556677889900112233445566778899001122334455667788990011",
Txs: 1,
ReceivedSat: (*Amount)(big.NewInt(9)),
SentSat: (*Amount)(big.NewInt(10)),
Time: 1521534812,
Txid: "0011223344556677889900112233445566778899001122334455667788990011",
Txs: 1,
},
{
ReceivedSat: (*Amount)(big.NewInt(11)),
SentSat: (*Amount)(big.NewInt(12)),
SentToSelfSat: (*Amount)(big.NewInt(6)),
Time: 1521534812,
Txid: "1122334455667788990011223344556677889900112233445566778899001100",
Txs: 1,
ReceivedSat: (*Amount)(big.NewInt(11)),
SentSat: (*Amount)(big.NewInt(12)),
Time: 1521534812,
Txid: "1122334455667788990011223344556677889900112233445566778899001100",
Txs: 1,
},
},
groupByTime: 3600,
want: []BalanceHistory{
{
ReceivedSat: (*Amount)(big.NewInt(11)),
SentSat: (*Amount)(big.NewInt(14)),
SentToSelfSat: (*Amount)(big.NewInt(5)),
Time: 1521504000,
Txs: 2,
ReceivedSat: (*Amount)(big.NewInt(11)),
SentSat: (*Amount)(big.NewInt(14)),
Time: 1521504000,
Txs: 2,
},
{
ReceivedSat: (*Amount)(big.NewInt(5)),
SentSat: (*Amount)(big.NewInt(6)),
SentToSelfSat: (*Amount)(big.NewInt(3)),
Time: 1521514800,
Txs: 1,
ReceivedSat: (*Amount)(big.NewInt(5)),
SentSat: (*Amount)(big.NewInt(6)),
Time: 1521514800,
Txs: 1,
},
{
ReceivedSat: (*Amount)(big.NewInt(20)),
SentSat: (*Amount)(big.NewInt(22)),
SentToSelfSat: (*Amount)(big.NewInt(11)),
Time: 1521532800,
Txs: 2,
ReceivedSat: (*Amount)(big.NewInt(20)),
SentSat: (*Amount)(big.NewInt(22)),
Time: 1521532800,
Txs: 2,
},
},
},

View File

@ -1,9 +1,8 @@
package api
import (
"blockbook/bchain"
"math/big"
"spacecruft.org/spacecruft/blockbook/bchain"
)
// ScriptSigV1 is used for legacy api v1

View File

@ -1,6 +1,10 @@
package api
import (
"blockbook/bchain"
"blockbook/bchain/coins/eth"
"blockbook/common"
"blockbook/db"
"bytes"
"encoding/json"
"fmt"
@ -14,10 +18,6 @@ import (
"github.com/golang/glog"
"github.com/juju/errors"
"spacecruft.org/spacecruft/blockbook/bchain"
"spacecruft.org/spacecruft/blockbook/bchain/coins/eth"
"spacecruft.org/spacecruft/blockbook/common"
"spacecruft.org/spacecruft/blockbook/db"
)
// Worker is handle to api worker
@ -253,7 +253,32 @@ func (w *Worker) GetTransactionFromBchainTx(bchainTx *bchain.Tx, height int, spe
if err != nil {
glog.Errorf("GetErc20FromTx error %v, %v", err, bchainTx)
}
tokens = w.getTokensFromErc20(ets)
tokens = make([]TokenTransfer, len(ets))
for i := range ets {
e := &ets[i]
cd, err := w.chainParser.GetAddrDescFromAddress(e.Contract)
if err != nil {
glog.Errorf("GetAddrDescFromAddress error %v, contract %v", err, e.Contract)
continue
}
erc20c, err := w.chain.EthereumTypeGetErc20ContractInfo(cd)
if err != nil {
glog.Errorf("GetErc20ContractInfo error %v, contract %v", err, e.Contract)
}
if erc20c == nil {
erc20c = &bchain.Erc20Contract{Name: e.Contract}
}
tokens[i] = TokenTransfer{
Type: ERC20TokenType,
Token: e.Contract,
From: e.From,
To: e.To,
Decimals: erc20c.Decimals,
Value: (*Amount)(&e.Tokens),
Name: erc20c.Name,
Symbol: erc20c.Symbol,
}
}
ethTxData := eth.GetEthereumTxData(bchainTx)
// mempool txs do not have fees yet
if ethTxData.GasUsed != nil {
@ -268,14 +293,12 @@ func (w *Worker) GetTransactionFromBchainTx(bchainTx *bchain.Tx, height int, spe
GasUsed: ethTxData.GasUsed,
Nonce: ethTxData.Nonce,
Status: ethTxData.Status,
Data: ethTxData.Data,
}
}
// for now do not return size, we would have to compute vsize of segwit transactions
// size:=len(bchainTx.Hex) / 2
var sj json.RawMessage
// return CoinSpecificData for all mempool transactions or if requested
if specificJSON || bchainTx.Confirmations == 0 {
if specificJSON {
sj, err = w.chain.GetTransactionSpecific(bchainTx)
if err != nil {
return nil, err
@ -300,140 +323,14 @@ func (w *Worker) GetTransactionFromBchainTx(bchainTx *bchain.Tx, height int, spe
Rbf: rbf,
Vin: vins,
Vout: vouts,
CoinSpecificData: sj,
CoinSpecificData: bchainTx.CoinSpecificData,
CoinSpecificJSON: sj,
TokenTransfers: tokens,
EthereumSpecific: ethSpecific,
}
return r, nil
}
// GetTransactionFromMempoolTx converts bchain.MempoolTx to Tx, with limited amount of data
// it is not doing any request to backend or to db
func (w *Worker) GetTransactionFromMempoolTx(mempoolTx *bchain.MempoolTx) (*Tx, error) {
var err error
var valInSat, valOutSat, feesSat big.Int
var pValInSat *big.Int
var tokens []TokenTransfer
var ethSpecific *EthereumSpecific
vins := make([]Vin, len(mempoolTx.Vin))
rbf := false
for i := range mempoolTx.Vin {
bchainVin := &mempoolTx.Vin[i]
vin := &vins[i]
vin.Txid = bchainVin.Txid
vin.N = i
vin.Vout = bchainVin.Vout
vin.Sequence = int64(bchainVin.Sequence)
// detect explicit Replace-by-Fee transactions as defined by BIP125
if bchainVin.Sequence < 0xffffffff-1 {
rbf = true
}
vin.Hex = bchainVin.ScriptSig.Hex
vin.Coinbase = bchainVin.Coinbase
if w.chainType == bchain.ChainBitcoinType {
// bchainVin.Txid=="" is coinbase transaction
if bchainVin.Txid != "" {
vin.ValueSat = (*Amount)(&bchainVin.ValueSat)
vin.AddrDesc = bchainVin.AddrDesc
vin.Addresses, vin.IsAddress, _ = w.chainParser.GetAddressesFromAddrDesc(vin.AddrDesc)
if vin.ValueSat != nil {
valInSat.Add(&valInSat, (*big.Int)(vin.ValueSat))
}
}
} else if w.chainType == bchain.ChainEthereumType {
if len(bchainVin.Addresses) > 0 {
vin.AddrDesc, err = w.chainParser.GetAddrDescFromAddress(bchainVin.Addresses[0])
if err != nil {
glog.Errorf("GetAddrDescFromAddress error %v, tx %v, bchainVin %v", err, mempoolTx.Txid, bchainVin)
}
vin.Addresses = bchainVin.Addresses
vin.IsAddress = true
}
}
}
vouts := make([]Vout, len(mempoolTx.Vout))
for i := range mempoolTx.Vout {
bchainVout := &mempoolTx.Vout[i]
vout := &vouts[i]
vout.N = i
vout.ValueSat = (*Amount)(&bchainVout.ValueSat)
valOutSat.Add(&valOutSat, &bchainVout.ValueSat)
vout.Hex = bchainVout.ScriptPubKey.Hex
vout.AddrDesc, vout.Addresses, vout.IsAddress, err = w.getAddressesFromVout(bchainVout)
if err != nil {
glog.V(2).Infof("getAddressesFromVout error %v, %v, output %v", err, mempoolTx.Txid, bchainVout.N)
}
}
if w.chainType == bchain.ChainBitcoinType {
// for coinbase transactions valIn is 0
feesSat.Sub(&valInSat, &valOutSat)
if feesSat.Sign() == -1 {
feesSat.SetUint64(0)
}
pValInSat = &valInSat
} else if w.chainType == bchain.ChainEthereumType {
if len(mempoolTx.Vout) > 0 {
valOutSat = mempoolTx.Vout[0].ValueSat
}
tokens = w.getTokensFromErc20(mempoolTx.Erc20)
ethTxData := eth.GetEthereumTxDataFromSpecificData(mempoolTx.CoinSpecificData)
ethSpecific = &EthereumSpecific{
GasLimit: ethTxData.GasLimit,
GasPrice: (*Amount)(ethTxData.GasPrice),
GasUsed: ethTxData.GasUsed,
Nonce: ethTxData.Nonce,
Status: ethTxData.Status,
Data: ethTxData.Data,
}
}
r := &Tx{
Blocktime: mempoolTx.Blocktime,
FeesSat: (*Amount)(&feesSat),
Locktime: mempoolTx.LockTime,
Txid: mempoolTx.Txid,
ValueInSat: (*Amount)(pValInSat),
ValueOutSat: (*Amount)(&valOutSat),
Version: mempoolTx.Version,
Hex: mempoolTx.Hex,
Rbf: rbf,
Vin: vins,
Vout: vouts,
TokenTransfers: tokens,
EthereumSpecific: ethSpecific,
}
return r, nil
}
func (w *Worker) getTokensFromErc20(erc20 []bchain.Erc20Transfer) []TokenTransfer {
tokens := make([]TokenTransfer, len(erc20))
for i := range erc20 {
e := &erc20[i]
cd, err := w.chainParser.GetAddrDescFromAddress(e.Contract)
if err != nil {
glog.Errorf("GetAddrDescFromAddress error %v, contract %v", err, e.Contract)
continue
}
erc20c, err := w.chain.EthereumTypeGetErc20ContractInfo(cd)
if err != nil {
glog.Errorf("GetErc20ContractInfo error %v, contract %v", err, e.Contract)
}
if erc20c == nil {
erc20c = &bchain.Erc20Contract{Name: e.Contract}
}
tokens[i] = TokenTransfer{
Type: ERC20TokenType,
Token: e.Contract,
From: e.From,
To: e.To,
Decimals: erc20c.Decimals,
Value: (*Amount)(&e.Tokens),
Name: erc20c.Name,
Symbol: erc20c.Symbol,
}
}
return tokens
}
func (w *Worker) getAddressTxids(addrDesc bchain.AddressDescriptor, mempool bool, filter *AddressFilter, maxResults int) ([]string, error) {
var err error
txids := make([]string, 0, 4)
@ -503,19 +400,6 @@ func (t *Tx) getAddrVoutValue(addrDesc bchain.AddressDescriptor) *big.Int {
}
return &val
}
func (t *Tx) getAddrEthereumTypeMempoolInputValue(addrDesc bchain.AddressDescriptor) *big.Int {
var val big.Int
if len(t.Vin) > 0 && len(t.Vout) > 0 && bytes.Equal(t.Vin[0].AddrDesc, addrDesc) {
val.Add(&val, (*big.Int)(t.Vout[0].ValueSat))
// add maximum possible fee (the used value is not yet known)
if t.EthereumSpecific != nil && t.EthereumSpecific.GasLimit != nil && t.EthereumSpecific.GasPrice != nil {
var fees big.Int
fees.Mul((*big.Int)(t.EthereumSpecific.GasPrice), t.EthereumSpecific.GasLimit)
val.Add(&val, &fees)
}
}
return &val
}
func (t *Tx) getAddrVinValue(addrDesc bchain.AddressDescriptor) *big.Int {
var val big.Int
@ -612,44 +496,6 @@ func computePaging(count, page, itemsOnPage int) (Paging, int, int, int) {
}, from, to, page
}
func (w *Worker) getEthereumToken(index int, addrDesc, contract bchain.AddressDescriptor, details AccountDetails, txs int) (*Token, error) {
var b *big.Int
validContract := true
ci, err := w.chain.EthereumTypeGetErc20ContractInfo(contract)
if err != nil {
return nil, errors.Annotatef(err, "EthereumTypeGetErc20ContractInfo %v", contract)
}
if ci == nil {
ci = &bchain.Erc20Contract{}
addresses, _, _ := w.chainParser.GetAddressesFromAddrDesc(contract)
if len(addresses) > 0 {
ci.Contract = addresses[0]
ci.Name = addresses[0]
}
validContract = false
}
// do not read contract balances etc in case of Basic option
if details >= AccountDetailsTokenBalances && validContract {
b, err = w.chain.EthereumTypeGetErc20ContractBalance(addrDesc, contract)
if err != nil {
// return nil, nil, nil, errors.Annotatef(err, "EthereumTypeGetErc20ContractBalance %v %v", addrDesc, c.Contract)
glog.Warningf("EthereumTypeGetErc20ContractBalance addr %v, contract %v, %v", addrDesc, contract, err)
}
} else {
b = nil
}
return &Token{
Type: ERC20TokenType,
BalanceSat: (*Amount)(b),
Contract: ci.Contract,
Name: ci.Name,
Symbol: ci.Symbol,
Transfers: txs,
Decimals: ci.Decimals,
ContractIndex: strconv.Itoa(index),
}, nil
}
func (w *Worker) getEthereumTypeAddressBalances(addrDesc bchain.AddressDescriptor, details AccountDetails, filter *AddressFilter) (*db.AddrBalance, []Token, *bchain.Erc20Contract, uint64, int, int, error) {
var (
ba *db.AddrBalance
@ -668,13 +514,6 @@ func (w *Worker) getEthereumTypeAddressBalances(addrDesc bchain.AddressDescripto
if err != nil {
return nil, nil, nil, 0, 0, 0, errors.Annotatef(err, "EthereumTypeGetBalance %v", addrDesc)
}
var filterDesc bchain.AddressDescriptor
if filter.Contract != "" {
filterDesc, err = w.chainParser.GetAddrDescFromAddress(filter.Contract)
if err != nil {
return nil, nil, nil, 0, 0, 0, NewAPIError(fmt.Sprintf("Invalid contract filter, %v", err), true)
}
}
if ca != nil {
ba = &db.AddrBalance{
Txs: uint32(ca.TotalTxs),
@ -686,6 +525,13 @@ func (w *Worker) getEthereumTypeAddressBalances(addrDesc bchain.AddressDescripto
if err != nil {
return nil, nil, nil, 0, 0, 0, errors.Annotatef(err, "EthereumTypeGetNonce %v", addrDesc)
}
var filterDesc bchain.AddressDescriptor
if filter.Contract != "" {
filterDesc, err = w.chainParser.GetAddrDescFromAddress(filter.Contract)
if err != nil {
return nil, nil, nil, 0, 0, 0, NewAPIError(fmt.Sprintf("Invalid contract filter, %v", err), true)
}
}
if details > AccountDetailsBasic {
tokens = make([]Token, len(ca.Contracts))
var j int
@ -697,26 +543,43 @@ func (w *Worker) getEthereumTypeAddressBalances(addrDesc bchain.AddressDescripto
// filter only transactions of this contract
filter.Vout = i + 1
}
t, err := w.getEthereumToken(i+1, addrDesc, c.Contract, details, int(c.Txs))
validContract := true
ci, err := w.chain.EthereumTypeGetErc20ContractInfo(c.Contract)
if err != nil {
return nil, nil, nil, 0, 0, 0, err
return nil, nil, nil, 0, 0, 0, errors.Annotatef(err, "EthereumTypeGetErc20ContractInfo %v", c.Contract)
}
if ci == nil {
ci = &bchain.Erc20Contract{}
addresses, _, _ := w.chainParser.GetAddressesFromAddrDesc(c.Contract)
if len(addresses) > 0 {
ci.Contract = addresses[0]
ci.Name = addresses[0]
}
validContract = false
}
// do not read contract balances etc in case of Basic option
if details >= AccountDetailsTokenBalances && validContract {
b, err = w.chain.EthereumTypeGetErc20ContractBalance(addrDesc, c.Contract)
if err != nil {
// return nil, nil, nil, errors.Annotatef(err, "EthereumTypeGetErc20ContractBalance %v %v", addrDesc, c.Contract)
glog.Warningf("EthereumTypeGetErc20ContractBalance addr %v, contract %v, %v", addrDesc, c.Contract, err)
}
} else {
b = nil
}
tokens[j] = Token{
Type: ERC20TokenType,
BalanceSat: (*Amount)(b),
Contract: ci.Contract,
Name: ci.Name,
Symbol: ci.Symbol,
Transfers: int(c.Txs),
Decimals: ci.Decimals,
ContractIndex: strconv.Itoa(i + 1),
}
tokens[j] = *t
j++
}
// special handling if filter has contract
// if the address has no transactions with given contract, check the balance, the address may have some balance even without transactions
if len(filterDesc) > 0 && j == 0 && details >= AccountDetailsTokens {
t, err := w.getEthereumToken(0, addrDesc, filterDesc, details, 0)
if err != nil {
return nil, nil, nil, 0, 0, 0, err
}
tokens = []Token{*t}
// switch off query for transactions, there are no transactions
filter.Vout = AddressFilterVoutQueryNotNecessary
} else {
tokens = tokens[:j]
}
tokens = tokens[:j]
}
ci, err = w.chain.EthereumTypeGetErc20ContractInfo(addrDesc)
if err != nil {
@ -730,8 +593,6 @@ func (w *Worker) getEthereumTypeAddressBalances(addrDesc bchain.AddressDescripto
totalResults = int(ca.NonContractTxs)
} else if filter.Vout > 0 && filter.Vout-1 < len(ca.Contracts) {
totalResults = int(ca.Contracts[filter.Vout-1].Txs)
} else if filter.Vout == AddressFilterVoutQueryNotNecessary {
totalResults = 0
}
}
nonContractTxs = int(ca.NonContractTxs)
@ -742,16 +603,6 @@ func (w *Worker) getEthereumTypeAddressBalances(addrDesc bchain.AddressDescripto
BalanceSat: *b,
}
}
// special handling if filtering for a contract, check the ballance of it
if len(filterDesc) > 0 && details >= AccountDetailsTokens {
t, err := w.getEthereumToken(0, addrDesc, filterDesc, details, 0)
if err != nil {
return nil, nil, nil, 0, 0, 0, err
}
tokens = []Token{*t}
// switch off query for transactions, there are no transactions
filter.Vout = AddressFilterVoutQueryNotNecessary
}
}
return ba, tokens, ci, n, nonContractTxs, totalResults, nil
}
@ -768,7 +619,7 @@ func (w *Worker) txFromTxid(txid string, bestheight uint32, option AccountDetail
if ta == nil {
glog.Warning("DB inconsistency: tx ", txid, ": not found in txAddresses")
// as fallback, get tx from backend
tx, err = w.GetTransaction(txid, false, false)
tx, err = w.GetTransaction(txid, false, true)
if err != nil {
return nil, errors.Annotatef(err, "GetTransaction %v", txid)
}
@ -787,7 +638,7 @@ func (w *Worker) txFromTxid(txid string, bestheight uint32, option AccountDetail
tx = w.txFromTxAddress(txid, ta, blockInfo, bestheight)
}
} else {
tx, err = w.GetTransaction(txid, false, false)
tx, err = w.GetTransaction(txid, false, true)
if err != nil {
return nil, errors.Annotatef(err, "GetTransaction %v", txid)
}
@ -876,7 +727,7 @@ func (w *Worker) GetAddress(address string, page int, txsOnPage int, option Acco
return nil, errors.Annotatef(err, "getAddressTxids %v true", addrDesc)
}
for _, txid := range txm {
tx, err := w.GetTransaction(txid, false, true)
tx, err := w.GetTransaction(txid, false, false)
// mempool transaction may fail
if err != nil || tx == nil {
glog.Warning("GetTransaction in mempool: ", err)
@ -885,12 +736,7 @@ func (w *Worker) GetAddress(address string, page int, txsOnPage int, option Acco
if tx.Confirmations == 0 {
unconfirmedTxs++
uBalSat.Add(&uBalSat, tx.getAddrVoutValue(addrDesc))
// ethereum has a different logic - value not in input and add maximum possible fees
if w.chainType == bchain.ChainEthereumType {
uBalSat.Sub(&uBalSat, tx.getAddrEthereumTypeMempoolInputValue(addrDesc))
} else {
uBalSat.Sub(&uBalSat, tx.getAddrVinValue(addrDesc))
}
uBalSat.Sub(&uBalSat, tx.getAddrVinValue(addrDesc))
if page == 0 {
if option == AccountDetailsTxidHistory {
txids = append(txids, tx.Txid)
@ -903,7 +749,7 @@ func (w *Worker) GetAddress(address string, page int, txsOnPage int, option Acco
}
}
// get tx history if requested by option or check mempool if there are some transactions for a new address
if option >= AccountDetailsTxidHistory && filter.Vout != AddressFilterVoutQueryNotNecessary {
if option >= AccountDetailsTxidHistory {
txc, err := w.getAddressTxids(addrDesc, false, filter, (page+1)*txsOnPage)
if err != nil {
return nil, errors.Annotatef(err, "getAddressTxids %v false", addrDesc)
@ -974,7 +820,7 @@ func (w *Worker) balanceHistoryHeightsFromTo(fromTimestamp, toTimestamp int64) (
return fromUnix, fromHeight, toUnix, toHeight
}
func (w *Worker) balanceHistoryForTxid(addrDesc bchain.AddressDescriptor, txid string, fromUnix, toUnix uint32, selfAddrDesc map[string]struct{}) (*BalanceHistory, error) {
func (w *Worker) balanceHistoryForTxid(addrDesc bchain.AddressDescriptor, txid string, fromUnix, toUnix uint32) (*BalanceHistory, error) {
var time uint32
var err error
var ta *db.TxAddresses
@ -1007,30 +853,17 @@ func (w *Worker) balanceHistoryForTxid(addrDesc bchain.AddressDescriptor, txid s
return nil, nil
}
bh := BalanceHistory{
Time: time,
Txs: 1,
ReceivedSat: &Amount{},
SentSat: &Amount{},
SentToSelfSat: &Amount{},
Txid: txid,
Time: time,
Txs: 1,
SentSat: &Amount{},
ReceivedSat: &Amount{},
Txid: txid,
}
countSentToSelf := false
if w.chainType == bchain.ChainBitcoinType {
// detect if this input is the first of selfAddrDesc
// to not to count sentToSelf multiple times if counting multiple xpub addresses
ownInputIndex := -1
for i := range ta.Inputs {
tai := &ta.Inputs[i]
if _, found := selfAddrDesc[string(tai.AddrDesc)]; found {
if ownInputIndex < 0 {
ownInputIndex = i
}
}
if bytes.Equal(addrDesc, tai.AddrDesc) {
(*big.Int)(bh.SentSat).Add((*big.Int)(bh.SentSat), &tai.ValueSat)
if ownInputIndex == i {
countSentToSelf = true
}
}
}
for i := range ta.Outputs {
@ -1038,17 +871,12 @@ func (w *Worker) balanceHistoryForTxid(addrDesc bchain.AddressDescriptor, txid s
if bytes.Equal(addrDesc, tao.AddrDesc) {
(*big.Int)(bh.ReceivedSat).Add((*big.Int)(bh.ReceivedSat), &tao.ValueSat)
}
if countSentToSelf {
if _, found := selfAddrDesc[string(tao.AddrDesc)]; found {
(*big.Int)(bh.SentToSelfSat).Add((*big.Int)(bh.SentToSelfSat), &tao.ValueSat)
}
}
}
} else if w.chainType == bchain.ChainEthereumType {
var value big.Int
ethTxData := eth.GetEthereumTxData(bchainTx)
// add received amount only for OK or unknown status (old) transactions
if ethTxData.Status == eth.TxStatusOK || ethTxData.Status == eth.TxStatusUnknown {
// add received amount only for OK transactions
if ethTxData.Status == 1 {
if len(bchainTx.Vout) > 0 {
bchainVout := &bchainTx.Vout[0]
value = bchainVout.ValueSat
@ -1060,9 +888,6 @@ func (w *Worker) balanceHistoryForTxid(addrDesc bchain.AddressDescriptor, txid s
if bytes.Equal(addrDesc, txAddrDesc) {
(*big.Int)(bh.ReceivedSat).Add((*big.Int)(bh.ReceivedSat), &value)
}
if _, found := selfAddrDesc[string(txAddrDesc)]; found {
countSentToSelf = true
}
}
}
}
@ -1074,14 +899,9 @@ func (w *Worker) balanceHistoryForTxid(addrDesc bchain.AddressDescriptor, txid s
return nil, err
}
if bytes.Equal(addrDesc, txAddrDesc) {
// add received amount only for OK or unknown status (old) transactions, fees always
if ethTxData.Status == eth.TxStatusOK || ethTxData.Status == eth.TxStatusUnknown {
// add sent amount only for OK transactions, however fees always
if ethTxData.Status == 1 {
(*big.Int)(bh.SentSat).Add((*big.Int)(bh.SentSat), &value)
if countSentToSelf {
if _, found := selfAddrDesc[string(txAddrDesc)]; found {
(*big.Int)(bh.SentToSelfSat).Add((*big.Int)(bh.SentToSelfSat), &value)
}
}
}
var feesSat big.Int
// mempool txs do not have fees yet
@ -1142,9 +962,8 @@ func (w *Worker) GetBalanceHistory(address string, fromTimestamp, toTimestamp in
if err != nil {
return nil, err
}
selfAddrDesc := map[string]struct{}{string(addrDesc): {}}
for txi := len(txs) - 1; txi >= 0; txi-- {
bh, err := w.balanceHistoryForTxid(addrDesc, txs[txi], fromUnix, toUnix, selfAddrDesc)
bh, err := w.balanceHistoryForTxid(addrDesc, txs[txi], fromUnix, toUnix)
if err != nil {
return nil, err
}
@ -1774,7 +1593,7 @@ func (w *Worker) GetSystemInfo(internal bool) (*SystemInfo, error) {
DbColumns: columnStats,
About: Text.BlockbookAbout,
}
backendInfo := &common.BackendInfo{
backendInfo := &BackendInfo{
BackendError: backendError,
BestBlockHash: ci.Bestblockhash,
Blocks: ci.Blocks,
@ -1787,9 +1606,7 @@ func (w *Worker) GetSystemInfo(internal bool) (*SystemInfo, error) {
Timeoffset: ci.Timeoffset,
Version: ci.Version,
Warnings: ci.Warnings,
Consensus: ci.Consensus,
}
w.is.SetBackendInfo(backendInfo)
glog.Info("GetSystemInfo finished in ", time.Since(start))
return &SystemInfo{blockbookInfo, backendInfo}, nil
}

View File

@ -1,6 +1,8 @@
package api
import (
"blockbook/bchain"
"blockbook/db"
"fmt"
"math/big"
"sort"
@ -9,8 +11,6 @@ import (
"github.com/golang/glog"
"github.com/juju/errors"
"spacecruft.org/spacecruft/blockbook/bchain"
"spacecruft.org/spacecruft/blockbook/db"
)
const defaultAddressesGap = 20
@ -416,7 +416,7 @@ func (w *Worker) GetXpubAddress(xpub string, page int, txsOnPage int, option Acc
// the same tx can have multiple addresses from the same xpub, get it from backend it only once
tx, foundTx := txmMap[txid.txid]
if !foundTx {
tx, err = w.GetTransaction(txid.txid, false, true)
tx, err = w.GetTransaction(txid.txid, false, false)
// mempool transaction may fail
if err != nil || tx == nil {
glog.Warning("GetTransaction in mempool: ", err)
@ -606,18 +606,12 @@ func (w *Worker) GetXpubBalanceHistory(xpub string, fromTimestamp, toTimestamp i
if err != nil {
return nil, err
}
selfAddrDesc := make(map[string]struct{})
for _, da := range [][]xpubAddress{data.addresses, data.changeAddresses} {
for i := range da {
selfAddrDesc[string(da[i].addrDesc)] = struct{}{}
}
}
for _, da := range [][]xpubAddress{data.addresses, data.changeAddresses} {
for i := range da {
ad := &da[i]
txids := ad.txids
for txi := len(txids) - 1; txi >= 0; txi-- {
bh, err := w.balanceHistoryForTxid(ad.addrDesc, txids[txi].txid, fromUnix, toUnix, selfAddrDesc)
bh, err := w.balanceHistoryForTxid(ad.addrDesc, txids[txi].txid, fromUnix, toUnix)
if err != nil {
return nil, err
}

View File

@ -3,7 +3,6 @@ package bchain
import (
"sort"
"sync"
"time"
)
type addrIndex struct {
@ -28,7 +27,6 @@ type BaseMempool struct {
txEntries map[string]txEntry
addrDescToTx map[string][]Outpoint
OnNewTxAddr OnNewTxAddrFunc
OnNewTx OnNewTxFunc
}
// GetTransactions returns slice of mempool transactions for given address
@ -115,22 +113,3 @@ func (m *BaseMempool) GetTransactionTime(txid string) uint32 {
}
return e.time
}
func (m *BaseMempool) txToMempoolTx(tx *Tx) *MempoolTx {
mtx := MempoolTx{
Hex: tx.Hex,
Blocktime: time.Now().Unix(),
LockTime: tx.LockTime,
Txid: tx.Txid,
Version: tx.Version,
Vout: tx.Vout,
CoinSpecificData: tx.CoinSpecificData,
}
mtx.Vin = make([]MempoolVin, len(tx.Vin))
for i, vin := range tx.Vin {
mtx.Vin[i] = MempoolVin{
Vin: vin,
}
}
return &mtx
}

View File

@ -9,7 +9,6 @@ import (
"github.com/gogo/protobuf/proto"
"github.com/golang/glog"
"github.com/juju/errors"
"spacecruft.org/spacecruft/blockbook/common"
)
// BaseParser implements data parsing/handling functionality base for all other parsers
@ -40,9 +39,9 @@ func (p *BaseParser) GetAddrDescForUnknownInput(tx *Tx, input int) AddressDescri
const zeros = "0000000000000000000000000000000000000000"
// AmountToBigInt converts amount in common.JSONNumber (string) to big.Int
// AmountToBigInt converts amount in json.Number (string) to big.Int
// it uses string operations to avoid problems with rounding
func (p *BaseParser) AmountToBigInt(n common.JSONNumber) (big.Int, error) {
func (p *BaseParser) AmountToBigInt(n json.Number) (big.Int, error) {
var r big.Int
s := string(n)
i := strings.IndexByte(s, '.')

View File

@ -1,12 +1,9 @@
// +build unittest
package bchain
import (
"encoding/json"
"math/big"
"testing"
"spacecruft.org/spacecruft/blockbook/common"
)
func NewBaseParser(adp int) *BaseParser {
@ -47,7 +44,7 @@ func TestBaseParser_AmountToDecimalString(t *testing.T) {
func TestBaseParser_AmountToBigInt(t *testing.T) {
for _, tt := range amounts {
t.Run(tt.s, func(t *testing.T) {
got, err := NewBaseParser(tt.adp).AmountToBigInt(common.JSONNumber(tt.s))
got, err := NewBaseParser(tt.adp).AmountToBigInt(json.Number(tt.s))
if err != nil {
t.Errorf("BaseParser.AmountToBigInt() error = %v", err)
return

View File

@ -1,6 +1,8 @@
package bch
import (
"blockbook/bchain"
"blockbook/bchain/coins/btc"
"fmt"
"github.com/martinboehm/bchutil"
@ -8,8 +10,6 @@ import (
"github.com/martinboehm/btcutil/chaincfg"
"github.com/martinboehm/btcutil/txscript"
"github.com/schancel/cashaddr-converter/address"
"spacecruft.org/spacecruft/blockbook/bchain"
"spacecruft.org/spacecruft/blockbook/bchain/coins/btc"
)
// AddressFormat type is used to specify different formats of address

View File

@ -3,6 +3,8 @@
package bch
import (
"blockbook/bchain"
"blockbook/bchain/coins/btc"
"encoding/hex"
"math/big"
"os"
@ -10,8 +12,6 @@ import (
"testing"
"github.com/martinboehm/btcutil/chaincfg"
"spacecruft.org/spacecruft/blockbook/bchain"
"spacecruft.org/spacecruft/blockbook/bchain/coins/btc"
)
func TestMain(m *testing.M) {

View File

@ -1,6 +1,8 @@
package bch
import (
"blockbook/bchain"
"blockbook/bchain/coins/btc"
"encoding/hex"
"encoding/json"
"math/big"
@ -8,8 +10,6 @@ import (
"github.com/golang/glog"
"github.com/juju/errors"
"github.com/martinboehm/bchutil"
"spacecruft.org/spacecruft/blockbook/bchain"
"spacecruft.org/spacecruft/blockbook/bchain/coins/btc"
)
// BCashRPC is an interface to JSON-RPC bitcoind service.

View File

@ -1,9 +1,10 @@
package bellcoin
import (
"blockbook/bchain/coins/btc"
"github.com/martinboehm/btcd/wire"
"github.com/martinboehm/btcutil/chaincfg"
"spacecruft.org/spacecruft/blockbook/bchain/coins/btc"
)
// magic numbers

View File

@ -3,6 +3,8 @@
package bellcoin
import (
"blockbook/bchain"
"blockbook/bchain/coins/btc"
"encoding/hex"
"math/big"
"os"
@ -10,8 +12,6 @@ import (
"testing"
"github.com/martinboehm/btcutil/chaincfg"
"spacecruft.org/spacecruft/blockbook/bchain"
"spacecruft.org/spacecruft/blockbook/bchain/coins/btc"
)
func TestMain(m *testing.M) {

View File

@ -1,11 +1,11 @@
package bellcoin
import (
"blockbook/bchain"
"blockbook/bchain/coins/btc"
"encoding/json"
"github.com/golang/glog"
"spacecruft.org/spacecruft/blockbook/bchain"
"spacecruft.org/spacecruft/blockbook/bchain/coins/btc"
)
// BellcoinRPC is an interface to JSON-RPC bitcoind service.

View File

@ -1,10 +1,10 @@
package bitcore
import (
"blockbook/bchain"
"blockbook/bchain/coins/btc"
"github.com/martinboehm/btcd/wire"
"github.com/martinboehm/btcutil/chaincfg"
"spacecruft.org/spacecruft/blockbook/bchain"
"spacecruft.org/spacecruft/blockbook/bchain/coins/btc"
)
const (

View File

@ -3,15 +3,14 @@
package bitcore
import (
"blockbook/bchain"
"blockbook/bchain/coins/btc"
"encoding/hex"
"github.com/martinboehm/btcutil/chaincfg"
"math/big"
"os"
"reflect"
"testing"
"github.com/martinboehm/btcutil/chaincfg"
"spacecruft.org/spacecruft/blockbook/bchain"
"spacecruft.org/spacecruft/blockbook/bchain/coins/btc"
)
func TestMain(m *testing.M) {

View File

@ -1,12 +1,11 @@
package bitcore
import (
"blockbook/bchain"
"blockbook/bchain/coins/btc"
"encoding/json"
"github.com/golang/glog"
"github.com/juju/errors"
"spacecruft.org/spacecruft/blockbook/bchain"
"spacecruft.org/spacecruft/blockbook/bchain/coins/btc"
)
// BitcoreRPC is an interface to JSON-RPC bitcoind service.

View File

@ -1,64 +0,0 @@
package bitzeny
import (
"spacecruft.org/spacecruft/blockbook/bchain/coins/btc"
"github.com/martinboehm/btcd/wire"
"github.com/martinboehm/btcutil/chaincfg"
)
// magic numbers
const (
MainnetMagic wire.BitcoinNet = 0xf9bea5da
TestnetMagic wire.BitcoinNet = 0x594e4559
)
// chain parameters
var (
MainNetParams chaincfg.Params
TestNetParams chaincfg.Params
)
func init() {
MainNetParams = chaincfg.MainNetParams
MainNetParams.Net = MainnetMagic
MainNetParams.PubKeyHashAddrID = []byte{81}
MainNetParams.ScriptHashAddrID = []byte{5}
MainNetParams.Bech32HRPSegwit = "bz"
TestNetParams = chaincfg.TestNet3Params
TestNetParams.Net = TestnetMagic
TestNetParams.PubKeyHashAddrID = []byte{111}
TestNetParams.ScriptHashAddrID = []byte{196}
TestNetParams.Bech32HRPSegwit = "tz"
}
// BitZenyParser handle
type BitZenyParser struct {
*btc.BitcoinParser
}
// NewBitZenyParser returns new BitZenyParser instance
func NewBitZenyParser(params *chaincfg.Params, c *btc.Configuration) *BitZenyParser {
return &BitZenyParser{BitcoinParser: btc.NewBitcoinParser(params, c)}
}
// GetChainParams contains network parameters for the main BitZeny network,
// and the test BitZeny network
func GetChainParams(chain string) *chaincfg.Params {
if !chaincfg.IsRegistered(&MainNetParams) {
err := chaincfg.Register(&MainNetParams)
if err == nil {
err = chaincfg.Register(&TestNetParams)
}
if err != nil {
panic(err)
}
}
switch chain {
case "test":
return &TestNetParams
default:
return &MainNetParams
}
}

View File

@ -1,290 +0,0 @@
// +build unittest
package bitzeny
import (
"encoding/hex"
"math/big"
"os"
"reflect"
"testing"
"spacecruft.org/spacecruft/blockbook/bchain"
"spacecruft.org/spacecruft/blockbook/bchain/coins/btc"
"github.com/martinboehm/btcutil/chaincfg"
)
func TestMain(m *testing.M) {
c := m.Run()
chaincfg.ResetParams()
os.Exit(c)
}
func Test_GetAddrDescFromAddress_Mainnet(t *testing.T) {
type args struct {
address string
}
tests := []struct {
name string
args args
want string
wantErr bool
}{
{
name: "P2PKH1",
args: args{address: "Zw74N1RSU2xV3a7SBERBiCP11fMwX5yvMu"},
want: "76a914d8658ca5c406149071687d370d1d22d972d2f88488ac",
wantErr: false,
},
{
name: "P2PKH2",
args: args{address: "ZiSn1vTSxGu2kFcnkjjm7bYGhT5BVAVfEG"},
want: "76a9144d869697281ad18370313122795e56dfdc3a331388ac",
wantErr: false,
},
{
name: "P2SH1",
args: args{address: "3CZ3357bm1K81StpEDQtEH3ho3ULx19nc8"},
want: "a9147726fc1144eae1b7bd301d87d0a7f846cadb591887",
wantErr: false,
},
{
name: "P2SH2",
args: args{address: "3M1AjZEuBzScbd9pchiGJSVT4yNfwzSmXP"},
want: "a914d3d93b5d7f57b94a4fecde93d4489f2b423fd3c287",
wantErr: false,
},
{
name: "witness_v0_keyhash",
args: args{address: "bz1q7rfrdacyyfwx8gppd8ah9hka8npgqsm44prfnd"},
want: "0014f0d236f704225c63a02169fb72dedd3cc2804375",
wantErr: false,
},
{
name: "witness_v0_scripthashx",
args: args{address: "bz1qd2mspe6m2wpztw4q2mccyvyess6569eu59sfvf0u0vdmdwltr5lse8d7sw"},
want: "00206ab700e75b538225baa056f182309984354d173ca1609625fc7b1bb6bbeb1d3f",
wantErr: false,
},
}
parser := NewBitZenyParser(GetChainParams("main"), &btc.Configuration{})
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
got, err := parser.GetAddrDescFromAddress(tt.args.address)
if (err != nil) != tt.wantErr {
t.Errorf("GetAddrDescFromAddress() error = %v, wantErr %v", err, tt.wantErr)
return
}
h := hex.EncodeToString(got)
if !reflect.DeepEqual(h, tt.want) {
t.Errorf("GetAddrDescFromAddress() = %v, want %v", h, tt.want)
}
})
}
}
func Test_GetAddressesFromAddrDesc(t *testing.T) {
type args struct {
script string
}
tests := []struct {
name string
args args
want []string
want2 bool
wantErr bool
}{
{
name: "P2PKH",
args: args{script: "76a914d8658ca5c406149071687d370d1d22d972d2f88488ac"},
want: []string{"Zw74N1RSU2xV3a7SBERBiCP11fMwX5yvMu"},
want2: true,
wantErr: false,
},
{
name: "P2SH",
args: args{script: "a9147726fc1144eae1b7bd301d87d0a7f846cadb591887"},
want: []string{"3CZ3357bm1K81StpEDQtEH3ho3ULx19nc8"},
want2: true,
wantErr: false,
},
{
name: "P2WPKH",
args: args{script: "0014f0d236f704225c63a02169fb72dedd3cc2804375"},
want: []string{"bz1q7rfrdacyyfwx8gppd8ah9hka8npgqsm44prfnd"},
want2: true,
wantErr: false,
},
{
name: "P2WSH",
args: args{script: "00206ab700e75b538225baa056f182309984354d173ca1609625fc7b1bb6bbeb1d3f"},
want: []string{"bz1qd2mspe6m2wpztw4q2mccyvyess6569eu59sfvf0u0vdmdwltr5lse8d7sw"},
want2: true,
wantErr: false,
},
{
name: "OP_RETURN ascii",
args: args{script: "6a0461686f6a"},
want: []string{"OP_RETURN (ahoj)"},
want2: false,
wantErr: false,
},
{
name: "OP_RETURN hex",
args: args{script: "6a072020f1686f6a20"},
want: []string{"OP_RETURN 2020f1686f6a20"},
want2: false,
wantErr: false,
},
}
parser := NewBitZenyParser(GetChainParams("main"), &btc.Configuration{})
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
b, _ := hex.DecodeString(tt.args.script)
got, got2, err := parser.GetAddressesFromAddrDesc(b)
if (err != nil) != tt.wantErr {
t.Errorf("outputScriptToAddresses() error = %v, wantErr %v", err, tt.wantErr)
return
}
if !reflect.DeepEqual(got, tt.want) {
t.Errorf("GetAddressesFromAddrDesc() = %v, want %v", got, tt.want)
}
if !reflect.DeepEqual(got2, tt.want2) {
t.Errorf("GetAddressesFromAddrDesc() = %v, want %v", got2, tt.want2)
}
})
}
}
var (
testTx1 bchain.Tx
testTxPacked1 = "001c3f1a8be6859d3e0100000001aef422fb91cd91e556966fed4121ac44017a761d71385596536bb447ae05213e000000006a47304402202341ac4297925257dc72eb418a069c45e76f7070340e27501f6308cc7eff45f802204a347915adceff5f6fc9b8075d95d47887d46b344c7bbc8066d315931b189ad001210228c2520812b7f8c63e7a088c61b6348b22fa0c98812e736a1fd896bc828d3c65feffffff028041f13d000000001976a91478379ea136bb5783b675cd11e412bf0703995aeb88aca9983141000000001976a9144d869697281ad18370313122795e56dfdc3a331388ac193f1c00"
)
func init() {
testTx1 = bchain.Tx{
Hex: "0100000001aef422fb91cd91e556966fed4121ac44017a761d71385596536bb447ae05213e000000006a47304402202341ac4297925257dc72eb418a069c45e76f7070340e27501f6308cc7eff45f802204a347915adceff5f6fc9b8075d95d47887d46b344c7bbc8066d315931b189ad001210228c2520812b7f8c63e7a088c61b6348b22fa0c98812e736a1fd896bc828d3c65feffffff028041f13d000000001976a91478379ea136bb5783b675cd11e412bf0703995aeb88aca9983141000000001976a9144d869697281ad18370313122795e56dfdc3a331388ac193f1c00",
Blocktime: 1583392607,
Txid: "f81c34b300961877328c3aaa7cd5e69068457868309fbf1e92544e3a6a915bcb",
LockTime: 1851161,
Version: 1,
Vin: []bchain.Vin{
{
ScriptSig: bchain.ScriptSig{
Hex: "47304402202341ac4297925257dc72eb418a069c45e76f7070340e27501f6308cc7eff45f802204a347915adceff5f6fc9b8075d95d47887d46b344c7bbc8066d315931b189ad001210228c2520812b7f8c63e7a088c61b6348b22fa0c98812e736a1fd896bc828d3c65",
},
Txid: "3e2105ae47b46b53965538711d767a0144ac2141ed6f9656e591cd91fb22f4ae",
Vout: 0,
Sequence: 4294967294,
},
},
Vout: []bchain.Vout{
{
ValueSat: *big.NewInt(1039221120),
N: 0,
ScriptPubKey: bchain.ScriptPubKey{
Hex: "76a91478379ea136bb5783b675cd11e412bf0703995aeb88ac",
Addresses: []string{
"ZnLWULVbAzjy1TSKxGnpkomeeaEDTHk5Nj",
},
},
},
{
ValueSat: *big.NewInt(1093769385),
N: 1,
ScriptPubKey: bchain.ScriptPubKey{
Hex: "76a9144d869697281ad18370313122795e56dfdc3a331388ac",
Addresses: []string{
"ZiSn1vTSxGu2kFcnkjjm7bYGhT5BVAVfEG",
},
},
},
},
}
}
func Test_PackTx(t *testing.T) {
type args struct {
tx bchain.Tx
height uint32
blockTime int64
parser *BitZenyParser
}
tests := []struct {
name string
args args
want string
wantErr bool
}{
{
name: "BitZeny-1",
args: args{
tx: testTx1,
height: 1851162,
blockTime: 1583392607,
parser: NewBitZenyParser(GetChainParams("main"), &btc.Configuration{}),
},
want: testTxPacked1,
wantErr: false,
},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
got, err := tt.args.parser.PackTx(&tt.args.tx, tt.args.height, tt.args.blockTime)
if (err != nil) != tt.wantErr {
t.Errorf("packTx() error = %v, wantErr %v", err, tt.wantErr)
return
}
h := hex.EncodeToString(got)
if !reflect.DeepEqual(h, tt.want) {
t.Errorf("packTx() = %v, want %v", h, tt.want)
}
})
}
}
func Test_UnpackTx(t *testing.T) {
type args struct {
packedTx string
parser *BitZenyParser
}
tests := []struct {
name string
args args
want *bchain.Tx
want1 uint32
wantErr bool
}{
{
name: "BitZeny-1",
args: args{
packedTx: testTxPacked1,
parser: NewBitZenyParser(GetChainParams("main"), &btc.Configuration{}),
},
want: &testTx1,
want1: 1851162,
wantErr: false,
},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
b, _ := hex.DecodeString(tt.args.packedTx)
got, got1, err := tt.args.parser.UnpackTx(b)
if (err != nil) != tt.wantErr {
t.Errorf("unpackTx() error = %v, wantErr %v", err, tt.wantErr)
return
}
if !reflect.DeepEqual(got, tt.want) {
t.Errorf("unpackTx() got = %v, want %v", got, tt.want)
}
if got1 != tt.want1 {
t.Errorf("unpackTx() got1 = %v, want %v", got1, tt.want1)
}
})
}
}

View File

@ -1,59 +0,0 @@
package bitzeny
import (
"encoding/json"
"spacecruft.org/spacecruft/blockbook/bchain"
"spacecruft.org/spacecruft/blockbook/bchain/coins/btc"
"github.com/golang/glog"
)
// BitZenyRPC is an interface to JSON-RPC bitcoind service.
type BitZenyRPC struct {
*btc.BitcoinRPC
}
// NewBitZenyRPC returns new BitZenyRPC instance.
func NewBitZenyRPC(config json.RawMessage, pushHandler func(bchain.NotificationType)) (bchain.BlockChain, error) {
b, err := btc.NewBitcoinRPC(config, pushHandler)
if err != nil {
return nil, err
}
s := &BitZenyRPC{
b.(*btc.BitcoinRPC),
}
s.RPCMarshaler = btc.JSONMarshalerV2{}
s.ChainConfig.SupportsEstimateFee = false
return s, nil
}
// Initialize initializes BitZenyRPC instance.
func (b *BitZenyRPC) Initialize() error {
ci, err := b.GetChainInfo()
if err != nil {
return err
}
chainName := ci.Chain
glog.Info("Chain name ", chainName)
params := GetChainParams(chainName)
// always create parser
b.Parser = NewBitZenyParser(params, b.ChainConfig)
// parameters for getInfo request
if params.Net == MainnetMagic {
b.Testnet = false
b.Network = "livenet"
} else {
b.Testnet = true
b.Network = "testnet"
}
glog.Info("rpc: block chain ", params.Name)
return nil
}

View File

@ -1,6 +1,44 @@
package coins
import (
"blockbook/bchain"
"blockbook/bchain/coins/bch"
"blockbook/bchain/coins/bellcoin"
"blockbook/bchain/coins/bitcore"
"blockbook/bchain/coins/btc"
"blockbook/bchain/coins/btg"
"blockbook/bchain/coins/cpuchain"
"blockbook/bchain/coins/dash"
"blockbook/bchain/coins/dcr"
"blockbook/bchain/coins/deeponion"
"blockbook/bchain/coins/digibyte"
"blockbook/bchain/coins/divi"
"blockbook/bchain/coins/dogecoin"
"blockbook/bchain/coins/eth"
"blockbook/bchain/coins/flo"
"blockbook/bchain/coins/fujicoin"
"blockbook/bchain/coins/gamecredits"
"blockbook/bchain/coins/grs"
"blockbook/bchain/coins/koto"
"blockbook/bchain/coins/liquid"
"blockbook/bchain/coins/litecoin"
"blockbook/bchain/coins/monacoin"
"blockbook/bchain/coins/monetaryunit"
"blockbook/bchain/coins/myriad"
"blockbook/bchain/coins/namecoin"
"blockbook/bchain/coins/nuls"
"blockbook/bchain/coins/pivx"
"blockbook/bchain/coins/polis"
"blockbook/bchain/coins/qtum"
"blockbook/bchain/coins/ravencoin"
"blockbook/bchain/coins/ritocoin"
"blockbook/bchain/coins/unobtanium"
"blockbook/bchain/coins/vertcoin"
"blockbook/bchain/coins/viacoin"
"blockbook/bchain/coins/vipstarcoin"
"blockbook/bchain/coins/xzc"
"blockbook/bchain/coins/zec"
"blockbook/common"
"context"
"encoding/json"
"fmt"
@ -10,48 +48,6 @@ import (
"time"
"github.com/juju/errors"
"spacecruft.org/spacecruft/blockbook/bchain"
"spacecruft.org/spacecruft/blockbook/bchain/coins/bch"
"spacecruft.org/spacecruft/blockbook/bchain/coins/bellcoin"
"spacecruft.org/spacecruft/blockbook/bchain/coins/bitcore"
"spacecruft.org/spacecruft/blockbook/bchain/coins/bitzeny"
"spacecruft.org/spacecruft/blockbook/bchain/coins/btc"
"spacecruft.org/spacecruft/blockbook/bchain/coins/btg"
"spacecruft.org/spacecruft/blockbook/bchain/coins/cpuchain"
"spacecruft.org/spacecruft/blockbook/bchain/coins/dash"
"spacecruft.org/spacecruft/blockbook/bchain/coins/dcr"
"spacecruft.org/spacecruft/blockbook/bchain/coins/deeponion"
"spacecruft.org/spacecruft/blockbook/bchain/coins/digibyte"
"spacecruft.org/spacecruft/blockbook/bchain/coins/divi"
"spacecruft.org/spacecruft/blockbook/bchain/coins/dogecoin"
"spacecruft.org/spacecruft/blockbook/bchain/coins/eth"
"spacecruft.org/spacecruft/blockbook/bchain/coins/firo"
"spacecruft.org/spacecruft/blockbook/bchain/coins/flo"
"spacecruft.org/spacecruft/blockbook/bchain/coins/fujicoin"
"spacecruft.org/spacecruft/blockbook/bchain/coins/gamecredits"
"spacecruft.org/spacecruft/blockbook/bchain/coins/grs"
"spacecruft.org/spacecruft/blockbook/bchain/coins/koto"
"spacecruft.org/spacecruft/blockbook/bchain/coins/liquid"
"spacecruft.org/spacecruft/blockbook/bchain/coins/litecoin"
"spacecruft.org/spacecruft/blockbook/bchain/coins/monacoin"
"spacecruft.org/spacecruft/blockbook/bchain/coins/monetaryunit"
"spacecruft.org/spacecruft/blockbook/bchain/coins/myriad"
"spacecruft.org/spacecruft/blockbook/bchain/coins/namecoin"
"spacecruft.org/spacecruft/blockbook/bchain/coins/nuls"
"spacecruft.org/spacecruft/blockbook/bchain/coins/omotenashicoin"
"spacecruft.org/spacecruft/blockbook/bchain/coins/pivx"
"spacecruft.org/spacecruft/blockbook/bchain/coins/polis"
"spacecruft.org/spacecruft/blockbook/bchain/coins/qtum"
"spacecruft.org/spacecruft/blockbook/bchain/coins/ravencoin"
"spacecruft.org/spacecruft/blockbook/bchain/coins/ritocoin"
"spacecruft.org/spacecruft/blockbook/bchain/coins/snowgem"
"spacecruft.org/spacecruft/blockbook/bchain/coins/trezarcoin"
"spacecruft.org/spacecruft/blockbook/bchain/coins/unobtanium"
"spacecruft.org/spacecruft/blockbook/bchain/coins/vertcoin"
"spacecruft.org/spacecruft/blockbook/bchain/coins/viacoin"
"spacecruft.org/spacecruft/blockbook/bchain/coins/vipstarcoin"
"spacecruft.org/spacecruft/blockbook/bchain/coins/zec"
"spacecruft.org/spacecruft/blockbook/common"
)
type blockChainFactory func(config json.RawMessage, pushHandler func(bchain.NotificationType)) (bchain.BlockChain, error)
@ -62,17 +58,14 @@ var BlockChainFactories = make(map[string]blockChainFactory)
func init() {
BlockChainFactories["Bitcoin"] = btc.NewBitcoinRPC
BlockChainFactories["Testnet"] = btc.NewBitcoinRPC
BlockChainFactories["Signet"] = btc.NewBitcoinRPC
BlockChainFactories["Zcash"] = zec.NewZCashRPC
BlockChainFactories["Zcash Testnet"] = zec.NewZCashRPC
BlockChainFactories["Ethereum"] = eth.NewEthereumRPC
BlockChainFactories["Ethereum Classic"] = eth.NewEthereumRPC
BlockChainFactories["Ethereum Testnet Ropsten"] = eth.NewEthereumRPC
BlockChainFactories["Ethereum Testnet Goerli"] = eth.NewEthereumRPC
BlockChainFactories["Bcash"] = bch.NewBCashRPC
BlockChainFactories["Bcash Testnet"] = bch.NewBCashRPC
BlockChainFactories["Bgold"] = btg.NewBGoldRPC
BlockChainFactories["Bgold Testnet"] = btg.NewBGoldRPC
BlockChainFactories["Dash"] = dash.NewDashRPC
BlockChainFactories["Dash Testnet"] = dash.NewDashRPC
BlockChainFactories["Decred"] = dcr.NewDecredRPC
@ -90,7 +83,6 @@ func init() {
BlockChainFactories["Monacoin Testnet"] = monacoin.NewMonacoinRPC
BlockChainFactories["MonetaryUnit"] = monetaryunit.NewMonetaryUnitRPC
BlockChainFactories["DigiByte"] = digibyte.NewDigiByteRPC
BlockChainFactories["DigiByte Testnet"] = digibyte.NewDigiByteRPC
BlockChainFactories["Myriad"] = myriad.NewMyriadRPC
BlockChainFactories["Liquid"] = liquid.NewLiquidRPC
BlockChainFactories["Groestlcoin"] = grs.NewGroestlcoinRPC
@ -98,7 +90,7 @@ func init() {
BlockChainFactories["PIVX"] = pivx.NewPivXRPC
BlockChainFactories["PIVX Testnet"] = pivx.NewPivXRPC
BlockChainFactories["Polis"] = polis.NewPolisRPC
BlockChainFactories["Firo"] = firo.NewFiroRPC
BlockChainFactories["Zcoin"] = xzc.NewZcoinRPC
BlockChainFactories["Fujicoin"] = fujicoin.NewFujicoinRPC
BlockChainFactories["Flo"] = flo.NewFloRPC
BlockChainFactories["Bellcoin"] = bellcoin.NewBellcoinRPC
@ -114,12 +106,7 @@ func init() {
BlockChainFactories["CPUchain"] = cpuchain.NewCPUchainRPC
BlockChainFactories["Unobtanium"] = unobtanium.NewUnobtaniumRPC
BlockChainFactories["DeepOnion"] = deeponion.NewDeepOnionRPC
BlockChainFactories["SnowGem"] = snowgem.NewSnowGemRPC
BlockChainFactories["Bitcore"] = bitcore.NewBitcoreRPC
BlockChainFactories["Omotenashicoin"] = omotenashicoin.NewOmotenashiCoinRPC
BlockChainFactories["Omotenashicoin Testnet"] = omotenashicoin.NewOmotenashiCoinRPC
BlockChainFactories["BitZeny"] = bitzeny.NewBitZenyRPC
BlockChainFactories["Trezarcoin"] = trezarcoin.NewTrezarcoinRPC
}
// GetCoinNameFromConfig gets coin name and coin shortcut from config file
@ -191,8 +178,8 @@ func (c *blockChainWithMetrics) CreateMempool(chain bchain.BlockChain) (bchain.M
return c.b.CreateMempool(chain)
}
func (c *blockChainWithMetrics) InitializeMempool(addrDescForOutpoint bchain.AddrDescForOutpointFunc, onNewTxAddr bchain.OnNewTxAddrFunc, onNewTx bchain.OnNewTxFunc) error {
return c.b.InitializeMempool(addrDescForOutpoint, onNewTxAddr, onNewTx)
func (c *blockChainWithMetrics) InitializeMempool(addrDescForOutpoint bchain.AddrDescForOutpointFunc, onNewTxAddr bchain.OnNewTxAddrFunc) error {
return c.b.InitializeMempool(addrDescForOutpoint, onNewTxAddr)
}
func (c *blockChainWithMetrics) Shutdown(ctx context.Context) error {

View File

@ -1,6 +1,7 @@
package btc
import (
"blockbook/bchain"
"bytes"
"encoding/binary"
"encoding/hex"
@ -15,25 +16,8 @@ import (
"github.com/martinboehm/btcutil/chaincfg"
"github.com/martinboehm/btcutil/hdkeychain"
"github.com/martinboehm/btcutil/txscript"
"spacecruft.org/spacecruft/blockbook/bchain"
)
// temp params for signet(wait btcd commit)
// magic numbers
const (
SignetMagic wire.BitcoinNet = 0x6a70c7f0
)
// chain parameters
var (
SigNetParams chaincfg.Params
)
func init() {
SigNetParams = chaincfg.TestNet3Params
SigNetParams.Net = SignetMagic
}
// OutputScriptToAddressesFunc converts ScriptPubKey to bitcoin addresses
type OutputScriptToAddressesFunc func(script []byte) ([]string, bool, error)
@ -79,8 +63,6 @@ func GetChainParams(chain string) *chaincfg.Params {
return &chaincfg.TestNet3Params
case "regtest":
return &chaincfg.RegressionNetParams
case "signet":
return &SigNetParams
}
return &chaincfg.MainNetParams
}

View File

@ -3,6 +3,7 @@
package btc
import (
"blockbook/bchain"
"encoding/hex"
"math/big"
"os"
@ -10,7 +11,6 @@ import (
"testing"
"github.com/martinboehm/btcutil/chaincfg"
"spacecruft.org/spacecruft/blockbook/bchain"
)
func TestMain(m *testing.M) {
@ -259,11 +259,10 @@ func TestGetAddressesFromAddrDesc(t *testing.T) {
}
var (
testTx1, testTx2, testTx3 bchain.Tx
testTx1, testTx2 bchain.Tx
testTxPacked1 = "0001e2408ba8d7af5401000000017f9a22c9cbf54bd902400df746f138f37bcf5b4d93eb755820e974ba43ed5f42040000006a4730440220037f4ed5427cde81d55b9b6a2fd08c8a25090c2c2fff3a75c1a57625ca8a7118022076c702fe55969fa08137f71afd4851c48e31082dd3c40c919c92cdbc826758d30121029f6da5623c9f9b68a9baf9c1bc7511df88fa34c6c2f71f7c62f2f03ff48dca80feffffff019c9700000000000017a9146144d57c8aff48492c9dfb914e120b20bad72d6f8773d00700"
testTxPacked2 = "0007c91a899ab7da6a010000000001019d64f0c72a0d206001decbffaa722eb1044534c74eee7a5df8318e42a4323ec10000000017160014550da1f5d25a9dae2eafd6902b4194c4c6500af6ffffffff02809698000000000017a914cd668d781ece600efa4b2404dc91fd26b8b8aed8870553d7360000000017a914246655bdbd54c7e477d0ea2375e86e0db2b8f80a8702473044022076aba4ad559616905fa51d4ddd357fc1fdb428d40cb388e042cdd1da4a1b7357022011916f90c712ead9a66d5f058252efd280439ad8956a967e95d437d246710bc9012102a80a5964c5612bb769ef73147b2cf3c149bc0fd4ecb02f8097629c94ab013ffd00000000"
testTxPacked3 = "00003d818bfda9aa3e02000000000102deb1999a857ab0a13d6b12fbd95ea75b409edde5f2ff747507ce42d9986a8b9d0000000000fdffffff9fd2d3361e203b2375eba6438efbef5b3075531e7e583c7cc76b7294fe7f22980000000000fdffffff02a0860100000000001600148091746745464e7555c31e9a5afceac14a02978ae7fc1c0000000000160014565ea9ff4589d3e05ba149ae6e257752bfdc2a1e0247304402207d67d320a8e813f986b35e9791935fcb736754812b7038686f5de6cfdcda99cd02201c3bb2c178e0056016437ecfe365a7eef84aa9d293ebdc566177af82e22fcdd3012103abb30c1bbe878b07b58dc169b1d061d48c60be8107f632a59778b38bf7ceea5a02473044022044f54a478cfe086e870cb026c9dcd4e14e63778bef569a4d55a6332725cd9a9802202f0e94c04e6f328fc64ad9efe552888c299750d1b8d033324825a3ff29920e030121036fcd433428aa7dc65c4f5408fa31f208c54fe4b4c6c1ae9c39a825ed4f1ac039813d0000"
)
func init() {
@ -336,54 +335,6 @@ func init() {
},
},
}
testTx3 = bchain.Tx{
Hex: "02000000000102deb1999a857ab0a13d6b12fbd95ea75b409edde5f2ff747507ce42d9986a8b9d0000000000fdffffff9fd2d3361e203b2375eba6438efbef5b3075531e7e583c7cc76b7294fe7f22980000000000fdffffff02a0860100000000001600148091746745464e7555c31e9a5afceac14a02978ae7fc1c0000000000160014565ea9ff4589d3e05ba149ae6e257752bfdc2a1e0247304402207d67d320a8e813f986b35e9791935fcb736754812b7038686f5de6cfdcda99cd02201c3bb2c178e0056016437ecfe365a7eef84aa9d293ebdc566177af82e22fcdd3012103abb30c1bbe878b07b58dc169b1d061d48c60be8107f632a59778b38bf7ceea5a02473044022044f54a478cfe086e870cb026c9dcd4e14e63778bef569a4d55a6332725cd9a9802202f0e94c04e6f328fc64ad9efe552888c299750d1b8d033324825a3ff29920e030121036fcd433428aa7dc65c4f5408fa31f208c54fe4b4c6c1ae9c39a825ed4f1ac039813d0000",
Blocktime: 1607805599,
Txid: "24551a58a1d1fb89d7052e2bbac7cb69a7825ee1e39439befbec8c32148cf735",
LockTime: 15745,
Version: 2,
Vin: []bchain.Vin{
{
ScriptSig: bchain.ScriptSig{
Hex: "",
},
Txid: "9d8b6a98d942ce077574fff2e5dd9e405ba75ed9fb126b3da1b07a859a99b1de",
Vout: 0,
Sequence: 4294967293,
},
{
ScriptSig: bchain.ScriptSig{
Hex: "",
},
Txid: "98227ffe94726bc77c3c587e1e5375305beffb8e43a6eb75233b201e36d3d29f",
Vout: 0,
Sequence: 4294967293,
},
},
Vout: []bchain.Vout{
{
ValueSat: *big.NewInt(100000),
N: 0,
ScriptPubKey: bchain.ScriptPubKey{
Hex: "00148091746745464e7555c31e9a5afceac14a02978a",
Addresses: []string{
"tb1qszghge69ge8824wrr6d94l82c99q99u2ccgv5w",
},
},
},
{
ValueSat: *big.NewInt(1899751),
N: 1,
ScriptPubKey: bchain.ScriptPubKey{
Hex: "0014565ea9ff4589d3e05ba149ae6e257752bfdc2a1e",
Addresses: []string{
"tb1q2e02nl6938f7qkapfxhxufth22lac2s792vsxp",
},
},
},
},
}
}
func TestPackTx(t *testing.T) {
@ -421,17 +372,6 @@ func TestPackTx(t *testing.T) {
want: testTxPacked2,
wantErr: false,
},
{
name: "signet-1",
args: args{
tx: testTx3,
height: 15745,
blockTime: 1607805599,
parser: NewBitcoinParser(GetChainParams("signet"), &Configuration{}),
},
want: testTxPacked3,
wantErr: false,
},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
@ -480,16 +420,6 @@ func TestUnpackTx(t *testing.T) {
want1: 510234,
wantErr: false,
},
{
name: "signet-1",
args: args{
packedTx: testTxPacked3,
parser: NewBitcoinParser(GetChainParams("signet"), &Configuration{}),
},
want: &testTx3,
want1: 15745,
wantErr: false,
},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {

View File

@ -1,6 +1,7 @@
package btc
import (
"blockbook/bchain"
"bytes"
"context"
"encoding/hex"
@ -16,8 +17,6 @@ import (
"github.com/golang/glog"
"github.com/juju/errors"
"github.com/martinboehm/btcd/wire"
"spacecruft.org/spacecruft/blockbook/bchain"
"spacecruft.org/spacecruft/blockbook/common"
)
// BitcoinRPC is an interface to JSON-RPC bitcoind service.
@ -155,13 +154,12 @@ func (b *BitcoinRPC) CreateMempool(chain bchain.BlockChain) (bchain.Mempool, err
}
// InitializeMempool creates ZeroMQ subscription and sets AddrDescForOutpointFunc to the Mempool
func (b *BitcoinRPC) InitializeMempool(addrDescForOutpoint bchain.AddrDescForOutpointFunc, onNewTxAddr bchain.OnNewTxAddrFunc, onNewTx bchain.OnNewTxFunc) error {
func (b *BitcoinRPC) InitializeMempool(addrDescForOutpoint bchain.AddrDescForOutpointFunc, onNewTxAddr bchain.OnNewTxAddrFunc) error {
if b.Mempool == nil {
return errors.New("Mempool not created")
}
b.Mempool.AddrDescForOutpoint = addrDescForOutpoint
b.Mempool.OnNewTxAddr = onNewTxAddr
b.Mempool.OnNewTx = onNewTx
if b.mq == nil {
mq, err := bchain.NewMQ(b.ChainConfig.MessageQueueBinding, b.pushHandler)
if err != nil {
@ -239,13 +237,13 @@ type CmdGetBlockChainInfo struct {
type ResGetBlockChainInfo struct {
Error *bchain.RPCError `json:"error"`
Result struct {
Chain string `json:"chain"`
Blocks int `json:"blocks"`
Headers int `json:"headers"`
Bestblockhash string `json:"bestblockhash"`
Difficulty common.JSONNumber `json:"difficulty"`
SizeOnDisk int64 `json:"size_on_disk"`
Warnings string `json:"warnings"`
Chain string `json:"chain"`
Blocks int `json:"blocks"`
Headers int `json:"headers"`
Bestblockhash string `json:"bestblockhash"`
Difficulty json.Number `json:"difficulty"`
SizeOnDisk int64 `json:"size_on_disk"`
Warnings string `json:"warnings"`
} `json:"result"`
}
@ -258,11 +256,11 @@ type CmdGetNetworkInfo struct {
type ResGetNetworkInfo struct {
Error *bchain.RPCError `json:"error"`
Result struct {
Version common.JSONNumber `json:"version"`
Subversion common.JSONNumber `json:"subversion"`
ProtocolVersion common.JSONNumber `json:"protocolversion"`
Timeoffset float64 `json:"timeoffset"`
Warnings string `json:"warnings"`
Version json.Number `json:"version"`
Subversion json.Number `json:"subversion"`
ProtocolVersion json.Number `json:"protocolversion"`
Timeoffset float64 `json:"timeoffset"`
Warnings string `json:"warnings"`
} `json:"result"`
}
@ -360,8 +358,8 @@ type CmdEstimateSmartFee struct {
type ResEstimateSmartFee struct {
Error *bchain.RPCError `json:"error"`
Result struct {
Feerate common.JSONNumber `json:"feerate"`
Blocks int `json:"blocks"`
Feerate json.Number `json:"feerate"`
Blocks int `json:"blocks"`
} `json:"result"`
}
@ -375,8 +373,8 @@ type CmdEstimateFee struct {
}
type ResEstimateFee struct {
Error *bchain.RPCError `json:"error"`
Result common.JSONNumber `json:"result"`
Error *bchain.RPCError `json:"error"`
Result json.Number `json:"result"`
}
// sendrawtransaction

View File

@ -1,6 +1,7 @@
package btc
import (
"blockbook/bchain"
"bytes"
"encoding/json"
"fmt"
@ -11,8 +12,8 @@ import (
"time"
"github.com/golang/glog"
"github.com/juju/errors"
"spacecruft.org/spacecruft/blockbook/bchain"
)
// https://whatthefee.io returns

View File

@ -1,6 +1,9 @@
package btg
import (
"blockbook/bchain"
"blockbook/bchain/coins/btc"
"blockbook/bchain/coins/utils"
"bytes"
"encoding/binary"
"io"
@ -8,9 +11,6 @@ import (
"github.com/martinboehm/btcd/chaincfg/chainhash"
"github.com/martinboehm/btcd/wire"
"github.com/martinboehm/btcutil/chaincfg"
"spacecruft.org/spacecruft/blockbook/bchain"
"spacecruft.org/spacecruft/blockbook/bchain/coins/btc"
"spacecruft.org/spacecruft/blockbook/bchain/coins/utils"
)
const (

View File

@ -3,6 +3,7 @@
package btg
import (
"blockbook/bchain/coins/btc"
"bytes"
"encoding/hex"
"fmt"
@ -12,7 +13,6 @@ import (
"testing"
"github.com/martinboehm/btcutil/chaincfg"
"spacecruft.org/spacecruft/blockbook/bchain/coins/btc"
)
func TestMain(m *testing.M) {

View File

@ -1,11 +1,11 @@
package btg
import (
"blockbook/bchain"
"blockbook/bchain/coins/btc"
"encoding/json"
"github.com/golang/glog"
"spacecruft.org/spacecruft/blockbook/bchain"
"spacecruft.org/spacecruft/blockbook/bchain/coins/btc"
)
// BGoldRPC is an interface to JSON-RPC bitcoind service.

View File

@ -1,9 +1,10 @@
package cpuchain
import (
"blockbook/bchain/coins/btc"
"github.com/martinboehm/btcd/wire"
"github.com/martinboehm/btcutil/chaincfg"
"spacecruft.org/spacecruft/blockbook/bchain/coins/btc"
)
// magic numbers

View File

@ -1,11 +1,11 @@
package cpuchain
import (
"blockbook/bchain"
"blockbook/bchain/coins/btc"
"encoding/json"
"github.com/golang/glog"
"spacecruft.org/spacecruft/blockbook/bchain"
"spacecruft.org/spacecruft/blockbook/bchain/coins/btc"
)
// CPUchainRPC is an interface to JSON-RPC bitcoind service.

View File

@ -1,10 +1,11 @@
package dash
import (
"blockbook/bchain"
"blockbook/bchain/coins/btc"
"github.com/martinboehm/btcd/wire"
"github.com/martinboehm/btcutil/chaincfg"
"spacecruft.org/spacecruft/blockbook/bchain"
"spacecruft.org/spacecruft/blockbook/bchain/coins/btc"
)
const (

View File

@ -1,8 +1,10 @@
// +build unittest
// build unittest
package dash
import (
"blockbook/bchain"
"blockbook/bchain/coins/btc"
"bytes"
"encoding/hex"
"fmt"
@ -11,9 +13,6 @@ import (
"path/filepath"
"reflect"
"testing"
"spacecruft.org/spacecruft/blockbook/bchain"
"spacecruft.org/spacecruft/blockbook/bchain/coins/btc"
)
type testBlock struct {

View File

@ -1,12 +1,12 @@
package dash
import (
"blockbook/bchain"
"blockbook/bchain/coins/btc"
"encoding/json"
"github.com/golang/glog"
"github.com/juju/errors"
"spacecruft.org/spacecruft/blockbook/bchain"
"spacecruft.org/spacecruft/blockbook/bchain/coins/btc"
)
const firstBlockWithSpecialTransactions = 1028160

View File

@ -9,19 +9,18 @@ import (
"math/big"
"strconv"
"blockbook/bchain"
"blockbook/bchain/coins/btc"
"blockbook/bchain/coins/utils"
cfg "github.com/decred/dcrd/chaincfg"
"github.com/decred/dcrd/chaincfg/chainhash"
cfg "github.com/decred/dcrd/chaincfg/v3"
"github.com/decred/dcrd/dcrec"
"github.com/decred/dcrd/dcrutil/v3"
"github.com/decred/dcrd/hdkeychain/v3"
"github.com/decred/dcrd/txscript/v3"
"github.com/decred/dcrd/hdkeychain"
"github.com/decred/dcrd/txscript"
"github.com/juju/errors"
"github.com/martinboehm/btcd/wire"
"github.com/martinboehm/btcutil/base58"
"github.com/martinboehm/btcutil/chaincfg"
"spacecruft.org/spacecruft/blockbook/bchain"
"spacecruft.org/spacecruft/blockbook/bchain/coins/btc"
"spacecruft.org/spacecruft/blockbook/bchain/coins/utils"
)
const (
@ -66,9 +65,9 @@ func NewDecredParser(params *chaincfg.Params, c *btc.Configuration) *DecredParse
switch d.BitcoinParser.Params.Name {
case "testnet3":
d.netConfig = cfg.TestNet3Params()
d.netConfig = &cfg.TestNet3Params
default:
d.netConfig = cfg.MainNetParams()
d.netConfig = &cfg.MainNetParams
}
return d
}
@ -204,10 +203,7 @@ func (p *DecredParser) GetAddrDescFromVout(output *bchain.Vout) (bchain.AddressD
return nil, err
}
const scriptVersion = 0
const treasuryEnabled = true
scriptClass, addresses, _, err := txscript.ExtractPkScriptAddrs(scriptVersion, script,
p.netConfig, treasuryEnabled)
scriptClass, addresses, _, err := txscript.ExtractPkScriptAddrs(txscript.DefaultScriptVersion, script, p.netConfig)
if err != nil {
return nil, err
}
@ -245,9 +241,7 @@ func (p *DecredParser) UnpackTx(buf []byte) (*bchain.Tx, uint32, error) {
}
func (p *DecredParser) addrDescFromExtKey(extKey *hdkeychain.ExtendedKey) (bchain.AddressDescriptor, error) {
pk := extKey.SerializedPubKey()
hash := dcrutil.Hash160(pk)
addr, err := dcrutil.NewAddressPubKeyHash(hash, p.netConfig, dcrec.STEcdsaSecp256k1)
var addr, err = extKey.Address(p.netConfig)
if err != nil {
return nil, err
}
@ -258,7 +252,7 @@ func (p *DecredParser) addrDescFromExtKey(extKey *hdkeychain.ExtendedKey) (bchai
// listed indexes
func (p *DecredParser) DeriveAddressDescriptors(xpub string, change uint32,
indexes []uint32) ([]bchain.AddressDescriptor, error) {
extKey, err := hdkeychain.NewKeyFromString(xpub, p.netConfig)
extKey, err := hdkeychain.NewKeyFromString(xpub)
if err != nil {
return nil, err
}
@ -289,7 +283,7 @@ func (p *DecredParser) DeriveAddressDescriptorsFromTo(xpub string, change uint32
if toIndex <= fromIndex {
return nil, errors.New("toIndex<=fromIndex")
}
extKey, err := hdkeychain.NewKeyFromString(xpub, p.netConfig)
extKey, err := hdkeychain.NewKeyFromString(xpub)
if err != nil {
return nil, err
}

View File

@ -3,14 +3,13 @@
package dcr
import (
"blockbook/bchain"
"blockbook/bchain/coins/btc"
"encoding/hex"
"math/big"
"os"
"reflect"
"testing"
"spacecruft.org/spacecruft/blockbook/bchain"
"spacecruft.org/spacecruft/blockbook/bchain/coins/btc"
)
var (

View File

@ -1,6 +1,7 @@
package dcr
import (
"blockbook/bchain"
"bytes"
"encoding/json"
"fmt"
@ -15,12 +16,11 @@ import (
"sync"
"time"
"github.com/decred/dcrd/dcrjson/v3"
"blockbook/bchain/coins/btc"
"github.com/decred/dcrd/dcrjson"
"github.com/golang/glog"
"github.com/juju/errors"
"spacecruft.org/spacecruft/blockbook/bchain"
"spacecruft.org/spacecruft/blockbook/bchain/coins/btc"
"spacecruft.org/spacecruft/blockbook/common"
)
// voteBitYes defines the vote bit set when a given block validates the previous
@ -168,61 +168,61 @@ type GetBlockHashResult struct {
type GetBlockResult struct {
Error Error `json:"error"`
Result struct {
Hash string `json:"hash"`
Confirmations int64 `json:"confirmations"`
Size int32 `json:"size"`
Height uint32 `json:"height"`
Version common.JSONNumber `json:"version"`
MerkleRoot string `json:"merkleroot"`
StakeRoot string `json:"stakeroot"`
RawTx []RawTx `json:"rawtx"`
Tx []string `json:"tx,omitempty"`
STx []string `json:"stx,omitempty"`
Time int64 `json:"time"`
Nonce common.JSONNumber `json:"nonce"`
VoteBits uint16 `json:"votebits"`
FinalState string `json:"finalstate"`
Voters uint16 `json:"voters"`
FreshStake uint8 `json:"freshstake"`
Revocations uint8 `json:"revocations"`
PoolSize uint32 `json:"poolsize"`
Bits string `json:"bits"`
SBits float64 `json:"sbits"`
ExtraData string `json:"extradata"`
StakeVersion uint32 `json:"stakeversion"`
Difficulty float64 `json:"difficulty"`
ChainWork string `json:"chainwork"`
PreviousHash string `json:"previousblockhash"`
NextHash string `json:"nextblockhash,omitempty"`
Hash string `json:"hash"`
Confirmations int64 `json:"confirmations"`
Size int32 `json:"size"`
Height uint32 `json:"height"`
Version json.Number `json:"version"`
MerkleRoot string `json:"merkleroot"`
StakeRoot string `json:"stakeroot"`
RawTx []RawTx `json:"rawtx"`
Tx []string `json:"tx,omitempty"`
STx []string `json:"stx,omitempty"`
Time int64 `json:"time"`
Nonce json.Number `json:"nonce"`
VoteBits uint16 `json:"votebits"`
FinalState string `json:"finalstate"`
Voters uint16 `json:"voters"`
FreshStake uint8 `json:"freshstake"`
Revocations uint8 `json:"revocations"`
PoolSize uint32 `json:"poolsize"`
Bits string `json:"bits"`
SBits float64 `json:"sbits"`
ExtraData string `json:"extradata"`
StakeVersion uint32 `json:"stakeversion"`
Difficulty float64 `json:"difficulty"`
ChainWork string `json:"chainwork"`
PreviousHash string `json:"previousblockhash"`
NextHash string `json:"nextblockhash,omitempty"`
} `json:"result"`
}
type GetBlockHeaderResult struct {
Error Error `json:"error"`
Result struct {
Hash string `json:"hash"`
Confirmations int64 `json:"confirmations"`
Version common.JSONNumber `json:"version"`
MerkleRoot string `json:"merkleroot"`
StakeRoot string `json:"stakeroot"`
VoteBits uint16 `json:"votebits"`
FinalState string `json:"finalstate"`
Voters uint16 `json:"voters"`
FreshStake uint8 `json:"freshstake"`
Revocations uint8 `json:"revocations"`
PoolSize uint32 `json:"poolsize"`
Bits string `json:"bits"`
SBits float64 `json:"sbits"`
Height uint32 `json:"height"`
Size uint32 `json:"size"`
Time int64 `json:"time"`
Nonce uint32 `json:"nonce"`
ExtraData string `json:"extradata"`
StakeVersion uint32 `json:"stakeversion"`
Difficulty float64 `json:"difficulty"`
ChainWork string `json:"chainwork"`
PreviousHash string `json:"previousblockhash,omitempty"`
NextHash string `json:"nextblockhash,omitempty"`
Hash string `json:"hash"`
Confirmations int64 `json:"confirmations"`
Version json.Number `json:"version"`
MerkleRoot string `json:"merkleroot"`
StakeRoot string `json:"stakeroot"`
VoteBits uint16 `json:"votebits"`
FinalState string `json:"finalstate"`
Voters uint16 `json:"voters"`
FreshStake uint8 `json:"freshstake"`
Revocations uint8 `json:"revocations"`
PoolSize uint32 `json:"poolsize"`
Bits string `json:"bits"`
SBits float64 `json:"sbits"`
Height uint32 `json:"height"`
Size uint32 `json:"size"`
Time int64 `json:"time"`
Nonce uint32 `json:"nonce"`
ExtraData string `json:"extradata"`
StakeVersion uint32 `json:"stakeversion"`
Difficulty float64 `json:"difficulty"`
ChainWork string `json:"chainwork"`
PreviousHash string `json:"previousblockhash,omitempty"`
NextHash string `json:"nextblockhash,omitempty"`
} `json:"result"`
}
@ -297,8 +297,8 @@ type EstimateSmartFeeResult struct {
}
type EstimateFeeResult struct {
Error Error `json:"error"`
Result common.JSONNumber `json:"result"`
Error Error `json:"error"`
Result json.Number `json:"result"`
}
type SendRawTransactionResult struct {
@ -637,7 +637,7 @@ func (d *DecredRPC) GetBlockInfo(hash string) (*bchain.BlockInfo, error) {
Version: block.Result.Version,
Nonce: block.Result.Nonce,
Bits: block.Result.Bits,
Difficulty: common.JSONNumber(strconv.FormatFloat(block.Result.Difficulty, 'e', -1, 64)),
Difficulty: json.Number(strconv.FormatFloat(block.Result.Difficulty, 'e', -1, 64)),
Txids: block.Result.Tx,
}

View File

@ -1,10 +1,11 @@
package deeponion
import (
"blockbook/bchain"
"blockbook/bchain/coins/btc"
"github.com/martinboehm/btcd/wire"
"github.com/martinboehm/btcutil/chaincfg"
"spacecruft.org/spacecruft/blockbook/bchain"
"spacecruft.org/spacecruft/blockbook/bchain/coins/btc"
)
// magic numbers

View File

@ -3,6 +3,8 @@
package deeponion
import (
"blockbook/bchain"
"blockbook/bchain/coins/btc"
"encoding/hex"
"math/big"
"os"
@ -10,8 +12,6 @@ import (
"testing"
"github.com/martinboehm/btcutil/chaincfg"
"spacecruft.org/spacecruft/blockbook/bchain"
"spacecruft.org/spacecruft/blockbook/bchain/coins/btc"
)
func TestMain(m *testing.M) {

View File

@ -1,12 +1,12 @@
package deeponion
import (
"blockbook/bchain"
"blockbook/bchain/coins/btc"
"encoding/json"
"github.com/golang/glog"
"github.com/juju/errors"
"spacecruft.org/spacecruft/blockbook/bchain"
"spacecruft.org/spacecruft/blockbook/bchain/coins/btc"
)
// DeepOnionRPC is an interface to JSON-RPC bitcoind service.

View File

@ -1,21 +1,20 @@
package digibyte
import (
"blockbook/bchain/coins/btc"
"github.com/martinboehm/btcd/wire"
"github.com/martinboehm/btcutil/chaincfg"
"spacecruft.org/spacecruft/blockbook/bchain/coins/btc"
)
const (
// MainnetMagic is mainnet network constant
MainnetMagic wire.BitcoinNet = 0xdab6c3fa
TestnetMagic wire.BitcoinNet = 0xddbdc8fd
)
var (
// MainNetParams are parser parameters for mainnet
MainNetParams chaincfg.Params
TestNetParams chaincfg.Params
)
func init() {
@ -24,12 +23,6 @@ func init() {
MainNetParams.PubKeyHashAddrID = []byte{30}
MainNetParams.ScriptHashAddrID = []byte{63}
MainNetParams.Bech32HRPSegwit = "dgb"
TestNetParams = chaincfg.TestNet3Params
TestNetParams.Net = TestnetMagic
TestNetParams.PubKeyHashAddrID = []byte{126}
TestNetParams.ScriptHashAddrID = []byte{140}
TestNetParams.Bech32HRPSegwit = "dgbt"
}
// DigiByteParser handle
@ -37,27 +30,18 @@ type DigiByteParser struct {
*btc.BitcoinParser
}
// NewDigiByteParser returns new DigiByteParser instance
// NewDigiByteParser returns new VertcoinParser instance
func NewDigiByteParser(params *chaincfg.Params, c *btc.Configuration) *DigiByteParser {
return &DigiByteParser{BitcoinParser: btc.NewBitcoinParser(params, c)}
}
// GetChainParams contains network parameters for the main DigiByte network
// and the DigiByte Testnet network
func GetChainParams(chain string) *chaincfg.Params {
if !chaincfg.IsRegistered(&MainNetParams) {
err := chaincfg.Register(&MainNetParams)
if err == nil {
err = chaincfg.Register(&TestNetParams)
}
if err != nil {
panic(err)
}
}
switch chain {
case "test":
return &TestNetParams
default:
return &MainNetParams
}
return &MainNetParams
}

View File

@ -3,6 +3,8 @@
package digibyte
import (
"blockbook/bchain"
"blockbook/bchain/coins/btc"
"encoding/hex"
"math/big"
"os"
@ -10,8 +12,6 @@ import (
"testing"
"github.com/martinboehm/btcutil/chaincfg"
"spacecruft.org/spacecruft/blockbook/bchain"
"spacecruft.org/spacecruft/blockbook/bchain/coins/btc"
)
func TestMain(m *testing.M) {

View File

@ -1,11 +1,11 @@
package digibyte
import (
"blockbook/bchain"
"blockbook/bchain/coins/btc"
"encoding/json"
"github.com/golang/glog"
"spacecruft.org/spacecruft/blockbook/bchain"
"spacecruft.org/spacecruft/blockbook/bchain/coins/btc"
)
// DigiByteRPC is an interface to JSON-RPC bitcoind service.

View File

@ -1,18 +1,20 @@
package divi
import (
"blockbook/bchain"
"blockbook/bchain/coins/btc"
"blockbook/bchain/coins/utils"
"bytes"
"io"
"encoding/hex"
"encoding/json"
"io"
"math/big"
"github.com/juju/errors"
"github.com/martinboehm/btcd/wire"
"github.com/martinboehm/btcutil/chaincfg"
"spacecruft.org/spacecruft/blockbook/bchain"
"spacecruft.org/spacecruft/blockbook/bchain/coins/btc"
"spacecruft.org/spacecruft/blockbook/bchain/coins/utils"
)
const (

View File

@ -3,6 +3,8 @@
package divi
import (
"blockbook/bchain"
"blockbook/bchain/coins/btc"
"bytes"
"encoding/hex"
"fmt"
@ -14,8 +16,6 @@ import (
"testing"
"github.com/martinboehm/btcutil/chaincfg"
"spacecruft.org/spacecruft/blockbook/bchain"
"spacecruft.org/spacecruft/blockbook/bchain/coins/btc"
)
func TestMain(m *testing.M) {

View File

@ -1,11 +1,11 @@
package divi
import (
"blockbook/bchain"
"blockbook/bchain/coins/btc"
"encoding/json"
"github.com/golang/glog"
"spacecruft.org/spacecruft/blockbook/bchain"
"spacecruft.org/spacecruft/blockbook/bchain/coins/btc"
)
// DivicoinRPC is an interface to JSON-RPC bitcoind service.

View File

@ -1,13 +1,13 @@
package dogecoin
import (
"blockbook/bchain"
"blockbook/bchain/coins/btc"
"blockbook/bchain/coins/utils"
"bytes"
"github.com/martinboehm/btcd/wire"
"github.com/martinboehm/btcutil/chaincfg"
"spacecruft.org/spacecruft/blockbook/bchain"
"spacecruft.org/spacecruft/blockbook/bchain/coins/btc"
"spacecruft.org/spacecruft/blockbook/bchain/coins/utils"
)
// magic numbers

View File

@ -3,6 +3,8 @@
package dogecoin
import (
"blockbook/bchain"
"blockbook/bchain/coins/btc"
"bytes"
"encoding/hex"
"fmt"
@ -14,8 +16,6 @@ import (
"testing"
"github.com/martinboehm/btcutil/chaincfg"
"spacecruft.org/spacecruft/blockbook/bchain"
"spacecruft.org/spacecruft/blockbook/bchain/coins/btc"
)
func TestMain(m *testing.M) {

View File

@ -1,11 +1,11 @@
package dogecoin
import (
"blockbook/bchain"
"blockbook/bchain/coins/btc"
"encoding/json"
"github.com/golang/glog"
"spacecruft.org/spacecruft/blockbook/bchain"
"spacecruft.org/spacecruft/blockbook/bchain/coins/btc"
)
// DogecoinRPC is an interface to JSON-RPC dogecoind service.

View File

@ -1,6 +1,7 @@
package eth
import (
"blockbook/bchain"
"bytes"
"context"
"encoding/hex"
@ -12,7 +13,6 @@ import (
ethcommon "github.com/ethereum/go-ethereum/common"
"github.com/golang/glog"
"github.com/juju/errors"
"spacecruft.org/spacecruft/blockbook/bchain"
)
var erc20abi = `[{"constant":true,"inputs":[],"name":"name","outputs":[{"name":"","type":"string"}],"payable":false,"type":"function","signature":"0x06fdde03"},
@ -145,26 +145,24 @@ func parseErc20StringProperty(contractDesc bchain.AddressDescriptor, data string
n := parseErc20NumericProperty(contractDesc, data[64:128])
if n != nil {
l := n.Uint64()
if l > 0 && 2*int(l) <= len(data)-128 {
if 2*int(l) <= len(data)-128 {
b, err := hex.DecodeString(data[128 : 128+2*l])
if err == nil {
return string(b)
}
}
}
}
// allow string properties as UTF-8 data
b, err := hex.DecodeString(data)
if err == nil {
i := bytes.Index(b, []byte{0})
if i > 32 {
i = 32
}
if i > 0 {
b = b[:i]
}
if utf8.Valid(b) {
return string(b)
} else if len(data) == 64 {
// allow string properties as 32 bytes of UTF-8 data
b, err := hex.DecodeString(data)
if err == nil {
i := bytes.Index(b, []byte{0})
if i > 0 {
b = b[:i]
}
if utf8.Valid(b) {
return string(b)
}
}
}
if glog.V(1) {
@ -183,26 +181,18 @@ func (b *EthereumRPC) EthereumTypeGetErc20ContractInfo(contractDesc bchain.Addre
address := EIP55Address(contractDesc)
data, err := b.ethCall(erc20NameSignature, 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
// https://github.com/ethereum/go-ethereum/issues/21249#issuecomment-648647672
glog.Warning(errors.Annotatef(err, "erc20NameSignature %v", address))
return nil, nil
// return nil, errors.Annotatef(err, "erc20NameSignature %v", address)
return nil, err
}
name := parseErc20StringProperty(contractDesc, data)
if name != "" {
data, err = b.ethCall(erc20SymbolSignature, address)
if err != nil {
glog.Warning(errors.Annotatef(err, "erc20SymbolSignature %v", address))
return nil, nil
// return nil, errors.Annotatef(err, "erc20SymbolSignature %v", address)
return nil, err
}
symbol := parseErc20StringProperty(contractDesc, data)
data, err = b.ethCall(erc20DecimalsSignature, address)
if err != nil {
glog.Warning(errors.Annotatef(err, "erc20DecimalsSignature %v", address))
// return nil, errors.Annotatef(err, "erc20DecimalsSignature %v", address)
return nil, err
}
contract = &bchain.Erc20Contract{
Contract: address,

View File

@ -3,13 +3,12 @@
package eth
import (
"fmt"
"blockbook/bchain"
"blockbook/tests/dbtestdata"
fmt "fmt"
"math/big"
"strings"
"testing"
"spacecruft.org/spacecruft/blockbook/bchain"
"spacecruft.org/spacecruft/blockbook/tests/dbtestdata"
)
func TestErc20_erc20GetTransfersFromLog(t *testing.T) {
@ -139,16 +138,6 @@ func TestErc20_parseErc20StringProperty(t *testing.T) {
args: "0x44616920537461626c65636f696e2076312e3020444444444444444444444444",
want: "Dai Stablecoin v1.0 DDDDDDDDDDDD",
},
{
name: "long",
args: "0x556e6973776170205631000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000",
want: "Uniswap V1",
},
{
name: "garbage",
args: "0x2234880850896048596206002535425366538144616734015984380565810000",
want: "",
},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {

View File

@ -1,6 +1,7 @@
package eth
import (
"blockbook/bchain"
"encoding/hex"
"math/big"
"strconv"
@ -8,7 +9,6 @@ import (
"github.com/ethereum/go-ethereum/common/hexutil"
"github.com/golang/protobuf/proto"
"github.com/juju/errors"
"spacecruft.org/spacecruft/blockbook/bchain"
"golang.org/x/crypto/sha3"
)
@ -76,6 +76,12 @@ type rpcReceipt struct {
Logs []*rpcLog `json:"logs"`
}
type rpcEtcReceipt struct {
GasUsed string `json:"gasUsed"`
Status int `json:"status"`
Logs []*rpcLog `json:"logs"`
}
type completeTransaction struct {
Tx *rpcTransaction `json:"tx"`
Receipt *rpcReceipt `json:"receipt,omitempty"`
@ -96,31 +102,18 @@ func ethNumber(n string) (int64, error) {
return 0, errors.Errorf("Not a number: '%v'", n)
}
func (p *EthereumParser) ethTxToTx(tx *rpcTransaction, receipt *rpcReceipt, blocktime int64, confirmations uint32, fixEIP55 bool) (*bchain.Tx, error) {
func (p *EthereumParser) ethTxToTx(tx *rpcTransaction, receipt *rpcReceipt, blocktime int64, confirmations uint32) (*bchain.Tx, error) {
txid := tx.Hash
var (
fa, ta []string
err error
)
if len(tx.From) > 2 {
if fixEIP55 {
tx.From = EIP55AddressFromAddress(tx.From)
}
fa = []string{tx.From}
}
if len(tx.To) > 2 {
if fixEIP55 {
tx.To = EIP55AddressFromAddress(tx.To)
}
ta = []string{tx.To}
}
if fixEIP55 && receipt != nil && receipt.Logs != nil {
for _, l := range receipt.Logs {
if len(l.Address) > 2 {
l.Address = EIP55AddressFromAddress(l.Address)
}
}
}
ct := completeTransaction{
Tx: tx,
Receipt: receipt,
@ -211,9 +204,6 @@ func EIP55Address(addrDesc bchain.AddressDescriptor) string {
// EIP55AddressFromAddress returns an EIP55-compliant hex string representation of the address
func EIP55AddressFromAddress(address string) string {
if has0xPrefix(address) {
address = address[2:]
}
b, err := hex.DecodeString(address)
if err != nil {
return address
@ -311,14 +301,8 @@ func (p *EthereumParser) PackTx(tx *bchain.Tx, height uint32, blockTime int64) (
if pt.Receipt.GasUsed, err = hexDecodeBig(r.Receipt.GasUsed); err != nil {
return nil, errors.Annotatef(err, "GasUsed %v", r.Receipt.GasUsed)
}
if r.Receipt.Status != "" {
if pt.Receipt.Status, err = hexDecodeBig(r.Receipt.Status); err != nil {
return nil, errors.Annotatef(err, "Status %v", r.Receipt.Status)
}
} else {
// unknown status, use 'U' as status bytes
// there is a potential for conflict with value 0x55 but this is not used by any chain at this moment
pt.Receipt.Status = []byte{'U'}
if pt.Receipt.Status, err = hexDecodeBig(r.Receipt.Status); err != nil {
return nil, errors.Annotatef(err, "Status %v", r.Receipt.Status)
}
ptLogs := make([]*ProtoCompleteTransaction_ReceiptType_LogType, len(r.Receipt.Logs))
for i, l := range r.Receipt.Logs {
@ -385,18 +369,13 @@ func (p *EthereumParser) UnpackTx(buf []byte) (*bchain.Tx, uint32, error) {
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 = &rpcReceipt{
GasUsed: hexEncodeBig(pt.Receipt.GasUsed),
Status: status,
Status: hexEncodeBig(pt.Receipt.Status),
Logs: logs,
}
}
tx, err := p.ethTxToTx(&rt, rr, int64(pt.BlockTime), 0, false)
tx, err := p.ethTxToTx(&rt, rr, int64(pt.BlockTime), 0)
if err != nil {
return nil, 0, err
}
@ -472,51 +451,40 @@ func (p *EthereumParser) EthereumTypeGetErc20FromTx(tx *bchain.Tx) ([]bchain.Erc
return r, nil
}
// TxStatus is status of transaction
type TxStatus int
// statuses of transaction
const (
TxStatusUnknown = TxStatus(iota - 2)
TxStatusPending
TxStatusFailure
TxStatusOK
txStatusUnknown = iota - 2
txStatusPending
txStatusFailure
txStatusOK
)
// EthereumTxData contains ethereum specific transaction data
type EthereumTxData struct {
Status TxStatus `json:"status"` // 1 OK, 0 Fail, -1 pending, -2 unknown
Status int `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"`
}
// GetEthereumTxData returns EthereumTxData from bchain.Tx
func GetEthereumTxData(tx *bchain.Tx) *EthereumTxData {
return GetEthereumTxDataFromSpecificData(tx.CoinSpecificData)
}
// GetEthereumTxDataFromSpecificData returns EthereumTxData from coinSpecificData
func GetEthereumTxDataFromSpecificData(coinSpecificData interface{}) *EthereumTxData {
etd := EthereumTxData{Status: TxStatusPending}
csd, ok := coinSpecificData.(completeTransaction)
etd := EthereumTxData{Status: txStatusPending}
csd, ok := tx.CoinSpecificData.(completeTransaction)
if ok {
if csd.Tx != nil {
etd.Nonce, _ = hexutil.DecodeUint64(csd.Tx.AccountNonce)
etd.GasLimit, _ = hexutil.DecodeBig(csd.Tx.GasLimit)
etd.GasPrice, _ = hexutil.DecodeBig(csd.Tx.GasPrice)
etd.Data = csd.Tx.Payload
}
if csd.Receipt != nil {
switch csd.Receipt.Status {
case "0x1":
etd.Status = TxStatusOK
etd.Status = txStatusOK
case "": // old transactions did not set status
etd.Status = TxStatusUnknown
etd.Status = txStatusUnknown
default:
etd.Status = TxStatusFailure
etd.Status = txStatusFailure
}
etd.GasUsed, _ = hexutil.DecodeBig(csd.Receipt.GasUsed)
}

View File

@ -3,14 +3,13 @@
package eth
import (
"blockbook/bchain"
"blockbook/tests/dbtestdata"
"encoding/hex"
"fmt"
"math/big"
"reflect"
"testing"
"spacecruft.org/spacecruft/blockbook/bchain"
"spacecruft.org/spacecruft/blockbook/tests/dbtestdata"
)
func TestEthParser_GetAddrDescFromAddress(t *testing.T) {
@ -68,7 +67,7 @@ func TestEthParser_GetAddrDescFromAddress(t *testing.T) {
}
}
var testTx1, testTx2, testTx1Failed, testTx1NoStatus bchain.Tx
var testTx1, testTx2 bchain.Tx
func init() {
@ -156,83 +155,6 @@ func init() {
},
},
}
testTx1Failed = bchain.Tx{
Blocktime: 1534858022,
Time: 1534858022,
Txid: "0xcd647151552b5132b2aef7c9be00dc6f73afc5901dde157aab131335baaa853b",
Vin: []bchain.Vin{
{
Addresses: []string{"0x3E3a3D69dc66bA10737F531ed088954a9EC89d97"},
},
},
Vout: []bchain.Vout{
{
ValueSat: *big.NewInt(1999622000000000000),
ScriptPubKey: bchain.ScriptPubKey{
Addresses: []string{"0x555Ee11FBDDc0E49A9bAB358A8941AD95fFDB48f"},
},
},
},
CoinSpecificData: completeTransaction{
Tx: &rpcTransaction{
AccountNonce: "0xb26c",
GasPrice: "0x430e23400",
GasLimit: "0x5208",
To: "0x555Ee11FBDDc0E49A9bAB358A8941AD95fFDB48f",
Value: "0x1bc0159d530e6000",
Payload: "0x",
Hash: "0xcd647151552b5132b2aef7c9be00dc6f73afc5901dde157aab131335baaa853b",
BlockNumber: "0x41eee8",
From: "0x3E3a3D69dc66bA10737F531ed088954a9EC89d97",
TransactionIndex: "0xa",
},
Receipt: &rpcReceipt{
GasUsed: "0x5208",
Status: "0x0",
Logs: []*rpcLog{},
},
},
}
testTx1NoStatus = bchain.Tx{
Blocktime: 1534858022,
Time: 1534858022,
Txid: "0xcd647151552b5132b2aef7c9be00dc6f73afc5901dde157aab131335baaa853b",
Vin: []bchain.Vin{
{
Addresses: []string{"0x3E3a3D69dc66bA10737F531ed088954a9EC89d97"},
},
},
Vout: []bchain.Vout{
{
ValueSat: *big.NewInt(1999622000000000000),
ScriptPubKey: bchain.ScriptPubKey{
Addresses: []string{"0x555Ee11FBDDc0E49A9bAB358A8941AD95fFDB48f"},
},
},
},
CoinSpecificData: completeTransaction{
Tx: &rpcTransaction{
AccountNonce: "0xb26c",
GasPrice: "0x430e23400",
GasLimit: "0x5208",
To: "0x555Ee11FBDDc0E49A9bAB358A8941AD95fFDB48f",
Value: "0x1bc0159d530e6000",
Payload: "0x",
Hash: "0xcd647151552b5132b2aef7c9be00dc6f73afc5901dde157aab131335baaa853b",
BlockNumber: "0x41eee8",
From: "0x3E3a3D69dc66bA10737F531ed088954a9EC89d97",
TransactionIndex: "0xa",
},
Receipt: &rpcReceipt{
GasUsed: "0x5208",
Status: "",
Logs: []*rpcLog{},
},
},
}
}
func TestEthereumParser_PackTx(t *testing.T) {
@ -266,24 +188,6 @@ func TestEthereumParser_PackTx(t *testing.T) {
},
want: dbtestdata.EthTx2Packed,
},
{
name: "3",
args: args{
tx: &testTx1Failed,
height: 4321000,
blockTime: 1534858022,
},
want: dbtestdata.EthTx1FailedPacked,
},
{
name: "4",
args: args{
tx: &testTx1NoStatus,
height: 4321000,
blockTime: 1534858022,
},
want: dbtestdata.EthTx1NoStatusPacked,
},
}
p := NewEthereumParser(1)
for _, tt := range tests {
@ -325,18 +229,6 @@ func TestEthereumParser_UnpackTx(t *testing.T) {
want: &testTx2,
want1: 4321000,
},
{
name: "3",
args: args{hex: dbtestdata.EthTx1FailedPacked},
want: &testTx1Failed,
want1: 4321000,
},
{
name: "4",
args: args{hex: dbtestdata.EthTx1NoStatusPacked},
want: &testTx1NoStatus,
want1: 4321000,
},
}
p := NewEthereumParser(1)
for _, tt := range tests {
@ -373,30 +265,3 @@ func TestEthereumParser_UnpackTx(t *testing.T) {
})
}
}
func TestEthereumParser_GetEthereumTxData(t *testing.T) {
tests := []struct {
name string
tx *bchain.Tx
want string
}{
{
name: "Test empty data",
tx: &testTx1,
want: "0x",
},
{
name: "Test non empty data",
tx: &testTx2,
want: "0xa9059cbb000000000000000000000000555ee11fbddc0e49a9bab358a8941ad95ffdb48f00000000000000000000000000000000000000000000021e19e0c9bab2400000",
},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
got := GetEthereumTxData(tt.tx)
if got.Data != tt.want {
t.Errorf("EthereumParser.GetEthereumTxData() = %v, want %v", got.Data, tt.want)
}
})
}
}

View File

@ -1,6 +1,7 @@
package eth
import (
"blockbook/bchain"
"context"
"encoding/json"
"fmt"
@ -11,14 +12,11 @@ import (
ethereum "github.com/ethereum/go-ethereum"
ethcommon "github.com/ethereum/go-ethereum/common"
"github.com/ethereum/go-ethereum/common/hexutil"
ethtypes "github.com/ethereum/go-ethereum/core/types"
"github.com/ethereum/go-ethereum/ethclient"
"github.com/ethereum/go-ethereum/rpc"
"github.com/golang/glog"
"github.com/juju/errors"
"spacecruft.org/spacecruft/blockbook/bchain"
"spacecruft.org/spacecruft/blockbook/common"
)
// EthereumNet type specifies the type of ethereum network
@ -29,8 +27,6 @@ const (
MainNet EthereumNet = 1
// TestNet is Ropsten test network
TestNet EthereumNet = 3
// TestNetGoerli is Goerli test network
TestNetGoerli EthereumNet = 5
)
// Configuration represents json config file
@ -61,6 +57,7 @@ type EthereumRPC struct {
chanNewTx chan ethcommon.Hash
newTxSubscription *rpc.ClientSubscription
ChainConfig *Configuration
isETC bool
}
// NewEthereumRPC returns new EthRPC instance.
@ -92,6 +89,9 @@ func NewEthereumRPC(config json.RawMessage, pushHandler func(bchain.Notification
s.Parser = NewEthereumParser(c.BlockAddressesToKeep)
s.timeout = time.Duration(c.RPCTimeout) * time.Second
// detect ethereum classic
s.isETC = s.ChainConfig.CoinName == "Ethereum Classic"
// new blocks notifications handling
// the subscription is done in Initialize
s.chanNewBlock = make(chan *ethtypes.Header)
@ -162,9 +162,6 @@ func (b *EthereumRPC) Initialize() error {
b.Testnet = true
b.Network = "testnet"
break
case TestNetGoerli:
b.Testnet = true
b.Network = "goerli"
default:
return errors.Errorf("Unknown network id %v", id)
}
@ -183,7 +180,7 @@ func (b *EthereumRPC) CreateMempool(chain bchain.BlockChain) (bchain.Mempool, er
}
// InitializeMempool creates subscriptions to newHeads and newPendingTransactions
func (b *EthereumRPC) InitializeMempool(addrDescForOutpoint bchain.AddrDescForOutpointFunc, onNewTxAddr bchain.OnNewTxAddrFunc, onNewTx bchain.OnNewTxFunc) error {
func (b *EthereumRPC) InitializeMempool(addrDescForOutpoint bchain.AddrDescForOutpointFunc, onNewTxAddr bchain.OnNewTxAddrFunc) error {
if b.Mempool == nil {
return errors.New("Mempool not created")
}
@ -198,7 +195,6 @@ func (b *EthereumRPC) InitializeMempool(addrDescForOutpoint bchain.AddrDescForOu
}
b.Mempool.OnNewTxAddr = onNewTxAddr
b.Mempool.OnNewTx = onNewTx
if err = b.subscribeEvents(); err != nil {
return err
@ -210,21 +206,25 @@ func (b *EthereumRPC) InitializeMempool(addrDescForOutpoint bchain.AddrDescForOu
}
func (b *EthereumRPC) subscribeEvents() error {
// subscriptions
if err := b.subscribe(func() (*rpc.ClientSubscription, error) {
// invalidate the previous subscription - it is either the first one or there was an error
b.newBlockSubscription = nil
ctx, cancel := context.WithTimeout(context.Background(), b.timeout)
defer cancel()
sub, err := b.rpc.EthSubscribe(ctx, b.chanNewBlock, "newHeads")
if err != nil {
return nil, errors.Annotatef(err, "EthSubscribe newHeads")
if b.isETC {
glog.Info(b.ChainConfig.CoinName, " does not support subscription to newHeads")
} else {
// subscriptions
if err := b.subscribe(func() (*rpc.ClientSubscription, error) {
// invalidate the previous subscription - it is either the first one or there was an error
b.newBlockSubscription = nil
ctx, cancel := context.WithTimeout(context.Background(), b.timeout)
defer cancel()
sub, err := b.rpc.EthSubscribe(ctx, b.chanNewBlock, "newHeads")
if err != nil {
return nil, errors.Annotatef(err, "EthSubscribe newHeads")
}
b.newBlockSubscription = sub
glog.Info("Subscribed to newHeads")
return sub, nil
}); err != nil {
return err
}
b.newBlockSubscription = sub
glog.Info("Subscribed to newHeads")
return sub, nil
}); err != nil {
return err
}
if err := b.subscribe(func() (*rpc.ClientSubscription, error) {
@ -340,15 +340,19 @@ func (b *EthereumRPC) GetChainInfo() (*bchain.ChainInfo, error) {
if err != nil {
return nil, err
}
var ver string
var ver, protocol string
if err := b.rpc.CallContext(ctx, &ver, "web3_clientVersion"); err != nil {
return nil, err
}
if err := b.rpc.CallContext(ctx, &protocol, "eth_protocolVersion"); err != nil {
return nil, err
}
rv := &bchain.ChainInfo{
Blocks: int(h.Number.Int64()),
Bestblockhash: h.Hash().Hex(),
Difficulty: h.Difficulty.String(),
Version: ver,
Blocks: int(h.Number.Int64()),
Bestblockhash: h.Hash().Hex(),
Difficulty: h.Difficulty.String(),
Version: ver,
ProtocolVersion: protocol,
}
idi := int(id.Uint64())
if idi == 1 {
@ -362,6 +366,12 @@ func (b *EthereumRPC) GetChainInfo() (*bchain.ChainInfo, error) {
func (b *EthereumRPC) getBestHeader() (*ethtypes.Header, error) {
b.bestHeaderLock.Lock()
defer b.bestHeaderLock.Unlock()
// ETC does not have newBlocks subscription, bestHeader must be updated very often (each 1 second)
if b.isETC {
if b.bestHeaderTime.Add(1 * time.Second).Before(time.Now()) {
b.bestHeader = nil
}
}
// if the best header was not updated for 15 minutes, there could be a subscription problem, reconnect RPC
// do it only in case of normal operation, not initial synchronization
if b.bestHeaderTime.Add(15*time.Minute).Before(time.Now()) && !b.bestHeaderTime.IsZero() && b.mempoolInitialized {
@ -537,7 +547,7 @@ func (b *EthereumRPC) GetBlock(hash string, height uint32) (*bchain.Block, error
btxs := make([]bchain.Tx, len(body.Transactions))
for i := range body.Transactions {
tx := &body.Transactions[i]
btx, err := b.Parser.ethTxToTx(tx, &rpcReceipt{Logs: logs[tx.Hash]}, bbh.Time, uint32(bbh.Confirmations), true)
btx, err := b.Parser.ethTxToTx(tx, &rpcReceipt{Logs: logs[tx.Hash]}, bbh.Time, uint32(bbh.Confirmations))
if err != nil {
return nil, errors.Annotatef(err, "hash %v, height %v, txid %v", hash, height, tx.Hash)
}
@ -573,8 +583,8 @@ func (b *EthereumRPC) GetBlockInfo(hash string) (*bchain.BlockInfo, error) {
}
return &bchain.BlockInfo{
BlockHeader: *bch,
Difficulty: common.JSONNumber(head.Difficulty),
Nonce: common.JSONNumber(head.Nonce),
Difficulty: json.Number(head.Difficulty),
Nonce: json.Number(head.Nonce),
Txids: txs.Transactions,
}, nil
}
@ -603,7 +613,7 @@ func (b *EthereumRPC) GetTransaction(txid string) (*bchain.Tx, error) {
var btx *bchain.Tx
if tx.BlockNumber == "" {
// mempool tx
btx, err = b.Parser.ethTxToTx(tx, nil, 0, 0, true)
btx, err = b.Parser.ethTxToTx(tx, nil, 0, 0)
if err != nil {
return nil, errors.Annotatef(err, "txid %v", txid)
}
@ -624,9 +634,33 @@ func (b *EthereumRPC) GetTransaction(txid string) (*bchain.Tx, error) {
return nil, errors.Annotatef(err, "txid %v", txid)
}
var receipt rpcReceipt
err = b.rpc.CallContext(ctx, &receipt, "eth_getTransactionReceipt", hash)
if err != nil {
return nil, errors.Annotatef(err, "txid %v", txid)
if b.isETC {
var rawReceipt json.RawMessage
var etcReceipt rpcEtcReceipt
err = b.rpc.CallContext(ctx, &rawReceipt, "eth_getTransactionReceipt", hash)
if err != nil {
return nil, errors.Annotatef(err, "txid %v", txid)
}
err = json.Unmarshal(rawReceipt, &etcReceipt)
if err == nil {
receipt.GasUsed = etcReceipt.GasUsed
receipt.Logs = etcReceipt.Logs
if etcReceipt.Status == 0 {
receipt.Status = "0x0"
} else {
receipt.Status = "0x1"
}
} else {
err = json.Unmarshal(rawReceipt, &receipt)
if err != nil {
return nil, errors.Annotatef(err, "unmarshal receipt for txid %v, %v", txid, string(rawReceipt))
}
}
} else {
err = b.rpc.CallContext(ctx, &receipt, "eth_getTransactionReceipt", hash)
if err != nil {
return nil, errors.Annotatef(err, "txid %v", txid)
}
}
n, err := ethNumber(tx.BlockNumber)
if err != nil {
@ -636,7 +670,7 @@ func (b *EthereumRPC) GetTransaction(txid string) (*bchain.Tx, error) {
if err != nil {
return nil, errors.Annotatef(err, "txid %v", txid)
}
btx, err = b.Parser.ethTxToTx(tx, &receipt, time, confirmations, true)
btx, err = b.Parser.ethTxToTx(tx, &receipt, time, confirmations)
if err != nil {
return nil, errors.Annotatef(err, "txid %v", txid)
}
@ -724,18 +758,6 @@ func (b *EthereumRPC) EthereumTypeEstimateGas(params map[string]interface{}) (ui
if ok && len(s) > 0 {
msg.Data = ethcommon.FromHex(s)
}
s, ok = getStringFromMap("value", params)
if ok && len(s) > 0 {
msg.Value, _ = hexutil.DecodeBig(s)
}
s, ok = getStringFromMap("gas", params)
if ok && len(s) > 0 {
msg.Gas, _ = hexutil.DecodeUint64(s)
}
s, ok = getStringFromMap("gasPrice", params)
if ok && len(s) > 0 {
msg.GasPrice, _ = hexutil.DecodeBig(s)
}
return b.client.EstimateGas(ctx, msg)
}

View File

@ -1,11 +1,11 @@
// Code generated by protoc-gen-go. DO NOT EDIT.
// source: bchain/coins/eth/ethtx.proto
// source: tx.proto
/*
Package eth is a generated protocol buffer package.
It is generated from these files:
bchain/coins/eth/ethtx.proto
tx.proto
It has these top-level messages:
ProtoCompleteTransaction
@ -228,34 +228,33 @@ func init() {
proto.RegisterType((*ProtoCompleteTransaction_ReceiptType_LogType)(nil), "eth.ProtoCompleteTransaction.ReceiptType.LogType")
}
func init() { proto.RegisterFile("bchain/coins/eth/ethtx.proto", fileDescriptor0) }
func init() { proto.RegisterFile("tx.proto", fileDescriptor0) }
var fileDescriptor0 = []byte{
// 409 bytes of a gzipped FileDescriptorProto
// 393 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,
0x14, 0xc6, 0xe9, 0x9f, 0xf9, 0xb3, 0xa7, 0x55, 0x24, 0x88, 0x84, 0xe2, 0x45, 0x59, 0xbc, 0xa8,
0x5e, 0x14, 0x5c, 0x7d, 0x81, 0x75, 0xc4, 0x55, 0x18, 0xd6, 0x21, 0x46, 0xef, 0xb3, 0x69, 0xd8,
0x29, 0xb6, 0x4d, 0x69, 0x52, 0xe8, 0xbe, 0x91, 0x2f, 0xe4, 0xbb, 0x78, 0x29, 0x39, 0x4d, 0xd7,
0x11, 0x51, 0xbc, 0x3b, 0xbf, 0x6f, 0xce, 0x37, 0xf9, 0xbe, 0xa4, 0xb0, 0xb5, 0x53, 0xd9, 0x0f,
0xda, 0x6a, 0x12, 0x29, 0x7b, 0x3c, 0xff, 0xb6, 0x02, 0x7a, 0x70, 0xb8, 0xd3, 0x6d, 0xdf, 0x28,
0xab, 0xf8, 0x20, 0x3a, 0x23, 0xa4, 0xad, 0x75, 0x47, 0x72, 0x48, 0xde, 0x34, 0x5a, 0x7e, 0xbd,
0x1e, 0xdb, 0x1b, 0x35, 0xd0, 0x20, 0x0f, 0x8a, 0x07, 0xec, 0x54, 0x22, 0x4f, 0xe1, 0x0c, 0x91,
0xd7, 0xad, 0xa2, 0x61, 0x1e, 0x14, 0x31, 0xfb, 0x25, 0x90, 0xd7, 0x10, 0xf2, 0x89, 0x46, 0x79,
0x50, 0x24, 0x17, 0xcf, 0x4a, 0x65, 0x8f, 0xe5, 0xdf, 0x8e, 0x2a, 0xf9, 0xc4, 0xef, 0x7a, 0xc5,
0x42, 0x3e, 0x91, 0x1d, 0x6c, 0x98, 0x92, 0xaa, 0xee, 0x2d, 0x8d, 0xd1, 0xfa, 0xfc, 0xdf, 0x56,
0xbf, 0x8c, 0xfe, 0xc5, 0x99, 0xfd, 0x08, 0x60, 0x3d, 0xff, 0x27, 0x39, 0x87, 0xf4, 0x52, 0x4a,
0x3d, 0x76, 0xf6, 0x5a, 0x77, 0x52, 0x61, 0x8d, 0x98, 0xfd, 0xa6, 0x91, 0x0c, 0xb6, 0x57, 0xc2,
0x1c, 0x86, 0x5a, 0xce, 0x35, 0x52, 0x76, 0xcf, 0xfe, 0xb7, 0x7d, 0xdd, 0xd6, 0x16, 0xbb, 0xc4,
0xec, 0x9e, 0xc9, 0x63, 0x58, 0x7d, 0x11, 0xcd, 0xa8, 0x30, 0x69, 0xca, 0x66, 0x20, 0x14, 0x36,
0x07, 0x71, 0xd7, 0x68, 0x51, 0xd1, 0x15, 0xea, 0x0b, 0x12, 0x02, 0xf1, 0x7b, 0x61, 0x8e, 0x74,
0x8d, 0x32, 0xce, 0xe4, 0x21, 0x84, 0x5c, 0xd3, 0x0d, 0x2a, 0x21, 0xd7, 0x6e, 0xe7, 0xdd, 0xa0,
0x5b, 0xba, 0x9d, 0x77, 0xdc, 0x4c, 0x5e, 0xc0, 0xa3, 0x93, 0xca, 0x1f, 0xba, 0x4a, 0x4d, 0xf4,
0x0c, 0x9f, 0xe3, 0x0f, 0x3d, 0xfb, 0x1e, 0x40, 0x72, 0x72, 0x27, 0x2e, 0xcd, 0x95, 0x30, 0x9f,
0x8d, 0xaa, 0xb0, 0x7a, 0xca, 0x16, 0x24, 0x4f, 0x60, 0xfd, 0xc9, 0x0a, 0x3b, 0x1a, 0xdf, 0xd9,
0x13, 0xd9, 0x41, 0xb4, 0xd7, 0xb7, 0x34, 0xca, 0xa3, 0x22, 0xb9, 0x78, 0xf9, 0xdf, 0xb7, 0x5f,
0xee, 0xf5, 0x2d, 0xbe, 0x82, 0x73, 0x67, 0x1f, 0x61, 0xe3, 0xd9, 0x25, 0xb8, 0xac, 0xaa, 0x41,
0x19, 0xb3, 0x24, 0xf0, 0xe8, 0xba, 0xbe, 0x15, 0x56, 0xf8, 0xf3, 0x71, 0x76, 0xa9, 0xb8, 0xee,
0x6b, 0x69, 0x30, 0x40, 0xca, 0x3c, 0xdd, 0xac, 0xf1, 0xb3, 0x7d, 0xf5, 0x33, 0x00, 0x00, 0xff,
0xff, 0xde, 0xd5, 0x28, 0xa3, 0xc2, 0x02, 0x00, 0x00,
}

View File

@ -1,64 +0,0 @@
package firo
import (
"bytes"
"io"
"github.com/martinboehm/btcd/chaincfg/chainhash"
"github.com/martinboehm/btcd/wire"
)
// FiroMsgTx encapsulate firo tx and extra
type FiroMsgTx struct {
wire.MsgTx
Extra []byte
}
// TxHash calculate hash of transaction
func (msg *FiroMsgTx) TxHash() chainhash.Hash {
extraSize := uint64(len(msg.Extra))
sizeOfExtraSize := 0
if extraSize != 0 {
sizeOfExtraSize = wire.VarIntSerializeSize(extraSize)
}
// Original payload
buf := bytes.NewBuffer(make([]byte, 0,
msg.SerializeSizeStripped()+sizeOfExtraSize+len(msg.Extra)))
_ = msg.SerializeNoWitness(buf)
// Extra payload
if extraSize != 0 {
wire.WriteVarInt(buf, 0, extraSize)
buf.Write(msg.Extra)
}
return chainhash.DoubleHashH(buf.Bytes())
}
// FiroDecode to decode bitcoin tx and extra
func (msg *FiroMsgTx) FiroDecode(r io.Reader, pver uint32, enc wire.MessageEncoding) error {
if err := msg.MsgTx.BtcDecode(r, pver, enc); err != nil {
return err
}
// extra
version := uint32(msg.Version)
txVersion := version & 0xffff
txType := (version >> 16) & 0xffff
if txVersion == 3 && txType != 0 {
extraSize, err := wire.ReadVarInt(r, 0)
if err != nil {
return err
}
msg.Extra = make([]byte, extraSize)
_, err = io.ReadFull(r, msg.Extra[:])
if err != nil {
return err
}
}
return nil
}

View File

@ -1,10 +1,11 @@
package flo
import (
"blockbook/bchain"
"blockbook/bchain/coins/btc"
"github.com/martinboehm/btcd/wire"
"github.com/martinboehm/btcutil/chaincfg"
"spacecruft.org/spacecruft/blockbook/bchain"
"spacecruft.org/spacecruft/blockbook/bchain/coins/btc"
)
// magic numbers

View File

@ -3,13 +3,13 @@
package flo
import (
"blockbook/bchain/coins/btc"
"encoding/hex"
"os"
"reflect"
"testing"
"github.com/martinboehm/btcutil/chaincfg"
"spacecruft.org/spacecruft/blockbook/bchain/coins/btc"
)
func TestMain(m *testing.M) {

View File

@ -1,12 +1,13 @@
package flo
import (
"blockbook/bchain"
"blockbook/bchain/coins/btc"
"encoding/json"
"github.com/golang/glog"
"github.com/juju/errors"
"spacecruft.org/spacecruft/blockbook/bchain"
"spacecruft.org/spacecruft/blockbook/bchain/coins/btc"
"github.com/golang/glog"
)
// FloRPC is an interface to JSON-RPC bitcoind service.

View File

@ -1,9 +1,10 @@
package fujicoin
import (
"blockbook/bchain/coins/btc"
"github.com/martinboehm/btcd/wire"
"github.com/martinboehm/btcutil/chaincfg"
"spacecruft.org/spacecruft/blockbook/bchain/coins/btc"
)
const (

View File

@ -3,6 +3,8 @@
package fujicoin
import (
"blockbook/bchain"
"blockbook/bchain/coins/btc"
"encoding/hex"
"math/big"
"os"
@ -10,8 +12,6 @@ import (
"testing"
"github.com/martinboehm/btcutil/chaincfg"
"spacecruft.org/spacecruft/blockbook/bchain"
"spacecruft.org/spacecruft/blockbook/bchain/coins/btc"
)
func TestMain(m *testing.M) {

View File

@ -1,11 +1,11 @@
package fujicoin
import (
"blockbook/bchain"
"blockbook/bchain/coins/btc"
"encoding/json"
"github.com/golang/glog"
"spacecruft.org/spacecruft/blockbook/bchain"
"spacecruft.org/spacecruft/blockbook/bchain/coins/btc"
)
// FujicoinRPC is an interface to JSON-RPC bitcoind service.

View File

@ -1,9 +1,10 @@
package gamecredits
import (
"blockbook/bchain/coins/btc"
"github.com/martinboehm/btcd/wire"
"github.com/martinboehm/btcutil/chaincfg"
"spacecruft.org/spacecruft/blockbook/bchain/coins/btc"
)
// magic numbers

View File

@ -3,6 +3,8 @@
package gamecredits
import (
"blockbook/bchain"
"blockbook/bchain/coins/btc"
"encoding/hex"
"math/big"
"os"
@ -10,8 +12,6 @@ import (
"testing"
"github.com/martinboehm/btcutil/chaincfg"
"spacecruft.org/spacecruft/blockbook/bchain"
"spacecruft.org/spacecruft/blockbook/bchain/coins/btc"
)
func TestMain(m *testing.M) {

View File

@ -1,11 +1,11 @@
package gamecredits
import (
"blockbook/bchain"
"blockbook/bchain/coins/btc"
"encoding/json"
"github.com/golang/glog"
"spacecruft.org/spacecruft/blockbook/bchain"
"spacecruft.org/spacecruft/blockbook/bchain/coins/btc"
)
// GameCreditsRPC is an interface to JSON-RPC bitcoind service.

View File

@ -1,11 +1,12 @@
package grs
import (
"blockbook/bchain"
"blockbook/bchain/coins/btc"
"github.com/martinboehm/btcd/wire"
"github.com/martinboehm/btcutil/base58"
"github.com/martinboehm/btcutil/chaincfg"
"spacecruft.org/spacecruft/blockbook/bchain"
"spacecruft.org/spacecruft/blockbook/bchain/coins/btc"
)
// magic numbers

View File

@ -3,6 +3,8 @@
package grs
import (
"blockbook/bchain"
"blockbook/bchain/coins/btc"
"bytes"
"encoding/hex"
"math/big"
@ -11,8 +13,6 @@ import (
"testing"
"github.com/martinboehm/btcutil/chaincfg"
"spacecruft.org/spacecruft/blockbook/bchain"
"spacecruft.org/spacecruft/blockbook/bchain/coins/btc"
)
var (

View File

@ -1,12 +1,12 @@
package grs
import (
"blockbook/bchain"
"blockbook/bchain/coins/btc"
"encoding/json"
"github.com/golang/glog"
"github.com/juju/errors"
"spacecruft.org/spacecruft/blockbook/bchain"
"spacecruft.org/spacecruft/blockbook/bchain/coins/btc"
)
// GroestlcoinRPC is an interface to JSON-RPC service

View File

@ -1,10 +1,11 @@
package koto
import (
"blockbook/bchain"
"blockbook/bchain/coins/btc"
"github.com/martinboehm/btcd/wire"
"github.com/martinboehm/btcutil/chaincfg"
"spacecruft.org/spacecruft/blockbook/bchain"
"spacecruft.org/spacecruft/blockbook/bchain/coins/btc"
)
// magic numbers

View File

@ -3,6 +3,8 @@
package koto
import (
"blockbook/bchain"
"blockbook/bchain/coins/btc"
"bytes"
"encoding/hex"
"math/big"
@ -11,8 +13,6 @@ import (
"testing"
"github.com/martinboehm/btcutil/chaincfg"
"spacecruft.org/spacecruft/blockbook/bchain"
"spacecruft.org/spacecruft/blockbook/bchain/coins/btc"
)
var (

View File

@ -1,12 +1,12 @@
package koto
import (
"blockbook/bchain"
"blockbook/bchain/coins/btc"
"encoding/json"
"github.com/golang/glog"
"github.com/juju/errors"
"spacecruft.org/spacecruft/blockbook/bchain"
"spacecruft.org/spacecruft/blockbook/bchain/coins/btc"
)
// KotoRPC is an interface to JSON-RPC bitcoind service

View File

@ -1,15 +1,16 @@
package liquid
import (
"blockbook/bchain"
"blockbook/bchain/coins/btc"
"strconv"
vlq "github.com/bsm/go-vlq"
"github.com/golang/glog"
"github.com/martinboehm/btcd/txscript"
"github.com/martinboehm/btcd/wire"
"github.com/martinboehm/btcutil/chaincfg"
"spacecruft.org/spacecruft/blockbook/bchain"
"spacecruft.org/spacecruft/blockbook/bchain/coins/btc"
)
const (

View File

@ -3,6 +3,8 @@
package liquid
import (
"blockbook/bchain"
"blockbook/bchain/coins/btc"
"encoding/hex"
"math/big"
"os"
@ -10,8 +12,6 @@ import (
"testing"
"github.com/martinboehm/btcutil/chaincfg"
"spacecruft.org/spacecruft/blockbook/bchain"
"spacecruft.org/spacecruft/blockbook/bchain/coins/btc"
)
func TestMain(m *testing.M) {

View File

@ -1,12 +1,12 @@
package liquid
import (
"blockbook/bchain"
"blockbook/bchain/coins/btc"
"encoding/json"
"github.com/golang/glog"
"github.com/juju/errors"
"spacecruft.org/spacecruft/blockbook/bchain"
"spacecruft.org/spacecruft/blockbook/bchain/coins/btc"
)
// LiquidRPC is an interface to JSON-RPC bitcoind service.

View File

@ -1,9 +1,10 @@
package litecoin
import (
"blockbook/bchain/coins/btc"
"github.com/martinboehm/btcd/wire"
"github.com/martinboehm/btcutil/chaincfg"
"spacecruft.org/spacecruft/blockbook/bchain/coins/btc"
)
// magic numbers

View File

@ -3,6 +3,8 @@
package litecoin
import (
"blockbook/bchain"
"blockbook/bchain/coins/btc"
"encoding/hex"
"math/big"
"os"
@ -10,8 +12,6 @@ import (
"testing"
"github.com/martinboehm/btcutil/chaincfg"
"spacecruft.org/spacecruft/blockbook/bchain"
"spacecruft.org/spacecruft/blockbook/bchain/coins/btc"
)
func TestMain(m *testing.M) {

View File

@ -1,11 +1,11 @@
package litecoin
import (
"blockbook/bchain"
"blockbook/bchain/coins/btc"
"encoding/json"
"github.com/golang/glog"
"spacecruft.org/spacecruft/blockbook/bchain"
"spacecruft.org/spacecruft/blockbook/bchain/coins/btc"
)
// LitecoinRPC is an interface to JSON-RPC bitcoind service.

View File

@ -1,9 +1,10 @@
package monacoin
import (
"blockbook/bchain/coins/btc"
"github.com/martinboehm/btcd/wire"
"github.com/martinboehm/btcutil/chaincfg"
"spacecruft.org/spacecruft/blockbook/bchain/coins/btc"
)
// magic numbers

View File

@ -3,6 +3,8 @@
package monacoin
import (
"blockbook/bchain"
"blockbook/bchain/coins/btc"
"encoding/hex"
"math/big"
"os"
@ -10,8 +12,6 @@ import (
"testing"
"github.com/martinboehm/btcutil/chaincfg"
"spacecruft.org/spacecruft/blockbook/bchain"
"spacecruft.org/spacecruft/blockbook/bchain/coins/btc"
)
func TestMain(m *testing.M) {

View File

@ -1,11 +1,11 @@
package monacoin
import (
"blockbook/bchain"
"blockbook/bchain/coins/btc"
"encoding/json"
"github.com/golang/glog"
"spacecruft.org/spacecruft/blockbook/bchain"
"spacecruft.org/spacecruft/blockbook/bchain/coins/btc"
)
// MonacoinRPC is an interface to JSON-RPC bitcoind service.

View File

@ -1,17 +1,18 @@
package monetaryunit
import (
"blockbook/bchain"
"blockbook/bchain/coins/btc"
"blockbook/bchain/coins/utils"
"bytes"
"io"
"encoding/hex"
"encoding/json"
"io"
"github.com/juju/errors"
"github.com/martinboehm/btcd/wire"
"github.com/martinboehm/btcutil/chaincfg"
"spacecruft.org/spacecruft/blockbook/bchain"
"spacecruft.org/spacecruft/blockbook/bchain/coins/btc"
"spacecruft.org/spacecruft/blockbook/bchain/coins/utils"
)
const (

View File

@ -3,6 +3,8 @@
package monetaryunit
import (
"blockbook/bchain"
"blockbook/bchain/coins/btc"
"encoding/hex"
"math/big"
"os"
@ -10,8 +12,6 @@ import (
"testing"
"github.com/martinboehm/btcutil/chaincfg"
"spacecruft.org/spacecruft/blockbook/bchain"
"spacecruft.org/spacecruft/blockbook/bchain/coins/btc"
)
func TestMain(m *testing.M) {

View File

@ -1,11 +1,11 @@
package monetaryunit
import (
"blockbook/bchain"
"blockbook/bchain/coins/btc"
"encoding/json"
"github.com/golang/glog"
"spacecruft.org/spacecruft/blockbook/bchain"
"spacecruft.org/spacecruft/blockbook/bchain/coins/btc"
)
// MonetaryUnitRPC is an interface to JSON-RPC bitcoind service.

View File

@ -1,13 +1,13 @@
package myriad
import (
"blockbook/bchain"
"blockbook/bchain/coins/btc"
"blockbook/bchain/coins/utils"
"bytes"
"github.com/martinboehm/btcd/wire"
"github.com/martinboehm/btcutil/chaincfg"
"spacecruft.org/spacecruft/blockbook/bchain"
"spacecruft.org/spacecruft/blockbook/bchain/coins/btc"
"spacecruft.org/spacecruft/blockbook/bchain/coins/utils"
)
// magic numbers

View File

@ -3,6 +3,8 @@
package myriad
import (
"blockbook/bchain"
"blockbook/bchain/coins/btc"
"encoding/hex"
"math/big"
"os"
@ -10,8 +12,6 @@ import (
"testing"
"github.com/martinboehm/btcutil/chaincfg"
"spacecruft.org/spacecruft/blockbook/bchain"
"spacecruft.org/spacecruft/blockbook/bchain/coins/btc"
)
func TestMain(m *testing.M) {

View File

@ -1,11 +1,11 @@
package myriad
import (
"blockbook/bchain"
"blockbook/bchain/coins/btc"
"encoding/json"
"github.com/golang/glog"
"spacecruft.org/spacecruft/blockbook/bchain"
"spacecruft.org/spacecruft/blockbook/bchain/coins/btc"
)
// MyriadRPC is an interface to JSON-RPC bitcoind service.

View File

@ -1,13 +1,13 @@
package namecoin
import (
"blockbook/bchain"
"blockbook/bchain/coins/btc"
"blockbook/bchain/coins/utils"
"bytes"
"github.com/martinboehm/btcd/wire"
"github.com/martinboehm/btcutil/chaincfg"
"spacecruft.org/spacecruft/blockbook/bchain"
"spacecruft.org/spacecruft/blockbook/bchain/coins/btc"
"spacecruft.org/spacecruft/blockbook/bchain/coins/utils"
)
const (

View File

@ -3,6 +3,7 @@
package namecoin
import (
"blockbook/bchain/coins/btc"
"bytes"
"encoding/hex"
"fmt"
@ -13,7 +14,6 @@ import (
"testing"
"github.com/martinboehm/btcutil/chaincfg"
"spacecruft.org/spacecruft/blockbook/bchain/coins/btc"
)
func TestMain(m *testing.M) {

View File

@ -1,11 +1,11 @@
package namecoin
import (
"blockbook/bchain"
"blockbook/bchain/coins/btc"
"encoding/json"
"github.com/golang/glog"
"spacecruft.org/spacecruft/blockbook/bchain"
"spacecruft.org/spacecruft/blockbook/bchain/coins/btc"
)
// NamecoinRPC is an interface to JSON-RPC namecoin service.

View File

@ -1,18 +1,18 @@
package nuls
import (
"blockbook/bchain"
"blockbook/bchain/coins/btc"
"bytes"
"encoding/binary"
"encoding/json"
"errors"
vlq "github.com/bsm/go-vlq"
"github.com/martinboehm/btcd/wire"
"github.com/martinboehm/btcutil/base58"
"github.com/martinboehm/btcd/wire"
"github.com/martinboehm/btcutil/chaincfg"
"github.com/martinboehm/btcutil/hdkeychain"
"spacecruft.org/spacecruft/blockbook/bchain"
"spacecruft.org/spacecruft/blockbook/bchain/coins/btc"
)
// magic numbers

View File

@ -1,18 +1,16 @@
// +build unittest
package nuls
import (
"blockbook/bchain"
"blockbook/bchain/coins/btc"
"encoding/hex"
"encoding/json"
"math/big"
"reflect"
"testing"
"github.com/ethereum/go-ethereum/common/hexutil"
"github.com/martinboehm/btcutil/hdkeychain"
"spacecruft.org/spacecruft/blockbook/bchain"
"spacecruft.org/spacecruft/blockbook/bchain/coins/btc"
"spacecruft.org/spacecruft/blockbook/common"
)
var (
@ -43,7 +41,7 @@ func init() {
{
ValueSat: *big.NewInt(399999000000),
N: 0,
JsonValue: common.JSONNumber("0"),
JsonValue: json.Number("0"),
ScriptPubKey: bchain.ScriptPubKey{
Hex: "Nse4zpZHsUuU7h5ymv28pcGbwHju3joV",
Addresses: []string{
@ -75,7 +73,7 @@ func init() {
{
ValueSat: *big.NewInt(400000000000),
N: 0,
JsonValue: common.JSONNumber("0"),
JsonValue: json.Number("0"),
ScriptPubKey: bchain.ScriptPubKey{
Hex: "Nse4ikjE88g2BgsNwsswTdkSwiSrKjjS",
Addresses: []string{
@ -86,7 +84,7 @@ func init() {
{
ValueSat: *big.NewInt(7286565570000),
N: 1,
JsonValue: common.JSONNumber("0"),
JsonValue: json.Number("0"),
ScriptPubKey: bchain.ScriptPubKey{
Hex: "Nse119z2oSDJYkFkxmwYDiYtPfBeNkqi",
Addresses: []string{

View File

@ -1,6 +1,8 @@
package nuls
import (
"blockbook/bchain"
"blockbook/bchain/coins/btc"
"bytes"
"encoding/base64"
"encoding/hex"
@ -14,10 +16,9 @@ import (
"strconv"
"time"
"github.com/golang/glog"
"github.com/juju/errors"
"spacecruft.org/spacecruft/blockbook/bchain"
"spacecruft.org/spacecruft/blockbook/bchain/coins/btc"
"github.com/golang/glog"
)
// NulsRPC is an interface to JSON-RPC bitcoind service

View File

@ -1,266 +0,0 @@
package omotenashicoin
import (
"bytes"
"encoding/hex"
"encoding/json"
"io"
"math/big"
"github.com/juju/errors"
"github.com/martinboehm/btcd/blockchain"
"github.com/martinboehm/btcd/wire"
"github.com/martinboehm/btcutil/chaincfg"
"spacecruft.org/spacecruft/blockbook/bchain"
"spacecruft.org/spacecruft/blockbook/bchain/coins/btc"
"spacecruft.org/spacecruft/blockbook/bchain/coins/utils"
)
// magic numbers
const (
MainnetMagic wire.BitcoinNet = 0xdda5b5d1
TestnetMagic wire.BitcoinNet = 0x54644363
// Zerocoin op codes
OP_ZEROCOINMINT = 0xc1
OP_ZEROCOINSPEND = 0xc2
)
// chain parameters
var (
MainNetParams chaincfg.Params
TestNetParams chaincfg.Params
)
func init() {
// mainnet Address encoding magics
MainNetParams = chaincfg.MainNetParams
MainNetParams.Net = MainnetMagic
MainNetParams.PubKeyHashAddrID = []byte{63} // char S
MainNetParams.ScriptHashAddrID = []byte{18}
MainNetParams.PrivateKeyID = []byte{191}
// testnet Address encoding magics
TestNetParams = chaincfg.TestNet3Params
TestNetParams.Net = TestnetMagic
TestNetParams.PubKeyHashAddrID = []byte{83}
TestNetParams.ScriptHashAddrID = []byte{18}
TestNetParams.PrivateKeyID = []byte{193}
}
// OmotenashiCoinParser handle
type OmotenashiCoinParser struct {
*btc.BitcoinParser
baseparser *bchain.BaseParser
BitcoinOutputScriptToAddressesFunc btc.OutputScriptToAddressesFunc
}
// NewOmotenashiCoinParser returns new OmotenashiCoinParser instance
func NewOmotenashiCoinParser(params *chaincfg.Params, c *btc.Configuration) *OmotenashiCoinParser {
p := &OmotenashiCoinParser{
BitcoinParser: btc.NewBitcoinParser(params, c),
baseparser: &bchain.BaseParser{},
}
p.BitcoinOutputScriptToAddressesFunc = p.OutputScriptToAddressesFunc
p.OutputScriptToAddressesFunc = p.outputScriptToAddresses
return p
}
// GetChainParams contains network parameters for the main OmotenashiCoin network
func GetChainParams(chain string) *chaincfg.Params {
if !chaincfg.IsRegistered(&MainNetParams) {
err := chaincfg.Register(&MainNetParams)
if err == nil {
err = chaincfg.Register(&TestNetParams)
}
if err != nil {
panic(err)
}
}
switch chain {
case "test":
return &TestNetParams
default:
return &MainNetParams
}
}
// ParseBlock parses raw block to our Block struct
func (p *OmotenashiCoinParser) ParseBlock(b []byte) (*bchain.Block, error) {
r := bytes.NewReader(b)
w := wire.MsgBlock{}
h := wire.BlockHeader{}
err := h.Deserialize(r)
if err != nil {
return nil, errors.Annotatef(err, "Deserialize")
}
if h.Version > 3 && h.Version < 7 {
// Skip past AccumulatorCheckpoint (block version 4, 5 and 6)
r.Seek(32, io.SeekCurrent)
}
err = utils.DecodeTransactions(r, 0, wire.WitnessEncoding, &w)
if err != nil {
return nil, errors.Annotatef(err, "DecodeTransactions")
}
txs := make([]bchain.Tx, len(w.Transactions))
for ti, t := range w.Transactions {
txs[ti] = p.TxFromMsgTx(t, false)
}
return &bchain.Block{
BlockHeader: bchain.BlockHeader{
Size: len(b),
Time: h.Timestamp.Unix(),
},
Txs: txs,
}, nil
}
// PackTx packs transaction to byte array using protobuf
func (p *OmotenashiCoinParser) PackTx(tx *bchain.Tx, height uint32, blockTime int64) ([]byte, error) {
return p.baseparser.PackTx(tx, height, blockTime)
}
// UnpackTx unpacks transaction from protobuf byte array
func (p *OmotenashiCoinParser) UnpackTx(buf []byte) (*bchain.Tx, uint32, error) {
return p.baseparser.UnpackTx(buf)
}
// ParseTx parses byte array containing transaction and returns Tx struct
func (p *OmotenashiCoinParser) ParseTx(b []byte) (*bchain.Tx, error) {
t := wire.MsgTx{}
r := bytes.NewReader(b)
if err := t.Deserialize(r); err != nil {
return nil, err
}
tx := p.TxFromMsgTx(&t, true)
tx.Hex = hex.EncodeToString(b)
return &tx, nil
}
// TxFromMsgTx parses tx and adds handling for OP_ZEROCOINSPEND inputs
func (p *OmotenashiCoinParser) TxFromMsgTx(t *wire.MsgTx, parseAddresses bool) bchain.Tx {
vin := make([]bchain.Vin, len(t.TxIn))
for i, in := range t.TxIn {
// extra check to not confuse Tx with single OP_ZEROCOINSPEND input as a coinbase Tx
if !isZeroCoinSpendScript(in.SignatureScript) && blockchain.IsCoinBaseTx(t) {
vin[i] = bchain.Vin{
Coinbase: hex.EncodeToString(in.SignatureScript),
Sequence: in.Sequence,
}
break
}
s := bchain.ScriptSig{
Hex: hex.EncodeToString(in.SignatureScript),
// missing: Asm,
}
txid := in.PreviousOutPoint.Hash.String()
vin[i] = bchain.Vin{
Txid: txid,
Vout: in.PreviousOutPoint.Index,
Sequence: in.Sequence,
ScriptSig: s,
}
}
vout := make([]bchain.Vout, len(t.TxOut))
for i, out := range t.TxOut {
addrs := []string{}
if parseAddresses {
addrs, _, _ = p.OutputScriptToAddressesFunc(out.PkScript)
}
s := bchain.ScriptPubKey{
Hex: hex.EncodeToString(out.PkScript),
Addresses: addrs,
// missing: Asm,
// missing: Type,
}
var vs big.Int
vs.SetInt64(out.Value)
vout[i] = bchain.Vout{
ValueSat: vs,
N: uint32(i),
ScriptPubKey: s,
}
}
tx := bchain.Tx{
Txid: t.TxHash().String(),
Version: t.Version,
LockTime: t.LockTime,
Vin: vin,
Vout: vout,
// skip: BlockHash,
// skip: Confirmations,
// skip: Time,
// skip: Blocktime,
}
return tx
}
// ParseTxFromJson parses JSON message containing transaction and returns Tx struct
func (p *OmotenashiCoinParser) ParseTxFromJson(msg json.RawMessage) (*bchain.Tx, error) {
var tx bchain.Tx
err := json.Unmarshal(msg, &tx)
if err != nil {
return nil, err
}
for i := range tx.Vout {
vout := &tx.Vout[i]
// convert vout.JsonValue to big.Int and clear it, it is only temporary value used for unmarshal
vout.ValueSat, err = p.AmountToBigInt(vout.JsonValue)
if err != nil {
return nil, err
}
vout.JsonValue = ""
if vout.ScriptPubKey.Addresses == nil {
vout.ScriptPubKey.Addresses = []string{}
}
}
return &tx, nil
}
// outputScriptToAddresses converts ScriptPubKey to bitcoin addresses
func (p *OmotenashiCoinParser) outputScriptToAddresses(script []byte) ([]string, bool, error) {
if isZeroCoinSpendScript(script) {
return []string{"Zerocoin Spend"}, false, nil
}
if isZeroCoinMintScript(script) {
return []string{"Zerocoin Mint"}, false, nil
}
rv, s, _ := p.BitcoinOutputScriptToAddressesFunc(script)
return rv, s, nil
}
func (p *OmotenashiCoinParser) GetAddrDescForUnknownInput(tx *bchain.Tx, input int) bchain.AddressDescriptor {
if len(tx.Vin) > input {
scriptHex := tx.Vin[input].ScriptSig.Hex
if scriptHex != "" {
script, _ := hex.DecodeString(scriptHex)
return script
}
}
s := make([]byte, 10)
return s
}
// Checks if script is OP_ZEROCOINMINT
func isZeroCoinMintScript(signatureScript []byte) bool {
return len(signatureScript) > 1 && signatureScript[0] == OP_ZEROCOINMINT
}
// Checks if script is OP_ZEROCOINSPEND
func isZeroCoinSpendScript(signatureScript []byte) bool {
return len(signatureScript) >= 100 && signatureScript[0] == OP_ZEROCOINSPEND
}

Some files were not shown because too many files have changed in this diff Show More