decred.org/dcrdex@v1.0.5/dex/networks/doge/block.go (about) 1 // This code is available on the terms of the project LICENSE.md file, 2 // also available online at https://blueoakcouncil.org/license/1.0.0. 3 4 package doge 5 6 import ( 7 "bytes" 8 "errors" 9 "fmt" 10 11 "github.com/btcsuite/btcd/chaincfg/chainhash" 12 "github.com/btcsuite/btcd/wire" 13 ) 14 15 func readMerkleBranch(buf *bytes.Buffer) error { 16 // Merkle branch for parent coinbase <-> parent Merkle root 17 branchLen, err := wire.ReadVarInt(buf, 0) 18 if err != nil { 19 return err 20 } 21 for i := 0; i < int(branchLen); i++ { 22 _, err := chainhash.NewHash(buf.Next(32)) 23 if err != nil { 24 return err 25 } 26 } 27 if buf.Len() < 4 { 28 return errors.New("out of bytes") 29 } 30 buf.Next(4) // int32 branch side mask / Merkle tree index 31 return nil 32 } 33 34 // DeserializeBlock decodes the bytes of a Dogecoin block. The block header and 35 // transaction serializations are identical to Bitcoin, but there is an optional 36 // "AuxPOW" section to support merged mining. The AuxPOW section is after the 37 // nonce field of the header, but before the block's transactions. This function 38 // decodes and discards the AuxPOW section if it exists. 39 // 40 // Refs: 41 // https://en.bitcoin.it/wiki/Merged_mining_specification#Aux_proof-of-work_block 42 // https://github.com/dogecoin/dogecoin/blob/31afd133119dd2e15862d46530cb99424cf564b0/src/primitives/block.h#L41-L46 43 // https://github.com/dogecoin/dogecoin/blob/31afd133119dd2e15862d46530cb99424cf564b0/src/auxpow.h#L155-L160 44 func DeserializeBlock(blk []byte) (*wire.MsgBlock, error) { 45 46 blkBuf := bytes.NewBuffer(blk) 47 48 // Block header 49 hdr := &wire.BlockHeader{} 50 err := hdr.Deserialize(blkBuf) 51 if err != nil { 52 return nil, fmt.Errorf("failed to deserialize block header: %w", err) 53 } 54 55 // AuxPOW region (optional) 56 isAuxPow := hdr.Version&(1<<8) != 0 57 if isAuxPow { 58 // Coinbase tx of parent block on other chain (i.e. LTC) 59 err = new(wire.MsgTx).Deserialize(blkBuf) 60 if err != nil { 61 return nil, fmt.Errorf("failed to deserialize AuxPOW>coinbase_txn: %w", err) 62 } 63 64 // Parent block hash 65 _, err = chainhash.NewHash(blkBuf.Next(32)) 66 if err != nil { 67 return nil, fmt.Errorf("failed to deserialize AuxPOW>parent_block_hash: %w", err) 68 } 69 if blkBuf.Len() == 0 { 70 return nil, errors.New("out of bytes in AuxPOW section") 71 } 72 73 // Merkle branch for parent coinbase <-> parent Merkle root 74 err = readMerkleBranch(blkBuf) 75 if err != nil { 76 return nil, fmt.Errorf("failed to deserialize AuxPOW>coinbase_branch: %w", err) 77 } 78 // Merkle branch for parent chain <-> other chains 79 err = readMerkleBranch(blkBuf) 80 if err != nil { 81 return nil, fmt.Errorf("failed to deserialize AuxPOW>blockchain_branch: %w", err) 82 } 83 84 // Parent block header 85 err = new(wire.BlockHeader).Deserialize(blkBuf) 86 if err != nil { 87 return nil, fmt.Errorf("failed to deserialize AuxPOW>parent_block_header: %w", err) 88 } 89 } 90 91 // This block's transactions 92 txnCount, err := wire.ReadVarInt(blkBuf, 0) 93 if err != nil { 94 return nil, fmt.Errorf("failed to parse transaction count: %w", err) 95 } 96 97 txns := make([]*wire.MsgTx, int(txnCount)) 98 99 for i := range txns { 100 msgTx := &wire.MsgTx{} 101 err = msgTx.Deserialize(blkBuf) 102 if err != nil { 103 return nil, fmt.Errorf("failed to deserialize transaction %d of %d in block %v: %w", 104 i+1, txnCount, hdr.BlockHash(), err) 105 } 106 txns[i] = msgTx 107 } 108 109 return &wire.MsgBlock{ 110 Header: *hdr, 111 Transactions: txns, 112 }, nil 113 }