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
|
||||
tags:
|
||||
- blockbook
|
||||
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
|
||||
script: ./contrib/scripts/backend-deploy-and-test.sh zcash_testnet zcash-testnet zcash=test testnet3/debug.log
|
||||
10
Makefile
10
Makefile
@ -1,9 +1,10 @@
|
||||
BIN_IMAGE = blockbook-build
|
||||
DEB_IMAGE = blockbook-build-deb
|
||||
PACKAGER = $(shell id -u):$(shell id -g)
|
||||
DOCKER_VERSION = $(shell docker version --format '{{.Client.Version}}')
|
||||
BASE_IMAGE = $$(awk -F= '$$1=="ID" { print $$2 ;}' /etc/os-release):$$(awk -F= '$$1=="VERSION_ID" { print $$2 ;}' /etc/os-release | tr -d '"')
|
||||
NO_CACHE = false
|
||||
TCMALLOC =
|
||||
TCMALLOC =
|
||||
PORTABLE = 0
|
||||
ARGS ?=
|
||||
|
||||
@ -27,7 +28,7 @@ test-all: .bin-image
|
||||
docker run -t --rm -e PACKAGER=$(PACKAGER) -v "$(CURDIR):/src" --network="host" $(BIN_IMAGE) make test-all ARGS="$(ARGS)"
|
||||
|
||||
deb-backend-%: .deb-image
|
||||
docker run -t --rm -e PACKAGER=$(PACKAGER) -v "$(CURDIR):/src" -v "$(CURDIR)/build:/out" $(DEB_IMAGE) /build/build-deb.sh backend $* $(ARGS)
|
||||
docker run -t --rm -e PACKAGER=$(PACKAGER) -v /var/run/docker.sock:/var/run/docker.sock -v "$(CURDIR):/src" -v "$(CURDIR)/build:/out" $(DEB_IMAGE) /build/build-deb.sh backend $* $(ARGS)
|
||||
|
||||
deb-blockbook-%: .deb-image
|
||||
docker run -t --rm -e PACKAGER=$(PACKAGER) -v "$(CURDIR):/src" -v "$(CURDIR)/build:/out" $(DEB_IMAGE) /build/build-deb.sh blockbook $* $(ARGS)
|
||||
@ -55,7 +56,7 @@ build-images: clean-images
|
||||
.deb-image: .bin-image
|
||||
@if [ $$(build/tools/image_status.sh $(DEB_IMAGE):latest build/docker) != "ok" ]; then \
|
||||
echo "Building image $(DEB_IMAGE)..."; \
|
||||
docker build --no-cache=$(NO_CACHE) -t $(DEB_IMAGE) build/docker/deb; \
|
||||
docker build --no-cache=$(NO_CACHE) --build-arg DOCKER_VERSION=$(DOCKER_VERSION) -t $(DEB_IMAGE) build/docker/deb; \
|
||||
else \
|
||||
echo "Image $(DEB_IMAGE) is up to date"; \
|
||||
fi
|
||||
@ -79,3 +80,6 @@ clean-bin-image:
|
||||
|
||||
clean-deb-image:
|
||||
- docker rmi $(DEB_IMAGE)
|
||||
|
||||
style:
|
||||
find . -name "*.go" -exec gofmt -w {} \;
|
||||
|
||||
154
README.md
154
README.md
@ -1,8 +1,154 @@
|
||||
[](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** 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
|
||||
- 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:
|
||||
|
||||
- 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).
|
||||
|
||||
@ -74,3 +220,7 @@ Blockbook stores data the key-value store RocksDB. Database format is described
|
||||
## API
|
||||
|
||||
Blockbook API is described [here](/docs/api.md).
|
||||
|
||||
## Environment variables
|
||||
|
||||
List of environment variables that affect Blockbook's behavior is [here](/docs/env.md).
|
||||
|
||||
@ -62,7 +62,7 @@ func (w *Worker) RefetchInternalDataRoutine() {
|
||||
if block != nil {
|
||||
blockSpecificData, _ = block.CoinSpecificData.(*bchain.EthereumBlockSpecificData)
|
||||
}
|
||||
if err != nil || block == nil || blockSpecificData == nil || blockSpecificData.InternalDataError != "" {
|
||||
if err != nil || block == nil || (blockSpecificData != nil && blockSpecificData.InternalDataError != "") {
|
||||
glog.Errorf("Refetching internal data for %d %s, error %v, retrying", ie.Height, ie.Hash, err)
|
||||
// try for second time to fetch the data - the 2nd attempt after the first unsuccessful has many times higher probability of success
|
||||
// probably something to do with data preloaded to cache on the backend
|
||||
|
||||
28
api/types.go
28
api/types.go
@ -208,9 +208,9 @@ type TokenTransfer struct {
|
||||
From string `json:"from"`
|
||||
To string `json:"to"`
|
||||
Contract string `json:"contract"`
|
||||
Name string `json:"name"`
|
||||
Symbol string `json:"symbol"`
|
||||
Decimals int `json:"decimals"`
|
||||
Name string `json:"name,omitempty"`
|
||||
Symbol string `json:"symbol,omitempty"`
|
||||
Decimals int `json:"decimals,omitempty"`
|
||||
Value *Amount `json:"value,omitempty"`
|
||||
MultiTokenValues []MultiTokenValue `json:"multiTokenValues,omitempty"`
|
||||
}
|
||||
@ -231,7 +231,11 @@ type EthereumSpecific struct {
|
||||
Nonce uint64 `json:"nonce"`
|
||||
GasLimit *big.Int `json:"gasLimit"`
|
||||
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"`
|
||||
ParsedData *bchain.EthereumParsedInputData `json:"parsedData,omitempty"`
|
||||
InternalTransfers []EthereumInternalTransfer `json:"internalTransfers,omitempty"`
|
||||
@ -316,6 +320,19 @@ type AddressFilter struct {
|
||||
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
|
||||
type Address struct {
|
||||
Paging
|
||||
@ -342,6 +359,7 @@ type Address struct {
|
||||
ContractInfo *bchain.ContractInfo `json:"contractInfo,omitempty"`
|
||||
Erc20Contract *bchain.ContractInfo `json:"erc20Contract,omitempty"` // deprecated
|
||||
AddressAliases AddressAliasesMap `json:"addressAliases,omitempty"`
|
||||
StakingPools []StakingPool `json:"stakingPools,omitempty"`
|
||||
// helpers for explorer
|
||||
Filter string `json:"-"`
|
||||
XPubAddresses map[string]struct{} `json:"-"`
|
||||
@ -485,6 +503,7 @@ type BlockRaw struct {
|
||||
// BlockbookInfo contains information about the running blockbook instance
|
||||
type BlockbookInfo struct {
|
||||
Coin string `json:"coin"`
|
||||
Network string `json:"network"`
|
||||
Host string `json:"host"`
|
||||
Version string `json:"version"`
|
||||
GitCommit string `json:"gitCommit"`
|
||||
@ -504,6 +523,7 @@ type BlockbookInfo struct {
|
||||
CurrentFiatRatesTime *time.Time `json:"currentFiatRatesTime,omitempty"`
|
||||
HistoricalFiatRatesTime *time.Time `json:"historicalFiatRatesTime,omitempty"`
|
||||
HistoricalTokenFiatRatesTime *time.Time `json:"historicalTokenFiatRatesTime,omitempty"`
|
||||
SupportedStakingPools []string `json:"supportedStakingPools,omitempty"`
|
||||
DbSizeFromColumns int64 `json:"dbSizeFromColumns,omitempty"`
|
||||
DbColumns []common.InternalStateColumn `json:"dbColumns,omitempty"`
|
||||
About string `json:"about"`
|
||||
|
||||
@ -2,7 +2,8 @@ package api
|
||||
|
||||
import (
|
||||
"math/big"
|
||||
|
||||
"encoding/json"
|
||||
"strconv"
|
||||
"github.com/trezor/blockbook/bchain"
|
||||
)
|
||||
|
||||
@ -21,9 +22,10 @@ type VinV1 struct {
|
||||
ScriptSig ScriptSigV1 `json:"scriptSig"`
|
||||
AddrDesc bchain.AddressDescriptor `json:"-"`
|
||||
Addresses []string `json:"addresses"`
|
||||
IsAddress bool `json:"-"`
|
||||
Value string `json:"value"`
|
||||
ValueSat big.Int `json:"-"`
|
||||
IsAddress bool `json:"isAddress"`
|
||||
Value float64 `json:"value"`
|
||||
ValueSat big.Int `json:"valueSat"`
|
||||
Coinbase string `json:"coinbase,omitempty"`
|
||||
}
|
||||
|
||||
// ScriptPubKeyV1 is used for legacy api v1
|
||||
@ -32,14 +34,14 @@ type ScriptPubKeyV1 struct {
|
||||
Asm string `json:"asm,omitempty"`
|
||||
AddrDesc bchain.AddressDescriptor `json:"-"`
|
||||
Addresses []string `json:"addresses"`
|
||||
IsAddress bool `json:"-"`
|
||||
IsAddress bool `json:"isAddress"`
|
||||
Type string `json:"type,omitempty"`
|
||||
}
|
||||
|
||||
// VoutV1 is used for legacy api v1
|
||||
type VoutV1 struct {
|
||||
Value string `json:"value"`
|
||||
ValueSat big.Int `json:"-"`
|
||||
Value float64 `json:"value"`
|
||||
ValueSat big.Int `json:"valueSat"`
|
||||
N int `json:"n"`
|
||||
ScriptPubKey ScriptPubKeyV1 `json:"scriptPubKey"`
|
||||
Spent bool `json:"spent"`
|
||||
@ -52,7 +54,7 @@ type VoutV1 struct {
|
||||
type TxV1 struct {
|
||||
Txid string `json:"txid"`
|
||||
Version int32 `json:"version,omitempty"`
|
||||
Locktime uint32 `json:"locktime,omitempty"`
|
||||
Locktime uint32 `json:"locktime"`
|
||||
Vin []VinV1 `json:"vin"`
|
||||
Vout []VoutV1 `json:"vout"`
|
||||
Blockhash string `json:"blockhash,omitempty"`
|
||||
@ -60,24 +62,29 @@ type TxV1 struct {
|
||||
Confirmations uint32 `json:"confirmations"`
|
||||
Time int64 `json:"time,omitempty"`
|
||||
Blocktime int64 `json:"blocktime"`
|
||||
ValueOut string `json:"valueOut"`
|
||||
ValueOutSat big.Int `json:"-"`
|
||||
ValueOut float64 `json:"valueOut"`
|
||||
ValueOutSat big.Int `json:"valueOutSat"`
|
||||
Size int `json:"size,omitempty"`
|
||||
ValueIn string `json:"valueIn"`
|
||||
ValueInSat big.Int `json:"-"`
|
||||
Fees string `json:"fees"`
|
||||
FeesSat big.Int `json:"-"`
|
||||
ValueIn float64 `json:"valueIn"`
|
||||
ValueInSat big.Int `json:"valueInSat"`
|
||||
Fees float64 `json:"fees"`
|
||||
FeesSat big.Int `json:"feesSat"`
|
||||
Hex string `json:"hex"`
|
||||
FloData string `json:"floData,omitempty"`
|
||||
}
|
||||
|
||||
// AddressV1 is used for legacy api v1
|
||||
type AddressV1 struct {
|
||||
Paging
|
||||
AddrStr string `json:"addrStr"`
|
||||
Balance string `json:"balance"`
|
||||
TotalReceived string `json:"totalReceived"`
|
||||
TotalSent string `json:"totalSent"`
|
||||
UnconfirmedBalance string `json:"unconfirmedBalance"`
|
||||
Balance float64 `json:"balance"`
|
||||
BalanceSat big.Int `json:"balanceSat"`
|
||||
TotalReceived float64 `json:"totalReceived"`
|
||||
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"`
|
||||
TxApperances int `json:"txApperances"`
|
||||
Transactions []*TxV1 `json:"txs,omitempty"`
|
||||
@ -88,7 +95,7 @@ type AddressV1 struct {
|
||||
type AddressUtxoV1 struct {
|
||||
Txid string `json:"txid"`
|
||||
Vout uint32 `json:"vout"`
|
||||
Amount string `json:"amount"`
|
||||
Amount float64 `json:"amount"`
|
||||
AmountSat big.Int `json:"satoshis"`
|
||||
Height int `json:"height,omitempty"`
|
||||
Confirmations int `json:"confirmations"`
|
||||
@ -102,6 +109,15 @@ type BlockV1 struct {
|
||||
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
|
||||
func (w *Worker) TxToV1(tx *Tx) *TxV1 {
|
||||
d := w.chainParser.AmountDecimals()
|
||||
@ -119,9 +135,10 @@ func (w *Worker) TxToV1(tx *Tx) *TxV1 {
|
||||
IsAddress: v.IsAddress,
|
||||
Sequence: v.Sequence,
|
||||
Txid: v.Txid,
|
||||
Value: v.ValueSat.DecimalString(d),
|
||||
Value: stringToFloat(v.ValueSat.DecimalString(d)),
|
||||
ValueSat: v.ValueSat.AsBigInt(),
|
||||
Vout: v.Vout,
|
||||
Coinbase: v.Coinbase,
|
||||
}
|
||||
}
|
||||
voutV1 := make([]VoutV1, len(tx.Vout))
|
||||
@ -141,29 +158,39 @@ func (w *Worker) TxToV1(tx *Tx) *TxV1 {
|
||||
SpentHeight: v.SpentHeight,
|
||||
SpentIndex: v.SpentIndex,
|
||||
SpentTxID: v.SpentTxID,
|
||||
Value: v.ValueSat.DecimalString(d),
|
||||
Value: stringToFloat(v.ValueSat.DecimalString(d)),
|
||||
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{
|
||||
Blockhash: tx.Blockhash,
|
||||
Blockheight: tx.Blockheight,
|
||||
Blocktime: tx.Blocktime,
|
||||
Confirmations: tx.Confirmations,
|
||||
Fees: tx.FeesSat.DecimalString(d),
|
||||
Fees: stringToFloat(tx.FeesSat.DecimalString(d)),
|
||||
FeesSat: tx.FeesSat.AsBigInt(),
|
||||
Hex: tx.Hex,
|
||||
Locktime: tx.Locktime,
|
||||
Size: tx.Size,
|
||||
Time: tx.Blocktime,
|
||||
Txid: tx.Txid,
|
||||
ValueIn: tx.ValueInSat.DecimalString(d),
|
||||
ValueIn: stringToFloat(tx.ValueInSat.DecimalString(d)),
|
||||
ValueInSat: tx.ValueInSat.AsBigInt(),
|
||||
ValueOut: tx.ValueOutSat.DecimalString(d),
|
||||
ValueOut: stringToFloat(tx.ValueOutSat.DecimalString(d)),
|
||||
ValueOutSat: tx.ValueOutSat.AsBigInt(),
|
||||
Version: tx.Version,
|
||||
Vin: vinV1,
|
||||
Vout: voutV1,
|
||||
FloData: coinData.FloData, //(tx.CoinSpecificData).FloData
|
||||
}
|
||||
}
|
||||
|
||||
@ -180,14 +207,18 @@ func (w *Worker) AddressToV1(a *Address) *AddressV1 {
|
||||
d := w.chainParser.AmountDecimals()
|
||||
return &AddressV1{
|
||||
AddrStr: a.AddrStr,
|
||||
Balance: a.BalanceSat.DecimalString(d),
|
||||
Balance: stringToFloat(a.BalanceSat.DecimalString(d)),
|
||||
BalanceSat: a.BalanceSat.AsBigInt(),
|
||||
Paging: a.Paging,
|
||||
TotalReceived: a.TotalReceivedSat.DecimalString(d),
|
||||
TotalSent: a.TotalSentSat.DecimalString(d),
|
||||
TotalReceived: stringToFloat(a.TotalReceivedSat.DecimalString(d)),
|
||||
TotalReceivedSat: a.TotalReceivedSat.AsBigInt(),
|
||||
TotalSent: stringToFloat(a.TotalSentSat.DecimalString(d)),
|
||||
TotalSentSat: a.TotalSentSat.AsBigInt(),
|
||||
Transactions: w.transactionsToV1(a.Transactions),
|
||||
TxApperances: a.Txs,
|
||||
Txids: a.Txids,
|
||||
UnconfirmedBalance: a.UnconfirmedBalanceSat.DecimalString(d),
|
||||
UnconfirmedBalance: stringToFloat(a.UnconfirmedBalanceSat.DecimalString(d)),
|
||||
UnconfirmedBalanceSat: a.UnconfirmedBalanceSat.AsBigInt(),
|
||||
UnconfirmedTxApperances: a.UnconfirmedTxs,
|
||||
}
|
||||
}
|
||||
@ -200,7 +231,7 @@ func (w *Worker) AddressUtxoToV1(au Utxos) []AddressUtxoV1 {
|
||||
utxo := &au[i]
|
||||
v1[i] = AddressUtxoV1{
|
||||
AmountSat: utxo.AmountSat.AsBigInt(),
|
||||
Amount: utxo.AmountSat.DecimalString(d),
|
||||
Amount: stringToFloat(utxo.AmountSat.DecimalString(d)),
|
||||
Confirmations: utxo.Confirmations,
|
||||
Height: utxo.Height,
|
||||
Txid: utxo.Txid,
|
||||
|
||||
239
api/worker.go
239
api/worker.go
@ -36,6 +36,9 @@ type Worker struct {
|
||||
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
|
||||
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{
|
||||
@ -169,9 +172,18 @@ func (w *Worker) getAddressAliases(addresses map[string]struct{}) AddressAliases
|
||||
}
|
||||
for a := range addresses {
|
||||
if w.chainType == bchain.ChainEthereumType {
|
||||
ci, err := w.db.GetContractInfoForAddress(a)
|
||||
if err == nil && ci != nil && ci.Name != "" {
|
||||
aliases[a] = AddressAlias{Type: "Contract", Alias: ci.Name}
|
||||
addrDesc, err := w.chainParser.GetAddrDescFromAddress(a)
|
||||
if err != nil || addrDesc == nil {
|
||||
continue
|
||||
}
|
||||
ci, err := w.db.GetContractInfo(addrDesc, bchain.UnknownTokenType)
|
||||
if err == nil && ci != nil {
|
||||
if ci.Type == bchain.UnhandledTokenType {
|
||||
ci, _, err = w.getContractDescriptorInfo(addrDesc, bchain.UnknownTokenType)
|
||||
}
|
||||
if err == nil && ci != nil && ci.Name != "" {
|
||||
aliases[a] = AddressAlias{Type: "Contract", Alias: ci.Name}
|
||||
}
|
||||
}
|
||||
}
|
||||
n := w.db.GetAddressAlias(a)
|
||||
@ -187,7 +199,7 @@ func (w *Worker) getAddressAliases(addresses map[string]struct{}) AddressAliases
|
||||
// GetTransaction reads transaction data from txid
|
||||
func (w *Worker) GetTransaction(txid string, spendingTxs bool, specificJSON bool) (*Tx, error) {
|
||||
addresses := w.newAddressesMapForAliases()
|
||||
tx, err := w.getTransaction(txid, spendingTxs, specificJSON, addresses)
|
||||
tx, err := w.getTransaction(txid, spendingTxs, /*specificJSON*/ true, addresses)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
@ -195,6 +207,11 @@ func (w *Worker) GetTransaction(txid string, spendingTxs bool, specificJSON bool
|
||||
return tx, nil
|
||||
}
|
||||
|
||||
// GetRawTransaction gets raw transaction data in hex format from txid
|
||||
func (w *Worker) GetRawTransaction(txid string) (string, error) {
|
||||
return w.chain.EthereumTypeGetRawTransaction(txid)
|
||||
}
|
||||
|
||||
// getTransaction reads transaction data from txid
|
||||
func (w *Worker) getTransaction(txid string, spendingTxs bool, specificJSON bool, addresses map[string]struct{}) (*Tx, error) {
|
||||
bchainTx, height, err := w.txCache.GetTransaction(txid)
|
||||
@ -426,18 +443,25 @@ func (w *Worker) getTransactionFromBchainTx(bchainTx *bchain.Tx, height int, spe
|
||||
// mempool txs do not have fees yet
|
||||
if ethTxData.GasUsed != nil {
|
||||
feesSat.Mul(ethTxData.GasPrice, ethTxData.GasUsed)
|
||||
if ethTxData.L1Fee != nil {
|
||||
feesSat.Add(&feesSat, ethTxData.L1Fee)
|
||||
}
|
||||
}
|
||||
if len(bchainTx.Vout) > 0 {
|
||||
valOutSat = bchainTx.Vout[0].ValueSat
|
||||
}
|
||||
ethSpecific = &EthereumSpecific{
|
||||
GasLimit: ethTxData.GasLimit,
|
||||
GasPrice: (*Amount)(ethTxData.GasPrice),
|
||||
GasUsed: ethTxData.GasUsed,
|
||||
Nonce: ethTxData.Nonce,
|
||||
Status: ethTxData.Status,
|
||||
Data: ethTxData.Data,
|
||||
ParsedData: parsedInputData,
|
||||
GasLimit: ethTxData.GasLimit,
|
||||
GasPrice: (*Amount)(ethTxData.GasPrice),
|
||||
GasUsed: ethTxData.GasUsed,
|
||||
L1Fee: ethTxData.L1Fee,
|
||||
L1FeeScalar: ethTxData.L1FeeScalar,
|
||||
L1GasPrice: (*Amount)(ethTxData.L1GasPrice),
|
||||
L1GasUsed: ethTxData.L1GasUsed,
|
||||
Nonce: ethTxData.Nonce,
|
||||
Status: ethTxData.Status,
|
||||
Data: ethTxData.Data,
|
||||
ParsedData: parsedInputData,
|
||||
}
|
||||
if internalData != nil {
|
||||
ethSpecific.Type = internalData.Type
|
||||
@ -598,7 +622,7 @@ func (w *Worker) GetTransactionFromMempoolTx(mempoolTx *bchain.MempoolTx) (*Tx,
|
||||
return r, nil
|
||||
}
|
||||
|
||||
func (w *Worker) getContractInfo(contract string, typeFromContext bchain.TokenTypeName) (*bchain.ContractInfo, bool, error) {
|
||||
func (w *Worker) GetContractInfo(contract string, typeFromContext bchain.TokenTypeName) (*bchain.ContractInfo, bool, error) {
|
||||
cd, err := w.chainParser.GetAddrDescFromAddress(contract)
|
||||
if err != nil {
|
||||
return nil, false, err
|
||||
@ -638,7 +662,7 @@ func (w *Worker) getContractDescriptorInfo(cd bchain.AddressDescriptor, typeFrom
|
||||
glog.Errorf("StoreContractInfo error %v, contract %v", err, cd)
|
||||
}
|
||||
}
|
||||
} else if (len(contractInfo.Name) > 0 && contractInfo.Name[0] == 0) || (len(contractInfo.Symbol) > 0 && contractInfo.Symbol[0] == 0) {
|
||||
} else if (contractInfo.Type == bchain.UnhandledTokenType || len(contractInfo.Name) > 0 && contractInfo.Name[0] == 0) || (len(contractInfo.Symbol) > 0 && contractInfo.Symbol[0] == 0) {
|
||||
// fix contract name/symbol that was parsed as a string consisting of zeroes
|
||||
blockchainContractInfo, err := w.chain.GetContractInfo(cd)
|
||||
if err != nil {
|
||||
@ -657,6 +681,10 @@ func (w *Worker) getContractDescriptorInfo(cd bchain.AddressDescriptor, typeFrom
|
||||
if blockchainContractInfo != nil {
|
||||
contractInfo.Decimals = blockchainContractInfo.Decimals
|
||||
}
|
||||
if contractInfo.Type == bchain.UnhandledTokenType {
|
||||
glog.Infof("Contract %v %v [%s] handled", cd, typeFromContext, contractInfo.Name)
|
||||
contractInfo.Type = typeFromContext
|
||||
}
|
||||
if err = w.db.StoreContractInfo(contractInfo); err != nil {
|
||||
glog.Errorf("StoreContractInfo error %v, contract %v", err, cd)
|
||||
}
|
||||
@ -666,39 +694,49 @@ func (w *Worker) getContractDescriptorInfo(cd bchain.AddressDescriptor, typeFrom
|
||||
}
|
||||
|
||||
func (w *Worker) getEthereumTokensTransfers(transfers bchain.TokenTransfers, addresses map[string]struct{}) []TokenTransfer {
|
||||
sort.Sort(transfers)
|
||||
tokens := make([]TokenTransfer, len(transfers))
|
||||
for i := range transfers {
|
||||
t := transfers[i]
|
||||
typeName := bchain.EthereumTokenTypeMap[t.Type]
|
||||
contractInfo, _, err := w.getContractInfo(t.Contract, typeName)
|
||||
if err != nil {
|
||||
glog.Errorf("getContractInfo error %v, contract %v", err, t.Contract)
|
||||
continue
|
||||
}
|
||||
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)
|
||||
if len(transfers) > 0 {
|
||||
sort.Sort(transfers)
|
||||
contractCache := make(contractInfoCache)
|
||||
for i := range transfers {
|
||||
t := transfers[i]
|
||||
typeName := bchain.EthereumTokenTypeMap[t.Type]
|
||||
var contractInfo *bchain.ContractInfo
|
||||
if info, ok := contractCache[t.Contract]; ok {
|
||||
contractInfo = info
|
||||
} else {
|
||||
info, _, err := w.GetContractInfo(t.Contract, typeName)
|
||||
if err != nil {
|
||||
glog.Errorf("getContractInfo error %v, contract %v", err, t.Contract)
|
||||
continue
|
||||
}
|
||||
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
|
||||
@ -1045,6 +1083,7 @@ type ethereumTypeAddressData struct {
|
||||
totalResults int
|
||||
tokensBaseValue float64
|
||||
tokensSecondaryValue float64
|
||||
stakingPools []StakingPool
|
||||
}
|
||||
|
||||
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]
|
||||
sort.Sort(d.tokens)
|
||||
}
|
||||
d.contractInfo, err = w.db.GetContractInfo(addrDesc, "")
|
||||
d.contractInfo, err = w.db.GetContractInfo(addrDesc, bchain.UnknownTokenType)
|
||||
if err != nil {
|
||||
return nil, nil, err
|
||||
}
|
||||
if d.contractInfo != nil && d.contractInfo.Type == bchain.UnhandledTokenType {
|
||||
d.contractInfo, _, err = w.getContractDescriptorInfo(addrDesc, bchain.UnknownTokenType)
|
||||
if err != nil {
|
||||
return nil, nil, err
|
||||
}
|
||||
}
|
||||
if filter.FromHeight == 0 && filter.ToHeight == 0 {
|
||||
// compute total results for paging
|
||||
if filter.Vout == AddressFilterVoutOff {
|
||||
@ -1144,9 +1189,41 @@ func (w *Worker) getEthereumTypeAddressBalances(addrDesc bchain.AddressDescripto
|
||||
filter.Vout = AddressFilterVoutQueryNotNecessary
|
||||
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
|
||||
}
|
||||
|
||||
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) {
|
||||
var tx *Tx
|
||||
var err error
|
||||
@ -1159,7 +1236,7 @@ func (w *Worker) txFromTxid(txid string, bestHeight uint32, option AccountDetail
|
||||
if ta == nil {
|
||||
glog.Warning("DB inconsistency: tx ", txid, ": not found in txAddresses")
|
||||
// as fallback, get tx from backend
|
||||
tx, err = w.getTransaction(txid, false, false, addresses)
|
||||
tx, err = w.getTransaction(txid, false, true, addresses)
|
||||
if err != nil {
|
||||
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)
|
||||
}
|
||||
} else {
|
||||
tx, err = w.getTransaction(txid, false, false, addresses)
|
||||
tx, err = w.getTransaction(txid, false, true, addresses)
|
||||
if err != nil {
|
||||
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 {
|
||||
txids = append(txids, txid)
|
||||
} else {
|
||||
tx, err := w.txFromTxid(txid, bestheight, option, nil, addresses)
|
||||
tx, err := w.txFromTxid(txid, bestheight, AccountDetailsTxHistory, nil, addresses)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
@ -1388,12 +1465,13 @@ func (w *Worker) GetAddress(address string, page int, txsOnPage int, option Acco
|
||||
ContractInfo: ed.contractInfo,
|
||||
Nonce: ed.nonce,
|
||||
AddressAliases: w.getAddressAliases(addresses),
|
||||
StakingPools: ed.stakingPools,
|
||||
}
|
||||
// keep address backward compatible, set deprecated Erc20Contract value if ERC20 token
|
||||
if ed.contractInfo != nil && ed.contractInfo.Type == bchain.ERC20TokenType {
|
||||
r.Erc20Contract = ed.contractInfo
|
||||
}
|
||||
glog.Info("GetAddress ", address, ", ", time.Since(start))
|
||||
glog.Info("GetAddress-", option, " ", address, ", ", time.Since(start))
|
||||
return r, nil
|
||||
}
|
||||
|
||||
@ -1603,6 +1681,17 @@ func (w *Worker) GetBalanceHistory(address string, fromTimestamp, toTimestamp in
|
||||
if err != nil {
|
||||
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)
|
||||
if fromHeight >= toHeight {
|
||||
return bhs, nil
|
||||
@ -1880,7 +1969,11 @@ func (w *Worker) GetCurrentFiatRates(currencies []string, token string) (*FiatTi
|
||||
ticker := w.fiatRates.GetCurrentTicker(vsCurrency, token)
|
||||
var err error
|
||||
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 {
|
||||
return nil, NewAPIError(fmt.Sprintf("Error finding ticker: %v", err), false)
|
||||
} else if ticker == nil {
|
||||
@ -2146,7 +2239,7 @@ func (w *Worker) GetBlock(bid string, page int, txsOnPage int) (*Block, error) {
|
||||
txi := 0
|
||||
addresses := w.newAddressesMapForAliases()
|
||||
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 {
|
||||
return nil, err
|
||||
}
|
||||
@ -2200,6 +2293,48 @@ func (w *Worker) GetBlockRaw(bid string) (*BlockRaw, error) {
|
||||
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
|
||||
func (w *Worker) ComputeFeeStats(blockFrom, blockTo int, stopCompute chan os.Signal) error {
|
||||
bestheight, _, err := w.db.GetBestBlock()
|
||||
@ -2302,6 +2437,7 @@ func (w *Worker) GetSystemInfo(internal bool) (*SystemInfo, error) {
|
||||
}
|
||||
blockbookInfo := &BlockbookInfo{
|
||||
Coin: w.is.Coin,
|
||||
Network: w.is.GetNetwork(),
|
||||
Host: w.is.Host,
|
||||
Version: vi.Version,
|
||||
GitCommit: vi.GitCommit,
|
||||
@ -2320,6 +2456,7 @@ func (w *Worker) GetSystemInfo(internal bool) (*SystemInfo, error) {
|
||||
CurrentFiatRatesTime: nonZeroTime(currentFiatRatesTime),
|
||||
HistoricalFiatRatesTime: nonZeroTime(w.is.HistoricalFiatRatesTime),
|
||||
HistoricalTokenFiatRatesTime: nonZeroTime(w.is.HistoricalTokenFiatRatesTime),
|
||||
SupportedStakingPools: w.chain.EthereumTypeGetSupportedStakingPools(),
|
||||
DbSize: w.db.DatabaseSizeOnDisk(),
|
||||
DbSizeFromColumns: internalDBSize,
|
||||
DbColumns: columnStats,
|
||||
|
||||
@ -556,7 +556,7 @@ func (w *Worker) GetXpubAddress(xpub string, page int, txsOnPage int, option Acc
|
||||
usedTokens++
|
||||
}
|
||||
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 ||
|
||||
filter.TokensToReturn == TokensToReturnUsed && ad.balance != nil ||
|
||||
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
|
||||
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
|
||||
func (b *BaseChain) EthereumTypeGetNonce(addrDesc AddressDescriptor) (uint64, error) {
|
||||
return 0, errors.New("Not supported")
|
||||
return 0, errors.New("not supported")
|
||||
}
|
||||
|
||||
// EthereumTypeEstimateGas is not supported
|
||||
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
|
||||
func (b *BaseChain) GetContractInfo(contractDesc AddressDescriptor) (*ContractInfo, error) {
|
||||
return nil, errors.New("Not supported")
|
||||
return nil, errors.New("not supported")
|
||||
}
|
||||
|
||||
// EthereumTypeGetErc20ContractBalance is not supported
|
||||
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) {
|
||||
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) {
|
||||
ci, err := b.EthereumRPC.GetChainInfo()
|
||||
if err != nil {
|
||||
fmt.Println(err)
|
||||
return nil, err
|
||||
}
|
||||
|
||||
|
||||
@ -337,10 +337,15 @@ func Test_UnpackTx(t *testing.T) {
|
||||
t.Run(tt.name, func(t *testing.T) {
|
||||
b, _ := hex.DecodeString(tt.args.packedTx)
|
||||
got, got1, err := tt.args.parser.UnpackTx(b)
|
||||
|
||||
if (err != nil) != tt.wantErr {
|
||||
t.Errorf("unpackTx() error = %v, wantErr %v", err, tt.wantErr)
|
||||
return
|
||||
}
|
||||
// ignore witness unpacking
|
||||
for i := range got.Vin {
|
||||
got.Vin[i].Witness = nil
|
||||
}
|
||||
if !reflect.DeepEqual(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)
|
||||
return
|
||||
}
|
||||
// ignore witness unpacking
|
||||
for i := range got.Vin {
|
||||
got.Vin[i].Witness = nil
|
||||
}
|
||||
if !reflect.DeepEqual(got, tt.want) {
|
||||
t.Errorf("unpackTx() got = %v, want %v", got, tt.want)
|
||||
}
|
||||
|
||||
@ -4,13 +4,14 @@ import (
|
||||
"context"
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"io/ioutil"
|
||||
"math/big"
|
||||
"os"
|
||||
"reflect"
|
||||
"time"
|
||||
|
||||
"github.com/juju/errors"
|
||||
"github.com/trezor/blockbook/bchain"
|
||||
"github.com/trezor/blockbook/bchain/coins/arbitrum"
|
||||
"github.com/trezor/blockbook/bchain/coins/avalanche"
|
||||
"github.com/trezor/blockbook/bchain/coins/bch"
|
||||
"github.com/trezor/blockbook/bchain/coins/bellcoin"
|
||||
@ -42,8 +43,10 @@ import (
|
||||
"github.com/trezor/blockbook/bchain/coins/namecoin"
|
||||
"github.com/trezor/blockbook/bchain/coins/nuls"
|
||||
"github.com/trezor/blockbook/bchain/coins/omotenashicoin"
|
||||
"github.com/trezor/blockbook/bchain/coins/optimism"
|
||||
"github.com/trezor/blockbook/bchain/coins/pivx"
|
||||
"github.com/trezor/blockbook/bchain/coins/polis"
|
||||
"github.com/trezor/blockbook/bchain/coins/polygon"
|
||||
"github.com/trezor/blockbook/bchain/coins/qtum"
|
||||
"github.com/trezor/blockbook/bchain/coins/ravencoin"
|
||||
"github.com/trezor/blockbook/bchain/coins/ritocoin"
|
||||
@ -65,6 +68,7 @@ var BlockChainFactories = make(map[string]blockChainFactory)
|
||||
func init() {
|
||||
BlockChainFactories["Bitcoin"] = btc.NewBitcoinRPC
|
||||
BlockChainFactories["Testnet"] = btc.NewBitcoinRPC
|
||||
BlockChainFactories["Testnet4"] = btc.NewBitcoinRPC
|
||||
BlockChainFactories["Signet"] = btc.NewBitcoinRPC
|
||||
BlockChainFactories["Regtest"] = btc.NewBitcoinRPC
|
||||
BlockChainFactories["Zcash"] = zec.NewZCashRPC
|
||||
@ -72,12 +76,10 @@ func init() {
|
||||
BlockChainFactories["Ethereum"] = eth.NewEthereumRPC
|
||||
BlockChainFactories["Ethereum Archive"] = 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 Archive"] = eth.NewEthereumRPC
|
||||
BlockChainFactories["Ethereum Testnet Holesky"] = eth.NewEthereumRPC
|
||||
BlockChainFactories["Ethereum Testnet Holesky Archive"] = eth.NewEthereumRPC
|
||||
BlockChainFactories["Bcash"] = bch.NewBCashRPC
|
||||
BlockChainFactories["Bcash Testnet"] = bch.NewBCashRPC
|
||||
BlockChainFactories["Bgold"] = btg.NewBGoldRPC
|
||||
@ -113,6 +115,7 @@ func init() {
|
||||
BlockChainFactories["Firo"] = firo.NewFiroRPC
|
||||
BlockChainFactories["Fujicoin"] = fujicoin.NewFujicoinRPC
|
||||
BlockChainFactories["Flo"] = flo.NewFloRPC
|
||||
BlockChainFactories["Flo Testnet"] = flo.NewFloRPC
|
||||
BlockChainFactories["Bellcoin"] = bellcoin.NewBellcoinRPC
|
||||
BlockChainFactories["Qtum"] = qtum.NewQtumRPC
|
||||
BlockChainFactories["Viacoin"] = viacoin.NewViacoinRPC
|
||||
@ -137,25 +140,19 @@ func init() {
|
||||
BlockChainFactories["Avalanche Archive"] = avalanche.NewAvalancheRPC
|
||||
BlockChainFactories["BNB Smart Chain"] = bsc.NewBNBSmartChainRPC
|
||||
BlockChainFactories["BNB Smart Chain Archive"] = bsc.NewBNBSmartChainRPC
|
||||
}
|
||||
|
||||
// GetCoinNameFromConfig gets coin name and coin shortcut from config file
|
||||
func GetCoinNameFromConfig(configFileContent []byte) (string, string, string, error) {
|
||||
var cn struct {
|
||||
CoinName string `json:"coin_name"`
|
||||
CoinShortcut string `json:"coin_shortcut"`
|
||||
CoinLabel string `json:"coin_label"`
|
||||
}
|
||||
err := json.Unmarshal(configFileContent, &cn)
|
||||
if err != nil {
|
||||
return "", "", "", errors.Annotatef(err, "Error parsing config file ")
|
||||
}
|
||||
return cn.CoinName, cn.CoinShortcut, cn.CoinLabel, nil
|
||||
BlockChainFactories["Polygon"] = polygon.NewPolygonRPC
|
||||
BlockChainFactories["Polygon Archive"] = polygon.NewPolygonRPC
|
||||
BlockChainFactories["Optimism"] = optimism.NewOptimismRPC
|
||||
BlockChainFactories["Optimism Archive"] = optimism.NewOptimismRPC
|
||||
BlockChainFactories["Arbitrum"] = arbitrum.NewArbitrumRPC
|
||||
BlockChainFactories["Arbitrum Archive"] = arbitrum.NewArbitrumRPC
|
||||
BlockChainFactories["Arbitrum Nova"] = arbitrum.NewArbitrumRPC
|
||||
BlockChainFactories["Arbitrum Nova Archive"] = arbitrum.NewArbitrumRPC
|
||||
}
|
||||
|
||||
// NewBlockChain creates bchain.BlockChain and bchain.Mempool for the coin passed by the parameter coin
|
||||
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 {
|
||||
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)
|
||||
}
|
||||
|
||||
// GetContractInfo returns URI of non fungible or multi token defined by token id
|
||||
// GetTokenURI returns URI of non fungible or multi token defined by token id
|
||||
func (c *blockChainWithMetrics) GetTokenURI(contractDesc bchain.AddressDescriptor, tokenID *big.Int) (v string, err error) {
|
||||
defer func(s time.Time) { c.observeRPCLatency("GetTokenURI", s, err) }(time.Now())
|
||||
return c.b.GetTokenURI(contractDesc, tokenID)
|
||||
}
|
||||
|
||||
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 {
|
||||
mempool bchain.Mempool
|
||||
m *common.Metrics
|
||||
|
||||
@ -4,8 +4,6 @@ import (
|
||||
"context"
|
||||
"encoding/json"
|
||||
|
||||
"github.com/ethereum/go-ethereum/ethclient"
|
||||
"github.com/ethereum/go-ethereum/rpc"
|
||||
"github.com/golang/glog"
|
||||
"github.com/juju/errors"
|
||||
"github.com/trezor/blockbook/bchain"
|
||||
@ -40,21 +38,14 @@ func NewBNBSmartChainRPC(config json.RawMessage, pushHandler func(bchain.Notific
|
||||
s := &BNBSmartChainRPC{
|
||||
EthereumRPC: c.(*eth.EthereumRPC),
|
||||
}
|
||||
s.Parser.EnsSuffix = ".bnb"
|
||||
|
||||
return s, nil
|
||||
}
|
||||
|
||||
// Initialize bnb smart chain rpc interface
|
||||
func (b *BNBSmartChainRPC) Initialize() error {
|
||||
b.OpenRPC = func(url string) (bchain.EVMRPCClient, bchain.EVMClient, error) {
|
||||
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
|
||||
}
|
||||
b.OpenRPC = eth.OpenRPC
|
||||
|
||||
rc, ec, err := b.OpenRPC(b.ChainConfig.RPCURL)
|
||||
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,
|
||||
Sequence: in.Sequence,
|
||||
ScriptSig: s,
|
||||
Witness: in.Witness,
|
||||
}
|
||||
}
|
||||
vout := make([]bchain.Vout, len(t.TxOut))
|
||||
|
||||
@ -4,11 +4,28 @@ import (
|
||||
"encoding/json"
|
||||
"math/big"
|
||||
|
||||
"github.com/martinboehm/btcd/wire"
|
||||
"github.com/martinboehm/btcutil/chaincfg"
|
||||
"github.com/trezor/blockbook/bchain"
|
||||
"github.com/trezor/blockbook/common"
|
||||
)
|
||||
|
||||
// temp params for signet(wait btcd commit)
|
||||
// magic numbers
|
||||
const (
|
||||
Testnet4Magic wire.BitcoinNet = 0x283f161c
|
||||
)
|
||||
|
||||
// chain parameters
|
||||
var (
|
||||
TestNet4Params chaincfg.Params
|
||||
)
|
||||
|
||||
func init() {
|
||||
TestNet4Params = chaincfg.TestNet3Params
|
||||
TestNet4Params.Net = Testnet4Magic
|
||||
}
|
||||
|
||||
// BitcoinParser handle
|
||||
type BitcoinParser struct {
|
||||
*BitcoinLikeParser
|
||||
@ -33,6 +50,8 @@ func GetChainParams(chain string) *chaincfg.Params {
|
||||
switch chain {
|
||||
case "test":
|
||||
return &chaincfg.TestNet3Params
|
||||
case "testnet4":
|
||||
return &TestNet4Params
|
||||
case "regtest":
|
||||
return &chaincfg.RegressionNetParams
|
||||
case "signet":
|
||||
|
||||
@ -467,11 +467,12 @@ func TestGetAddressesFromAddrDescTestnet(t *testing.T) {
|
||||
}
|
||||
|
||||
var (
|
||||
testTx1, testTx2, testTx3 bchain.Tx
|
||||
testTx1, testTx2, testTx3, testTx4 bchain.Tx
|
||||
|
||||
testTxPacked1 = "0001e2408ba8d7af5401000000017f9a22c9cbf54bd902400df746f138f37bcf5b4d93eb755820e974ba43ed5f42040000006a4730440220037f4ed5427cde81d55b9b6a2fd08c8a25090c2c2fff3a75c1a57625ca8a7118022076c702fe55969fa08137f71afd4851c48e31082dd3c40c919c92cdbc826758d30121029f6da5623c9f9b68a9baf9c1bc7511df88fa34c6c2f71f7c62f2f03ff48dca80feffffff019c9700000000000017a9146144d57c8aff48492c9dfb914e120b20bad72d6f8773d00700"
|
||||
testTxPacked2 = "0007c91a899ab7da6a010000000001019d64f0c72a0d206001decbffaa722eb1044534c74eee7a5df8318e42a4323ec10000000017160014550da1f5d25a9dae2eafd6902b4194c4c6500af6ffffffff02809698000000000017a914cd668d781ece600efa4b2404dc91fd26b8b8aed8870553d7360000000017a914246655bdbd54c7e477d0ea2375e86e0db2b8f80a8702473044022076aba4ad559616905fa51d4ddd357fc1fdb428d40cb388e042cdd1da4a1b7357022011916f90c712ead9a66d5f058252efd280439ad8956a967e95d437d246710bc9012102a80a5964c5612bb769ef73147b2cf3c149bc0fd4ecb02f8097629c94ab013ffd00000000"
|
||||
testTxPacked3 = "00003d818bfda9aa3e02000000000102deb1999a857ab0a13d6b12fbd95ea75b409edde5f2ff747507ce42d9986a8b9d0000000000fdffffff9fd2d3361e203b2375eba6438efbef5b3075531e7e583c7cc76b7294fe7f22980000000000fdffffff02a0860100000000001600148091746745464e7555c31e9a5afceac14a02978ae7fc1c0000000000160014565ea9ff4589d3e05ba149ae6e257752bfdc2a1e0247304402207d67d320a8e813f986b35e9791935fcb736754812b7038686f5de6cfdcda99cd02201c3bb2c178e0056016437ecfe365a7eef84aa9d293ebdc566177af82e22fcdd3012103abb30c1bbe878b07b58dc169b1d061d48c60be8107f632a59778b38bf7ceea5a02473044022044f54a478cfe086e870cb026c9dcd4e14e63778bef569a4d55a6332725cd9a9802202f0e94c04e6f328fc64ad9efe552888c299750d1b8d033324825a3ff29920e030121036fcd433428aa7dc65c4f5408fa31f208c54fe4b4c6c1ae9c39a825ed4f1ac039813d0000"
|
||||
testTxPacked4 = "0000a2b98ced82b6400300000000010148f8f93ebb12407809920d2ab9cc1bf01289b314eb23028c83fdab21e5fefa690100000000fdffffff0150c3000000000000160014cb888de3c89670a3061fb6ef6590f187649cca060247304402206a9db8d7157e4b0a06a1f090b9de88cdc616028b431b80617a055117877e479a02202937d6d1658d4a8afde86b245325c3bb0e769a87cb09d802bcefaa21550065e201210374aa8f312de4ebccbef55609700a39764387aa4ff5d76f1ccb4d2382e454f05b00000000"
|
||||
)
|
||||
|
||||
func init() {
|
||||
@ -595,6 +596,37 @@ func init() {
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
testTx4 = bchain.Tx{
|
||||
Hex: "0300000000010148f8f93ebb12407809920d2ab9cc1bf01289b314eb23028c83fdab21e5fefa690100000000fdffffff0150c3000000000000160014cb888de3c89670a3061fb6ef6590f187649cca060247304402206a9db8d7157e4b0a06a1f090b9de88cdc616028b431b80617a055117877e479a02202937d6d1658d4a8afde86b245325c3bb0e769a87cb09d802bcefaa21550065e201210374aa8f312de4ebccbef55609700a39764387aa4ff5d76f1ccb4d2382e454f05b00000000",
|
||||
Blocktime: 1724927392,
|
||||
Txid: "8e3f38bf6854dd3c358be8d4f9a40a6dccc50de49616125d27af9fdbe65287eb",
|
||||
LockTime: 0,
|
||||
VSize: 110,
|
||||
Version: 3,
|
||||
Vin: []bchain.Vin{
|
||||
{
|
||||
ScriptSig: bchain.ScriptSig{
|
||||
Hex: "",
|
||||
},
|
||||
Txid: "69fafee521abfd838c0223eb14b38912f01bccb92a0d9209784012bb3ef9f848",
|
||||
Vout: 1,
|
||||
Sequence: 4294967293,
|
||||
},
|
||||
},
|
||||
Vout: []bchain.Vout{
|
||||
{
|
||||
ValueSat: *big.NewInt(50000),
|
||||
N: 0,
|
||||
ScriptPubKey: bchain.ScriptPubKey{
|
||||
Hex: "0014cb888de3c89670a3061fb6ef6590f187649cca06",
|
||||
Addresses: []string{
|
||||
"tb1qewygmc7gjec2xpslkmhkty83sajfejsxqmy5dq",
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
func TestPackTx(t *testing.T) {
|
||||
@ -643,6 +675,17 @@ func TestPackTx(t *testing.T) {
|
||||
want: testTxPacked3,
|
||||
wantErr: false,
|
||||
},
|
||||
{
|
||||
name: "testnet4-1",
|
||||
args: args{
|
||||
tx: testTx4,
|
||||
height: 41657,
|
||||
blockTime: 1724927392,
|
||||
parser: NewBitcoinParser(GetChainParams("testnet4"), &Configuration{}),
|
||||
},
|
||||
want: testTxPacked4,
|
||||
wantErr: false,
|
||||
},
|
||||
}
|
||||
for _, tt := range tests {
|
||||
t.Run(tt.name, func(t *testing.T) {
|
||||
@ -701,6 +744,16 @@ func TestUnpackTx(t *testing.T) {
|
||||
want1: 15745,
|
||||
wantErr: false,
|
||||
},
|
||||
{
|
||||
name: "testnet4-1",
|
||||
args: args{
|
||||
packedTx: testTxPacked4,
|
||||
parser: NewBitcoinParser(GetChainParams("testnet4"), &Configuration{}),
|
||||
},
|
||||
want: &testTx4,
|
||||
want1: 41657,
|
||||
wantErr: false,
|
||||
},
|
||||
}
|
||||
for _, tt := range tests {
|
||||
t.Run(tt.name, func(t *testing.T) {
|
||||
@ -710,6 +763,10 @@ func TestUnpackTx(t *testing.T) {
|
||||
t.Errorf("unpackTx() error = %v, wantErr %v", err, tt.wantErr)
|
||||
return
|
||||
}
|
||||
// ignore witness unpacking
|
||||
for i := range got.Vin {
|
||||
got.Vin[i].Witness = nil
|
||||
}
|
||||
if !reflect.DeepEqual(got, tt.want) {
|
||||
t.Errorf("unpackTx() got = %v, want %v", got, tt.want)
|
||||
}
|
||||
|
||||
@ -6,7 +6,6 @@ import (
|
||||
"encoding/hex"
|
||||
"encoding/json"
|
||||
"io"
|
||||
"io/ioutil"
|
||||
"math/big"
|
||||
"net"
|
||||
"net/http"
|
||||
@ -23,18 +22,20 @@ import (
|
||||
// BitcoinRPC is an interface to JSON-RPC bitcoind service.
|
||||
type BitcoinRPC struct {
|
||||
*bchain.BaseChain
|
||||
client http.Client
|
||||
rpcURL string
|
||||
user string
|
||||
password string
|
||||
Mempool *bchain.MempoolBitcoinType
|
||||
ParseBlocks bool
|
||||
pushHandler func(bchain.NotificationType)
|
||||
mq *bchain.MQ
|
||||
ChainConfig *Configuration
|
||||
RPCMarshaler RPCMarshaler
|
||||
golombFilterP uint8
|
||||
mempoolFilterScripts string
|
||||
client http.Client
|
||||
rpcURL string
|
||||
user string
|
||||
password string
|
||||
Mempool *bchain.MempoolBitcoinType
|
||||
ParseBlocks bool
|
||||
pushHandler func(bchain.NotificationType)
|
||||
mq *bchain.MQ
|
||||
ChainConfig *Configuration
|
||||
RPCMarshaler RPCMarshaler
|
||||
mempoolGolombFilterP uint8
|
||||
mempoolFilterScripts string
|
||||
mempoolUseZeroedKey bool
|
||||
alternativeFeeProvider alternativeFeeProviderInterface
|
||||
}
|
||||
|
||||
// Configuration represents json config file
|
||||
@ -62,8 +63,9 @@ type Configuration struct {
|
||||
AlternativeEstimateFee string `json:"alternative_estimate_fee,omitempty"`
|
||||
AlternativeEstimateFeeParams string `json:"alternative_estimate_fee_params,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"`
|
||||
MempoolFilterUseZeroedKey bool `json:"mempool_filter_use_zeroed_key,omitempty"`
|
||||
}
|
||||
|
||||
// NewBitcoinRPC returns new BitcoinRPC instance.
|
||||
@ -109,8 +111,9 @@ func NewBitcoinRPC(config json.RawMessage, pushHandler func(bchain.NotificationT
|
||||
ChainConfig: &c,
|
||||
pushHandler: pushHandler,
|
||||
RPCMarshaler: JSONMarshalerV2{},
|
||||
golombFilterP: c.GolombFilterP,
|
||||
mempoolGolombFilterP: c.MempoolGolombFilterP,
|
||||
mempoolFilterScripts: c.MempoolFilterScripts,
|
||||
mempoolUseZeroedKey: c.MempoolFilterUseZeroedKey,
|
||||
}
|
||||
|
||||
return s, nil
|
||||
@ -143,10 +146,16 @@ func (b *BitcoinRPC) Initialize() error {
|
||||
glog.Info("rpc: block chain ", params.Name)
|
||||
|
||||
if b.ChainConfig.AlternativeEstimateFee == "whatthefee" {
|
||||
if err = InitWhatTheFee(b, b.ChainConfig.AlternativeEstimateFeeParams); err != nil {
|
||||
glog.Error("InitWhatTheFee error ", err, " Reverting to default estimateFee functionality")
|
||||
if b.alternativeFeeProvider, err = NewWhatTheFee(b, b.ChainConfig.AlternativeEstimateFeeParams); err != nil {
|
||||
glog.Error("NewWhatTheFee error ", err, " Reverting to default estimateFee functionality")
|
||||
// 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
|
||||
func (b *BitcoinRPC) CreateMempool(chain bchain.BlockChain) (bchain.Mempool, error) {
|
||||
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
|
||||
}
|
||||
@ -772,8 +781,7 @@ func (b *BitcoinRPC) getRawTransaction(txid string) (json.RawMessage, error) {
|
||||
return res.Result, nil
|
||||
}
|
||||
|
||||
// EstimateSmartFee returns fee estimation
|
||||
func (b *BitcoinRPC) EstimateSmartFee(blocks int, conservative bool) (big.Int, error) {
|
||||
func (b *BitcoinRPC) blockchainEstimateSmartFee(blocks int, conservative bool) (big.Int, error) {
|
||||
// use EstimateFee if EstimateSmartFee is not supported
|
||||
if !b.ChainConfig.SupportsEstimateSmartFee && b.ChainConfig.SupportsEstimateFee {
|
||||
return b.EstimateFee(blocks)
|
||||
@ -790,7 +798,6 @@ func (b *BitcoinRPC) EstimateSmartFee(blocks int, conservative bool) (big.Int, e
|
||||
req.Params.EstimateMode = "ECONOMICAL"
|
||||
}
|
||||
err := b.Call(&req, &res)
|
||||
|
||||
var r big.Int
|
||||
if err != nil {
|
||||
return r, err
|
||||
@ -805,8 +812,31 @@ func (b *BitcoinRPC) EstimateSmartFee(blocks int, conservative bool) (big.Int, e
|
||||
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.
|
||||
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
|
||||
if !b.ChainConfig.SupportsEstimateFee && b.ChainConfig.SupportsEstimateSmartFee {
|
||||
return b.EstimateSmartFee(blocks, true)
|
||||
@ -817,9 +847,8 @@ func (b *BitcoinRPC) EstimateFee(blocks int) (big.Int, error) {
|
||||
res := ResEstimateFee{}
|
||||
req := CmdEstimateFee{Method: "estimatefee"}
|
||||
req.Params.Blocks = blocks
|
||||
err := b.Call(&req, &res)
|
||||
err = b.Call(&req, &res)
|
||||
|
||||
var r big.Int
|
||||
if err != nil {
|
||||
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 {
|
||||
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 (
|
||||
"bytes"
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"math"
|
||||
"net/http"
|
||||
"strconv"
|
||||
"sync"
|
||||
"time"
|
||||
|
||||
"github.com/golang/glog"
|
||||
@ -34,49 +32,40 @@ type whatTheFeeParams struct {
|
||||
PeriodSeconds int `periodSeconds:"url"`
|
||||
}
|
||||
|
||||
type whatTheFeeFee struct {
|
||||
blocks int
|
||||
feesPerKB []int
|
||||
}
|
||||
|
||||
type whatTheFeeData struct {
|
||||
type whatTheFeeProvider struct {
|
||||
*alternativeFeeProvider
|
||||
params whatTheFeeParams
|
||||
probabilities []string
|
||||
fees []whatTheFeeFee
|
||||
lastSync time.Time
|
||||
chain bchain.BlockChain
|
||||
mux sync.Mutex
|
||||
}
|
||||
|
||||
var whatTheFee whatTheFeeData
|
||||
|
||||
// InitWhatTheFee initializes https://whatthefee.io handler
|
||||
func InitWhatTheFee(chain bchain.BlockChain, params string) error {
|
||||
err := json.Unmarshal([]byte(params), &whatTheFee.params)
|
||||
// NewWhatTheFee initializes https://whatthefee.io provider
|
||||
func NewWhatTheFee(chain bchain.BlockChain, params string) (alternativeFeeProviderInterface, error) {
|
||||
var p whatTheFeeProvider
|
||||
err := json.Unmarshal([]byte(params), &p.params)
|
||||
if err != nil {
|
||||
return err
|
||||
return nil, err
|
||||
}
|
||||
if whatTheFee.params.URL == "" || whatTheFee.params.PeriodSeconds == 0 {
|
||||
return errors.New("Missing parameters")
|
||||
if p.params.URL == "" || p.params.PeriodSeconds == 0 {
|
||||
return nil, errors.New("NewWhatTheFee: Missing parameters")
|
||||
}
|
||||
whatTheFee.chain = chain
|
||||
go whatTheFeeDownloader()
|
||||
return nil
|
||||
p.chain = chain
|
||||
go p.whatTheFeeDownloader()
|
||||
return &p, nil
|
||||
}
|
||||
|
||||
func whatTheFeeDownloader() {
|
||||
period := time.Duration(whatTheFee.params.PeriodSeconds) * time.Second
|
||||
func (p *whatTheFeeProvider) whatTheFeeDownloader() {
|
||||
period := time.Duration(p.params.PeriodSeconds) * time.Second
|
||||
timer := time.NewTimer(period)
|
||||
counter := 0
|
||||
for {
|
||||
var data whatTheFeeServiceResult
|
||||
err := whatTheFeeGetData(&data)
|
||||
err := p.whatTheFeeGetData(&data)
|
||||
if err != nil {
|
||||
glog.Error("whatTheFeeGetData ", err)
|
||||
} else {
|
||||
if whatTheFeeProcessData(&data) {
|
||||
if p.whatTheFeeProcessData(&data) {
|
||||
if counter%60 == 0 {
|
||||
whatTheFeeCompareToDefault()
|
||||
p.compareToDefault()
|
||||
}
|
||||
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 {
|
||||
glog.Errorf("invalid data %+v", data)
|
||||
return false
|
||||
}
|
||||
whatTheFee.mux.Lock()
|
||||
defer whatTheFee.mux.Unlock()
|
||||
whatTheFee.probabilities = data.Columns
|
||||
whatTheFee.fees = make([]whatTheFeeFee, len(data.Index))
|
||||
p.mux.Lock()
|
||||
defer p.mux.Unlock()
|
||||
p.probabilities = data.Columns
|
||||
p.fees = make([]alternativeFeeProviderFee, len(data.Index))
|
||||
for i, blocks := range data.Index {
|
||||
if len(data.Columns) != len(data.Data[i]) {
|
||||
glog.Errorf("invalid data %+v", data)
|
||||
@ -104,19 +93,19 @@ func whatTheFeeProcessData(data *whatTheFeeServiceResult) bool {
|
||||
for j, l := range data.Data[i] {
|
||||
fees[j] = int(1000 * math.Exp(float64(l)/100))
|
||||
}
|
||||
whatTheFee.fees[i] = whatTheFeeFee{
|
||||
blocks: blocks,
|
||||
feesPerKB: fees,
|
||||
p.fees[i] = alternativeFeeProviderFee{
|
||||
blocks: blocks,
|
||||
feePerKB: fees[len(fees)/2],
|
||||
}
|
||||
}
|
||||
whatTheFee.lastSync = time.Now()
|
||||
glog.Infof("%+v", whatTheFee.fees)
|
||||
p.lastSync = time.Now()
|
||||
glog.Infof("whatTheFees: %+v", p.fees)
|
||||
return true
|
||||
}
|
||||
|
||||
func whatTheFeeGetData(res interface{}) error {
|
||||
func (p *whatTheFeeProvider) whatTheFeeGetData(res interface{}) error {
|
||||
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 {
|
||||
return err
|
||||
}
|
||||
@ -132,25 +121,3 @@ func whatTheFeeGetData(res interface{}) error {
|
||||
}
|
||||
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 (
|
||||
"fmt"
|
||||
|
||||
"github.com/pirk/ecashutil"
|
||||
"github.com/martinboehm/btcutil"
|
||||
"github.com/martinboehm/btcutil/chaincfg"
|
||||
"github.com/martinboehm/btcutil/txscript"
|
||||
"github.com/pirk/ecashaddr-converter/address"
|
||||
"github.com/pirk/ecashutil"
|
||||
"github.com/trezor/blockbook/bchain"
|
||||
"github.com/trezor/blockbook/bchain/coins/btc"
|
||||
)
|
||||
|
||||
@ -342,6 +342,10 @@ func Test_UnpackTx(t *testing.T) {
|
||||
t.Errorf("unpackTx() error = %v, wantErr %v", err, tt.wantErr)
|
||||
return
|
||||
}
|
||||
// ignore witness unpacking
|
||||
for i := range got.Vin {
|
||||
got.Vin[i].Witness = nil
|
||||
}
|
||||
if !reflect.DeepEqual(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
|
||||
}
|
||||
|
||||
func (b *EthereumRPC) ethCall(data, to string) (string, error) {
|
||||
// EthereumTypeRpcCall calls eth_call with given data and to address
|
||||
func (b *EthereumRPC) EthereumTypeRpcCall(data, to, from string) (string, error) {
|
||||
ctx, cancel := context.WithTimeout(context.Background(), b.Timeout)
|
||||
defer cancel()
|
||||
var r string
|
||||
err := b.RPC.CallContext(ctx, &r, "eth_call", map[string]interface{}{
|
||||
args := map[string]interface{}{
|
||||
"data": data,
|
||||
"to": to,
|
||||
}, "latest")
|
||||
}
|
||||
if from != "" {
|
||||
args["from"] = from
|
||||
}
|
||||
err := b.RPC.CallContext(ctx, &r, "eth_call", args, "latest")
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
@ -289,7 +294,7 @@ func (b *EthereumRPC) ethCall(data, to string) (string, error) {
|
||||
|
||||
func (b *EthereumRPC) fetchContractInfo(address string) (*bchain.ContractInfo, error) {
|
||||
var contract bchain.ContractInfo
|
||||
data, err := b.ethCall(contractNameSignature, address)
|
||||
data, err := b.EthereumTypeRpcCall(contractNameSignature, address, "")
|
||||
if err != nil {
|
||||
// ignore the error from the eth_call - since geth v1.9.15 they changed the behavior
|
||||
// and returning error "execution reverted" for some non contract addresses
|
||||
@ -300,14 +305,14 @@ func (b *EthereumRPC) fetchContractInfo(address string) (*bchain.ContractInfo, e
|
||||
}
|
||||
name := strings.TrimSpace(parseSimpleStringProperty(data))
|
||||
if name != "" {
|
||||
data, err = b.ethCall(contractSymbolSignature, address)
|
||||
data, err = b.EthereumTypeRpcCall(contractSymbolSignature, address, "")
|
||||
if err != nil {
|
||||
// glog.Warning(errors.Annotatef(err, "Contract SymbolSignature %v", address))
|
||||
return nil, nil
|
||||
// return nil, errors.Annotatef(err, "erc20SymbolSignature %v", address)
|
||||
}
|
||||
symbol := strings.TrimSpace(parseSimpleStringProperty(data))
|
||||
data, _ = b.ethCall(contractDecimalsSignature, address)
|
||||
data, _ = b.EthereumTypeRpcCall(contractDecimalsSignature, address, "")
|
||||
// if err != nil {
|
||||
// glog.Warning(errors.Annotatef(err, "Contract DecimalsSignature %v", address))
|
||||
// // return nil, errors.Annotatef(err, "erc20DecimalsSignature %v", address)
|
||||
@ -337,10 +342,10 @@ func (b *EthereumRPC) GetContractInfo(contractDesc bchain.AddressDescriptor) (*b
|
||||
|
||||
// EthereumTypeGetErc20ContractBalance returns balance of ERC20 contract for given address
|
||||
func (b *EthereumRPC) EthereumTypeGetErc20ContractBalance(addrDesc, contractDesc bchain.AddressDescriptor) (*big.Int, error) {
|
||||
addr := hexutil.Encode(addrDesc)
|
||||
addr := hexutil.Encode(addrDesc)[2:]
|
||||
contract := hexutil.Encode(contractDesc)
|
||||
req := contractBalanceOfSignature + "0000000000000000000000000000000000000000000000000000000000000000"[len(addr)-2:] + addr[2:]
|
||||
data, err := b.ethCall(req, contract)
|
||||
req := contractBalanceOfSignature + "0000000000000000000000000000000000000000000000000000000000000000"[len(addr):] + addr
|
||||
data, err := b.EthereumTypeRpcCall(req, contract, "")
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
@ -351,7 +356,7 @@ func (b *EthereumRPC) EthereumTypeGetErc20ContractBalance(addrDesc, contractDesc
|
||||
return r, nil
|
||||
}
|
||||
|
||||
// GetContractInfo returns URI of non fungible or multi token defined by token id
|
||||
// GetTokenURI returns URI of non fungible or multi token defined by token id
|
||||
func (b *EthereumRPC) GetTokenURI(contractDesc bchain.AddressDescriptor, tokenID *big.Int) (string, error) {
|
||||
address := hexutil.Encode(contractDesc)
|
||||
// CryptoKitties do not fully support ERC721 standard, do not have tokenURI method
|
||||
@ -364,7 +369,7 @@ func (b *EthereumRPC) GetTokenURI(contractDesc bchain.AddressDescriptor, tokenID
|
||||
}
|
||||
// try ERC721 tokenURI method and ERC1155 uri method
|
||||
for _, method := range []string{erc721TokenURIMethodSignature, erc1155URIMethodSignature} {
|
||||
data, err := b.ethCall(method+id, address)
|
||||
data, err := b.EthereumTypeRpcCall(method+id, address, "")
|
||||
if err == nil && data != "" {
|
||||
uri := parseSimpleStringProperty(data)
|
||||
// try to sanitize the URI returned from the contract
|
||||
|
||||
@ -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"
|
||||
|
||||
"github.com/ethereum/go-ethereum/common/hexutil"
|
||||
"github.com/golang/protobuf/proto"
|
||||
"github.com/juju/errors"
|
||||
"github.com/trezor/blockbook/bchain"
|
||||
"golang.org/x/crypto/sha3"
|
||||
"google.golang.org/protobuf/proto"
|
||||
)
|
||||
|
||||
// EthereumTypeAddressDescriptorLen - the AddressDescriptor of EthereumType has fixed length
|
||||
@ -25,15 +25,19 @@ const EtherAmountDecimalPoint = 18
|
||||
// EthereumParser handle
|
||||
type EthereumParser struct {
|
||||
*bchain.BaseParser
|
||||
EnsSuffix string
|
||||
}
|
||||
|
||||
// NewEthereumParser returns new EthereumParser instance
|
||||
func NewEthereumParser(b int, addressAliases bool) *EthereumParser {
|
||||
return &EthereumParser{&bchain.BaseParser{
|
||||
BlockAddressesToKeep: b,
|
||||
AmountDecimalPoint: EtherAmountDecimalPoint,
|
||||
AddressAliases: addressAliases,
|
||||
}}
|
||||
return &EthereumParser{
|
||||
BaseParser: &bchain.BaseParser{
|
||||
BlockAddressesToKeep: b,
|
||||
AmountDecimalPoint: EtherAmountDecimalPoint,
|
||||
AddressAliases: addressAliases,
|
||||
},
|
||||
EnsSuffix: ".eth",
|
||||
}
|
||||
}
|
||||
|
||||
type rpcHeader struct {
|
||||
@ -331,6 +335,24 @@ func (p *EthereumParser) PackTx(tx *bchain.Tx, height uint32, blockTime int64) (
|
||||
|
||||
}
|
||||
pt.Receipt.Log = ptLogs
|
||||
if r.Receipt.L1Fee != "" {
|
||||
if pt.Receipt.L1Fee, err = hexDecodeBig(r.Receipt.L1Fee); err != nil {
|
||||
return nil, errors.Annotatef(err, "L1Fee %v", r.Receipt.L1Fee)
|
||||
}
|
||||
}
|
||||
if r.Receipt.L1FeeScalar != "" {
|
||||
pt.Receipt.L1FeeScalar = []byte(r.Receipt.L1FeeScalar)
|
||||
}
|
||||
if r.Receipt.L1GasPrice != "" {
|
||||
if pt.Receipt.L1GasPrice, err = hexDecodeBig(r.Receipt.L1GasPrice); err != nil {
|
||||
return nil, errors.Annotatef(err, "L1GasPrice %v", r.Receipt.L1GasPrice)
|
||||
}
|
||||
}
|
||||
if r.Receipt.L1GasUsed != "" {
|
||||
if pt.Receipt.L1GasUsed, err = hexDecodeBig(r.Receipt.L1GasUsed); err != nil {
|
||||
return nil, errors.Annotatef(err, "L1GasUsed %v", r.Receipt.L1GasUsed)
|
||||
}
|
||||
}
|
||||
}
|
||||
return proto.Marshal(pt)
|
||||
}
|
||||
@ -359,27 +381,37 @@ func (p *EthereumParser) UnpackTx(buf []byte) (*bchain.Tx, uint32, error) {
|
||||
}
|
||||
var rr *bchain.RpcReceipt
|
||||
if pt.Receipt != nil {
|
||||
logs := make([]*bchain.RpcLog, len(pt.Receipt.Log))
|
||||
rr = &bchain.RpcReceipt{
|
||||
GasUsed: hexEncodeBig(pt.Receipt.GasUsed),
|
||||
Status: "",
|
||||
Logs: make([]*bchain.RpcLog, len(pt.Receipt.Log)),
|
||||
}
|
||||
for i, l := range pt.Receipt.Log {
|
||||
topics := make([]string, len(l.Topics))
|
||||
for j, t := range l.Topics {
|
||||
topics[j] = hexutil.Encode(t)
|
||||
}
|
||||
logs[i] = &bchain.RpcLog{
|
||||
rr.Logs[i] = &bchain.RpcLog{
|
||||
Address: EIP55Address(l.Address),
|
||||
Data: hexutil.Encode(l.Data),
|
||||
Topics: topics,
|
||||
}
|
||||
}
|
||||
status := ""
|
||||
// handle a special value []byte{'U'} as unknown state
|
||||
if len(pt.Receipt.Status) != 1 || pt.Receipt.Status[0] != 'U' {
|
||||
status = hexEncodeBig(pt.Receipt.Status)
|
||||
rr.Status = hexEncodeBig(pt.Receipt.Status)
|
||||
}
|
||||
rr = &bchain.RpcReceipt{
|
||||
GasUsed: hexEncodeBig(pt.Receipt.GasUsed),
|
||||
Status: status,
|
||||
Logs: logs,
|
||||
if len(pt.Receipt.L1Fee) > 0 {
|
||||
rr.L1Fee = hexEncodeBig(pt.Receipt.L1Fee)
|
||||
}
|
||||
if len(pt.Receipt.L1FeeScalar) > 0 {
|
||||
rr.L1FeeScalar = string(pt.Receipt.L1FeeScalar)
|
||||
}
|
||||
if len(pt.Receipt.L1GasPrice) > 0 {
|
||||
rr.L1GasPrice = hexEncodeBig(pt.Receipt.L1GasPrice)
|
||||
}
|
||||
if len(pt.Receipt.L1GasUsed) > 0 {
|
||||
rr.L1GasUsed = hexEncodeBig(pt.Receipt.L1GasUsed)
|
||||
}
|
||||
}
|
||||
// TODO handle internal transactions
|
||||
@ -461,7 +493,7 @@ func (p *EthereumParser) EthereumTypeGetTokenTransfersFromTx(tx *bchain.Tx) (bch
|
||||
|
||||
// FormatAddressAlias adds .eth to a name alias
|
||||
func (p *EthereumParser) FormatAddressAlias(address string, name string) string {
|
||||
return name + ".eth"
|
||||
return name + p.EnsSuffix
|
||||
}
|
||||
|
||||
// TxStatus is status of transaction
|
||||
@ -477,12 +509,16 @@ const (
|
||||
|
||||
// EthereumTxData contains ethereum specific transaction data
|
||||
type EthereumTxData struct {
|
||||
Status TxStatus `json:"status"` // 1 OK, 0 Fail, -1 pending, -2 unknown
|
||||
Nonce uint64 `json:"nonce"`
|
||||
GasLimit *big.Int `json:"gaslimit"`
|
||||
GasUsed *big.Int `json:"gasused"`
|
||||
GasPrice *big.Int `json:"gasprice"`
|
||||
Data string `json:"data"`
|
||||
Status TxStatus `json:"status"` // 1 OK, 0 Fail, -1 pending, -2 unknown
|
||||
Nonce uint64 `json:"nonce"`
|
||||
GasLimit *big.Int `json:"gaslimit"`
|
||||
GasUsed *big.Int `json:"gasused"`
|
||||
GasPrice *big.Int `json:"gasprice"`
|
||||
L1Fee *big.Int `json:"l1Fee,omitempty"`
|
||||
L1FeeScalar string `json:"l1FeeScalar,omitempty"`
|
||||
L1GasPrice *big.Int `json:"l1GasPrice,omitempty"`
|
||||
L1GasUsed *big.Int `json:"L1GasUsed,omitempty"`
|
||||
Data string `json:"data"`
|
||||
}
|
||||
|
||||
// GetEthereumTxData returns EthereumTxData from bchain.Tx
|
||||
@ -511,6 +547,10 @@ func GetEthereumTxDataFromSpecificData(coinSpecificData interface{}) *EthereumTx
|
||||
etd.Status = TxStatusFailure
|
||||
}
|
||||
etd.GasUsed, _ = hexutil.DecodeBig(csd.Receipt.GasUsed)
|
||||
etd.L1Fee, _ = hexutil.DecodeBig(csd.Receipt.L1Fee)
|
||||
etd.L1GasPrice, _ = hexutil.DecodeBig(csd.Receipt.L1GasPrice)
|
||||
etd.L1GasUsed, _ = hexutil.DecodeBig(csd.Receipt.L1GasUsed)
|
||||
etd.L1FeeScalar = csd.Receipt.L1FeeScalar
|
||||
}
|
||||
}
|
||||
return &etd
|
||||
|
||||
@ -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"
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"io/ioutil"
|
||||
"io"
|
||||
"math/big"
|
||||
"net/http"
|
||||
"strconv"
|
||||
@ -30,18 +30,17 @@ type Network uint32
|
||||
const (
|
||||
// MainNet is production network
|
||||
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 Network = 11155111
|
||||
// TestNetHolesky is Holesky test network
|
||||
TestNetHolesky Network = 17000
|
||||
)
|
||||
|
||||
// Configuration represents json config file
|
||||
type Configuration struct {
|
||||
CoinName string `json:"coin_name"`
|
||||
CoinShortcut string `json:"coin_shortcut"`
|
||||
Network string `json:"network"`
|
||||
RPCURL string `json:"rpc_url"`
|
||||
RPCTimeout int `json:"rpc_timeout"`
|
||||
BlockAddressesToKeep int `json:"block_addresses_to_keep"`
|
||||
@ -51,28 +50,32 @@ type Configuration struct {
|
||||
ProcessInternalTransactions bool `json:"processInternalTransactions"`
|
||||
ProcessZeroInternalTransactions bool `json:"processZeroInternalTransactions"`
|
||||
ConsensusNodeVersionURL string `json:"consensusNodeVersion"`
|
||||
DisableMempoolSync bool `json:"disableMempoolSync,omitempty"`
|
||||
}
|
||||
|
||||
// EthereumRPC is an interface to JSON-RPC eth service.
|
||||
type EthereumRPC struct {
|
||||
*bchain.BaseChain
|
||||
Client bchain.EVMClient
|
||||
RPC bchain.EVMRPCClient
|
||||
MainNetChainID Network
|
||||
Timeout time.Duration
|
||||
Parser *EthereumParser
|
||||
PushHandler func(bchain.NotificationType)
|
||||
OpenRPC func(string) (bchain.EVMRPCClient, bchain.EVMClient, error)
|
||||
Mempool *bchain.MempoolEthereumType
|
||||
mempoolInitialized bool
|
||||
bestHeaderLock sync.Mutex
|
||||
bestHeader bchain.EVMHeader
|
||||
bestHeaderTime time.Time
|
||||
NewBlock bchain.EVMNewBlockSubscriber
|
||||
newBlockSubscription bchain.EVMClientSubscription
|
||||
NewTx bchain.EVMNewTxSubscriber
|
||||
newTxSubscription bchain.EVMClientSubscription
|
||||
ChainConfig *Configuration
|
||||
Client bchain.EVMClient
|
||||
RPC bchain.EVMRPCClient
|
||||
MainNetChainID Network
|
||||
Timeout time.Duration
|
||||
Parser *EthereumParser
|
||||
PushHandler func(bchain.NotificationType)
|
||||
OpenRPC func(string) (bchain.EVMRPCClient, bchain.EVMClient, error)
|
||||
Mempool *bchain.MempoolEthereumType
|
||||
mempoolInitialized bool
|
||||
bestHeaderLock sync.Mutex
|
||||
bestHeader bchain.EVMHeader
|
||||
bestHeaderTime time.Time
|
||||
NewBlock bchain.EVMNewBlockSubscriber
|
||||
newBlockSubscription bchain.EVMClientSubscription
|
||||
NewTx bchain.EVMNewTxSubscriber
|
||||
newTxSubscription bchain.EVMClientSubscription
|
||||
ChainConfig *Configuration
|
||||
supportedStakingPools []string
|
||||
stakingPoolNames []string
|
||||
stakingPoolContracts []string
|
||||
}
|
||||
|
||||
// ProcessInternalTransactions specifies if internal transactions are processed
|
||||
@ -106,17 +109,22 @@ func NewEthereumRPC(config json.RawMessage, pushHandler func(bchain.Notification
|
||||
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
|
||||
func (b *EthereumRPC) Initialize() error {
|
||||
b.OpenRPC = func(url string) (bchain.EVMRPCClient, bchain.EVMClient, error) {
|
||||
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
|
||||
}
|
||||
b.OpenRPC = OpenRPC
|
||||
|
||||
rc, ec, err := b.OpenRPC(b.ChainConfig.RPCURL)
|
||||
if err != nil {
|
||||
@ -143,18 +151,21 @@ func (b *EthereumRPC) Initialize() error {
|
||||
case MainNet:
|
||||
b.Testnet = false
|
||||
b.Network = "livenet"
|
||||
case TestNet:
|
||||
b.Testnet = true
|
||||
b.Network = "testnet"
|
||||
case TestNetGoerli:
|
||||
b.Testnet = true
|
||||
b.Network = "goerli"
|
||||
case TestNetSepolia:
|
||||
b.Testnet = true
|
||||
b.Network = "sepolia"
|
||||
case TestNetHolesky:
|
||||
b.Testnet = true
|
||||
b.Network = "holesky"
|
||||
default:
|
||||
return errors.Errorf("Unknown network id %v", id)
|
||||
}
|
||||
|
||||
err = b.initStakingPools()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
glog.Info("rpc: block chain ", b.Network)
|
||||
|
||||
return nil
|
||||
@ -164,7 +175,7 @@ func (b *EthereumRPC) Initialize() error {
|
||||
func (b *EthereumRPC) CreateMempool(chain bchain.BlockChain) (bchain.Mempool, error) {
|
||||
if b.Mempool == nil {
|
||||
b.Mempool = bchain.NewMempoolEthereumType(chain, b.ChainConfig.MempoolTxTimeoutHours, b.ChainConfig.QueryBackendOnMempoolResync)
|
||||
glog.Info("mempool created, MempoolTxTimeoutHours=", b.ChainConfig.MempoolTxTimeoutHours, ", QueryBackendOnMempoolResync=", b.ChainConfig.QueryBackendOnMempoolResync)
|
||||
glog.Info("mempool created, MempoolTxTimeoutHours=", b.ChainConfig.MempoolTxTimeoutHours, ", QueryBackendOnMempoolResync=", b.ChainConfig.QueryBackendOnMempoolResync, ", DisableMempoolSync=", b.ChainConfig.DisableMempoolSync)
|
||||
}
|
||||
return b.Mempool, nil
|
||||
}
|
||||
@ -175,11 +186,19 @@ func (b *EthereumRPC) InitializeMempool(addrDescForOutpoint bchain.AddrDescForOu
|
||||
return errors.New("Mempool not created")
|
||||
}
|
||||
|
||||
var err error
|
||||
var txs []string
|
||||
// get initial mempool transactions
|
||||
txs, err := b.GetMempoolTransactions()
|
||||
if err != nil {
|
||||
return err
|
||||
// workaround for an occasional `decoding block` error from getBlockRaw - try 3 times with a delay and then proceed
|
||||
for i := 0; i < 3; i++ {
|
||||
txs, err = b.GetMempoolTransactions()
|
||||
if err == nil {
|
||||
break
|
||||
}
|
||||
glog.Error("GetMempoolTransaction ", err)
|
||||
time.Sleep(time.Second * 5)
|
||||
}
|
||||
|
||||
for _, txid := range txs {
|
||||
b.Mempool.AddTransactionToMempool(txid)
|
||||
}
|
||||
@ -238,26 +257,30 @@ func (b *EthereumRPC) subscribeEvents() error {
|
||||
if glog.V(2) {
|
||||
glog.Info("rpc: new tx ", hex)
|
||||
}
|
||||
b.Mempool.AddTransactionToMempool(hex)
|
||||
b.PushHandler(bchain.NotificationNewTx)
|
||||
added := b.Mempool.AddTransactionToMempool(hex)
|
||||
if added {
|
||||
b.PushHandler(bchain.NotificationNewTx)
|
||||
}
|
||||
}
|
||||
}()
|
||||
|
||||
// new mempool transaction subscription
|
||||
if err := b.subscribe(func() (bchain.EVMClientSubscription, error) {
|
||||
// invalidate the previous subscription - it is either the first one or there was an error
|
||||
b.newTxSubscription = nil
|
||||
ctx, cancel := context.WithTimeout(context.Background(), b.Timeout)
|
||||
defer cancel()
|
||||
sub, err := b.RPC.EthSubscribe(ctx, b.NewTx.Channel(), "newPendingTransactions")
|
||||
if err != nil {
|
||||
return nil, errors.Annotatef(err, "EthSubscribe newPendingTransactions")
|
||||
if !b.ChainConfig.DisableMempoolSync {
|
||||
// new mempool transaction subscription
|
||||
if err := b.subscribe(func() (bchain.EVMClientSubscription, error) {
|
||||
// invalidate the previous subscription - it is either the first one or there was an error
|
||||
b.newTxSubscription = nil
|
||||
ctx, cancel := context.WithTimeout(context.Background(), b.Timeout)
|
||||
defer cancel()
|
||||
sub, err := b.RPC.EthSubscribe(ctx, b.NewTx.Channel(), "newPendingTransactions")
|
||||
if err != nil {
|
||||
return nil, errors.Annotatef(err, "EthSubscribe newPendingTransactions")
|
||||
}
|
||||
b.newTxSubscription = sub
|
||||
glog.Info("Subscribed to newPendingTransactions")
|
||||
return sub, nil
|
||||
}); err != nil {
|
||||
return err
|
||||
}
|
||||
b.newTxSubscription = sub
|
||||
glog.Info("Subscribed to newPendingTransactions")
|
||||
return sub, nil
|
||||
}); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
return nil
|
||||
@ -358,7 +381,7 @@ func (b *EthereumRPC) getConsensusVersion() string {
|
||||
glog.Error("getConsensusVersion ", err)
|
||||
return ""
|
||||
}
|
||||
body, err := ioutil.ReadAll(resp.Body)
|
||||
body, err := io.ReadAll(resp.Body)
|
||||
if err != nil {
|
||||
glog.Error("getConsensusVersion ", err)
|
||||
return ""
|
||||
@ -591,19 +614,24 @@ type rpcTraceResult struct {
|
||||
}
|
||||
|
||||
func (b *EthereumRPC) getCreationContractInfo(contract string, height uint32) *bchain.ContractInfo {
|
||||
ci, err := b.fetchContractInfo(contract)
|
||||
if ci == nil || err != nil {
|
||||
ci = &bchain.ContractInfo{
|
||||
Contract: contract,
|
||||
}
|
||||
// do not fetch fetchContractInfo in sync, it slows it down
|
||||
// the contract will be fetched only when asked by a client
|
||||
// ci, err := b.fetchContractInfo(contract)
|
||||
// if ci == nil || err != nil {
|
||||
ci := &bchain.ContractInfo{
|
||||
Contract: contract,
|
||||
}
|
||||
ci.Type = bchain.UnknownTokenType
|
||||
// }
|
||||
ci.Type = bchain.UnhandledTokenType
|
||||
ci.CreatedInBlock = height
|
||||
return ci
|
||||
}
|
||||
|
||||
func (b *EthereumRPC) processCallTrace(call *rpcCallTrace, d *bchain.EthereumInternalData, contracts []bchain.ContractInfo, blockHeight uint32) []bchain.ContractInfo {
|
||||
value, err := hexutil.DecodeBig(call.Value)
|
||||
if err != nil {
|
||||
value = new(big.Int)
|
||||
}
|
||||
if call.Type == "CREATE" || call.Type == "CREATE2" {
|
||||
d.Transfers = append(d.Transfers, bchain.EthereumInternalTransfer{
|
||||
Type: bchain.CREATE,
|
||||
@ -653,8 +681,28 @@ func (b *EthereumRPC) getInternalDataForBlock(blockHash string, blockHeight uint
|
||||
return data, contracts, err
|
||||
}
|
||||
if len(trace) != len(data) {
|
||||
glog.Error("debug_traceBlockByHash block ", blockHash, ", error: trace length does not match block length ", len(trace), "!=", len(data))
|
||||
return data, contracts, err
|
||||
if len(trace) < len(data) {
|
||||
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 {
|
||||
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) {
|
||||
ctx, cancel := context.WithTimeout(context.Background(), b.Timeout)
|
||||
defer cancel()
|
||||
var tx *bchain.RpcTransaction
|
||||
tx := &bchain.RpcTransaction{}
|
||||
hash := ethcommon.HexToHash(txid)
|
||||
err := b.RPC.CallContext(ctx, &tx, "eth_getTransactionByHash", hash)
|
||||
err := b.RPC.CallContext(ctx, tx, "eth_getTransactionByHash", hash)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
} else if tx == nil {
|
||||
}
|
||||
if *tx == (bchain.RpcTransaction{}) {
|
||||
if b.mempoolInitialized {
|
||||
b.Mempool.RemoveTransactionFromMempool(txid)
|
||||
}
|
||||
@ -943,21 +992,31 @@ func (b *EthereumRPC) EthereumTypeEstimateGas(params map[string]interface{}) (ui
|
||||
|
||||
// SendRawTransaction sends raw transaction
|
||||
func (b *EthereumRPC) SendRawTransaction(hex string) (string, error) {
|
||||
return b.callRpcStringResult("eth_sendRawTransaction", hex)
|
||||
}
|
||||
|
||||
// EthereumTypeGetRawTransaction gets raw transaction in hex format
|
||||
func (b *EthereumRPC) EthereumTypeGetRawTransaction(txid string) (string, error) {
|
||||
return b.callRpcStringResult("eth_getRawTransactionByHash", txid)
|
||||
}
|
||||
|
||||
// Helper function for calling ETH RPC with parameters and getting string result
|
||||
func (b *EthereumRPC) callRpcStringResult(rpcMethod string, args ...interface{}) (string, error) {
|
||||
ctx, cancel := context.WithTimeout(context.Background(), b.Timeout)
|
||||
defer cancel()
|
||||
var raw json.RawMessage
|
||||
err := b.RPC.CallContext(ctx, &raw, "eth_sendRawTransaction", hex)
|
||||
err := b.RPC.CallContext(ctx, &raw, rpcMethod, args...)
|
||||
if err != nil {
|
||||
return "", err
|
||||
} else if len(raw) == 0 {
|
||||
return "", errors.New("SendRawTransaction: failed")
|
||||
return "", errors.New(rpcMethod + " : failed")
|
||||
}
|
||||
var result string
|
||||
if err := json.Unmarshal(raw, &result); err != nil {
|
||||
return "", errors.Annotatef(err, "raw result %v", raw)
|
||||
}
|
||||
if result == "" {
|
||||
return "", errors.New("SendRawTransaction: failed, empty result")
|
||||
return "", errors.New(rpcMethod + " : failed, empty result")
|
||||
}
|
||||
return result, nil
|
||||
}
|
||||
|
||||
@ -1,261 +1,530 @@
|
||||
// Code generated by protoc-gen-go. DO NOT EDIT.
|
||||
// versions:
|
||||
// protoc-gen-go v1.28.1
|
||||
// protoc v3.21.12
|
||||
// source: bchain/coins/eth/ethtx.proto
|
||||
|
||||
/*
|
||||
Package eth is a generated protocol buffer package.
|
||||
|
||||
It is generated from these files:
|
||||
bchain/coins/eth/ethtx.proto
|
||||
|
||||
It has these top-level messages:
|
||||
ProtoCompleteTransaction
|
||||
*/
|
||||
package eth
|
||||
|
||||
import proto "github.com/golang/protobuf/proto"
|
||||
import fmt "fmt"
|
||||
import math "math"
|
||||
import (
|
||||
protoreflect "google.golang.org/protobuf/reflect/protoreflect"
|
||||
protoimpl "google.golang.org/protobuf/runtime/protoimpl"
|
||||
reflect "reflect"
|
||||
sync "sync"
|
||||
)
|
||||
|
||||
// Reference imports to suppress errors if they are not otherwise used.
|
||||
var _ = proto.Marshal
|
||||
var _ = fmt.Errorf
|
||||
var _ = math.Inf
|
||||
|
||||
// This is a compile-time assertion to ensure that this generated file
|
||||
// is compatible with the proto package it is being compiled against.
|
||||
// A compilation error at this line likely means your copy of the
|
||||
// proto package needs to be updated.
|
||||
const _ = proto.ProtoPackageIsVersion2 // please upgrade the proto package
|
||||
const (
|
||||
// Verify that this generated code is sufficiently up-to-date.
|
||||
_ = protoimpl.EnforceVersion(20 - protoimpl.MinVersion)
|
||||
// Verify that runtime/protoimpl is sufficiently up-to-date.
|
||||
_ = protoimpl.EnforceVersion(protoimpl.MaxVersion - 20)
|
||||
)
|
||||
|
||||
type ProtoCompleteTransaction struct {
|
||||
BlockNumber uint32 `protobuf:"varint,1,opt,name=BlockNumber" json:"BlockNumber,omitempty"`
|
||||
BlockTime uint64 `protobuf:"varint,2,opt,name=BlockTime" json:"BlockTime,omitempty"`
|
||||
Tx *ProtoCompleteTransaction_TxType `protobuf:"bytes,3,opt,name=Tx" json:"Tx,omitempty"`
|
||||
Receipt *ProtoCompleteTransaction_ReceiptType `protobuf:"bytes,4,opt,name=Receipt" json:"Receipt,omitempty"`
|
||||
state protoimpl.MessageState
|
||||
sizeCache protoimpl.SizeCache
|
||||
unknownFields protoimpl.UnknownFields
|
||||
|
||||
BlockNumber uint32 `protobuf:"varint,1,opt,name=BlockNumber,proto3" json:"BlockNumber,omitempty"`
|
||||
BlockTime uint64 `protobuf:"varint,2,opt,name=BlockTime,proto3" json:"BlockTime,omitempty"`
|
||||
Tx *ProtoCompleteTransaction_TxType `protobuf:"bytes,3,opt,name=Tx,proto3" json:"Tx,omitempty"`
|
||||
Receipt *ProtoCompleteTransaction_ReceiptType `protobuf:"bytes,4,opt,name=Receipt,proto3" json:"Receipt,omitempty"`
|
||||
}
|
||||
|
||||
func (m *ProtoCompleteTransaction) Reset() { *m = ProtoCompleteTransaction{} }
|
||||
func (m *ProtoCompleteTransaction) String() string { return proto.CompactTextString(m) }
|
||||
func (*ProtoCompleteTransaction) ProtoMessage() {}
|
||||
func (*ProtoCompleteTransaction) Descriptor() ([]byte, []int) { return fileDescriptor0, []int{0} }
|
||||
func (x *ProtoCompleteTransaction) Reset() {
|
||||
*x = ProtoCompleteTransaction{}
|
||||
if protoimpl.UnsafeEnabled {
|
||||
mi := &file_bchain_coins_eth_ethtx_proto_msgTypes[0]
|
||||
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
||||
ms.StoreMessageInfo(mi)
|
||||
}
|
||||
}
|
||||
|
||||
func (m *ProtoCompleteTransaction) GetBlockNumber() uint32 {
|
||||
if m != nil {
|
||||
return m.BlockNumber
|
||||
func (x *ProtoCompleteTransaction) String() string {
|
||||
return protoimpl.X.MessageStringOf(x)
|
||||
}
|
||||
|
||||
func (*ProtoCompleteTransaction) ProtoMessage() {}
|
||||
|
||||
func (x *ProtoCompleteTransaction) ProtoReflect() protoreflect.Message {
|
||||
mi := &file_bchain_coins_eth_ethtx_proto_msgTypes[0]
|
||||
if protoimpl.UnsafeEnabled && x != nil {
|
||||
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
||||
if ms.LoadMessageInfo() == nil {
|
||||
ms.StoreMessageInfo(mi)
|
||||
}
|
||||
return ms
|
||||
}
|
||||
return mi.MessageOf(x)
|
||||
}
|
||||
|
||||
// Deprecated: Use ProtoCompleteTransaction.ProtoReflect.Descriptor instead.
|
||||
func (*ProtoCompleteTransaction) Descriptor() ([]byte, []int) {
|
||||
return file_bchain_coins_eth_ethtx_proto_rawDescGZIP(), []int{0}
|
||||
}
|
||||
|
||||
func (x *ProtoCompleteTransaction) GetBlockNumber() uint32 {
|
||||
if x != nil {
|
||||
return x.BlockNumber
|
||||
}
|
||||
return 0
|
||||
}
|
||||
|
||||
func (m *ProtoCompleteTransaction) GetBlockTime() uint64 {
|
||||
if m != nil {
|
||||
return m.BlockTime
|
||||
func (x *ProtoCompleteTransaction) GetBlockTime() uint64 {
|
||||
if x != nil {
|
||||
return x.BlockTime
|
||||
}
|
||||
return 0
|
||||
}
|
||||
|
||||
func (m *ProtoCompleteTransaction) GetTx() *ProtoCompleteTransaction_TxType {
|
||||
if m != nil {
|
||||
return m.Tx
|
||||
func (x *ProtoCompleteTransaction) GetTx() *ProtoCompleteTransaction_TxType {
|
||||
if x != nil {
|
||||
return x.Tx
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (m *ProtoCompleteTransaction) GetReceipt() *ProtoCompleteTransaction_ReceiptType {
|
||||
if m != nil {
|
||||
return m.Receipt
|
||||
func (x *ProtoCompleteTransaction) GetReceipt() *ProtoCompleteTransaction_ReceiptType {
|
||||
if x != nil {
|
||||
return x.Receipt
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
type ProtoCompleteTransaction_TxType struct {
|
||||
AccountNonce uint64 `protobuf:"varint,1,opt,name=AccountNonce" json:"AccountNonce,omitempty"`
|
||||
state protoimpl.MessageState
|
||||
sizeCache protoimpl.SizeCache
|
||||
unknownFields protoimpl.UnknownFields
|
||||
|
||||
AccountNonce uint64 `protobuf:"varint,1,opt,name=AccountNonce,proto3" json:"AccountNonce,omitempty"`
|
||||
GasPrice []byte `protobuf:"bytes,2,opt,name=GasPrice,proto3" json:"GasPrice,omitempty"`
|
||||
GasLimit uint64 `protobuf:"varint,3,opt,name=GasLimit" json:"GasLimit,omitempty"`
|
||||
GasLimit uint64 `protobuf:"varint,3,opt,name=GasLimit,proto3" json:"GasLimit,omitempty"`
|
||||
Value []byte `protobuf:"bytes,4,opt,name=Value,proto3" json:"Value,omitempty"`
|
||||
Payload []byte `protobuf:"bytes,5,opt,name=Payload,proto3" json:"Payload,omitempty"`
|
||||
Hash []byte `protobuf:"bytes,6,opt,name=Hash,proto3" json:"Hash,omitempty"`
|
||||
To []byte `protobuf:"bytes,7,opt,name=To,proto3" json:"To,omitempty"`
|
||||
From []byte `protobuf:"bytes,8,opt,name=From,proto3" json:"From,omitempty"`
|
||||
TransactionIndex uint32 `protobuf:"varint,9,opt,name=TransactionIndex" json:"TransactionIndex,omitempty"`
|
||||
TransactionIndex uint32 `protobuf:"varint,9,opt,name=TransactionIndex,proto3" json:"TransactionIndex,omitempty"`
|
||||
}
|
||||
|
||||
func (m *ProtoCompleteTransaction_TxType) Reset() { *m = ProtoCompleteTransaction_TxType{} }
|
||||
func (m *ProtoCompleteTransaction_TxType) String() string { return proto.CompactTextString(m) }
|
||||
func (*ProtoCompleteTransaction_TxType) ProtoMessage() {}
|
||||
func (x *ProtoCompleteTransaction_TxType) Reset() {
|
||||
*x = ProtoCompleteTransaction_TxType{}
|
||||
if protoimpl.UnsafeEnabled {
|
||||
mi := &file_bchain_coins_eth_ethtx_proto_msgTypes[1]
|
||||
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
||||
ms.StoreMessageInfo(mi)
|
||||
}
|
||||
}
|
||||
|
||||
func (x *ProtoCompleteTransaction_TxType) String() string {
|
||||
return protoimpl.X.MessageStringOf(x)
|
||||
}
|
||||
|
||||
func (*ProtoCompleteTransaction_TxType) ProtoMessage() {}
|
||||
|
||||
func (x *ProtoCompleteTransaction_TxType) ProtoReflect() protoreflect.Message {
|
||||
mi := &file_bchain_coins_eth_ethtx_proto_msgTypes[1]
|
||||
if protoimpl.UnsafeEnabled && x != nil {
|
||||
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
||||
if ms.LoadMessageInfo() == nil {
|
||||
ms.StoreMessageInfo(mi)
|
||||
}
|
||||
return ms
|
||||
}
|
||||
return mi.MessageOf(x)
|
||||
}
|
||||
|
||||
// Deprecated: Use ProtoCompleteTransaction_TxType.ProtoReflect.Descriptor instead.
|
||||
func (*ProtoCompleteTransaction_TxType) Descriptor() ([]byte, []int) {
|
||||
return fileDescriptor0, []int{0, 0}
|
||||
return file_bchain_coins_eth_ethtx_proto_rawDescGZIP(), []int{0, 0}
|
||||
}
|
||||
|
||||
func (m *ProtoCompleteTransaction_TxType) GetAccountNonce() uint64 {
|
||||
if m != nil {
|
||||
return m.AccountNonce
|
||||
func (x *ProtoCompleteTransaction_TxType) GetAccountNonce() uint64 {
|
||||
if x != nil {
|
||||
return x.AccountNonce
|
||||
}
|
||||
return 0
|
||||
}
|
||||
|
||||
func (m *ProtoCompleteTransaction_TxType) GetGasPrice() []byte {
|
||||
if m != nil {
|
||||
return m.GasPrice
|
||||
func (x *ProtoCompleteTransaction_TxType) GetGasPrice() []byte {
|
||||
if x != nil {
|
||||
return x.GasPrice
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (m *ProtoCompleteTransaction_TxType) GetGasLimit() uint64 {
|
||||
if m != nil {
|
||||
return m.GasLimit
|
||||
func (x *ProtoCompleteTransaction_TxType) GetGasLimit() uint64 {
|
||||
if x != nil {
|
||||
return x.GasLimit
|
||||
}
|
||||
return 0
|
||||
}
|
||||
|
||||
func (m *ProtoCompleteTransaction_TxType) GetValue() []byte {
|
||||
if m != nil {
|
||||
return m.Value
|
||||
func (x *ProtoCompleteTransaction_TxType) GetValue() []byte {
|
||||
if x != nil {
|
||||
return x.Value
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (m *ProtoCompleteTransaction_TxType) GetPayload() []byte {
|
||||
if m != nil {
|
||||
return m.Payload
|
||||
func (x *ProtoCompleteTransaction_TxType) GetPayload() []byte {
|
||||
if x != nil {
|
||||
return x.Payload
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (m *ProtoCompleteTransaction_TxType) GetHash() []byte {
|
||||
if m != nil {
|
||||
return m.Hash
|
||||
func (x *ProtoCompleteTransaction_TxType) GetHash() []byte {
|
||||
if x != nil {
|
||||
return x.Hash
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (m *ProtoCompleteTransaction_TxType) GetTo() []byte {
|
||||
if m != nil {
|
||||
return m.To
|
||||
func (x *ProtoCompleteTransaction_TxType) GetTo() []byte {
|
||||
if x != nil {
|
||||
return x.To
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (m *ProtoCompleteTransaction_TxType) GetFrom() []byte {
|
||||
if m != nil {
|
||||
return m.From
|
||||
func (x *ProtoCompleteTransaction_TxType) GetFrom() []byte {
|
||||
if x != nil {
|
||||
return x.From
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (m *ProtoCompleteTransaction_TxType) GetTransactionIndex() uint32 {
|
||||
if m != nil {
|
||||
return m.TransactionIndex
|
||||
func (x *ProtoCompleteTransaction_TxType) GetTransactionIndex() uint32 {
|
||||
if x != nil {
|
||||
return x.TransactionIndex
|
||||
}
|
||||
return 0
|
||||
}
|
||||
|
||||
type ProtoCompleteTransaction_ReceiptType struct {
|
||||
GasUsed []byte `protobuf:"bytes,1,opt,name=GasUsed,proto3" json:"GasUsed,omitempty"`
|
||||
Status []byte `protobuf:"bytes,2,opt,name=Status,proto3" json:"Status,omitempty"`
|
||||
Log []*ProtoCompleteTransaction_ReceiptType_LogType `protobuf:"bytes,3,rep,name=Log" json:"Log,omitempty"`
|
||||
state protoimpl.MessageState
|
||||
sizeCache protoimpl.SizeCache
|
||||
unknownFields protoimpl.UnknownFields
|
||||
|
||||
GasUsed []byte `protobuf:"bytes,1,opt,name=GasUsed,proto3" json:"GasUsed,omitempty"`
|
||||
Status []byte `protobuf:"bytes,2,opt,name=Status,proto3" json:"Status,omitempty"`
|
||||
Log []*ProtoCompleteTransaction_ReceiptType_LogType `protobuf:"bytes,3,rep,name=Log,proto3" json:"Log,omitempty"`
|
||||
L1Fee []byte `protobuf:"bytes,4,opt,name=L1Fee,proto3,oneof" json:"L1Fee,omitempty"`
|
||||
L1FeeScalar []byte `protobuf:"bytes,5,opt,name=L1FeeScalar,proto3,oneof" json:"L1FeeScalar,omitempty"`
|
||||
L1GasPrice []byte `protobuf:"bytes,6,opt,name=L1GasPrice,proto3,oneof" json:"L1GasPrice,omitempty"`
|
||||
L1GasUsed []byte `protobuf:"bytes,7,opt,name=L1GasUsed,proto3,oneof" json:"L1GasUsed,omitempty"`
|
||||
}
|
||||
|
||||
func (m *ProtoCompleteTransaction_ReceiptType) Reset() { *m = ProtoCompleteTransaction_ReceiptType{} }
|
||||
func (m *ProtoCompleteTransaction_ReceiptType) String() string { return proto.CompactTextString(m) }
|
||||
func (*ProtoCompleteTransaction_ReceiptType) ProtoMessage() {}
|
||||
func (x *ProtoCompleteTransaction_ReceiptType) Reset() {
|
||||
*x = ProtoCompleteTransaction_ReceiptType{}
|
||||
if protoimpl.UnsafeEnabled {
|
||||
mi := &file_bchain_coins_eth_ethtx_proto_msgTypes[2]
|
||||
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
||||
ms.StoreMessageInfo(mi)
|
||||
}
|
||||
}
|
||||
|
||||
func (x *ProtoCompleteTransaction_ReceiptType) String() string {
|
||||
return protoimpl.X.MessageStringOf(x)
|
||||
}
|
||||
|
||||
func (*ProtoCompleteTransaction_ReceiptType) ProtoMessage() {}
|
||||
|
||||
func (x *ProtoCompleteTransaction_ReceiptType) ProtoReflect() protoreflect.Message {
|
||||
mi := &file_bchain_coins_eth_ethtx_proto_msgTypes[2]
|
||||
if protoimpl.UnsafeEnabled && x != nil {
|
||||
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
||||
if ms.LoadMessageInfo() == nil {
|
||||
ms.StoreMessageInfo(mi)
|
||||
}
|
||||
return ms
|
||||
}
|
||||
return mi.MessageOf(x)
|
||||
}
|
||||
|
||||
// Deprecated: Use ProtoCompleteTransaction_ReceiptType.ProtoReflect.Descriptor instead.
|
||||
func (*ProtoCompleteTransaction_ReceiptType) Descriptor() ([]byte, []int) {
|
||||
return fileDescriptor0, []int{0, 1}
|
||||
return file_bchain_coins_eth_ethtx_proto_rawDescGZIP(), []int{0, 1}
|
||||
}
|
||||
|
||||
func (m *ProtoCompleteTransaction_ReceiptType) GetGasUsed() []byte {
|
||||
if m != nil {
|
||||
return m.GasUsed
|
||||
func (x *ProtoCompleteTransaction_ReceiptType) GetGasUsed() []byte {
|
||||
if x != nil {
|
||||
return x.GasUsed
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (m *ProtoCompleteTransaction_ReceiptType) GetStatus() []byte {
|
||||
if m != nil {
|
||||
return m.Status
|
||||
func (x *ProtoCompleteTransaction_ReceiptType) GetStatus() []byte {
|
||||
if x != nil {
|
||||
return x.Status
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (m *ProtoCompleteTransaction_ReceiptType) GetLog() []*ProtoCompleteTransaction_ReceiptType_LogType {
|
||||
if m != nil {
|
||||
return m.Log
|
||||
func (x *ProtoCompleteTransaction_ReceiptType) GetLog() []*ProtoCompleteTransaction_ReceiptType_LogType {
|
||||
if x != nil {
|
||||
return x.Log
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (x *ProtoCompleteTransaction_ReceiptType) GetL1Fee() []byte {
|
||||
if x != nil {
|
||||
return x.L1Fee
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (x *ProtoCompleteTransaction_ReceiptType) GetL1FeeScalar() []byte {
|
||||
if x != nil {
|
||||
return x.L1FeeScalar
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (x *ProtoCompleteTransaction_ReceiptType) GetL1GasPrice() []byte {
|
||||
if x != nil {
|
||||
return x.L1GasPrice
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (x *ProtoCompleteTransaction_ReceiptType) GetL1GasUsed() []byte {
|
||||
if x != nil {
|
||||
return x.L1GasUsed
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
type ProtoCompleteTransaction_ReceiptType_LogType struct {
|
||||
state protoimpl.MessageState
|
||||
sizeCache protoimpl.SizeCache
|
||||
unknownFields protoimpl.UnknownFields
|
||||
|
||||
Address []byte `protobuf:"bytes,1,opt,name=Address,proto3" json:"Address,omitempty"`
|
||||
Data []byte `protobuf:"bytes,2,opt,name=Data,proto3" json:"Data,omitempty"`
|
||||
Topics [][]byte `protobuf:"bytes,3,rep,name=Topics,proto3" json:"Topics,omitempty"`
|
||||
}
|
||||
|
||||
func (m *ProtoCompleteTransaction_ReceiptType_LogType) Reset() {
|
||||
*m = ProtoCompleteTransaction_ReceiptType_LogType{}
|
||||
func (x *ProtoCompleteTransaction_ReceiptType_LogType) Reset() {
|
||||
*x = ProtoCompleteTransaction_ReceiptType_LogType{}
|
||||
if protoimpl.UnsafeEnabled {
|
||||
mi := &file_bchain_coins_eth_ethtx_proto_msgTypes[3]
|
||||
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
||||
ms.StoreMessageInfo(mi)
|
||||
}
|
||||
}
|
||||
func (m *ProtoCompleteTransaction_ReceiptType_LogType) String() string {
|
||||
return proto.CompactTextString(m)
|
||||
|
||||
func (x *ProtoCompleteTransaction_ReceiptType_LogType) String() string {
|
||||
return protoimpl.X.MessageStringOf(x)
|
||||
}
|
||||
|
||||
func (*ProtoCompleteTransaction_ReceiptType_LogType) ProtoMessage() {}
|
||||
|
||||
func (x *ProtoCompleteTransaction_ReceiptType_LogType) ProtoReflect() protoreflect.Message {
|
||||
mi := &file_bchain_coins_eth_ethtx_proto_msgTypes[3]
|
||||
if protoimpl.UnsafeEnabled && x != nil {
|
||||
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
||||
if ms.LoadMessageInfo() == nil {
|
||||
ms.StoreMessageInfo(mi)
|
||||
}
|
||||
return ms
|
||||
}
|
||||
return mi.MessageOf(x)
|
||||
}
|
||||
|
||||
// Deprecated: Use ProtoCompleteTransaction_ReceiptType_LogType.ProtoReflect.Descriptor instead.
|
||||
func (*ProtoCompleteTransaction_ReceiptType_LogType) Descriptor() ([]byte, []int) {
|
||||
return fileDescriptor0, []int{0, 1, 0}
|
||||
return file_bchain_coins_eth_ethtx_proto_rawDescGZIP(), []int{0, 1, 0}
|
||||
}
|
||||
|
||||
func (m *ProtoCompleteTransaction_ReceiptType_LogType) GetAddress() []byte {
|
||||
if m != nil {
|
||||
return m.Address
|
||||
func (x *ProtoCompleteTransaction_ReceiptType_LogType) GetAddress() []byte {
|
||||
if x != nil {
|
||||
return x.Address
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (m *ProtoCompleteTransaction_ReceiptType_LogType) GetData() []byte {
|
||||
if m != nil {
|
||||
return m.Data
|
||||
func (x *ProtoCompleteTransaction_ReceiptType_LogType) GetData() []byte {
|
||||
if x != nil {
|
||||
return x.Data
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (m *ProtoCompleteTransaction_ReceiptType_LogType) GetTopics() [][]byte {
|
||||
if m != nil {
|
||||
return m.Topics
|
||||
func (x *ProtoCompleteTransaction_ReceiptType_LogType) GetTopics() [][]byte {
|
||||
if x != nil {
|
||||
return x.Topics
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func init() {
|
||||
proto.RegisterType((*ProtoCompleteTransaction)(nil), "eth.ProtoCompleteTransaction")
|
||||
proto.RegisterType((*ProtoCompleteTransaction_TxType)(nil), "eth.ProtoCompleteTransaction.TxType")
|
||||
proto.RegisterType((*ProtoCompleteTransaction_ReceiptType)(nil), "eth.ProtoCompleteTransaction.ReceiptType")
|
||||
proto.RegisterType((*ProtoCompleteTransaction_ReceiptType_LogType)(nil), "eth.ProtoCompleteTransaction.ReceiptType.LogType")
|
||||
var File_bchain_coins_eth_ethtx_proto protoreflect.FileDescriptor
|
||||
|
||||
var file_bchain_coins_eth_ethtx_proto_rawDesc = []byte{
|
||||
0x0a, 0x1c, 0x62, 0x63, 0x68, 0x61, 0x69, 0x6e, 0x2f, 0x63, 0x6f, 0x69, 0x6e, 0x73, 0x2f, 0x65,
|
||||
0x74, 0x68, 0x2f, 0x65, 0x74, 0x68, 0x74, 0x78, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x22, 0xdd,
|
||||
0x06, 0x0a, 0x18, 0x50, 0x72, 0x6f, 0x74, 0x6f, 0x43, 0x6f, 0x6d, 0x70, 0x6c, 0x65, 0x74, 0x65,
|
||||
0x54, 0x72, 0x61, 0x6e, 0x73, 0x61, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x12, 0x20, 0x0a, 0x0b, 0x42,
|
||||
0x6c, 0x6f, 0x63, 0x6b, 0x4e, 0x75, 0x6d, 0x62, 0x65, 0x72, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0d,
|
||||
0x52, 0x0b, 0x42, 0x6c, 0x6f, 0x63, 0x6b, 0x4e, 0x75, 0x6d, 0x62, 0x65, 0x72, 0x12, 0x1c, 0x0a,
|
||||
0x09, 0x42, 0x6c, 0x6f, 0x63, 0x6b, 0x54, 0x69, 0x6d, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x04,
|
||||
0x52, 0x09, 0x42, 0x6c, 0x6f, 0x63, 0x6b, 0x54, 0x69, 0x6d, 0x65, 0x12, 0x30, 0x0a, 0x02, 0x54,
|
||||
0x78, 0x18, 0x03, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x20, 0x2e, 0x50, 0x72, 0x6f, 0x74, 0x6f, 0x43,
|
||||
0x6f, 0x6d, 0x70, 0x6c, 0x65, 0x74, 0x65, 0x54, 0x72, 0x61, 0x6e, 0x73, 0x61, 0x63, 0x74, 0x69,
|
||||
0x6f, 0x6e, 0x2e, 0x54, 0x78, 0x54, 0x79, 0x70, 0x65, 0x52, 0x02, 0x54, 0x78, 0x12, 0x3f, 0x0a,
|
||||
0x07, 0x52, 0x65, 0x63, 0x65, 0x69, 0x70, 0x74, 0x18, 0x04, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x25,
|
||||
0x2e, 0x50, 0x72, 0x6f, 0x74, 0x6f, 0x43, 0x6f, 0x6d, 0x70, 0x6c, 0x65, 0x74, 0x65, 0x54, 0x72,
|
||||
0x61, 0x6e, 0x73, 0x61, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x2e, 0x52, 0x65, 0x63, 0x65, 0x69, 0x70,
|
||||
0x74, 0x54, 0x79, 0x70, 0x65, 0x52, 0x07, 0x52, 0x65, 0x63, 0x65, 0x69, 0x70, 0x74, 0x1a, 0xf8,
|
||||
0x01, 0x0a, 0x06, 0x54, 0x78, 0x54, 0x79, 0x70, 0x65, 0x12, 0x22, 0x0a, 0x0c, 0x41, 0x63, 0x63,
|
||||
0x6f, 0x75, 0x6e, 0x74, 0x4e, 0x6f, 0x6e, 0x63, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x04, 0x52,
|
||||
0x0c, 0x41, 0x63, 0x63, 0x6f, 0x75, 0x6e, 0x74, 0x4e, 0x6f, 0x6e, 0x63, 0x65, 0x12, 0x1a, 0x0a,
|
||||
0x08, 0x47, 0x61, 0x73, 0x50, 0x72, 0x69, 0x63, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0c, 0x52,
|
||||
0x08, 0x47, 0x61, 0x73, 0x50, 0x72, 0x69, 0x63, 0x65, 0x12, 0x1a, 0x0a, 0x08, 0x47, 0x61, 0x73,
|
||||
0x4c, 0x69, 0x6d, 0x69, 0x74, 0x18, 0x03, 0x20, 0x01, 0x28, 0x04, 0x52, 0x08, 0x47, 0x61, 0x73,
|
||||
0x4c, 0x69, 0x6d, 0x69, 0x74, 0x12, 0x14, 0x0a, 0x05, 0x56, 0x61, 0x6c, 0x75, 0x65, 0x18, 0x04,
|
||||
0x20, 0x01, 0x28, 0x0c, 0x52, 0x05, 0x56, 0x61, 0x6c, 0x75, 0x65, 0x12, 0x18, 0x0a, 0x07, 0x50,
|
||||
0x61, 0x79, 0x6c, 0x6f, 0x61, 0x64, 0x18, 0x05, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x07, 0x50, 0x61,
|
||||
0x79, 0x6c, 0x6f, 0x61, 0x64, 0x12, 0x12, 0x0a, 0x04, 0x48, 0x61, 0x73, 0x68, 0x18, 0x06, 0x20,
|
||||
0x01, 0x28, 0x0c, 0x52, 0x04, 0x48, 0x61, 0x73, 0x68, 0x12, 0x0e, 0x0a, 0x02, 0x54, 0x6f, 0x18,
|
||||
0x07, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x02, 0x54, 0x6f, 0x12, 0x12, 0x0a, 0x04, 0x46, 0x72, 0x6f,
|
||||
0x6d, 0x18, 0x08, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x04, 0x46, 0x72, 0x6f, 0x6d, 0x12, 0x2a, 0x0a,
|
||||
0x10, 0x54, 0x72, 0x61, 0x6e, 0x73, 0x61, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x49, 0x6e, 0x64, 0x65,
|
||||
0x78, 0x18, 0x09, 0x20, 0x01, 0x28, 0x0d, 0x52, 0x10, 0x54, 0x72, 0x61, 0x6e, 0x73, 0x61, 0x63,
|
||||
0x74, 0x69, 0x6f, 0x6e, 0x49, 0x6e, 0x64, 0x65, 0x78, 0x1a, 0x92, 0x03, 0x0a, 0x0b, 0x52, 0x65,
|
||||
0x63, 0x65, 0x69, 0x70, 0x74, 0x54, 0x79, 0x70, 0x65, 0x12, 0x18, 0x0a, 0x07, 0x47, 0x61, 0x73,
|
||||
0x55, 0x73, 0x65, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x07, 0x47, 0x61, 0x73, 0x55,
|
||||
0x73, 0x65, 0x64, 0x12, 0x16, 0x0a, 0x06, 0x53, 0x74, 0x61, 0x74, 0x75, 0x73, 0x18, 0x02, 0x20,
|
||||
0x01, 0x28, 0x0c, 0x52, 0x06, 0x53, 0x74, 0x61, 0x74, 0x75, 0x73, 0x12, 0x3f, 0x0a, 0x03, 0x4c,
|
||||
0x6f, 0x67, 0x18, 0x03, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x2d, 0x2e, 0x50, 0x72, 0x6f, 0x74, 0x6f,
|
||||
0x43, 0x6f, 0x6d, 0x70, 0x6c, 0x65, 0x74, 0x65, 0x54, 0x72, 0x61, 0x6e, 0x73, 0x61, 0x63, 0x74,
|
||||
0x69, 0x6f, 0x6e, 0x2e, 0x52, 0x65, 0x63, 0x65, 0x69, 0x70, 0x74, 0x54, 0x79, 0x70, 0x65, 0x2e,
|
||||
0x4c, 0x6f, 0x67, 0x54, 0x79, 0x70, 0x65, 0x52, 0x03, 0x4c, 0x6f, 0x67, 0x12, 0x19, 0x0a, 0x05,
|
||||
0x4c, 0x31, 0x46, 0x65, 0x65, 0x18, 0x04, 0x20, 0x01, 0x28, 0x0c, 0x48, 0x00, 0x52, 0x05, 0x4c,
|
||||
0x31, 0x46, 0x65, 0x65, 0x88, 0x01, 0x01, 0x12, 0x25, 0x0a, 0x0b, 0x4c, 0x31, 0x46, 0x65, 0x65,
|
||||
0x53, 0x63, 0x61, 0x6c, 0x61, 0x72, 0x18, 0x05, 0x20, 0x01, 0x28, 0x0c, 0x48, 0x01, 0x52, 0x0b,
|
||||
0x4c, 0x31, 0x46, 0x65, 0x65, 0x53, 0x63, 0x61, 0x6c, 0x61, 0x72, 0x88, 0x01, 0x01, 0x12, 0x23,
|
||||
0x0a, 0x0a, 0x4c, 0x31, 0x47, 0x61, 0x73, 0x50, 0x72, 0x69, 0x63, 0x65, 0x18, 0x06, 0x20, 0x01,
|
||||
0x28, 0x0c, 0x48, 0x02, 0x52, 0x0a, 0x4c, 0x31, 0x47, 0x61, 0x73, 0x50, 0x72, 0x69, 0x63, 0x65,
|
||||
0x88, 0x01, 0x01, 0x12, 0x21, 0x0a, 0x09, 0x4c, 0x31, 0x47, 0x61, 0x73, 0x55, 0x73, 0x65, 0x64,
|
||||
0x18, 0x07, 0x20, 0x01, 0x28, 0x0c, 0x48, 0x03, 0x52, 0x09, 0x4c, 0x31, 0x47, 0x61, 0x73, 0x55,
|
||||
0x73, 0x65, 0x64, 0x88, 0x01, 0x01, 0x1a, 0x4f, 0x0a, 0x07, 0x4c, 0x6f, 0x67, 0x54, 0x79, 0x70,
|
||||
0x65, 0x12, 0x18, 0x0a, 0x07, 0x41, 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, 0x18, 0x01, 0x20, 0x01,
|
||||
0x28, 0x0c, 0x52, 0x07, 0x41, 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, 0x12, 0x12, 0x0a, 0x04, 0x44,
|
||||
0x61, 0x74, 0x61, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x04, 0x44, 0x61, 0x74, 0x61, 0x12,
|
||||
0x16, 0x0a, 0x06, 0x54, 0x6f, 0x70, 0x69, 0x63, 0x73, 0x18, 0x03, 0x20, 0x03, 0x28, 0x0c, 0x52,
|
||||
0x06, 0x54, 0x6f, 0x70, 0x69, 0x63, 0x73, 0x42, 0x08, 0x0a, 0x06, 0x5f, 0x4c, 0x31, 0x46, 0x65,
|
||||
0x65, 0x42, 0x0e, 0x0a, 0x0c, 0x5f, 0x4c, 0x31, 0x46, 0x65, 0x65, 0x53, 0x63, 0x61, 0x6c, 0x61,
|
||||
0x72, 0x42, 0x0d, 0x0a, 0x0b, 0x5f, 0x4c, 0x31, 0x47, 0x61, 0x73, 0x50, 0x72, 0x69, 0x63, 0x65,
|
||||
0x42, 0x0c, 0x0a, 0x0a, 0x5f, 0x4c, 0x31, 0x47, 0x61, 0x73, 0x55, 0x73, 0x65, 0x64, 0x42, 0x12,
|
||||
0x5a, 0x10, 0x62, 0x63, 0x68, 0x61, 0x69, 0x6e, 0x2f, 0x63, 0x6f, 0x69, 0x6e, 0x73, 0x2f, 0x65,
|
||||
0x74, 0x68, 0x62, 0x06, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x33,
|
||||
}
|
||||
|
||||
func init() { proto.RegisterFile("bchain/coins/eth/ethtx.proto", fileDescriptor0) }
|
||||
var (
|
||||
file_bchain_coins_eth_ethtx_proto_rawDescOnce sync.Once
|
||||
file_bchain_coins_eth_ethtx_proto_rawDescData = file_bchain_coins_eth_ethtx_proto_rawDesc
|
||||
)
|
||||
|
||||
var fileDescriptor0 = []byte{
|
||||
// 409 bytes of a gzipped FileDescriptorProto
|
||||
0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0x8c, 0x92, 0xdf, 0x8a, 0xd4, 0x30,
|
||||
0x18, 0xc5, 0xe9, 0x9f, 0x99, 0xd9, 0xfd, 0xa6, 0x8a, 0x04, 0x91, 0x30, 0xec, 0x45, 0x59, 0xbc,
|
||||
0x18, 0xbd, 0xe8, 0xe2, 0xea, 0x0b, 0xac, 0x23, 0xae, 0xc2, 0xb0, 0x0e, 0x31, 0x7a, 0x9f, 0x49,
|
||||
0xc3, 0x36, 0x38, 0x6d, 0x4a, 0x93, 0x42, 0xf7, 0x8d, 0x7c, 0x21, 0xdf, 0xc5, 0x4b, 0xc9, 0xd7,
|
||||
0x74, 0x1d, 0x11, 0x65, 0x2f, 0x0a, 0xf9, 0x9d, 0x7e, 0xa7, 0x39, 0x27, 0x29, 0x9c, 0xed, 0x65,
|
||||
0x25, 0x74, 0x73, 0x21, 0x8d, 0x6e, 0xec, 0x85, 0x72, 0x95, 0x7f, 0xdc, 0x50, 0xb4, 0x9d, 0x71,
|
||||
0x86, 0x24, 0xca, 0x55, 0xe7, 0xdf, 0x67, 0x40, 0x77, 0x1e, 0x37, 0xa6, 0x6e, 0x0f, 0xca, 0x29,
|
||||
0xde, 0x89, 0xc6, 0x0a, 0xe9, 0xb4, 0x69, 0x48, 0x0e, 0xcb, 0xb7, 0x07, 0x23, 0xbf, 0xdd, 0xf4,
|
||||
0xf5, 0x5e, 0x75, 0x34, 0xca, 0xa3, 0xf5, 0x23, 0x76, 0x2c, 0x91, 0x33, 0x38, 0x45, 0xe4, 0xba,
|
||||
0x56, 0x34, 0xce, 0xa3, 0x75, 0xca, 0x7e, 0x0b, 0xe4, 0x0d, 0xc4, 0x7c, 0xa0, 0x49, 0x1e, 0xad,
|
||||
0x97, 0x97, 0xcf, 0x0b, 0xe5, 0xaa, 0xe2, 0x5f, 0x5b, 0x15, 0x7c, 0xe0, 0x77, 0xad, 0x62, 0x31,
|
||||
0x1f, 0xc8, 0x06, 0x16, 0x4c, 0x49, 0xa5, 0x5b, 0x47, 0x53, 0xb4, 0xbe, 0xf8, 0xbf, 0x35, 0x0c,
|
||||
0xa3, 0x7f, 0x72, 0xae, 0x7e, 0x46, 0x30, 0x1f, 0xbf, 0x49, 0xce, 0x21, 0xbb, 0x92, 0xd2, 0xf4,
|
||||
0x8d, 0xbb, 0x31, 0x8d, 0x54, 0x58, 0x23, 0x65, 0x7f, 0x68, 0x64, 0x05, 0x27, 0xd7, 0xc2, 0xee,
|
||||
0x3a, 0x2d, 0xc7, 0x1a, 0x19, 0xbb, 0xe7, 0xf0, 0x6e, 0xab, 0x6b, 0xed, 0xb0, 0x4b, 0xca, 0xee,
|
||||
0x99, 0x3c, 0x85, 0xd9, 0x57, 0x71, 0xe8, 0x15, 0x26, 0xcd, 0xd8, 0x08, 0x84, 0xc2, 0x62, 0x27,
|
||||
0xee, 0x0e, 0x46, 0x94, 0x74, 0x86, 0xfa, 0x84, 0x84, 0x40, 0xfa, 0x41, 0xd8, 0x8a, 0xce, 0x51,
|
||||
0xc6, 0x35, 0x79, 0x0c, 0x31, 0x37, 0x74, 0x81, 0x4a, 0xcc, 0x8d, 0x9f, 0x79, 0xdf, 0x99, 0x9a,
|
||||
0x9e, 0x8c, 0x33, 0x7e, 0x4d, 0x5e, 0xc2, 0x93, 0xa3, 0xca, 0x1f, 0x9b, 0x52, 0x0d, 0xf4, 0x14,
|
||||
0xaf, 0xe3, 0x2f, 0x7d, 0xf5, 0x23, 0x82, 0xe5, 0xd1, 0x99, 0xf8, 0x34, 0xd7, 0xc2, 0x7e, 0xb1,
|
||||
0xaa, 0xc4, 0xea, 0x19, 0x9b, 0x90, 0x3c, 0x83, 0xf9, 0x67, 0x27, 0x5c, 0x6f, 0x43, 0xe7, 0x40,
|
||||
0x64, 0x03, 0xc9, 0xd6, 0xdc, 0xd2, 0x24, 0x4f, 0xd6, 0xcb, 0xcb, 0x57, 0x0f, 0x3e, 0xfd, 0x62,
|
||||
0x6b, 0x6e, 0xf1, 0x16, 0xbc, 0x7b, 0xf5, 0x09, 0x16, 0x81, 0x7d, 0x82, 0xab, 0xb2, 0xec, 0x94,
|
||||
0xb5, 0x53, 0x82, 0x80, 0xbe, 0xeb, 0x3b, 0xe1, 0x44, 0xd8, 0x1f, 0xd7, 0x3e, 0x15, 0x37, 0xad,
|
||||
0x96, 0x16, 0x03, 0x64, 0x2c, 0xd0, 0x7e, 0x8e, 0xbf, 0xed, 0xeb, 0x5f, 0x01, 0x00, 0x00, 0xff,
|
||||
0xff, 0xc2, 0x69, 0x8d, 0xdf, 0xd6, 0x02, 0x00, 0x00,
|
||||
func file_bchain_coins_eth_ethtx_proto_rawDescGZIP() []byte {
|
||||
file_bchain_coins_eth_ethtx_proto_rawDescOnce.Do(func() {
|
||||
file_bchain_coins_eth_ethtx_proto_rawDescData = protoimpl.X.CompressGZIP(file_bchain_coins_eth_ethtx_proto_rawDescData)
|
||||
})
|
||||
return file_bchain_coins_eth_ethtx_proto_rawDescData
|
||||
}
|
||||
|
||||
var file_bchain_coins_eth_ethtx_proto_msgTypes = make([]protoimpl.MessageInfo, 4)
|
||||
var file_bchain_coins_eth_ethtx_proto_goTypes = []interface{}{
|
||||
(*ProtoCompleteTransaction)(nil), // 0: ProtoCompleteTransaction
|
||||
(*ProtoCompleteTransaction_TxType)(nil), // 1: ProtoCompleteTransaction.TxType
|
||||
(*ProtoCompleteTransaction_ReceiptType)(nil), // 2: ProtoCompleteTransaction.ReceiptType
|
||||
(*ProtoCompleteTransaction_ReceiptType_LogType)(nil), // 3: ProtoCompleteTransaction.ReceiptType.LogType
|
||||
}
|
||||
var file_bchain_coins_eth_ethtx_proto_depIdxs = []int32{
|
||||
1, // 0: ProtoCompleteTransaction.Tx:type_name -> ProtoCompleteTransaction.TxType
|
||||
2, // 1: ProtoCompleteTransaction.Receipt:type_name -> ProtoCompleteTransaction.ReceiptType
|
||||
3, // 2: ProtoCompleteTransaction.ReceiptType.Log:type_name -> ProtoCompleteTransaction.ReceiptType.LogType
|
||||
3, // [3:3] is the sub-list for method output_type
|
||||
3, // [3:3] is the sub-list for method input_type
|
||||
3, // [3:3] is the sub-list for extension type_name
|
||||
3, // [3:3] is the sub-list for extension extendee
|
||||
0, // [0:3] is the sub-list for field type_name
|
||||
}
|
||||
|
||||
func init() { file_bchain_coins_eth_ethtx_proto_init() }
|
||||
func file_bchain_coins_eth_ethtx_proto_init() {
|
||||
if File_bchain_coins_eth_ethtx_proto != nil {
|
||||
return
|
||||
}
|
||||
if !protoimpl.UnsafeEnabled {
|
||||
file_bchain_coins_eth_ethtx_proto_msgTypes[0].Exporter = func(v interface{}, i int) interface{} {
|
||||
switch v := v.(*ProtoCompleteTransaction); i {
|
||||
case 0:
|
||||
return &v.state
|
||||
case 1:
|
||||
return &v.sizeCache
|
||||
case 2:
|
||||
return &v.unknownFields
|
||||
default:
|
||||
return nil
|
||||
}
|
||||
}
|
||||
file_bchain_coins_eth_ethtx_proto_msgTypes[1].Exporter = func(v interface{}, i int) interface{} {
|
||||
switch v := v.(*ProtoCompleteTransaction_TxType); i {
|
||||
case 0:
|
||||
return &v.state
|
||||
case 1:
|
||||
return &v.sizeCache
|
||||
case 2:
|
||||
return &v.unknownFields
|
||||
default:
|
||||
return nil
|
||||
}
|
||||
}
|
||||
file_bchain_coins_eth_ethtx_proto_msgTypes[2].Exporter = func(v interface{}, i int) interface{} {
|
||||
switch v := v.(*ProtoCompleteTransaction_ReceiptType); i {
|
||||
case 0:
|
||||
return &v.state
|
||||
case 1:
|
||||
return &v.sizeCache
|
||||
case 2:
|
||||
return &v.unknownFields
|
||||
default:
|
||||
return nil
|
||||
}
|
||||
}
|
||||
file_bchain_coins_eth_ethtx_proto_msgTypes[3].Exporter = func(v interface{}, i int) interface{} {
|
||||
switch v := v.(*ProtoCompleteTransaction_ReceiptType_LogType); i {
|
||||
case 0:
|
||||
return &v.state
|
||||
case 1:
|
||||
return &v.sizeCache
|
||||
case 2:
|
||||
return &v.unknownFields
|
||||
default:
|
||||
return nil
|
||||
}
|
||||
}
|
||||
}
|
||||
file_bchain_coins_eth_ethtx_proto_msgTypes[2].OneofWrappers = []interface{}{}
|
||||
type x struct{}
|
||||
out := protoimpl.TypeBuilder{
|
||||
File: protoimpl.DescBuilder{
|
||||
GoPackagePath: reflect.TypeOf(x{}).PkgPath(),
|
||||
RawDescriptor: file_bchain_coins_eth_ethtx_proto_rawDesc,
|
||||
NumEnums: 0,
|
||||
NumMessages: 4,
|
||||
NumExtensions: 0,
|
||||
NumServices: 0,
|
||||
},
|
||||
GoTypes: file_bchain_coins_eth_ethtx_proto_goTypes,
|
||||
DependencyIndexes: file_bchain_coins_eth_ethtx_proto_depIdxs,
|
||||
MessageInfos: file_bchain_coins_eth_ethtx_proto_msgTypes,
|
||||
}.Build()
|
||||
File_bchain_coins_eth_ethtx_proto = out.File
|
||||
file_bchain_coins_eth_ethtx_proto_rawDesc = nil
|
||||
file_bchain_coins_eth_ethtx_proto_goTypes = nil
|
||||
file_bchain_coins_eth_ethtx_proto_depIdxs = nil
|
||||
}
|
||||
|
||||
@ -1,30 +1,34 @@
|
||||
syntax = "proto3";
|
||||
package eth;
|
||||
|
||||
message ProtoCompleteTransaction {
|
||||
message TxType {
|
||||
uint64 AccountNonce = 1;
|
||||
bytes GasPrice = 2;
|
||||
uint64 GasLimit = 3;
|
||||
bytes Value = 4;
|
||||
bytes Payload = 5;
|
||||
bytes Hash = 6;
|
||||
bytes To = 7;
|
||||
bytes From = 8;
|
||||
uint32 TransactionIndex = 9;
|
||||
}
|
||||
message ReceiptType {
|
||||
message LogType {
|
||||
bytes Address = 1;
|
||||
bytes Data = 2;
|
||||
repeated bytes Topics = 3;
|
||||
}
|
||||
bytes GasUsed = 1;
|
||||
bytes Status = 2;
|
||||
repeated LogType Log = 3;
|
||||
}
|
||||
uint32 BlockNumber = 1;
|
||||
uint64 BlockTime = 2;
|
||||
TxType Tx = 3;
|
||||
ReceiptType Receipt = 4;
|
||||
}
|
||||
option go_package = "bchain/coins/eth";
|
||||
|
||||
message ProtoCompleteTransaction {
|
||||
message TxType {
|
||||
uint64 AccountNonce = 1;
|
||||
bytes GasPrice = 2;
|
||||
uint64 GasLimit = 3;
|
||||
bytes Value = 4;
|
||||
bytes Payload = 5;
|
||||
bytes Hash = 6;
|
||||
bytes To = 7;
|
||||
bytes From = 8;
|
||||
uint32 TransactionIndex = 9;
|
||||
}
|
||||
message ReceiptType {
|
||||
message LogType {
|
||||
bytes Address = 1;
|
||||
bytes Data = 2;
|
||||
repeated bytes Topics = 3;
|
||||
}
|
||||
bytes GasUsed = 1;
|
||||
bytes Status = 2;
|
||||
repeated LogType Log = 3;
|
||||
optional bytes L1Fee = 4;
|
||||
optional bytes L1FeeScalar = 5;
|
||||
optional bytes L1GasPrice = 6;
|
||||
optional bytes L1GasUsed = 7;
|
||||
}
|
||||
uint32 BlockNumber = 1;
|
||||
uint64 BlockTime = 2;
|
||||
TxType Tx = 3;
|
||||
ReceiptType Receipt = 4;
|
||||
}
|
||||
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 (
|
||||
OpZeroCoinMint = 0xc1
|
||||
OpZeroCoinSpend = 0xc2
|
||||
OpSigmaMint = 0xc3
|
||||
OpSigmaSpend = 0xc4
|
||||
OpLelantusMint = 0xc5
|
||||
OpLelantusJMint = 0xc6
|
||||
OpLelantusJoinSplit = 0xc7
|
||||
OpZeroCoinMint = 0xc1
|
||||
OpZeroCoinSpend = 0xc2
|
||||
OpSigmaMint = 0xc3
|
||||
OpSigmaSpend = 0xc4
|
||||
OpLelantusMint = 0xc5
|
||||
OpLelantusJMint = 0xc6
|
||||
OpLelantusJoinSplit = 0xc7
|
||||
OpLelantusJoinSplitPayload = 0xc9
|
||||
|
||||
MainnetMagic wire.BitcoinNet = 0xe3d9fef1
|
||||
@ -194,7 +194,6 @@ func (p *FiroParser) ParseBlock(b []byte) (*bchain.Block, error) {
|
||||
break
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
if !isAllZero {
|
||||
// hash data
|
||||
@ -344,7 +343,7 @@ type MTPHashDataRoot struct {
|
||||
}
|
||||
|
||||
type MTPHashData struct {
|
||||
BlockMTP [128][128]uint64
|
||||
BlockMTP [128][128]uint64
|
||||
}
|
||||
|
||||
type MTPBlockHeader struct {
|
||||
|
||||
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 (
|
||||
"bytes"
|
||||
"encoding/binary"
|
||||
"encoding/hex"
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"io"
|
||||
"math/big"
|
||||
|
||||
@ -13,7 +15,6 @@ import (
|
||||
"github.com/martinboehm/btcutil/chaincfg"
|
||||
"github.com/trezor/blockbook/bchain"
|
||||
"github.com/trezor/blockbook/bchain/coins/btc"
|
||||
"github.com/trezor/blockbook/bchain/coins/utils"
|
||||
)
|
||||
|
||||
// magic numbers
|
||||
@ -100,7 +101,12 @@ func (p *PivXParser) ParseBlock(b []byte) (*bchain.Block, error) {
|
||||
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 {
|
||||
return nil, errors.Annotatef(err, "DecodeTransactions")
|
||||
}
|
||||
@ -255,6 +261,90 @@ func (p *PivXParser) GetAddrDescForUnknownInput(tx *bchain.Tx, input int) bchain
|
||||
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
|
||||
func isZeroCoinMintScript(signatureScript []byte) bool {
|
||||
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)
|
||||
return
|
||||
}
|
||||
// ignore witness unpacking
|
||||
for i := range got.Vin {
|
||||
got.Vin[i].Witness = nil
|
||||
}
|
||||
if !reflect.DeepEqual(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 (
|
||||
"encoding/hex"
|
||||
"errors"
|
||||
"fmt"
|
||||
"math/big"
|
||||
"time"
|
||||
|
||||
"github.com/golang/glog"
|
||||
"github.com/martinboehm/btcutil/gcs"
|
||||
"github.com/juju/errors"
|
||||
)
|
||||
|
||||
type chanInputPayload struct {
|
||||
@ -16,14 +14,6 @@ type chanInputPayload struct {
|
||||
index int
|
||||
}
|
||||
|
||||
type filterScriptsType int
|
||||
|
||||
const (
|
||||
filterScriptsInvalid = filterScriptsType(iota)
|
||||
filterScriptsAll
|
||||
filterScriptsTaproot
|
||||
)
|
||||
|
||||
// MempoolBitcoinType is mempool handle.
|
||||
type MempoolBitcoinType struct {
|
||||
BaseMempool
|
||||
@ -31,19 +21,13 @@ type MempoolBitcoinType struct {
|
||||
chanAddrIndex chan txidio
|
||||
AddrDescForOutpoint AddrDescForOutpointFunc
|
||||
golombFilterP uint8
|
||||
golombFilterM uint64
|
||||
filterScripts filterScriptsType
|
||||
filterScripts string
|
||||
useZeroedKey bool
|
||||
}
|
||||
|
||||
// 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
|
||||
func NewMempoolBitcoinType(chain BlockChain, workers int, subworkers int, golombFilterP uint8, filterScripts string) *MempoolBitcoinType {
|
||||
filterScriptsType := filterScriptsToScriptsType(filterScripts)
|
||||
if filterScriptsType == filterScriptsInvalid {
|
||||
glog.Error("Invalid filterScripts ", filterScripts, ", switching off golomb filter")
|
||||
golombFilterP = 0
|
||||
}
|
||||
golombFilterM := uint64(1 << golombFilterP)
|
||||
func NewMempoolBitcoinType(chain BlockChain, workers int, subworkers int, golombFilterP uint8, filterScripts string, useZeroedKey bool) *MempoolBitcoinType {
|
||||
m := &MempoolBitcoinType{
|
||||
BaseMempool: BaseMempool{
|
||||
chain: chain,
|
||||
@ -53,8 +37,8 @@ func NewMempoolBitcoinType(chain BlockChain, workers int, subworkers int, golomb
|
||||
chanTxid: make(chan string, 1),
|
||||
chanAddrIndex: make(chan txidio, 1),
|
||||
golombFilterP: golombFilterP,
|
||||
golombFilterM: golombFilterM,
|
||||
filterScripts: filterScriptsType,
|
||||
filterScripts: filterScripts,
|
||||
useZeroedKey: useZeroedKey,
|
||||
}
|
||||
for i := 0; i < workers; i++ {
|
||||
go func(i int) {
|
||||
@ -81,16 +65,6 @@ func NewMempoolBitcoinType(chain BlockChain, workers int, subworkers int, golomb
|
||||
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 {
|
||||
var addrDesc AddressDescriptor
|
||||
var value *big.Int
|
||||
@ -125,56 +99,21 @@ func (m *MempoolBitcoinType) getInputAddress(payload *chanInputPayload) *addrInd
|
||||
|
||||
}
|
||||
|
||||
func isTaproot(addrDesc AddressDescriptor) bool {
|
||||
if len(addrDesc) == 34 && addrDesc[0] == 0x51 && addrDesc[1] == 0x20 {
|
||||
return true
|
||||
func (m *MempoolBitcoinType) computeGolombFilter(mtx *MempoolTx, tx *Tx) string {
|
||||
gf, _ := NewGolombFilter(m.golombFilterP, m.filterScripts, mtx.Txid, m.useZeroedKey)
|
||||
if gf == nil || !gf.Enabled {
|
||||
return ""
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
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 _, vin := range mtx.Vin {
|
||||
gf.AddAddrDesc(vin.AddrDesc, tx)
|
||||
}
|
||||
for i := range mtx.Vout {
|
||||
vout := &mtx.Vout[i]
|
||||
for _, vout := range mtx.Vout {
|
||||
b, err := hex.DecodeString(vout.ScriptPubKey.Hex)
|
||||
if err == nil {
|
||||
if m.filterScripts == filterScriptsAll || (m.filterScripts == filterScriptsTaproot && isTaproot(b)) {
|
||||
s := string(b)
|
||||
if _, found := uniqueScripts[s]; !found {
|
||||
filterData = append(filterData, b)
|
||||
uniqueScripts[s] = struct{}{}
|
||||
}
|
||||
}
|
||||
gf.AddAddrDesc(b, tx)
|
||||
}
|
||||
}
|
||||
if len(filterData) == 0 {
|
||||
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 ""
|
||||
}
|
||||
fb := gf.Compute()
|
||||
return hex.EncodeToString(fb)
|
||||
}
|
||||
|
||||
@ -231,7 +170,7 @@ func (m *MempoolBitcoinType) getTxAddrs(txid string, chanInput chan chanInputPay
|
||||
}
|
||||
var golombFilter string
|
||||
if m.golombFilterP > 0 {
|
||||
golombFilter = m.computeGolombFilter(mtx)
|
||||
golombFilter = m.computeGolombFilter(mtx, tx)
|
||||
}
|
||||
if m.OnNewTx != nil {
|
||||
m.OnNewTx(mtx)
|
||||
@ -301,8 +240,8 @@ func (m *MempoolBitcoinType) Resync() (int, error) {
|
||||
|
||||
// GetTxidFilterEntries returns all mempool entries with golomb filter from
|
||||
func (m *MempoolBitcoinType) GetTxidFilterEntries(filterScripts string, fromTimestamp uint32) (MempoolTxidFilterEntries, error) {
|
||||
if m.filterScripts != filterScriptsToScriptsType(filterScripts) {
|
||||
return MempoolTxidFilterEntries{}, errors.New(fmt.Sprint("Unsupported script filter ", filterScripts))
|
||||
if m.filterScripts != filterScripts {
|
||||
return MempoolTxidFilterEntries{}, errors.Errorf("Unsupported script filter %s", filterScripts)
|
||||
}
|
||||
m.mux.Lock()
|
||||
entries := make(map[string]string)
|
||||
@ -312,5 +251,5 @@ func (m *MempoolBitcoinType) GetTxidFilterEntries(filterScripts string, fromTime
|
||||
}
|
||||
}
|
||||
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")
|
||||
m := &MempoolBitcoinType{
|
||||
golombFilterP: 20,
|
||||
golombFilterM: uint64(1 << 20),
|
||||
filterScripts: filterScriptsTaproot,
|
||||
filterScripts: "taproot",
|
||||
}
|
||||
golombFilterM := GetGolombParamM(m.golombFilterP)
|
||||
tests := []struct {
|
||||
name string
|
||||
mtx MempoolTx
|
||||
@ -194,13 +194,13 @@ func TestMempoolBitcoinType_computeGolombFilter_taproot(t *testing.T) {
|
||||
}
|
||||
for _, tt := range tests {
|
||||
t.Run(tt.name, func(t *testing.T) {
|
||||
got := m.computeGolombFilter(&tt.mtx)
|
||||
got := m.computeGolombFilter(&tt.mtx, nil)
|
||||
if got != tt.want {
|
||||
t.Errorf("MempoolBitcoinType.computeGolombFilter() = %v, want %v", got, tt.want)
|
||||
}
|
||||
if got != "" {
|
||||
// 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 {
|
||||
t.Errorf("gcs.BuildGCSFilter() unexpected error %v", err)
|
||||
}
|
||||
@ -211,8 +211,8 @@ func TestMempoolBitcoinType_computeGolombFilter_taproot(t *testing.T) {
|
||||
if err != nil {
|
||||
t.Errorf("filter.Match vin[%d] unexpected error %v", i, err)
|
||||
}
|
||||
if match != isTaproot(tt.mtx.Vin[i].AddrDesc) {
|
||||
t.Errorf("filter.Match vin[%d] got %v, want %v", i, 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, tt.mtx.Vin[i].AddrDesc.IsTaproot())
|
||||
}
|
||||
}
|
||||
// check that the vout scripts match the filter
|
||||
@ -222,8 +222,8 @@ func TestMempoolBitcoinType_computeGolombFilter_taproot(t *testing.T) {
|
||||
if err != nil {
|
||||
t.Errorf("filter.Match vout[%d] unexpected error %v", i, err)
|
||||
}
|
||||
if match != isTaproot(s) {
|
||||
t.Errorf("filter.Match vout[%d] got %v, want %v", i, match, isTaproot(s))
|
||||
if match != AddressDescriptor(s).IsTaproot() {
|
||||
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
|
||||
@ -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
|
||||
}
|
||||
|
||||
// AddTransactionToMempool adds transactions to mempool
|
||||
func (m *MempoolEthereumType) AddTransactionToMempool(txid string) {
|
||||
// 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) bool {
|
||||
m.mux.Lock()
|
||||
_, exists := m.txEntries[txid]
|
||||
m.mux.Unlock()
|
||||
@ -143,7 +143,7 @@ func (m *MempoolEthereumType) AddTransactionToMempool(txid string) {
|
||||
if !exists {
|
||||
entry, ok := m.createTxEntry(txid, uint32(time.Now().Unix()))
|
||||
if !ok {
|
||||
return
|
||||
return false
|
||||
}
|
||||
m.mux.Lock()
|
||||
m.txEntries[txid] = entry
|
||||
@ -152,6 +152,7 @@ func (m *MempoolEthereumType) AddTransactionToMempool(txid string) {
|
||||
}
|
||||
m.mux.Unlock()
|
||||
}
|
||||
return !exists
|
||||
}
|
||||
|
||||
// RemoveTransactionFromMempool removes transaction from mempool
|
||||
|
||||
@ -57,6 +57,7 @@ type Vin struct {
|
||||
ScriptSig ScriptSig `json:"scriptSig"`
|
||||
Sequence uint32 `json:"sequence"`
|
||||
Addresses []string `json:"addresses"`
|
||||
Witness [][]byte `json:"-"`
|
||||
}
|
||||
|
||||
// ScriptPubKey contains data about output script
|
||||
@ -130,7 +131,8 @@ type TokenTypeName string
|
||||
|
||||
// Token types
|
||||
const (
|
||||
UnknownTokenType TokenTypeName = ""
|
||||
UnknownTokenType TokenTypeName = ""
|
||||
UnhandledTokenType TokenTypeName = "-"
|
||||
|
||||
// XPUBAddressTokenType is address derived from xpub
|
||||
XPUBAddressTokenType TokenTypeName = "XPUBAddress"
|
||||
@ -226,6 +228,13 @@ func (ad AddressDescriptor) String() string {
|
||||
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
|
||||
func AddressDescriptorFromString(s string) (AddressDescriptor, error) {
|
||||
if len(s) > 3 && s[0:3] == "ad:" {
|
||||
@ -266,8 +275,10 @@ type XpubDescriptor struct {
|
||||
type MempoolTxidEntries []MempoolTxidEntry
|
||||
|
||||
// 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 {
|
||||
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
|
||||
@ -323,6 +334,10 @@ type BlockChain interface {
|
||||
EthereumTypeGetNonce(addrDesc AddressDescriptor) (uint64, error)
|
||||
EthereumTypeEstimateGas(params map[string]interface{}) (uint64, 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)
|
||||
}
|
||||
|
||||
|
||||
@ -122,9 +122,13 @@ type RpcLog struct {
|
||||
|
||||
// RpcLog is returned by eth_getTransactionReceipt
|
||||
type RpcReceipt struct {
|
||||
GasUsed string `json:"gasUsed"`
|
||||
Status string `json:"status"`
|
||||
Logs []*RpcLog `json:"logs"`
|
||||
GasUsed string `json:"gasUsed"`
|
||||
Status string `json:"status"`
|
||||
Logs []*RpcLog `json:"logs"`
|
||||
L1Fee string `json:"l1Fee,omitempty"`
|
||||
L1FeeScalar string `json:"l1FeeScalar,omitempty"`
|
||||
L1GasPrice string `json:"l1GasPrice,omitempty"`
|
||||
L1GasUsed string `json:"l1GasUsed,omitempty"`
|
||||
}
|
||||
|
||||
// EthereumSpecificData contains data specific to Ethereum transactions
|
||||
@ -146,3 +150,16 @@ type EthereumBlockSpecificData struct {
|
||||
AddressAliasRecords []AddressAliasRecord
|
||||
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;
|
||||
gasLimit: number;
|
||||
gasUsed?: number;
|
||||
gasPrice: string;
|
||||
gasPrice?: string;
|
||||
l1Fee?: number;
|
||||
l1FeeScalar?: string;
|
||||
l1GasPrice?: string;
|
||||
l1GasUsed?: number;
|
||||
data?: string;
|
||||
parsedData?: EthereumParsedInputData;
|
||||
internalTransfers?: EthereumInternalTransfer[];
|
||||
@ -46,9 +50,9 @@ export interface TokenTransfer {
|
||||
from: string;
|
||||
to: string;
|
||||
contract: string;
|
||||
name: string;
|
||||
symbol: string;
|
||||
decimals: number;
|
||||
name?: string;
|
||||
symbol?: string;
|
||||
decimals?: number;
|
||||
value?: string;
|
||||
multiTokenValues?: MultiTokenValue[];
|
||||
}
|
||||
@ -109,6 +113,17 @@ export interface FeeStats {
|
||||
averageFeePerKb: 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 {
|
||||
type: string;
|
||||
contract: string;
|
||||
@ -161,6 +176,7 @@ export interface Address {
|
||||
contractInfo?: ContractInfo;
|
||||
erc20Contract?: ContractInfo;
|
||||
addressAliases?: { [key: string]: AddressAlias };
|
||||
stakingPools?: StakingPool[];
|
||||
}
|
||||
export interface Utxo {
|
||||
txid: string;
|
||||
@ -245,6 +261,7 @@ export interface InternalStateColumn {
|
||||
}
|
||||
export interface BlockbookInfo {
|
||||
coin: string;
|
||||
network: string;
|
||||
host: string;
|
||||
version: string;
|
||||
gitCommit: string;
|
||||
@ -264,6 +281,7 @@ export interface BlockbookInfo {
|
||||
currentFiatRatesTime?: string;
|
||||
historicalFiatRatesTime?: string;
|
||||
historicalTokenFiatRatesTime?: string;
|
||||
supportedStakingPools?: string[];
|
||||
dbSizeFromColumns?: number;
|
||||
dbColumns?: InternalStateColumn[];
|
||||
about: string;
|
||||
@ -338,6 +356,7 @@ export interface WsBackendInfo {
|
||||
export interface WsInfoRes {
|
||||
name: string;
|
||||
shortcut: string;
|
||||
network: string;
|
||||
decimals: number;
|
||||
version: string;
|
||||
bestHeight: number;
|
||||
@ -357,6 +376,17 @@ export interface WsBlockReq {
|
||||
pageSize?: 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 {
|
||||
descriptor: string;
|
||||
}
|
||||
@ -416,7 +446,17 @@ export interface WsFiatRatesTickersListReq {
|
||||
export interface WsMempoolFiltersReq {
|
||||
scriptType: string;
|
||||
fromTimestamp: number;
|
||||
M?: number;
|
||||
}
|
||||
export interface WsRpcCallReq {
|
||||
from?: string;
|
||||
to: string;
|
||||
data: string;
|
||||
}
|
||||
export interface WsRpcCallRes {
|
||||
data: string;
|
||||
}
|
||||
export interface MempoolTxidFilterEntries {
|
||||
entries?: { [key: string]: string };
|
||||
usedZeroedKey?: boolean;
|
||||
}
|
||||
|
||||
53
blockbook.go
53
blockbook.go
@ -2,7 +2,6 @@ package main
|
||||
|
||||
import (
|
||||
"context"
|
||||
"encoding/json"
|
||||
"flag"
|
||||
"log"
|
||||
"math/rand"
|
||||
@ -11,6 +10,7 @@ import (
|
||||
"os"
|
||||
"os/signal"
|
||||
"runtime/debug"
|
||||
"strconv"
|
||||
"strings"
|
||||
"syscall"
|
||||
"time"
|
||||
@ -152,30 +152,19 @@ func mainWithExitCode() int {
|
||||
return exitCodeOK
|
||||
}
|
||||
|
||||
if *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)
|
||||
config, err := common.GetConfig(*configFile)
|
||||
if err != nil {
|
||||
glog.Error("config: ", err)
|
||||
return exitCodeFatal
|
||||
}
|
||||
|
||||
metrics, err = common.GetMetrics(coin)
|
||||
metrics, err = common.GetMetrics(config.CoinName)
|
||||
if err != nil {
|
||||
glog.Error("metrics: ", err)
|
||||
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)
|
||||
return exitCodeFatal
|
||||
}
|
||||
@ -187,7 +176,7 @@ func mainWithExitCode() int {
|
||||
}
|
||||
defer index.Close()
|
||||
|
||||
internalState, err = newInternalState(coin, coinShortcut, coinLabel, index, *enableSubNewTx)
|
||||
internalState, err = newInternalState(config, index, *enableSubNewTx)
|
||||
if err != nil {
|
||||
glog.Error("internalState: ", err)
|
||||
return exitCodeFatal
|
||||
@ -279,7 +268,7 @@ func mainWithExitCode() int {
|
||||
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)
|
||||
return exitCodeFatal
|
||||
}
|
||||
@ -368,7 +357,7 @@ func mainWithExitCode() int {
|
||||
|
||||
if internalServer != nil || publicServer != nil || chain != nil {
|
||||
// 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)
|
||||
}
|
||||
|
||||
@ -501,16 +490,12 @@ func blockbookAppInfoMetric(db *db.RocksDB, chain bchain.BlockChain, txCache *db
|
||||
return nil
|
||||
}
|
||||
|
||||
func newInternalState(coin, coinShortcut, coinLabel string, d *db.RocksDB, enableSubNewTx bool) (*common.InternalState, error) {
|
||||
is, err := d.LoadInternalState(coin)
|
||||
func newInternalState(config *common.Config, d *db.RocksDB, enableSubNewTx bool) (*common.InternalState, error) {
|
||||
is, err := d.LoadInternalState(config)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
is.CoinShortcut = coinShortcut
|
||||
if coinLabel == "" {
|
||||
coinLabel = coin
|
||||
}
|
||||
is.CoinLabel = coinLabel
|
||||
|
||||
is.EnableSubNewTx = enableSubNewTx
|
||||
name, err := os.Hostname()
|
||||
if err != nil {
|
||||
@ -521,6 +506,12 @@ func newInternalState(coin, coinShortcut, coinLabel string, d *db.RocksDB, enabl
|
||||
}
|
||||
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
|
||||
}
|
||||
|
||||
@ -702,21 +693,11 @@ func computeFeeStats(stopCompute chan os.Signal, blockFrom, blockTo int, db *db.
|
||||
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 {
|
||||
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 {
|
||||
fbsd, err := fourbyte.NewFourByteSignaturesDownloader(db, config.FourByteSignatures)
|
||||
if err != nil {
|
||||
|
||||
@ -11,7 +11,7 @@ RUN apt-get update && \
|
||||
libzstd-dev liblz4-dev graphviz && \
|
||||
apt-get clean
|
||||
ARG GOLANG_VERSION
|
||||
ENV GOLANG_VERSION=go1.19.2
|
||||
ENV GOLANG_VERSION=go1.22.8
|
||||
ENV ROCKSDB_VERSION=v7.7.2
|
||||
ENV GOPATH=/go
|
||||
ENV PATH=$PATH:$GOPATH/bin
|
||||
|
||||
@ -38,5 +38,4 @@ prepare-sources:
|
||||
mkdir -p $(BLOCKBOOK_BASE)
|
||||
cp -r /src $(BLOCKBOOK_SRC)
|
||||
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
|
||||
|
||||
@ -6,9 +6,19 @@ ENV DEBIAN_FRONTEND=noninteractive
|
||||
|
||||
RUN apt-get update && \
|
||||
apt-get upgrade -y && \
|
||||
apt-get install -y devscripts debhelper make dh-exec && \
|
||||
apt-get install -y devscripts debhelper make dh-exec zstd && \
|
||||
apt-get clean
|
||||
|
||||
# install docker cli
|
||||
ARG DOCKER_VERSION
|
||||
|
||||
RUN if [ -z "$DOCKER_VERSION" ]; then echo "DOCKER_VERSION is a required build arg" && exit 1; fi
|
||||
|
||||
RUN wget -O docker.tgz "https://download.docker.com/linux/static/stable/x86_64/docker-${DOCKER_VERSION}.tgz" && \
|
||||
tar -xzf docker.tgz --strip 1 -C /usr/local/bin/ && \
|
||||
rm docker.tgz && \
|
||||
docker --version
|
||||
|
||||
ADD gpg-keys /tmp/gpg-keys
|
||||
RUN gpg --batch --import /tmp/gpg-keys/*
|
||||
|
||||
|
||||
@ -1,5 +1,103 @@
|
||||
-----BEGIN PGP PUBLIC KEY BLOCK-----
|
||||
|
||||
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
|
||||
MgQQAQgAHRYhBClZA2Lsh4qB/TwgK1JSe+2r6HmEBQJlqfWlAAoJEFJSe+2r6HmE
|
||||
C1QP9Ryh2XiUhQmvtiiDFPxzK0sa9YNAk84nUAOSrRLIQ1Xs3g33cg15kxMvtKf9
|
||||
OIJD14Mu1ypnfa1jsDr6zdy3CQCKAKEBTH41jw3XLa9R9XWaT6+0YV+meIHZ6uVJ
|
||||
3+5M1xZGsnErsTM+iGGmneRIt2L0cZTt7HRJaL0EJrd7PXQb8B9BxgPnRa4UVpqd
|
||||
FlhMhNHad7rz5hFAz8YkYEGX/bctF2y/gmHnu/xKkQsOlV+fQfROOlo/wQ/2vXRY
|
||||
YBqWrVw0gAFDaI4P43CoKlYFzZOxrX+RLSc6eOSgmRkwMx5NzpOvfbypuiXLCmed
|
||||
8pTF9SeXH3LzdO1gJQsKkia04OBohCosmnIjOCjeN3bxf606HZpBgXhj72kXZOX0
|
||||
NeA+yxEh1QIhvjxvD0WyIUChaXYsGy61F16vIUytE319diU/e/KQKnTC+oepiju6
|
||||
N23Iy8c2gRux48ghkmcN58bLOCUUvO+UYb7U9YYsi6HEiL8yd8KVPHVJ293NcMt0
|
||||
FsmxFd4Fddr2HYK0NLtf5MDo4yYMw2PmbQ/1/cy/Sr6BvlHmZ6R9+I9beO5LjPBQ
|
||||
EN62PWWBfl6b2EpYyA9RTFUKFiRhEoqLpmORlzMcUcmIsIYX5ZWanitBnSnIznGe
|
||||
TapoOXPE93OrpDJU9vIcYx7Y4E8drNAdW1zZcFBo9ilNexq0i1Bhc3RhIFl1Ymlr
|
||||
ZXkgKFRoaXMgaXMgYW4gb2ZmbGluZSBvbmx5IGtleSB1c2VkIGZvciB0aGUgaGln
|
||||
aGVzdCBsZXZlbCBvZiB2YWxpZGF0aW9uLiBNeSBtYWluIGtleSBpcyA1MjUyN0JF
|
||||
REFCRTg3OTg0LiBTZWUga2V5YmFzZS5pby9wYXN0YSmJAWUEEwEIAE8CGwMFCwkI
|
||||
BwIGFQoJCAsCBRYCAwEAAh4EFiEEYKz3C/cSZFBJ7m8V7+rxZoYiX2QFAmWp/HEY
|
||||
GGhrcHM6Ly9rZXlzLm9wZW5wZ3Aub3JnAAoJEO/q8WaGIl9kVUYH/2HrXiEHYIZU
|
||||
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
|
||||
gZfWLfoIul+B10SwJHXuoQ==
|
||||
=/A3N
|
||||
-----END PGP PUBLIC KEY BLOCK-----
|
||||
|
||||
-----BEGIN PGP PUBLIC KEY BLOCK-----
|
||||
|
||||
mQINBF1ULyUBEADFFliU0Hr+PRCQNT9/9ZEhZtLmMMu7tai3VCxhmrHrOpNJJHqX
|
||||
f1/CeUyBhmCvXpKIpAAbH66l/Uc9GH5UgMZ19gMyGa3q3QJn9A6RR9ud4ALRg60P
|
||||
fmYTAci+6Luko7bqTzkS+fYOUSy/LY57s5ANTpveE+iTsBd5grXczCxaYYnthKKA
|
||||
@ -11,55 +109,317 @@ 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
|
||||
96I=
|
||||
=85Kq
|
||||
-----END PGP PUBLIC KEY BLOCK-----
|
||||
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
|
||||
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}})
|
||||
|
||||
all:
|
||||
mkdir backend
|
||||
{{- if ne .Backend.DockerImage "" }}
|
||||
docker container inspect extract > /dev/null 2>&1 && docker rm extract || true
|
||||
docker create --name extract {{.Backend.DockerImage}}
|
||||
{{- if eq .Backend.VerificationType "docker"}}
|
||||
[ "$$(docker inspect --format='{{`{{index .RepoDigests 0}}`}}' {{.Backend.DockerImage}} | sed 's/.*@sha256://')" = "{{.Backend.VerificationSource}}" ]
|
||||
{{- end}}
|
||||
{{.Backend.ExtractCommand}}
|
||||
docker rm extract
|
||||
{{- else }}
|
||||
wget {{.Backend.BinaryURL}}
|
||||
{{- if eq .Backend.VerificationType "gpg"}}
|
||||
wget {{.Backend.VerificationSource}} -O checksum
|
||||
@ -13,8 +23,8 @@ all:
|
||||
{{- else if eq .Backend.VerificationType "sha256"}}
|
||||
[ "$$(sha256sum ${ARCHIVE} | cut -d ' ' -f 1)" = "{{.Backend.VerificationSource}}" ]
|
||||
{{- end}}
|
||||
mkdir backend
|
||||
{{.Backend.ExtractCommand}} ${ARCHIVE}
|
||||
{{- end}}
|
||||
{{- if .Backend.ExcludeFiles}}
|
||||
# generated from exclude_files
|
||||
{{- range $index, $name := .Backend.ExcludeFiles}}
|
||||
|
||||
@ -12,8 +12,12 @@ 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}}
|
||||
|
||||
@ -12,6 +12,8 @@ rpcworkqueue=1100
|
||||
maxmempool=2000
|
||||
dbcache=1000
|
||||
|
||||
deprecatedrpc=warnings
|
||||
|
||||
{{- if .Backend.AdditionalParams}}
|
||||
# generated from additional_params
|
||||
{{- range $name, $value := .Backend.AdditionalParams}}
|
||||
|
||||
@ -13,6 +13,8 @@ rpcworkqueue=1100
|
||||
maxmempool=2000
|
||||
dbcache=1000
|
||||
|
||||
deprecatedrpc=warnings
|
||||
|
||||
{{- if .Backend.AdditionalParams}}
|
||||
# generated from additional_params
|
||||
{{- 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" .}}
|
||||
|
||||
# Resource limits
|
||||
LimitNOFILE=500000
|
||||
LimitNOFILE=2000000
|
||||
|
||||
# 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}}
|
||||
"coin_name": "{{.Coin.Name}}",
|
||||
"coin_shortcut": "{{.Coin.Shortcut}}",
|
||||
{{- if .Coin.Network}}
|
||||
"network": "{{.Coin.Network}}",{{end}}
|
||||
"coin_label": "{{.Coin.Label}}",
|
||||
"rpc_url": "{{template "IPC.RPCURLTemplate" .}}",
|
||||
"rpc_user": "{{.IPC.RPCUser}}",
|
||||
|
||||
@ -21,6 +21,7 @@ type Backend struct {
|
||||
SystemUser string `json:"system_user"`
|
||||
Version string `json:"version"`
|
||||
BinaryURL string `json:"binary_url"`
|
||||
DockerImage string `json:"docker_image"`
|
||||
VerificationType string `json:"verification_type"`
|
||||
VerificationSource string `json:"verification_source"`
|
||||
ExtractCommand string `json:"extract_command"`
|
||||
@ -44,6 +45,7 @@ type Config struct {
|
||||
Coin struct {
|
||||
Name string `json:"name"`
|
||||
Shortcut string `json:"shortcut"`
|
||||
Network string `json:"network,omitempty"`
|
||||
Label string `json:"label"`
|
||||
Alias string `json:"alias"`
|
||||
} `json:"coin"`
|
||||
@ -203,6 +205,7 @@ func LoadConfig(configsDir, coin string) (*Config, error) {
|
||||
case "gpg":
|
||||
case "sha256":
|
||||
case "gpg-sha256":
|
||||
case "docker":
|
||||
default:
|
||||
return nil, fmt.Errorf("Invalid verification type: %s", config.Backend.VerificationType)
|
||||
}
|
||||
|
||||
@ -1,4 +1,4 @@
|
||||
//usr/bin/go run $0 $@ ; exit
|
||||
// usr/bin/go run $0 $@ ; exit
|
||||
package main
|
||||
|
||||
import (
|
||||
|
||||
@ -45,6 +45,8 @@ func main() {
|
||||
t.Add(server.WsBlockHashReq{})
|
||||
t.Add(server.WsBlockHashRes{})
|
||||
t.Add(server.WsBlockReq{})
|
||||
t.Add(server.WsBlockFilterReq{})
|
||||
t.Add(server.WsBlockFiltersBatchReq{})
|
||||
t.Add(server.WsAccountUtxoReq{})
|
||||
t.Add(server.WsBalanceHistoryReq{})
|
||||
t.Add(server.WsTransactionReq{})
|
||||
@ -58,6 +60,8 @@ func main() {
|
||||
t.Add(server.WsFiatRatesForTimestampsReq{})
|
||||
t.Add(server.WsFiatRatesTickersListReq{})
|
||||
t.Add(server.WsMempoolFiltersReq{})
|
||||
t.Add(server.WsRpcCallReq{})
|
||||
t.Add(server.WsRpcCallRes{})
|
||||
t.Add(bchain.MempoolTxidFilterEntries{})
|
||||
|
||||
err := t.ConvertToFile("blockbook-api.ts")
|
||||
|
||||
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"`
|
||||
CoinLabel string `json:"coinLabel"`
|
||||
Host string `json:"host"`
|
||||
Network string `json:"network,omitempty"`
|
||||
|
||||
DbState uint32 `json:"dbState"`
|
||||
ExtendedIndex bool `json:"extendedIndex"`
|
||||
@ -92,6 +93,15 @@ type InternalState struct {
|
||||
// database migrations
|
||||
UtxoChecked bool `json:"utxoChecked"`
|
||||
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
|
||||
@ -296,6 +306,15 @@ func (is *InternalState) computeAvgBlockPeriod() {
|
||||
is.AvgBlockPeriod = (is.BlockTimes[last] - is.BlockTimes[first]) / avgBlockPeriodSample
|
||||
}
|
||||
|
||||
// GetNetwork returns network. If not set returns the same value as CoinShortcut
|
||||
func (is *InternalState) GetNetwork() string {
|
||||
network := is.Network
|
||||
if network == "" {
|
||||
return is.CoinShortcut
|
||||
}
|
||||
return network
|
||||
}
|
||||
|
||||
// SetBackendInfo sets new BackendInfo
|
||||
func (is *InternalState) SetBackendInfo(bi *BackendInfo) {
|
||||
is.mux.Lock()
|
||||
@ -336,3 +355,15 @@ func SetInShutdown() {
|
||||
func IsInShutdown() bool {
|
||||
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
|
||||
// to handle data which can be numbers in double quotes or possibly not numbers at all
|
||||
//
|
||||
// to handle data which can be numbers in double quotes or possibly not numbers at all
|
||||
//
|
||||
// see https://github.com/golang/go/issues/37308
|
||||
type JSONNumber string
|
||||
|
||||
|
||||
@ -72,7 +72,7 @@ func GetMetrics(coin string) (*Metrics, error) {
|
||||
prometheus.HistogramOpts{
|
||||
Name: "blockbook_socketio_req_duration",
|
||||
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},
|
||||
},
|
||||
[]string{"method"},
|
||||
@ -104,7 +104,7 @@ func GetMetrics(coin string) (*Metrics, error) {
|
||||
prometheus.HistogramOpts{
|
||||
Name: "blockbook_websocket_req_duration",
|
||||
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},
|
||||
},
|
||||
[]string{"method"},
|
||||
@ -113,7 +113,7 @@ func GetMetrics(coin string) (*Metrics, error) {
|
||||
prometheus.HistogramOpts{
|
||||
Name: "blockbook_index_resync_duration",
|
||||
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},
|
||||
},
|
||||
)
|
||||
@ -121,7 +121,7 @@ func GetMetrics(coin string) (*Metrics, error) {
|
||||
prometheus.HistogramOpts{
|
||||
Name: "blockbook_mempool_resync_duration",
|
||||
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},
|
||||
},
|
||||
)
|
||||
|
||||
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_revision": "satoshilabs-1",
|
||||
"system_user": "avalanche",
|
||||
"version": "1.9.11",
|
||||
"binary_url": "https://github.com/ava-labs/avalanchego/releases/download/v1.9.11/avalanchego-linux-amd64-v1.9.11.tar.gz",
|
||||
"version": "1.12.1",
|
||||
"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_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",
|
||||
"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==",
|
||||
@ -36,8 +36,8 @@
|
||||
"client_config_file": "",
|
||||
"platforms": {
|
||||
"arm64": {
|
||||
"binary_url": "https://github.com/ava-labs/avalanchego/releases/download/v1.9.11/avalanchego-linux-arm64-v1.9.11.tar.gz",
|
||||
"verification_source": "https://github.com/ava-labs/avalanchego/releases/download/v1.9.11/avalanchego-linux-arm64-v1.9.11.tar.gz.sig"
|
||||
"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.12.1/avalanchego-linux-arm64-v1.12.1.tar.gz.sig"
|
||||
}
|
||||
}
|
||||
},
|
||||
|
||||
@ -19,10 +19,10 @@
|
||||
"package_name": "backend-avalanche-archive",
|
||||
"package_revision": "satoshilabs-1",
|
||||
"system_user": "avalanche",
|
||||
"version": "1.9.11",
|
||||
"binary_url": "https://github.com/ava-labs/avalanchego/releases/download/v1.9.11/avalanchego-linux-amd64-v1.9.11.tar.gz",
|
||||
"version": "1.12.1",
|
||||
"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_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",
|
||||
"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==",
|
||||
@ -36,8 +36,8 @@
|
||||
"client_config_file": "",
|
||||
"platforms": {
|
||||
"arm64": {
|
||||
"binary_url": "https://github.com/ava-labs/avalanchego/releases/download/v1.9.11/avalanchego-linux-arm64-v1.9.11.tar.gz",
|
||||
"verification_source": "https://github.com/ava-labs/avalanchego/releases/download/v1.9.11/avalanchego-linux-arm64-v1.9.11.tar.gz.sig"
|
||||
"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.12.1/avalanchego-linux-arm64-v1.12.1.tar.gz.sig"
|
||||
}
|
||||
}
|
||||
},
|
||||
|
||||
@ -22,10 +22,10 @@
|
||||
"package_name": "backend-bcash",
|
||||
"package_revision": "satoshilabs-1",
|
||||
"system_user": "bcash",
|
||||
"version": "26.1.0",
|
||||
"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",
|
||||
"version": "28.0.1",
|
||||
"binary_url": "https://github.com/bitcoin-cash-node/bitcoin-cash-node/releases/download/v28.0.1/bitcoin-cash-node-28.0.1-x86_64-linux-gnu.tar.gz",
|
||||
"verification_type": "sha256",
|
||||
"verification_source": "68cb24d57898d5b47a1162a9683d0b0e36c6701b5a16b93edc94bbd82113c04b",
|
||||
"verification_source": "d69ee632147f886ca540cecdff5b1b85512612b4c005e86b09083a63c35b64fa",
|
||||
"extract_command": "tar -C backend --strip 1 -xf",
|
||||
"exclude_files": ["bin/bitcoin-qt"],
|
||||
"exec_command_template": "{{.Env.BackendInstallPath}}/{{.Coin.Alias}}/bin/bitcoind -datadir={{.Env.BackendDataPath}}/{{.Coin.Alias}}/backend -conf={{.Env.BackendInstallPath}}/{{.Coin.Alias}}/{{.Coin.Alias}}.conf -pid=/run/{{.Coin.Alias}}/{{.Coin.Alias}}.pid",
|
||||
|
||||
@ -1,66 +1,64 @@
|
||||
{
|
||||
"coin": {
|
||||
"name": "Bcash Testnet",
|
||||
"shortcut": "TBCH",
|
||||
"label": "Bitcoin Cash Testnet",
|
||||
"alias": "bcash_testnet"
|
||||
},
|
||||
"ports": {
|
||||
"backend_rpc": 18031,
|
||||
"backend_message_queue": 48331,
|
||||
"blockbook_internal": 19031,
|
||||
"blockbook_public": 19131
|
||||
},
|
||||
"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-bcash-testnet",
|
||||
"package_revision": "satoshilabs-1",
|
||||
"system_user": "bcash",
|
||||
"version": "26.1.0",
|
||||
"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",
|
||||
"verification_type": "sha256",
|
||||
"verification_source": "68cb24d57898d5b47a1162a9683d0b0e36c6701b5a16b93edc94bbd82113c04b",
|
||||
"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/testnet3/*.log",
|
||||
"postinst_script_template": "",
|
||||
"service_type": "forking",
|
||||
"service_additional_params_template": "",
|
||||
"protect_memory": true,
|
||||
"mainnet": false,
|
||||
"server_config_file": "bitcoin.conf",
|
||||
"client_config_file": "bitcoin_client.conf"
|
||||
},
|
||||
"blockbook": {
|
||||
"package_name": "blockbook-bcash-testnet",
|
||||
"system_user": "blockbook-bcash",
|
||||
"internal_binding_template": ":{{.Ports.BlockbookInternal}}",
|
||||
"public_binding_template": ":{{.Ports.BlockbookPublic}}",
|
||||
"explorer_url": "",
|
||||
"additional_params": "",
|
||||
"block_chain": {
|
||||
"parse": true,
|
||||
"subversion": "/Bitcoin ABC Cash Node:22.1.0/",
|
||||
"address_format": "cashaddr",
|
||||
"mempool_workers": 8,
|
||||
"mempool_sub_workers": 2,
|
||||
"block_addresses_to_keep": 300,
|
||||
"xpub_magic": 70617039,
|
||||
"slip44": 1,
|
||||
"additional_params": {}
|
||||
"coin": {
|
||||
"name": "Bcash Testnet",
|
||||
"shortcut": "TBCH",
|
||||
"label": "Bitcoin Cash Testnet",
|
||||
"alias": "bcash_testnet"
|
||||
},
|
||||
"ports": {
|
||||
"backend_rpc": 18031,
|
||||
"backend_message_queue": 48331,
|
||||
"blockbook_internal": 19031,
|
||||
"blockbook_public": 19131
|
||||
},
|
||||
"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-bcash-testnet",
|
||||
"package_revision": "satoshilabs-1",
|
||||
"system_user": "bcash",
|
||||
"version": "28.0.1",
|
||||
"binary_url": "https://github.com/bitcoin-cash-node/bitcoin-cash-node/releases/download/v28.0.1/bitcoin-cash-node-28.0.1-x86_64-linux-gnu.tar.gz",
|
||||
"verification_type": "sha256",
|
||||
"verification_source": "d69ee632147f886ca540cecdff5b1b85512612b4c005e86b09083a63c35b64fa",
|
||||
"extract_command": "tar -C backend --strip 1 -xf",
|
||||
"exclude_files": ["bin/bitcoin-qt"],
|
||||
"exec_command_template": "{{.Env.BackendInstallPath}}/{{.Coin.Alias}}/bin/bitcoind -datadir={{.Env.BackendDataPath}}/{{.Coin.Alias}}/backend -conf={{.Env.BackendInstallPath}}/{{.Coin.Alias}}/{{.Coin.Alias}}.conf -pid=/run/{{.Coin.Alias}}/{{.Coin.Alias}}.pid",
|
||||
"logrotate_files_template": "{{.Env.BackendDataPath}}/{{.Coin.Alias}}/backend/testnet3/*.log",
|
||||
"postinst_script_template": "",
|
||||
"service_type": "forking",
|
||||
"service_additional_params_template": "",
|
||||
"protect_memory": true,
|
||||
"mainnet": false,
|
||||
"server_config_file": "bcash.conf",
|
||||
"client_config_file": "bitcoin_client.conf"
|
||||
},
|
||||
"blockbook": {
|
||||
"package_name": "blockbook-bcash-testnet",
|
||||
"system_user": "blockbook-bcash",
|
||||
"internal_binding_template": ":{{.Ports.BlockbookInternal}}",
|
||||
"public_binding_template": ":{{.Ports.BlockbookPublic}}",
|
||||
"explorer_url": "",
|
||||
"additional_params": "",
|
||||
"block_chain": {
|
||||
"parse": true,
|
||||
"subversion": "/Bitcoin ABC Cash Node:22.1.0/",
|
||||
"address_format": "cashaddr",
|
||||
"mempool_workers": 8,
|
||||
"mempool_sub_workers": 2,
|
||||
"block_addresses_to_keep": 300,
|
||||
"xpub_magic": 70617039,
|
||||
"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_revision": "satoshilabs-1",
|
||||
"system_user": "bitcoin",
|
||||
"version": "25.0",
|
||||
"binary_url": "https://bitcoincore.org/bin/bitcoin-core-25.0/bitcoin-25.0-x86_64-linux-gnu.tar.gz",
|
||||
"version": "28.0",
|
||||
"binary_url": "https://bitcoincore.org/bin/bitcoin-core-28.0/bitcoin-28.0-x86_64-linux-gnu.tar.gz",
|
||||
"verification_type": "sha256",
|
||||
"verification_source": "33930d432593e49d58a9bff4c30078823e9af5d98594d2935862788ce8a20aec",
|
||||
"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",
|
||||
@ -38,12 +38,13 @@
|
||||
"server_config_file": "bitcoin.conf",
|
||||
"client_config_file": "bitcoin_client.conf",
|
||||
"additional_params": {
|
||||
"deprecatedrpc": "estimatefee"
|
||||
"deprecatedrpc": "estimatefee",
|
||||
"addnode": ["ove.palatinus.cz"]
|
||||
},
|
||||
"platforms": {
|
||||
"arm64": {
|
||||
"binary_url": "https://bitcoincore.org/bin/bitcoin-core-25.0/bitcoin-25.0-aarch64-linux-gnu.tar.gz",
|
||||
"verification_source": "3a7bdd959a0b426624f63f394f25e5b7769a5a2f96f8126dcc2ea53f3fa5212b"
|
||||
"binary_url": "https://bitcoincore.org/bin/bitcoin-core-28.0/bitcoin-28.0-aarch64-linux-gnu.tar.gz",
|
||||
"verification_source": "7fa582d99a25c354d23e371a5848bd9e6a79702870f9cbbf1292b86e647d0f4e"
|
||||
}
|
||||
}
|
||||
},
|
||||
@ -63,13 +64,17 @@
|
||||
"xpub_magic_segwit_p2sh": 77429938,
|
||||
"xpub_magic_segwit_native": 78792518,
|
||||
"additional_params": {
|
||||
"alternative_estimate_fee": "whatthefee-disabled",
|
||||
"alternative_estimate_fee_params": "{\"url\": \"https://whatthefee.io/data.json\", \"periodSeconds\": 60}",
|
||||
"alternative_estimate_fee": "mempoolspace",
|
||||
"alternative_estimate_fee_params": "{\"url\": \"https://mempool.space/api/v1/fees/recommended\", \"periodSeconds\": 20}",
|
||||
"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\": \"bitcoin\", \"periodSeconds\": 900}",
|
||||
"golomb_filter_p": 20,
|
||||
"mempool_filter_scripts": "taproot"
|
||||
"fiat_rates_params": "{\"coin\": \"bitcoin\", \"periodSeconds\": 60}",
|
||||
"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
|
||||
}
|
||||
}
|
||||
},
|
||||
|
||||
@ -22,10 +22,10 @@
|
||||
"package_name": "backend-bitcoin-regtest",
|
||||
"package_revision": "satoshilabs-1",
|
||||
"system_user": "bitcoin",
|
||||
"version": "25.0",
|
||||
"binary_url": "https://bitcoincore.org/bin/bitcoin-core-25.0/bitcoin-25.0-x86_64-linux-gnu.tar.gz",
|
||||
"version": "28.0",
|
||||
"binary_url": "https://bitcoincore.org/bin/bitcoin-core-28.0/bitcoin-28.0-x86_64-linux-gnu.tar.gz",
|
||||
"verification_type": "sha256",
|
||||
"verification_source": "33930d432593e49d58a9bff4c30078823e9af5d98594d2935862788ce8a20aec",
|
||||
"verification_source": "7fe294b02b25b51acb8e8e0a0eb5af6bbafa7cd0c5b0e5fcbb61263104a82fbc",
|
||||
"extract_command": "tar -C backend --strip 1 -xf",
|
||||
"exclude_files": ["bin/bitcoin-qt"],
|
||||
"exec_command_template": "{{.Env.BackendInstallPath}}/{{.Coin.Alias}}/bin/bitcoind -datadir={{.Env.BackendDataPath}}/{{.Coin.Alias}}/backend -conf={{.Env.BackendInstallPath}}/{{.Coin.Alias}}/{{.Coin.Alias}}.conf -pid=/run/{{.Coin.Alias}}/{{.Coin.Alias}}.pid",
|
||||
@ -42,8 +42,8 @@
|
||||
},
|
||||
"platforms": {
|
||||
"arm64": {
|
||||
"binary_url": "https://bitcoincore.org/bin/bitcoin-core-25.0/bitcoin-25.0-aarch64-linux-gnu.tar.gz",
|
||||
"verification_source": "3a7bdd959a0b426624f63f394f25e5b7769a5a2f96f8126dcc2ea53f3fa5212b"
|
||||
"binary_url": "https://bitcoincore.org/bin/bitcoin-core-28.0/bitcoin-28.0-aarch64-linux-gnu.tar.gz",
|
||||
"verification_source": "7fa582d99a25c354d23e371a5848bd9e6a79702870f9cbbf1292b86e647d0f4e"
|
||||
}
|
||||
}
|
||||
},
|
||||
@ -63,7 +63,14 @@
|
||||
"xpub_magic_segwit_p2sh": 71979618,
|
||||
"xpub_magic_segwit_native": 73342198,
|
||||
"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": {
|
||||
|
||||
@ -22,10 +22,10 @@
|
||||
"package_name": "backend-bitcoin-signet",
|
||||
"package_revision": "satoshilabs-1",
|
||||
"system_user": "bitcoin",
|
||||
"version": "25.0",
|
||||
"binary_url": "https://bitcoincore.org/bin/bitcoin-core-25.0/bitcoin-25.0-x86_64-linux-gnu.tar.gz",
|
||||
"version": "28.0",
|
||||
"binary_url": "https://bitcoincore.org/bin/bitcoin-core-28.0/bitcoin-28.0-x86_64-linux-gnu.tar.gz",
|
||||
"verification_type": "sha256",
|
||||
"verification_source": "33930d432593e49d58a9bff4c30078823e9af5d98594d2935862788ce8a20aec",
|
||||
"verification_source": "7fe294b02b25b51acb8e8e0a0eb5af6bbafa7cd0c5b0e5fcbb61263104a82fbc",
|
||||
"extract_command": "tar -C backend --strip 1 -xf",
|
||||
"exclude_files": ["bin/bitcoin-qt"],
|
||||
"exec_command_template": "{{.Env.BackendInstallPath}}/{{.Coin.Alias}}/bin/bitcoind -datadir={{.Env.BackendDataPath}}/{{.Coin.Alias}}/backend -conf={{.Env.BackendInstallPath}}/{{.Coin.Alias}}/{{.Coin.Alias}}.conf -pid=/run/{{.Coin.Alias}}/{{.Coin.Alias}}.pid",
|
||||
@ -35,15 +35,15 @@
|
||||
"service_additional_params_template": "",
|
||||
"protect_memory": true,
|
||||
"mainnet": false,
|
||||
"server_config_file": "bitcoin-signet.conf",
|
||||
"server_config_file": "bitcoin_signet.conf",
|
||||
"client_config_file": "bitcoin_client.conf",
|
||||
"additional_params": {
|
||||
"deprecatedrpc": "estimatefee"
|
||||
},
|
||||
"platforms": {
|
||||
"arm64": {
|
||||
"binary_url": "https://bitcoincore.org/bin/bitcoin-core-25.0/bitcoin-25.0-aarch64-linux-gnu.tar.gz",
|
||||
"verification_source": "3a7bdd959a0b426624f63f394f25e5b7769a5a2f96f8126dcc2ea53f3fa5212b"
|
||||
"binary_url": "https://bitcoincore.org/bin/bitcoin-core-28.0/bitcoin-28.0-aarch64-linux-gnu.tar.gz",
|
||||
"verification_source": "7fa582d99a25c354d23e371a5848bd9e6a79702870f9cbbf1292b86e647d0f4e"
|
||||
}
|
||||
}
|
||||
},
|
||||
|
||||
@ -22,10 +22,10 @@
|
||||
"package_name": "backend-bitcoin-testnet",
|
||||
"package_revision": "satoshilabs-1",
|
||||
"system_user": "bitcoin",
|
||||
"version": "25.0",
|
||||
"binary_url": "https://bitcoincore.org/bin/bitcoin-core-25.0/bitcoin-25.0-x86_64-linux-gnu.tar.gz",
|
||||
"version": "28.0",
|
||||
"binary_url": "https://bitcoincore.org/bin/bitcoin-core-28.0/bitcoin-28.0-x86_64-linux-gnu.tar.gz",
|
||||
"verification_type": "sha256",
|
||||
"verification_source": "33930d432593e49d58a9bff4c30078823e9af5d98594d2935862788ce8a20aec",
|
||||
"verification_source": "7fe294b02b25b51acb8e8e0a0eb5af6bbafa7cd0c5b0e5fcbb61263104a82fbc",
|
||||
"extract_command": "tar -C backend --strip 1 -xf",
|
||||
"exclude_files": ["bin/bitcoin-qt"],
|
||||
"exec_command_template": "{{.Env.BackendInstallPath}}/{{.Coin.Alias}}/bin/bitcoind -datadir={{.Env.BackendDataPath}}/{{.Coin.Alias}}/backend -conf={{.Env.BackendInstallPath}}/{{.Coin.Alias}}/{{.Coin.Alias}}.conf -pid=/run/{{.Coin.Alias}}/{{.Coin.Alias}}.pid",
|
||||
@ -42,8 +42,8 @@
|
||||
},
|
||||
"platforms": {
|
||||
"arm64": {
|
||||
"binary_url": "https://bitcoincore.org/bin/bitcoin-core-25.0/bitcoin-25.0-aarch64-linux-gnu.tar.gz",
|
||||
"verification_source": "3a7bdd959a0b426624f63f394f25e5b7769a5a2f96f8126dcc2ea53f3fa5212b"
|
||||
"binary_url": "https://bitcoincore.org/bin/bitcoin-core-28.0/bitcoin-28.0-aarch64-linux-gnu.tar.gz",
|
||||
"verification_source": "7fa582d99a25c354d23e371a5848bd9e6a79702870f9cbbf1292b86e647d0f4e"
|
||||
}
|
||||
}
|
||||
},
|
||||
@ -58,14 +58,18 @@
|
||||
"parse": true,
|
||||
"mempool_workers": 8,
|
||||
"mempool_sub_workers": 2,
|
||||
"block_addresses_to_keep": 300,
|
||||
"block_addresses_to_keep": 10000,
|
||||
"xpub_magic": 70617039,
|
||||
"xpub_magic_segwit_p2sh": 71979618,
|
||||
"xpub_magic_segwit_native": 73342198,
|
||||
"slip44": 1,
|
||||
"additional_params": {
|
||||
"golomb_filter_p": 20,
|
||||
"mempool_filter_scripts": "taproot"
|
||||
"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
|
||||
}
|
||||
}
|
||||
},
|
||||
|
||||
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": {
|
||||
"name": "BNB Smart Chain",
|
||||
"shortcut": "BNB",
|
||||
"network": "BSC",
|
||||
"label": "BNB Smart Chain",
|
||||
"alias": "bsc"
|
||||
},
|
||||
|
||||
@ -2,6 +2,7 @@
|
||||
"coin": {
|
||||
"name": "BNB Smart Chain Archive",
|
||||
"shortcut": "BNB",
|
||||
"network": "BSC",
|
||||
"label": "BNB Smart Chain",
|
||||
"alias": "bsc_archive"
|
||||
},
|
||||
|
||||
@ -22,10 +22,10 @@
|
||||
"package_name": "backend-dash",
|
||||
"package_revision": "satoshilabs-1",
|
||||
"system_user": "dash",
|
||||
"version": "19.2.0",
|
||||
"binary_url": "https://github.com/dashpay/dash/releases/download/v19.2.0/dashcore-19.2.0-x86_64-linux-gnu.tar.gz",
|
||||
"version": "22.0.0",
|
||||
"binary_url": "https://github.com/dashpay/dash/releases/download/v22.0.0/dashcore-22.0.0-x86_64-linux-gnu.tar.gz",
|
||||
"verification_type": "gpg-sha256",
|
||||
"verification_source": "https://github.com/dashpay/dash/releases/download/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",
|
||||
"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",
|
||||
|
||||
@ -22,10 +22,10 @@
|
||||
"package_name": "backend-dash-testnet",
|
||||
"package_revision": "satoshilabs-1",
|
||||
"system_user": "dash",
|
||||
"version": "19.2.0",
|
||||
"binary_url": "https://github.com/dashpay/dash/releases/download/v19.2.0/dashcore-19.2.0-x86_64-linux-gnu.tar.gz",
|
||||
"version": "22.0.0",
|
||||
"binary_url": "https://github.com/dashpay/dash/releases/download/v22.0.0/dashcore-22.0.0-x86_64-linux-gnu.tar.gz",
|
||||
"verification_type": "gpg-sha256",
|
||||
"verification_source": "https://github.com/dashpay/dash/releases/download/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",
|
||||
"exclude_files": [
|
||||
"bin/dash-qt"
|
||||
|
||||
@ -22,10 +22,10 @@
|
||||
"package_name": "backend-dogecoin",
|
||||
"package_revision": "satoshilabs-1",
|
||||
"system_user": "dogecoin",
|
||||
"version": "1.14.6",
|
||||
"binary_url": "https://github.com/dogecoin/dogecoin/releases/download/v1.14.6/dogecoin-1.14.6-x86_64-linux-gnu.tar.gz",
|
||||
"version": "1.14.9",
|
||||
"binary_url": "https://github.com/dogecoin/dogecoin/releases/download/v1.14.9/dogecoin-1.14.9-x86_64-linux-gnu.tar.gz",
|
||||
"verification_type": "sha256",
|
||||
"verification_source": "fe9c9cdab946155866a5bd5a5127d2971a9eed3e0b65fb553fe393ad1daaebb0",
|
||||
"verification_source": "4f227117b411a7c98622c970986e27bcfc3f547a72bef65e7d9e82989175d4f8",
|
||||
"extract_command": "tar -C backend --strip 1 -xf",
|
||||
"exclude_files": ["bin/dogecoin-qt"],
|
||||
"exec_command_template": "{{.Env.BackendInstallPath}}/{{.Coin.Alias}}/bin/dogecoind -datadir={{.Env.BackendDataPath}}/{{.Coin.Alias}}/backend -conf={{.Env.BackendInstallPath}}/{{.Coin.Alias}}/{{.Coin.Alias}}.conf -pid=/run/{{.Coin.Alias}}/{{.Coin.Alias}}.pid",
|
||||
@ -45,8 +45,8 @@
|
||||
},
|
||||
"platforms": {
|
||||
"arm64": {
|
||||
"binary_url": "https://github.com/dogecoin/dogecoin/releases/download/v1.14.6/dogecoin-1.14.6-aarch64-linux-gnu.tar.gz",
|
||||
"verification_source": "87419c29607b2612746fccebd694037e4be7600fc32198c4989f919be20952db",
|
||||
"binary_url": "https://github.com/dogecoin/dogecoin/releases/download/v1.14.9/dogecoin-1.14.9-aarch64-linux-gnu.tar.gz",
|
||||
"verification_source": "6928c895a20d0bcb6d5c7dcec753d35c884a471aaf8ad4242a89a96acb4f2985",
|
||||
"exclude_files": []
|
||||
}
|
||||
}
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue
Block a user