1616import sys
1717import time
1818
19- from .script import CScript , CScriptWitness
19+ from .script import CScript , CScriptWitness , CScriptOp , OP_RETURN
2020
2121from .serialize import *
2222
23+ if sys .version > '3' :
24+ _bytes = bytes
25+ else :
26+ _bytes = lambda x : bytes (bytearray (x ))
27+
2328# Core definitions
2429COIN = 100000000
2530MAX_BLOCK_SIZE = 1000000
31+ MAX_BLOCK_WEIGHT = 4000000
2632MAX_BLOCK_SIGOPS = MAX_BLOCK_SIZE / 50
33+ WITNESS_COINBASE_SCRIPTPUBKEY_MAGIC = _bytes ([OP_RETURN , 0x24 , 0xaa , 0x21 , 0xa9 , 0xed ])
2734
2835def MoneyRange (nValue , params = None ):
2936 global coreparams
@@ -426,9 +433,9 @@ def stream_deserialize(cls, f):
426433 return cls (vin , vout , nLockTime , nVersion )
427434
428435
429- def stream_serialize (self , f ):
436+ def stream_serialize (self , f , include_witness = True ):
430437 f .write (struct .pack (b"<i" , self .nVersion ))
431- if not self .wit .is_null ():
438+ if include_witness and not self .wit .is_null ():
432439 assert (len (self .wit .vtxinwit ) <= len (self .vin ))
433440 f .write (b'\x00 ' ) # Marker
434441 f .write (b'\x01 ' ) # Flag
@@ -443,6 +450,10 @@ def stream_serialize(self, f):
443450 def is_coinbase (self ):
444451 return len (self .vin ) == 1 and self .vin [0 ].prevout .is_null ()
445452
453+ def has_witness (self ):
454+ """True if witness"""
455+ return not self .wit .is_null ()
456+
446457 def __repr__ (self ):
447458 return "CTransaction(%r, %r, %i, %i, %r)" % (self .vin , self .vout ,
448459 self .nLockTime , self .nVersion , self .wit )
@@ -561,9 +572,12 @@ def __repr__(self):
561572 (self .__class__ .__name__ , self .nVersion , b2lx (self .hashPrevBlock ), b2lx (self .hashMerkleRoot ),
562573 self .nTime , self .nBits , self .nNonce )
563574
575+ class NoWitnessData (Exception ):
576+ """The block does not have witness data"""
577+
564578class CBlock (CBlockHeader ):
565579 """A block including all transactions in it"""
566- __slots__ = ['vtx' , 'vMerkleTree' ]
580+ __slots__ = ['vtx' , 'vMerkleTree' , 'vWitnessMerkleTree' ]
567581
568582 @staticmethod
569583 def build_merkle_tree_from_txids (txids ):
@@ -612,12 +626,60 @@ def calc_merkle_root(self):
612626 raise ValueError ('Block contains no transactions' )
613627 return self .build_merkle_tree_from_txs (self .vtx )[- 1 ]
614628
629+ @staticmethod
630+ def build_witness_merkle_tree_from_txs (txs ):
631+ """Calculate the witness merkle tree from transactions"""
632+ has_witness = False
633+ hashes = []
634+ for tx in txs :
635+ hashes .append (tx .GetHash ())
636+ has_witness |= tx .has_witness ()
637+ if not has_witness :
638+ raise NoWitnessData
639+ hashes [0 ] = b'\x00 ' * 32
640+ return CBlock .build_merkle_tree_from_txids (hashes )
641+
642+ def calc_witness_merkle_root (self ):
643+ """Calculate the witness merkle root
644+
645+ The calculated merkle root is not cached; every invocation
646+ re-calculates it from scratch.
647+ """
648+ if not len (self .vtx ):
649+ raise ValueError ('Block contains no transactions' )
650+ return self .build_witness_merkle_tree_from_txs (self .vtx )[- 1 ]
651+
652+ def get_witness_commitment_index (self ):
653+ """Return None or an index"""
654+ if not len (self .vtx ):
655+ raise ValueError ('Block contains no transactions' )
656+ commit_pos = None
657+ for index , out in enumerate (self .vtx [0 ].vout ):
658+ script = out .scriptPubKey
659+ if len (script ) >= 38 and script [:6 ] == WITNESS_COINBASE_SCRIPTPUBKEY_MAGIC :
660+ commit_pos = index
661+ if commit_pos is None :
662+ raise ValueError ('The witness commitment is missed' )
663+ return commit_pos
664+
615665 def __init__ (self , nVersion = 2 , hashPrevBlock = b'\x00 ' * 32 , hashMerkleRoot = b'\x00 ' * 32 , nTime = 0 , nBits = 0 , nNonce = 0 , vtx = ()):
616666 """Create a new block"""
667+ if vtx :
668+ vMerkleTree = tuple (CBlock .build_merkle_tree_from_txs (vtx ))
669+ if hashMerkleRoot == b'\x00 ' * 32 :
670+ hashMerkleRoot = vMerkleTree [- 1 ]
671+ elif hashMerkleRoot != vMerkleTree [- 1 ]:
672+ raise CheckBlockError ("CBlock : hashMerkleRoot is not compatible with vtx" )
673+ else :
674+ vMerkleTree = ()
617675 super (CBlock , self ).__init__ (nVersion , hashPrevBlock , hashMerkleRoot , nTime , nBits , nNonce )
618676
619- vMerkleTree = tuple (CBlock .build_merkle_tree_from_txs (vtx ))
620677 object .__setattr__ (self , 'vMerkleTree' , vMerkleTree )
678+ try :
679+ vWitnessMerkleTree = tuple (CBlock .build_witness_merkle_tree_from_txs (vtx ))
680+ except NoWitnessData :
681+ vWitnessMerkleTree = ()
682+ object .__setattr__ (self , 'vWitnessMerkleTree' , vWitnessMerkleTree )
621683 object .__setattr__ (self , 'vtx' , tuple (CTransaction .from_tx (tx ) for tx in vtx ))
622684
623685 @classmethod
@@ -627,13 +689,18 @@ def stream_deserialize(cls, f):
627689 vtx = VectorSerializer .stream_deserialize (CTransaction , f )
628690 vMerkleTree = tuple (CBlock .build_merkle_tree_from_txs (vtx ))
629691 object .__setattr__ (self , 'vMerkleTree' , vMerkleTree )
692+ try :
693+ vWitnessMerkleTree = tuple (CBlock .build_witness_merkle_tree_from_txs (vtx ))
694+ except NoWitnessData :
695+ vWitnessMerkleTree = ()
696+ object .__setattr__ (self , 'vWitnessMerkleTree' , vWitnessMerkleTree )
630697 object .__setattr__ (self , 'vtx' , tuple (vtx ))
631698
632699 return self
633700
634- def stream_serialize (self , f ):
701+ def stream_serialize (self , f , include_witness = True ):
635702 super (CBlock , self ).stream_serialize (f )
636- VectorSerializer .stream_serialize (CTransaction , self .vtx , f )
703+ VectorSerializer .stream_serialize (CTransaction , self .vtx , f , dict ( include_witness = include_witness ) )
637704
638705 def get_header (self ):
639706 """Return the block header
@@ -660,6 +727,10 @@ def GetHash(self):
660727 object .__setattr__ (self , '_cached_GetHash' , _cached_GetHash )
661728 return _cached_GetHash
662729
730+ def GetWeight (self ):
731+ """Return the block weight: (stripped_size * 3) + total_size"""
732+ return len (self .serialize (dict (include_witness = False ))) * 3 + len (self .serialize ())
733+
663734class CoreChainParams (object ):
664735 """Define consensus-critical parameters of a given instance of the Bitcoin system"""
665736 MAX_MONEY = None
@@ -721,7 +792,8 @@ def CheckTransaction(tx):
721792 raise CheckTransactionError ("CheckTransaction() : vout empty" )
722793
723794 # Size limits
724- if len (tx .serialize ()) > MAX_BLOCK_SIZE :
795+ base_tx = CTransaction (tx .vin , tx .vout , tx .nLockTime , tx .nVersion )
796+ if len (base_tx .serialize ()) > MAX_BLOCK_SIZE :
725797 raise CheckTransactionError ("CheckTransaction() : size limits failed" )
726798
727799 # Check for negative or overflow output values
@@ -820,7 +892,8 @@ def CheckBlock(block, fCheckPoW = True, fCheckMerkleRoot = True, cur_time=None):
820892
821893 fCheckPoW - Check proof-of-work.
822894
823- fCheckMerkleRoot - Check merkle root matches transactions.
895+ fCheckMerkleRoot - Check merkle root and witness merkle root matches transactions.
896+ - Check witness commitment in coinbase
824897
825898 cur_time - Current time. Defaults to time.time()
826899 """
@@ -831,9 +904,12 @@ def CheckBlock(block, fCheckPoW = True, fCheckMerkleRoot = True, cur_time=None):
831904 # Size limits
832905 if not block .vtx :
833906 raise CheckBlockError ("CheckBlock() : vtx empty" )
834- if len (block .serialize ()) > MAX_BLOCK_SIZE :
907+ if len (block .serialize (dict ( include_witness = False ) )) > MAX_BLOCK_SIZE :
835908 raise CheckBlockError ("CheckBlock() : block larger than MAX_BLOCK_SIZE" )
836909
910+ if block .GetWeight () > MAX_BLOCK_WEIGHT :
911+ raise CheckBlockError ("CheckBlock() : block larger than MAX_BLOCK_WEIGHT" )
912+
837913 # First transaction must be coinbase
838914 if not block .vtx [0 ].is_coinbase ():
839915 raise CheckBlockError ("CheckBlock() : first tx is not coinbase" )
@@ -861,8 +937,29 @@ def CheckBlock(block, fCheckPoW = True, fCheckMerkleRoot = True, cur_time=None):
861937 raise CheckBlockError ("CheckBlock() : out-of-bounds SigOpCount" )
862938
863939 # Check merkle root
864- if fCheckMerkleRoot and block .hashMerkleRoot != block .calc_merkle_root ():
865- raise CheckBlockError ("CheckBlock() : hashMerkleRoot mismatch" )
940+ if fCheckMerkleRoot :
941+ if block .hashMerkleRoot != block .calc_merkle_root ():
942+ raise CheckBlockError ("CheckBlock() : hashMerkleRoot mismatch" )
943+ if len (block .vWitnessMerkleTree ):
944+ # At least 1 tx has witness: check witness merkle tree
945+ root = block .vWitnessMerkleTree [- 1 ]
946+ # vtx[0]: coinbase
947+ # vtxinwit[0]: first input
948+ nonce_script = block .vtx [0 ].wit .vtxinwit [0 ].scriptWitness
949+ nonce = nonce_script .stack [0 ]
950+ if len (nonce_script .stack ) != 1 or len (nonce ) != 32 :
951+ raise CheckBlockError ("CheckBlock() : invalid coinbase witnessScript" )
952+ try :
953+ index = block .get_witness_commitment_index ()
954+ except ValueError as e :
955+ raise CheckBlockError ("CheckBlock() : " + str (e ))
956+ commit_script = block .vtx [0 ].vout [index ].scriptPubKey
957+ if not (6 + 32 <= len (commit_script ) <= 6 + 32 + 1 ):
958+ raise CheckBlockError ("CheckBlock() : invalid segwit commitment length" )
959+ commitment = commit_script [6 :6 + 32 ]
960+ commit = commit_script [6 :6 + 32 ]
961+ if commit != Hash (root + nonce ):
962+ raise CheckBlockError ("CheckBlock() : invalid segwit commitment" )
866963
867964__all__ = (
868965 'Hash' ,
@@ -885,6 +982,8 @@ def CheckBlock(block, fCheckPoW = True, fCheckMerkleRoot = True, cur_time=None):
885982 'CMutableTxOut' ,
886983 'CTransaction' ,
887984 'CMutableTransaction' ,
985+ 'CTxWitness' ,
986+ 'CTxInWitness' ,
888987 'CBlockHeader' ,
889988 'CBlock' ,
890989 'CoreChainParams' ,
0 commit comments