github.com/bchainhub/blockbook@v0.3.2/bchain/coins/dcr/decredrpc.go (about)

     1  package dcr
     2  
     3  import (
     4  	"blockbook/bchain"
     5  	"bytes"
     6  	"encoding/json"
     7  	"fmt"
     8  	"io"
     9  	"io/ioutil"
    10  	"math/big"
    11  	"net"
    12  	"net/http"
    13  	"runtime/debug"
    14  	"strconv"
    15  	"strings"
    16  	"sync"
    17  	"time"
    18  
    19  	"blockbook/bchain/coins/btc"
    20  
    21  	"github.com/decred/dcrd/dcrjson"
    22  	"github.com/golang/glog"
    23  	"github.com/juju/errors"
    24  )
    25  
    26  // voteBitYes defines the vote bit set when a given block validates the previous
    27  // block
    28  const voteBitYes = 0x0001
    29  
    30  type DecredRPC struct {
    31  	*btc.BitcoinRPC
    32  	mtx         sync.Mutex
    33  	client      http.Client
    34  	rpcURL      string
    35  	rpcUser     string
    36  	bestBlock   uint32
    37  	rpcPassword string
    38  }
    39  
    40  // NewDecredRPC returns new DecredRPC instance.
    41  func NewDecredRPC(config json.RawMessage, pushHandler func(bchain.NotificationType)) (bchain.BlockChain, error) {
    42  	b, err := btc.NewBitcoinRPC(config, pushHandler)
    43  	if err != nil {
    44  		return nil, err
    45  	}
    46  
    47  	var c btc.Configuration
    48  	if err = json.Unmarshal(config, &c); err != nil {
    49  		return nil, errors.Annotate(err, "Invalid configuration file")
    50  	}
    51  
    52  	transport := &http.Transport{
    53  		Dial:                (&net.Dialer{KeepAlive: 600 * time.Second}).Dial,
    54  		MaxIdleConns:        100,
    55  		MaxIdleConnsPerHost: 100, // necessary to not to deplete ports
    56  	}
    57  
    58  	d := &DecredRPC{
    59  		BitcoinRPC:  b.(*btc.BitcoinRPC),
    60  		client:      http.Client{Timeout: time.Duration(c.RPCTimeout) * time.Second, Transport: transport},
    61  		rpcURL:      c.RPCURL,
    62  		rpcUser:     c.RPCUser,
    63  		rpcPassword: c.RPCPass,
    64  	}
    65  
    66  	d.BitcoinRPC.RPCMarshaler = btc.JSONMarshalerV1{}
    67  	d.BitcoinRPC.ChainConfig.SupportsEstimateSmartFee = false
    68  
    69  	return d, nil
    70  }
    71  
    72  // Initialize initializes DecredRPC instance.
    73  func (d *DecredRPC) Initialize() error {
    74  	chainInfo, err := d.GetChainInfo()
    75  	if err != nil {
    76  		return err
    77  	}
    78  
    79  	chainName := chainInfo.Chain
    80  	glog.Info("Chain name ", chainName)
    81  
    82  	params := GetChainParams(chainName)
    83  
    84  	// always create parser
    85  	d.BitcoinRPC.Parser = NewDecredParser(params, d.BitcoinRPC.ChainConfig)
    86  
    87  	// parameters for getInfo request
    88  	if params.Net == MainnetMagic {
    89  		d.BitcoinRPC.Testnet = false
    90  		d.BitcoinRPC.Network = "livenet"
    91  	} else {
    92  		d.BitcoinRPC.Testnet = true
    93  		d.BitcoinRPC.Network = "testnet"
    94  	}
    95  
    96  	glog.Info("rpc: block chain ", params.Name)
    97  
    98  	return nil
    99  }
   100  
   101  type Error struct {
   102  	Code    int    `json:"code"`
   103  	Message string `json:"message"`
   104  }
   105  
   106  type GenericCmd struct {
   107  	ID     int           `json:"id"`
   108  	Method string        `json:"method"`
   109  	Params []interface{} `json:"params,omitempty"`
   110  }
   111  
   112  type GetBlockChainInfoResult struct {
   113  	Error  Error `json:"error"`
   114  	Result struct {
   115  		Chain                string  `json:"chain"`
   116  		Blocks               int64   `json:"blocks"`
   117  		Headers              int64   `json:"headers"`
   118  		SyncHeight           int64   `json:"syncheight"`
   119  		BestBlockHash        string  `json:"bestblockhash"`
   120  		Difficulty           uint32  `json:"difficulty"`
   121  		VerificationProgress float64 `json:"verificationprogress"`
   122  		ChainWork            string  `json:"chainwork"`
   123  		InitialBlockDownload bool    `json:"initialblockdownload"`
   124  		MaxBlockSize         int64   `json:"maxblocksize"`
   125  	} `json:"result"`
   126  }
   127  
   128  type GetNetworkInfoResult struct {
   129  	Error  Error `json:"error"`
   130  	Result struct {
   131  		Version         int32   `json:"version"`
   132  		ProtocolVersion int32   `json:"protocolversion"`
   133  		TimeOffset      int64   `json:"timeoffset"`
   134  		Connections     int32   `json:"connections"`
   135  		RelayFee        float64 `json:"relayfee"`
   136  	} `json:"result"`
   137  }
   138  
   139  type GetInfoChainResult struct {
   140  	Error  Error `json:"error"`
   141  	Result struct {
   142  		Version         int32   `json:"version"`
   143  		ProtocolVersion int32   `json:"protocolversion"`
   144  		Blocks          int64   `json:"blocks"`
   145  		TimeOffset      int64   `json:"timeoffset"`
   146  		Connections     int32   `json:"connections"`
   147  		Proxy           string  `json:"proxy"`
   148  		Difficulty      float64 `json:"difficulty"`
   149  		TestNet         bool    `json:"testnet"`
   150  		RelayFee        float64 `json:"relayfee"`
   151  		Errors          string  `json:"errors"`
   152  	}
   153  }
   154  
   155  type GetBestBlockResult struct {
   156  	Error  Error `json:"error"`
   157  	Result struct {
   158  		Hash   string `json:"hash"`
   159  		Height uint32 `json:"height"`
   160  	} `json:"result"`
   161  }
   162  
   163  type GetBlockHashResult struct {
   164  	Error  Error  `json:"error"`
   165  	Result string `json:"result"`
   166  }
   167  
   168  type GetBlockResult struct {
   169  	Error  Error `json:"error"`
   170  	Result struct {
   171  		Hash          string      `json:"hash"`
   172  		Confirmations int64       `json:"confirmations"`
   173  		Size          int32       `json:"size"`
   174  		Height        uint32      `json:"height"`
   175  		Version       json.Number `json:"version"`
   176  		MerkleRoot    string      `json:"merkleroot"`
   177  		StakeRoot     string      `json:"stakeroot"`
   178  		RawTx         []RawTx     `json:"rawtx"`
   179  		Tx            []string    `json:"tx,omitempty"`
   180  		STx           []string    `json:"stx,omitempty"`
   181  		Time          int64       `json:"time"`
   182  		Nonce         json.Number `json:"nonce"`
   183  		VoteBits      uint16      `json:"votebits"`
   184  		FinalState    string      `json:"finalstate"`
   185  		Voters        uint16      `json:"voters"`
   186  		FreshStake    uint8       `json:"freshstake"`
   187  		Revocations   uint8       `json:"revocations"`
   188  		PoolSize      uint32      `json:"poolsize"`
   189  		Bits          string      `json:"bits"`
   190  		SBits         float64     `json:"sbits"`
   191  		ExtraData     string      `json:"extradata"`
   192  		StakeVersion  uint32      `json:"stakeversion"`
   193  		Difficulty    float64     `json:"difficulty"`
   194  		ChainWork     string      `json:"chainwork"`
   195  		PreviousHash  string      `json:"previousblockhash"`
   196  		NextHash      string      `json:"nextblockhash,omitempty"`
   197  	} `json:"result"`
   198  }
   199  
   200  type GetBlockHeaderResult struct {
   201  	Error  Error `json:"error"`
   202  	Result struct {
   203  		Hash          string      `json:"hash"`
   204  		Confirmations int64       `json:"confirmations"`
   205  		Version       json.Number `json:"version"`
   206  		MerkleRoot    string      `json:"merkleroot"`
   207  		StakeRoot     string      `json:"stakeroot"`
   208  		VoteBits      uint16      `json:"votebits"`
   209  		FinalState    string      `json:"finalstate"`
   210  		Voters        uint16      `json:"voters"`
   211  		FreshStake    uint8       `json:"freshstake"`
   212  		Revocations   uint8       `json:"revocations"`
   213  		PoolSize      uint32      `json:"poolsize"`
   214  		Bits          string      `json:"bits"`
   215  		SBits         float64     `json:"sbits"`
   216  		Height        uint32      `json:"height"`
   217  		Size          uint32      `json:"size"`
   218  		Time          int64       `json:"time"`
   219  		Nonce         uint32      `json:"nonce"`
   220  		ExtraData     string      `json:"extradata"`
   221  		StakeVersion  uint32      `json:"stakeversion"`
   222  		Difficulty    float64     `json:"difficulty"`
   223  		ChainWork     string      `json:"chainwork"`
   224  		PreviousHash  string      `json:"previousblockhash,omitempty"`
   225  		NextHash      string      `json:"nextblockhash,omitempty"`
   226  	} `json:"result"`
   227  }
   228  
   229  type ScriptSig struct {
   230  	Asm string `json:"asm"`
   231  	Hex string `json:"hex"`
   232  }
   233  
   234  type Vin struct {
   235  	Coinbase    string     `json:"coinbase"`
   236  	Stakebase   string     `json:"stakebase"`
   237  	Txid        string     `json:"txid"`
   238  	Vout        uint32     `json:"vout"`
   239  	Tree        int8       `json:"tree"`
   240  	Sequence    uint32     `json:"sequence"`
   241  	AmountIn    float64    `json:"amountin"`
   242  	BlockHeight uint32     `json:"blockheight"`
   243  	BlockIndex  uint32     `json:"blockindex"`
   244  	ScriptSig   *ScriptSig `json:"scriptsig"`
   245  }
   246  
   247  type ScriptPubKeyResult struct {
   248  	Asm       string   `json:"asm"`
   249  	Hex       string   `json:"hex,omitempty"`
   250  	ReqSigs   int32    `json:"reqSigs,omitempty"`
   251  	Type      string   `json:"type"`
   252  	Addresses []string `json:"addresses,omitempty"`
   253  	CommitAmt *float64 `json:"commitamt,omitempty"`
   254  }
   255  
   256  type Vout struct {
   257  	Value        float64            `json:"value"`
   258  	N            uint32             `json:"n"`
   259  	Version      uint16             `json:"version"`
   260  	ScriptPubKey ScriptPubKeyResult `json:"scriptPubKey"`
   261  }
   262  
   263  type RawTx struct {
   264  	Hex           string `json:"hex"`
   265  	Txid          string `json:"txid"`
   266  	Version       int32  `json:"version"`
   267  	LockTime      uint32 `json:"locktime"`
   268  	Vin           []Vin  `json:"vin"`
   269  	Vout          []Vout `json:"vout"`
   270  	Expiry        uint32 `json:"expiry"`
   271  	BlockIndex    uint32 `json:"blockindex,omitempty"`
   272  	Confirmations int64  `json:"confirmations,omitempty"`
   273  	Time          int64  `json:"time,omitempty"`
   274  	Blocktime     int64  `json:"blocktime,omitempty"`
   275  	TxExtraInfo
   276  }
   277  
   278  type GetTransactionResult struct {
   279  	Error  Error `json:"error"`
   280  	Result struct {
   281  		RawTx
   282  	} `json:"result"`
   283  }
   284  
   285  type MempoolTxsResult struct {
   286  	Error  Error    `json:"error"`
   287  	Result []string `json:"result"`
   288  }
   289  
   290  type EstimateSmartFeeResult struct {
   291  	Error  Error `json:"error"`
   292  	Result struct {
   293  		FeeRate float64  `json:"feerate"`
   294  		Errors  []string `json:"errors"`
   295  		Blocks  int64    `json:"blocks"`
   296  	} `json:"result"`
   297  }
   298  
   299  type EstimateFeeResult struct {
   300  	Error  Error       `json:"error"`
   301  	Result json.Number `json:"result"`
   302  }
   303  
   304  type SendRawTransactionResult struct {
   305  	Error  Error  `json:"error"`
   306  	Result string `json:"result"`
   307  }
   308  
   309  type DecodeRawTransactionResult struct {
   310  	Error  Error `json:"error"`
   311  	Result struct {
   312  		Txid     string `json:"txid"`
   313  		Version  int32  `json:"version"`
   314  		Locktime uint32 `json:"locktime"`
   315  		Expiry   uint32 `json:"expiry"`
   316  		Vin      []Vin  `json:"vin"`
   317  		Vout     []Vout `json:"vout"`
   318  		TxExtraInfo
   319  	} `json:"result"`
   320  }
   321  
   322  type TxExtraInfo struct {
   323  	BlockHeight uint32 `json:"blockheight,omitempty"`
   324  	BlockHash   string `json:"blockhash,omitempty"`
   325  }
   326  
   327  func (d *DecredRPC) GetChainInfo() (*bchain.ChainInfo, error) {
   328  	blockchainInfoRequest := GenericCmd{
   329  		ID:     1,
   330  		Method: "getblockchaininfo",
   331  	}
   332  
   333  	var blockchainInfoResult GetBlockChainInfoResult
   334  	if err := d.Call(blockchainInfoRequest, &blockchainInfoResult); err != nil {
   335  		return nil, err
   336  	}
   337  
   338  	if blockchainInfoResult.Error.Message != "" {
   339  		return nil, mapToStandardErr("Error fetching blockchain info: %s", blockchainInfoResult.Error)
   340  	}
   341  
   342  	infoChainRequest := GenericCmd{
   343  		ID:     2,
   344  		Method: "getinfo",
   345  	}
   346  
   347  	var infoChainResult GetInfoChainResult
   348  	if err := d.Call(infoChainRequest, &infoChainResult); err != nil {
   349  		return nil, err
   350  	}
   351  
   352  	if infoChainResult.Error.Message != "" {
   353  		return nil, mapToStandardErr("Error fetching network info: %s", infoChainResult.Error)
   354  	}
   355  
   356  	chainInfo := &bchain.ChainInfo{
   357  		Chain:           blockchainInfoResult.Result.Chain,
   358  		Blocks:          int(blockchainInfoResult.Result.Blocks),
   359  		Headers:         int(blockchainInfoResult.Result.Headers),
   360  		Bestblockhash:   blockchainInfoResult.Result.BestBlockHash,
   361  		Difficulty:      strconv.Itoa(int(blockchainInfoResult.Result.Difficulty)),
   362  		SizeOnDisk:      blockchainInfoResult.Result.SyncHeight,
   363  		Version:         strconv.Itoa(int(infoChainResult.Result.Version)),
   364  		Subversion:      "",
   365  		ProtocolVersion: strconv.Itoa(int(infoChainResult.Result.ProtocolVersion)),
   366  		Timeoffset:      float64(infoChainResult.Result.TimeOffset),
   367  		Warnings:        "",
   368  	}
   369  	return chainInfo, nil
   370  }
   371  
   372  // getChainBestBlock returns the best block according to dcrd chain. This block
   373  // has no atleast one confirming block.
   374  func (d *DecredRPC) getChainBestBlock() (*GetBestBlockResult, error) {
   375  	bestBlockRequest := GenericCmd{
   376  		ID:     1,
   377  		Method: "getbestblock",
   378  	}
   379  
   380  	var bestBlockResult GetBestBlockResult
   381  	if err := d.Call(bestBlockRequest, &bestBlockResult); err != nil {
   382  		return nil, err
   383  	}
   384  
   385  	if bestBlockResult.Error.Message != "" {
   386  		return nil, mapToStandardErr("Error fetching best block: %s", bestBlockResult.Error)
   387  	}
   388  
   389  	return &bestBlockResult, nil
   390  }
   391  
   392  // getBestBlock returns details for the block mined immediately before the
   393  // official dcrd chain's bestblock i.e. it has a minimum of 1 confirmation.
   394  // The chain's best block is not returned as its block validity is not guarranteed.
   395  func (d *DecredRPC) getBestBlock() (*GetBestBlockResult, error) {
   396  	bestBlockResult, err := d.getChainBestBlock()
   397  	if err != nil {
   398  		return nil, err
   399  	}
   400  
   401  	// remove the block with less than 1 confirming block
   402  	bestBlockResult.Result.Height--
   403  	validBlockHash, err := d.getBlockHashByHeight(bestBlockResult.Result.Height)
   404  	if err != nil {
   405  		return nil, err
   406  	}
   407  
   408  	bestBlockResult.Result.Hash = validBlockHash.Result
   409  
   410  	return bestBlockResult, nil
   411  }
   412  
   413  // GetBestBlockHash returns the block hash of the most recent block to be mined
   414  // and has a minimum of 1 confirming block.
   415  func (d *DecredRPC) GetBestBlockHash() (string, error) {
   416  	bestBlock, err := d.getBestBlock()
   417  	if err != nil {
   418  		return "", err
   419  	}
   420  
   421  	return bestBlock.Result.Hash, nil
   422  }
   423  
   424  // GetBestBlockHeight returns the block height of the most recent block to be mined
   425  // and has a minimum of 1 confirming block.
   426  func (d *DecredRPC) GetBestBlockHeight() (uint32, error) {
   427  	bestBlock, err := d.getBestBlock()
   428  	if err != nil {
   429  		return 0, err
   430  	}
   431  
   432  	return uint32(bestBlock.Result.Height), err
   433  }
   434  
   435  // GetBlockHash returns the block hash of the block at the provided height.
   436  func (d *DecredRPC) GetBlockHash(height uint32) (string, error) {
   437  	blockHashResult, err := d.getBlockHashByHeight(height)
   438  	if err != nil {
   439  		return "", err
   440  	}
   441  
   442  	return blockHashResult.Result, nil
   443  }
   444  
   445  func (d *DecredRPC) getBlockHashByHeight(height uint32) (*GetBlockHashResult, error) {
   446  	blockHashRequest := GenericCmd{
   447  		ID:     1,
   448  		Method: "getblockhash",
   449  		Params: []interface{}{height},
   450  	}
   451  
   452  	var blockHashResult GetBlockHashResult
   453  	if err := d.Call(blockHashRequest, &blockHashResult); err != nil {
   454  		return nil, err
   455  	}
   456  
   457  	if blockHashResult.Error.Message != "" {
   458  		return nil, mapToStandardErr("Error fetching block hash: %s", blockHashResult.Error)
   459  	}
   460  
   461  	return &blockHashResult, nil
   462  }
   463  
   464  // GetBlockHeader returns the block header of the block the provided block hash.
   465  func (d *DecredRPC) GetBlockHeader(hash string) (*bchain.BlockHeader, error) {
   466  	blockHeaderRequest := GenericCmd{
   467  		ID:     1,
   468  		Method: "getblockheader",
   469  		Params: []interface{}{hash},
   470  	}
   471  
   472  	var blockHeader GetBlockHeaderResult
   473  	if err := d.Call(blockHeaderRequest, &blockHeader); err != nil {
   474  		return nil, err
   475  	}
   476  
   477  	if blockHeader.Error.Message != "" {
   478  		return nil, mapToStandardErr("Error fetching block info: %s", blockHeader.Error)
   479  	}
   480  
   481  	header := &bchain.BlockHeader{
   482  		Hash:          blockHeader.Result.Hash,
   483  		Prev:          blockHeader.Result.PreviousHash,
   484  		Next:          blockHeader.Result.NextHash,
   485  		Height:        blockHeader.Result.Height,
   486  		Confirmations: int(blockHeader.Result.Confirmations),
   487  		Size:          int(blockHeader.Result.Size),
   488  		Time:          blockHeader.Result.Time,
   489  	}
   490  
   491  	return header, nil
   492  }
   493  
   494  // GetBlock returns the block retrieved using the provided block hash by default
   495  // or using the block height if an empty hash string was provided. If the
   496  // requested block has less than 2 confirmation bchain.ErrBlockNotFound error
   497  // is returned. This rule is in places to guarrantee that only validated block
   498  // details (txs) are saved to the db. Access to the bestBlock height is threadsafe.
   499  func (d *DecredRPC) GetBlock(hash string, height uint32) (*bchain.Block, error) {
   500  	// Confirm if the block at provided height has at least 2 confirming blocks.
   501  	d.mtx.Lock()
   502  	if height > d.bestBlock {
   503  		bestBlock, err := d.getBestBlock()
   504  		if err != nil || height > bestBlock.Result.Height {
   505  			// If an error occurred or the current height doesn't have a minimum
   506  			// of two confirming blocks (greater than best block), quit.
   507  			d.mtx.Unlock()
   508  			return nil, bchain.ErrBlockNotFound
   509  		}
   510  
   511  		d.bestBlock = bestBlock.Result.Height
   512  	}
   513  	d.mtx.Unlock() // Releases the lock soonest possible
   514  
   515  	if hash == "" {
   516  		getHashResult, err := d.getBlockHashByHeight(height)
   517  		if err != nil {
   518  			return nil, err
   519  		}
   520  		hash = getHashResult.Result
   521  	}
   522  
   523  	block, err := d.getBlock(hash)
   524  	if err != nil {
   525  		return nil, err
   526  	}
   527  
   528  	header := bchain.BlockHeader{
   529  		Hash:          block.Result.Hash,
   530  		Prev:          block.Result.PreviousHash,
   531  		Next:          block.Result.NextHash,
   532  		Height:        block.Result.Height,
   533  		Confirmations: int(block.Result.Confirmations),
   534  		Size:          int(block.Result.Size),
   535  		Time:          block.Result.Time,
   536  	}
   537  
   538  	bchainBlock := &bchain.Block{BlockHeader: header}
   539  
   540  	// Check the current block validity by fetch the next block
   541  	nextBlockHashResult, err := d.getBlockHashByHeight(height + 1)
   542  	if err != nil {
   543  		return nil, err
   544  	}
   545  
   546  	nextBlock, err := d.getBlock(nextBlockHashResult.Result)
   547  	if err != nil {
   548  		return nil, err
   549  	}
   550  
   551  	// If the Votesbits set equals to voteBitYes append the regular transactions.
   552  	if nextBlock.Result.VoteBits == voteBitYes {
   553  		for _, txID := range block.Result.Tx {
   554  			if block.Result.Height == 0 {
   555  				continue
   556  			}
   557  
   558  			tx, err := d.GetTransaction(txID)
   559  			if err != nil {
   560  				return nil, err
   561  			}
   562  
   563  			bchainBlock.Txs = append(bchainBlock.Txs, *tx)
   564  		}
   565  	}
   566  
   567  	return bchainBlock, nil
   568  }
   569  
   570  func (d *DecredRPC) getBlock(hash string) (*GetBlockResult, error) {
   571  	blockRequest := GenericCmd{
   572  		ID:     1,
   573  		Method: "getblock",
   574  		Params: []interface{}{hash},
   575  	}
   576  
   577  	var block GetBlockResult
   578  	if err := d.Call(blockRequest, &block); err != nil {
   579  		return nil, err
   580  	}
   581  
   582  	if block.Error.Message != "" {
   583  		return nil, mapToStandardErr("Error fetching block info: %s", block.Error)
   584  	}
   585  
   586  	return &block, nil
   587  }
   588  
   589  func (d *DecredRPC) decodeRawTransaction(txHex string) (*bchain.Tx, error) {
   590  	decodeRawTxRequest := GenericCmd{
   591  		ID:     1,
   592  		Method: "decoderawtransaction",
   593  		Params: []interface{}{txHex},
   594  	}
   595  
   596  	var decodeRawTxResult DecodeRawTransactionResult
   597  	if err := d.Call(decodeRawTxRequest, &decodeRawTxResult); err != nil {
   598  		return nil, err
   599  	}
   600  
   601  	if decodeRawTxResult.Error.Message != "" {
   602  		return nil, mapToStandardErr("Error decoding raw tx: %s", decodeRawTxResult.Error)
   603  	}
   604  
   605  	tx := &bchain.Tx{
   606  		Hex:      txHex,
   607  		Txid:     decodeRawTxResult.Result.Txid,
   608  		Version:  decodeRawTxResult.Result.Version,
   609  		LockTime: decodeRawTxResult.Result.Locktime,
   610  	}
   611  
   612  	// Add block height and block hash info
   613  	tx.CoinSpecificData = decodeRawTxResult.Result.TxExtraInfo
   614  
   615  	return tx, nil
   616  }
   617  
   618  func (d *DecredRPC) GetBlockInfo(hash string) (*bchain.BlockInfo, error) {
   619  	block, err := d.getBlock(hash)
   620  	if err != nil {
   621  		return nil, err
   622  	}
   623  
   624  	header := bchain.BlockHeader{
   625  		Hash:          block.Result.Hash,
   626  		Prev:          block.Result.PreviousHash,
   627  		Next:          block.Result.NextHash,
   628  		Height:        block.Result.Height,
   629  		Confirmations: int(block.Result.Confirmations),
   630  		Size:          int(block.Result.Size),
   631  		Time:          int64(block.Result.Time),
   632  	}
   633  
   634  	bInfo := &bchain.BlockInfo{
   635  		BlockHeader: header,
   636  		MerkleRoot:  block.Result.MerkleRoot,
   637  		Version:     block.Result.Version,
   638  		Nonce:       block.Result.Nonce,
   639  		Bits:        block.Result.Bits,
   640  		Difficulty:  json.Number(strconv.FormatFloat(block.Result.Difficulty, 'e', -1, 64)),
   641  		Txids:       block.Result.Tx,
   642  	}
   643  
   644  	return bInfo, nil
   645  }
   646  
   647  // GetTransaction returns a transaction by the transaction ID
   648  func (d *DecredRPC) GetTransaction(txid string) (*bchain.Tx, error) {
   649  	r, err := d.getRawTransaction(txid)
   650  	if err != nil {
   651  		return nil, err
   652  	}
   653  
   654  	tx, err := d.Parser.ParseTxFromJson(r)
   655  	if err != nil {
   656  		return nil, errors.Annotatef(err, "txid %v", txid)
   657  	}
   658  
   659  	return tx, nil
   660  }
   661  
   662  // getRawTransaction returns json as returned by backend, with all coin specific data
   663  func (d *DecredRPC) getRawTransaction(txid string) (json.RawMessage, error) {
   664  	if txid == "" {
   665  		return nil, bchain.ErrTxidMissing
   666  	}
   667  
   668  	verbose := 1
   669  	getTxRequest := GenericCmd{
   670  		ID:     1,
   671  		Method: "getrawtransaction",
   672  		Params: []interface{}{txid, &verbose},
   673  	}
   674  
   675  	var getTxResult GetTransactionResult
   676  	if err := d.Call(getTxRequest, &getTxResult); err != nil {
   677  		return nil, err
   678  	}
   679  
   680  	if getTxResult.Error.Message != "" {
   681  		return nil, mapToStandardErr("Error fetching transaction: %s", getTxResult.Error)
   682  	}
   683  
   684  	bytes, err := json.Marshal(getTxResult.Result)
   685  	if err != nil {
   686  		return nil, errors.Annotatef(err, "txid %v", txid)
   687  	}
   688  
   689  	return json.RawMessage(bytes), nil
   690  }
   691  
   692  // GetTransactionForMempool returns the full tx information identified by the
   693  // provided txid.
   694  func (d *DecredRPC) GetTransactionForMempool(txid string) (*bchain.Tx, error) {
   695  	return d.GetTransaction(txid)
   696  }
   697  
   698  // GetMempoolTransactions returns a slice of regular transactions currently in
   699  // the mempool. The block whose validation is still undecided will have its txs,
   700  // listed like they are still in the mempool till the block is confirmed.
   701  func (d *DecredRPC) GetMempoolTransactions() ([]string, error) {
   702  	verbose := false
   703  	txType := "regular"
   704  	mempoolRequest := GenericCmd{
   705  		ID:     1,
   706  		Method: "getrawmempool",
   707  		Params: []interface{}{&verbose, &txType},
   708  	}
   709  
   710  	var mempool MempoolTxsResult
   711  	if err := d.Call(mempoolRequest, &mempool); err != nil {
   712  		return []string{}, err
   713  	}
   714  
   715  	if mempool.Error.Message != "" {
   716  		return nil, mapToStandardErr("Error fetching mempool data: %s", mempool.Error)
   717  	}
   718  
   719  	unvalidatedBlockResult, err := d.getChainBestBlock()
   720  	if err != nil {
   721  		return nil, err
   722  	}
   723  
   724  	unvalidatedBlock, err := d.getBlock(unvalidatedBlockResult.Result.Hash)
   725  	if err != nil {
   726  		return nil, err
   727  	}
   728  
   729  	mempool.Result = append(mempool.Result, unvalidatedBlock.Result.Tx...)
   730  
   731  	return mempool.Result, nil
   732  }
   733  
   734  // GetTransactionSpecific returns the json raw message for the tx identified by
   735  // the provided txid.
   736  func (d *DecredRPC) GetTransactionSpecific(tx *bchain.Tx) (json.RawMessage, error) {
   737  	return d.getRawTransaction(tx.Txid)
   738  }
   739  
   740  // EstimateSmartFee returns fee estimation
   741  func (d *DecredRPC) EstimateSmartFee(blocks int, conservative bool) (big.Int, error) {
   742  	estimateSmartFeeRequest := GenericCmd{
   743  		ID:     1,
   744  		Method: "estimatesmartfee",
   745  		Params: []interface{}{blocks},
   746  	}
   747  
   748  	var smartFeeEstimate EstimateSmartFeeResult
   749  	if err := d.Call(estimateSmartFeeRequest, &smartFeeEstimate); err != nil {
   750  		return *big.NewInt(0), err
   751  	}
   752  
   753  	if smartFeeEstimate.Error.Message != "" {
   754  		return *big.NewInt(0), mapToStandardErr("Error fetching smart fee estimate: %s", smartFeeEstimate.Error)
   755  	}
   756  
   757  	return *big.NewInt(int64(smartFeeEstimate.Result.FeeRate)), nil
   758  }
   759  
   760  // EstimateFee returns fee estimation.
   761  func (d *DecredRPC) EstimateFee(blocks int) (big.Int, error) {
   762  	estimateFeeRequest := GenericCmd{
   763  		ID:     1,
   764  		Method: "estimatefee",
   765  		Params: []interface{}{blocks},
   766  	}
   767  
   768  	var feeEstimate EstimateFeeResult
   769  	if err := d.Call(estimateFeeRequest, &feeEstimate); err != nil {
   770  		return *big.NewInt(0), err
   771  	}
   772  
   773  	if feeEstimate.Error.Message != "" {
   774  		return *big.NewInt(0), mapToStandardErr("Error fetching fee estimate: %s", feeEstimate.Error)
   775  	}
   776  
   777  	r, err := d.Parser.AmountToBigInt(feeEstimate.Result)
   778  	if err != nil {
   779  		return r, err
   780  	}
   781  
   782  	return r, nil
   783  }
   784  
   785  func (d *DecredRPC) SendRawTransaction(tx string) (string, error) {
   786  	sendRawTxRequest := &GenericCmd{
   787  		ID:     1,
   788  		Method: "sendrawtransaction",
   789  		Params: []interface{}{tx},
   790  	}
   791  
   792  	var sendRawTxResult SendRawTransactionResult
   793  	err := d.Call(sendRawTxRequest, &sendRawTxResult)
   794  	if err != nil {
   795  		return "", err
   796  	}
   797  
   798  	if sendRawTxResult.Error.Message != "" {
   799  		return "", mapToStandardErr("error sending raw transaction: %s", sendRawTxResult.Error)
   800  	}
   801  
   802  	return sendRawTxResult.Result, nil
   803  }
   804  
   805  // Call calls Backend RPC interface, using RPCMarshaler interface to marshall the request
   806  func (d *DecredRPC) Call(req interface{}, res interface{}) error {
   807  	httpData, err := json.Marshal(req)
   808  	if err != nil {
   809  		return err
   810  	}
   811  
   812  	httpReq, err := http.NewRequest("POST", d.rpcURL, bytes.NewBuffer(httpData))
   813  	if err != nil {
   814  		return err
   815  	}
   816  	httpReq.SetBasicAuth(d.rpcUser, d.rpcPassword)
   817  	httpRes, err := d.client.Do(httpReq)
   818  	// in some cases the httpRes can contain data even if it returns error
   819  	// see http://devs.cloudimmunity.com/gotchas-and-common-mistakes-in-go-golang/
   820  	if httpRes != nil {
   821  		defer httpRes.Body.Close()
   822  	}
   823  	if err != nil {
   824  		return err
   825  	}
   826  
   827  	// if server returns HTTP error code it might not return json with response
   828  	// handle both cases
   829  	if httpRes.StatusCode != 200 {
   830  		if err = safeDecodeResponse(httpRes.Body, &res); err != nil {
   831  			return errors.Errorf("%v %v", httpRes.Status, err)
   832  		}
   833  		return nil
   834  	}
   835  	return safeDecodeResponse(httpRes.Body, &res)
   836  }
   837  
   838  func safeDecodeResponse(body io.ReadCloser, res *interface{}) (err error) {
   839  	var data []byte
   840  	defer func() {
   841  		if r := recover(); r != nil {
   842  			glog.Error("unmarshal json recovered from panic: ", r, "; data: ", string(data))
   843  			debug.PrintStack()
   844  			if len(data) > 0 && len(data) < 2048 {
   845  				err = errors.Errorf("Error: %v", string(data))
   846  			} else {
   847  				err = errors.New("Internal error")
   848  			}
   849  		}
   850  	}()
   851  	data, err = ioutil.ReadAll(body)
   852  	if err != nil {
   853  		return err
   854  	}
   855  
   856  	error := json.Unmarshal(data, res)
   857  	return error
   858  }
   859  
   860  // mapToStandardErr map the dcrd API Message errors to the standard error messages
   861  // supported by trezor. Dcrd errors to be mapped are listed here:
   862  // https://github.com/decred/dcrd/blob/2f5e47371263b996bb99e8dc3484f659309bd83a/dcrjson/jsonerr.go
   863  func mapToStandardErr(customPrefix string, err Error) error {
   864  	switch {
   865  	case strings.Contains(err.Message, dcrjson.ErrBlockNotFound.Message) || // Block not found
   866  		strings.Contains(err.Message, dcrjson.ErrOutOfRange.Message) || // Block number out of range
   867  		strings.Contains(err.Message, dcrjson.ErrBestBlockHash.Message): // Error getting best block hash
   868  		return bchain.ErrBlockNotFound
   869  	case strings.Contains(err.Message, dcrjson.ErrNoTxInfo.Message): // No information available about transaction
   870  		return bchain.ErrTxNotFound
   871  	case strings.Contains(err.Message, dcrjson.ErrInvalidTxVout.Message): // Output index number (vout) does not exist for transaction
   872  		return bchain.ErrTxidMissing
   873  	default:
   874  		return fmt.Errorf(customPrefix, err.Message)
   875  	}
   876  }