Example #1
0
def main():

    # Creating and loading tests
    ad = Address.create(PW, LABEL)
    ad_b = Address.load(PW, LABEL)
    print(ad.public_key == ad_b.public_key)
    print(ad.raw == ad_b.raw)

    # Wallet tests
    wallet = Wallet()
    wallet.sign_up(PW2, LABEL2)
    print(wallet.current_address.label)
    wallet2 = Wallet()
    wallet2.log_in(PW2, LABEL2)
    print(wallet2.current_address.label)

    # Transaction test
    transaction = wallet.create_transaction(ad.raw, 20)
    print(
        '\tReceiver: {0}\n\tAmount: {1}\n\tSignature: {2}\n\t Timestamp: {3}'.
        format(transaction.receiver, transaction.amount, transaction.signature,
               transaction.timestamp))

    # Signature verification example (and therefore test)
    verify_signature(transaction)
    transaction2 = Transaction.parse(Transaction.serialize(transaction))

    transaction.sender_public_key = ad.public_key  # Changing the public key so signature shouldn't be correct
    verify_signature(transaction)
    print("TX2 verify", transaction2.verify_signature())
Example #2
0
    def create(self, validated_data):

        validated_data["transaction_id"] = uuid4().hex
        instance = Transaction(**validated_data)
        instance.save()

        counter_validated_data = copy(validated_data)
        counter_validated_data["account"] = validated_data["counter_account"]
        counter_validated_data["counter_account"] = validated_data["account"]
        counter_validated_data["debit"] = validated_data["credit"]
        counter_validated_data["credit"] = validated_data["debit"]
        counter_instance = Transaction(**counter_validated_data)
        counter_instance.save()

        return instance
 def get(self, request):
     server = Relay()
     if 'exclude_hash' in request.data:
         exclude = request.data['exclude_hash']
     else:
         exclude = []
         logger.debug("'exclude_hash' not in request.")
     transaction = server.get_transaction(exclude)
     if transaction is not None:
         return Response(Transaction.serialize(transaction),
                         status=status.HTTP_200_OK)
     else:
         return Response({'errors': 'no transaction to send'},
                         status=status.HTTP_404_NOT_FOUND)
 def post(self, request):
     """
     Add a new transaction to the relay transactions list.
     If the transaction.hash is already in the list,
     it will not be added and return 406
     :param request:
     :return: 201 if transaction added, 406 otherwise (hash already exist)
     """
     server = Relay()
     try:
         transaction = Transaction.parse(request.data)
         server.add_transaction(transaction)
         return Response(status=status.HTTP_201_CREATED)
     except (RelayError, ParseException) as e:
         return Response(str(e), status=status.HTTP_406_NOT_ACCEPTABLE)
    def delete(self, request):
        """
        Delete transactions receive in request.data['transactions']
        This is usually done when masternode receive an incorrect block
        and reject some transaction.

        :param request:
        :return: 2OO (OK)
        """
        # TODO make sure that only masters can request deletes
        server = Relay()
        for tx_data in request.data['transactions']:
            try:
                transaction = Transaction.parse(tx_data)
            except ParseException as e:
                logger.warning("Cannot remove transaction: %s" % (str(e)))
            else:
                logger.debug("Removing transaction %s " % transaction.hash)
            server.remove_transaction(transaction)
        return Response(status=status.HTTP_200_OK)
