Пример #1
0
 def test_int_to_little_endian(self):
     n = 1
     want = b"\x01\x00\x00\x00"
     self.assertEqual(int_to_little_endian(n, 4), want)
     n = 10011545
     want = b"\x99\xc3\x98\x00\x00\x00\x00\x00"
     self.assertEqual(int_to_little_endian(n, 8), want)
Пример #2
0
 def sig_hash_bip143(
     self,
     input_index,
     redeem_script=None,
     witness_script=None,
     hash_type=SIGHASH_ALL,
 ):
     """Returns the integer representation of the hash that needs to get
     signed for index input_index"""
     # grab the input being signed by looking up the input_index
     tx_in = self.tx_ins[input_index]
     # start with the version in 4 bytes, little endian
     s = int_to_little_endian(self.version, 4)
     # add the HashPrevouts and HashSequence
     if hash_type & SIGHASH_ANYONECANPAY != SIGHASH_ANYONECANPAY:
         s += self.hash_prevouts()
     if hash_type & SIGHASH_ANYONECANPAY != SIGHASH_ANYONECANPAY and (
             hash_type & 3) not in (SIGHASH_SINGLE, SIGHASH_NONE):
         s += self.hash_sequence()
     # add the previous transaction hash in little endian
     s += tx_in.prev_tx[::-1]
     # add the previous transaction index in 4 bytes, little endian
     s += int_to_little_endian(tx_in.prev_index, 4)
     # for p2wpkh, we need to compute the ScriptCode
     # Exercise 1: account for p2wsh. Check first for the existence of a WitnessScript
     if witness_script:
         # for p2wsh and p2sh-p2wsh the ScriptCode is the WitnessScript
         script_code = witness_script
     elif redeem_script:
         # for p2sh-p2wpkh, get the hash160 which is the 2nd command of the RedeemScript
         h160 = redeem_script.commands[1]
         # the ScriptCode is the P2PKHScriptPubKey created using the hash160
         script_code = P2PKHScriptPubKey(h160)
     else:
         # get the script pubkey associated with the previous output (remember network)
         script_pubkey = tx_in.script_pubkey(self.network)
         # next get the hash160 in the script_pubkey. for p2wpkh, it's the second command
         h160 = script_pubkey.commands[1]
         # finally the ScriptCode is the P2PKHScriptPubKey created using the hash160
         script_code = P2PKHScriptPubKey(h160)
     # add the serialized ScriptCode
     s += script_code.serialize()
     # add the value of the input in 8 bytes, little endian
     s += int_to_little_endian(tx_in.value(network=self.network), 8)
     # add the sequence of the input in 4 bytes, little endian
     s += tx_in.sequence.serialize()
     # add the HashOutputs
     if (hash_type & 3) not in (SIGHASH_SINGLE, SIGHASH_NONE):
         s += self.hash_outputs()
     elif hash_type & SIGHASH_SINGLE == SIGHASH_SINGLE:
         s += self.tx_outs[input_index].serialize()
     # add the locktime in 4 bytes, little endian
     s += self.locktime.serialize()
     # add the sighash (SIGHASH_ALL) in 4 bytes, little endian
     s += int_to_little_endian(hash_type, 4)
     # hash256 the whole thing, interpret the as a big endian integer using int_to_big_endian
     return big_endian_to_int(hash256(s))
Пример #3
0
 def filterload(self, flag=1):
     """Return a network message whose command is filterload"""
     # encode_varint self.size
     payload = encode_varint(self.size)
     # next is the self.filter_bytes()
     payload += self.filter_bytes()
     # function count is 4 bytes little endian
     payload += int_to_little_endian(self.function_count, 4)
     # tweak is 4 bytes little endian
     payload += int_to_little_endian(self.tweak, 4)
     # flag is 1 byte little endian
     payload += int_to_byte(flag)
     # return a GenericMessage with b'filterload' as the command
     return GenericMessage(b"filterload", payload)
