コード例 #1
0
ファイル: tx.py プロジェクト: summa-tx/riemann
    def from_bytes(Tx, byte_string: bytes) -> 'Tx':
        '''Instantiate a Tx object from a bytestring'''

        # Get the version number
        version = byte_string[0:4]

        # Check if this is a witness tx
        if byte_string[4:6] == riemann.network.SEGWIT_TX_FLAG:
            tx_ins_num_loc = 6
            flag = riemann.network.SEGWIT_TX_FLAG
        else:
            tx_ins_num_loc = 4
            flag = None

        # Get the length of the tx_in vector
        tx_ins = []
        tx_ins_num = VarInt.from_bytes(byte_string[tx_ins_num_loc:])

        # `current` is the index of next read
        current = tx_ins_num_loc + len(tx_ins_num)

        # Deserialize all tx_ins
        for _ in range(tx_ins_num.number):
            tx_in = TxIn.from_bytes(byte_string[current:])
            current += len(tx_in)
            tx_ins.append(tx_in)

        # Get the length of the tx_out vector
        tx_outs = []
        tx_outs_num = VarInt.from_bytes(byte_string[current:])

        # Deserialize all outputs
        current += len(tx_outs_num)
        for _ in range(tx_outs_num.number):
            tx_out = TxOut.from_bytes(byte_string[current:])
            current += len(tx_out)
            tx_outs.append(tx_out)

        # Deserialize all witnesses if necessary
        tx_witnesses: List[InputWitness] = []
        if flag and len(byte_string[current:]) > 4:
            tx_witnesses_num = tx_ins_num
            for _ in range(tx_witnesses_num.number):
                tx_witness = InputWitness.from_bytes(byte_string[current:])
                current += len(tx_witness)
                tx_witnesses.append(tx_witness)

        # Get the lock time and return a complete tx
        lock_time = byte_string[current:current + 4]
        return Tx(
            version=version,
            flag=flag,
            tx_ins=tx_ins,
            tx_outs=tx_outs,
            tx_witnesses=tx_witnesses,
            lock_time=lock_time)
コード例 #2
0
 def no_witness(self):
     '''
     Tx -> bytes
     '''
     tx = bytes()
     tx += self.version
     tx += VarInt(len(self.tx_ins)).to_bytes()
     for tx_in in self.tx_ins:
         tx += tx_in.to_bytes()
     tx += VarInt(len(self.tx_outs)).to_bytes()
     for tx_out in self.tx_outs:
         tx += tx_out.to_bytes()
     tx += self.lock_time
     return bytes(tx)
コード例 #3
0
ファイル: tx.py プロジェクト: summa-tx/riemann
 def no_witness(self) -> bytes:
     '''
     Return the Tx as a bytestring stripped of witnesses. This is the
     preimage of `tx_id` and `tx_id_le`.
     '''
     tx = bytes()
     tx += self.version
     tx += VarInt(len(self.tx_ins)).to_bytes()
     for tx_in in self.tx_ins:
         tx += tx_in.to_bytes()
     tx += VarInt(len(self.tx_outs)).to_bytes()
     for tx_out in self.tx_outs:
         tx += tx_out.to_bytes()
     tx += self.lock_time
     return tx
コード例 #4
0
    def __init__(self, outpoint, stack_script, redeem_script, sequence):
        super().__init__()

        self.validate_bytes(outpoint, 36)
        self.validate_bytes(stack_script, None)
        self.validate_bytes(redeem_script, None)
        self.validate_bytes(sequence, 4)

        if len(stack_script) + len(redeem_script) > 1650:
            raise ValueError('Input script_sig is too long. '
                             'Expected <= 1650 bytes. Got {} bytes.'.format(
                                 len(stack_script) + len(redeem_script)))

        self += outpoint
        self += VarInt(len(stack_script) + len(redeem_script))
        self += stack_script
        self += redeem_script
        self += sequence

        self.outpoint = outpoint
        self.script_len = len(stack_script + redeem_script)
        self.stack_script = stack_script
        self.redeem_script = redeem_script
        self.script_sig = self.stack_script + self.redeem_script
        self.sequence = sequence

        self._make_immutable()
