def withdraw_proportion_all(cls, address, bitcoin_payments_proportions): """hash BitcoinPayment -> Proportion""" final_amount = Decimal("0.0") print bitcoin_payments_proportions for bp, proportion in bitcoin_payments_proportions.iteritems(): am = bp.calculate_amount(proportion) final_amount += am bp.add_transaction(am, address) bitcoind.send(address, final_amount) return True
def withdraw_proportion_all(cls, address, bitcoin_payments_proportions): """hash BitcoinPayment -> Proportion""" final_amount=Decimal("0.0") print bitcoin_payments_proportions for bp, proportion in bitcoin_payments_proportions.iteritems(): am=bp.calculate_amount(proportion) final_amount+=am bp.add_transaction(am, address) bitcoind.send(address, final_amount) return True
def withdraw_proportion(self, address, proportion): if proportion<=Decimal("0") or proportion>Decimal("100"): raise Exception("Illegal proportion.") amount = self.calculate_amount(proportion) if self.amount-self.withdrawn_total > amount: raise Exception("Trying to withdraw too much.") self.add_transaction(amount, address) bitcoind.send(address, amount)
def withdraw_proportion(self, address, proportion): if proportion <= Decimal("0") or proportion > Decimal("100"): raise Exception("Illegal proportion.") amount = self.calculate_amount(proportion) if self.amount - self.withdrawn_total > amount: raise Exception("Trying to withdraw too much.") self.add_transaction(amount, address) bitcoind.send(address, amount)
def withdraw_all(cls, bitcoinpayments, addresses_shares): # if len(bitcoinpayments)!=len(addresses_shares): # raise Exception("") amounts_all = Payment.calculate_amounts(bitcoinpayments, addresses_shares) for bp in bitcoinpayments: am = bp.withdraw_amounts(addresses_shares) bp.withdraw_addresses = ",".join(addresses_shares.keys()) bp.withdraw_proportions = ",".join([str(x) for x in addresses_shares.values()]) bp.withdraw_amounts = ",".join([str(x) for x in am]) bp.withdrawn_at = datetime.datetime.now() bp.withdrawn_total = sum(am) bp.save() for i, share in enumerate(addresses_shares.keys()): bitcoind.send(share, amounts_all[i]) return True
def process_outgoing_transactions(): with CacheLock('process_outgoing_transactions'): update_wallets = [] for ot in OutgoingTransaction.objects.filter(executed_at=None): result = None OutgoingTransaction.objects.filter(id=ot.id).update(executed_at=datetime.datetime.now(), txid=result) db_transaction.commit() try: result = bitcoind.send(ot.to_bitcoinaddress, ot.amount) except jsonrpc.JSONRPCException: raise OutgoingTransaction.objects.filter(id=ot.id).update(txid=result) transaction = bitcoind.gettransaction(result) if Decimal(transaction['fee']) < Decimal(0): wt = ot.wallettransaction_set.all()[0] fee_transaction = WalletTransaction.objects.create( amount=Decimal(transaction['fee']) * Decimal(-1), from_wallet_id=wt.from_wallet_id) update_wallets.append(wt.from_wallet_id) db_transaction.commit() for wid in update_wallets: if getattr(django_settings, "CELERY_ALWAYS_EAGER", False): # Do not do asyncrhonous transaction processing update_wallet_balance(wid) db_transaction.commit() else: update_wallet_balance.delay(wid)
def send_to_address(self, address, amount, description=''): if settings.BITCOIN_DISABLE_OUTGOING: raise Exception("Outgoing transactions disabled! contact support.") address = address.strip() if type(amount) != Decimal: amount = Decimal(amount) amount = amount.quantize(Decimal('0.00000001')) if not is_valid_btc_address(str(address)): raise Exception(_("Not a valid bitcoin address") + ":" + address) if amount <= 0: raise Exception(_("Can't send zero or negative amounts")) # concurrency check with db_transaction.autocommit(): db_transaction.enter_transaction_management() db_transaction.commit() avail = self.total_balance() updated = Wallet.objects.filter(Q(id=self.id)).update(last_balance=avail) if amount > avail: raise Exception(_("Trying to send too much")) new_balance = avail - amount updated = Wallet.objects.filter(Q(id=self.id) & Q(transaction_counter=self.transaction_counter) & Q(last_balance=avail) )\ .update(last_balance=new_balance, transaction_counter=self.transaction_counter+1) if not updated: print "address transaction concurrency:", new_balance, avail, self.transaction_counter, self.last_balance, self.total_balance() raise Exception(_("Concurrency error with transactions. Please try again.")) # concurrency check end bwt = WalletTransaction.objects.create( amount=amount, from_wallet=self, to_bitcoinaddress=address, description=description) try: result = bitcoind.send(address, amount) except jsonrpc.JSONRPCException: bwt.delete() raise self.transaction_counter = self.transaction_counter+1 self.last_balance = new_balance # check if a transaction fee exists, and deduct it from the wallet # TODO: because fee can't be known beforehand, can result in negative wallet balance. # currently isn't much of a issue, but might be in the future, depending of the application transaction = bitcoind.gettransaction(result) fee_transaction = None total_amount = amount if Decimal(transaction['fee']) < Decimal(0): fee_transaction = WalletTransaction.objects.create( amount=Decimal(transaction['fee']) * Decimal(-1), from_wallet=self) total_amount += fee_transaction.amount if settings.BITCOIN_TRANSACTION_SIGNALING: balance_changed.send(sender=self, changed=(Decimal(-1) * total_amount), transaction=bwt) balance_changed_confirmed.send(sender=self, changed=(Decimal(-1) * total_amount), transaction=bwt) return (bwt, fee_transaction)
def withdraw_all(cls, bitcoinpayments, addresses_shares): #if len(bitcoinpayments)!=len(addresses_shares): # raise Exception("") amounts_all = Payment.calculate_amounts(bitcoinpayments, addresses_shares) for bp in bitcoinpayments: am = bp.withdraw_amounts(addresses_shares) bp.withdraw_addresses = ",".join(addresses_shares.keys()) bp.withdraw_proportions = ",".join( [str(x) for x in addresses_shares.values()]) bp.withdraw_amounts = ",".join([str(x) for x in am]) bp.withdrawn_at = datetime.datetime.now() bp.withdrawn_total = sum(am) bp.save() for i, share in enumerate(addresses_shares.keys()): bitcoind.send(share, amounts_all[i]) return True
def send_to_address(self, address, amount, description=''): if settings.BITCOIN_DISABLE_OUTGOING: raise Exception("Outgoing transactions disabled! contact support.") address = address.strip() if type(amount) != Decimal: amount = Decimal(amount) amount = amount.quantize(Decimal('0.00000001')) if not is_valid_btc_address(str(address)): raise Exception(_("Not a valid bitcoin address") + ":" + address) if amount <= 0: raise Exception(_("Can't send zero or negative amounts")) # concurrency check with db_transaction.autocommit(): avail = self.total_balance() updated = Wallet.objects.filter(Q(id=self.id)).update(last_balance=avail) if amount > avail: raise Exception(_("Trying to send too much")) new_balance = avail - amount updated = Wallet.objects.filter(Q(id=self.id) & Q(transaction_counter=self.transaction_counter) & Q(last_balance=avail) )\ .update(last_balance=new_balance, transaction_counter=self.transaction_counter+1) if not updated: print "address transaction concurrency:", new_balance, avail, self.transaction_counter, self.last_balance, self.total_balance() raise Exception(_("Concurrency error with transactions. Please try again.")) # concurrency check end bwt = WalletTransaction.objects.create( amount=amount, from_wallet=self, to_bitcoinaddress=address, description=description) try: result = bitcoind.send(address, amount) except jsonrpc.JSONRPCException: bwt.delete() raise self.transaction_counter = self.transaction_counter+1 self.last_balance = new_balance # check if a transaction fee exists, and deduct it from the wallet # TODO: because fee can't be known beforehand, can result in negative wallet balance. # currently isn't much of a issue, but might be in the future, depending of the application transaction = bitcoind.gettransaction(result) fee_transaction = None total_amount = amount if Decimal(transaction['fee']) < Decimal(0): fee_transaction = WalletTransaction.objects.create( amount=Decimal(transaction['fee']) * Decimal(-1), from_wallet=self) total_amount += fee_transaction.amount if settings.BITCOIN_TRANSACTION_SIGNALING: balance_changed.send(sender=self, changed=(Decimal(-1) * total_amount), transaction=bwt) balance_changed_confirmed.send(sender=self, changed=(Decimal(-1) * total_amount), transaction=bwt) return (bwt, fee_transaction)
def handle_noargs(self, **options): final_wallets = [] process_num = random.randint(0, 1000) with warnings.catch_warnings(): warnings.filterwarnings("ignore", category=RuntimeWarning) for i in range(0, 3): w = Wallet.objects.create() # print "starting w.id", w.id addr = w.receiving_address() # print "taddr", w.id, addr final_wallets.append(w) for w in final_wallets: if w.total_balance_sql() > 0: print str(process_num) + " error", w.id raise Exception("damn!") # print "final", w.id, w.static_receiving_address(), w.receiving_address() print str( process_num ) + " loading 0.001 to wallet #1", w1.static_receiving_address() w1 = final_wallets[0] w2 = final_wallets[1] w3 = final_wallets[2] bitcoind.send(w1.static_receiving_address(), Decimal("0.001")) while w1.total_balance_sql() <= 0: sleep(1) w1 = Wallet.objects.get(id=w1.id) # print w1.last_balance print str(process_num) + " w1.last_balance " + str(w1.last_balance) print str(process_num) + "loading" w1.send_to_wallet(w2, Decimal("0.0002")) w1.send_to_wallet(w3, Decimal("0.0005")) w3.send_to_address(w1, Decimal("0.0004")) print str(process_num) + " w1.last_balance " + str(w1.last_balance) print str(process_num) + " w2.last_balance " + str(w2.last_balance) print str(process_num) + " w3.last_balance " + str(w3.last_balance) while w1.total_balance_sql() <= 0: sleep(1) w1 = Wallet.objects.get(id=w1.id) print str(process_num) + "catching" print str(process_num) + " w1.last_balance " + str(w1.last_balance) print str(process_num) + " w2.last_balance " + str(w2.last_balance) print str(process_num) + " w3.last_balance " + str(w3.last_balance)
def handle_noargs(self, **options): final_wallets = [] process_num = random.randint(0, 1000) with warnings.catch_warnings(): warnings.filterwarnings("ignore", category=RuntimeWarning) for i in range(0, 3): w = Wallet.objects.create() # print "starting w.id", w.id addr = w.receiving_address() # print "taddr", w.id, addr final_wallets.append(w) for w in final_wallets: if w.total_balance_sql() > 0: print str(process_num) + " error", w.id raise Exception("damn!") # print "final", w.id, w.static_receiving_address(), w.receiving_address() print str(process_num) + " loading 0.001 to wallet #1", w1.static_receiving_address() w1 = final_wallets[0] w2 = final_wallets[1] w3 = final_wallets[2] bitcoind.send(w1.static_receiving_address(), Decimal("0.001")) while w1.total_balance_sql() <= 0: sleep(1) w1 = Wallet.objects.get(id=w1.id) # print w1.last_balance print str(process_num) + " w1.last_balance " + str(w1.last_balance) print str(process_num) + "loading" w1.send_to_wallet(w2, Decimal("0.0002")) w1.send_to_wallet(w3, Decimal("0.0005")) w3.send_to_address(w1, Decimal("0.0004")) print str(process_num) + " w1.last_balance " + str(w1.last_balance) print str(process_num) + " w2.last_balance " + str(w2.last_balance) print str(process_num) + " w3.last_balance " + str(w3.last_balance) while w1.total_balance_sql() <= 0: sleep(1) w1 = Wallet.objects.get(id=w1.id) print str(process_num) + "catching" print str(process_num) + " w1.last_balance " + str(w1.last_balance) print str(process_num) + " w2.last_balance " + str(w2.last_balance) print str(process_num) + " w3.last_balance " + str(w3.last_balance)
def process_outgoing_transactions(): if cache.get("process_outgoing_transactions"): print "process ongoing, skipping..." db_transaction.rollback() return if cache.get("wallet_downtime_utc"): db_transaction.rollback() return # try out bitcoind connection print bitcoind.bitcoind_api.getinfo() with NonBlockingCacheLock('process_outgoing_transactions'): update_wallets = [] for ot in OutgoingTransaction.objects.filter(executed_at=None)[:3]: result = None updated = OutgoingTransaction.objects.filter(id=ot.id, executed_at=None, txid=None, under_execution=False).select_for_update().update(executed_at=datetime.datetime.now(), txid=result) db_transaction.commit() if updated: try: result = bitcoind.send(ot.to_bitcoinaddress, ot.amount) updated2 = OutgoingTransaction.objects.filter(id=ot.id, txid=None).select_for_update().update(txid=result) db_transaction.commit() if updated2: transaction = bitcoind.gettransaction(result) if Decimal(transaction['fee']) < Decimal(0): wt = ot.wallettransaction_set.all()[0] fee_transaction = WalletTransaction.objects.create( amount=Decimal(transaction['fee']) * Decimal(-1), from_wallet_id=wt.from_wallet_id) update_wallets.append(wt.from_wallet_id) except jsonrpc.JSONRPCException as e: if e.error == u"{u'message': u'Insufficient funds', u'code': -4}": OutgoingTransaction.objects.filter(id=ot.id, txid=None, under_execution=False).select_for_update().update(executed_at=None) db_transaction.commit() # sleep(10) raise else: OutgoingTransaction.objects.filter(id=ot.id).select_for_update().update(under_execution=True) db_transaction.commit() raise else: raise Exception("Outgoingtransaction can't be updated!") db_transaction.commit() for wid in update_wallets: update_wallet_balance.delay(wid)