Example #6
0
    def settlement(merchant_id, wechat_amount, alipay_amount):
        assert merchant_id is not None
        assert wechat_amount is not None
        assert alipay_amount is not None

        with transaction.atomic():
            now_timestamp = timezone.now()

            merchant_account_id = Merchant.objects.get(
                pk=merchant_id).account_id
            merchant_account = Account.objects.select_for_update().get(
                id=merchant_account_id)

            # 最近一条结算账单记账日期必须小于当前记账时间,避免重复结算
            latest_settlement = Settlement.objects.filter(account__id=merchant_account_id)\
                            .filter(status=SETTLEMENT_STATUS['PROCESSING']).order_by('-datetime').first()
            if latest_settlement and latest_settlement.datetime.date(
            ) >= now_timestamp.date():
                raise SettlementDuplicateException(
                    f"{now_timestamp.strftime('%Y-%m-%d %H:%M:%S.%f')} occur duplicate settlement"
                    f",merchant's account's id is {merchant_account_id},"
                    f" wechat_amount is {wechat_amount} fen, alipay_amount is {alipay_amount} fen"
                )

            # 校验金额
            if merchant_account.balance < wechat_amount or \
                    merchant_account.withdrawable_balance < wechat_amount or \
                    merchant_account.alipay_balance < alipay_amount or \
                    merchant_account.alipay_withdrawable_balance < alipay_amount:
                raise SettlementAbnormalBalanceException(
                    f"{now_timestamp.strftime('%Y-%m-%d %H:%M:%S.%f')} occur abnormal balance settlement"
                    f",merchant's account's id is {merchant_account_id},"
                    f" wechat_amount is {wechat_amount} fen, alipay_amount is {alipay_amount} fen"
                )

            # 账户扣钱
            if wechat_amount > 0:
                merchant_account.balance = merchant_account.balance - wechat_amount
                merchant_account.withdrawable_balance = merchant_account.withdrawable_balance - wechat_amount
            if alipay_amount > 0:
                merchant_account.alipay_balance = merchant_account.alipay_balance - alipay_amount
                merchant_account.alipay_withdrawable_balance = merchant_account.alipay_withdrawable_balance - alipay_amount
            merchant_account.save()

            new_settlement = Settlement.objects.create(
                serial_number=generate_serial_number(),
                datetime=now_timestamp,
                finished_datetime=None,
                status=SETTLEMENT_STATUS['PROCESSING'],
                account=merchant_account,
                wechat_amount=wechat_amount,
                alipay_amount=alipay_amount,
            )

            Transaction.objects.bulk_create([
                Transaction(
                    content_object=new_settlement,
                    transaction_type=TRANSACTION_TYPE[
                        'MERCHANT_WECHAT_SETTLEMENT'],
                    datetime=now_timestamp,
                    account=merchant_account,
                    amount=-wechat_amount,
                    balance_after_transaction=merchant_account.balance),
                Transaction(
                    content_object=new_settlement,
                    transaction_type=TRANSACTION_TYPE[
                        'MERCHANT_ALIPAY_SETTLEMENT'],
                    datetime=now_timestamp,
                    account=merchant_account,
                    amount=-alipay_amount,
                    balance_after_transaction=merchant_account.alipay_balance)
            ])
Example #7
0
 def create_transaction(self, destination_address, amount):
     new_transaction = Transaction(destination_address, amount,
                                   datetime.now().timestamp(),
                                   self.current_address.public_key)
     self.sign_transaction(new_transaction)
     return new_transaction
def send_transaction(transaction):
    return requests.post(relay_addr(TRANSACTION_ENDPOINT),
                         data=Transaction.serialize(transaction)).status_code
    def post(self, request):
        """
        Manage the POST request, the Master Node will receive a block and it
        will check wether it is accepted or not and will add it to the
        rest of the blockchain accordingly only
        if the one requesting it is a Relay Node (see user and password above).
        If the block is rejected because of bad transactions, those transactions
        are returned to the relay node that made the request.
        If the block is accepted, the new block is sent to all relay nodes.
        """
        try:
            # request contains the block, and the address of the miner
            logger.debug("Block received from %s" % request.data['miner_address'])
            block_data = request.data['block']
            block = Block.parse(block_data)
        except KeyError:
            logger.debug("No block given.")
            return Response({"errors": "No block given."},
                            status=status.HTTP_406_NOT_ACCEPTABLE)
        except ParseException as e:
            logger.debug("Parsing block error.")
            return Response({"errors": "%s" % e},
                            status=status.HTTP_406_NOT_ACCEPTABLE)

        (hash_verify, bad_transactions) = self.server.update_blockchain(block)
        if hash_verify and len(bad_transactions) == 0:  # block is valid
            logger.debug("Block '%s' successfully added" % block.header)
            data = {'transactions': []}
            for transaction in block.transactions:
                data['transactions'].append(Transaction.serialize(transaction))
            for relay_ip in settings.RELAY_IP:
                logger.debug("Sending block '%s' to relay %s" % (block.header, relay_ip))
                client.post(relay_ip, 'blockchain', block_data)
                client.delete(relay_ip, 'transactions', data)
            if self.server.balance >= settings.REWARD:
                self.server.balance -= settings.REWARD
                miner_transaction = self.server.wallet.create_transaction(
                    request.data['miner_address'],
                    settings.REWARD)
                client.post(relay_ip, 'transactions', Transaction.serialize(miner_transaction))
            response = Response({"detail": "Block successfully added!"},
                                status=status.HTTP_201_CREATED)
        else:
            logger.debug("Block '%s' can NOT be added (bad header or bad TXs)." % block.header)
            data = {'transactions': []}
            if len(bad_transactions) > 0:
                for transaction in bad_transactions:
                    logger.debug("Bad TX '%s'" % transaction.hash)
                    data['transactions'].append(Transaction.serialize(transaction))
                # Send to all relays bad TXs, since the miner can request
                # transactions from any relay
                for relay_ip in settings.RELAY_IP:
                    logger.debug("Sending bad TXs to relay %s" % relay_ip)
                    client.delete(relay_ip, 'transactions', data)
                    response = Response({"errors": "Bad transactions where found in new block.",
                                         "data": data},
                                        status=status.HTTP_406_NOT_ACCEPTABLE)
            else:
                response = Response({"errors": "Bad header.",
                                     "data": block_data},
                                    status=status.HTTP_406_NOT_ACCEPTABLE)
        return response
