Skip to content

Commit e0aec09

Browse files
committed
Merge remote-tracking branch 'upstream/master'
2 parents 04fb44c + 2023481 commit e0aec09

File tree

3 files changed

+236
-46
lines changed

3 files changed

+236
-46
lines changed

bchain/coins/zec/zcashrpc.go

Lines changed: 166 additions & 29 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,10 @@
11
package zec
22

33
import (
4+
"bytes"
45
"encoding/json"
6+
"os/exec"
7+
"reflect"
58

69
"github.com/golang/glog"
710
"github.com/juju/errors"
@@ -42,7 +45,7 @@ func NewZCashRPC(config json.RawMessage, pushHandler func(bchain.NotificationTyp
4245
z := &ZCashRPC{
4346
BitcoinRPC: b.(*btc.BitcoinRPC),
4447
}
45-
z.RPCMarshaler = btc.JSONMarshalerV1{}
48+
z.RPCMarshaler = JSONMarshalerV1Zebra{}
4649
z.ChainConfig.SupportsEstimateSmartFee = false
4750
return z, nil
4851
}
@@ -84,13 +87,16 @@ func (z *ZCashRPC) GetChainInfo() (*bchain.ChainInfo, error) {
8487
return nil, chainInfo.Error
8588
}
8689

90+
// networkinfo not supported by zebra
8791
networkInfo := btc.ResGetNetworkInfo{}
88-
err = z.Call(&btc.CmdGetNetworkInfo{Method: "getnetworkinfo"}, &networkInfo)
89-
if err != nil {
90-
return nil, err
91-
}
92-
if networkInfo.Error != nil {
93-
return nil, networkInfo.Error
92+
93+
zebrad := "zebra"
94+
cmd := exec.Command("/opt/coins/nodes/zcash/bin/zebrad", "--version")
95+
var out bytes.Buffer
96+
cmd.Stdout = &out
97+
err = cmd.Run()
98+
if err == nil {
99+
zebrad = out.String()
94100
}
95101

96102
return &bchain.ChainInfo{
@@ -100,7 +106,7 @@ func (z *ZCashRPC) GetChainInfo() (*bchain.ChainInfo, error) {
100106
Difficulty: string(chainInfo.Result.Difficulty),
101107
Headers: chainInfo.Result.Headers,
102108
SizeOnDisk: chainInfo.Result.SizeOnDisk,
103-
Version: string(networkInfo.Result.Version),
109+
Version: zebrad,
104110
Subversion: string(networkInfo.Result.Subversion),
105111
ProtocolVersion: string(networkInfo.Result.ProtocolVersion),
106112
Timeoffset: networkInfo.Result.Timeoffset,
@@ -111,6 +117,22 @@ func (z *ZCashRPC) GetChainInfo() (*bchain.ChainInfo, error) {
111117

112118
// GetBlock returns block with given hash.
113119
func (z *ZCashRPC) GetBlock(hash string, height uint32) (*bchain.Block, error) {
120+
type rpcBlock struct {
121+
bchain.BlockHeader
122+
Txs []bchain.Tx `json:"tx"`
123+
}
124+
type rpcBlockTxids struct {
125+
Txids []string `json:"tx"`
126+
}
127+
type resGetBlockV1 struct {
128+
Error *bchain.RPCError `json:"error"`
129+
Result rpcBlockTxids `json:"result"`
130+
}
131+
type resGetBlockV2 struct {
132+
Error *bchain.RPCError `json:"error"`
133+
Result rpcBlock `json:"result"`
134+
}
135+
114136
var err error
115137
if hash == "" && height > 0 {
116138
hash, err = z.GetBlockHash(height)
@@ -119,40 +141,86 @@ func (z *ZCashRPC) GetBlock(hash string, height uint32) (*bchain.Block, error) {
119141
}
120142
}
121143

122-
glog.V(1).Info("rpc: getblock (verbosity=1) ", hash)
123-
124-
res := btc.ResGetBlockThin{}
144+
var rawResponse json.RawMessage
145+
resV2 := resGetBlockV2{}
125146
req := btc.CmdGetBlock{Method: "getblock"}
126147
req.Params.BlockHash = hash
127-
req.Params.Verbosity = 1
128-
err = z.Call(&req, &res)
129-
148+
req.Params.Verbosity = 2
149+
err = z.Call(&req, &rawResponse)
130150
if err != nil {
131151
return nil, errors.Annotatef(err, "hash %v", hash)
132152
}
133-
if res.Error != nil {
134-
return nil, errors.Annotatef(res.Error, "hash %v", hash)
153+
// hack for ZCash, where the field "valueZat" is used instead of "valueSat"
154+
rawResponse = bytes.ReplaceAll(rawResponse, []byte(`"valueZat"`), []byte(`"valueSat"`))
155+
err = json.Unmarshal(rawResponse, &resV2)
156+
if err != nil {
157+
return nil, errors.Annotatef(err, "hash %v", hash)
135158
}
136159

137-
txs := make([]bchain.Tx, 0, len(res.Result.Txids))
138-
for _, txid := range res.Result.Txids {
139-
tx, err := z.GetTransaction(txid)
140-
if err != nil {
141-
if err == bchain.ErrTxNotFound {
142-
glog.Errorf("rpc: getblock: skipping transanction in block %s due error: %s", hash, err)
143-
continue
144-
}
145-
return nil, err
146-
}
147-
txs = append(txs, *tx)
160+
if resV2.Error != nil {
161+
return nil, errors.Annotatef(resV2.Error, "hash %v", hash)
148162
}
149163
block := &bchain.Block{
150-
BlockHeader: res.Result.BlockHeader,
151-
Txs: txs,
164+
BlockHeader: resV2.Result.BlockHeader,
165+
Txs: resV2.Result.Txs,
166+
}
167+
168+
// transactions fetched in block with verbosity 2 do not contain txids, so we need to get it separately
169+
resV1 := resGetBlockV1{}
170+
req.Params.Verbosity = 1
171+
err = z.Call(&req, &resV1)
172+
if err != nil {
173+
return nil, errors.Annotatef(err, "hash %v", hash)
174+
}
175+
if resV1.Error != nil {
176+
return nil, errors.Annotatef(resV1.Error, "hash %v", hash)
177+
}
178+
for i := range resV1.Result.Txids {
179+
block.Txs[i].Txid = resV1.Result.Txids[i]
152180
}
153181
return block, nil
154182
}
155183

184+
// GetTransaction returns a transaction by the transaction ID
185+
func (z *ZCashRPC) GetTransaction(txid string) (*bchain.Tx, error) {
186+
r, err := z.getRawTransaction(txid)
187+
if err != nil {
188+
return nil, err
189+
}
190+
// hack for ZCash, where the field "valueZat" is used instead of "valueSat"
191+
r = bytes.ReplaceAll(r, []byte(`"valueZat"`), []byte(`"valueSat"`))
192+
tx, err := z.Parser.ParseTxFromJson(r)
193+
if err != nil {
194+
return nil, errors.Annotatef(err, "txid %v", txid)
195+
}
196+
tx.Blocktime = tx.Time
197+
tx.Txid = txid
198+
tx.CoinSpecificData = r
199+
return tx, nil
200+
}
201+
202+
// getRawTransaction returns json as returned by backend, with all coin specific data
203+
func (z *ZCashRPC) getRawTransaction(txid string) (json.RawMessage, error) {
204+
glog.V(1).Info("rpc: getrawtransaction ", txid)
205+
206+
res := btc.ResGetRawTransaction{}
207+
req := btc.CmdGetRawTransaction{Method: "getrawtransaction"}
208+
req.Params.Txid = txid
209+
req.Params.Verbose = true
210+
err := z.Call(&req, &res)
211+
212+
if err != nil {
213+
return nil, errors.Annotatef(err, "txid %v", txid)
214+
}
215+
if res.Error != nil {
216+
if btc.IsMissingTx(res.Error) {
217+
return nil, bchain.ErrTxNotFound
218+
}
219+
return nil, errors.Annotatef(res.Error, "txid %v", txid)
220+
}
221+
return res.Result, nil
222+
}
223+
156224
// GetTransactionForMempool returns a transaction by the transaction ID.
157225
// It could be optimized for mempool, i.e. without block time and confirmations
158226
func (z *ZCashRPC) GetTransactionForMempool(txid string) (*bchain.Tx, error) {
@@ -168,3 +236,72 @@ func (z *ZCashRPC) GetMempoolEntry(txid string) (*bchain.MempoolEntry, error) {
168236
func (z *ZCashRPC) GetBlockRaw(hash string) (string, error) {
169237
return "", errors.New("GetBlockRaw: not supported")
170238
}
239+
240+
// JSONMarshalerV1 is used for marshalling requests to legacy Bitcoin Type RPC interfaces
241+
type JSONMarshalerV1Zebra struct{}
242+
243+
// Marshal converts struct passed by parameter to JSON
244+
func (JSONMarshalerV1Zebra) Marshal(v interface{}) ([]byte, error) {
245+
u := cmdUntypedParams{}
246+
247+
switch v := v.(type) {
248+
case *btc.CmdGetBlock:
249+
u.Method = v.Method
250+
u.Params = append(u.Params, v.Params.BlockHash)
251+
u.Params = append(u.Params, v.Params.Verbosity)
252+
case *btc.CmdGetRawTransaction:
253+
var n int
254+
if v.Params.Verbose {
255+
n = 1
256+
}
257+
u.Method = v.Method
258+
u.Params = append(u.Params, v.Params.Txid)
259+
u.Params = append(u.Params, n)
260+
default:
261+
{
262+
v := reflect.ValueOf(v).Elem()
263+
264+
f := v.FieldByName("Method")
265+
if !f.IsValid() || f.Kind() != reflect.String {
266+
return nil, btc.ErrInvalidValue
267+
}
268+
u.Method = f.String()
269+
270+
f = v.FieldByName("Params")
271+
if f.IsValid() {
272+
var arr []interface{}
273+
switch f.Kind() {
274+
case reflect.Slice:
275+
arr = make([]interface{}, f.Len())
276+
for i := 0; i < f.Len(); i++ {
277+
arr[i] = f.Index(i).Interface()
278+
}
279+
case reflect.Struct:
280+
arr = make([]interface{}, f.NumField())
281+
for i := 0; i < f.NumField(); i++ {
282+
arr[i] = f.Field(i).Interface()
283+
}
284+
default:
285+
return nil, btc.ErrInvalidValue
286+
}
287+
u.Params = arr
288+
}
289+
}
290+
}
291+
u.Id = "-"
292+
if u.Params == nil {
293+
u.Params = make([]interface{}, 0)
294+
}
295+
d, err := json.Marshal(u)
296+
if err != nil {
297+
return nil, err
298+
}
299+
300+
return d, nil
301+
}
302+
303+
type cmdUntypedParams struct {
304+
Method string `json:"method"`
305+
Id string `json:"id"`
306+
Params []interface{} `json:"params"`
307+
}
Lines changed: 57 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,57 @@
1+
{{define "main" -}}[consensus]
2+
checkpoint_sync = true
3+
4+
[mempool]
5+
eviction_memory_time = "1h"
6+
tx_cost_limit = 80000000
7+
8+
[metrics]
9+
10+
[mining]
11+
debug_like_zcashd = true
12+
internal_miner = false
13+
14+
[network]
15+
cache_dir = true
16+
crawl_new_peer_interval = "1m 1s"
17+
initial_mainnet_peers = [
18+
"dnsseed.z.cash:8233",
19+
"dnsseed.str4d.xyz:8233",
20+
"mainnet.seeder.zfnd.org:8233",
21+
"mainnet.is.yolo.money:8233",
22+
]
23+
initial_testnet_peers = [
24+
"dnsseed.testnet.z.cash:18233",
25+
"testnet.seeder.zfnd.org:18233",
26+
"testnet.is.yolo.money:18233",
27+
]
28+
listen_addr = "0.0.0.0:8233"
29+
max_connections_per_ip = 1
30+
network = "Mainnet"
31+
peerset_initial_target_size = 25
32+
33+
[rpc]
34+
cookie_dir = "{{.Env.BackendDataPath}}/{{.Coin.Alias}}/backend"
35+
debug_force_finished_sync = false
36+
enable_cookie_auth = false
37+
parallel_cpu_threads = 0
38+
listen_addr = '127.0.0.1:{{.Ports.BackendRPC}}'
39+
40+
[state]
41+
cache_dir = "{{.Env.BackendDataPath}}/{{.Coin.Alias}}/backend/zebra"
42+
delete_old_database = true
43+
ephemeral = false
44+
45+
[sync]
46+
checkpoint_verify_concurrency_limit = 1000
47+
download_concurrency_limit = 50
48+
full_verify_concurrency_limit = 20
49+
parallel_cpu_threads = 0
50+
51+
[tracing]
52+
buffer_limit = 128000
53+
force_use_color = false
54+
use_color = true
55+
use_journald = false
56+
log_file = "{{.Env.BackendDataPath}}/{{.Coin.Alias}}/backend/zebra.log"
57+
{{end}}

configs/coins/zcash.json

Lines changed: 13 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -22,33 +22,29 @@
2222
"package_name": "backend-zcash",
2323
"package_revision": "satoshilabs-1",
2424
"system_user": "zcash",
25-
"version": "6.2.0",
26-
"binary_url": "https://download.z.cash/downloads/zcash-6.2.0-linux64-debian-bullseye.tar.gz",
27-
"verification_type": "sha256",
28-
"verification_source": "71cf378c27582a4b9f9d57cafc2b5a57a46e9e52a5eda33be112dc9790c64c6f",
29-
"extract_command": "tar -C backend --strip 1 -xf",
25+
"version": "2.3.0",
26+
"docker_image": "zfnd/zebra:2.3.0",
27+
"verification_type": "docker",
28+
"verification_source": "70835d84cc6dceeda160707a35c611b11e616acb3627c99862e92bb5f0789ab4",
29+
"extract_command": "mkdir backend/bin && docker cp extract:/usr/local/bin/zebrad backend/bin/zebrad",
3030
"exclude_files": [],
31-
"exec_command_template": "{{.Env.BackendInstallPath}}/{{.Coin.Alias}}/bin/zcashd -datadir={{.Env.BackendDataPath}}/{{.Coin.Alias}}/backend -conf={{.Env.BackendInstallPath}}/{{.Coin.Alias}}/{{.Coin.Alias}}.conf -pid=/run/{{.Coin.Alias}}/{{.Coin.Alias}}.pid",
31+
"exec_command_template": "{{.Env.BackendInstallPath}}/{{.Coin.Alias}}/bin/zebrad --config {{.Env.BackendInstallPath}}/{{.Coin.Alias}}/zcash.conf start",
3232
"logrotate_files_template": "{{.Env.BackendDataPath}}/{{.Coin.Alias}}/backend/*.log",
33-
"postinst_script_template": "HOME={{.Env.BackendDataPath}}/{{.Coin.Alias}}/backend {{.Env.BackendInstallPath}}/{{.Coin.Alias}}/bin/zcash-fetch-params",
34-
"service_type": "forking",
35-
"service_additional_params_template": "Environment=\"HOME={{.Env.BackendDataPath}}/{{.Coin.Alias}}/backend\"",
36-
"protect_memory": false,
33+
"postinst_script_template": "",
34+
"service_type": "simple",
35+
"service_additional_params_template": "",
36+
"protect_memory": true,
3737
"mainnet": true,
38-
"server_config_file": "bitcoin_like.conf",
39-
"client_config_file": "bitcoin_like_client.conf",
40-
"additional_params": {
41-
"addnode": ["mainnet.z.cash"],
42-
"i-am-aware-zcashd-will-be-replaced-by-zebrad-and-zallet-in-2025": 1
43-
}
38+
"server_config_file": "zcash.conf",
39+
"client_config_file": "bitcoin_like_client.conf"
4440
},
4541
"blockbook": {
4642
"package_name": "blockbook-zcash",
4743
"system_user": "blockbook-zcash",
4844
"internal_binding_template": ":{{.Ports.BlockbookInternal}}",
4945
"public_binding_template": ":{{.Ports.BlockbookPublic}}",
5046
"explorer_url": "",
51-
"additional_params": "",
47+
"additional_params": "-resyncindexperiod=50000 -resyncmempoolperiod=3000",
5248
"block_chain": {
5349
"parse": true,
5450
"mempool_workers": 4,

0 commit comments

Comments
 (0)