github.com/mit-dci/lit@v0.0.0-20221102210550-8c3d3b49f2ce/uspv/mblock.go (about) 1 package uspv 2 3 import ( 4 "fmt" 5 6 "github.com/mit-dci/lit/logging" 7 8 "github.com/mit-dci/lit/btcutil/chaincfg/chainhash" 9 "github.com/mit-dci/lit/wire" 10 ) 11 12 // MakeMerkleParent ... 13 func MakeMerkleParent(left, right *chainhash.Hash) *chainhash.Hash { 14 // dupes can screw things up; CVE-2012-2459. check for them 15 if left != nil && right != nil && left.IsEqual(right) { 16 logging.Infof("DUP HASH CRASH") 17 return nil 18 } 19 // if left child is nil, output nil. Need this for hard mode. 20 if left == nil { 21 return nil 22 } 23 // if right is nil, hash left with itself 24 if right == nil { 25 right = left 26 } 27 28 // Concatenate the left and right nodes 29 var sha [64]byte 30 copy(sha[:32], left[:]) 31 copy(sha[32:], right[:]) 32 33 newSha := chainhash.DoubleHashH(sha[:]) 34 return &newSha 35 } 36 37 type merkleNode struct { 38 p uint32 // position in the binary tree 39 h *chainhash.Hash // hash 40 } 41 42 // given n merkle leaves, how deep is the tree? 43 // iterate shifting left until greater than n 44 func treeDepth(n uint32) (e uint8) { 45 for ; (1 << e) < n; e++ { 46 } 47 return 48 } 49 50 // smallest power of 2 that can contain n 51 func nextPowerOfTwo(n uint32) uint32 { 52 return 1 << treeDepth(n) // 2^exponent 53 } 54 55 // check if a node is populated based on node position and size of tree 56 func inDeadZone(pos, size uint32) bool { 57 msb := nextPowerOfTwo(size) 58 last := size - 1 // last valid position is 1 less than size 59 if pos > (msb<<1)-2 { // greater than root; not even in the tree 60 logging.Infof(" ?? greater than root ") 61 return true 62 } 63 h := msb 64 for pos >= h { 65 h = h>>1 | msb 66 last = last>>1 | msb 67 } 68 return pos > last 69 } 70 71 // take in a merkle block, parse through it, and return txids indicated 72 // If there's any problem return an error. Checks self-consistency only. 73 // doing it with a stack instead of recursion. Because... 74 // OK I don't know why I'm just not in to recursion OK? 75 func checkMBlock(m *wire.MsgMerkleBlock) ([]*chainhash.Hash, error) { 76 if m.Transactions == 0 { 77 return nil, fmt.Errorf("No transactions in merkleblock") 78 } 79 if len(m.Flags) == 0 { 80 return nil, fmt.Errorf("No flag bits") 81 } 82 var s []merkleNode // the stack 83 var r []*chainhash.Hash // slice to return; txids we care about 84 85 // set initial position to root of merkle tree 86 msb := nextPowerOfTwo(m.Transactions) // most significant bit possible 87 pos := (msb << 1) - 2 // current position in tree 88 89 var i uint8 // position in the current flag byte 90 var tip int 91 // main loop 92 for { 93 tip = len(s) - 1 // slice position of stack tip 94 // First check if stack operations can be performed 95 // is stack one filled item? that's complete. 96 if tip == 0 && s[0].h != nil { 97 if s[0].h.IsEqual(&m.Header.MerkleRoot) { 98 return r, nil 99 } 100 return nil, fmt.Errorf("computed root %s but expect %s\n", 101 s[0].h.String(), m.Header.MerkleRoot.String()) 102 } 103 // is current position in the tree's dead zone? partial parent 104 if inDeadZone(pos, m.Transactions) { 105 // create merkle parent from single side (left) 106 s[tip-1].h = MakeMerkleParent(s[tip].h, nil) 107 s = s[:tip] // remove 1 from stack 108 pos = s[tip-1].p | 1 // move position to parent's sibling 109 continue 110 } 111 // does stack have 3+ items? and are last 2 items filled? 112 if tip > 1 && s[tip-1].h != nil && s[tip].h != nil { 113 //logging.Infof("nodes %d and %d combine into %d\n", 114 // s[tip-1].p, s[tip].p, s[tip-2].p) 115 // combine two filled nodes into parent node 116 s[tip-2].h = MakeMerkleParent(s[tip-1].h, s[tip].h) 117 // remove children 118 s = s[:tip-1] 119 // move position to parent's sibling 120 pos = s[tip-2].p | 1 121 continue 122 } 123 124 // no stack ops to perform, so make new node from message hashes 125 if len(m.Hashes) == 0 { 126 return nil, fmt.Errorf("Ran out of hashes at position %d.", pos) 127 } 128 if len(m.Flags) == 0 { 129 return nil, fmt.Errorf("Ran out of flag bits.") 130 } 131 var n merkleNode // make new node 132 n.p = pos // set current position for new node 133 134 if pos&msb != 0 { // upper non-txid hash 135 if m.Flags[0]&(1<<i) == 0 { // flag bit says fill node 136 n.h = m.Hashes[0] // copy hash from message 137 m.Hashes = m.Hashes[1:] // pop off message 138 if pos&1 != 0 { // right side; ascend 139 pos = pos>>1 | msb 140 } else { // left side, go to sibling 141 pos |= 1 142 } 143 } else { // flag bit says skip; put empty on stack and descend 144 pos = (pos ^ msb) << 1 // descend to left 145 } 146 s = append(s, n) // push new node on stack 147 } else { // bottom row txid; flag bit indicates tx of interest 148 if pos >= m.Transactions { 149 // this can't happen because we check deadzone above... 150 return nil, fmt.Errorf("got into an invalid txid node") 151 } 152 n.h = m.Hashes[0] // copy hash from message 153 m.Hashes = m.Hashes[1:] // pop off message 154 if m.Flags[0]&(1<<i) != 0 { //txid of interest 155 r = append(r, n.h) 156 } 157 if pos&1 == 0 { // left side, go to sibling 158 pos |= 1 159 } // if on right side we don't move; stack ops will move next 160 s = append(s, n) // push new node onto the stack 161 } 162 163 // done with pushing onto stack; advance flag bit 164 i++ 165 if i == 8 { // move to next byte 166 i = 0 167 m.Flags = m.Flags[1:] 168 } 169 } 170 }