package dcr import ( "bytes" "encoding/hex" "encoding/json" "math" "math/big" "blockbook/bchain" "blockbook/bchain/coins/btc" "blockbook/bchain/coins/utils" cfg "github.com/decred/dcrd/chaincfg" "github.com/decred/dcrd/txscript" "github.com/martinboehm/btcd/wire" "github.com/martinboehm/btcutil/chaincfg" ) const ( // MainnetMagic is mainnet network constant MainnetMagic wire.BitcoinNet = 0xd9b400f9 // TestnetMagic is testnet network constant TestnetMagic wire.BitcoinNet = 0xb194aa75 ) var ( // MainNetParams are parser parameters for mainnet MainNetParams chaincfg.Params // TestNet3Params are parser parameters for testnet TestNet3Params chaincfg.Params ) func init() { MainNetParams = chaincfg.MainNetParams MainNetParams.Net = MainnetMagic MainNetParams.PubKeyHashAddrID = []byte{0x07, 0x3f} MainNetParams.ScriptHashAddrID = []byte{0x07, 0x1a} TestNet3Params = chaincfg.TestNet3Params TestNet3Params.Net = TestnetMagic TestNet3Params.PubKeyHashAddrID = []byte{0x0f, 0x21} TestNet3Params.ScriptHashAddrID = []byte{0x0e, 0xfc} } // DecredParser handle type DecredParser struct { *btc.BitcoinParser baseParser *bchain.BaseParser } // NewDecredParser returns new DecredParser instance func NewDecredParser(params *chaincfg.Params, c *btc.Configuration) *DecredParser { return &DecredParser{ BitcoinParser: btc.NewBitcoinParser(params, c), baseParser: &bchain.BaseParser{}, } } // GetChainParams contains network parameters for the main Decred network, // and the test Decred network. func GetChainParams(chain string) *chaincfg.Params { var param *chaincfg.Params switch chain { case "testnet3": param = &TestNet3Params default: param = &MainNetParams } if !chaincfg.IsRegistered(param) { if err := chaincfg.Register(param); err != nil { panic(err) } } return param } // ParseBlock parses raw block to our Block struct. func (p *DecredParser) ParseBlock(b []byte) (*bchain.Block, error) { r := bytes.NewReader(b) h := wire.BlockHeader{} if err := h.Deserialize(r); err != nil { return nil, err } if (h.Version & utils.VersionAuxpow) != 0 { if err := utils.SkipAuxpow(r); err != nil { return nil, err } } var w wire.MsgBlock if err := utils.DecodeTransactions(r, 0, wire.WitnessEncoding, &w); err != nil { return nil, err } txs := make([]bchain.Tx, len(w.Transactions)) for ti, t := range w.Transactions { txs[ti] = p.TxFromMsgTx(t, false) } return &bchain.Block{ BlockHeader: bchain.BlockHeader{ Size: len(b), Time: h.Timestamp.Unix(), }, Txs: txs, }, nil } func (p *DecredParser) ParseTxFromJson(jsonTx json.RawMessage) (*bchain.Tx, error) { var getTxResult GetTransactionResult if err := json.Unmarshal([]byte(jsonTx), &getTxResult.Result); err != nil { return nil, err } vins := make([]bchain.Vin, len(getTxResult.Result.Vin)) for index, input := range getTxResult.Result.Vin { hexData := bchain.ScriptSig{} if input.ScriptSig != nil { hexData.Hex = input.ScriptSig.Hex } vins[index] = bchain.Vin{ Coinbase: input.Coinbase, Txid: input.Txid, Vout: input.Vout, ScriptSig: hexData, Sequence: input.Sequence, // Addresses: []string{}, } } vouts := make([]bchain.Vout, len(getTxResult.Result.Vout)) for index, output := range getTxResult.Result.Vout { addr := output.ScriptPubKey.Addresses // If nulldata type found make asm field the address data. if output.ScriptPubKey.Type == "nulldata" { addr = []string{output.ScriptPubKey.Asm} } vouts[index] = bchain.Vout{ ValueSat: *big.NewInt(int64(math.Round(output.Value * 1e8))), N: output.N, ScriptPubKey: bchain.ScriptPubKey{ Hex: output.ScriptPubKey.Hex, Addresses: addr, }, } } tx := &bchain.Tx{ Hex: getTxResult.Result.Hex, Txid: getTxResult.Result.Txid, Version: getTxResult.Result.Version, LockTime: getTxResult.Result.LockTime, Vin: vins, Vout: vouts, Confirmations: uint32(getTxResult.Result.Confirmations), Time: getTxResult.Result.Time, Blocktime: getTxResult.Result.Blocktime, } tx.CoinSpecificData = getTxResult.Result.TxExtraInfo return tx, nil } // GetAddrDescForUnknownInput returns nil AddressDescriptor func (p *DecredParser) GetAddrDescForUnknownInput(tx *bchain.Tx, input int) bchain.AddressDescriptor { return nil } func (p *DecredParser) GetAddrDescFromAddress(address string) (bchain.AddressDescriptor, error) { addressByte := []byte(address) return bchain.AddressDescriptor(addressByte), nil } func (p *DecredParser) GetAddrDescFromVout(output *bchain.Vout) (bchain.AddressDescriptor, error) { script, err := hex.DecodeString(output.ScriptPubKey.Hex) if err != nil { return nil, err } var params cfg.Params if p.Params.Name == "mainnet" { params = cfg.MainNetParams } else { params = cfg.TestNet3Params } scriptClass, addresses, _, err := txscript.ExtractPkScriptAddrs(txscript.DefaultScriptVersion, script, ¶ms) if err != nil { return nil, err } if scriptClass.String() == "nulldata" { if parsedOPReturn := p.BitcoinParser.TryParseOPReturn(script); parsedOPReturn != "" { return []byte(parsedOPReturn), nil } } var addressByte []byte for i := range addresses { addressByte = append(addressByte, addresses[i].String()...) } return bchain.AddressDescriptor(addressByte), nil } func (p *DecredParser) GetAddressesFromAddrDesc(addrDesc bchain.AddressDescriptor) ([]string, bool, error) { var addrs []string if addrDesc != nil { addrs = append(addrs, string(addrDesc)) } return addrs, true, nil } // PackTx packs transaction to byte array using protobuf func (p *DecredParser) PackTx(tx *bchain.Tx, height uint32, blockTime int64) ([]byte, error) { return p.baseParser.PackTx(tx, height, blockTime) } // UnpackTx unpacks transaction from protobuf byte array func (p *DecredParser) UnpackTx(buf []byte) (*bchain.Tx, uint32, error) { return p.baseParser.UnpackTx(buf) }