コード例 #5
0
ファイル: tx.py プロジェクト: summa-tx/riemann
    def from_bytes(TxIn, byte_string: bytes) -> 'TxIn':
        '''
        Parse a TxIn from a bytestring. Also available as from_hex
        '''
        outpoint = Outpoint.from_bytes(byte_string[:36])

        # Extract the script sig length
        script_sig_len = VarInt.from_bytes(byte_string[36:45])

        # Extract the script sig
        script_start = 36 + len(script_sig_len)
        script_end = script_start + script_sig_len.number
        script_sig = byte_string[script_start:script_end]

        sequence = byte_string[script_end:script_end + 4]

        # If the script-sig is blank, both stack and redeem are blank
        if script_sig == b'':
            stack_script = b''
            redeem_script = b''
        # If the outpoint is null (coinbase), don't try parsing the script sig
        elif outpoint == Outpoint.null():
            stack_script = script_sig
            redeem_script = b''
        # Parse the script sig into stack and redeem
        else:
            stack_script, redeem_script = TxIn._parse_script_sig(script_sig)
        return TxIn(
            outpoint=outpoint,
            stack_script=stack_script,
            redeem_script=redeem_script,
            sequence=sequence)
コード例 #6
0
ファイル: tx.py プロジェクト: summa-tx/riemann
 def from_bytes(WitnessStackItem, byte_string: bytes) -> 'WitnessStackItem':
     '''
     Parse a WitnessStackItem from a bytestring. Also available as from_hex
     '''
     n = VarInt.from_bytes(byte_string)
     item_start = len(n)
     item_end = item_start + n.number
     return WitnessStackItem(byte_string[item_start:item_end])
コード例 #7
0
 def from_bytes(InputWitness, byte_string):
     stack_items = VarInt.from_bytes(byte_string)
     item_start = len(stack_items)
     items = []
     while len(items) < stack_items.number:
         item = WitnessStackItem.from_bytes(byte_string[item_start:])
         item_start += len(item)
         items.append(item)
     return InputWitness(items)
コード例 #8
0
 def from_bytes(TxOut, byte_string):
     n = VarInt.from_bytes(byte_string[8:])
     script_start = 8 + len(n)
     script_end = script_start + n.number
     if n.number < 0xfc:
         return TxOut(value=byte_string[:8],
                      output_script=byte_string[script_start:script_end])
     else:
         raise NotImplementedError(
             'No support for abnormally long pk_scripts.')
コード例 #9
0
    def from_bytes(Tx, byte_string):
        version = byte_string[0:4]
        if byte_string[4:6] == riemann.network.SEGWIT_TX_FLAG:
            tx_ins_num_loc = 6
            flag = riemann.network.SEGWIT_TX_FLAG
        else:
            tx_ins_num_loc = 4
            flag = None
        tx_ins = []
        tx_ins_num = VarInt.from_bytes(byte_string[tx_ins_num_loc:])

        current = tx_ins_num_loc + len(tx_ins_num)

        for _ in range(tx_ins_num.number):
            tx_in = TxIn.from_bytes(byte_string[current:])
            current += len(tx_in)
            tx_ins.append(tx_in)

        tx_outs = []
        tx_outs_num = VarInt.from_bytes(byte_string[current:])
        current += len(tx_outs_num)
        for _ in range(tx_outs_num.number):
            tx_out = TxOut.from_bytes(byte_string[current:])
            current += len(tx_out)
            tx_outs.append(tx_out)

        if flag and len(byte_string[current:]) > 4:
            tx_witnesses = []
            tx_witnesses_num = tx_ins_num
            for _ in range(tx_witnesses_num.number):
                tx_witness = InputWitness.from_bytes(byte_string[current:])
                current += len(tx_witness)
                tx_witnesses.append(tx_witness)
        else:
            tx_witnesses = None

        lock_time = byte_string[current:current + 4]
        return Tx(version=version,
                  flag=flag,
                  tx_ins=tx_ins,
                  tx_outs=tx_outs,
                  tx_witnesses=tx_witnesses,
                  lock_time=lock_time)
