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)
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)
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
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()
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)
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])
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)
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.')
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)
def __init__(self, item: bytes): super().__init__() self.validate_bytes(item, None) self += VarInt(len(item)) self += item self.item = item self._make_immutable()
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)
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.')
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()
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()
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
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()
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)
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)
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()
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])