Example #10
0
 def get_transaction(self):
     return Transaction()
Example #11
0
    def on_payment_unfreeze(cls, payment):
        """
        unfreeze payment.
        :param payment:
        :return:
        :raise: InvalidStatusError
        """
        with PayChannelContext(payment.pay_channel):
            with transaction.atomic():
                timestamp = timezone.now()
                accounts = None
                merchant_account = None

                if payment.coupon:  # 使用了优惠券的情况
                    merchant_account_id = payment.merchant.account_id
                    originator_account_id = payment.coupon.originator_merchant.account_id
                    inviter_account_id = payment.merchant.inviter.account_id

                    accounts = AccountProxy.objects.select_for_update().filter(
                        id__in=(PLATFORM_ACCOUNT_ID, merchant_account_id,
                                originator_account_id, inviter_account_id))
                else:
                    merchant_account_id = payment.merchant.account_id
                    merchant_account = AccountProxy.objects.select_for_update(
                    ).get(id=merchant_account_id)

                payment = Payment.objects.select_for_update().select_related(
                    'coupon').get(serial_number=payment.serial_number)

                if payment.status != PAYMENT_STATUS.FROZEN:
                    raise InvalidStatusError()

                if payment.coupon:  # 使用了优惠券的情况
                    accounts = {a.id: a for a in accounts}
                    if len(accounts) != 4:
                        logger.error('Cannot find all the accounts:{}'.format(
                            repr((PLATFORM_ACCOUNT_ID, merchant_account_id,
                                  originator_account_id, inviter_account_id))))
                        raise AccountProxy.DoesNotExist()

                    platform_account = accounts[PLATFORM_ACCOUNT_ID]
                    merchant_account = accounts[merchant_account_id]
                    originator_account = accounts[originator_account_id]
                    inviter_account = accounts[inviter_account_id]

                    platform_account.channel_balance -= payment.originator_share + payment.inviter_share
                    platform_account.save()

                    originator_account.channel_balance += payment.originator_share
                    originator_account.channel_withdrawable_balance += payment.originator_share
                    originator_account.save()

                    inviter_account.channel_balance += payment.inviter_share
                    inviter_account.channel_withdrawable_balance += payment.inviter_share
                    inviter_account.save()

                    payment.status = PAYMENT_STATUS.FINISHED
                    payment.save()

                    merchant_account.channel_withdrawable_balance += payment.order_price - payment.coupon.discount - sum(
                        (payment.platform_share, payment.originator_share,
                         payment.inviter_share))
                    merchant_account.save()

                    # 记录Transaction
                    Transaction.objects.bulk_create([
                        Transaction(content_object=payment,
                                    transaction_type=TRANSACTION_TYPE[
                                        'PLATFORM_EXPEND_MERCHANT_SHARE'],
                                    datetime=timestamp,
                                    account=platform_account,
                                    amount=-payment.originator_share,
                                    balance_after_transaction=platform_account.
                                    channel_balance + payment.inviter_share),
                        Transaction(content_object=payment,
                                    transaction_type=TRANSACTION_TYPE[
                                        'PLATFORM_EXPEND_MARKETER_SHARE'],
                                    datetime=timestamp,
                                    account=platform_account,
                                    amount=-payment.inviter_share,
                                    balance_after_transaction=platform_account.
                                    channel_balance),
                        Transaction(content_object=payment,
                                    transaction_type=TRANSACTION_TYPE[
                                        'PLATFORM_EXPEND_PLATFORM_SHARE'],
                                    datetime=timestamp,
                                    account=platform_account,
                                    amount=-payment.platform_share,
                                    balance_after_transaction=platform_account.
                                    channel_balance - payment.platform_share),
                        Transaction(content_object=payment,
                                    transaction_type=TRANSACTION_TYPE[
                                        'PLATFORM_SHARE'],
                                    datetime=timestamp,
                                    account=platform_account,
                                    amount=payment.platform_share,
                                    balance_after_transaction=platform_account.
                                    channel_balance),
                        Transaction(
                            content_object=payment,
                            transaction_type=TRANSACTION_TYPE[
                                'MERCHANT_SHARE'],
                            datetime=timestamp,
                            account=originator_account,
                            amount=payment.originator_share,
                            balance_after_transaction=originator_account.
                            channel_balance),
                        Transaction(content_object=payment,
                                    transaction_type=TRANSACTION_TYPE[
                                        'MARKETER_SHARE'],
                                    datetime=timestamp,
                                    account=inviter_account,
                                    amount=payment.inviter_share,
                                    balance_after_transaction=inviter_account.
                                    channel_balance)
                    ])

                else:  # 没有使用优惠券的情况
                    payment.status = PAYMENT_STATUS.FINISHED
                    payment.save()

                    merchant_account.channel_withdrawable_balance += payment.order_price
                    merchant_account.save()
