def sign(self, private_keys): '''Signs the transaction. prvkeys (list of PrivateKey items)''' for i, txin in enumerate(self._inputs): prvkeys = private_keys[i] if isinstance(prvkeys, PrivateKey): assert txin['nsigs'] == 1 prvkeys = [prvkeys] elif isinstance(prvkeys, list): assert len(prvkeys) == txin['nsigs'] # Sorting keys sorted_prvkeys = [] for prvkey in prvkeys: pubkey = PublicKey.from_prvkey(prvkey) assert (pubkey in txin['pubkeys']) sorted_prvkeys += [(txin['pubkeys'].index(pubkey), prvkey)] sorted_prvkeys.sort(key=lambda x: x[0]) prvkeys = [k[1] for k in sorted_prvkeys] else: raise TransactionError('wrong type for private keys') if txin['type'] in ('p2pkh', 'p2sh'): prehash = dsha256(self.serialize_legacy_preimage(txin)) elif txin['type'] in ('p2wpkh', 'p2wsh', 'p2sh-p2wpkh', 'p2sh-p2wsh'): prehash = dsha256(self.serialize_preimage(txin)) hashtype = bytes([self.hashtype & 0xff]).hex() self._inputs[i]['signatures'] = [ prvkey.sign(prehash, alg="ecdsa", strtype=True) + hashtype for prvkey in prvkeys ]
def unwrap_network_message(data): datacpy = data if len(data) < 24: return None, None, None, data magic, data = read_bytes(data, 4, int, 'little') assert magic == Constants.NETWORK_MAGIC cmd, data = read_bytes(data, 12, bytes, 'big') i = 0 while cmd[i] != 0 and i < 12: i += 1 try: command = cmd[:i].decode('ascii') except UnicodeDecodeError: raise NetworkError("Invalid command encoding") except Exception as e: print(e) length, data = read_bytes(data, 4, int, 'little') if (len(data) - 4) < length: return command, None, length, datacpy checksum, data = read_bytes(data, 4, bytes, 'big') payload, data = read_bytes(data, length, bytes, 'big') assert checksum == dsha256(payload)[:4] return command, payload, length, data
def wrap_network_message(command, payload): ''' Message Structure for Bitcoin Protocol. command (str) : command (e.g. "version") payload (bytes) : actual data ''' magic = Constants.NETWORK_MAGIC.to_bytes(4, 'little') cmdb = command.encode('ascii') cmd = cmdb + ((12 - len(cmdb)) * b"\00") length = len(payload).to_bytes(4, 'little') checksum = dsha256(payload)[:4] return magic + cmd + length + checksum + payload
def serialize_preimage(self, txin): ''' Serializes the preimage of the transaction (BIP-143).''' nVersion = self.version.to_bytes(4, 'little') nLocktime = self.locktime.to_bytes(4, 'little') nHashtype = self.hashtype.to_bytes( 4, 'little') # signature hashtype (little-endian) hashPrevouts = dsha256(bytes().join( self.serialize_outpoint(txi) for txi in self._inputs)) hashSequence = dsha256(bytes().join( txi['sequence'].to_bytes(4, 'little') for txi in self._inputs)) outpoint = self.serialize_outpoint(txin) prevLockingScript = self.get_preimage_script(txin) prevLockingScriptSize = var_int(len(prevLockingScript)) prevValue = txin['value'].to_bytes(8, 'little') nSequence = txin['sequence'].to_bytes(4, 'little') hashOutputs = dsha256(bytes().join( self.serialize_output(txo) for txo in self._outputs)) return (nVersion + hashPrevouts + hashSequence + outpoint + prevLockingScriptSize + prevLockingScript + prevValue + nSequence + hashOutputs + nLocktime + nHashtype)
def txid(self): '''Returns transaction identifier.''' if self.is_complete(): return dsha256(self.serialize())[::-1] else: return None
def check(self): return int.from_bytes(dsha256(self.serialize()), 'little') <= self.target()
def block_id(self): raw = self.serialize() return dsha256(raw)[::-1]