Ejemplo n.º 1
0
 def parse_segwit(cls, s, testnet=False):
     version = little_to_int(s.read(4))
     marker = s.read(2)
     if marker != b'\x00\x01':
         raise RuntimeError(f"Not a SegWit Transaction: {marker}")
     num_inputs = read_varint(s)
     inputs = []
     for _ in range(num_inputs):
         inputs.append(TxIn.parse(s))
     num_outputs = read_varint(s)
     outputs = []
     for _ in range(num_outputs):
         outputs.append(TxOut.parse(s))
     for tx_in in inputs:
         num_items = read_varint(s)
         items = []
         for _ in range(num_items):
             item_len = read_varint(s)
             if item_len == 0:
                 items.append(0)
             else:
                 items.append(s.read(item_len))
         tx_in.witness = items
     locktime = little_to_int(s.read(4))
     return cls(version,
                inputs,
                outputs,
                locktime,
                testnet=testnet,
                segwit=True)
Ejemplo n.º 2
0
 def parse(cls, s):
     '''Takes a byte stream and parses the tx_input at the start
     return a TxIn object
     '''
     # prev_tx is 32 bytes, little endian
     prev_tx = s.read(32)[::-1]
     # prev_index is an integer in 4 bytes, little endian
     prev_index = little_to_int(s.read(4))
     # use Script.parse to get the ScriptSig
     script_sig = Script.parse(s)
     # sequence is an integer in 4 bytes, little-endian
     sequence = little_to_int(s.read(4))
     # return an instance of the class (see __init__ for args)
     return cls(prev_tx, prev_index, script_sig, sequence)
Ejemplo n.º 3
0
	def get_sighash_type(self, idx):
		found = self.psbt.maps["inputs"][idx].get(IN_SIGHASH_TYPE)
		if found is None:
			raise PSBTWarning(f"No SIGHASH key for input {idx}")
			return None
		else:
			return little_to_int(found)
Ejemplo n.º 4
0
 def parse(cls, s):
     '''Takes a byte stream and parses the tx_output at the start
     return a TxOut object
     '''
     # amount is an integer in 8 bytes, little endian
     amount = little_to_int(s.read(8))
     # use Script.parse to get the ScriptPubKey
     script_pubkey = Script.parse(s)
     # return an instance of the class (see __init__ for args)
     return cls(amount, script_pubkey)
Ejemplo n.º 5
0
 def load_cache(cls, filename):
     disk_cache = json.loads(open(filename, 'r').read())
     for k, raw_hex in disk_cache.items():
         raw = bytes.fromhex(raw_hex)
         if raw[4] == 0:
             raw = raw[:4] + raw[6:]
             tx = Tx.parse(BytesIO(raw))
             tx.locktime = little_to_int(raw[-4:])
         else:
             tx = Tx.parse(BytesIO(raw))
         cls.cache[k] = tx
Ejemplo n.º 6
0
 def parse(cls, s):
     # get the length of the entire field
     length = read_varint(s)
     # initialize the cmds array
     cmds = []
     # initialize the number of bytes we've read to 0
     count = 0
     # loop until we've read length bytes
     while count < length:
         # get the current byte
         current = s.read(1)
         # increment the bytes we've read
         count += 1
         # convert the current byte to an integer
         current_byte = current[0]
         # if the current byte is between 1 and 75 inclusive
         if current_byte >= 1 and current_byte <= 75:
             # we have an cmd set n to be the current byte
             n = current_byte
             # add the next n bytes as an cmd
             cmds.append(s.read(n))
             # increase the count by n
             count += n
         elif current_byte == 76:
             # op_pushdata1
             data_length = little_to_int(s.read(1))
             cmds.append(s.read(data_length))
             count += data_length + 1
         elif current_byte == 77:
             # op_pushdata2
             data_length = little_to_int(s.read(2))
             cmds.append(s.read(data_length))
             count += data_length + 2
         else:
             # we have an opcode. set the current byte to op_code
             op_code = current_byte
             # add the op_code to the list of cmds
             cmds.append(op_code)
     if count != length:
         raise SyntaxError('parsing script failed')
     return cls(cmds)
Ejemplo n.º 7
0
 def parse_legacy(cls, s, testnet=False):
     '''Takes a byte stream and parses the transaction at the start
     return a Tx object
     '''
     # s.read(n) will return n bytes
     # version is an integer in 4 bytes, little-endian
     version = little_to_int(s.read(4))
     # num_inputs is a varint, use read_varint(s)
     num_inputs = read_varint(s)
     # parse num_inputs number of TxIns
     inputs = []
     for _ in range(num_inputs):
         inputs.append(TxIn.parse(s))
     # num_outputs is a varint, use read_varint(s)
     num_outputs = read_varint(s)
     # parse num_outputs number of TxOuts
     outputs = []
     for _ in range(num_outputs):
         outputs.append(TxOut.parse(s))
     # locktime is an integer in 4 bytes, little-endian
     locktime = little_to_int(s.read(4))
     # return an instance of the class (see __init__ for args)
     return cls(version, inputs, outputs, locktime, testnet=testnet)
Ejemplo n.º 8
0
	def add_partial_sig(self, new_sig, pubkey, idx=None):
		if idx is None:
			idx = self._get_input_index(pubkey)
		# Note: Assumes that the sighash type is only the last byte of sig. 
		# Note: Assumes inputs in psbt and indexed the same as in unsigned tx
		this_sighash = little_to_int(new_sig[-1:])
		if idx is not None:
			if not self.check_sighash(idx=idx, sighash=this_sighash):
				raise PSBTError(f"Sighash type {this_sighash} on Signature does not match specified Sighash ({self.get_sighash_type(idx)}) for this input.")
			curr_input = self.psbt.maps["inputs"][idx]
			if IN_NON_WITNESS_UTXO in curr_input:
				global_txid = Tx.parse(BytesIO(self.psbt.maps["global"][GLOBAL_UNSIGNED_TX])).tx_ins[idx].prev_tx
				curr_txid = hash256(curr_input[IN_NON_WITNESS_UTXO])#[::-1]
				if global_txid != curr_txid:
					raise PSBTError("UTXO of this input does not match the UTXO specified in global unsigned Tx")
			elif IN_WITNESS_UTXO in curr_input:
				raise NotImplementedError("SegWit Not yet implemented.")

			self.psbt.maps["inputs"][idx][IN_PARTIAL_SIG+pubkey] = new_sig
		else:
			raise PSBTError("Signature cannot be added. The Pubkey provided is not avaialbe in this PSBT")
		return
Ejemplo n.º 9
0
 def fetch(cls, tx_id, testnet=False, fresh=False):
     if fresh or (tx_id not in cls.cache):
         url = '{}/tx/{}.hex'.format(cls.get_url(testnet), tx_id)
         response = requests.get(url)
         try:
             raw = bytes.fromhex(response.text.strip())
         except ValueError:
             raise ValueError('unexpected response: {}'.format(
                 response.text))
         # make sure the tx we got matches to the hash we requested
         if raw[4] == 0:
             raw = raw[:4] + raw[6:]
             tx = Tx.parse(BytesIO(raw), testnet=testnet)
             tx.locktime = little_to_int(raw[-4:])
         else:
             tx = Tx.parse(BytesIO(raw), testnet=testnet)
         if tx.id() != tx_id:
             raise ValueError('not the same id: {} vs {}'.format(
                 tx.id(), tx_id))
         cls.cache[tx_id] = tx
     cls.cache[tx_id].testnet = testnet
     return cls.cache[tx_id]