@@ -103,13 +103,90 @@ def __getBlockIndexes(self, index):
103103 self .indexPath = index
104104 return self .blockIndexes
105105
106+ def _index_confirmed (self , chain_indexes , num_confirmations = 6 ):
107+ """Check if the first block index in "chain_indexes" has at least
108+ "num_confirmation" (6) blocks built on top of it.
109+ If it doesn't it is not confirmed and is an orphan.
110+ """
111+
112+ # chains holds a 2D list of sequential block hash chains
113+ # as soon as there an element of length num_confirmations,
114+ # we can make a decision about whether or not the block in question
115+ # is confirmed by checking if it's hash is in that list
116+ chains = []
117+ # this is the block in question
118+ first_block = None
119+
120+ # loop through all future blocks
121+ for i , index in enumerate (chain_indexes ):
122+ # if this block doesn't have data don't confirm the block in question
123+ if index .file == - 1 or index .data_pos == - 1 :
124+ return False
125+
126+ # parse the block
127+ blkFile = os .path .join (self .path , "blk%05d.dat" % index .file )
128+ block = Block (get_block (blkFile , index .data_pos ))
129+
130+ if i == 0 :
131+ first_block = block
132+
133+ chains .append ([block .hash ])
134+
135+ for chain in chains :
136+ # if this block can be appended to an existing block in one
137+ # of the chains, do it
138+ if chain [- 1 ] == block .header .previous_block_hash :
139+ chain .append (block .hash )
140+
141+ # if we've found a chain whose length == num_dependencies (usually 6)
142+ # we are ready to make a decesion on whether or not the block in
143+ # question belongs to a fork or the main chain
144+ if len (chain ) == num_confirmations :
145+ if first_block .hash in chain : return True
146+ else : return False
147+
106148 def get_ordered_blocks (self , index , start = 0 , end = None ):
107149 """Yields the blocks contained in the .blk files as per
108150 the heigt extract from the leveldb index present at path
109151 index maintained by bitcoind.
110152 """
111153 blockIndexes = self .__getBlockIndexes (index )
112154
155+ # remove small forks that may have occured while the node was running live.
156+ # Occassionally a node will receive two different solutions to the next block
157+ # at the same time. The Leveldb index seems to save both, not pruning the
158+ # the block that leads to a shorter chain once the fork is settled without
159+ # "-reindex"ing the bitcoind block data. This leads to at least two
160+ # blocks with the same height in the database.
161+ # We throw out blocks that don't have at least 6 other blocks on top of
162+ # it (6 confirmations).
163+ orphans = [] # hold blocks that are orphans/forks with < 6 blocks built on top
164+ last_height = - 1
165+ for i , blockIdx in enumerate (blockIndexes ):
166+ if last_height > - 1 :
167+ # if this block is the same height as the last block an orphan has
168+ # occurred, now we have to figure out which of the two to keep
169+ if blockIdx .height == last_height :
170+
171+ # loop through future blocks until we find a chain of at least
172+ # six blocks that includes this block. If we can't find one
173+ # remove this block as it is invalid
174+ if self ._index_confirmed (blockIndexes [i :]):
175+
176+ # if this block is confirmed, the unconfirmed block is
177+ # the previous one. Remove it.
178+ orphans .append (blockIndexes [i - 1 ].hash )
179+ else :
180+
181+ # if this block isn't confirmed, remove it.
182+ orphans .append (blockIndexes [i ].hash )
183+
184+ last_height = blockIdx .height
185+
186+ # filter out the orphan blocks, so we are left only with block indexes
187+ # that have been confirmed (or are new enough that they haven't yet been confirmed)
188+ blockIndexes = list (filter (lambda block : block .hash not in orphans , blockIndexes ))
189+
113190 if end is None :
114191 end = len (blockIndexes )
115192
0 commit comments