Example #12
0
    def on_payment_success(cls, payment):
        """
        :param payment:
        :return:
        """
        with PayChannelContext(payment.pay_channel):
            with transaction.atomic():
                timestamp = timezone.now()

                platform_account = AccountProxy.objects.select_for_update(
                ).get(id=PLATFORM_ACCOUNT_ID)
                merchant_account = AccountProxy.objects.select_for_update(
                ).get(id=payment.merchant.account.id)
                payment = Payment.objects.select_for_update().get(
                    serial_number=payment.serial_number)

                if payment.status != PAYMENT_STATUS['UNPAID']:
                    raise InvalidStatusError()  # Duplicated callback
                payment.status = PAYMENT_STATUS['FROZEN']
                payment.save()

                if not payment.coupon:  # 没有使用优惠券的情况
                    merchant_account.channel_balance = merchant_account.channel_balance + payment.order_price
                    merchant_account.save()

                    Transaction.objects.bulk_create([
                        Transaction(content_object=payment,
                                    transaction_type=TRANSACTION_TYPE[
                                        'PLATFORM_RECEIVE'],
                                    datetime=timestamp,
                                    account=platform_account,
                                    amount=payment.order_price,
                                    balance_after_transaction=platform_account.
                                    channel_balance + payment.order_price),
                        Transaction(content_object=payment,
                                    transaction_type=TRANSACTION_TYPE[
                                        'PLATFORM_EXPEND_MERCHANT_RECEIVE'],
                                    datetime=timestamp,
                                    account=platform_account,
                                    amount=-payment.order_price,
                                    balance_after_transaction=platform_account.
                                    channel_balance),
                        Transaction(content_object=payment,
                                    transaction_type=TRANSACTION_TYPE[
                                        'MERCHANT_RECEIVE'],
                                    datetime=timestamp,
                                    account=merchant_account,
                                    amount=payment.order_price,
                                    balance_after_transaction=merchant_account.
                                    channel_balance)
                    ])
                else:  # 使用了优惠券的情况
                    paid_price = payment.order_price - payment.coupon.discount
                    total_share = payment.platform_share + payment.inviter_share + payment.originator_share

                    platform_account.channel_balance = platform_account.channel_balance + total_share
                    platform_account.save()
                    merchant_account.channel_balance = merchant_account.channel_balance + paid_price - total_share
                    merchant_account.save()

                    Transaction.objects.bulk_create([
                        Transaction(content_object=payment,
                                    transaction_type=TRANSACTION_TYPE[
                                        'PLATFORM_RECEIVE'],
                                    datetime=timestamp,
                                    account=platform_account,
                                    amount=paid_price,
                                    balance_after_transaction=platform_account.
                                    channel_balance + paid_price -
                                    total_share),
                        Transaction(content_object=payment,
                                    transaction_type=TRANSACTION_TYPE[
                                        'PLATFORM_EXPEND_MERCHANT_RECEIVE'],
                                    datetime=timestamp,
                                    account=platform_account,
                                    amount=-(paid_price - total_share),
                                    balance_after_transaction=platform_account.
                                    channel_balance),
                        Transaction(content_object=payment,
                                    transaction_type=TRANSACTION_TYPE[
                                        'MERCHANT_RECEIVE'],
                                    datetime=timestamp,
                                    account=merchant_account,
                                    amount=paid_price - total_share,
                                    balance_after_transaction=merchant_account.
                                    channel_balance)
                    ])
