github.com/cerberus-wallet/blockbook@v0.3.2/bchain/coins/dcr/decredparser.go (about) 1 package dcr 2 3 import ( 4 "bytes" 5 "encoding/binary" 6 "encoding/hex" 7 "encoding/json" 8 "math" 9 "math/big" 10 "strconv" 11 12 "blockbook/bchain" 13 "blockbook/bchain/coins/btc" 14 "blockbook/bchain/coins/utils" 15 16 cfg "github.com/decred/dcrd/chaincfg" 17 "github.com/decred/dcrd/chaincfg/chainhash" 18 "github.com/decred/dcrd/hdkeychain" 19 "github.com/decred/dcrd/txscript" 20 "github.com/juju/errors" 21 "github.com/martinboehm/btcd/wire" 22 "github.com/martinboehm/btcutil/base58" 23 "github.com/martinboehm/btcutil/chaincfg" 24 ) 25 26 const ( 27 // MainnetMagic is mainnet network constant 28 MainnetMagic wire.BitcoinNet = 0xd9b400f9 29 // TestnetMagic is testnet network constant 30 TestnetMagic wire.BitcoinNet = 0xb194aa75 31 ) 32 33 var ( 34 // MainNetParams are parser parameters for mainnet 35 MainNetParams chaincfg.Params 36 // TestNet3Params are parser parameters for testnet 37 TestNet3Params chaincfg.Params 38 ) 39 40 func init() { 41 MainNetParams = chaincfg.MainNetParams 42 MainNetParams.Net = MainnetMagic 43 MainNetParams.PubKeyHashAddrID = []byte{0x07, 0x3f} 44 MainNetParams.ScriptHashAddrID = []byte{0x07, 0x1a} 45 46 TestNet3Params = chaincfg.TestNet3Params 47 TestNet3Params.Net = TestnetMagic 48 TestNet3Params.PubKeyHashAddrID = []byte{0x0f, 0x21} 49 TestNet3Params.ScriptHashAddrID = []byte{0x0e, 0xfc} 50 } 51 52 // DecredParser handle 53 type DecredParser struct { 54 *btc.BitcoinParser 55 baseParser *bchain.BaseParser 56 netConfig *cfg.Params 57 } 58 59 // NewDecredParser returns new DecredParser instance 60 func NewDecredParser(params *chaincfg.Params, c *btc.Configuration) *DecredParser { 61 d := &DecredParser{ 62 BitcoinParser: btc.NewBitcoinParser(params, c), 63 baseParser: &bchain.BaseParser{}, 64 } 65 66 switch d.BitcoinParser.Params.Name { 67 case "testnet3": 68 d.netConfig = &cfg.TestNet3Params 69 default: 70 d.netConfig = &cfg.MainNetParams 71 } 72 return d 73 } 74 75 // GetChainParams contains network parameters for the main Decred network, 76 // and the test Decred network. 77 func GetChainParams(chain string) *chaincfg.Params { 78 var param *chaincfg.Params 79 80 switch chain { 81 case "testnet3": 82 param = &TestNet3Params 83 default: 84 param = &MainNetParams 85 } 86 87 if !chaincfg.IsRegistered(param) { 88 if err := chaincfg.Register(param); err != nil { 89 panic(err) 90 } 91 } 92 return param 93 } 94 95 // ParseBlock parses raw block to our Block struct. 96 func (p *DecredParser) ParseBlock(b []byte) (*bchain.Block, error) { 97 r := bytes.NewReader(b) 98 h := wire.BlockHeader{} 99 if err := h.Deserialize(r); err != nil { 100 return nil, err 101 } 102 103 if (h.Version & utils.VersionAuxpow) != 0 { 104 if err := utils.SkipAuxpow(r); err != nil { 105 return nil, err 106 } 107 } 108 109 var w wire.MsgBlock 110 if err := utils.DecodeTransactions(r, 0, wire.WitnessEncoding, &w); err != nil { 111 return nil, err 112 } 113 114 txs := make([]bchain.Tx, len(w.Transactions)) 115 for ti, t := range w.Transactions { 116 txs[ti] = p.TxFromMsgTx(t, false) 117 } 118 119 return &bchain.Block{ 120 BlockHeader: bchain.BlockHeader{ 121 Size: len(b), 122 Time: h.Timestamp.Unix(), 123 }, 124 Txs: txs, 125 }, nil 126 } 127 128 // ParseTxFromJson parses JSON message containing transaction and returns Tx struct 129 func (p *DecredParser) ParseTxFromJson(jsonTx json.RawMessage) (*bchain.Tx, error) { 130 var getTxResult GetTransactionResult 131 if err := json.Unmarshal([]byte(jsonTx), &getTxResult.Result); err != nil { 132 return nil, err 133 } 134 135 vins := make([]bchain.Vin, len(getTxResult.Result.Vin)) 136 for index, input := range getTxResult.Result.Vin { 137 hexData := bchain.ScriptSig{} 138 if input.ScriptSig != nil { 139 hexData.Hex = input.ScriptSig.Hex 140 } 141 142 vins[index] = bchain.Vin{ 143 Coinbase: input.Coinbase, 144 Txid: input.Txid, 145 Vout: input.Vout, 146 ScriptSig: hexData, 147 Sequence: input.Sequence, 148 // Addresses: []string{}, 149 } 150 } 151 152 vouts := make([]bchain.Vout, len(getTxResult.Result.Vout)) 153 for index, output := range getTxResult.Result.Vout { 154 addr := output.ScriptPubKey.Addresses 155 // If nulldata type found make asm field the address data. 156 if output.ScriptPubKey.Type == "nulldata" { 157 addr = []string{output.ScriptPubKey.Asm} 158 } 159 160 vouts[index] = bchain.Vout{ 161 ValueSat: *big.NewInt(int64(math.Round(output.Value * 1e8))), 162 N: output.N, 163 ScriptPubKey: bchain.ScriptPubKey{ 164 Hex: output.ScriptPubKey.Hex, 165 Addresses: addr, 166 }, 167 } 168 } 169 170 tx := &bchain.Tx{ 171 Hex: getTxResult.Result.Hex, 172 Txid: getTxResult.Result.Txid, 173 Version: getTxResult.Result.Version, 174 LockTime: getTxResult.Result.LockTime, 175 BlockHeight: getTxResult.Result.BlockHeight, 176 Vin: vins, 177 Vout: vouts, 178 Confirmations: uint32(getTxResult.Result.Confirmations), 179 Time: getTxResult.Result.Time, 180 Blocktime: getTxResult.Result.Blocktime, 181 } 182 183 tx.CoinSpecificData = getTxResult.Result.TxExtraInfo 184 185 return tx, nil 186 } 187 188 // GetAddrDescForUnknownInput returns nil AddressDescriptor. 189 func (p *DecredParser) GetAddrDescForUnknownInput(tx *bchain.Tx, input int) bchain.AddressDescriptor { 190 return nil 191 } 192 193 // GetAddrDescFromAddress returns internal address representation of a given address. 194 func (p *DecredParser) GetAddrDescFromAddress(address string) (bchain.AddressDescriptor, error) { 195 addressByte := []byte(address) 196 return bchain.AddressDescriptor(addressByte), nil 197 } 198 199 // GetAddrDescFromVout returns internal address representation of a given transaction output. 200 func (p *DecredParser) GetAddrDescFromVout(output *bchain.Vout) (bchain.AddressDescriptor, error) { 201 script, err := hex.DecodeString(output.ScriptPubKey.Hex) 202 if err != nil { 203 return nil, err 204 } 205 206 scriptClass, addresses, _, err := txscript.ExtractPkScriptAddrs(txscript.DefaultScriptVersion, script, p.netConfig) 207 if err != nil { 208 return nil, err 209 } 210 211 if scriptClass.String() == "nulldata" { 212 if parsedOPReturn := p.BitcoinParser.TryParseOPReturn(script); parsedOPReturn != "" { 213 return []byte(parsedOPReturn), nil 214 } 215 } 216 217 var addressByte []byte 218 for i := range addresses { 219 addressByte = append(addressByte, addresses[i].String()...) 220 } 221 return bchain.AddressDescriptor(addressByte), nil 222 } 223 224 // GetAddressesFromAddrDesc returns addresses obtained from the internal address representation 225 func (p *DecredParser) GetAddressesFromAddrDesc(addrDesc bchain.AddressDescriptor) ([]string, bool, error) { 226 var addrs []string 227 if addrDesc != nil { 228 addrs = append(addrs, string(addrDesc)) 229 } 230 return addrs, true, nil 231 } 232 233 // PackTx packs transaction to byte array using protobuf 234 func (p *DecredParser) PackTx(tx *bchain.Tx, height uint32, blockTime int64) ([]byte, error) { 235 return p.baseParser.PackTx(tx, height, blockTime) 236 } 237 238 // UnpackTx unpacks transaction from protobuf byte array 239 func (p *DecredParser) UnpackTx(buf []byte) (*bchain.Tx, uint32, error) { 240 return p.baseParser.UnpackTx(buf) 241 } 242 243 func (p *DecredParser) addrDescFromExtKey(extKey *hdkeychain.ExtendedKey) (bchain.AddressDescriptor, error) { 244 var addr, err = extKey.Address(p.netConfig) 245 if err != nil { 246 return nil, err 247 } 248 return p.GetAddrDescFromAddress(addr.String()) 249 } 250 251 // DeriveAddressDescriptors derives address descriptors from given xpub for 252 // listed indexes 253 func (p *DecredParser) DeriveAddressDescriptors(xpub string, change uint32, 254 indexes []uint32) ([]bchain.AddressDescriptor, error) { 255 extKey, err := hdkeychain.NewKeyFromString(xpub) 256 if err != nil { 257 return nil, err 258 } 259 260 changeExtKey, err := extKey.Child(change) 261 if err != nil { 262 return nil, err 263 } 264 265 ad := make([]bchain.AddressDescriptor, len(indexes)) 266 for i, index := range indexes { 267 indexExtKey, err := changeExtKey.Child(index) 268 if err != nil { 269 return nil, err 270 } 271 ad[i], err = p.addrDescFromExtKey(indexExtKey) 272 if err != nil { 273 return nil, err 274 } 275 } 276 return ad, nil 277 } 278 279 // DeriveAddressDescriptorsFromTo derives address descriptors from given xpub for 280 // addresses in index range 281 func (p *DecredParser) DeriveAddressDescriptorsFromTo(xpub string, change uint32, 282 fromIndex uint32, toIndex uint32) ([]bchain.AddressDescriptor, error) { 283 if toIndex <= fromIndex { 284 return nil, errors.New("toIndex<=fromIndex") 285 } 286 extKey, err := hdkeychain.NewKeyFromString(xpub) 287 if err != nil { 288 return nil, err 289 } 290 changeExtKey, err := extKey.Child(change) 291 if err != nil { 292 return nil, err 293 } 294 295 ad := make([]bchain.AddressDescriptor, toIndex-fromIndex) 296 for index := fromIndex; index < toIndex; index++ { 297 indexExtKey, err := changeExtKey.Child(index) 298 if err != nil { 299 return nil, err 300 } 301 ad[index-fromIndex], err = p.addrDescFromExtKey(indexExtKey) 302 if err != nil { 303 return nil, err 304 } 305 } 306 return ad, nil 307 } 308 309 // DerivationBasePath returns base path of xpub which whose full format is 310 // m/44'/<coin type>'/<account>'/<branch>/<address index>. This function only 311 // returns a path up to m/44'/<coin type>'/<account>'/ whereby the rest of the 312 // other details (<branch>/<address index>) are populated automatically. 313 func (p *DecredParser) DerivationBasePath(xpub string) (string, error) { 314 var c string 315 cn, depth, err := p.decodeXpub(xpub) 316 if err != nil { 317 return "", err 318 } 319 320 if cn >= hdkeychain.HardenedKeyStart { 321 cn -= hdkeychain.HardenedKeyStart 322 c = "'" 323 } 324 325 c = strconv.Itoa(int(cn)) + c 326 if depth != 3 { 327 return "unknown/" + c, nil 328 } 329 330 return "m/44'/" + strconv.Itoa(int(p.Slip44)) + "'/" + c, nil 331 } 332 333 func (p *DecredParser) decodeXpub(xpub string) (childNum uint32, depth uint16, err error) { 334 decoded := base58.Decode(xpub) 335 336 // serializedKeyLen is the length of a serialized public or private 337 // extended key. It consists of 4 bytes version, 1 byte depth, 4 bytes 338 // fingerprint, 4 bytes child number, 32 bytes chain code, and 33 bytes 339 // public/private key data. 340 serializedKeyLen := 4 + 1 + 4 + 4 + 32 + 33 // 78 bytes 341 if len(decoded) != serializedKeyLen+4 { 342 err = errors.New("invalid extended key length") 343 return 344 } 345 346 payload := decoded[:len(decoded)-4] 347 checkSum := decoded[len(decoded)-4:] 348 expectedCheckSum := chainhash.HashB(chainhash.HashB(payload))[:4] 349 if !bytes.Equal(checkSum, expectedCheckSum) { 350 err = errors.New("bad checksum value") 351 return 352 } 353 354 depth = uint16(payload[4:5][0]) 355 childNum = binary.BigEndian.Uint32(payload[9:13]) 356 return 357 }