github.com/aychain/blockbook@v0.1.1-0.20181121092459-6d1fc7e07c5b/bchain/coins/zec/zcashrpc.go (about) 1 package zec 2 3 import ( 4 "blockbook/bchain" 5 "blockbook/bchain/coins/btc" 6 "encoding/json" 7 8 "github.com/golang/glog" 9 "github.com/juju/errors" 10 ) 11 12 type ZCashRPC struct { 13 *btc.BitcoinRPC 14 } 15 16 func NewZCashRPC(config json.RawMessage, pushHandler func(bchain.NotificationType)) (bchain.BlockChain, error) { 17 b, err := btc.NewBitcoinRPC(config, pushHandler) 18 if err != nil { 19 return nil, err 20 } 21 z := &ZCashRPC{ 22 BitcoinRPC: b.(*btc.BitcoinRPC), 23 } 24 z.RPCMarshaler = btc.JSONMarshalerV1{} 25 z.ChainConfig.SupportsEstimateSmartFee = false 26 return z, nil 27 } 28 29 // Initialize initializes ZCashRPC instance. 30 func (z *ZCashRPC) Initialize() error { 31 chainName, err := z.GetChainInfoAndInitializeMempool(z) 32 if err != nil { 33 return err 34 } 35 36 params := GetChainParams(chainName) 37 38 z.Parser = NewZCashParser(params, z.ChainConfig) 39 40 // parameters for getInfo request 41 if params.Net == MainnetMagic { 42 z.Testnet = false 43 z.Network = "livenet" 44 } else { 45 z.Testnet = true 46 z.Network = "testnet" 47 } 48 49 glog.Info("rpc: block chain ", params.Name) 50 51 return nil 52 } 53 54 // GetBlock returns block with given hash. 55 func (z *ZCashRPC) GetBlock(hash string, height uint32) (*bchain.Block, error) { 56 var err error 57 if hash == "" && height > 0 { 58 hash, err = z.GetBlockHash(height) 59 if err != nil { 60 return nil, err 61 } 62 } 63 64 glog.V(1).Info("rpc: getblock (verbosity=1) ", hash) 65 66 res := btc.ResGetBlockThin{} 67 req := btc.CmdGetBlock{Method: "getblock"} 68 req.Params.BlockHash = hash 69 req.Params.Verbosity = 1 70 err = z.Call(&req, &res) 71 72 if err != nil { 73 return nil, errors.Annotatef(err, "hash %v", hash) 74 } 75 if res.Error != nil { 76 return nil, errors.Annotatef(res.Error, "hash %v", hash) 77 } 78 79 txs := make([]bchain.Tx, 0, len(res.Result.Txids)) 80 for _, txid := range res.Result.Txids { 81 tx, err := z.GetTransaction(txid) 82 if err != nil { 83 if isInvalidTx(err) { 84 glog.Errorf("rpc: getblock: skipping transanction in block %s due error: %s", hash, err) 85 continue 86 } 87 return nil, err 88 } 89 txs = append(txs, *tx) 90 } 91 block := &bchain.Block{ 92 BlockHeader: res.Result.BlockHeader, 93 Txs: txs, 94 } 95 return block, nil 96 } 97 98 func isInvalidTx(err error) bool { 99 switch e1 := err.(type) { 100 case *errors.Err: 101 switch e2 := e1.Cause().(type) { 102 case *bchain.RPCError: 103 if e2.Code == -5 { // "No information available about transaction" 104 return true 105 } 106 } 107 } 108 109 return false 110 } 111 112 // GetTransactionForMempool returns a transaction by the transaction ID. 113 // It could be optimized for mempool, i.e. without block time and confirmations 114 func (z *ZCashRPC) GetTransactionForMempool(txid string) (*bchain.Tx, error) { 115 return z.GetTransaction(txid) 116 } 117 118 // GetMempoolEntry returns mempool data for given transaction 119 func (z *ZCashRPC) GetMempoolEntry(txid string) (*bchain.MempoolEntry, error) { 120 return nil, errors.New("GetMempoolEntry: not implemented") 121 } 122 123 func isErrBlockNotFound(err *bchain.RPCError) bool { 124 return err.Message == "Block not found" || 125 err.Message == "Block height out of range" 126 }