github.com/bchainhub/blockbook@v0.3.2/bchain/coins/divi/diviparser.go (about)

     1  package divi
     2  
     3  import (
     4  	"blockbook/bchain"
     5  	"blockbook/bchain/coins/btc"
     6  	"blockbook/bchain/coins/utils"
     7  	"bytes"
     8  	"io"
     9  
    10  	"encoding/hex"
    11  	"encoding/json"
    12  
    13  	"math/big"
    14  
    15  	"github.com/juju/errors"
    16  	"github.com/martinboehm/btcd/wire"
    17  	"github.com/martinboehm/btcutil/chaincfg"
    18  )
    19  
    20  const (
    21  	// MainnetMagic = "network messages so the messages can be identified to belong to a specific coin"
    22  	// Source https://github.com/DiviProject/Divi/blob/master0/divi/src/chainparams.cpp#L128-L136
    23  	MainnetMagic wire.BitcoinNet = 0x8f8da0df
    24  )
    25  
    26  var (
    27  	// MainNetParams = ???
    28  	MainNetParams chaincfg.Params
    29  )
    30  
    31  func init() {
    32  	// DIVI mainnet Address encoding magics
    33  	MainNetParams = chaincfg.MainNetParams
    34  	MainNetParams.Net = MainnetMagic
    35  	MainNetParams.PubKeyHashAddrID = []byte{30} // starting with 'D'
    36  	MainNetParams.ScriptHashAddrID = []byte{13}
    37  	MainNetParams.PrivateKeyID = []byte{212}
    38  }
    39  
    40  // DivicoinParser handle
    41  type DivicoinParser struct {
    42  	*btc.BitcoinParser
    43  	baseparser                         *bchain.BaseParser
    44  	BitcoinOutputScriptToAddressesFunc btc.OutputScriptToAddressesFunc
    45  }
    46  
    47  // NewDiviParser returns new DivicoinParser instance
    48  func NewDiviParser(params *chaincfg.Params, c *btc.Configuration) *DivicoinParser {
    49  	p := &DivicoinParser{
    50  		BitcoinParser: btc.NewBitcoinParser(params, c),
    51  		baseparser:    &bchain.BaseParser{},
    52  	}
    53  	p.BitcoinOutputScriptToAddressesFunc = p.OutputScriptToAddressesFunc
    54  	p.OutputScriptToAddressesFunc = p.outputScriptToAddresses
    55  	return p
    56  }
    57  
    58  // GetChainParams contains network parameters for the main Divi network
    59  func GetChainParams(chain string) *chaincfg.Params {
    60  	if !chaincfg.IsRegistered(&MainNetParams) {
    61  		err := chaincfg.Register(&MainNetParams)
    62  		/*if err == nil {
    63  			err = chaincfg.Register(&TestNetParams)
    64  		}*/
    65  		if err != nil {
    66  			panic(err)
    67  		}
    68  	} /*
    69  		switch chain {
    70  		case "test":
    71  			return &TestNetParams
    72  		default:
    73  	*/return &MainNetParams
    74  	//}
    75  }
    76  
    77  // ParseBlock parses raw block to our Block struct
    78  func (p *DivicoinParser) ParseBlock(b []byte) (*bchain.Block, error) {
    79  	r := bytes.NewReader(b)
    80  	w := wire.MsgBlock{}
    81  	h := wire.BlockHeader{}
    82  	err := h.Deserialize(r)
    83  	if err != nil {
    84  		return nil, errors.Annotatef(err, "Deserialize")
    85  	}
    86  
    87  	if h.Version > 3 {
    88  		// Skip past AccumulatorCheckpoint which was added in pivx block version 4
    89  		r.Seek(32, io.SeekCurrent)
    90  	}
    91  
    92  	err = utils.DecodeTransactions(r, 0, wire.WitnessEncoding, &w)
    93  	if err != nil {
    94  		return nil, errors.Annotatef(err, "DecodeTransactions")
    95  	}
    96  
    97  	txs := make([]bchain.Tx, len(w.Transactions))
    98  	for ti, t := range w.Transactions {
    99  		txs[ti] = p.TxFromMsgTx(t, false)
   100  	}
   101  
   102  	return &bchain.Block{
   103  		BlockHeader: bchain.BlockHeader{
   104  			Size: len(b),
   105  			Time: h.Timestamp.Unix(),
   106  		},
   107  		Txs: txs,
   108  	}, nil
   109  }
   110  
   111  // PackTx packs transaction to byte array using protobuf
   112  func (p *DivicoinParser) PackTx(tx *bchain.Tx, height uint32, blockTime int64) ([]byte, error) {
   113  	return p.baseparser.PackTx(tx, height, blockTime)
   114  }
   115  
   116  // UnpackTx unpacks transaction from protobuf byte array
   117  func (p *DivicoinParser) UnpackTx(buf []byte) (*bchain.Tx, uint32, error) {
   118  	return p.baseparser.UnpackTx(buf)
   119  }
   120  
   121  // ParseTx parses byte array containing transaction and returns Tx struct
   122  func (p *DivicoinParser) ParseTx(b []byte) (*bchain.Tx, error) {
   123  	t := wire.MsgTx{}
   124  	r := bytes.NewReader(b)
   125  	if err := t.Deserialize(r); err != nil {
   126  		return nil, err
   127  	}
   128  	tx := p.TxFromMsgTx(&t, true)
   129  	tx.Hex = hex.EncodeToString(b)
   130  	return &tx, nil
   131  }
   132  
   133  // TxFromMsgTx parses tx and adds handling for OP_ZEROCOINSPEND inputs
   134  func (p *DivicoinParser) TxFromMsgTx(t *wire.MsgTx, parseAddresses bool) bchain.Tx {
   135  	vin := make([]bchain.Vin, len(t.TxIn))
   136  	for i, in := range t.TxIn {
   137  		s := bchain.ScriptSig{
   138  			Hex: hex.EncodeToString(in.SignatureScript),
   139  			// missing: Asm,
   140  		}
   141  
   142  		txid := in.PreviousOutPoint.Hash.String()
   143  
   144  		vin[i] = bchain.Vin{
   145  			Txid:      txid,
   146  			Vout:      in.PreviousOutPoint.Index,
   147  			Sequence:  in.Sequence,
   148  			ScriptSig: s,
   149  		}
   150  	}
   151  	vout := make([]bchain.Vout, len(t.TxOut))
   152  	for i, out := range t.TxOut {
   153  		addrs := []string{}
   154  		if parseAddresses {
   155  			addrs, _, _ = p.OutputScriptToAddressesFunc(out.PkScript)
   156  		}
   157  		s := bchain.ScriptPubKey{
   158  			Hex:       hex.EncodeToString(out.PkScript),
   159  			Addresses: addrs,
   160  			// missing: Asm,
   161  			// missing: Type,
   162  		}
   163  		var vs big.Int
   164  		vs.SetInt64(out.Value)
   165  		vout[i] = bchain.Vout{
   166  			ValueSat:     vs,
   167  			N:            uint32(i),
   168  			ScriptPubKey: s,
   169  		}
   170  	}
   171  	tx := bchain.Tx{
   172  		Txid:     t.TxHash().String(),
   173  		Version:  t.Version,
   174  		LockTime: t.LockTime,
   175  		Vin:      vin,
   176  		Vout:     vout,
   177  		// skip: BlockHash,
   178  		// skip: Confirmations,
   179  		// skip: Time,
   180  		// skip: Blocktime,
   181  	}
   182  	return tx
   183  }
   184  
   185  // ParseTxFromJSON parses JSON message containing transaction and returns Tx struct
   186  func (p *DivicoinParser) ParseTxFromJSON(msg json.RawMessage) (*bchain.Tx, error) {
   187  	var tx bchain.Tx
   188  	err := json.Unmarshal(msg, &tx)
   189  	if err != nil {
   190  		return nil, err
   191  	}
   192  
   193  	for i := range tx.Vout {
   194  		vout := &tx.Vout[i]
   195  		// convert vout.JsonValue to big.Int and clear it, it is only temporary value used for unmarshal
   196  		vout.ValueSat, err = p.AmountToBigInt(vout.JsonValue)
   197  		if err != nil {
   198  			return nil, err
   199  		}
   200  		vout.JsonValue = ""
   201  
   202  		if vout.ScriptPubKey.Addresses == nil {
   203  			vout.ScriptPubKey.Addresses = []string{}
   204  		}
   205  	}
   206  
   207  	return &tx, nil
   208  }
   209  
   210  // outputScriptToAddresses converts ScriptPubKey to bitcoin addresses
   211  func (p *DivicoinParser) outputScriptToAddresses(script []byte) ([]string, bool, error) {
   212  	rv, s, _ := p.BitcoinOutputScriptToAddressesFunc(script)
   213  	return rv, s, nil
   214  }
   215  
   216  // GetAddrDescForUnknownInput = ???
   217  func (p *DivicoinParser) GetAddrDescForUnknownInput(tx *bchain.Tx, input int) bchain.AddressDescriptor {
   218  	if len(tx.Vin) > input {
   219  		scriptHex := tx.Vin[input].ScriptSig.Hex
   220  
   221  		if scriptHex != "" {
   222  			script, _ := hex.DecodeString(scriptHex)
   223  			return script
   224  		}
   225  	}
   226  
   227  	s := make([]byte, 10)
   228  	return s
   229  }