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 }