コード例 #10
0
ファイル: tx.py プロジェクト: summa-tx/riemann
    def __init__(self, item: bytes):
        super().__init__()

        self.validate_bytes(item, None)

        self += VarInt(len(item))
        self += item

        self.item = item

        self._make_immutable()
コード例 #11
0
ファイル: tx.py プロジェクト: summa-tx/riemann
 def from_bytes(InputWitness, byte_string: bytes) -> 'InputWitness':
     '''
     Parse an InputWitness from a bytestring. Also available as from_hex
     '''
     stack_items = VarInt.from_bytes(byte_string)
     item_start = len(stack_items)
     items: List[WitnessStackItem] = []
     while len(items) < stack_items.number:
         item = WitnessStackItem.from_bytes(byte_string[item_start:])
         item_start += len(item)
         items.append(item)
     return InputWitness(items)
コード例 #12
0
ファイル: tx.py プロジェクト: summa-tx/riemann
 def from_bytes(TxOut, byte_string: bytes) -> 'TxOut':
     '''
     Parse a TxOut from a bytestring. Also available as from_hex
     '''
     n = VarInt.from_bytes(byte_string[8:])
     script_start = 8 + len(n)
     script_end = script_start + n.number
     if n.number < 0xfc:
         return TxOut(
             value=byte_string[:8],
             output_script=byte_string[script_start:script_end])
     else:
         raise NotImplementedError(
             'No support for abnormally long pk_scripts.')
コード例 #13
0
    def __init__(self, item):
        super().__init__()

        self.validate_bytes(item, None)
        if len(item) > 520:
            raise ValueError('Item is too large. Expected <=520 bytes. '
                             'Got: {} bytes'.format(len(item)))
        self += VarInt(len(item))
        self += item

        self.item_len = len(item)
        self.item = item

        self._make_immutable()
コード例 #14
0
ファイル: tx.py プロジェクト: summa-tx/riemann
    def __init__(self, value: bytes, output_script: bytes):
        super().__init__()

        self.validate_bytes(value, 8)
        self.validate_bytes(output_script, None)

        self += value
        self += VarInt(len(output_script))
        self += output_script

        self.value = value
        self.output_script = output_script

        self._make_immutable()
コード例 #15
0
    def _adjusted_script_code(self, script):
        '''
        Checks if the script code pased in to the sighash function is already
        length-prepended
        This will break if there's a redeem script that's just a pushdata
        That won't happen in practice

        Args:
            script (bytes): the spend script
        Returns:
            (bytes): the length-prepended script (if necessary)
        '''
        script_code = ByteData()
        if script[0] == len(script) - 1:
            return script
        script_code += VarInt(len(script))
        script_code += script
        return script_code
コード例 #16
0
    def __init__(self, stack):
        '''
        list(WitnessStackItem) -> InputWitness
        '''
        super().__init__()
        for item in stack:
            if not isinstance(item, WitnessStackItem):
                raise ValueError(
                    'Invalid witness stack item. '
                    'Expected WitnessStackItem. Got {}'.format(item))

        self += VarInt(len(stack))
        for item in stack:
            self += item

        self.stack_len = len(stack)
        self.stack = [item for item in stack]

        self._make_immutable()
コード例 #17
0
ファイル: tx.py プロジェクト: summa-tx/riemann
    def _sighash_prep(self, index: int, script: bytes) -> 'Tx':
        '''
        Sighashes suck
        Performs the sighash setup described here:
        https://en.bitcoin.it/wiki/OP_CHECKSIG#How_it_works
        https://bitcoin.stackexchange.com/questions/3374/how-to-redeem-a-basic-tx
        We save on complexity by refusing to support OP_CODESEPARATOR
        '''
        # 0 out scripts in tx_ins
        copy_tx_ins = [tx_in.copy(stack_script=b'', redeem_script=b'')
                       for tx_in in self.tx_ins]

        # NB: The script for the current transaction input in txCopy is set to
        #     subScript (lead in by its length as a var-integer encoded!)
        to_strip = VarInt.from_bytes(script)
        copy_tx_ins[index] = \
            copy_tx_ins[index].copy(redeem_script=script[len(to_strip):])

        return self.copy(tx_ins=copy_tx_ins)
