github.com/jackcoble/blockbook@v0.3.2/bchain/baseparser.go (about)

     1  package bchain
     2  
     3  import (
     4  	"encoding/hex"
     5  	"encoding/json"
     6  	"math/big"
     7  	"strings"
     8  
     9  	"github.com/gogo/protobuf/proto"
    10  	"github.com/golang/glog"
    11  	"github.com/juju/errors"
    12  )
    13  
    14  // BaseParser implements data parsing/handling functionality base for all other parsers
    15  type BaseParser struct {
    16  	BlockAddressesToKeep int
    17  	AmountDecimalPoint   int
    18  }
    19  
    20  // ParseBlock parses raw block to our Block struct - currently not implemented
    21  func (p *BaseParser) ParseBlock(b []byte) (*Block, error) {
    22  	return nil, errors.New("ParseBlock: not implemented")
    23  }
    24  
    25  // ParseTx parses byte array containing transaction and returns Tx struct - currently not implemented
    26  func (p *BaseParser) ParseTx(b []byte) (*Tx, error) {
    27  	return nil, errors.New("ParseTx: not implemented")
    28  }
    29  
    30  // GetAddrDescForUnknownInput returns nil AddressDescriptor
    31  func (p *BaseParser) GetAddrDescForUnknownInput(tx *Tx, input int) AddressDescriptor {
    32  	var iTxid string
    33  	if len(tx.Vin) > input {
    34  		iTxid = tx.Vin[input].Txid
    35  	}
    36  	glog.Warningf("tx %v, input tx %v not found in txAddresses", tx.Txid, iTxid)
    37  	return nil
    38  }
    39  
    40  const zeros = "0000000000000000000000000000000000000000"
    41  
    42  // AmountToBigInt converts amount in json.Number (string) to big.Int
    43  // it uses string operations to avoid problems with rounding
    44  func (p *BaseParser) AmountToBigInt(n json.Number) (big.Int, error) {
    45  	var r big.Int
    46  	s := string(n)
    47  	i := strings.IndexByte(s, '.')
    48  	d := p.AmountDecimalPoint
    49  	if d > len(zeros) {
    50  		d = len(zeros)
    51  	}
    52  	if i == -1 {
    53  		s = s + zeros[:d]
    54  	} else {
    55  		z := d - len(s) + i + 1
    56  		if z > 0 {
    57  			s = s[:i] + s[i+1:] + zeros[:z]
    58  		} else {
    59  			s = s[:i] + s[i+1:len(s)+z]
    60  		}
    61  	}
    62  	if _, ok := r.SetString(s, 10); !ok {
    63  		return r, errors.New("AmountToBigInt: failed to convert")
    64  	}
    65  	return r, nil
    66  }
    67  
    68  // AmountToDecimalString converts amount in big.Int to string with decimal point in the place defined by the parameter d
    69  func AmountToDecimalString(a *big.Int, d int) string {
    70  	if a == nil {
    71  		return ""
    72  	}
    73  	n := a.String()
    74  	var s string
    75  	if n[0] == '-' {
    76  		n = n[1:]
    77  		s = "-"
    78  	}
    79  	if d > len(zeros) {
    80  		d = len(zeros)
    81  	}
    82  	if len(n) <= d {
    83  		n = zeros[:d-len(n)+1] + n
    84  	}
    85  	i := len(n) - d
    86  	ad := strings.TrimRight(n[i:], "0")
    87  	if len(ad) > 0 {
    88  		n = n[:i] + "." + ad
    89  	} else {
    90  		n = n[:i]
    91  	}
    92  	return s + n
    93  }
    94  
    95  // AmountToDecimalString converts amount in big.Int to string with decimal point in the correct place
    96  func (p *BaseParser) AmountToDecimalString(a *big.Int) string {
    97  	return AmountToDecimalString(a, p.AmountDecimalPoint)
    98  }
    99  
   100  // AmountDecimals returns number of decimal places in amounts
   101  func (p *BaseParser) AmountDecimals() int {
   102  	return p.AmountDecimalPoint
   103  }
   104  
   105  // ParseTxFromJson parses JSON message containing transaction and returns Tx struct
   106  func (p *BaseParser) ParseTxFromJson(msg json.RawMessage) (*Tx, error) {
   107  	var tx Tx
   108  	err := json.Unmarshal(msg, &tx)
   109  	if err != nil {
   110  		return nil, err
   111  	}
   112  
   113  	for i := range tx.Vout {
   114  		vout := &tx.Vout[i]
   115  		// convert vout.JsonValue to big.Int and clear it, it is only temporary value used for unmarshal
   116  		vout.ValueSat, err = p.AmountToBigInt(vout.JsonValue)
   117  		if err != nil {
   118  			return nil, err
   119  		}
   120  		vout.JsonValue = ""
   121  	}
   122  
   123  	return &tx, nil
   124  }
   125  
   126  // PackedTxidLen returns length in bytes of packed txid
   127  func (p *BaseParser) PackedTxidLen() int {
   128  	return 32
   129  }
   130  
   131  // KeepBlockAddresses returns number of blocks which are to be kept in blockaddresses column
   132  func (p *BaseParser) KeepBlockAddresses() int {
   133  	return p.BlockAddressesToKeep
   134  }
   135  
   136  // PackTxid packs txid to byte array
   137  func (p *BaseParser) PackTxid(txid string) ([]byte, error) {
   138  	if txid == "" {
   139  		return nil, ErrTxidMissing
   140  	}
   141  	return hex.DecodeString(txid)
   142  }
   143  
   144  // UnpackTxid unpacks byte array to txid
   145  func (p *BaseParser) UnpackTxid(buf []byte) (string, error) {
   146  	return hex.EncodeToString(buf), nil
   147  }
   148  
   149  // PackBlockHash packs block hash to byte array
   150  func (p *BaseParser) PackBlockHash(hash string) ([]byte, error) {
   151  	return hex.DecodeString(hash)
   152  }
   153  
   154  // UnpackBlockHash unpacks byte array to block hash
   155  func (p *BaseParser) UnpackBlockHash(buf []byte) (string, error) {
   156  	return hex.EncodeToString(buf), nil
   157  }
   158  
   159  // GetChainType is type of the blockchain, default is ChainBitcoinType
   160  func (p *BaseParser) GetChainType() ChainType {
   161  	return ChainBitcoinType
   162  }
   163  
   164  // MinimumCoinbaseConfirmations returns minimum number of confirmations a coinbase transaction must have before it can be spent
   165  func (p *BaseParser) MinimumCoinbaseConfirmations() int {
   166  	return 0
   167  }
   168  
   169  // PackTx packs transaction to byte array using protobuf
   170  func (p *BaseParser) PackTx(tx *Tx, height uint32, blockTime int64) ([]byte, error) {
   171  	var err error
   172  	pti := make([]*ProtoTransaction_VinType, len(tx.Vin))
   173  	for i, vi := range tx.Vin {
   174  		hex, err := hex.DecodeString(vi.ScriptSig.Hex)
   175  		if err != nil {
   176  			return nil, errors.Annotatef(err, "Vin %v Hex %v", i, vi.ScriptSig.Hex)
   177  		}
   178  		// coinbase txs do not have Vin.txid
   179  		itxid, err := p.PackTxid(vi.Txid)
   180  		if err != nil && err != ErrTxidMissing {
   181  			return nil, errors.Annotatef(err, "Vin %v Txid %v", i, vi.Txid)
   182  		}
   183  		pti[i] = &ProtoTransaction_VinType{
   184  			Addresses:    vi.Addresses,
   185  			Coinbase:     vi.Coinbase,
   186  			ScriptSigHex: hex,
   187  			Sequence:     vi.Sequence,
   188  			Txid:         itxid,
   189  			Vout:         vi.Vout,
   190  		}
   191  	}
   192  	pto := make([]*ProtoTransaction_VoutType, len(tx.Vout))
   193  	for i, vo := range tx.Vout {
   194  		hex, err := hex.DecodeString(vo.ScriptPubKey.Hex)
   195  		if err != nil {
   196  			return nil, errors.Annotatef(err, "Vout %v Hex %v", i, vo.ScriptPubKey.Hex)
   197  		}
   198  		pto[i] = &ProtoTransaction_VoutType{
   199  			Addresses:       vo.ScriptPubKey.Addresses,
   200  			N:               vo.N,
   201  			ScriptPubKeyHex: hex,
   202  			ValueSat:        vo.ValueSat.Bytes(),
   203  		}
   204  	}
   205  	pt := &ProtoTransaction{
   206  		Blocktime: uint64(blockTime),
   207  		Height:    height,
   208  		Locktime:  tx.LockTime,
   209  		Vin:       pti,
   210  		Vout:      pto,
   211  		Version:   tx.Version,
   212  	}
   213  	if pt.Hex, err = hex.DecodeString(tx.Hex); err != nil {
   214  		return nil, errors.Annotatef(err, "Hex %v", tx.Hex)
   215  	}
   216  	if pt.Txid, err = p.PackTxid(tx.Txid); err != nil {
   217  		return nil, errors.Annotatef(err, "Txid %v", tx.Txid)
   218  	}
   219  	return proto.Marshal(pt)
   220  }
   221  
   222  // UnpackTx unpacks transaction from protobuf byte array
   223  func (p *BaseParser) UnpackTx(buf []byte) (*Tx, uint32, error) {
   224  	var pt ProtoTransaction
   225  	err := proto.Unmarshal(buf, &pt)
   226  	if err != nil {
   227  		return nil, 0, err
   228  	}
   229  	txid, err := p.UnpackTxid(pt.Txid)
   230  	if err != nil {
   231  		return nil, 0, err
   232  	}
   233  	vin := make([]Vin, len(pt.Vin))
   234  	for i, pti := range pt.Vin {
   235  		itxid, err := p.UnpackTxid(pti.Txid)
   236  		if err != nil {
   237  			return nil, 0, err
   238  		}
   239  		vin[i] = Vin{
   240  			Addresses: pti.Addresses,
   241  			Coinbase:  pti.Coinbase,
   242  			ScriptSig: ScriptSig{
   243  				Hex: hex.EncodeToString(pti.ScriptSigHex),
   244  			},
   245  			Sequence: pti.Sequence,
   246  			Txid:     itxid,
   247  			Vout:     pti.Vout,
   248  		}
   249  	}
   250  	vout := make([]Vout, len(pt.Vout))
   251  	for i, pto := range pt.Vout {
   252  		var vs big.Int
   253  		vs.SetBytes(pto.ValueSat)
   254  		vout[i] = Vout{
   255  			N: pto.N,
   256  			ScriptPubKey: ScriptPubKey{
   257  				Addresses: pto.Addresses,
   258  				Hex:       hex.EncodeToString(pto.ScriptPubKeyHex),
   259  			},
   260  			ValueSat: vs,
   261  		}
   262  	}
   263  	tx := Tx{
   264  		Blocktime: int64(pt.Blocktime),
   265  		Hex:       hex.EncodeToString(pt.Hex),
   266  		LockTime:  pt.Locktime,
   267  		Time:      int64(pt.Blocktime),
   268  		Txid:      txid,
   269  		Vin:       vin,
   270  		Vout:      vout,
   271  		Version:   pt.Version,
   272  	}
   273  	return &tx, pt.Height, nil
   274  }
   275  
   276  // IsAddrDescIndexable returns true if AddressDescriptor should be added to index
   277  // by default all AddressDescriptors are indexable
   278  func (p *BaseParser) IsAddrDescIndexable(addrDesc AddressDescriptor) bool {
   279  	return true
   280  }
   281  
   282  // DerivationBasePath is unsupported
   283  func (p *BaseParser) DerivationBasePath(xpub string) (string, error) {
   284  	return "", errors.New("Not supported")
   285  }
   286  
   287  // DeriveAddressDescriptors is unsupported
   288  func (p *BaseParser) DeriveAddressDescriptors(xpub string, change uint32, indexes []uint32) ([]AddressDescriptor, error) {
   289  	return nil, errors.New("Not supported")
   290  }
   291  
   292  // DeriveAddressDescriptorsFromTo is unsupported
   293  func (p *BaseParser) DeriveAddressDescriptorsFromTo(xpub string, change uint32, fromIndex uint32, toIndex uint32) ([]AddressDescriptor, error) {
   294  	return nil, errors.New("Not supported")
   295  }
   296  
   297  // EthereumTypeGetErc20FromTx is unsupported
   298  func (p *BaseParser) EthereumTypeGetErc20FromTx(tx *Tx) ([]Erc20Transfer, error) {
   299  	return nil, errors.New("Not supported")
   300  }