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( tx_in.prev_index, 4) all_sequence += int_to_little(tx_in.sequence, 4) self._hash_prevouts = hash256(all_prevouts) self._hash_sequence = hash256(all_sequence) return self._hash_prevouts
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(self.prev_index, 4) # serialize the script_sig result += self.script_sig.serialize() # serialize sequence, 4 bytes, little endian result += int_to_little(self.sequence, 4) return result
def serialize(self): '''Returns the byte serialization of the transaction output''' # serialize amount, 8 bytes, little endian result = int_to_little(self.amount, 8) # serialize the script_pubkey result += self.script_pubkey.serialize() return result
def serialize_legacy(self): '''Returns the byte serialization of the transaction''' # serialize version (4 bytes, little endian) result = int_to_little(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 += int_to_little(self.locktime, 4) return result
def serialize_segwit(self): result = int_to_little(self.version, 4) result += b'\x00\x01' result += encode_varint(len(self.tx_ins)) for tx_in in self.tx_ins: result += tx_in.serialize() result += encode_varint(len(self.tx_outs)) for tx_out in self.tx_outs: result += tx_out.serialize() # Witness for tx_in in self.tx_ins: result += int_to_little(len(tx_in.witness), 1) for item in tx_in.witness: if type(item) == int: result += int_to_little(item, 1) else: result += encode_varint(len(item)) + item result += int_to_little(self.locktime, 4) return result
def sig_hash(self, idx, sighash_type=SIGHASH_ALL, redeem_script=None): '''Returns the integer representation of the hash that needs to get signed for index idx''' # start the serialization with version # use int_to_little in 4 bytes s = int_to_little(self.version, 4) # add how many inputs there are using encode_varint s += encode_varint(len(self.tx_ins)) # loop through each input using enumerate, so we have the input index for i, tx_in in enumerate(self.tx_ins): # if the input index is the one we're signing if i == idx: # 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.testnet) # Otherwise, the ScriptSig is empty else: script_sig = None # add the serialization of the input with the ScriptSig we want s += TxIn( prev_tx=tx_in.prev_tx, prev_index=tx_in.prev_index, script_sig=script_sig, sequence=tx_in.sequence, ).serialize() # add how many outputs there are using encode_varint s += encode_varint(len(self.tx_outs)) # add the serialization of each output for tx_out in self.tx_outs: s += tx_out.serialize() # add the locktime using int_to_little in 4 bytes s += int_to_little(self.locktime, 4) # add SIGHASH_ALL using int_to_little in 4 bytes s += int_to_little(sighash_type, 4) # hash256 the serialization h256 = hash256(s) # convert the result to an integer using int.from_bytes(x, 'big') return int.from_bytes(h256, 'big')
def get_path_bytes(self): ''' returns path as concatenated bytes''' levels = self.path.split("/") path_bytes = b"" for lev in levels: i = 0 if lev[-1] == "'": i = SOFT_CAP lev = lev[:-1] i += int(lev) path_bytes += int_to_little(i, 4) return path_bytes
def raw_serialize(self): # initialize what we'll send back result = b'' # go through each cmd for cmd in self.cmds: # if the cmd is an integer, it's an opcode if type(cmd) == int: # turn the cmd into a single byte integer using int_to_little result += int_to_little(cmd, 1) else: # otherwise, this is an element # get the length in bytes length = len(cmd) # for large lengths, we have to use a pushdata opcode if length < 75: # turn the length into a single byte integer result += int_to_little(length, 1) elif length > 75 and length < 0x100: # 76 is pushdata1 result += int_to_little(76, 1) result += int_to_little(length, 1) elif length >= 0x100 and length <= 520: # 77 is pushdata2 result += int_to_little(77, 1) result += int_to_little(length, 2) else: raise ValueError('too long a cmd') if type(cmd) == str: print(cmd) result += cmd return result
def sig_hash_bip143(self, idx, redeem_script=None, witness_script=None, sighash_type=SIGHASH_ALL): '''Returns the integer representation of the hash that needs to get signed for index idx''' tx_in = self.tx_ins[idx] # per BIP143 spec s = int_to_little(self.version, 4) s += self.hash_prevouts() + self.hash_sequence() s += tx_in.prev_tx[::-1] + int_to_little(tx_in.prev_index, 4) if witness_script: script_code = witness_script.serialize() elif redeem_script: script_code = p2pkh_script(redeem_script.cmds[1]).serialize() else: script_code = p2pkh_script( tx_in.script_pubkey(self.testnet).cmds[1]).serialize() s += script_code s += int_to_little(tx_in.value(), 8) s += int_to_little(tx_in.sequence, 4) s += self.hash_outputs() s += int_to_little(self.locktime, 4) s += int_to_little(sighash_type, 4) return int.from_bytes(hash256(s), 'big')
def add_sighash_type(self, idx, sighash): self.psbt.maps["inputs"][idx][IN_SIGHASH_TYPE] = int_to_little(n=sighash, length=4)