Пример #4
0
 def serialize(self):
     """Serialize this message to send over the network"""
     # version is 4 bytes little endian
     result = int_to_little_endian(self.version, 4)
     # services is 8 bytes little endian
     result += int_to_little_endian(self.services, 8)
     # timestamp is 8 bytes little endian
     result += int_to_little_endian(self.timestamp, 8)
     # receiver services is 8 bytes little endian
     result += int_to_little_endian(self.receiver_services, 8)
     # IPV4 is 10 00 bytes and 2 ff bytes then receiver ip
     result += b"\x00" * 10 + b"\xff\xff" + self.receiver_ip
     # receiver port is 2 bytes, little endian
     result += int_to_little_endian(self.receiver_port, 2)
     # sender services is 8 bytes little endian
     result += int_to_little_endian(self.sender_services, 8)
     # IPV4 is 10 00 bytes and 2 ff bytes then sender ip
     result += b"\x00" * 10 + b"\xff\xff" + self.sender_ip
     # sender port is 2 bytes, little endian
     result += int_to_little_endian(self.sender_port, 2)
     # nonce
     result += self.nonce
     # useragent is a variable string, so varint first
     result += encode_varint(len(self.user_agent))
     result += self.user_agent
     # latest block is 4 bytes little endian
     result += int_to_little_endian(self.latest_block, 4)
     # relay is 00 if false, 01 if true
     if self.relay:
         result += b"\x01"
     else:
         result += b"\x00"
     return result
Пример #5
0
 def serialize(self):
     """Returns the 80 byte block header"""
     # version - 4 bytes, little endian
     result = int_to_little_endian(self.version, 4)
     # prev_block - 32 bytes, little endian
     result += self.prev_block[::-1]
     # merkle_root - 32 bytes, little endian
     result += self.merkle_root[::-1]
     # timestamp - 4 bytes, little endian
     result += int_to_little_endian(self.timestamp, 4)
     # bits - 4 bytes
     result += self.bits
     # nonce - 4 bytes
     result += self.nonce
     return result
Пример #6
0
 def serialize(self):
     """Returns the byte serialization of the transaction output"""
     # serialize amount, 8 bytes, little endian
     result = int_to_little_endian(self.amount, 8)
     # serialize the script_pubkey
     result += self.script_pubkey.serialize()
     return result
Пример #7
0
 def raw_serialize(self):
     if self.raw:
         return self.raw
     # initialize what we'll send back
     result = b""
     # go through each command
     for command in self.commands:
         # if the command is an integer, it's an op code
         if type(command) == int:
             # turn the command into a single byte integer using int_to_byte
             result += int_to_byte(command)
         else:
             # otherwise, this is an element
             # get the length in bytes
             length = len(command)
             # for large lengths, we have to use a pushdata op code
             if length < 75:
                 # turn the length into a single byte integer
                 result += int_to_byte(length)
             elif length > 75 and length < 0x100:
                 # 76 is pushdata1
                 result += int_to_byte(76)
                 result += int_to_byte(length)
             elif length >= 0x100 and length <= 520:
                 # 77 is pushdata2
                 result += int_to_byte(77)
                 result += int_to_little_endian(length, 2)
             else:
                 raise ValueError("too long a command")
             result += command
     return result
Пример #8
0
 def __init__(
     self,
     version=70015,
     services=0,
     timestamp=None,
     receiver_services=0,
     receiver_ip=b"\x00\x00\x00\x00",
     receiver_port=8333,
     sender_services=0,
     sender_ip=b"\x00\x00\x00\x00",
     sender_port=8333,
     nonce=None,
     user_agent=b"/programmingblockchain:0.1/",
     latest_block=0,
     relay=True,
 ):
     self.version = version
     self.services = services
     if timestamp is None:
         self.timestamp = int(time.time())
     else:
         self.timestamp = timestamp
     self.receiver_services = receiver_services
     self.receiver_ip = receiver_ip
     self.receiver_port = receiver_port
     self.sender_services = sender_services
     self.sender_ip = sender_ip
     self.sender_port = sender_port
     if nonce is None:
         self.nonce = int_to_little_endian(randint(0, 2**64), 8)
     else:
         self.nonce = nonce
     self.user_agent = user_agent
     self.latest_block = latest_block
     self.relay = relay
Пример #9
0
 def serialize(self):
     # start with the number of items as a varint
     result = encode_varint(len(self.data))
     for data_type, identifier in self.data:
         # data type is 4 bytes little endian
         result += int_to_little_endian(data_type, 4)
         # identifier needs to be in little endian
         result += identifier[::-1]
     return result
