|
| 1 | +package block |
| 2 | + |
| 3 | +import ( |
| 4 | + "bytes" |
| 5 | + "encoding/hex" |
| 6 | + "errors" |
| 7 | + |
| 8 | + "github.com/btcsuite/btcd/wire" |
| 9 | + |
| 10 | + "github.com/btcsuite/btcd/blockchain" |
| 11 | + |
| 12 | + "github.com/btcsuite/btcd/chaincfg/chainhash" |
| 13 | +) |
| 14 | + |
| 15 | +const ( |
| 16 | + // The maximum allowed weight for a block, see BIP 141 (network rule) |
| 17 | + maxBlockWeight = 4000000 |
| 18 | + witnessScaleFactor = 4 |
| 19 | + minTransactionWeight = witnessScaleFactor * 60 // 60 is the lower bound for the size of a valid serialized tx |
| 20 | + |
| 21 | +) |
| 22 | + |
| 23 | +type MerkleBlock struct { |
| 24 | + BlockHeader *wire.BlockHeader |
| 25 | + PartialMerkleTree *PartialMerkleTree |
| 26 | +} |
| 27 | + |
| 28 | +type PartialMerkleTree struct { |
| 29 | + TxTotalCount uint32 |
| 30 | + TxHashes [][]byte |
| 31 | + FBad bool |
| 32 | + VBits []bool |
| 33 | +} |
| 34 | + |
| 35 | +func NewMerkleBlockFromBuffer(buf *bytes.Buffer) (*MerkleBlock, error) { |
| 36 | + return deserializeMerkleBlock(buf) |
| 37 | +} |
| 38 | + |
| 39 | +func NewMerkleBlockFromHex(h string) (*MerkleBlock, error) { |
| 40 | + hexBytes, err := hex.DecodeString(h) |
| 41 | + if err != nil { |
| 42 | + return nil, err |
| 43 | + } |
| 44 | + buf := bytes.NewBuffer(hexBytes) |
| 45 | + return NewMerkleBlockFromBuffer(buf) |
| 46 | +} |
| 47 | + |
| 48 | +func (m *MerkleBlock) ExtractMatches() (*chainhash.Hash, []chainhash.Hash, error) { |
| 49 | + vMatch := make([]chainhash.Hash, 0) |
| 50 | + |
| 51 | + if m.PartialMerkleTree.TxTotalCount == 0 { |
| 52 | + return nil, nil, errors.New("tx count equal 0") |
| 53 | + } |
| 54 | + |
| 55 | + if m.PartialMerkleTree.TxTotalCount > maxBlockWeight/minTransactionWeight { |
| 56 | + return nil, nil, errors.New("invalid tx count") |
| 57 | + } |
| 58 | + if len(m.PartialMerkleTree.TxHashes) > int(m.PartialMerkleTree.TxTotalCount) { |
| 59 | + return nil, nil, errors.New( |
| 60 | + "there can never be more hashes provided than one for every txid", |
| 61 | + ) |
| 62 | + } |
| 63 | + |
| 64 | + if len(m.PartialMerkleTree.VBits) < len(m.PartialMerkleTree.TxHashes) { |
| 65 | + return nil, nil, errors.New( |
| 66 | + "there must be at least one bit per node in the partial tree, " + |
| 67 | + "and at least one node per hash", |
| 68 | + ) |
| 69 | + } |
| 70 | + |
| 71 | + // Calculate the number of merkle branches (height) in the tree. |
| 72 | + height := uint32(0) |
| 73 | + for m.calcTreeWidth(height) > 1 { |
| 74 | + height++ |
| 75 | + } |
| 76 | + |
| 77 | + var bitsUsed, hashUsed, position = 0, 0, 0 |
| 78 | + hashMerkleRoot, err := m.traverseAndExtract( |
| 79 | + height, |
| 80 | + position, |
| 81 | + &bitsUsed, |
| 82 | + &hashUsed, |
| 83 | + &vMatch, |
| 84 | + ) |
| 85 | + if err != nil { |
| 86 | + return nil, nil, err |
| 87 | + } |
| 88 | + |
| 89 | + if m.PartialMerkleTree.FBad { |
| 90 | + return nil, nil, errors.New( |
| 91 | + "there must be at least one bit per node in the partial tree, " + |
| 92 | + "and at least one node per hash", |
| 93 | + ) |
| 94 | + } |
| 95 | + // verify that all bits were consumed (except for the padding caused by serializing it as a byte sequence) |
| 96 | + if (bitsUsed+7)/8 != (len(m.PartialMerkleTree.VBits)+7)/8 { |
| 97 | + return nil, nil, errors.New( |
| 98 | + "except for the padding caused by serializing it as a byte" + |
| 99 | + " sequence, not all bits were consumed", |
| 100 | + ) |
| 101 | + } |
| 102 | + // verify that all hashes were consumed |
| 103 | + if hashUsed != len(m.PartialMerkleTree.TxHashes) { |
| 104 | + return nil, nil, errors.New("not all hashes were consumed") |
| 105 | + } |
| 106 | + |
| 107 | + return hashMerkleRoot, vMatch, nil |
| 108 | +} |
| 109 | + |
| 110 | +func (m *MerkleBlock) traverseAndExtract( |
| 111 | + height uint32, |
| 112 | + position int, |
| 113 | + bitsUsed *int, |
| 114 | + hashUsed *int, |
| 115 | + vMatch *[]chainhash.Hash, |
| 116 | +) (*chainhash.Hash, error) { |
| 117 | + if *bitsUsed >= len(m.PartialMerkleTree.VBits) { |
| 118 | + m.PartialMerkleTree.FBad = true |
| 119 | + return nil, errors.New("overflowed the bits array") |
| 120 | + } |
| 121 | + |
| 122 | + fParentOfMatch := m.PartialMerkleTree.VBits[*bitsUsed] |
| 123 | + *bitsUsed++ |
| 124 | + if height == 0 || !fParentOfMatch { |
| 125 | + // if at height 0, or nothing interesting below, use stored hash and do not descend |
| 126 | + if *hashUsed >= len(m.PartialMerkleTree.TxHashes) { |
| 127 | + m.PartialMerkleTree.FBad = true |
| 128 | + return nil, errors.New("overflowed the hash array") |
| 129 | + } |
| 130 | + hash, err := chainhash.NewHash(m.PartialMerkleTree.TxHashes[*hashUsed]) |
| 131 | + if err != nil { |
| 132 | + return nil, err |
| 133 | + } |
| 134 | + |
| 135 | + *hashUsed++ |
| 136 | + if height == 0 && fParentOfMatch { // in case of height 0, we have a matched txid |
| 137 | + *vMatch = append(*vMatch, *hash) |
| 138 | + } |
| 139 | + |
| 140 | + return hash, nil |
| 141 | + } else { |
| 142 | + //otherwise, descend into the subtrees to extract matched txids and hashes |
| 143 | + left, err := m.traverseAndExtract( |
| 144 | + height-1, |
| 145 | + position*2, |
| 146 | + bitsUsed, |
| 147 | + hashUsed, |
| 148 | + vMatch, |
| 149 | + ) |
| 150 | + if err != nil { |
| 151 | + return nil, err |
| 152 | + } |
| 153 | + var right *chainhash.Hash |
| 154 | + if position*2+1 < int(m.calcTreeWidth(height-1)) { |
| 155 | + right, err = m.traverseAndExtract( |
| 156 | + height-1, |
| 157 | + position*2+1, |
| 158 | + bitsUsed, |
| 159 | + hashUsed, |
| 160 | + vMatch, |
| 161 | + ) |
| 162 | + if err != nil { |
| 163 | + return nil, err |
| 164 | + } |
| 165 | + if left.IsEqual(right) { |
| 166 | + // The left and right branches should never be identical, as the transaction |
| 167 | + // hashes covered by them must each be unique. |
| 168 | + m.PartialMerkleTree.FBad = true |
| 169 | + } |
| 170 | + } else { |
| 171 | + right = left |
| 172 | + } |
| 173 | + |
| 174 | + return blockchain.HashMerkleBranches(left, right), nil |
| 175 | + } |
| 176 | +} |
| 177 | + |
| 178 | +// calcTreeWidth calculates and returns the the number of nodes (width) or a |
| 179 | +// merkle tree at the given depth-first height. |
| 180 | +func (m *MerkleBlock) calcTreeWidth(height uint32) uint32 { |
| 181 | + return (m.PartialMerkleTree.TxTotalCount + (1 << height) - 1) >> height |
| 182 | +} |
| 183 | + |
| 184 | +func deserializePartialMerkleTree( |
| 185 | + mb wire.MsgMerkleBlock, |
| 186 | +) (*PartialMerkleTree, error) { |
| 187 | + txHashes := make([][]byte, 0, len(mb.Hashes)) |
| 188 | + for _, v := range mb.Hashes { |
| 189 | + |
| 190 | + txHashes = append(txHashes, v.CloneBytes()) |
| 191 | + } |
| 192 | + |
| 193 | + return &PartialMerkleTree{ |
| 194 | + TxTotalCount: mb.Transactions, |
| 195 | + TxHashes: txHashes, |
| 196 | + FBad: false, |
| 197 | + VBits: serializeVBits(mb.Flags), |
| 198 | + }, nil |
| 199 | +} |
| 200 | + |
| 201 | +func deserializeMerkleBlock(buf *bytes.Buffer) (*MerkleBlock, error) { |
| 202 | + mb := wire.MsgMerkleBlock{} |
| 203 | + err := mb.BtcDecode(buf, wire.ProtocolVersion, wire.LatestEncoding) |
| 204 | + if err != nil { |
| 205 | + return nil, err |
| 206 | + } |
| 207 | + |
| 208 | + partialMerkleTree, err := deserializePartialMerkleTree(mb) |
| 209 | + if err != nil { |
| 210 | + return nil, err |
| 211 | + } |
| 212 | + |
| 213 | + return &MerkleBlock{ |
| 214 | + BlockHeader: &mb.Header, |
| 215 | + PartialMerkleTree: partialMerkleTree, |
| 216 | + }, nil |
| 217 | +} |
| 218 | + |
| 219 | +func serializeVBits(b []byte) []bool { |
| 220 | + bits := make([]bool, 0) |
| 221 | + |
| 222 | + for _, v := range b { |
| 223 | + l := byteToBits(v) |
| 224 | + for _, v := range l { |
| 225 | + if v == 1 { |
| 226 | + bits = append(bits, true) |
| 227 | + } else { |
| 228 | + bits = append(bits, false) |
| 229 | + } |
| 230 | + } |
| 231 | + } |
| 232 | + |
| 233 | + return bits |
| 234 | +} |
| 235 | + |
| 236 | +func byteToBits(b byte) []byte { |
| 237 | + return []byte{ |
| 238 | + (b >> 0) & 0x1, |
| 239 | + (b >> 1) & 0x1, |
| 240 | + (b >> 2) & 0x1, |
| 241 | + (b >> 3) & 0x1, |
| 242 | + (b >> 4) & 0x1, |
| 243 | + (b >> 5) & 0x1, |
| 244 | + (b >> 6) & 0x1, |
| 245 | + (b >> 7) & 0x1, |
| 246 | + } |
| 247 | +} |
0 commit comments