github.com/cerberus-wallet/blockbook@v0.3.2/bchain/coins/xzc/zcoinrpc.go (about)

     1  package xzc
     2  
     3  import (
     4  	"blockbook/bchain"
     5  	"blockbook/bchain/coins/btc"
     6  	"encoding/hex"
     7  	"encoding/json"
     8  
     9  	"github.com/golang/glog"
    10  	"github.com/juju/errors"
    11  )
    12  
    13  type ZcoinRPC struct {
    14  	*btc.BitcoinRPC
    15  }
    16  
    17  func NewZcoinRPC(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 zcoin implementation
    25  	zc := &ZcoinRPC{
    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 *ZcoinRPC) 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 = NewZcoinParser(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 *ZcoinRPC) 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.GetBlockRaw(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 *ZcoinRPC) 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 *ZcoinRPC) GetBlockWithoutHeader(hash string, height uint32) (*bchain.Block, error) {
   121  	data, err := zc.GetBlockRaw(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  func (zc *ZcoinRPC) GetBlockRaw(hash string) ([]byte, error) {
   138  	glog.V(1).Info("rpc: getblock (verbosity=false) ", hash)
   139  
   140  	res := btc.ResGetBlockRaw{}
   141  	req := cmdGetBlock{Method: "getblock"}
   142  	req.Params.BlockHash = hash
   143  	req.Params.Verbosity = false
   144  	err := zc.Call(&req, &res)
   145  
   146  	if err != nil {
   147  		return nil, errors.Annotatef(err, "hash %v", hash)
   148  	}
   149  	if res.Error != nil {
   150  		if btc.IsErrBlockNotFound(res.Error) {
   151  			return nil, bchain.ErrBlockNotFound
   152  		}
   153  		return nil, errors.Annotatef(res.Error, "hash %v", hash)
   154  	}
   155  	return hex.DecodeString(res.Result)
   156  }
   157  
   158  func (zc *ZcoinRPC) GetTransactionForMempool(txid string) (*bchain.Tx, error) {
   159  	glog.V(1).Info("rpc: getrawtransaction nonverbose ", txid)
   160  
   161  	res := btc.ResGetRawTransactionNonverbose{}
   162  	req := cmdGetRawTransaction{Method: "getrawtransaction"}
   163  	req.Params.Txid = txid
   164  	req.Params.Verbose = 0
   165  	err := zc.Call(&req, &res)
   166  	if err != nil {
   167  		return nil, errors.Annotatef(err, "txid %v", txid)
   168  	}
   169  	if res.Error != nil {
   170  		if btc.IsMissingTx(res.Error) {
   171  			return nil, bchain.ErrTxNotFound
   172  		}
   173  		return nil, errors.Annotatef(res.Error, "txid %v", txid)
   174  	}
   175  	data, err := hex.DecodeString(res.Result)
   176  	if err != nil {
   177  		return nil, errors.Annotatef(err, "txid %v", txid)
   178  	}
   179  	tx, err := zc.Parser.ParseTx(data)
   180  	if err != nil {
   181  		return nil, errors.Annotatef(err, "txid %v", txid)
   182  	}
   183  	return tx, nil
   184  }
   185  
   186  func (zc *ZcoinRPC) GetTransaction(txid string) (*bchain.Tx, error) {
   187  	r, err := zc.getRawTransaction(txid)
   188  	if err != nil {
   189  		return nil, err
   190  	}
   191  
   192  	tx, err := zc.Parser.ParseTxFromJson(r)
   193  	tx.CoinSpecificData = r
   194  	if err != nil {
   195  		return nil, errors.Annotatef(err, "txid %v", txid)
   196  	}
   197  
   198  	return tx, nil
   199  }
   200  
   201  func (zc *ZcoinRPC) GetTransactionSpecific(tx *bchain.Tx) (json.RawMessage, error) {
   202  	if csd, ok := tx.CoinSpecificData.(json.RawMessage); ok {
   203  		return csd, nil
   204  	}
   205  	return zc.getRawTransaction(tx.Txid)
   206  }
   207  
   208  func (zc *ZcoinRPC) getRawTransaction(txid string) (json.RawMessage, error) {
   209  	glog.V(1).Info("rpc: getrawtransaction ", txid)
   210  
   211  	res := btc.ResGetRawTransaction{}
   212  	req := cmdGetRawTransaction{Method: "getrawtransaction"}
   213  	req.Params.Txid = txid
   214  	req.Params.Verbose = 1
   215  	err := zc.Call(&req, &res)
   216  
   217  	if err != nil {
   218  		return nil, errors.Annotatef(err, "txid %v", txid)
   219  	}
   220  	if res.Error != nil {
   221  		if btc.IsMissingTx(res.Error) {
   222  			return nil, bchain.ErrTxNotFound
   223  		}
   224  		return nil, errors.Annotatef(res.Error, "txid %v", txid)
   225  	}
   226  	return res.Result, nil
   227  }
   228  
   229  type cmdGetBlock struct {
   230  	Method string `json:"method"`
   231  	Params struct {
   232  		BlockHash string `json:"blockhash"`
   233  		Verbosity bool   `json:"verbosity"`
   234  	} `json:"params"`
   235  }
   236  
   237  type cmdGetRawTransaction struct {
   238  	Method string `json:"method"`
   239  	Params struct {
   240  		Txid    string `json:"txid"`
   241  		Verbose int    `json:"verbose"`
   242  	} `json:"params"`
   243  }