Compare commits
227 Commits
master
...
flo-upstre
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
bd1543d418 | ||
|
|
4a7fdb5095 | ||
|
|
70f34cedeb | ||
|
|
84be24ef7f | ||
|
|
b40948a781 | ||
|
|
1334a16d3a | ||
|
|
40be3e7219 | ||
|
|
fab4dd78ca | ||
|
|
8b05dbc9b9 | ||
|
|
4c5c0bd32f | ||
|
|
d771291eca | ||
|
|
bdc477050b | ||
|
|
22fe25b9cf | ||
|
|
6f4a6aa8e3 | ||
|
|
144a369f92 | ||
|
|
f2cd67e81f | ||
|
|
c3cdf9bca4 | ||
|
|
a4f1730364 | ||
|
|
e283ac8915 | ||
|
|
46156d296f | ||
|
|
a55c69a8a1 | ||
|
|
19a902360e | ||
|
|
1fe4ee04f3 | ||
|
|
6eb3ba2201 | ||
|
|
4ba04f119b | ||
|
|
66b4ddbe01 | ||
|
|
04a5d8d95d | ||
|
|
d6aaa09e06 | ||
|
|
afe4749f6d | ||
|
|
132bd77af7 | ||
|
|
f373a73bea | ||
|
|
fe676b354d | ||
|
|
572d7e5075 | ||
|
|
c3cd444578 | ||
|
|
d8c68f2b6b | ||
|
|
0cc953fcca | ||
|
|
76664cdbf3 | ||
|
|
059086cd3d | ||
|
|
1c70a269b0 | ||
|
|
a2aa489b65 | ||
|
|
a93a011d8f | ||
|
|
996fa2d88c | ||
|
|
3cf7e6abe8 | ||
|
|
a1434979fa | ||
|
|
345ea17031 | ||
|
|
3cb815ba27 | ||
|
|
424055d689 | ||
|
|
a0960c8e17 | ||
|
|
c1f2e62c45 | ||
|
|
f6899a7712 | ||
|
|
0afcb3a002 | ||
|
|
4b9a0a90bb | ||
|
|
7e5be4837b | ||
|
|
3ce286f82d | ||
|
|
80f05727c1 | ||
|
|
2e3ac06ea0 | ||
|
|
d814abae0e | ||
|
|
f0dd0e80b0 | ||
|
|
6f170e07b0 | ||
|
|
8d22752bec | ||
|
|
45c778a14a | ||
|
|
2fe72ac150 | ||
|
|
eeca7e72a3 | ||
|
|
8ac418b267 | ||
|
|
6a7c4e96ed | ||
|
|
d20379ada9 | ||
|
|
78b4ec1dc4 | ||
|
|
35ab7a3966 | ||
|
|
2751a9b03f | ||
|
|
eaf8f4815c | ||
|
|
c0dbeeea9a | ||
|
|
21780d439f | ||
|
|
0d418deceb | ||
|
|
f5cb71de7e | ||
|
|
067a2da75d | ||
|
|
c16143f6e1 | ||
|
|
b0bec47364 | ||
|
|
b5bbf8c376 | ||
|
|
beaadf16cd | ||
|
|
87652aa6ac | ||
|
|
1b47447c77 | ||
|
|
9b5c79c878 | ||
|
|
754169958e | ||
|
|
ab5235b732 | ||
|
|
0277c2a8e6 | ||
|
|
e9a08582ee | ||
|
|
3c57a0c010 | ||
|
|
b5cfbdfde5 | ||
|
|
9a2fe4dbe4 | ||
|
|
1df02d9df5 | ||
|
|
60fb37da4f | ||
|
|
52561322f8 | ||
|
|
847c40a29e | ||
|
|
d8cd7b4d0b | ||
|
|
2c84ed4eb2 | ||
|
|
913c0e5198 | ||
|
|
4d60edc231 | ||
|
|
f05159a7fa | ||
|
|
ca3a023493 | ||
|
|
da34069d24 | ||
|
|
8802a73017 | ||
|
|
b4249ab4bb | ||
|
|
8780151664 | ||
|
|
8d78397969 | ||
|
|
a13feaccd9 | ||
|
|
4e3ba20610 | ||
|
|
5f47f3c489 | ||
|
|
0ed95dca32 | ||
|
|
11ad8141ac | ||
|
|
55860c001a | ||
|
|
1d95413f73 | ||
|
|
ac46385f49 | ||
|
|
f03c625def | ||
|
|
c2cb64856b | ||
|
|
3e1f456632 | ||
|
|
c43bcb25d0 | ||
|
|
b10b790760 | ||
|
|
a8fbfd2448 | ||
|
|
536a4701c0 | ||
|
|
bfc3c7193b | ||
|
|
23314e523c | ||
|
|
9ea7fb23df | ||
|
|
12de050229 | ||
|
|
c2b2f10df4 | ||
|
|
c1c44b19ca | ||
|
|
aa13c065b1 | ||
|
|
7d2a4ef3db | ||
|
|
ca41c4a29e | ||
|
|
24e08ec053 | ||
|
|
e464e16a33 | ||
|
|
e7ee4a95d8 | ||
|
|
f6edc06630 | ||
|
|
a24afcb7d5 | ||
|
|
6a1c8ad725 | ||
|
|
33b885da68 | ||
|
|
05737ec510 | ||
|
|
474d41c93f | ||
|
|
61bdb8a346 | ||
|
|
f28a747baa | ||
|
|
3d1a3ff550 | ||
|
|
8c2a59aa0e | ||
|
|
0c95abe025 | ||
|
|
f4b340fc5d | ||
|
|
22de7e55d0 | ||
|
|
e67bb3176c | ||
|
|
f4d06ab08d | ||
|
|
3c29b07c7c | ||
|
|
08389b5e05 | ||
|
|
6992be6f58 | ||
|
|
2eebd7aed6 | ||
|
|
b9fee439ed | ||
|
|
8fa0612e48 | ||
|
|
8646c99dea | ||
|
|
a2ab9da785 | ||
|
|
a5bbb7d8ee | ||
|
|
8d4dd5d69d | ||
|
|
9c04322971 | ||
|
|
56ba302766 | ||
|
|
856c85e1e7 | ||
|
|
35dec9e9c4 | ||
|
|
3b0e108f45 | ||
|
|
78f0be0f23 | ||
|
|
80afffa7b0 | ||
|
|
8ef09d124e | ||
|
|
7d0c424ad8 | ||
|
|
a1a17b4331 | ||
|
|
4b6f19632d | ||
|
|
83d411be4e | ||
|
|
96dbc8c9dc | ||
|
|
911454f171 | ||
|
|
bc8ce22ed0 | ||
|
|
61eeeed03e | ||
|
|
3d93da0d64 | ||
|
|
1c71a696f2 | ||
|
|
059c60d2a1 | ||
|
|
137d6b2141 | ||
|
|
6ccfa19cb5 | ||
|
|
5f53f3b614 | ||
| 1818d14e70 | |||
| bd1075ba8b | |||
| 81462530fe | |||
| 63cdae7747 | |||
| d7ae525352 | |||
| dbf4ee83fd | |||
| e11746c3c3 | |||
| ef568ba31d | |||
|
|
9c5ae9585f | ||
|
|
52f86d2ed3 | ||
|
|
682b62fde8 | ||
|
|
c314a64ea8 | ||
|
|
d8c32533de | ||
|
|
b91b36e86b | ||
|
|
a586ce22e6 | ||
|
|
8859e21b02 | ||
|
|
c902332bc2 | ||
|
|
85e5b22d1c | ||
|
|
d4af0f5e14 | ||
|
|
95ee9b5b64 | ||
|
|
915f4926d3 | ||
|
|
6e51bdefd3 | ||
| bbc9239a27 | |||
|
|
823d0f992d | ||
|
|
4f7d8f0956 | ||
|
|
11ed72b58e | ||
|
|
04fa1df87a | ||
|
|
8e18ca0e32 | ||
|
|
e21decd769 | ||
|
|
e1d6493a2e | ||
|
|
a139dd5d52 | ||
|
|
65cd73d081 | ||
|
|
6b022bb9c5 | ||
|
|
083285f4d3 | ||
| d5eeb47199 | |||
| 9fda269d8d | |||
|
|
23b13cc814 | ||
|
|
9fa5ee3618 | ||
|
|
d1a0c9326b | ||
|
|
e5c4c0dc65 | ||
|
|
d90608d8eb | ||
|
|
fcd88b3ab4 | ||
|
|
d1ffa7bb9e | ||
|
|
9f0286cef4 | ||
|
|
ac1da72ba8 | ||
|
|
f821c02dbc | ||
|
|
3c83f1af21 | ||
|
|
9003df740d | ||
|
|
c30d2f79fe |
10
.editorconfig
Normal file
10
.editorconfig
Normal file
@ -0,0 +1,10 @@
|
|||||||
|
root = true
|
||||||
|
|
||||||
|
[*.md]
|
||||||
|
indent_style = space
|
||||||
|
indent_size = 4
|
||||||
|
trim_trailing_whitespace = false
|
||||||
|
max_line_length = 80
|
||||||
|
insert_final_newline = true
|
||||||
|
charset = utf-8
|
||||||
|
end_of_line = lf
|
||||||
41
.github/workflows/build-release-flo-deb.yml
vendored
Normal file
41
.github/workflows/build-release-flo-deb.yml
vendored
Normal file
@ -0,0 +1,41 @@
|
|||||||
|
name: Create Release
|
||||||
|
|
||||||
|
on:
|
||||||
|
push:
|
||||||
|
branches:
|
||||||
|
- flo
|
||||||
|
|
||||||
|
jobs:
|
||||||
|
build-and-release-flo-deb:
|
||||||
|
runs-on: self-hosted
|
||||||
|
|
||||||
|
steps:
|
||||||
|
- name: Checkout Repository
|
||||||
|
uses: actions/checkout@v2
|
||||||
|
|
||||||
|
- name: Build .deb File
|
||||||
|
run: |
|
||||||
|
make all-flo
|
||||||
|
mkdir -p release
|
||||||
|
mv ./build/*.deb ./release/
|
||||||
|
timeout-minutes: 130 # Adjust the timeout according to the estimated duration of "make all-flo"
|
||||||
|
|
||||||
|
- name: Create Release
|
||||||
|
id: create_release
|
||||||
|
uses: actions/create-release@v1
|
||||||
|
env:
|
||||||
|
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
||||||
|
with:
|
||||||
|
tag_name: FLO # Use the commit SHA as the tag name
|
||||||
|
release_name: Release FLO # Use the commit SHA as the release name
|
||||||
|
body: |
|
||||||
|
Release commit: ${{ github.sha }}
|
||||||
|
Commit message: ${{ github.event.head_commit.message }}
|
||||||
|
draft: false
|
||||||
|
prerelease: false
|
||||||
|
|
||||||
|
- name: Upload .deb File
|
||||||
|
uses: actions/upload-artifact@v2
|
||||||
|
with:
|
||||||
|
name: deb-file
|
||||||
|
path: ./release/*.deb
|
||||||
@ -157,15 +157,4 @@ backend-deploy-and-test-zcash_testnet:
|
|||||||
- configs/coins/zcash_testnet.json
|
- configs/coins/zcash_testnet.json
|
||||||
tags:
|
tags:
|
||||||
- blockbook
|
- blockbook
|
||||||
script: ./contrib/scripts/backend-deploy-and-test.sh zcash_testnet zcash-testnet zcash=test testnet3/debug.log
|
script: ./contrib/scripts/backend-deploy-and-test.sh zcash_testnet zcash-testnet zcash=test testnet3/debug.log
|
||||||
|
|
||||||
backend-deploy-and-test-goerli-archive:
|
|
||||||
stage: backend-deploy-and-test
|
|
||||||
only:
|
|
||||||
refs:
|
|
||||||
- master
|
|
||||||
changes:
|
|
||||||
- configs/coins/ethereum_testnet_goerli_archive.json
|
|
||||||
tags:
|
|
||||||
- blockbook
|
|
||||||
script: ./contrib/scripts/backend-deploy-and-test.sh ethereum_testnet_goerli_archive ethereum-testnet-goerli-archive ethereum=test ethereum_testnet_goerli_archive.log
|
|
||||||
10
Makefile
10
Makefile
@ -1,9 +1,10 @@
|
|||||||
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)
|
||||||
|
DOCKER_VERSION = $(shell docker version --format '{{.Client.Version}}')
|
||||||
BASE_IMAGE = $$(awk -F= '$$1=="ID" { print $$2 ;}' /etc/os-release):$$(awk -F= '$$1=="VERSION_ID" { print $$2 ;}' /etc/os-release | tr -d '"')
|
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
|
||||||
TCMALLOC =
|
TCMALLOC =
|
||||||
PORTABLE = 0
|
PORTABLE = 0
|
||||||
ARGS ?=
|
ARGS ?=
|
||||||
|
|
||||||
@ -27,7 +28,7 @@ test-all: .bin-image
|
|||||||
docker run -t --rm -e PACKAGER=$(PACKAGER) -v "$(CURDIR):/src" --network="host" $(BIN_IMAGE) make test-all ARGS="$(ARGS)"
|
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) -v "$(CURDIR):/src" -v "$(CURDIR)/build:/out" $(DEB_IMAGE) /build/build-deb.sh backend $* $(ARGS)
|
docker run -t --rm -e PACKAGER=$(PACKAGER) -v /var/run/docker.sock:/var/run/docker.sock -v "$(CURDIR):/src" -v "$(CURDIR)/build:/out" $(DEB_IMAGE) /build/build-deb.sh backend $* $(ARGS)
|
||||||
|
|
||||||
deb-blockbook-%: .deb-image
|
deb-blockbook-%: .deb-image
|
||||||
docker run -t --rm -e PACKAGER=$(PACKAGER) -v "$(CURDIR):/src" -v "$(CURDIR)/build:/out" $(DEB_IMAGE) /build/build-deb.sh blockbook $* $(ARGS)
|
docker run -t --rm -e PACKAGER=$(PACKAGER) -v "$(CURDIR):/src" -v "$(CURDIR)/build:/out" $(DEB_IMAGE) /build/build-deb.sh blockbook $* $(ARGS)
|
||||||
@ -55,7 +56,7 @@ build-images: clean-images
|
|||||||
.deb-image: .bin-image
|
.deb-image: .bin-image
|
||||||
@if [ $$(build/tools/image_status.sh $(DEB_IMAGE):latest build/docker) != "ok" ]; then \
|
@if [ $$(build/tools/image_status.sh $(DEB_IMAGE):latest build/docker) != "ok" ]; then \
|
||||||
echo "Building image $(DEB_IMAGE)..."; \
|
echo "Building image $(DEB_IMAGE)..."; \
|
||||||
docker build --no-cache=$(NO_CACHE) -t $(DEB_IMAGE) build/docker/deb; \
|
docker build --no-cache=$(NO_CACHE) --build-arg DOCKER_VERSION=$(DOCKER_VERSION) -t $(DEB_IMAGE) build/docker/deb; \
|
||||||
else \
|
else \
|
||||||
echo "Image $(DEB_IMAGE) is up to date"; \
|
echo "Image $(DEB_IMAGE) is up to date"; \
|
||||||
fi
|
fi
|
||||||
@ -79,3 +80,6 @@ clean-bin-image:
|
|||||||
|
|
||||||
clean-deb-image:
|
clean-deb-image:
|
||||||
- docker rmi $(DEB_IMAGE)
|
- docker rmi $(DEB_IMAGE)
|
||||||
|
|
||||||
|
style:
|
||||||
|
find . -name "*.go" -exec gofmt -w {} \;
|
||||||
|
|||||||
154
README.md
154
README.md
@ -1,8 +1,154 @@
|
|||||||
[](https://goreportcard.com/report/trezor/blockbook)
|
[](https://goreportcard.com/report/trezor/blockbook)
|
||||||
|
[](https://github.com/ranchimall/blockbook/actions/workflows/build-release-flo-deb.yml)
|
||||||
|
|
||||||
|
# IMPORTANT Changes needed to migrate to blockbook from flosight
|
||||||
|
1. blockbook URL link
|
||||||
|
2. API URIs (path)
|
||||||
|
3. response object path for tx vin floID (for processes that need to find sender id from tx details)
|
||||||
|
4. The link for fetching details of transactions for every ADDRESS has changed slightly
|
||||||
|
|
||||||
|
```
|
||||||
|
- For point 3
|
||||||
|
We need to change
|
||||||
|
|
||||||
|
vin[x].addr
|
||||||
|
to
|
||||||
|
vin[x].addresses[0]
|
||||||
|
```
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
## Changes needed for UI in FLO applications
|
||||||
|
|
||||||
|
- OLD BLOCK LINK
|
||||||
|
- https://flosight.duckdns.org/block/48fb49a89317c0852eb894b0251ae3c830621d416b2481ecd1d541d0b01e5ab8
|
||||||
|
- https://flosight.duckdns.org/api/block/48fb49a89317c0852eb894b0251ae3c830621d416b2481ecd1d541d0b01e5ab8
|
||||||
|
|
||||||
|
- NEW BLOCK LINK
|
||||||
|
- https://blockbook.ranchimall.net/block/48fb49a89317c0852eb894b0251ae3c830621d416b2481ecd1d541d0b01e5ab8
|
||||||
|
- https://blockbook.ranchimall.net/api/block/48fb49a89317c0852eb894b0251ae3c830621d416b2481ecd1d541d0b01e5ab8
|
||||||
|
|
||||||
|
- OLD tx LINK
|
||||||
|
- https://flosight.duckdns.org/tx/ae7886df36832824e0e0f37cd003150cc7222e35bc7320d226f1561a598ce39a
|
||||||
|
- https://flosight.duckdns.org/api/tx/ae7886df36832824e0e0f37cd003150cc7222e35bc7320d226f1561a598ce39a
|
||||||
|
|
||||||
|
- NEW tx LINK
|
||||||
|
- https://blockbook.ranchimall.net/tx/ae7886df36832824e0e0f37cd003150cc7222e35bc7320d226f1561a598ce39a
|
||||||
|
- https://blockbook.ranchimall.net/api/tx/ae7886df36832824e0e0f37cd003150cc7222e35bc7320d226f1561a598ce39a
|
||||||
|
|
||||||
|
```
|
||||||
|
Make this change for sender address in tx API here
|
||||||
|
|
||||||
|
vin[x].addr
|
||||||
|
to
|
||||||
|
vin[x].addresses[0]
|
||||||
|
```
|
||||||
|
|
||||||
|
- OLD Address LINK
|
||||||
|
- https://flosight.duckdns.org/address/F9RgXE1WYxHwvejktpi6EnjnscEkpiWxvS
|
||||||
|
- https://flosight.duckdns.org/api/address/F9RgXE1WYxHwvejktpi6EnjnscEkpiWxvS
|
||||||
|
|
||||||
|
- NEW ADDRESS LINK
|
||||||
|
- https://blockbook.ranchimall.net/address/F9RgXE1WYxHwvejktpi6EnjnscEkpiWxvS
|
||||||
|
- https://blockbook.ranchimall.net/api/address/F9RgXE1WYxHwvejktpi6EnjnscEkpiWxvS
|
||||||
|
|
||||||
|
- OLD
|
||||||
|
- https://flosight.ranchimall.net/api/addrs/FBL45szT4jDQmViVirUxPeJjn1tkCDMxeT/txs
|
||||||
|
- https://flosight.ranchimall.net/api/addrs/FBL45szT4jDQmViVirUxPeJjn1tkCDMxeT/txs?from=0&to=359
|
||||||
|
|
||||||
|
- NEW
|
||||||
|
- https://blockbook.ranchimall.net/api/address/FBL45szT4jDQmViVirUxPeJjn1tkCDMxeT?details=basic
|
||||||
|
- https://blockbook.ranchimall.net/api/address/FBL45szT4jDQmViVirUxPeJjn1tkCDMxeT?details=txs
|
||||||
|
|
||||||
|
- with paging for address
|
||||||
|
- https://blockbook.ranchimall.net/api/address/FBL45szT4jDQmViVirUxPeJjn1tkCDMxeT?details=txs&pageSize=10&page=2
|
||||||
|
|
||||||
|
|
||||||
|
```javascript
|
||||||
|
//Flosight
|
||||||
|
var response = ajax("GET",`api/addrs/${addr}/txs?from=0&to=${nRequired}`);
|
||||||
|
//Blockbook
|
||||||
|
var response = ajax("GET",`api/address/${addr}&details=txs?pageSize=${nRequired}&page=1`);
|
||||||
|
```
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
- OLD LINK FOR DIRECT BALANCE QUERY
|
||||||
|
- https://flosight.duckdns.org/api/addr/FBL45szT4jDQmViVirUxPeJjn1tkCDMxeT/balance
|
||||||
|
|
||||||
|
- NO BLOCKBOOK EQUIVALENT
|
||||||
|
- THIS HAS TO BE FETCHED FROM THIS FORMAT
|
||||||
|
- https://blockbook.ranchimall.net/api/address/FBL45szT4jDQmViVirUxPeJjn1tkCDMxeT?details=basic
|
||||||
|
|
||||||
|
```javascript
|
||||||
|
// https://blockbook.ranchimall.net/api/address/FBL45szT4jDQmViVirUxPeJjn1tkCDMxeT?details=basic
|
||||||
|
// JSON data as a string
|
||||||
|
var jsonData = '{"addrStr":"FBL45szT4jDQmViVirUxPeJjn1tkCDMxeT","balance":0.1663,"balanceSat":16630000,"totalReceived":29.4465,"totalReceivedSat":2944650000,"totalSent":29.2802,"totalSentSat":2928020000,"unconfirmedBalance":0,"unconfirmedBalanceSat":0,"unconfirmedTxApperances":0,"txApperances":407}';
|
||||||
|
|
||||||
|
// Parse the JSON data into a JavaScript object
|
||||||
|
var dataObject = JSON.parse(jsonData);
|
||||||
|
|
||||||
|
// Extract the balance value
|
||||||
|
var balance = dataObject.balance;
|
||||||
|
|
||||||
|
// Output the balance
|
||||||
|
console.log(balance); // Output: 0.1663
|
||||||
|
```
|
||||||
|
|
||||||
|
- To broadcast tx in Blockbook
|
||||||
|
- https://blockbook.ranchimall.net/api/sendtx/hex_tx_data
|
||||||
|
|
||||||
|
```
|
||||||
|
//THIS IS FLOSIGHT CODE TO BROADCAST TRANSACTION -- NOT NEEDED IN BLOCKBOOK
|
||||||
|
function broadcastTx(signedTxHash) {
|
||||||
|
var http = new XMLHttpRequest();
|
||||||
|
var url = `${api_url}/api/tx/send`;
|
||||||
|
if (signedTxHash.length < 1) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
var params = `{"rawtx":"${signedTxHash}"}`;
|
||||||
|
var result;
|
||||||
|
http.open('POST', url, false);
|
||||||
|
|
||||||
|
//Send the proper header information along with the request
|
||||||
|
http.setRequestHeader('Content-type', 'application/json');
|
||||||
|
|
||||||
|
http.onreadystatechange = function () { //Call a function when the state changes.
|
||||||
|
if (http.readyState == 4 && http.status == 200) {
|
||||||
|
console.log(http.response);
|
||||||
|
var txid = JSON.parse(http.response).txid.result;
|
||||||
|
console.log("Transaction successful! txid : " + txid);
|
||||||
|
result = txid;
|
||||||
|
} else {
|
||||||
|
console.log(http.responseText);
|
||||||
|
result = false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
http.send(params);
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
# Websocket Connectivity issue with Nginx
|
||||||
|
|
||||||
|
- Nginx needs more directives to permit Websocket traffic to pass.
|
||||||
|
- `proxy_set_header Upgrade $http_upgrade;` AND `proxy_set_header Connection "upgrade";` must be set in location in nginx conf file
|
||||||
|
|
||||||
|
```
|
||||||
|
location / {
|
||||||
|
proxy_pass https://0.0.0.0:98765/;
|
||||||
|
proxy_http_version 1.1;
|
||||||
|
proxy_set_header Upgrade $http_upgrade;
|
||||||
|
proxy_set_header Connection "upgrade";
|
||||||
|
proxy_set_header Host $host;
|
||||||
|
}
|
||||||
|
|
||||||
|
```
|
||||||
|
|
||||||
# Blockbook
|
# Blockbook
|
||||||
|
|
||||||
**Blockbook** is back-end service for Trezor wallet. Main features of **Blockbook** are:
|
**Blockbook** is a back-end service for Trezor Suite. The main features of **Blockbook** are:
|
||||||
|
|
||||||
- index of addresses and address balances of the connected block chain
|
- index of addresses and address balances of the connected block chain
|
||||||
- fast index search
|
- fast index search
|
||||||
@ -35,7 +181,7 @@ the rest of coins were implemented by the community.
|
|||||||
|
|
||||||
Testnets for some coins are also supported, for example:
|
Testnets for some coins are also supported, for example:
|
||||||
|
|
||||||
- Bitcoin Testnet, Bitcoin Cash Testnet, ZCash Testnet, Ethereum Testnets (Goerli, Sepolia)
|
- Bitcoin Testnet, Bitcoin Cash Testnet, ZCash Testnet, Ethereum Testnets (Sepolia, Holesky)
|
||||||
|
|
||||||
List of all implemented coins is in [the registry of ports](/docs/ports.md).
|
List of all implemented coins is in [the registry of ports](/docs/ports.md).
|
||||||
|
|
||||||
@ -74,3 +220,7 @@ Blockbook stores data the key-value store RocksDB. Database format is described
|
|||||||
## API
|
## API
|
||||||
|
|
||||||
Blockbook API is described [here](/docs/api.md).
|
Blockbook API is described [here](/docs/api.md).
|
||||||
|
|
||||||
|
## Environment variables
|
||||||
|
|
||||||
|
List of environment variables that affect Blockbook's behavior is [here](/docs/env.md).
|
||||||
|
|||||||
@ -62,7 +62,7 @@ func (w *Worker) RefetchInternalDataRoutine() {
|
|||||||
if block != nil {
|
if block != nil {
|
||||||
blockSpecificData, _ = block.CoinSpecificData.(*bchain.EthereumBlockSpecificData)
|
blockSpecificData, _ = block.CoinSpecificData.(*bchain.EthereumBlockSpecificData)
|
||||||
}
|
}
|
||||||
if err != nil || block == nil || blockSpecificData == nil || blockSpecificData.InternalDataError != "" {
|
if err != nil || block == nil || (blockSpecificData != nil && blockSpecificData.InternalDataError != "") {
|
||||||
glog.Errorf("Refetching internal data for %d %s, error %v, retrying", ie.Height, ie.Hash, err)
|
glog.Errorf("Refetching internal data for %d %s, error %v, retrying", ie.Height, ie.Hash, err)
|
||||||
// try for second time to fetch the data - the 2nd attempt after the first unsuccessful has many times higher probability of success
|
// try for second time to fetch the data - the 2nd attempt after the first unsuccessful has many times higher probability of success
|
||||||
// probably something to do with data preloaded to cache on the backend
|
// probably something to do with data preloaded to cache on the backend
|
||||||
|
|||||||
28
api/types.go
28
api/types.go
@ -208,9 +208,9 @@ type TokenTransfer struct {
|
|||||||
From string `json:"from"`
|
From string `json:"from"`
|
||||||
To string `json:"to"`
|
To string `json:"to"`
|
||||||
Contract string `json:"contract"`
|
Contract string `json:"contract"`
|
||||||
Name string `json:"name"`
|
Name string `json:"name,omitempty"`
|
||||||
Symbol string `json:"symbol"`
|
Symbol string `json:"symbol,omitempty"`
|
||||||
Decimals int `json:"decimals"`
|
Decimals int `json:"decimals,omitempty"`
|
||||||
Value *Amount `json:"value,omitempty"`
|
Value *Amount `json:"value,omitempty"`
|
||||||
MultiTokenValues []MultiTokenValue `json:"multiTokenValues,omitempty"`
|
MultiTokenValues []MultiTokenValue `json:"multiTokenValues,omitempty"`
|
||||||
}
|
}
|
||||||
@ -231,7 +231,11 @@ type EthereumSpecific struct {
|
|||||||
Nonce uint64 `json:"nonce"`
|
Nonce uint64 `json:"nonce"`
|
||||||
GasLimit *big.Int `json:"gasLimit"`
|
GasLimit *big.Int `json:"gasLimit"`
|
||||||
GasUsed *big.Int `json:"gasUsed,omitempty"`
|
GasUsed *big.Int `json:"gasUsed,omitempty"`
|
||||||
GasPrice *Amount `json:"gasPrice"`
|
GasPrice *Amount `json:"gasPrice,omitempty"`
|
||||||
|
L1Fee *big.Int `json:"l1Fee,omitempty"`
|
||||||
|
L1FeeScalar string `json:"l1FeeScalar,omitempty"`
|
||||||
|
L1GasPrice *Amount `json:"l1GasPrice,omitempty"`
|
||||||
|
L1GasUsed *big.Int `json:"l1GasUsed,omitempty"`
|
||||||
Data string `json:"data,omitempty"`
|
Data string `json:"data,omitempty"`
|
||||||
ParsedData *bchain.EthereumParsedInputData `json:"parsedData,omitempty"`
|
ParsedData *bchain.EthereumParsedInputData `json:"parsedData,omitempty"`
|
||||||
InternalTransfers []EthereumInternalTransfer `json:"internalTransfers,omitempty"`
|
InternalTransfers []EthereumInternalTransfer `json:"internalTransfers,omitempty"`
|
||||||
@ -316,6 +320,19 @@ type AddressFilter struct {
|
|||||||
OnlyConfirmed bool
|
OnlyConfirmed bool
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// StakingPool holds data about address participation in a staking pool contract
|
||||||
|
type StakingPool struct {
|
||||||
|
Contract string `json:"contract"`
|
||||||
|
Name string `json:"name"`
|
||||||
|
PendingBalance *Amount `json:"pendingBalance"`
|
||||||
|
PendingDepositedBalance *Amount `json:"pendingDepositedBalance"`
|
||||||
|
DepositedBalance *Amount `json:"depositedBalance"`
|
||||||
|
WithdrawTotalAmount *Amount `json:"withdrawTotalAmount"`
|
||||||
|
ClaimableAmount *Amount `json:"claimableAmount"`
|
||||||
|
RestakedReward *Amount `json:"restakedReward"`
|
||||||
|
AutocompoundBalance *Amount `json:"autocompoundBalance"`
|
||||||
|
}
|
||||||
|
|
||||||
// Address holds information about address and its transactions
|
// Address holds information about address and its transactions
|
||||||
type Address struct {
|
type Address struct {
|
||||||
Paging
|
Paging
|
||||||
@ -342,6 +359,7 @@ type Address struct {
|
|||||||
ContractInfo *bchain.ContractInfo `json:"contractInfo,omitempty"`
|
ContractInfo *bchain.ContractInfo `json:"contractInfo,omitempty"`
|
||||||
Erc20Contract *bchain.ContractInfo `json:"erc20Contract,omitempty"` // deprecated
|
Erc20Contract *bchain.ContractInfo `json:"erc20Contract,omitempty"` // deprecated
|
||||||
AddressAliases AddressAliasesMap `json:"addressAliases,omitempty"`
|
AddressAliases AddressAliasesMap `json:"addressAliases,omitempty"`
|
||||||
|
StakingPools []StakingPool `json:"stakingPools,omitempty"`
|
||||||
// helpers for explorer
|
// helpers for explorer
|
||||||
Filter string `json:"-"`
|
Filter string `json:"-"`
|
||||||
XPubAddresses map[string]struct{} `json:"-"`
|
XPubAddresses map[string]struct{} `json:"-"`
|
||||||
@ -485,6 +503,7 @@ type BlockRaw struct {
|
|||||||
// BlockbookInfo contains information about the running blockbook instance
|
// BlockbookInfo contains information about the running blockbook instance
|
||||||
type BlockbookInfo struct {
|
type BlockbookInfo struct {
|
||||||
Coin string `json:"coin"`
|
Coin string `json:"coin"`
|
||||||
|
Network string `json:"network"`
|
||||||
Host string `json:"host"`
|
Host string `json:"host"`
|
||||||
Version string `json:"version"`
|
Version string `json:"version"`
|
||||||
GitCommit string `json:"gitCommit"`
|
GitCommit string `json:"gitCommit"`
|
||||||
@ -504,6 +523,7 @@ type BlockbookInfo struct {
|
|||||||
CurrentFiatRatesTime *time.Time `json:"currentFiatRatesTime,omitempty"`
|
CurrentFiatRatesTime *time.Time `json:"currentFiatRatesTime,omitempty"`
|
||||||
HistoricalFiatRatesTime *time.Time `json:"historicalFiatRatesTime,omitempty"`
|
HistoricalFiatRatesTime *time.Time `json:"historicalFiatRatesTime,omitempty"`
|
||||||
HistoricalTokenFiatRatesTime *time.Time `json:"historicalTokenFiatRatesTime,omitempty"`
|
HistoricalTokenFiatRatesTime *time.Time `json:"historicalTokenFiatRatesTime,omitempty"`
|
||||||
|
SupportedStakingPools []string `json:"supportedStakingPools,omitempty"`
|
||||||
DbSizeFromColumns int64 `json:"dbSizeFromColumns,omitempty"`
|
DbSizeFromColumns int64 `json:"dbSizeFromColumns,omitempty"`
|
||||||
DbColumns []common.InternalStateColumn `json:"dbColumns,omitempty"`
|
DbColumns []common.InternalStateColumn `json:"dbColumns,omitempty"`
|
||||||
About string `json:"about"`
|
About string `json:"about"`
|
||||||
|
|||||||
@ -2,7 +2,8 @@ package api
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"math/big"
|
"math/big"
|
||||||
|
"encoding/json"
|
||||||
|
"strconv"
|
||||||
"github.com/trezor/blockbook/bchain"
|
"github.com/trezor/blockbook/bchain"
|
||||||
)
|
)
|
||||||
|
|
||||||
@ -21,9 +22,10 @@ type VinV1 struct {
|
|||||||
ScriptSig ScriptSigV1 `json:"scriptSig"`
|
ScriptSig ScriptSigV1 `json:"scriptSig"`
|
||||||
AddrDesc bchain.AddressDescriptor `json:"-"`
|
AddrDesc bchain.AddressDescriptor `json:"-"`
|
||||||
Addresses []string `json:"addresses"`
|
Addresses []string `json:"addresses"`
|
||||||
IsAddress bool `json:"-"`
|
IsAddress bool `json:"isAddress"`
|
||||||
Value string `json:"value"`
|
Value float64 `json:"value"`
|
||||||
ValueSat big.Int `json:"-"`
|
ValueSat big.Int `json:"valueSat"`
|
||||||
|
Coinbase string `json:"coinbase,omitempty"`
|
||||||
}
|
}
|
||||||
|
|
||||||
// ScriptPubKeyV1 is used for legacy api v1
|
// ScriptPubKeyV1 is used for legacy api v1
|
||||||
@ -32,14 +34,14 @@ type ScriptPubKeyV1 struct {
|
|||||||
Asm string `json:"asm,omitempty"`
|
Asm string `json:"asm,omitempty"`
|
||||||
AddrDesc bchain.AddressDescriptor `json:"-"`
|
AddrDesc bchain.AddressDescriptor `json:"-"`
|
||||||
Addresses []string `json:"addresses"`
|
Addresses []string `json:"addresses"`
|
||||||
IsAddress bool `json:"-"`
|
IsAddress bool `json:"isAddress"`
|
||||||
Type string `json:"type,omitempty"`
|
Type string `json:"type,omitempty"`
|
||||||
}
|
}
|
||||||
|
|
||||||
// VoutV1 is used for legacy api v1
|
// VoutV1 is used for legacy api v1
|
||||||
type VoutV1 struct {
|
type VoutV1 struct {
|
||||||
Value string `json:"value"`
|
Value float64 `json:"value"`
|
||||||
ValueSat big.Int `json:"-"`
|
ValueSat big.Int `json:"valueSat"`
|
||||||
N int `json:"n"`
|
N int `json:"n"`
|
||||||
ScriptPubKey ScriptPubKeyV1 `json:"scriptPubKey"`
|
ScriptPubKey ScriptPubKeyV1 `json:"scriptPubKey"`
|
||||||
Spent bool `json:"spent"`
|
Spent bool `json:"spent"`
|
||||||
@ -52,7 +54,7 @@ type VoutV1 struct {
|
|||||||
type TxV1 struct {
|
type TxV1 struct {
|
||||||
Txid string `json:"txid"`
|
Txid string `json:"txid"`
|
||||||
Version int32 `json:"version,omitempty"`
|
Version int32 `json:"version,omitempty"`
|
||||||
Locktime uint32 `json:"locktime,omitempty"`
|
Locktime uint32 `json:"locktime"`
|
||||||
Vin []VinV1 `json:"vin"`
|
Vin []VinV1 `json:"vin"`
|
||||||
Vout []VoutV1 `json:"vout"`
|
Vout []VoutV1 `json:"vout"`
|
||||||
Blockhash string `json:"blockhash,omitempty"`
|
Blockhash string `json:"blockhash,omitempty"`
|
||||||
@ -60,24 +62,29 @@ type TxV1 struct {
|
|||||||
Confirmations uint32 `json:"confirmations"`
|
Confirmations uint32 `json:"confirmations"`
|
||||||
Time int64 `json:"time,omitempty"`
|
Time int64 `json:"time,omitempty"`
|
||||||
Blocktime int64 `json:"blocktime"`
|
Blocktime int64 `json:"blocktime"`
|
||||||
ValueOut string `json:"valueOut"`
|
ValueOut float64 `json:"valueOut"`
|
||||||
ValueOutSat big.Int `json:"-"`
|
ValueOutSat big.Int `json:"valueOutSat"`
|
||||||
Size int `json:"size,omitempty"`
|
Size int `json:"size,omitempty"`
|
||||||
ValueIn string `json:"valueIn"`
|
ValueIn float64 `json:"valueIn"`
|
||||||
ValueInSat big.Int `json:"-"`
|
ValueInSat big.Int `json:"valueInSat"`
|
||||||
Fees string `json:"fees"`
|
Fees float64 `json:"fees"`
|
||||||
FeesSat big.Int `json:"-"`
|
FeesSat big.Int `json:"feesSat"`
|
||||||
Hex string `json:"hex"`
|
Hex string `json:"hex"`
|
||||||
|
FloData string `json:"floData,omitempty"`
|
||||||
}
|
}
|
||||||
|
|
||||||
// AddressV1 is used for legacy api v1
|
// AddressV1 is used for legacy api v1
|
||||||
type AddressV1 struct {
|
type AddressV1 struct {
|
||||||
Paging
|
Paging
|
||||||
AddrStr string `json:"addrStr"`
|
AddrStr string `json:"addrStr"`
|
||||||
Balance string `json:"balance"`
|
Balance float64 `json:"balance"`
|
||||||
TotalReceived string `json:"totalReceived"`
|
BalanceSat big.Int `json:"balanceSat"`
|
||||||
TotalSent string `json:"totalSent"`
|
TotalReceived float64 `json:"totalReceived"`
|
||||||
UnconfirmedBalance string `json:"unconfirmedBalance"`
|
TotalReceivedSat big.Int `json:"totalReceivedSat"`
|
||||||
|
TotalSent float64 `json:"totalSent"`
|
||||||
|
TotalSentSat big.Int `json:"totalSentSat"`
|
||||||
|
UnconfirmedBalance float64 `json:"unconfirmedBalance"`
|
||||||
|
UnconfirmedBalanceSat big.Int `json:"unconfirmedBalanceSat"`
|
||||||
UnconfirmedTxApperances int `json:"unconfirmedTxApperances"`
|
UnconfirmedTxApperances int `json:"unconfirmedTxApperances"`
|
||||||
TxApperances int `json:"txApperances"`
|
TxApperances int `json:"txApperances"`
|
||||||
Transactions []*TxV1 `json:"txs,omitempty"`
|
Transactions []*TxV1 `json:"txs,omitempty"`
|
||||||
@ -88,7 +95,7 @@ type AddressV1 struct {
|
|||||||
type AddressUtxoV1 struct {
|
type AddressUtxoV1 struct {
|
||||||
Txid string `json:"txid"`
|
Txid string `json:"txid"`
|
||||||
Vout uint32 `json:"vout"`
|
Vout uint32 `json:"vout"`
|
||||||
Amount string `json:"amount"`
|
Amount float64 `json:"amount"`
|
||||||
AmountSat big.Int `json:"satoshis"`
|
AmountSat big.Int `json:"satoshis"`
|
||||||
Height int `json:"height,omitempty"`
|
Height int `json:"height,omitempty"`
|
||||||
Confirmations int `json:"confirmations"`
|
Confirmations int `json:"confirmations"`
|
||||||
@ -102,6 +109,15 @@ type BlockV1 struct {
|
|||||||
Transactions []*TxV1 `json:"txs,omitempty"`
|
Transactions []*TxV1 `json:"txs,omitempty"`
|
||||||
}
|
}
|
||||||
|
|
||||||
|
type CoinSpecificDataV0 struct {
|
||||||
|
FloData string
|
||||||
|
}
|
||||||
|
|
||||||
|
func stringToFloat(f string) float64 {
|
||||||
|
s, _ := strconv.ParseFloat(f, 64)
|
||||||
|
return s
|
||||||
|
}
|
||||||
|
|
||||||
// TxToV1 converts Tx to TxV1
|
// TxToV1 converts Tx to TxV1
|
||||||
func (w *Worker) TxToV1(tx *Tx) *TxV1 {
|
func (w *Worker) TxToV1(tx *Tx) *TxV1 {
|
||||||
d := w.chainParser.AmountDecimals()
|
d := w.chainParser.AmountDecimals()
|
||||||
@ -119,9 +135,10 @@ func (w *Worker) TxToV1(tx *Tx) *TxV1 {
|
|||||||
IsAddress: v.IsAddress,
|
IsAddress: v.IsAddress,
|
||||||
Sequence: v.Sequence,
|
Sequence: v.Sequence,
|
||||||
Txid: v.Txid,
|
Txid: v.Txid,
|
||||||
Value: v.ValueSat.DecimalString(d),
|
Value: stringToFloat(v.ValueSat.DecimalString(d)),
|
||||||
ValueSat: v.ValueSat.AsBigInt(),
|
ValueSat: v.ValueSat.AsBigInt(),
|
||||||
Vout: v.Vout,
|
Vout: v.Vout,
|
||||||
|
Coinbase: v.Coinbase,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
voutV1 := make([]VoutV1, len(tx.Vout))
|
voutV1 := make([]VoutV1, len(tx.Vout))
|
||||||
@ -141,29 +158,39 @@ func (w *Worker) TxToV1(tx *Tx) *TxV1 {
|
|||||||
SpentHeight: v.SpentHeight,
|
SpentHeight: v.SpentHeight,
|
||||||
SpentIndex: v.SpentIndex,
|
SpentIndex: v.SpentIndex,
|
||||||
SpentTxID: v.SpentTxID,
|
SpentTxID: v.SpentTxID,
|
||||||
Value: v.ValueSat.DecimalString(d),
|
Value: stringToFloat(v.ValueSat.DecimalString(d)),
|
||||||
ValueSat: v.ValueSat.AsBigInt(),
|
ValueSat: v.ValueSat.AsBigInt(),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
//floData
|
||||||
|
var coinData CoinSpecificDataV0
|
||||||
|
// Notice the dereferencing asterisk *
|
||||||
|
err := json.Unmarshal(tx.CoinSpecificData, &coinData)
|
||||||
|
if err != nil {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
return &TxV1{
|
return &TxV1{
|
||||||
Blockhash: tx.Blockhash,
|
Blockhash: tx.Blockhash,
|
||||||
Blockheight: tx.Blockheight,
|
Blockheight: tx.Blockheight,
|
||||||
Blocktime: tx.Blocktime,
|
Blocktime: tx.Blocktime,
|
||||||
Confirmations: tx.Confirmations,
|
Confirmations: tx.Confirmations,
|
||||||
Fees: tx.FeesSat.DecimalString(d),
|
Fees: stringToFloat(tx.FeesSat.DecimalString(d)),
|
||||||
FeesSat: tx.FeesSat.AsBigInt(),
|
FeesSat: tx.FeesSat.AsBigInt(),
|
||||||
Hex: tx.Hex,
|
Hex: tx.Hex,
|
||||||
Locktime: tx.Locktime,
|
Locktime: tx.Locktime,
|
||||||
Size: tx.Size,
|
Size: tx.Size,
|
||||||
Time: tx.Blocktime,
|
Time: tx.Blocktime,
|
||||||
Txid: tx.Txid,
|
Txid: tx.Txid,
|
||||||
ValueIn: tx.ValueInSat.DecimalString(d),
|
ValueIn: stringToFloat(tx.ValueInSat.DecimalString(d)),
|
||||||
ValueInSat: tx.ValueInSat.AsBigInt(),
|
ValueInSat: tx.ValueInSat.AsBigInt(),
|
||||||
ValueOut: tx.ValueOutSat.DecimalString(d),
|
ValueOut: stringToFloat(tx.ValueOutSat.DecimalString(d)),
|
||||||
ValueOutSat: tx.ValueOutSat.AsBigInt(),
|
ValueOutSat: tx.ValueOutSat.AsBigInt(),
|
||||||
Version: tx.Version,
|
Version: tx.Version,
|
||||||
Vin: vinV1,
|
Vin: vinV1,
|
||||||
Vout: voutV1,
|
Vout: voutV1,
|
||||||
|
FloData: coinData.FloData, //(tx.CoinSpecificData).FloData
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -180,14 +207,18 @@ func (w *Worker) AddressToV1(a *Address) *AddressV1 {
|
|||||||
d := w.chainParser.AmountDecimals()
|
d := w.chainParser.AmountDecimals()
|
||||||
return &AddressV1{
|
return &AddressV1{
|
||||||
AddrStr: a.AddrStr,
|
AddrStr: a.AddrStr,
|
||||||
Balance: a.BalanceSat.DecimalString(d),
|
Balance: stringToFloat(a.BalanceSat.DecimalString(d)),
|
||||||
|
BalanceSat: a.BalanceSat.AsBigInt(),
|
||||||
Paging: a.Paging,
|
Paging: a.Paging,
|
||||||
TotalReceived: a.TotalReceivedSat.DecimalString(d),
|
TotalReceived: stringToFloat(a.TotalReceivedSat.DecimalString(d)),
|
||||||
TotalSent: a.TotalSentSat.DecimalString(d),
|
TotalReceivedSat: a.TotalReceivedSat.AsBigInt(),
|
||||||
|
TotalSent: stringToFloat(a.TotalSentSat.DecimalString(d)),
|
||||||
|
TotalSentSat: a.TotalSentSat.AsBigInt(),
|
||||||
Transactions: w.transactionsToV1(a.Transactions),
|
Transactions: w.transactionsToV1(a.Transactions),
|
||||||
TxApperances: a.Txs,
|
TxApperances: a.Txs,
|
||||||
Txids: a.Txids,
|
Txids: a.Txids,
|
||||||
UnconfirmedBalance: a.UnconfirmedBalanceSat.DecimalString(d),
|
UnconfirmedBalance: stringToFloat(a.UnconfirmedBalanceSat.DecimalString(d)),
|
||||||
|
UnconfirmedBalanceSat: a.UnconfirmedBalanceSat.AsBigInt(),
|
||||||
UnconfirmedTxApperances: a.UnconfirmedTxs,
|
UnconfirmedTxApperances: a.UnconfirmedTxs,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -200,7 +231,7 @@ func (w *Worker) AddressUtxoToV1(au Utxos) []AddressUtxoV1 {
|
|||||||
utxo := &au[i]
|
utxo := &au[i]
|
||||||
v1[i] = AddressUtxoV1{
|
v1[i] = AddressUtxoV1{
|
||||||
AmountSat: utxo.AmountSat.AsBigInt(),
|
AmountSat: utxo.AmountSat.AsBigInt(),
|
||||||
Amount: utxo.AmountSat.DecimalString(d),
|
Amount: stringToFloat(utxo.AmountSat.DecimalString(d)),
|
||||||
Confirmations: utxo.Confirmations,
|
Confirmations: utxo.Confirmations,
|
||||||
Height: utxo.Height,
|
Height: utxo.Height,
|
||||||
Txid: utxo.Txid,
|
Txid: utxo.Txid,
|
||||||
|
|||||||
239
api/worker.go
239
api/worker.go
@ -36,6 +36,9 @@ type Worker struct {
|
|||||||
metrics *common.Metrics
|
metrics *common.Metrics
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// contractInfoCache is a temporary cache of contract information for ethereum token transfers
|
||||||
|
type contractInfoCache = map[string]*bchain.ContractInfo
|
||||||
|
|
||||||
// NewWorker creates new api worker
|
// NewWorker creates new api worker
|
||||||
func NewWorker(db *db.RocksDB, chain bchain.BlockChain, mempool bchain.Mempool, txCache *db.TxCache, metrics *common.Metrics, is *common.InternalState, fiatRates *fiat.FiatRates) (*Worker, error) {
|
func NewWorker(db *db.RocksDB, chain bchain.BlockChain, mempool bchain.Mempool, txCache *db.TxCache, metrics *common.Metrics, is *common.InternalState, fiatRates *fiat.FiatRates) (*Worker, error) {
|
||||||
w := &Worker{
|
w := &Worker{
|
||||||
@ -169,9 +172,18 @@ func (w *Worker) getAddressAliases(addresses map[string]struct{}) AddressAliases
|
|||||||
}
|
}
|
||||||
for a := range addresses {
|
for a := range addresses {
|
||||||
if w.chainType == bchain.ChainEthereumType {
|
if w.chainType == bchain.ChainEthereumType {
|
||||||
ci, err := w.db.GetContractInfoForAddress(a)
|
addrDesc, err := w.chainParser.GetAddrDescFromAddress(a)
|
||||||
if err == nil && ci != nil && ci.Name != "" {
|
if err != nil || addrDesc == nil {
|
||||||
aliases[a] = AddressAlias{Type: "Contract", Alias: ci.Name}
|
continue
|
||||||
|
}
|
||||||
|
ci, err := w.db.GetContractInfo(addrDesc, bchain.UnknownTokenType)
|
||||||
|
if err == nil && ci != nil {
|
||||||
|
if ci.Type == bchain.UnhandledTokenType {
|
||||||
|
ci, _, err = w.getContractDescriptorInfo(addrDesc, bchain.UnknownTokenType)
|
||||||
|
}
|
||||||
|
if err == nil && ci != nil && ci.Name != "" {
|
||||||
|
aliases[a] = AddressAlias{Type: "Contract", Alias: ci.Name}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
n := w.db.GetAddressAlias(a)
|
n := w.db.GetAddressAlias(a)
|
||||||
@ -187,7 +199,7 @@ func (w *Worker) getAddressAliases(addresses map[string]struct{}) AddressAliases
|
|||||||
// GetTransaction reads transaction data from txid
|
// GetTransaction reads transaction data from txid
|
||||||
func (w *Worker) GetTransaction(txid string, spendingTxs bool, specificJSON bool) (*Tx, error) {
|
func (w *Worker) GetTransaction(txid string, spendingTxs bool, specificJSON bool) (*Tx, error) {
|
||||||
addresses := w.newAddressesMapForAliases()
|
addresses := w.newAddressesMapForAliases()
|
||||||
tx, err := w.getTransaction(txid, spendingTxs, specificJSON, addresses)
|
tx, err := w.getTransaction(txid, spendingTxs, /*specificJSON*/ true, addresses)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
@ -195,6 +207,11 @@ func (w *Worker) GetTransaction(txid string, spendingTxs bool, specificJSON bool
|
|||||||
return tx, nil
|
return tx, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// GetRawTransaction gets raw transaction data in hex format from txid
|
||||||
|
func (w *Worker) GetRawTransaction(txid string) (string, error) {
|
||||||
|
return w.chain.EthereumTypeGetRawTransaction(txid)
|
||||||
|
}
|
||||||
|
|
||||||
// getTransaction reads transaction data from txid
|
// getTransaction reads transaction data from txid
|
||||||
func (w *Worker) getTransaction(txid string, spendingTxs bool, specificJSON bool, addresses map[string]struct{}) (*Tx, error) {
|
func (w *Worker) getTransaction(txid string, spendingTxs bool, specificJSON bool, addresses map[string]struct{}) (*Tx, error) {
|
||||||
bchainTx, height, err := w.txCache.GetTransaction(txid)
|
bchainTx, height, err := w.txCache.GetTransaction(txid)
|
||||||
@ -426,18 +443,25 @@ func (w *Worker) getTransactionFromBchainTx(bchainTx *bchain.Tx, height int, spe
|
|||||||
// mempool txs do not have fees yet
|
// mempool txs do not have fees yet
|
||||||
if ethTxData.GasUsed != nil {
|
if ethTxData.GasUsed != nil {
|
||||||
feesSat.Mul(ethTxData.GasPrice, ethTxData.GasUsed)
|
feesSat.Mul(ethTxData.GasPrice, ethTxData.GasUsed)
|
||||||
|
if ethTxData.L1Fee != nil {
|
||||||
|
feesSat.Add(&feesSat, ethTxData.L1Fee)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
if len(bchainTx.Vout) > 0 {
|
if len(bchainTx.Vout) > 0 {
|
||||||
valOutSat = bchainTx.Vout[0].ValueSat
|
valOutSat = bchainTx.Vout[0].ValueSat
|
||||||
}
|
}
|
||||||
ethSpecific = &EthereumSpecific{
|
ethSpecific = &EthereumSpecific{
|
||||||
GasLimit: ethTxData.GasLimit,
|
GasLimit: ethTxData.GasLimit,
|
||||||
GasPrice: (*Amount)(ethTxData.GasPrice),
|
GasPrice: (*Amount)(ethTxData.GasPrice),
|
||||||
GasUsed: ethTxData.GasUsed,
|
GasUsed: ethTxData.GasUsed,
|
||||||
Nonce: ethTxData.Nonce,
|
L1Fee: ethTxData.L1Fee,
|
||||||
Status: ethTxData.Status,
|
L1FeeScalar: ethTxData.L1FeeScalar,
|
||||||
Data: ethTxData.Data,
|
L1GasPrice: (*Amount)(ethTxData.L1GasPrice),
|
||||||
ParsedData: parsedInputData,
|
L1GasUsed: ethTxData.L1GasUsed,
|
||||||
|
Nonce: ethTxData.Nonce,
|
||||||
|
Status: ethTxData.Status,
|
||||||
|
Data: ethTxData.Data,
|
||||||
|
ParsedData: parsedInputData,
|
||||||
}
|
}
|
||||||
if internalData != nil {
|
if internalData != nil {
|
||||||
ethSpecific.Type = internalData.Type
|
ethSpecific.Type = internalData.Type
|
||||||
@ -598,7 +622,7 @@ func (w *Worker) GetTransactionFromMempoolTx(mempoolTx *bchain.MempoolTx) (*Tx,
|
|||||||
return r, nil
|
return r, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (w *Worker) getContractInfo(contract string, typeFromContext bchain.TokenTypeName) (*bchain.ContractInfo, bool, error) {
|
func (w *Worker) GetContractInfo(contract string, typeFromContext bchain.TokenTypeName) (*bchain.ContractInfo, bool, error) {
|
||||||
cd, err := w.chainParser.GetAddrDescFromAddress(contract)
|
cd, err := w.chainParser.GetAddrDescFromAddress(contract)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, false, err
|
return nil, false, err
|
||||||
@ -638,7 +662,7 @@ func (w *Worker) getContractDescriptorInfo(cd bchain.AddressDescriptor, typeFrom
|
|||||||
glog.Errorf("StoreContractInfo error %v, contract %v", err, cd)
|
glog.Errorf("StoreContractInfo error %v, contract %v", err, cd)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} else if (len(contractInfo.Name) > 0 && contractInfo.Name[0] == 0) || (len(contractInfo.Symbol) > 0 && contractInfo.Symbol[0] == 0) {
|
} else if (contractInfo.Type == bchain.UnhandledTokenType || len(contractInfo.Name) > 0 && contractInfo.Name[0] == 0) || (len(contractInfo.Symbol) > 0 && contractInfo.Symbol[0] == 0) {
|
||||||
// fix contract name/symbol that was parsed as a string consisting of zeroes
|
// fix contract name/symbol that was parsed as a string consisting of zeroes
|
||||||
blockchainContractInfo, err := w.chain.GetContractInfo(cd)
|
blockchainContractInfo, err := w.chain.GetContractInfo(cd)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
@ -657,6 +681,10 @@ func (w *Worker) getContractDescriptorInfo(cd bchain.AddressDescriptor, typeFrom
|
|||||||
if blockchainContractInfo != nil {
|
if blockchainContractInfo != nil {
|
||||||
contractInfo.Decimals = blockchainContractInfo.Decimals
|
contractInfo.Decimals = blockchainContractInfo.Decimals
|
||||||
}
|
}
|
||||||
|
if contractInfo.Type == bchain.UnhandledTokenType {
|
||||||
|
glog.Infof("Contract %v %v [%s] handled", cd, typeFromContext, contractInfo.Name)
|
||||||
|
contractInfo.Type = typeFromContext
|
||||||
|
}
|
||||||
if err = w.db.StoreContractInfo(contractInfo); err != nil {
|
if err = w.db.StoreContractInfo(contractInfo); err != nil {
|
||||||
glog.Errorf("StoreContractInfo error %v, contract %v", err, cd)
|
glog.Errorf("StoreContractInfo error %v, contract %v", err, cd)
|
||||||
}
|
}
|
||||||
@ -666,39 +694,49 @@ func (w *Worker) getContractDescriptorInfo(cd bchain.AddressDescriptor, typeFrom
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (w *Worker) getEthereumTokensTransfers(transfers bchain.TokenTransfers, addresses map[string]struct{}) []TokenTransfer {
|
func (w *Worker) getEthereumTokensTransfers(transfers bchain.TokenTransfers, addresses map[string]struct{}) []TokenTransfer {
|
||||||
sort.Sort(transfers)
|
|
||||||
tokens := make([]TokenTransfer, len(transfers))
|
tokens := make([]TokenTransfer, len(transfers))
|
||||||
for i := range transfers {
|
if len(transfers) > 0 {
|
||||||
t := transfers[i]
|
sort.Sort(transfers)
|
||||||
typeName := bchain.EthereumTokenTypeMap[t.Type]
|
contractCache := make(contractInfoCache)
|
||||||
contractInfo, _, err := w.getContractInfo(t.Contract, typeName)
|
for i := range transfers {
|
||||||
if err != nil {
|
t := transfers[i]
|
||||||
glog.Errorf("getContractInfo error %v, contract %v", err, t.Contract)
|
typeName := bchain.EthereumTokenTypeMap[t.Type]
|
||||||
continue
|
var contractInfo *bchain.ContractInfo
|
||||||
}
|
if info, ok := contractCache[t.Contract]; ok {
|
||||||
var value *Amount
|
contractInfo = info
|
||||||
var values []MultiTokenValue
|
} else {
|
||||||
if t.Type == bchain.MultiToken {
|
info, _, err := w.GetContractInfo(t.Contract, typeName)
|
||||||
values = make([]MultiTokenValue, len(t.MultiTokenValues))
|
if err != nil {
|
||||||
for j := range values {
|
glog.Errorf("getContractInfo error %v, contract %v", err, t.Contract)
|
||||||
values[j].Id = (*Amount)(&t.MultiTokenValues[j].Id)
|
continue
|
||||||
values[j].Value = (*Amount)(&t.MultiTokenValues[j].Value)
|
}
|
||||||
|
contractInfo = info
|
||||||
|
contractCache[t.Contract] = info
|
||||||
|
}
|
||||||
|
var value *Amount
|
||||||
|
var values []MultiTokenValue
|
||||||
|
if t.Type == bchain.MultiToken {
|
||||||
|
values = make([]MultiTokenValue, len(t.MultiTokenValues))
|
||||||
|
for j := range values {
|
||||||
|
values[j].Id = (*Amount)(&t.MultiTokenValues[j].Id)
|
||||||
|
values[j].Value = (*Amount)(&t.MultiTokenValues[j].Value)
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
value = (*Amount)(&t.Value)
|
||||||
|
}
|
||||||
|
aggregateAddress(addresses, t.From)
|
||||||
|
aggregateAddress(addresses, t.To)
|
||||||
|
tokens[i] = TokenTransfer{
|
||||||
|
Type: typeName,
|
||||||
|
Contract: t.Contract,
|
||||||
|
From: t.From,
|
||||||
|
To: t.To,
|
||||||
|
Value: value,
|
||||||
|
MultiTokenValues: values,
|
||||||
|
Decimals: contractInfo.Decimals,
|
||||||
|
Name: contractInfo.Name,
|
||||||
|
Symbol: contractInfo.Symbol,
|
||||||
}
|
}
|
||||||
} else {
|
|
||||||
value = (*Amount)(&t.Value)
|
|
||||||
}
|
|
||||||
aggregateAddress(addresses, t.From)
|
|
||||||
aggregateAddress(addresses, t.To)
|
|
||||||
tokens[i] = TokenTransfer{
|
|
||||||
Type: typeName,
|
|
||||||
Contract: t.Contract,
|
|
||||||
From: t.From,
|
|
||||||
To: t.To,
|
|
||||||
Value: value,
|
|
||||||
MultiTokenValues: values,
|
|
||||||
Decimals: contractInfo.Decimals,
|
|
||||||
Name: contractInfo.Name,
|
|
||||||
Symbol: contractInfo.Symbol,
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return tokens
|
return tokens
|
||||||
@ -1045,6 +1083,7 @@ type ethereumTypeAddressData struct {
|
|||||||
totalResults int
|
totalResults int
|
||||||
tokensBaseValue float64
|
tokensBaseValue float64
|
||||||
tokensSecondaryValue float64
|
tokensSecondaryValue float64
|
||||||
|
stakingPools []StakingPool
|
||||||
}
|
}
|
||||||
|
|
||||||
func (w *Worker) getEthereumTypeAddressBalances(addrDesc bchain.AddressDescriptor, details AccountDetails, filter *AddressFilter, secondaryCoin string) (*db.AddrBalance, *ethereumTypeAddressData, error) {
|
func (w *Worker) getEthereumTypeAddressBalances(addrDesc bchain.AddressDescriptor, details AccountDetails, filter *AddressFilter, secondaryCoin string) (*db.AddrBalance, *ethereumTypeAddressData, error) {
|
||||||
@ -1103,10 +1142,16 @@ func (w *Worker) getEthereumTypeAddressBalances(addrDesc bchain.AddressDescripto
|
|||||||
d.tokens = d.tokens[:j]
|
d.tokens = d.tokens[:j]
|
||||||
sort.Sort(d.tokens)
|
sort.Sort(d.tokens)
|
||||||
}
|
}
|
||||||
d.contractInfo, err = w.db.GetContractInfo(addrDesc, "")
|
d.contractInfo, err = w.db.GetContractInfo(addrDesc, bchain.UnknownTokenType)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, nil, err
|
return nil, nil, err
|
||||||
}
|
}
|
||||||
|
if d.contractInfo != nil && d.contractInfo.Type == bchain.UnhandledTokenType {
|
||||||
|
d.contractInfo, _, err = w.getContractDescriptorInfo(addrDesc, bchain.UnknownTokenType)
|
||||||
|
if err != nil {
|
||||||
|
return nil, nil, err
|
||||||
|
}
|
||||||
|
}
|
||||||
if filter.FromHeight == 0 && filter.ToHeight == 0 {
|
if filter.FromHeight == 0 && filter.ToHeight == 0 {
|
||||||
// compute total results for paging
|
// compute total results for paging
|
||||||
if filter.Vout == AddressFilterVoutOff {
|
if filter.Vout == AddressFilterVoutOff {
|
||||||
@ -1144,9 +1189,41 @@ func (w *Worker) getEthereumTypeAddressBalances(addrDesc bchain.AddressDescripto
|
|||||||
filter.Vout = AddressFilterVoutQueryNotNecessary
|
filter.Vout = AddressFilterVoutQueryNotNecessary
|
||||||
d.totalResults = -1
|
d.totalResults = -1
|
||||||
}
|
}
|
||||||
|
// if staking pool enabled, fetch the staking pool details
|
||||||
|
if details >= AccountDetailsTokenBalances {
|
||||||
|
d.stakingPools, err = w.getStakingPoolsData(addrDesc)
|
||||||
|
if err != nil {
|
||||||
|
return nil, nil, err
|
||||||
|
}
|
||||||
|
}
|
||||||
return ba, &d, nil
|
return ba, &d, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (w *Worker) getStakingPoolsData(addrDesc bchain.AddressDescriptor) ([]StakingPool, error) {
|
||||||
|
var pools []StakingPool
|
||||||
|
if len(w.chain.EthereumTypeGetSupportedStakingPools()) > 0 {
|
||||||
|
sp, err := w.chain.EthereumTypeGetStakingPoolsData(addrDesc)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
for i := range sp {
|
||||||
|
p := &sp[i]
|
||||||
|
pools = append(pools, StakingPool{
|
||||||
|
Contract: p.Contract,
|
||||||
|
Name: p.Name,
|
||||||
|
PendingBalance: (*Amount)(&p.PendingBalance),
|
||||||
|
PendingDepositedBalance: (*Amount)(&p.PendingDepositedBalance),
|
||||||
|
DepositedBalance: (*Amount)(&p.DepositedBalance),
|
||||||
|
WithdrawTotalAmount: (*Amount)(&p.WithdrawTotalAmount),
|
||||||
|
ClaimableAmount: (*Amount)(&p.ClaimableAmount),
|
||||||
|
RestakedReward: (*Amount)(&p.RestakedReward),
|
||||||
|
AutocompoundBalance: (*Amount)(&p.AutocompoundBalance),
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return pools, nil
|
||||||
|
}
|
||||||
|
|
||||||
func (w *Worker) txFromTxid(txid string, bestHeight uint32, option AccountDetails, blockInfo *db.BlockInfo, addresses map[string]struct{}) (*Tx, error) {
|
func (w *Worker) txFromTxid(txid string, bestHeight uint32, option AccountDetails, blockInfo *db.BlockInfo, addresses map[string]struct{}) (*Tx, error) {
|
||||||
var tx *Tx
|
var tx *Tx
|
||||||
var err error
|
var err error
|
||||||
@ -1159,7 +1236,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, false, addresses)
|
tx, err = w.getTransaction(txid, false, true, addresses)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, errors.Annotatef(err, "getTransaction %v", txid)
|
return nil, errors.Annotatef(err, "getTransaction %v", txid)
|
||||||
}
|
}
|
||||||
@ -1178,7 +1255,7 @@ func (w *Worker) txFromTxid(txid string, bestHeight uint32, option AccountDetail
|
|||||||
tx = w.txFromTxAddress(txid, ta, blockInfo, bestHeight, addresses)
|
tx = w.txFromTxAddress(txid, ta, blockInfo, bestHeight, addresses)
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
tx, err = w.getTransaction(txid, false, false, addresses)
|
tx, err = w.getTransaction(txid, false, true, addresses)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, errors.Annotatef(err, "getTransaction %v", txid)
|
return nil, errors.Annotatef(err, "getTransaction %v", txid)
|
||||||
}
|
}
|
||||||
@ -1337,7 +1414,7 @@ func (w *Worker) GetAddress(address string, page int, txsOnPage int, option Acco
|
|||||||
if option == AccountDetailsTxidHistory {
|
if option == AccountDetailsTxidHistory {
|
||||||
txids = append(txids, txid)
|
txids = append(txids, txid)
|
||||||
} else {
|
} else {
|
||||||
tx, err := w.txFromTxid(txid, bestheight, option, nil, addresses)
|
tx, err := w.txFromTxid(txid, bestheight, AccountDetailsTxHistory, nil, addresses)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
@ -1388,12 +1465,13 @@ func (w *Worker) GetAddress(address string, page int, txsOnPage int, option Acco
|
|||||||
ContractInfo: ed.contractInfo,
|
ContractInfo: ed.contractInfo,
|
||||||
Nonce: ed.nonce,
|
Nonce: ed.nonce,
|
||||||
AddressAliases: w.getAddressAliases(addresses),
|
AddressAliases: w.getAddressAliases(addresses),
|
||||||
|
StakingPools: ed.stakingPools,
|
||||||
}
|
}
|
||||||
// keep address backward compatible, set deprecated Erc20Contract value if ERC20 token
|
// keep address backward compatible, set deprecated Erc20Contract value if ERC20 token
|
||||||
if ed.contractInfo != nil && ed.contractInfo.Type == bchain.ERC20TokenType {
|
if ed.contractInfo != nil && ed.contractInfo.Type == bchain.ERC20TokenType {
|
||||||
r.Erc20Contract = ed.contractInfo
|
r.Erc20Contract = ed.contractInfo
|
||||||
}
|
}
|
||||||
glog.Info("GetAddress ", address, ", ", time.Since(start))
|
glog.Info("GetAddress-", option, " ", address, ", ", time.Since(start))
|
||||||
return r, nil
|
return r, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1603,6 +1681,17 @@ func (w *Worker) GetBalanceHistory(address string, fromTimestamp, toTimestamp in
|
|||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
// do not get balance history for contracts
|
||||||
|
if w.chainType == bchain.ChainEthereumType {
|
||||||
|
ci, err := w.db.GetContractInfo(addrDesc, bchain.UnknownTokenType)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
if ci != nil {
|
||||||
|
glog.Info("GetBalanceHistory ", address, " is a contract, skipping")
|
||||||
|
return nil, NewAPIError("GetBalanceHistory for a contract not allowed", true)
|
||||||
|
}
|
||||||
|
}
|
||||||
fromUnix, fromHeight, toUnix, toHeight := w.balanceHistoryHeightsFromTo(fromTimestamp, toTimestamp)
|
fromUnix, fromHeight, toUnix, toHeight := w.balanceHistoryHeightsFromTo(fromTimestamp, toTimestamp)
|
||||||
if fromHeight >= toHeight {
|
if fromHeight >= toHeight {
|
||||||
return bhs, nil
|
return bhs, nil
|
||||||
@ -1880,7 +1969,11 @@ func (w *Worker) GetCurrentFiatRates(currencies []string, token string) (*FiatTi
|
|||||||
ticker := w.fiatRates.GetCurrentTicker(vsCurrency, token)
|
ticker := w.fiatRates.GetCurrentTicker(vsCurrency, token)
|
||||||
var err error
|
var err error
|
||||||
if ticker == nil {
|
if ticker == nil {
|
||||||
ticker, err = w.db.FiatRatesFindLastTicker(vsCurrency, token)
|
if token == "" {
|
||||||
|
// fallback - get last fiat rate from db if not in current ticker
|
||||||
|
// not for tokens, many tokens do not have fiat rates at all and it is very costly to do DB search for token without an exchange rate
|
||||||
|
ticker, err = w.db.FiatRatesFindLastTicker(vsCurrency, token)
|
||||||
|
}
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, NewAPIError(fmt.Sprintf("Error finding ticker: %v", err), false)
|
return nil, NewAPIError(fmt.Sprintf("Error finding ticker: %v", err), false)
|
||||||
} else if ticker == nil {
|
} else if ticker == nil {
|
||||||
@ -2146,7 +2239,7 @@ func (w *Worker) GetBlock(bid string, page int, txsOnPage int) (*Block, error) {
|
|||||||
txi := 0
|
txi := 0
|
||||||
addresses := w.newAddressesMapForAliases()
|
addresses := w.newAddressesMapForAliases()
|
||||||
for i := from; i < to; i++ {
|
for i := from; i < to; i++ {
|
||||||
txs[txi], err = w.txFromTxid(bi.Txids[i], bestheight, AccountDetailsTxHistoryLight, dbi, addresses)
|
txs[txi], err = w.txFromTxid(bi.Txids[i], bestheight, AccountDetailsTxHistory, dbi, addresses)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
@ -2200,6 +2293,48 @@ func (w *Worker) GetBlockRaw(bid string) (*BlockRaw, error) {
|
|||||||
return &BlockRaw{Hex: hex}, err
|
return &BlockRaw{Hex: hex}, err
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// GetBlockFiltersBatch returns array of block filter data in the format ["height:hash:filter",...] if blocks greater than bestKnownBlockHash
|
||||||
|
func (w *Worker) GetBlockFiltersBatch(bestKnownBlockHash string, pageSize int) ([]string, error) {
|
||||||
|
if w.is.BlockGolombFilterP == 0 {
|
||||||
|
return nil, NewAPIError("Not supported", true)
|
||||||
|
}
|
||||||
|
if pageSize > 10000 {
|
||||||
|
return nil, NewAPIError("pageSize max 10000", true)
|
||||||
|
}
|
||||||
|
if pageSize <= 0 {
|
||||||
|
pageSize = 1000
|
||||||
|
}
|
||||||
|
bi, err := w.chain.GetBlockInfo(bestKnownBlockHash)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
bestHeight, _, err := w.db.GetBestBlock()
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
from := bi.Height + 1
|
||||||
|
to := bestHeight + 1
|
||||||
|
if from >= to {
|
||||||
|
return []string{}, nil
|
||||||
|
}
|
||||||
|
if to-from > uint32(pageSize) {
|
||||||
|
to = from + uint32(pageSize)
|
||||||
|
}
|
||||||
|
r := make([]string, 0, to-from)
|
||||||
|
for i := from; i < to; i++ {
|
||||||
|
blockHash, err := w.db.GetBlockHash(uint32(i))
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
blockFilter, err := w.db.GetBlockFilter(blockHash)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
r = append(r, fmt.Sprintf("%d:%s:%s", i, blockHash, blockFilter))
|
||||||
|
}
|
||||||
|
return r, err
|
||||||
|
}
|
||||||
|
|
||||||
// ComputeFeeStats computes fee distribution in defined blocks and logs them to log
|
// ComputeFeeStats computes fee distribution in defined blocks and logs them to log
|
||||||
func (w *Worker) ComputeFeeStats(blockFrom, blockTo int, stopCompute chan os.Signal) error {
|
func (w *Worker) ComputeFeeStats(blockFrom, blockTo int, stopCompute chan os.Signal) error {
|
||||||
bestheight, _, err := w.db.GetBestBlock()
|
bestheight, _, err := w.db.GetBestBlock()
|
||||||
@ -2302,6 +2437,7 @@ func (w *Worker) GetSystemInfo(internal bool) (*SystemInfo, error) {
|
|||||||
}
|
}
|
||||||
blockbookInfo := &BlockbookInfo{
|
blockbookInfo := &BlockbookInfo{
|
||||||
Coin: w.is.Coin,
|
Coin: w.is.Coin,
|
||||||
|
Network: w.is.GetNetwork(),
|
||||||
Host: w.is.Host,
|
Host: w.is.Host,
|
||||||
Version: vi.Version,
|
Version: vi.Version,
|
||||||
GitCommit: vi.GitCommit,
|
GitCommit: vi.GitCommit,
|
||||||
@ -2320,6 +2456,7 @@ func (w *Worker) GetSystemInfo(internal bool) (*SystemInfo, error) {
|
|||||||
CurrentFiatRatesTime: nonZeroTime(currentFiatRatesTime),
|
CurrentFiatRatesTime: nonZeroTime(currentFiatRatesTime),
|
||||||
HistoricalFiatRatesTime: nonZeroTime(w.is.HistoricalFiatRatesTime),
|
HistoricalFiatRatesTime: nonZeroTime(w.is.HistoricalFiatRatesTime),
|
||||||
HistoricalTokenFiatRatesTime: nonZeroTime(w.is.HistoricalTokenFiatRatesTime),
|
HistoricalTokenFiatRatesTime: nonZeroTime(w.is.HistoricalTokenFiatRatesTime),
|
||||||
|
SupportedStakingPools: w.chain.EthereumTypeGetSupportedStakingPools(),
|
||||||
DbSize: w.db.DatabaseSizeOnDisk(),
|
DbSize: w.db.DatabaseSizeOnDisk(),
|
||||||
DbSizeFromColumns: internalDBSize,
|
DbSizeFromColumns: internalDBSize,
|
||||||
DbColumns: columnStats,
|
DbColumns: columnStats,
|
||||||
|
|||||||
@ -556,7 +556,7 @@ func (w *Worker) GetXpubAddress(xpub string, page int, txsOnPage int, option Acc
|
|||||||
usedTokens++
|
usedTokens++
|
||||||
}
|
}
|
||||||
if option > AccountDetailsBasic {
|
if option > AccountDetailsBasic {
|
||||||
token := w.tokenFromXpubAddress(data, ad, ci, i, option)
|
token := w.tokenFromXpubAddress(data, ad, int(xd.ChangeIndexes[ci]), i, option)
|
||||||
if filter.TokensToReturn == TokensToReturnDerived ||
|
if filter.TokensToReturn == TokensToReturnDerived ||
|
||||||
filter.TokensToReturn == TokensToReturnUsed && ad.balance != nil ||
|
filter.TokensToReturn == TokensToReturnUsed && ad.balance != nil ||
|
||||||
filter.TokensToReturn == TokensToReturnNonzeroBalance && ad.balance != nil && !IsZeroBigInt(&ad.balance.BalanceSat) {
|
filter.TokensToReturn == TokensToReturnNonzeroBalance && ad.balance != nil && !IsZeroBigInt(&ad.balance.BalanceSat) {
|
||||||
|
|||||||
@ -41,30 +41,47 @@ func (b *BaseChain) GetMempoolEntry(txid string) (*MempoolEntry, error) {
|
|||||||
|
|
||||||
// EthereumTypeGetBalance is not supported
|
// EthereumTypeGetBalance is not supported
|
||||||
func (b *BaseChain) EthereumTypeGetBalance(addrDesc AddressDescriptor) (*big.Int, error) {
|
func (b *BaseChain) EthereumTypeGetBalance(addrDesc AddressDescriptor) (*big.Int, error) {
|
||||||
return nil, errors.New("Not supported")
|
return nil, errors.New("not supported")
|
||||||
}
|
}
|
||||||
|
|
||||||
// EthereumTypeGetNonce is not supported
|
// EthereumTypeGetNonce is not supported
|
||||||
func (b *BaseChain) EthereumTypeGetNonce(addrDesc AddressDescriptor) (uint64, error) {
|
func (b *BaseChain) EthereumTypeGetNonce(addrDesc AddressDescriptor) (uint64, error) {
|
||||||
return 0, errors.New("Not supported")
|
return 0, errors.New("not supported")
|
||||||
}
|
}
|
||||||
|
|
||||||
// EthereumTypeEstimateGas is not supported
|
// EthereumTypeEstimateGas is not supported
|
||||||
func (b *BaseChain) EthereumTypeEstimateGas(params map[string]interface{}) (uint64, error) {
|
func (b *BaseChain) EthereumTypeEstimateGas(params map[string]interface{}) (uint64, error) {
|
||||||
return 0, errors.New("Not supported")
|
return 0, errors.New("not supported")
|
||||||
}
|
}
|
||||||
|
|
||||||
// GetContractInfo is not supported
|
// GetContractInfo is not supported
|
||||||
func (b *BaseChain) GetContractInfo(contractDesc AddressDescriptor) (*ContractInfo, error) {
|
func (b *BaseChain) GetContractInfo(contractDesc AddressDescriptor) (*ContractInfo, error) {
|
||||||
return nil, errors.New("Not supported")
|
return nil, errors.New("not supported")
|
||||||
}
|
}
|
||||||
|
|
||||||
// EthereumTypeGetErc20ContractBalance is not supported
|
// EthereumTypeGetErc20ContractBalance is not supported
|
||||||
func (b *BaseChain) EthereumTypeGetErc20ContractBalance(addrDesc, contractDesc AddressDescriptor) (*big.Int, error) {
|
func (b *BaseChain) EthereumTypeGetErc20ContractBalance(addrDesc, contractDesc AddressDescriptor) (*big.Int, error) {
|
||||||
return nil, errors.New("Not supported")
|
return nil, errors.New("not supported")
|
||||||
}
|
}
|
||||||
|
|
||||||
// GetContractInfo returns URI of non fungible or multi token defined by token id
|
// GetTokenURI returns URI of non fungible or multi token defined by token id
|
||||||
func (p *BaseChain) GetTokenURI(contractDesc AddressDescriptor, tokenID *big.Int) (string, error) {
|
func (p *BaseChain) GetTokenURI(contractDesc AddressDescriptor, tokenID *big.Int) (string, error) {
|
||||||
return "", errors.New("Not supported")
|
return "", errors.New("not supported")
|
||||||
|
}
|
||||||
|
|
||||||
|
func (b *BaseChain) EthereumTypeGetSupportedStakingPools() []string {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (b *BaseChain) EthereumTypeGetStakingPoolsData(addrDesc AddressDescriptor) ([]StakingPoolData, error) {
|
||||||
|
return nil, errors.New("not supported")
|
||||||
|
}
|
||||||
|
|
||||||
|
// EthereumTypeRpcCall calls eth_call with given data and to address
|
||||||
|
func (b *BaseChain) EthereumTypeRpcCall(data, to, from string) (string, error) {
|
||||||
|
return "", errors.New("not supported")
|
||||||
|
}
|
||||||
|
|
||||||
|
func (b *BaseChain) EthereumTypeGetRawTransaction(txid string) (string, error) {
|
||||||
|
return "", errors.New("not supported")
|
||||||
}
|
}
|
||||||
|
|||||||
77
bchain/coins/arbitrum/arbitrumrpc.go
Normal file
77
bchain/coins/arbitrum/arbitrumrpc.go
Normal file
@ -0,0 +1,77 @@
|
|||||||
|
package arbitrum
|
||||||
|
|
||||||
|
import (
|
||||||
|
"context"
|
||||||
|
"encoding/json"
|
||||||
|
|
||||||
|
"github.com/golang/glog"
|
||||||
|
"github.com/juju/errors"
|
||||||
|
"github.com/trezor/blockbook/bchain"
|
||||||
|
"github.com/trezor/blockbook/bchain/coins/eth"
|
||||||
|
)
|
||||||
|
|
||||||
|
const (
|
||||||
|
ArbitrumOneMainNet eth.Network = 42161
|
||||||
|
ArbitrumNovaMainNet eth.Network = 42170
|
||||||
|
)
|
||||||
|
|
||||||
|
// ArbitrumRPC is an interface to JSON-RPC arbitrum service.
|
||||||
|
type ArbitrumRPC struct {
|
||||||
|
*eth.EthereumRPC
|
||||||
|
}
|
||||||
|
|
||||||
|
// NewArbitrumRPC returns new ArbitrumRPC instance.
|
||||||
|
func NewArbitrumRPC(config json.RawMessage, pushHandler func(bchain.NotificationType)) (bchain.BlockChain, error) {
|
||||||
|
c, err := eth.NewEthereumRPC(config, pushHandler)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
s := &ArbitrumRPC{
|
||||||
|
EthereumRPC: c.(*eth.EthereumRPC),
|
||||||
|
}
|
||||||
|
|
||||||
|
return s, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// Initialize arbitrum rpc interface
|
||||||
|
func (b *ArbitrumRPC) Initialize() error {
|
||||||
|
b.OpenRPC = eth.OpenRPC
|
||||||
|
|
||||||
|
rc, ec, err := b.OpenRPC(b.ChainConfig.RPCURL)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
// set chain specific
|
||||||
|
b.Client = ec
|
||||||
|
b.RPC = rc
|
||||||
|
b.NewBlock = eth.NewEthereumNewBlock()
|
||||||
|
b.NewTx = eth.NewEthereumNewTx()
|
||||||
|
|
||||||
|
ctx, cancel := context.WithTimeout(context.Background(), b.Timeout)
|
||||||
|
defer cancel()
|
||||||
|
|
||||||
|
id, err := b.Client.NetworkID(ctx)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
// parameters for getInfo request
|
||||||
|
switch eth.Network(id.Uint64()) {
|
||||||
|
case ArbitrumOneMainNet:
|
||||||
|
b.MainNetChainID = ArbitrumOneMainNet
|
||||||
|
b.Testnet = false
|
||||||
|
b.Network = "livenet"
|
||||||
|
case ArbitrumNovaMainNet:
|
||||||
|
b.MainNetChainID = ArbitrumNovaMainNet
|
||||||
|
b.Testnet = false
|
||||||
|
b.Network = "livenet"
|
||||||
|
default:
|
||||||
|
return errors.Errorf("Unknown network id %v", id)
|
||||||
|
}
|
||||||
|
|
||||||
|
glog.Info("rpc: block chain ", b.Network)
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
@ -110,7 +110,6 @@ func (b *AvalancheRPC) Initialize() error {
|
|||||||
func (b *AvalancheRPC) GetChainInfo() (*bchain.ChainInfo, error) {
|
func (b *AvalancheRPC) GetChainInfo() (*bchain.ChainInfo, error) {
|
||||||
ci, err := b.EthereumRPC.GetChainInfo()
|
ci, err := b.EthereumRPC.GetChainInfo()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
fmt.Println(err)
|
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -337,10 +337,15 @@ func Test_UnpackTx(t *testing.T) {
|
|||||||
t.Run(tt.name, func(t *testing.T) {
|
t.Run(tt.name, func(t *testing.T) {
|
||||||
b, _ := hex.DecodeString(tt.args.packedTx)
|
b, _ := hex.DecodeString(tt.args.packedTx)
|
||||||
got, got1, err := tt.args.parser.UnpackTx(b)
|
got, got1, err := tt.args.parser.UnpackTx(b)
|
||||||
|
|
||||||
if (err != nil) != tt.wantErr {
|
if (err != nil) != tt.wantErr {
|
||||||
t.Errorf("unpackTx() error = %v, wantErr %v", err, tt.wantErr)
|
t.Errorf("unpackTx() error = %v, wantErr %v", err, tt.wantErr)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
// ignore witness unpacking
|
||||||
|
for i := range got.Vin {
|
||||||
|
got.Vin[i].Witness = nil
|
||||||
|
}
|
||||||
if !reflect.DeepEqual(got, tt.want) {
|
if !reflect.DeepEqual(got, tt.want) {
|
||||||
t.Errorf("unpackTx() got = %v, want %v", got, tt.want)
|
t.Errorf("unpackTx() got = %v, want %v", got, tt.want)
|
||||||
}
|
}
|
||||||
|
|||||||
@ -316,6 +316,10 @@ func Test_UnpackTx(t *testing.T) {
|
|||||||
t.Errorf("unpackTx() error = %v, wantErr %v", err, tt.wantErr)
|
t.Errorf("unpackTx() error = %v, wantErr %v", err, tt.wantErr)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
// ignore witness unpacking
|
||||||
|
for i := range got.Vin {
|
||||||
|
got.Vin[i].Witness = nil
|
||||||
|
}
|
||||||
if !reflect.DeepEqual(got, tt.want) {
|
if !reflect.DeepEqual(got, tt.want) {
|
||||||
t.Errorf("unpackTx() got = %v, want %v", got, tt.want)
|
t.Errorf("unpackTx() got = %v, want %v", got, tt.want)
|
||||||
}
|
}
|
||||||
|
|||||||
@ -4,13 +4,14 @@ import (
|
|||||||
"context"
|
"context"
|
||||||
"encoding/json"
|
"encoding/json"
|
||||||
"fmt"
|
"fmt"
|
||||||
"io/ioutil"
|
|
||||||
"math/big"
|
"math/big"
|
||||||
|
"os"
|
||||||
"reflect"
|
"reflect"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
"github.com/juju/errors"
|
"github.com/juju/errors"
|
||||||
"github.com/trezor/blockbook/bchain"
|
"github.com/trezor/blockbook/bchain"
|
||||||
|
"github.com/trezor/blockbook/bchain/coins/arbitrum"
|
||||||
"github.com/trezor/blockbook/bchain/coins/avalanche"
|
"github.com/trezor/blockbook/bchain/coins/avalanche"
|
||||||
"github.com/trezor/blockbook/bchain/coins/bch"
|
"github.com/trezor/blockbook/bchain/coins/bch"
|
||||||
"github.com/trezor/blockbook/bchain/coins/bellcoin"
|
"github.com/trezor/blockbook/bchain/coins/bellcoin"
|
||||||
@ -42,8 +43,10 @@ import (
|
|||||||
"github.com/trezor/blockbook/bchain/coins/namecoin"
|
"github.com/trezor/blockbook/bchain/coins/namecoin"
|
||||||
"github.com/trezor/blockbook/bchain/coins/nuls"
|
"github.com/trezor/blockbook/bchain/coins/nuls"
|
||||||
"github.com/trezor/blockbook/bchain/coins/omotenashicoin"
|
"github.com/trezor/blockbook/bchain/coins/omotenashicoin"
|
||||||
|
"github.com/trezor/blockbook/bchain/coins/optimism"
|
||||||
"github.com/trezor/blockbook/bchain/coins/pivx"
|
"github.com/trezor/blockbook/bchain/coins/pivx"
|
||||||
"github.com/trezor/blockbook/bchain/coins/polis"
|
"github.com/trezor/blockbook/bchain/coins/polis"
|
||||||
|
"github.com/trezor/blockbook/bchain/coins/polygon"
|
||||||
"github.com/trezor/blockbook/bchain/coins/qtum"
|
"github.com/trezor/blockbook/bchain/coins/qtum"
|
||||||
"github.com/trezor/blockbook/bchain/coins/ravencoin"
|
"github.com/trezor/blockbook/bchain/coins/ravencoin"
|
||||||
"github.com/trezor/blockbook/bchain/coins/ritocoin"
|
"github.com/trezor/blockbook/bchain/coins/ritocoin"
|
||||||
@ -65,6 +68,7 @@ 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["Testnet4"] = btc.NewBitcoinRPC
|
||||||
BlockChainFactories["Signet"] = btc.NewBitcoinRPC
|
BlockChainFactories["Signet"] = btc.NewBitcoinRPC
|
||||||
BlockChainFactories["Regtest"] = btc.NewBitcoinRPC
|
BlockChainFactories["Regtest"] = btc.NewBitcoinRPC
|
||||||
BlockChainFactories["Zcash"] = zec.NewZCashRPC
|
BlockChainFactories["Zcash"] = zec.NewZCashRPC
|
||||||
@ -72,12 +76,10 @@ func init() {
|
|||||||
BlockChainFactories["Ethereum"] = eth.NewEthereumRPC
|
BlockChainFactories["Ethereum"] = eth.NewEthereumRPC
|
||||||
BlockChainFactories["Ethereum Archive"] = eth.NewEthereumRPC
|
BlockChainFactories["Ethereum Archive"] = eth.NewEthereumRPC
|
||||||
BlockChainFactories["Ethereum Classic"] = eth.NewEthereumRPC
|
BlockChainFactories["Ethereum Classic"] = eth.NewEthereumRPC
|
||||||
BlockChainFactories["Ethereum Testnet Ropsten"] = eth.NewEthereumRPC
|
|
||||||
BlockChainFactories["Ethereum Testnet Ropsten Archive"] = eth.NewEthereumRPC
|
|
||||||
BlockChainFactories["Ethereum Testnet Goerli"] = eth.NewEthereumRPC
|
|
||||||
BlockChainFactories["Ethereum Testnet Goerli Archive"] = eth.NewEthereumRPC
|
|
||||||
BlockChainFactories["Ethereum Testnet Sepolia"] = eth.NewEthereumRPC
|
BlockChainFactories["Ethereum Testnet Sepolia"] = eth.NewEthereumRPC
|
||||||
BlockChainFactories["Ethereum Testnet Sepolia Archive"] = eth.NewEthereumRPC
|
BlockChainFactories["Ethereum Testnet Sepolia Archive"] = eth.NewEthereumRPC
|
||||||
|
BlockChainFactories["Ethereum Testnet Holesky"] = eth.NewEthereumRPC
|
||||||
|
BlockChainFactories["Ethereum Testnet Holesky Archive"] = 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
|
||||||
@ -113,6 +115,7 @@ func init() {
|
|||||||
BlockChainFactories["Firo"] = firo.NewFiroRPC
|
BlockChainFactories["Firo"] = firo.NewFiroRPC
|
||||||
BlockChainFactories["Fujicoin"] = fujicoin.NewFujicoinRPC
|
BlockChainFactories["Fujicoin"] = fujicoin.NewFujicoinRPC
|
||||||
BlockChainFactories["Flo"] = flo.NewFloRPC
|
BlockChainFactories["Flo"] = flo.NewFloRPC
|
||||||
|
BlockChainFactories["Flo Testnet"] = flo.NewFloRPC
|
||||||
BlockChainFactories["Bellcoin"] = bellcoin.NewBellcoinRPC
|
BlockChainFactories["Bellcoin"] = bellcoin.NewBellcoinRPC
|
||||||
BlockChainFactories["Qtum"] = qtum.NewQtumRPC
|
BlockChainFactories["Qtum"] = qtum.NewQtumRPC
|
||||||
BlockChainFactories["Viacoin"] = viacoin.NewViacoinRPC
|
BlockChainFactories["Viacoin"] = viacoin.NewViacoinRPC
|
||||||
@ -137,25 +140,19 @@ func init() {
|
|||||||
BlockChainFactories["Avalanche Archive"] = avalanche.NewAvalancheRPC
|
BlockChainFactories["Avalanche Archive"] = avalanche.NewAvalancheRPC
|
||||||
BlockChainFactories["BNB Smart Chain"] = bsc.NewBNBSmartChainRPC
|
BlockChainFactories["BNB Smart Chain"] = bsc.NewBNBSmartChainRPC
|
||||||
BlockChainFactories["BNB Smart Chain Archive"] = bsc.NewBNBSmartChainRPC
|
BlockChainFactories["BNB Smart Chain Archive"] = bsc.NewBNBSmartChainRPC
|
||||||
}
|
BlockChainFactories["Polygon"] = polygon.NewPolygonRPC
|
||||||
|
BlockChainFactories["Polygon Archive"] = polygon.NewPolygonRPC
|
||||||
// GetCoinNameFromConfig gets coin name and coin shortcut from config file
|
BlockChainFactories["Optimism"] = optimism.NewOptimismRPC
|
||||||
func GetCoinNameFromConfig(configFileContent []byte) (string, string, string, error) {
|
BlockChainFactories["Optimism Archive"] = optimism.NewOptimismRPC
|
||||||
var cn struct {
|
BlockChainFactories["Arbitrum"] = arbitrum.NewArbitrumRPC
|
||||||
CoinName string `json:"coin_name"`
|
BlockChainFactories["Arbitrum Archive"] = arbitrum.NewArbitrumRPC
|
||||||
CoinShortcut string `json:"coin_shortcut"`
|
BlockChainFactories["Arbitrum Nova"] = arbitrum.NewArbitrumRPC
|
||||||
CoinLabel string `json:"coin_label"`
|
BlockChainFactories["Arbitrum Nova Archive"] = arbitrum.NewArbitrumRPC
|
||||||
}
|
|
||||||
err := json.Unmarshal(configFileContent, &cn)
|
|
||||||
if err != nil {
|
|
||||||
return "", "", "", errors.Annotatef(err, "Error parsing config file ")
|
|
||||||
}
|
|
||||||
return cn.CoinName, cn.CoinShortcut, cn.CoinLabel, nil
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// NewBlockChain creates bchain.BlockChain and bchain.Mempool for the coin passed by the parameter coin
|
// NewBlockChain creates bchain.BlockChain and bchain.Mempool for the coin passed by the parameter coin
|
||||||
func NewBlockChain(coin string, configfile string, pushHandler func(bchain.NotificationType), metrics *common.Metrics) (bchain.BlockChain, bchain.Mempool, error) {
|
func NewBlockChain(coin string, configfile string, pushHandler func(bchain.NotificationType), metrics *common.Metrics) (bchain.BlockChain, bchain.Mempool, error) {
|
||||||
data, err := ioutil.ReadFile(configfile)
|
data, err := os.ReadFile(configfile)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, nil, errors.Annotatef(err, "Error reading file %v", configfile)
|
return nil, nil, errors.Annotatef(err, "Error reading file %v", configfile)
|
||||||
}
|
}
|
||||||
@ -337,12 +334,32 @@ func (c *blockChainWithMetrics) EthereumTypeGetErc20ContractBalance(addrDesc, co
|
|||||||
return c.b.EthereumTypeGetErc20ContractBalance(addrDesc, contractDesc)
|
return c.b.EthereumTypeGetErc20ContractBalance(addrDesc, contractDesc)
|
||||||
}
|
}
|
||||||
|
|
||||||
// GetContractInfo returns URI of non fungible or multi token defined by token id
|
// GetTokenURI returns URI of non fungible or multi token defined by token id
|
||||||
func (c *blockChainWithMetrics) GetTokenURI(contractDesc bchain.AddressDescriptor, tokenID *big.Int) (v string, err error) {
|
func (c *blockChainWithMetrics) GetTokenURI(contractDesc bchain.AddressDescriptor, tokenID *big.Int) (v string, err error) {
|
||||||
defer func(s time.Time) { c.observeRPCLatency("GetTokenURI", s, err) }(time.Now())
|
defer func(s time.Time) { c.observeRPCLatency("GetTokenURI", s, err) }(time.Now())
|
||||||
return c.b.GetTokenURI(contractDesc, tokenID)
|
return c.b.GetTokenURI(contractDesc, tokenID)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (c *blockChainWithMetrics) EthereumTypeGetSupportedStakingPools() []string {
|
||||||
|
return c.b.EthereumTypeGetSupportedStakingPools()
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *blockChainWithMetrics) EthereumTypeGetStakingPoolsData(addrDesc bchain.AddressDescriptor) (v []bchain.StakingPoolData, err error) {
|
||||||
|
defer func(s time.Time) { c.observeRPCLatency("EthereumTypeStakingPoolsData", s, err) }(time.Now())
|
||||||
|
return c.b.EthereumTypeGetStakingPoolsData(addrDesc)
|
||||||
|
}
|
||||||
|
|
||||||
|
// EthereumTypeRpcCall calls eth_call with given data and to address
|
||||||
|
func (c *blockChainWithMetrics) EthereumTypeRpcCall(data, to, from string) (v string, err error) {
|
||||||
|
defer func(s time.Time) { c.observeRPCLatency("EthereumTypeRpcCall", s, err) }(time.Now())
|
||||||
|
return c.b.EthereumTypeRpcCall(data, to, from)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *blockChainWithMetrics) EthereumTypeGetRawTransaction(txid string) (v string, err error) {
|
||||||
|
defer func(s time.Time) { c.observeRPCLatency("EthereumTypeGetRawTransaction", s, err) }(time.Now())
|
||||||
|
return c.b.EthereumTypeGetRawTransaction(txid)
|
||||||
|
}
|
||||||
|
|
||||||
type mempoolWithMetrics struct {
|
type mempoolWithMetrics struct {
|
||||||
mempool bchain.Mempool
|
mempool bchain.Mempool
|
||||||
m *common.Metrics
|
m *common.Metrics
|
||||||
|
|||||||
@ -4,8 +4,6 @@ import (
|
|||||||
"context"
|
"context"
|
||||||
"encoding/json"
|
"encoding/json"
|
||||||
|
|
||||||
"github.com/ethereum/go-ethereum/ethclient"
|
|
||||||
"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"
|
"github.com/trezor/blockbook/bchain"
|
||||||
@ -40,21 +38,14 @@ func NewBNBSmartChainRPC(config json.RawMessage, pushHandler func(bchain.Notific
|
|||||||
s := &BNBSmartChainRPC{
|
s := &BNBSmartChainRPC{
|
||||||
EthereumRPC: c.(*eth.EthereumRPC),
|
EthereumRPC: c.(*eth.EthereumRPC),
|
||||||
}
|
}
|
||||||
|
s.Parser.EnsSuffix = ".bnb"
|
||||||
|
|
||||||
return s, nil
|
return s, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// Initialize bnb smart chain rpc interface
|
// Initialize bnb smart chain rpc interface
|
||||||
func (b *BNBSmartChainRPC) Initialize() error {
|
func (b *BNBSmartChainRPC) Initialize() error {
|
||||||
b.OpenRPC = func(url string) (bchain.EVMRPCClient, bchain.EVMClient, error) {
|
b.OpenRPC = eth.OpenRPC
|
||||||
r, err := rpc.Dial(url)
|
|
||||||
if err != nil {
|
|
||||||
return nil, nil, err
|
|
||||||
}
|
|
||||||
rc := ð.EthereumRPCClient{Client: r}
|
|
||||||
ec := ð.EthereumClient{Client: ethclient.NewClient(r)}
|
|
||||||
return rc, ec, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
rc, ec, err := b.OpenRPC(b.ChainConfig.RPCURL)
|
rc, ec, err := b.OpenRPC(b.ChainConfig.RPCURL)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
|||||||
68
bchain/coins/btc/alternativefeeprovider.go
Normal file
68
bchain/coins/btc/alternativefeeprovider.go
Normal file
@ -0,0 +1,68 @@
|
|||||||
|
package btc
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
"math/big"
|
||||||
|
"sync"
|
||||||
|
"time"
|
||||||
|
|
||||||
|
"github.com/golang/glog"
|
||||||
|
"github.com/juju/errors"
|
||||||
|
"github.com/trezor/blockbook/bchain"
|
||||||
|
)
|
||||||
|
|
||||||
|
type alternativeFeeProviderFee struct {
|
||||||
|
blocks int
|
||||||
|
feePerKB int
|
||||||
|
}
|
||||||
|
|
||||||
|
type alternativeFeeProvider struct {
|
||||||
|
fees []alternativeFeeProviderFee
|
||||||
|
lastSync time.Time
|
||||||
|
chain bchain.BlockChain
|
||||||
|
mux sync.Mutex
|
||||||
|
}
|
||||||
|
|
||||||
|
type alternativeFeeProviderInterface interface {
|
||||||
|
compareToDefault()
|
||||||
|
estimateFee(blocks int) (big.Int, error)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (p *alternativeFeeProvider) compareToDefault() {
|
||||||
|
output := ""
|
||||||
|
for _, fee := range p.fees {
|
||||||
|
conservative, err := p.chain.(*BitcoinRPC).blockchainEstimateSmartFee(fee.blocks, true)
|
||||||
|
if err != nil {
|
||||||
|
glog.Error(err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
economical, err := p.chain.(*BitcoinRPC).blockchainEstimateSmartFee(fee.blocks, false)
|
||||||
|
if err != nil {
|
||||||
|
glog.Error(err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
output += fmt.Sprintf("Blocks %d: alternative %d, conservative %s, economical %s\n", fee.blocks, fee.feePerKB, conservative.String(), economical.String())
|
||||||
|
}
|
||||||
|
glog.Info("alternativeFeeProviderCompareToDefault\n", output)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (p *alternativeFeeProvider) estimateFee(blocks int) (big.Int, error) {
|
||||||
|
var r big.Int
|
||||||
|
p.mux.Lock()
|
||||||
|
defer p.mux.Unlock()
|
||||||
|
if len(p.fees) == 0 {
|
||||||
|
return r, errors.New("alternativeFeeProvider: no fees")
|
||||||
|
}
|
||||||
|
if p.lastSync.Before(time.Now().Add(time.Duration(-10) * time.Minute)) {
|
||||||
|
return r, errors.Errorf("alternativeFeeProvider: Missing recent value, last sync at %v", p.lastSync)
|
||||||
|
}
|
||||||
|
for i := range p.fees {
|
||||||
|
if p.fees[i].blocks >= blocks {
|
||||||
|
r = *big.NewInt(int64(p.fees[i].feePerKB))
|
||||||
|
return r, nil
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// use the last value as fallback
|
||||||
|
r = *big.NewInt(int64(p.fees[len(p.fees)-1].feePerKB))
|
||||||
|
return r, nil
|
||||||
|
}
|
||||||
@ -231,6 +231,7 @@ func (p *BitcoinLikeParser) TxFromMsgTx(t *wire.MsgTx, parseAddresses bool) bcha
|
|||||||
Vout: in.PreviousOutPoint.Index,
|
Vout: in.PreviousOutPoint.Index,
|
||||||
Sequence: in.Sequence,
|
Sequence: in.Sequence,
|
||||||
ScriptSig: s,
|
ScriptSig: s,
|
||||||
|
Witness: in.Witness,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
vout := make([]bchain.Vout, len(t.TxOut))
|
vout := make([]bchain.Vout, len(t.TxOut))
|
||||||
|
|||||||
@ -4,11 +4,28 @@ import (
|
|||||||
"encoding/json"
|
"encoding/json"
|
||||||
"math/big"
|
"math/big"
|
||||||
|
|
||||||
|
"github.com/martinboehm/btcd/wire"
|
||||||
"github.com/martinboehm/btcutil/chaincfg"
|
"github.com/martinboehm/btcutil/chaincfg"
|
||||||
"github.com/trezor/blockbook/bchain"
|
"github.com/trezor/blockbook/bchain"
|
||||||
"github.com/trezor/blockbook/common"
|
"github.com/trezor/blockbook/common"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
// temp params for signet(wait btcd commit)
|
||||||
|
// magic numbers
|
||||||
|
const (
|
||||||
|
Testnet4Magic wire.BitcoinNet = 0x283f161c
|
||||||
|
)
|
||||||
|
|
||||||
|
// chain parameters
|
||||||
|
var (
|
||||||
|
TestNet4Params chaincfg.Params
|
||||||
|
)
|
||||||
|
|
||||||
|
func init() {
|
||||||
|
TestNet4Params = chaincfg.TestNet3Params
|
||||||
|
TestNet4Params.Net = Testnet4Magic
|
||||||
|
}
|
||||||
|
|
||||||
// BitcoinParser handle
|
// BitcoinParser handle
|
||||||
type BitcoinParser struct {
|
type BitcoinParser struct {
|
||||||
*BitcoinLikeParser
|
*BitcoinLikeParser
|
||||||
@ -33,6 +50,8 @@ func GetChainParams(chain string) *chaincfg.Params {
|
|||||||
switch chain {
|
switch chain {
|
||||||
case "test":
|
case "test":
|
||||||
return &chaincfg.TestNet3Params
|
return &chaincfg.TestNet3Params
|
||||||
|
case "testnet4":
|
||||||
|
return &TestNet4Params
|
||||||
case "regtest":
|
case "regtest":
|
||||||
return &chaincfg.RegressionNetParams
|
return &chaincfg.RegressionNetParams
|
||||||
case "signet":
|
case "signet":
|
||||||
|
|||||||
@ -467,11 +467,12 @@ func TestGetAddressesFromAddrDescTestnet(t *testing.T) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
var (
|
var (
|
||||||
testTx1, testTx2, testTx3 bchain.Tx
|
testTx1, testTx2, testTx3, testTx4 bchain.Tx
|
||||||
|
|
||||||
testTxPacked1 = "0001e2408ba8d7af5401000000017f9a22c9cbf54bd902400df746f138f37bcf5b4d93eb755820e974ba43ed5f42040000006a4730440220037f4ed5427cde81d55b9b6a2fd08c8a25090c2c2fff3a75c1a57625ca8a7118022076c702fe55969fa08137f71afd4851c48e31082dd3c40c919c92cdbc826758d30121029f6da5623c9f9b68a9baf9c1bc7511df88fa34c6c2f71f7c62f2f03ff48dca80feffffff019c9700000000000017a9146144d57c8aff48492c9dfb914e120b20bad72d6f8773d00700"
|
testTxPacked1 = "0001e2408ba8d7af5401000000017f9a22c9cbf54bd902400df746f138f37bcf5b4d93eb755820e974ba43ed5f42040000006a4730440220037f4ed5427cde81d55b9b6a2fd08c8a25090c2c2fff3a75c1a57625ca8a7118022076c702fe55969fa08137f71afd4851c48e31082dd3c40c919c92cdbc826758d30121029f6da5623c9f9b68a9baf9c1bc7511df88fa34c6c2f71f7c62f2f03ff48dca80feffffff019c9700000000000017a9146144d57c8aff48492c9dfb914e120b20bad72d6f8773d00700"
|
||||||
testTxPacked2 = "0007c91a899ab7da6a010000000001019d64f0c72a0d206001decbffaa722eb1044534c74eee7a5df8318e42a4323ec10000000017160014550da1f5d25a9dae2eafd6902b4194c4c6500af6ffffffff02809698000000000017a914cd668d781ece600efa4b2404dc91fd26b8b8aed8870553d7360000000017a914246655bdbd54c7e477d0ea2375e86e0db2b8f80a8702473044022076aba4ad559616905fa51d4ddd357fc1fdb428d40cb388e042cdd1da4a1b7357022011916f90c712ead9a66d5f058252efd280439ad8956a967e95d437d246710bc9012102a80a5964c5612bb769ef73147b2cf3c149bc0fd4ecb02f8097629c94ab013ffd00000000"
|
testTxPacked2 = "0007c91a899ab7da6a010000000001019d64f0c72a0d206001decbffaa722eb1044534c74eee7a5df8318e42a4323ec10000000017160014550da1f5d25a9dae2eafd6902b4194c4c6500af6ffffffff02809698000000000017a914cd668d781ece600efa4b2404dc91fd26b8b8aed8870553d7360000000017a914246655bdbd54c7e477d0ea2375e86e0db2b8f80a8702473044022076aba4ad559616905fa51d4ddd357fc1fdb428d40cb388e042cdd1da4a1b7357022011916f90c712ead9a66d5f058252efd280439ad8956a967e95d437d246710bc9012102a80a5964c5612bb769ef73147b2cf3c149bc0fd4ecb02f8097629c94ab013ffd00000000"
|
||||||
testTxPacked3 = "00003d818bfda9aa3e02000000000102deb1999a857ab0a13d6b12fbd95ea75b409edde5f2ff747507ce42d9986a8b9d0000000000fdffffff9fd2d3361e203b2375eba6438efbef5b3075531e7e583c7cc76b7294fe7f22980000000000fdffffff02a0860100000000001600148091746745464e7555c31e9a5afceac14a02978ae7fc1c0000000000160014565ea9ff4589d3e05ba149ae6e257752bfdc2a1e0247304402207d67d320a8e813f986b35e9791935fcb736754812b7038686f5de6cfdcda99cd02201c3bb2c178e0056016437ecfe365a7eef84aa9d293ebdc566177af82e22fcdd3012103abb30c1bbe878b07b58dc169b1d061d48c60be8107f632a59778b38bf7ceea5a02473044022044f54a478cfe086e870cb026c9dcd4e14e63778bef569a4d55a6332725cd9a9802202f0e94c04e6f328fc64ad9efe552888c299750d1b8d033324825a3ff29920e030121036fcd433428aa7dc65c4f5408fa31f208c54fe4b4c6c1ae9c39a825ed4f1ac039813d0000"
|
testTxPacked3 = "00003d818bfda9aa3e02000000000102deb1999a857ab0a13d6b12fbd95ea75b409edde5f2ff747507ce42d9986a8b9d0000000000fdffffff9fd2d3361e203b2375eba6438efbef5b3075531e7e583c7cc76b7294fe7f22980000000000fdffffff02a0860100000000001600148091746745464e7555c31e9a5afceac14a02978ae7fc1c0000000000160014565ea9ff4589d3e05ba149ae6e257752bfdc2a1e0247304402207d67d320a8e813f986b35e9791935fcb736754812b7038686f5de6cfdcda99cd02201c3bb2c178e0056016437ecfe365a7eef84aa9d293ebdc566177af82e22fcdd3012103abb30c1bbe878b07b58dc169b1d061d48c60be8107f632a59778b38bf7ceea5a02473044022044f54a478cfe086e870cb026c9dcd4e14e63778bef569a4d55a6332725cd9a9802202f0e94c04e6f328fc64ad9efe552888c299750d1b8d033324825a3ff29920e030121036fcd433428aa7dc65c4f5408fa31f208c54fe4b4c6c1ae9c39a825ed4f1ac039813d0000"
|
||||||
|
testTxPacked4 = "0000a2b98ced82b6400300000000010148f8f93ebb12407809920d2ab9cc1bf01289b314eb23028c83fdab21e5fefa690100000000fdffffff0150c3000000000000160014cb888de3c89670a3061fb6ef6590f187649cca060247304402206a9db8d7157e4b0a06a1f090b9de88cdc616028b431b80617a055117877e479a02202937d6d1658d4a8afde86b245325c3bb0e769a87cb09d802bcefaa21550065e201210374aa8f312de4ebccbef55609700a39764387aa4ff5d76f1ccb4d2382e454f05b00000000"
|
||||||
)
|
)
|
||||||
|
|
||||||
func init() {
|
func init() {
|
||||||
@ -595,6 +596,37 @@ func init() {
|
|||||||
},
|
},
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
|
testTx4 = bchain.Tx{
|
||||||
|
Hex: "0300000000010148f8f93ebb12407809920d2ab9cc1bf01289b314eb23028c83fdab21e5fefa690100000000fdffffff0150c3000000000000160014cb888de3c89670a3061fb6ef6590f187649cca060247304402206a9db8d7157e4b0a06a1f090b9de88cdc616028b431b80617a055117877e479a02202937d6d1658d4a8afde86b245325c3bb0e769a87cb09d802bcefaa21550065e201210374aa8f312de4ebccbef55609700a39764387aa4ff5d76f1ccb4d2382e454f05b00000000",
|
||||||
|
Blocktime: 1724927392,
|
||||||
|
Txid: "8e3f38bf6854dd3c358be8d4f9a40a6dccc50de49616125d27af9fdbe65287eb",
|
||||||
|
LockTime: 0,
|
||||||
|
VSize: 110,
|
||||||
|
Version: 3,
|
||||||
|
Vin: []bchain.Vin{
|
||||||
|
{
|
||||||
|
ScriptSig: bchain.ScriptSig{
|
||||||
|
Hex: "",
|
||||||
|
},
|
||||||
|
Txid: "69fafee521abfd838c0223eb14b38912f01bccb92a0d9209784012bb3ef9f848",
|
||||||
|
Vout: 1,
|
||||||
|
Sequence: 4294967293,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
Vout: []bchain.Vout{
|
||||||
|
{
|
||||||
|
ValueSat: *big.NewInt(50000),
|
||||||
|
N: 0,
|
||||||
|
ScriptPubKey: bchain.ScriptPubKey{
|
||||||
|
Hex: "0014cb888de3c89670a3061fb6ef6590f187649cca06",
|
||||||
|
Addresses: []string{
|
||||||
|
"tb1qewygmc7gjec2xpslkmhkty83sajfejsxqmy5dq",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestPackTx(t *testing.T) {
|
func TestPackTx(t *testing.T) {
|
||||||
@ -643,6 +675,17 @@ func TestPackTx(t *testing.T) {
|
|||||||
want: testTxPacked3,
|
want: testTxPacked3,
|
||||||
wantErr: false,
|
wantErr: false,
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
name: "testnet4-1",
|
||||||
|
args: args{
|
||||||
|
tx: testTx4,
|
||||||
|
height: 41657,
|
||||||
|
blockTime: 1724927392,
|
||||||
|
parser: NewBitcoinParser(GetChainParams("testnet4"), &Configuration{}),
|
||||||
|
},
|
||||||
|
want: testTxPacked4,
|
||||||
|
wantErr: false,
|
||||||
|
},
|
||||||
}
|
}
|
||||||
for _, tt := range tests {
|
for _, tt := range tests {
|
||||||
t.Run(tt.name, func(t *testing.T) {
|
t.Run(tt.name, func(t *testing.T) {
|
||||||
@ -701,6 +744,16 @@ func TestUnpackTx(t *testing.T) {
|
|||||||
want1: 15745,
|
want1: 15745,
|
||||||
wantErr: false,
|
wantErr: false,
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
name: "testnet4-1",
|
||||||
|
args: args{
|
||||||
|
packedTx: testTxPacked4,
|
||||||
|
parser: NewBitcoinParser(GetChainParams("testnet4"), &Configuration{}),
|
||||||
|
},
|
||||||
|
want: &testTx4,
|
||||||
|
want1: 41657,
|
||||||
|
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) {
|
||||||
@ -710,6 +763,10 @@ func TestUnpackTx(t *testing.T) {
|
|||||||
t.Errorf("unpackTx() error = %v, wantErr %v", err, tt.wantErr)
|
t.Errorf("unpackTx() error = %v, wantErr %v", err, tt.wantErr)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
// ignore witness unpacking
|
||||||
|
for i := range got.Vin {
|
||||||
|
got.Vin[i].Witness = nil
|
||||||
|
}
|
||||||
if !reflect.DeepEqual(got, tt.want) {
|
if !reflect.DeepEqual(got, tt.want) {
|
||||||
t.Errorf("unpackTx() got = %v, want %v", got, tt.want)
|
t.Errorf("unpackTx() got = %v, want %v", got, tt.want)
|
||||||
}
|
}
|
||||||
|
|||||||
@ -6,7 +6,6 @@ import (
|
|||||||
"encoding/hex"
|
"encoding/hex"
|
||||||
"encoding/json"
|
"encoding/json"
|
||||||
"io"
|
"io"
|
||||||
"io/ioutil"
|
|
||||||
"math/big"
|
"math/big"
|
||||||
"net"
|
"net"
|
||||||
"net/http"
|
"net/http"
|
||||||
@ -23,18 +22,20 @@ import (
|
|||||||
// BitcoinRPC is an interface to JSON-RPC bitcoind service.
|
// BitcoinRPC is an interface to JSON-RPC bitcoind service.
|
||||||
type BitcoinRPC struct {
|
type BitcoinRPC struct {
|
||||||
*bchain.BaseChain
|
*bchain.BaseChain
|
||||||
client http.Client
|
client http.Client
|
||||||
rpcURL string
|
rpcURL string
|
||||||
user string
|
user string
|
||||||
password string
|
password string
|
||||||
Mempool *bchain.MempoolBitcoinType
|
Mempool *bchain.MempoolBitcoinType
|
||||||
ParseBlocks bool
|
ParseBlocks bool
|
||||||
pushHandler func(bchain.NotificationType)
|
pushHandler func(bchain.NotificationType)
|
||||||
mq *bchain.MQ
|
mq *bchain.MQ
|
||||||
ChainConfig *Configuration
|
ChainConfig *Configuration
|
||||||
RPCMarshaler RPCMarshaler
|
RPCMarshaler RPCMarshaler
|
||||||
golombFilterP uint8
|
mempoolGolombFilterP uint8
|
||||||
mempoolFilterScripts string
|
mempoolFilterScripts string
|
||||||
|
mempoolUseZeroedKey bool
|
||||||
|
alternativeFeeProvider alternativeFeeProviderInterface
|
||||||
}
|
}
|
||||||
|
|
||||||
// Configuration represents json config file
|
// Configuration represents json config file
|
||||||
@ -62,8 +63,9 @@ type Configuration struct {
|
|||||||
AlternativeEstimateFee string `json:"alternative_estimate_fee,omitempty"`
|
AlternativeEstimateFee string `json:"alternative_estimate_fee,omitempty"`
|
||||||
AlternativeEstimateFeeParams string `json:"alternative_estimate_fee_params,omitempty"`
|
AlternativeEstimateFeeParams string `json:"alternative_estimate_fee_params,omitempty"`
|
||||||
MinimumCoinbaseConfirmations int `json:"minimumCoinbaseConfirmations,omitempty"`
|
MinimumCoinbaseConfirmations int `json:"minimumCoinbaseConfirmations,omitempty"`
|
||||||
GolombFilterP uint8 `json:"golomb_filter_p,omitempty"`
|
MempoolGolombFilterP uint8 `json:"mempool_golomb_filter_p,omitempty"`
|
||||||
MempoolFilterScripts string `json:"mempool_filter_scripts,omitempty"`
|
MempoolFilterScripts string `json:"mempool_filter_scripts,omitempty"`
|
||||||
|
MempoolFilterUseZeroedKey bool `json:"mempool_filter_use_zeroed_key,omitempty"`
|
||||||
}
|
}
|
||||||
|
|
||||||
// NewBitcoinRPC returns new BitcoinRPC instance.
|
// NewBitcoinRPC returns new BitcoinRPC instance.
|
||||||
@ -109,8 +111,9 @@ func NewBitcoinRPC(config json.RawMessage, pushHandler func(bchain.NotificationT
|
|||||||
ChainConfig: &c,
|
ChainConfig: &c,
|
||||||
pushHandler: pushHandler,
|
pushHandler: pushHandler,
|
||||||
RPCMarshaler: JSONMarshalerV2{},
|
RPCMarshaler: JSONMarshalerV2{},
|
||||||
golombFilterP: c.GolombFilterP,
|
mempoolGolombFilterP: c.MempoolGolombFilterP,
|
||||||
mempoolFilterScripts: c.MempoolFilterScripts,
|
mempoolFilterScripts: c.MempoolFilterScripts,
|
||||||
|
mempoolUseZeroedKey: c.MempoolFilterUseZeroedKey,
|
||||||
}
|
}
|
||||||
|
|
||||||
return s, nil
|
return s, nil
|
||||||
@ -143,10 +146,16 @@ func (b *BitcoinRPC) Initialize() error {
|
|||||||
glog.Info("rpc: block chain ", params.Name)
|
glog.Info("rpc: block chain ", params.Name)
|
||||||
|
|
||||||
if b.ChainConfig.AlternativeEstimateFee == "whatthefee" {
|
if b.ChainConfig.AlternativeEstimateFee == "whatthefee" {
|
||||||
if err = InitWhatTheFee(b, b.ChainConfig.AlternativeEstimateFeeParams); err != nil {
|
if b.alternativeFeeProvider, err = NewWhatTheFee(b, b.ChainConfig.AlternativeEstimateFeeParams); err != nil {
|
||||||
glog.Error("InitWhatTheFee error ", err, " Reverting to default estimateFee functionality")
|
glog.Error("NewWhatTheFee error ", err, " Reverting to default estimateFee functionality")
|
||||||
// disable AlternativeEstimateFee logic
|
// disable AlternativeEstimateFee logic
|
||||||
b.ChainConfig.AlternativeEstimateFee = ""
|
b.alternativeFeeProvider = nil
|
||||||
|
}
|
||||||
|
} else if b.ChainConfig.AlternativeEstimateFee == "mempoolspace" {
|
||||||
|
if b.alternativeFeeProvider, err = NewMempoolSpaceFee(b, b.ChainConfig.AlternativeEstimateFeeParams); err != nil {
|
||||||
|
glog.Error("MempoolSpaceFee error ", err, " Reverting to default estimateFee functionality")
|
||||||
|
// disable AlternativeEstimateFee logic
|
||||||
|
b.alternativeFeeProvider = nil
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -156,7 +165,7 @@ func (b *BitcoinRPC) Initialize() error {
|
|||||||
// CreateMempool creates mempool if not already created, however does not initialize it
|
// CreateMempool creates mempool if not already created, however does not initialize it
|
||||||
func (b *BitcoinRPC) CreateMempool(chain bchain.BlockChain) (bchain.Mempool, error) {
|
func (b *BitcoinRPC) CreateMempool(chain bchain.BlockChain) (bchain.Mempool, error) {
|
||||||
if b.Mempool == nil {
|
if b.Mempool == nil {
|
||||||
b.Mempool = bchain.NewMempoolBitcoinType(chain, b.ChainConfig.MempoolWorkers, b.ChainConfig.MempoolSubWorkers, b.golombFilterP, b.mempoolFilterScripts)
|
b.Mempool = bchain.NewMempoolBitcoinType(chain, b.ChainConfig.MempoolWorkers, b.ChainConfig.MempoolSubWorkers, b.mempoolGolombFilterP, b.mempoolFilterScripts, b.mempoolUseZeroedKey)
|
||||||
}
|
}
|
||||||
return b.Mempool, nil
|
return b.Mempool, nil
|
||||||
}
|
}
|
||||||
@ -772,8 +781,7 @@ func (b *BitcoinRPC) getRawTransaction(txid string) (json.RawMessage, error) {
|
|||||||
return res.Result, nil
|
return res.Result, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// EstimateSmartFee returns fee estimation
|
func (b *BitcoinRPC) blockchainEstimateSmartFee(blocks int, conservative bool) (big.Int, error) {
|
||||||
func (b *BitcoinRPC) EstimateSmartFee(blocks int, conservative bool) (big.Int, error) {
|
|
||||||
// use EstimateFee if EstimateSmartFee is not supported
|
// use EstimateFee if EstimateSmartFee is not supported
|
||||||
if !b.ChainConfig.SupportsEstimateSmartFee && b.ChainConfig.SupportsEstimateFee {
|
if !b.ChainConfig.SupportsEstimateSmartFee && b.ChainConfig.SupportsEstimateFee {
|
||||||
return b.EstimateFee(blocks)
|
return b.EstimateFee(blocks)
|
||||||
@ -790,7 +798,6 @@ func (b *BitcoinRPC) EstimateSmartFee(blocks int, conservative bool) (big.Int, e
|
|||||||
req.Params.EstimateMode = "ECONOMICAL"
|
req.Params.EstimateMode = "ECONOMICAL"
|
||||||
}
|
}
|
||||||
err := b.Call(&req, &res)
|
err := b.Call(&req, &res)
|
||||||
|
|
||||||
var r big.Int
|
var r big.Int
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return r, err
|
return r, err
|
||||||
@ -805,8 +812,31 @@ func (b *BitcoinRPC) EstimateSmartFee(blocks int, conservative bool) (big.Int, e
|
|||||||
return r, nil
|
return r, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// EstimateSmartFee returns fee estimation
|
||||||
|
func (b *BitcoinRPC) EstimateSmartFee(blocks int, conservative bool) (big.Int, error) {
|
||||||
|
// use alternative estimator if enabled
|
||||||
|
if b.alternativeFeeProvider != nil {
|
||||||
|
r, err := b.alternativeFeeProvider.estimateFee(blocks)
|
||||||
|
// in case of error, fallback to default estimator
|
||||||
|
if err == nil {
|
||||||
|
return r, nil
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return b.blockchainEstimateSmartFee(blocks, conservative)
|
||||||
|
}
|
||||||
|
|
||||||
// EstimateFee returns fee estimation.
|
// EstimateFee returns fee estimation.
|
||||||
func (b *BitcoinRPC) EstimateFee(blocks int) (big.Int, error) {
|
func (b *BitcoinRPC) EstimateFee(blocks int) (big.Int, error) {
|
||||||
|
var r big.Int
|
||||||
|
var err error
|
||||||
|
// use alternative estimator if enabled
|
||||||
|
if b.alternativeFeeProvider != nil {
|
||||||
|
r, err = b.alternativeFeeProvider.estimateFee(blocks)
|
||||||
|
// in case of error, fallback to default estimator
|
||||||
|
if err == nil {
|
||||||
|
return r, nil
|
||||||
|
}
|
||||||
|
}
|
||||||
// use EstimateSmartFee if EstimateFee is not supported
|
// use EstimateSmartFee if EstimateFee is not supported
|
||||||
if !b.ChainConfig.SupportsEstimateFee && b.ChainConfig.SupportsEstimateSmartFee {
|
if !b.ChainConfig.SupportsEstimateFee && b.ChainConfig.SupportsEstimateSmartFee {
|
||||||
return b.EstimateSmartFee(blocks, true)
|
return b.EstimateSmartFee(blocks, true)
|
||||||
@ -817,9 +847,8 @@ func (b *BitcoinRPC) EstimateFee(blocks int) (big.Int, error) {
|
|||||||
res := ResEstimateFee{}
|
res := ResEstimateFee{}
|
||||||
req := CmdEstimateFee{Method: "estimatefee"}
|
req := CmdEstimateFee{Method: "estimatefee"}
|
||||||
req.Params.Blocks = blocks
|
req.Params.Blocks = blocks
|
||||||
err := b.Call(&req, &res)
|
err = b.Call(&req, &res)
|
||||||
|
|
||||||
var r big.Int
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return r, err
|
return r, err
|
||||||
}
|
}
|
||||||
@ -891,7 +920,7 @@ func safeDecodeResponse(body io.ReadCloser, res interface{}) (err error) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}()
|
}()
|
||||||
data, err = ioutil.ReadAll(body)
|
data, err = io.ReadAll(body)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|||||||
135
bchain/coins/btc/mempoolspace.go
Normal file
135
bchain/coins/btc/mempoolspace.go
Normal file
@ -0,0 +1,135 @@
|
|||||||
|
package btc
|
||||||
|
|
||||||
|
import (
|
||||||
|
"bytes"
|
||||||
|
"encoding/json"
|
||||||
|
"net/http"
|
||||||
|
"strconv"
|
||||||
|
"time"
|
||||||
|
|
||||||
|
"github.com/golang/glog"
|
||||||
|
"github.com/juju/errors"
|
||||||
|
"github.com/trezor/blockbook/bchain"
|
||||||
|
)
|
||||||
|
|
||||||
|
// https://mempool.space/api/v1/fees/recommended returns
|
||||||
|
// {"fastestFee":41,"halfHourFee":39,"hourFee":36,"economyFee":36,"minimumFee":20}
|
||||||
|
|
||||||
|
type mempoolSpaceFeeResult struct {
|
||||||
|
FastestFee int `json:"fastestFee"`
|
||||||
|
HalfHourFee int `json:"halfHourFee"`
|
||||||
|
HourFee int `json:"hourFee"`
|
||||||
|
EconomyFee int `json:"economyFee"`
|
||||||
|
MinimumFee int `json:"minimumFee"`
|
||||||
|
}
|
||||||
|
|
||||||
|
type mempoolSpaceFeeParams struct {
|
||||||
|
URL string `json:"url"`
|
||||||
|
PeriodSeconds int `periodSeconds:"url"`
|
||||||
|
}
|
||||||
|
|
||||||
|
type mempoolSpaceFeeProvider struct {
|
||||||
|
*alternativeFeeProvider
|
||||||
|
params mempoolSpaceFeeParams
|
||||||
|
}
|
||||||
|
|
||||||
|
// NewMempoolSpaceFee initializes https://mempool.space provider
|
||||||
|
func NewMempoolSpaceFee(chain bchain.BlockChain, params string) (alternativeFeeProviderInterface, error) {
|
||||||
|
p := &mempoolSpaceFeeProvider{alternativeFeeProvider: &alternativeFeeProvider{}}
|
||||||
|
err := json.Unmarshal([]byte(params), &p.params)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
if p.params.URL == "" || p.params.PeriodSeconds == 0 {
|
||||||
|
return nil, errors.New("NewWhatTheFee: Missing parameters")
|
||||||
|
}
|
||||||
|
p.chain = chain
|
||||||
|
go p.mempoolSpaceFeeDownloader()
|
||||||
|
return p, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (p *mempoolSpaceFeeProvider) mempoolSpaceFeeDownloader() {
|
||||||
|
period := time.Duration(p.params.PeriodSeconds) * time.Second
|
||||||
|
timer := time.NewTimer(period)
|
||||||
|
counter := 0
|
||||||
|
for {
|
||||||
|
var data mempoolSpaceFeeResult
|
||||||
|
err := p.mempoolSpaceFeeGetData(&data)
|
||||||
|
if err != nil {
|
||||||
|
glog.Error("mempoolSpaceFeeGetData ", err)
|
||||||
|
} else {
|
||||||
|
if p.mempoolSpaceFeeProcessData(&data) {
|
||||||
|
if counter%60 == 0 {
|
||||||
|
p.compareToDefault()
|
||||||
|
}
|
||||||
|
counter++
|
||||||
|
}
|
||||||
|
}
|
||||||
|
<-timer.C
|
||||||
|
timer.Reset(period)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (p *mempoolSpaceFeeProvider) mempoolSpaceFeeProcessData(data *mempoolSpaceFeeResult) bool {
|
||||||
|
if data.MinimumFee == 0 || data.EconomyFee == 0 || data.HourFee == 0 || data.HalfHourFee == 0 || data.FastestFee == 0 {
|
||||||
|
glog.Errorf("mempoolSpaceFeeProcessData: invalid data %+v", data)
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
p.mux.Lock()
|
||||||
|
defer p.mux.Unlock()
|
||||||
|
p.fees = make([]alternativeFeeProviderFee, 5)
|
||||||
|
// map mempoool.space fees to blocks
|
||||||
|
|
||||||
|
// FastestFee is for 1 block
|
||||||
|
p.fees[0] = alternativeFeeProviderFee{
|
||||||
|
blocks: 1,
|
||||||
|
feePerKB: data.FastestFee * 1000,
|
||||||
|
}
|
||||||
|
|
||||||
|
// HalfHourFee is for 2-6 blocks
|
||||||
|
p.fees[1] = alternativeFeeProviderFee{
|
||||||
|
blocks: 6,
|
||||||
|
feePerKB: data.HalfHourFee * 1000,
|
||||||
|
}
|
||||||
|
|
||||||
|
// HourFee is for 7-36 blocks
|
||||||
|
p.fees[2] = alternativeFeeProviderFee{
|
||||||
|
blocks: 36,
|
||||||
|
feePerKB: data.HourFee * 1000,
|
||||||
|
}
|
||||||
|
|
||||||
|
// EconomyFee is for 37-200 blocks
|
||||||
|
p.fees[3] = alternativeFeeProviderFee{
|
||||||
|
blocks: 500,
|
||||||
|
feePerKB: data.EconomyFee * 1000,
|
||||||
|
}
|
||||||
|
|
||||||
|
// MinimumFee is for over 500 blocks
|
||||||
|
p.fees[4] = alternativeFeeProviderFee{
|
||||||
|
blocks: 1000,
|
||||||
|
feePerKB: data.MinimumFee * 1000,
|
||||||
|
}
|
||||||
|
|
||||||
|
p.lastSync = time.Now()
|
||||||
|
// glog.Infof("mempoolSpaceFees: %+v", p.fees)
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
|
||||||
|
func (p *mempoolSpaceFeeProvider) mempoolSpaceFeeGetData(res interface{}) error {
|
||||||
|
var httpData []byte
|
||||||
|
httpReq, err := http.NewRequest("GET", p.params.URL, bytes.NewBuffer(httpData))
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
httpRes, err := http.DefaultClient.Do(httpReq)
|
||||||
|
if httpRes != nil {
|
||||||
|
defer httpRes.Body.Close()
|
||||||
|
}
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
if httpRes.StatusCode != http.StatusOK {
|
||||||
|
return errors.New(p.params.URL + " returned status " + strconv.Itoa(httpRes.StatusCode))
|
||||||
|
}
|
||||||
|
return safeDecodeResponse(httpRes.Body, &res)
|
||||||
|
}
|
||||||
53
bchain/coins/btc/mempoolspace_test.go
Normal file
53
bchain/coins/btc/mempoolspace_test.go
Normal file
@ -0,0 +1,53 @@
|
|||||||
|
package btc
|
||||||
|
|
||||||
|
import (
|
||||||
|
"math/big"
|
||||||
|
"strconv"
|
||||||
|
"testing"
|
||||||
|
)
|
||||||
|
|
||||||
|
func Test_mempoolSpaceFeeProvider(t *testing.T) {
|
||||||
|
m := &mempoolSpaceFeeProvider{alternativeFeeProvider: &alternativeFeeProvider{}}
|
||||||
|
m.mempoolSpaceFeeProcessData(&mempoolSpaceFeeResult{
|
||||||
|
MinimumFee: 10,
|
||||||
|
EconomyFee: 20,
|
||||||
|
HourFee: 30,
|
||||||
|
HalfHourFee: 40,
|
||||||
|
FastestFee: 50,
|
||||||
|
})
|
||||||
|
|
||||||
|
tests := []struct {
|
||||||
|
blocks int
|
||||||
|
want big.Int
|
||||||
|
}{
|
||||||
|
{0, *big.NewInt(50000)},
|
||||||
|
{1, *big.NewInt(50000)},
|
||||||
|
{2, *big.NewInt(40000)},
|
||||||
|
{5, *big.NewInt(40000)},
|
||||||
|
{6, *big.NewInt(40000)},
|
||||||
|
{7, *big.NewInt(30000)},
|
||||||
|
{10, *big.NewInt(30000)},
|
||||||
|
{18, *big.NewInt(30000)},
|
||||||
|
{19, *big.NewInt(30000)},
|
||||||
|
{36, *big.NewInt(30000)},
|
||||||
|
{37, *big.NewInt(20000)},
|
||||||
|
{100, *big.NewInt(20000)},
|
||||||
|
{101, *big.NewInt(20000)},
|
||||||
|
{200, *big.NewInt(20000)},
|
||||||
|
{201, *big.NewInt(20000)},
|
||||||
|
{500, *big.NewInt(20000)},
|
||||||
|
{501, *big.NewInt(10000)},
|
||||||
|
{5000000, *big.NewInt(10000)},
|
||||||
|
}
|
||||||
|
for _, tt := range tests {
|
||||||
|
t.Run(strconv.Itoa(tt.blocks), func(t *testing.T) {
|
||||||
|
got, err := m.estimateFee(tt.blocks)
|
||||||
|
if err != nil {
|
||||||
|
t.Error("estimateFee returned error ", err)
|
||||||
|
}
|
||||||
|
if got.Cmp(&tt.want) != 0 {
|
||||||
|
t.Errorf("estimateFee(%d) = %v, want %v", tt.blocks, got, tt.want)
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -3,11 +3,9 @@ package btc
|
|||||||
import (
|
import (
|
||||||
"bytes"
|
"bytes"
|
||||||
"encoding/json"
|
"encoding/json"
|
||||||
"fmt"
|
|
||||||
"math"
|
"math"
|
||||||
"net/http"
|
"net/http"
|
||||||
"strconv"
|
"strconv"
|
||||||
"sync"
|
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
"github.com/golang/glog"
|
"github.com/golang/glog"
|
||||||
@ -34,49 +32,40 @@ type whatTheFeeParams struct {
|
|||||||
PeriodSeconds int `periodSeconds:"url"`
|
PeriodSeconds int `periodSeconds:"url"`
|
||||||
}
|
}
|
||||||
|
|
||||||
type whatTheFeeFee struct {
|
type whatTheFeeProvider struct {
|
||||||
blocks int
|
*alternativeFeeProvider
|
||||||
feesPerKB []int
|
|
||||||
}
|
|
||||||
|
|
||||||
type whatTheFeeData struct {
|
|
||||||
params whatTheFeeParams
|
params whatTheFeeParams
|
||||||
probabilities []string
|
probabilities []string
|
||||||
fees []whatTheFeeFee
|
|
||||||
lastSync time.Time
|
|
||||||
chain bchain.BlockChain
|
|
||||||
mux sync.Mutex
|
|
||||||
}
|
}
|
||||||
|
|
||||||
var whatTheFee whatTheFeeData
|
// NewWhatTheFee initializes https://whatthefee.io provider
|
||||||
|
func NewWhatTheFee(chain bchain.BlockChain, params string) (alternativeFeeProviderInterface, error) {
|
||||||
// InitWhatTheFee initializes https://whatthefee.io handler
|
var p whatTheFeeProvider
|
||||||
func InitWhatTheFee(chain bchain.BlockChain, params string) error {
|
err := json.Unmarshal([]byte(params), &p.params)
|
||||||
err := json.Unmarshal([]byte(params), &whatTheFee.params)
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return nil, err
|
||||||
}
|
}
|
||||||
if whatTheFee.params.URL == "" || whatTheFee.params.PeriodSeconds == 0 {
|
if p.params.URL == "" || p.params.PeriodSeconds == 0 {
|
||||||
return errors.New("Missing parameters")
|
return nil, errors.New("NewWhatTheFee: Missing parameters")
|
||||||
}
|
}
|
||||||
whatTheFee.chain = chain
|
p.chain = chain
|
||||||
go whatTheFeeDownloader()
|
go p.whatTheFeeDownloader()
|
||||||
return nil
|
return &p, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func whatTheFeeDownloader() {
|
func (p *whatTheFeeProvider) whatTheFeeDownloader() {
|
||||||
period := time.Duration(whatTheFee.params.PeriodSeconds) * time.Second
|
period := time.Duration(p.params.PeriodSeconds) * time.Second
|
||||||
timer := time.NewTimer(period)
|
timer := time.NewTimer(period)
|
||||||
counter := 0
|
counter := 0
|
||||||
for {
|
for {
|
||||||
var data whatTheFeeServiceResult
|
var data whatTheFeeServiceResult
|
||||||
err := whatTheFeeGetData(&data)
|
err := p.whatTheFeeGetData(&data)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
glog.Error("whatTheFeeGetData ", err)
|
glog.Error("whatTheFeeGetData ", err)
|
||||||
} else {
|
} else {
|
||||||
if whatTheFeeProcessData(&data) {
|
if p.whatTheFeeProcessData(&data) {
|
||||||
if counter%60 == 0 {
|
if counter%60 == 0 {
|
||||||
whatTheFeeCompareToDefault()
|
p.compareToDefault()
|
||||||
}
|
}
|
||||||
counter++
|
counter++
|
||||||
}
|
}
|
||||||
@ -86,15 +75,15 @@ func whatTheFeeDownloader() {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func whatTheFeeProcessData(data *whatTheFeeServiceResult) bool {
|
func (p *whatTheFeeProvider) whatTheFeeProcessData(data *whatTheFeeServiceResult) bool {
|
||||||
if len(data.Index) == 0 || len(data.Index) != len(data.Data) || len(data.Columns) == 0 {
|
if len(data.Index) == 0 || len(data.Index) != len(data.Data) || len(data.Columns) == 0 {
|
||||||
glog.Errorf("invalid data %+v", data)
|
glog.Errorf("invalid data %+v", data)
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
whatTheFee.mux.Lock()
|
p.mux.Lock()
|
||||||
defer whatTheFee.mux.Unlock()
|
defer p.mux.Unlock()
|
||||||
whatTheFee.probabilities = data.Columns
|
p.probabilities = data.Columns
|
||||||
whatTheFee.fees = make([]whatTheFeeFee, len(data.Index))
|
p.fees = make([]alternativeFeeProviderFee, len(data.Index))
|
||||||
for i, blocks := range data.Index {
|
for i, blocks := range data.Index {
|
||||||
if len(data.Columns) != len(data.Data[i]) {
|
if len(data.Columns) != len(data.Data[i]) {
|
||||||
glog.Errorf("invalid data %+v", data)
|
glog.Errorf("invalid data %+v", data)
|
||||||
@ -104,19 +93,19 @@ func whatTheFeeProcessData(data *whatTheFeeServiceResult) bool {
|
|||||||
for j, l := range data.Data[i] {
|
for j, l := range data.Data[i] {
|
||||||
fees[j] = int(1000 * math.Exp(float64(l)/100))
|
fees[j] = int(1000 * math.Exp(float64(l)/100))
|
||||||
}
|
}
|
||||||
whatTheFee.fees[i] = whatTheFeeFee{
|
p.fees[i] = alternativeFeeProviderFee{
|
||||||
blocks: blocks,
|
blocks: blocks,
|
||||||
feesPerKB: fees,
|
feePerKB: fees[len(fees)/2],
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
whatTheFee.lastSync = time.Now()
|
p.lastSync = time.Now()
|
||||||
glog.Infof("%+v", whatTheFee.fees)
|
glog.Infof("whatTheFees: %+v", p.fees)
|
||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
|
|
||||||
func whatTheFeeGetData(res interface{}) error {
|
func (p *whatTheFeeProvider) whatTheFeeGetData(res interface{}) error {
|
||||||
var httpData []byte
|
var httpData []byte
|
||||||
httpReq, err := http.NewRequest("GET", whatTheFee.params.URL, bytes.NewBuffer(httpData))
|
httpReq, err := http.NewRequest("GET", p.params.URL, bytes.NewBuffer(httpData))
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
@ -132,25 +121,3 @@ func whatTheFeeGetData(res interface{}) error {
|
|||||||
}
|
}
|
||||||
return safeDecodeResponse(httpRes.Body, &res)
|
return safeDecodeResponse(httpRes.Body, &res)
|
||||||
}
|
}
|
||||||
|
|
||||||
func whatTheFeeCompareToDefault() {
|
|
||||||
output := ""
|
|
||||||
for _, fee := range whatTheFee.fees {
|
|
||||||
output += fmt.Sprint(fee.blocks, ",")
|
|
||||||
for _, wtf := range fee.feesPerKB {
|
|
||||||
output += fmt.Sprint(wtf, ",")
|
|
||||||
}
|
|
||||||
conservative, err := whatTheFee.chain.EstimateSmartFee(fee.blocks, true)
|
|
||||||
if err != nil {
|
|
||||||
glog.Error(err)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
economical, err := whatTheFee.chain.EstimateSmartFee(fee.blocks, false)
|
|
||||||
if err != nil {
|
|
||||||
glog.Error(err)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
output += fmt.Sprint(conservative.String(), ",", economical.String(), "\n")
|
|
||||||
}
|
|
||||||
glog.Info("whatTheFeeCompareToDefault\n", output)
|
|
||||||
}
|
|
||||||
|
|||||||
@ -3,11 +3,11 @@ package ecash
|
|||||||
import (
|
import (
|
||||||
"fmt"
|
"fmt"
|
||||||
|
|
||||||
"github.com/pirk/ecashutil"
|
|
||||||
"github.com/martinboehm/btcutil"
|
"github.com/martinboehm/btcutil"
|
||||||
"github.com/martinboehm/btcutil/chaincfg"
|
"github.com/martinboehm/btcutil/chaincfg"
|
||||||
"github.com/martinboehm/btcutil/txscript"
|
"github.com/martinboehm/btcutil/txscript"
|
||||||
"github.com/pirk/ecashaddr-converter/address"
|
"github.com/pirk/ecashaddr-converter/address"
|
||||||
|
"github.com/pirk/ecashutil"
|
||||||
"github.com/trezor/blockbook/bchain"
|
"github.com/trezor/blockbook/bchain"
|
||||||
"github.com/trezor/blockbook/bchain/coins/btc"
|
"github.com/trezor/blockbook/bchain/coins/btc"
|
||||||
)
|
)
|
||||||
|
|||||||
@ -342,6 +342,10 @@ func Test_UnpackTx(t *testing.T) {
|
|||||||
t.Errorf("unpackTx() error = %v, wantErr %v", err, tt.wantErr)
|
t.Errorf("unpackTx() error = %v, wantErr %v", err, tt.wantErr)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
// ignore witness unpacking
|
||||||
|
for i := range got.Vin {
|
||||||
|
got.Vin[i].Witness = nil
|
||||||
|
}
|
||||||
if !reflect.DeepEqual(got, tt.want) {
|
if !reflect.DeepEqual(got, tt.want) {
|
||||||
t.Errorf("unpackTx() got = %v, want %v", got, tt.want)
|
t.Errorf("unpackTx() got = %v, want %v", got, tt.want)
|
||||||
}
|
}
|
||||||
|
|||||||
@ -273,14 +273,19 @@ func contractGetTransfersFromTx(tx *bchain.RpcTransaction) (bchain.TokenTransfer
|
|||||||
return r, nil
|
return r, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (b *EthereumRPC) ethCall(data, to string) (string, error) {
|
// EthereumTypeRpcCall calls eth_call with given data and to address
|
||||||
|
func (b *EthereumRPC) EthereumTypeRpcCall(data, to, from string) (string, error) {
|
||||||
ctx, cancel := context.WithTimeout(context.Background(), b.Timeout)
|
ctx, cancel := context.WithTimeout(context.Background(), b.Timeout)
|
||||||
defer cancel()
|
defer cancel()
|
||||||
var r string
|
var r string
|
||||||
err := b.RPC.CallContext(ctx, &r, "eth_call", map[string]interface{}{
|
args := map[string]interface{}{
|
||||||
"data": data,
|
"data": data,
|
||||||
"to": to,
|
"to": to,
|
||||||
}, "latest")
|
}
|
||||||
|
if from != "" {
|
||||||
|
args["from"] = from
|
||||||
|
}
|
||||||
|
err := b.RPC.CallContext(ctx, &r, "eth_call", args, "latest")
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return "", err
|
return "", err
|
||||||
}
|
}
|
||||||
@ -289,7 +294,7 @@ func (b *EthereumRPC) ethCall(data, to string) (string, error) {
|
|||||||
|
|
||||||
func (b *EthereumRPC) fetchContractInfo(address string) (*bchain.ContractInfo, error) {
|
func (b *EthereumRPC) fetchContractInfo(address string) (*bchain.ContractInfo, error) {
|
||||||
var contract bchain.ContractInfo
|
var contract bchain.ContractInfo
|
||||||
data, err := b.ethCall(contractNameSignature, address)
|
data, err := b.EthereumTypeRpcCall(contractNameSignature, address, "")
|
||||||
if err != nil {
|
if err != nil {
|
||||||
// ignore the error from the eth_call - since geth v1.9.15 they changed the behavior
|
// 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
|
// and returning error "execution reverted" for some non contract addresses
|
||||||
@ -300,14 +305,14 @@ func (b *EthereumRPC) fetchContractInfo(address string) (*bchain.ContractInfo, e
|
|||||||
}
|
}
|
||||||
name := strings.TrimSpace(parseSimpleStringProperty(data))
|
name := strings.TrimSpace(parseSimpleStringProperty(data))
|
||||||
if name != "" {
|
if name != "" {
|
||||||
data, err = b.ethCall(contractSymbolSignature, address)
|
data, err = b.EthereumTypeRpcCall(contractSymbolSignature, address, "")
|
||||||
if err != nil {
|
if err != nil {
|
||||||
// glog.Warning(errors.Annotatef(err, "Contract SymbolSignature %v", address))
|
// glog.Warning(errors.Annotatef(err, "Contract SymbolSignature %v", address))
|
||||||
return nil, nil
|
return nil, nil
|
||||||
// return nil, errors.Annotatef(err, "erc20SymbolSignature %v", address)
|
// return nil, errors.Annotatef(err, "erc20SymbolSignature %v", address)
|
||||||
}
|
}
|
||||||
symbol := strings.TrimSpace(parseSimpleStringProperty(data))
|
symbol := strings.TrimSpace(parseSimpleStringProperty(data))
|
||||||
data, _ = b.ethCall(contractDecimalsSignature, address)
|
data, _ = b.EthereumTypeRpcCall(contractDecimalsSignature, address, "")
|
||||||
// if err != nil {
|
// if err != nil {
|
||||||
// glog.Warning(errors.Annotatef(err, "Contract DecimalsSignature %v", address))
|
// glog.Warning(errors.Annotatef(err, "Contract DecimalsSignature %v", address))
|
||||||
// // return nil, errors.Annotatef(err, "erc20DecimalsSignature %v", address)
|
// // return nil, errors.Annotatef(err, "erc20DecimalsSignature %v", address)
|
||||||
@ -337,10 +342,10 @@ func (b *EthereumRPC) GetContractInfo(contractDesc bchain.AddressDescriptor) (*b
|
|||||||
|
|
||||||
// EthereumTypeGetErc20ContractBalance returns balance of ERC20 contract for given address
|
// EthereumTypeGetErc20ContractBalance returns balance of ERC20 contract for given address
|
||||||
func (b *EthereumRPC) EthereumTypeGetErc20ContractBalance(addrDesc, contractDesc bchain.AddressDescriptor) (*big.Int, error) {
|
func (b *EthereumRPC) EthereumTypeGetErc20ContractBalance(addrDesc, contractDesc bchain.AddressDescriptor) (*big.Int, error) {
|
||||||
addr := hexutil.Encode(addrDesc)
|
addr := hexutil.Encode(addrDesc)[2:]
|
||||||
contract := hexutil.Encode(contractDesc)
|
contract := hexutil.Encode(contractDesc)
|
||||||
req := contractBalanceOfSignature + "0000000000000000000000000000000000000000000000000000000000000000"[len(addr)-2:] + addr[2:]
|
req := contractBalanceOfSignature + "0000000000000000000000000000000000000000000000000000000000000000"[len(addr):] + addr
|
||||||
data, err := b.ethCall(req, contract)
|
data, err := b.EthereumTypeRpcCall(req, contract, "")
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
@ -351,7 +356,7 @@ func (b *EthereumRPC) EthereumTypeGetErc20ContractBalance(addrDesc, contractDesc
|
|||||||
return r, nil
|
return r, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// GetContractInfo returns URI of non fungible or multi token defined by token id
|
// GetTokenURI returns URI of non fungible or multi token defined by token id
|
||||||
func (b *EthereumRPC) GetTokenURI(contractDesc bchain.AddressDescriptor, tokenID *big.Int) (string, error) {
|
func (b *EthereumRPC) GetTokenURI(contractDesc bchain.AddressDescriptor, tokenID *big.Int) (string, error) {
|
||||||
address := hexutil.Encode(contractDesc)
|
address := hexutil.Encode(contractDesc)
|
||||||
// CryptoKitties do not fully support ERC721 standard, do not have tokenURI method
|
// CryptoKitties do not fully support ERC721 standard, do not have tokenURI method
|
||||||
@ -364,7 +369,7 @@ func (b *EthereumRPC) GetTokenURI(contractDesc bchain.AddressDescriptor, tokenID
|
|||||||
}
|
}
|
||||||
// try ERC721 tokenURI method and ERC1155 uri method
|
// try ERC721 tokenURI method and ERC1155 uri method
|
||||||
for _, method := range []string{erc721TokenURIMethodSignature, erc1155URIMethodSignature} {
|
for _, method := range []string{erc721TokenURIMethodSignature, erc1155URIMethodSignature} {
|
||||||
data, err := b.ethCall(method+id, address)
|
data, err := b.EthereumTypeRpcCall(method+id, address, "")
|
||||||
if err == nil && data != "" {
|
if err == nil && data != "" {
|
||||||
uri := parseSimpleStringProperty(data)
|
uri := parseSimpleStringProperty(data)
|
||||||
// try to sanitize the URI returned from the contract
|
// try to sanitize the URI returned from the contract
|
||||||
|
|||||||
@ -1,291 +0,0 @@
|
|||||||
//go:build unittest
|
|
||||||
|
|
||||||
package eth
|
|
||||||
|
|
||||||
import (
|
|
||||||
"fmt"
|
|
||||||
"math/big"
|
|
||||||
"strings"
|
|
||||||
"testing"
|
|
||||||
|
|
||||||
"github.com/trezor/blockbook/bchain"
|
|
||||||
"github.com/trezor/blockbook/tests/dbtestdata"
|
|
||||||
)
|
|
||||||
|
|
||||||
func Test_contractGetTransfersFromLog(t *testing.T) {
|
|
||||||
tests := []struct {
|
|
||||||
name string
|
|
||||||
args []*bchain.RpcLog
|
|
||||||
want bchain.TokenTransfers
|
|
||||||
wantErr bool
|
|
||||||
}{
|
|
||||||
{
|
|
||||||
name: "ERC20 transfer 1",
|
|
||||||
args: []*bchain.RpcLog{
|
|
||||||
{
|
|
||||||
Address: "0x76a45e8976499ab9ae223cc584019341d5a84e96",
|
|
||||||
Topics: []string{
|
|
||||||
"0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef",
|
|
||||||
"0x0000000000000000000000002aacf811ac1a60081ea39f7783c0d26c500871a8",
|
|
||||||
"0x000000000000000000000000e9a5216ff992cfa01594d43501a56e12769eb9d2",
|
|
||||||
},
|
|
||||||
Data: "0x0000000000000000000000000000000000000000000000000000000000000123",
|
|
||||||
},
|
|
||||||
},
|
|
||||||
want: bchain.TokenTransfers{
|
|
||||||
{
|
|
||||||
Contract: "0x76a45e8976499ab9ae223cc584019341d5a84e96",
|
|
||||||
From: "0x2aacf811ac1a60081ea39f7783c0d26c500871a8",
|
|
||||||
To: "0xe9a5216ff992cfa01594d43501a56e12769eb9d2",
|
|
||||||
Value: *big.NewInt(0x123),
|
|
||||||
},
|
|
||||||
},
|
|
||||||
},
|
|
||||||
{
|
|
||||||
name: "ERC20 transfer 2",
|
|
||||||
args: []*bchain.RpcLog{
|
|
||||||
{ // Transfer
|
|
||||||
Address: "0x0d0f936ee4c93e25944694d6c121de94d9760f11",
|
|
||||||
Topics: []string{
|
|
||||||
"0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef",
|
|
||||||
"0x0000000000000000000000006f44cceb49b4a5812d54b6f494fc2febf25511ed",
|
|
||||||
"0x0000000000000000000000004bda106325c335df99eab7fe363cac8a0ba2a24d",
|
|
||||||
},
|
|
||||||
Data: "0x0000000000000000000000000000000000000000000000006a8313d60b1f606b",
|
|
||||||
},
|
|
||||||
{ // Transfer
|
|
||||||
Address: "0xc778417e063141139fce010982780140aa0cd5ab",
|
|
||||||
Topics: []string{
|
|
||||||
"0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef",
|
|
||||||
"0x0000000000000000000000004bda106325c335df99eab7fe363cac8a0ba2a24d",
|
|
||||||
"0x0000000000000000000000006f44cceb49b4a5812d54b6f494fc2febf25511ed",
|
|
||||||
},
|
|
||||||
Data: "0x000000000000000000000000000000000000000000000000000308fd0e798ac0",
|
|
||||||
},
|
|
||||||
{ // not Transfer
|
|
||||||
Address: "0x479cc461fecd078f766ecc58533d6f69580cf3ac",
|
|
||||||
Topics: []string{
|
|
||||||
"0x0d0b9391970d9a25552f37d436d2aae2925e2bfe1b2a923754bada030c498cb3",
|
|
||||||
"0x0000000000000000000000006f44cceb49b4a5812d54b6f494fc2febf25511ed",
|
|
||||||
"0x0000000000000000000000000000000000000000000000000000000000000000",
|
|
||||||
"0x5af266c0a89a07c1917deaa024414577e6c3c31c8907d079e13eb448c082594f",
|
|
||||||
},
|
|
||||||
Data: "0x0000000000000000000000004bda106325c335df99eab7fe363cac8a0ba2a24d0000000000000",
|
|
||||||
},
|
|
||||||
{ // not Transfer
|
|
||||||
Address: "0x0d0f936ee4c93e25944694d6c121de94d9760f11",
|
|
||||||
Topics: []string{
|
|
||||||
"0x0d0b9391970d9a25552f37d436d2aae2925e2bfe1b2a923754bada030c498cb3",
|
|
||||||
"0x0000000000000000000000007b62eb7fe80350dc7ec945c0b73242cb9877fb1b",
|
|
||||||
"0xb0b69dad58df6032c3b266e19b1045b19c87acd2c06fb0c598090f44b8e263aa",
|
|
||||||
},
|
|
||||||
Data: "0x0000000000000000000000004bda106325c335df99eab7fe363cac8a0ba2a24d000000000000000000000000c778417e063141139fce010982780140aa0cd5ab0000000000000000000000000d0f936ee4c93e25944694d6c121de94d9760f1100000000000000000000000000000000000000000000000000031855667df7a80000000000000000000000000000000000000000000000006a8313d60b1f800000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000",
|
|
||||||
},
|
|
||||||
},
|
|
||||||
want: bchain.TokenTransfers{
|
|
||||||
{
|
|
||||||
Contract: "0x0d0f936ee4c93e25944694d6c121de94d9760f11",
|
|
||||||
From: "0x6f44cceb49b4a5812d54b6f494fc2febf25511ed",
|
|
||||||
To: "0x4bda106325c335df99eab7fe363cac8a0ba2a24d",
|
|
||||||
Value: *big.NewInt(0x6a8313d60b1f606b),
|
|
||||||
},
|
|
||||||
{
|
|
||||||
Contract: "0xc778417e063141139fce010982780140aa0cd5ab",
|
|
||||||
From: "0x4bda106325c335df99eab7fe363cac8a0ba2a24d",
|
|
||||||
To: "0x6f44cceb49b4a5812d54b6f494fc2febf25511ed",
|
|
||||||
Value: *big.NewInt(0x308fd0e798ac0),
|
|
||||||
},
|
|
||||||
},
|
|
||||||
},
|
|
||||||
{
|
|
||||||
name: "ERC721 transfer 1",
|
|
||||||
args: []*bchain.RpcLog{
|
|
||||||
{ // Approval
|
|
||||||
Address: "0x5689b918D34C038901870105A6C7fc24744D31eB",
|
|
||||||
Topics: []string{
|
|
||||||
"0x8c5be1e5ebec7d5bd14f71427d1e84f3dd0314c0f7b2291e5b200ac8c7c3b925",
|
|
||||||
"0x0000000000000000000000000a206d4d5ff79cb5069def7fe3598421cff09391",
|
|
||||||
"0x0000000000000000000000000000000000000000000000000000000000000000",
|
|
||||||
"0x0000000000000000000000000000000000000000000000000000000000001396",
|
|
||||||
},
|
|
||||||
Data: "0x",
|
|
||||||
},
|
|
||||||
{ // Transfer
|
|
||||||
Address: "0x5689b918D34C038901870105A6C7fc24744D31eB",
|
|
||||||
Topics: []string{
|
|
||||||
"0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef",
|
|
||||||
"0x0000000000000000000000000a206d4d5ff79cb5069def7fe3598421cff09391",
|
|
||||||
"0x0000000000000000000000006a016d7eec560549ffa0fbdb7f15c2b27302087f",
|
|
||||||
"0x0000000000000000000000000000000000000000000000000000000000001396",
|
|
||||||
},
|
|
||||||
Data: "0x",
|
|
||||||
},
|
|
||||||
{ // OrdersMatched
|
|
||||||
Address: "0x7Be8076f4EA4A4AD08075C2508e481d6C946D12b",
|
|
||||||
Topics: []string{
|
|
||||||
"0xc4109843e0b7d514e4c093114b863f8e7d8d9a458c372cd51bfe526b588006c9",
|
|
||||||
"0x0000000000000000000000000a206d4d5ff79cb5069def7fe3598421cff09391",
|
|
||||||
"0x0000000000000000000000006a016d7eec560549ffa0fbdb7f15c2b27302087f",
|
|
||||||
"0x0000000000000000000000000000000000000000000000000000000000000000",
|
|
||||||
},
|
|
||||||
Data: "0x000000000000000000000000000000000000000000000000000000000000000069d3f0cc25f121f2aa96215f51ec4b4f1966f2d2ffbd3d8d8a45ad27b1c90323000000000000000000000000000000000000000000000000008e1bc9bf040000",
|
|
||||||
},
|
|
||||||
},
|
|
||||||
want: bchain.TokenTransfers{
|
|
||||||
{
|
|
||||||
Type: bchain.NonFungibleToken,
|
|
||||||
Contract: "0x5689b918D34C038901870105A6C7fc24744D31eB",
|
|
||||||
From: "0x0a206d4d5ff79cb5069def7fe3598421cff09391",
|
|
||||||
To: "0x6a016d7eec560549ffa0fbdb7f15c2b27302087f",
|
|
||||||
Value: *big.NewInt(0x1396),
|
|
||||||
},
|
|
||||||
},
|
|
||||||
},
|
|
||||||
{
|
|
||||||
name: "ERC1155 TransferSingle",
|
|
||||||
args: []*bchain.RpcLog{
|
|
||||||
{ // Transfer
|
|
||||||
Address: "0x6Fd712E3A5B556654044608F9129040A4839E36c",
|
|
||||||
Topics: []string{
|
|
||||||
"0x5f9832c7244497a64c11c4a4f7597934bdf02b0361c54ad8e90091c2ce1f9e3c",
|
|
||||||
},
|
|
||||||
Data: "0x000000000000000000000000a3950b823cb063dd9afc0d27f35008b805b3ed530000000000000000000000004392faf3bb96b5694ecc6ef64726f61cdd4bb0ec000000000000000000000000000000000000000000000000000000000000008000000000000000000000000000000000000000000000000000000000000000c00000000000000000000000000000000000000000000000000000000000000001000000000000000000000000000000000000000000000000000000000000009600000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000001",
|
|
||||||
},
|
|
||||||
{ // TransferSingle
|
|
||||||
Address: "0x6Fd712E3A5B556654044608F9129040A4839E36c",
|
|
||||||
Topics: []string{
|
|
||||||
"0xc3d58168c5ae7397731d063d5bbf3d657854427343f4c083240f7aacaa2d0f62",
|
|
||||||
"0x0000000000000000000000009248a6048a58db9f0212dc7cd85ee8741128be72",
|
|
||||||
"0x000000000000000000000000a3950b823cb063dd9afc0d27f35008b805b3ed53",
|
|
||||||
"0x0000000000000000000000004392faf3bb96b5694ecc6ef64726f61cdd4bb0ec",
|
|
||||||
},
|
|
||||||
Data: "0x00000000000000000000000000000000000000000000000000000000000000960000000000000000000000000000000000000000000000000000000000000011",
|
|
||||||
},
|
|
||||||
{ // unknown
|
|
||||||
Address: "0x9248A6048a58db9f0212dC7CD85eE8741128be72",
|
|
||||||
Topics: []string{
|
|
||||||
"0x0b7bef9468bee71526deef3cbbded0ec1a0aa3d5a3e81eaffb0e758552b33199",
|
|
||||||
},
|
|
||||||
Data: "0x0000000000000000000000000000000000000000000000000000000000000060000000000000000000000000a3950b823cb063dd9afc0d27f35008b805b3ed530000000000000000000000004392faf3bb96b5694ecc6ef64726f61cdd4bb0ec0000000000000000000000000000000000000000000000000000000000000001",
|
|
||||||
},
|
|
||||||
},
|
|
||||||
want: bchain.TokenTransfers{
|
|
||||||
{
|
|
||||||
Type: bchain.MultiToken,
|
|
||||||
Contract: "0x6Fd712E3A5B556654044608F9129040A4839E36c",
|
|
||||||
From: "0xa3950b823cb063dd9afc0d27f35008b805b3ed53",
|
|
||||||
To: "0x4392faf3bb96b5694ecc6ef64726f61cdd4bb0ec",
|
|
||||||
MultiTokenValues: []bchain.MultiTokenValue{{Id: *big.NewInt(150), Value: *big.NewInt(0x11)}},
|
|
||||||
},
|
|
||||||
},
|
|
||||||
},
|
|
||||||
{
|
|
||||||
name: "ERC1155 TransferBatch",
|
|
||||||
args: []*bchain.RpcLog{
|
|
||||||
{ // TransferBatch
|
|
||||||
Address: "0x6c42C26a081c2F509F8bb68fb7Ac3062311cCfB7",
|
|
||||||
Topics: []string{
|
|
||||||
"0x4a39dc06d4c0dbc64b70af90fd698a233a518aa5d07e595d983b8c0526c8f7fb",
|
|
||||||
"0x0000000000000000000000005dc6288b35e0807a3d6feb89b3a2ff4ab773168e",
|
|
||||||
"0x0000000000000000000000000000000000000000000000000000000000000000",
|
|
||||||
"0x0000000000000000000000005dc6288b35e0807a3d6feb89b3a2ff4ab773168e",
|
|
||||||
},
|
|
||||||
Data: "0x000000000000000000000000000000000000000000000000000000000000004000000000000000000000000000000000000000000000000000000000000000a0000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000006f0000000000000000000000000000000000000000000000000000000000000076a00000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000001000000000000000000000000000000000000000000000000000000000000000a",
|
|
||||||
},
|
|
||||||
},
|
|
||||||
want: bchain.TokenTransfers{
|
|
||||||
{
|
|
||||||
Type: bchain.MultiToken,
|
|
||||||
Contract: "0x6c42c26a081c2f509f8bb68fb7ac3062311ccfb7",
|
|
||||||
From: "0x0000000000000000000000000000000000000000",
|
|
||||||
To: "0x5dc6288b35e0807a3d6feb89b3a2ff4ab773168e",
|
|
||||||
MultiTokenValues: []bchain.MultiTokenValue{
|
|
||||||
{Id: *big.NewInt(1776), Value: *big.NewInt(1)},
|
|
||||||
{Id: *big.NewInt(1898), Value: *big.NewInt(10)},
|
|
||||||
},
|
|
||||||
},
|
|
||||||
},
|
|
||||||
}}
|
|
||||||
for _, tt := range tests {
|
|
||||||
t.Run(tt.name, func(t *testing.T) {
|
|
||||||
got, err := contractGetTransfersFromLog(tt.args)
|
|
||||||
if (err != nil) != tt.wantErr {
|
|
||||||
t.Errorf("contractGetTransfersFromLog error = %v, wantErr %v", err, tt.wantErr)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
if len(got) != len(tt.want) {
|
|
||||||
t.Errorf("contractGetTransfersFromLog len not same, %+v, want %+v", got, tt.want)
|
|
||||||
}
|
|
||||||
for i := range got {
|
|
||||||
// the addresses could have different case
|
|
||||||
if strings.ToLower(fmt.Sprint(got[i])) != strings.ToLower(fmt.Sprint(tt.want[i])) {
|
|
||||||
t.Errorf("contractGetTransfersFromLog %d = %+v, want %+v", i, got[i], tt.want[i])
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
})
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func Test_contractGetTransfersFromTx(t *testing.T) {
|
|
||||||
p := NewEthereumParser(1, false)
|
|
||||||
b1 := dbtestdata.GetTestEthereumTypeBlock1(p)
|
|
||||||
b2 := dbtestdata.GetTestEthereumTypeBlock2(p)
|
|
||||||
bn, _ := new(big.Int).SetString("21e19e0c9bab2400000", 16)
|
|
||||||
tests := []struct {
|
|
||||||
name string
|
|
||||||
args *bchain.RpcTransaction
|
|
||||||
want bchain.TokenTransfers
|
|
||||||
}{
|
|
||||||
{
|
|
||||||
name: "no contract transfer",
|
|
||||||
args: (b1.Txs[0].CoinSpecificData.(bchain.EthereumSpecificData)).Tx,
|
|
||||||
want: bchain.TokenTransfers{},
|
|
||||||
},
|
|
||||||
{
|
|
||||||
name: "ERC20 transfer",
|
|
||||||
args: (b1.Txs[1].CoinSpecificData.(bchain.EthereumSpecificData)).Tx,
|
|
||||||
want: bchain.TokenTransfers{
|
|
||||||
{
|
|
||||||
Type: bchain.FungibleToken,
|
|
||||||
Contract: "0x4af4114f73d1c1c903ac9e0361b379d1291808a2",
|
|
||||||
From: "0x20cd153de35d469ba46127a0c8f18626b59a256a",
|
|
||||||
To: "0x555ee11fbddc0e49a9bab358a8941ad95ffdb48f",
|
|
||||||
Value: *bn,
|
|
||||||
},
|
|
||||||
},
|
|
||||||
},
|
|
||||||
{
|
|
||||||
name: "ERC721 transferFrom",
|
|
||||||
args: (b2.Txs[2].CoinSpecificData.(bchain.EthereumSpecificData)).Tx,
|
|
||||||
want: bchain.TokenTransfers{
|
|
||||||
{
|
|
||||||
Type: bchain.NonFungibleToken,
|
|
||||||
Contract: "0xcda9fc258358ecaa88845f19af595e908bb7efe9",
|
|
||||||
From: "0x837e3f699d85a4b0b99894567e9233dfb1dcb081",
|
|
||||||
To: "0x7b62eb7fe80350dc7ec945c0b73242cb9877fb1b",
|
|
||||||
Value: *big.NewInt(1),
|
|
||||||
},
|
|
||||||
},
|
|
||||||
},
|
|
||||||
}
|
|
||||||
for _, tt := range tests {
|
|
||||||
t.Run(tt.name, func(t *testing.T) {
|
|
||||||
got, err := contractGetTransfersFromTx(tt.args)
|
|
||||||
if err != nil {
|
|
||||||
t.Errorf("contractGetTransfersFromTx error = %v", err)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
if len(got) != len(tt.want) {
|
|
||||||
t.Errorf("contractGetTransfersFromTx len not same, %+v, want %+v", got, tt.want)
|
|
||||||
}
|
|
||||||
for i := range got {
|
|
||||||
// the addresses could have different case
|
|
||||||
if strings.ToLower(fmt.Sprint(got[i])) != strings.ToLower(fmt.Sprint(tt.want[i])) {
|
|
||||||
t.Errorf("contractGetTransfersFromTx %d = %+v, want %+v", i, got[i], tt.want[i])
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
})
|
|
||||||
}
|
|
||||||
}
|
|
||||||
File diff suppressed because one or more lines are too long
@ -7,10 +7,10 @@ import (
|
|||||||
"strings"
|
"strings"
|
||||||
|
|
||||||
"github.com/ethereum/go-ethereum/common/hexutil"
|
"github.com/ethereum/go-ethereum/common/hexutil"
|
||||||
"github.com/golang/protobuf/proto"
|
|
||||||
"github.com/juju/errors"
|
"github.com/juju/errors"
|
||||||
"github.com/trezor/blockbook/bchain"
|
"github.com/trezor/blockbook/bchain"
|
||||||
"golang.org/x/crypto/sha3"
|
"golang.org/x/crypto/sha3"
|
||||||
|
"google.golang.org/protobuf/proto"
|
||||||
)
|
)
|
||||||
|
|
||||||
// EthereumTypeAddressDescriptorLen - the AddressDescriptor of EthereumType has fixed length
|
// EthereumTypeAddressDescriptorLen - the AddressDescriptor of EthereumType has fixed length
|
||||||
@ -25,15 +25,19 @@ const EtherAmountDecimalPoint = 18
|
|||||||
// EthereumParser handle
|
// EthereumParser handle
|
||||||
type EthereumParser struct {
|
type EthereumParser struct {
|
||||||
*bchain.BaseParser
|
*bchain.BaseParser
|
||||||
|
EnsSuffix string
|
||||||
}
|
}
|
||||||
|
|
||||||
// NewEthereumParser returns new EthereumParser instance
|
// NewEthereumParser returns new EthereumParser instance
|
||||||
func NewEthereumParser(b int, addressAliases bool) *EthereumParser {
|
func NewEthereumParser(b int, addressAliases bool) *EthereumParser {
|
||||||
return &EthereumParser{&bchain.BaseParser{
|
return &EthereumParser{
|
||||||
BlockAddressesToKeep: b,
|
BaseParser: &bchain.BaseParser{
|
||||||
AmountDecimalPoint: EtherAmountDecimalPoint,
|
BlockAddressesToKeep: b,
|
||||||
AddressAliases: addressAliases,
|
AmountDecimalPoint: EtherAmountDecimalPoint,
|
||||||
}}
|
AddressAliases: addressAliases,
|
||||||
|
},
|
||||||
|
EnsSuffix: ".eth",
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
type rpcHeader struct {
|
type rpcHeader struct {
|
||||||
@ -331,6 +335,24 @@ func (p *EthereumParser) PackTx(tx *bchain.Tx, height uint32, blockTime int64) (
|
|||||||
|
|
||||||
}
|
}
|
||||||
pt.Receipt.Log = ptLogs
|
pt.Receipt.Log = ptLogs
|
||||||
|
if r.Receipt.L1Fee != "" {
|
||||||
|
if pt.Receipt.L1Fee, err = hexDecodeBig(r.Receipt.L1Fee); err != nil {
|
||||||
|
return nil, errors.Annotatef(err, "L1Fee %v", r.Receipt.L1Fee)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if r.Receipt.L1FeeScalar != "" {
|
||||||
|
pt.Receipt.L1FeeScalar = []byte(r.Receipt.L1FeeScalar)
|
||||||
|
}
|
||||||
|
if r.Receipt.L1GasPrice != "" {
|
||||||
|
if pt.Receipt.L1GasPrice, err = hexDecodeBig(r.Receipt.L1GasPrice); err != nil {
|
||||||
|
return nil, errors.Annotatef(err, "L1GasPrice %v", r.Receipt.L1GasPrice)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if r.Receipt.L1GasUsed != "" {
|
||||||
|
if pt.Receipt.L1GasUsed, err = hexDecodeBig(r.Receipt.L1GasUsed); err != nil {
|
||||||
|
return nil, errors.Annotatef(err, "L1GasUsed %v", r.Receipt.L1GasUsed)
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
return proto.Marshal(pt)
|
return proto.Marshal(pt)
|
||||||
}
|
}
|
||||||
@ -359,27 +381,37 @@ func (p *EthereumParser) UnpackTx(buf []byte) (*bchain.Tx, uint32, error) {
|
|||||||
}
|
}
|
||||||
var rr *bchain.RpcReceipt
|
var rr *bchain.RpcReceipt
|
||||||
if pt.Receipt != nil {
|
if pt.Receipt != nil {
|
||||||
logs := make([]*bchain.RpcLog, len(pt.Receipt.Log))
|
rr = &bchain.RpcReceipt{
|
||||||
|
GasUsed: hexEncodeBig(pt.Receipt.GasUsed),
|
||||||
|
Status: "",
|
||||||
|
Logs: make([]*bchain.RpcLog, len(pt.Receipt.Log)),
|
||||||
|
}
|
||||||
for i, l := range pt.Receipt.Log {
|
for i, l := range pt.Receipt.Log {
|
||||||
topics := make([]string, len(l.Topics))
|
topics := make([]string, len(l.Topics))
|
||||||
for j, t := range l.Topics {
|
for j, t := range l.Topics {
|
||||||
topics[j] = hexutil.Encode(t)
|
topics[j] = hexutil.Encode(t)
|
||||||
}
|
}
|
||||||
logs[i] = &bchain.RpcLog{
|
rr.Logs[i] = &bchain.RpcLog{
|
||||||
Address: EIP55Address(l.Address),
|
Address: EIP55Address(l.Address),
|
||||||
Data: hexutil.Encode(l.Data),
|
Data: hexutil.Encode(l.Data),
|
||||||
Topics: topics,
|
Topics: topics,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
status := ""
|
|
||||||
// handle a special value []byte{'U'} as unknown state
|
// handle a special value []byte{'U'} as unknown state
|
||||||
if len(pt.Receipt.Status) != 1 || pt.Receipt.Status[0] != 'U' {
|
if len(pt.Receipt.Status) != 1 || pt.Receipt.Status[0] != 'U' {
|
||||||
status = hexEncodeBig(pt.Receipt.Status)
|
rr.Status = hexEncodeBig(pt.Receipt.Status)
|
||||||
}
|
}
|
||||||
rr = &bchain.RpcReceipt{
|
if len(pt.Receipt.L1Fee) > 0 {
|
||||||
GasUsed: hexEncodeBig(pt.Receipt.GasUsed),
|
rr.L1Fee = hexEncodeBig(pt.Receipt.L1Fee)
|
||||||
Status: status,
|
}
|
||||||
Logs: logs,
|
if len(pt.Receipt.L1FeeScalar) > 0 {
|
||||||
|
rr.L1FeeScalar = string(pt.Receipt.L1FeeScalar)
|
||||||
|
}
|
||||||
|
if len(pt.Receipt.L1GasPrice) > 0 {
|
||||||
|
rr.L1GasPrice = hexEncodeBig(pt.Receipt.L1GasPrice)
|
||||||
|
}
|
||||||
|
if len(pt.Receipt.L1GasUsed) > 0 {
|
||||||
|
rr.L1GasUsed = hexEncodeBig(pt.Receipt.L1GasUsed)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
// TODO handle internal transactions
|
// TODO handle internal transactions
|
||||||
@ -461,7 +493,7 @@ func (p *EthereumParser) EthereumTypeGetTokenTransfersFromTx(tx *bchain.Tx) (bch
|
|||||||
|
|
||||||
// FormatAddressAlias adds .eth to a name alias
|
// FormatAddressAlias adds .eth to a name alias
|
||||||
func (p *EthereumParser) FormatAddressAlias(address string, name string) string {
|
func (p *EthereumParser) FormatAddressAlias(address string, name string) string {
|
||||||
return name + ".eth"
|
return name + p.EnsSuffix
|
||||||
}
|
}
|
||||||
|
|
||||||
// TxStatus is status of transaction
|
// TxStatus is status of transaction
|
||||||
@ -477,12 +509,16 @@ const (
|
|||||||
|
|
||||||
// EthereumTxData contains ethereum specific transaction data
|
// EthereumTxData contains ethereum specific transaction data
|
||||||
type EthereumTxData struct {
|
type EthereumTxData struct {
|
||||||
Status TxStatus `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"`
|
||||||
GasPrice *big.Int `json:"gasprice"`
|
GasPrice *big.Int `json:"gasprice"`
|
||||||
Data string `json:"data"`
|
L1Fee *big.Int `json:"l1Fee,omitempty"`
|
||||||
|
L1FeeScalar string `json:"l1FeeScalar,omitempty"`
|
||||||
|
L1GasPrice *big.Int `json:"l1GasPrice,omitempty"`
|
||||||
|
L1GasUsed *big.Int `json:"L1GasUsed,omitempty"`
|
||||||
|
Data string `json:"data"`
|
||||||
}
|
}
|
||||||
|
|
||||||
// GetEthereumTxData returns EthereumTxData from bchain.Tx
|
// GetEthereumTxData returns EthereumTxData from bchain.Tx
|
||||||
@ -511,6 +547,10 @@ func GetEthereumTxDataFromSpecificData(coinSpecificData interface{}) *EthereumTx
|
|||||||
etd.Status = TxStatusFailure
|
etd.Status = TxStatusFailure
|
||||||
}
|
}
|
||||||
etd.GasUsed, _ = hexutil.DecodeBig(csd.Receipt.GasUsed)
|
etd.GasUsed, _ = hexutil.DecodeBig(csd.Receipt.GasUsed)
|
||||||
|
etd.L1Fee, _ = hexutil.DecodeBig(csd.Receipt.L1Fee)
|
||||||
|
etd.L1GasPrice, _ = hexutil.DecodeBig(csd.Receipt.L1GasPrice)
|
||||||
|
etd.L1GasUsed, _ = hexutil.DecodeBig(csd.Receipt.L1GasUsed)
|
||||||
|
etd.L1FeeScalar = csd.Receipt.L1FeeScalar
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return &etd
|
return &etd
|
||||||
|
|||||||
@ -1,496 +0,0 @@
|
|||||||
//go:build unittest
|
|
||||||
|
|
||||||
package eth
|
|
||||||
|
|
||||||
import (
|
|
||||||
"encoding/hex"
|
|
||||||
"fmt"
|
|
||||||
"math/big"
|
|
||||||
"reflect"
|
|
||||||
"testing"
|
|
||||||
|
|
||||||
"github.com/trezor/blockbook/bchain"
|
|
||||||
"github.com/trezor/blockbook/tests/dbtestdata"
|
|
||||||
)
|
|
||||||
|
|
||||||
func TestEthParser_GetAddrDescFromAddress(t *testing.T) {
|
|
||||||
type args struct {
|
|
||||||
address string
|
|
||||||
}
|
|
||||||
tests := []struct {
|
|
||||||
name string
|
|
||||||
args args
|
|
||||||
want string
|
|
||||||
wantErr bool
|
|
||||||
}{
|
|
||||||
{
|
|
||||||
name: "with 0x prefix",
|
|
||||||
args: args{address: "0x81b7e08f65bdf5648606c89998a9cc8164397647"},
|
|
||||||
want: "81b7e08f65bdf5648606c89998a9cc8164397647",
|
|
||||||
},
|
|
||||||
{
|
|
||||||
name: "without 0x prefix",
|
|
||||||
args: args{address: "47526228d673e9f079630d6cdaff5a2ed13e0e60"},
|
|
||||||
want: "47526228d673e9f079630d6cdaff5a2ed13e0e60",
|
|
||||||
},
|
|
||||||
{
|
|
||||||
name: "address of wrong length",
|
|
||||||
args: args{address: "7526228d673e9f079630d6cdaff5a2ed13e0e60"},
|
|
||||||
want: "",
|
|
||||||
wantErr: true,
|
|
||||||
},
|
|
||||||
{
|
|
||||||
name: "ErrAddressMissing",
|
|
||||||
args: args{address: ""},
|
|
||||||
want: "",
|
|
||||||
wantErr: true,
|
|
||||||
},
|
|
||||||
{
|
|
||||||
name: "error - not eth address",
|
|
||||||
args: args{address: "1JKgN43B9SyLuZH19H5ECvr4KcfrbVHzZ6"},
|
|
||||||
want: "",
|
|
||||||
wantErr: true,
|
|
||||||
},
|
|
||||||
}
|
|
||||||
for _, tt := range tests {
|
|
||||||
t.Run(tt.name, func(t *testing.T) {
|
|
||||||
p := NewEthereumParser(1, false)
|
|
||||||
got, err := p.GetAddrDescFromAddress(tt.args.address)
|
|
||||||
if (err != nil) != tt.wantErr {
|
|
||||||
t.Errorf("EthParser.GetAddrDescFromAddress() error = %v, wantErr %v", err, tt.wantErr)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
h := hex.EncodeToString(got)
|
|
||||||
if !reflect.DeepEqual(h, tt.want) {
|
|
||||||
t.Errorf("EthParser.GetAddrDescFromAddress() = %v, want %v", h, tt.want)
|
|
||||||
}
|
|
||||||
})
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
var testTx1, testTx2, testTx1Failed, testTx1NoStatus bchain.Tx
|
|
||||||
|
|
||||||
func init() {
|
|
||||||
|
|
||||||
testTx1 = 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: bchain.EthereumSpecificData{
|
|
||||||
Tx: &bchain.RpcTransaction{
|
|
||||||
AccountNonce: "0xb26c",
|
|
||||||
GasPrice: "0x430e23400",
|
|
||||||
GasLimit: "0x5208",
|
|
||||||
To: "0x555Ee11FBDDc0E49A9bAB358A8941AD95fFDB48f",
|
|
||||||
Value: "0x1bc0159d530e6000",
|
|
||||||
Payload: "0x",
|
|
||||||
Hash: "0xcd647151552b5132b2aef7c9be00dc6f73afc5901dde157aab131335baaa853b",
|
|
||||||
BlockNumber: "0x41eee8",
|
|
||||||
From: "0x3E3a3D69dc66bA10737F531ed088954a9EC89d97",
|
|
||||||
TransactionIndex: "0xa",
|
|
||||||
},
|
|
||||||
Receipt: &bchain.RpcReceipt{
|
|
||||||
GasUsed: "0x5208",
|
|
||||||
Status: "0x1",
|
|
||||||
Logs: []*bchain.RpcLog{},
|
|
||||||
},
|
|
||||||
},
|
|
||||||
}
|
|
||||||
|
|
||||||
testTx2 = bchain.Tx{
|
|
||||||
Blocktime: 1534858022,
|
|
||||||
Time: 1534858022,
|
|
||||||
Txid: "0xa9cd088aba2131000da6f38a33c20169baee476218deea6b78720700b895b101",
|
|
||||||
Vin: []bchain.Vin{
|
|
||||||
{
|
|
||||||
Addresses: []string{"0x20cD153de35D469BA46127A0C8F18626b59a256A"},
|
|
||||||
},
|
|
||||||
},
|
|
||||||
Vout: []bchain.Vout{
|
|
||||||
{
|
|
||||||
ValueSat: *big.NewInt(0),
|
|
||||||
ScriptPubKey: bchain.ScriptPubKey{
|
|
||||||
Addresses: []string{"0x4af4114F73d1c1C903aC9E0361b379D1291808A2"},
|
|
||||||
},
|
|
||||||
},
|
|
||||||
},
|
|
||||||
CoinSpecificData: bchain.EthereumSpecificData{
|
|
||||||
Tx: &bchain.RpcTransaction{
|
|
||||||
AccountNonce: "0xd0",
|
|
||||||
GasPrice: "0x9502f9000",
|
|
||||||
GasLimit: "0x130d5",
|
|
||||||
To: "0x4af4114F73d1c1C903aC9E0361b379D1291808A2",
|
|
||||||
Value: "0x0",
|
|
||||||
Payload: "0xa9059cbb000000000000000000000000555ee11fbddc0e49a9bab358a8941ad95ffdb48f00000000000000000000000000000000000000000000021e19e0c9bab2400000",
|
|
||||||
Hash: "0xa9cd088aba2131000da6f38a33c20169baee476218deea6b78720700b895b101",
|
|
||||||
BlockNumber: "0x41eee8",
|
|
||||||
From: "0x20cD153de35D469BA46127A0C8F18626b59a256A",
|
|
||||||
TransactionIndex: "0x0"},
|
|
||||||
Receipt: &bchain.RpcReceipt{
|
|
||||||
GasUsed: "0xcb39",
|
|
||||||
Status: "0x1",
|
|
||||||
Logs: []*bchain.RpcLog{
|
|
||||||
{
|
|
||||||
Address: "0x4af4114F73d1c1C903aC9E0361b379D1291808A2",
|
|
||||||
Data: "0x00000000000000000000000000000000000000000000021e19e0c9bab2400000",
|
|
||||||
Topics: []string{
|
|
||||||
"0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef",
|
|
||||||
"0x00000000000000000000000020cd153de35d469ba46127a0c8f18626b59a256a",
|
|
||||||
"0x000000000000000000000000555ee11fbddc0e49a9bab358a8941ad95ffdb48f",
|
|
||||||
},
|
|
||||||
},
|
|
||||||
},
|
|
||||||
},
|
|
||||||
},
|
|
||||||
}
|
|
||||||
|
|
||||||
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: bchain.EthereumSpecificData{
|
|
||||||
Tx: &bchain.RpcTransaction{
|
|
||||||
AccountNonce: "0xb26c",
|
|
||||||
GasPrice: "0x430e23400",
|
|
||||||
GasLimit: "0x5208",
|
|
||||||
To: "0x555Ee11FBDDc0E49A9bAB358A8941AD95fFDB48f",
|
|
||||||
Value: "0x1bc0159d530e6000",
|
|
||||||
Payload: "0x",
|
|
||||||
Hash: "0xcd647151552b5132b2aef7c9be00dc6f73afc5901dde157aab131335baaa853b",
|
|
||||||
BlockNumber: "0x41eee8",
|
|
||||||
From: "0x3E3a3D69dc66bA10737F531ed088954a9EC89d97",
|
|
||||||
TransactionIndex: "0xa",
|
|
||||||
},
|
|
||||||
Receipt: &bchain.RpcReceipt{
|
|
||||||
GasUsed: "0x5208",
|
|
||||||
Status: "0x0",
|
|
||||||
Logs: []*bchain.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: bchain.EthereumSpecificData{
|
|
||||||
Tx: &bchain.RpcTransaction{
|
|
||||||
AccountNonce: "0xb26c",
|
|
||||||
GasPrice: "0x430e23400",
|
|
||||||
GasLimit: "0x5208",
|
|
||||||
To: "0x555Ee11FBDDc0E49A9bAB358A8941AD95fFDB48f",
|
|
||||||
Value: "0x1bc0159d530e6000",
|
|
||||||
Payload: "0x",
|
|
||||||
Hash: "0xcd647151552b5132b2aef7c9be00dc6f73afc5901dde157aab131335baaa853b",
|
|
||||||
BlockNumber: "0x41eee8",
|
|
||||||
From: "0x3E3a3D69dc66bA10737F531ed088954a9EC89d97",
|
|
||||||
TransactionIndex: "0xa",
|
|
||||||
},
|
|
||||||
Receipt: &bchain.RpcReceipt{
|
|
||||||
GasUsed: "0x5208",
|
|
||||||
Status: "",
|
|
||||||
Logs: []*bchain.RpcLog{},
|
|
||||||
},
|
|
||||||
},
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
func TestEthereumParser_PackTx(t *testing.T) {
|
|
||||||
type args struct {
|
|
||||||
tx *bchain.Tx
|
|
||||||
height uint32
|
|
||||||
blockTime int64
|
|
||||||
}
|
|
||||||
tests := []struct {
|
|
||||||
name string
|
|
||||||
p *EthereumParser
|
|
||||||
args args
|
|
||||||
want string
|
|
||||||
wantErr bool
|
|
||||||
}{
|
|
||||||
{
|
|
||||||
name: "1",
|
|
||||||
args: args{
|
|
||||||
tx: &testTx1,
|
|
||||||
height: 4321000,
|
|
||||||
blockTime: 1534858022,
|
|
||||||
},
|
|
||||||
want: dbtestdata.EthTx1Packed,
|
|
||||||
},
|
|
||||||
{
|
|
||||||
name: "2",
|
|
||||||
args: args{
|
|
||||||
tx: &testTx2,
|
|
||||||
height: 4321000,
|
|
||||||
blockTime: 1534858022,
|
|
||||||
},
|
|
||||||
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, false)
|
|
||||||
for _, tt := range tests {
|
|
||||||
t.Run(tt.name, func(t *testing.T) {
|
|
||||||
got, err := p.PackTx(tt.args.tx, tt.args.height, tt.args.blockTime)
|
|
||||||
if (err != nil) != tt.wantErr {
|
|
||||||
t.Errorf("EthereumParser.PackTx() error = %v, wantErr %v", err, tt.wantErr)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
h := hex.EncodeToString(got)
|
|
||||||
if !reflect.DeepEqual(h, tt.want) {
|
|
||||||
t.Errorf("EthereumParser.PackTx() = %v, want %v", h, tt.want)
|
|
||||||
}
|
|
||||||
})
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func TestEthereumParser_UnpackTx(t *testing.T) {
|
|
||||||
type args struct {
|
|
||||||
hex string
|
|
||||||
}
|
|
||||||
tests := []struct {
|
|
||||||
name string
|
|
||||||
p *EthereumParser
|
|
||||||
args args
|
|
||||||
want *bchain.Tx
|
|
||||||
want1 uint32
|
|
||||||
wantErr bool
|
|
||||||
}{
|
|
||||||
{
|
|
||||||
name: "1",
|
|
||||||
args: args{hex: dbtestdata.EthTx1Packed},
|
|
||||||
want: &testTx1,
|
|
||||||
want1: 4321000,
|
|
||||||
},
|
|
||||||
{
|
|
||||||
name: "2",
|
|
||||||
args: args{hex: dbtestdata.EthTx2Packed},
|
|
||||||
want: &testTx2,
|
|
||||||
want1: 4321000,
|
|
||||||
},
|
|
||||||
{
|
|
||||||
name: "3",
|
|
||||||
args: args{hex: dbtestdata.EthTx1FailedPacked},
|
|
||||||
want: &testTx1Failed,
|
|
||||||
want1: 4321000,
|
|
||||||
},
|
|
||||||
{
|
|
||||||
name: "4",
|
|
||||||
args: args{hex: dbtestdata.EthTx1NoStatusPacked},
|
|
||||||
want: &testTx1NoStatus,
|
|
||||||
want1: 4321000,
|
|
||||||
},
|
|
||||||
}
|
|
||||||
p := NewEthereumParser(1, false)
|
|
||||||
for _, tt := range tests {
|
|
||||||
t.Run(tt.name, func(t *testing.T) {
|
|
||||||
b, err := hex.DecodeString(tt.args.hex)
|
|
||||||
if err != nil {
|
|
||||||
panic(err)
|
|
||||||
}
|
|
||||||
got, got1, err := p.UnpackTx(b)
|
|
||||||
if (err != nil) != tt.wantErr {
|
|
||||||
t.Errorf("EthereumParser.UnpackTx() error = %v, wantErr %v", err, tt.wantErr)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
// DeepEqual has problems with pointers in completeTransaction
|
|
||||||
gs := got.CoinSpecificData.(bchain.EthereumSpecificData)
|
|
||||||
ws := tt.want.CoinSpecificData.(bchain.EthereumSpecificData)
|
|
||||||
gc := *got
|
|
||||||
wc := *tt.want
|
|
||||||
gc.CoinSpecificData = nil
|
|
||||||
wc.CoinSpecificData = nil
|
|
||||||
if fmt.Sprint(gc) != fmt.Sprint(wc) {
|
|
||||||
// if !reflect.DeepEqual(gc, wc) {
|
|
||||||
t.Errorf("EthereumParser.UnpackTx() gc got = %+v, want %+v", gc, wc)
|
|
||||||
}
|
|
||||||
if !reflect.DeepEqual(gs.Tx, ws.Tx) {
|
|
||||||
t.Errorf("EthereumParser.UnpackTx() gs.Tx got = %+v, want %+v", gs.Tx, ws.Tx)
|
|
||||||
}
|
|
||||||
if !reflect.DeepEqual(gs.Receipt, ws.Receipt) {
|
|
||||||
t.Errorf("EthereumParser.UnpackTx() gs.Receipt got = %+v, want %+v", gs.Receipt, ws.Receipt)
|
|
||||||
}
|
|
||||||
if got1 != tt.want1 {
|
|
||||||
t.Errorf("EthereumParser.UnpackTx() got1 = %v, want %v", got1, tt.want1)
|
|
||||||
}
|
|
||||||
})
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func TestEthereumParser_GetEthereumTxData(t *testing.T) {
|
|
||||||
tests := []struct {
|
|
||||||
name string
|
|
||||||
tx *bchain.Tx
|
|
||||||
want string
|
|
||||||
}{
|
|
||||||
{
|
|
||||||
name: "Test empty data",
|
|
||||||
tx: &testTx1,
|
|
||||||
want: "0x",
|
|
||||||
},
|
|
||||||
{
|
|
||||||
name: "Test non empty data",
|
|
||||||
tx: &testTx2,
|
|
||||||
want: "0xa9059cbb000000000000000000000000555ee11fbddc0e49a9bab358a8941ad95ffdb48f00000000000000000000000000000000000000000000021e19e0c9bab2400000",
|
|
||||||
},
|
|
||||||
}
|
|
||||||
for _, tt := range tests {
|
|
||||||
t.Run(tt.name, func(t *testing.T) {
|
|
||||||
got := GetEthereumTxData(tt.tx)
|
|
||||||
if got.Data != tt.want {
|
|
||||||
t.Errorf("EthereumParser.GetEthereumTxData() = %v, want %v", got.Data, tt.want)
|
|
||||||
}
|
|
||||||
})
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func TestEthereumParser_ParseErrorFromOutput(t *testing.T) {
|
|
||||||
tests := []struct {
|
|
||||||
name string
|
|
||||||
output string
|
|
||||||
want string
|
|
||||||
}{
|
|
||||||
{
|
|
||||||
name: "ParseErrorFromOutput 1",
|
|
||||||
output: "0x08c379a000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000031546f74616c206e756d626572206f662067726f757073206d7573742062652067726561746572207468616e207a65726f2e000000000000000000000000000000",
|
|
||||||
want: "Total number of groups must be greater than zero.",
|
|
||||||
},
|
|
||||||
{
|
|
||||||
name: "ParseErrorFromOutput 2",
|
|
||||||
output: "0x08c379a0000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000126e6f7420656e6f7567682062616c616e63650000000000000000000000000000",
|
|
||||||
want: "not enough balance",
|
|
||||||
},
|
|
||||||
{
|
|
||||||
name: "ParseErrorFromOutput empty",
|
|
||||||
output: "",
|
|
||||||
want: "",
|
|
||||||
},
|
|
||||||
{
|
|
||||||
name: "ParseErrorFromOutput short",
|
|
||||||
output: "0x08c379a000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000012",
|
|
||||||
want: "",
|
|
||||||
},
|
|
||||||
{
|
|
||||||
name: "ParseErrorFromOutput invalid signature",
|
|
||||||
output: "0x08c379b0000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000126e6f7420656e6f7567682062616c616e63650000000000000000000000000000",
|
|
||||||
want: "",
|
|
||||||
},
|
|
||||||
}
|
|
||||||
for _, tt := range tests {
|
|
||||||
t.Run(tt.name, func(t *testing.T) {
|
|
||||||
got := ParseErrorFromOutput(tt.output)
|
|
||||||
if got != tt.want {
|
|
||||||
t.Errorf("EthereumParser.ParseErrorFromOutput() = %v, want %v", got, tt.want)
|
|
||||||
}
|
|
||||||
})
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func TestEthereumParser_PackInternalTransactionError_UnpackInternalTransactionError(t *testing.T) {
|
|
||||||
tests := []struct {
|
|
||||||
name string
|
|
||||||
original string
|
|
||||||
packed string
|
|
||||||
unpacked string
|
|
||||||
}{
|
|
||||||
{
|
|
||||||
name: "execution reverted",
|
|
||||||
original: "execution reverted",
|
|
||||||
packed: "\x01",
|
|
||||||
unpacked: "Reverted.",
|
|
||||||
},
|
|
||||||
{
|
|
||||||
name: "out of gas",
|
|
||||||
original: "out of gas",
|
|
||||||
packed: "\x02",
|
|
||||||
unpacked: "Out of gas.",
|
|
||||||
},
|
|
||||||
{
|
|
||||||
name: "contract creation code storage out of gas",
|
|
||||||
original: "contract creation code storage out of gas",
|
|
||||||
packed: "\x03",
|
|
||||||
unpacked: "Contract creation code storage out of gas.",
|
|
||||||
},
|
|
||||||
{
|
|
||||||
name: "max code size exceeded",
|
|
||||||
original: "max code size exceeded",
|
|
||||||
packed: "\x04",
|
|
||||||
unpacked: "Max code size exceeded.",
|
|
||||||
},
|
|
||||||
{
|
|
||||||
name: "unknown error",
|
|
||||||
original: "unknown error",
|
|
||||||
packed: "unknown error",
|
|
||||||
unpacked: "unknown error",
|
|
||||||
},
|
|
||||||
}
|
|
||||||
for _, tt := range tests {
|
|
||||||
t.Run(tt.name, func(t *testing.T) {
|
|
||||||
packed := PackInternalTransactionError(tt.original)
|
|
||||||
if packed != tt.packed {
|
|
||||||
t.Errorf("EthereumParser.PackInternalTransactionError() = %v, want %v", packed, tt.packed)
|
|
||||||
}
|
|
||||||
unpacked := UnpackInternalTransactionError([]byte(packed))
|
|
||||||
if unpacked != tt.unpacked {
|
|
||||||
t.Errorf("EthereumParser.UnpackInternalTransactionError() = %v, want %v", unpacked, tt.unpacked)
|
|
||||||
}
|
|
||||||
})
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@ -4,7 +4,7 @@ import (
|
|||||||
"context"
|
"context"
|
||||||
"encoding/json"
|
"encoding/json"
|
||||||
"fmt"
|
"fmt"
|
||||||
"io/ioutil"
|
"io"
|
||||||
"math/big"
|
"math/big"
|
||||||
"net/http"
|
"net/http"
|
||||||
"strconv"
|
"strconv"
|
||||||
@ -30,18 +30,17 @@ type Network uint32
|
|||||||
const (
|
const (
|
||||||
// MainNet is production network
|
// MainNet is production network
|
||||||
MainNet Network = 1
|
MainNet Network = 1
|
||||||
// TestNet is Ropsten test network
|
|
||||||
TestNet Network = 3
|
|
||||||
// TestNetGoerli is Goerli test network
|
|
||||||
TestNetGoerli Network = 5
|
|
||||||
// TestNetSepolia is Sepolia test network
|
// TestNetSepolia is Sepolia test network
|
||||||
TestNetSepolia Network = 11155111
|
TestNetSepolia Network = 11155111
|
||||||
|
// TestNetHolesky is Holesky test network
|
||||||
|
TestNetHolesky Network = 17000
|
||||||
)
|
)
|
||||||
|
|
||||||
// Configuration represents json config file
|
// Configuration represents json config file
|
||||||
type Configuration struct {
|
type Configuration struct {
|
||||||
CoinName string `json:"coin_name"`
|
CoinName string `json:"coin_name"`
|
||||||
CoinShortcut string `json:"coin_shortcut"`
|
CoinShortcut string `json:"coin_shortcut"`
|
||||||
|
Network string `json:"network"`
|
||||||
RPCURL string `json:"rpc_url"`
|
RPCURL string `json:"rpc_url"`
|
||||||
RPCTimeout int `json:"rpc_timeout"`
|
RPCTimeout int `json:"rpc_timeout"`
|
||||||
BlockAddressesToKeep int `json:"block_addresses_to_keep"`
|
BlockAddressesToKeep int `json:"block_addresses_to_keep"`
|
||||||
@ -51,28 +50,32 @@ type Configuration struct {
|
|||||||
ProcessInternalTransactions bool `json:"processInternalTransactions"`
|
ProcessInternalTransactions bool `json:"processInternalTransactions"`
|
||||||
ProcessZeroInternalTransactions bool `json:"processZeroInternalTransactions"`
|
ProcessZeroInternalTransactions bool `json:"processZeroInternalTransactions"`
|
||||||
ConsensusNodeVersionURL string `json:"consensusNodeVersion"`
|
ConsensusNodeVersionURL string `json:"consensusNodeVersion"`
|
||||||
|
DisableMempoolSync bool `json:"disableMempoolSync,omitempty"`
|
||||||
}
|
}
|
||||||
|
|
||||||
// EthereumRPC is an interface to JSON-RPC eth service.
|
// EthereumRPC is an interface to JSON-RPC eth service.
|
||||||
type EthereumRPC struct {
|
type EthereumRPC struct {
|
||||||
*bchain.BaseChain
|
*bchain.BaseChain
|
||||||
Client bchain.EVMClient
|
Client bchain.EVMClient
|
||||||
RPC bchain.EVMRPCClient
|
RPC bchain.EVMRPCClient
|
||||||
MainNetChainID Network
|
MainNetChainID Network
|
||||||
Timeout time.Duration
|
Timeout time.Duration
|
||||||
Parser *EthereumParser
|
Parser *EthereumParser
|
||||||
PushHandler func(bchain.NotificationType)
|
PushHandler func(bchain.NotificationType)
|
||||||
OpenRPC func(string) (bchain.EVMRPCClient, bchain.EVMClient, error)
|
OpenRPC func(string) (bchain.EVMRPCClient, bchain.EVMClient, error)
|
||||||
Mempool *bchain.MempoolEthereumType
|
Mempool *bchain.MempoolEthereumType
|
||||||
mempoolInitialized bool
|
mempoolInitialized bool
|
||||||
bestHeaderLock sync.Mutex
|
bestHeaderLock sync.Mutex
|
||||||
bestHeader bchain.EVMHeader
|
bestHeader bchain.EVMHeader
|
||||||
bestHeaderTime time.Time
|
bestHeaderTime time.Time
|
||||||
NewBlock bchain.EVMNewBlockSubscriber
|
NewBlock bchain.EVMNewBlockSubscriber
|
||||||
newBlockSubscription bchain.EVMClientSubscription
|
newBlockSubscription bchain.EVMClientSubscription
|
||||||
NewTx bchain.EVMNewTxSubscriber
|
NewTx bchain.EVMNewTxSubscriber
|
||||||
newTxSubscription bchain.EVMClientSubscription
|
newTxSubscription bchain.EVMClientSubscription
|
||||||
ChainConfig *Configuration
|
ChainConfig *Configuration
|
||||||
|
supportedStakingPools []string
|
||||||
|
stakingPoolNames []string
|
||||||
|
stakingPoolContracts []string
|
||||||
}
|
}
|
||||||
|
|
||||||
// ProcessInternalTransactions specifies if internal transactions are processed
|
// ProcessInternalTransactions specifies if internal transactions are processed
|
||||||
@ -106,17 +109,22 @@ func NewEthereumRPC(config json.RawMessage, pushHandler func(bchain.Notification
|
|||||||
return s, nil
|
return s, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// OpenRPC opens RPC connection to ETH backend
|
||||||
|
var OpenRPC = func(url string) (bchain.EVMRPCClient, bchain.EVMClient, error) {
|
||||||
|
opts := []rpc.ClientOption{}
|
||||||
|
opts = append(opts, rpc.WithWebsocketMessageSizeLimit(0))
|
||||||
|
r, err := rpc.DialOptions(context.Background(), url, opts...)
|
||||||
|
if err != nil {
|
||||||
|
return nil, nil, err
|
||||||
|
}
|
||||||
|
rc := &EthereumRPCClient{Client: r}
|
||||||
|
ec := &EthereumClient{Client: ethclient.NewClient(r)}
|
||||||
|
return rc, ec, nil
|
||||||
|
}
|
||||||
|
|
||||||
// Initialize initializes ethereum rpc interface
|
// Initialize initializes ethereum rpc interface
|
||||||
func (b *EthereumRPC) Initialize() error {
|
func (b *EthereumRPC) Initialize() error {
|
||||||
b.OpenRPC = func(url string) (bchain.EVMRPCClient, bchain.EVMClient, error) {
|
b.OpenRPC = OpenRPC
|
||||||
r, err := rpc.Dial(url)
|
|
||||||
if err != nil {
|
|
||||||
return nil, nil, err
|
|
||||||
}
|
|
||||||
rc := &EthereumRPCClient{Client: r}
|
|
||||||
ec := &EthereumClient{Client: ethclient.NewClient(r)}
|
|
||||||
return rc, ec, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
rc, ec, err := b.OpenRPC(b.ChainConfig.RPCURL)
|
rc, ec, err := b.OpenRPC(b.ChainConfig.RPCURL)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
@ -143,18 +151,21 @@ func (b *EthereumRPC) Initialize() error {
|
|||||||
case MainNet:
|
case MainNet:
|
||||||
b.Testnet = false
|
b.Testnet = false
|
||||||
b.Network = "livenet"
|
b.Network = "livenet"
|
||||||
case TestNet:
|
|
||||||
b.Testnet = true
|
|
||||||
b.Network = "testnet"
|
|
||||||
case TestNetGoerli:
|
|
||||||
b.Testnet = true
|
|
||||||
b.Network = "goerli"
|
|
||||||
case TestNetSepolia:
|
case TestNetSepolia:
|
||||||
b.Testnet = true
|
b.Testnet = true
|
||||||
b.Network = "sepolia"
|
b.Network = "sepolia"
|
||||||
|
case TestNetHolesky:
|
||||||
|
b.Testnet = true
|
||||||
|
b.Network = "holesky"
|
||||||
default:
|
default:
|
||||||
return errors.Errorf("Unknown network id %v", id)
|
return errors.Errorf("Unknown network id %v", id)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
err = b.initStakingPools()
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
glog.Info("rpc: block chain ", b.Network)
|
glog.Info("rpc: block chain ", b.Network)
|
||||||
|
|
||||||
return nil
|
return nil
|
||||||
@ -164,7 +175,7 @@ func (b *EthereumRPC) Initialize() error {
|
|||||||
func (b *EthereumRPC) CreateMempool(chain bchain.BlockChain) (bchain.Mempool, error) {
|
func (b *EthereumRPC) CreateMempool(chain bchain.BlockChain) (bchain.Mempool, error) {
|
||||||
if b.Mempool == nil {
|
if b.Mempool == nil {
|
||||||
b.Mempool = bchain.NewMempoolEthereumType(chain, b.ChainConfig.MempoolTxTimeoutHours, b.ChainConfig.QueryBackendOnMempoolResync)
|
b.Mempool = bchain.NewMempoolEthereumType(chain, b.ChainConfig.MempoolTxTimeoutHours, b.ChainConfig.QueryBackendOnMempoolResync)
|
||||||
glog.Info("mempool created, MempoolTxTimeoutHours=", b.ChainConfig.MempoolTxTimeoutHours, ", QueryBackendOnMempoolResync=", b.ChainConfig.QueryBackendOnMempoolResync)
|
glog.Info("mempool created, MempoolTxTimeoutHours=", b.ChainConfig.MempoolTxTimeoutHours, ", QueryBackendOnMempoolResync=", b.ChainConfig.QueryBackendOnMempoolResync, ", DisableMempoolSync=", b.ChainConfig.DisableMempoolSync)
|
||||||
}
|
}
|
||||||
return b.Mempool, nil
|
return b.Mempool, nil
|
||||||
}
|
}
|
||||||
@ -175,11 +186,19 @@ func (b *EthereumRPC) InitializeMempool(addrDescForOutpoint bchain.AddrDescForOu
|
|||||||
return errors.New("Mempool not created")
|
return errors.New("Mempool not created")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
var err error
|
||||||
|
var txs []string
|
||||||
// get initial mempool transactions
|
// get initial mempool transactions
|
||||||
txs, err := b.GetMempoolTransactions()
|
// workaround for an occasional `decoding block` error from getBlockRaw - try 3 times with a delay and then proceed
|
||||||
if err != nil {
|
for i := 0; i < 3; i++ {
|
||||||
return err
|
txs, err = b.GetMempoolTransactions()
|
||||||
|
if err == nil {
|
||||||
|
break
|
||||||
|
}
|
||||||
|
glog.Error("GetMempoolTransaction ", err)
|
||||||
|
time.Sleep(time.Second * 5)
|
||||||
}
|
}
|
||||||
|
|
||||||
for _, txid := range txs {
|
for _, txid := range txs {
|
||||||
b.Mempool.AddTransactionToMempool(txid)
|
b.Mempool.AddTransactionToMempool(txid)
|
||||||
}
|
}
|
||||||
@ -238,26 +257,30 @@ func (b *EthereumRPC) subscribeEvents() error {
|
|||||||
if glog.V(2) {
|
if glog.V(2) {
|
||||||
glog.Info("rpc: new tx ", hex)
|
glog.Info("rpc: new tx ", hex)
|
||||||
}
|
}
|
||||||
b.Mempool.AddTransactionToMempool(hex)
|
added := b.Mempool.AddTransactionToMempool(hex)
|
||||||
b.PushHandler(bchain.NotificationNewTx)
|
if added {
|
||||||
|
b.PushHandler(bchain.NotificationNewTx)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}()
|
}()
|
||||||
|
|
||||||
// new mempool transaction subscription
|
if !b.ChainConfig.DisableMempoolSync {
|
||||||
if err := b.subscribe(func() (bchain.EVMClientSubscription, error) {
|
// new mempool transaction subscription
|
||||||
// invalidate the previous subscription - it is either the first one or there was an error
|
if err := b.subscribe(func() (bchain.EVMClientSubscription, error) {
|
||||||
b.newTxSubscription = nil
|
// invalidate the previous subscription - it is either the first one or there was an error
|
||||||
ctx, cancel := context.WithTimeout(context.Background(), b.Timeout)
|
b.newTxSubscription = nil
|
||||||
defer cancel()
|
ctx, cancel := context.WithTimeout(context.Background(), b.Timeout)
|
||||||
sub, err := b.RPC.EthSubscribe(ctx, b.NewTx.Channel(), "newPendingTransactions")
|
defer cancel()
|
||||||
if err != nil {
|
sub, err := b.RPC.EthSubscribe(ctx, b.NewTx.Channel(), "newPendingTransactions")
|
||||||
return nil, errors.Annotatef(err, "EthSubscribe newPendingTransactions")
|
if err != nil {
|
||||||
|
return nil, errors.Annotatef(err, "EthSubscribe newPendingTransactions")
|
||||||
|
}
|
||||||
|
b.newTxSubscription = sub
|
||||||
|
glog.Info("Subscribed to newPendingTransactions")
|
||||||
|
return sub, nil
|
||||||
|
}); err != nil {
|
||||||
|
return err
|
||||||
}
|
}
|
||||||
b.newTxSubscription = sub
|
|
||||||
glog.Info("Subscribed to newPendingTransactions")
|
|
||||||
return sub, nil
|
|
||||||
}); err != nil {
|
|
||||||
return err
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return nil
|
return nil
|
||||||
@ -358,7 +381,7 @@ func (b *EthereumRPC) getConsensusVersion() string {
|
|||||||
glog.Error("getConsensusVersion ", err)
|
glog.Error("getConsensusVersion ", err)
|
||||||
return ""
|
return ""
|
||||||
}
|
}
|
||||||
body, err := ioutil.ReadAll(resp.Body)
|
body, err := io.ReadAll(resp.Body)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
glog.Error("getConsensusVersion ", err)
|
glog.Error("getConsensusVersion ", err)
|
||||||
return ""
|
return ""
|
||||||
@ -591,19 +614,24 @@ type rpcTraceResult struct {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (b *EthereumRPC) getCreationContractInfo(contract string, height uint32) *bchain.ContractInfo {
|
func (b *EthereumRPC) getCreationContractInfo(contract string, height uint32) *bchain.ContractInfo {
|
||||||
ci, err := b.fetchContractInfo(contract)
|
// do not fetch fetchContractInfo in sync, it slows it down
|
||||||
if ci == nil || err != nil {
|
// the contract will be fetched only when asked by a client
|
||||||
ci = &bchain.ContractInfo{
|
// ci, err := b.fetchContractInfo(contract)
|
||||||
Contract: contract,
|
// if ci == nil || err != nil {
|
||||||
}
|
ci := &bchain.ContractInfo{
|
||||||
|
Contract: contract,
|
||||||
}
|
}
|
||||||
ci.Type = bchain.UnknownTokenType
|
// }
|
||||||
|
ci.Type = bchain.UnhandledTokenType
|
||||||
ci.CreatedInBlock = height
|
ci.CreatedInBlock = height
|
||||||
return ci
|
return ci
|
||||||
}
|
}
|
||||||
|
|
||||||
func (b *EthereumRPC) processCallTrace(call *rpcCallTrace, d *bchain.EthereumInternalData, contracts []bchain.ContractInfo, blockHeight uint32) []bchain.ContractInfo {
|
func (b *EthereumRPC) processCallTrace(call *rpcCallTrace, d *bchain.EthereumInternalData, contracts []bchain.ContractInfo, blockHeight uint32) []bchain.ContractInfo {
|
||||||
value, err := hexutil.DecodeBig(call.Value)
|
value, err := hexutil.DecodeBig(call.Value)
|
||||||
|
if err != nil {
|
||||||
|
value = new(big.Int)
|
||||||
|
}
|
||||||
if call.Type == "CREATE" || call.Type == "CREATE2" {
|
if call.Type == "CREATE" || call.Type == "CREATE2" {
|
||||||
d.Transfers = append(d.Transfers, bchain.EthereumInternalTransfer{
|
d.Transfers = append(d.Transfers, bchain.EthereumInternalTransfer{
|
||||||
Type: bchain.CREATE,
|
Type: bchain.CREATE,
|
||||||
@ -653,8 +681,28 @@ func (b *EthereumRPC) getInternalDataForBlock(blockHash string, blockHeight uint
|
|||||||
return data, contracts, err
|
return data, contracts, err
|
||||||
}
|
}
|
||||||
if len(trace) != len(data) {
|
if len(trace) != len(data) {
|
||||||
glog.Error("debug_traceBlockByHash block ", blockHash, ", error: trace length does not match block length ", len(trace), "!=", len(data))
|
if len(trace) < len(data) {
|
||||||
return data, contracts, err
|
for i := range transactions {
|
||||||
|
tx := &transactions[i]
|
||||||
|
// bridging transactions in Polygon do not create trace and cause mismatch between the trace size and block size, it is necessary to adjust the trace size
|
||||||
|
// bridging transaction that from and to zero address
|
||||||
|
if tx.To == "0x0000000000000000000000000000000000000000" && tx.From == "0x0000000000000000000000000000000000000000" {
|
||||||
|
if i >= len(trace) {
|
||||||
|
trace = append(trace, rpcTraceResult{})
|
||||||
|
} else {
|
||||||
|
trace = append(trace[:i+1], trace[i:]...)
|
||||||
|
trace[i] = rpcTraceResult{}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if len(trace) != len(data) {
|
||||||
|
e := fmt.Sprint("trace length does not match block length ", len(trace), "!=", len(data))
|
||||||
|
glog.Error("debug_traceBlockByHash block ", blockHash, ", error: ", e)
|
||||||
|
return data, contracts, errors.New(e)
|
||||||
|
} else {
|
||||||
|
glog.Warning("debug_traceBlockByHash block ", blockHash, ", trace adjusted to match the number of transactions in block")
|
||||||
|
}
|
||||||
}
|
}
|
||||||
for i, result := range trace {
|
for i, result := range trace {
|
||||||
r := &result.Result
|
r := &result.Result
|
||||||
@ -795,12 +843,13 @@ func (b *EthereumRPC) GetTransactionForMempool(txid string) (*bchain.Tx, error)
|
|||||||
func (b *EthereumRPC) GetTransaction(txid string) (*bchain.Tx, error) {
|
func (b *EthereumRPC) GetTransaction(txid string) (*bchain.Tx, error) {
|
||||||
ctx, cancel := context.WithTimeout(context.Background(), b.Timeout)
|
ctx, cancel := context.WithTimeout(context.Background(), b.Timeout)
|
||||||
defer cancel()
|
defer cancel()
|
||||||
var tx *bchain.RpcTransaction
|
tx := &bchain.RpcTransaction{}
|
||||||
hash := ethcommon.HexToHash(txid)
|
hash := ethcommon.HexToHash(txid)
|
||||||
err := b.RPC.CallContext(ctx, &tx, "eth_getTransactionByHash", hash)
|
err := b.RPC.CallContext(ctx, tx, "eth_getTransactionByHash", hash)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
} else if tx == nil {
|
}
|
||||||
|
if *tx == (bchain.RpcTransaction{}) {
|
||||||
if b.mempoolInitialized {
|
if b.mempoolInitialized {
|
||||||
b.Mempool.RemoveTransactionFromMempool(txid)
|
b.Mempool.RemoveTransactionFromMempool(txid)
|
||||||
}
|
}
|
||||||
@ -943,21 +992,31 @@ func (b *EthereumRPC) EthereumTypeEstimateGas(params map[string]interface{}) (ui
|
|||||||
|
|
||||||
// SendRawTransaction sends raw transaction
|
// SendRawTransaction sends raw transaction
|
||||||
func (b *EthereumRPC) SendRawTransaction(hex string) (string, error) {
|
func (b *EthereumRPC) SendRawTransaction(hex string) (string, error) {
|
||||||
|
return b.callRpcStringResult("eth_sendRawTransaction", hex)
|
||||||
|
}
|
||||||
|
|
||||||
|
// EthereumTypeGetRawTransaction gets raw transaction in hex format
|
||||||
|
func (b *EthereumRPC) EthereumTypeGetRawTransaction(txid string) (string, error) {
|
||||||
|
return b.callRpcStringResult("eth_getRawTransactionByHash", txid)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Helper function for calling ETH RPC with parameters and getting string result
|
||||||
|
func (b *EthereumRPC) callRpcStringResult(rpcMethod string, args ...interface{}) (string, error) {
|
||||||
ctx, cancel := context.WithTimeout(context.Background(), b.Timeout)
|
ctx, cancel := context.WithTimeout(context.Background(), b.Timeout)
|
||||||
defer cancel()
|
defer cancel()
|
||||||
var raw json.RawMessage
|
var raw json.RawMessage
|
||||||
err := b.RPC.CallContext(ctx, &raw, "eth_sendRawTransaction", hex)
|
err := b.RPC.CallContext(ctx, &raw, rpcMethod, args...)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return "", err
|
return "", err
|
||||||
} else if len(raw) == 0 {
|
} else if len(raw) == 0 {
|
||||||
return "", errors.New("SendRawTransaction: failed")
|
return "", errors.New(rpcMethod + " : failed")
|
||||||
}
|
}
|
||||||
var result string
|
var result string
|
||||||
if err := json.Unmarshal(raw, &result); err != nil {
|
if err := json.Unmarshal(raw, &result); err != nil {
|
||||||
return "", errors.Annotatef(err, "raw result %v", raw)
|
return "", errors.Annotatef(err, "raw result %v", raw)
|
||||||
}
|
}
|
||||||
if result == "" {
|
if result == "" {
|
||||||
return "", errors.New("SendRawTransaction: failed, empty result")
|
return "", errors.New(rpcMethod + " : failed, empty result")
|
||||||
}
|
}
|
||||||
return result, nil
|
return result, nil
|
||||||
}
|
}
|
||||||
|
|||||||
@ -1,261 +1,530 @@
|
|||||||
// Code generated by protoc-gen-go. DO NOT EDIT.
|
// Code generated by protoc-gen-go. DO NOT EDIT.
|
||||||
|
// versions:
|
||||||
|
// protoc-gen-go v1.28.1
|
||||||
|
// protoc v3.21.12
|
||||||
// source: bchain/coins/eth/ethtx.proto
|
// source: bchain/coins/eth/ethtx.proto
|
||||||
|
|
||||||
/*
|
|
||||||
Package eth is a generated protocol buffer package.
|
|
||||||
|
|
||||||
It is generated from these files:
|
|
||||||
bchain/coins/eth/ethtx.proto
|
|
||||||
|
|
||||||
It has these top-level messages:
|
|
||||||
ProtoCompleteTransaction
|
|
||||||
*/
|
|
||||||
package eth
|
package eth
|
||||||
|
|
||||||
import proto "github.com/golang/protobuf/proto"
|
import (
|
||||||
import fmt "fmt"
|
protoreflect "google.golang.org/protobuf/reflect/protoreflect"
|
||||||
import math "math"
|
protoimpl "google.golang.org/protobuf/runtime/protoimpl"
|
||||||
|
reflect "reflect"
|
||||||
|
sync "sync"
|
||||||
|
)
|
||||||
|
|
||||||
// Reference imports to suppress errors if they are not otherwise used.
|
const (
|
||||||
var _ = proto.Marshal
|
// Verify that this generated code is sufficiently up-to-date.
|
||||||
var _ = fmt.Errorf
|
_ = protoimpl.EnforceVersion(20 - protoimpl.MinVersion)
|
||||||
var _ = math.Inf
|
// Verify that runtime/protoimpl is sufficiently up-to-date.
|
||||||
|
_ = protoimpl.EnforceVersion(protoimpl.MaxVersion - 20)
|
||||||
// This is a compile-time assertion to ensure that this generated file
|
)
|
||||||
// is compatible with the proto package it is being compiled against.
|
|
||||||
// A compilation error at this line likely means your copy of the
|
|
||||||
// proto package needs to be updated.
|
|
||||||
const _ = proto.ProtoPackageIsVersion2 // please upgrade the proto package
|
|
||||||
|
|
||||||
type ProtoCompleteTransaction struct {
|
type ProtoCompleteTransaction struct {
|
||||||
BlockNumber uint32 `protobuf:"varint,1,opt,name=BlockNumber" json:"BlockNumber,omitempty"`
|
state protoimpl.MessageState
|
||||||
BlockTime uint64 `protobuf:"varint,2,opt,name=BlockTime" json:"BlockTime,omitempty"`
|
sizeCache protoimpl.SizeCache
|
||||||
Tx *ProtoCompleteTransaction_TxType `protobuf:"bytes,3,opt,name=Tx" json:"Tx,omitempty"`
|
unknownFields protoimpl.UnknownFields
|
||||||
Receipt *ProtoCompleteTransaction_ReceiptType `protobuf:"bytes,4,opt,name=Receipt" json:"Receipt,omitempty"`
|
|
||||||
|
BlockNumber uint32 `protobuf:"varint,1,opt,name=BlockNumber,proto3" json:"BlockNumber,omitempty"`
|
||||||
|
BlockTime uint64 `protobuf:"varint,2,opt,name=BlockTime,proto3" json:"BlockTime,omitempty"`
|
||||||
|
Tx *ProtoCompleteTransaction_TxType `protobuf:"bytes,3,opt,name=Tx,proto3" json:"Tx,omitempty"`
|
||||||
|
Receipt *ProtoCompleteTransaction_ReceiptType `protobuf:"bytes,4,opt,name=Receipt,proto3" json:"Receipt,omitempty"`
|
||||||
}
|
}
|
||||||
|
|
||||||
func (m *ProtoCompleteTransaction) Reset() { *m = ProtoCompleteTransaction{} }
|
func (x *ProtoCompleteTransaction) Reset() {
|
||||||
func (m *ProtoCompleteTransaction) String() string { return proto.CompactTextString(m) }
|
*x = ProtoCompleteTransaction{}
|
||||||
func (*ProtoCompleteTransaction) ProtoMessage() {}
|
if protoimpl.UnsafeEnabled {
|
||||||
func (*ProtoCompleteTransaction) Descriptor() ([]byte, []int) { return fileDescriptor0, []int{0} }
|
mi := &file_bchain_coins_eth_ethtx_proto_msgTypes[0]
|
||||||
|
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
||||||
|
ms.StoreMessageInfo(mi)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
func (m *ProtoCompleteTransaction) GetBlockNumber() uint32 {
|
func (x *ProtoCompleteTransaction) String() string {
|
||||||
if m != nil {
|
return protoimpl.X.MessageStringOf(x)
|
||||||
return m.BlockNumber
|
}
|
||||||
|
|
||||||
|
func (*ProtoCompleteTransaction) ProtoMessage() {}
|
||||||
|
|
||||||
|
func (x *ProtoCompleteTransaction) ProtoReflect() protoreflect.Message {
|
||||||
|
mi := &file_bchain_coins_eth_ethtx_proto_msgTypes[0]
|
||||||
|
if protoimpl.UnsafeEnabled && x != nil {
|
||||||
|
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
||||||
|
if ms.LoadMessageInfo() == nil {
|
||||||
|
ms.StoreMessageInfo(mi)
|
||||||
|
}
|
||||||
|
return ms
|
||||||
|
}
|
||||||
|
return mi.MessageOf(x)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Deprecated: Use ProtoCompleteTransaction.ProtoReflect.Descriptor instead.
|
||||||
|
func (*ProtoCompleteTransaction) Descriptor() ([]byte, []int) {
|
||||||
|
return file_bchain_coins_eth_ethtx_proto_rawDescGZIP(), []int{0}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (x *ProtoCompleteTransaction) GetBlockNumber() uint32 {
|
||||||
|
if x != nil {
|
||||||
|
return x.BlockNumber
|
||||||
}
|
}
|
||||||
return 0
|
return 0
|
||||||
}
|
}
|
||||||
|
|
||||||
func (m *ProtoCompleteTransaction) GetBlockTime() uint64 {
|
func (x *ProtoCompleteTransaction) GetBlockTime() uint64 {
|
||||||
if m != nil {
|
if x != nil {
|
||||||
return m.BlockTime
|
return x.BlockTime
|
||||||
}
|
}
|
||||||
return 0
|
return 0
|
||||||
}
|
}
|
||||||
|
|
||||||
func (m *ProtoCompleteTransaction) GetTx() *ProtoCompleteTransaction_TxType {
|
func (x *ProtoCompleteTransaction) GetTx() *ProtoCompleteTransaction_TxType {
|
||||||
if m != nil {
|
if x != nil {
|
||||||
return m.Tx
|
return x.Tx
|
||||||
}
|
}
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (m *ProtoCompleteTransaction) GetReceipt() *ProtoCompleteTransaction_ReceiptType {
|
func (x *ProtoCompleteTransaction) GetReceipt() *ProtoCompleteTransaction_ReceiptType {
|
||||||
if m != nil {
|
if x != nil {
|
||||||
return m.Receipt
|
return x.Receipt
|
||||||
}
|
}
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
type ProtoCompleteTransaction_TxType struct {
|
type ProtoCompleteTransaction_TxType struct {
|
||||||
AccountNonce uint64 `protobuf:"varint,1,opt,name=AccountNonce" json:"AccountNonce,omitempty"`
|
state protoimpl.MessageState
|
||||||
|
sizeCache protoimpl.SizeCache
|
||||||
|
unknownFields protoimpl.UnknownFields
|
||||||
|
|
||||||
|
AccountNonce uint64 `protobuf:"varint,1,opt,name=AccountNonce,proto3" json:"AccountNonce,omitempty"`
|
||||||
GasPrice []byte `protobuf:"bytes,2,opt,name=GasPrice,proto3" json:"GasPrice,omitempty"`
|
GasPrice []byte `protobuf:"bytes,2,opt,name=GasPrice,proto3" json:"GasPrice,omitempty"`
|
||||||
GasLimit uint64 `protobuf:"varint,3,opt,name=GasLimit" json:"GasLimit,omitempty"`
|
GasLimit uint64 `protobuf:"varint,3,opt,name=GasLimit,proto3" json:"GasLimit,omitempty"`
|
||||||
Value []byte `protobuf:"bytes,4,opt,name=Value,proto3" json:"Value,omitempty"`
|
Value []byte `protobuf:"bytes,4,opt,name=Value,proto3" json:"Value,omitempty"`
|
||||||
Payload []byte `protobuf:"bytes,5,opt,name=Payload,proto3" json:"Payload,omitempty"`
|
Payload []byte `protobuf:"bytes,5,opt,name=Payload,proto3" json:"Payload,omitempty"`
|
||||||
Hash []byte `protobuf:"bytes,6,opt,name=Hash,proto3" json:"Hash,omitempty"`
|
Hash []byte `protobuf:"bytes,6,opt,name=Hash,proto3" json:"Hash,omitempty"`
|
||||||
To []byte `protobuf:"bytes,7,opt,name=To,proto3" json:"To,omitempty"`
|
To []byte `protobuf:"bytes,7,opt,name=To,proto3" json:"To,omitempty"`
|
||||||
From []byte `protobuf:"bytes,8,opt,name=From,proto3" json:"From,omitempty"`
|
From []byte `protobuf:"bytes,8,opt,name=From,proto3" json:"From,omitempty"`
|
||||||
TransactionIndex uint32 `protobuf:"varint,9,opt,name=TransactionIndex" json:"TransactionIndex,omitempty"`
|
TransactionIndex uint32 `protobuf:"varint,9,opt,name=TransactionIndex,proto3" json:"TransactionIndex,omitempty"`
|
||||||
}
|
}
|
||||||
|
|
||||||
func (m *ProtoCompleteTransaction_TxType) Reset() { *m = ProtoCompleteTransaction_TxType{} }
|
func (x *ProtoCompleteTransaction_TxType) Reset() {
|
||||||
func (m *ProtoCompleteTransaction_TxType) String() string { return proto.CompactTextString(m) }
|
*x = ProtoCompleteTransaction_TxType{}
|
||||||
func (*ProtoCompleteTransaction_TxType) ProtoMessage() {}
|
if protoimpl.UnsafeEnabled {
|
||||||
|
mi := &file_bchain_coins_eth_ethtx_proto_msgTypes[1]
|
||||||
|
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
||||||
|
ms.StoreMessageInfo(mi)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (x *ProtoCompleteTransaction_TxType) String() string {
|
||||||
|
return protoimpl.X.MessageStringOf(x)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (*ProtoCompleteTransaction_TxType) ProtoMessage() {}
|
||||||
|
|
||||||
|
func (x *ProtoCompleteTransaction_TxType) ProtoReflect() protoreflect.Message {
|
||||||
|
mi := &file_bchain_coins_eth_ethtx_proto_msgTypes[1]
|
||||||
|
if protoimpl.UnsafeEnabled && x != nil {
|
||||||
|
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
||||||
|
if ms.LoadMessageInfo() == nil {
|
||||||
|
ms.StoreMessageInfo(mi)
|
||||||
|
}
|
||||||
|
return ms
|
||||||
|
}
|
||||||
|
return mi.MessageOf(x)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Deprecated: Use ProtoCompleteTransaction_TxType.ProtoReflect.Descriptor instead.
|
||||||
func (*ProtoCompleteTransaction_TxType) Descriptor() ([]byte, []int) {
|
func (*ProtoCompleteTransaction_TxType) Descriptor() ([]byte, []int) {
|
||||||
return fileDescriptor0, []int{0, 0}
|
return file_bchain_coins_eth_ethtx_proto_rawDescGZIP(), []int{0, 0}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (m *ProtoCompleteTransaction_TxType) GetAccountNonce() uint64 {
|
func (x *ProtoCompleteTransaction_TxType) GetAccountNonce() uint64 {
|
||||||
if m != nil {
|
if x != nil {
|
||||||
return m.AccountNonce
|
return x.AccountNonce
|
||||||
}
|
}
|
||||||
return 0
|
return 0
|
||||||
}
|
}
|
||||||
|
|
||||||
func (m *ProtoCompleteTransaction_TxType) GetGasPrice() []byte {
|
func (x *ProtoCompleteTransaction_TxType) GetGasPrice() []byte {
|
||||||
if m != nil {
|
if x != nil {
|
||||||
return m.GasPrice
|
return x.GasPrice
|
||||||
}
|
}
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (m *ProtoCompleteTransaction_TxType) GetGasLimit() uint64 {
|
func (x *ProtoCompleteTransaction_TxType) GetGasLimit() uint64 {
|
||||||
if m != nil {
|
if x != nil {
|
||||||
return m.GasLimit
|
return x.GasLimit
|
||||||
}
|
}
|
||||||
return 0
|
return 0
|
||||||
}
|
}
|
||||||
|
|
||||||
func (m *ProtoCompleteTransaction_TxType) GetValue() []byte {
|
func (x *ProtoCompleteTransaction_TxType) GetValue() []byte {
|
||||||
if m != nil {
|
if x != nil {
|
||||||
return m.Value
|
return x.Value
|
||||||
}
|
}
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (m *ProtoCompleteTransaction_TxType) GetPayload() []byte {
|
func (x *ProtoCompleteTransaction_TxType) GetPayload() []byte {
|
||||||
if m != nil {
|
if x != nil {
|
||||||
return m.Payload
|
return x.Payload
|
||||||
}
|
}
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (m *ProtoCompleteTransaction_TxType) GetHash() []byte {
|
func (x *ProtoCompleteTransaction_TxType) GetHash() []byte {
|
||||||
if m != nil {
|
if x != nil {
|
||||||
return m.Hash
|
return x.Hash
|
||||||
}
|
}
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (m *ProtoCompleteTransaction_TxType) GetTo() []byte {
|
func (x *ProtoCompleteTransaction_TxType) GetTo() []byte {
|
||||||
if m != nil {
|
if x != nil {
|
||||||
return m.To
|
return x.To
|
||||||
}
|
}
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (m *ProtoCompleteTransaction_TxType) GetFrom() []byte {
|
func (x *ProtoCompleteTransaction_TxType) GetFrom() []byte {
|
||||||
if m != nil {
|
if x != nil {
|
||||||
return m.From
|
return x.From
|
||||||
}
|
}
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (m *ProtoCompleteTransaction_TxType) GetTransactionIndex() uint32 {
|
func (x *ProtoCompleteTransaction_TxType) GetTransactionIndex() uint32 {
|
||||||
if m != nil {
|
if x != nil {
|
||||||
return m.TransactionIndex
|
return x.TransactionIndex
|
||||||
}
|
}
|
||||||
return 0
|
return 0
|
||||||
}
|
}
|
||||||
|
|
||||||
type ProtoCompleteTransaction_ReceiptType struct {
|
type ProtoCompleteTransaction_ReceiptType struct {
|
||||||
GasUsed []byte `protobuf:"bytes,1,opt,name=GasUsed,proto3" json:"GasUsed,omitempty"`
|
state protoimpl.MessageState
|
||||||
Status []byte `protobuf:"bytes,2,opt,name=Status,proto3" json:"Status,omitempty"`
|
sizeCache protoimpl.SizeCache
|
||||||
Log []*ProtoCompleteTransaction_ReceiptType_LogType `protobuf:"bytes,3,rep,name=Log" json:"Log,omitempty"`
|
unknownFields protoimpl.UnknownFields
|
||||||
|
|
||||||
|
GasUsed []byte `protobuf:"bytes,1,opt,name=GasUsed,proto3" json:"GasUsed,omitempty"`
|
||||||
|
Status []byte `protobuf:"bytes,2,opt,name=Status,proto3" json:"Status,omitempty"`
|
||||||
|
Log []*ProtoCompleteTransaction_ReceiptType_LogType `protobuf:"bytes,3,rep,name=Log,proto3" json:"Log,omitempty"`
|
||||||
|
L1Fee []byte `protobuf:"bytes,4,opt,name=L1Fee,proto3,oneof" json:"L1Fee,omitempty"`
|
||||||
|
L1FeeScalar []byte `protobuf:"bytes,5,opt,name=L1FeeScalar,proto3,oneof" json:"L1FeeScalar,omitempty"`
|
||||||
|
L1GasPrice []byte `protobuf:"bytes,6,opt,name=L1GasPrice,proto3,oneof" json:"L1GasPrice,omitempty"`
|
||||||
|
L1GasUsed []byte `protobuf:"bytes,7,opt,name=L1GasUsed,proto3,oneof" json:"L1GasUsed,omitempty"`
|
||||||
}
|
}
|
||||||
|
|
||||||
func (m *ProtoCompleteTransaction_ReceiptType) Reset() { *m = ProtoCompleteTransaction_ReceiptType{} }
|
func (x *ProtoCompleteTransaction_ReceiptType) Reset() {
|
||||||
func (m *ProtoCompleteTransaction_ReceiptType) String() string { return proto.CompactTextString(m) }
|
*x = ProtoCompleteTransaction_ReceiptType{}
|
||||||
func (*ProtoCompleteTransaction_ReceiptType) ProtoMessage() {}
|
if protoimpl.UnsafeEnabled {
|
||||||
|
mi := &file_bchain_coins_eth_ethtx_proto_msgTypes[2]
|
||||||
|
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
||||||
|
ms.StoreMessageInfo(mi)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (x *ProtoCompleteTransaction_ReceiptType) String() string {
|
||||||
|
return protoimpl.X.MessageStringOf(x)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (*ProtoCompleteTransaction_ReceiptType) ProtoMessage() {}
|
||||||
|
|
||||||
|
func (x *ProtoCompleteTransaction_ReceiptType) ProtoReflect() protoreflect.Message {
|
||||||
|
mi := &file_bchain_coins_eth_ethtx_proto_msgTypes[2]
|
||||||
|
if protoimpl.UnsafeEnabled && x != nil {
|
||||||
|
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
||||||
|
if ms.LoadMessageInfo() == nil {
|
||||||
|
ms.StoreMessageInfo(mi)
|
||||||
|
}
|
||||||
|
return ms
|
||||||
|
}
|
||||||
|
return mi.MessageOf(x)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Deprecated: Use ProtoCompleteTransaction_ReceiptType.ProtoReflect.Descriptor instead.
|
||||||
func (*ProtoCompleteTransaction_ReceiptType) Descriptor() ([]byte, []int) {
|
func (*ProtoCompleteTransaction_ReceiptType) Descriptor() ([]byte, []int) {
|
||||||
return fileDescriptor0, []int{0, 1}
|
return file_bchain_coins_eth_ethtx_proto_rawDescGZIP(), []int{0, 1}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (m *ProtoCompleteTransaction_ReceiptType) GetGasUsed() []byte {
|
func (x *ProtoCompleteTransaction_ReceiptType) GetGasUsed() []byte {
|
||||||
if m != nil {
|
if x != nil {
|
||||||
return m.GasUsed
|
return x.GasUsed
|
||||||
}
|
}
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (m *ProtoCompleteTransaction_ReceiptType) GetStatus() []byte {
|
func (x *ProtoCompleteTransaction_ReceiptType) GetStatus() []byte {
|
||||||
if m != nil {
|
if x != nil {
|
||||||
return m.Status
|
return x.Status
|
||||||
}
|
}
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (m *ProtoCompleteTransaction_ReceiptType) GetLog() []*ProtoCompleteTransaction_ReceiptType_LogType {
|
func (x *ProtoCompleteTransaction_ReceiptType) GetLog() []*ProtoCompleteTransaction_ReceiptType_LogType {
|
||||||
if m != nil {
|
if x != nil {
|
||||||
return m.Log
|
return x.Log
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (x *ProtoCompleteTransaction_ReceiptType) GetL1Fee() []byte {
|
||||||
|
if x != nil {
|
||||||
|
return x.L1Fee
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (x *ProtoCompleteTransaction_ReceiptType) GetL1FeeScalar() []byte {
|
||||||
|
if x != nil {
|
||||||
|
return x.L1FeeScalar
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (x *ProtoCompleteTransaction_ReceiptType) GetL1GasPrice() []byte {
|
||||||
|
if x != nil {
|
||||||
|
return x.L1GasPrice
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (x *ProtoCompleteTransaction_ReceiptType) GetL1GasUsed() []byte {
|
||||||
|
if x != nil {
|
||||||
|
return x.L1GasUsed
|
||||||
}
|
}
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
type ProtoCompleteTransaction_ReceiptType_LogType struct {
|
type ProtoCompleteTransaction_ReceiptType_LogType struct {
|
||||||
|
state protoimpl.MessageState
|
||||||
|
sizeCache protoimpl.SizeCache
|
||||||
|
unknownFields protoimpl.UnknownFields
|
||||||
|
|
||||||
Address []byte `protobuf:"bytes,1,opt,name=Address,proto3" json:"Address,omitempty"`
|
Address []byte `protobuf:"bytes,1,opt,name=Address,proto3" json:"Address,omitempty"`
|
||||||
Data []byte `protobuf:"bytes,2,opt,name=Data,proto3" json:"Data,omitempty"`
|
Data []byte `protobuf:"bytes,2,opt,name=Data,proto3" json:"Data,omitempty"`
|
||||||
Topics [][]byte `protobuf:"bytes,3,rep,name=Topics,proto3" json:"Topics,omitempty"`
|
Topics [][]byte `protobuf:"bytes,3,rep,name=Topics,proto3" json:"Topics,omitempty"`
|
||||||
}
|
}
|
||||||
|
|
||||||
func (m *ProtoCompleteTransaction_ReceiptType_LogType) Reset() {
|
func (x *ProtoCompleteTransaction_ReceiptType_LogType) Reset() {
|
||||||
*m = ProtoCompleteTransaction_ReceiptType_LogType{}
|
*x = ProtoCompleteTransaction_ReceiptType_LogType{}
|
||||||
|
if protoimpl.UnsafeEnabled {
|
||||||
|
mi := &file_bchain_coins_eth_ethtx_proto_msgTypes[3]
|
||||||
|
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
||||||
|
ms.StoreMessageInfo(mi)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
func (m *ProtoCompleteTransaction_ReceiptType_LogType) String() string {
|
|
||||||
return proto.CompactTextString(m)
|
func (x *ProtoCompleteTransaction_ReceiptType_LogType) String() string {
|
||||||
|
return protoimpl.X.MessageStringOf(x)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (*ProtoCompleteTransaction_ReceiptType_LogType) ProtoMessage() {}
|
func (*ProtoCompleteTransaction_ReceiptType_LogType) ProtoMessage() {}
|
||||||
|
|
||||||
|
func (x *ProtoCompleteTransaction_ReceiptType_LogType) ProtoReflect() protoreflect.Message {
|
||||||
|
mi := &file_bchain_coins_eth_ethtx_proto_msgTypes[3]
|
||||||
|
if protoimpl.UnsafeEnabled && x != nil {
|
||||||
|
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
||||||
|
if ms.LoadMessageInfo() == nil {
|
||||||
|
ms.StoreMessageInfo(mi)
|
||||||
|
}
|
||||||
|
return ms
|
||||||
|
}
|
||||||
|
return mi.MessageOf(x)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Deprecated: Use ProtoCompleteTransaction_ReceiptType_LogType.ProtoReflect.Descriptor instead.
|
||||||
func (*ProtoCompleteTransaction_ReceiptType_LogType) Descriptor() ([]byte, []int) {
|
func (*ProtoCompleteTransaction_ReceiptType_LogType) Descriptor() ([]byte, []int) {
|
||||||
return fileDescriptor0, []int{0, 1, 0}
|
return file_bchain_coins_eth_ethtx_proto_rawDescGZIP(), []int{0, 1, 0}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (m *ProtoCompleteTransaction_ReceiptType_LogType) GetAddress() []byte {
|
func (x *ProtoCompleteTransaction_ReceiptType_LogType) GetAddress() []byte {
|
||||||
if m != nil {
|
if x != nil {
|
||||||
return m.Address
|
return x.Address
|
||||||
}
|
}
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (m *ProtoCompleteTransaction_ReceiptType_LogType) GetData() []byte {
|
func (x *ProtoCompleteTransaction_ReceiptType_LogType) GetData() []byte {
|
||||||
if m != nil {
|
if x != nil {
|
||||||
return m.Data
|
return x.Data
|
||||||
}
|
}
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (m *ProtoCompleteTransaction_ReceiptType_LogType) GetTopics() [][]byte {
|
func (x *ProtoCompleteTransaction_ReceiptType_LogType) GetTopics() [][]byte {
|
||||||
if m != nil {
|
if x != nil {
|
||||||
return m.Topics
|
return x.Topics
|
||||||
}
|
}
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func init() {
|
var File_bchain_coins_eth_ethtx_proto protoreflect.FileDescriptor
|
||||||
proto.RegisterType((*ProtoCompleteTransaction)(nil), "eth.ProtoCompleteTransaction")
|
|
||||||
proto.RegisterType((*ProtoCompleteTransaction_TxType)(nil), "eth.ProtoCompleteTransaction.TxType")
|
var file_bchain_coins_eth_ethtx_proto_rawDesc = []byte{
|
||||||
proto.RegisterType((*ProtoCompleteTransaction_ReceiptType)(nil), "eth.ProtoCompleteTransaction.ReceiptType")
|
0x0a, 0x1c, 0x62, 0x63, 0x68, 0x61, 0x69, 0x6e, 0x2f, 0x63, 0x6f, 0x69, 0x6e, 0x73, 0x2f, 0x65,
|
||||||
proto.RegisterType((*ProtoCompleteTransaction_ReceiptType_LogType)(nil), "eth.ProtoCompleteTransaction.ReceiptType.LogType")
|
0x74, 0x68, 0x2f, 0x65, 0x74, 0x68, 0x74, 0x78, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x22, 0xdd,
|
||||||
|
0x06, 0x0a, 0x18, 0x50, 0x72, 0x6f, 0x74, 0x6f, 0x43, 0x6f, 0x6d, 0x70, 0x6c, 0x65, 0x74, 0x65,
|
||||||
|
0x54, 0x72, 0x61, 0x6e, 0x73, 0x61, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x12, 0x20, 0x0a, 0x0b, 0x42,
|
||||||
|
0x6c, 0x6f, 0x63, 0x6b, 0x4e, 0x75, 0x6d, 0x62, 0x65, 0x72, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0d,
|
||||||
|
0x52, 0x0b, 0x42, 0x6c, 0x6f, 0x63, 0x6b, 0x4e, 0x75, 0x6d, 0x62, 0x65, 0x72, 0x12, 0x1c, 0x0a,
|
||||||
|
0x09, 0x42, 0x6c, 0x6f, 0x63, 0x6b, 0x54, 0x69, 0x6d, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x04,
|
||||||
|
0x52, 0x09, 0x42, 0x6c, 0x6f, 0x63, 0x6b, 0x54, 0x69, 0x6d, 0x65, 0x12, 0x30, 0x0a, 0x02, 0x54,
|
||||||
|
0x78, 0x18, 0x03, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x20, 0x2e, 0x50, 0x72, 0x6f, 0x74, 0x6f, 0x43,
|
||||||
|
0x6f, 0x6d, 0x70, 0x6c, 0x65, 0x74, 0x65, 0x54, 0x72, 0x61, 0x6e, 0x73, 0x61, 0x63, 0x74, 0x69,
|
||||||
|
0x6f, 0x6e, 0x2e, 0x54, 0x78, 0x54, 0x79, 0x70, 0x65, 0x52, 0x02, 0x54, 0x78, 0x12, 0x3f, 0x0a,
|
||||||
|
0x07, 0x52, 0x65, 0x63, 0x65, 0x69, 0x70, 0x74, 0x18, 0x04, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x25,
|
||||||
|
0x2e, 0x50, 0x72, 0x6f, 0x74, 0x6f, 0x43, 0x6f, 0x6d, 0x70, 0x6c, 0x65, 0x74, 0x65, 0x54, 0x72,
|
||||||
|
0x61, 0x6e, 0x73, 0x61, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x2e, 0x52, 0x65, 0x63, 0x65, 0x69, 0x70,
|
||||||
|
0x74, 0x54, 0x79, 0x70, 0x65, 0x52, 0x07, 0x52, 0x65, 0x63, 0x65, 0x69, 0x70, 0x74, 0x1a, 0xf8,
|
||||||
|
0x01, 0x0a, 0x06, 0x54, 0x78, 0x54, 0x79, 0x70, 0x65, 0x12, 0x22, 0x0a, 0x0c, 0x41, 0x63, 0x63,
|
||||||
|
0x6f, 0x75, 0x6e, 0x74, 0x4e, 0x6f, 0x6e, 0x63, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x04, 0x52,
|
||||||
|
0x0c, 0x41, 0x63, 0x63, 0x6f, 0x75, 0x6e, 0x74, 0x4e, 0x6f, 0x6e, 0x63, 0x65, 0x12, 0x1a, 0x0a,
|
||||||
|
0x08, 0x47, 0x61, 0x73, 0x50, 0x72, 0x69, 0x63, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0c, 0x52,
|
||||||
|
0x08, 0x47, 0x61, 0x73, 0x50, 0x72, 0x69, 0x63, 0x65, 0x12, 0x1a, 0x0a, 0x08, 0x47, 0x61, 0x73,
|
||||||
|
0x4c, 0x69, 0x6d, 0x69, 0x74, 0x18, 0x03, 0x20, 0x01, 0x28, 0x04, 0x52, 0x08, 0x47, 0x61, 0x73,
|
||||||
|
0x4c, 0x69, 0x6d, 0x69, 0x74, 0x12, 0x14, 0x0a, 0x05, 0x56, 0x61, 0x6c, 0x75, 0x65, 0x18, 0x04,
|
||||||
|
0x20, 0x01, 0x28, 0x0c, 0x52, 0x05, 0x56, 0x61, 0x6c, 0x75, 0x65, 0x12, 0x18, 0x0a, 0x07, 0x50,
|
||||||
|
0x61, 0x79, 0x6c, 0x6f, 0x61, 0x64, 0x18, 0x05, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x07, 0x50, 0x61,
|
||||||
|
0x79, 0x6c, 0x6f, 0x61, 0x64, 0x12, 0x12, 0x0a, 0x04, 0x48, 0x61, 0x73, 0x68, 0x18, 0x06, 0x20,
|
||||||
|
0x01, 0x28, 0x0c, 0x52, 0x04, 0x48, 0x61, 0x73, 0x68, 0x12, 0x0e, 0x0a, 0x02, 0x54, 0x6f, 0x18,
|
||||||
|
0x07, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x02, 0x54, 0x6f, 0x12, 0x12, 0x0a, 0x04, 0x46, 0x72, 0x6f,
|
||||||
|
0x6d, 0x18, 0x08, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x04, 0x46, 0x72, 0x6f, 0x6d, 0x12, 0x2a, 0x0a,
|
||||||
|
0x10, 0x54, 0x72, 0x61, 0x6e, 0x73, 0x61, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x49, 0x6e, 0x64, 0x65,
|
||||||
|
0x78, 0x18, 0x09, 0x20, 0x01, 0x28, 0x0d, 0x52, 0x10, 0x54, 0x72, 0x61, 0x6e, 0x73, 0x61, 0x63,
|
||||||
|
0x74, 0x69, 0x6f, 0x6e, 0x49, 0x6e, 0x64, 0x65, 0x78, 0x1a, 0x92, 0x03, 0x0a, 0x0b, 0x52, 0x65,
|
||||||
|
0x63, 0x65, 0x69, 0x70, 0x74, 0x54, 0x79, 0x70, 0x65, 0x12, 0x18, 0x0a, 0x07, 0x47, 0x61, 0x73,
|
||||||
|
0x55, 0x73, 0x65, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x07, 0x47, 0x61, 0x73, 0x55,
|
||||||
|
0x73, 0x65, 0x64, 0x12, 0x16, 0x0a, 0x06, 0x53, 0x74, 0x61, 0x74, 0x75, 0x73, 0x18, 0x02, 0x20,
|
||||||
|
0x01, 0x28, 0x0c, 0x52, 0x06, 0x53, 0x74, 0x61, 0x74, 0x75, 0x73, 0x12, 0x3f, 0x0a, 0x03, 0x4c,
|
||||||
|
0x6f, 0x67, 0x18, 0x03, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x2d, 0x2e, 0x50, 0x72, 0x6f, 0x74, 0x6f,
|
||||||
|
0x43, 0x6f, 0x6d, 0x70, 0x6c, 0x65, 0x74, 0x65, 0x54, 0x72, 0x61, 0x6e, 0x73, 0x61, 0x63, 0x74,
|
||||||
|
0x69, 0x6f, 0x6e, 0x2e, 0x52, 0x65, 0x63, 0x65, 0x69, 0x70, 0x74, 0x54, 0x79, 0x70, 0x65, 0x2e,
|
||||||
|
0x4c, 0x6f, 0x67, 0x54, 0x79, 0x70, 0x65, 0x52, 0x03, 0x4c, 0x6f, 0x67, 0x12, 0x19, 0x0a, 0x05,
|
||||||
|
0x4c, 0x31, 0x46, 0x65, 0x65, 0x18, 0x04, 0x20, 0x01, 0x28, 0x0c, 0x48, 0x00, 0x52, 0x05, 0x4c,
|
||||||
|
0x31, 0x46, 0x65, 0x65, 0x88, 0x01, 0x01, 0x12, 0x25, 0x0a, 0x0b, 0x4c, 0x31, 0x46, 0x65, 0x65,
|
||||||
|
0x53, 0x63, 0x61, 0x6c, 0x61, 0x72, 0x18, 0x05, 0x20, 0x01, 0x28, 0x0c, 0x48, 0x01, 0x52, 0x0b,
|
||||||
|
0x4c, 0x31, 0x46, 0x65, 0x65, 0x53, 0x63, 0x61, 0x6c, 0x61, 0x72, 0x88, 0x01, 0x01, 0x12, 0x23,
|
||||||
|
0x0a, 0x0a, 0x4c, 0x31, 0x47, 0x61, 0x73, 0x50, 0x72, 0x69, 0x63, 0x65, 0x18, 0x06, 0x20, 0x01,
|
||||||
|
0x28, 0x0c, 0x48, 0x02, 0x52, 0x0a, 0x4c, 0x31, 0x47, 0x61, 0x73, 0x50, 0x72, 0x69, 0x63, 0x65,
|
||||||
|
0x88, 0x01, 0x01, 0x12, 0x21, 0x0a, 0x09, 0x4c, 0x31, 0x47, 0x61, 0x73, 0x55, 0x73, 0x65, 0x64,
|
||||||
|
0x18, 0x07, 0x20, 0x01, 0x28, 0x0c, 0x48, 0x03, 0x52, 0x09, 0x4c, 0x31, 0x47, 0x61, 0x73, 0x55,
|
||||||
|
0x73, 0x65, 0x64, 0x88, 0x01, 0x01, 0x1a, 0x4f, 0x0a, 0x07, 0x4c, 0x6f, 0x67, 0x54, 0x79, 0x70,
|
||||||
|
0x65, 0x12, 0x18, 0x0a, 0x07, 0x41, 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, 0x18, 0x01, 0x20, 0x01,
|
||||||
|
0x28, 0x0c, 0x52, 0x07, 0x41, 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, 0x12, 0x12, 0x0a, 0x04, 0x44,
|
||||||
|
0x61, 0x74, 0x61, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x04, 0x44, 0x61, 0x74, 0x61, 0x12,
|
||||||
|
0x16, 0x0a, 0x06, 0x54, 0x6f, 0x70, 0x69, 0x63, 0x73, 0x18, 0x03, 0x20, 0x03, 0x28, 0x0c, 0x52,
|
||||||
|
0x06, 0x54, 0x6f, 0x70, 0x69, 0x63, 0x73, 0x42, 0x08, 0x0a, 0x06, 0x5f, 0x4c, 0x31, 0x46, 0x65,
|
||||||
|
0x65, 0x42, 0x0e, 0x0a, 0x0c, 0x5f, 0x4c, 0x31, 0x46, 0x65, 0x65, 0x53, 0x63, 0x61, 0x6c, 0x61,
|
||||||
|
0x72, 0x42, 0x0d, 0x0a, 0x0b, 0x5f, 0x4c, 0x31, 0x47, 0x61, 0x73, 0x50, 0x72, 0x69, 0x63, 0x65,
|
||||||
|
0x42, 0x0c, 0x0a, 0x0a, 0x5f, 0x4c, 0x31, 0x47, 0x61, 0x73, 0x55, 0x73, 0x65, 0x64, 0x42, 0x12,
|
||||||
|
0x5a, 0x10, 0x62, 0x63, 0x68, 0x61, 0x69, 0x6e, 0x2f, 0x63, 0x6f, 0x69, 0x6e, 0x73, 0x2f, 0x65,
|
||||||
|
0x74, 0x68, 0x62, 0x06, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x33,
|
||||||
}
|
}
|
||||||
|
|
||||||
func init() { proto.RegisterFile("bchain/coins/eth/ethtx.proto", fileDescriptor0) }
|
var (
|
||||||
|
file_bchain_coins_eth_ethtx_proto_rawDescOnce sync.Once
|
||||||
|
file_bchain_coins_eth_ethtx_proto_rawDescData = file_bchain_coins_eth_ethtx_proto_rawDesc
|
||||||
|
)
|
||||||
|
|
||||||
var fileDescriptor0 = []byte{
|
func file_bchain_coins_eth_ethtx_proto_rawDescGZIP() []byte {
|
||||||
// 409 bytes of a gzipped FileDescriptorProto
|
file_bchain_coins_eth_ethtx_proto_rawDescOnce.Do(func() {
|
||||||
0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0x8c, 0x92, 0xdf, 0x8a, 0xd4, 0x30,
|
file_bchain_coins_eth_ethtx_proto_rawDescData = protoimpl.X.CompressGZIP(file_bchain_coins_eth_ethtx_proto_rawDescData)
|
||||||
0x18, 0xc5, 0xe9, 0x9f, 0x99, 0xd9, 0xfd, 0xa6, 0x8a, 0x04, 0x91, 0x30, 0xec, 0x45, 0x59, 0xbc,
|
})
|
||||||
0x18, 0xbd, 0xe8, 0xe2, 0xea, 0x0b, 0xac, 0x23, 0xae, 0xc2, 0xb0, 0x0e, 0x31, 0x7a, 0x9f, 0x49,
|
return file_bchain_coins_eth_ethtx_proto_rawDescData
|
||||||
0xc3, 0x36, 0x38, 0x6d, 0x4a, 0x93, 0x42, 0xf7, 0x8d, 0x7c, 0x21, 0xdf, 0xc5, 0x4b, 0xc9, 0xd7,
|
}
|
||||||
0x74, 0x1d, 0x11, 0x65, 0x2f, 0x0a, 0xf9, 0x9d, 0x7e, 0xa7, 0x39, 0x27, 0x29, 0x9c, 0xed, 0x65,
|
|
||||||
0x25, 0x74, 0x73, 0x21, 0x8d, 0x6e, 0xec, 0x85, 0x72, 0x95, 0x7f, 0xdc, 0x50, 0xb4, 0x9d, 0x71,
|
var file_bchain_coins_eth_ethtx_proto_msgTypes = make([]protoimpl.MessageInfo, 4)
|
||||||
0x86, 0x24, 0xca, 0x55, 0xe7, 0xdf, 0x67, 0x40, 0x77, 0x1e, 0x37, 0xa6, 0x6e, 0x0f, 0xca, 0x29,
|
var file_bchain_coins_eth_ethtx_proto_goTypes = []interface{}{
|
||||||
0xde, 0x89, 0xc6, 0x0a, 0xe9, 0xb4, 0x69, 0x48, 0x0e, 0xcb, 0xb7, 0x07, 0x23, 0xbf, 0xdd, 0xf4,
|
(*ProtoCompleteTransaction)(nil), // 0: ProtoCompleteTransaction
|
||||||
0xf5, 0x5e, 0x75, 0x34, 0xca, 0xa3, 0xf5, 0x23, 0x76, 0x2c, 0x91, 0x33, 0x38, 0x45, 0xe4, 0xba,
|
(*ProtoCompleteTransaction_TxType)(nil), // 1: ProtoCompleteTransaction.TxType
|
||||||
0x56, 0x34, 0xce, 0xa3, 0x75, 0xca, 0x7e, 0x0b, 0xe4, 0x0d, 0xc4, 0x7c, 0xa0, 0x49, 0x1e, 0xad,
|
(*ProtoCompleteTransaction_ReceiptType)(nil), // 2: ProtoCompleteTransaction.ReceiptType
|
||||||
0x97, 0x97, 0xcf, 0x0b, 0xe5, 0xaa, 0xe2, 0x5f, 0x5b, 0x15, 0x7c, 0xe0, 0x77, 0xad, 0x62, 0x31,
|
(*ProtoCompleteTransaction_ReceiptType_LogType)(nil), // 3: ProtoCompleteTransaction.ReceiptType.LogType
|
||||||
0x1f, 0xc8, 0x06, 0x16, 0x4c, 0x49, 0xa5, 0x5b, 0x47, 0x53, 0xb4, 0xbe, 0xf8, 0xbf, 0x35, 0x0c,
|
}
|
||||||
0xa3, 0x7f, 0x72, 0xae, 0x7e, 0x46, 0x30, 0x1f, 0xbf, 0x49, 0xce, 0x21, 0xbb, 0x92, 0xd2, 0xf4,
|
var file_bchain_coins_eth_ethtx_proto_depIdxs = []int32{
|
||||||
0x8d, 0xbb, 0x31, 0x8d, 0x54, 0x58, 0x23, 0x65, 0x7f, 0x68, 0x64, 0x05, 0x27, 0xd7, 0xc2, 0xee,
|
1, // 0: ProtoCompleteTransaction.Tx:type_name -> ProtoCompleteTransaction.TxType
|
||||||
0x3a, 0x2d, 0xc7, 0x1a, 0x19, 0xbb, 0xe7, 0xf0, 0x6e, 0xab, 0x6b, 0xed, 0xb0, 0x4b, 0xca, 0xee,
|
2, // 1: ProtoCompleteTransaction.Receipt:type_name -> ProtoCompleteTransaction.ReceiptType
|
||||||
0x99, 0x3c, 0x85, 0xd9, 0x57, 0x71, 0xe8, 0x15, 0x26, 0xcd, 0xd8, 0x08, 0x84, 0xc2, 0x62, 0x27,
|
3, // 2: ProtoCompleteTransaction.ReceiptType.Log:type_name -> ProtoCompleteTransaction.ReceiptType.LogType
|
||||||
0xee, 0x0e, 0x46, 0x94, 0x74, 0x86, 0xfa, 0x84, 0x84, 0x40, 0xfa, 0x41, 0xd8, 0x8a, 0xce, 0x51,
|
3, // [3:3] is the sub-list for method output_type
|
||||||
0xc6, 0x35, 0x79, 0x0c, 0x31, 0x37, 0x74, 0x81, 0x4a, 0xcc, 0x8d, 0x9f, 0x79, 0xdf, 0x99, 0x9a,
|
3, // [3:3] is the sub-list for method input_type
|
||||||
0x9e, 0x8c, 0x33, 0x7e, 0x4d, 0x5e, 0xc2, 0x93, 0xa3, 0xca, 0x1f, 0x9b, 0x52, 0x0d, 0xf4, 0x14,
|
3, // [3:3] is the sub-list for extension type_name
|
||||||
0xaf, 0xe3, 0x2f, 0x7d, 0xf5, 0x23, 0x82, 0xe5, 0xd1, 0x99, 0xf8, 0x34, 0xd7, 0xc2, 0x7e, 0xb1,
|
3, // [3:3] is the sub-list for extension extendee
|
||||||
0xaa, 0xc4, 0xea, 0x19, 0x9b, 0x90, 0x3c, 0x83, 0xf9, 0x67, 0x27, 0x5c, 0x6f, 0x43, 0xe7, 0x40,
|
0, // [0:3] is the sub-list for field type_name
|
||||||
0x64, 0x03, 0xc9, 0xd6, 0xdc, 0xd2, 0x24, 0x4f, 0xd6, 0xcb, 0xcb, 0x57, 0x0f, 0x3e, 0xfd, 0x62,
|
}
|
||||||
0x6b, 0x6e, 0xf1, 0x16, 0xbc, 0x7b, 0xf5, 0x09, 0x16, 0x81, 0x7d, 0x82, 0xab, 0xb2, 0xec, 0x94,
|
|
||||||
0xb5, 0x53, 0x82, 0x80, 0xbe, 0xeb, 0x3b, 0xe1, 0x44, 0xd8, 0x1f, 0xd7, 0x3e, 0x15, 0x37, 0xad,
|
func init() { file_bchain_coins_eth_ethtx_proto_init() }
|
||||||
0x96, 0x16, 0x03, 0x64, 0x2c, 0xd0, 0x7e, 0x8e, 0xbf, 0xed, 0xeb, 0x5f, 0x01, 0x00, 0x00, 0xff,
|
func file_bchain_coins_eth_ethtx_proto_init() {
|
||||||
0xff, 0xc2, 0x69, 0x8d, 0xdf, 0xd6, 0x02, 0x00, 0x00,
|
if File_bchain_coins_eth_ethtx_proto != nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
if !protoimpl.UnsafeEnabled {
|
||||||
|
file_bchain_coins_eth_ethtx_proto_msgTypes[0].Exporter = func(v interface{}, i int) interface{} {
|
||||||
|
switch v := v.(*ProtoCompleteTransaction); i {
|
||||||
|
case 0:
|
||||||
|
return &v.state
|
||||||
|
case 1:
|
||||||
|
return &v.sizeCache
|
||||||
|
case 2:
|
||||||
|
return &v.unknownFields
|
||||||
|
default:
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
}
|
||||||
|
file_bchain_coins_eth_ethtx_proto_msgTypes[1].Exporter = func(v interface{}, i int) interface{} {
|
||||||
|
switch v := v.(*ProtoCompleteTransaction_TxType); i {
|
||||||
|
case 0:
|
||||||
|
return &v.state
|
||||||
|
case 1:
|
||||||
|
return &v.sizeCache
|
||||||
|
case 2:
|
||||||
|
return &v.unknownFields
|
||||||
|
default:
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
}
|
||||||
|
file_bchain_coins_eth_ethtx_proto_msgTypes[2].Exporter = func(v interface{}, i int) interface{} {
|
||||||
|
switch v := v.(*ProtoCompleteTransaction_ReceiptType); i {
|
||||||
|
case 0:
|
||||||
|
return &v.state
|
||||||
|
case 1:
|
||||||
|
return &v.sizeCache
|
||||||
|
case 2:
|
||||||
|
return &v.unknownFields
|
||||||
|
default:
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
}
|
||||||
|
file_bchain_coins_eth_ethtx_proto_msgTypes[3].Exporter = func(v interface{}, i int) interface{} {
|
||||||
|
switch v := v.(*ProtoCompleteTransaction_ReceiptType_LogType); i {
|
||||||
|
case 0:
|
||||||
|
return &v.state
|
||||||
|
case 1:
|
||||||
|
return &v.sizeCache
|
||||||
|
case 2:
|
||||||
|
return &v.unknownFields
|
||||||
|
default:
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
file_bchain_coins_eth_ethtx_proto_msgTypes[2].OneofWrappers = []interface{}{}
|
||||||
|
type x struct{}
|
||||||
|
out := protoimpl.TypeBuilder{
|
||||||
|
File: protoimpl.DescBuilder{
|
||||||
|
GoPackagePath: reflect.TypeOf(x{}).PkgPath(),
|
||||||
|
RawDescriptor: file_bchain_coins_eth_ethtx_proto_rawDesc,
|
||||||
|
NumEnums: 0,
|
||||||
|
NumMessages: 4,
|
||||||
|
NumExtensions: 0,
|
||||||
|
NumServices: 0,
|
||||||
|
},
|
||||||
|
GoTypes: file_bchain_coins_eth_ethtx_proto_goTypes,
|
||||||
|
DependencyIndexes: file_bchain_coins_eth_ethtx_proto_depIdxs,
|
||||||
|
MessageInfos: file_bchain_coins_eth_ethtx_proto_msgTypes,
|
||||||
|
}.Build()
|
||||||
|
File_bchain_coins_eth_ethtx_proto = out.File
|
||||||
|
file_bchain_coins_eth_ethtx_proto_rawDesc = nil
|
||||||
|
file_bchain_coins_eth_ethtx_proto_goTypes = nil
|
||||||
|
file_bchain_coins_eth_ethtx_proto_depIdxs = nil
|
||||||
}
|
}
|
||||||
|
|||||||
@ -1,30 +1,34 @@
|
|||||||
syntax = "proto3";
|
syntax = "proto3";
|
||||||
package eth;
|
option go_package = "bchain/coins/eth";
|
||||||
|
|
||||||
message ProtoCompleteTransaction {
|
message ProtoCompleteTransaction {
|
||||||
message TxType {
|
message TxType {
|
||||||
uint64 AccountNonce = 1;
|
uint64 AccountNonce = 1;
|
||||||
bytes GasPrice = 2;
|
bytes GasPrice = 2;
|
||||||
uint64 GasLimit = 3;
|
uint64 GasLimit = 3;
|
||||||
bytes Value = 4;
|
bytes Value = 4;
|
||||||
bytes Payload = 5;
|
bytes Payload = 5;
|
||||||
bytes Hash = 6;
|
bytes Hash = 6;
|
||||||
bytes To = 7;
|
bytes To = 7;
|
||||||
bytes From = 8;
|
bytes From = 8;
|
||||||
uint32 TransactionIndex = 9;
|
uint32 TransactionIndex = 9;
|
||||||
}
|
}
|
||||||
message ReceiptType {
|
message ReceiptType {
|
||||||
message LogType {
|
message LogType {
|
||||||
bytes Address = 1;
|
bytes Address = 1;
|
||||||
bytes Data = 2;
|
bytes Data = 2;
|
||||||
repeated bytes Topics = 3;
|
repeated bytes Topics = 3;
|
||||||
}
|
}
|
||||||
bytes GasUsed = 1;
|
bytes GasUsed = 1;
|
||||||
bytes Status = 2;
|
bytes Status = 2;
|
||||||
repeated LogType Log = 3;
|
repeated LogType Log = 3;
|
||||||
}
|
optional bytes L1Fee = 4;
|
||||||
uint32 BlockNumber = 1;
|
optional bytes L1FeeScalar = 5;
|
||||||
uint64 BlockTime = 2;
|
optional bytes L1GasPrice = 6;
|
||||||
TxType Tx = 3;
|
optional bytes L1GasUsed = 7;
|
||||||
ReceiptType Receipt = 4;
|
}
|
||||||
}
|
uint32 BlockNumber = 1;
|
||||||
|
uint64 BlockTime = 2;
|
||||||
|
TxType Tx = 3;
|
||||||
|
ReceiptType Receipt = 4;
|
||||||
|
}
|
||||||
146
bchain/coins/eth/stakingpool.go
Normal file
146
bchain/coins/eth/stakingpool.go
Normal file
@ -0,0 +1,146 @@
|
|||||||
|
package eth
|
||||||
|
|
||||||
|
import (
|
||||||
|
"math/big"
|
||||||
|
"os"
|
||||||
|
"strings"
|
||||||
|
|
||||||
|
"github.com/ethereum/go-ethereum/common/hexutil"
|
||||||
|
"github.com/golang/glog"
|
||||||
|
"github.com/juju/errors"
|
||||||
|
"github.com/trezor/blockbook/bchain"
|
||||||
|
)
|
||||||
|
|
||||||
|
func (b *EthereumRPC) initStakingPools() error {
|
||||||
|
network := b.ChainConfig.Network
|
||||||
|
if network == "" {
|
||||||
|
network = b.ChainConfig.CoinShortcut
|
||||||
|
}
|
||||||
|
// for now only single staking pool
|
||||||
|
envVar := strings.ToUpper(network) + "_STAKING_POOL_CONTRACT"
|
||||||
|
envValue := os.Getenv(envVar)
|
||||||
|
if envValue != "" {
|
||||||
|
parts := strings.Split(envValue, "/")
|
||||||
|
if len(parts) != 2 {
|
||||||
|
glog.Errorf("Wrong format of environment variable %s=%s, expecting value '<pool name>/<pool contract>', staking pools not enabled", envVar, envValue)
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
b.supportedStakingPools = []string{envValue}
|
||||||
|
b.stakingPoolNames = []string{parts[0]}
|
||||||
|
b.stakingPoolContracts = []string{parts[1]}
|
||||||
|
glog.Info("Support of staking pools enabled with these pools: ", b.supportedStakingPools)
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (b *EthereumRPC) EthereumTypeGetSupportedStakingPools() []string {
|
||||||
|
return b.supportedStakingPools
|
||||||
|
}
|
||||||
|
|
||||||
|
func (b *EthereumRPC) EthereumTypeGetStakingPoolsData(addrDesc bchain.AddressDescriptor) ([]bchain.StakingPoolData, error) {
|
||||||
|
// for now only single staking pool - Everstake
|
||||||
|
addr := hexutil.Encode(addrDesc)[2:]
|
||||||
|
if len(b.supportedStakingPools) == 1 {
|
||||||
|
data, err := b.everstakePoolData(addr, b.stakingPoolContracts[0], b.stakingPoolNames[0])
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
if data != nil {
|
||||||
|
return []bchain.StakingPoolData{*data}, nil
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return nil, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
const everstakePendingBalanceOfMethodSignature = "0x59b8c763" // pendingBalanceOf(address)
|
||||||
|
const everstakePendingDepositedBalanceOfMethodSignature = "0x80f14ecc" // pendingDepositedBalanceOf(address)
|
||||||
|
const everstakeDepositedBalanceOfMethodSignature = "0x68b48254" // depositedBalanceOf(address)
|
||||||
|
const everstakeWithdrawRequestMethodSignature = "0x14cbc46a" // withdrawRequest(address)
|
||||||
|
const everstakeRestakedRewardOfMethodSignature = "0x0c98929a" // restakedRewardOf(address)
|
||||||
|
const everstakeAutocompoundBalanceOfMethodSignature = "0x2fec7966" // autocompoundBalanceOf(address)
|
||||||
|
|
||||||
|
func isZeroBigInt(b *big.Int) bool {
|
||||||
|
return len(b.Bits()) == 0
|
||||||
|
}
|
||||||
|
|
||||||
|
func (b *EthereumRPC) everstakeBalanceTypeContractCall(signature, addr, contract string) (string, error) {
|
||||||
|
req := signature + "0000000000000000000000000000000000000000000000000000000000000000"[len(addr):] + addr
|
||||||
|
return b.EthereumTypeRpcCall(req, contract, "")
|
||||||
|
}
|
||||||
|
|
||||||
|
func (b *EthereumRPC) everstakeContractCallSimpleNumeric(signature, addr, contract string) (*big.Int, error) {
|
||||||
|
data, err := b.everstakeBalanceTypeContractCall(signature, addr, contract)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
r := parseSimpleNumericProperty(data)
|
||||||
|
if r == nil {
|
||||||
|
return nil, errors.New("Invalid balance")
|
||||||
|
}
|
||||||
|
return r, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (b *EthereumRPC) everstakePoolData(addr, contract, name string) (*bchain.StakingPoolData, error) {
|
||||||
|
poolData := bchain.StakingPoolData{
|
||||||
|
Contract: contract,
|
||||||
|
Name: name,
|
||||||
|
}
|
||||||
|
allZeros := true
|
||||||
|
|
||||||
|
value, err := b.everstakeContractCallSimpleNumeric(everstakePendingBalanceOfMethodSignature, addr, contract)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
poolData.PendingBalance = *value
|
||||||
|
allZeros = allZeros && isZeroBigInt(value)
|
||||||
|
|
||||||
|
value, err = b.everstakeContractCallSimpleNumeric(everstakePendingDepositedBalanceOfMethodSignature, addr, contract)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
poolData.PendingDepositedBalance = *value
|
||||||
|
allZeros = allZeros && isZeroBigInt(value)
|
||||||
|
|
||||||
|
value, err = b.everstakeContractCallSimpleNumeric(everstakeDepositedBalanceOfMethodSignature, addr, contract)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
poolData.DepositedBalance = *value
|
||||||
|
allZeros = allZeros && isZeroBigInt(value)
|
||||||
|
|
||||||
|
data, err := b.everstakeBalanceTypeContractCall(everstakeWithdrawRequestMethodSignature, addr, contract)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
value = parseSimpleNumericProperty(data)
|
||||||
|
if value == nil {
|
||||||
|
return nil, errors.New("Invalid balance")
|
||||||
|
}
|
||||||
|
poolData.WithdrawTotalAmount = *value
|
||||||
|
allZeros = allZeros && isZeroBigInt(value)
|
||||||
|
value = parseSimpleNumericProperty(data[64+2:])
|
||||||
|
if value == nil {
|
||||||
|
return nil, errors.New("Invalid balance")
|
||||||
|
}
|
||||||
|
poolData.ClaimableAmount = *value
|
||||||
|
allZeros = allZeros && isZeroBigInt(value)
|
||||||
|
|
||||||
|
value, err = b.everstakeContractCallSimpleNumeric(everstakeRestakedRewardOfMethodSignature, addr, contract)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
poolData.RestakedReward = *value
|
||||||
|
allZeros = allZeros && isZeroBigInt(value)
|
||||||
|
|
||||||
|
value, err = b.everstakeContractCallSimpleNumeric(everstakeAutocompoundBalanceOfMethodSignature, addr, contract)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
poolData.AutocompoundBalance = *value
|
||||||
|
allZeros = allZeros && isZeroBigInt(value)
|
||||||
|
|
||||||
|
if allZeros {
|
||||||
|
return nil, nil
|
||||||
|
}
|
||||||
|
return &poolData, nil
|
||||||
|
}
|
||||||
@ -14,13 +14,13 @@ import (
|
|||||||
)
|
)
|
||||||
|
|
||||||
const (
|
const (
|
||||||
OpZeroCoinMint = 0xc1
|
OpZeroCoinMint = 0xc1
|
||||||
OpZeroCoinSpend = 0xc2
|
OpZeroCoinSpend = 0xc2
|
||||||
OpSigmaMint = 0xc3
|
OpSigmaMint = 0xc3
|
||||||
OpSigmaSpend = 0xc4
|
OpSigmaSpend = 0xc4
|
||||||
OpLelantusMint = 0xc5
|
OpLelantusMint = 0xc5
|
||||||
OpLelantusJMint = 0xc6
|
OpLelantusJMint = 0xc6
|
||||||
OpLelantusJoinSplit = 0xc7
|
OpLelantusJoinSplit = 0xc7
|
||||||
OpLelantusJoinSplitPayload = 0xc9
|
OpLelantusJoinSplitPayload = 0xc9
|
||||||
|
|
||||||
MainnetMagic wire.BitcoinNet = 0xe3d9fef1
|
MainnetMagic wire.BitcoinNet = 0xe3d9fef1
|
||||||
@ -194,7 +194,6 @@ func (p *FiroParser) ParseBlock(b []byte) (*bchain.Block, error) {
|
|||||||
break
|
break
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
if !isAllZero {
|
if !isAllZero {
|
||||||
// hash data
|
// hash data
|
||||||
@ -344,7 +343,7 @@ type MTPHashDataRoot struct {
|
|||||||
}
|
}
|
||||||
|
|
||||||
type MTPHashData struct {
|
type MTPHashData struct {
|
||||||
BlockMTP [128][128]uint64
|
BlockMTP [128][128]uint64
|
||||||
}
|
}
|
||||||
|
|
||||||
type MTPBlockHeader struct {
|
type MTPBlockHeader struct {
|
||||||
|
|||||||
45
bchain/coins/optimism/evm.go
Normal file
45
bchain/coins/optimism/evm.go
Normal file
@ -0,0 +1,45 @@
|
|||||||
|
package optimism
|
||||||
|
|
||||||
|
import (
|
||||||
|
"context"
|
||||||
|
|
||||||
|
"github.com/ethereum/go-ethereum/rpc"
|
||||||
|
"github.com/trezor/blockbook/bchain"
|
||||||
|
)
|
||||||
|
|
||||||
|
// OptimismRPCClient wraps an rpc client to implement the EVMRPCClient interface
|
||||||
|
type OptimismRPCClient struct {
|
||||||
|
*rpc.Client
|
||||||
|
}
|
||||||
|
|
||||||
|
// EthSubscribe subscribes to events and returns a client subscription that implements the EVMClientSubscription interface
|
||||||
|
func (c *OptimismRPCClient) EthSubscribe(ctx context.Context, channel interface{}, args ...interface{}) (bchain.EVMClientSubscription, error) {
|
||||||
|
sub, err := c.Client.EthSubscribe(ctx, channel, args...)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
return &OptimismClientSubscription{ClientSubscription: sub}, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// CallContext performs a JSON-RPC call with the given arguments
|
||||||
|
func (c *OptimismRPCClient) CallContext(ctx context.Context, result interface{}, method string, args ...interface{}) error {
|
||||||
|
if err := c.Client.CallContext(ctx, result, method, args...); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
// special case to handle empty gas price for a valid rpc transaction
|
||||||
|
// (https://goerli-optimism.etherscan.io/tx/0x9b62094073147508471e3371920b68070979beea32100acdc49c721350b69cb9)
|
||||||
|
if r, ok := result.(*bchain.RpcTransaction); ok {
|
||||||
|
if *r != (bchain.RpcTransaction{}) && r.GasPrice == "" {
|
||||||
|
r.GasPrice = "0x0"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// OptimismClientSubscription wraps a client subcription to implement the EVMClientSubscription interface
|
||||||
|
type OptimismClientSubscription struct {
|
||||||
|
*rpc.ClientSubscription
|
||||||
|
}
|
||||||
73
bchain/coins/optimism/optimismrpc.go
Normal file
73
bchain/coins/optimism/optimismrpc.go
Normal file
@ -0,0 +1,73 @@
|
|||||||
|
package optimism
|
||||||
|
|
||||||
|
import (
|
||||||
|
"context"
|
||||||
|
"encoding/json"
|
||||||
|
|
||||||
|
"github.com/golang/glog"
|
||||||
|
"github.com/juju/errors"
|
||||||
|
"github.com/trezor/blockbook/bchain"
|
||||||
|
"github.com/trezor/blockbook/bchain/coins/eth"
|
||||||
|
)
|
||||||
|
|
||||||
|
const (
|
||||||
|
// MainNet is production network
|
||||||
|
MainNet eth.Network = 10
|
||||||
|
)
|
||||||
|
|
||||||
|
// OptimismRPC is an interface to JSON-RPC optimism service.
|
||||||
|
type OptimismRPC struct {
|
||||||
|
*eth.EthereumRPC
|
||||||
|
}
|
||||||
|
|
||||||
|
// NewOptimismRPC returns new OptimismRPC instance.
|
||||||
|
func NewOptimismRPC(config json.RawMessage, pushHandler func(bchain.NotificationType)) (bchain.BlockChain, error) {
|
||||||
|
c, err := eth.NewEthereumRPC(config, pushHandler)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
s := &OptimismRPC{
|
||||||
|
EthereumRPC: c.(*eth.EthereumRPC),
|
||||||
|
}
|
||||||
|
|
||||||
|
return s, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// Initialize bnb smart chain rpc interface
|
||||||
|
func (b *OptimismRPC) Initialize() error {
|
||||||
|
b.OpenRPC = eth.OpenRPC
|
||||||
|
|
||||||
|
rc, ec, err := b.OpenRPC(b.ChainConfig.RPCURL)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
// set chain specific
|
||||||
|
b.Client = ec
|
||||||
|
b.RPC = rc
|
||||||
|
b.MainNetChainID = MainNet
|
||||||
|
b.NewBlock = eth.NewEthereumNewBlock()
|
||||||
|
b.NewTx = eth.NewEthereumNewTx()
|
||||||
|
|
||||||
|
ctx, cancel := context.WithTimeout(context.Background(), b.Timeout)
|
||||||
|
defer cancel()
|
||||||
|
|
||||||
|
id, err := b.Client.NetworkID(ctx)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
// parameters for getInfo request
|
||||||
|
switch eth.Network(id.Uint64()) {
|
||||||
|
case MainNet:
|
||||||
|
b.Testnet = false
|
||||||
|
b.Network = "livenet"
|
||||||
|
default:
|
||||||
|
return errors.Errorf("Unknown network id %v", id)
|
||||||
|
}
|
||||||
|
|
||||||
|
glog.Info("rpc: block chain ", b.Network)
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
@ -2,8 +2,10 @@ package pivx
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"bytes"
|
"bytes"
|
||||||
|
"encoding/binary"
|
||||||
"encoding/hex"
|
"encoding/hex"
|
||||||
"encoding/json"
|
"encoding/json"
|
||||||
|
"fmt"
|
||||||
"io"
|
"io"
|
||||||
"math/big"
|
"math/big"
|
||||||
|
|
||||||
@ -13,7 +15,6 @@ import (
|
|||||||
"github.com/martinboehm/btcutil/chaincfg"
|
"github.com/martinboehm/btcutil/chaincfg"
|
||||||
"github.com/trezor/blockbook/bchain"
|
"github.com/trezor/blockbook/bchain"
|
||||||
"github.com/trezor/blockbook/bchain/coins/btc"
|
"github.com/trezor/blockbook/bchain/coins/btc"
|
||||||
"github.com/trezor/blockbook/bchain/coins/utils"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
// magic numbers
|
// magic numbers
|
||||||
@ -100,7 +101,12 @@ func (p *PivXParser) ParseBlock(b []byte) (*bchain.Block, error) {
|
|||||||
r.Seek(32, io.SeekCurrent)
|
r.Seek(32, io.SeekCurrent)
|
||||||
}
|
}
|
||||||
|
|
||||||
err = utils.DecodeTransactions(r, 0, wire.WitnessEncoding, &w)
|
if h.Version > 7 {
|
||||||
|
// Skip new hashFinalSaplingRoot (block version 8 or newer)
|
||||||
|
r.Seek(32, io.SeekCurrent)
|
||||||
|
}
|
||||||
|
|
||||||
|
err = p.PivxDecodeTransactions(r, 0, &w)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, errors.Annotatef(err, "DecodeTransactions")
|
return nil, errors.Annotatef(err, "DecodeTransactions")
|
||||||
}
|
}
|
||||||
@ -255,6 +261,90 @@ func (p *PivXParser) GetAddrDescForUnknownInput(tx *bchain.Tx, input int) bchain
|
|||||||
return s
|
return s
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (p *PivXParser) PivxDecodeTransactions(r *bytes.Reader, pver uint32, blk *wire.MsgBlock) error {
|
||||||
|
maxTxPerBlock := uint64((wire.MaxBlockPayload / 10) + 1)
|
||||||
|
|
||||||
|
txCount, err := wire.ReadVarInt(r, pver)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
// Prevent more transactions than could possibly fit into a block.
|
||||||
|
// It would be possible to cause memory exhaustion and panics without
|
||||||
|
// a sane upper bound on this count.
|
||||||
|
if txCount > maxTxPerBlock {
|
||||||
|
str := fmt.Sprintf("too many transactions to fit into a block "+
|
||||||
|
"[count %d, max %d]", txCount, maxTxPerBlock)
|
||||||
|
return &wire.MessageError{Func: "utils.decodeTransactions", Description: str}
|
||||||
|
}
|
||||||
|
|
||||||
|
blk.Transactions = make([]*wire.MsgTx, 0, txCount)
|
||||||
|
for i := uint64(0); i < txCount; i++ {
|
||||||
|
tx := wire.MsgTx{}
|
||||||
|
|
||||||
|
// read version & seek back to original state
|
||||||
|
var version uint32 = 0
|
||||||
|
if err = binary.Read(r, binary.LittleEndian, &version); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
if _, err = r.Seek(-4, io.SeekCurrent); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
txVersion := version & 0xffff
|
||||||
|
enc := wire.WitnessEncoding
|
||||||
|
|
||||||
|
// shielded transactions
|
||||||
|
if txVersion >= 3 {
|
||||||
|
enc = wire.BaseEncoding
|
||||||
|
}
|
||||||
|
|
||||||
|
err := p.PivxDecode(&tx, r, pver, enc)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
blk.Transactions = append(blk.Transactions, &tx)
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (p *PivXParser) PivxDecode(MsgTx *wire.MsgTx, r *bytes.Reader, pver uint32, enc wire.MessageEncoding) error {
|
||||||
|
if err := MsgTx.BtcDecode(r, pver, enc); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
// extra
|
||||||
|
version := uint32(MsgTx.Version)
|
||||||
|
txVersion := version & 0xffff
|
||||||
|
|
||||||
|
if txVersion >= 3 {
|
||||||
|
// valueBalance
|
||||||
|
r.Seek(9, io.SeekCurrent)
|
||||||
|
|
||||||
|
vShieldedSpend, err := wire.ReadVarInt(r, 0)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
if vShieldedSpend > 0 {
|
||||||
|
r.Seek(int64(vShieldedSpend*384), io.SeekCurrent)
|
||||||
|
}
|
||||||
|
|
||||||
|
vShieldOutput, err := wire.ReadVarInt(r, 0)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
if vShieldOutput > 0 {
|
||||||
|
r.Seek(int64(vShieldOutput*948), io.SeekCurrent)
|
||||||
|
}
|
||||||
|
|
||||||
|
// bindingSig
|
||||||
|
r.Seek(64, io.SeekCurrent)
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
// Checks if script is OP_ZEROCOINMINT
|
// Checks if script is OP_ZEROCOINMINT
|
||||||
func isZeroCoinMintScript(signatureScript []byte) bool {
|
func isZeroCoinMintScript(signatureScript []byte) bool {
|
||||||
return len(signatureScript) > 1 && signatureScript[0] == OP_ZEROCOINMINT
|
return len(signatureScript) > 1 && signatureScript[0] == OP_ZEROCOINMINT
|
||||||
|
|||||||
73
bchain/coins/polygon/polygonrpc.go
Normal file
73
bchain/coins/polygon/polygonrpc.go
Normal file
@ -0,0 +1,73 @@
|
|||||||
|
package polygon
|
||||||
|
|
||||||
|
import (
|
||||||
|
"context"
|
||||||
|
"encoding/json"
|
||||||
|
|
||||||
|
"github.com/golang/glog"
|
||||||
|
"github.com/juju/errors"
|
||||||
|
"github.com/trezor/blockbook/bchain"
|
||||||
|
"github.com/trezor/blockbook/bchain/coins/eth"
|
||||||
|
)
|
||||||
|
|
||||||
|
const (
|
||||||
|
// MainNet is production network
|
||||||
|
MainNet eth.Network = 137
|
||||||
|
)
|
||||||
|
|
||||||
|
// PolygonRPC is an interface to JSON-RPC polygon service.
|
||||||
|
type PolygonRPC struct {
|
||||||
|
*eth.EthereumRPC
|
||||||
|
}
|
||||||
|
|
||||||
|
// NewPolygonRPC returns new PolygonRPC instance.
|
||||||
|
func NewPolygonRPC(config json.RawMessage, pushHandler func(bchain.NotificationType)) (bchain.BlockChain, error) {
|
||||||
|
c, err := eth.NewEthereumRPC(config, pushHandler)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
s := &PolygonRPC{
|
||||||
|
EthereumRPC: c.(*eth.EthereumRPC),
|
||||||
|
}
|
||||||
|
|
||||||
|
return s, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// Initialize polygon rpc interface
|
||||||
|
func (b *PolygonRPC) Initialize() error {
|
||||||
|
b.OpenRPC = eth.OpenRPC
|
||||||
|
|
||||||
|
rc, ec, err := b.OpenRPC(b.ChainConfig.RPCURL)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
// set chain specific
|
||||||
|
b.Client = ec
|
||||||
|
b.RPC = rc
|
||||||
|
b.MainNetChainID = MainNet
|
||||||
|
b.NewBlock = eth.NewEthereumNewBlock()
|
||||||
|
b.NewTx = eth.NewEthereumNewTx()
|
||||||
|
|
||||||
|
ctx, cancel := context.WithTimeout(context.Background(), b.Timeout)
|
||||||
|
defer cancel()
|
||||||
|
|
||||||
|
id, err := b.Client.NetworkID(ctx)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
// parameters for getInfo request
|
||||||
|
switch eth.Network(id.Uint64()) {
|
||||||
|
case MainNet:
|
||||||
|
b.Testnet = false
|
||||||
|
b.Network = "livenet"
|
||||||
|
default:
|
||||||
|
return errors.Errorf("Unknown network id %v", id)
|
||||||
|
}
|
||||||
|
|
||||||
|
glog.Info("rpc: block chain ", b.Network)
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
@ -294,6 +294,10 @@ func Test_UnpackTx(t *testing.T) {
|
|||||||
t.Errorf("unpackTx() error = %v, wantErr %v", err, tt.wantErr)
|
t.Errorf("unpackTx() error = %v, wantErr %v", err, tt.wantErr)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
// ignore witness unpacking
|
||||||
|
for i := range got.Vin {
|
||||||
|
got.Vin[i].Witness = nil
|
||||||
|
}
|
||||||
if !reflect.DeepEqual(got, tt.want) {
|
if !reflect.DeepEqual(got, tt.want) {
|
||||||
t.Errorf("unpackTx() got = %v, want %v", got, tt.want)
|
t.Errorf("unpackTx() got = %v, want %v", got, tt.want)
|
||||||
}
|
}
|
||||||
|
|||||||
217
bchain/golomb.go
Normal file
217
bchain/golomb.go
Normal file
@ -0,0 +1,217 @@
|
|||||||
|
package bchain
|
||||||
|
|
||||||
|
import (
|
||||||
|
"bytes"
|
||||||
|
"encoding/hex"
|
||||||
|
|
||||||
|
"github.com/golang/glog"
|
||||||
|
"github.com/juju/errors"
|
||||||
|
"github.com/martinboehm/btcutil/gcs"
|
||||||
|
)
|
||||||
|
|
||||||
|
type FilterScriptsType int
|
||||||
|
|
||||||
|
const (
|
||||||
|
FilterScriptsInvalid = FilterScriptsType(iota)
|
||||||
|
FilterScriptsAll
|
||||||
|
FilterScriptsTaproot
|
||||||
|
FilterScriptsTaprootNoOrdinals
|
||||||
|
)
|
||||||
|
|
||||||
|
// GolombFilter is computing golomb filter of address descriptors
|
||||||
|
type GolombFilter struct {
|
||||||
|
Enabled bool
|
||||||
|
UseZeroedKey bool
|
||||||
|
p uint8
|
||||||
|
key string
|
||||||
|
filterScripts string
|
||||||
|
filterScriptsType FilterScriptsType
|
||||||
|
filterData [][]byte
|
||||||
|
uniqueData map[string]struct{}
|
||||||
|
// All the unique txids that contain ordinal data
|
||||||
|
ordinalTxIds map[string]struct{}
|
||||||
|
// Mapping of txid to address descriptors - only used in case of taproot-noordinals
|
||||||
|
allAddressDescriptors map[string][]AddressDescriptor
|
||||||
|
}
|
||||||
|
|
||||||
|
// NewGolombFilter initializes the GolombFilter handler
|
||||||
|
func NewGolombFilter(p uint8, filterScripts string, key string, useZeroedKey bool) (*GolombFilter, error) {
|
||||||
|
if p == 0 {
|
||||||
|
return &GolombFilter{Enabled: false}, nil
|
||||||
|
}
|
||||||
|
gf := GolombFilter{
|
||||||
|
Enabled: true,
|
||||||
|
UseZeroedKey: useZeroedKey,
|
||||||
|
p: p,
|
||||||
|
key: key,
|
||||||
|
filterScripts: filterScripts,
|
||||||
|
filterScriptsType: filterScriptsToScriptsType(filterScripts),
|
||||||
|
filterData: make([][]byte, 0),
|
||||||
|
uniqueData: make(map[string]struct{}),
|
||||||
|
}
|
||||||
|
// reject invalid filterScripts
|
||||||
|
if gf.filterScriptsType == FilterScriptsInvalid {
|
||||||
|
return nil, errors.Errorf("Invalid/unsupported filterScripts parameter %s", filterScripts)
|
||||||
|
}
|
||||||
|
// set ordinal-related fields if needed
|
||||||
|
if gf.ignoreOrdinals() {
|
||||||
|
gf.ordinalTxIds = make(map[string]struct{})
|
||||||
|
gf.allAddressDescriptors = make(map[string][]AddressDescriptor)
|
||||||
|
}
|
||||||
|
return &gf, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// Gets the M parameter that we are using for the filter
|
||||||
|
// Currently it relies on P parameter, but that can change
|
||||||
|
func GetGolombParamM(p uint8) uint64 {
|
||||||
|
return uint64(1 << uint64(p))
|
||||||
|
}
|
||||||
|
|
||||||
|
// Checks whether this input contains ordinal data
|
||||||
|
func isInputOrdinal(vin Vin) bool {
|
||||||
|
byte_pattern := []byte{
|
||||||
|
0x00, // OP_0, OP_FALSE
|
||||||
|
0x63, // OP_IF
|
||||||
|
0x03, // OP_PUSHBYTES_3
|
||||||
|
0x6f, // "o"
|
||||||
|
0x72, // "r"
|
||||||
|
0x64, // "d"
|
||||||
|
0x01, // OP_PUSHBYTES_1
|
||||||
|
}
|
||||||
|
// Witness needs to have at least 3 items and the second one needs to contain certain pattern
|
||||||
|
return len(vin.Witness) > 2 && bytes.Contains(vin.Witness[1], byte_pattern)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Whether a transaction contains any ordinal data
|
||||||
|
func txContainsOrdinal(tx *Tx) bool {
|
||||||
|
for _, vin := range tx.Vin {
|
||||||
|
if isInputOrdinal(vin) {
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
|
// Saving all the ordinal-related txIds so we can later ignore their address descriptors
|
||||||
|
func (f *GolombFilter) markTxAndParentsAsOrdinals(tx *Tx) {
|
||||||
|
f.ordinalTxIds[tx.Txid] = struct{}{}
|
||||||
|
for _, vin := range tx.Vin {
|
||||||
|
f.ordinalTxIds[vin.Txid] = struct{}{}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Adding a new address descriptor mapped to a txid
|
||||||
|
func (f *GolombFilter) addTxIdMapping(ad AddressDescriptor, tx *Tx) {
|
||||||
|
f.allAddressDescriptors[tx.Txid] = append(f.allAddressDescriptors[tx.Txid], ad)
|
||||||
|
}
|
||||||
|
|
||||||
|
// AddAddrDesc adds taproot address descriptor to the data for the filter
|
||||||
|
func (f *GolombFilter) AddAddrDesc(ad AddressDescriptor, tx *Tx) {
|
||||||
|
if f.ignoreNonTaproot() && !ad.IsTaproot() {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
if f.ignoreOrdinals() && tx != nil && txContainsOrdinal(tx) {
|
||||||
|
f.markTxAndParentsAsOrdinals(tx)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
if len(ad) == 0 {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
// When ignoring ordinals, we need to save all the address descriptors before
|
||||||
|
// filtering out the "invalid" ones.
|
||||||
|
if f.ignoreOrdinals() && tx != nil {
|
||||||
|
f.addTxIdMapping(ad, tx)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
f.includeAddrDesc(ad)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Private function to be called with descriptors that were already validated
|
||||||
|
func (f *GolombFilter) includeAddrDesc(ad AddressDescriptor) {
|
||||||
|
s := string(ad)
|
||||||
|
if _, found := f.uniqueData[s]; !found {
|
||||||
|
f.filterData = append(f.filterData, ad)
|
||||||
|
f.uniqueData[s] = struct{}{}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Including all the address descriptors from non-ordinal transactions
|
||||||
|
func (f *GolombFilter) includeAllAddressDescriptorsOrdinals() {
|
||||||
|
for txid, ads := range f.allAddressDescriptors {
|
||||||
|
// Ignoring the txids that contain ordinal data
|
||||||
|
if _, found := f.ordinalTxIds[txid]; found {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
for _, ad := range ads {
|
||||||
|
f.includeAddrDesc(ad)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Compute computes golomb filter from the data
|
||||||
|
func (f *GolombFilter) Compute() []byte {
|
||||||
|
m := GetGolombParamM(f.p)
|
||||||
|
|
||||||
|
// In case of ignoring the ordinals, we still need to assemble the filter data
|
||||||
|
if f.ignoreOrdinals() {
|
||||||
|
f.includeAllAddressDescriptorsOrdinals()
|
||||||
|
}
|
||||||
|
|
||||||
|
if len(f.filterData) == 0 {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// Used key is possibly just zeroes, otherwise get it from the supplied key
|
||||||
|
var key [gcs.KeySize]byte
|
||||||
|
if f.UseZeroedKey {
|
||||||
|
key = [gcs.KeySize]byte{}
|
||||||
|
} else {
|
||||||
|
b, _ := hex.DecodeString(f.key)
|
||||||
|
if len(b) < gcs.KeySize {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
copy(key[:], b[:gcs.KeySize])
|
||||||
|
}
|
||||||
|
|
||||||
|
filter, err := gcs.BuildGCSFilter(f.p, m, key, f.filterData)
|
||||||
|
if err != nil {
|
||||||
|
glog.Error("Cannot create golomb filter for ", f.key, ", ", err)
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
fb, err := filter.NBytes()
|
||||||
|
if err != nil {
|
||||||
|
glog.Error("Error getting NBytes from golomb filter for ", f.key, ", ", err)
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
return fb
|
||||||
|
}
|
||||||
|
|
||||||
|
func (f *GolombFilter) ignoreNonTaproot() bool {
|
||||||
|
switch f.filterScriptsType {
|
||||||
|
case FilterScriptsTaproot, FilterScriptsTaprootNoOrdinals:
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
|
func (f *GolombFilter) ignoreOrdinals() bool {
|
||||||
|
switch f.filterScriptsType {
|
||||||
|
case FilterScriptsTaprootNoOrdinals:
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
|
func filterScriptsToScriptsType(filterScripts string) FilterScriptsType {
|
||||||
|
switch filterScripts {
|
||||||
|
case "":
|
||||||
|
return FilterScriptsAll
|
||||||
|
case "taproot":
|
||||||
|
return FilterScriptsTaproot
|
||||||
|
case "taproot-noordinals":
|
||||||
|
return FilterScriptsTaprootNoOrdinals
|
||||||
|
}
|
||||||
|
return FilterScriptsInvalid
|
||||||
|
}
|
||||||
282
bchain/golomb_test.go
Normal file
282
bchain/golomb_test.go
Normal file
@ -0,0 +1,282 @@
|
|||||||
|
// //go:build unittest
|
||||||
|
|
||||||
|
package bchain
|
||||||
|
|
||||||
|
import (
|
||||||
|
"encoding/hex"
|
||||||
|
"testing"
|
||||||
|
)
|
||||||
|
|
||||||
|
func getCommonAddressDescriptors() []AddressDescriptor {
|
||||||
|
return []AddressDescriptor{
|
||||||
|
// bc1pgeqrcq5capal83ypxczmypjdhk4d9wwcea4k66c7ghe07p2qt97sqh8sy5
|
||||||
|
hexToBytes("512046403c0298e87bf3c4813605b2064dbdaad2b9d8cf6b6d6b1e45f2ff0540597d"),
|
||||||
|
// bc1p7en40zu9hmf9d3luh8evmfyg655pu5k2gtna6j7zr623f9tz7z0stfnwav
|
||||||
|
hexToBytes("5120f667578b85bed256c7fcb9f2cda488d5281e52ca42e7dd4bc21e95149562f09f"),
|
||||||
|
// 39ECUF8YaFRX7XfttfAiLa5ir43bsrQUZJ
|
||||||
|
hexToBytes("a91452ae9441d9920d9eb4a3c0a877ca8d8de547ce6587"),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestGolombFilter(t *testing.T) {
|
||||||
|
tests := []struct {
|
||||||
|
name string
|
||||||
|
p uint8
|
||||||
|
useZeroedKey bool
|
||||||
|
filterScripts string
|
||||||
|
key string
|
||||||
|
addressDescriptors []AddressDescriptor
|
||||||
|
wantError bool
|
||||||
|
wantEnabled bool
|
||||||
|
want string
|
||||||
|
}{
|
||||||
|
{
|
||||||
|
name: "taproot",
|
||||||
|
p: 20,
|
||||||
|
useZeroedKey: false,
|
||||||
|
filterScripts: "taproot",
|
||||||
|
key: "86336c62a63f509a278624e3f400cdd50838d035a44e0af8a7d6d133c04cc2d2",
|
||||||
|
addressDescriptors: getCommonAddressDescriptors(),
|
||||||
|
wantEnabled: true,
|
||||||
|
wantError: false,
|
||||||
|
want: "0235dddcce5d60",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "taproot-zeroed-key",
|
||||||
|
p: 20,
|
||||||
|
useZeroedKey: true,
|
||||||
|
filterScripts: "taproot",
|
||||||
|
key: "86336c62a63f509a278624e3f400cdd50838d035a44e0af8a7d6d133c04cc2d2",
|
||||||
|
addressDescriptors: getCommonAddressDescriptors(),
|
||||||
|
wantEnabled: true,
|
||||||
|
wantError: false,
|
||||||
|
want: "0218c23a013600",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "taproot p=21",
|
||||||
|
p: 21,
|
||||||
|
useZeroedKey: false,
|
||||||
|
filterScripts: "taproot",
|
||||||
|
key: "86336c62a63f509a278624e3f400cdd50838d035a44e0af8a7d6d133c04cc2d2",
|
||||||
|
addressDescriptors: getCommonAddressDescriptors(),
|
||||||
|
wantEnabled: true,
|
||||||
|
wantError: false,
|
||||||
|
want: "0235ddda672eb0",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "all",
|
||||||
|
p: 20,
|
||||||
|
useZeroedKey: false,
|
||||||
|
filterScripts: "",
|
||||||
|
key: "86336c62a63f509a278624e3f400cdd50838d035a44e0af8a7d6d133c04cc2d2",
|
||||||
|
addressDescriptors: getCommonAddressDescriptors(),
|
||||||
|
wantEnabled: true,
|
||||||
|
wantError: false,
|
||||||
|
want: "0350ccc61ac611976c80",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "taproot-noordinals",
|
||||||
|
p: 20,
|
||||||
|
useZeroedKey: false,
|
||||||
|
filterScripts: "taproot-noordinals",
|
||||||
|
key: "86336c62a63f509a278624e3f400cdd50838d035a44e0af8a7d6d133c04cc2d2",
|
||||||
|
addressDescriptors: getCommonAddressDescriptors(),
|
||||||
|
wantEnabled: true,
|
||||||
|
wantError: false,
|
||||||
|
want: "0235dddcce5d60",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "not supported filter",
|
||||||
|
p: 20,
|
||||||
|
useZeroedKey: false,
|
||||||
|
filterScripts: "notsupported",
|
||||||
|
wantEnabled: false,
|
||||||
|
wantError: true,
|
||||||
|
want: "",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "not enabled",
|
||||||
|
p: 0,
|
||||||
|
useZeroedKey: false,
|
||||||
|
filterScripts: "",
|
||||||
|
wantEnabled: false,
|
||||||
|
wantError: false,
|
||||||
|
want: "",
|
||||||
|
},
|
||||||
|
}
|
||||||
|
for _, tt := range tests {
|
||||||
|
t.Run(tt.name, func(t *testing.T) {
|
||||||
|
gf, err := NewGolombFilter(tt.p, tt.filterScripts, tt.key, tt.useZeroedKey)
|
||||||
|
if err != nil && !tt.wantError {
|
||||||
|
t.Errorf("TestGolombFilter.NewGolombFilter() got unexpected error '%v'", err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
if err == nil && tt.wantError {
|
||||||
|
t.Errorf("TestGolombFilter.NewGolombFilter() wanted error, got none")
|
||||||
|
return
|
||||||
|
}
|
||||||
|
if gf == nil && tt.wantError {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
if gf.Enabled != tt.wantEnabled {
|
||||||
|
t.Errorf("TestGolombFilter.NewGolombFilter() got gf.Enabled %v, want %v", gf.Enabled, tt.wantEnabled)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
for _, ad := range tt.addressDescriptors {
|
||||||
|
gf.AddAddrDesc(ad, nil)
|
||||||
|
}
|
||||||
|
f := gf.Compute()
|
||||||
|
got := hex.EncodeToString(f)
|
||||||
|
if got != tt.want {
|
||||||
|
t.Errorf("TestGolombFilter Compute() got %v, want %v", got, tt.want)
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Preparation transaction, locking BTC redeemable by ordinal witness - parent of the reveal transaction
|
||||||
|
func getOrdinalCommitTx() (Tx, []AddressDescriptor) {
|
||||||
|
tx := Tx{
|
||||||
|
// https://mempool.space/tx/11111c17cbe86aebab146ee039d4e354cb55a9fb226ebdd2e30948630e7710ad
|
||||||
|
Txid: "11111c17cbe86aebab146ee039d4e354cb55a9fb226ebdd2e30948630e7710ad",
|
||||||
|
Vin: []Vin{
|
||||||
|
{
|
||||||
|
// https://mempool.space/tx/c4cae52a6e681b66c85c12feafb42f3617f34977032df1ee139eae07370863ef
|
||||||
|
Txid: "c163fe1fdc21269cb05621adec38045e46a65289a356f9354df6010bce064916",
|
||||||
|
Vout: 0,
|
||||||
|
Witness: [][]byte{
|
||||||
|
hexToBytes("0371633164dd16345c02e80c9963042f9a502aa2c8109c0f61da333ac1503c3ce2a1b79895359bbdee5979ab2cb44f3395892e1c419c3a8f67d31d33d7e764c9"),
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
Vout: []Vout{
|
||||||
|
{
|
||||||
|
ScriptPubKey: ScriptPubKey{
|
||||||
|
Hex: "51206a711358bac6ca8f7ddfdf8f733546e658208122939f0bf7a3727f8143dfbbff",
|
||||||
|
Addresses: []string{
|
||||||
|
"bc1pdfc3xk96cm9g7lwlm78hxd2xuevzpqfzjw0shaarwflczs7lh0lstksdn0",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
ScriptPubKey: ScriptPubKey{
|
||||||
|
Hex: "a9144390d0b3d2b6d48b8c205ffbe40b2d84c40de07f87",
|
||||||
|
Addresses: []string{
|
||||||
|
"37rGgLSLX6C6LS9am4KWd6GT1QCEP4H4py",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
ScriptPubKey: ScriptPubKey{
|
||||||
|
Hex: "76a914ba6b046dd832aa8bc41c158232bcc18211387c4388ac",
|
||||||
|
Addresses: []string{
|
||||||
|
"1HzgtNdRCXszf95rFYemsDSHJQBbs9rbZf",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
}
|
||||||
|
addressDescriptors := []AddressDescriptor{
|
||||||
|
// bc1pdfc3xk96cm9g7lwlm78hxd2xuevzpqfzjw0shaarwflczs7lh0lstksdn0
|
||||||
|
hexToBytes("51206a711358bac6ca8f7ddfdf8f733546e658208122939f0bf7a3727f8143dfbbff"),
|
||||||
|
// 37rGgLSLX6C6LS9am4KWd6GT1QCEP4H4py
|
||||||
|
hexToBytes("a9144390d0b3d2b6d48b8c205ffbe40b2d84c40de07f87"),
|
||||||
|
// 1HzgtNdRCXszf95rFYemsDSHJQBbs9rbZf
|
||||||
|
hexToBytes("76a914ba6b046dd832aa8bc41c158232bcc18211387c4388ac"),
|
||||||
|
}
|
||||||
|
return tx, addressDescriptors
|
||||||
|
}
|
||||||
|
|
||||||
|
// Transaction containing the actual ordinal data in witness - child of the commit transaction
|
||||||
|
func getOrdinalRevealTx() (Tx, []AddressDescriptor) {
|
||||||
|
tx := Tx{
|
||||||
|
// https://mempool.space/tx/c4cae52a6e681b66c85c12feafb42f3617f34977032df1ee139eae07370863ef
|
||||||
|
Txid: "c4cae52a6e681b66c85c12feafb42f3617f34977032df1ee139eae07370863ef",
|
||||||
|
Vin: []Vin{
|
||||||
|
{
|
||||||
|
Txid: "11111c17cbe86aebab146ee039d4e354cb55a9fb226ebdd2e30948630e7710ad",
|
||||||
|
Vout: 0,
|
||||||
|
Witness: [][]byte{
|
||||||
|
hexToBytes("737ad2835962e3d147cd74a578f1109e9314eac9d00c9fad304ce2050b78fac21a2d124fd886d1d646cf1de5d5c9754b0415b960b1319526fa25e36ca1f650ce"),
|
||||||
|
hexToBytes("2029f34532e043fade4471779b4955005db8fa9b64c9e8d0a2dae4a38bbca23328ac0063036f726401010a696d6167652f77656270004d08025249464650020000574542505650384c440200002f57c2950067a026009086939b7785a104699656f4f53388355445b6415d22f8924000fd83bd31d346ca69f8fcfed6d8d18231846083f90f00ffbf203883666c36463c6ba8662257d789935e002192245bd15ac00216b080052cac85b380052c60e1593859f33a7a7abff7ed88feb361db3692341bc83553aef7aec75669ffb1ffd87fec3ff61ffb8ffdc736f20a96a0fba34071d4fdf111c435381df667728f95c4e82b6872d82471bfdc1665107bb80fd46df1686425bcd2e27eb59adc9d17b54b997ee96776a7c37ca2b57b9551bcffeb71d88768765af7384c2e3ba031ca3f19c9ddb0c6ec55223fbfe3731a1e8d7bb010de8532d53293bbbb6145597ee53559a612e6de4f8fc66936ef463eea7498555643ac0dafad6627575f2733b9fb352e411e7d9df8fc80fde75f5f66f5c5381a46b9a697d9c97555c4bf41a4909b9dd071557c3dfe0bfcd6459e06514266c65756ce9f25705230df63d30fef6076b797e1f49d00b41e87b5ccecb1c237f419e4b3ca6876053c14fc979a629459a62f78d735fb078bfa0e7a1fc69ad379447d817e06b3d7f1de820f28534f85fa20469cd6f93ddc6c5f2a94878fc64a98ac336294c99d27d11742268ae1a34cd61f31e2e4aee94b0ff496f55068fa727ace6ad2ec1e6e3f59e6a8bd154f287f652fbfaa05cac067951de1bfacc0e330c3bf6dd2efde4c509646566836eb71986154731daf722a6ff585001e87f9479559a61265d6e330f3682bf87ab2598fc3fca36da778e59cee71584594ef175e6d7d5f70d6deb02c4b371e5063c35669ffb1ffd87ffe0e730068"),
|
||||||
|
hexToBytes("c129f34532e043fade4471779b4955005db8fa9b64c9e8d0a2dae4a38bbca23328"),
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
Vout: []Vout{
|
||||||
|
{
|
||||||
|
ScriptPubKey: ScriptPubKey{
|
||||||
|
Hex: "51206850b179630df0f7012ae2b111bafa52ebb9b54e1435fc4f98fbe0af6f95076a",
|
||||||
|
Addresses: []string{
|
||||||
|
"bc1pdpgtz7trphc0wqf2u2c3rwh62t4mnd2wzs6lcnucl0s27mu4qa4q4md9ta",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
}
|
||||||
|
addressDescriptors := []AddressDescriptor{
|
||||||
|
// bc1pdpgtz7trphc0wqf2u2c3rwh62t4mnd2wzs6lcnucl0s27mu4qa4q4md9ta
|
||||||
|
hexToBytes("51206850b179630df0f7012ae2b111bafa52ebb9b54e1435fc4f98fbe0af6f95076a"),
|
||||||
|
}
|
||||||
|
return tx, addressDescriptors
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestGolombIsOrdinal(t *testing.T) {
|
||||||
|
revealTx, _ := getOrdinalRevealTx()
|
||||||
|
if txContainsOrdinal(&revealTx) != true {
|
||||||
|
t.Error("Ordinal not found in reveal Tx")
|
||||||
|
}
|
||||||
|
commitTx, _ := getOrdinalCommitTx()
|
||||||
|
if txContainsOrdinal(&commitTx) != false {
|
||||||
|
t.Error("Ordinal found in commit Tx, but should not be there")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestGolombOrdinalTransactions(t *testing.T) {
|
||||||
|
tests := []struct {
|
||||||
|
name string
|
||||||
|
filterScripts string
|
||||||
|
want string
|
||||||
|
}{
|
||||||
|
{
|
||||||
|
name: "all",
|
||||||
|
filterScripts: "",
|
||||||
|
want: "04256e660160e42ff40ee320", // take all four descriptors
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "taproot",
|
||||||
|
filterScripts: "taproot",
|
||||||
|
want: "0212b734c2ebe0", // filter out two non-taproot ones
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "taproot-noordinals",
|
||||||
|
filterScripts: "taproot-noordinals",
|
||||||
|
want: "", // ignore everything
|
||||||
|
},
|
||||||
|
}
|
||||||
|
for _, tt := range tests {
|
||||||
|
t.Run(tt.name, func(t *testing.T) {
|
||||||
|
gf, err := NewGolombFilter(20, tt.filterScripts, "", true)
|
||||||
|
if err != nil {
|
||||||
|
t.Errorf("TestGolombOrdinalTransactions.NewGolombFilter() got unexpected error '%v'", err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
commitTx, addressDescriptorsCommit := getOrdinalCommitTx()
|
||||||
|
revealTx, addressDescriptorsReveal := getOrdinalRevealTx()
|
||||||
|
|
||||||
|
for _, ad := range addressDescriptorsCommit {
|
||||||
|
gf.AddAddrDesc(ad, &commitTx)
|
||||||
|
}
|
||||||
|
for _, ad := range addressDescriptorsReveal {
|
||||||
|
gf.AddAddrDesc(ad, &revealTx)
|
||||||
|
}
|
||||||
|
|
||||||
|
f := gf.Compute()
|
||||||
|
got := hex.EncodeToString(f)
|
||||||
|
if got != tt.want {
|
||||||
|
t.Errorf("TestGolombOrdinalTransactions Compute() got %v, want %v", got, tt.want)
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -2,13 +2,11 @@ package bchain
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"encoding/hex"
|
"encoding/hex"
|
||||||
"errors"
|
|
||||||
"fmt"
|
|
||||||
"math/big"
|
"math/big"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
"github.com/golang/glog"
|
"github.com/golang/glog"
|
||||||
"github.com/martinboehm/btcutil/gcs"
|
"github.com/juju/errors"
|
||||||
)
|
)
|
||||||
|
|
||||||
type chanInputPayload struct {
|
type chanInputPayload struct {
|
||||||
@ -16,14 +14,6 @@ type chanInputPayload struct {
|
|||||||
index int
|
index int
|
||||||
}
|
}
|
||||||
|
|
||||||
type filterScriptsType int
|
|
||||||
|
|
||||||
const (
|
|
||||||
filterScriptsInvalid = filterScriptsType(iota)
|
|
||||||
filterScriptsAll
|
|
||||||
filterScriptsTaproot
|
|
||||||
)
|
|
||||||
|
|
||||||
// MempoolBitcoinType is mempool handle.
|
// MempoolBitcoinType is mempool handle.
|
||||||
type MempoolBitcoinType struct {
|
type MempoolBitcoinType struct {
|
||||||
BaseMempool
|
BaseMempool
|
||||||
@ -31,19 +21,13 @@ type MempoolBitcoinType struct {
|
|||||||
chanAddrIndex chan txidio
|
chanAddrIndex chan txidio
|
||||||
AddrDescForOutpoint AddrDescForOutpointFunc
|
AddrDescForOutpoint AddrDescForOutpointFunc
|
||||||
golombFilterP uint8
|
golombFilterP uint8
|
||||||
golombFilterM uint64
|
filterScripts string
|
||||||
filterScripts filterScriptsType
|
useZeroedKey bool
|
||||||
}
|
}
|
||||||
|
|
||||||
// NewMempoolBitcoinType creates new mempool handler.
|
// NewMempoolBitcoinType creates new mempool handler.
|
||||||
// For now there is no cleanup of sync routines, the expectation is that the mempool is created only once per process
|
// For now there is no cleanup of sync routines, the expectation is that the mempool is created only once per process
|
||||||
func NewMempoolBitcoinType(chain BlockChain, workers int, subworkers int, golombFilterP uint8, filterScripts string) *MempoolBitcoinType {
|
func NewMempoolBitcoinType(chain BlockChain, workers int, subworkers int, golombFilterP uint8, filterScripts string, useZeroedKey bool) *MempoolBitcoinType {
|
||||||
filterScriptsType := filterScriptsToScriptsType(filterScripts)
|
|
||||||
if filterScriptsType == filterScriptsInvalid {
|
|
||||||
glog.Error("Invalid filterScripts ", filterScripts, ", switching off golomb filter")
|
|
||||||
golombFilterP = 0
|
|
||||||
}
|
|
||||||
golombFilterM := uint64(1 << golombFilterP)
|
|
||||||
m := &MempoolBitcoinType{
|
m := &MempoolBitcoinType{
|
||||||
BaseMempool: BaseMempool{
|
BaseMempool: BaseMempool{
|
||||||
chain: chain,
|
chain: chain,
|
||||||
@ -53,8 +37,8 @@ func NewMempoolBitcoinType(chain BlockChain, workers int, subworkers int, golomb
|
|||||||
chanTxid: make(chan string, 1),
|
chanTxid: make(chan string, 1),
|
||||||
chanAddrIndex: make(chan txidio, 1),
|
chanAddrIndex: make(chan txidio, 1),
|
||||||
golombFilterP: golombFilterP,
|
golombFilterP: golombFilterP,
|
||||||
golombFilterM: golombFilterM,
|
filterScripts: filterScripts,
|
||||||
filterScripts: filterScriptsType,
|
useZeroedKey: useZeroedKey,
|
||||||
}
|
}
|
||||||
for i := 0; i < workers; i++ {
|
for i := 0; i < workers; i++ {
|
||||||
go func(i int) {
|
go func(i int) {
|
||||||
@ -81,16 +65,6 @@ func NewMempoolBitcoinType(chain BlockChain, workers int, subworkers int, golomb
|
|||||||
return m
|
return m
|
||||||
}
|
}
|
||||||
|
|
||||||
func filterScriptsToScriptsType(filterScripts string) filterScriptsType {
|
|
||||||
switch filterScripts {
|
|
||||||
case "":
|
|
||||||
return filterScriptsAll
|
|
||||||
case "taproot":
|
|
||||||
return filterScriptsTaproot
|
|
||||||
}
|
|
||||||
return filterScriptsInvalid
|
|
||||||
}
|
|
||||||
|
|
||||||
func (m *MempoolBitcoinType) getInputAddress(payload *chanInputPayload) *addrIndex {
|
func (m *MempoolBitcoinType) getInputAddress(payload *chanInputPayload) *addrIndex {
|
||||||
var addrDesc AddressDescriptor
|
var addrDesc AddressDescriptor
|
||||||
var value *big.Int
|
var value *big.Int
|
||||||
@ -125,56 +99,21 @@ func (m *MempoolBitcoinType) getInputAddress(payload *chanInputPayload) *addrInd
|
|||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func isTaproot(addrDesc AddressDescriptor) bool {
|
func (m *MempoolBitcoinType) computeGolombFilter(mtx *MempoolTx, tx *Tx) string {
|
||||||
if len(addrDesc) == 34 && addrDesc[0] == 0x51 && addrDesc[1] == 0x20 {
|
gf, _ := NewGolombFilter(m.golombFilterP, m.filterScripts, mtx.Txid, m.useZeroedKey)
|
||||||
return true
|
if gf == nil || !gf.Enabled {
|
||||||
|
return ""
|
||||||
}
|
}
|
||||||
return false
|
for _, vin := range mtx.Vin {
|
||||||
}
|
gf.AddAddrDesc(vin.AddrDesc, tx)
|
||||||
|
|
||||||
func (m *MempoolBitcoinType) computeGolombFilter(mtx *MempoolTx) string {
|
|
||||||
uniqueScripts := make(map[string]struct{})
|
|
||||||
filterData := make([][]byte, 0)
|
|
||||||
for i := range mtx.Vin {
|
|
||||||
vin := &mtx.Vin[i]
|
|
||||||
if m.filterScripts == filterScriptsAll || (m.filterScripts == filterScriptsTaproot && isTaproot(vin.AddrDesc)) {
|
|
||||||
s := string(vin.AddrDesc)
|
|
||||||
if _, found := uniqueScripts[s]; !found {
|
|
||||||
filterData = append(filterData, vin.AddrDesc)
|
|
||||||
uniqueScripts[s] = struct{}{}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
for i := range mtx.Vout {
|
for _, vout := range mtx.Vout {
|
||||||
vout := &mtx.Vout[i]
|
|
||||||
b, err := hex.DecodeString(vout.ScriptPubKey.Hex)
|
b, err := hex.DecodeString(vout.ScriptPubKey.Hex)
|
||||||
if err == nil {
|
if err == nil {
|
||||||
if m.filterScripts == filterScriptsAll || (m.filterScripts == filterScriptsTaproot && isTaproot(b)) {
|
gf.AddAddrDesc(b, tx)
|
||||||
s := string(b)
|
|
||||||
if _, found := uniqueScripts[s]; !found {
|
|
||||||
filterData = append(filterData, b)
|
|
||||||
uniqueScripts[s] = struct{}{}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if len(filterData) == 0 {
|
fb := gf.Compute()
|
||||||
return ""
|
|
||||||
}
|
|
||||||
b, _ := hex.DecodeString(mtx.Txid)
|
|
||||||
if len(b) < gcs.KeySize {
|
|
||||||
return ""
|
|
||||||
}
|
|
||||||
filter, err := gcs.BuildGCSFilter(m.golombFilterP, m.golombFilterM, *(*[gcs.KeySize]byte)(b[:gcs.KeySize]), filterData)
|
|
||||||
if err != nil {
|
|
||||||
glog.Error("Cannot create golomb filter for ", mtx.Txid, ", ", err)
|
|
||||||
return ""
|
|
||||||
}
|
|
||||||
fb, err := filter.NBytes()
|
|
||||||
if err != nil {
|
|
||||||
glog.Error("Error getting NBytes from golomb filter for ", mtx.Txid, ", ", err)
|
|
||||||
return ""
|
|
||||||
}
|
|
||||||
return hex.EncodeToString(fb)
|
return hex.EncodeToString(fb)
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -231,7 +170,7 @@ func (m *MempoolBitcoinType) getTxAddrs(txid string, chanInput chan chanInputPay
|
|||||||
}
|
}
|
||||||
var golombFilter string
|
var golombFilter string
|
||||||
if m.golombFilterP > 0 {
|
if m.golombFilterP > 0 {
|
||||||
golombFilter = m.computeGolombFilter(mtx)
|
golombFilter = m.computeGolombFilter(mtx, tx)
|
||||||
}
|
}
|
||||||
if m.OnNewTx != nil {
|
if m.OnNewTx != nil {
|
||||||
m.OnNewTx(mtx)
|
m.OnNewTx(mtx)
|
||||||
@ -301,8 +240,8 @@ func (m *MempoolBitcoinType) Resync() (int, error) {
|
|||||||
|
|
||||||
// GetTxidFilterEntries returns all mempool entries with golomb filter from
|
// GetTxidFilterEntries returns all mempool entries with golomb filter from
|
||||||
func (m *MempoolBitcoinType) GetTxidFilterEntries(filterScripts string, fromTimestamp uint32) (MempoolTxidFilterEntries, error) {
|
func (m *MempoolBitcoinType) GetTxidFilterEntries(filterScripts string, fromTimestamp uint32) (MempoolTxidFilterEntries, error) {
|
||||||
if m.filterScripts != filterScriptsToScriptsType(filterScripts) {
|
if m.filterScripts != filterScripts {
|
||||||
return MempoolTxidFilterEntries{}, errors.New(fmt.Sprint("Unsupported script filter ", filterScripts))
|
return MempoolTxidFilterEntries{}, errors.Errorf("Unsupported script filter %s", filterScripts)
|
||||||
}
|
}
|
||||||
m.mux.Lock()
|
m.mux.Lock()
|
||||||
entries := make(map[string]string)
|
entries := make(map[string]string)
|
||||||
@ -312,5 +251,5 @@ func (m *MempoolBitcoinType) GetTxidFilterEntries(filterScripts string, fromTime
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
m.mux.Unlock()
|
m.mux.Unlock()
|
||||||
return MempoolTxidFilterEntries{entries}, nil
|
return MempoolTxidFilterEntries{entries, m.useZeroedKey}, nil
|
||||||
}
|
}
|
||||||
|
|||||||
@ -16,9 +16,9 @@ func TestMempoolBitcoinType_computeGolombFilter_taproot(t *testing.T) {
|
|||||||
randomScript := hexToBytes("a914ff074800343a81ada8fe86c2d5d5a0e55b93dd7a87")
|
randomScript := hexToBytes("a914ff074800343a81ada8fe86c2d5d5a0e55b93dd7a87")
|
||||||
m := &MempoolBitcoinType{
|
m := &MempoolBitcoinType{
|
||||||
golombFilterP: 20,
|
golombFilterP: 20,
|
||||||
golombFilterM: uint64(1 << 20),
|
filterScripts: "taproot",
|
||||||
filterScripts: filterScriptsTaproot,
|
|
||||||
}
|
}
|
||||||
|
golombFilterM := GetGolombParamM(m.golombFilterP)
|
||||||
tests := []struct {
|
tests := []struct {
|
||||||
name string
|
name string
|
||||||
mtx MempoolTx
|
mtx MempoolTx
|
||||||
@ -194,13 +194,13 @@ func TestMempoolBitcoinType_computeGolombFilter_taproot(t *testing.T) {
|
|||||||
}
|
}
|
||||||
for _, tt := range tests {
|
for _, tt := range tests {
|
||||||
t.Run(tt.name, func(t *testing.T) {
|
t.Run(tt.name, func(t *testing.T) {
|
||||||
got := m.computeGolombFilter(&tt.mtx)
|
got := m.computeGolombFilter(&tt.mtx, nil)
|
||||||
if got != tt.want {
|
if got != tt.want {
|
||||||
t.Errorf("MempoolBitcoinType.computeGolombFilter() = %v, want %v", got, tt.want)
|
t.Errorf("MempoolBitcoinType.computeGolombFilter() = %v, want %v", got, tt.want)
|
||||||
}
|
}
|
||||||
if got != "" {
|
if got != "" {
|
||||||
// build the filter from computed value
|
// build the filter from computed value
|
||||||
filter, err := gcs.FromNBytes(m.golombFilterP, m.golombFilterM, hexToBytes(got))
|
filter, err := gcs.FromNBytes(m.golombFilterP, golombFilterM, hexToBytes(got))
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Errorf("gcs.BuildGCSFilter() unexpected error %v", err)
|
t.Errorf("gcs.BuildGCSFilter() unexpected error %v", err)
|
||||||
}
|
}
|
||||||
@ -211,8 +211,8 @@ func TestMempoolBitcoinType_computeGolombFilter_taproot(t *testing.T) {
|
|||||||
if err != nil {
|
if err != nil {
|
||||||
t.Errorf("filter.Match vin[%d] unexpected error %v", i, err)
|
t.Errorf("filter.Match vin[%d] unexpected error %v", i, err)
|
||||||
}
|
}
|
||||||
if match != isTaproot(tt.mtx.Vin[i].AddrDesc) {
|
if match != tt.mtx.Vin[i].AddrDesc.IsTaproot() {
|
||||||
t.Errorf("filter.Match vin[%d] got %v, want %v", i, match, isTaproot(tt.mtx.Vin[i].AddrDesc))
|
t.Errorf("filter.Match vin[%d] got %v, want %v", i, match, tt.mtx.Vin[i].AddrDesc.IsTaproot())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
// check that the vout scripts match the filter
|
// check that the vout scripts match the filter
|
||||||
@ -222,8 +222,8 @@ func TestMempoolBitcoinType_computeGolombFilter_taproot(t *testing.T) {
|
|||||||
if err != nil {
|
if err != nil {
|
||||||
t.Errorf("filter.Match vout[%d] unexpected error %v", i, err)
|
t.Errorf("filter.Match vout[%d] unexpected error %v", i, err)
|
||||||
}
|
}
|
||||||
if match != isTaproot(s) {
|
if match != AddressDescriptor(s).IsTaproot() {
|
||||||
t.Errorf("filter.Match vout[%d] got %v, want %v", i, match, isTaproot(s))
|
t.Errorf("filter.Match vout[%d] got %v, want %v", i, match, AddressDescriptor(s).IsTaproot())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
// check that a random script does not match the filter
|
// check that a random script does not match the filter
|
||||||
@ -238,3 +238,115 @@ func TestMempoolBitcoinType_computeGolombFilter_taproot(t *testing.T) {
|
|||||||
})
|
})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func TestMempoolBitcoinType_computeGolombFilter_taproot_noordinals(t *testing.T) {
|
||||||
|
m := &MempoolBitcoinType{
|
||||||
|
golombFilterP: 20,
|
||||||
|
filterScripts: "taproot-noordinals",
|
||||||
|
}
|
||||||
|
tests := []struct {
|
||||||
|
name string
|
||||||
|
mtx MempoolTx
|
||||||
|
tx Tx
|
||||||
|
want string
|
||||||
|
}{
|
||||||
|
{
|
||||||
|
name: "taproot-no-ordinals normal taproot tx",
|
||||||
|
mtx: MempoolTx{
|
||||||
|
Txid: "86336c62a63f509a278624e3f400cdd50838d035a44e0af8a7d6d133c04cc2d2",
|
||||||
|
Vin: []MempoolVin{
|
||||||
|
{
|
||||||
|
// bc1pdfc3xk96cm9g7lwlm78hxd2xuevzpqfzjw0shaarwflczs7lh0lstksdn0
|
||||||
|
AddrDesc: hexToBytes("51206a711358bac6ca8f7ddfdf8f733546e658208122939f0bf7a3727f8143dfbbff"),
|
||||||
|
},
|
||||||
|
},
|
||||||
|
Vout: []Vout{
|
||||||
|
{
|
||||||
|
ScriptPubKey: ScriptPubKey{
|
||||||
|
Hex: "51206850b179630df0f7012ae2b111bafa52ebb9b54e1435fc4f98fbe0af6f95076a",
|
||||||
|
Addresses: []string{
|
||||||
|
"bc1pdpgtz7trphc0wqf2u2c3rwh62t4mnd2wzs6lcnucl0s27mu4qa4q4md9ta",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
tx: Tx{
|
||||||
|
Vin: []Vin{
|
||||||
|
{
|
||||||
|
Witness: [][]byte{
|
||||||
|
hexToBytes("737ad2835962e3d147cd74a578f1109e9314eac9d00c9fad304ce2050b78fac21a2d124fd886d1d646cf1de5d5c9754b0415b960b1319526fa25e36ca1f650ce"),
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
Vout: []Vout{
|
||||||
|
{
|
||||||
|
ScriptPubKey: ScriptPubKey{
|
||||||
|
Hex: "51206850b179630df0f7012ae2b111bafa52ebb9b54e1435fc4f98fbe0af6f95076a",
|
||||||
|
Addresses: []string{
|
||||||
|
"bc1pdpgtz7trphc0wqf2u2c3rwh62t4mnd2wzs6lcnucl0s27mu4qa4q4md9ta",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
want: "02899e8c952b40",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "taproot-no-ordinals ordinal tx",
|
||||||
|
mtx: MempoolTx{
|
||||||
|
Txid: "86336c62a63f509a278624e3f400cdd50838d035a44e0af8a7d6d133c04cc2d2",
|
||||||
|
Vin: []MempoolVin{
|
||||||
|
{
|
||||||
|
// bc1pdfc3xk96cm9g7lwlm78hxd2xuevzpqfzjw0shaarwflczs7lh0lstksdn0
|
||||||
|
AddrDesc: hexToBytes("51206a711358bac6ca8f7ddfdf8f733546e658208122939f0bf7a3727f8143dfbbff"),
|
||||||
|
},
|
||||||
|
},
|
||||||
|
Vout: []Vout{
|
||||||
|
{
|
||||||
|
ScriptPubKey: ScriptPubKey{
|
||||||
|
Hex: "51206850b179630df0f7012ae2b111bafa52ebb9b54e1435fc4f98fbe0af6f95076a",
|
||||||
|
Addresses: []string{
|
||||||
|
"bc1pdpgtz7trphc0wqf2u2c3rwh62t4mnd2wzs6lcnucl0s27mu4qa4q4md9ta",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
tx: Tx{
|
||||||
|
// https://mempool.space/tx/c4cae52a6e681b66c85c12feafb42f3617f34977032df1ee139eae07370863ef
|
||||||
|
Txid: "c4cae52a6e681b66c85c12feafb42f3617f34977032df1ee139eae07370863ef",
|
||||||
|
Vin: []Vin{
|
||||||
|
{
|
||||||
|
Txid: "11111c17cbe86aebab146ee039d4e354cb55a9fb226ebdd2e30948630e7710ad",
|
||||||
|
Vout: 0,
|
||||||
|
Witness: [][]byte{
|
||||||
|
hexToBytes("737ad2835962e3d147cd74a578f1109e9314eac9d00c9fad304ce2050b78fac21a2d124fd886d1d646cf1de5d5c9754b0415b960b1319526fa25e36ca1f650ce"),
|
||||||
|
hexToBytes("2029f34532e043fade4471779b4955005db8fa9b64c9e8d0a2dae4a38bbca23328ac0063036f726401010a696d6167652f77656270004d08025249464650020000574542505650384c440200002f57c2950067a026009086939b7785a104699656f4f53388355445b6415d22f8924000fd83bd31d346ca69f8fcfed6d8d18231846083f90f00ffbf203883666c36463c6ba8662257d789935e002192245bd15ac00216b080052cac85b380052c60e1593859f33a7a7abff7ed88feb361db3692341bc83553aef7aec75669ffb1ffd87fec3ff61ffb8ffdc736f20a96a0fba34071d4fdf111c435381df667728f95c4e82b6872d82471bfdc1665107bb80fd46df1686425bcd2e27eb59adc9d17b54b997ee96776a7c37ca2b57b9551bcffeb71d88768765af7384c2e3ba031ca3f19c9ddb0c6ec55223fbfe3731a1e8d7bb010de8532d53293bbbb6145597ee53559a612e6de4f8fc66936ef463eea7498555643ac0dafad6627575f2733b9fb352e411e7d9df8fc80fde75f5f66f5c5381a46b9a697d9c97555c4bf41a4909b9dd071557c3dfe0bfcd6459e06514266c65756ce9f25705230df63d30fef6076b797e1f49d00b41e87b5ccecb1c237f419e4b3ca6876053c14fc979a629459a62f78d735fb078bfa0e7a1fc69ad379447d817e06b3d7f1de820f28534f85fa20469cd6f93ddc6c5f2a94878fc64a98ac336294c99d27d11742268ae1a34cd61f31e2e4aee94b0ff496f55068fa727ace6ad2ec1e6e3f59e6a8bd154f287f652fbfaa05cac067951de1bfacc0e330c3bf6dd2efde4c509646566836eb71986154731daf722a6ff585001e87f9479559a61265d6e330f3682bf87ab2598fc3fca36da778e59cee71584594ef175e6d7d5f70d6deb02c4b371e5063c35669ffb1ffd87ffe0e730068"),
|
||||||
|
hexToBytes("c129f34532e043fade4471779b4955005db8fa9b64c9e8d0a2dae4a38bbca23328"),
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
Vout: []Vout{
|
||||||
|
{
|
||||||
|
ScriptPubKey: ScriptPubKey{
|
||||||
|
Hex: "51206850b179630df0f7012ae2b111bafa52ebb9b54e1435fc4f98fbe0af6f95076a",
|
||||||
|
Addresses: []string{
|
||||||
|
"bc1pdpgtz7trphc0wqf2u2c3rwh62t4mnd2wzs6lcnucl0s27mu4qa4q4md9ta",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
want: "",
|
||||||
|
},
|
||||||
|
}
|
||||||
|
for _, tt := range tests {
|
||||||
|
t.Run(tt.name, func(t *testing.T) {
|
||||||
|
got := m.computeGolombFilter(&tt.mtx, &tt.tx)
|
||||||
|
if got != tt.want {
|
||||||
|
t.Errorf("MempoolBitcoinType.computeGolombFilter() = %v, want %v", got, tt.want)
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|||||||
@ -132,8 +132,8 @@ func (m *MempoolEthereumType) Resync() (int, error) {
|
|||||||
return entries, nil
|
return entries, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// AddTransactionToMempool adds transactions to mempool
|
// AddTransactionToMempool adds transactions to mempool, returns true if tx added to mempool, false if not added (for example duplicate call)
|
||||||
func (m *MempoolEthereumType) AddTransactionToMempool(txid string) {
|
func (m *MempoolEthereumType) AddTransactionToMempool(txid string) bool {
|
||||||
m.mux.Lock()
|
m.mux.Lock()
|
||||||
_, exists := m.txEntries[txid]
|
_, exists := m.txEntries[txid]
|
||||||
m.mux.Unlock()
|
m.mux.Unlock()
|
||||||
@ -143,7 +143,7 @@ func (m *MempoolEthereumType) AddTransactionToMempool(txid string) {
|
|||||||
if !exists {
|
if !exists {
|
||||||
entry, ok := m.createTxEntry(txid, uint32(time.Now().Unix()))
|
entry, ok := m.createTxEntry(txid, uint32(time.Now().Unix()))
|
||||||
if !ok {
|
if !ok {
|
||||||
return
|
return false
|
||||||
}
|
}
|
||||||
m.mux.Lock()
|
m.mux.Lock()
|
||||||
m.txEntries[txid] = entry
|
m.txEntries[txid] = entry
|
||||||
@ -152,6 +152,7 @@ func (m *MempoolEthereumType) AddTransactionToMempool(txid string) {
|
|||||||
}
|
}
|
||||||
m.mux.Unlock()
|
m.mux.Unlock()
|
||||||
}
|
}
|
||||||
|
return !exists
|
||||||
}
|
}
|
||||||
|
|
||||||
// RemoveTransactionFromMempool removes transaction from mempool
|
// RemoveTransactionFromMempool removes transaction from mempool
|
||||||
|
|||||||
@ -57,6 +57,7 @@ type Vin struct {
|
|||||||
ScriptSig ScriptSig `json:"scriptSig"`
|
ScriptSig ScriptSig `json:"scriptSig"`
|
||||||
Sequence uint32 `json:"sequence"`
|
Sequence uint32 `json:"sequence"`
|
||||||
Addresses []string `json:"addresses"`
|
Addresses []string `json:"addresses"`
|
||||||
|
Witness [][]byte `json:"-"`
|
||||||
}
|
}
|
||||||
|
|
||||||
// ScriptPubKey contains data about output script
|
// ScriptPubKey contains data about output script
|
||||||
@ -130,7 +131,8 @@ type TokenTypeName string
|
|||||||
|
|
||||||
// Token types
|
// Token types
|
||||||
const (
|
const (
|
||||||
UnknownTokenType TokenTypeName = ""
|
UnknownTokenType TokenTypeName = ""
|
||||||
|
UnhandledTokenType TokenTypeName = "-"
|
||||||
|
|
||||||
// XPUBAddressTokenType is address derived from xpub
|
// XPUBAddressTokenType is address derived from xpub
|
||||||
XPUBAddressTokenType TokenTypeName = "XPUBAddress"
|
XPUBAddressTokenType TokenTypeName = "XPUBAddress"
|
||||||
@ -226,6 +228,13 @@ func (ad AddressDescriptor) String() string {
|
|||||||
return "ad:" + hex.EncodeToString(ad)
|
return "ad:" + hex.EncodeToString(ad)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (ad AddressDescriptor) IsTaproot() bool {
|
||||||
|
if len(ad) == 34 && ad[0] == 0x51 && ad[1] == 0x20 {
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
// AddressDescriptorFromString converts string created by AddressDescriptor.String to AddressDescriptor
|
// AddressDescriptorFromString converts string created by AddressDescriptor.String to AddressDescriptor
|
||||||
func AddressDescriptorFromString(s string) (AddressDescriptor, error) {
|
func AddressDescriptorFromString(s string) (AddressDescriptor, error) {
|
||||||
if len(s) > 3 && s[0:3] == "ad:" {
|
if len(s) > 3 && s[0:3] == "ad:" {
|
||||||
@ -266,8 +275,10 @@ type XpubDescriptor struct {
|
|||||||
type MempoolTxidEntries []MempoolTxidEntry
|
type MempoolTxidEntries []MempoolTxidEntry
|
||||||
|
|
||||||
// MempoolTxidFilterEntries is a map of txids to mempool golomb filters
|
// MempoolTxidFilterEntries is a map of txids to mempool golomb filters
|
||||||
|
// Also contains a flag whether constant zeroed key was used when calculating the filters
|
||||||
type MempoolTxidFilterEntries struct {
|
type MempoolTxidFilterEntries struct {
|
||||||
Entries map[string]string `json:"entries,omitempty"`
|
Entries map[string]string `json:"entries,omitempty"`
|
||||||
|
UsedZeroedKey bool `json:"usedZeroedKey,omitempty"`
|
||||||
}
|
}
|
||||||
|
|
||||||
// OnNewBlockFunc is used to send notification about a new block
|
// OnNewBlockFunc is used to send notification about a new block
|
||||||
@ -323,6 +334,10 @@ type BlockChain interface {
|
|||||||
EthereumTypeGetNonce(addrDesc AddressDescriptor) (uint64, error)
|
EthereumTypeGetNonce(addrDesc AddressDescriptor) (uint64, error)
|
||||||
EthereumTypeEstimateGas(params map[string]interface{}) (uint64, error)
|
EthereumTypeEstimateGas(params map[string]interface{}) (uint64, error)
|
||||||
EthereumTypeGetErc20ContractBalance(addrDesc, contractDesc AddressDescriptor) (*big.Int, error)
|
EthereumTypeGetErc20ContractBalance(addrDesc, contractDesc AddressDescriptor) (*big.Int, error)
|
||||||
|
EthereumTypeGetSupportedStakingPools() []string
|
||||||
|
EthereumTypeGetStakingPoolsData(addrDesc AddressDescriptor) ([]StakingPoolData, error)
|
||||||
|
EthereumTypeRpcCall(data, to, from string) (string, error)
|
||||||
|
EthereumTypeGetRawTransaction(txid string) (string, error)
|
||||||
GetTokenURI(contractDesc AddressDescriptor, tokenID *big.Int) (string, error)
|
GetTokenURI(contractDesc AddressDescriptor, tokenID *big.Int) (string, error)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -122,9 +122,13 @@ type RpcLog struct {
|
|||||||
|
|
||||||
// RpcLog is returned by eth_getTransactionReceipt
|
// RpcLog is returned by eth_getTransactionReceipt
|
||||||
type RpcReceipt struct {
|
type RpcReceipt struct {
|
||||||
GasUsed string `json:"gasUsed"`
|
GasUsed string `json:"gasUsed"`
|
||||||
Status string `json:"status"`
|
Status string `json:"status"`
|
||||||
Logs []*RpcLog `json:"logs"`
|
Logs []*RpcLog `json:"logs"`
|
||||||
|
L1Fee string `json:"l1Fee,omitempty"`
|
||||||
|
L1FeeScalar string `json:"l1FeeScalar,omitempty"`
|
||||||
|
L1GasPrice string `json:"l1GasPrice,omitempty"`
|
||||||
|
L1GasUsed string `json:"l1GasUsed,omitempty"`
|
||||||
}
|
}
|
||||||
|
|
||||||
// EthereumSpecificData contains data specific to Ethereum transactions
|
// EthereumSpecificData contains data specific to Ethereum transactions
|
||||||
@ -146,3 +150,16 @@ type EthereumBlockSpecificData struct {
|
|||||||
AddressAliasRecords []AddressAliasRecord
|
AddressAliasRecords []AddressAliasRecord
|
||||||
Contracts []ContractInfo
|
Contracts []ContractInfo
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// StakingPool holds data about address participation in a staking pool contract
|
||||||
|
type StakingPoolData struct {
|
||||||
|
Contract string `json:"contract"`
|
||||||
|
Name string `json:"name"`
|
||||||
|
PendingBalance big.Int `json:"pendingBalance"` // pendingBalanceOf method
|
||||||
|
PendingDepositedBalance big.Int `json:"pendingDepositedBalance"` // pendingDepositedBalanceOf method
|
||||||
|
DepositedBalance big.Int `json:"depositedBalance"` // depositedBalanceOf method
|
||||||
|
WithdrawTotalAmount big.Int `json:"withdrawTotalAmount"` // withdrawRequest method, return value [0]
|
||||||
|
ClaimableAmount big.Int `json:"claimableAmount"` // withdrawRequest method, return value [1]
|
||||||
|
RestakedReward big.Int `json:"restakedReward"` // restakedRewardOf method
|
||||||
|
AutocompoundBalance big.Int `json:"autocompoundBalance"` // autocompoundBalanceOf method
|
||||||
|
}
|
||||||
|
|||||||
@ -32,7 +32,11 @@ export interface EthereumSpecific {
|
|||||||
nonce: number;
|
nonce: number;
|
||||||
gasLimit: number;
|
gasLimit: number;
|
||||||
gasUsed?: number;
|
gasUsed?: number;
|
||||||
gasPrice: string;
|
gasPrice?: string;
|
||||||
|
l1Fee?: number;
|
||||||
|
l1FeeScalar?: string;
|
||||||
|
l1GasPrice?: string;
|
||||||
|
l1GasUsed?: number;
|
||||||
data?: string;
|
data?: string;
|
||||||
parsedData?: EthereumParsedInputData;
|
parsedData?: EthereumParsedInputData;
|
||||||
internalTransfers?: EthereumInternalTransfer[];
|
internalTransfers?: EthereumInternalTransfer[];
|
||||||
@ -46,9 +50,9 @@ export interface TokenTransfer {
|
|||||||
from: string;
|
from: string;
|
||||||
to: string;
|
to: string;
|
||||||
contract: string;
|
contract: string;
|
||||||
name: string;
|
name?: string;
|
||||||
symbol: string;
|
symbol?: string;
|
||||||
decimals: number;
|
decimals?: number;
|
||||||
value?: string;
|
value?: string;
|
||||||
multiTokenValues?: MultiTokenValue[];
|
multiTokenValues?: MultiTokenValue[];
|
||||||
}
|
}
|
||||||
@ -109,6 +113,17 @@ export interface FeeStats {
|
|||||||
averageFeePerKb: number;
|
averageFeePerKb: number;
|
||||||
decilesFeePerKb: number[];
|
decilesFeePerKb: number[];
|
||||||
}
|
}
|
||||||
|
export interface StakingPool {
|
||||||
|
contract: string;
|
||||||
|
name: string;
|
||||||
|
pendingBalance: string;
|
||||||
|
pendingDepositedBalance: string;
|
||||||
|
depositedBalance: string;
|
||||||
|
withdrawTotalAmount: string;
|
||||||
|
claimableAmount: string;
|
||||||
|
restakedReward: string;
|
||||||
|
autocompoundBalance: string;
|
||||||
|
}
|
||||||
export interface ContractInfo {
|
export interface ContractInfo {
|
||||||
type: string;
|
type: string;
|
||||||
contract: string;
|
contract: string;
|
||||||
@ -161,6 +176,7 @@ export interface Address {
|
|||||||
contractInfo?: ContractInfo;
|
contractInfo?: ContractInfo;
|
||||||
erc20Contract?: ContractInfo;
|
erc20Contract?: ContractInfo;
|
||||||
addressAliases?: { [key: string]: AddressAlias };
|
addressAliases?: { [key: string]: AddressAlias };
|
||||||
|
stakingPools?: StakingPool[];
|
||||||
}
|
}
|
||||||
export interface Utxo {
|
export interface Utxo {
|
||||||
txid: string;
|
txid: string;
|
||||||
@ -245,6 +261,7 @@ export interface InternalStateColumn {
|
|||||||
}
|
}
|
||||||
export interface BlockbookInfo {
|
export interface BlockbookInfo {
|
||||||
coin: string;
|
coin: string;
|
||||||
|
network: string;
|
||||||
host: string;
|
host: string;
|
||||||
version: string;
|
version: string;
|
||||||
gitCommit: string;
|
gitCommit: string;
|
||||||
@ -264,6 +281,7 @@ export interface BlockbookInfo {
|
|||||||
currentFiatRatesTime?: string;
|
currentFiatRatesTime?: string;
|
||||||
historicalFiatRatesTime?: string;
|
historicalFiatRatesTime?: string;
|
||||||
historicalTokenFiatRatesTime?: string;
|
historicalTokenFiatRatesTime?: string;
|
||||||
|
supportedStakingPools?: string[];
|
||||||
dbSizeFromColumns?: number;
|
dbSizeFromColumns?: number;
|
||||||
dbColumns?: InternalStateColumn[];
|
dbColumns?: InternalStateColumn[];
|
||||||
about: string;
|
about: string;
|
||||||
@ -338,6 +356,7 @@ export interface WsBackendInfo {
|
|||||||
export interface WsInfoRes {
|
export interface WsInfoRes {
|
||||||
name: string;
|
name: string;
|
||||||
shortcut: string;
|
shortcut: string;
|
||||||
|
network: string;
|
||||||
decimals: number;
|
decimals: number;
|
||||||
version: string;
|
version: string;
|
||||||
bestHeight: number;
|
bestHeight: number;
|
||||||
@ -357,6 +376,17 @@ export interface WsBlockReq {
|
|||||||
pageSize?: number;
|
pageSize?: number;
|
||||||
page?: number;
|
page?: number;
|
||||||
}
|
}
|
||||||
|
export interface WsBlockFilterReq {
|
||||||
|
scriptType: string;
|
||||||
|
blockHash: string;
|
||||||
|
M?: number;
|
||||||
|
}
|
||||||
|
export interface WsBlockFiltersBatchReq {
|
||||||
|
scriptType: string;
|
||||||
|
bestKnownBlockHash: string;
|
||||||
|
pageSize?: number;
|
||||||
|
M?: number;
|
||||||
|
}
|
||||||
export interface WsAccountUtxoReq {
|
export interface WsAccountUtxoReq {
|
||||||
descriptor: string;
|
descriptor: string;
|
||||||
}
|
}
|
||||||
@ -416,7 +446,17 @@ export interface WsFiatRatesTickersListReq {
|
|||||||
export interface WsMempoolFiltersReq {
|
export interface WsMempoolFiltersReq {
|
||||||
scriptType: string;
|
scriptType: string;
|
||||||
fromTimestamp: number;
|
fromTimestamp: number;
|
||||||
|
M?: number;
|
||||||
|
}
|
||||||
|
export interface WsRpcCallReq {
|
||||||
|
from?: string;
|
||||||
|
to: string;
|
||||||
|
data: string;
|
||||||
|
}
|
||||||
|
export interface WsRpcCallRes {
|
||||||
|
data: string;
|
||||||
}
|
}
|
||||||
export interface MempoolTxidFilterEntries {
|
export interface MempoolTxidFilterEntries {
|
||||||
entries?: { [key: string]: string };
|
entries?: { [key: string]: string };
|
||||||
|
usedZeroedKey?: boolean;
|
||||||
}
|
}
|
||||||
|
|||||||
53
blockbook.go
53
blockbook.go
@ -2,7 +2,6 @@ package main
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"context"
|
"context"
|
||||||
"encoding/json"
|
|
||||||
"flag"
|
"flag"
|
||||||
"log"
|
"log"
|
||||||
"math/rand"
|
"math/rand"
|
||||||
@ -11,6 +10,7 @@ import (
|
|||||||
"os"
|
"os"
|
||||||
"os/signal"
|
"os/signal"
|
||||||
"runtime/debug"
|
"runtime/debug"
|
||||||
|
"strconv"
|
||||||
"strings"
|
"strings"
|
||||||
"syscall"
|
"syscall"
|
||||||
"time"
|
"time"
|
||||||
@ -152,30 +152,19 @@ func mainWithExitCode() int {
|
|||||||
return exitCodeOK
|
return exitCodeOK
|
||||||
}
|
}
|
||||||
|
|
||||||
if *configFile == "" {
|
config, err := common.GetConfig(*configFile)
|
||||||
glog.Error("Missing blockchaincfg configuration parameter")
|
|
||||||
return exitCodeFatal
|
|
||||||
}
|
|
||||||
|
|
||||||
configFileContent, err := os.ReadFile(*configFile)
|
|
||||||
if err != nil {
|
|
||||||
glog.Errorf("Error reading file %v, %v", configFile, err)
|
|
||||||
return exitCodeFatal
|
|
||||||
}
|
|
||||||
|
|
||||||
coin, coinShortcut, coinLabel, err := coins.GetCoinNameFromConfig(configFileContent)
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
glog.Error("config: ", err)
|
glog.Error("config: ", err)
|
||||||
return exitCodeFatal
|
return exitCodeFatal
|
||||||
}
|
}
|
||||||
|
|
||||||
metrics, err = common.GetMetrics(coin)
|
metrics, err = common.GetMetrics(config.CoinName)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
glog.Error("metrics: ", err)
|
glog.Error("metrics: ", err)
|
||||||
return exitCodeFatal
|
return exitCodeFatal
|
||||||
}
|
}
|
||||||
|
|
||||||
if chain, mempool, err = getBlockChainWithRetry(coin, *configFile, pushSynchronizationHandler, metrics, 120); err != nil {
|
if chain, mempool, err = getBlockChainWithRetry(config.CoinName, *configFile, pushSynchronizationHandler, metrics, 120); err != nil {
|
||||||
glog.Error("rpc: ", err)
|
glog.Error("rpc: ", err)
|
||||||
return exitCodeFatal
|
return exitCodeFatal
|
||||||
}
|
}
|
||||||
@ -187,7 +176,7 @@ func mainWithExitCode() int {
|
|||||||
}
|
}
|
||||||
defer index.Close()
|
defer index.Close()
|
||||||
|
|
||||||
internalState, err = newInternalState(coin, coinShortcut, coinLabel, index, *enableSubNewTx)
|
internalState, err = newInternalState(config, index, *enableSubNewTx)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
glog.Error("internalState: ", err)
|
glog.Error("internalState: ", err)
|
||||||
return exitCodeFatal
|
return exitCodeFatal
|
||||||
@ -279,7 +268,7 @@ func mainWithExitCode() int {
|
|||||||
return exitCodeFatal
|
return exitCodeFatal
|
||||||
}
|
}
|
||||||
|
|
||||||
if fiatRates, err = fiat.NewFiatRates(index, configFileContent, metrics, onNewFiatRatesTicker); err != nil {
|
if fiatRates, err = fiat.NewFiatRates(index, config, metrics, onNewFiatRatesTicker); err != nil {
|
||||||
glog.Error("fiatRates ", err)
|
glog.Error("fiatRates ", err)
|
||||||
return exitCodeFatal
|
return exitCodeFatal
|
||||||
}
|
}
|
||||||
@ -368,7 +357,7 @@ func mainWithExitCode() int {
|
|||||||
|
|
||||||
if internalServer != nil || publicServer != nil || chain != nil {
|
if internalServer != nil || publicServer != nil || chain != nil {
|
||||||
// start fiat rates downloader only if not shutting down immediately
|
// start fiat rates downloader only if not shutting down immediately
|
||||||
initDownloaders(index, chain, configFileContent)
|
initDownloaders(index, chain, config)
|
||||||
waitForSignalAndShutdown(internalServer, publicServer, chain, 10*time.Second)
|
waitForSignalAndShutdown(internalServer, publicServer, chain, 10*time.Second)
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -501,16 +490,12 @@ func blockbookAppInfoMetric(db *db.RocksDB, chain bchain.BlockChain, txCache *db
|
|||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func newInternalState(coin, coinShortcut, coinLabel string, d *db.RocksDB, enableSubNewTx bool) (*common.InternalState, error) {
|
func newInternalState(config *common.Config, d *db.RocksDB, enableSubNewTx bool) (*common.InternalState, error) {
|
||||||
is, err := d.LoadInternalState(coin)
|
is, err := d.LoadInternalState(config)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
is.CoinShortcut = coinShortcut
|
|
||||||
if coinLabel == "" {
|
|
||||||
coinLabel = coin
|
|
||||||
}
|
|
||||||
is.CoinLabel = coinLabel
|
|
||||||
is.EnableSubNewTx = enableSubNewTx
|
is.EnableSubNewTx = enableSubNewTx
|
||||||
name, err := os.Hostname()
|
name, err := os.Hostname()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
@ -521,6 +506,12 @@ func newInternalState(coin, coinShortcut, coinLabel string, d *db.RocksDB, enabl
|
|||||||
}
|
}
|
||||||
is.Host = name
|
is.Host = name
|
||||||
}
|
}
|
||||||
|
|
||||||
|
is.WsGetAccountInfoLimit, _ = strconv.Atoi(os.Getenv(strings.ToUpper(is.GetNetwork()) + "_WS_GETACCOUNTINFO_LIMIT"))
|
||||||
|
if is.WsGetAccountInfoLimit > 0 {
|
||||||
|
glog.Info("WsGetAccountInfoLimit enabled with limit ", is.WsGetAccountInfoLimit)
|
||||||
|
is.WsLimitExceedingIPs = make(map[string]int)
|
||||||
|
}
|
||||||
return is, nil
|
return is, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -702,21 +693,11 @@ func computeFeeStats(stopCompute chan os.Signal, blockFrom, blockTo int, db *db.
|
|||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
func initDownloaders(db *db.RocksDB, chain bchain.BlockChain, configFileContent []byte) {
|
func initDownloaders(db *db.RocksDB, chain bchain.BlockChain, config *common.Config) {
|
||||||
if fiatRates.Enabled {
|
if fiatRates.Enabled {
|
||||||
go fiatRates.RunDownloader()
|
go fiatRates.RunDownloader()
|
||||||
}
|
}
|
||||||
|
|
||||||
var config struct {
|
|
||||||
FourByteSignatures string `json:"fourByteSignatures"`
|
|
||||||
}
|
|
||||||
|
|
||||||
err := json.Unmarshal(configFileContent, &config)
|
|
||||||
if err != nil {
|
|
||||||
glog.Errorf("Error parsing config file %v, %v", *configFile, err)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
if config.FourByteSignatures != "" && chain.GetChainParser().GetChainType() == bchain.ChainEthereumType {
|
if config.FourByteSignatures != "" && chain.GetChainParser().GetChainType() == bchain.ChainEthereumType {
|
||||||
fbsd, err := fourbyte.NewFourByteSignaturesDownloader(db, config.FourByteSignatures)
|
fbsd, err := fourbyte.NewFourByteSignaturesDownloader(db, config.FourByteSignatures)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
|||||||
@ -11,7 +11,7 @@ RUN apt-get update && \
|
|||||||
libzstd-dev liblz4-dev graphviz && \
|
libzstd-dev liblz4-dev graphviz && \
|
||||||
apt-get clean
|
apt-get clean
|
||||||
ARG GOLANG_VERSION
|
ARG GOLANG_VERSION
|
||||||
ENV GOLANG_VERSION=go1.19.2
|
ENV GOLANG_VERSION=go1.22.8
|
||||||
ENV ROCKSDB_VERSION=v7.7.2
|
ENV ROCKSDB_VERSION=v7.7.2
|
||||||
ENV GOPATH=/go
|
ENV GOPATH=/go
|
||||||
ENV PATH=$PATH:$GOPATH/bin
|
ENV PATH=$PATH:$GOPATH/bin
|
||||||
|
|||||||
@ -38,5 +38,4 @@ prepare-sources:
|
|||||||
mkdir -p $(BLOCKBOOK_BASE)
|
mkdir -p $(BLOCKBOOK_BASE)
|
||||||
cp -r /src $(BLOCKBOOK_SRC)
|
cp -r /src $(BLOCKBOOK_SRC)
|
||||||
cd $(BLOCKBOOK_SRC) && go mod download
|
cd $(BLOCKBOOK_SRC) && go mod download
|
||||||
sed -i 's/wsMessageSizeLimit\ =\ 15\ \*\ 1024\ \*\ 1024/wsMessageSizeLimit = 80 * 1024 * 1024/g' $(GOPATH)/pkg/mod/github.com/ethereum/go-ethereum*/rpc/websocket.go
|
|
||||||
sed -i 's/wsMessageSizeLimit\ =\ 15\ \*\ 1024\ \*\ 1024/wsMessageSizeLimit = 80 * 1024 * 1024/g' $(GOPATH)/pkg/mod/github.com/ava-labs/coreth*/rpc/websocket.go
|
sed -i 's/wsMessageSizeLimit\ =\ 15\ \*\ 1024\ \*\ 1024/wsMessageSizeLimit = 80 * 1024 * 1024/g' $(GOPATH)/pkg/mod/github.com/ava-labs/coreth*/rpc/websocket.go
|
||||||
|
|||||||
@ -6,9 +6,19 @@ ENV DEBIAN_FRONTEND=noninteractive
|
|||||||
|
|
||||||
RUN apt-get update && \
|
RUN apt-get update && \
|
||||||
apt-get upgrade -y && \
|
apt-get upgrade -y && \
|
||||||
apt-get install -y devscripts debhelper make dh-exec && \
|
apt-get install -y devscripts debhelper make dh-exec zstd && \
|
||||||
apt-get clean
|
apt-get clean
|
||||||
|
|
||||||
|
# install docker cli
|
||||||
|
ARG DOCKER_VERSION
|
||||||
|
|
||||||
|
RUN if [ -z "$DOCKER_VERSION" ]; then echo "DOCKER_VERSION is a required build arg" && exit 1; fi
|
||||||
|
|
||||||
|
RUN wget -O docker.tgz "https://download.docker.com/linux/static/stable/x86_64/docker-${DOCKER_VERSION}.tgz" && \
|
||||||
|
tar -xzf docker.tgz --strip 1 -C /usr/local/bin/ && \
|
||||||
|
rm docker.tgz && \
|
||||||
|
docker --version
|
||||||
|
|
||||||
ADD gpg-keys /tmp/gpg-keys
|
ADD gpg-keys /tmp/gpg-keys
|
||||||
RUN gpg --batch --import /tmp/gpg-keys/*
|
RUN gpg --batch --import /tmp/gpg-keys/*
|
||||||
|
|
||||||
|
|||||||
@ -1,5 +1,103 @@
|
|||||||
-----BEGIN PGP PUBLIC KEY BLOCK-----
|
-----BEGIN PGP PUBLIC KEY BLOCK-----
|
||||||
|
|
||||||
|
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
|
||||||
|
gZfWLfoIul+B10SwJHXuoQ==
|
||||||
|
=/A3N
|
||||||
|
-----END PGP PUBLIC KEY BLOCK-----
|
||||||
|
|
||||||
|
-----BEGIN PGP PUBLIC KEY BLOCK-----
|
||||||
|
|
||||||
mQINBF1ULyUBEADFFliU0Hr+PRCQNT9/9ZEhZtLmMMu7tai3VCxhmrHrOpNJJHqX
|
mQINBF1ULyUBEADFFliU0Hr+PRCQNT9/9ZEhZtLmMMu7tai3VCxhmrHrOpNJJHqX
|
||||||
f1/CeUyBhmCvXpKIpAAbH66l/Uc9GH5UgMZ19gMyGa3q3QJn9A6RR9ud4ALRg60P
|
f1/CeUyBhmCvXpKIpAAbH66l/Uc9GH5UgMZ19gMyGa3q3QJn9A6RR9ud4ALRg60P
|
||||||
fmYTAci+6Luko7bqTzkS+fYOUSy/LY57s5ANTpveE+iTsBd5grXczCxaYYnthKKA
|
fmYTAci+6Luko7bqTzkS+fYOUSy/LY57s5ANTpveE+iTsBd5grXczCxaYYnthKKA
|
||||||
@ -11,55 +109,317 @@ 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
|
||||||
96I=
|
xITv/DddKRjYc7fPRlrje7H19+urJgqqkWzmuUbNlxKiXiVW/OPmCjjI89Okt3dZ
|
||||||
=85Kq
|
GCTicEAPzJ6LTpoVgo4n/Eu81nMm6caf++Pzz1vEI3bJdPHPYyI+gN64mEhfP4OJ
|
||||||
-----END PGP PUBLIC KEY BLOCK-----
|
u8v2XTbj+0ua3JxYWilxF7haytApmaPqeT7uOEBrX7EV1M+DlQCSM61u2EC5eIwA
|
||||||
|
oDba/ENXNyg5Z1JbFe3DxqE6ZVcAcZWXGdtPotayuEy6WL3LB2UUsM4UB4FPSUwc
|
||||||
|
FvnkV8YzBSV8Rqx+mkOFM6BhxzwK0zPvY+vv+rXSwz7uE/yrToqO9KvGhFxMwMwz
|
||||||
|
TRAJXI870fJQ9c5z2LzxoNg5gOUQH4vPG6YQT1ev04fj7IGYch9EhrSjuLCm94BA
|
||||||
|
pOEA+h/TTN6+xVLemUSB/l+Obm5701PP/naVprCJcCqIU3tH5HU3BXpZH++AzWo0
|
||||||
|
pmgbtd7ECsR/y0NR4Mxoef677q9YGJEG/psYC0GZlzWsY5zjala+bEVn5gvbw6Lh
|
||||||
|
4Q2gwpvVXdygb6PSPwRSkpgHtUxdvIQsDEaBBGg/ae0x3O55z2/z95acnhIMRqQp
|
||||||
|
UpnPmDZUBKlsDJ8tivw/2r8o16YtAlJ0iQEzBBABCAAdFiEEYKz3C/cSZFBJ7m8V
|
||||||
|
7+rxZoYiX2QFAmWp9dIACgkQ7+rxZoYiX2StMwf8CdL0fhz2TM1R79n+FW7QCSaI
|
||||||
|
NBzIE1lN2TbdVEZeyiwQLn9cbqOvVPFavj4vxWFIXfAYzitLDHkikmg5Qzj7OXB2
|
||||||
|
plFnqJxZ1tZSC1EdMHuNX1j55FDAggV/U/yv2PDY2XuwJbj/hLj80oNzIL5qLnNc
|
||||||
|
o0CLggB8QLLleFw4BTKycGDrzQCk4AGQ8tDRNoyI6Q/oFQtWQgQdm9Cs02Myr51Q
|
||||||
|
ZBe09XXA4wpyqv9BM+E0o8SLp/x/wZXM99vDNa7Df0nsRIQukFy5HqJJTufP1b6Q
|
||||||
|
FVMY1ouweyLxABXO4cvtYpOAUwQroY4U/q9ZnRzxj8Sq+reAt8O/wwJ8ujy9ILQW
|
||||||
|
UGFzdGEgPHBhc3RhQGRhc2gub3JnPokCVAQTAQgAPgIbAwUJA8PHawIXgBYhBClZ
|
||||||
|
A2Lsh4qB/TwgK1JSe+2r6HmEBQJlqf1lBQsJCAcCBhUKCQgLAgQWAgMBAh4FAAoJ
|
||||||
|
EFJSe+2r6HmECFwQAIDwX6fe0y6bc42zNU3Sqtd+Q3OgZfW0Rg23viI1ujyJE1uk
|
||||||
|
mmGR0i0b2luM+lSw1xOpr+pEsRX0dfaqAbbyUVIgyIZ5viXDZyWyJXr7NuBQZalX
|
||||||
|
k4njNfAELnQN2MPy/dqpelb6/J+kn6q4TC4DN95bJtSzPLK16rI94sSO+XUAJaiU
|
||||||
|
pr++cUelALoa5yHBL0mGuhlkNgCNdTE0eVwBLRQDrAywcUOEb6f2eNHyK6UY7WLy
|
||||||
|
0/LZZv2SzG/ZNQEQNY15/vrDwsQvD1ZueY5haCRK0Ga5o3GWZACU/+/c4VL2Ew7K
|
||||||
|
odxAjhVHBz50wIe35DUKVkYOQDIx9y+e50CPJicKOsnwjpC+NzQCk462ixCO9DFI
|
||||||
|
+9AFTJ6TD2BxVRHxLyUY7J21Mes4EILKFAV2dAOSZnd6LgqiYzqovJl6FmaLJyRM
|
||||||
|
JEfqvTi6Vy38Ns/6PCVGJTWKVsKz2lDas6U3/71jS0FSEwEJ9Rv9Yo75uErypNlJ
|
||||||
|
MiEahwy7kxqs8BKLtuPrF6QKRB7RgWgVxxU7z92VKCBzKDD0Oe3CDu4Lfva0487d
|
||||||
|
+TwNIGJdDeJ+ywhhFXIoGmeRm1YZferx1u5PCphiDLVkDDlLEolbp3bxKnN+l4wC
|
||||||
|
OUvhabciX46H3sM6KGMSoDRjh5n0UPr2+67qBq/rNJRCkALEFrG46i/+mNrYiQEz
|
||||||
|
BBABCAAdFiEEYKz3C/cSZFBJ7m8V7+rxZoYiX2QFAmWp9dIACgkQ7+rxZoYiX2Se
|
||||||
|
cQf+IKiMpD8+D93HtmmwG0twBbPMOVta0NU90Gvjxkw/v/JIDEWlZECClUW6Se8Z
|
||||||
|
Icq+WRZeDP6UZharGAg2GfRpfrKIwVt/aP16LsCqq+SiP4xaohmpcXQxacS5u813
|
||||||
|
G9FFuxmHud3x7/sXtxKSVQRkhgQlq+RRG/s5CodNvjliM5OQiiXGr+q1tWy5QhRs
|
||||||
|
xCXj4CTc2CiV0ycWB36Cx9tkx+/s0pf7X4778wCrhzT6Ds5fT0W9uZifcglfI/p5
|
||||||
|
jYYQkGpOrnOiHkBU3F80iFowIGsiv8pfaSqBP8yBAOtNBSVo5ksqSaH+TpVeIb0/
|
||||||
|
pfGrM1BOzpTVfTmEj77qSE2tvrkCDQRdVC8lARAAu64IaLWAvMStxVsC/+NnwBBx
|
||||||
|
YPef4Iq5gB5P1NgkmkD+tyohWVnzdN/hwVDX3BAXevF8M+y6MouUA9IxJRt2W9PK
|
||||||
|
06ArTdwhFpiam2NAO5OOUhuJ1F8eAhRQ5VvI8MbVttZKSk3LiCmXGSj5UUXEFKS1
|
||||||
|
B7WztZVwqG6YswoAPwbNerZuwYbH2gfa9LK+av1cdZ8tnDaVmZWL8z1xSCyfRa/U
|
||||||
|
AtZht/CEoTvAwXJ6CxVUBngIlqVnK0KvOrNzol2m5x4NgPcdtdDlrTQE+SpqTKjy
|
||||||
|
roRe27D+atiO6pFG/TOTkx4TWXR07YTeZQJT/fntV409daIxEgShD0md7nJ7rVYy
|
||||||
|
8u+9Z4JLlt2mtnsUKHezo1Axrlri05cewPVYQLuJND/5e2X9UzSTpY3NubQAtkD1
|
||||||
|
PpM5JeCbslT9PcMnRuUydZbhn7ieW0b57uWpOpE11s2eIJ5ixSci4mSJE9kW+IcC
|
||||||
|
ic/PPoD1Rh2CvFTBPl/bsw6Bzw64LMflPjgWkR7NVQb1DETfXo5C2A/QU6Z/o7O4
|
||||||
|
JaAeAoGki/sCmeAi5W+F1kcjPk/L/TXM6ZccMytVQOECYBOYVUxZ2VbhknKOcSFQ
|
||||||
|
cpk8bj2xsD1xX2EYhkXcCQkvutIgHGz/dt6dtvcaaL85krWD/y8h68TTFjQXK0+g
|
||||||
|
8gcpexfqTMcLnF7pqEEAEQEAAYkCPAQYAQgAJhYhBClZA2Lsh4qB/TwgK1JSe+2r
|
||||||
|
6HmEBQJdVC8lAhsMBQkDw8drAAoJEFJSe+2r6HmEDzEP/A8H3JkeSa/03kWvudFl
|
||||||
|
oVbGbfvP+XkKvGnAZPGHz3ne/SV2tcXljNgU15xHvLktI4GluEfJxRPUqvUal1zO
|
||||||
|
R9hqpas0vX8gsf0r0d3om2DHCyMY8GscfDF05Y8fqf0nU5/oLDlwwp11IyW8BDLS
|
||||||
|
wwANsTLZ1ysukfYc4hoopU71/wdAl85fae7I2QRduImWlMADfUtc9Orfb1tAhPta
|
||||||
|
CJVZj5vgfUNSZOTUJ73RGbdL3Z2dc42lO3mRMyDkPdykkq0EgOo6zZLuHZQFhxTz
|
||||||
|
WIWeUT8vWNjpkdTeRHLvv3cwPRx1k1atrM+pE9YkhCg0EOMTcmN+FMekgnU+ee0c
|
||||||
|
ibn5wWOvE05zwRKYROx34va2U6TUU6KkV3fFuq3qqkXaiMFauhI1lSFGgccg7BCN
|
||||||
|
MhbBpOBkfGI3croFGSm2pTydJ87/+P9C9ecOZSqCE7Zt5IfDs/xV7DjxBK99Z5+R
|
||||||
|
GxtsIpNlxpsUvlMSsxUNhOWyiCKr6NIOfOzdLYDkhHcKMqWGmc1zC3HHHuZvX5u6
|
||||||
|
orTyYXWqc8X5p3Kh7Qjf/ChtN2P6SCOUQquEvpiY5J1TdmQSuoqHzg3ZrN+7EOKd
|
||||||
|
nUH7y1KB7iTvgQ07lcHnAMbkFDcpQA+tAMd99LVNSXh8urXhJ/AtxaJbNbCSvpkO
|
||||||
|
GB4WHLy/V+JdomFC9Pb3oPeiiQI8BBgBCAAmAhsMFiEEKVkDYuyHioH9PCArUlJ7
|
||||||
|
7avoeYQFAmEb0RAFCQ0to2sACgkQUlJ77avoeYRHuxAAigKlhF2q7RYOxcCIsA+z
|
||||||
|
Af4jJCCkpdOWwWhjqgjtbFrS/39/FoRSC9TClO2CU4j5FIAkPKdv7EFiAXaMIDur
|
||||||
|
tpN4Ps+l6wUX/tS+xaGDVseRoAdhVjp7ilG9WIvmV3UMqxge6hbam3H5JhiVlmS+
|
||||||
|
DAxG07dbHiFrdqeHrVZU/3649K8JOO9/xSs7Qzf6XJqepfzCjQ4ZRnGy4A/0hhYT
|
||||||
|
yzGeJOcTNigSjsPHl5PNipG0xbnAn7mxFm2i5XdVmTMCqsThkH6Ac3OBbLgRBvBh
|
||||||
|
VRWUR1Fbod7ypLTjOrXFW3Yvm7mtbZU8oqLKgcaACyXaIvwAoBY9dIXgrws6Z1dg
|
||||||
|
wvFH+1N7V2A+mVkbjPzS7Iko9lC1e5WBAJ7VkW20/5Ki08JXpLmd7UyglCcioQTM
|
||||||
|
d7YyE/Aho3zQbo/9A10REC4kOsl/Ou6IeEURa+mfb9MYPgoVGTcKZnaX0d40auRJ
|
||||||
|
ptosuoYLenXciRdUmfsADAb2pVdm5b2H3+NLXf+TnbyY/zm24ZFGPXBRSj7tQgaV
|
||||||
|
6kn9NPSg32Z1WcR+pAn3Jwqts3f1PNuYCrZvWv66NohJRrdCZc1wV4dkYvl2M1s+
|
||||||
|
zf8iTVti4IifNjn57slXtEsH36miQy2vN6Cp9I3A7m5WeL07i27P8bvhxOg9q6r3
|
||||||
|
NAgNcAK3mOfpQ/ej25jgI5w=
|
||||||
|
=LIEu
|
||||||
|
-----END PGP PUBLIC KEY BLOCK-----
|
||||||
|
|
||||||
|
-----BEGIN PGP PUBLIC KEY BLOCK-----
|
||||||
|
|
||||||
|
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
|
||||||
|
=d05p
|
||||||
|
-----END PGP PUBLIC KEY BLOCK-----
|
||||||
|
-----BEGIN PGP PUBLIC KEY BLOCK-----
|
||||||
|
|
||||||
|
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
|
||||||
|
=lTCd
|
||||||
|
-----END PGP PUBLIC KEY BLOCK-----
|
||||||
|
|||||||
@ -2,6 +2,16 @@
|
|||||||
ARCHIVE := $(shell basename {{.Backend.BinaryURL}})
|
ARCHIVE := $(shell basename {{.Backend.BinaryURL}})
|
||||||
|
|
||||||
all:
|
all:
|
||||||
|
mkdir backend
|
||||||
|
{{- if ne .Backend.DockerImage "" }}
|
||||||
|
docker container inspect extract > /dev/null 2>&1 && docker rm extract || true
|
||||||
|
docker create --name extract {{.Backend.DockerImage}}
|
||||||
|
{{- if eq .Backend.VerificationType "docker"}}
|
||||||
|
[ "$$(docker inspect --format='{{`{{index .RepoDigests 0}}`}}' {{.Backend.DockerImage}} | sed 's/.*@sha256://')" = "{{.Backend.VerificationSource}}" ]
|
||||||
|
{{- end}}
|
||||||
|
{{.Backend.ExtractCommand}}
|
||||||
|
docker rm extract
|
||||||
|
{{- else }}
|
||||||
wget {{.Backend.BinaryURL}}
|
wget {{.Backend.BinaryURL}}
|
||||||
{{- if eq .Backend.VerificationType "gpg"}}
|
{{- if eq .Backend.VerificationType "gpg"}}
|
||||||
wget {{.Backend.VerificationSource}} -O checksum
|
wget {{.Backend.VerificationSource}} -O checksum
|
||||||
@ -13,8 +23,8 @@ all:
|
|||||||
{{- else if eq .Backend.VerificationType "sha256"}}
|
{{- else if eq .Backend.VerificationType "sha256"}}
|
||||||
[ "$$(sha256sum ${ARCHIVE} | cut -d ' ' -f 1)" = "{{.Backend.VerificationSource}}" ]
|
[ "$$(sha256sum ${ARCHIVE} | cut -d ' ' -f 1)" = "{{.Backend.VerificationSource}}" ]
|
||||||
{{- end}}
|
{{- end}}
|
||||||
mkdir backend
|
|
||||||
{{.Backend.ExtractCommand}} ${ARCHIVE}
|
{{.Backend.ExtractCommand}} ${ARCHIVE}
|
||||||
|
{{- end}}
|
||||||
{{- if .Backend.ExcludeFiles}}
|
{{- if .Backend.ExcludeFiles}}
|
||||||
# generated from exclude_files
|
# generated from exclude_files
|
||||||
{{- range $index, $name := .Backend.ExcludeFiles}}
|
{{- range $index, $name := .Backend.ExcludeFiles}}
|
||||||
|
|||||||
@ -12,8 +12,12 @@ zmqpubhashblock={{template "IPC.MessageQueueBindingTemplate" .}}
|
|||||||
rpcworkqueue=1100
|
rpcworkqueue=1100
|
||||||
maxmempool=4096
|
maxmempool=4096
|
||||||
mempoolexpiry=8760
|
mempoolexpiry=8760
|
||||||
|
mempoolfullrbf=1
|
||||||
|
|
||||||
dbcache=1000
|
dbcache=1000
|
||||||
|
|
||||||
|
deprecatedrpc=warnings
|
||||||
|
|
||||||
{{- if .Backend.AdditionalParams}}
|
{{- if .Backend.AdditionalParams}}
|
||||||
# generated from additional_params
|
# generated from additional_params
|
||||||
{{- range $name, $value := .Backend.AdditionalParams}}
|
{{- range $name, $value := .Backend.AdditionalParams}}
|
||||||
|
|||||||
@ -12,6 +12,8 @@ rpcworkqueue=1100
|
|||||||
maxmempool=2000
|
maxmempool=2000
|
||||||
dbcache=1000
|
dbcache=1000
|
||||||
|
|
||||||
|
deprecatedrpc=warnings
|
||||||
|
|
||||||
{{- if .Backend.AdditionalParams}}
|
{{- if .Backend.AdditionalParams}}
|
||||||
# generated from additional_params
|
# generated from additional_params
|
||||||
{{- range $name, $value := .Backend.AdditionalParams}}
|
{{- range $name, $value := .Backend.AdditionalParams}}
|
||||||
|
|||||||
@ -13,6 +13,8 @@ rpcworkqueue=1100
|
|||||||
maxmempool=2000
|
maxmempool=2000
|
||||||
dbcache=1000
|
dbcache=1000
|
||||||
|
|
||||||
|
deprecatedrpc=warnings
|
||||||
|
|
||||||
{{- if .Backend.AdditionalParams}}
|
{{- if .Backend.AdditionalParams}}
|
||||||
# generated from additional_params
|
# generated from additional_params
|
||||||
{{- range $name, $value := .Backend.AdditionalParams}}
|
{{- range $name, $value := .Backend.AdditionalParams}}
|
||||||
38
build/templates/backend/config/bitcoin_testnet4.conf
Normal file
38
build/templates/backend/config/bitcoin_testnet4.conf
Normal file
@ -0,0 +1,38 @@
|
|||||||
|
{{define "main" -}}
|
||||||
|
daemon=1
|
||||||
|
server=1
|
||||||
|
{{if .Backend.Mainnet}}mainnet=1{{else}}testnet4=1{{end}}
|
||||||
|
nolisten=1
|
||||||
|
txindex=1
|
||||||
|
disablewallet=1
|
||||||
|
|
||||||
|
zmqpubhashtx={{template "IPC.MessageQueueBindingTemplate" .}}
|
||||||
|
zmqpubhashblock={{template "IPC.MessageQueueBindingTemplate" .}}
|
||||||
|
|
||||||
|
rpcworkqueue=1100
|
||||||
|
maxmempool=4096
|
||||||
|
mempoolexpiry=8760
|
||||||
|
mempoolfullrbf=1
|
||||||
|
|
||||||
|
dbcache=1000
|
||||||
|
|
||||||
|
deprecatedrpc=warnings
|
||||||
|
|
||||||
|
{{- if .Backend.AdditionalParams}}
|
||||||
|
# generated from additional_params
|
||||||
|
{{- range $name, $value := .Backend.AdditionalParams}}
|
||||||
|
{{- if eq $name "addnode"}}
|
||||||
|
{{- range $index, $node := $value}}
|
||||||
|
addnode={{$node}}
|
||||||
|
{{- end}}
|
||||||
|
{{- else}}
|
||||||
|
{{$name}}={{$value}}
|
||||||
|
{{- end}}
|
||||||
|
{{- end}}
|
||||||
|
{{- end}}
|
||||||
|
|
||||||
|
{{if .Backend.Mainnet}}[main]{{else}}[testnet4]{{end}}
|
||||||
|
{{generateRPCAuth .IPC.RPCUser .IPC.RPCPass -}}
|
||||||
|
rpcport={{.Ports.BackendRPC}}
|
||||||
|
|
||||||
|
{{end}}
|
||||||
@ -19,7 +19,7 @@ Type=simple
|
|||||||
{{template "Backend.ServiceAdditionalParamsTemplate" .}}
|
{{template "Backend.ServiceAdditionalParamsTemplate" .}}
|
||||||
|
|
||||||
# Resource limits
|
# Resource limits
|
||||||
LimitNOFILE=500000
|
LimitNOFILE=2000000
|
||||||
|
|
||||||
# Hardening measures
|
# Hardening measures
|
||||||
####################
|
####################
|
||||||
|
|||||||
34
build/templates/backend/scripts/arbitrum.sh
Executable file
34
build/templates/backend/scripts/arbitrum.sh
Executable file
@ -0,0 +1,34 @@
|
|||||||
|
#!/bin/sh
|
||||||
|
|
||||||
|
{{define "main" -}}
|
||||||
|
|
||||||
|
set -e
|
||||||
|
|
||||||
|
INSTALL_DIR={{.Env.BackendInstallPath}}/{{.Coin.Alias}}
|
||||||
|
DATA_DIR={{.Env.BackendDataPath}}/{{.Coin.Alias}}/backend
|
||||||
|
|
||||||
|
NITRO_BIN=$INSTALL_DIR/nitro
|
||||||
|
|
||||||
|
$NITRO_BIN \
|
||||||
|
--chain.name arb1 \
|
||||||
|
--init.latest pruned \
|
||||||
|
--init.download-path $DATA_DIR/tmp \
|
||||||
|
--auth.jwtsecret $DATA_DIR/jwtsecret \
|
||||||
|
--persistent.chain $DATA_DIR \
|
||||||
|
--parent-chain.connection.url http://127.0.0.1:8136 \
|
||||||
|
--parent-chain.blob-client.beacon-url http://127.0.0.1:7536 \
|
||||||
|
--http.addr 127.0.0.1 \
|
||||||
|
--http.port {{.Ports.BackendHttp}} \
|
||||||
|
--http.api eth,net,web3,debug,txpool,arb \
|
||||||
|
--http.vhosts '*' \
|
||||||
|
--http.corsdomain '*' \
|
||||||
|
--ws.addr 127.0.0.1 \
|
||||||
|
--ws.api eth,net,web3,debug,txpool,arb \
|
||||||
|
--ws.port {{.Ports.BackendRPC}} \
|
||||||
|
--ws.origins '*' \
|
||||||
|
--file-logging.enable='false' \
|
||||||
|
--node.staker.enable='false' \
|
||||||
|
--execution.tx-lookup-limit 0 \
|
||||||
|
--validation.wasm.allowed-wasm-module-roots "$INSTALL_DIR/nitro-legacy/machines,$INSTALL_DIR/target/machines"
|
||||||
|
|
||||||
|
{{end}}
|
||||||
35
build/templates/backend/scripts/arbitrum_archive.sh
Executable file
35
build/templates/backend/scripts/arbitrum_archive.sh
Executable file
@ -0,0 +1,35 @@
|
|||||||
|
#!/bin/sh
|
||||||
|
|
||||||
|
{{define "main" -}}
|
||||||
|
|
||||||
|
set -e
|
||||||
|
|
||||||
|
INSTALL_DIR={{.Env.BackendInstallPath}}/{{.Coin.Alias}}
|
||||||
|
DATA_DIR={{.Env.BackendDataPath}}/{{.Coin.Alias}}/backend
|
||||||
|
|
||||||
|
NITRO_BIN=$INSTALL_DIR/nitro
|
||||||
|
|
||||||
|
$NITRO_BIN \
|
||||||
|
--chain.name arb1 \
|
||||||
|
--init.latest archive \
|
||||||
|
--init.download-path $DATA_DIR/tmp \
|
||||||
|
--auth.jwtsecret $DATA_DIR/jwtsecret \
|
||||||
|
--persistent.chain $DATA_DIR \
|
||||||
|
--parent-chain.connection.url http://127.0.0.1:8116 \
|
||||||
|
--parent-chain.blob-client.beacon-url http://127.0.0.1:7516 \
|
||||||
|
--http.addr 127.0.0.1 \
|
||||||
|
--http.port {{.Ports.BackendHttp}} \
|
||||||
|
--http.api eth,net,web3,debug,txpool,arb \
|
||||||
|
--http.vhosts '*' \
|
||||||
|
--http.corsdomain '*' \
|
||||||
|
--ws.addr 127.0.0.1 \
|
||||||
|
--ws.api eth,net,web3,debug,txpool,arb \
|
||||||
|
--ws.port {{.Ports.BackendRPC}} \
|
||||||
|
--ws.origins '*' \
|
||||||
|
--file-logging.enable='false' \
|
||||||
|
--node.staker.enable='false' \
|
||||||
|
--execution.caching.archive \
|
||||||
|
--execution.tx-lookup-limit 0 \
|
||||||
|
--validation.wasm.allowed-wasm-module-roots "$INSTALL_DIR/nitro-legacy/machines,$INSTALL_DIR/target/machines"
|
||||||
|
|
||||||
|
{{end}}
|
||||||
34
build/templates/backend/scripts/arbitrum_nova.sh
Executable file
34
build/templates/backend/scripts/arbitrum_nova.sh
Executable file
@ -0,0 +1,34 @@
|
|||||||
|
#!/bin/sh
|
||||||
|
|
||||||
|
{{define "main" -}}
|
||||||
|
|
||||||
|
set -e
|
||||||
|
|
||||||
|
INSTALL_DIR={{.Env.BackendInstallPath}}/{{.Coin.Alias}}
|
||||||
|
DATA_DIR={{.Env.BackendDataPath}}/{{.Coin.Alias}}/backend
|
||||||
|
|
||||||
|
NITRO_BIN=$INSTALL_DIR/nitro
|
||||||
|
|
||||||
|
$NITRO_BIN \
|
||||||
|
--chain.name nova \
|
||||||
|
--init.latest pruned \
|
||||||
|
--init.download-path $DATA_DIR/tmp \
|
||||||
|
--auth.jwtsecret $DATA_DIR/jwtsecret \
|
||||||
|
--persistent.chain $DATA_DIR \
|
||||||
|
--parent-chain.connection.url http://127.0.0.1:8136 \
|
||||||
|
--parent-chain.blob-client.beacon-url http://127.0.0.1:7536 \
|
||||||
|
--http.addr 127.0.0.1 \
|
||||||
|
--http.port {{.Ports.BackendHttp}} \
|
||||||
|
--http.api eth,net,web3,debug,txpool,arb \
|
||||||
|
--http.vhosts '*' \
|
||||||
|
--http.corsdomain '*' \
|
||||||
|
--ws.addr 127.0.0.1 \
|
||||||
|
--ws.api eth,net,web3,debug,txpool,arb \
|
||||||
|
--ws.port {{.Ports.BackendRPC}} \
|
||||||
|
--ws.origins '*' \
|
||||||
|
--file-logging.enable='false' \
|
||||||
|
--node.staker.enable='false' \
|
||||||
|
--execution.tx-lookup-limit 0 \
|
||||||
|
--validation.wasm.allowed-wasm-module-roots "$INSTALL_DIR/nitro-legacy/machines,$INSTALL_DIR/target/machines"
|
||||||
|
|
||||||
|
{{end}}
|
||||||
35
build/templates/backend/scripts/arbitrum_nova_archive.sh
Executable file
35
build/templates/backend/scripts/arbitrum_nova_archive.sh
Executable file
@ -0,0 +1,35 @@
|
|||||||
|
#!/bin/sh
|
||||||
|
|
||||||
|
{{define "main" -}}
|
||||||
|
|
||||||
|
set -e
|
||||||
|
|
||||||
|
INSTALL_DIR={{.Env.BackendInstallPath}}/{{.Coin.Alias}}
|
||||||
|
DATA_DIR={{.Env.BackendDataPath}}/{{.Coin.Alias}}/backend
|
||||||
|
|
||||||
|
NITRO_BIN=$INSTALL_DIR/nitro
|
||||||
|
|
||||||
|
$NITRO_BIN \
|
||||||
|
--chain.name nova \
|
||||||
|
--init.latest archive \
|
||||||
|
--init.download-path $DATA_DIR/tmp \
|
||||||
|
--auth.jwtsecret $DATA_DIR/jwtsecret \
|
||||||
|
--persistent.chain $DATA_DIR \
|
||||||
|
--parent-chain.connection.url http://127.0.0.1:8116 \
|
||||||
|
--parent-chain.blob-client.beacon-url http://127.0.0.1:7516 \
|
||||||
|
--http.addr 127.0.0.1 \
|
||||||
|
--http.port {{.Ports.BackendHttp}} \
|
||||||
|
--http.api eth,net,web3,debug,txpool,arb \
|
||||||
|
--http.vhosts '*' \
|
||||||
|
--http.corsdomain '*' \
|
||||||
|
--ws.addr 127.0.0.1 \
|
||||||
|
--ws.api eth,net,web3,debug,txpool,arb \
|
||||||
|
--ws.port {{.Ports.BackendRPC}} \
|
||||||
|
--ws.origins '*' \
|
||||||
|
--file-logging.enable='false' \
|
||||||
|
--node.staker.enable='false' \
|
||||||
|
--execution.caching.archive \
|
||||||
|
--execution.tx-lookup-limit 0 \
|
||||||
|
--validation.wasm.allowed-wasm-module-roots "$INSTALL_DIR/nitro-legacy/machines,$INSTALL_DIR/target/machines"
|
||||||
|
|
||||||
|
{{end}}
|
||||||
44
build/templates/backend/scripts/optimism.sh
Normal file
44
build/templates/backend/scripts/optimism.sh
Normal file
@ -0,0 +1,44 @@
|
|||||||
|
#!/bin/sh
|
||||||
|
|
||||||
|
{{define "main" -}}
|
||||||
|
|
||||||
|
set -e
|
||||||
|
|
||||||
|
GETH_BIN={{.Env.BackendInstallPath}}/{{.Coin.Alias}}/geth
|
||||||
|
DATA_DIR={{.Env.BackendDataPath}}/{{.Coin.Alias}}/backend
|
||||||
|
|
||||||
|
CHAINDATA_DIR=$DATA_DIR/geth/chaindata
|
||||||
|
SNAPSHOT=https://r2-snapshots.fastnode.io/op/$(curl -s https://r2-snapshots.fastnode.io/op/latest-mainnet)
|
||||||
|
|
||||||
|
if [ ! -d "$CHAINDATA_DIR" ]; then
|
||||||
|
wget -c $SNAPSHOT -O - | lz4 -cd | tar xf - -C $DATA_DIR
|
||||||
|
fi
|
||||||
|
|
||||||
|
$GETH_BIN \
|
||||||
|
--op-network op-mainnet \
|
||||||
|
--datadir $DATA_DIR \
|
||||||
|
--authrpc.jwtsecret $DATA_DIR/jwtsecret \
|
||||||
|
--authrpc.addr 127.0.0.1 \
|
||||||
|
--authrpc.port {{.Ports.BackendAuthRpc}} \
|
||||||
|
--authrpc.vhosts "*" \
|
||||||
|
--port {{.Ports.BackendP2P}} \
|
||||||
|
--http \
|
||||||
|
--http.port {{.Ports.BackendHttp}} \
|
||||||
|
--http.addr 127.0.0.1 \
|
||||||
|
--http.api eth,net,web3,debug,txpool,engine \
|
||||||
|
--http.vhosts "*" \
|
||||||
|
--http.corsdomain "*" \
|
||||||
|
--ws \
|
||||||
|
--ws.port {{.Ports.BackendRPC}} \
|
||||||
|
--ws.addr 127.0.0.1 \
|
||||||
|
--ws.api eth,net,web3,debug,txpool,engine \
|
||||||
|
--ws.origins "*" \
|
||||||
|
--rollup.disabletxpoolgossip=true \
|
||||||
|
--rollup.sequencerhttp https://mainnet-sequencer.optimism.io \
|
||||||
|
--txlookuplimit 0 \
|
||||||
|
--cache 4096 \
|
||||||
|
--syncmode full \
|
||||||
|
--maxpeers 0 \
|
||||||
|
--nodiscover
|
||||||
|
|
||||||
|
{{end}}
|
||||||
48
build/templates/backend/scripts/optimism_archive.sh
Normal file
48
build/templates/backend/scripts/optimism_archive.sh
Normal file
@ -0,0 +1,48 @@
|
|||||||
|
#!/bin/sh
|
||||||
|
|
||||||
|
{{define "main" -}}
|
||||||
|
|
||||||
|
set -e
|
||||||
|
|
||||||
|
GETH_BIN={{.Env.BackendInstallPath}}/{{.Coin.Alias}}/geth
|
||||||
|
DATA_DIR={{.Env.BackendDataPath}}/{{.Coin.Alias}}/backend
|
||||||
|
|
||||||
|
CHAINDATA_DIR=$DATA_DIR/geth/chaindata
|
||||||
|
SNAPSHOT=https://datadirs.optimism.io/latest
|
||||||
|
|
||||||
|
if [ ! -d "$CHAINDATA_DIR" ]; then
|
||||||
|
wget -c $(curl -sL $SNAPSHOT | grep -oP '(?<=url=)[^"]*') -O - | zstd -cd | tar xf - -C $DATA_DIR
|
||||||
|
fi
|
||||||
|
|
||||||
|
$GETH_BIN \
|
||||||
|
--op-network op-mainnet \
|
||||||
|
--datadir $DATA_DIR \
|
||||||
|
--authrpc.jwtsecret $DATA_DIR/jwtsecret \
|
||||||
|
--authrpc.addr 127.0.0.1 \
|
||||||
|
--authrpc.port {{.Ports.BackendAuthRpc}} \
|
||||||
|
--authrpc.vhosts "*" \
|
||||||
|
--port {{.Ports.BackendP2P}} \
|
||||||
|
--http \
|
||||||
|
--http.port {{.Ports.BackendHttp}} \
|
||||||
|
--http.addr 127.0.0.1 \
|
||||||
|
--http.api eth,net,web3,debug,txpool,engine \
|
||||||
|
--http.vhosts "*" \
|
||||||
|
--http.corsdomain "*" \
|
||||||
|
--ws \
|
||||||
|
--ws.port {{.Ports.BackendRPC}} \
|
||||||
|
--ws.addr 127.0.0.1 \
|
||||||
|
--ws.api eth,net,web3,debug,txpool,engine \
|
||||||
|
--ws.origins "*" \
|
||||||
|
--rollup.disabletxpoolgossip=true \
|
||||||
|
--rollup.historicalrpc http://127.0.0.1:8304 \
|
||||||
|
--rollup.sequencerhttp https://mainnet.sequencer.optimism.io \
|
||||||
|
--cache 4096 \
|
||||||
|
--cache.gc 0 \
|
||||||
|
--cache.trie 30 \
|
||||||
|
--cache.snapshot 20 \
|
||||||
|
--syncmode full \
|
||||||
|
--gcmode archive \
|
||||||
|
--maxpeers 0 \
|
||||||
|
--nodiscover
|
||||||
|
|
||||||
|
{{end}}
|
||||||
@ -0,0 +1,40 @@
|
|||||||
|
#!/bin/sh
|
||||||
|
|
||||||
|
{{define "main" -}}
|
||||||
|
|
||||||
|
set -e
|
||||||
|
|
||||||
|
export USING_OVM=true
|
||||||
|
export ETH1_SYNC_SERVICE_ENABLE=false
|
||||||
|
|
||||||
|
GETH_BIN={{.Env.BackendInstallPath}}/{{.Coin.Alias}}/geth
|
||||||
|
DATA_DIR={{.Env.BackendDataPath}}/{{.Coin.Alias}}/backend
|
||||||
|
|
||||||
|
CHAINDATA_DIR=$DATA_DIR/geth/chaindata
|
||||||
|
SNAPSHOT=https://datadirs.optimism.io/mainnet-legacy-archival.tar.zst
|
||||||
|
|
||||||
|
if [ ! -d "$CHAINDATA_DIR" ]; then
|
||||||
|
wget -c $SNAPSHOT -O - | zstd -cd | tar xf - -C $DATA_DIR
|
||||||
|
fi
|
||||||
|
|
||||||
|
$GETH_BIN \
|
||||||
|
--networkid 10 \
|
||||||
|
--datadir $DATA_DIR \
|
||||||
|
--port {{.Ports.BackendP2P}} \
|
||||||
|
--rpc \
|
||||||
|
--rpcport {{.Ports.BackendHttp}} \
|
||||||
|
--rpcaddr 127.0.0.1 \
|
||||||
|
--rpcapi eth,rollup,net,web3,debug \
|
||||||
|
--rpcvhosts "*" \
|
||||||
|
--rpccorsdomain "*" \
|
||||||
|
--ws \
|
||||||
|
--wsport {{.Ports.BackendRPC}} \
|
||||||
|
--wsaddr 0.0.0.0 \
|
||||||
|
--wsapi eth,rollup,net,web3,debug \
|
||||||
|
--wsorigins "*" \
|
||||||
|
--nousb \
|
||||||
|
--ipcdisable \
|
||||||
|
--nat=none \
|
||||||
|
--nodiscover
|
||||||
|
|
||||||
|
{{end}}
|
||||||
24
build/templates/backend/scripts/optimism_archive_op_node.sh
Normal file
24
build/templates/backend/scripts/optimism_archive_op_node.sh
Normal file
@ -0,0 +1,24 @@
|
|||||||
|
#!/bin/sh
|
||||||
|
|
||||||
|
{{define "main" -}}
|
||||||
|
|
||||||
|
set -e
|
||||||
|
|
||||||
|
BIN={{.Env.BackendInstallPath}}/{{.Coin.Alias}}/op-node
|
||||||
|
PATH={{.Env.BackendDataPath}}/{{.Coin.Alias}}/backend
|
||||||
|
|
||||||
|
$BIN \
|
||||||
|
--network op-mainnet \
|
||||||
|
--l1 http://127.0.0.1:8116 \
|
||||||
|
--l1.beacon http://127.0.0.1:7516 \
|
||||||
|
--l1.trustrpc \
|
||||||
|
--l1.rpckind=debug_geth \
|
||||||
|
--l2 http://127.0.0.1:8402 \
|
||||||
|
--rpc.addr 127.0.0.1 \
|
||||||
|
--rpc.port {{.Ports.BackendRPC}} \
|
||||||
|
--l2.jwt-secret {{.Env.BackendDataPath}}/optimism_archive/backend/jwtsecret \
|
||||||
|
--p2p.priv.path $PATH/opnode_p2p_priv.txt \
|
||||||
|
--p2p.peerstore.path $PATH/opnode_peerstore_db \
|
||||||
|
--p2p.discovery.path $PATH/opnode_discovery_db
|
||||||
|
|
||||||
|
{{end}}
|
||||||
24
build/templates/backend/scripts/optimism_op_node.sh
Normal file
24
build/templates/backend/scripts/optimism_op_node.sh
Normal file
@ -0,0 +1,24 @@
|
|||||||
|
#!/bin/sh
|
||||||
|
|
||||||
|
{{define "main" -}}
|
||||||
|
|
||||||
|
set -e
|
||||||
|
|
||||||
|
BIN={{.Env.BackendInstallPath}}/{{.Coin.Alias}}/op-node
|
||||||
|
PATH={{.Env.BackendDataPath}}/{{.Coin.Alias}}/backend
|
||||||
|
|
||||||
|
$BIN \
|
||||||
|
--network op-mainnet \
|
||||||
|
--l1 http://127.0.0.1:8136 \
|
||||||
|
--l1.beacon http://127.0.0.1:7536 \
|
||||||
|
--l1.trustrpc \
|
||||||
|
--l1.rpckind=debug_geth \
|
||||||
|
--l2 http://127.0.0.1:8400 \
|
||||||
|
--rpc.addr 127.0.0.1 \
|
||||||
|
--rpc.port {{.Ports.BackendRPC}} \
|
||||||
|
--l2.jwt-secret {{.Env.BackendDataPath}}/optimism/backend/jwtsecret \
|
||||||
|
--p2p.priv.path $PATH/opnode_p2p_priv.txt \
|
||||||
|
--p2p.peerstore.path $PATH/opnode_peerstore_db \
|
||||||
|
--p2p.discovery.path $PATH/opnode_discovery_db
|
||||||
|
|
||||||
|
{{end}}
|
||||||
35
build/templates/backend/scripts/polygon_archive_bor.sh
Normal file
35
build/templates/backend/scripts/polygon_archive_bor.sh
Normal file
@ -0,0 +1,35 @@
|
|||||||
|
#!/bin/sh
|
||||||
|
|
||||||
|
{{define "main" -}}
|
||||||
|
|
||||||
|
set -e
|
||||||
|
|
||||||
|
INSTALL_DIR={{.Env.BackendInstallPath}}/{{.Coin.Alias}}
|
||||||
|
DATA_DIR={{.Env.BackendDataPath}}/{{.Coin.Alias}}/backend
|
||||||
|
|
||||||
|
BOR_BIN=$INSTALL_DIR/bor
|
||||||
|
|
||||||
|
# --bor.heimdall = backend-polygon-heimdall-archive ports.backend_http
|
||||||
|
$BOR_BIN server \
|
||||||
|
--chain $INSTALL_DIR/genesis.json \
|
||||||
|
--syncmode full \
|
||||||
|
--datadir $DATA_DIR \
|
||||||
|
--bor.heimdall http://127.0.0.1:8173 \
|
||||||
|
--maxpeers 200 \
|
||||||
|
--bootnodes enode://76316d1cb93c8ed407d3332d595233401250d48f8fbb1d9c65bd18c0495eca1b43ec38ee0ea1c257c0abb7d1f25d649d359cdfe5a805842159cfe36c5f66b7e8@52.78.36.216:30303,enode://b8f1cc9c5d4403703fbf377116469667d2b1823c0daf16b7250aa576bacf399e42c3930ccfcb02c5df6879565a2b8931335565f0e8d3f8e72385ecf4a4bf160a@3.36.224.80:30303,enode://8729e0c825f3d9cad382555f3e46dcff21af323e89025a0e6312df541f4a9e73abfa562d64906f5e59c51fe6f0501b3e61b07979606c56329c020ed739910759@54.194.245.5:30303,enode://681ebac58d8dd2d8a6eef15329dfbad0ab960561524cf2dfde40ad646736fe5c244020f20b87e7c1520820bc625cfb487dd71d63a3a3bf0baea2dbb8ec7c79f1@34.240.245.39:30303,enode://93faa5d49ba61fa03f43f7e3c76907a9c72953e8628650eef09f5bddc646d9012916824cdd60da989fd954a852205df9a1fd9661379504c92e103a1ada4c2ceb@148.251.142.52:30314,enode://91f6d9873ee2ceee27b4054ec70844e21fa7c525e8d820d6a09989473f4f883951da75a09ef098d544c0c8a71e9ddd2e649e5b455b137260ba8657b2f96cad2c@178.63.148.12:30308,enode://2776f6f0d1c1e4dfddeb9a4b1c3b1a8777fbb3054b92fc55b405d35603667e974e9cad4408f1036cfc17af03dd1a6270c5cb40f854b94760474516b2d8c0f185@88.198.101.172:30308,enode://157321664e79855ee0f914fd05b21cc29ae3a7e805114d1c26efa1d4d2781f5d5bc4e76ed9d00f26d6138f80cc84ea183894c390fcb0e07100a845aed02f6f40@136.243.210.177:30303,enode://6a5e65c6ef3356bc79a780cf0c7534c299fb8cd7b37db80155830478c1e29d35336fe52a888efdf53c0e9bb9b94e20b5349d68798860f1cf36ae96da2b3826cc@178.63.247.234:30304,enode://d6da5ad18e51d492481b29443bd0f588b59d3f72f0da43a722b07fe2a9223a717c976a1cfe00ad86c557756b2bf297ea56c64a1f3d09bebcb9b81290689d8e33@178.63.197.250:30320,enode://51cbc8b750e28d5a4f250d141c032cf282ea873eb1c533c5156cfc51e6a5117d465b7b39b4e0088ee597ee87b89e06cc6c1ed5e6e050b1c3f638765ee584c4f4@178.63.163.68:30310,enode://6484d4394215c222257c97ac74fdcd6f77ecf00e896c38ef35cc41a44add96da64649139b37cc094e88bb985eb84b04d4c6c78f86bf205c9e112c31254cdc443@54.38.217.112:30303?discport=30346,enode://eb3b67d68daef47badfa683c8b04a1cba6a7c431613b8d7619a013aad38bd8d405eb1d0e41279b4f6fe15b264bd388e88282a77a908247b2d1e0198bd4def57b@148.251.224.230:30315,enode://aa228d96217dd91564e13536f3c2808d2040115c7c50509f26f836275e8e65d1bf9400bce3294760be18c9e00a4bf47026e661ba8d8ce1cf2ced30f0a70e5da8@89.187.163.132:30303?discport=30356,enode://c10ab147ba266a80f34dbc423cd12689434cb2cc1f18ced8f4e5828e23d6943a666c2db0f8464983ccc95666b36099b513d1e45d5df94139e42fbecde25832fa@87.249.137.89:30303?discport=30436,enode://e68049c37b182a36c8913fc0780aea5196c1841c917cbd76f83f1a3a8ae99fcfbd2dfa44e36081668120354439008fe4325ffc0d0176771ec2c1863033d4769e@65.108.199.236:30303,enode://a4c74da28447bacd2b3e8443d0917cca7798bca39dbb48b0e210f0fb6685538ba9d1608a2493424086363f04be5e6a99e6eabb70946ed503448d6b282056f87a@198.244.213.85:30303?discport=30315,enode://e28fce95f52cf3368b7b624c6f83379dec858fcebf6a7ff07e97aa9b9445736a165bf1c51cad7bdf6e3167e2b00b11c7911fc330dabb484998d899a1b01d75cf@148.251.194.252:30303?discport=30892,enode://412fdb01125f6868a188f472cf15f07c8f93d606395b909dd5010f2a4a2702739102cea18abb6437fbacd12e695982a77f28edd9bbdd36635b04e9b3c2948f8d@34.203.27.246:30303?discport=30388,enode://9703d9591cb1013b4fa6ea889e8effe7579aa59c324a6e019d690a13e108ef9b4419698347e4305f05291e644a713518a91b0fc32a3442c1394619e2a9b8251e@79.127.216.33:30303?discport=30349 \
|
||||||
|
--port {{.Ports.BackendP2P}} \
|
||||||
|
--http \
|
||||||
|
--http.addr 0.0.0.0 \
|
||||||
|
--http.port {{.Ports.BackendHttp}} \
|
||||||
|
--http.api eth,net,web3,debug,txpool,bor \
|
||||||
|
--http.vhosts '*' \
|
||||||
|
--http.corsdomain '*' \
|
||||||
|
--ws \
|
||||||
|
--ws.addr 0.0.0.0 \
|
||||||
|
--ws.port {{.Ports.BackendRPC}} \
|
||||||
|
--ws.api eth,net,web3,debug,txpool,bor \
|
||||||
|
--ws.origins '*' \
|
||||||
|
--gcmode archive \
|
||||||
|
--txlookuplimit 0 \
|
||||||
|
--cache 4096
|
||||||
|
{{end}}
|
||||||
36
build/templates/backend/scripts/polygon_archive_heimdall.sh
Normal file
36
build/templates/backend/scripts/polygon_archive_heimdall.sh
Normal file
@ -0,0 +1,36 @@
|
|||||||
|
#!/bin/sh
|
||||||
|
|
||||||
|
{{define "main" -}}
|
||||||
|
|
||||||
|
set -e
|
||||||
|
|
||||||
|
INSTALL_DIR={{.Env.BackendInstallPath}}/{{.Coin.Alias}}
|
||||||
|
DATA_DIR={{.Env.BackendDataPath}}/{{.Coin.Alias}}/backend
|
||||||
|
|
||||||
|
HEIMDALL_BIN=$INSTALL_DIR/heimdalld
|
||||||
|
HOME_DIR=$DATA_DIR/heimdalld
|
||||||
|
CONFIG_DIR=$HOME_DIR/config
|
||||||
|
|
||||||
|
if [ ! -d "$CONFIG_DIR" ]; then
|
||||||
|
# init chain
|
||||||
|
$HEIMDALL_BIN init --home $HOME_DIR
|
||||||
|
|
||||||
|
# overwrite genesis file
|
||||||
|
cp $INSTALL_DIR/genesis.json $CONFIG_DIR/genesis.json
|
||||||
|
fi
|
||||||
|
|
||||||
|
# --bor_rpc_url: backend-polygon-bor-archive ports.backend_http
|
||||||
|
# --eth_rpc_url: backend-ethereum-archive ports.backend_http
|
||||||
|
$HEIMDALL_BIN start \
|
||||||
|
--home $HOME_DIR \
|
||||||
|
--chain=mainnet \
|
||||||
|
--rpc.laddr tcp://127.0.0.1:{{.Ports.BackendRPC}} \
|
||||||
|
--p2p.laddr tcp://0.0.0.0:{{.Ports.BackendP2P}} \
|
||||||
|
--laddr tcp://127.0.0.1:{{.Ports.BackendHttp}} \
|
||||||
|
--p2p.seeds "f4f605d60b8ffaaf15240564e58a81103510631c@159.203.9.164:26656,4fb1bc820088764a564d4f66bba1963d47d82329@44.232.55.71:26656,2eadba4be3ce47ac8db0a3538cb923b57b41c927@35.199.4.13:26656,3b23b20017a6f348d329c102ddc0088f0a10a444@35.221.13.28:26656,25f5f65a09c56e9f1d2d90618aa70cd358aa68da@35.230.116.151:26656,4cd60c1d76e44b05f7dfd8bab3f447b119e87042@54.147.31.250:26656,b18bbe1f3d8576f4b73d9b18976e71c65e839149@34.226.134.117:26656,1500161dd491b67fb1ac81868952be49e2509c9f@52.78.36.216:26656,dd4a3f1750af5765266231b9d8ac764599921736@3.36.224.80:26656,8ea4f592ad6cc38d7532aff418d1fb97052463af@34.240.245.39:26656,e772e1fb8c3492a9570a377a5eafdb1dc53cd778@54.194.245.5:26656,6726b826df45ac8e9afb4bdb2469c7771bd797f1@52.209.21.164:26656" \
|
||||||
|
--node tcp://127.0.0.1:{{.Ports.BackendRPC}} \
|
||||||
|
--bor_rpc_url http://127.0.0.1:8172 \
|
||||||
|
--eth_rpc_url http://127.0.0.1:8116 \
|
||||||
|
--rest-server
|
||||||
|
|
||||||
|
{{end}}
|
||||||
35
build/templates/backend/scripts/polygon_bor.sh
Normal file
35
build/templates/backend/scripts/polygon_bor.sh
Normal file
@ -0,0 +1,35 @@
|
|||||||
|
#!/bin/sh
|
||||||
|
|
||||||
|
{{define "main" -}}
|
||||||
|
|
||||||
|
set -e
|
||||||
|
|
||||||
|
INSTALL_DIR={{.Env.BackendInstallPath}}/{{.Coin.Alias}}
|
||||||
|
DATA_DIR={{.Env.BackendDataPath}}/{{.Coin.Alias}}/backend
|
||||||
|
|
||||||
|
BOR_BIN=$INSTALL_DIR/bor
|
||||||
|
|
||||||
|
# --bor.heimdall = backend-polygon-heimdall ports.backend_http
|
||||||
|
$BOR_BIN server \
|
||||||
|
--chain $INSTALL_DIR/genesis.json \
|
||||||
|
--syncmode full \
|
||||||
|
--datadir $DATA_DIR \
|
||||||
|
--bor.heimdall http://127.0.0.1:8171 \
|
||||||
|
--maxpeers 200 \
|
||||||
|
--bootnodes enode://76316d1cb93c8ed407d3332d595233401250d48f8fbb1d9c65bd18c0495eca1b43ec38ee0ea1c257c0abb7d1f25d649d359cdfe5a805842159cfe36c5f66b7e8@52.78.36.216:30303,enode://b8f1cc9c5d4403703fbf377116469667d2b1823c0daf16b7250aa576bacf399e42c3930ccfcb02c5df6879565a2b8931335565f0e8d3f8e72385ecf4a4bf160a@3.36.224.80:30303,enode://8729e0c825f3d9cad382555f3e46dcff21af323e89025a0e6312df541f4a9e73abfa562d64906f5e59c51fe6f0501b3e61b07979606c56329c020ed739910759@54.194.245.5:30303,enode://681ebac58d8dd2d8a6eef15329dfbad0ab960561524cf2dfde40ad646736fe5c244020f20b87e7c1520820bc625cfb487dd71d63a3a3bf0baea2dbb8ec7c79f1@34.240.245.39:30303,enode://93faa5d49ba61fa03f43f7e3c76907a9c72953e8628650eef09f5bddc646d9012916824cdd60da989fd954a852205df9a1fd9661379504c92e103a1ada4c2ceb@148.251.142.52:30314,enode://91f6d9873ee2ceee27b4054ec70844e21fa7c525e8d820d6a09989473f4f883951da75a09ef098d544c0c8a71e9ddd2e649e5b455b137260ba8657b2f96cad2c@178.63.148.12:30308,enode://2776f6f0d1c1e4dfddeb9a4b1c3b1a8777fbb3054b92fc55b405d35603667e974e9cad4408f1036cfc17af03dd1a6270c5cb40f854b94760474516b2d8c0f185@88.198.101.172:30308,enode://157321664e79855ee0f914fd05b21cc29ae3a7e805114d1c26efa1d4d2781f5d5bc4e76ed9d00f26d6138f80cc84ea183894c390fcb0e07100a845aed02f6f40@136.243.210.177:30303,enode://6a5e65c6ef3356bc79a780cf0c7534c299fb8cd7b37db80155830478c1e29d35336fe52a888efdf53c0e9bb9b94e20b5349d68798860f1cf36ae96da2b3826cc@178.63.247.234:30304,enode://d6da5ad18e51d492481b29443bd0f588b59d3f72f0da43a722b07fe2a9223a717c976a1cfe00ad86c557756b2bf297ea56c64a1f3d09bebcb9b81290689d8e33@178.63.197.250:30320,enode://51cbc8b750e28d5a4f250d141c032cf282ea873eb1c533c5156cfc51e6a5117d465b7b39b4e0088ee597ee87b89e06cc6c1ed5e6e050b1c3f638765ee584c4f4@178.63.163.68:30310,enode://6484d4394215c222257c97ac74fdcd6f77ecf00e896c38ef35cc41a44add96da64649139b37cc094e88bb985eb84b04d4c6c78f86bf205c9e112c31254cdc443@54.38.217.112:30303?discport=30346,enode://eb3b67d68daef47badfa683c8b04a1cba6a7c431613b8d7619a013aad38bd8d405eb1d0e41279b4f6fe15b264bd388e88282a77a908247b2d1e0198bd4def57b@148.251.224.230:30315,enode://aa228d96217dd91564e13536f3c2808d2040115c7c50509f26f836275e8e65d1bf9400bce3294760be18c9e00a4bf47026e661ba8d8ce1cf2ced30f0a70e5da8@89.187.163.132:30303?discport=30356,enode://c10ab147ba266a80f34dbc423cd12689434cb2cc1f18ced8f4e5828e23d6943a666c2db0f8464983ccc95666b36099b513d1e45d5df94139e42fbecde25832fa@87.249.137.89:30303?discport=30436,enode://e68049c37b182a36c8913fc0780aea5196c1841c917cbd76f83f1a3a8ae99fcfbd2dfa44e36081668120354439008fe4325ffc0d0176771ec2c1863033d4769e@65.108.199.236:30303,enode://a4c74da28447bacd2b3e8443d0917cca7798bca39dbb48b0e210f0fb6685538ba9d1608a2493424086363f04be5e6a99e6eabb70946ed503448d6b282056f87a@198.244.213.85:30303?discport=30315,enode://e28fce95f52cf3368b7b624c6f83379dec858fcebf6a7ff07e97aa9b9445736a165bf1c51cad7bdf6e3167e2b00b11c7911fc330dabb484998d899a1b01d75cf@148.251.194.252:30303?discport=30892,enode://412fdb01125f6868a188f472cf15f07c8f93d606395b909dd5010f2a4a2702739102cea18abb6437fbacd12e695982a77f28edd9bbdd36635b04e9b3c2948f8d@34.203.27.246:30303?discport=30388,enode://9703d9591cb1013b4fa6ea889e8effe7579aa59c324a6e019d690a13e108ef9b4419698347e4305f05291e644a713518a91b0fc32a3442c1394619e2a9b8251e@79.127.216.33:30303?discport=30349 \
|
||||||
|
--port {{.Ports.BackendP2P}} \
|
||||||
|
--http \
|
||||||
|
--http.addr 127.0.0.1 \
|
||||||
|
--http.port {{.Ports.BackendHttp}} \
|
||||||
|
--http.api eth,net,web3,debug,txpool,bor \
|
||||||
|
--http.vhosts '*' \
|
||||||
|
--http.corsdomain '*' \
|
||||||
|
--ws \
|
||||||
|
--ws.addr 127.0.0.1 \
|
||||||
|
--ws.port {{.Ports.BackendRPC}} \
|
||||||
|
--ws.api eth,net,web3,debug,txpool,bor \
|
||||||
|
--ws.origins '*' \
|
||||||
|
--txlookuplimit 0 \
|
||||||
|
--cache 4096
|
||||||
|
|
||||||
|
{{end}}
|
||||||
36
build/templates/backend/scripts/polygon_heimdall.sh
Normal file
36
build/templates/backend/scripts/polygon_heimdall.sh
Normal file
@ -0,0 +1,36 @@
|
|||||||
|
#!/bin/sh
|
||||||
|
|
||||||
|
{{define "main" -}}
|
||||||
|
|
||||||
|
set -e
|
||||||
|
|
||||||
|
INSTALL_DIR={{.Env.BackendInstallPath}}/{{.Coin.Alias}}
|
||||||
|
DATA_DIR={{.Env.BackendDataPath}}/{{.Coin.Alias}}/backend
|
||||||
|
|
||||||
|
HEIMDALL_BIN=$INSTALL_DIR/heimdalld
|
||||||
|
HOME_DIR=$DATA_DIR/heimdalld
|
||||||
|
CONFIG_DIR=$HOME_DIR/config
|
||||||
|
|
||||||
|
if [ ! -d "$CONFIG_DIR" ]; then
|
||||||
|
# init chain
|
||||||
|
$HEIMDALL_BIN init --home $HOME_DIR
|
||||||
|
|
||||||
|
# overwrite genesis file
|
||||||
|
cp $INSTALL_DIR/genesis.json $CONFIG_DIR/genesis.json
|
||||||
|
fi
|
||||||
|
|
||||||
|
# --bor_rpc_url: backend-polygon-bor ports.backend_http
|
||||||
|
# --eth_rpc_url: backend-ethereum ports.backend_http
|
||||||
|
$HEIMDALL_BIN start \
|
||||||
|
--home $HOME_DIR \
|
||||||
|
--chain=mainnet \
|
||||||
|
--rpc.laddr tcp://127.0.0.1:{{.Ports.BackendRPC}} \
|
||||||
|
--p2p.laddr tcp://0.0.0.0:{{.Ports.BackendP2P}} \
|
||||||
|
--laddr tcp://127.0.0.1:{{.Ports.BackendHttp}} \
|
||||||
|
--p2p.seeds "f4f605d60b8ffaaf15240564e58a81103510631c@159.203.9.164:26656,4fb1bc820088764a564d4f66bba1963d47d82329@44.232.55.71:26656,2eadba4be3ce47ac8db0a3538cb923b57b41c927@35.199.4.13:26656,3b23b20017a6f348d329c102ddc0088f0a10a444@35.221.13.28:26656,25f5f65a09c56e9f1d2d90618aa70cd358aa68da@35.230.116.151:26656,4cd60c1d76e44b05f7dfd8bab3f447b119e87042@54.147.31.250:26656,b18bbe1f3d8576f4b73d9b18976e71c65e839149@34.226.134.117:26656,1500161dd491b67fb1ac81868952be49e2509c9f@52.78.36.216:26656,dd4a3f1750af5765266231b9d8ac764599921736@3.36.224.80:26656,8ea4f592ad6cc38d7532aff418d1fb97052463af@34.240.245.39:26656,e772e1fb8c3492a9570a377a5eafdb1dc53cd778@54.194.245.5:26656,6726b826df45ac8e9afb4bdb2469c7771bd797f1@52.209.21.164:26656" \
|
||||||
|
--node tcp://127.0.0.1:{{.Ports.BackendRPC}} \
|
||||||
|
--bor_rpc_url http://127.0.0.1:8170 \
|
||||||
|
--eth_rpc_url http://127.0.0.1:8136 \
|
||||||
|
--rest-server
|
||||||
|
|
||||||
|
{{end}}
|
||||||
@ -7,6 +7,8 @@
|
|||||||
{{end}}
|
{{end}}
|
||||||
"coin_name": "{{.Coin.Name}}",
|
"coin_name": "{{.Coin.Name}}",
|
||||||
"coin_shortcut": "{{.Coin.Shortcut}}",
|
"coin_shortcut": "{{.Coin.Shortcut}}",
|
||||||
|
{{- if .Coin.Network}}
|
||||||
|
"network": "{{.Coin.Network}}",{{end}}
|
||||||
"coin_label": "{{.Coin.Label}}",
|
"coin_label": "{{.Coin.Label}}",
|
||||||
"rpc_url": "{{template "IPC.RPCURLTemplate" .}}",
|
"rpc_url": "{{template "IPC.RPCURLTemplate" .}}",
|
||||||
"rpc_user": "{{.IPC.RPCUser}}",
|
"rpc_user": "{{.IPC.RPCUser}}",
|
||||||
|
|||||||
@ -21,6 +21,7 @@ type Backend struct {
|
|||||||
SystemUser string `json:"system_user"`
|
SystemUser string `json:"system_user"`
|
||||||
Version string `json:"version"`
|
Version string `json:"version"`
|
||||||
BinaryURL string `json:"binary_url"`
|
BinaryURL string `json:"binary_url"`
|
||||||
|
DockerImage string `json:"docker_image"`
|
||||||
VerificationType string `json:"verification_type"`
|
VerificationType string `json:"verification_type"`
|
||||||
VerificationSource string `json:"verification_source"`
|
VerificationSource string `json:"verification_source"`
|
||||||
ExtractCommand string `json:"extract_command"`
|
ExtractCommand string `json:"extract_command"`
|
||||||
@ -44,6 +45,7 @@ type Config struct {
|
|||||||
Coin struct {
|
Coin struct {
|
||||||
Name string `json:"name"`
|
Name string `json:"name"`
|
||||||
Shortcut string `json:"shortcut"`
|
Shortcut string `json:"shortcut"`
|
||||||
|
Network string `json:"network,omitempty"`
|
||||||
Label string `json:"label"`
|
Label string `json:"label"`
|
||||||
Alias string `json:"alias"`
|
Alias string `json:"alias"`
|
||||||
} `json:"coin"`
|
} `json:"coin"`
|
||||||
@ -203,6 +205,7 @@ func LoadConfig(configsDir, coin string) (*Config, error) {
|
|||||||
case "gpg":
|
case "gpg":
|
||||||
case "sha256":
|
case "sha256":
|
||||||
case "gpg-sha256":
|
case "gpg-sha256":
|
||||||
|
case "docker":
|
||||||
default:
|
default:
|
||||||
return nil, fmt.Errorf("Invalid verification type: %s", config.Backend.VerificationType)
|
return nil, fmt.Errorf("Invalid verification type: %s", config.Backend.VerificationType)
|
||||||
}
|
}
|
||||||
|
|||||||
@ -1,4 +1,4 @@
|
|||||||
//usr/bin/go run $0 $@ ; exit
|
// usr/bin/go run $0 $@ ; exit
|
||||||
package main
|
package main
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
|||||||
@ -45,6 +45,8 @@ func main() {
|
|||||||
t.Add(server.WsBlockHashReq{})
|
t.Add(server.WsBlockHashReq{})
|
||||||
t.Add(server.WsBlockHashRes{})
|
t.Add(server.WsBlockHashRes{})
|
||||||
t.Add(server.WsBlockReq{})
|
t.Add(server.WsBlockReq{})
|
||||||
|
t.Add(server.WsBlockFilterReq{})
|
||||||
|
t.Add(server.WsBlockFiltersBatchReq{})
|
||||||
t.Add(server.WsAccountUtxoReq{})
|
t.Add(server.WsAccountUtxoReq{})
|
||||||
t.Add(server.WsBalanceHistoryReq{})
|
t.Add(server.WsBalanceHistoryReq{})
|
||||||
t.Add(server.WsTransactionReq{})
|
t.Add(server.WsTransactionReq{})
|
||||||
@ -58,6 +60,8 @@ func main() {
|
|||||||
t.Add(server.WsFiatRatesForTimestampsReq{})
|
t.Add(server.WsFiatRatesForTimestampsReq{})
|
||||||
t.Add(server.WsFiatRatesTickersListReq{})
|
t.Add(server.WsFiatRatesTickersListReq{})
|
||||||
t.Add(server.WsMempoolFiltersReq{})
|
t.Add(server.WsMempoolFiltersReq{})
|
||||||
|
t.Add(server.WsRpcCallReq{})
|
||||||
|
t.Add(server.WsRpcCallRes{})
|
||||||
t.Add(bchain.MempoolTxidFilterEntries{})
|
t.Add(bchain.MempoolTxidFilterEntries{})
|
||||||
|
|
||||||
err := t.ConvertToFile("blockbook-api.ts")
|
err := t.ConvertToFile("blockbook-api.ts")
|
||||||
|
|||||||
42
common/config.go
Normal file
42
common/config.go
Normal file
@ -0,0 +1,42 @@
|
|||||||
|
package common
|
||||||
|
|
||||||
|
import (
|
||||||
|
"encoding/json"
|
||||||
|
"os"
|
||||||
|
|
||||||
|
"github.com/juju/errors"
|
||||||
|
)
|
||||||
|
|
||||||
|
// Config struct
|
||||||
|
type Config struct {
|
||||||
|
CoinName string `json:"coin_name"`
|
||||||
|
CoinShortcut string `json:"coin_shortcut"`
|
||||||
|
CoinLabel string `json:"coin_label"`
|
||||||
|
Network string `json:"network"`
|
||||||
|
FourByteSignatures string `json:"fourByteSignatures"`
|
||||||
|
FiatRates string `json:"fiat_rates"`
|
||||||
|
FiatRatesParams string `json:"fiat_rates_params"`
|
||||||
|
FiatRatesVsCurrencies string `json:"fiat_rates_vs_currencies"`
|
||||||
|
BlockGolombFilterP uint8 `json:"block_golomb_filter_p"`
|
||||||
|
BlockFilterScripts string `json:"block_filter_scripts"`
|
||||||
|
BlockFilterUseZeroedKey bool `json:"block_filter_use_zeroed_key"`
|
||||||
|
}
|
||||||
|
|
||||||
|
// GetConfig loads and parses the config file and returns Config struct
|
||||||
|
func GetConfig(configFile string) (*Config, error) {
|
||||||
|
if configFile == "" {
|
||||||
|
return nil, errors.New("Missing blockchaincfg configuration parameter")
|
||||||
|
}
|
||||||
|
|
||||||
|
configFileContent, err := os.ReadFile(configFile)
|
||||||
|
if err != nil {
|
||||||
|
return nil, errors.Errorf("Error reading file %v, %v", configFile, err)
|
||||||
|
}
|
||||||
|
|
||||||
|
var cn Config
|
||||||
|
err = json.Unmarshal(configFileContent, &cn)
|
||||||
|
if err != nil {
|
||||||
|
return nil, errors.Annotatef(err, "Error parsing config file ")
|
||||||
|
}
|
||||||
|
return &cn, nil
|
||||||
|
}
|
||||||
@ -57,6 +57,7 @@ type InternalState struct {
|
|||||||
CoinShortcut string `json:"coinShortcut"`
|
CoinShortcut string `json:"coinShortcut"`
|
||||||
CoinLabel string `json:"coinLabel"`
|
CoinLabel string `json:"coinLabel"`
|
||||||
Host string `json:"host"`
|
Host string `json:"host"`
|
||||||
|
Network string `json:"network,omitempty"`
|
||||||
|
|
||||||
DbState uint32 `json:"dbState"`
|
DbState uint32 `json:"dbState"`
|
||||||
ExtendedIndex bool `json:"extendedIndex"`
|
ExtendedIndex bool `json:"extendedIndex"`
|
||||||
@ -92,6 +93,15 @@ type InternalState struct {
|
|||||||
// database migrations
|
// database migrations
|
||||||
UtxoChecked bool `json:"utxoChecked"`
|
UtxoChecked bool `json:"utxoChecked"`
|
||||||
SortedAddressContracts bool `json:"sortedAddressContracts"`
|
SortedAddressContracts bool `json:"sortedAddressContracts"`
|
||||||
|
|
||||||
|
// golomb filter settings
|
||||||
|
BlockGolombFilterP uint8 `json:"block_golomb_filter_p"`
|
||||||
|
BlockFilterScripts string `json:"block_filter_scripts"`
|
||||||
|
BlockFilterUseZeroedKey bool `json:"block_filter_use_zeroed_key"`
|
||||||
|
|
||||||
|
// allowed number of fetched accounts over websocket
|
||||||
|
WsGetAccountInfoLimit int `json:"-"`
|
||||||
|
WsLimitExceedingIPs map[string]int `json:"-"`
|
||||||
}
|
}
|
||||||
|
|
||||||
// StartedSync signals start of synchronization
|
// StartedSync signals start of synchronization
|
||||||
@ -296,6 +306,15 @@ func (is *InternalState) computeAvgBlockPeriod() {
|
|||||||
is.AvgBlockPeriod = (is.BlockTimes[last] - is.BlockTimes[first]) / avgBlockPeriodSample
|
is.AvgBlockPeriod = (is.BlockTimes[last] - is.BlockTimes[first]) / avgBlockPeriodSample
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// GetNetwork returns network. If not set returns the same value as CoinShortcut
|
||||||
|
func (is *InternalState) GetNetwork() string {
|
||||||
|
network := is.Network
|
||||||
|
if network == "" {
|
||||||
|
return is.CoinShortcut
|
||||||
|
}
|
||||||
|
return network
|
||||||
|
}
|
||||||
|
|
||||||
// SetBackendInfo sets new BackendInfo
|
// SetBackendInfo sets new BackendInfo
|
||||||
func (is *InternalState) SetBackendInfo(bi *BackendInfo) {
|
func (is *InternalState) SetBackendInfo(bi *BackendInfo) {
|
||||||
is.mux.Lock()
|
is.mux.Lock()
|
||||||
@ -336,3 +355,15 @@ func SetInShutdown() {
|
|||||||
func IsInShutdown() bool {
|
func IsInShutdown() bool {
|
||||||
return atomic.LoadInt32(&inShutdown) != 0
|
return atomic.LoadInt32(&inShutdown) != 0
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (is *InternalState) AddWsLimitExceedingIP(ip string) {
|
||||||
|
is.mux.Lock()
|
||||||
|
defer is.mux.Unlock()
|
||||||
|
is.WsLimitExceedingIPs[ip] = is.WsLimitExceedingIPs[ip] + 1
|
||||||
|
}
|
||||||
|
|
||||||
|
func (is *InternalState) ResetWsLimitExceedingIPs() {
|
||||||
|
is.mux.Lock()
|
||||||
|
defer is.mux.Unlock()
|
||||||
|
is.WsLimitExceedingIPs = make(map[string]int)
|
||||||
|
}
|
||||||
|
|||||||
@ -6,7 +6,9 @@ import (
|
|||||||
)
|
)
|
||||||
|
|
||||||
// JSONNumber is used instead of json.Number after upgrade to go 1.14
|
// JSONNumber is used instead of json.Number after upgrade to go 1.14
|
||||||
// to handle data which can be numbers in double quotes or possibly not numbers at all
|
//
|
||||||
|
// to handle data which can be numbers in double quotes or possibly not numbers at all
|
||||||
|
//
|
||||||
// see https://github.com/golang/go/issues/37308
|
// see https://github.com/golang/go/issues/37308
|
||||||
type JSONNumber string
|
type JSONNumber string
|
||||||
|
|
||||||
|
|||||||
@ -72,7 +72,7 @@ func GetMetrics(coin string) (*Metrics, error) {
|
|||||||
prometheus.HistogramOpts{
|
prometheus.HistogramOpts{
|
||||||
Name: "blockbook_socketio_req_duration",
|
Name: "blockbook_socketio_req_duration",
|
||||||
Help: "Socketio request duration by method (in microseconds)",
|
Help: "Socketio request duration by method (in microseconds)",
|
||||||
Buckets: []float64{1, 5, 10, 25, 50, 75, 100, 250},
|
Buckets: []float64{10, 100, 1_000, 10_000, 100_000, 1_000_000, 10_0000_000},
|
||||||
ConstLabels: Labels{"coin": coin},
|
ConstLabels: Labels{"coin": coin},
|
||||||
},
|
},
|
||||||
[]string{"method"},
|
[]string{"method"},
|
||||||
@ -104,7 +104,7 @@ func GetMetrics(coin string) (*Metrics, error) {
|
|||||||
prometheus.HistogramOpts{
|
prometheus.HistogramOpts{
|
||||||
Name: "blockbook_websocket_req_duration",
|
Name: "blockbook_websocket_req_duration",
|
||||||
Help: "Websocket request duration by method (in microseconds)",
|
Help: "Websocket request duration by method (in microseconds)",
|
||||||
Buckets: []float64{1, 5, 10, 25, 50, 75, 100, 250},
|
Buckets: []float64{10, 100, 1_000, 10_000, 100_000, 1_000_000, 10_0000_000},
|
||||||
ConstLabels: Labels{"coin": coin},
|
ConstLabels: Labels{"coin": coin},
|
||||||
},
|
},
|
||||||
[]string{"method"},
|
[]string{"method"},
|
||||||
@ -113,7 +113,7 @@ func GetMetrics(coin string) (*Metrics, error) {
|
|||||||
prometheus.HistogramOpts{
|
prometheus.HistogramOpts{
|
||||||
Name: "blockbook_index_resync_duration",
|
Name: "blockbook_index_resync_duration",
|
||||||
Help: "Duration of index resync operation (in milliseconds)",
|
Help: "Duration of index resync operation (in milliseconds)",
|
||||||
Buckets: []float64{50, 100, 150, 200, 250, 300, 350, 400, 450, 500, 600, 700, 1000, 2000, 5000},
|
Buckets: []float64{10, 100, 500, 1000, 2000, 5000, 10000},
|
||||||
ConstLabels: Labels{"coin": coin},
|
ConstLabels: Labels{"coin": coin},
|
||||||
},
|
},
|
||||||
)
|
)
|
||||||
@ -121,7 +121,7 @@ func GetMetrics(coin string) (*Metrics, error) {
|
|||||||
prometheus.HistogramOpts{
|
prometheus.HistogramOpts{
|
||||||
Name: "blockbook_mempool_resync_duration",
|
Name: "blockbook_mempool_resync_duration",
|
||||||
Help: "Duration of mempool resync operation (in milliseconds)",
|
Help: "Duration of mempool resync operation (in milliseconds)",
|
||||||
Buckets: []float64{10, 25, 50, 75, 100, 150, 250, 500, 750, 1000, 2000, 5000},
|
Buckets: []float64{10, 100, 500, 1000, 2000, 5000, 10000},
|
||||||
ConstLabels: Labels{"coin": coin},
|
ConstLabels: Labels{"coin": coin},
|
||||||
},
|
},
|
||||||
)
|
)
|
||||||
|
|||||||
66
configs/coins/arbitrum.json
Normal file
66
configs/coins/arbitrum.json
Normal file
@ -0,0 +1,66 @@
|
|||||||
|
{
|
||||||
|
"coin": {
|
||||||
|
"name": "Arbitrum",
|
||||||
|
"shortcut": "ETH",
|
||||||
|
"network": "ARB",
|
||||||
|
"label": "Arbitrum",
|
||||||
|
"alias": "arbitrum"
|
||||||
|
},
|
||||||
|
"ports": {
|
||||||
|
"backend_rpc": 8205,
|
||||||
|
"backend_p2p": 38405,
|
||||||
|
"backend_http": 8305,
|
||||||
|
"blockbook_internal": 9205,
|
||||||
|
"blockbook_public": 9305
|
||||||
|
},
|
||||||
|
"ipc": {
|
||||||
|
"rpc_url_template": "ws://127.0.0.1:{{.Ports.BackendRPC}}",
|
||||||
|
"rpc_timeout": 25
|
||||||
|
},
|
||||||
|
"backend": {
|
||||||
|
"package_name": "backend-arbitrum",
|
||||||
|
"package_revision": "satoshilabs-1",
|
||||||
|
"system_user": "arbitrum",
|
||||||
|
"version": "3.2.1",
|
||||||
|
"docker_image": "offchainlabs/nitro-node:v3.2.1-d81324d",
|
||||||
|
"verification_type": "docker",
|
||||||
|
"verification_source": "724ebdcca39cd0c28ffd025ecea8d1622a376f41344201b729afb60352cbc306",
|
||||||
|
"extract_command": "docker cp extract:/home/user/target backend/target; docker cp extract:/home/user/nitro-legacy backend/nitro-legacy; docker cp extract:/usr/local/bin/nitro backend/nitro",
|
||||||
|
"exclude_files": [],
|
||||||
|
"exec_command_template": "/bin/sh -c '{{.Env.BackendInstallPath}}/{{.Coin.Alias}}/arbitrum_exec.sh 2>> {{.Env.BackendDataPath}}/{{.Coin.Alias}}/backend/{{.Coin.Alias}}.log'",
|
||||||
|
"exec_script": "arbitrum.sh",
|
||||||
|
"logrotate_files_template": "{{.Env.BackendDataPath}}/{{.Coin.Alias}}/backend/{{.Coin.Alias}}.log",
|
||||||
|
"postinst_script_template": "openssl rand -hex 32 > {{.Env.BackendDataPath}}/{{.Coin.Alias}}/backend/jwtsecret",
|
||||||
|
"service_type": "simple",
|
||||||
|
"service_additional_params_template": "",
|
||||||
|
"protect_memory": true,
|
||||||
|
"mainnet": true,
|
||||||
|
"server_config_file": "",
|
||||||
|
"client_config_file": ""
|
||||||
|
},
|
||||||
|
"blockbook": {
|
||||||
|
"package_name": "blockbook-arbitrum",
|
||||||
|
"system_user": "blockbook-arbitrum",
|
||||||
|
"internal_binding_template": ":{{.Ports.BlockbookInternal}}",
|
||||||
|
"public_binding_template": ":{{.Ports.BlockbookPublic}}",
|
||||||
|
"explorer_url": "",
|
||||||
|
"additional_params": "",
|
||||||
|
"block_chain": {
|
||||||
|
"parse": true,
|
||||||
|
"mempool_workers": 8,
|
||||||
|
"mempool_sub_workers": 2,
|
||||||
|
"block_addresses_to_keep": 300,
|
||||||
|
"additional_params": {
|
||||||
|
"mempoolTxTimeoutHours": 48,
|
||||||
|
"queryBackendOnMempoolResync": false,
|
||||||
|
"fiat_rates": "coingecko",
|
||||||
|
"fiat_rates_vs_currencies": "AED,ARS,AUD,BDT,BHD,BMD,BRL,CAD,CHF,CLP,CNY,CZK,DKK,EUR,GBP,HKD,HUF,IDR,ILS,INR,JPY,KRW,KWD,LKR,MMK,MXN,MYR,NGN,NOK,NZD,PHP,PKR,PLN,RUB,SAR,SEK,SGD,THB,TRY,TWD,UAH,USD,VEF,VND,ZAR,BTC,ETH",
|
||||||
|
"fiat_rates_params": "{\"coin\": \"ethereum\",\"platformIdentifier\": \"arbitrum-one\",\"platformVsCurrency\": \"eth\",\"periodSeconds\": 900}"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"meta": {
|
||||||
|
"package_maintainer": "IT",
|
||||||
|
"package_maintainer_email": "it@satoshilabs.com"
|
||||||
|
}
|
||||||
|
}
|
||||||
68
configs/coins/arbitrum_archive.json
Normal file
68
configs/coins/arbitrum_archive.json
Normal file
@ -0,0 +1,68 @@
|
|||||||
|
{
|
||||||
|
"coin": {
|
||||||
|
"name": "Arbitrum Archive",
|
||||||
|
"shortcut": "ETH",
|
||||||
|
"network": "ARB",
|
||||||
|
"label": "Arbitrum",
|
||||||
|
"alias": "arbitrum_archive"
|
||||||
|
},
|
||||||
|
"ports": {
|
||||||
|
"backend_rpc": 8306,
|
||||||
|
"backend_p2p": 38406,
|
||||||
|
"blockbook_internal": 9206,
|
||||||
|
"blockbook_public": 9306
|
||||||
|
},
|
||||||
|
"ipc": {
|
||||||
|
"rpc_url_template": "ws://127.0.0.1:{{.Ports.BackendRPC}}",
|
||||||
|
"rpc_timeout": 25
|
||||||
|
},
|
||||||
|
"backend": {
|
||||||
|
"package_name": "backend-arbitrum-archive",
|
||||||
|
"package_revision": "satoshilabs-1",
|
||||||
|
"system_user": "arbitrum",
|
||||||
|
"version": "3.2.1",
|
||||||
|
"docker_image": "offchainlabs/nitro-node:v3.2.1-d81324d",
|
||||||
|
"verification_type": "docker",
|
||||||
|
"verification_source": "724ebdcca39cd0c28ffd025ecea8d1622a376f41344201b729afb60352cbc306",
|
||||||
|
"extract_command": "docker cp extract:/home/user/target backend/target; docker cp extract:/home/user/nitro-legacy backend/nitro-legacy; docker cp extract:/usr/local/bin/nitro backend/nitro",
|
||||||
|
"exclude_files": [],
|
||||||
|
"exec_command_template": "/bin/sh -c '{{.Env.BackendInstallPath}}/{{.Coin.Alias}}/arbitrum_archive_exec.sh 2>> {{.Env.BackendDataPath}}/{{.Coin.Alias}}/backend/{{.Coin.Alias}}.log'",
|
||||||
|
"exec_script": "arbitrum_archive.sh",
|
||||||
|
"logrotate_files_template": "{{.Env.BackendDataPath}}/{{.Coin.Alias}}/backend/{{.Coin.Alias}}.log",
|
||||||
|
"postinst_script_template": "openssl rand -hex 32 > {{.Env.BackendDataPath}}/{{.Coin.Alias}}/backend/jwtsecret",
|
||||||
|
"service_type": "simple",
|
||||||
|
"service_additional_params_template": "",
|
||||||
|
"protect_memory": true,
|
||||||
|
"mainnet": true,
|
||||||
|
"server_config_file": "",
|
||||||
|
"client_config_file": ""
|
||||||
|
},
|
||||||
|
"blockbook": {
|
||||||
|
"package_name": "blockbook-arbitrum-archive",
|
||||||
|
"system_user": "blockbook-arbitrum",
|
||||||
|
"internal_binding_template": ":{{.Ports.BlockbookInternal}}",
|
||||||
|
"public_binding_template": ":{{.Ports.BlockbookPublic}}",
|
||||||
|
"explorer_url": "",
|
||||||
|
"additional_params": "-workers=16",
|
||||||
|
"block_chain": {
|
||||||
|
"parse": true,
|
||||||
|
"mempool_workers": 8,
|
||||||
|
"mempool_sub_workers": 2,
|
||||||
|
"block_addresses_to_keep": 600,
|
||||||
|
"additional_params": {
|
||||||
|
"address_aliases": true,
|
||||||
|
"mempoolTxTimeoutHours": 48,
|
||||||
|
"processInternalTransactions": true,
|
||||||
|
"queryBackendOnMempoolResync": false,
|
||||||
|
"fiat_rates": "coingecko",
|
||||||
|
"fiat_rates_vs_currencies": "AED,ARS,AUD,BDT,BHD,BMD,BRL,CAD,CHF,CLP,CNY,CZK,DKK,EUR,GBP,HKD,HUF,IDR,ILS,INR,JPY,KRW,KWD,LKR,MMK,MXN,MYR,NGN,NOK,NZD,PHP,PKR,PLN,RUB,SAR,SEK,SGD,THB,TRY,TWD,UAH,USD,VEF,VND,ZAR,BTC,ETH",
|
||||||
|
"fiat_rates_params": "{\"coin\": \"ethereum\",\"platformIdentifier\": \"arbitrum-one\",\"platformVsCurrency\": \"eth\",\"periodSeconds\": 900}",
|
||||||
|
"fourByteSignatures": "https://www.4byte.directory/api/v1/signatures/"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"meta": {
|
||||||
|
"package_maintainer": "IT",
|
||||||
|
"package_maintainer_email": "it@satoshilabs.com"
|
||||||
|
}
|
||||||
|
}
|
||||||
65
configs/coins/arbitrum_nova.json
Normal file
65
configs/coins/arbitrum_nova.json
Normal file
@ -0,0 +1,65 @@
|
|||||||
|
{
|
||||||
|
"coin": {
|
||||||
|
"name": "Arbitrum Nova",
|
||||||
|
"shortcut": "ETH",
|
||||||
|
"label": "Arbitrum Nova",
|
||||||
|
"alias": "arbitrum_nova"
|
||||||
|
},
|
||||||
|
"ports": {
|
||||||
|
"backend_rpc": 8207,
|
||||||
|
"backend_p2p": 38407,
|
||||||
|
"backend_http": 8307,
|
||||||
|
"blockbook_internal": 9207,
|
||||||
|
"blockbook_public": 9307
|
||||||
|
},
|
||||||
|
"ipc": {
|
||||||
|
"rpc_url_template": "ws://127.0.0.1:{{.Ports.BackendRPC}}",
|
||||||
|
"rpc_timeout": 25
|
||||||
|
},
|
||||||
|
"backend": {
|
||||||
|
"package_name": "backend-arbitrum-nova",
|
||||||
|
"package_revision": "satoshilabs-1",
|
||||||
|
"system_user": "arbitrum",
|
||||||
|
"version": "3.2.1",
|
||||||
|
"docker_image": "offchainlabs/nitro-node:v3.2.1-d81324d",
|
||||||
|
"verification_type": "docker",
|
||||||
|
"verification_source": "724ebdcca39cd0c28ffd025ecea8d1622a376f41344201b729afb60352cbc306",
|
||||||
|
"extract_command": "docker cp extract:/home/user/target backend/target; docker cp extract:/home/user/nitro-legacy backend/nitro-legacy; docker cp extract:/usr/local/bin/nitro backend/nitro",
|
||||||
|
"exclude_files": [],
|
||||||
|
"exec_command_template": "/bin/sh -c '{{.Env.BackendInstallPath}}/{{.Coin.Alias}}/arbitrum_nova_exec.sh 2>> {{.Env.BackendDataPath}}/{{.Coin.Alias}}/backend/{{.Coin.Alias}}.log'",
|
||||||
|
"exec_script": "arbitrum_nova.sh",
|
||||||
|
"logrotate_files_template": "{{.Env.BackendDataPath}}/{{.Coin.Alias}}/backend/{{.Coin.Alias}}.log",
|
||||||
|
"postinst_script_template": "openssl rand -hex 32 > {{.Env.BackendDataPath}}/{{.Coin.Alias}}/backend/jwtsecret",
|
||||||
|
"service_type": "simple",
|
||||||
|
"service_additional_params_template": "",
|
||||||
|
"protect_memory": true,
|
||||||
|
"mainnet": true,
|
||||||
|
"server_config_file": "",
|
||||||
|
"client_config_file": ""
|
||||||
|
},
|
||||||
|
"blockbook": {
|
||||||
|
"package_name": "blockbook-arbitrum-nova",
|
||||||
|
"system_user": "blockbook-arbitrum",
|
||||||
|
"internal_binding_template": ":{{.Ports.BlockbookInternal}}",
|
||||||
|
"public_binding_template": ":{{.Ports.BlockbookPublic}}",
|
||||||
|
"explorer_url": "",
|
||||||
|
"additional_params": "",
|
||||||
|
"block_chain": {
|
||||||
|
"parse": true,
|
||||||
|
"mempool_workers": 8,
|
||||||
|
"mempool_sub_workers": 2,
|
||||||
|
"block_addresses_to_keep": 300,
|
||||||
|
"additional_params": {
|
||||||
|
"mempoolTxTimeoutHours": 48,
|
||||||
|
"queryBackendOnMempoolResync": false,
|
||||||
|
"fiat_rates": "coingecko",
|
||||||
|
"fiat_rates_vs_currencies": "AED,ARS,AUD,BDT,BHD,BMD,BRL,CAD,CHF,CLP,CNY,CZK,DKK,EUR,GBP,HKD,HUF,IDR,ILS,INR,JPY,KRW,KWD,LKR,MMK,MXN,MYR,NGN,NOK,NZD,PHP,PKR,PLN,RUB,SAR,SEK,SGD,THB,TRY,TWD,UAH,USD,VEF,VND,ZAR,BTC,ETH",
|
||||||
|
"fiat_rates_params": "{\"coin\": \"ethereum\",\"platformIdentifier\": \"ethereum\",\"platformVsCurrency\": \"eth\",\"periodSeconds\": 900}"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"meta": {
|
||||||
|
"package_maintainer": "IT",
|
||||||
|
"package_maintainer_email": "it@satoshilabs.com"
|
||||||
|
}
|
||||||
|
}
|
||||||
67
configs/coins/arbitrum_nova_archive.json
Normal file
67
configs/coins/arbitrum_nova_archive.json
Normal file
@ -0,0 +1,67 @@
|
|||||||
|
{
|
||||||
|
"coin": {
|
||||||
|
"name": "Arbitrum Nova Archive",
|
||||||
|
"shortcut": "ETH",
|
||||||
|
"label": "Arbitrum Nova",
|
||||||
|
"alias": "arbitrum_nova_archive"
|
||||||
|
},
|
||||||
|
"ports": {
|
||||||
|
"backend_rpc": 8308,
|
||||||
|
"backend_p2p": 38408,
|
||||||
|
"blockbook_internal": 9208,
|
||||||
|
"blockbook_public": 9308
|
||||||
|
},
|
||||||
|
"ipc": {
|
||||||
|
"rpc_url_template": "ws://127.0.0.1:{{.Ports.BackendRPC}}",
|
||||||
|
"rpc_timeout": 25
|
||||||
|
},
|
||||||
|
"backend": {
|
||||||
|
"package_name": "backend-arbitrum-nova-archive",
|
||||||
|
"package_revision": "satoshilabs-1",
|
||||||
|
"system_user": "arbitrum",
|
||||||
|
"version": "3.2.1",
|
||||||
|
"docker_image": "offchainlabs/nitro-node:v3.2.1-d81324d",
|
||||||
|
"verification_type": "docker",
|
||||||
|
"verification_source": "724ebdcca39cd0c28ffd025ecea8d1622a376f41344201b729afb60352cbc306",
|
||||||
|
"extract_command": "docker cp extract:/home/user/target backend/target; docker cp extract:/home/user/nitro-legacy backend/nitro-legacy; docker cp extract:/usr/local/bin/nitro backend/nitro",
|
||||||
|
"exclude_files": [],
|
||||||
|
"exec_command_template": "/bin/sh -c '{{.Env.BackendInstallPath}}/{{.Coin.Alias}}/arbitrum_nova_archive_exec.sh 2>> {{.Env.BackendDataPath}}/{{.Coin.Alias}}/backend/{{.Coin.Alias}}.log'",
|
||||||
|
"exec_script": "arbitrum_nova_archive.sh",
|
||||||
|
"logrotate_files_template": "{{.Env.BackendDataPath}}/{{.Coin.Alias}}/backend/{{.Coin.Alias}}.log",
|
||||||
|
"postinst_script_template": "openssl rand -hex 32 > {{.Env.BackendDataPath}}/{{.Coin.Alias}}/backend/jwtsecret",
|
||||||
|
"service_type": "simple",
|
||||||
|
"service_additional_params_template": "",
|
||||||
|
"protect_memory": true,
|
||||||
|
"mainnet": true,
|
||||||
|
"server_config_file": "",
|
||||||
|
"client_config_file": ""
|
||||||
|
},
|
||||||
|
"blockbook": {
|
||||||
|
"package_name": "blockbook-arbitrum-nova-archive",
|
||||||
|
"system_user": "blockbook-arbitrum",
|
||||||
|
"internal_binding_template": ":{{.Ports.BlockbookInternal}}",
|
||||||
|
"public_binding_template": ":{{.Ports.BlockbookPublic}}",
|
||||||
|
"explorer_url": "",
|
||||||
|
"additional_params": "-workers=16",
|
||||||
|
"block_chain": {
|
||||||
|
"parse": true,
|
||||||
|
"mempool_workers": 8,
|
||||||
|
"mempool_sub_workers": 2,
|
||||||
|
"block_addresses_to_keep": 600,
|
||||||
|
"additional_params": {
|
||||||
|
"address_aliases": true,
|
||||||
|
"mempoolTxTimeoutHours": 48,
|
||||||
|
"processInternalTransactions": true,
|
||||||
|
"queryBackendOnMempoolResync": false,
|
||||||
|
"fiat_rates": "coingecko",
|
||||||
|
"fiat_rates_vs_currencies": "AED,ARS,AUD,BDT,BHD,BMD,BRL,CAD,CHF,CLP,CNY,CZK,DKK,EUR,GBP,HKD,HUF,IDR,ILS,INR,JPY,KRW,KWD,LKR,MMK,MXN,MYR,NGN,NOK,NZD,PHP,PKR,PLN,RUB,SAR,SEK,SGD,THB,TRY,TWD,UAH,USD,VEF,VND,ZAR,BTC,ETH",
|
||||||
|
"fiat_rates_params": "{\"coin\": \"ethereum\",\"platformIdentifier\": \"ethereum\",\"platformVsCurrency\": \"eth\",\"periodSeconds\": 900}",
|
||||||
|
"fourByteSignatures": "https://www.4byte.directory/api/v1/signatures/"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"meta": {
|
||||||
|
"package_maintainer": "IT",
|
||||||
|
"package_maintainer_email": "it@satoshilabs.com"
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -19,10 +19,10 @@
|
|||||||
"package_name": "backend-avalanche",
|
"package_name": "backend-avalanche",
|
||||||
"package_revision": "satoshilabs-1",
|
"package_revision": "satoshilabs-1",
|
||||||
"system_user": "avalanche",
|
"system_user": "avalanche",
|
||||||
"version": "1.9.11",
|
"version": "1.12.1",
|
||||||
"binary_url": "https://github.com/ava-labs/avalanchego/releases/download/v1.9.11/avalanchego-linux-amd64-v1.9.11.tar.gz",
|
"binary_url": "https://github.com/ava-labs/avalanchego/releases/download/v1.12.1/avalanchego-linux-amd64-v1.12.1.tar.gz",
|
||||||
"verification_type": "gpg",
|
"verification_type": "gpg",
|
||||||
"verification_source": "https://github.com/ava-labs/avalanchego/releases/download/v1.9.11/avalanchego-linux-amd64-v1.9.11.tar.gz.sig",
|
"verification_source": "https://github.com/ava-labs/avalanchego/releases/download/v1.12.1/avalanchego-linux-amd64-v1.12.1.tar.gz.sig",
|
||||||
"extract_command": "tar -C backend --strip 1 -xf",
|
"extract_command": "tar -C backend --strip 1 -xf",
|
||||||
"exclude_files": [],
|
"exclude_files": [],
|
||||||
"exec_command_template": "{{.Env.BackendInstallPath}}/{{.Coin.Alias}}/avalanchego --data-dir {{.Env.BackendDataPath}}/{{.Coin.Alias}}/backend --log-dir {{.Env.BackendDataPath}}/{{.Coin.Alias}}/backend --http-port {{.Ports.BackendRPC}} --staking-port {{.Ports.BackendP2P}} --public-ip 127.0.0.1 --staking-ephemeral-cert-enabled --chain-config-content ewogICJDIjp7CiAgICAiY29uZmlnIjoiZXdvZ0lDSmxkR2d0WVhCcGN5STZXd29nSUNBZ0ltVjBhQ0lzQ2lBZ0lDQWlaWFJvTFdacGJIUmxjaUlzQ2lBZ0lDQWlibVYwSWl3S0lDQWdJQ0prWldKMVp5MTBjbUZqWlhJaUxBb2dJQ0FnSW5kbFlqTWlMQW9nSUNBZ0ltbHVkR1Z5Ym1Gc0xXVjBhQ0lzQ2lBZ0lDQWlhVzUwWlhKdVlXd3RZbXh2WTJ0amFHRnBiaUlzQ2lBZ0lDQWlhVzUwWlhKdVlXd3RkSEpoYm5OaFkzUnBiMjRpTEFvZ0lDQWdJbWx1ZEdWeWJtRnNMWFI0TFhCdmIyd2lMQW9nSUNBZ0ltbHVkR1Z5Ym1Gc0xXUmxZblZuSWdvZ0lGMEtmUT09IgogIH0KfQ==",
|
"exec_command_template": "{{.Env.BackendInstallPath}}/{{.Coin.Alias}}/avalanchego --data-dir {{.Env.BackendDataPath}}/{{.Coin.Alias}}/backend --log-dir {{.Env.BackendDataPath}}/{{.Coin.Alias}}/backend --http-port {{.Ports.BackendRPC}} --staking-port {{.Ports.BackendP2P}} --public-ip 127.0.0.1 --staking-ephemeral-cert-enabled --chain-config-content ewogICJDIjp7CiAgICAiY29uZmlnIjoiZXdvZ0lDSmxkR2d0WVhCcGN5STZXd29nSUNBZ0ltVjBhQ0lzQ2lBZ0lDQWlaWFJvTFdacGJIUmxjaUlzQ2lBZ0lDQWlibVYwSWl3S0lDQWdJQ0prWldKMVp5MTBjbUZqWlhJaUxBb2dJQ0FnSW5kbFlqTWlMQW9nSUNBZ0ltbHVkR1Z5Ym1Gc0xXVjBhQ0lzQ2lBZ0lDQWlhVzUwWlhKdVlXd3RZbXh2WTJ0amFHRnBiaUlzQ2lBZ0lDQWlhVzUwWlhKdVlXd3RkSEpoYm5OaFkzUnBiMjRpTEFvZ0lDQWdJbWx1ZEdWeWJtRnNMWFI0TFhCdmIyd2lMQW9nSUNBZ0ltbHVkR1Z5Ym1Gc0xXUmxZblZuSWdvZ0lGMEtmUT09IgogIH0KfQ==",
|
||||||
@ -36,8 +36,8 @@
|
|||||||
"client_config_file": "",
|
"client_config_file": "",
|
||||||
"platforms": {
|
"platforms": {
|
||||||
"arm64": {
|
"arm64": {
|
||||||
"binary_url": "https://github.com/ava-labs/avalanchego/releases/download/v1.9.11/avalanchego-linux-arm64-v1.9.11.tar.gz",
|
"binary_url": "https://github.com/ava-labs/avalanchego/releases/download/v1.12.1/avalanchego-linux-arm64-v1.12.1.tar.gz",
|
||||||
"verification_source": "https://github.com/ava-labs/avalanchego/releases/download/v1.9.11/avalanchego-linux-arm64-v1.9.11.tar.gz.sig"
|
"verification_source": "https://github.com/ava-labs/avalanchego/releases/download/v1.12.1/avalanchego-linux-arm64-v1.12.1.tar.gz.sig"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|||||||
@ -19,10 +19,10 @@
|
|||||||
"package_name": "backend-avalanche-archive",
|
"package_name": "backend-avalanche-archive",
|
||||||
"package_revision": "satoshilabs-1",
|
"package_revision": "satoshilabs-1",
|
||||||
"system_user": "avalanche",
|
"system_user": "avalanche",
|
||||||
"version": "1.9.11",
|
"version": "1.12.1",
|
||||||
"binary_url": "https://github.com/ava-labs/avalanchego/releases/download/v1.9.11/avalanchego-linux-amd64-v1.9.11.tar.gz",
|
"binary_url": "https://github.com/ava-labs/avalanchego/releases/download/v1.12.1/avalanchego-linux-amd64-v1.12.1.tar.gz",
|
||||||
"verification_type": "gpg",
|
"verification_type": "gpg",
|
||||||
"verification_source": "https://github.com/ava-labs/avalanchego/releases/download/v1.9.11/avalanchego-linux-amd64-v1.9.11.tar.gz.sig",
|
"verification_source": "https://github.com/ava-labs/avalanchego/releases/download/v1.12.1/avalanchego-linux-amd64-v1.12.1.tar.gz.sig",
|
||||||
"extract_command": "tar -C backend --strip 1 -xf",
|
"extract_command": "tar -C backend --strip 1 -xf",
|
||||||
"exclude_files": [],
|
"exclude_files": [],
|
||||||
"exec_command_template": "{{.Env.BackendInstallPath}}/{{.Coin.Alias}}/avalanchego --data-dir {{.Env.BackendDataPath}}/{{.Coin.Alias}}/backend --log-dir {{.Env.BackendDataPath}}/{{.Coin.Alias}}/backend --http-port {{.Ports.BackendRPC}} --staking-port {{.Ports.BackendP2P}} --public-ip 127.0.0.1 --staking-ephemeral-cert-enabled --chain-config-content ewogICJDIjp7CiAgICAiY29uZmlnIjoiZXdvZ0lDSmxkR2d0WVhCcGN5STZXd29nSUNBZ0ltVjBhQ0lzQ2lBZ0lDQWlaWFJvTFdacGJIUmxjaUlzQ2lBZ0lDQWlibVYwSWl3S0lDQWdJQ0prWldKMVp5MTBjbUZqWlhJaUxBb2dJQ0FnSW5kbFlqTWlMQW9nSUNBZ0ltbHVkR1Z5Ym1Gc0xXVjBhQ0lzQ2lBZ0lDQWlhVzUwWlhKdVlXd3RZbXh2WTJ0amFHRnBiaUlzQ2lBZ0lDQWlhVzUwWlhKdVlXd3RkSEpoYm5OaFkzUnBiMjRpTEFvZ0lDQWdJbWx1ZEdWeWJtRnNMWFI0TFhCdmIyd2lMQW9nSUNBZ0ltbHVkR1Z5Ym1Gc0xXUmxZblZuSWdvZ0lGMHNDaUFnSW5CeWRXNXBibWN0Wlc1aFlteGxaQ0k2Wm1Gc2MyVUtmUT09IgogIH0KfQ==",
|
"exec_command_template": "{{.Env.BackendInstallPath}}/{{.Coin.Alias}}/avalanchego --data-dir {{.Env.BackendDataPath}}/{{.Coin.Alias}}/backend --log-dir {{.Env.BackendDataPath}}/{{.Coin.Alias}}/backend --http-port {{.Ports.BackendRPC}} --staking-port {{.Ports.BackendP2P}} --public-ip 127.0.0.1 --staking-ephemeral-cert-enabled --chain-config-content ewogICJDIjp7CiAgICAiY29uZmlnIjoiZXdvZ0lDSmxkR2d0WVhCcGN5STZXd29nSUNBZ0ltVjBhQ0lzQ2lBZ0lDQWlaWFJvTFdacGJIUmxjaUlzQ2lBZ0lDQWlibVYwSWl3S0lDQWdJQ0prWldKMVp5MTBjbUZqWlhJaUxBb2dJQ0FnSW5kbFlqTWlMQW9nSUNBZ0ltbHVkR1Z5Ym1Gc0xXVjBhQ0lzQ2lBZ0lDQWlhVzUwWlhKdVlXd3RZbXh2WTJ0amFHRnBiaUlzQ2lBZ0lDQWlhVzUwWlhKdVlXd3RkSEpoYm5OaFkzUnBiMjRpTEFvZ0lDQWdJbWx1ZEdWeWJtRnNMWFI0TFhCdmIyd2lMQW9nSUNBZ0ltbHVkR1Z5Ym1Gc0xXUmxZblZuSWdvZ0lGMHNDaUFnSW5CeWRXNXBibWN0Wlc1aFlteGxaQ0k2Wm1Gc2MyVUtmUT09IgogIH0KfQ==",
|
||||||
@ -36,8 +36,8 @@
|
|||||||
"client_config_file": "",
|
"client_config_file": "",
|
||||||
"platforms": {
|
"platforms": {
|
||||||
"arm64": {
|
"arm64": {
|
||||||
"binary_url": "https://github.com/ava-labs/avalanchego/releases/download/v1.9.11/avalanchego-linux-arm64-v1.9.11.tar.gz",
|
"binary_url": "https://github.com/ava-labs/avalanchego/releases/download/v1.12.1/avalanchego-linux-arm64-v1.12.1.tar.gz",
|
||||||
"verification_source": "https://github.com/ava-labs/avalanchego/releases/download/v1.9.11/avalanchego-linux-arm64-v1.9.11.tar.gz.sig"
|
"verification_source": "https://github.com/ava-labs/avalanchego/releases/download/v1.12.1/avalanchego-linux-arm64-v1.12.1.tar.gz.sig"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|||||||
@ -22,10 +22,10 @@
|
|||||||
"package_name": "backend-bcash",
|
"package_name": "backend-bcash",
|
||||||
"package_revision": "satoshilabs-1",
|
"package_revision": "satoshilabs-1",
|
||||||
"system_user": "bcash",
|
"system_user": "bcash",
|
||||||
"version": "26.1.0",
|
"version": "28.0.1",
|
||||||
"binary_url": "https://github.com/bitcoin-cash-node/bitcoin-cash-node/releases/download/v26.1.0/bitcoin-cash-node-26.1.0-x86_64-linux-gnu.tar.gz",
|
"binary_url": "https://github.com/bitcoin-cash-node/bitcoin-cash-node/releases/download/v28.0.1/bitcoin-cash-node-28.0.1-x86_64-linux-gnu.tar.gz",
|
||||||
"verification_type": "sha256",
|
"verification_type": "sha256",
|
||||||
"verification_source": "68cb24d57898d5b47a1162a9683d0b0e36c6701b5a16b93edc94bbd82113c04b",
|
"verification_source": "d69ee632147f886ca540cecdff5b1b85512612b4c005e86b09083a63c35b64fa",
|
||||||
"extract_command": "tar -C backend --strip 1 -xf",
|
"extract_command": "tar -C backend --strip 1 -xf",
|
||||||
"exclude_files": ["bin/bitcoin-qt"],
|
"exclude_files": ["bin/bitcoin-qt"],
|
||||||
"exec_command_template": "{{.Env.BackendInstallPath}}/{{.Coin.Alias}}/bin/bitcoind -datadir={{.Env.BackendDataPath}}/{{.Coin.Alias}}/backend -conf={{.Env.BackendInstallPath}}/{{.Coin.Alias}}/{{.Coin.Alias}}.conf -pid=/run/{{.Coin.Alias}}/{{.Coin.Alias}}.pid",
|
"exec_command_template": "{{.Env.BackendInstallPath}}/{{.Coin.Alias}}/bin/bitcoind -datadir={{.Env.BackendDataPath}}/{{.Coin.Alias}}/backend -conf={{.Env.BackendInstallPath}}/{{.Coin.Alias}}/{{.Coin.Alias}}.conf -pid=/run/{{.Coin.Alias}}/{{.Coin.Alias}}.pid",
|
||||||
|
|||||||
@ -1,66 +1,64 @@
|
|||||||
{
|
{
|
||||||
"coin": {
|
"coin": {
|
||||||
"name": "Bcash Testnet",
|
"name": "Bcash Testnet",
|
||||||
"shortcut": "TBCH",
|
"shortcut": "TBCH",
|
||||||
"label": "Bitcoin Cash Testnet",
|
"label": "Bitcoin Cash Testnet",
|
||||||
"alias": "bcash_testnet"
|
"alias": "bcash_testnet"
|
||||||
},
|
},
|
||||||
"ports": {
|
"ports": {
|
||||||
"backend_rpc": 18031,
|
"backend_rpc": 18031,
|
||||||
"backend_message_queue": 48331,
|
"backend_message_queue": 48331,
|
||||||
"blockbook_internal": 19031,
|
"blockbook_internal": 19031,
|
||||||
"blockbook_public": 19131
|
"blockbook_public": 19131
|
||||||
},
|
},
|
||||||
"ipc": {
|
"ipc": {
|
||||||
"rpc_url_template": "http://127.0.0.1:{{.Ports.BackendRPC}}",
|
"rpc_url_template": "http://127.0.0.1:{{.Ports.BackendRPC}}",
|
||||||
"rpc_user": "rpc",
|
"rpc_user": "rpc",
|
||||||
"rpc_pass": "rpc",
|
"rpc_pass": "rpc",
|
||||||
"rpc_timeout": 25,
|
"rpc_timeout": 25,
|
||||||
"message_queue_binding_template": "tcp://127.0.0.1:{{.Ports.BackendMessageQueue}}"
|
"message_queue_binding_template": "tcp://127.0.0.1:{{.Ports.BackendMessageQueue}}"
|
||||||
},
|
},
|
||||||
"backend": {
|
"backend": {
|
||||||
"package_name": "backend-bcash-testnet",
|
"package_name": "backend-bcash-testnet",
|
||||||
"package_revision": "satoshilabs-1",
|
"package_revision": "satoshilabs-1",
|
||||||
"system_user": "bcash",
|
"system_user": "bcash",
|
||||||
"version": "26.1.0",
|
"version": "28.0.1",
|
||||||
"binary_url": "https://github.com/bitcoin-cash-node/bitcoin-cash-node/releases/download/v26.1.0/bitcoin-cash-node-26.1.0-x86_64-linux-gnu.tar.gz",
|
"binary_url": "https://github.com/bitcoin-cash-node/bitcoin-cash-node/releases/download/v28.0.1/bitcoin-cash-node-28.0.1-x86_64-linux-gnu.tar.gz",
|
||||||
"verification_type": "sha256",
|
"verification_type": "sha256",
|
||||||
"verification_source": "68cb24d57898d5b47a1162a9683d0b0e36c6701b5a16b93edc94bbd82113c04b",
|
"verification_source": "d69ee632147f886ca540cecdff5b1b85512612b4c005e86b09083a63c35b64fa",
|
||||||
"extract_command": "tar -C backend --strip 1 -xf",
|
"extract_command": "tar -C backend --strip 1 -xf",
|
||||||
"exclude_files": [
|
"exclude_files": ["bin/bitcoin-qt"],
|
||||||
"bin/bitcoin-qt"
|
"exec_command_template": "{{.Env.BackendInstallPath}}/{{.Coin.Alias}}/bin/bitcoind -datadir={{.Env.BackendDataPath}}/{{.Coin.Alias}}/backend -conf={{.Env.BackendInstallPath}}/{{.Coin.Alias}}/{{.Coin.Alias}}.conf -pid=/run/{{.Coin.Alias}}/{{.Coin.Alias}}.pid",
|
||||||
],
|
"logrotate_files_template": "{{.Env.BackendDataPath}}/{{.Coin.Alias}}/backend/testnet3/*.log",
|
||||||
"exec_command_template": "{{.Env.BackendInstallPath}}/{{.Coin.Alias}}/bin/bitcoind -datadir={{.Env.BackendDataPath}}/{{.Coin.Alias}}/backend -conf={{.Env.BackendInstallPath}}/{{.Coin.Alias}}/{{.Coin.Alias}}.conf -pid=/run/{{.Coin.Alias}}/{{.Coin.Alias}}.pid",
|
"postinst_script_template": "",
|
||||||
"logrotate_files_template": "{{.Env.BackendDataPath}}/{{.Coin.Alias}}/backend/testnet3/*.log",
|
"service_type": "forking",
|
||||||
"postinst_script_template": "",
|
"service_additional_params_template": "",
|
||||||
"service_type": "forking",
|
"protect_memory": true,
|
||||||
"service_additional_params_template": "",
|
"mainnet": false,
|
||||||
"protect_memory": true,
|
"server_config_file": "bcash.conf",
|
||||||
"mainnet": false,
|
"client_config_file": "bitcoin_client.conf"
|
||||||
"server_config_file": "bitcoin.conf",
|
},
|
||||||
"client_config_file": "bitcoin_client.conf"
|
"blockbook": {
|
||||||
},
|
"package_name": "blockbook-bcash-testnet",
|
||||||
"blockbook": {
|
"system_user": "blockbook-bcash",
|
||||||
"package_name": "blockbook-bcash-testnet",
|
"internal_binding_template": ":{{.Ports.BlockbookInternal}}",
|
||||||
"system_user": "blockbook-bcash",
|
"public_binding_template": ":{{.Ports.BlockbookPublic}}",
|
||||||
"internal_binding_template": ":{{.Ports.BlockbookInternal}}",
|
"explorer_url": "",
|
||||||
"public_binding_template": ":{{.Ports.BlockbookPublic}}",
|
"additional_params": "",
|
||||||
"explorer_url": "",
|
"block_chain": {
|
||||||
"additional_params": "",
|
"parse": true,
|
||||||
"block_chain": {
|
"subversion": "/Bitcoin ABC Cash Node:22.1.0/",
|
||||||
"parse": true,
|
"address_format": "cashaddr",
|
||||||
"subversion": "/Bitcoin ABC Cash Node:22.1.0/",
|
"mempool_workers": 8,
|
||||||
"address_format": "cashaddr",
|
"mempool_sub_workers": 2,
|
||||||
"mempool_workers": 8,
|
"block_addresses_to_keep": 300,
|
||||||
"mempool_sub_workers": 2,
|
"xpub_magic": 70617039,
|
||||||
"block_addresses_to_keep": 300,
|
"slip44": 1,
|
||||||
"xpub_magic": 70617039,
|
"additional_params": {}
|
||||||
"slip44": 1,
|
}
|
||||||
"additional_params": {}
|
},
|
||||||
|
"meta": {
|
||||||
|
"package_maintainer": "IT",
|
||||||
|
"package_maintainer_email": "it@satoshilabs.com"
|
||||||
}
|
}
|
||||||
},
|
|
||||||
"meta": {
|
|
||||||
"package_maintainer": "IT",
|
|
||||||
"package_maintainer_email": "it@satoshilabs.com"
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|||||||
@ -22,10 +22,10 @@
|
|||||||
"package_name": "backend-bitcoin",
|
"package_name": "backend-bitcoin",
|
||||||
"package_revision": "satoshilabs-1",
|
"package_revision": "satoshilabs-1",
|
||||||
"system_user": "bitcoin",
|
"system_user": "bitcoin",
|
||||||
"version": "25.0",
|
"version": "28.0",
|
||||||
"binary_url": "https://bitcoincore.org/bin/bitcoin-core-25.0/bitcoin-25.0-x86_64-linux-gnu.tar.gz",
|
"binary_url": "https://bitcoincore.org/bin/bitcoin-core-28.0/bitcoin-28.0-x86_64-linux-gnu.tar.gz",
|
||||||
"verification_type": "sha256",
|
"verification_type": "sha256",
|
||||||
"verification_source": "33930d432593e49d58a9bff4c30078823e9af5d98594d2935862788ce8a20aec",
|
"verification_source": "7fe294b02b25b51acb8e8e0a0eb5af6bbafa7cd0c5b0e5fcbb61263104a82fbc",
|
||||||
"extract_command": "tar -C backend --strip 1 -xf",
|
"extract_command": "tar -C backend --strip 1 -xf",
|
||||||
"exclude_files": ["bin/bitcoin-qt"],
|
"exclude_files": ["bin/bitcoin-qt"],
|
||||||
"exec_command_template": "{{.Env.BackendInstallPath}}/{{.Coin.Alias}}/bin/bitcoind -datadir={{.Env.BackendDataPath}}/{{.Coin.Alias}}/backend -conf={{.Env.BackendInstallPath}}/{{.Coin.Alias}}/{{.Coin.Alias}}.conf -pid=/run/{{.Coin.Alias}}/{{.Coin.Alias}}.pid",
|
"exec_command_template": "{{.Env.BackendInstallPath}}/{{.Coin.Alias}}/bin/bitcoind -datadir={{.Env.BackendDataPath}}/{{.Coin.Alias}}/backend -conf={{.Env.BackendInstallPath}}/{{.Coin.Alias}}/{{.Coin.Alias}}.conf -pid=/run/{{.Coin.Alias}}/{{.Coin.Alias}}.pid",
|
||||||
@ -38,12 +38,13 @@
|
|||||||
"server_config_file": "bitcoin.conf",
|
"server_config_file": "bitcoin.conf",
|
||||||
"client_config_file": "bitcoin_client.conf",
|
"client_config_file": "bitcoin_client.conf",
|
||||||
"additional_params": {
|
"additional_params": {
|
||||||
"deprecatedrpc": "estimatefee"
|
"deprecatedrpc": "estimatefee",
|
||||||
|
"addnode": ["ove.palatinus.cz"]
|
||||||
},
|
},
|
||||||
"platforms": {
|
"platforms": {
|
||||||
"arm64": {
|
"arm64": {
|
||||||
"binary_url": "https://bitcoincore.org/bin/bitcoin-core-25.0/bitcoin-25.0-aarch64-linux-gnu.tar.gz",
|
"binary_url": "https://bitcoincore.org/bin/bitcoin-core-28.0/bitcoin-28.0-aarch64-linux-gnu.tar.gz",
|
||||||
"verification_source": "3a7bdd959a0b426624f63f394f25e5b7769a5a2f96f8126dcc2ea53f3fa5212b"
|
"verification_source": "7fa582d99a25c354d23e371a5848bd9e6a79702870f9cbbf1292b86e647d0f4e"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
@ -63,13 +64,17 @@
|
|||||||
"xpub_magic_segwit_p2sh": 77429938,
|
"xpub_magic_segwit_p2sh": 77429938,
|
||||||
"xpub_magic_segwit_native": 78792518,
|
"xpub_magic_segwit_native": 78792518,
|
||||||
"additional_params": {
|
"additional_params": {
|
||||||
"alternative_estimate_fee": "whatthefee-disabled",
|
"alternative_estimate_fee": "mempoolspace",
|
||||||
"alternative_estimate_fee_params": "{\"url\": \"https://whatthefee.io/data.json\", \"periodSeconds\": 60}",
|
"alternative_estimate_fee_params": "{\"url\": \"https://mempool.space/api/v1/fees/recommended\", \"periodSeconds\": 20}",
|
||||||
"fiat_rates": "coingecko",
|
"fiat_rates": "coingecko",
|
||||||
"fiat_rates_vs_currencies": "AED,ARS,AUD,BDT,BHD,BMD,BRL,CAD,CHF,CLP,CNY,CZK,DKK,EUR,GBP,HKD,HUF,IDR,ILS,INR,JPY,KRW,KWD,LKR,MMK,MXN,MYR,NGN,NOK,NZD,PHP,PKR,PLN,RUB,SAR,SEK,SGD,THB,TRY,TWD,UAH,USD,VEF,VND,ZAR,BTC,ETH",
|
"fiat_rates_vs_currencies": "AED,ARS,AUD,BDT,BHD,BMD,BRL,CAD,CHF,CLP,CNY,CZK,DKK,EUR,GBP,HKD,HUF,IDR,ILS,INR,JPY,KRW,KWD,LKR,MMK,MXN,MYR,NGN,NOK,NZD,PHP,PKR,PLN,RUB,SAR,SEK,SGD,THB,TRY,TWD,UAH,USD,VEF,VND,ZAR,BTC,ETH",
|
||||||
"fiat_rates_params": "{\"coin\": \"bitcoin\", \"periodSeconds\": 900}",
|
"fiat_rates_params": "{\"coin\": \"bitcoin\", \"periodSeconds\": 60}",
|
||||||
"golomb_filter_p": 20,
|
"block_golomb_filter_p": 20,
|
||||||
"mempool_filter_scripts": "taproot"
|
"block_filter_scripts": "taproot-noordinals",
|
||||||
|
"block_filter_use_zeroed_key": true,
|
||||||
|
"mempool_golomb_filter_p": 20,
|
||||||
|
"mempool_filter_scripts": "taproot",
|
||||||
|
"mempool_filter_use_zeroed_key": false
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|||||||
@ -22,10 +22,10 @@
|
|||||||
"package_name": "backend-bitcoin-regtest",
|
"package_name": "backend-bitcoin-regtest",
|
||||||
"package_revision": "satoshilabs-1",
|
"package_revision": "satoshilabs-1",
|
||||||
"system_user": "bitcoin",
|
"system_user": "bitcoin",
|
||||||
"version": "25.0",
|
"version": "28.0",
|
||||||
"binary_url": "https://bitcoincore.org/bin/bitcoin-core-25.0/bitcoin-25.0-x86_64-linux-gnu.tar.gz",
|
"binary_url": "https://bitcoincore.org/bin/bitcoin-core-28.0/bitcoin-28.0-x86_64-linux-gnu.tar.gz",
|
||||||
"verification_type": "sha256",
|
"verification_type": "sha256",
|
||||||
"verification_source": "33930d432593e49d58a9bff4c30078823e9af5d98594d2935862788ce8a20aec",
|
"verification_source": "7fe294b02b25b51acb8e8e0a0eb5af6bbafa7cd0c5b0e5fcbb61263104a82fbc",
|
||||||
"extract_command": "tar -C backend --strip 1 -xf",
|
"extract_command": "tar -C backend --strip 1 -xf",
|
||||||
"exclude_files": ["bin/bitcoin-qt"],
|
"exclude_files": ["bin/bitcoin-qt"],
|
||||||
"exec_command_template": "{{.Env.BackendInstallPath}}/{{.Coin.Alias}}/bin/bitcoind -datadir={{.Env.BackendDataPath}}/{{.Coin.Alias}}/backend -conf={{.Env.BackendInstallPath}}/{{.Coin.Alias}}/{{.Coin.Alias}}.conf -pid=/run/{{.Coin.Alias}}/{{.Coin.Alias}}.pid",
|
"exec_command_template": "{{.Env.BackendInstallPath}}/{{.Coin.Alias}}/bin/bitcoind -datadir={{.Env.BackendDataPath}}/{{.Coin.Alias}}/backend -conf={{.Env.BackendInstallPath}}/{{.Coin.Alias}}/{{.Coin.Alias}}.conf -pid=/run/{{.Coin.Alias}}/{{.Coin.Alias}}.pid",
|
||||||
@ -42,8 +42,8 @@
|
|||||||
},
|
},
|
||||||
"platforms": {
|
"platforms": {
|
||||||
"arm64": {
|
"arm64": {
|
||||||
"binary_url": "https://bitcoincore.org/bin/bitcoin-core-25.0/bitcoin-25.0-aarch64-linux-gnu.tar.gz",
|
"binary_url": "https://bitcoincore.org/bin/bitcoin-core-28.0/bitcoin-28.0-aarch64-linux-gnu.tar.gz",
|
||||||
"verification_source": "3a7bdd959a0b426624f63f394f25e5b7769a5a2f96f8126dcc2ea53f3fa5212b"
|
"verification_source": "7fa582d99a25c354d23e371a5848bd9e6a79702870f9cbbf1292b86e647d0f4e"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
@ -63,7 +63,14 @@
|
|||||||
"xpub_magic_segwit_p2sh": 71979618,
|
"xpub_magic_segwit_p2sh": 71979618,
|
||||||
"xpub_magic_segwit_native": 73342198,
|
"xpub_magic_segwit_native": 73342198,
|
||||||
"slip44": 1,
|
"slip44": 1,
|
||||||
"additional_params": {}
|
"additional_params": {
|
||||||
|
"block_golomb_filter_p": 20,
|
||||||
|
"block_filter_scripts": "taproot-noordinals",
|
||||||
|
"block_filter_use_zeroed_key": true,
|
||||||
|
"mempool_golomb_filter_p": 20,
|
||||||
|
"mempool_filter_scripts": "taproot",
|
||||||
|
"mempool_filter_use_zeroed_key": false
|
||||||
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"meta": {
|
"meta": {
|
||||||
|
|||||||
@ -22,10 +22,10 @@
|
|||||||
"package_name": "backend-bitcoin-signet",
|
"package_name": "backend-bitcoin-signet",
|
||||||
"package_revision": "satoshilabs-1",
|
"package_revision": "satoshilabs-1",
|
||||||
"system_user": "bitcoin",
|
"system_user": "bitcoin",
|
||||||
"version": "25.0",
|
"version": "28.0",
|
||||||
"binary_url": "https://bitcoincore.org/bin/bitcoin-core-25.0/bitcoin-25.0-x86_64-linux-gnu.tar.gz",
|
"binary_url": "https://bitcoincore.org/bin/bitcoin-core-28.0/bitcoin-28.0-x86_64-linux-gnu.tar.gz",
|
||||||
"verification_type": "sha256",
|
"verification_type": "sha256",
|
||||||
"verification_source": "33930d432593e49d58a9bff4c30078823e9af5d98594d2935862788ce8a20aec",
|
"verification_source": "7fe294b02b25b51acb8e8e0a0eb5af6bbafa7cd0c5b0e5fcbb61263104a82fbc",
|
||||||
"extract_command": "tar -C backend --strip 1 -xf",
|
"extract_command": "tar -C backend --strip 1 -xf",
|
||||||
"exclude_files": ["bin/bitcoin-qt"],
|
"exclude_files": ["bin/bitcoin-qt"],
|
||||||
"exec_command_template": "{{.Env.BackendInstallPath}}/{{.Coin.Alias}}/bin/bitcoind -datadir={{.Env.BackendDataPath}}/{{.Coin.Alias}}/backend -conf={{.Env.BackendInstallPath}}/{{.Coin.Alias}}/{{.Coin.Alias}}.conf -pid=/run/{{.Coin.Alias}}/{{.Coin.Alias}}.pid",
|
"exec_command_template": "{{.Env.BackendInstallPath}}/{{.Coin.Alias}}/bin/bitcoind -datadir={{.Env.BackendDataPath}}/{{.Coin.Alias}}/backend -conf={{.Env.BackendInstallPath}}/{{.Coin.Alias}}/{{.Coin.Alias}}.conf -pid=/run/{{.Coin.Alias}}/{{.Coin.Alias}}.pid",
|
||||||
@ -35,15 +35,15 @@
|
|||||||
"service_additional_params_template": "",
|
"service_additional_params_template": "",
|
||||||
"protect_memory": true,
|
"protect_memory": true,
|
||||||
"mainnet": false,
|
"mainnet": false,
|
||||||
"server_config_file": "bitcoin-signet.conf",
|
"server_config_file": "bitcoin_signet.conf",
|
||||||
"client_config_file": "bitcoin_client.conf",
|
"client_config_file": "bitcoin_client.conf",
|
||||||
"additional_params": {
|
"additional_params": {
|
||||||
"deprecatedrpc": "estimatefee"
|
"deprecatedrpc": "estimatefee"
|
||||||
},
|
},
|
||||||
"platforms": {
|
"platforms": {
|
||||||
"arm64": {
|
"arm64": {
|
||||||
"binary_url": "https://bitcoincore.org/bin/bitcoin-core-25.0/bitcoin-25.0-aarch64-linux-gnu.tar.gz",
|
"binary_url": "https://bitcoincore.org/bin/bitcoin-core-28.0/bitcoin-28.0-aarch64-linux-gnu.tar.gz",
|
||||||
"verification_source": "3a7bdd959a0b426624f63f394f25e5b7769a5a2f96f8126dcc2ea53f3fa5212b"
|
"verification_source": "7fa582d99a25c354d23e371a5848bd9e6a79702870f9cbbf1292b86e647d0f4e"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|||||||
@ -22,10 +22,10 @@
|
|||||||
"package_name": "backend-bitcoin-testnet",
|
"package_name": "backend-bitcoin-testnet",
|
||||||
"package_revision": "satoshilabs-1",
|
"package_revision": "satoshilabs-1",
|
||||||
"system_user": "bitcoin",
|
"system_user": "bitcoin",
|
||||||
"version": "25.0",
|
"version": "28.0",
|
||||||
"binary_url": "https://bitcoincore.org/bin/bitcoin-core-25.0/bitcoin-25.0-x86_64-linux-gnu.tar.gz",
|
"binary_url": "https://bitcoincore.org/bin/bitcoin-core-28.0/bitcoin-28.0-x86_64-linux-gnu.tar.gz",
|
||||||
"verification_type": "sha256",
|
"verification_type": "sha256",
|
||||||
"verification_source": "33930d432593e49d58a9bff4c30078823e9af5d98594d2935862788ce8a20aec",
|
"verification_source": "7fe294b02b25b51acb8e8e0a0eb5af6bbafa7cd0c5b0e5fcbb61263104a82fbc",
|
||||||
"extract_command": "tar -C backend --strip 1 -xf",
|
"extract_command": "tar -C backend --strip 1 -xf",
|
||||||
"exclude_files": ["bin/bitcoin-qt"],
|
"exclude_files": ["bin/bitcoin-qt"],
|
||||||
"exec_command_template": "{{.Env.BackendInstallPath}}/{{.Coin.Alias}}/bin/bitcoind -datadir={{.Env.BackendDataPath}}/{{.Coin.Alias}}/backend -conf={{.Env.BackendInstallPath}}/{{.Coin.Alias}}/{{.Coin.Alias}}.conf -pid=/run/{{.Coin.Alias}}/{{.Coin.Alias}}.pid",
|
"exec_command_template": "{{.Env.BackendInstallPath}}/{{.Coin.Alias}}/bin/bitcoind -datadir={{.Env.BackendDataPath}}/{{.Coin.Alias}}/backend -conf={{.Env.BackendInstallPath}}/{{.Coin.Alias}}/{{.Coin.Alias}}.conf -pid=/run/{{.Coin.Alias}}/{{.Coin.Alias}}.pid",
|
||||||
@ -42,8 +42,8 @@
|
|||||||
},
|
},
|
||||||
"platforms": {
|
"platforms": {
|
||||||
"arm64": {
|
"arm64": {
|
||||||
"binary_url": "https://bitcoincore.org/bin/bitcoin-core-25.0/bitcoin-25.0-aarch64-linux-gnu.tar.gz",
|
"binary_url": "https://bitcoincore.org/bin/bitcoin-core-28.0/bitcoin-28.0-aarch64-linux-gnu.tar.gz",
|
||||||
"verification_source": "3a7bdd959a0b426624f63f394f25e5b7769a5a2f96f8126dcc2ea53f3fa5212b"
|
"verification_source": "7fa582d99a25c354d23e371a5848bd9e6a79702870f9cbbf1292b86e647d0f4e"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
@ -58,14 +58,18 @@
|
|||||||
"parse": true,
|
"parse": true,
|
||||||
"mempool_workers": 8,
|
"mempool_workers": 8,
|
||||||
"mempool_sub_workers": 2,
|
"mempool_sub_workers": 2,
|
||||||
"block_addresses_to_keep": 300,
|
"block_addresses_to_keep": 10000,
|
||||||
"xpub_magic": 70617039,
|
"xpub_magic": 70617039,
|
||||||
"xpub_magic_segwit_p2sh": 71979618,
|
"xpub_magic_segwit_p2sh": 71979618,
|
||||||
"xpub_magic_segwit_native": 73342198,
|
"xpub_magic_segwit_native": 73342198,
|
||||||
"slip44": 1,
|
"slip44": 1,
|
||||||
"additional_params": {
|
"additional_params": {
|
||||||
"golomb_filter_p": 20,
|
"block_golomb_filter_p": 20,
|
||||||
"mempool_filter_scripts": "taproot"
|
"block_filter_scripts": "taproot-noordinals",
|
||||||
|
"block_filter_use_zeroed_key": true,
|
||||||
|
"mempool_golomb_filter_p": 20,
|
||||||
|
"mempool_filter_scripts": "taproot",
|
||||||
|
"mempool_filter_use_zeroed_key": false
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|||||||
80
configs/coins/bitcoin_testnet4.json
Normal file
80
configs/coins/bitcoin_testnet4.json
Normal file
@ -0,0 +1,80 @@
|
|||||||
|
{
|
||||||
|
"coin": {
|
||||||
|
"name": "Testnet4",
|
||||||
|
"shortcut": "TEST",
|
||||||
|
"label": "Bitcoin Testnet4",
|
||||||
|
"alias": "bitcoin_testnet4"
|
||||||
|
},
|
||||||
|
"ports": {
|
||||||
|
"backend_rpc": 18029,
|
||||||
|
"backend_message_queue": 48329,
|
||||||
|
"blockbook_internal": 19029,
|
||||||
|
"blockbook_public": 19129
|
||||||
|
},
|
||||||
|
"ipc": {
|
||||||
|
"rpc_url_template": "http://127.0.0.1:{{.Ports.BackendRPC}}",
|
||||||
|
"rpc_user": "rpc",
|
||||||
|
"rpc_pass": "rpc",
|
||||||
|
"rpc_timeout": 25,
|
||||||
|
"message_queue_binding_template": "tcp://127.0.0.1:{{.Ports.BackendMessageQueue}}"
|
||||||
|
},
|
||||||
|
"backend": {
|
||||||
|
"package_name": "backend-bitcoin-testnet4",
|
||||||
|
"package_revision": "satoshilabs-1",
|
||||||
|
"system_user": "bitcoin",
|
||||||
|
"version": "28.0",
|
||||||
|
"binary_url": "https://bitcoincore.org/bin/bitcoin-core-28.0/bitcoin-28.0-x86_64-linux-gnu.tar.gz",
|
||||||
|
"verification_type": "sha256",
|
||||||
|
"verification_source": "7fe294b02b25b51acb8e8e0a0eb5af6bbafa7cd0c5b0e5fcbb61263104a82fbc",
|
||||||
|
"extract_command": "tar -C backend --strip 1 -xf",
|
||||||
|
"exclude_files": ["bin/bitcoin-qt"],
|
||||||
|
"exec_command_template": "{{.Env.BackendInstallPath}}/{{.Coin.Alias}}/bin/bitcoind -datadir={{.Env.BackendDataPath}}/{{.Coin.Alias}}/backend -conf={{.Env.BackendInstallPath}}/{{.Coin.Alias}}/{{.Coin.Alias}}.conf -pid=/run/{{.Coin.Alias}}/{{.Coin.Alias}}.pid",
|
||||||
|
"logrotate_files_template": "{{.Env.BackendDataPath}}/{{.Coin.Alias}}/backend/testnet4/*.log",
|
||||||
|
"postinst_script_template": "",
|
||||||
|
"service_type": "forking",
|
||||||
|
"service_additional_params_template": "",
|
||||||
|
"protect_memory": true,
|
||||||
|
"mainnet": false,
|
||||||
|
"server_config_file": "bitcoin_testnet4.conf",
|
||||||
|
"client_config_file": "bitcoin_client.conf",
|
||||||
|
"additional_params": {
|
||||||
|
"deprecatedrpc": "estimatefee"
|
||||||
|
},
|
||||||
|
"platforms": {
|
||||||
|
"arm64": {
|
||||||
|
"binary_url": "https://bitcoincore.org/bin/bitcoin-core-28.0/bitcoin-28.0-aarch64-linux-gnu.tar.gz",
|
||||||
|
"verification_source": "7fa582d99a25c354d23e371a5848bd9e6a79702870f9cbbf1292b86e647d0f4e"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"blockbook": {
|
||||||
|
"package_name": "blockbook-bitcoin-testnet4",
|
||||||
|
"system_user": "blockbook-bitcoin",
|
||||||
|
"internal_binding_template": ":{{.Ports.BlockbookInternal}}",
|
||||||
|
"public_binding_template": ":{{.Ports.BlockbookPublic}}",
|
||||||
|
"explorer_url": "",
|
||||||
|
"additional_params": "-enablesubnewtx -extendedindex",
|
||||||
|
"block_chain": {
|
||||||
|
"parse": true,
|
||||||
|
"mempool_workers": 8,
|
||||||
|
"mempool_sub_workers": 2,
|
||||||
|
"block_addresses_to_keep": 10000,
|
||||||
|
"xpub_magic": 70617039,
|
||||||
|
"xpub_magic_segwit_p2sh": 71979618,
|
||||||
|
"xpub_magic_segwit_native": 73342198,
|
||||||
|
"slip44": 1,
|
||||||
|
"additional_params": {
|
||||||
|
"block_golomb_filter_p": 20,
|
||||||
|
"block_filter_scripts": "taproot-noordinals",
|
||||||
|
"block_filter_use_zeroed_key": true,
|
||||||
|
"mempool_golomb_filter_p": 20,
|
||||||
|
"mempool_filter_scripts": "taproot",
|
||||||
|
"mempool_filter_use_zeroed_key": false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"meta": {
|
||||||
|
"package_maintainer": "IT",
|
||||||
|
"package_maintainer_email": "it@satoshilabs.com"
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -2,6 +2,7 @@
|
|||||||
"coin": {
|
"coin": {
|
||||||
"name": "BNB Smart Chain",
|
"name": "BNB Smart Chain",
|
||||||
"shortcut": "BNB",
|
"shortcut": "BNB",
|
||||||
|
"network": "BSC",
|
||||||
"label": "BNB Smart Chain",
|
"label": "BNB Smart Chain",
|
||||||
"alias": "bsc"
|
"alias": "bsc"
|
||||||
},
|
},
|
||||||
|
|||||||
@ -2,6 +2,7 @@
|
|||||||
"coin": {
|
"coin": {
|
||||||
"name": "BNB Smart Chain Archive",
|
"name": "BNB Smart Chain Archive",
|
||||||
"shortcut": "BNB",
|
"shortcut": "BNB",
|
||||||
|
"network": "BSC",
|
||||||
"label": "BNB Smart Chain",
|
"label": "BNB Smart Chain",
|
||||||
"alias": "bsc_archive"
|
"alias": "bsc_archive"
|
||||||
},
|
},
|
||||||
|
|||||||
@ -22,10 +22,10 @@
|
|||||||
"package_name": "backend-dash",
|
"package_name": "backend-dash",
|
||||||
"package_revision": "satoshilabs-1",
|
"package_revision": "satoshilabs-1",
|
||||||
"system_user": "dash",
|
"system_user": "dash",
|
||||||
"version": "19.2.0",
|
"version": "22.0.0",
|
||||||
"binary_url": "https://github.com/dashpay/dash/releases/download/v19.2.0/dashcore-19.2.0-x86_64-linux-gnu.tar.gz",
|
"binary_url": "https://github.com/dashpay/dash/releases/download/v22.0.0/dashcore-22.0.0-x86_64-linux-gnu.tar.gz",
|
||||||
"verification_type": "gpg-sha256",
|
"verification_type": "gpg-sha256",
|
||||||
"verification_source": "https://github.com/dashpay/dash/releases/download/v19.2.0/SHA256SUMS.asc",
|
"verification_source": "https://github.com/dashpay/dash/releases/download/v22.0.0/SHA256SUMS.asc",
|
||||||
"extract_command": "tar -C backend --strip 1 -xf",
|
"extract_command": "tar -C backend --strip 1 -xf",
|
||||||
"exclude_files": ["bin/dash-qt"],
|
"exclude_files": ["bin/dash-qt"],
|
||||||
"exec_command_template": "{{.Env.BackendInstallPath}}/{{.Coin.Alias}}/bin/dashd -deprecatedrpc=estimatefee -datadir={{.Env.BackendDataPath}}/{{.Coin.Alias}}/backend -conf={{.Env.BackendInstallPath}}/{{.Coin.Alias}}/{{.Coin.Alias}}.conf -pid=/run/{{.Coin.Alias}}/{{.Coin.Alias}}.pid",
|
"exec_command_template": "{{.Env.BackendInstallPath}}/{{.Coin.Alias}}/bin/dashd -deprecatedrpc=estimatefee -datadir={{.Env.BackendDataPath}}/{{.Coin.Alias}}/backend -conf={{.Env.BackendInstallPath}}/{{.Coin.Alias}}/{{.Coin.Alias}}.conf -pid=/run/{{.Coin.Alias}}/{{.Coin.Alias}}.pid",
|
||||||
|
|||||||
@ -22,10 +22,10 @@
|
|||||||
"package_name": "backend-dash-testnet",
|
"package_name": "backend-dash-testnet",
|
||||||
"package_revision": "satoshilabs-1",
|
"package_revision": "satoshilabs-1",
|
||||||
"system_user": "dash",
|
"system_user": "dash",
|
||||||
"version": "19.2.0",
|
"version": "22.0.0",
|
||||||
"binary_url": "https://github.com/dashpay/dash/releases/download/v19.2.0/dashcore-19.2.0-x86_64-linux-gnu.tar.gz",
|
"binary_url": "https://github.com/dashpay/dash/releases/download/v22.0.0/dashcore-22.0.0-x86_64-linux-gnu.tar.gz",
|
||||||
"verification_type": "gpg-sha256",
|
"verification_type": "gpg-sha256",
|
||||||
"verification_source": "https://github.com/dashpay/dash/releases/download/v19.2.0/SHA256SUMS.asc",
|
"verification_source": "https://github.com/dashpay/dash/releases/download/v22.0.0/SHA256SUMS.asc",
|
||||||
"extract_command": "tar -C backend --strip 1 -xf",
|
"extract_command": "tar -C backend --strip 1 -xf",
|
||||||
"exclude_files": [
|
"exclude_files": [
|
||||||
"bin/dash-qt"
|
"bin/dash-qt"
|
||||||
|
|||||||
@ -22,10 +22,10 @@
|
|||||||
"package_name": "backend-dogecoin",
|
"package_name": "backend-dogecoin",
|
||||||
"package_revision": "satoshilabs-1",
|
"package_revision": "satoshilabs-1",
|
||||||
"system_user": "dogecoin",
|
"system_user": "dogecoin",
|
||||||
"version": "1.14.6",
|
"version": "1.14.9",
|
||||||
"binary_url": "https://github.com/dogecoin/dogecoin/releases/download/v1.14.6/dogecoin-1.14.6-x86_64-linux-gnu.tar.gz",
|
"binary_url": "https://github.com/dogecoin/dogecoin/releases/download/v1.14.9/dogecoin-1.14.9-x86_64-linux-gnu.tar.gz",
|
||||||
"verification_type": "sha256",
|
"verification_type": "sha256",
|
||||||
"verification_source": "fe9c9cdab946155866a5bd5a5127d2971a9eed3e0b65fb553fe393ad1daaebb0",
|
"verification_source": "4f227117b411a7c98622c970986e27bcfc3f547a72bef65e7d9e82989175d4f8",
|
||||||
"extract_command": "tar -C backend --strip 1 -xf",
|
"extract_command": "tar -C backend --strip 1 -xf",
|
||||||
"exclude_files": ["bin/dogecoin-qt"],
|
"exclude_files": ["bin/dogecoin-qt"],
|
||||||
"exec_command_template": "{{.Env.BackendInstallPath}}/{{.Coin.Alias}}/bin/dogecoind -datadir={{.Env.BackendDataPath}}/{{.Coin.Alias}}/backend -conf={{.Env.BackendInstallPath}}/{{.Coin.Alias}}/{{.Coin.Alias}}.conf -pid=/run/{{.Coin.Alias}}/{{.Coin.Alias}}.pid",
|
"exec_command_template": "{{.Env.BackendInstallPath}}/{{.Coin.Alias}}/bin/dogecoind -datadir={{.Env.BackendDataPath}}/{{.Coin.Alias}}/backend -conf={{.Env.BackendInstallPath}}/{{.Coin.Alias}}/{{.Coin.Alias}}.conf -pid=/run/{{.Coin.Alias}}/{{.Coin.Alias}}.pid",
|
||||||
@ -45,8 +45,8 @@
|
|||||||
},
|
},
|
||||||
"platforms": {
|
"platforms": {
|
||||||
"arm64": {
|
"arm64": {
|
||||||
"binary_url": "https://github.com/dogecoin/dogecoin/releases/download/v1.14.6/dogecoin-1.14.6-aarch64-linux-gnu.tar.gz",
|
"binary_url": "https://github.com/dogecoin/dogecoin/releases/download/v1.14.9/dogecoin-1.14.9-aarch64-linux-gnu.tar.gz",
|
||||||
"verification_source": "87419c29607b2612746fccebd694037e4be7600fc32198c4989f919be20952db",
|
"verification_source": "6928c895a20d0bcb6d5c7dcec753d35c884a471aaf8ad4242a89a96acb4f2985",
|
||||||
"exclude_files": []
|
"exclude_files": []
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue
Block a user