@@ -539,6 +539,123 @@ def GetHash(self):
539539 object .__setattr__ (self , '_cached_GetHash' , _cached_GetHash )
540540 return _cached_GetHash
541541
542+ class CMerkleBlock (CBlockHeader ):
543+ """
544+ The merkle block returned to spv clients when a filter is set on the remote peer.
545+ """
546+
547+ __slots__ = ['nTX' , 'vHashes' , 'vFlags' ]
548+
549+ def __init__ (self , nVersion = 3 , hashPrevBlock = b'\x00 ' * 32 , hashMerkleRoot = b'\x00 ' * 32 , nTime = 0 , nBits = 0 , nNonce = 0 , nTX = 0 , vHashes = (), vFlags = ()):
550+ """Create a new block"""
551+ super (CMerkleBlock , self ).__init__ (nVersion , hashPrevBlock , hashMerkleRoot , nTime , nBits , nNonce )
552+
553+ object .__setattr__ (self , 'nTX' , nTX )
554+ object .__setattr__ (self , 'vHashes' , vHashes )
555+ object .__setattr__ (self , 'vFlags' , vFlags )
556+
557+ @classmethod
558+ def stream_deserialize (cls , f ):
559+
560+ def bits (f , n ):
561+ ret = []
562+ bytes = (ord (b ) for b in f .read (n ))
563+ for b in bytes :
564+ for i in xrange (8 ):
565+ ret .append ((b >> i ) & 1 )
566+ return ret
567+
568+ self = super (CMerkleBlock , cls ).stream_deserialize (f )
569+
570+ nTX = struct .unpack ('<L' , ser_read (f , 4 ))[0 ]
571+ nHashes = VarIntSerializer .stream_deserialize (f )
572+ vHashes = []
573+ for i in range (nHashes ):
574+ vHashes .append (ser_read (f , 32 ))
575+ nFlags = VarIntSerializer .stream_deserialize (f )
576+ vFlags = bits (f , nFlags )
577+ object .__setattr__ (self , 'nTX' , nTX )
578+ object .__setattr__ (self , 'vHashes' , vHashes )
579+ object .__setattr__ (self , 'vFlags' , vFlags )
580+
581+ return self
582+
583+ def stream_serialize (self , f ):
584+ super (CMerkleBlock , self ).stream_serialize (f )
585+ f .write (struct .pack ('<L' , self .nTX ))
586+ VarIntSerializer .stream_serialize (len (self .vHashes ), f )
587+ for hash in self .vHashes :
588+ f .write (hash )
589+ VarIntSerializer .stream_serialize (int (len (self .vFlags )/ 8 ), f )
590+ bin_string = ""
591+ for bit in self .vFlags :
592+ bin_string += str (bit )
593+ if len (bin_string ) == 8 :
594+ f .write (struct .pack ('B' , int (bin_string [::- 1 ], 2 )))
595+ bin_string = ""
596+
597+ def get_matched_txs (self ):
598+ """
599+ Return a list of transaction hashes that matched the filter. These txs
600+ have been validated against the merkle tree structure and are definitely
601+ in the block. However, the block hash still needs to be checked against
602+ the best chain.
603+ """
604+ def getTreeWidth (transaction_count , height ):
605+ return (transaction_count + (1 << height ) - 1 ) >> height
606+
607+ matched_hashes = []
608+
609+ def recursive_extract_hashes (height , pos ):
610+ parent_of_match = bool (self .vFlags .pop (0 ))
611+ if height == 0 or not parent_of_match :
612+ hash = self .vHashes .pop (0 )
613+ if height == 0 and parent_of_match :
614+ matched_hashes .append (hash )
615+ return hash
616+ else :
617+ left = recursive_extract_hashes (height - 1 , pos * 2 )
618+ if pos * 2 + 1 < getTreeWidth (self .nTX , height - 1 ):
619+ right = recursive_extract_hashes (height - 1 , pos * 2 + 1 )
620+ if left == right :
621+ raise Exception ("Invalid Merkle Tree" )
622+ else :
623+ right = left
624+ return sha256 (sha256 (left + right ).digest ()).digest ()
625+
626+ height = 0
627+ while getTreeWidth (self .nTX , height ) > 1 :
628+ height += 1
629+
630+ calculated_root = recursive_extract_hashes (height , 0 )
631+ if calculated_root == self .get_header ().hashMerkleRoot :
632+ return matched_hashes
633+ else :
634+ return None
635+
636+ def get_header (self ):
637+ """Return the block header
638+ Returned header is a new object.
639+ """
640+ return CBlockHeader (nVersion = self .nVersion ,
641+ hashPrevBlock = self .hashPrevBlock ,
642+ hashMerkleRoot = self .hashMerkleRoot ,
643+ nTime = self .nTime ,
644+ nBits = self .nBits ,
645+ nNonce = self .nNonce )
646+
647+ def GetHash (self ):
648+ """Return the block hash
649+ Note that this is the hash of the header, not the entire serialized
650+ block.
651+ """
652+ try :
653+ return self ._cached_GetHash
654+ except AttributeError :
655+ _cached_GetHash = self .get_header ().GetHash ()
656+ object .__setattr__ (self , '_cached_GetHash' , _cached_GetHash )
657+ return _cached_GetHash
658+
542659class CoreChainParams (object ):
543660 """Define consensus-critical parameters of a given instance of the Bitcoin system"""
544661 MAX_MONEY = None
@@ -766,6 +883,7 @@ def CheckBlock(block, fCheckPoW = True, fCheckMerkleRoot = True, cur_time=None):
766883 'CMutableTransaction' ,
767884 'CBlockHeader' ,
768885 'CBlock' ,
886+ 'CMerkleBlock' ,
769887 'CoreChainParams' ,
770888 'CoreMainParams' ,
771889 'CoreTestNetParams' ,
0 commit comments