def __init__(self, coin, inputs, outputs, **params): self.id = None self.raw = None self.coin = coin self.version = params.get('version') or coin.get('version') or b'\x01\x00\x00\x00' self.sequence = params.get('sequence') or coin.get('sequence') or b'\xff\xff\xff\xff' self.lock_time = params.get('lock_time') or coin.get('lock_time') or b'\x00\x00\x00\x00' self.hash_type = params.get('hash_type') or coin.get('hash_type') or b'\x01\x00\x00\x00' self.last_block = params.get('check_block_at_height') self.inputs = [ TransactionInput( transaction_id=input['transaction_id'], output_index=input['output_index'], locking_script=input['locking_script'], satoshis=input['satoshis'], private_key=input.get('private_key'), unlocking_script=input.get('unlocking_script', '')) for input in inputs] self.inputs_counter = int_to_bytes(len(self.inputs), byteorder='little') self.outputs = [ TransactionOutput( address=output['address'], satoshis=output['satoshis'], coin=coin) for output in outputs] self.outputs_counter = int_to_bytes(len(self.outputs), byteorder='little')
def get_encoded_outputs(self): output_block = b'' for output in self.outputs: script = output.script if self.last_block: script += b'\x20' + hex_to_bytes(self.last_block['hash'], byteorder='little') height_bytes = int_to_bytes(self.last_block['height'], byteorder='little') script += len(height_bytes).to_bytes(1, byteorder='big') + height_bytes + b'\xb4' output_block += output.satoshis.to_bytes(8, byteorder='little') output_block += int_to_bytes(len(script), byteorder='little') output_block += script return output_block
def __init__(self, transaction_id, output_index, locking_script, satoshis, private_key=None, unlocking_script=None): """ :param transaction_id: Transaction id in hex format :param output_index: Number (int) specifying the output of the transaction which becomes new transaction input :param locking_script: Locking script in hex format :param satoshis: Amount in satoshis (int) :param private_key: Private key (int) needed to claim the input """ self.transaction_id = hex_to_bytes(transaction_id, byteorder='big') self.output_index = output_index.to_bytes(4, byteorder='little') self.script = hex_to_bytes(locking_script, byteorder='big') self.script_length = int_to_bytes(len(self.script), byteorder='little') self.satoshis = satoshis.to_bytes(8, byteorder='little') if private_key: self.private_key = private_key self.public_key = private_key * secp256k1.G compressed_public_key_hash = calculate_public_key_hash(self.public_key, compressed=True) if compressed_public_key_hash.hex() not in locking_script: is_compressed_public_key = False else: is_compressed_public_key = True self.encoded_public_key = encode_point( self.public_key, compressed=is_compressed_public_key) self.public_key_len = len(self.encoded_public_key).to_bytes(1, byteorder='little') self.unlocking_script = hex_to_bytes(unlocking_script, byteorder='big')
def base58_to_bytes(base58_data): data_without_leading_ones = base58_data.lstrip('1') value = 0 for digit in data_without_leading_ones: value *= 58 value += base58_digits_values[digit] leading_zeros = b'\x00' * (len(base58_data) - len(data_without_leading_ones)) return leading_zeros + int_to_bytes(value, byteorder='big')
def sign_input(self, position): input = self.inputs[position] if is_p2sh(input.script): input.script = input.unlocking_script input.script_length = int_to_bytes(len(input.script), byteorder='little') return message = self.get_data_to_sign(position) sig = sign(message, input.private_key, secp256k1, double_sha256) # ECDSA signing encoded_signature = der_encode_signature(sig) signature = encoded_signature + self.coin.get('sig_hash', b'\x01') script_sig = ( len(signature).to_bytes(1, byteorder='little') + signature + input.public_key_len + input.encoded_public_key ) input.script = script_sig input.script_length = int_to_bytes(len(script_sig), byteorder='little')