Compare commits
129 Commits
v0.3.3
...
deepcrayon
Author | SHA1 | Date |
---|---|---|
jebba | a8595591f0 | |
jebba | cd8161a10d | |
jebba | f4f7612655 | |
jebba | e2a3404b06 | |
jebba | afabba64a9 | |
jebba | 473df3d139 | |
jebba | a337163a2d | |
jebba | 65be7edda2 | |
jebba | 0c93f8803d | |
jebba | 8fd633c6d3 | |
jebba | 2771784113 | |
jebba | f05eff6b13 | |
jebba | 7ba8d7f143 | |
jebba | 14c92e8bd5 | |
jebba | 4b352b5bbc | |
jebba | 124717da69 | |
jebba | 2f1c4bc3af | |
jebba | 0ce520d1d5 | |
jebba | 8ef0a2a3d5 | |
jebba | 27c9434383 | |
jebba | fb64efefdc | |
kaladin | 1f6cddd4ab | |
CodeFace | 78c8a9d499 | |
Vitalij DovhanyÄŤ | d8640f4e2f | |
vdovhanyc | d588904fb3 | |
Martin Boehm | e6e6e64351 | |
jsimon | 61c2834002 | |
Martin Boehm | 0ae8ba57a2 | |
Martin Boehm | 8f3106d009 | |
vdovhanych | 099a158f8c | |
Perlover | 37c7f4fbd1 | |
Martin Boehm | db597c1f66 | |
Martin Boehm | dcbcb99055 | |
Martin Boehm | 212b767925 | |
WO | 3fe28d185c | |
Rikard Wissing | d0a1cb29f6 | |
Martin Boehm | 2be5930862 | |
Yusaku Senga | 5fdc26bc14 | |
Martin Boehm | 7e54336e0c | |
Martin Boehm | 7dffe2e0f9 | |
Martin Boehm | d992369426 | |
David Hill | d97b5e14e8 | |
JoHnY | 9df39273ea | |
Pavol Rusnak | 66c072bf25 | |
Jin Eguchi | 505d859f91 | |
Dehumanizer77 | d631bf9265 | |
Martin Kuvandzhiev | 295b630ec8 | |
Dehumanizer77 | b4149946bd | |
Dehumanizer77 | 6981222a43 | |
Peter John Bushnell | bb9fce02cb | |
Jin Eguchi | 077e637093 | |
araarakelyan1985 | 15b88ef23d | |
Martin | 4697d756e0 | |
Martin | 4766110255 | |
Tomas Susanka | 360cac85f6 | |
jackielove4u | 554041c32c | |
CodeFace | d12e6551ea | |
Martin Boehm | 96e8329171 | |
Martin Boehm | f094ee578d | |
Martin Boehm | 00352cb5fe | |
CryptoManiac | c0c2dc4151 | |
Martin Boehm | da1c0d762e | |
Martin Boehm | fc267ed2f4 | |
Martin Boehm | 69d13e0688 | |
Martin Boehm | 248de3cb34 | |
Martin Boehm | 636167c72a | |
Martin Boehm | 24a783be50 | |
Martin Boehm | 579b42cf27 | |
Martin Boehm | 576b8b57b7 | |
Martin Kuvandzhiev | 786047f8c2 | |
Dehumanizer77 | 3ccfd181b7 | |
Dehumanizer77 | 6274f4b3d4 | |
Dehumanizer77 | 2b786c9832 | |
Dehumanizer77 | bc009454d0 | |
Dehumanizer77 | 5e7d0e9f75 | |
Pavol Rusnak | c915f35224 | |
Pavol Rusnak | 3369295e10 | |
hewigovens | 5534372e7c | |
Martin Boehm | fc25200ff8 | |
Martin Boehm | 3d9954bf79 | |
nezero | 214d0144ef | |
Liam Alford | ec79702bab | |
Scotty0448 | e666e7c5a4 | |
JoHnY | 4832205f45 | |
1000101 | b05346b1a1 | |
WO | dcf77a5680 | |
1000101 | 7f1cf09d05 | |
Martin | a1993173ab | |
jackielove4u | bea6b6230f | |
jackielove4u | 72486c606f | |
1000101 | a8ee6aefb0 | |
1000101 | 52cbc7162d | |
Pavol Rusnak | 81ce876d8b | |
Braydon Fuller | 7b70ee0ad0 | |
Braydon Fuller | a83cb7684f | |
Pavol Rusnak | 0f4eadd935 | |
1000101 | e66fa79383 | |
1000101 | f99406e9cf | |
1000101 | be73064223 | |
Panu | 79907e7aa5 | |
1000101 | 2fb1e779c0 | |
1000101 | a530f5612a | |
Martin Boehm | ab285c6b05 | |
Martin Boehm | 17c9080135 | |
1000101 | 791948623e | |
Scotty0448 | af5e8f18ba | |
root | 07ac3c8401 | |
Martin Boehm | 83616bce83 | |
codeface | 22145d0cc2 | |
Dehumanizer77 | 92ae2052c3 | |
Dehumanizer77 | 30149e51d2 | |
Martin Boehm | abb6453fb3 | |
Martin Boehm | eb4e10ac67 | |
1000101 | 5350027e1d | |
1000101 | 7d6c61623e | |
Martin Boehm | 994567aed9 | |
Martin Boehm | dd7964297d | |
Martin Boehm | 3be3bb5c3d | |
Martin Boehm | 0a3ea6e225 | |
Martin Boehm | bc001ce3a3 | |
Martin Boehm | 76324be8ec | |
Martin Boehm | 01d8e48e73 | |
Martin Boehm | ff607bc334 | |
Martin Boehm | e60c320ae7 | |
Martin Boehm | dd2dc6b2ee | |
wakiyamap | b957ed66ab | |
Adam Collier | 3ebe99edb2 | |
v | bad9f992e1 | |
jackielove4u | 707ac28954 |
|
@ -8,6 +8,7 @@ debug*
|
||||||
docker/blockbook
|
docker/blockbook
|
||||||
build/pkg-defs
|
build/pkg-defs
|
||||||
build/blockbook
|
build/blockbook
|
||||||
|
build/blockchaincfg.json
|
||||||
build/ldb
|
build/ldb
|
||||||
build/sst_dump
|
build/sst_dump
|
||||||
build/*.deb
|
build/*.deb
|
||||||
|
|
23
Makefile
23
Makefile
|
@ -1,8 +1,9 @@
|
||||||
BIN_IMAGE = blockbook-build
|
BIN_IMAGE = blockbook-build
|
||||||
DEB_IMAGE = blockbook-build-deb
|
DEB_IMAGE = blockbook-build-deb
|
||||||
PACKAGER = $(shell id -u):$(shell id -g)
|
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
|
NO_CACHE = false
|
||||||
UPDATE_VENDOR = 1
|
TCMALLOC =
|
||||||
ARGS ?=
|
ARGS ?=
|
||||||
|
|
||||||
TARGETS=$(subst .json,, $(shell ls configs/coins))
|
TARGETS=$(subst .json,, $(shell ls configs/coins))
|
||||||
|
@ -10,28 +11,28 @@ TARGETS=$(subst .json,, $(shell ls configs/coins))
|
||||||
.PHONY: build build-debug test deb
|
.PHONY: build build-debug test deb
|
||||||
|
|
||||||
build: .bin-image
|
build: .bin-image
|
||||||
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)"
|
docker run -t --rm -e PACKAGER=$(PACKAGER) -v "$(CURDIR):/src" -v "$(CURDIR)/build:/out" $(BIN_IMAGE) make build ARGS="$(ARGS)"
|
||||||
|
|
||||||
build-debug: .bin-image
|
build-debug: .bin-image
|
||||||
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)"
|
docker run -t --rm -e PACKAGER=$(PACKAGER) -v "$(CURDIR):/src" -v "$(CURDIR)/build:/out" $(BIN_IMAGE) make build-debug ARGS="$(ARGS)"
|
||||||
|
|
||||||
test: .bin-image
|
test: .bin-image
|
||||||
docker run -t --rm -e PACKAGER=$(PACKAGER) -e UPDATE_VENDOR=$(UPDATE_VENDOR) -v "$(CURDIR):/src" --network="host" $(BIN_IMAGE) make test ARGS="$(ARGS)"
|
docker run -t --rm -e PACKAGER=$(PACKAGER) -v "$(CURDIR):/src" --network="host" $(BIN_IMAGE) make test ARGS="$(ARGS)"
|
||||||
|
|
||||||
test-integration: .bin-image
|
test-integration: .bin-image
|
||||||
docker run -t --rm -e PACKAGER=$(PACKAGER) -e UPDATE_VENDOR=$(UPDATE_VENDOR) -v "$(CURDIR):/src" --network="host" $(BIN_IMAGE) make test-integration ARGS="$(ARGS)"
|
docker run -t --rm -e PACKAGER=$(PACKAGER) -v "$(CURDIR):/src" --network="host" $(BIN_IMAGE) make test-integration ARGS="$(ARGS)"
|
||||||
|
|
||||||
test-all: .bin-image
|
test-all: .bin-image
|
||||||
docker run -t --rm -e PACKAGER=$(PACKAGER) -e UPDATE_VENDOR=$(UPDATE_VENDOR) -v "$(CURDIR):/src" --network="host" $(BIN_IMAGE) make test-all ARGS="$(ARGS)"
|
docker run -t --rm -e PACKAGER=$(PACKAGER) -v "$(CURDIR):/src" --network="host" $(BIN_IMAGE) make test-all ARGS="$(ARGS)"
|
||||||
|
|
||||||
deb-backend-%: .deb-image
|
deb-backend-%: .deb-image
|
||||||
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)
|
docker run -t --rm -e PACKAGER=$(PACKAGER) -v "$(CURDIR):/src" -v "$(CURDIR)/build:/out" $(DEB_IMAGE) /build/build-deb.sh backend $* $(ARGS)
|
||||||
|
|
||||||
deb-blockbook-%: .deb-image
|
deb-blockbook-%: .deb-image
|
||||||
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)
|
docker run -t --rm -e PACKAGER=$(PACKAGER) -v "$(CURDIR):/src" -v "$(CURDIR)/build:/out" $(DEB_IMAGE) /build/build-deb.sh blockbook $* $(ARGS)
|
||||||
|
|
||||||
deb-%: .deb-image
|
deb-%: .deb-image
|
||||||
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)
|
docker run -t --rm -e PACKAGER=$(PACKAGER) -v "$(CURDIR):/src" -v "$(CURDIR)/build:/out" $(DEB_IMAGE) /build/build-deb.sh all $* $(ARGS)
|
||||||
|
|
||||||
deb-blockbook-all: clean-deb $(addprefix deb-blockbook-, $(TARGETS))
|
deb-blockbook-all: clean-deb $(addprefix deb-blockbook-, $(TARGETS))
|
||||||
|
|
||||||
|
@ -44,8 +45,8 @@ build-images: clean-images
|
||||||
|
|
||||||
.bin-image:
|
.bin-image:
|
||||||
@if [ $$(build/tools/image_status.sh $(BIN_IMAGE):latest build/docker) != "ok" ]; then \
|
@if [ $$(build/tools/image_status.sh $(BIN_IMAGE):latest build/docker) != "ok" ]; then \
|
||||||
echo "Building image $(BIN_IMAGE)..."; \
|
echo "Building image $(BIN_IMAGE) from $(BASE_IMAGE)"; \
|
||||||
docker build --no-cache=$(NO_CACHE) -t $(BIN_IMAGE) build/docker/bin; \
|
docker build --no-cache=$(NO_CACHE) --build-arg TCMALLOC=$(TCMALLOC) --build-arg BASE_IMAGE=$(BASE_IMAGE) -t $(BIN_IMAGE) build/docker/bin; \
|
||||||
else \
|
else \
|
||||||
echo "Image $(BIN_IMAGE) is up to date"; \
|
echo "Image $(BIN_IMAGE) is up to date"; \
|
||||||
fi
|
fi
|
||||||
|
|
|
@ -0,0 +1,74 @@
|
||||||
|
[![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).
|
93
README.md
93
README.md
|
@ -1,74 +1,57 @@
|
||||||
[![Go Report Card](https://goreportcard.com/badge/trezor/blockbook)](https://goreportcard.com/report/trezor/blockbook)
|
# Fork
|
||||||
|
Fork of Trezor Blockbook.
|
||||||
|
|
||||||
# Blockbook
|
|
||||||
|
|
||||||
**Blockbook** is back-end service for Trezor wallet. Main features of **Blockbook** are:
|
The differences:
|
||||||
|
|
||||||
- index of addresses and address balances of the connected block chain
|
* Just for Ethereum.
|
||||||
- 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
|
* Use existing `geth --full` server.
|
||||||
|
|
||||||
Officially supported platform is **Debian Linux** and **AMD64** architecture.
|
* Don't require `backend-*` package.
|
||||||
|
|
||||||
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.
|
* Minimal UI, dark theme.
|
||||||
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)).
|
* Listen only on localhost, no SSL.
|
||||||
|
|
||||||
Developer build guide is [here](/docs/build.md).
|
* Use spacecruft repos, not github.
|
||||||
|
|
||||||
Contribution guide is [here](CONTRIBUTING.md).
|
* Don't use CDN.
|
||||||
|
|
||||||
## Implemented coins
|
# Install
|
||||||
|
|
||||||
Blockbook currently supports over 30 coins. The Trezor team implemented
|
```
|
||||||
|
# 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
|
||||||
|
```
|
||||||
|
|
||||||
- Bitcoin, Bitcoin Cash, Zcash, Dash, Litecoin, Bitcoin Gold, Ethereum, Ethereum Classic, Dogecoin, Namecoin, Vertcoin, DigiByte, Liquid
|
Edit config:
|
||||||
|
```
|
||||||
|
vim /opt/coins/blockbook/ethereum/config/blockchaincfg.json
|
||||||
|
```
|
||||||
|
|
||||||
the rest of coins were implemented by the community.
|
XXX Hardcoded into systemd script, set `geth` node:
|
||||||
|
|
||||||
Testnets for some coins are also supported, for example:
|
```
|
||||||
- Bitcoin Testnet, Bitcoin Cash Testnet, ZCash Testnet, Ethereum Testnet Ropsten
|
vim /lib/systemd/system/blockbook-ethereum.service
|
||||||
|
systemctl daemon-reload
|
||||||
|
```
|
||||||
|
|
||||||
List of all implemented coins is in [the registry of ports](/docs/ports.md).
|
Start:
|
||||||
|
```
|
||||||
|
systemctl start blockbook-ethereum.service
|
||||||
|
```
|
||||||
|
|
||||||
## Common issues when running Blockbook or implementing additional coins
|
Logs:
|
||||||
|
```
|
||||||
|
tail -f /opt/coins/blockbook/ethereum/logs/blockbook.INFO
|
||||||
|
```
|
||||||
|
|
||||||
#### Out of memory when doing initial synchronization
|
# Upstream
|
||||||
|
Fork of Trezor Blockbook. See `README-upstream.md`.
|
||||||
|
|
||||||
How to reduce memory footprint of the initial sync:
|
* https://github.com/trezor/blockbook
|
||||||
|
|
||||||
- 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).
|
|
||||||
|
|
72
api/types.go
72
api/types.go
|
@ -7,9 +7,10 @@ import (
|
||||||
"sort"
|
"sort"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
"github.com/trezor/blockbook/bchain"
|
"spacecruft.org/spacecruft/blockbook/bchain"
|
||||||
"github.com/trezor/blockbook/common"
|
"spacecruft.org/spacecruft/blockbook/bchain/coins/eth"
|
||||||
"github.com/trezor/blockbook/db"
|
"spacecruft.org/spacecruft/blockbook/common"
|
||||||
|
"spacecruft.org/spacecruft/blockbook/db"
|
||||||
)
|
)
|
||||||
|
|
||||||
const maxUint32 = ^uint32(0)
|
const maxUint32 = ^uint32(0)
|
||||||
|
@ -170,12 +171,12 @@ type TokenTransfer struct {
|
||||||
|
|
||||||
// EthereumSpecific contains ethereum specific transaction data
|
// EthereumSpecific contains ethereum specific transaction data
|
||||||
type EthereumSpecific struct {
|
type EthereumSpecific struct {
|
||||||
Status int `json:"status"` // 1 OK, 0 Fail, -1 pending
|
Status eth.TxStatus `json:"status"` // 1 OK, 0 Fail, -1 pending
|
||||||
Nonce uint64 `json:"nonce"`
|
Nonce uint64 `json:"nonce"`
|
||||||
GasLimit *big.Int `json:"gasLimit"`
|
GasLimit *big.Int `json:"gasLimit"`
|
||||||
GasUsed *big.Int `json:"gasUsed"`
|
GasUsed *big.Int `json:"gasUsed"`
|
||||||
GasPrice *Amount `json:"gasPrice"`
|
GasPrice *Amount `json:"gasPrice"`
|
||||||
Data string `json:"data,omitempty"`
|
Data string `json:"data,omitempty"`
|
||||||
}
|
}
|
||||||
|
|
||||||
// Tx holds information about a transaction
|
// Tx holds information about a transaction
|
||||||
|
@ -195,8 +196,7 @@ type Tx struct {
|
||||||
FeesSat *Amount `json:"fees,omitempty"`
|
FeesSat *Amount `json:"fees,omitempty"`
|
||||||
Hex string `json:"hex,omitempty"`
|
Hex string `json:"hex,omitempty"`
|
||||||
Rbf bool `json:"rbf,omitempty"`
|
Rbf bool `json:"rbf,omitempty"`
|
||||||
CoinSpecificData interface{} `json:"-"`
|
CoinSpecificData json.RawMessage `json:"coinSpecificData,omitempty"`
|
||||||
CoinSpecificJSON json.RawMessage `json:"-"`
|
|
||||||
TokenTransfers []TokenTransfer `json:"tokenTransfers,omitempty"`
|
TokenTransfers []TokenTransfer `json:"tokenTransfers,omitempty"`
|
||||||
EthereumSpecific *EthereumSpecific `json:"ethereumSpecific,omitempty"`
|
EthereumSpecific *EthereumSpecific `json:"ethereumSpecific,omitempty"`
|
||||||
}
|
}
|
||||||
|
@ -226,6 +226,8 @@ const (
|
||||||
AddressFilterVoutInputs = -2
|
AddressFilterVoutInputs = -2
|
||||||
// AddressFilterVoutOutputs specifies that only txs where the address is as output are returned
|
// AddressFilterVoutOutputs specifies that only txs where the address is as output are returned
|
||||||
AddressFilterVoutOutputs = -3
|
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 - return only tokens with nonzero balance
|
||||||
TokensToReturnNonzeroBalance TokensToReturn = 0
|
TokensToReturnNonzeroBalance TokensToReturn = 0
|
||||||
|
@ -301,12 +303,13 @@ func (a Utxos) Less(i, j int) bool {
|
||||||
|
|
||||||
// BalanceHistory contains info about one point in time of balance history
|
// BalanceHistory contains info about one point in time of balance history
|
||||||
type BalanceHistory struct {
|
type BalanceHistory struct {
|
||||||
Time uint32 `json:"time"`
|
Time uint32 `json:"time"`
|
||||||
Txs uint32 `json:"txs"`
|
Txs uint32 `json:"txs"`
|
||||||
ReceivedSat *Amount `json:"received"`
|
ReceivedSat *Amount `json:"received"`
|
||||||
SentSat *Amount `json:"sent"`
|
SentSat *Amount `json:"sent"`
|
||||||
FiatRates map[string]float64 `json:"rates,omitempty"`
|
SentToSelfSat *Amount `json:"sentToSelf"`
|
||||||
Txid string `json:"txid,omitempty"`
|
FiatRates map[string]float64 `json:"rates,omitempty"`
|
||||||
|
Txid string `json:"txid,omitempty"`
|
||||||
}
|
}
|
||||||
|
|
||||||
// BalanceHistories is array of BalanceHistory
|
// BalanceHistories is array of BalanceHistory
|
||||||
|
@ -328,8 +331,9 @@ func (a BalanceHistories) SortAndAggregate(groupByTime uint32) BalanceHistories
|
||||||
bhs := make(BalanceHistories, 0)
|
bhs := make(BalanceHistories, 0)
|
||||||
if len(a) > 0 {
|
if len(a) > 0 {
|
||||||
bha := BalanceHistory{
|
bha := BalanceHistory{
|
||||||
SentSat: &Amount{},
|
ReceivedSat: &Amount{},
|
||||||
ReceivedSat: &Amount{},
|
SentSat: &Amount{},
|
||||||
|
SentToSelfSat: &Amount{},
|
||||||
}
|
}
|
||||||
sort.Sort(a)
|
sort.Sort(a)
|
||||||
for i := range a {
|
for i := range a {
|
||||||
|
@ -342,17 +346,19 @@ func (a BalanceHistories) SortAndAggregate(groupByTime uint32) BalanceHistories
|
||||||
bhs = append(bhs, bha)
|
bhs = append(bhs, bha)
|
||||||
}
|
}
|
||||||
bha = BalanceHistory{
|
bha = BalanceHistory{
|
||||||
Time: time,
|
Time: time,
|
||||||
SentSat: &Amount{},
|
ReceivedSat: &Amount{},
|
||||||
ReceivedSat: &Amount{},
|
SentSat: &Amount{},
|
||||||
|
SentToSelfSat: &Amount{},
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if bha.Txid != bh.Txid {
|
if bha.Txid != bh.Txid {
|
||||||
bha.Txs += bh.Txs
|
bha.Txs += bh.Txs
|
||||||
bha.Txid = bh.Txid
|
bha.Txid = bh.Txid
|
||||||
}
|
}
|
||||||
(*big.Int)(bha.SentSat).Add((*big.Int)(bha.SentSat), (*big.Int)(bh.SentSat))
|
|
||||||
(*big.Int)(bha.ReceivedSat).Add((*big.Int)(bha.ReceivedSat), (*big.Int)(bh.ReceivedSat))
|
(*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))
|
||||||
}
|
}
|
||||||
if bha.Txs > 0 {
|
if bha.Txs > 0 {
|
||||||
bha.Txid = ""
|
bha.Txid = ""
|
||||||
|
@ -415,26 +421,10 @@ type BlockbookInfo struct {
|
||||||
About string `json:"about"`
|
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
|
// SystemInfo contains information about the running blockbook and backend instance
|
||||||
type SystemInfo struct {
|
type SystemInfo struct {
|
||||||
Blockbook *BlockbookInfo `json:"blockbook"`
|
Blockbook *BlockbookInfo `json:"blockbook"`
|
||||||
Backend *BackendInfo `json:"backend"`
|
Backend *common.BackendInfo `json:"backend"`
|
||||||
}
|
}
|
||||||
|
|
||||||
// MempoolTxid contains information about a transaction in mempool
|
// MempoolTxid contains information about a transaction in mempool
|
||||||
|
|
|
@ -67,20 +67,22 @@ func TestBalanceHistories_SortAndAggregate(t *testing.T) {
|
||||||
name: "one",
|
name: "one",
|
||||||
a: []BalanceHistory{
|
a: []BalanceHistory{
|
||||||
{
|
{
|
||||||
ReceivedSat: (*Amount)(big.NewInt(1)),
|
ReceivedSat: (*Amount)(big.NewInt(1)),
|
||||||
SentSat: (*Amount)(big.NewInt(2)),
|
SentSat: (*Amount)(big.NewInt(2)),
|
||||||
Time: 1521514812,
|
SentToSelfSat: (*Amount)(big.NewInt(1)),
|
||||||
Txid: "00b2c06055e5e90e9c82bd4181fde310104391a7fa4f289b1704e5d90caa3840",
|
Time: 1521514812,
|
||||||
Txs: 1,
|
Txid: "00b2c06055e5e90e9c82bd4181fde310104391a7fa4f289b1704e5d90caa3840",
|
||||||
|
Txs: 1,
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
groupByTime: 3600,
|
groupByTime: 3600,
|
||||||
want: []BalanceHistory{
|
want: []BalanceHistory{
|
||||||
{
|
{
|
||||||
ReceivedSat: (*Amount)(big.NewInt(1)),
|
ReceivedSat: (*Amount)(big.NewInt(1)),
|
||||||
SentSat: (*Amount)(big.NewInt(2)),
|
SentSat: (*Amount)(big.NewInt(2)),
|
||||||
Time: 1521514800,
|
SentToSelfSat: (*Amount)(big.NewInt(1)),
|
||||||
Txs: 1,
|
Time: 1521514800,
|
||||||
|
Txs: 1,
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
@ -88,67 +90,76 @@ func TestBalanceHistories_SortAndAggregate(t *testing.T) {
|
||||||
name: "aggregate",
|
name: "aggregate",
|
||||||
a: []BalanceHistory{
|
a: []BalanceHistory{
|
||||||
{
|
{
|
||||||
ReceivedSat: (*Amount)(big.NewInt(1)),
|
ReceivedSat: (*Amount)(big.NewInt(1)),
|
||||||
SentSat: (*Amount)(big.NewInt(2)),
|
SentSat: (*Amount)(big.NewInt(2)),
|
||||||
Time: 1521504812,
|
SentToSelfSat: (*Amount)(big.NewInt(0)),
|
||||||
Txid: "0011223344556677889900112233445566778899001122334455667788990011",
|
Time: 1521504812,
|
||||||
Txs: 1,
|
Txid: "0011223344556677889900112233445566778899001122334455667788990011",
|
||||||
|
Txs: 1,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
ReceivedSat: (*Amount)(big.NewInt(3)),
|
ReceivedSat: (*Amount)(big.NewInt(3)),
|
||||||
SentSat: (*Amount)(big.NewInt(4)),
|
SentSat: (*Amount)(big.NewInt(4)),
|
||||||
Time: 1521504812,
|
SentToSelfSat: (*Amount)(big.NewInt(2)),
|
||||||
Txid: "00b2c06055e5e90e9c82bd4181fde310104391a7fa4f289b1704e5d90caa3840",
|
Time: 1521504812,
|
||||||
Txs: 1,
|
Txid: "00b2c06055e5e90e9c82bd4181fde310104391a7fa4f289b1704e5d90caa3840",
|
||||||
|
Txs: 1,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
ReceivedSat: (*Amount)(big.NewInt(5)),
|
ReceivedSat: (*Amount)(big.NewInt(5)),
|
||||||
SentSat: (*Amount)(big.NewInt(6)),
|
SentSat: (*Amount)(big.NewInt(6)),
|
||||||
Time: 1521514812,
|
SentToSelfSat: (*Amount)(big.NewInt(3)),
|
||||||
Txid: "00b2c06055e5e90e9c82bd4181fde310104391a7fa4f289b1704e5d90caa3840",
|
Time: 1521514812,
|
||||||
Txs: 1,
|
Txid: "00b2c06055e5e90e9c82bd4181fde310104391a7fa4f289b1704e5d90caa3840",
|
||||||
|
Txs: 1,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
ReceivedSat: (*Amount)(big.NewInt(7)),
|
ReceivedSat: (*Amount)(big.NewInt(7)),
|
||||||
SentSat: (*Amount)(big.NewInt(8)),
|
SentSat: (*Amount)(big.NewInt(8)),
|
||||||
Time: 1521504812,
|
SentToSelfSat: (*Amount)(big.NewInt(3)),
|
||||||
Txid: "00b2c06055e5e90e9c82bd4181fde310104391a7fa4f289b1704e5d90caa3840",
|
Time: 1521504812,
|
||||||
Txs: 1,
|
Txid: "00b2c06055e5e90e9c82bd4181fde310104391a7fa4f289b1704e5d90caa3840",
|
||||||
|
Txs: 1,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
ReceivedSat: (*Amount)(big.NewInt(9)),
|
ReceivedSat: (*Amount)(big.NewInt(9)),
|
||||||
SentSat: (*Amount)(big.NewInt(10)),
|
SentSat: (*Amount)(big.NewInt(10)),
|
||||||
Time: 1521534812,
|
SentToSelfSat: (*Amount)(big.NewInt(5)),
|
||||||
Txid: "0011223344556677889900112233445566778899001122334455667788990011",
|
Time: 1521534812,
|
||||||
Txs: 1,
|
Txid: "0011223344556677889900112233445566778899001122334455667788990011",
|
||||||
|
Txs: 1,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
ReceivedSat: (*Amount)(big.NewInt(11)),
|
ReceivedSat: (*Amount)(big.NewInt(11)),
|
||||||
SentSat: (*Amount)(big.NewInt(12)),
|
SentSat: (*Amount)(big.NewInt(12)),
|
||||||
Time: 1521534812,
|
SentToSelfSat: (*Amount)(big.NewInt(6)),
|
||||||
Txid: "1122334455667788990011223344556677889900112233445566778899001100",
|
Time: 1521534812,
|
||||||
Txs: 1,
|
Txid: "1122334455667788990011223344556677889900112233445566778899001100",
|
||||||
|
Txs: 1,
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
groupByTime: 3600,
|
groupByTime: 3600,
|
||||||
want: []BalanceHistory{
|
want: []BalanceHistory{
|
||||||
{
|
{
|
||||||
ReceivedSat: (*Amount)(big.NewInt(11)),
|
ReceivedSat: (*Amount)(big.NewInt(11)),
|
||||||
SentSat: (*Amount)(big.NewInt(14)),
|
SentSat: (*Amount)(big.NewInt(14)),
|
||||||
Time: 1521504000,
|
SentToSelfSat: (*Amount)(big.NewInt(5)),
|
||||||
Txs: 2,
|
Time: 1521504000,
|
||||||
|
Txs: 2,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
ReceivedSat: (*Amount)(big.NewInt(5)),
|
ReceivedSat: (*Amount)(big.NewInt(5)),
|
||||||
SentSat: (*Amount)(big.NewInt(6)),
|
SentSat: (*Amount)(big.NewInt(6)),
|
||||||
Time: 1521514800,
|
SentToSelfSat: (*Amount)(big.NewInt(3)),
|
||||||
Txs: 1,
|
Time: 1521514800,
|
||||||
|
Txs: 1,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
ReceivedSat: (*Amount)(big.NewInt(20)),
|
ReceivedSat: (*Amount)(big.NewInt(20)),
|
||||||
SentSat: (*Amount)(big.NewInt(22)),
|
SentSat: (*Amount)(big.NewInt(22)),
|
||||||
Time: 1521532800,
|
SentToSelfSat: (*Amount)(big.NewInt(11)),
|
||||||
Txs: 2,
|
Time: 1521532800,
|
||||||
|
Txs: 2,
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
|
|
@ -3,7 +3,7 @@ package api
|
||||||
import (
|
import (
|
||||||
"math/big"
|
"math/big"
|
||||||
|
|
||||||
"github.com/trezor/blockbook/bchain"
|
"spacecruft.org/spacecruft/blockbook/bchain"
|
||||||
)
|
)
|
||||||
|
|
||||||
// ScriptSigV1 is used for legacy api v1
|
// ScriptSigV1 is used for legacy api v1
|
||||||
|
|
362
api/worker.go
362
api/worker.go
|
@ -14,10 +14,10 @@ import (
|
||||||
|
|
||||||
"github.com/golang/glog"
|
"github.com/golang/glog"
|
||||||
"github.com/juju/errors"
|
"github.com/juju/errors"
|
||||||
"github.com/trezor/blockbook/bchain"
|
"spacecruft.org/spacecruft/blockbook/bchain"
|
||||||
"github.com/trezor/blockbook/bchain/coins/eth"
|
"spacecruft.org/spacecruft/blockbook/bchain/coins/eth"
|
||||||
"github.com/trezor/blockbook/common"
|
"spacecruft.org/spacecruft/blockbook/common"
|
||||||
"github.com/trezor/blockbook/db"
|
"spacecruft.org/spacecruft/blockbook/db"
|
||||||
)
|
)
|
||||||
|
|
||||||
// Worker is handle to api worker
|
// Worker is handle to api worker
|
||||||
|
@ -253,32 +253,7 @@ func (w *Worker) GetTransactionFromBchainTx(bchainTx *bchain.Tx, height int, spe
|
||||||
if err != nil {
|
if err != nil {
|
||||||
glog.Errorf("GetErc20FromTx error %v, %v", err, bchainTx)
|
glog.Errorf("GetErc20FromTx error %v, %v", err, bchainTx)
|
||||||
}
|
}
|
||||||
tokens = make([]TokenTransfer, len(ets))
|
tokens = w.getTokensFromErc20(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)
|
ethTxData := eth.GetEthereumTxData(bchainTx)
|
||||||
// mempool txs do not have fees yet
|
// mempool txs do not have fees yet
|
||||||
if ethTxData.GasUsed != nil {
|
if ethTxData.GasUsed != nil {
|
||||||
|
@ -299,7 +274,8 @@ func (w *Worker) GetTransactionFromBchainTx(bchainTx *bchain.Tx, height int, spe
|
||||||
// for now do not return size, we would have to compute vsize of segwit transactions
|
// for now do not return size, we would have to compute vsize of segwit transactions
|
||||||
// size:=len(bchainTx.Hex) / 2
|
// size:=len(bchainTx.Hex) / 2
|
||||||
var sj json.RawMessage
|
var sj json.RawMessage
|
||||||
if specificJSON {
|
// return CoinSpecificData for all mempool transactions or if requested
|
||||||
|
if specificJSON || bchainTx.Confirmations == 0 {
|
||||||
sj, err = w.chain.GetTransactionSpecific(bchainTx)
|
sj, err = w.chain.GetTransactionSpecific(bchainTx)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
|
@ -324,14 +300,140 @@ func (w *Worker) GetTransactionFromBchainTx(bchainTx *bchain.Tx, height int, spe
|
||||||
Rbf: rbf,
|
Rbf: rbf,
|
||||||
Vin: vins,
|
Vin: vins,
|
||||||
Vout: vouts,
|
Vout: vouts,
|
||||||
CoinSpecificData: bchainTx.CoinSpecificData,
|
CoinSpecificData: sj,
|
||||||
CoinSpecificJSON: sj,
|
|
||||||
TokenTransfers: tokens,
|
TokenTransfers: tokens,
|
||||||
EthereumSpecific: ethSpecific,
|
EthereumSpecific: ethSpecific,
|
||||||
}
|
}
|
||||||
return r, nil
|
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) {
|
func (w *Worker) getAddressTxids(addrDesc bchain.AddressDescriptor, mempool bool, filter *AddressFilter, maxResults int) ([]string, error) {
|
||||||
var err error
|
var err error
|
||||||
txids := make([]string, 0, 4)
|
txids := make([]string, 0, 4)
|
||||||
|
@ -401,6 +503,19 @@ func (t *Tx) getAddrVoutValue(addrDesc bchain.AddressDescriptor) *big.Int {
|
||||||
}
|
}
|
||||||
return &val
|
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 {
|
func (t *Tx) getAddrVinValue(addrDesc bchain.AddressDescriptor) *big.Int {
|
||||||
var val big.Int
|
var val big.Int
|
||||||
|
@ -497,6 +612,44 @@ func computePaging(count, page, itemsOnPage int) (Paging, int, int, int) {
|
||||||
}, from, to, page
|
}, 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) {
|
func (w *Worker) getEthereumTypeAddressBalances(addrDesc bchain.AddressDescriptor, details AccountDetails, filter *AddressFilter) (*db.AddrBalance, []Token, *bchain.Erc20Contract, uint64, int, int, error) {
|
||||||
var (
|
var (
|
||||||
ba *db.AddrBalance
|
ba *db.AddrBalance
|
||||||
|
@ -515,6 +668,13 @@ func (w *Worker) getEthereumTypeAddressBalances(addrDesc bchain.AddressDescripto
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, nil, nil, 0, 0, 0, errors.Annotatef(err, "EthereumTypeGetBalance %v", addrDesc)
|
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 {
|
if ca != nil {
|
||||||
ba = &db.AddrBalance{
|
ba = &db.AddrBalance{
|
||||||
Txs: uint32(ca.TotalTxs),
|
Txs: uint32(ca.TotalTxs),
|
||||||
|
@ -526,13 +686,6 @@ func (w *Worker) getEthereumTypeAddressBalances(addrDesc bchain.AddressDescripto
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, nil, nil, 0, 0, 0, errors.Annotatef(err, "EthereumTypeGetNonce %v", addrDesc)
|
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 {
|
if details > AccountDetailsBasic {
|
||||||
tokens = make([]Token, len(ca.Contracts))
|
tokens = make([]Token, len(ca.Contracts))
|
||||||
var j int
|
var j int
|
||||||
|
@ -544,43 +697,26 @@ func (w *Worker) getEthereumTypeAddressBalances(addrDesc bchain.AddressDescripto
|
||||||
// filter only transactions of this contract
|
// filter only transactions of this contract
|
||||||
filter.Vout = i + 1
|
filter.Vout = i + 1
|
||||||
}
|
}
|
||||||
validContract := true
|
t, err := w.getEthereumToken(i+1, addrDesc, c.Contract, details, int(c.Txs))
|
||||||
ci, err := w.chain.EthereumTypeGetErc20ContractInfo(c.Contract)
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, nil, nil, 0, 0, 0, errors.Annotatef(err, "EthereumTypeGetErc20ContractInfo %v", c.Contract)
|
return nil, nil, nil, 0, 0, 0, err
|
||||||
}
|
|
||||||
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++
|
j++
|
||||||
}
|
}
|
||||||
tokens = tokens[: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]
|
||||||
|
}
|
||||||
}
|
}
|
||||||
ci, err = w.chain.EthereumTypeGetErc20ContractInfo(addrDesc)
|
ci, err = w.chain.EthereumTypeGetErc20ContractInfo(addrDesc)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
@ -594,6 +730,8 @@ func (w *Worker) getEthereumTypeAddressBalances(addrDesc bchain.AddressDescripto
|
||||||
totalResults = int(ca.NonContractTxs)
|
totalResults = int(ca.NonContractTxs)
|
||||||
} else if filter.Vout > 0 && filter.Vout-1 < len(ca.Contracts) {
|
} else if filter.Vout > 0 && filter.Vout-1 < len(ca.Contracts) {
|
||||||
totalResults = int(ca.Contracts[filter.Vout-1].Txs)
|
totalResults = int(ca.Contracts[filter.Vout-1].Txs)
|
||||||
|
} else if filter.Vout == AddressFilterVoutQueryNotNecessary {
|
||||||
|
totalResults = 0
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
nonContractTxs = int(ca.NonContractTxs)
|
nonContractTxs = int(ca.NonContractTxs)
|
||||||
|
@ -604,6 +742,16 @@ func (w *Worker) getEthereumTypeAddressBalances(addrDesc bchain.AddressDescripto
|
||||||
BalanceSat: *b,
|
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
|
return ba, tokens, ci, n, nonContractTxs, totalResults, nil
|
||||||
}
|
}
|
||||||
|
@ -620,7 +768,7 @@ func (w *Worker) txFromTxid(txid string, bestheight uint32, option AccountDetail
|
||||||
if ta == nil {
|
if ta == nil {
|
||||||
glog.Warning("DB inconsistency: tx ", txid, ": not found in txAddresses")
|
glog.Warning("DB inconsistency: tx ", txid, ": not found in txAddresses")
|
||||||
// as fallback, get tx from backend
|
// as fallback, get tx from backend
|
||||||
tx, err = w.GetTransaction(txid, false, true)
|
tx, err = w.GetTransaction(txid, false, false)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, errors.Annotatef(err, "GetTransaction %v", txid)
|
return nil, errors.Annotatef(err, "GetTransaction %v", txid)
|
||||||
}
|
}
|
||||||
|
@ -639,7 +787,7 @@ func (w *Worker) txFromTxid(txid string, bestheight uint32, option AccountDetail
|
||||||
tx = w.txFromTxAddress(txid, ta, blockInfo, bestheight)
|
tx = w.txFromTxAddress(txid, ta, blockInfo, bestheight)
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
tx, err = w.GetTransaction(txid, false, true)
|
tx, err = w.GetTransaction(txid, false, false)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, errors.Annotatef(err, "GetTransaction %v", txid)
|
return nil, errors.Annotatef(err, "GetTransaction %v", txid)
|
||||||
}
|
}
|
||||||
|
@ -728,7 +876,7 @@ func (w *Worker) GetAddress(address string, page int, txsOnPage int, option Acco
|
||||||
return nil, errors.Annotatef(err, "getAddressTxids %v true", addrDesc)
|
return nil, errors.Annotatef(err, "getAddressTxids %v true", addrDesc)
|
||||||
}
|
}
|
||||||
for _, txid := range txm {
|
for _, txid := range txm {
|
||||||
tx, err := w.GetTransaction(txid, false, false)
|
tx, err := w.GetTransaction(txid, false, true)
|
||||||
// mempool transaction may fail
|
// mempool transaction may fail
|
||||||
if err != nil || tx == nil {
|
if err != nil || tx == nil {
|
||||||
glog.Warning("GetTransaction in mempool: ", err)
|
glog.Warning("GetTransaction in mempool: ", err)
|
||||||
|
@ -737,7 +885,12 @@ func (w *Worker) GetAddress(address string, page int, txsOnPage int, option Acco
|
||||||
if tx.Confirmations == 0 {
|
if tx.Confirmations == 0 {
|
||||||
unconfirmedTxs++
|
unconfirmedTxs++
|
||||||
uBalSat.Add(&uBalSat, tx.getAddrVoutValue(addrDesc))
|
uBalSat.Add(&uBalSat, tx.getAddrVoutValue(addrDesc))
|
||||||
uBalSat.Sub(&uBalSat, tx.getAddrVinValue(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))
|
||||||
|
}
|
||||||
if page == 0 {
|
if page == 0 {
|
||||||
if option == AccountDetailsTxidHistory {
|
if option == AccountDetailsTxidHistory {
|
||||||
txids = append(txids, tx.Txid)
|
txids = append(txids, tx.Txid)
|
||||||
|
@ -750,7 +903,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
|
// get tx history if requested by option or check mempool if there are some transactions for a new address
|
||||||
if option >= AccountDetailsTxidHistory {
|
if option >= AccountDetailsTxidHistory && filter.Vout != AddressFilterVoutQueryNotNecessary {
|
||||||
txc, err := w.getAddressTxids(addrDesc, false, filter, (page+1)*txsOnPage)
|
txc, err := w.getAddressTxids(addrDesc, false, filter, (page+1)*txsOnPage)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, errors.Annotatef(err, "getAddressTxids %v false", addrDesc)
|
return nil, errors.Annotatef(err, "getAddressTxids %v false", addrDesc)
|
||||||
|
@ -821,7 +974,7 @@ func (w *Worker) balanceHistoryHeightsFromTo(fromTimestamp, toTimestamp int64) (
|
||||||
return fromUnix, fromHeight, toUnix, toHeight
|
return fromUnix, fromHeight, toUnix, toHeight
|
||||||
}
|
}
|
||||||
|
|
||||||
func (w *Worker) balanceHistoryForTxid(addrDesc bchain.AddressDescriptor, txid string, fromUnix, toUnix uint32) (*BalanceHistory, error) {
|
func (w *Worker) balanceHistoryForTxid(addrDesc bchain.AddressDescriptor, txid string, fromUnix, toUnix uint32, selfAddrDesc map[string]struct{}) (*BalanceHistory, error) {
|
||||||
var time uint32
|
var time uint32
|
||||||
var err error
|
var err error
|
||||||
var ta *db.TxAddresses
|
var ta *db.TxAddresses
|
||||||
|
@ -854,17 +1007,30 @@ func (w *Worker) balanceHistoryForTxid(addrDesc bchain.AddressDescriptor, txid s
|
||||||
return nil, nil
|
return nil, nil
|
||||||
}
|
}
|
||||||
bh := BalanceHistory{
|
bh := BalanceHistory{
|
||||||
Time: time,
|
Time: time,
|
||||||
Txs: 1,
|
Txs: 1,
|
||||||
SentSat: &Amount{},
|
ReceivedSat: &Amount{},
|
||||||
ReceivedSat: &Amount{},
|
SentSat: &Amount{},
|
||||||
Txid: txid,
|
SentToSelfSat: &Amount{},
|
||||||
|
Txid: txid,
|
||||||
}
|
}
|
||||||
|
countSentToSelf := false
|
||||||
if w.chainType == bchain.ChainBitcoinType {
|
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 {
|
for i := range ta.Inputs {
|
||||||
tai := &ta.Inputs[i]
|
tai := &ta.Inputs[i]
|
||||||
|
if _, found := selfAddrDesc[string(tai.AddrDesc)]; found {
|
||||||
|
if ownInputIndex < 0 {
|
||||||
|
ownInputIndex = i
|
||||||
|
}
|
||||||
|
}
|
||||||
if bytes.Equal(addrDesc, tai.AddrDesc) {
|
if bytes.Equal(addrDesc, tai.AddrDesc) {
|
||||||
(*big.Int)(bh.SentSat).Add((*big.Int)(bh.SentSat), &tai.ValueSat)
|
(*big.Int)(bh.SentSat).Add((*big.Int)(bh.SentSat), &tai.ValueSat)
|
||||||
|
if ownInputIndex == i {
|
||||||
|
countSentToSelf = true
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
for i := range ta.Outputs {
|
for i := range ta.Outputs {
|
||||||
|
@ -872,12 +1038,17 @@ func (w *Worker) balanceHistoryForTxid(addrDesc bchain.AddressDescriptor, txid s
|
||||||
if bytes.Equal(addrDesc, tao.AddrDesc) {
|
if bytes.Equal(addrDesc, tao.AddrDesc) {
|
||||||
(*big.Int)(bh.ReceivedSat).Add((*big.Int)(bh.ReceivedSat), &tao.ValueSat)
|
(*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 {
|
} else if w.chainType == bchain.ChainEthereumType {
|
||||||
var value big.Int
|
var value big.Int
|
||||||
ethTxData := eth.GetEthereumTxData(bchainTx)
|
ethTxData := eth.GetEthereumTxData(bchainTx)
|
||||||
// add received amount only for OK transactions
|
// add received amount only for OK or unknown status (old) transactions
|
||||||
if ethTxData.Status == 1 {
|
if ethTxData.Status == eth.TxStatusOK || ethTxData.Status == eth.TxStatusUnknown {
|
||||||
if len(bchainTx.Vout) > 0 {
|
if len(bchainTx.Vout) > 0 {
|
||||||
bchainVout := &bchainTx.Vout[0]
|
bchainVout := &bchainTx.Vout[0]
|
||||||
value = bchainVout.ValueSat
|
value = bchainVout.ValueSat
|
||||||
|
@ -889,6 +1060,9 @@ func (w *Worker) balanceHistoryForTxid(addrDesc bchain.AddressDescriptor, txid s
|
||||||
if bytes.Equal(addrDesc, txAddrDesc) {
|
if bytes.Equal(addrDesc, txAddrDesc) {
|
||||||
(*big.Int)(bh.ReceivedSat).Add((*big.Int)(bh.ReceivedSat), &value)
|
(*big.Int)(bh.ReceivedSat).Add((*big.Int)(bh.ReceivedSat), &value)
|
||||||
}
|
}
|
||||||
|
if _, found := selfAddrDesc[string(txAddrDesc)]; found {
|
||||||
|
countSentToSelf = true
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -900,9 +1074,14 @@ func (w *Worker) balanceHistoryForTxid(addrDesc bchain.AddressDescriptor, txid s
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
if bytes.Equal(addrDesc, txAddrDesc) {
|
if bytes.Equal(addrDesc, txAddrDesc) {
|
||||||
// add sent amount only for OK transactions, however fees always
|
// add received amount only for OK or unknown status (old) transactions, fees always
|
||||||
if ethTxData.Status == 1 {
|
if ethTxData.Status == eth.TxStatusOK || ethTxData.Status == eth.TxStatusUnknown {
|
||||||
(*big.Int)(bh.SentSat).Add((*big.Int)(bh.SentSat), &value)
|
(*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
|
var feesSat big.Int
|
||||||
// mempool txs do not have fees yet
|
// mempool txs do not have fees yet
|
||||||
|
@ -963,8 +1142,9 @@ func (w *Worker) GetBalanceHistory(address string, fromTimestamp, toTimestamp in
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
selfAddrDesc := map[string]struct{}{string(addrDesc): {}}
|
||||||
for txi := len(txs) - 1; txi >= 0; txi-- {
|
for txi := len(txs) - 1; txi >= 0; txi-- {
|
||||||
bh, err := w.balanceHistoryForTxid(addrDesc, txs[txi], fromUnix, toUnix)
|
bh, err := w.balanceHistoryForTxid(addrDesc, txs[txi], fromUnix, toUnix, selfAddrDesc)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
@ -1594,7 +1774,7 @@ func (w *Worker) GetSystemInfo(internal bool) (*SystemInfo, error) {
|
||||||
DbColumns: columnStats,
|
DbColumns: columnStats,
|
||||||
About: Text.BlockbookAbout,
|
About: Text.BlockbookAbout,
|
||||||
}
|
}
|
||||||
backendInfo := &BackendInfo{
|
backendInfo := &common.BackendInfo{
|
||||||
BackendError: backendError,
|
BackendError: backendError,
|
||||||
BestBlockHash: ci.Bestblockhash,
|
BestBlockHash: ci.Bestblockhash,
|
||||||
Blocks: ci.Blocks,
|
Blocks: ci.Blocks,
|
||||||
|
@ -1607,7 +1787,9 @@ func (w *Worker) GetSystemInfo(internal bool) (*SystemInfo, error) {
|
||||||
Timeoffset: ci.Timeoffset,
|
Timeoffset: ci.Timeoffset,
|
||||||
Version: ci.Version,
|
Version: ci.Version,
|
||||||
Warnings: ci.Warnings,
|
Warnings: ci.Warnings,
|
||||||
|
Consensus: ci.Consensus,
|
||||||
}
|
}
|
||||||
|
w.is.SetBackendInfo(backendInfo)
|
||||||
glog.Info("GetSystemInfo finished in ", time.Since(start))
|
glog.Info("GetSystemInfo finished in ", time.Since(start))
|
||||||
return &SystemInfo{blockbookInfo, backendInfo}, nil
|
return &SystemInfo{blockbookInfo, backendInfo}, nil
|
||||||
}
|
}
|
||||||
|
|
14
api/xpub.go
14
api/xpub.go
|
@ -9,8 +9,8 @@ import (
|
||||||
|
|
||||||
"github.com/golang/glog"
|
"github.com/golang/glog"
|
||||||
"github.com/juju/errors"
|
"github.com/juju/errors"
|
||||||
"github.com/trezor/blockbook/bchain"
|
"spacecruft.org/spacecruft/blockbook/bchain"
|
||||||
"github.com/trezor/blockbook/db"
|
"spacecruft.org/spacecruft/blockbook/db"
|
||||||
)
|
)
|
||||||
|
|
||||||
const defaultAddressesGap = 20
|
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
|
// the same tx can have multiple addresses from the same xpub, get it from backend it only once
|
||||||
tx, foundTx := txmMap[txid.txid]
|
tx, foundTx := txmMap[txid.txid]
|
||||||
if !foundTx {
|
if !foundTx {
|
||||||
tx, err = w.GetTransaction(txid.txid, false, false)
|
tx, err = w.GetTransaction(txid.txid, false, true)
|
||||||
// mempool transaction may fail
|
// mempool transaction may fail
|
||||||
if err != nil || tx == nil {
|
if err != nil || tx == nil {
|
||||||
glog.Warning("GetTransaction in mempool: ", err)
|
glog.Warning("GetTransaction in mempool: ", err)
|
||||||
|
@ -606,12 +606,18 @@ func (w *Worker) GetXpubBalanceHistory(xpub string, fromTimestamp, toTimestamp i
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
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 _, da := range [][]xpubAddress{data.addresses, data.changeAddresses} {
|
||||||
for i := range da {
|
for i := range da {
|
||||||
ad := &da[i]
|
ad := &da[i]
|
||||||
txids := ad.txids
|
txids := ad.txids
|
||||||
for txi := len(txids) - 1; txi >= 0; txi-- {
|
for txi := len(txids) - 1; txi >= 0; txi-- {
|
||||||
bh, err := w.balanceHistoryForTxid(ad.addrDesc, txids[txi].txid, fromUnix, toUnix)
|
bh, err := w.balanceHistoryForTxid(ad.addrDesc, txids[txi].txid, fromUnix, toUnix, selfAddrDesc)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
|
@ -3,6 +3,7 @@ package bchain
|
||||||
import (
|
import (
|
||||||
"sort"
|
"sort"
|
||||||
"sync"
|
"sync"
|
||||||
|
"time"
|
||||||
)
|
)
|
||||||
|
|
||||||
type addrIndex struct {
|
type addrIndex struct {
|
||||||
|
@ -27,6 +28,7 @@ type BaseMempool struct {
|
||||||
txEntries map[string]txEntry
|
txEntries map[string]txEntry
|
||||||
addrDescToTx map[string][]Outpoint
|
addrDescToTx map[string][]Outpoint
|
||||||
OnNewTxAddr OnNewTxAddrFunc
|
OnNewTxAddr OnNewTxAddrFunc
|
||||||
|
OnNewTx OnNewTxFunc
|
||||||
}
|
}
|
||||||
|
|
||||||
// GetTransactions returns slice of mempool transactions for given address
|
// GetTransactions returns slice of mempool transactions for given address
|
||||||
|
@ -113,3 +115,22 @@ func (m *BaseMempool) GetTransactionTime(txid string) uint32 {
|
||||||
}
|
}
|
||||||
return e.time
|
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
|
||||||
|
}
|
||||||
|
|
|
@ -9,7 +9,7 @@ import (
|
||||||
"github.com/gogo/protobuf/proto"
|
"github.com/gogo/protobuf/proto"
|
||||||
"github.com/golang/glog"
|
"github.com/golang/glog"
|
||||||
"github.com/juju/errors"
|
"github.com/juju/errors"
|
||||||
"github.com/trezor/blockbook/common"
|
"spacecruft.org/spacecruft/blockbook/common"
|
||||||
)
|
)
|
||||||
|
|
||||||
// BaseParser implements data parsing/handling functionality base for all other parsers
|
// BaseParser implements data parsing/handling functionality base for all other parsers
|
||||||
|
|
|
@ -6,7 +6,7 @@ import (
|
||||||
"math/big"
|
"math/big"
|
||||||
"testing"
|
"testing"
|
||||||
|
|
||||||
"github.com/trezor/blockbook/common"
|
"spacecruft.org/spacecruft/blockbook/common"
|
||||||
)
|
)
|
||||||
|
|
||||||
func NewBaseParser(adp int) *BaseParser {
|
func NewBaseParser(adp int) *BaseParser {
|
||||||
|
|
|
@ -8,8 +8,8 @@ import (
|
||||||
"github.com/martinboehm/btcutil/chaincfg"
|
"github.com/martinboehm/btcutil/chaincfg"
|
||||||
"github.com/martinboehm/btcutil/txscript"
|
"github.com/martinboehm/btcutil/txscript"
|
||||||
"github.com/schancel/cashaddr-converter/address"
|
"github.com/schancel/cashaddr-converter/address"
|
||||||
"github.com/trezor/blockbook/bchain"
|
"spacecruft.org/spacecruft/blockbook/bchain"
|
||||||
"github.com/trezor/blockbook/bchain/coins/btc"
|
"spacecruft.org/spacecruft/blockbook/bchain/coins/btc"
|
||||||
)
|
)
|
||||||
|
|
||||||
// AddressFormat type is used to specify different formats of address
|
// AddressFormat type is used to specify different formats of address
|
||||||
|
|
|
@ -10,8 +10,8 @@ import (
|
||||||
"testing"
|
"testing"
|
||||||
|
|
||||||
"github.com/martinboehm/btcutil/chaincfg"
|
"github.com/martinboehm/btcutil/chaincfg"
|
||||||
"github.com/trezor/blockbook/bchain"
|
"spacecruft.org/spacecruft/blockbook/bchain"
|
||||||
"github.com/trezor/blockbook/bchain/coins/btc"
|
"spacecruft.org/spacecruft/blockbook/bchain/coins/btc"
|
||||||
)
|
)
|
||||||
|
|
||||||
func TestMain(m *testing.M) {
|
func TestMain(m *testing.M) {
|
||||||
|
|
|
@ -8,8 +8,8 @@ import (
|
||||||
"github.com/golang/glog"
|
"github.com/golang/glog"
|
||||||
"github.com/juju/errors"
|
"github.com/juju/errors"
|
||||||
"github.com/martinboehm/bchutil"
|
"github.com/martinboehm/bchutil"
|
||||||
"github.com/trezor/blockbook/bchain"
|
"spacecruft.org/spacecruft/blockbook/bchain"
|
||||||
"github.com/trezor/blockbook/bchain/coins/btc"
|
"spacecruft.org/spacecruft/blockbook/bchain/coins/btc"
|
||||||
)
|
)
|
||||||
|
|
||||||
// BCashRPC is an interface to JSON-RPC bitcoind service.
|
// BCashRPC is an interface to JSON-RPC bitcoind service.
|
||||||
|
|
|
@ -3,7 +3,7 @@ package bellcoin
|
||||||
import (
|
import (
|
||||||
"github.com/martinboehm/btcd/wire"
|
"github.com/martinboehm/btcd/wire"
|
||||||
"github.com/martinboehm/btcutil/chaincfg"
|
"github.com/martinboehm/btcutil/chaincfg"
|
||||||
"github.com/trezor/blockbook/bchain/coins/btc"
|
"spacecruft.org/spacecruft/blockbook/bchain/coins/btc"
|
||||||
)
|
)
|
||||||
|
|
||||||
// magic numbers
|
// magic numbers
|
||||||
|
|
|
@ -10,8 +10,8 @@ import (
|
||||||
"testing"
|
"testing"
|
||||||
|
|
||||||
"github.com/martinboehm/btcutil/chaincfg"
|
"github.com/martinboehm/btcutil/chaincfg"
|
||||||
"github.com/trezor/blockbook/bchain"
|
"spacecruft.org/spacecruft/blockbook/bchain"
|
||||||
"github.com/trezor/blockbook/bchain/coins/btc"
|
"spacecruft.org/spacecruft/blockbook/bchain/coins/btc"
|
||||||
)
|
)
|
||||||
|
|
||||||
func TestMain(m *testing.M) {
|
func TestMain(m *testing.M) {
|
||||||
|
|
|
@ -4,8 +4,8 @@ import (
|
||||||
"encoding/json"
|
"encoding/json"
|
||||||
|
|
||||||
"github.com/golang/glog"
|
"github.com/golang/glog"
|
||||||
"github.com/trezor/blockbook/bchain"
|
"spacecruft.org/spacecruft/blockbook/bchain"
|
||||||
"github.com/trezor/blockbook/bchain/coins/btc"
|
"spacecruft.org/spacecruft/blockbook/bchain/coins/btc"
|
||||||
)
|
)
|
||||||
|
|
||||||
// BellcoinRPC is an interface to JSON-RPC bitcoind service.
|
// BellcoinRPC is an interface to JSON-RPC bitcoind service.
|
||||||
|
|
|
@ -3,8 +3,8 @@ package bitcore
|
||||||
import (
|
import (
|
||||||
"github.com/martinboehm/btcd/wire"
|
"github.com/martinboehm/btcd/wire"
|
||||||
"github.com/martinboehm/btcutil/chaincfg"
|
"github.com/martinboehm/btcutil/chaincfg"
|
||||||
"github.com/trezor/blockbook/bchain"
|
"spacecruft.org/spacecruft/blockbook/bchain"
|
||||||
"github.com/trezor/blockbook/bchain/coins/btc"
|
"spacecruft.org/spacecruft/blockbook/bchain/coins/btc"
|
||||||
)
|
)
|
||||||
|
|
||||||
const (
|
const (
|
||||||
|
|
|
@ -10,8 +10,8 @@ import (
|
||||||
"testing"
|
"testing"
|
||||||
|
|
||||||
"github.com/martinboehm/btcutil/chaincfg"
|
"github.com/martinboehm/btcutil/chaincfg"
|
||||||
"github.com/trezor/blockbook/bchain"
|
"spacecruft.org/spacecruft/blockbook/bchain"
|
||||||
"github.com/trezor/blockbook/bchain/coins/btc"
|
"spacecruft.org/spacecruft/blockbook/bchain/coins/btc"
|
||||||
)
|
)
|
||||||
|
|
||||||
func TestMain(m *testing.M) {
|
func TestMain(m *testing.M) {
|
||||||
|
|
|
@ -5,8 +5,8 @@ import (
|
||||||
|
|
||||||
"github.com/golang/glog"
|
"github.com/golang/glog"
|
||||||
"github.com/juju/errors"
|
"github.com/juju/errors"
|
||||||
"github.com/trezor/blockbook/bchain"
|
"spacecruft.org/spacecruft/blockbook/bchain"
|
||||||
"github.com/trezor/blockbook/bchain/coins/btc"
|
"spacecruft.org/spacecruft/blockbook/bchain/coins/btc"
|
||||||
)
|
)
|
||||||
|
|
||||||
// BitcoreRPC is an interface to JSON-RPC bitcoind service.
|
// BitcoreRPC is an interface to JSON-RPC bitcoind service.
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
package bitzeny
|
package bitzeny
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"github.com/trezor/blockbook/bchain/coins/btc"
|
"spacecruft.org/spacecruft/blockbook/bchain/coins/btc"
|
||||||
|
|
||||||
"github.com/martinboehm/btcd/wire"
|
"github.com/martinboehm/btcd/wire"
|
||||||
"github.com/martinboehm/btcutil/chaincfg"
|
"github.com/martinboehm/btcutil/chaincfg"
|
||||||
|
|
|
@ -9,8 +9,8 @@ import (
|
||||||
"reflect"
|
"reflect"
|
||||||
"testing"
|
"testing"
|
||||||
|
|
||||||
"github.com/trezor/blockbook/bchain"
|
"spacecruft.org/spacecruft/blockbook/bchain"
|
||||||
"github.com/trezor/blockbook/bchain/coins/btc"
|
"spacecruft.org/spacecruft/blockbook/bchain/coins/btc"
|
||||||
|
|
||||||
"github.com/martinboehm/btcutil/chaincfg"
|
"github.com/martinboehm/btcutil/chaincfg"
|
||||||
)
|
)
|
||||||
|
|
|
@ -3,8 +3,8 @@ package bitzeny
|
||||||
import (
|
import (
|
||||||
"encoding/json"
|
"encoding/json"
|
||||||
|
|
||||||
"github.com/trezor/blockbook/bchain"
|
"spacecruft.org/spacecruft/blockbook/bchain"
|
||||||
"github.com/trezor/blockbook/bchain/coins/btc"
|
"spacecruft.org/spacecruft/blockbook/bchain/coins/btc"
|
||||||
|
|
||||||
"github.com/golang/glog"
|
"github.com/golang/glog"
|
||||||
)
|
)
|
||||||
|
|
|
@ -10,47 +10,48 @@ import (
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
"github.com/juju/errors"
|
"github.com/juju/errors"
|
||||||
"github.com/trezor/blockbook/bchain"
|
"spacecruft.org/spacecruft/blockbook/bchain"
|
||||||
"github.com/trezor/blockbook/bchain/coins/bch"
|
"spacecruft.org/spacecruft/blockbook/bchain/coins/bch"
|
||||||
"github.com/trezor/blockbook/bchain/coins/bellcoin"
|
"spacecruft.org/spacecruft/blockbook/bchain/coins/bellcoin"
|
||||||
"github.com/trezor/blockbook/bchain/coins/bitcore"
|
"spacecruft.org/spacecruft/blockbook/bchain/coins/bitcore"
|
||||||
"github.com/trezor/blockbook/bchain/coins/bitzeny"
|
"spacecruft.org/spacecruft/blockbook/bchain/coins/bitzeny"
|
||||||
"github.com/trezor/blockbook/bchain/coins/btc"
|
"spacecruft.org/spacecruft/blockbook/bchain/coins/btc"
|
||||||
"github.com/trezor/blockbook/bchain/coins/btg"
|
"spacecruft.org/spacecruft/blockbook/bchain/coins/btg"
|
||||||
"github.com/trezor/blockbook/bchain/coins/cpuchain"
|
"spacecruft.org/spacecruft/blockbook/bchain/coins/cpuchain"
|
||||||
"github.com/trezor/blockbook/bchain/coins/dash"
|
"spacecruft.org/spacecruft/blockbook/bchain/coins/dash"
|
||||||
"github.com/trezor/blockbook/bchain/coins/dcr"
|
"spacecruft.org/spacecruft/blockbook/bchain/coins/dcr"
|
||||||
"github.com/trezor/blockbook/bchain/coins/deeponion"
|
"spacecruft.org/spacecruft/blockbook/bchain/coins/deeponion"
|
||||||
"github.com/trezor/blockbook/bchain/coins/digibyte"
|
"spacecruft.org/spacecruft/blockbook/bchain/coins/digibyte"
|
||||||
"github.com/trezor/blockbook/bchain/coins/divi"
|
"spacecruft.org/spacecruft/blockbook/bchain/coins/divi"
|
||||||
"github.com/trezor/blockbook/bchain/coins/dogecoin"
|
"spacecruft.org/spacecruft/blockbook/bchain/coins/dogecoin"
|
||||||
"github.com/trezor/blockbook/bchain/coins/eth"
|
"spacecruft.org/spacecruft/blockbook/bchain/coins/eth"
|
||||||
"github.com/trezor/blockbook/bchain/coins/flo"
|
"spacecruft.org/spacecruft/blockbook/bchain/coins/firo"
|
||||||
"github.com/trezor/blockbook/bchain/coins/fujicoin"
|
"spacecruft.org/spacecruft/blockbook/bchain/coins/flo"
|
||||||
"github.com/trezor/blockbook/bchain/coins/gamecredits"
|
"spacecruft.org/spacecruft/blockbook/bchain/coins/fujicoin"
|
||||||
"github.com/trezor/blockbook/bchain/coins/grs"
|
"spacecruft.org/spacecruft/blockbook/bchain/coins/gamecredits"
|
||||||
"github.com/trezor/blockbook/bchain/coins/koto"
|
"spacecruft.org/spacecruft/blockbook/bchain/coins/grs"
|
||||||
"github.com/trezor/blockbook/bchain/coins/liquid"
|
"spacecruft.org/spacecruft/blockbook/bchain/coins/koto"
|
||||||
"github.com/trezor/blockbook/bchain/coins/litecoin"
|
"spacecruft.org/spacecruft/blockbook/bchain/coins/liquid"
|
||||||
"github.com/trezor/blockbook/bchain/coins/monacoin"
|
"spacecruft.org/spacecruft/blockbook/bchain/coins/litecoin"
|
||||||
"github.com/trezor/blockbook/bchain/coins/monetaryunit"
|
"spacecruft.org/spacecruft/blockbook/bchain/coins/monacoin"
|
||||||
"github.com/trezor/blockbook/bchain/coins/myriad"
|
"spacecruft.org/spacecruft/blockbook/bchain/coins/monetaryunit"
|
||||||
"github.com/trezor/blockbook/bchain/coins/namecoin"
|
"spacecruft.org/spacecruft/blockbook/bchain/coins/myriad"
|
||||||
"github.com/trezor/blockbook/bchain/coins/nuls"
|
"spacecruft.org/spacecruft/blockbook/bchain/coins/namecoin"
|
||||||
"github.com/trezor/blockbook/bchain/coins/omotenashicoin"
|
"spacecruft.org/spacecruft/blockbook/bchain/coins/nuls"
|
||||||
"github.com/trezor/blockbook/bchain/coins/pivx"
|
"spacecruft.org/spacecruft/blockbook/bchain/coins/omotenashicoin"
|
||||||
"github.com/trezor/blockbook/bchain/coins/polis"
|
"spacecruft.org/spacecruft/blockbook/bchain/coins/pivx"
|
||||||
"github.com/trezor/blockbook/bchain/coins/qtum"
|
"spacecruft.org/spacecruft/blockbook/bchain/coins/polis"
|
||||||
"github.com/trezor/blockbook/bchain/coins/ravencoin"
|
"spacecruft.org/spacecruft/blockbook/bchain/coins/qtum"
|
||||||
"github.com/trezor/blockbook/bchain/coins/ritocoin"
|
"spacecruft.org/spacecruft/blockbook/bchain/coins/ravencoin"
|
||||||
"github.com/trezor/blockbook/bchain/coins/snowgem"
|
"spacecruft.org/spacecruft/blockbook/bchain/coins/ritocoin"
|
||||||
"github.com/trezor/blockbook/bchain/coins/unobtanium"
|
"spacecruft.org/spacecruft/blockbook/bchain/coins/snowgem"
|
||||||
"github.com/trezor/blockbook/bchain/coins/vertcoin"
|
"spacecruft.org/spacecruft/blockbook/bchain/coins/trezarcoin"
|
||||||
"github.com/trezor/blockbook/bchain/coins/viacoin"
|
"spacecruft.org/spacecruft/blockbook/bchain/coins/unobtanium"
|
||||||
"github.com/trezor/blockbook/bchain/coins/vipstarcoin"
|
"spacecruft.org/spacecruft/blockbook/bchain/coins/vertcoin"
|
||||||
"github.com/trezor/blockbook/bchain/coins/xzc"
|
"spacecruft.org/spacecruft/blockbook/bchain/coins/viacoin"
|
||||||
"github.com/trezor/blockbook/bchain/coins/zec"
|
"spacecruft.org/spacecruft/blockbook/bchain/coins/vipstarcoin"
|
||||||
"github.com/trezor/blockbook/common"
|
"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)
|
type blockChainFactory func(config json.RawMessage, pushHandler func(bchain.NotificationType)) (bchain.BlockChain, error)
|
||||||
|
@ -61,14 +62,17 @@ var BlockChainFactories = make(map[string]blockChainFactory)
|
||||||
func init() {
|
func init() {
|
||||||
BlockChainFactories["Bitcoin"] = btc.NewBitcoinRPC
|
BlockChainFactories["Bitcoin"] = btc.NewBitcoinRPC
|
||||||
BlockChainFactories["Testnet"] = btc.NewBitcoinRPC
|
BlockChainFactories["Testnet"] = btc.NewBitcoinRPC
|
||||||
|
BlockChainFactories["Signet"] = btc.NewBitcoinRPC
|
||||||
BlockChainFactories["Zcash"] = zec.NewZCashRPC
|
BlockChainFactories["Zcash"] = zec.NewZCashRPC
|
||||||
BlockChainFactories["Zcash Testnet"] = zec.NewZCashRPC
|
BlockChainFactories["Zcash Testnet"] = zec.NewZCashRPC
|
||||||
BlockChainFactories["Ethereum"] = eth.NewEthereumRPC
|
BlockChainFactories["Ethereum"] = eth.NewEthereumRPC
|
||||||
BlockChainFactories["Ethereum Classic"] = eth.NewEthereumRPC
|
BlockChainFactories["Ethereum Classic"] = eth.NewEthereumRPC
|
||||||
BlockChainFactories["Ethereum Testnet Ropsten"] = eth.NewEthereumRPC
|
BlockChainFactories["Ethereum Testnet Ropsten"] = eth.NewEthereumRPC
|
||||||
|
BlockChainFactories["Ethereum Testnet Goerli"] = eth.NewEthereumRPC
|
||||||
BlockChainFactories["Bcash"] = bch.NewBCashRPC
|
BlockChainFactories["Bcash"] = bch.NewBCashRPC
|
||||||
BlockChainFactories["Bcash Testnet"] = bch.NewBCashRPC
|
BlockChainFactories["Bcash Testnet"] = bch.NewBCashRPC
|
||||||
BlockChainFactories["Bgold"] = btg.NewBGoldRPC
|
BlockChainFactories["Bgold"] = btg.NewBGoldRPC
|
||||||
|
BlockChainFactories["Bgold Testnet"] = btg.NewBGoldRPC
|
||||||
BlockChainFactories["Dash"] = dash.NewDashRPC
|
BlockChainFactories["Dash"] = dash.NewDashRPC
|
||||||
BlockChainFactories["Dash Testnet"] = dash.NewDashRPC
|
BlockChainFactories["Dash Testnet"] = dash.NewDashRPC
|
||||||
BlockChainFactories["Decred"] = dcr.NewDecredRPC
|
BlockChainFactories["Decred"] = dcr.NewDecredRPC
|
||||||
|
@ -86,6 +90,7 @@ func init() {
|
||||||
BlockChainFactories["Monacoin Testnet"] = monacoin.NewMonacoinRPC
|
BlockChainFactories["Monacoin Testnet"] = monacoin.NewMonacoinRPC
|
||||||
BlockChainFactories["MonetaryUnit"] = monetaryunit.NewMonetaryUnitRPC
|
BlockChainFactories["MonetaryUnit"] = monetaryunit.NewMonetaryUnitRPC
|
||||||
BlockChainFactories["DigiByte"] = digibyte.NewDigiByteRPC
|
BlockChainFactories["DigiByte"] = digibyte.NewDigiByteRPC
|
||||||
|
BlockChainFactories["DigiByte Testnet"] = digibyte.NewDigiByteRPC
|
||||||
BlockChainFactories["Myriad"] = myriad.NewMyriadRPC
|
BlockChainFactories["Myriad"] = myriad.NewMyriadRPC
|
||||||
BlockChainFactories["Liquid"] = liquid.NewLiquidRPC
|
BlockChainFactories["Liquid"] = liquid.NewLiquidRPC
|
||||||
BlockChainFactories["Groestlcoin"] = grs.NewGroestlcoinRPC
|
BlockChainFactories["Groestlcoin"] = grs.NewGroestlcoinRPC
|
||||||
|
@ -93,7 +98,7 @@ func init() {
|
||||||
BlockChainFactories["PIVX"] = pivx.NewPivXRPC
|
BlockChainFactories["PIVX"] = pivx.NewPivXRPC
|
||||||
BlockChainFactories["PIVX Testnet"] = pivx.NewPivXRPC
|
BlockChainFactories["PIVX Testnet"] = pivx.NewPivXRPC
|
||||||
BlockChainFactories["Polis"] = polis.NewPolisRPC
|
BlockChainFactories["Polis"] = polis.NewPolisRPC
|
||||||
BlockChainFactories["Zcoin"] = xzc.NewZcoinRPC
|
BlockChainFactories["Firo"] = firo.NewFiroRPC
|
||||||
BlockChainFactories["Fujicoin"] = fujicoin.NewFujicoinRPC
|
BlockChainFactories["Fujicoin"] = fujicoin.NewFujicoinRPC
|
||||||
BlockChainFactories["Flo"] = flo.NewFloRPC
|
BlockChainFactories["Flo"] = flo.NewFloRPC
|
||||||
BlockChainFactories["Bellcoin"] = bellcoin.NewBellcoinRPC
|
BlockChainFactories["Bellcoin"] = bellcoin.NewBellcoinRPC
|
||||||
|
@ -114,6 +119,7 @@ func init() {
|
||||||
BlockChainFactories["Omotenashicoin"] = omotenashicoin.NewOmotenashiCoinRPC
|
BlockChainFactories["Omotenashicoin"] = omotenashicoin.NewOmotenashiCoinRPC
|
||||||
BlockChainFactories["Omotenashicoin Testnet"] = omotenashicoin.NewOmotenashiCoinRPC
|
BlockChainFactories["Omotenashicoin Testnet"] = omotenashicoin.NewOmotenashiCoinRPC
|
||||||
BlockChainFactories["BitZeny"] = bitzeny.NewBitZenyRPC
|
BlockChainFactories["BitZeny"] = bitzeny.NewBitZenyRPC
|
||||||
|
BlockChainFactories["Trezarcoin"] = trezarcoin.NewTrezarcoinRPC
|
||||||
}
|
}
|
||||||
|
|
||||||
// GetCoinNameFromConfig gets coin name and coin shortcut from config file
|
// GetCoinNameFromConfig gets coin name and coin shortcut from config file
|
||||||
|
@ -185,8 +191,8 @@ func (c *blockChainWithMetrics) CreateMempool(chain bchain.BlockChain) (bchain.M
|
||||||
return c.b.CreateMempool(chain)
|
return c.b.CreateMempool(chain)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c *blockChainWithMetrics) InitializeMempool(addrDescForOutpoint bchain.AddrDescForOutpointFunc, onNewTxAddr bchain.OnNewTxAddrFunc) error {
|
func (c *blockChainWithMetrics) InitializeMempool(addrDescForOutpoint bchain.AddrDescForOutpointFunc, onNewTxAddr bchain.OnNewTxAddrFunc, onNewTx bchain.OnNewTxFunc) error {
|
||||||
return c.b.InitializeMempool(addrDescForOutpoint, onNewTxAddr)
|
return c.b.InitializeMempool(addrDescForOutpoint, onNewTxAddr, onNewTx)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c *blockChainWithMetrics) Shutdown(ctx context.Context) error {
|
func (c *blockChainWithMetrics) Shutdown(ctx context.Context) error {
|
||||||
|
|
|
@ -15,9 +15,25 @@ import (
|
||||||
"github.com/martinboehm/btcutil/chaincfg"
|
"github.com/martinboehm/btcutil/chaincfg"
|
||||||
"github.com/martinboehm/btcutil/hdkeychain"
|
"github.com/martinboehm/btcutil/hdkeychain"
|
||||||
"github.com/martinboehm/btcutil/txscript"
|
"github.com/martinboehm/btcutil/txscript"
|
||||||
"github.com/trezor/blockbook/bchain"
|
"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
|
// OutputScriptToAddressesFunc converts ScriptPubKey to bitcoin addresses
|
||||||
type OutputScriptToAddressesFunc func(script []byte) ([]string, bool, error)
|
type OutputScriptToAddressesFunc func(script []byte) ([]string, bool, error)
|
||||||
|
|
||||||
|
@ -63,6 +79,8 @@ func GetChainParams(chain string) *chaincfg.Params {
|
||||||
return &chaincfg.TestNet3Params
|
return &chaincfg.TestNet3Params
|
||||||
case "regtest":
|
case "regtest":
|
||||||
return &chaincfg.RegressionNetParams
|
return &chaincfg.RegressionNetParams
|
||||||
|
case "signet":
|
||||||
|
return &SigNetParams
|
||||||
}
|
}
|
||||||
return &chaincfg.MainNetParams
|
return &chaincfg.MainNetParams
|
||||||
}
|
}
|
||||||
|
|
|
@ -10,7 +10,7 @@ import (
|
||||||
"testing"
|
"testing"
|
||||||
|
|
||||||
"github.com/martinboehm/btcutil/chaincfg"
|
"github.com/martinboehm/btcutil/chaincfg"
|
||||||
"github.com/trezor/blockbook/bchain"
|
"spacecruft.org/spacecruft/blockbook/bchain"
|
||||||
)
|
)
|
||||||
|
|
||||||
func TestMain(m *testing.M) {
|
func TestMain(m *testing.M) {
|
||||||
|
@ -259,10 +259,11 @@ func TestGetAddressesFromAddrDesc(t *testing.T) {
|
||||||
}
|
}
|
||||||
|
|
||||||
var (
|
var (
|
||||||
testTx1, testTx2 bchain.Tx
|
testTx1, testTx2, testTx3 bchain.Tx
|
||||||
|
|
||||||
testTxPacked1 = "0001e2408ba8d7af5401000000017f9a22c9cbf54bd902400df746f138f37bcf5b4d93eb755820e974ba43ed5f42040000006a4730440220037f4ed5427cde81d55b9b6a2fd08c8a25090c2c2fff3a75c1a57625ca8a7118022076c702fe55969fa08137f71afd4851c48e31082dd3c40c919c92cdbc826758d30121029f6da5623c9f9b68a9baf9c1bc7511df88fa34c6c2f71f7c62f2f03ff48dca80feffffff019c9700000000000017a9146144d57c8aff48492c9dfb914e120b20bad72d6f8773d00700"
|
testTxPacked1 = "0001e2408ba8d7af5401000000017f9a22c9cbf54bd902400df746f138f37bcf5b4d93eb755820e974ba43ed5f42040000006a4730440220037f4ed5427cde81d55b9b6a2fd08c8a25090c2c2fff3a75c1a57625ca8a7118022076c702fe55969fa08137f71afd4851c48e31082dd3c40c919c92cdbc826758d30121029f6da5623c9f9b68a9baf9c1bc7511df88fa34c6c2f71f7c62f2f03ff48dca80feffffff019c9700000000000017a9146144d57c8aff48492c9dfb914e120b20bad72d6f8773d00700"
|
||||||
testTxPacked2 = "0007c91a899ab7da6a010000000001019d64f0c72a0d206001decbffaa722eb1044534c74eee7a5df8318e42a4323ec10000000017160014550da1f5d25a9dae2eafd6902b4194c4c6500af6ffffffff02809698000000000017a914cd668d781ece600efa4b2404dc91fd26b8b8aed8870553d7360000000017a914246655bdbd54c7e477d0ea2375e86e0db2b8f80a8702473044022076aba4ad559616905fa51d4ddd357fc1fdb428d40cb388e042cdd1da4a1b7357022011916f90c712ead9a66d5f058252efd280439ad8956a967e95d437d246710bc9012102a80a5964c5612bb769ef73147b2cf3c149bc0fd4ecb02f8097629c94ab013ffd00000000"
|
testTxPacked2 = "0007c91a899ab7da6a010000000001019d64f0c72a0d206001decbffaa722eb1044534c74eee7a5df8318e42a4323ec10000000017160014550da1f5d25a9dae2eafd6902b4194c4c6500af6ffffffff02809698000000000017a914cd668d781ece600efa4b2404dc91fd26b8b8aed8870553d7360000000017a914246655bdbd54c7e477d0ea2375e86e0db2b8f80a8702473044022076aba4ad559616905fa51d4ddd357fc1fdb428d40cb388e042cdd1da4a1b7357022011916f90c712ead9a66d5f058252efd280439ad8956a967e95d437d246710bc9012102a80a5964c5612bb769ef73147b2cf3c149bc0fd4ecb02f8097629c94ab013ffd00000000"
|
||||||
|
testTxPacked3 = "00003d818bfda9aa3e02000000000102deb1999a857ab0a13d6b12fbd95ea75b409edde5f2ff747507ce42d9986a8b9d0000000000fdffffff9fd2d3361e203b2375eba6438efbef5b3075531e7e583c7cc76b7294fe7f22980000000000fdffffff02a0860100000000001600148091746745464e7555c31e9a5afceac14a02978ae7fc1c0000000000160014565ea9ff4589d3e05ba149ae6e257752bfdc2a1e0247304402207d67d320a8e813f986b35e9791935fcb736754812b7038686f5de6cfdcda99cd02201c3bb2c178e0056016437ecfe365a7eef84aa9d293ebdc566177af82e22fcdd3012103abb30c1bbe878b07b58dc169b1d061d48c60be8107f632a59778b38bf7ceea5a02473044022044f54a478cfe086e870cb026c9dcd4e14e63778bef569a4d55a6332725cd9a9802202f0e94c04e6f328fc64ad9efe552888c299750d1b8d033324825a3ff29920e030121036fcd433428aa7dc65c4f5408fa31f208c54fe4b4c6c1ae9c39a825ed4f1ac039813d0000"
|
||||||
)
|
)
|
||||||
|
|
||||||
func init() {
|
func init() {
|
||||||
|
@ -335,6 +336,54 @@ 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) {
|
func TestPackTx(t *testing.T) {
|
||||||
|
@ -372,6 +421,17 @@ func TestPackTx(t *testing.T) {
|
||||||
want: testTxPacked2,
|
want: testTxPacked2,
|
||||||
wantErr: false,
|
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 {
|
for _, tt := range tests {
|
||||||
t.Run(tt.name, func(t *testing.T) {
|
t.Run(tt.name, func(t *testing.T) {
|
||||||
|
@ -420,6 +480,16 @@ func TestUnpackTx(t *testing.T) {
|
||||||
want1: 510234,
|
want1: 510234,
|
||||||
wantErr: false,
|
wantErr: false,
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
name: "signet-1",
|
||||||
|
args: args{
|
||||||
|
packedTx: testTxPacked3,
|
||||||
|
parser: NewBitcoinParser(GetChainParams("signet"), &Configuration{}),
|
||||||
|
},
|
||||||
|
want: &testTx3,
|
||||||
|
want1: 15745,
|
||||||
|
wantErr: false,
|
||||||
|
},
|
||||||
}
|
}
|
||||||
for _, tt := range tests {
|
for _, tt := range tests {
|
||||||
t.Run(tt.name, func(t *testing.T) {
|
t.Run(tt.name, func(t *testing.T) {
|
||||||
|
|
|
@ -16,8 +16,8 @@ import (
|
||||||
"github.com/golang/glog"
|
"github.com/golang/glog"
|
||||||
"github.com/juju/errors"
|
"github.com/juju/errors"
|
||||||
"github.com/martinboehm/btcd/wire"
|
"github.com/martinboehm/btcd/wire"
|
||||||
"github.com/trezor/blockbook/bchain"
|
"spacecruft.org/spacecruft/blockbook/bchain"
|
||||||
"github.com/trezor/blockbook/common"
|
"spacecruft.org/spacecruft/blockbook/common"
|
||||||
)
|
)
|
||||||
|
|
||||||
// BitcoinRPC is an interface to JSON-RPC bitcoind service.
|
// BitcoinRPC is an interface to JSON-RPC bitcoind service.
|
||||||
|
@ -155,12 +155,13 @@ func (b *BitcoinRPC) CreateMempool(chain bchain.BlockChain) (bchain.Mempool, err
|
||||||
}
|
}
|
||||||
|
|
||||||
// InitializeMempool creates ZeroMQ subscription and sets AddrDescForOutpointFunc to the Mempool
|
// InitializeMempool creates ZeroMQ subscription and sets AddrDescForOutpointFunc to the Mempool
|
||||||
func (b *BitcoinRPC) InitializeMempool(addrDescForOutpoint bchain.AddrDescForOutpointFunc, onNewTxAddr bchain.OnNewTxAddrFunc) error {
|
func (b *BitcoinRPC) InitializeMempool(addrDescForOutpoint bchain.AddrDescForOutpointFunc, onNewTxAddr bchain.OnNewTxAddrFunc, onNewTx bchain.OnNewTxFunc) error {
|
||||||
if b.Mempool == nil {
|
if b.Mempool == nil {
|
||||||
return errors.New("Mempool not created")
|
return errors.New("Mempool not created")
|
||||||
}
|
}
|
||||||
b.Mempool.AddrDescForOutpoint = addrDescForOutpoint
|
b.Mempool.AddrDescForOutpoint = addrDescForOutpoint
|
||||||
b.Mempool.OnNewTxAddr = onNewTxAddr
|
b.Mempool.OnNewTxAddr = onNewTxAddr
|
||||||
|
b.Mempool.OnNewTx = onNewTx
|
||||||
if b.mq == nil {
|
if b.mq == nil {
|
||||||
mq, err := bchain.NewMQ(b.ChainConfig.MessageQueueBinding, b.pushHandler)
|
mq, err := bchain.NewMQ(b.ChainConfig.MessageQueueBinding, b.pushHandler)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
|
|
@ -12,7 +12,7 @@ import (
|
||||||
|
|
||||||
"github.com/golang/glog"
|
"github.com/golang/glog"
|
||||||
"github.com/juju/errors"
|
"github.com/juju/errors"
|
||||||
"github.com/trezor/blockbook/bchain"
|
"spacecruft.org/spacecruft/blockbook/bchain"
|
||||||
)
|
)
|
||||||
|
|
||||||
// https://whatthefee.io returns
|
// https://whatthefee.io returns
|
||||||
|
|
|
@ -8,9 +8,9 @@ import (
|
||||||
"github.com/martinboehm/btcd/chaincfg/chainhash"
|
"github.com/martinboehm/btcd/chaincfg/chainhash"
|
||||||
"github.com/martinboehm/btcd/wire"
|
"github.com/martinboehm/btcd/wire"
|
||||||
"github.com/martinboehm/btcutil/chaincfg"
|
"github.com/martinboehm/btcutil/chaincfg"
|
||||||
"github.com/trezor/blockbook/bchain"
|
"spacecruft.org/spacecruft/blockbook/bchain"
|
||||||
"github.com/trezor/blockbook/bchain/coins/btc"
|
"spacecruft.org/spacecruft/blockbook/bchain/coins/btc"
|
||||||
"github.com/trezor/blockbook/bchain/coins/utils"
|
"spacecruft.org/spacecruft/blockbook/bchain/coins/utils"
|
||||||
)
|
)
|
||||||
|
|
||||||
const (
|
const (
|
||||||
|
|
|
@ -12,7 +12,7 @@ import (
|
||||||
"testing"
|
"testing"
|
||||||
|
|
||||||
"github.com/martinboehm/btcutil/chaincfg"
|
"github.com/martinboehm/btcutil/chaincfg"
|
||||||
"github.com/trezor/blockbook/bchain/coins/btc"
|
"spacecruft.org/spacecruft/blockbook/bchain/coins/btc"
|
||||||
)
|
)
|
||||||
|
|
||||||
func TestMain(m *testing.M) {
|
func TestMain(m *testing.M) {
|
||||||
|
|
|
@ -4,8 +4,8 @@ import (
|
||||||
"encoding/json"
|
"encoding/json"
|
||||||
|
|
||||||
"github.com/golang/glog"
|
"github.com/golang/glog"
|
||||||
"github.com/trezor/blockbook/bchain"
|
"spacecruft.org/spacecruft/blockbook/bchain"
|
||||||
"github.com/trezor/blockbook/bchain/coins/btc"
|
"spacecruft.org/spacecruft/blockbook/bchain/coins/btc"
|
||||||
)
|
)
|
||||||
|
|
||||||
// BGoldRPC is an interface to JSON-RPC bitcoind service.
|
// BGoldRPC is an interface to JSON-RPC bitcoind service.
|
||||||
|
|
|
@ -3,7 +3,7 @@ package cpuchain
|
||||||
import (
|
import (
|
||||||
"github.com/martinboehm/btcd/wire"
|
"github.com/martinboehm/btcd/wire"
|
||||||
"github.com/martinboehm/btcutil/chaincfg"
|
"github.com/martinboehm/btcutil/chaincfg"
|
||||||
"github.com/trezor/blockbook/bchain/coins/btc"
|
"spacecruft.org/spacecruft/blockbook/bchain/coins/btc"
|
||||||
)
|
)
|
||||||
|
|
||||||
// magic numbers
|
// magic numbers
|
||||||
|
|
|
@ -4,8 +4,8 @@ import (
|
||||||
"encoding/json"
|
"encoding/json"
|
||||||
|
|
||||||
"github.com/golang/glog"
|
"github.com/golang/glog"
|
||||||
"github.com/trezor/blockbook/bchain"
|
"spacecruft.org/spacecruft/blockbook/bchain"
|
||||||
"github.com/trezor/blockbook/bchain/coins/btc"
|
"spacecruft.org/spacecruft/blockbook/bchain/coins/btc"
|
||||||
)
|
)
|
||||||
|
|
||||||
// CPUchainRPC is an interface to JSON-RPC bitcoind service.
|
// CPUchainRPC is an interface to JSON-RPC bitcoind service.
|
||||||
|
|
|
@ -3,8 +3,8 @@ package dash
|
||||||
import (
|
import (
|
||||||
"github.com/martinboehm/btcd/wire"
|
"github.com/martinboehm/btcd/wire"
|
||||||
"github.com/martinboehm/btcutil/chaincfg"
|
"github.com/martinboehm/btcutil/chaincfg"
|
||||||
"github.com/trezor/blockbook/bchain"
|
"spacecruft.org/spacecruft/blockbook/bchain"
|
||||||
"github.com/trezor/blockbook/bchain/coins/btc"
|
"spacecruft.org/spacecruft/blockbook/bchain/coins/btc"
|
||||||
)
|
)
|
||||||
|
|
||||||
const (
|
const (
|
||||||
|
|
|
@ -12,8 +12,8 @@ import (
|
||||||
"reflect"
|
"reflect"
|
||||||
"testing"
|
"testing"
|
||||||
|
|
||||||
"github.com/trezor/blockbook/bchain"
|
"spacecruft.org/spacecruft/blockbook/bchain"
|
||||||
"github.com/trezor/blockbook/bchain/coins/btc"
|
"spacecruft.org/spacecruft/blockbook/bchain/coins/btc"
|
||||||
)
|
)
|
||||||
|
|
||||||
type testBlock struct {
|
type testBlock struct {
|
||||||
|
|
|
@ -5,8 +5,8 @@ import (
|
||||||
|
|
||||||
"github.com/golang/glog"
|
"github.com/golang/glog"
|
||||||
"github.com/juju/errors"
|
"github.com/juju/errors"
|
||||||
"github.com/trezor/blockbook/bchain"
|
"spacecruft.org/spacecruft/blockbook/bchain"
|
||||||
"github.com/trezor/blockbook/bchain/coins/btc"
|
"spacecruft.org/spacecruft/blockbook/bchain/coins/btc"
|
||||||
)
|
)
|
||||||
|
|
||||||
const firstBlockWithSpecialTransactions = 1028160
|
const firstBlockWithSpecialTransactions = 1028160
|
||||||
|
|
|
@ -9,17 +9,19 @@ import (
|
||||||
"math/big"
|
"math/big"
|
||||||
"strconv"
|
"strconv"
|
||||||
|
|
||||||
cfg "github.com/decred/dcrd/chaincfg"
|
|
||||||
"github.com/decred/dcrd/chaincfg/chainhash"
|
"github.com/decred/dcrd/chaincfg/chainhash"
|
||||||
"github.com/decred/dcrd/hdkeychain"
|
cfg "github.com/decred/dcrd/chaincfg/v3"
|
||||||
"github.com/decred/dcrd/txscript"
|
"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/juju/errors"
|
"github.com/juju/errors"
|
||||||
"github.com/martinboehm/btcd/wire"
|
"github.com/martinboehm/btcd/wire"
|
||||||
"github.com/martinboehm/btcutil/base58"
|
"github.com/martinboehm/btcutil/base58"
|
||||||
"github.com/martinboehm/btcutil/chaincfg"
|
"github.com/martinboehm/btcutil/chaincfg"
|
||||||
"github.com/trezor/blockbook/bchain"
|
"spacecruft.org/spacecruft/blockbook/bchain"
|
||||||
"github.com/trezor/blockbook/bchain/coins/btc"
|
"spacecruft.org/spacecruft/blockbook/bchain/coins/btc"
|
||||||
"github.com/trezor/blockbook/bchain/coins/utils"
|
"spacecruft.org/spacecruft/blockbook/bchain/coins/utils"
|
||||||
)
|
)
|
||||||
|
|
||||||
const (
|
const (
|
||||||
|
@ -64,9 +66,9 @@ func NewDecredParser(params *chaincfg.Params, c *btc.Configuration) *DecredParse
|
||||||
|
|
||||||
switch d.BitcoinParser.Params.Name {
|
switch d.BitcoinParser.Params.Name {
|
||||||
case "testnet3":
|
case "testnet3":
|
||||||
d.netConfig = &cfg.TestNet3Params
|
d.netConfig = cfg.TestNet3Params()
|
||||||
default:
|
default:
|
||||||
d.netConfig = &cfg.MainNetParams
|
d.netConfig = cfg.MainNetParams()
|
||||||
}
|
}
|
||||||
return d
|
return d
|
||||||
}
|
}
|
||||||
|
@ -202,7 +204,10 @@ func (p *DecredParser) GetAddrDescFromVout(output *bchain.Vout) (bchain.AddressD
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
scriptClass, addresses, _, err := txscript.ExtractPkScriptAddrs(txscript.DefaultScriptVersion, script, p.netConfig)
|
const scriptVersion = 0
|
||||||
|
const treasuryEnabled = true
|
||||||
|
scriptClass, addresses, _, err := txscript.ExtractPkScriptAddrs(scriptVersion, script,
|
||||||
|
p.netConfig, treasuryEnabled)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
@ -240,7 +245,9 @@ func (p *DecredParser) UnpackTx(buf []byte) (*bchain.Tx, uint32, error) {
|
||||||
}
|
}
|
||||||
|
|
||||||
func (p *DecredParser) addrDescFromExtKey(extKey *hdkeychain.ExtendedKey) (bchain.AddressDescriptor, error) {
|
func (p *DecredParser) addrDescFromExtKey(extKey *hdkeychain.ExtendedKey) (bchain.AddressDescriptor, error) {
|
||||||
var addr, err = extKey.Address(p.netConfig)
|
pk := extKey.SerializedPubKey()
|
||||||
|
hash := dcrutil.Hash160(pk)
|
||||||
|
addr, err := dcrutil.NewAddressPubKeyHash(hash, p.netConfig, dcrec.STEcdsaSecp256k1)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
@ -251,7 +258,7 @@ func (p *DecredParser) addrDescFromExtKey(extKey *hdkeychain.ExtendedKey) (bchai
|
||||||
// listed indexes
|
// listed indexes
|
||||||
func (p *DecredParser) DeriveAddressDescriptors(xpub string, change uint32,
|
func (p *DecredParser) DeriveAddressDescriptors(xpub string, change uint32,
|
||||||
indexes []uint32) ([]bchain.AddressDescriptor, error) {
|
indexes []uint32) ([]bchain.AddressDescriptor, error) {
|
||||||
extKey, err := hdkeychain.NewKeyFromString(xpub)
|
extKey, err := hdkeychain.NewKeyFromString(xpub, p.netConfig)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
@ -282,7 +289,7 @@ func (p *DecredParser) DeriveAddressDescriptorsFromTo(xpub string, change uint32
|
||||||
if toIndex <= fromIndex {
|
if toIndex <= fromIndex {
|
||||||
return nil, errors.New("toIndex<=fromIndex")
|
return nil, errors.New("toIndex<=fromIndex")
|
||||||
}
|
}
|
||||||
extKey, err := hdkeychain.NewKeyFromString(xpub)
|
extKey, err := hdkeychain.NewKeyFromString(xpub, p.netConfig)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
|
@ -9,8 +9,8 @@ import (
|
||||||
"reflect"
|
"reflect"
|
||||||
"testing"
|
"testing"
|
||||||
|
|
||||||
"github.com/trezor/blockbook/bchain"
|
"spacecruft.org/spacecruft/blockbook/bchain"
|
||||||
"github.com/trezor/blockbook/bchain/coins/btc"
|
"spacecruft.org/spacecruft/blockbook/bchain/coins/btc"
|
||||||
)
|
)
|
||||||
|
|
||||||
var (
|
var (
|
||||||
|
|
|
@ -15,12 +15,12 @@ import (
|
||||||
"sync"
|
"sync"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
"github.com/decred/dcrd/dcrjson"
|
"github.com/decred/dcrd/dcrjson/v3"
|
||||||
"github.com/golang/glog"
|
"github.com/golang/glog"
|
||||||
"github.com/juju/errors"
|
"github.com/juju/errors"
|
||||||
"github.com/trezor/blockbook/bchain"
|
"spacecruft.org/spacecruft/blockbook/bchain"
|
||||||
"github.com/trezor/blockbook/bchain/coins/btc"
|
"spacecruft.org/spacecruft/blockbook/bchain/coins/btc"
|
||||||
"github.com/trezor/blockbook/common"
|
"spacecruft.org/spacecruft/blockbook/common"
|
||||||
)
|
)
|
||||||
|
|
||||||
// voteBitYes defines the vote bit set when a given block validates the previous
|
// voteBitYes defines the vote bit set when a given block validates the previous
|
||||||
|
|
|
@ -3,8 +3,8 @@ package deeponion
|
||||||
import (
|
import (
|
||||||
"github.com/martinboehm/btcd/wire"
|
"github.com/martinboehm/btcd/wire"
|
||||||
"github.com/martinboehm/btcutil/chaincfg"
|
"github.com/martinboehm/btcutil/chaincfg"
|
||||||
"github.com/trezor/blockbook/bchain"
|
"spacecruft.org/spacecruft/blockbook/bchain"
|
||||||
"github.com/trezor/blockbook/bchain/coins/btc"
|
"spacecruft.org/spacecruft/blockbook/bchain/coins/btc"
|
||||||
)
|
)
|
||||||
|
|
||||||
// magic numbers
|
// magic numbers
|
||||||
|
|
|
@ -10,8 +10,8 @@ import (
|
||||||
"testing"
|
"testing"
|
||||||
|
|
||||||
"github.com/martinboehm/btcutil/chaincfg"
|
"github.com/martinboehm/btcutil/chaincfg"
|
||||||
"github.com/trezor/blockbook/bchain"
|
"spacecruft.org/spacecruft/blockbook/bchain"
|
||||||
"github.com/trezor/blockbook/bchain/coins/btc"
|
"spacecruft.org/spacecruft/blockbook/bchain/coins/btc"
|
||||||
)
|
)
|
||||||
|
|
||||||
func TestMain(m *testing.M) {
|
func TestMain(m *testing.M) {
|
||||||
|
|
|
@ -5,8 +5,8 @@ import (
|
||||||
|
|
||||||
"github.com/golang/glog"
|
"github.com/golang/glog"
|
||||||
"github.com/juju/errors"
|
"github.com/juju/errors"
|
||||||
"github.com/trezor/blockbook/bchain"
|
"spacecruft.org/spacecruft/blockbook/bchain"
|
||||||
"github.com/trezor/blockbook/bchain/coins/btc"
|
"spacecruft.org/spacecruft/blockbook/bchain/coins/btc"
|
||||||
)
|
)
|
||||||
|
|
||||||
// DeepOnionRPC is an interface to JSON-RPC bitcoind service.
|
// DeepOnionRPC is an interface to JSON-RPC bitcoind service.
|
||||||
|
|
|
@ -3,17 +3,19 @@ package digibyte
|
||||||
import (
|
import (
|
||||||
"github.com/martinboehm/btcd/wire"
|
"github.com/martinboehm/btcd/wire"
|
||||||
"github.com/martinboehm/btcutil/chaincfg"
|
"github.com/martinboehm/btcutil/chaincfg"
|
||||||
"github.com/trezor/blockbook/bchain/coins/btc"
|
"spacecruft.org/spacecruft/blockbook/bchain/coins/btc"
|
||||||
)
|
)
|
||||||
|
|
||||||
const (
|
const (
|
||||||
// MainnetMagic is mainnet network constant
|
// MainnetMagic is mainnet network constant
|
||||||
MainnetMagic wire.BitcoinNet = 0xdab6c3fa
|
MainnetMagic wire.BitcoinNet = 0xdab6c3fa
|
||||||
|
TestnetMagic wire.BitcoinNet = 0xddbdc8fd
|
||||||
)
|
)
|
||||||
|
|
||||||
var (
|
var (
|
||||||
// MainNetParams are parser parameters for mainnet
|
// MainNetParams are parser parameters for mainnet
|
||||||
MainNetParams chaincfg.Params
|
MainNetParams chaincfg.Params
|
||||||
|
TestNetParams chaincfg.Params
|
||||||
)
|
)
|
||||||
|
|
||||||
func init() {
|
func init() {
|
||||||
|
@ -22,6 +24,12 @@ func init() {
|
||||||
MainNetParams.PubKeyHashAddrID = []byte{30}
|
MainNetParams.PubKeyHashAddrID = []byte{30}
|
||||||
MainNetParams.ScriptHashAddrID = []byte{63}
|
MainNetParams.ScriptHashAddrID = []byte{63}
|
||||||
MainNetParams.Bech32HRPSegwit = "dgb"
|
MainNetParams.Bech32HRPSegwit = "dgb"
|
||||||
|
|
||||||
|
TestNetParams = chaincfg.TestNet3Params
|
||||||
|
TestNetParams.Net = TestnetMagic
|
||||||
|
TestNetParams.PubKeyHashAddrID = []byte{126}
|
||||||
|
TestNetParams.ScriptHashAddrID = []byte{140}
|
||||||
|
TestNetParams.Bech32HRPSegwit = "dgbt"
|
||||||
}
|
}
|
||||||
|
|
||||||
// DigiByteParser handle
|
// DigiByteParser handle
|
||||||
|
@ -29,18 +37,27 @@ type DigiByteParser struct {
|
||||||
*btc.BitcoinParser
|
*btc.BitcoinParser
|
||||||
}
|
}
|
||||||
|
|
||||||
// NewDigiByteParser returns new VertcoinParser instance
|
// NewDigiByteParser returns new DigiByteParser instance
|
||||||
func NewDigiByteParser(params *chaincfg.Params, c *btc.Configuration) *DigiByteParser {
|
func NewDigiByteParser(params *chaincfg.Params, c *btc.Configuration) *DigiByteParser {
|
||||||
return &DigiByteParser{BitcoinParser: btc.NewBitcoinParser(params, c)}
|
return &DigiByteParser{BitcoinParser: btc.NewBitcoinParser(params, c)}
|
||||||
}
|
}
|
||||||
|
|
||||||
// GetChainParams contains network parameters for the main DigiByte network
|
// GetChainParams contains network parameters for the main DigiByte network
|
||||||
|
// and the DigiByte Testnet network
|
||||||
func GetChainParams(chain string) *chaincfg.Params {
|
func GetChainParams(chain string) *chaincfg.Params {
|
||||||
if !chaincfg.IsRegistered(&MainNetParams) {
|
if !chaincfg.IsRegistered(&MainNetParams) {
|
||||||
err := chaincfg.Register(&MainNetParams)
|
err := chaincfg.Register(&MainNetParams)
|
||||||
|
if err == nil {
|
||||||
|
err = chaincfg.Register(&TestNetParams)
|
||||||
|
}
|
||||||
if err != nil {
|
if err != nil {
|
||||||
panic(err)
|
panic(err)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return &MainNetParams
|
switch chain {
|
||||||
|
case "test":
|
||||||
|
return &TestNetParams
|
||||||
|
default:
|
||||||
|
return &MainNetParams
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -10,8 +10,8 @@ import (
|
||||||
"testing"
|
"testing"
|
||||||
|
|
||||||
"github.com/martinboehm/btcutil/chaincfg"
|
"github.com/martinboehm/btcutil/chaincfg"
|
||||||
"github.com/trezor/blockbook/bchain"
|
"spacecruft.org/spacecruft/blockbook/bchain"
|
||||||
"github.com/trezor/blockbook/bchain/coins/btc"
|
"spacecruft.org/spacecruft/blockbook/bchain/coins/btc"
|
||||||
)
|
)
|
||||||
|
|
||||||
func TestMain(m *testing.M) {
|
func TestMain(m *testing.M) {
|
||||||
|
|
|
@ -4,8 +4,8 @@ import (
|
||||||
"encoding/json"
|
"encoding/json"
|
||||||
|
|
||||||
"github.com/golang/glog"
|
"github.com/golang/glog"
|
||||||
"github.com/trezor/blockbook/bchain"
|
"spacecruft.org/spacecruft/blockbook/bchain"
|
||||||
"github.com/trezor/blockbook/bchain/coins/btc"
|
"spacecruft.org/spacecruft/blockbook/bchain/coins/btc"
|
||||||
)
|
)
|
||||||
|
|
||||||
// DigiByteRPC is an interface to JSON-RPC bitcoind service.
|
// DigiByteRPC is an interface to JSON-RPC bitcoind service.
|
||||||
|
|
|
@ -10,9 +10,9 @@ import (
|
||||||
"github.com/juju/errors"
|
"github.com/juju/errors"
|
||||||
"github.com/martinboehm/btcd/wire"
|
"github.com/martinboehm/btcd/wire"
|
||||||
"github.com/martinboehm/btcutil/chaincfg"
|
"github.com/martinboehm/btcutil/chaincfg"
|
||||||
"github.com/trezor/blockbook/bchain"
|
"spacecruft.org/spacecruft/blockbook/bchain"
|
||||||
"github.com/trezor/blockbook/bchain/coins/btc"
|
"spacecruft.org/spacecruft/blockbook/bchain/coins/btc"
|
||||||
"github.com/trezor/blockbook/bchain/coins/utils"
|
"spacecruft.org/spacecruft/blockbook/bchain/coins/utils"
|
||||||
)
|
)
|
||||||
|
|
||||||
const (
|
const (
|
||||||
|
|
|
@ -14,8 +14,8 @@ import (
|
||||||
"testing"
|
"testing"
|
||||||
|
|
||||||
"github.com/martinboehm/btcutil/chaincfg"
|
"github.com/martinboehm/btcutil/chaincfg"
|
||||||
"github.com/trezor/blockbook/bchain"
|
"spacecruft.org/spacecruft/blockbook/bchain"
|
||||||
"github.com/trezor/blockbook/bchain/coins/btc"
|
"spacecruft.org/spacecruft/blockbook/bchain/coins/btc"
|
||||||
)
|
)
|
||||||
|
|
||||||
func TestMain(m *testing.M) {
|
func TestMain(m *testing.M) {
|
||||||
|
|
|
@ -4,8 +4,8 @@ import (
|
||||||
"encoding/json"
|
"encoding/json"
|
||||||
|
|
||||||
"github.com/golang/glog"
|
"github.com/golang/glog"
|
||||||
"github.com/trezor/blockbook/bchain"
|
"spacecruft.org/spacecruft/blockbook/bchain"
|
||||||
"github.com/trezor/blockbook/bchain/coins/btc"
|
"spacecruft.org/spacecruft/blockbook/bchain/coins/btc"
|
||||||
)
|
)
|
||||||
|
|
||||||
// DivicoinRPC is an interface to JSON-RPC bitcoind service.
|
// DivicoinRPC is an interface to JSON-RPC bitcoind service.
|
||||||
|
|
|
@ -5,9 +5,9 @@ import (
|
||||||
|
|
||||||
"github.com/martinboehm/btcd/wire"
|
"github.com/martinboehm/btcd/wire"
|
||||||
"github.com/martinboehm/btcutil/chaincfg"
|
"github.com/martinboehm/btcutil/chaincfg"
|
||||||
"github.com/trezor/blockbook/bchain"
|
"spacecruft.org/spacecruft/blockbook/bchain"
|
||||||
"github.com/trezor/blockbook/bchain/coins/btc"
|
"spacecruft.org/spacecruft/blockbook/bchain/coins/btc"
|
||||||
"github.com/trezor/blockbook/bchain/coins/utils"
|
"spacecruft.org/spacecruft/blockbook/bchain/coins/utils"
|
||||||
)
|
)
|
||||||
|
|
||||||
// magic numbers
|
// magic numbers
|
||||||
|
|
|
@ -14,8 +14,8 @@ import (
|
||||||
"testing"
|
"testing"
|
||||||
|
|
||||||
"github.com/martinboehm/btcutil/chaincfg"
|
"github.com/martinboehm/btcutil/chaincfg"
|
||||||
"github.com/trezor/blockbook/bchain"
|
"spacecruft.org/spacecruft/blockbook/bchain"
|
||||||
"github.com/trezor/blockbook/bchain/coins/btc"
|
"spacecruft.org/spacecruft/blockbook/bchain/coins/btc"
|
||||||
)
|
)
|
||||||
|
|
||||||
func TestMain(m *testing.M) {
|
func TestMain(m *testing.M) {
|
||||||
|
|
|
@ -4,8 +4,8 @@ import (
|
||||||
"encoding/json"
|
"encoding/json"
|
||||||
|
|
||||||
"github.com/golang/glog"
|
"github.com/golang/glog"
|
||||||
"github.com/trezor/blockbook/bchain"
|
"spacecruft.org/spacecruft/blockbook/bchain"
|
||||||
"github.com/trezor/blockbook/bchain/coins/btc"
|
"spacecruft.org/spacecruft/blockbook/bchain/coins/btc"
|
||||||
)
|
)
|
||||||
|
|
||||||
// DogecoinRPC is an interface to JSON-RPC dogecoind service.
|
// DogecoinRPC is an interface to JSON-RPC dogecoind service.
|
||||||
|
|
|
@ -12,7 +12,7 @@ import (
|
||||||
ethcommon "github.com/ethereum/go-ethereum/common"
|
ethcommon "github.com/ethereum/go-ethereum/common"
|
||||||
"github.com/golang/glog"
|
"github.com/golang/glog"
|
||||||
"github.com/juju/errors"
|
"github.com/juju/errors"
|
||||||
"github.com/trezor/blockbook/bchain"
|
"spacecruft.org/spacecruft/blockbook/bchain"
|
||||||
)
|
)
|
||||||
|
|
||||||
var erc20abi = `[{"constant":true,"inputs":[],"name":"name","outputs":[{"name":"","type":"string"}],"payable":false,"type":"function","signature":"0x06fdde03"},
|
var erc20abi = `[{"constant":true,"inputs":[],"name":"name","outputs":[{"name":"","type":"string"}],"payable":false,"type":"function","signature":"0x06fdde03"},
|
||||||
|
@ -183,18 +183,26 @@ func (b *EthereumRPC) EthereumTypeGetErc20ContractInfo(contractDesc bchain.Addre
|
||||||
address := EIP55Address(contractDesc)
|
address := EIP55Address(contractDesc)
|
||||||
data, err := b.ethCall(erc20NameSignature, address)
|
data, err := b.ethCall(erc20NameSignature, address)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
// 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)
|
||||||
}
|
}
|
||||||
name := parseErc20StringProperty(contractDesc, data)
|
name := parseErc20StringProperty(contractDesc, data)
|
||||||
if name != "" {
|
if name != "" {
|
||||||
data, err = b.ethCall(erc20SymbolSignature, address)
|
data, err = b.ethCall(erc20SymbolSignature, address)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
glog.Warning(errors.Annotatef(err, "erc20SymbolSignature %v", address))
|
||||||
|
return nil, nil
|
||||||
|
// return nil, errors.Annotatef(err, "erc20SymbolSignature %v", address)
|
||||||
}
|
}
|
||||||
symbol := parseErc20StringProperty(contractDesc, data)
|
symbol := parseErc20StringProperty(contractDesc, data)
|
||||||
data, err = b.ethCall(erc20DecimalsSignature, address)
|
data, err = b.ethCall(erc20DecimalsSignature, address)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
glog.Warning(errors.Annotatef(err, "erc20DecimalsSignature %v", address))
|
||||||
|
// return nil, errors.Annotatef(err, "erc20DecimalsSignature %v", address)
|
||||||
}
|
}
|
||||||
contract = &bchain.Erc20Contract{
|
contract = &bchain.Erc20Contract{
|
||||||
Contract: address,
|
Contract: address,
|
||||||
|
|
|
@ -8,8 +8,8 @@ import (
|
||||||
"strings"
|
"strings"
|
||||||
"testing"
|
"testing"
|
||||||
|
|
||||||
"github.com/trezor/blockbook/bchain"
|
"spacecruft.org/spacecruft/blockbook/bchain"
|
||||||
"github.com/trezor/blockbook/tests/dbtestdata"
|
"spacecruft.org/spacecruft/blockbook/tests/dbtestdata"
|
||||||
)
|
)
|
||||||
|
|
||||||
func TestErc20_erc20GetTransfersFromLog(t *testing.T) {
|
func TestErc20_erc20GetTransfersFromLog(t *testing.T) {
|
||||||
|
|
|
@ -8,7 +8,7 @@ import (
|
||||||
"github.com/ethereum/go-ethereum/common/hexutil"
|
"github.com/ethereum/go-ethereum/common/hexutil"
|
||||||
"github.com/golang/protobuf/proto"
|
"github.com/golang/protobuf/proto"
|
||||||
"github.com/juju/errors"
|
"github.com/juju/errors"
|
||||||
"github.com/trezor/blockbook/bchain"
|
"spacecruft.org/spacecruft/blockbook/bchain"
|
||||||
"golang.org/x/crypto/sha3"
|
"golang.org/x/crypto/sha3"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
@ -311,8 +311,14 @@ func (p *EthereumParser) PackTx(tx *bchain.Tx, height uint32, blockTime int64) (
|
||||||
if pt.Receipt.GasUsed, err = hexDecodeBig(r.Receipt.GasUsed); err != nil {
|
if pt.Receipt.GasUsed, err = hexDecodeBig(r.Receipt.GasUsed); err != nil {
|
||||||
return nil, errors.Annotatef(err, "GasUsed %v", r.Receipt.GasUsed)
|
return nil, errors.Annotatef(err, "GasUsed %v", r.Receipt.GasUsed)
|
||||||
}
|
}
|
||||||
if pt.Receipt.Status, err = hexDecodeBig(r.Receipt.Status); err != nil {
|
if r.Receipt.Status != "" {
|
||||||
return nil, errors.Annotatef(err, "Status %v", 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'}
|
||||||
}
|
}
|
||||||
ptLogs := make([]*ProtoCompleteTransaction_ReceiptType_LogType, len(r.Receipt.Logs))
|
ptLogs := make([]*ProtoCompleteTransaction_ReceiptType_LogType, len(r.Receipt.Logs))
|
||||||
for i, l := range r.Receipt.Logs {
|
for i, l := range r.Receipt.Logs {
|
||||||
|
@ -379,9 +385,14 @@ func (p *EthereumParser) UnpackTx(buf []byte) (*bchain.Tx, uint32, error) {
|
||||||
Topics: topics,
|
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{
|
rr = &rpcReceipt{
|
||||||
GasUsed: hexEncodeBig(pt.Receipt.GasUsed),
|
GasUsed: hexEncodeBig(pt.Receipt.GasUsed),
|
||||||
Status: hexEncodeBig(pt.Receipt.Status),
|
Status: status,
|
||||||
Logs: logs,
|
Logs: logs,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -461,16 +472,20 @@ func (p *EthereumParser) EthereumTypeGetErc20FromTx(tx *bchain.Tx) ([]bchain.Erc
|
||||||
return r, nil
|
return r, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// TxStatus is status of transaction
|
||||||
|
type TxStatus int
|
||||||
|
|
||||||
|
// statuses of transaction
|
||||||
const (
|
const (
|
||||||
txStatusUnknown = iota - 2
|
TxStatusUnknown = TxStatus(iota - 2)
|
||||||
txStatusPending
|
TxStatusPending
|
||||||
txStatusFailure
|
TxStatusFailure
|
||||||
txStatusOK
|
TxStatusOK
|
||||||
)
|
)
|
||||||
|
|
||||||
// EthereumTxData contains ethereum specific transaction data
|
// EthereumTxData contains ethereum specific transaction data
|
||||||
type EthereumTxData struct {
|
type EthereumTxData struct {
|
||||||
Status int `json:"status"` // 1 OK, 0 Fail, -1 pending, -2 unknown
|
Status TxStatus `json:"status"` // 1 OK, 0 Fail, -1 pending, -2 unknown
|
||||||
Nonce uint64 `json:"nonce"`
|
Nonce uint64 `json:"nonce"`
|
||||||
GasLimit *big.Int `json:"gaslimit"`
|
GasLimit *big.Int `json:"gaslimit"`
|
||||||
GasUsed *big.Int `json:"gasused"`
|
GasUsed *big.Int `json:"gasused"`
|
||||||
|
@ -480,8 +495,13 @@ type EthereumTxData struct {
|
||||||
|
|
||||||
// GetEthereumTxData returns EthereumTxData from bchain.Tx
|
// GetEthereumTxData returns EthereumTxData from bchain.Tx
|
||||||
func GetEthereumTxData(tx *bchain.Tx) *EthereumTxData {
|
func GetEthereumTxData(tx *bchain.Tx) *EthereumTxData {
|
||||||
etd := EthereumTxData{Status: txStatusPending}
|
return GetEthereumTxDataFromSpecificData(tx.CoinSpecificData)
|
||||||
csd, ok := tx.CoinSpecificData.(completeTransaction)
|
}
|
||||||
|
|
||||||
|
// GetEthereumTxDataFromSpecificData returns EthereumTxData from coinSpecificData
|
||||||
|
func GetEthereumTxDataFromSpecificData(coinSpecificData interface{}) *EthereumTxData {
|
||||||
|
etd := EthereumTxData{Status: TxStatusPending}
|
||||||
|
csd, ok := coinSpecificData.(completeTransaction)
|
||||||
if ok {
|
if ok {
|
||||||
if csd.Tx != nil {
|
if csd.Tx != nil {
|
||||||
etd.Nonce, _ = hexutil.DecodeUint64(csd.Tx.AccountNonce)
|
etd.Nonce, _ = hexutil.DecodeUint64(csd.Tx.AccountNonce)
|
||||||
|
@ -492,11 +512,11 @@ func GetEthereumTxData(tx *bchain.Tx) *EthereumTxData {
|
||||||
if csd.Receipt != nil {
|
if csd.Receipt != nil {
|
||||||
switch csd.Receipt.Status {
|
switch csd.Receipt.Status {
|
||||||
case "0x1":
|
case "0x1":
|
||||||
etd.Status = txStatusOK
|
etd.Status = TxStatusOK
|
||||||
case "": // old transactions did not set status
|
case "": // old transactions did not set status
|
||||||
etd.Status = txStatusUnknown
|
etd.Status = TxStatusUnknown
|
||||||
default:
|
default:
|
||||||
etd.Status = txStatusFailure
|
etd.Status = TxStatusFailure
|
||||||
}
|
}
|
||||||
etd.GasUsed, _ = hexutil.DecodeBig(csd.Receipt.GasUsed)
|
etd.GasUsed, _ = hexutil.DecodeBig(csd.Receipt.GasUsed)
|
||||||
}
|
}
|
||||||
|
|
|
@ -9,8 +9,8 @@ import (
|
||||||
"reflect"
|
"reflect"
|
||||||
"testing"
|
"testing"
|
||||||
|
|
||||||
"github.com/trezor/blockbook/bchain"
|
"spacecruft.org/spacecruft/blockbook/bchain"
|
||||||
"github.com/trezor/blockbook/tests/dbtestdata"
|
"spacecruft.org/spacecruft/blockbook/tests/dbtestdata"
|
||||||
)
|
)
|
||||||
|
|
||||||
func TestEthParser_GetAddrDescFromAddress(t *testing.T) {
|
func TestEthParser_GetAddrDescFromAddress(t *testing.T) {
|
||||||
|
@ -68,7 +68,7 @@ func TestEthParser_GetAddrDescFromAddress(t *testing.T) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
var testTx1, testTx2 bchain.Tx
|
var testTx1, testTx2, testTx1Failed, testTx1NoStatus bchain.Tx
|
||||||
|
|
||||||
func init() {
|
func init() {
|
||||||
|
|
||||||
|
@ -156,6 +156,83 @@ 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) {
|
func TestEthereumParser_PackTx(t *testing.T) {
|
||||||
|
@ -189,6 +266,24 @@ func TestEthereumParser_PackTx(t *testing.T) {
|
||||||
},
|
},
|
||||||
want: dbtestdata.EthTx2Packed,
|
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)
|
p := NewEthereumParser(1)
|
||||||
for _, tt := range tests {
|
for _, tt := range tests {
|
||||||
|
@ -230,6 +325,18 @@ func TestEthereumParser_UnpackTx(t *testing.T) {
|
||||||
want: &testTx2,
|
want: &testTx2,
|
||||||
want1: 4321000,
|
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)
|
p := NewEthereumParser(1)
|
||||||
for _, tt := range tests {
|
for _, tt := range tests {
|
||||||
|
|
|
@ -11,13 +11,14 @@ import (
|
||||||
|
|
||||||
ethereum "github.com/ethereum/go-ethereum"
|
ethereum "github.com/ethereum/go-ethereum"
|
||||||
ethcommon "github.com/ethereum/go-ethereum/common"
|
ethcommon "github.com/ethereum/go-ethereum/common"
|
||||||
|
"github.com/ethereum/go-ethereum/common/hexutil"
|
||||||
ethtypes "github.com/ethereum/go-ethereum/core/types"
|
ethtypes "github.com/ethereum/go-ethereum/core/types"
|
||||||
"github.com/ethereum/go-ethereum/ethclient"
|
"github.com/ethereum/go-ethereum/ethclient"
|
||||||
"github.com/ethereum/go-ethereum/rpc"
|
"github.com/ethereum/go-ethereum/rpc"
|
||||||
"github.com/golang/glog"
|
"github.com/golang/glog"
|
||||||
"github.com/juju/errors"
|
"github.com/juju/errors"
|
||||||
"github.com/trezor/blockbook/bchain"
|
"spacecruft.org/spacecruft/blockbook/bchain"
|
||||||
"github.com/trezor/blockbook/common"
|
"spacecruft.org/spacecruft/blockbook/common"
|
||||||
)
|
)
|
||||||
|
|
||||||
// EthereumNet type specifies the type of ethereum network
|
// EthereumNet type specifies the type of ethereum network
|
||||||
|
@ -28,6 +29,8 @@ const (
|
||||||
MainNet EthereumNet = 1
|
MainNet EthereumNet = 1
|
||||||
// TestNet is Ropsten test network
|
// TestNet is Ropsten test network
|
||||||
TestNet EthereumNet = 3
|
TestNet EthereumNet = 3
|
||||||
|
// TestNetGoerli is Goerli test network
|
||||||
|
TestNetGoerli EthereumNet = 5
|
||||||
)
|
)
|
||||||
|
|
||||||
// Configuration represents json config file
|
// Configuration represents json config file
|
||||||
|
@ -159,6 +162,9 @@ func (b *EthereumRPC) Initialize() error {
|
||||||
b.Testnet = true
|
b.Testnet = true
|
||||||
b.Network = "testnet"
|
b.Network = "testnet"
|
||||||
break
|
break
|
||||||
|
case TestNetGoerli:
|
||||||
|
b.Testnet = true
|
||||||
|
b.Network = "goerli"
|
||||||
default:
|
default:
|
||||||
return errors.Errorf("Unknown network id %v", id)
|
return errors.Errorf("Unknown network id %v", id)
|
||||||
}
|
}
|
||||||
|
@ -177,7 +183,7 @@ func (b *EthereumRPC) CreateMempool(chain bchain.BlockChain) (bchain.Mempool, er
|
||||||
}
|
}
|
||||||
|
|
||||||
// InitializeMempool creates subscriptions to newHeads and newPendingTransactions
|
// InitializeMempool creates subscriptions to newHeads and newPendingTransactions
|
||||||
func (b *EthereumRPC) InitializeMempool(addrDescForOutpoint bchain.AddrDescForOutpointFunc, onNewTxAddr bchain.OnNewTxAddrFunc) error {
|
func (b *EthereumRPC) InitializeMempool(addrDescForOutpoint bchain.AddrDescForOutpointFunc, onNewTxAddr bchain.OnNewTxAddrFunc, onNewTx bchain.OnNewTxFunc) error {
|
||||||
if b.Mempool == nil {
|
if b.Mempool == nil {
|
||||||
return errors.New("Mempool not created")
|
return errors.New("Mempool not created")
|
||||||
}
|
}
|
||||||
|
@ -192,6 +198,7 @@ func (b *EthereumRPC) InitializeMempool(addrDescForOutpoint bchain.AddrDescForOu
|
||||||
}
|
}
|
||||||
|
|
||||||
b.Mempool.OnNewTxAddr = onNewTxAddr
|
b.Mempool.OnNewTxAddr = onNewTxAddr
|
||||||
|
b.Mempool.OnNewTx = onNewTx
|
||||||
|
|
||||||
if err = b.subscribeEvents(); err != nil {
|
if err = b.subscribeEvents(); err != nil {
|
||||||
return err
|
return err
|
||||||
|
@ -333,19 +340,15 @@ func (b *EthereumRPC) GetChainInfo() (*bchain.ChainInfo, error) {
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
var ver, protocol string
|
var ver string
|
||||||
if err := b.rpc.CallContext(ctx, &ver, "web3_clientVersion"); err != nil {
|
if err := b.rpc.CallContext(ctx, &ver, "web3_clientVersion"); err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
if err := b.rpc.CallContext(ctx, &protocol, "eth_protocolVersion"); err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
rv := &bchain.ChainInfo{
|
rv := &bchain.ChainInfo{
|
||||||
Blocks: int(h.Number.Int64()),
|
Blocks: int(h.Number.Int64()),
|
||||||
Bestblockhash: h.Hash().Hex(),
|
Bestblockhash: h.Hash().Hex(),
|
||||||
Difficulty: h.Difficulty.String(),
|
Difficulty: h.Difficulty.String(),
|
||||||
Version: ver,
|
Version: ver,
|
||||||
ProtocolVersion: protocol,
|
|
||||||
}
|
}
|
||||||
idi := int(id.Uint64())
|
idi := int(id.Uint64())
|
||||||
if idi == 1 {
|
if idi == 1 {
|
||||||
|
@ -721,6 +724,18 @@ func (b *EthereumRPC) EthereumTypeEstimateGas(params map[string]interface{}) (ui
|
||||||
if ok && len(s) > 0 {
|
if ok && len(s) > 0 {
|
||||||
msg.Data = ethcommon.FromHex(s)
|
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)
|
return b.client.EstimateGas(ctx, msg)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -1,11 +1,11 @@
|
||||||
// Code generated by protoc-gen-go. DO NOT EDIT.
|
// Code generated by protoc-gen-go. DO NOT EDIT.
|
||||||
// source: tx.proto
|
// source: bchain/coins/eth/ethtx.proto
|
||||||
|
|
||||||
/*
|
/*
|
||||||
Package eth is a generated protocol buffer package.
|
Package eth is a generated protocol buffer package.
|
||||||
|
|
||||||
It is generated from these files:
|
It is generated from these files:
|
||||||
tx.proto
|
bchain/coins/eth/ethtx.proto
|
||||||
|
|
||||||
It has these top-level messages:
|
It has these top-level messages:
|
||||||
ProtoCompleteTransaction
|
ProtoCompleteTransaction
|
||||||
|
@ -228,33 +228,34 @@ func init() {
|
||||||
proto.RegisterType((*ProtoCompleteTransaction_ReceiptType_LogType)(nil), "eth.ProtoCompleteTransaction.ReceiptType.LogType")
|
proto.RegisterType((*ProtoCompleteTransaction_ReceiptType_LogType)(nil), "eth.ProtoCompleteTransaction.ReceiptType.LogType")
|
||||||
}
|
}
|
||||||
|
|
||||||
func init() { proto.RegisterFile("tx.proto", fileDescriptor0) }
|
func init() { proto.RegisterFile("bchain/coins/eth/ethtx.proto", fileDescriptor0) }
|
||||||
|
|
||||||
var fileDescriptor0 = []byte{
|
var fileDescriptor0 = []byte{
|
||||||
// 393 bytes of a gzipped FileDescriptorProto
|
// 409 bytes of a gzipped FileDescriptorProto
|
||||||
0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0x8c, 0x92, 0xdf, 0x8a, 0xd4, 0x30,
|
0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0x8c, 0x92, 0xdf, 0x8a, 0xd4, 0x30,
|
||||||
0x14, 0xc6, 0xe9, 0x9f, 0xf9, 0xb3, 0xa7, 0x55, 0x24, 0x88, 0x84, 0xe2, 0x45, 0x59, 0xbc, 0xa8,
|
0x18, 0xc5, 0xe9, 0x9f, 0x99, 0xd9, 0xfd, 0xa6, 0x8a, 0x04, 0x91, 0x30, 0xec, 0x45, 0x59, 0xbc,
|
||||||
0x5e, 0x14, 0x5c, 0x7d, 0x81, 0x75, 0xc4, 0x55, 0x18, 0xd6, 0x21, 0x46, 0xef, 0xb3, 0x69, 0xd8,
|
0x18, 0xbd, 0xe8, 0xe2, 0xea, 0x0b, 0xac, 0x23, 0xae, 0xc2, 0xb0, 0x0e, 0x31, 0x7a, 0x9f, 0x49,
|
||||||
0x29, 0xb6, 0x4d, 0x69, 0x52, 0xe8, 0xbe, 0x91, 0x2f, 0xe4, 0xbb, 0x78, 0x29, 0x39, 0x4d, 0xd7,
|
0xc3, 0x36, 0x38, 0x6d, 0x4a, 0x93, 0x42, 0xf7, 0x8d, 0x7c, 0x21, 0xdf, 0xc5, 0x4b, 0xc9, 0xd7,
|
||||||
0x11, 0x51, 0xbc, 0x3b, 0xbf, 0x6f, 0xce, 0x37, 0xf9, 0xbe, 0xa4, 0xb0, 0xb5, 0x53, 0xd9, 0x0f,
|
0x74, 0x1d, 0x11, 0x65, 0x2f, 0x0a, 0xf9, 0x9d, 0x7e, 0xa7, 0x39, 0x27, 0x29, 0x9c, 0xed, 0x65,
|
||||||
0xda, 0x6a, 0x12, 0x29, 0x7b, 0x3c, 0xff, 0xb6, 0x02, 0x7a, 0x70, 0xb8, 0xd3, 0x6d, 0xdf, 0x28,
|
0x25, 0x74, 0x73, 0x21, 0x8d, 0x6e, 0xec, 0x85, 0x72, 0x95, 0x7f, 0xdc, 0x50, 0xb4, 0x9d, 0x71,
|
||||||
0xab, 0xf8, 0x20, 0x3a, 0x23, 0xa4, 0xad, 0x75, 0x47, 0x72, 0x48, 0xde, 0x34, 0x5a, 0x7e, 0xbd,
|
0x86, 0x24, 0xca, 0x55, 0xe7, 0xdf, 0x67, 0x40, 0x77, 0x1e, 0x37, 0xa6, 0x6e, 0x0f, 0xca, 0x29,
|
||||||
0x1e, 0xdb, 0x1b, 0x35, 0xd0, 0x20, 0x0f, 0x8a, 0x07, 0xec, 0x54, 0x22, 0x4f, 0xe1, 0x0c, 0x91,
|
0xde, 0x89, 0xc6, 0x0a, 0xe9, 0xb4, 0x69, 0x48, 0x0e, 0xcb, 0xb7, 0x07, 0x23, 0xbf, 0xdd, 0xf4,
|
||||||
0xd7, 0xad, 0xa2, 0x61, 0x1e, 0x14, 0x31, 0xfb, 0x25, 0x90, 0xd7, 0x10, 0xf2, 0x89, 0x46, 0x79,
|
0xf5, 0x5e, 0x75, 0x34, 0xca, 0xa3, 0xf5, 0x23, 0x76, 0x2c, 0x91, 0x33, 0x38, 0x45, 0xe4, 0xba,
|
||||||
0x50, 0x24, 0x17, 0xcf, 0x4a, 0x65, 0x8f, 0xe5, 0xdf, 0x8e, 0x2a, 0xf9, 0xc4, 0xef, 0x7a, 0xc5,
|
0x56, 0x34, 0xce, 0xa3, 0x75, 0xca, 0x7e, 0x0b, 0xe4, 0x0d, 0xc4, 0x7c, 0xa0, 0x49, 0x1e, 0xad,
|
||||||
0x42, 0x3e, 0x91, 0x1d, 0x6c, 0x98, 0x92, 0xaa, 0xee, 0x2d, 0x8d, 0xd1, 0xfa, 0xfc, 0xdf, 0x56,
|
0x97, 0x97, 0xcf, 0x0b, 0xe5, 0xaa, 0xe2, 0x5f, 0x5b, 0x15, 0x7c, 0xe0, 0x77, 0xad, 0x62, 0x31,
|
||||||
0xbf, 0x8c, 0xfe, 0xc5, 0x99, 0xfd, 0x08, 0x60, 0x3d, 0xff, 0x27, 0x39, 0x87, 0xf4, 0x52, 0x4a,
|
0x1f, 0xc8, 0x06, 0x16, 0x4c, 0x49, 0xa5, 0x5b, 0x47, 0x53, 0xb4, 0xbe, 0xf8, 0xbf, 0x35, 0x0c,
|
||||||
0x3d, 0x76, 0xf6, 0x5a, 0x77, 0x52, 0x61, 0x8d, 0x98, 0xfd, 0xa6, 0x91, 0x0c, 0xb6, 0x57, 0xc2,
|
0xa3, 0x7f, 0x72, 0xae, 0x7e, 0x46, 0x30, 0x1f, 0xbf, 0x49, 0xce, 0x21, 0xbb, 0x92, 0xd2, 0xf4,
|
||||||
0x1c, 0x86, 0x5a, 0xce, 0x35, 0x52, 0x76, 0xcf, 0xfe, 0xb7, 0x7d, 0xdd, 0xd6, 0x16, 0xbb, 0xc4,
|
0x8d, 0xbb, 0x31, 0x8d, 0x54, 0x58, 0x23, 0x65, 0x7f, 0x68, 0x64, 0x05, 0x27, 0xd7, 0xc2, 0xee,
|
||||||
0xec, 0x9e, 0xc9, 0x63, 0x58, 0x7d, 0x11, 0xcd, 0xa8, 0x30, 0x69, 0xca, 0x66, 0x20, 0x14, 0x36,
|
0x3a, 0x2d, 0xc7, 0x1a, 0x19, 0xbb, 0xe7, 0xf0, 0x6e, 0xab, 0x6b, 0xed, 0xb0, 0x4b, 0xca, 0xee,
|
||||||
0x07, 0x71, 0xd7, 0x68, 0x51, 0xd1, 0x15, 0xea, 0x0b, 0x12, 0x02, 0xf1, 0x7b, 0x61, 0x8e, 0x74,
|
0x99, 0x3c, 0x85, 0xd9, 0x57, 0x71, 0xe8, 0x15, 0x26, 0xcd, 0xd8, 0x08, 0x84, 0xc2, 0x62, 0x27,
|
||||||
0x8d, 0x32, 0xce, 0xe4, 0x21, 0x84, 0x5c, 0xd3, 0x0d, 0x2a, 0x21, 0xd7, 0x6e, 0xe7, 0xdd, 0xa0,
|
0xee, 0x0e, 0x46, 0x94, 0x74, 0x86, 0xfa, 0x84, 0x84, 0x40, 0xfa, 0x41, 0xd8, 0x8a, 0xce, 0x51,
|
||||||
0x5b, 0xba, 0x9d, 0x77, 0xdc, 0x4c, 0x5e, 0xc0, 0xa3, 0x93, 0xca, 0x1f, 0xba, 0x4a, 0x4d, 0xf4,
|
0xc6, 0x35, 0x79, 0x0c, 0x31, 0x37, 0x74, 0x81, 0x4a, 0xcc, 0x8d, 0x9f, 0x79, 0xdf, 0x99, 0x9a,
|
||||||
0x0c, 0x9f, 0xe3, 0x0f, 0x3d, 0xfb, 0x1e, 0x40, 0x72, 0x72, 0x27, 0x2e, 0xcd, 0x95, 0x30, 0x9f,
|
0x9e, 0x8c, 0x33, 0x7e, 0x4d, 0x5e, 0xc2, 0x93, 0xa3, 0xca, 0x1f, 0x9b, 0x52, 0x0d, 0xf4, 0x14,
|
||||||
0x8d, 0xaa, 0xb0, 0x7a, 0xca, 0x16, 0x24, 0x4f, 0x60, 0xfd, 0xc9, 0x0a, 0x3b, 0x1a, 0xdf, 0xd9,
|
0xaf, 0xe3, 0x2f, 0x7d, 0xf5, 0x23, 0x82, 0xe5, 0xd1, 0x99, 0xf8, 0x34, 0xd7, 0xc2, 0x7e, 0xb1,
|
||||||
0x13, 0xd9, 0x41, 0xb4, 0xd7, 0xb7, 0x34, 0xca, 0xa3, 0x22, 0xb9, 0x78, 0xf9, 0xdf, 0xb7, 0x5f,
|
0xaa, 0xc4, 0xea, 0x19, 0x9b, 0x90, 0x3c, 0x83, 0xf9, 0x67, 0x27, 0x5c, 0x6f, 0x43, 0xe7, 0x40,
|
||||||
0xee, 0xf5, 0x2d, 0xbe, 0x82, 0x73, 0x67, 0x1f, 0x61, 0xe3, 0xd9, 0x25, 0xb8, 0xac, 0xaa, 0x41,
|
0x64, 0x03, 0xc9, 0xd6, 0xdc, 0xd2, 0x24, 0x4f, 0xd6, 0xcb, 0xcb, 0x57, 0x0f, 0x3e, 0xfd, 0x62,
|
||||||
0x19, 0xb3, 0x24, 0xf0, 0xe8, 0xba, 0xbe, 0x15, 0x56, 0xf8, 0xf3, 0x71, 0x76, 0xa9, 0xb8, 0xee,
|
0x6b, 0x6e, 0xf1, 0x16, 0xbc, 0x7b, 0xf5, 0x09, 0x16, 0x81, 0x7d, 0x82, 0xab, 0xb2, 0xec, 0x94,
|
||||||
0x6b, 0x69, 0x30, 0x40, 0xca, 0x3c, 0xdd, 0xac, 0xf1, 0xb3, 0x7d, 0xf5, 0x33, 0x00, 0x00, 0xff,
|
0xb5, 0x53, 0x82, 0x80, 0xbe, 0xeb, 0x3b, 0xe1, 0x44, 0xd8, 0x1f, 0xd7, 0x3e, 0x15, 0x37, 0xad,
|
||||||
0xff, 0xde, 0xd5, 0x28, 0xa3, 0xc2, 0x02, 0x00, 0x00,
|
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,
|
||||||
}
|
}
|
|
@ -0,0 +1,64 @@
|
||||||
|
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
|
||||||
|
}
|
|
@ -1,4 +1,4 @@
|
||||||
package xzc
|
package firo
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"bytes"
|
"bytes"
|
||||||
|
@ -9,15 +9,18 @@ import (
|
||||||
"github.com/martinboehm/btcd/chaincfg/chainhash"
|
"github.com/martinboehm/btcd/chaincfg/chainhash"
|
||||||
"github.com/martinboehm/btcd/wire"
|
"github.com/martinboehm/btcd/wire"
|
||||||
"github.com/martinboehm/btcutil/chaincfg"
|
"github.com/martinboehm/btcutil/chaincfg"
|
||||||
"github.com/trezor/blockbook/bchain"
|
"spacecruft.org/spacecruft/blockbook/bchain"
|
||||||
"github.com/trezor/blockbook/bchain/coins/btc"
|
"spacecruft.org/spacecruft/blockbook/bchain/coins/btc"
|
||||||
)
|
)
|
||||||
|
|
||||||
const (
|
const (
|
||||||
OpZeroCoinMint = 0xc1
|
OpZeroCoinMint = 0xc1
|
||||||
OpZeroCoinSpend = 0xc2
|
OpZeroCoinSpend = 0xc2
|
||||||
OpSigmaMint = 0xc3
|
OpSigmaMint = 0xc3
|
||||||
OpSigmaSpend = 0xc4
|
OpSigmaSpend = 0xc4
|
||||||
|
OpLelantusMint = 0xc5
|
||||||
|
OpLelantusJMint = 0xc6
|
||||||
|
OpLelantusJoinSplit = 0xc7
|
||||||
|
|
||||||
MainnetMagic wire.BitcoinNet = 0xe3d9fef1
|
MainnetMagic wire.BitcoinNet = 0xe3d9fef1
|
||||||
TestnetMagic wire.BitcoinNet = 0xcffcbeea
|
TestnetMagic wire.BitcoinNet = 0xcffcbeea
|
||||||
|
@ -28,6 +31,8 @@ const (
|
||||||
MTPL = 64
|
MTPL = 64
|
||||||
|
|
||||||
SpendTxID = "0000000000000000000000000000000000000000000000000000000000000000"
|
SpendTxID = "0000000000000000000000000000000000000000000000000000000000000000"
|
||||||
|
|
||||||
|
TransactionQuorumCommitmentType = 6
|
||||||
)
|
)
|
||||||
|
|
||||||
var (
|
var (
|
||||||
|
@ -58,21 +63,21 @@ func init() {
|
||||||
RegtestParams.Net = RegtestMagic
|
RegtestParams.Net = RegtestMagic
|
||||||
}
|
}
|
||||||
|
|
||||||
// ZcoinParser handle
|
// FiroParser handle
|
||||||
type ZcoinParser struct {
|
type FiroParser struct {
|
||||||
*btc.BitcoinParser
|
*btc.BitcoinParser
|
||||||
}
|
}
|
||||||
|
|
||||||
// NewZcoinParser returns new ZcoinParser instance
|
// NewFiroParser returns new FiroParser instance
|
||||||
func NewZcoinParser(params *chaincfg.Params, c *btc.Configuration) *ZcoinParser {
|
func NewFiroParser(params *chaincfg.Params, c *btc.Configuration) *FiroParser {
|
||||||
return &ZcoinParser{
|
return &FiroParser{
|
||||||
BitcoinParser: btc.NewBitcoinParser(params, c),
|
BitcoinParser: btc.NewBitcoinParser(params, c),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// GetChainParams contains network parameters for the main Zcoin network,
|
// GetChainParams contains network parameters for the main Firo network,
|
||||||
// the regression test Zcoin network, the test Zcoin network and
|
// the regression test Firo network, the test Firo network and
|
||||||
// the simulation test Zcoin network, in this order
|
// the simulation test Firo network, in this order
|
||||||
func GetChainParams(chain string) *chaincfg.Params {
|
func GetChainParams(chain string) *chaincfg.Params {
|
||||||
if !chaincfg.IsRegistered(&MainNetParams) {
|
if !chaincfg.IsRegistered(&MainNetParams) {
|
||||||
err := chaincfg.Register(&MainNetParams)
|
err := chaincfg.Register(&MainNetParams)
|
||||||
|
@ -97,7 +102,7 @@ func GetChainParams(chain string) *chaincfg.Params {
|
||||||
}
|
}
|
||||||
|
|
||||||
// GetAddressesFromAddrDesc returns addresses for given address descriptor with flag if the addresses are searchable
|
// GetAddressesFromAddrDesc returns addresses for given address descriptor with flag if the addresses are searchable
|
||||||
func (p *ZcoinParser) GetAddressesFromAddrDesc(addrDesc bchain.AddressDescriptor) ([]string, bool, error) {
|
func (p *FiroParser) GetAddressesFromAddrDesc(addrDesc bchain.AddressDescriptor) ([]string, bool, error) {
|
||||||
|
|
||||||
if len(addrDesc) > 0 {
|
if len(addrDesc) > 0 {
|
||||||
switch addrDesc[0] {
|
switch addrDesc[0] {
|
||||||
|
@ -109,6 +114,12 @@ func (p *ZcoinParser) GetAddressesFromAddrDesc(addrDesc bchain.AddressDescriptor
|
||||||
return []string{"Sigmamint"}, false, nil
|
return []string{"Sigmamint"}, false, nil
|
||||||
case OpSigmaSpend:
|
case OpSigmaSpend:
|
||||||
return []string{"Sigmaspend"}, false, nil
|
return []string{"Sigmaspend"}, false, nil
|
||||||
|
case OpLelantusMint:
|
||||||
|
return []string{"LelantusMint"}, false, nil
|
||||||
|
case OpLelantusJMint:
|
||||||
|
return []string{"LelantusJMint"}, false, nil
|
||||||
|
case OpLelantusJoinSplit:
|
||||||
|
return []string{"LelantusJoinSplit"}, false, nil
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -116,17 +127,27 @@ func (p *ZcoinParser) GetAddressesFromAddrDesc(addrDesc bchain.AddressDescriptor
|
||||||
}
|
}
|
||||||
|
|
||||||
// PackTx packs transaction to byte array using protobuf
|
// PackTx packs transaction to byte array using protobuf
|
||||||
func (p *ZcoinParser) PackTx(tx *bchain.Tx, height uint32, blockTime int64) ([]byte, error) {
|
func (p *FiroParser) PackTx(tx *bchain.Tx, height uint32, blockTime int64) ([]byte, error) {
|
||||||
return p.BaseParser.PackTx(tx, height, blockTime)
|
return p.BaseParser.PackTx(tx, height, blockTime)
|
||||||
}
|
}
|
||||||
|
|
||||||
// UnpackTx unpacks transaction from protobuf byte array
|
// UnpackTx unpacks transaction from protobuf byte array
|
||||||
func (p *ZcoinParser) UnpackTx(buf []byte) (*bchain.Tx, uint32, error) {
|
func (p *FiroParser) UnpackTx(buf []byte) (*bchain.Tx, uint32, error) {
|
||||||
return p.BaseParser.UnpackTx(buf)
|
return p.BaseParser.UnpackTx(buf)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// TxFromFiroMsgTx converts bitcoin wire Tx to bchain.Tx
|
||||||
|
func (p *FiroParser) TxFromFiroMsgTx(t *FiroMsgTx, parseAddresses bool) bchain.Tx {
|
||||||
|
btx := p.TxFromMsgTx(&t.MsgTx, parseAddresses)
|
||||||
|
|
||||||
|
// NOTE: wire.MsgTx.TxHash() doesn't include extra
|
||||||
|
btx.Txid = t.TxHash().String()
|
||||||
|
|
||||||
|
return btx
|
||||||
|
}
|
||||||
|
|
||||||
// ParseBlock parses raw block to our Block struct
|
// ParseBlock parses raw block to our Block struct
|
||||||
func (p *ZcoinParser) ParseBlock(b []byte) (*bchain.Block, error) {
|
func (p *FiroParser) ParseBlock(b []byte) (*bchain.Block, error) {
|
||||||
reader := bytes.NewReader(b)
|
reader := bytes.NewReader(b)
|
||||||
|
|
||||||
// parse standard block header first
|
// parse standard block header first
|
||||||
|
@ -181,16 +202,37 @@ func (p *ZcoinParser) ParseBlock(b []byte) (*bchain.Block, error) {
|
||||||
txs := make([]bchain.Tx, ntx)
|
txs := make([]bchain.Tx, ntx)
|
||||||
|
|
||||||
for i := uint64(0); i < ntx; i++ {
|
for i := uint64(0); i < ntx; i++ {
|
||||||
tx := wire.MsgTx{}
|
tx := FiroMsgTx{}
|
||||||
|
|
||||||
err := tx.BtcDecode(reader, 0, wire.WitnessEncoding)
|
// read version and seek back
|
||||||
if err != nil {
|
var version uint32 = 0
|
||||||
|
if err = binary.Read(reader, binary.LittleEndian, &version); err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
btx := p.TxFromMsgTx(&tx, false)
|
if _, err = reader.Seek(-4, io.SeekCurrent); err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
p.parseZcoinTx(&btx)
|
txVersion := version & 0xffff
|
||||||
|
txType := (version >> 16) & 0xffff
|
||||||
|
|
||||||
|
enc := wire.WitnessEncoding
|
||||||
|
|
||||||
|
// transaction quorum commitment could not be parsed with witness flag
|
||||||
|
if txVersion == 3 && txType == TransactionQuorumCommitmentType {
|
||||||
|
enc = wire.BaseEncoding
|
||||||
|
}
|
||||||
|
|
||||||
|
if err = tx.FiroDecode(reader, 0, enc); err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
btx := p.TxFromFiroMsgTx(&tx, false)
|
||||||
|
|
||||||
|
if err = p.parseFiroTx(&btx); err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
txs[i] = btx
|
txs[i] = btx
|
||||||
}
|
}
|
||||||
|
@ -205,7 +247,7 @@ func (p *ZcoinParser) ParseBlock(b []byte) (*bchain.Block, error) {
|
||||||
}
|
}
|
||||||
|
|
||||||
// ParseTxFromJson parses JSON message containing transaction and returns Tx struct
|
// ParseTxFromJson parses JSON message containing transaction and returns Tx struct
|
||||||
func (p *ZcoinParser) ParseTxFromJson(msg json.RawMessage) (*bchain.Tx, error) {
|
func (p *FiroParser) ParseTxFromJson(msg json.RawMessage) (*bchain.Tx, error) {
|
||||||
var tx bchain.Tx
|
var tx bchain.Tx
|
||||||
err := json.Unmarshal(msg, &tx)
|
err := json.Unmarshal(msg, &tx)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
@ -222,12 +264,12 @@ func (p *ZcoinParser) ParseTxFromJson(msg json.RawMessage) (*bchain.Tx, error) {
|
||||||
vout.JsonValue = ""
|
vout.JsonValue = ""
|
||||||
}
|
}
|
||||||
|
|
||||||
p.parseZcoinTx(&tx)
|
p.parseFiroTx(&tx)
|
||||||
|
|
||||||
return &tx, nil
|
return &tx, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (p *ZcoinParser) parseZcoinTx(tx *bchain.Tx) error {
|
func (p *FiroParser) parseFiroTx(tx *bchain.Tx) error {
|
||||||
for i := range tx.Vin {
|
for i := range tx.Vin {
|
||||||
vin := &tx.Vin[i]
|
vin := &tx.Vin[i]
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
// +build unittest
|
// +build unittest
|
||||||
|
|
||||||
package xzc
|
package firo
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"bytes"
|
"bytes"
|
||||||
|
@ -13,16 +13,18 @@ import (
|
||||||
"strings"
|
"strings"
|
||||||
"testing"
|
"testing"
|
||||||
|
|
||||||
|
"github.com/martinboehm/btcd/wire"
|
||||||
"github.com/martinboehm/btcutil/chaincfg"
|
"github.com/martinboehm/btcutil/chaincfg"
|
||||||
"github.com/trezor/blockbook/bchain"
|
"spacecruft.org/spacecruft/blockbook/bchain"
|
||||||
"github.com/trezor/blockbook/bchain/coins/btc"
|
"spacecruft.org/spacecruft/blockbook/bchain/coins/btc"
|
||||||
)
|
)
|
||||||
|
|
||||||
var (
|
var (
|
||||||
testTx1, testTx2, testTx3, testTx4 bchain.Tx
|
testTx1, testTx2, testTx3, testTx4, testTx5, testTx6 bchain.Tx
|
||||||
testTxPacked1, testTxPacked2, testTxPacked3, testTxPacked4 string
|
rawTestTx1, rawTestTx2, rawTestTx3, rawTestTx4, rawTestTx5, rawTestTx6 string
|
||||||
rawBlock1, rawBlock2 string
|
testTxPacked1, testTxPacked2, testTxPacked3, testTxPacked4, testTxPacked5, testTxPacked6 string
|
||||||
jsonTx json.RawMessage
|
rawBlock1, rawBlock2, rawBlock3 string
|
||||||
|
jsonTx json.RawMessage
|
||||||
)
|
)
|
||||||
|
|
||||||
func readHexs(path string) []string {
|
func readHexs(path string) []string {
|
||||||
|
@ -39,12 +41,15 @@ func init() {
|
||||||
rawBlocks := readHexs("./testdata/rawblock.hex")
|
rawBlocks := readHexs("./testdata/rawblock.hex")
|
||||||
rawBlock1 = rawBlocks[0]
|
rawBlock1 = rawBlocks[0]
|
||||||
rawBlock2 = rawBlocks[1]
|
rawBlock2 = rawBlocks[1]
|
||||||
|
rawBlock3 = rawBlocks[2]
|
||||||
|
|
||||||
hextxs := readHexs("./testdata/txs.hex")
|
hextxs := readHexs("./testdata/txs.hex")
|
||||||
rawTestTx1 := hextxs[0]
|
rawTestTx1 = hextxs[0]
|
||||||
rawTestTx2 := hextxs[1]
|
rawTestTx2 = hextxs[1]
|
||||||
rawTestTx3 := hextxs[2]
|
rawTestTx3 = hextxs[2]
|
||||||
rawTestTx4 := hextxs[3]
|
rawTestTx4 = hextxs[3]
|
||||||
|
rawTestTx5 = hextxs[4]
|
||||||
|
rawTestTx6 = hextxs[5]
|
||||||
|
|
||||||
rawSpendHex := readHexs("./testdata/rawspend.hex")[0]
|
rawSpendHex := readHexs("./testdata/rawspend.hex")[0]
|
||||||
|
|
||||||
|
@ -59,13 +64,15 @@ func init() {
|
||||||
testTxPacked2 = testTxPackeds[1]
|
testTxPacked2 = testTxPackeds[1]
|
||||||
testTxPacked3 = testTxPackeds[2]
|
testTxPacked3 = testTxPackeds[2]
|
||||||
testTxPacked4 = testTxPackeds[3]
|
testTxPacked4 = testTxPackeds[3]
|
||||||
|
testTxPacked5 = testTxPackeds[4]
|
||||||
|
testTxPacked6 = testTxPackeds[5]
|
||||||
|
|
||||||
testTx1 = bchain.Tx{
|
testTx1 = bchain.Tx{
|
||||||
Hex: rawTestTx1,
|
Hex: rawTestTx1,
|
||||||
Blocktime: 1533980594,
|
Blocktime: 1533980594,
|
||||||
Time: 1533980594,
|
Time: 1533980594,
|
||||||
Txid: "9d9e759dd970d86df9e105a7d4f671543bc16a03b6c5d2b48895f2a00aa7dd23",
|
Txid: "9d9e759dd970d86df9e105a7d4f671543bc16a03b6c5d2b48895f2a00aa7dd23",
|
||||||
LockTime: 0,
|
LockTime: 99688,
|
||||||
Vin: []bchain.Vin{
|
Vin: []bchain.Vin{
|
||||||
{
|
{
|
||||||
ScriptSig: bchain.ScriptSig{
|
ScriptSig: bchain.ScriptSig{
|
||||||
|
@ -78,14 +85,14 @@ func init() {
|
||||||
},
|
},
|
||||||
Vout: []bchain.Vout{
|
Vout: []bchain.Vout{
|
||||||
{
|
{
|
||||||
ValueSat: *big.NewInt(18188266638),
|
ValueSat: *big.NewInt(100000000),
|
||||||
N: 0,
|
N: 0,
|
||||||
ScriptPubKey: bchain.ScriptPubKey{
|
ScriptPubKey: bchain.ScriptPubKey{
|
||||||
Hex: "c10280004c80f767f3ee79953c67a7ed386dcccf1243619eb4bbbe414a3982dd94a83c1b69ac52d6ab3b653a3e05c4e4516c8dfe1e58ada40461bc5835a4a0d0387a51c29ac11b72ae25bbcdef745f50ad08f08b3e9bc2c31a35444398a490e65ac090e9f341f1abdebe47e57e8237ac25d098e951b4164a35caea29f30acb50b12e4425df28",
|
Hex: "c10280004c80f767f3ee79953c67a7ed386dcccf1243619eb4bbbe414a3982dd94a83c1b69ac52d6ab3b653a3e05c4e4516c8dfe1e58ada40461bc5835a4a0d0387a51c29ac11b72ae25bbcdef745f50ad08f08b3e9bc2c31a35444398a490e65ac090e9f341f1abdebe47e57e8237ac25d098e951b4164a35caea29f30acb50b12e4425df28",
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
ValueSat: *big.NewInt(18188266638),
|
ValueSat: *big.NewInt(871824000),
|
||||||
N: 1,
|
N: 1,
|
||||||
ScriptPubKey: bchain.ScriptPubKey{
|
ScriptPubKey: bchain.ScriptPubKey{
|
||||||
Hex: "76a914c963f917c7f23cb4243e079db33107571b87690588ac",
|
Hex: "76a914c963f917c7f23cb4243e079db33107571b87690588ac",
|
||||||
|
@ -105,9 +112,7 @@ func init() {
|
||||||
LockTime: 0,
|
LockTime: 0,
|
||||||
Vin: []bchain.Vin{
|
Vin: []bchain.Vin{
|
||||||
{
|
{
|
||||||
ScriptSig: bchain.ScriptSig{
|
Coinbase: rawSpendHex,
|
||||||
Hex: rawSpendHex,
|
|
||||||
},
|
|
||||||
Txid: "0000000000000000000000000000000000000000000000000000000000000000",
|
Txid: "0000000000000000000000000000000000000000000000000000000000000000",
|
||||||
Vout: 4294967295,
|
Vout: 4294967295,
|
||||||
Sequence: 2,
|
Sequence: 2,
|
||||||
|
@ -226,7 +231,7 @@ func init() {
|
||||||
ScriptPubKey: bchain.ScriptPubKey{
|
ScriptPubKey: bchain.ScriptPubKey{
|
||||||
Hex: "76a914ff71b0c9c2a90c6164a50a2fb523eb54a8a6b55088ac",
|
Hex: "76a914ff71b0c9c2a90c6164a50a2fb523eb54a8a6b55088ac",
|
||||||
Addresses: []string{
|
Addresses: []string{
|
||||||
"a1HwTdCmQV3NspP2QqCGpehoFpi8NY4Zg3",
|
"aQ18FBVFtnueucZKeVg4srhmzbpAeb1KoN",
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
@ -250,6 +255,103 @@ func init() {
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
// TODO: test segwit
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
testTx5 = bchain.Tx{
|
||||||
|
Hex: rawTestTx5,
|
||||||
|
Blocktime: 1591752749,
|
||||||
|
Time: 1591752749,
|
||||||
|
Txid: "8d1f32f35c32d2c127a7400dc1ec52049fbf0b8bcdf284cfaa3da59b6169a22d",
|
||||||
|
LockTime: 0,
|
||||||
|
Vin: []bchain.Vin{},
|
||||||
|
Vout: []bchain.Vout{},
|
||||||
|
}
|
||||||
|
|
||||||
|
testTx6 = bchain.Tx{
|
||||||
|
Hex: rawTestTx6,
|
||||||
|
Blocktime: 1591762049,
|
||||||
|
Time: 1591762049,
|
||||||
|
Txid: "e5767d3606230a65f150837a6f28b4f0e4c2702a683045df3883d57702739c61",
|
||||||
|
LockTime: 0,
|
||||||
|
Vin: []bchain.Vin{
|
||||||
|
{
|
||||||
|
Coinbase: "02b4140101",
|
||||||
|
Sequence: 4294967295,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
Vout: []bchain.Vout{
|
||||||
|
{
|
||||||
|
ValueSat: *big.NewInt(1400000000),
|
||||||
|
N: 0,
|
||||||
|
ScriptPubKey: bchain.ScriptPubKey{
|
||||||
|
Hex: "2103fb09a216761d5e7f248294970c2370f7f84ce1ad564b8e7096b1e19116af1d52ac",
|
||||||
|
Addresses: []string{
|
||||||
|
"TAn9Ghkp31myXRgejCj11wWVHT14Lsj349",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
ValueSat: *big.NewInt(50000000),
|
||||||
|
N: 1,
|
||||||
|
ScriptPubKey: bchain.ScriptPubKey{
|
||||||
|
Hex: "76a914296134d2415bf1f2b518b3f673816d7e603b160088ac",
|
||||||
|
Addresses: []string{
|
||||||
|
"TDk19wPKYq91i18qmY6U9FeTdTxwPeSveo",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
ValueSat: *big.NewInt(50000000),
|
||||||
|
N: 2,
|
||||||
|
ScriptPubKey: bchain.ScriptPubKey{
|
||||||
|
Hex: "76a914e1e1dc06a889c1b6d3eb00eef7a96f6a7cfb884888ac",
|
||||||
|
Addresses: []string{
|
||||||
|
"TWZZcDGkNixTAMtRBqzZkkMHbq1G6vUTk5",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
ValueSat: *big.NewInt(50000000),
|
||||||
|
N: 3,
|
||||||
|
ScriptPubKey: bchain.ScriptPubKey{
|
||||||
|
Hex: "76a914ab03ecfddee6330497be894d16c29ae341c123aa88ac",
|
||||||
|
Addresses: []string{
|
||||||
|
"TRZTFdNCKCKbLMQV8cZDkQN9Vwuuq4gDzT",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
ValueSat: *big.NewInt(150000000),
|
||||||
|
N: 4,
|
||||||
|
ScriptPubKey: bchain.ScriptPubKey{
|
||||||
|
Hex: "76a9144281a58a1d5b2d3285e00cb45a8492debbdad4c588ac",
|
||||||
|
Addresses: []string{
|
||||||
|
"TG2ruj59E5b1u9G3F7HQVs6pCcVDBxrQve",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
ValueSat: *big.NewInt(50000000),
|
||||||
|
N: 5,
|
||||||
|
ScriptPubKey: bchain.ScriptPubKey{
|
||||||
|
Hex: "76a9141fd264c0bb53bd9fef18e2248ddf1383d6e811ae88ac",
|
||||||
|
Addresses: []string{
|
||||||
|
"TCsTzQZKVn4fao8jDmB9zQBk9YQNEZ3XfS",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
ValueSat: *big.NewInt(750000000),
|
||||||
|
N: 6,
|
||||||
|
ScriptPubKey: bchain.ScriptPubKey{
|
||||||
|
Hex: "76a91471a3892d164ffa3829078bf9ad5f114a3908ce5588ac",
|
||||||
|
Addresses: []string{
|
||||||
|
"TLL5GQULX4uBfz7yXL6VcZyvzdKVv1RGxm",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -263,32 +365,32 @@ func TestMain(m *testing.M) {
|
||||||
func TestGetAddrDesc(t *testing.T) {
|
func TestGetAddrDesc(t *testing.T) {
|
||||||
type args struct {
|
type args struct {
|
||||||
tx bchain.Tx
|
tx bchain.Tx
|
||||||
parser *ZcoinParser
|
parser *FiroParser
|
||||||
}
|
}
|
||||||
tests := []struct {
|
tests := []struct {
|
||||||
name string
|
name string
|
||||||
args args
|
args args
|
||||||
}{
|
}{
|
||||||
{
|
{
|
||||||
name: "xzc-1",
|
name: "firo-1",
|
||||||
args: args{
|
args: args{
|
||||||
tx: testTx1,
|
tx: testTx1,
|
||||||
parser: NewZcoinParser(GetChainParams("main"), &btc.Configuration{}),
|
parser: NewFiroParser(GetChainParams("main"), &btc.Configuration{}),
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
// FIXME: work around handle zerocoin spend as coinbase
|
// FIXME: work around handle zerocoin spend as coinbase
|
||||||
// {
|
// {
|
||||||
// name: "xzc-2",
|
// name: "firo-2",
|
||||||
// args: args{
|
// args: args{
|
||||||
// tx: testTx2,
|
// tx: testTx2,
|
||||||
// parser: NewZcoinParser(GetChainParams("main"), &btc.Configuration{}),
|
// parser: NewFiroParser(GetChainParams("main"), &btc.Configuration{}),
|
||||||
// },
|
// },
|
||||||
// },
|
// },
|
||||||
{
|
{
|
||||||
name: "xzc-3",
|
name: "firo-3",
|
||||||
args: args{
|
args: args{
|
||||||
tx: testTx3,
|
tx: testTx3,
|
||||||
parser: NewZcoinParser(GetChainParams("main"), &btc.Configuration{}),
|
parser: NewFiroParser(GetChainParams("main"), &btc.Configuration{}),
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
@ -346,7 +448,7 @@ func TestGetAddrDescFromVoutForMint(t *testing.T) {
|
||||||
wantErr: false,
|
wantErr: false,
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
parser := NewZcoinParser(GetChainParams("main"), &btc.Configuration{})
|
parser := NewFiroParser(GetChainParams("main"), &btc.Configuration{})
|
||||||
|
|
||||||
for _, tt := range tests {
|
for _, tt := range tests {
|
||||||
t.Run(tt.name, func(t *testing.T) {
|
t.Run(tt.name, func(t *testing.T) {
|
||||||
|
@ -396,7 +498,7 @@ func TestGetAddressesFromAddrDescForMint(t *testing.T) {
|
||||||
wantErr: false,
|
wantErr: false,
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
parser := NewZcoinParser(GetChainParams("main"), &btc.Configuration{})
|
parser := NewFiroParser(GetChainParams("main"), &btc.Configuration{})
|
||||||
|
|
||||||
for _, tt := range tests {
|
for _, tt := range tests {
|
||||||
t.Run(tt.name, func(t *testing.T) {
|
t.Run(tt.name, func(t *testing.T) {
|
||||||
|
@ -421,7 +523,7 @@ func TestPackTx(t *testing.T) {
|
||||||
tx bchain.Tx
|
tx bchain.Tx
|
||||||
height uint32
|
height uint32
|
||||||
blockTime int64
|
blockTime int64
|
||||||
parser *ZcoinParser
|
parser *FiroParser
|
||||||
}
|
}
|
||||||
tests := []struct {
|
tests := []struct {
|
||||||
name string
|
name string
|
||||||
|
@ -430,50 +532,72 @@ func TestPackTx(t *testing.T) {
|
||||||
wantErr bool
|
wantErr bool
|
||||||
}{
|
}{
|
||||||
{
|
{
|
||||||
name: "xzc-1",
|
name: "firo-1",
|
||||||
args: args{
|
args: args{
|
||||||
tx: testTx1,
|
tx: testTx1,
|
||||||
height: 100002,
|
height: 100002,
|
||||||
blockTime: 1533980594,
|
blockTime: 1533980594,
|
||||||
parser: NewZcoinParser(GetChainParams("main"), &btc.Configuration{}),
|
parser: NewFiroParser(GetChainParams("main"), &btc.Configuration{}),
|
||||||
},
|
},
|
||||||
want: testTxPacked1,
|
want: testTxPacked1,
|
||||||
wantErr: false,
|
wantErr: false,
|
||||||
},
|
},
|
||||||
// FIXME: work around handle zerocoin spend as coinbase
|
// FIXME: work around handle zerocoin spend as coinbase
|
||||||
// {
|
// {
|
||||||
// name: "xzc-2",
|
// name: "firo-2",
|
||||||
// args: args{
|
// args: args{
|
||||||
// tx: testTx2,
|
// tx: testTx2,
|
||||||
// height: 11002,
|
// height: 11002,
|
||||||
// blockTime: 1481277009,
|
// blockTime: 1481277009,
|
||||||
// parser: NewZcoinParser(GetChainParams("main"), &btc.Configuration{}),
|
// parser: NewFiroParser(GetChainParams("main"), &btc.Configuration{}),
|
||||||
// },
|
// },
|
||||||
// want: testTxPacked2,
|
// want: testTxPacked2,
|
||||||
// wantErr: true,
|
// wantErr: true,
|
||||||
// },
|
// },
|
||||||
{
|
{
|
||||||
name: "xzc-3",
|
name: "firo-3",
|
||||||
args: args{
|
args: args{
|
||||||
tx: testTx3,
|
tx: testTx3,
|
||||||
height: 126202,
|
height: 126202,
|
||||||
blockTime: 1547091829,
|
blockTime: 1547091829,
|
||||||
parser: NewZcoinParser(GetChainParams("main"), &btc.Configuration{}),
|
parser: NewFiroParser(GetChainParams("main"), &btc.Configuration{}),
|
||||||
},
|
},
|
||||||
want: testTxPacked3,
|
want: testTxPacked3,
|
||||||
wantErr: false,
|
wantErr: false,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
name: "xzc-coinbase",
|
name: "firo-coinbase",
|
||||||
args: args{
|
args: args{
|
||||||
tx: testTx4,
|
tx: testTx4,
|
||||||
height: 100001,
|
height: 100001,
|
||||||
blockTime: 1533977563,
|
blockTime: 1533977563,
|
||||||
parser: NewZcoinParser(GetChainParams("main"), &btc.Configuration{}),
|
parser: NewFiroParser(GetChainParams("main"), &btc.Configuration{}),
|
||||||
},
|
},
|
||||||
want: testTxPacked4,
|
want: testTxPacked4,
|
||||||
wantErr: false,
|
wantErr: false,
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
name: "firo-quorum-commitment-tx",
|
||||||
|
args: args{
|
||||||
|
tx: testTx5,
|
||||||
|
height: 5268,
|
||||||
|
blockTime: 1591752749,
|
||||||
|
parser: NewFiroParser(GetChainParams("test"), &btc.Configuration{}),
|
||||||
|
},
|
||||||
|
want: testTxPacked5,
|
||||||
|
wantErr: false,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "firo-special-coinbase-tx",
|
||||||
|
args: args{
|
||||||
|
tx: testTx6,
|
||||||
|
height: 5300,
|
||||||
|
blockTime: 1591762049,
|
||||||
|
parser: NewFiroParser(GetChainParams("test"), &btc.Configuration{}),
|
||||||
|
},
|
||||||
|
want: testTxPacked6,
|
||||||
|
wantErr: false,
|
||||||
|
},
|
||||||
}
|
}
|
||||||
for _, tt := range tests {
|
for _, tt := range tests {
|
||||||
t.Run(tt.name, func(t *testing.T) {
|
t.Run(tt.name, func(t *testing.T) {
|
||||||
|
@ -495,7 +619,7 @@ func TestPackTx(t *testing.T) {
|
||||||
func TestUnpackTx(t *testing.T) {
|
func TestUnpackTx(t *testing.T) {
|
||||||
type args struct {
|
type args struct {
|
||||||
packedTx string
|
packedTx string
|
||||||
parser *ZcoinParser
|
parser *FiroParser
|
||||||
}
|
}
|
||||||
tests := []struct {
|
tests := []struct {
|
||||||
name string
|
name string
|
||||||
|
@ -505,10 +629,10 @@ func TestUnpackTx(t *testing.T) {
|
||||||
wantErr bool
|
wantErr bool
|
||||||
}{
|
}{
|
||||||
{
|
{
|
||||||
name: "xzc-1",
|
name: "firo-1",
|
||||||
args: args{
|
args: args{
|
||||||
packedTx: testTxPacked1,
|
packedTx: testTxPacked1,
|
||||||
parser: NewZcoinParser(GetChainParams("main"), &btc.Configuration{}),
|
parser: NewFiroParser(GetChainParams("main"), &btc.Configuration{}),
|
||||||
},
|
},
|
||||||
want: &testTx1,
|
want: &testTx1,
|
||||||
want1: 100002,
|
want1: 100002,
|
||||||
|
@ -516,35 +640,55 @@ func TestUnpackTx(t *testing.T) {
|
||||||
},
|
},
|
||||||
// FIXME: work around handle zerocoin spend as coinbase
|
// FIXME: work around handle zerocoin spend as coinbase
|
||||||
// {
|
// {
|
||||||
// name: "xzc-2",
|
// name: "firo-2",
|
||||||
// args: args{
|
// args: args{
|
||||||
// packedTx: testTxPacked2,
|
// packedTx: testTxPacked2,
|
||||||
// parser: NewZcoinParser(GetChainParams("main"), &btc.Configuration{}),
|
// parser: NewFiroParser(GetChainParams("main"), &btc.Configuration{}),
|
||||||
// },
|
// },
|
||||||
// want: &testTx2,
|
// want: &testTx2,
|
||||||
// want1: 11002,
|
// want1: 11002,
|
||||||
// wantErr: true,
|
// wantErr: true,
|
||||||
// },
|
// },
|
||||||
{
|
{
|
||||||
name: "xzc-3",
|
name: "firo-3",
|
||||||
args: args{
|
args: args{
|
||||||
packedTx: testTxPacked3,
|
packedTx: testTxPacked3,
|
||||||
parser: NewZcoinParser(GetChainParams("main"), &btc.Configuration{}),
|
parser: NewFiroParser(GetChainParams("main"), &btc.Configuration{}),
|
||||||
},
|
},
|
||||||
want: &testTx3,
|
want: &testTx3,
|
||||||
want1: 126202,
|
want1: 126202,
|
||||||
wantErr: false,
|
wantErr: false,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
name: "xzc-coinbase",
|
name: "firo-coinbase",
|
||||||
args: args{
|
args: args{
|
||||||
packedTx: testTxPacked4,
|
packedTx: testTxPacked4,
|
||||||
parser: NewZcoinParser(GetChainParams("main"), &btc.Configuration{}),
|
parser: NewFiroParser(GetChainParams("main"), &btc.Configuration{}),
|
||||||
},
|
},
|
||||||
want: &testTx4,
|
want: &testTx4,
|
||||||
want1: 100001,
|
want1: 100001,
|
||||||
wantErr: false,
|
wantErr: false,
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
name: "firo-special-tx",
|
||||||
|
args: args{
|
||||||
|
packedTx: testTxPacked5,
|
||||||
|
parser: NewFiroParser(GetChainParams("test"), &btc.Configuration{}),
|
||||||
|
},
|
||||||
|
want: &testTx5,
|
||||||
|
want1: 5268,
|
||||||
|
wantErr: false,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "firo-special-coinbase-tx",
|
||||||
|
args: args{
|
||||||
|
packedTx: testTxPacked6,
|
||||||
|
parser: NewFiroParser(GetChainParams("test"), &btc.Configuration{}),
|
||||||
|
},
|
||||||
|
want: &testTx6,
|
||||||
|
want1: 5300,
|
||||||
|
wantErr: false,
|
||||||
|
},
|
||||||
}
|
}
|
||||||
for _, tt := range tests {
|
for _, tt := range tests {
|
||||||
t.Run(tt.name, func(t *testing.T) {
|
t.Run(tt.name, func(t *testing.T) {
|
||||||
|
@ -570,7 +714,7 @@ func TestUnpackTx(t *testing.T) {
|
||||||
func TestParseBlock(t *testing.T) {
|
func TestParseBlock(t *testing.T) {
|
||||||
type args struct {
|
type args struct {
|
||||||
rawBlock string
|
rawBlock string
|
||||||
parser *ZcoinParser
|
parser *FiroParser
|
||||||
}
|
}
|
||||||
tests := []struct {
|
tests := []struct {
|
||||||
name string
|
name string
|
||||||
|
@ -583,7 +727,7 @@ func TestParseBlock(t *testing.T) {
|
||||||
name: "normal-block",
|
name: "normal-block",
|
||||||
args: args{
|
args: args{
|
||||||
rawBlock: rawBlock1,
|
rawBlock: rawBlock1,
|
||||||
parser: NewZcoinParser(GetChainParams("main"), &btc.Configuration{}),
|
parser: NewFiroParser(GetChainParams("main"), &btc.Configuration{}),
|
||||||
},
|
},
|
||||||
want: &bchain.Block{
|
want: &bchain.Block{
|
||||||
BlockHeader: bchain.BlockHeader{
|
BlockHeader: bchain.BlockHeader{
|
||||||
|
@ -598,7 +742,7 @@ func TestParseBlock(t *testing.T) {
|
||||||
name: "spend-block",
|
name: "spend-block",
|
||||||
args: args{
|
args: args{
|
||||||
rawBlock: rawBlock2,
|
rawBlock: rawBlock2,
|
||||||
parser: NewZcoinParser(GetChainParams("main"), &btc.Configuration{}),
|
parser: NewFiroParser(GetChainParams("main"), &btc.Configuration{}),
|
||||||
},
|
},
|
||||||
want: &bchain.Block{
|
want: &bchain.Block{
|
||||||
BlockHeader: bchain.BlockHeader{
|
BlockHeader: bchain.BlockHeader{
|
||||||
|
@ -609,6 +753,21 @@ func TestParseBlock(t *testing.T) {
|
||||||
wantTxs: 4,
|
wantTxs: 4,
|
||||||
wantErr: false,
|
wantErr: false,
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
name: "special-tx-block",
|
||||||
|
args: args{
|
||||||
|
rawBlock: rawBlock3,
|
||||||
|
parser: NewFiroParser(GetChainParams("test"), &btc.Configuration{}),
|
||||||
|
},
|
||||||
|
want: &bchain.Block{
|
||||||
|
BlockHeader: bchain.BlockHeader{
|
||||||
|
Size: 200062,
|
||||||
|
Time: 1591752749,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
wantTxs: 3,
|
||||||
|
wantErr: false,
|
||||||
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
for _, tt := range tests {
|
for _, tt := range tests {
|
||||||
|
@ -632,3 +791,191 @@ func TestParseBlock(t *testing.T) {
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func TestDecodeTransaction(t *testing.T) {
|
||||||
|
type args struct {
|
||||||
|
enc wire.MessageEncoding
|
||||||
|
rawTransaction string
|
||||||
|
parser *FiroParser
|
||||||
|
privacyType byte // 0 as non privacy
|
||||||
|
}
|
||||||
|
tests := []struct {
|
||||||
|
name string
|
||||||
|
args args
|
||||||
|
want bchain.Tx
|
||||||
|
wantErr bool
|
||||||
|
}{
|
||||||
|
{
|
||||||
|
name: "normal-transaction",
|
||||||
|
args: args{
|
||||||
|
enc: wire.WitnessEncoding,
|
||||||
|
rawTransaction: rawTestTx1,
|
||||||
|
parser: NewFiroParser(GetChainParams("main"), &btc.Configuration{}),
|
||||||
|
},
|
||||||
|
want: testTx1,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "coinbase-firospend",
|
||||||
|
args: args{
|
||||||
|
enc: wire.WitnessEncoding,
|
||||||
|
rawTransaction: rawTestTx2,
|
||||||
|
parser: NewFiroParser(GetChainParams("main"), &btc.Configuration{}),
|
||||||
|
privacyType: OpSigmaSpend,
|
||||||
|
},
|
||||||
|
want: testTx2,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "normal-transaction-2",
|
||||||
|
args: args{
|
||||||
|
enc: wire.WitnessEncoding,
|
||||||
|
rawTransaction: rawTestTx3,
|
||||||
|
parser: NewFiroParser(GetChainParams("main"), &btc.Configuration{}),
|
||||||
|
},
|
||||||
|
want: testTx3,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "coinbase-transaction",
|
||||||
|
args: args{
|
||||||
|
enc: wire.WitnessEncoding,
|
||||||
|
rawTransaction: rawTestTx4,
|
||||||
|
parser: NewFiroParser(GetChainParams("main"), &btc.Configuration{}),
|
||||||
|
},
|
||||||
|
want: testTx4,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "quorum-commitment-transaction",
|
||||||
|
args: args{
|
||||||
|
enc: wire.BaseEncoding,
|
||||||
|
rawTransaction: rawTestTx5,
|
||||||
|
parser: NewFiroParser(GetChainParams("main"), &btc.Configuration{}),
|
||||||
|
},
|
||||||
|
want: testTx5,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "quorum-commitment-transaction-witness",
|
||||||
|
args: args{
|
||||||
|
enc: wire.WitnessEncoding,
|
||||||
|
rawTransaction: rawTestTx5,
|
||||||
|
parser: NewFiroParser(GetChainParams("main"), &btc.Configuration{}),
|
||||||
|
},
|
||||||
|
wantErr: true,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "special-coinbase",
|
||||||
|
args: args{
|
||||||
|
enc: wire.WitnessEncoding,
|
||||||
|
rawTransaction: rawTestTx6,
|
||||||
|
parser: NewFiroParser(GetChainParams("test"), &btc.Configuration{}),
|
||||||
|
},
|
||||||
|
want: testTx6,
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
for _, tt := range tests {
|
||||||
|
t.Run(tt.name, func(t *testing.T) {
|
||||||
|
b, _ := hex.DecodeString(tt.args.rawTransaction)
|
||||||
|
r := bytes.NewReader(b)
|
||||||
|
|
||||||
|
msg := FiroMsgTx{}
|
||||||
|
err := msg.FiroDecode(r, 0, tt.args.enc)
|
||||||
|
|
||||||
|
if tt.wantErr {
|
||||||
|
if err == nil {
|
||||||
|
t.Errorf("Want error")
|
||||||
|
}
|
||||||
|
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
if err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
got := tt.args.parser.TxFromFiroMsgTx(&msg, true)
|
||||||
|
if pErr := tt.args.parser.parseFiroTx(&got); pErr != nil {
|
||||||
|
t.Fatal(pErr)
|
||||||
|
}
|
||||||
|
|
||||||
|
if r.Len() != 0 {
|
||||||
|
t.Errorf("Expected EOF but there are remaining %d bytes to read", r.Len())
|
||||||
|
}
|
||||||
|
|
||||||
|
if len(got.Vin) != len(tt.want.Vin) {
|
||||||
|
t.Errorf("Check vin size, got %v, want %v", len(got.Vin), len(tt.want.Vin))
|
||||||
|
}
|
||||||
|
|
||||||
|
for i := 0; i != len(got.Vin); i++ {
|
||||||
|
if !reflect.DeepEqual(got.Vin[i].Addresses, tt.want.Vin[i].Addresses) {
|
||||||
|
t.Errorf("Check Addresses at input %d, got %v, want %v",
|
||||||
|
i, got.Vin[i].Addresses, tt.want.Vin[i].Addresses)
|
||||||
|
}
|
||||||
|
|
||||||
|
if !reflect.DeepEqual(got.Vin[i].Coinbase, tt.want.Vin[i].Coinbase) {
|
||||||
|
t.Errorf("Check Coinbase at input %d, got %v, want %v",
|
||||||
|
i, got.Vin[i].Coinbase, tt.want.Vin[i].Coinbase)
|
||||||
|
}
|
||||||
|
|
||||||
|
if !reflect.DeepEqual(got.Vin[i].ScriptSig, tt.want.Vin[i].ScriptSig) {
|
||||||
|
t.Errorf("Check ScriptSig at input %d, got %v, want %v",
|
||||||
|
i, got.Vin[i].ScriptSig, tt.want.Vin[i].ScriptSig)
|
||||||
|
}
|
||||||
|
|
||||||
|
if !reflect.DeepEqual(got.Vin[i].Sequence, tt.want.Vin[i].Sequence) {
|
||||||
|
t.Errorf("Check Sequence at input %d, got %v, want %v",
|
||||||
|
i, got.Vin[i].Sequence, tt.want.Vin[i].Sequence)
|
||||||
|
}
|
||||||
|
|
||||||
|
if tt.args.privacyType == 0 && !reflect.DeepEqual(got.Vin[i].Txid, tt.want.Vin[i].Txid) {
|
||||||
|
t.Errorf("Check Txid at input %d, got %v, want %v",
|
||||||
|
i, got.Vin[i].Txid, tt.want.Vin[i].Txid)
|
||||||
|
}
|
||||||
|
|
||||||
|
if tt.args.privacyType == 0 && !reflect.DeepEqual(got.Vin[i].Vout, tt.want.Vin[i].Vout) {
|
||||||
|
t.Errorf("Check Vout at input %d, got %v, want %v",
|
||||||
|
i, got.Vin[i].Vout, tt.want.Vin[i].Vout)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if len(got.Vout) != len(tt.want.Vout) {
|
||||||
|
t.Errorf("Check vout size, got %v, want %v", len(got.Vout), len(tt.want.Vout))
|
||||||
|
}
|
||||||
|
|
||||||
|
for i := 0; i != len(got.Vout); i++ {
|
||||||
|
if !reflect.DeepEqual(got.Vout[i].JsonValue, tt.want.Vout[i].JsonValue) {
|
||||||
|
t.Errorf("Check JsonValue at output %d, got %v, want %v",
|
||||||
|
i, got.Vout[i].JsonValue, tt.want.Vout[i].JsonValue)
|
||||||
|
}
|
||||||
|
|
||||||
|
if !reflect.DeepEqual(got.Vout[i].N, tt.want.Vout[i].N) {
|
||||||
|
t.Errorf("Check N at output %d, got %v, want %v",
|
||||||
|
i, got.Vout[i].N, tt.want.Vout[i].N)
|
||||||
|
}
|
||||||
|
|
||||||
|
// empty addresses and null should be the same
|
||||||
|
if !((len(got.Vout[i].ScriptPubKey.Addresses) == 0 && len(got.Vout[i].ScriptPubKey.Addresses) == len(tt.want.Vout[i].ScriptPubKey.Addresses)) ||
|
||||||
|
reflect.DeepEqual(got.Vout[i].ScriptPubKey.Addresses, tt.want.Vout[i].ScriptPubKey.Addresses)) {
|
||||||
|
t.Errorf("Check ScriptPubKey.Addresses at output %d, got %v, want %v",
|
||||||
|
i, got.Vout[i].ScriptPubKey.Addresses, tt.want.Vout[i].ScriptPubKey.Addresses)
|
||||||
|
}
|
||||||
|
|
||||||
|
if !reflect.DeepEqual(got.Vout[i].ScriptPubKey.Hex, tt.want.Vout[i].ScriptPubKey.Hex) {
|
||||||
|
t.Errorf("Check ScriptPubKey.Hex at output %d, got %v, want %v",
|
||||||
|
i, got.Vout[i].ScriptPubKey.Hex, tt.want.Vout[i].ScriptPubKey.Hex)
|
||||||
|
}
|
||||||
|
|
||||||
|
if !reflect.DeepEqual(got.Vout[i].ValueSat, tt.want.Vout[i].ValueSat) {
|
||||||
|
t.Errorf("Check ValueSat at output %d, got %v, want %v",
|
||||||
|
i, got.Vout[i].ValueSat, tt.want.Vout[i].ValueSat)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if got.LockTime != tt.want.LockTime {
|
||||||
|
t.Errorf("Check LockTime, got %v, want %v", got.LockTime, tt.want.LockTime)
|
||||||
|
}
|
||||||
|
|
||||||
|
if got.Txid != tt.want.Txid {
|
||||||
|
t.Errorf("Check TxId, got %v, want %v", got.Txid, tt.want.Txid)
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
|
@ -1,4 +1,4 @@
|
||||||
package xzc
|
package firo
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"encoding/hex"
|
"encoding/hex"
|
||||||
|
@ -6,23 +6,23 @@ import (
|
||||||
|
|
||||||
"github.com/golang/glog"
|
"github.com/golang/glog"
|
||||||
"github.com/juju/errors"
|
"github.com/juju/errors"
|
||||||
"github.com/trezor/blockbook/bchain"
|
"spacecruft.org/spacecruft/blockbook/bchain"
|
||||||
"github.com/trezor/blockbook/bchain/coins/btc"
|
"spacecruft.org/spacecruft/blockbook/bchain/coins/btc"
|
||||||
)
|
)
|
||||||
|
|
||||||
type ZcoinRPC struct {
|
type FiroRPC struct {
|
||||||
*btc.BitcoinRPC
|
*btc.BitcoinRPC
|
||||||
}
|
}
|
||||||
|
|
||||||
func NewZcoinRPC(config json.RawMessage, pushHandler func(bchain.NotificationType)) (bchain.BlockChain, error) {
|
func NewFiroRPC(config json.RawMessage, pushHandler func(bchain.NotificationType)) (bchain.BlockChain, error) {
|
||||||
// init base implementation
|
// init base implementation
|
||||||
bc, err := btc.NewBitcoinRPC(config, pushHandler)
|
bc, err := btc.NewBitcoinRPC(config, pushHandler)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
// init zcoin implementation
|
// init firo implementation
|
||||||
zc := &ZcoinRPC{
|
zc := &FiroRPC{
|
||||||
BitcoinRPC: bc.(*btc.BitcoinRPC),
|
BitcoinRPC: bc.(*btc.BitcoinRPC),
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -35,7 +35,7 @@ func NewZcoinRPC(config json.RawMessage, pushHandler func(bchain.NotificationTyp
|
||||||
return zc, nil
|
return zc, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (zc *ZcoinRPC) Initialize() error {
|
func (zc *FiroRPC) Initialize() error {
|
||||||
ci, err := zc.GetChainInfo()
|
ci, err := zc.GetChainInfo()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
|
@ -45,7 +45,7 @@ func (zc *ZcoinRPC) Initialize() error {
|
||||||
params := GetChainParams(chainName)
|
params := GetChainParams(chainName)
|
||||||
|
|
||||||
// always create parser
|
// always create parser
|
||||||
zc.Parser = NewZcoinParser(params, zc.ChainConfig)
|
zc.Parser = NewFiroParser(params, zc.ChainConfig)
|
||||||
|
|
||||||
// parameters for getInfo request
|
// parameters for getInfo request
|
||||||
if params.Net == MainnetMagic {
|
if params.Net == MainnetMagic {
|
||||||
|
@ -61,7 +61,7 @@ func (zc *ZcoinRPC) Initialize() error {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (zc *ZcoinRPC) GetBlock(hash string, height uint32) (*bchain.Block, error) {
|
func (zc *FiroRPC) GetBlock(hash string, height uint32) (*bchain.Block, error) {
|
||||||
var err error
|
var err error
|
||||||
|
|
||||||
if hash == "" {
|
if hash == "" {
|
||||||
|
@ -96,7 +96,7 @@ func (zc *ZcoinRPC) GetBlock(hash string, height uint32) (*bchain.Block, error)
|
||||||
return block, nil
|
return block, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (zc *ZcoinRPC) GetBlockInfo(hash string) (*bchain.BlockInfo, error) {
|
func (zc *FiroRPC) GetBlockInfo(hash string) (*bchain.BlockInfo, error) {
|
||||||
glog.V(1).Info("rpc: getblock (verbosity=true) ", hash)
|
glog.V(1).Info("rpc: getblock (verbosity=true) ", hash)
|
||||||
|
|
||||||
res := btc.ResGetBlockInfo{}
|
res := btc.ResGetBlockInfo{}
|
||||||
|
@ -117,7 +117,7 @@ func (zc *ZcoinRPC) GetBlockInfo(hash string) (*bchain.BlockInfo, error) {
|
||||||
return &res.Result, nil
|
return &res.Result, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (zc *ZcoinRPC) GetBlockWithoutHeader(hash string, height uint32) (*bchain.Block, error) {
|
func (zc *FiroRPC) GetBlockWithoutHeader(hash string, height uint32) (*bchain.Block, error) {
|
||||||
data, err := zc.GetBlockRaw(hash)
|
data, err := zc.GetBlockRaw(hash)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
|
@ -134,7 +134,7 @@ func (zc *ZcoinRPC) GetBlockWithoutHeader(hash string, height uint32) (*bchain.B
|
||||||
return block, nil
|
return block, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (zc *ZcoinRPC) GetBlockRaw(hash string) ([]byte, error) {
|
func (zc *FiroRPC) GetBlockRaw(hash string) ([]byte, error) {
|
||||||
glog.V(1).Info("rpc: getblock (verbosity=false) ", hash)
|
glog.V(1).Info("rpc: getblock (verbosity=false) ", hash)
|
||||||
|
|
||||||
res := btc.ResGetBlockRaw{}
|
res := btc.ResGetBlockRaw{}
|
||||||
|
@ -155,7 +155,7 @@ func (zc *ZcoinRPC) GetBlockRaw(hash string) ([]byte, error) {
|
||||||
return hex.DecodeString(res.Result)
|
return hex.DecodeString(res.Result)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (zc *ZcoinRPC) GetTransactionForMempool(txid string) (*bchain.Tx, error) {
|
func (zc *FiroRPC) GetTransactionForMempool(txid string) (*bchain.Tx, error) {
|
||||||
glog.V(1).Info("rpc: getrawtransaction nonverbose ", txid)
|
glog.V(1).Info("rpc: getrawtransaction nonverbose ", txid)
|
||||||
|
|
||||||
res := btc.ResGetRawTransactionNonverbose{}
|
res := btc.ResGetRawTransactionNonverbose{}
|
||||||
|
@ -183,7 +183,7 @@ func (zc *ZcoinRPC) GetTransactionForMempool(txid string) (*bchain.Tx, error) {
|
||||||
return tx, nil
|
return tx, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (zc *ZcoinRPC) GetTransaction(txid string) (*bchain.Tx, error) {
|
func (zc *FiroRPC) GetTransaction(txid string) (*bchain.Tx, error) {
|
||||||
r, err := zc.getRawTransaction(txid)
|
r, err := zc.getRawTransaction(txid)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
|
@ -198,14 +198,14 @@ func (zc *ZcoinRPC) GetTransaction(txid string) (*bchain.Tx, error) {
|
||||||
return tx, nil
|
return tx, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (zc *ZcoinRPC) GetTransactionSpecific(tx *bchain.Tx) (json.RawMessage, error) {
|
func (zc *FiroRPC) GetTransactionSpecific(tx *bchain.Tx) (json.RawMessage, error) {
|
||||||
if csd, ok := tx.CoinSpecificData.(json.RawMessage); ok {
|
if csd, ok := tx.CoinSpecificData.(json.RawMessage); ok {
|
||||||
return csd, nil
|
return csd, nil
|
||||||
}
|
}
|
||||||
return zc.getRawTransaction(tx.Txid)
|
return zc.getRawTransaction(tx.Txid)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (zc *ZcoinRPC) getRawTransaction(txid string) (json.RawMessage, error) {
|
func (zc *FiroRPC) getRawTransaction(txid string) (json.RawMessage, error) {
|
||||||
glog.V(1).Info("rpc: getrawtransaction ", txid)
|
glog.V(1).Info("rpc: getrawtransaction ", txid)
|
||||||
|
|
||||||
res := btc.ResGetRawTransaction{}
|
res := btc.ResGetRawTransaction{}
|
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
|
@ -3,8 +3,8 @@ package flo
|
||||||
import (
|
import (
|
||||||
"github.com/martinboehm/btcd/wire"
|
"github.com/martinboehm/btcd/wire"
|
||||||
"github.com/martinboehm/btcutil/chaincfg"
|
"github.com/martinboehm/btcutil/chaincfg"
|
||||||
"github.com/trezor/blockbook/bchain"
|
"spacecruft.org/spacecruft/blockbook/bchain"
|
||||||
"github.com/trezor/blockbook/bchain/coins/btc"
|
"spacecruft.org/spacecruft/blockbook/bchain/coins/btc"
|
||||||
)
|
)
|
||||||
|
|
||||||
// magic numbers
|
// magic numbers
|
||||||
|
|
|
@ -9,7 +9,7 @@ import (
|
||||||
"testing"
|
"testing"
|
||||||
|
|
||||||
"github.com/martinboehm/btcutil/chaincfg"
|
"github.com/martinboehm/btcutil/chaincfg"
|
||||||
"github.com/trezor/blockbook/bchain/coins/btc"
|
"spacecruft.org/spacecruft/blockbook/bchain/coins/btc"
|
||||||
)
|
)
|
||||||
|
|
||||||
func TestMain(m *testing.M) {
|
func TestMain(m *testing.M) {
|
||||||
|
|
|
@ -5,8 +5,8 @@ import (
|
||||||
|
|
||||||
"github.com/golang/glog"
|
"github.com/golang/glog"
|
||||||
"github.com/juju/errors"
|
"github.com/juju/errors"
|
||||||
"github.com/trezor/blockbook/bchain"
|
"spacecruft.org/spacecruft/blockbook/bchain"
|
||||||
"github.com/trezor/blockbook/bchain/coins/btc"
|
"spacecruft.org/spacecruft/blockbook/bchain/coins/btc"
|
||||||
)
|
)
|
||||||
|
|
||||||
// FloRPC is an interface to JSON-RPC bitcoind service.
|
// FloRPC is an interface to JSON-RPC bitcoind service.
|
||||||
|
|
|
@ -3,7 +3,7 @@ package fujicoin
|
||||||
import (
|
import (
|
||||||
"github.com/martinboehm/btcd/wire"
|
"github.com/martinboehm/btcd/wire"
|
||||||
"github.com/martinboehm/btcutil/chaincfg"
|
"github.com/martinboehm/btcutil/chaincfg"
|
||||||
"github.com/trezor/blockbook/bchain/coins/btc"
|
"spacecruft.org/spacecruft/blockbook/bchain/coins/btc"
|
||||||
)
|
)
|
||||||
|
|
||||||
const (
|
const (
|
||||||
|
|
|
@ -10,8 +10,8 @@ import (
|
||||||
"testing"
|
"testing"
|
||||||
|
|
||||||
"github.com/martinboehm/btcutil/chaincfg"
|
"github.com/martinboehm/btcutil/chaincfg"
|
||||||
"github.com/trezor/blockbook/bchain"
|
"spacecruft.org/spacecruft/blockbook/bchain"
|
||||||
"github.com/trezor/blockbook/bchain/coins/btc"
|
"spacecruft.org/spacecruft/blockbook/bchain/coins/btc"
|
||||||
)
|
)
|
||||||
|
|
||||||
func TestMain(m *testing.M) {
|
func TestMain(m *testing.M) {
|
||||||
|
|
|
@ -4,8 +4,8 @@ import (
|
||||||
"encoding/json"
|
"encoding/json"
|
||||||
|
|
||||||
"github.com/golang/glog"
|
"github.com/golang/glog"
|
||||||
"github.com/trezor/blockbook/bchain"
|
"spacecruft.org/spacecruft/blockbook/bchain"
|
||||||
"github.com/trezor/blockbook/bchain/coins/btc"
|
"spacecruft.org/spacecruft/blockbook/bchain/coins/btc"
|
||||||
)
|
)
|
||||||
|
|
||||||
// FujicoinRPC is an interface to JSON-RPC bitcoind service.
|
// FujicoinRPC is an interface to JSON-RPC bitcoind service.
|
||||||
|
|
|
@ -3,7 +3,7 @@ package gamecredits
|
||||||
import (
|
import (
|
||||||
"github.com/martinboehm/btcd/wire"
|
"github.com/martinboehm/btcd/wire"
|
||||||
"github.com/martinboehm/btcutil/chaincfg"
|
"github.com/martinboehm/btcutil/chaincfg"
|
||||||
"github.com/trezor/blockbook/bchain/coins/btc"
|
"spacecruft.org/spacecruft/blockbook/bchain/coins/btc"
|
||||||
)
|
)
|
||||||
|
|
||||||
// magic numbers
|
// magic numbers
|
||||||
|
|
|
@ -10,8 +10,8 @@ import (
|
||||||
"testing"
|
"testing"
|
||||||
|
|
||||||
"github.com/martinboehm/btcutil/chaincfg"
|
"github.com/martinboehm/btcutil/chaincfg"
|
||||||
"github.com/trezor/blockbook/bchain"
|
"spacecruft.org/spacecruft/blockbook/bchain"
|
||||||
"github.com/trezor/blockbook/bchain/coins/btc"
|
"spacecruft.org/spacecruft/blockbook/bchain/coins/btc"
|
||||||
)
|
)
|
||||||
|
|
||||||
func TestMain(m *testing.M) {
|
func TestMain(m *testing.M) {
|
||||||
|
|
|
@ -4,8 +4,8 @@ import (
|
||||||
"encoding/json"
|
"encoding/json"
|
||||||
|
|
||||||
"github.com/golang/glog"
|
"github.com/golang/glog"
|
||||||
"github.com/trezor/blockbook/bchain"
|
"spacecruft.org/spacecruft/blockbook/bchain"
|
||||||
"github.com/trezor/blockbook/bchain/coins/btc"
|
"spacecruft.org/spacecruft/blockbook/bchain/coins/btc"
|
||||||
)
|
)
|
||||||
|
|
||||||
// GameCreditsRPC is an interface to JSON-RPC bitcoind service.
|
// GameCreditsRPC is an interface to JSON-RPC bitcoind service.
|
||||||
|
|
|
@ -4,8 +4,8 @@ import (
|
||||||
"github.com/martinboehm/btcd/wire"
|
"github.com/martinboehm/btcd/wire"
|
||||||
"github.com/martinboehm/btcutil/base58"
|
"github.com/martinboehm/btcutil/base58"
|
||||||
"github.com/martinboehm/btcutil/chaincfg"
|
"github.com/martinboehm/btcutil/chaincfg"
|
||||||
"github.com/trezor/blockbook/bchain"
|
"spacecruft.org/spacecruft/blockbook/bchain"
|
||||||
"github.com/trezor/blockbook/bchain/coins/btc"
|
"spacecruft.org/spacecruft/blockbook/bchain/coins/btc"
|
||||||
)
|
)
|
||||||
|
|
||||||
// magic numbers
|
// magic numbers
|
||||||
|
|
|
@ -11,8 +11,8 @@ import (
|
||||||
"testing"
|
"testing"
|
||||||
|
|
||||||
"github.com/martinboehm/btcutil/chaincfg"
|
"github.com/martinboehm/btcutil/chaincfg"
|
||||||
"github.com/trezor/blockbook/bchain"
|
"spacecruft.org/spacecruft/blockbook/bchain"
|
||||||
"github.com/trezor/blockbook/bchain/coins/btc"
|
"spacecruft.org/spacecruft/blockbook/bchain/coins/btc"
|
||||||
)
|
)
|
||||||
|
|
||||||
var (
|
var (
|
||||||
|
|
|
@ -5,8 +5,8 @@ import (
|
||||||
|
|
||||||
"github.com/golang/glog"
|
"github.com/golang/glog"
|
||||||
"github.com/juju/errors"
|
"github.com/juju/errors"
|
||||||
"github.com/trezor/blockbook/bchain"
|
"spacecruft.org/spacecruft/blockbook/bchain"
|
||||||
"github.com/trezor/blockbook/bchain/coins/btc"
|
"spacecruft.org/spacecruft/blockbook/bchain/coins/btc"
|
||||||
)
|
)
|
||||||
|
|
||||||
// GroestlcoinRPC is an interface to JSON-RPC service
|
// GroestlcoinRPC is an interface to JSON-RPC service
|
||||||
|
|
|
@ -3,8 +3,8 @@ package koto
|
||||||
import (
|
import (
|
||||||
"github.com/martinboehm/btcd/wire"
|
"github.com/martinboehm/btcd/wire"
|
||||||
"github.com/martinboehm/btcutil/chaincfg"
|
"github.com/martinboehm/btcutil/chaincfg"
|
||||||
"github.com/trezor/blockbook/bchain"
|
"spacecruft.org/spacecruft/blockbook/bchain"
|
||||||
"github.com/trezor/blockbook/bchain/coins/btc"
|
"spacecruft.org/spacecruft/blockbook/bchain/coins/btc"
|
||||||
)
|
)
|
||||||
|
|
||||||
// magic numbers
|
// magic numbers
|
||||||
|
|
|
@ -11,8 +11,8 @@ import (
|
||||||
"testing"
|
"testing"
|
||||||
|
|
||||||
"github.com/martinboehm/btcutil/chaincfg"
|
"github.com/martinboehm/btcutil/chaincfg"
|
||||||
"github.com/trezor/blockbook/bchain"
|
"spacecruft.org/spacecruft/blockbook/bchain"
|
||||||
"github.com/trezor/blockbook/bchain/coins/btc"
|
"spacecruft.org/spacecruft/blockbook/bchain/coins/btc"
|
||||||
)
|
)
|
||||||
|
|
||||||
var (
|
var (
|
||||||
|
|
|
@ -5,8 +5,8 @@ import (
|
||||||
|
|
||||||
"github.com/golang/glog"
|
"github.com/golang/glog"
|
||||||
"github.com/juju/errors"
|
"github.com/juju/errors"
|
||||||
"github.com/trezor/blockbook/bchain"
|
"spacecruft.org/spacecruft/blockbook/bchain"
|
||||||
"github.com/trezor/blockbook/bchain/coins/btc"
|
"spacecruft.org/spacecruft/blockbook/bchain/coins/btc"
|
||||||
)
|
)
|
||||||
|
|
||||||
// KotoRPC is an interface to JSON-RPC bitcoind service
|
// KotoRPC is an interface to JSON-RPC bitcoind service
|
||||||
|
|
|
@ -8,8 +8,8 @@ import (
|
||||||
"github.com/martinboehm/btcd/txscript"
|
"github.com/martinboehm/btcd/txscript"
|
||||||
"github.com/martinboehm/btcd/wire"
|
"github.com/martinboehm/btcd/wire"
|
||||||
"github.com/martinboehm/btcutil/chaincfg"
|
"github.com/martinboehm/btcutil/chaincfg"
|
||||||
"github.com/trezor/blockbook/bchain"
|
"spacecruft.org/spacecruft/blockbook/bchain"
|
||||||
"github.com/trezor/blockbook/bchain/coins/btc"
|
"spacecruft.org/spacecruft/blockbook/bchain/coins/btc"
|
||||||
)
|
)
|
||||||
|
|
||||||
const (
|
const (
|
||||||
|
|
|
@ -10,8 +10,8 @@ import (
|
||||||
"testing"
|
"testing"
|
||||||
|
|
||||||
"github.com/martinboehm/btcutil/chaincfg"
|
"github.com/martinboehm/btcutil/chaincfg"
|
||||||
"github.com/trezor/blockbook/bchain"
|
"spacecruft.org/spacecruft/blockbook/bchain"
|
||||||
"github.com/trezor/blockbook/bchain/coins/btc"
|
"spacecruft.org/spacecruft/blockbook/bchain/coins/btc"
|
||||||
)
|
)
|
||||||
|
|
||||||
func TestMain(m *testing.M) {
|
func TestMain(m *testing.M) {
|
||||||
|
|
|
@ -5,8 +5,8 @@ import (
|
||||||
|
|
||||||
"github.com/golang/glog"
|
"github.com/golang/glog"
|
||||||
"github.com/juju/errors"
|
"github.com/juju/errors"
|
||||||
"github.com/trezor/blockbook/bchain"
|
"spacecruft.org/spacecruft/blockbook/bchain"
|
||||||
"github.com/trezor/blockbook/bchain/coins/btc"
|
"spacecruft.org/spacecruft/blockbook/bchain/coins/btc"
|
||||||
)
|
)
|
||||||
|
|
||||||
// LiquidRPC is an interface to JSON-RPC bitcoind service.
|
// LiquidRPC is an interface to JSON-RPC bitcoind service.
|
||||||
|
|
|
@ -3,7 +3,7 @@ package litecoin
|
||||||
import (
|
import (
|
||||||
"github.com/martinboehm/btcd/wire"
|
"github.com/martinboehm/btcd/wire"
|
||||||
"github.com/martinboehm/btcutil/chaincfg"
|
"github.com/martinboehm/btcutil/chaincfg"
|
||||||
"github.com/trezor/blockbook/bchain/coins/btc"
|
"spacecruft.org/spacecruft/blockbook/bchain/coins/btc"
|
||||||
)
|
)
|
||||||
|
|
||||||
// magic numbers
|
// magic numbers
|
||||||
|
|
|
@ -10,8 +10,8 @@ import (
|
||||||
"testing"
|
"testing"
|
||||||
|
|
||||||
"github.com/martinboehm/btcutil/chaincfg"
|
"github.com/martinboehm/btcutil/chaincfg"
|
||||||
"github.com/trezor/blockbook/bchain"
|
"spacecruft.org/spacecruft/blockbook/bchain"
|
||||||
"github.com/trezor/blockbook/bchain/coins/btc"
|
"spacecruft.org/spacecruft/blockbook/bchain/coins/btc"
|
||||||
)
|
)
|
||||||
|
|
||||||
func TestMain(m *testing.M) {
|
func TestMain(m *testing.M) {
|
||||||
|
|
|
@ -4,8 +4,8 @@ import (
|
||||||
"encoding/json"
|
"encoding/json"
|
||||||
|
|
||||||
"github.com/golang/glog"
|
"github.com/golang/glog"
|
||||||
"github.com/trezor/blockbook/bchain"
|
"spacecruft.org/spacecruft/blockbook/bchain"
|
||||||
"github.com/trezor/blockbook/bchain/coins/btc"
|
"spacecruft.org/spacecruft/blockbook/bchain/coins/btc"
|
||||||
)
|
)
|
||||||
|
|
||||||
// LitecoinRPC is an interface to JSON-RPC bitcoind service.
|
// LitecoinRPC is an interface to JSON-RPC bitcoind service.
|
||||||
|
|
|
@ -3,7 +3,7 @@ package monacoin
|
||||||
import (
|
import (
|
||||||
"github.com/martinboehm/btcd/wire"
|
"github.com/martinboehm/btcd/wire"
|
||||||
"github.com/martinboehm/btcutil/chaincfg"
|
"github.com/martinboehm/btcutil/chaincfg"
|
||||||
"github.com/trezor/blockbook/bchain/coins/btc"
|
"spacecruft.org/spacecruft/blockbook/bchain/coins/btc"
|
||||||
)
|
)
|
||||||
|
|
||||||
// magic numbers
|
// magic numbers
|
||||||
|
|
|
@ -10,8 +10,8 @@ import (
|
||||||
"testing"
|
"testing"
|
||||||
|
|
||||||
"github.com/martinboehm/btcutil/chaincfg"
|
"github.com/martinboehm/btcutil/chaincfg"
|
||||||
"github.com/trezor/blockbook/bchain"
|
"spacecruft.org/spacecruft/blockbook/bchain"
|
||||||
"github.com/trezor/blockbook/bchain/coins/btc"
|
"spacecruft.org/spacecruft/blockbook/bchain/coins/btc"
|
||||||
)
|
)
|
||||||
|
|
||||||
func TestMain(m *testing.M) {
|
func TestMain(m *testing.M) {
|
||||||
|
|
|
@ -4,8 +4,8 @@ import (
|
||||||
"encoding/json"
|
"encoding/json"
|
||||||
|
|
||||||
"github.com/golang/glog"
|
"github.com/golang/glog"
|
||||||
"github.com/trezor/blockbook/bchain"
|
"spacecruft.org/spacecruft/blockbook/bchain"
|
||||||
"github.com/trezor/blockbook/bchain/coins/btc"
|
"spacecruft.org/spacecruft/blockbook/bchain/coins/btc"
|
||||||
)
|
)
|
||||||
|
|
||||||
// MonacoinRPC is an interface to JSON-RPC bitcoind service.
|
// MonacoinRPC is an interface to JSON-RPC bitcoind service.
|
||||||
|
|
|
@ -9,9 +9,9 @@ import (
|
||||||
"github.com/juju/errors"
|
"github.com/juju/errors"
|
||||||
"github.com/martinboehm/btcd/wire"
|
"github.com/martinboehm/btcd/wire"
|
||||||
"github.com/martinboehm/btcutil/chaincfg"
|
"github.com/martinboehm/btcutil/chaincfg"
|
||||||
"github.com/trezor/blockbook/bchain"
|
"spacecruft.org/spacecruft/blockbook/bchain"
|
||||||
"github.com/trezor/blockbook/bchain/coins/btc"
|
"spacecruft.org/spacecruft/blockbook/bchain/coins/btc"
|
||||||
"github.com/trezor/blockbook/bchain/coins/utils"
|
"spacecruft.org/spacecruft/blockbook/bchain/coins/utils"
|
||||||
)
|
)
|
||||||
|
|
||||||
const (
|
const (
|
||||||
|
|
|
@ -10,8 +10,8 @@ import (
|
||||||
"testing"
|
"testing"
|
||||||
|
|
||||||
"github.com/martinboehm/btcutil/chaincfg"
|
"github.com/martinboehm/btcutil/chaincfg"
|
||||||
"github.com/trezor/blockbook/bchain"
|
"spacecruft.org/spacecruft/blockbook/bchain"
|
||||||
"github.com/trezor/blockbook/bchain/coins/btc"
|
"spacecruft.org/spacecruft/blockbook/bchain/coins/btc"
|
||||||
)
|
)
|
||||||
|
|
||||||
func TestMain(m *testing.M) {
|
func TestMain(m *testing.M) {
|
||||||
|
|
|
@ -4,8 +4,8 @@ import (
|
||||||
"encoding/json"
|
"encoding/json"
|
||||||
|
|
||||||
"github.com/golang/glog"
|
"github.com/golang/glog"
|
||||||
"github.com/trezor/blockbook/bchain"
|
"spacecruft.org/spacecruft/blockbook/bchain"
|
||||||
"github.com/trezor/blockbook/bchain/coins/btc"
|
"spacecruft.org/spacecruft/blockbook/bchain/coins/btc"
|
||||||
)
|
)
|
||||||
|
|
||||||
// MonetaryUnitRPC is an interface to JSON-RPC bitcoind service.
|
// MonetaryUnitRPC is an interface to JSON-RPC bitcoind service.
|
||||||
|
|
|
@ -5,9 +5,9 @@ import (
|
||||||
|
|
||||||
"github.com/martinboehm/btcd/wire"
|
"github.com/martinboehm/btcd/wire"
|
||||||
"github.com/martinboehm/btcutil/chaincfg"
|
"github.com/martinboehm/btcutil/chaincfg"
|
||||||
"github.com/trezor/blockbook/bchain"
|
"spacecruft.org/spacecruft/blockbook/bchain"
|
||||||
"github.com/trezor/blockbook/bchain/coins/btc"
|
"spacecruft.org/spacecruft/blockbook/bchain/coins/btc"
|
||||||
"github.com/trezor/blockbook/bchain/coins/utils"
|
"spacecruft.org/spacecruft/blockbook/bchain/coins/utils"
|
||||||
)
|
)
|
||||||
|
|
||||||
// magic numbers
|
// magic numbers
|
||||||
|
|
|
@ -10,8 +10,8 @@ import (
|
||||||
"testing"
|
"testing"
|
||||||
|
|
||||||
"github.com/martinboehm/btcutil/chaincfg"
|
"github.com/martinboehm/btcutil/chaincfg"
|
||||||
"github.com/trezor/blockbook/bchain"
|
"spacecruft.org/spacecruft/blockbook/bchain"
|
||||||
"github.com/trezor/blockbook/bchain/coins/btc"
|
"spacecruft.org/spacecruft/blockbook/bchain/coins/btc"
|
||||||
)
|
)
|
||||||
|
|
||||||
func TestMain(m *testing.M) {
|
func TestMain(m *testing.M) {
|
||||||
|
|
|
@ -4,8 +4,8 @@ import (
|
||||||
"encoding/json"
|
"encoding/json"
|
||||||
|
|
||||||
"github.com/golang/glog"
|
"github.com/golang/glog"
|
||||||
"github.com/trezor/blockbook/bchain"
|
"spacecruft.org/spacecruft/blockbook/bchain"
|
||||||
"github.com/trezor/blockbook/bchain/coins/btc"
|
"spacecruft.org/spacecruft/blockbook/bchain/coins/btc"
|
||||||
)
|
)
|
||||||
|
|
||||||
// MyriadRPC is an interface to JSON-RPC bitcoind service.
|
// MyriadRPC is an interface to JSON-RPC bitcoind service.
|
||||||
|
|
|
@ -5,9 +5,9 @@ import (
|
||||||
|
|
||||||
"github.com/martinboehm/btcd/wire"
|
"github.com/martinboehm/btcd/wire"
|
||||||
"github.com/martinboehm/btcutil/chaincfg"
|
"github.com/martinboehm/btcutil/chaincfg"
|
||||||
"github.com/trezor/blockbook/bchain"
|
"spacecruft.org/spacecruft/blockbook/bchain"
|
||||||
"github.com/trezor/blockbook/bchain/coins/btc"
|
"spacecruft.org/spacecruft/blockbook/bchain/coins/btc"
|
||||||
"github.com/trezor/blockbook/bchain/coins/utils"
|
"spacecruft.org/spacecruft/blockbook/bchain/coins/utils"
|
||||||
)
|
)
|
||||||
|
|
||||||
const (
|
const (
|
||||||
|
|
|
@ -13,7 +13,7 @@ import (
|
||||||
"testing"
|
"testing"
|
||||||
|
|
||||||
"github.com/martinboehm/btcutil/chaincfg"
|
"github.com/martinboehm/btcutil/chaincfg"
|
||||||
"github.com/trezor/blockbook/bchain/coins/btc"
|
"spacecruft.org/spacecruft/blockbook/bchain/coins/btc"
|
||||||
)
|
)
|
||||||
|
|
||||||
func TestMain(m *testing.M) {
|
func TestMain(m *testing.M) {
|
||||||
|
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue