decred.org/dcrdex@v1.0.5/dex/networks/zec/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 3 4 package zec 5 6 import ( 7 "bytes" 8 "fmt" 9 "io" 10 "time" 11 12 "decred.org/dcrdex/dex/utils" 13 "github.com/btcsuite/btcd/wire" 14 ) 15 16 // Block extends a wire.MsgBlock to specify Zcash specific fields, or in the 17 // case of the Nonce, a type-variant. 18 type Block struct { 19 wire.MsgBlock 20 // Transactions and MsgBlock.Transactions should both be populated. Each 21 // *Tx.MsgTx will be the same as the *MsgTx in MsgBlock.Transactions. 22 Transactions []*Tx 23 HashBlockCommitments [32]byte // Using NU5 name 24 Nonce [32]byte // Bitcoin uses uint32 25 Solution []byte // length 1344 on main and testnet, 36 on regtest 26 } 27 28 // DeserializeBlock deserializes the Zcash-encoded block. 29 func DeserializeBlock(b []byte) (*Block, error) { 30 zecBlock := &Block{} 31 32 // https://zips.z.cash/protocol/protocol.pdf section 7.6 33 r := bytes.NewReader(b) 34 35 if err := zecBlock.decodeBlockHeader(r); err != nil { 36 return nil, err 37 } 38 39 txCount, err := wire.ReadVarInt(r, pver) 40 if err != nil { 41 return nil, err 42 } 43 44 // TODO: Limit txCount based on block size, header size, min tx size. 45 46 zecBlock.MsgBlock.Transactions = make([]*wire.MsgTx, 0, txCount) 47 zecBlock.Transactions = make([]*Tx, 0, txCount) 48 for i := uint64(0); i < txCount; i++ { 49 tx := &Tx{MsgTx: new(wire.MsgTx)} 50 51 if err := tx.ZecDecode(r); err != nil { 52 blockHash := zecBlock.BlockHash() 53 return nil, fmt.Errorf("error decoding tx at index %d in block %s: %w", i, blockHash, err) 54 } 55 zecBlock.MsgBlock.Transactions = append(zecBlock.MsgBlock.Transactions, tx.MsgTx) 56 zecBlock.Transactions = append(zecBlock.Transactions, tx) 57 } 58 59 return zecBlock, nil 60 } 61 62 func DeserializeBlockHeader(b []byte) (*wire.BlockHeader, error) { 63 zecBlock := &Block{} 64 65 // https://zips.z.cash/protocol/protocol.pdf section 7.6 66 r := bytes.NewReader(b) 67 68 if err := zecBlock.decodeBlockHeader(r); err != nil { 69 return nil, err 70 } 71 return &zecBlock.Header, nil 72 } 73 74 // See github.com/zcash/zcash CBlockHeader -> SerializeOp 75 func (z *Block) decodeBlockHeader(r io.Reader) error { 76 hdr := &z.MsgBlock.Header 77 78 nVersion, err := readUint32(r) 79 if err != nil { 80 return err 81 } 82 hdr.Version = int32(nVersion) 83 84 if _, err = io.ReadFull(r, hdr.PrevBlock[:]); err != nil { 85 return err 86 } 87 88 if _, err := io.ReadFull(r, hdr.MerkleRoot[:]); err != nil { 89 return err 90 } 91 92 _, err = io.ReadFull(r, z.HashBlockCommitments[:]) 93 if err != nil { 94 return err 95 } 96 97 nTime, err := readUint32(r) 98 if err != nil { 99 return err 100 } 101 hdr.Timestamp = time.Unix(int64(nTime), 0) 102 103 hdr.Bits, err = readUint32(r) 104 if err != nil { 105 return err 106 } 107 108 err = readInternalByteOrder(r, z.Nonce[:]) 109 if err != nil { 110 return err 111 } 112 113 solSize, err := wire.ReadVarInt(r, pver) 114 if err != nil { 115 return err 116 } 117 if solSize != 1344 && solSize != 36 && solSize != 400 /* zclassic */ { 118 return fmt.Errorf("wrong solution size %d", solSize) 119 } 120 z.Solution = make([]byte, solSize) 121 122 _, err = io.ReadFull(r, z.Solution) 123 if err != nil { 124 return err 125 } 126 127 return nil 128 } 129 130 func readInternalByteOrder(r io.Reader, b []byte) error { 131 if _, err := io.ReadFull(r, b); err != nil { 132 return err 133 } 134 // Reverse the bytes 135 utils.ReverseSlice(b) 136 return nil 137 }