github.com/trezor/blockbook@v0.4.1-0.20240328132726-e9a08582ee2c/bchain/coins/divi/diviparser.go (about)

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