github.com/trezor/blockbook@v0.4.1-0.20240328132726-e9a08582ee2c/bchain/coins/firo/firorpc.go (about) 1 package firo 2 3 import ( 4 "encoding/hex" 5 "encoding/json" 6 7 "github.com/golang/glog" 8 "github.com/juju/errors" 9 "github.com/trezor/blockbook/bchain" 10 "github.com/trezor/blockbook/bchain/coins/btc" 11 ) 12 13 type FiroRPC struct { 14 *btc.BitcoinRPC 15 } 16 17 func NewFiroRPC(config json.RawMessage, pushHandler func(bchain.NotificationType)) (bchain.BlockChain, error) { 18 // init base implementation 19 bc, err := btc.NewBitcoinRPC(config, pushHandler) 20 if err != nil { 21 return nil, err 22 } 23 24 // init firo implementation 25 zc := &FiroRPC{ 26 BitcoinRPC: bc.(*btc.BitcoinRPC), 27 } 28 29 zc.ChainConfig.Parse = true 30 zc.ChainConfig.SupportsEstimateFee = true 31 zc.ChainConfig.SupportsEstimateSmartFee = false 32 zc.ParseBlocks = true 33 zc.RPCMarshaler = btc.JSONMarshalerV1{} 34 35 return zc, nil 36 } 37 38 func (zc *FiroRPC) Initialize() error { 39 ci, err := zc.GetChainInfo() 40 if err != nil { 41 return err 42 } 43 chainName := ci.Chain 44 45 params := GetChainParams(chainName) 46 47 // always create parser 48 zc.Parser = NewFiroParser(params, zc.ChainConfig) 49 50 // parameters for getInfo request 51 if params.Net == MainnetMagic { 52 zc.Testnet = false 53 zc.Network = "livenet" 54 } else { 55 zc.Testnet = true 56 zc.Network = "testnet" 57 } 58 59 glog.Info("rpc: block chain ", params.Name) 60 61 return nil 62 } 63 64 func (zc *FiroRPC) GetBlock(hash string, height uint32) (*bchain.Block, error) { 65 var err error 66 67 if hash == "" { 68 hash, err = zc.GetBlockHash(height) 69 if err != nil { 70 return nil, err 71 } 72 } 73 74 // optimization 75 if height > 0 { 76 return zc.GetBlockWithoutHeader(hash, height) 77 } 78 79 header, err := zc.GetBlockHeader(hash) 80 if err != nil { 81 return nil, err 82 } 83 84 data, err := zc.GetBlockBytes(hash) 85 if err != nil { 86 return nil, err 87 } 88 89 block, err := zc.Parser.ParseBlock(data) 90 if err != nil { 91 return nil, errors.Annotatef(err, "hash %v", hash) 92 } 93 94 block.BlockHeader = *header 95 96 return block, nil 97 } 98 99 func (zc *FiroRPC) GetBlockInfo(hash string) (*bchain.BlockInfo, error) { 100 glog.V(1).Info("rpc: getblock (verbosity=true) ", hash) 101 102 res := btc.ResGetBlockInfo{} 103 req := cmdGetBlock{Method: "getblock"} 104 req.Params.BlockHash = hash 105 req.Params.Verbosity = true 106 err := zc.Call(&req, &res) 107 108 if err != nil { 109 return nil, errors.Annotatef(err, "hash %v", hash) 110 } 111 if res.Error != nil { 112 if btc.IsErrBlockNotFound(res.Error) { 113 return nil, bchain.ErrBlockNotFound 114 } 115 return nil, errors.Annotatef(res.Error, "hash %v", hash) 116 } 117 return &res.Result, nil 118 } 119 120 func (zc *FiroRPC) GetBlockWithoutHeader(hash string, height uint32) (*bchain.Block, error) { 121 data, err := zc.GetBlockBytes(hash) 122 if err != nil { 123 return nil, err 124 } 125 126 block, err := zc.Parser.ParseBlock(data) 127 if err != nil { 128 return nil, errors.Annotatef(err, "%v %v", height, hash) 129 } 130 131 block.BlockHeader.Hash = hash 132 block.BlockHeader.Height = height 133 134 return block, nil 135 } 136 137 // GetBlockRaw returns block with given hash as hex string 138 func (zc *FiroRPC) GetBlockRaw(hash string) (string, error) { 139 glog.V(1).Info("rpc: getblock (verbosity=false) ", hash) 140 141 res := btc.ResGetBlockRaw{} 142 req := cmdGetBlock{Method: "getblock"} 143 req.Params.BlockHash = hash 144 req.Params.Verbosity = false 145 err := zc.Call(&req, &res) 146 147 if err != nil { 148 return "", errors.Annotatef(err, "hash %v", hash) 149 } 150 if res.Error != nil { 151 if btc.IsErrBlockNotFound(res.Error) { 152 return "", bchain.ErrBlockNotFound 153 } 154 return "", errors.Annotatef(res.Error, "hash %v", hash) 155 } 156 return res.Result, nil 157 } 158 159 // GetBlockBytes returns block with given hash as bytes 160 func (zc *FiroRPC) GetBlockBytes(hash string) ([]byte, error) { 161 block, err := zc.GetBlockRaw(hash) 162 if err != nil { 163 return nil, err 164 } 165 return hex.DecodeString(block) 166 } 167 168 func (zc *FiroRPC) GetTransactionForMempool(txid string) (*bchain.Tx, error) { 169 glog.V(1).Info("rpc: getrawtransaction nonverbose ", txid) 170 171 res := btc.ResGetRawTransactionNonverbose{} 172 req := cmdGetRawTransaction{Method: "getrawtransaction"} 173 req.Params.Txid = txid 174 req.Params.Verbose = 0 175 err := zc.Call(&req, &res) 176 if err != nil { 177 return nil, errors.Annotatef(err, "txid %v", txid) 178 } 179 if res.Error != nil { 180 if btc.IsMissingTx(res.Error) { 181 return nil, bchain.ErrTxNotFound 182 } 183 return nil, errors.Annotatef(res.Error, "txid %v", txid) 184 } 185 data, err := hex.DecodeString(res.Result) 186 if err != nil { 187 return nil, errors.Annotatef(err, "txid %v", txid) 188 } 189 tx, err := zc.Parser.ParseTx(data) 190 if err != nil { 191 return nil, errors.Annotatef(err, "txid %v", txid) 192 } 193 return tx, nil 194 } 195 196 func (zc *FiroRPC) GetTransaction(txid string) (*bchain.Tx, error) { 197 r, err := zc.getRawTransaction(txid) 198 if err != nil { 199 return nil, err 200 } 201 202 tx, err := zc.Parser.ParseTxFromJson(r) 203 tx.CoinSpecificData = r 204 if err != nil { 205 return nil, errors.Annotatef(err, "txid %v", txid) 206 } 207 208 return tx, nil 209 } 210 211 func (zc *FiroRPC) GetTransactionSpecific(tx *bchain.Tx) (json.RawMessage, error) { 212 if csd, ok := tx.CoinSpecificData.(json.RawMessage); ok { 213 return csd, nil 214 } 215 return zc.getRawTransaction(tx.Txid) 216 } 217 218 func (zc *FiroRPC) getRawTransaction(txid string) (json.RawMessage, error) { 219 glog.V(1).Info("rpc: getrawtransaction ", txid) 220 221 res := btc.ResGetRawTransaction{} 222 req := cmdGetRawTransaction{Method: "getrawtransaction"} 223 req.Params.Txid = txid 224 req.Params.Verbose = 1 225 err := zc.Call(&req, &res) 226 227 if err != nil { 228 return nil, errors.Annotatef(err, "txid %v", txid) 229 } 230 if res.Error != nil { 231 if btc.IsMissingTx(res.Error) { 232 return nil, bchain.ErrTxNotFound 233 } 234 return nil, errors.Annotatef(res.Error, "txid %v", txid) 235 } 236 return res.Result, nil 237 } 238 239 type cmdGetBlock struct { 240 Method string `json:"method"` 241 Params struct { 242 BlockHash string `json:"blockhash"` 243 Verbosity bool `json:"verbosity"` 244 } `json:"params"` 245 } 246 247 type cmdGetRawTransaction struct { 248 Method string `json:"method"` 249 Params struct { 250 Txid string `json:"txid"` 251 Verbose int `json:"verbose"` 252 } `json:"params"` 253 }