class TransactionFactory(object): def __init__(self, config, mongo, block_height, bulletin_secret='', username='', value=0, fee=0.0, requester_rid='', requested_rid='', public_key='', dh_public_key='', private_key='', dh_private_key='', to='', inputs='', outputs='', coinbase=False, chattext=None, signin=None): self.config = config self.mongo = mongo self.block_height = block_height self.bulletin_secret = bulletin_secret self.username = username self.requester_rid = requester_rid self.requested_rid = requested_rid self.public_key = public_key self.dh_public_key = dh_public_key self.private_key = private_key self.value = value self.fee = float(fee) self.dh_private_key = dh_private_key self.to = to self.time = str(int(time.time())) self.outputs = [] for x in outputs: self.outputs.append(Output.from_dict(x)) self.inputs = [] for x in inputs: if 'signature' in x: self.inputs.append( ExternalInput.from_dict(self.config, self.mongo, x)) else: self.inputs.append(Input.from_dict(x)) self.coinbase = coinbase self.chattext = chattext self.signin = signin self.do_money() inputs_concat = self.get_input_hashes() outputs_concat = self.get_output_hashes() if bulletin_secret: self.rid = self.generate_rid() if self.chattext: self.relationship = json.dumps({"chatText": self.chattext}) self.cipher = Crypt(self.config.wif) self.encrypted_relationship = self.cipher.encrypt( self.relationship) elif self.signin: for shared_secret in TU.get_shared_secrets_by_rid( self.config, self.mongo, self.rid): self.relationship = SignIn(self.signin) self.cipher = Crypt(shared_secret.encode('hex'), shared=True) self.encrypted_relationship = self.cipher.shared_encrypt( self.relationship.to_json()) else: if not self.dh_public_key or not self.dh_private_key: a = os.urandom(32) self.dh_public_key = scalarmult_base(a).encode('hex') self.dh_private_key = a.encode('hex') self.relationship = self.generate_relationship() if not private_key: raise BaseException('missing private key') self.cipher = Crypt(self.config.wif) self.encrypted_relationship = self.cipher.encrypt( self.relationship.to_json()) else: self.rid = '' self.encrypted_relationship = '' self.header = (self.public_key + self.time + self.dh_public_key + self.rid + self.encrypted_relationship + "{0:.8f}".format(self.fee) + self.requester_rid + self.requested_rid + inputs_concat + outputs_concat) self.hash = hashlib.sha256(self.header).digest().encode('hex') if self.private_key: self.transaction_signature = TU.generate_signature_with_private_key( private_key, self.hash) else: self.transaction_signature = '' self.transaction = self.generate_transaction() def do_money(self): my_address = str( P2PKHBitcoinAddress.from_pubkey(self.public_key.decode('hex'))) input_txns = BU.get_wallet_unspent_transactions( self.config, self.mongo, my_address) miner_transactions = self.mongo.db.miner_transactions.find() mtxn_ids = [] for mtxn in miner_transactions: for mtxninput in mtxn['inputs']: mtxn_ids.append(mtxninput['id']) if self.inputs: inputs = self.inputs else: inputs = [] for input_txn in input_txns: if input_txn['id'] not in mtxn_ids: if 'signature' in input_txn: inputs.append( ExternalInput.from_dict(self.config, self.mongo, input_txn)) else: inputs.append(Input.from_dict(input_txn)) input_sum = 0 if self.coinbase: self.inputs = [] else: if inputs: needed_inputs = [] done = False for y in inputs: print y.id txn = BU.get_transaction_by_id(self.config, self.mongo, y.id, instance=True) if isinstance(y, ExternalInput): y.verify() address = str( P2PKHBitcoinAddress.from_pubkey( txn.public_key.decode('hex'))) else: address = my_address for txn_output in txn.outputs: if txn_output.to == address: input_sum += txn_output.value needed_inputs.append(y) if input_sum >= ( sum([x.value for x in self.outputs]) + self.fee): done = True break if done == True: break if not done: raise NotEnoughMoneyException('not enough money') self.inputs = needed_inputs else: self.inputs = [] remainder = input_sum - (sum([x.value for x in self.outputs]) + self.fee) found = False for x in self.outputs: if my_address == x.to: found = True x.value += remainder if not found: return_change_output = Output(to=my_address, value=remainder) self.outputs.append(return_change_output) def get_input_hashes(self): from fastgraph import FastGraph input_hashes = [] for x in self.inputs: txn = BU.get_transaction_by_id(self.config, self.mongo, x.id, instance=True, include_fastgraph=isinstance( self, FastGraph)) input_hashes.append(str(txn.transaction_signature)) return ''.join(sorted(input_hashes, key=str.lower)) def get_output_hashes(self): outputs_sorted = sorted([x.to_dict() for x in self.outputs], key=lambda x: x['to'].lower()) return ''.join( [x['to'] + "{0:.8f}".format(x['value']) for x in outputs_sorted]) def generate_rid(self): my_bulletin_secret = self.config.get_bulletin_secret() if my_bulletin_secret == self.bulletin_secret: raise BaseException( 'bulletin secrets are identical. do you love yourself so much that you want a relationship on the blockchain?' ) bulletin_secrets = sorted( [str(my_bulletin_secret), str(self.bulletin_secret)], key=str.lower) return hashlib.sha256( str(bulletin_secrets[0]) + str(bulletin_secrets[1])).digest().encode('hex') def generate_relationship(self): return Relationship( dh_private_key=self.dh_private_key, their_bulletin_secret=self.bulletin_secret, their_username=self.username, my_bulletin_secret=self.config.get_bulletin_secret(), my_username=self.config.username) def generate_transaction(self): return Transaction(self.config, self.mongo, self.block_height, self.time, self.rid, self.transaction_signature, self.encrypted_relationship, self.public_key, self.dh_public_key, float(self.fee), self.requester_rid, self.requested_rid, self.hash, inputs=[x.to_dict() for x in self.inputs], outputs=[x.to_dict() for x in self.outputs], coinbase=self.coinbase) def generate_transaction_signature(self): return TU.generate_signature(self.hash, self.private_key)
class TransactionFactory(object): def __init__(self, bulletin_secret='', username='', value=0, fee=0.0, requester_rid='', requested_rid='', public_key='', dh_public_key='', private_key='', dh_private_key='', to='', inputs='', outputs='', coinbase=False, chattext=None, signin=None): self.bulletin_secret = bulletin_secret self.username = username self.requester_rid = requester_rid self.requested_rid = requested_rid self.public_key = public_key self.dh_public_key = dh_public_key self.private_key = private_key self.value = value self.fee = float(fee) self.dh_private_key = dh_private_key self.to = to self.outputs = outputs or [] self.inputs = inputs self.coinbase = coinbase self.chattext = chattext self.signin = signin self.do_money() inputs_concat = self.get_input_hashes() outputs_concat = self.get_output_hashes() if bulletin_secret: self.rid = self.generate_rid() if self.chattext: self.relationship = json.dumps({"chatText": self.chattext}) elif self.signin: for shared_secret in TU.get_shared_secrets_by_rid(self.rid): self.relationship = SignIn(self.signin) self.cipher = Crypt(shared_secret.encode('hex'), shared=True) self.encrypted_relationship = self.cipher.shared_encrypt( self.relationship.to_json()) else: self.relationship = self.generate_relationship() if not private_key: raise BaseException('missing private key') self.cipher = Crypt(Config.wif) self.encrypted_relationship = self.cipher.encrypt( self.relationship.to_json()) else: self.rid = '' self.encrypted_relationship = '' self.hash = hashlib.sha256(self.dh_public_key + self.rid + self.encrypted_relationship + "{0:.8f}".format(self.fee) + self.requester_rid + self.requested_rid + inputs_concat + outputs_concat).digest().encode('hex') self.transaction_signature = self.generate_transaction_signature() self.transaction = self.generate_transaction() def do_money(self): Mongo.init() my_address = str( P2PKHBitcoinAddress.from_pubkey(self.public_key.decode('hex'))) input_txns = BU.get_wallet_unspent_transactions(my_address) miner_transactions = Mongo.db.miner_transactions.find() mtxn_ids = [] for mtxn in miner_transactions: for mtxninput in mtxn['inputs']: mtxn_ids.append(mtxninput['id']) inputs = [ Input.from_dict(input_txn) for input_txn in input_txns if input_txn['id'] not in mtxn_ids ] input_sum = 0 if self.coinbase: self.inputs = [] else: needed_inputs = [] done = False for y in inputs: print y.id txn = BU.get_transaction_by_id(y.id, instance=True) for txn_output in txn.outputs: if txn_output.to == my_address: input_sum += txn_output.value needed_inputs.append(y) if input_sum >= (sum([x.value for x in self.outputs]) + self.fee): done = True break if done == True: break if not done: raise NotEnoughMoneyException('not enough money') self.inputs = needed_inputs return_change_output = Output( to=my_address, value=input_sum - (sum([x.value for x in self.outputs]) + self.fee)) self.outputs.append(return_change_output) def get_input_hashes(self): input_hashes = [] for x in self.inputs: txn = BU.get_transaction_by_id(x.id, instance=True) input_hashes.append(str(txn.transaction_signature)) return ''.join(sorted(input_hashes, key=str.lower)) def get_output_hashes(self): outputs_sorted = sorted([x.to_dict() for x in self.outputs], key=lambda x: x['to'].lower()) return ''.join( [x['to'] + "{0:.8f}".format(x['value']) for x in outputs_sorted]) def generate_rid(self): my_bulletin_secret = Config.get_bulletin_secret() if my_bulletin_secret == self.bulletin_secret: raise BaseException( 'bulletin secrets are identical. do you love yourself so much that you want a relationship on the blockchain?' ) bulletin_secrets = sorted( [str(my_bulletin_secret), str(self.bulletin_secret)], key=str.lower) return hashlib.sha256( str(bulletin_secrets[0]) + str(bulletin_secrets[1])).digest().encode('hex') def generate_relationship(self): return Relationship(dh_private_key=self.dh_private_key, their_bulletin_secret=self.bulletin_secret, their_username=self.username, my_bulletin_secret=Config.get_bulletin_secret(), my_username=Config.username) def generate_transaction(self): return Transaction(self.rid, self.transaction_signature, self.encrypted_relationship, self.public_key, self.dh_public_key, float(self.fee), self.requester_rid, self.requested_rid, self.hash, inputs=self.inputs, outputs=self.outputs, coinbase=self.coinbase) def generate_transaction_signature(self): return TU.generate_signature(self.hash)