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

     1  package monetaryunit
     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  	"github.com/juju/errors"
    14  	"github.com/martinboehm/btcd/wire"
    15  	"github.com/martinboehm/btcutil/chaincfg"
    16  )
    17  
    18  const (
    19  	// Net Magics
    20  	MainnetMagic wire.BitcoinNet = 0x91c4fdea
    21  	TestnetMagic wire.BitcoinNet = 0x477665bd
    22  )
    23  
    24  var (
    25  	MainNetParams chaincfg.Params
    26  	TestNetParams chaincfg.Params
    27  )
    28  
    29  func init() {
    30  	// MonetaryUnit mainnet Address encoding magics
    31  	MainNetParams = chaincfg.MainNetParams
    32  	MainNetParams.Net = MainnetMagic
    33  	MainNetParams.PubKeyHashAddrID = []byte{16} // starting with '7'
    34  	MainNetParams.ScriptHashAddrID = []byte{76}
    35  	MainNetParams.PrivateKeyID = []byte{126}
    36  
    37  	// MonetaryUnit testnet Address encoding magics
    38  	TestNetParams = chaincfg.TestNet3Params
    39  	TestNetParams.Net = TestnetMagic
    40  	TestNetParams.PubKeyHashAddrID = []byte{139} // starting with 'x' or 'y'
    41  	TestNetParams.ScriptHashAddrID = []byte{19}
    42  	TestNetParams.PrivateKeyID = []byte{239}
    43  }
    44  
    45  // MonetaryUnitParser handle
    46  type MonetaryUnitParser struct {
    47  	*btc.BitcoinParser
    48  	baseparser                         *bchain.BaseParser
    49  	BitcoinOutputScriptToAddressesFunc btc.OutputScriptToAddressesFunc
    50  }
    51  
    52  // NewMonetaryUnitParser returns new MonetaryUnitParser instance
    53  func NewMonetaryUnitParser(params *chaincfg.Params, c *btc.Configuration) *MonetaryUnitParser {
    54  	p := &MonetaryUnitParser{
    55  		BitcoinParser: btc.NewBitcoinParser(params, c),
    56  		baseparser:    &bchain.BaseParser{},
    57  	}
    58  	p.BitcoinOutputScriptToAddressesFunc = p.OutputScriptToAddressesFunc
    59  	p.OutputScriptToAddressesFunc = p.outputScriptToAddresses
    60  	return p
    61  }
    62  
    63  // GetChainParams contains network parameters for the main MonetaryUnit network
    64  func GetChainParams(chain string) *chaincfg.Params {
    65  	if !chaincfg.IsRegistered(&MainNetParams) {
    66  		err := chaincfg.Register(&MainNetParams)
    67  		if err == nil {
    68  			err = chaincfg.Register(&TestNetParams)
    69  		}
    70  		if err != nil {
    71  			panic(err)
    72  		}
    73  	}
    74  	switch chain {
    75  	case "test":
    76  		return &TestNetParams
    77  	default:
    78  		return &MainNetParams
    79  	}
    80  }
    81  
    82  // ParseBlock parses raw block to our Block struct
    83  func (p *MonetaryUnitParser) ParseBlock(b []byte) (*bchain.Block, error) {
    84  	r := bytes.NewReader(b)
    85  	w := wire.MsgBlock{}
    86  	h := wire.BlockHeader{}
    87  	err := h.Deserialize(r)
    88  	if err != nil {
    89  		return nil, errors.Annotatef(err, "Deserialize")
    90  	}
    91  
    92  	if h.Version > 3 {
    93  		// Skip past AccumulatorCheckpoint which was added in MonetaryUnit block version 4
    94  		r.Seek(32, io.SeekCurrent)
    95  	}
    96  
    97  	err = utils.DecodeTransactions(r, 0, wire.WitnessEncoding, &w)
    98  	if err != nil {
    99  		return nil, errors.Annotatef(err, "DecodeTransactions")
   100  	}
   101  
   102  	txs := make([]bchain.Tx, len(w.Transactions))
   103  	for ti, t := range w.Transactions {
   104  		txs[ti] = p.TxFromMsgTx(t, false)
   105  	}
   106  
   107  	return &bchain.Block{
   108  		BlockHeader: bchain.BlockHeader{
   109  			Size: len(b),
   110  			Time: h.Timestamp.Unix(),
   111  		},
   112  		Txs: txs,
   113  	}, nil
   114  }
   115  
   116  // PackTx packs transaction to byte array using protobuf
   117  func (p *MonetaryUnitParser) PackTx(tx *bchain.Tx, height uint32, blockTime int64) ([]byte, error) {
   118  	return p.baseparser.PackTx(tx, height, blockTime)
   119  }
   120  
   121  // UnpackTx unpacks transaction from protobuf byte array
   122  func (p *MonetaryUnitParser) UnpackTx(buf []byte) (*bchain.Tx, uint32, error) {
   123  	return p.baseparser.UnpackTx(buf)
   124  }
   125  
   126  // ParseTx parses byte array containing transaction and returns Tx struct
   127  func (p *MonetaryUnitParser) ParseTx(b []byte) (*bchain.Tx, error) {
   128  	t := wire.MsgTx{}
   129  	r := bytes.NewReader(b)
   130  	if err := t.Deserialize(r); err != nil {
   131  		return nil, err
   132  	}
   133  	tx := p.TxFromMsgTx(&t, true)
   134  	tx.Hex = hex.EncodeToString(b)
   135  	return &tx, nil
   136  }
   137  
   138  // ParseTxFromJson parses JSON message containing transaction and returns Tx struct
   139  func (p *MonetaryUnitParser) ParseTxFromJson(msg json.RawMessage) (*bchain.Tx, error) {
   140  	var tx bchain.Tx
   141  	err := json.Unmarshal(msg, &tx)
   142  	if err != nil {
   143  		return nil, err
   144  	}
   145  
   146  	for i := range tx.Vout {
   147  		vout := &tx.Vout[i]
   148  		// convert vout.JsonValue to big.Int and clear it, it is only temporary value used for unmarshal
   149  		vout.ValueSat, err = p.AmountToBigInt(vout.JsonValue)
   150  		if err != nil {
   151  			return nil, err
   152  		}
   153  		vout.JsonValue = ""
   154  
   155  		if vout.ScriptPubKey.Addresses == nil {
   156  			vout.ScriptPubKey.Addresses = []string{}
   157  		}
   158  	}
   159  
   160  	return &tx, nil
   161  }
   162  
   163  // outputScriptToAddresses converts ScriptPubKey to bitcoin addresses
   164  func (p *MonetaryUnitParser) outputScriptToAddresses(script []byte) ([]string, bool, error) {
   165  
   166  	rv, s, _ := p.BitcoinOutputScriptToAddressesFunc(script)
   167  	return rv, s, nil
   168  }
   169  
   170  func (p *MonetaryUnitParser) GetAddrDescForUnknownInput(tx *bchain.Tx, input int) bchain.AddressDescriptor {
   171  	if len(tx.Vin) > input {
   172  		scriptHex := tx.Vin[input].ScriptSig.Hex
   173  
   174  		if scriptHex != "" {
   175  			script, _ := hex.DecodeString(scriptHex)
   176  			return script
   177  		}
   178  	}
   179  
   180  	s := make([]byte, 10)
   181  	return s
   182  }