コード例 #18
0
    def from_bytes(TxIn, byte_string):
        '''
        byte_string -> TxIn
        parses a TxIn from a byte-like object
        '''
        outpoint = Outpoint.from_bytes(byte_string[:36])

        script_sig_len = VarInt.from_bytes(byte_string[36:45])
        script_start = 36 + len(script_sig_len)
        script_end = script_start + script_sig_len.number
        script_sig = byte_string[script_start:script_end]

        sequence = byte_string[script_end:script_end + 4]
        if script_sig == b'':
            stack_script = b''
            redeem_script = b''
        else:
            stack_script, redeem_script = TxIn._parse_script_sig(script_sig)
        return TxIn(outpoint=outpoint,
                    stack_script=stack_script,
                    redeem_script=redeem_script,
                    sequence=sequence)
コード例 #19
0
    def __init__(self, version, flag, tx_ins, tx_outs, tx_witnesses,
                 lock_time):

        super().__init__()

        self.validate_bytes(version, 4)
        self.validate_bytes(lock_time, 4)

        if flag is not None:
            if flag != riemann.network.SEGWIT_TX_FLAG:
                raise ValueError('Invald segwit flag. '
                                 'Expected None or {}. Got: {}'.format(
                                     riemann.network.SEGWIT_TX_FLAG, flag))

        if tx_witnesses is not None:
            if flag is None:
                raise ValueError('Got witnesses but no segwit flag.')
            if len(tx_witnesses) != len(tx_ins):
                raise ValueError('Witness and TxIn lists must be same length. '
                                 'Got {} inputs and {} witnesses.'.format(
                                     len(tx_ins), len(tx_witnesses)))
            for witness in tx_witnesses:
                if not isinstance(witness, InputWitness):
                    raise ValueError(
                        'Invalid InputWitness. '
                        'Expected instance of InputWitness. Got {}'.format(
                            type(witness)))

        if min(len(tx_ins), len(tx_outs)) == 0:
            raise ValueError('Too few inputs or outputs. Stop that.')

        for tx_in in tx_ins:
            if not isinstance(tx_in, TxIn):
                raise ValueError('Invalid TxIn. '
                                 'Expected instance of TxIn. Got {}'.format(
                                     type(tx_in).__name__))

        for tx_out in tx_outs:
            if not isinstance(tx_out, TxOut):
                raise ValueError('Invalid TxOut. '
                                 'Expected instance of TxOut. Got {}'.format(
                                     type(tx_out).__name__))

        self += version
        if flag is not None:
            self += flag
        self += VarInt(len(tx_ins))
        for tx_in in tx_ins:
            self += tx_in
        self += VarInt(len(tx_outs))
        for tx_out in tx_outs:
            self += tx_out
        if tx_witnesses is not None:
            for witness in tx_witnesses:
                self += witness
        self += lock_time

        self.version = version
        self.flag = flag
        self.tx_ins_len = len(tx_ins)
        self.tx_ins = tuple(tx_in for tx_in in tx_ins)
        self.tx_outs_len = len(tx_outs)
        self.tx_outs = tuple(tx_out for tx_out in tx_outs)
        self.tx_witnesses_len = self.tx_ins_len
        self.tx_witnesses = \
            tuple(wit for wit in tx_witnesses) if tx_witnesses is not None \
            else None
        self.lock_time = lock_time

        if flag is not None:
            self.tx_id_le = utils.hash256(self.no_witness())
            self.wtx_id_le = utils.hash256(self.to_bytes())
            self.tx_id = utils.change_endianness(self.tx_id_le)
            self.wtx_id = utils.change_endianness(self.wtx_id_le)

        else:
            self.tx_id_le = utils.hash256(self.to_bytes())
            self.tx_id = utils.change_endianness(self.tx_id_le)
            self.wtx_id = None
            self.wtx_le = None

        self._make_immutable()
コード例 #20
0
 def from_bytes(WitnessStackItem, byte_string):
     n = VarInt.from_bytes(byte_string)
     item_start = len(n)
     item_end = item_start + n.number
     return WitnessStackItem(byte_string[item_start:item_end])