Пример #10
0
 def sha_prevouts(self):
     if self._sha_prevouts is None:
         all_prevouts = b""
         all_amounts = b""
         all_script_pubkeys = b""
         all_sequence = b""
         for tx_in in self.tx_ins:
             all_prevouts += tx_in.prev_tx[::-1] + int_to_little_endian(
                 tx_in.prev_index, 4)
             all_amounts += int_to_little_endian(tx_in.value(self.network),
                                                 8)
             all_script_pubkeys += tx_in.script_pubkey(
                 self.network).serialize()
             all_sequence += tx_in.sequence.serialize()
         self._sha_prevouts = sha256(all_prevouts)
         self._sha_amounts = sha256(all_amounts)
         self._sha_script_pubkeys = sha256(all_script_pubkeys)
         self._sha_sequences = sha256(all_sequence)
     return self._sha_prevouts
Пример #11
0
 def serialize(self):
     """Returns the byte serialization of the transaction input"""
     # serialize prev_tx, little endian
     result = self.prev_tx[::-1]
     # serialize prev_index, 4 bytes, little endian
     result += int_to_little_endian(self.prev_index, 4)
     # serialize the script_sig
     result += self.script_sig.serialize()
     # serialize sequence, 4 bytes, little endian
     result += self.sequence.serialize()
     return result
Пример #12
0
 def hash_prevouts(self):
     if self._hash_prevouts is None:
         all_prevouts = b""
         all_sequence = b""
         for tx_in in self.tx_ins:
             all_prevouts += tx_in.prev_tx[::-1] + int_to_little_endian(
                 tx_in.prev_index, 4)
             all_sequence += tx_in.sequence.serialize()
         self._hash_prevouts = hash256(all_prevouts)
         self._hash_sequence = hash256(all_sequence)
     return self._hash_prevouts
Пример #13
0
 def serialize(self):
     """Serialize this message to send over the network"""
     # protocol version is 4 bytes little-endian
     result = int_to_little_endian(self.version, 4)
     # number of hashes is a varint
     result += encode_varint(self.num_hashes)
     # start block is in little-endian
     result += self.start_block[::-1]
     # end block is also in little-endian
     result += self.end_block[::-1]
     return result
Пример #14
0
 def serialize(self):
     """Returns the byte serialization of the entire network message"""
     # add the network magic using self.magic
     result = self.magic
     # command 12 bytes, fill leftover with b'\x00' * (12 - len(self.command))
     result += self.command + b"\x00" * (12 - len(self.command))
     # payload length 4 bytes, little endian
     result += int_to_little_endian(len(self.payload), 4)
     # checksum 4 bytes, first four of hash256 of payload
     result += hash256(self.payload)[:4]
     # payload
     result += self.payload
     return result
Пример #15
0
 def sig_hash_bip341(self,
                     input_index,
                     ext_flag=0,
                     hash_type=SIGHASH_DEFAULT):
     """Returns the root message being signed for p2tr"""
     tx_in = self.tx_ins[input_index]
     s = b"\x00"
     s += int_to_byte(hash_type)
     s += int_to_little_endian(self.version, 4)
     s += self.locktime.serialize()
     if not hash_type & SIGHASH_ANYONECANPAY:
         s += self.sha_prevouts()
         s += self.sha_amounts()
         s += self.sha_script_pubkeys()
         s += self.sha_sequences()
     if (hash_type & 3) not in (SIGHASH_NONE, SIGHASH_SINGLE):
         s += self.sha_outputs()
     spend_type = ext_flag * 2
     if tx_in.witness.has_annex():
         spend_type += 1
     s += int_to_byte(spend_type)
     if hash_type & SIGHASH_ANYONECANPAY:
         s += tx_in.prev_tx[::-1] + int_to_little_endian(
             tx_in.prev_index, 4)
         s += int_to_little_endian(tx_in.value(), 8)
         s += tx_in.script_pubkey().serialize()
         s += tx_in.sequence.serialize()
     else:
         s += int_to_little_endian(input_index, 4)
     if hash_type & SIGHASH_SINGLE == SIGHASH_SINGLE:
         s += sha256(self.tx_outs[input_index].serialize())
     if tx_in.witness.has_annex():
         s += sha256(encode_varstr(tx_in.witness[-1]))
     if ext_flag == 1:
         tapleaf_hash = tx_in.witness.tap_leaf().hash()
         # extension defined in BIP0342
         s += tapleaf_hash + b"\x00\xff\xff\xff\xff"
     return hash_tapsighash(s)