Example #13
0
    def on_refund_success(cls, refund):

        with transaction.atomic():
            timestamp = timezone.now()

            platform_account = AccountProxy.objects.select_for_update().get(
                id=PLATFORM_ACCOUNT_ID)
            merchant_account = AccountProxy.objects.select_for_update().get(
                id=refund.payment.merchant.account.id)

            coupon = refund.payment.coupon
            if coupon:
                coupon = Coupon.objects.select_for_update().get(id=coupon.id)

            payment = Payment.objects.select_for_update().get(
                serial_number=refund.payment.serial_number)
            refund = Refund.objects.select_for_update().get(
                serial_number=refund.serial_number)

            with PayChannelContext(payment.pay_channel):
                if refund.status != REFUND_STATUS['REQUESTED'] \
                        or payment.status != PAYMENT_STATUS['REFUND_REQUESTED']:
                    raise InvalidStatusError()

                refund.status = REFUND_STATUS['FINISHED']
                refund.save()

                payment.status = PAYMENT_STATUS['REFUND']
                payment.save()

                if not coupon:  # 没有使用优惠券
                    merchant_account.channel_balance = merchant_account.channel_balance - payment.order_price
                    merchant_account.save()

                    Transaction.objects.bulk_create([
                        Transaction(content_object=refund,
                                    transaction_type=TRANSACTION_TYPE[
                                        'MERCHANT_REFUND'],
                                    datetime=timestamp,
                                    account=merchant_account,
                                    amount=-payment.order_price,
                                    balance_after_transaction=merchant_account.
                                    channel_balance),
                        Transaction(content_object=refund,
                                    transaction_type=TRANSACTION_TYPE[
                                        'PLATFORM_EARNING_MERCHANT_REFUND'],
                                    datetime=timestamp,
                                    account=platform_account,
                                    amount=payment.order_price,
                                    balance_after_transaction=platform_account.
                                    channel_balance + payment.order_price),
                        Transaction(content_object=refund,
                                    transaction_type=TRANSACTION_TYPE[
                                        'PLATFORM_REFUND'],
                                    datetime=timestamp,
                                    account=platform_account,
                                    amount=-payment.order_price,
                                    balance_after_transaction=platform_account.
                                    channel_balance)
                    ])
                else:  # 有使用优惠券的情况
                    paid_price = payment.order_price - payment.coupon.discount
                    total_share = payment.platform_share + payment.inviter_share + payment.originator_share

                    merchant_account.channel_balance = merchant_account.channel_balance - (
                        paid_price - total_share)
                    merchant_account.save()

                    platform_account.channel_balance = platform_account.channel_balance - total_share
                    platform_account.save()

                    Transaction.objects.bulk_create([
                        Transaction(content_object=refund,
                                    transaction_type=TRANSACTION_TYPE[
                                        'MERCHANT_REFUND'],
                                    datetime=timestamp,
                                    account=merchant_account,
                                    amount=-(paid_price - total_share),
                                    balance_after_transaction=merchant_account.
                                    channel_balance),
                        Transaction(content_object=refund,
                                    transaction_type=TRANSACTION_TYPE[
                                        'PLATFORM_EARNING_MERCHANT_REFUND'],
                                    datetime=timestamp,
                                    account=platform_account,
                                    amount=(paid_price - total_share),
                                    balance_after_transaction=platform_account.
                                    channel_balance + paid_price),
                        Transaction(content_object=refund,
                                    transaction_type=TRANSACTION_TYPE[
                                        'PLATFORM_REFUND'],
                                    datetime=timestamp,
                                    account=platform_account,
                                    amount=-paid_price,
                                    balance_after_transaction=platform_account.
                                    channel_balance)
                    ])

                    # 设置原优惠券为销毁状态,并退给用户一张新的优惠券
                    coupon.status = COUPON_STATUS.DESTROYED
                    coupon.save()

                    new_coupon = Coupon.objects.create(
                        rule_id=coupon.rule_id,
                        client_id=coupon.client_id,
                        discount=coupon.discount,
                        min_charge=coupon.min_charge,
                        originator_merchant_id=coupon.originator_merchant_id,
                        status=COUPON_STATUS.NOT_USED,
                        obtain_datetime=coupon.obtain_datetime,
                    )