decred.org/dcrdex@v1.0.5/client/asset/firo/block_deserialize.go (about)

     1  package firo
     2  
     3  import (
     4  	"bytes"
     5  	"errors"
     6  	"fmt"
     7  
     8  	"github.com/btcsuite/btcd/chaincfg"
     9  	"github.com/btcsuite/btcd/chaincfg/chainhash"
    10  	"github.com/btcsuite/btcd/wire"
    11  )
    12  
    13  const (
    14  	// Only blocks mined with progpow are considered.
    15  	// Previous mining algorithms: MTP and Lyra2z ignored as being too early for
    16  	// Firo wallet on Dex ~ late 2023
    17  	ProgpowStartTime        = 1635228000 // Tue Oct 26 2021 06:00:00 UTC+0
    18  	HeaderLength            = 80
    19  	ProgpowExtraLength      = 40
    20  	ProgpowFullHeaderLength = HeaderLength + ProgpowExtraLength
    21  )
    22  
    23  var errInvalidBlockLength = errors.New("invalid block length")
    24  
    25  // deserializeBlock deserializes the wire bytes passed in as blk and returns the
    26  // header for the network plus any Transparent transactions found parsed into a
    27  // wire.MsgBlock.
    28  //
    29  // Other transaction types are discarded; including coinbase.
    30  func deserializeBlock(net *chaincfg.Params, blk []byte) (*wire.MsgBlock, error) {
    31  	var hdrHash chainhash.Hash
    32  	var hdr *wire.BlockHeader
    33  
    34  	// hash header
    35  	var header []byte
    36  	switch net.Name {
    37  	case "mainnet", "testnet3", "testnet":
    38  		if len(blk) < ProgpowFullHeaderLength {
    39  			return nil, errInvalidBlockLength
    40  		}
    41  		header = make([]byte, ProgpowFullHeaderLength)
    42  		copy(header, blk[:ProgpowFullHeaderLength])
    43  
    44  	case "regtest":
    45  		if len(blk) < HeaderLength {
    46  			return nil, errInvalidBlockLength
    47  		}
    48  		header = make([]byte, HeaderLength)
    49  		copy(header, blk[:HeaderLength])
    50  
    51  	default:
    52  		return nil, fmt.Errorf("unknown net: %s", net.Name)
    53  	}
    54  	hdrHash = chainhash.DoubleHashH(header)
    55  
    56  	// make a reader over the full block
    57  	r := bytes.NewReader(blk)
    58  
    59  	// deserialize the first 80 bytes of the header
    60  	hdr = &wire.BlockHeader{}
    61  	err := hdr.Deserialize(r)
    62  	if err != nil {
    63  		return nil, fmt.Errorf("failed to deserialize block header: %w", err)
    64  	}
    65  
    66  	if int(hdr.Timestamp.Unix()) < ProgpowStartTime {
    67  		return nil, fmt.Errorf("dex not considering blocks mined before progpow")
    68  	}
    69  
    70  	if net.Name != "regtest" {
    71  		// Blocks mined later than progpow start time have 40 extra bytes holding
    72  		// mining info. Skip over!
    73  		var extraBytes = make([]byte, ProgpowExtraLength)
    74  		r.Read(extraBytes)
    75  	}
    76  
    77  	// This block's transactions
    78  	txnCount, err := wire.ReadVarInt(r, 0)
    79  	if err != nil {
    80  		return nil, fmt.Errorf("failed to parse transaction count: %w", err)
    81  	}
    82  
    83  	if txnCount == 0 {
    84  		return nil, fmt.Errorf("invalid transaction count 0 -- must at least have a coinbase")
    85  	}
    86  
    87  	txns := make([]*wire.MsgTx, 0, txnCount)
    88  	for i := 0; i < int(txnCount); i++ {
    89  		tx, err := deserializeTransaction(r)
    90  
    91  		if err != nil {
    92  			return nil, fmt.Errorf("failed to deserialize transaction %d of %d (type=%d) in block %s: %w",
    93  				i+1, txnCount, tx.txType, hdrHash.String(), err)
    94  		}
    95  
    96  		if tx.txType == TransactionNormal {
    97  			txns = append(txns, tx.msgTx)
    98  		}
    99  	}
   100  
   101  	return &wire.MsgBlock{
   102  		Header:       *hdr,
   103  		Transactions: txns,
   104  	}, nil
   105  }