@@ -91,6 +91,9 @@ type blockNode struct {
91
91
// parent is the parent block for this node.
92
92
parent * blockNode
93
93
94
+ // ancestor is a block that is more than one block back from this node.
95
+ ancestor * blockNode
96
+
94
97
// hash is the double sha 256 of the block.
95
98
hash chainhash.Hash
96
99
@@ -137,6 +140,7 @@ func initBlockNode(node *blockNode, blockHeader *wire.BlockHeader, parent *block
137
140
node .parent = parent
138
141
node .height = parent .height + 1
139
142
node .workSum = node .workSum .Add (parent .workSum , node .workSum )
143
+ node .buildAncestor ()
140
144
}
141
145
}
142
146
@@ -168,6 +172,26 @@ func (node *blockNode) Header() wire.BlockHeader {
168
172
}
169
173
}
170
174
175
+ // invertLowestOne turns the lowest 1 bit in the binary representation of a number into a 0.
176
+ func invertLowestOne (n int32 ) int32 {
177
+ return n & (n - 1 )
178
+ }
179
+
180
+ // getAncestorHeight returns a suitable ancestor for the node at the given height.
181
+ func getAncestorHeight (height int32 ) int32 {
182
+ // We pop off two 1 bits of the height.
183
+ // This results in a maximum of 330 steps to go back to an ancestor
184
+ // from height 1<<29.
185
+ return invertLowestOne (invertLowestOne (height ))
186
+ }
187
+
188
+ // buildAncestor sets an ancestor for the given blocknode.
189
+ func (node * blockNode ) buildAncestor () {
190
+ if node .parent != nil {
191
+ node .ancestor = node .parent .Ancestor (getAncestorHeight (node .height ))
192
+ }
193
+ }
194
+
171
195
// Ancestor returns the ancestor block node at the provided height by following
172
196
// the chain backwards from this node. The returned block will be nil when a
173
197
// height is requested that is after the height of the passed node or is less
@@ -179,9 +203,22 @@ func (node *blockNode) Ancestor(height int32) *blockNode {
179
203
return nil
180
204
}
181
205
206
+ // Traverse back until we find the desired node.
182
207
n := node
183
- for ; n != nil && n .height != height ; n = n .parent {
184
- // Intentionally left blank
208
+ for n != nil && n .height != height {
209
+ // If there's an ancestor available, use it. Otherwise, just
210
+ // follow the parent.
211
+ if n .ancestor != nil {
212
+ // Calculate the height for this ancestor and
213
+ // check if we can take the ancestor skip.
214
+ if getAncestorHeight (n .height ) >= height {
215
+ n = n .ancestor
216
+ continue
217
+ }
218
+ }
219
+
220
+ // We couldn't take the ancestor skip so traverse back to the parent.
221
+ n = n .parent
185
222
}
186
223
187
224
return n
0 commit comments