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  }