github.com/trezor/blockbook@v0.4.1-0.20240328132726-e9a08582ee2c/bchain/coins/ecash/ecashrpc.go (about) 1 package ecash 2 3 import ( 4 "encoding/hex" 5 "encoding/json" 6 "math/big" 7 8 "github.com/golang/glog" 9 "github.com/juju/errors" 10 "github.com/pirk/ecashutil" 11 "github.com/trezor/blockbook/bchain" 12 "github.com/trezor/blockbook/bchain/coins/btc" 13 ) 14 15 // ECashRPC is an interface to JSON-RPC bitcoind service. 16 type ECashRPC struct { 17 *btc.BitcoinRPC 18 } 19 20 // NewECashRPC returns new ECashRPC instance. 21 func NewECashRPC(config json.RawMessage, pushHandler func(bchain.NotificationType)) (bchain.BlockChain, error) { 22 b, err := btc.NewBitcoinRPC(config, pushHandler) 23 if err != nil { 24 return nil, err 25 } 26 27 s := &ECashRPC{ 28 b.(*btc.BitcoinRPC), 29 } 30 s.ChainConfig.SupportsEstimateSmartFee = false 31 32 return s, nil 33 } 34 35 // Initialize initializes ECashRPC instance. 36 func (b *ECashRPC) Initialize() error { 37 ci, err := b.GetChainInfo() 38 if err != nil { 39 return err 40 } 41 chainName := ci.Chain 42 43 params := GetChainParams(chainName) 44 45 // always create parser 46 b.Parser, err = NewECashParser(params, b.ChainConfig) 47 48 if err != nil { 49 return err 50 } 51 52 // parameters for getInfo request 53 if params.Net == ecashutil.MainnetMagic { 54 b.Testnet = false 55 b.Network = "livenet" 56 } else { 57 b.Testnet = true 58 b.Network = "testnet" 59 } 60 61 glog.Info("rpc: block chain ", params.Name) 62 63 return nil 64 } 65 66 // getblock 67 68 type cmdGetBlock struct { 69 Method string `json:"method"` 70 Params struct { 71 BlockHash string `json:"blockhash"` 72 Verbose bool `json:"verbose"` 73 } `json:"params"` 74 } 75 76 // estimatesmartfee 77 78 type cmdEstimateSmartFee struct { 79 Method string `json:"method"` 80 Params struct { 81 Blocks int `json:"nblocks"` 82 } `json:"params"` 83 } 84 85 // GetBlock returns block with given hash. 86 func (b *ECashRPC) GetBlock(hash string, height uint32) (*bchain.Block, error) { 87 var err error 88 if hash == "" && height > 0 { 89 hash, err = b.GetBlockHash(height) 90 if err != nil { 91 return nil, err 92 } 93 } 94 header, err := b.GetBlockHeader(hash) 95 if err != nil { 96 return nil, err 97 } 98 data, err := b.GetBlockBytes(hash) 99 if err != nil { 100 return nil, err 101 } 102 block, err := b.Parser.ParseBlock(data) 103 if err != nil { 104 return nil, errors.Annotatef(err, "hash %v", hash) 105 } 106 // size is not returned by GetBlockHeader and would be overwritten 107 size := block.Size 108 block.BlockHeader = *header 109 block.Size = size 110 return block, nil 111 } 112 113 // GetBlockRaw returns block with given hash as bytes. 114 func (b *ECashRPC) GetBlockRaw(hash string) (string, error) { 115 glog.V(1).Info("rpc: getblock (verbose=0) ", hash) 116 117 res := btc.ResGetBlockRaw{} 118 req := cmdGetBlock{Method: "getblock"} 119 req.Params.BlockHash = hash 120 req.Params.Verbose = false 121 err := b.Call(&req, &res) 122 123 if err != nil { 124 return "", errors.Annotatef(err, "hash %v", hash) 125 } 126 if res.Error != nil { 127 if isErrBlockNotFound(res.Error) { 128 return "", bchain.ErrBlockNotFound 129 } 130 return "", errors.Annotatef(res.Error, "hash %v", hash) 131 } 132 return res.Result, nil 133 } 134 135 // GetBlockBytes returns block with given hash as bytes 136 func (b *ECashRPC) GetBlockBytes(hash string) ([]byte, error) { 137 block, err := b.GetBlockRaw(hash) 138 if err != nil { 139 return nil, err 140 } 141 return hex.DecodeString(block) 142 } 143 144 // GetBlockInfo returns extended header (more info than in bchain.BlockHeader) with a list of txids 145 func (b *ECashRPC) GetBlockInfo(hash string) (*bchain.BlockInfo, error) { 146 glog.V(1).Info("rpc: getblock (verbosity=1) ", hash) 147 148 res := btc.ResGetBlockInfo{} 149 req := cmdGetBlock{Method: "getblock"} 150 req.Params.BlockHash = hash 151 req.Params.Verbose = true 152 err := b.Call(&req, &res) 153 154 if err != nil { 155 return nil, errors.Annotatef(err, "hash %v", hash) 156 } 157 if res.Error != nil { 158 if isErrBlockNotFound(res.Error) { 159 return nil, bchain.ErrBlockNotFound 160 } 161 return nil, errors.Annotatef(res.Error, "hash %v", hash) 162 } 163 return &res.Result, nil 164 } 165 166 // GetBlockFull returns block with given hash. 167 func (b *ECashRPC) GetBlockFull(hash string) (*bchain.Block, error) { 168 return nil, errors.New("Not implemented") 169 } 170 171 func isErrBlockNotFound(err *bchain.RPCError) bool { 172 return err.Message == "Block not found" || 173 err.Message == "Block height out of range" 174 } 175 176 // EstimateFee returns fee estimation 177 func (b *ECashRPC) EstimateFee(blocks int) (big.Int, error) { 178 glog.V(1).Info("rpc: estimatefee ", blocks) 179 180 res := btc.ResEstimateFee{} 181 req := struct { 182 Method string `json:"method"` 183 }{ 184 Method: "estimatefee", 185 } 186 187 err := b.Call(&req, &res) 188 189 var r big.Int 190 if err != nil { 191 return r, err 192 } 193 if res.Error != nil { 194 return r, res.Error 195 } 196 r, err = b.Parser.AmountToBigInt(res.Result) 197 if err != nil { 198 return r, err 199 } 200 return r, nil 201 } 202 203 // EstimateSmartFee returns fee estimation 204 func (b *ECashRPC) EstimateSmartFee(blocks int, conservative bool) (big.Int, error) { 205 // EstimateSmartFee is not supported by ecash 206 return b.EstimateFee(blocks) 207 }