forked from trezor/blockbook
-
Notifications
You must be signed in to change notification settings - Fork 0
/
zcashrpc.go
168 lines (146 loc) · 4.56 KB
/
zcashrpc.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
package zec
import (
"encoding/json"
"github.com/golang/glog"
"github.com/juju/errors"
"github.com/trezor/blockbook/bchain"
"github.com/trezor/blockbook/bchain/coins/btc"
"github.com/trezor/blockbook/common"
)
// ZCashRPC is an interface to JSON-RPC bitcoind service
type ZCashRPC struct {
*btc.BitcoinRPC
}
type ResGetBlockChainInfo struct {
Error *bchain.RPCError `json:"error"`
Result struct {
Chain string `json:"chain"`
Blocks int `json:"blocks"`
Headers int `json:"headers"`
Bestblockhash string `json:"bestblockhash"`
Difficulty common.JSONNumber `json:"difficulty"`
Pruned bool `json:"pruned"`
SizeOnDisk int64 `json:"size_on_disk"`
Consensus struct {
Chaintip string `json:"chaintip"`
Nextblock string `json:"nextblock"`
} `json:"consensus"`
} `json:"result"`
}
// NewZCashRPC returns new ZCashRPC instance
func NewZCashRPC(config json.RawMessage, pushHandler func(bchain.NotificationType)) (bchain.BlockChain, error) {
b, err := btc.NewBitcoinRPC(config, pushHandler)
if err != nil {
return nil, err
}
z := &ZCashRPC{
BitcoinRPC: b.(*btc.BitcoinRPC),
}
z.RPCMarshaler = btc.JSONMarshalerV1{}
z.ChainConfig.SupportsEstimateSmartFee = false
return z, nil
}
// Initialize initializes ZCashRPC instance
func (z *ZCashRPC) Initialize() error {
ci, err := z.GetChainInfo()
if err != nil {
return err
}
chainName := ci.Chain
params := GetChainParams(chainName)
z.Parser = NewZCashParser(params, z.ChainConfig)
// parameters for getInfo request
if params.Net == MainnetMagic {
z.Testnet = false
z.Network = "livenet"
} else {
z.Testnet = true
z.Network = "testnet"
}
glog.Info("rpc: block chain ", params.Name)
return nil
}
func (z *ZCashRPC) GetChainInfo() (*bchain.ChainInfo, error) {
chainInfo := ResGetBlockChainInfo{}
err := z.Call(&btc.CmdGetBlockChainInfo{Method: "getblockchaininfo"}, &chainInfo)
if err != nil {
return nil, err
}
if chainInfo.Error != nil {
return nil, chainInfo.Error
}
networkInfo := btc.ResGetNetworkInfo{}
err = z.Call(&btc.CmdGetNetworkInfo{Method: "getnetworkinfo"}, &networkInfo)
if err != nil {
return nil, err
}
if networkInfo.Error != nil {
return nil, networkInfo.Error
}
return &bchain.ChainInfo{
Bestblockhash: chainInfo.Result.Bestblockhash,
Blocks: chainInfo.Result.Blocks,
Chain: chainInfo.Result.Chain,
Difficulty: string(chainInfo.Result.Difficulty),
Headers: chainInfo.Result.Headers,
SizeOnDisk: chainInfo.Result.SizeOnDisk,
Version: string(networkInfo.Result.Version),
Subversion: string(networkInfo.Result.Subversion),
ProtocolVersion: string(networkInfo.Result.ProtocolVersion),
Timeoffset: networkInfo.Result.Timeoffset,
Consensus: chainInfo.Result.Consensus,
Warnings: networkInfo.Result.Warnings,
}, nil
}
// GetBlock returns block with given hash.
func (z *ZCashRPC) GetBlock(hash string, height uint32) (*bchain.Block, error) {
var err error
if hash == "" && height > 0 {
hash, err = z.GetBlockHash(height)
if err != nil {
return nil, err
}
}
glog.V(1).Info("rpc: getblock (verbosity=1) ", hash)
res := btc.ResGetBlockThin{}
req := btc.CmdGetBlock{Method: "getblock"}
req.Params.BlockHash = hash
req.Params.Verbosity = 1
err = z.Call(&req, &res)
if err != nil {
return nil, errors.Annotatef(err, "hash %v", hash)
}
if res.Error != nil {
return nil, errors.Annotatef(res.Error, "hash %v", hash)
}
txs := make([]bchain.Tx, 0, len(res.Result.Txids))
for _, txid := range res.Result.Txids {
tx, err := z.GetTransaction(txid)
if err != nil {
if err == bchain.ErrTxNotFound {
glog.Errorf("rpc: getblock: skipping transanction in block %s due error: %s", hash, err)
continue
}
return nil, err
}
txs = append(txs, *tx)
}
block := &bchain.Block{
BlockHeader: res.Result.BlockHeader,
Txs: txs,
}
return block, nil
}
// GetTransactionForMempool returns a transaction by the transaction ID.
// It could be optimized for mempool, i.e. without block time and confirmations
func (z *ZCashRPC) GetTransactionForMempool(txid string) (*bchain.Tx, error) {
return z.GetTransaction(txid)
}
// GetMempoolEntry returns mempool data for given transaction
func (z *ZCashRPC) GetMempoolEntry(txid string) (*bchain.MempoolEntry, error) {
return nil, errors.New("GetMempoolEntry: not implemented")
}
func isErrBlockNotFound(err *bchain.RPCError) bool {
return err.Message == "Block not found" ||
err.Message == "Block height out of range"
}