Пример #16
0
 def serialize_legacy(self):
     """Returns the byte serialization of the transaction"""
     # serialize version (4 bytes, little endian)
     result = int_to_little_endian(self.version, 4)
     # encode_varint on the number of inputs
     result += encode_varint(len(self.tx_ins))
     # iterate inputs
     for tx_in in self.tx_ins:
         # serialize each input
         result += tx_in.serialize()
     # encode_varint on the number of outputs
     result += encode_varint(len(self.tx_outs))
     # iterate outputs
     for tx_out in self.tx_outs:
         # serialize each output
         result += tx_out.serialize()
     # serialize locktime (4 bytes, little endian)
     result += self.locktime.serialize()
     return result
Пример #17
0
 def serialize(self):
     result = self.filter_type.to_bytes(1, "big")
     result += int_to_little_endian(self.start_height, 4)
     result += self.stop_hash[::-1]
     return result
Пример #18
0
    def sig_hash_legacy(self,
                        input_index,
                        redeem_script=None,
                        hash_type=SIGHASH_ALL):
        """Returns the integer representation of the hash that needs to get
        signed for index input_index"""

        # consensus bugs related to invalid input indices
        DEFAULT = 1 << 248
        if input_index >= len(self.tx_ins):
            return DEFAULT
        elif hash_type & 3 == SIGHASH_SINGLE and input_index >= len(
                self.tx_outs):
            return DEFAULT
        # create the serialization per spec
        # start with version: int_to_little_endian in 4 bytes
        s = int_to_little_endian(self.version, 4)
        # next, how many inputs there are: encode_varint
        s += encode_varint(len(self.tx_ins))
        # loop through each input: for i, tx_in in enumerate(self.tx_ins)
        for i, tx_in in enumerate(self.tx_ins):
            sequence = tx_in.sequence
            # if the input index is the one we're signing
            if i == input_index:
                # if the RedeemScript was passed in, that's the ScriptSig
                if redeem_script:
                    script_sig = redeem_script
                # otherwise the previous tx's ScriptPubkey is the ScriptSig
                else:
                    script_sig = tx_in.script_pubkey(self.network)
            # Otherwise, the ScriptSig is empty
            else:
                script_sig = None
                if hash_type & 3 in (SIGHASH_NONE, SIGHASH_SINGLE):
                    sequence = Sequence(0)
            # create a TxIn object with the prev_tx, prev_index and sequence
            # the same as the current tx_in and the script_sig from above
            new_tx_in = TxIn(
                prev_tx=tx_in.prev_tx,
                prev_index=tx_in.prev_index,
                script_sig=script_sig,
                sequence=sequence,
            )
            # add the serialization of the TxIn object
            if hash_type & SIGHASH_ANYONECANPAY:
                if i == input_index:
                    s += new_tx_in.serialize()
            else:
                s += new_tx_in.serialize()
        # add how many outputs there are using encode_varint
        s += encode_varint(len(self.tx_outs))
        # add the serialization of each output
        for i, tx_out in enumerate(self.tx_outs):
            if hash_type & 3 == SIGHASH_NONE:
                continue
            elif hash_type & 3 == SIGHASH_SINGLE:
                if i == input_index:
                    s += tx_out.serialize()
                    break
                else:
                    s += b"\xff\xff\xff\xff\xff\xff\xff\xff\x00"
            else:
                s += tx_out.serialize()
        # add the locktime using int_to_little_endian in 4 bytes
        s += self.locktime.serialize()
        # add SIGHASH_ALL using int_to_little_endian in 4 bytes
        s += int_to_little_endian(hash_type, 4)
        # hash256 the serialization
        h256 = hash256(s)
        # convert the result to an integer using big_endian_to_int(x)
        return big_endian_to_int(h256)
Пример #19
0
 def serialize(self):
     return int_to_little_endian(self, 4)