Esempio n. 1
0
    def test_history2(self, node_param):
        if node_param == "non_appbase":
            stm = self.bts
        else:
            stm = self.appbase
        account = Account("dpaygobot", dpay_instance=stm)
        h_list = []
        max_index = account.virtual_op_count()
        for h in account.history(start=max_index - 4, stop=max_index, use_block_num=False, batch_size=2, raw_output=False):
            h_list.append(h)
        self.assertEqual(len(h_list), 5)
        for i in range(1, 5):
            self.assertEqual(h_list[i]["index"] - h_list[i - 1]["index"], 1)

        h_list = []
        for h in account.history(start=max_index - 4, stop=max_index, use_block_num=False, batch_size=6, raw_output=False):
            h_list.append(h)
        self.assertEqual(len(h_list), 5)
        for i in range(1, 5):
            self.assertEqual(h_list[i]["index"] - h_list[i - 1]["index"], 1)

        h_list = []
        for h in account.history(start=max_index - 4, stop=max_index, use_block_num=False, batch_size=2, raw_output=True):
            h_list.append(h)
        self.assertEqual(len(h_list), 5)
        for i in range(1, 5):
            self.assertEqual(h_list[i][0] - h_list[i - 1][0], 1)

        h_list = []
        for h in account.history(start=max_index - 4, stop=max_index, use_block_num=False, batch_size=6, raw_output=True):
            h_list.append(h)
        self.assertEqual(len(h_list), 5)
        for i in range(1, 5):
            self.assertEqual(h_list[i][0] - h_list[i - 1][0], 1)
Esempio n. 2
0
 def test_history_votes(self):
     stm = self.bts
     account = Account("gtg", dpay_instance=stm)
     utc = pytz.timezone('UTC')
     limit_time = utc.localize(datetime.utcnow()) - timedelta(days=2)
     votes_list = []
     for v in account.history(start=limit_time, only_ops=["vote"]):
         votes_list.append(v)
     start_num = votes_list[0]["block"]
     votes_list2 = []
     for v in account.history(start=start_num, only_ops=["vote"]):
         votes_list2.append(v)
     self.assertTrue(abs(len(votes_list) - len(votes_list2)) < 2)
Esempio n. 3
0
 def test_history_block_num(self, node_param):
     if node_param == "non_appbase":
         stm = self.bts
         zero_element = 0
     else:
         stm = self.appbase
         zero_element = 0  # bug in dpay
     account = Account("fullnodeupdate", dpay_instance=stm)
     h_all_raw = []
     for h in account.history_reverse(raw_output=True):
         h_all_raw.append(h)
     h_list = []
     for h in account.history(start=h_all_raw[-1][1]["block"], stop=h_all_raw[-11 + zero_element][1]["block"], use_block_num=True, batch_size=10, raw_output=True):
         h_list.append(h)
     self.assertEqual(h_list[0][0], zero_element)
     self.assertEqual(h_list[-1][0], 10)
     self.assertEqual(h_list[0][1]['block'], h_all_raw[-1][1]['block'])
     self.assertEqual(h_list[-1][1]['block'], h_all_raw[-11 + zero_element][1]['block'])
     h_list = []
     for h in account.history_reverse(start=h_all_raw[-11 + zero_element][1]["block"], stop=h_all_raw[-1][1]["block"], use_block_num=True, batch_size=10, raw_output=True):
         h_list.append(h)
     self.assertEqual(h_list[0][0], 10)
     self.assertEqual(h_list[-1][0], zero_element)
     self.assertEqual(h_list[0][1]['block'], h_all_raw[-11 + zero_element][1]['block'])
     self.assertEqual(h_list[-1][1]['block'], h_all_raw[-1][1]['block'])
     h_list = []
     for h in account.get_account_history(10, 10, use_block_num=True, start=h_all_raw[-2 + zero_element][1]["block"], stop=h_all_raw[-10 + zero_element][1]["block"], order=1, raw_output=True):
         h_list.append(h)
     self.assertEqual(h_list[0][0], 1)
     self.assertEqual(h_list[-1][0], 9)
     self.assertEqual(h_list[0][1]['block'], h_all_raw[-2 + zero_element][1]['block'])
     self.assertEqual(h_list[-1][1]['block'], h_all_raw[-10 + zero_element][1]['block'])
     h_list = []
     for h in account.get_account_history(10, 10, use_block_num=True, start=h_all_raw[-10 + zero_element][1]["block"], stop=h_all_raw[-2 + zero_element][1]["block"], order=-1, raw_output=True):
         h_list.append(h)
     self.assertEqual(h_list[0][0], 9)
     self.assertEqual(h_list[-1][0], 1)
     self.assertEqual(h_list[0][1]['block'], h_all_raw[-10 + zero_element][1]['block'])
     self.assertEqual(h_list[-1][1]['block'], h_all_raw[-2 + zero_element][1]['block'])
 print("dpay_acc.get_account_votes() {}".format(
     dpay_acc.get_account_votes()))
 # get_withdraw_routes
 print("dpaygo_acc.get_withdraw_routes()  {}".format(
     dpaygo_acc.get_withdraw_routes()))
 print("dpay_acc.get_withdraw_routes() {}".format(
     dpay_acc.get_withdraw_routes()))
 # get_conversion_requests
 print("dpaygo_acc.get_conversion_requests()  {}".format(
     dpaygo_acc.get_conversion_requests()))
 print("dpay_acc.get_conversion_requests() {}".format(
     dpay_acc.get_conversion_requests()))
 # export
 # history
 dpaygo_hist = []
 for h in dpaygo_acc.history(only_ops=["transfer"]):
     dpaygo_hist.append(h)
     if len(dpaygo_hist) >= 10:
         break
 dpay_hist = []
 for h in dpay_acc.history(filter_by="transfer", start=0):
     dpay_hist.append(h)
     if len(dpay_hist) >= 10:
         break
 print("dpaygo_acc.history()  {}".format(dpaygo_hist))
 print("dpay_acc.history() {}".format(dpay_hist))
 # history_reverse
 dpaygo_hist = []
 for h in dpaygo_acc.history_reverse(only_ops=["transfer"]):
     dpaygo_hist.append(h)
     if len(dpaygo_hist) >= 10:
Esempio n. 5
0
class AccountSnapshot(list):
    """ This class allows to easily access Account history

        :param str account_name: Name of the account
        :param dpaygo.dpay.DPay dpay_instance: DPay
               instance
    """
    def __init__(self, account, account_history=[], dpay_instance=None):
        self.dpay = dpay_instance or shared_dpay_instance()
        self.account = Account(account, dpay_instance=self.dpay)
        self.reset()
        super(AccountSnapshot, self).__init__(account_history)

    def reset(self):
        """ Resets the arrays not the stored account history
        """
        self.own_vests = [Amount("0 VESTS", dpay_instance=self.dpay)]
        self.own_dpay = [Amount("0 BEX", dpay_instance=self.dpay)]
        self.own_bbd = [Amount("0 BBD", dpay_instance=self.dpay)]
        self.delegated_vests_in = [{}]
        self.delegated_vests_out = [{}]
        self.timestamps = [addTzInfo(datetime(1970, 1, 1, 0, 0, 0, 0))]
        import dpaygobase.operationids
        self.ops_statistics = dpaygobase.operationids.operations.copy()
        for key in self.ops_statistics:
            self.ops_statistics[key] = 0
        self.reward_timestamps = []
        self.author_rewards = []
        self.curation_rewards = []
        self.curation_per_1000_SP_timestamp = []
        self.curation_per_1000_SP = []
        self.out_vote_timestamp = []
        self.out_vote_weight = []
        self.in_vote_timestamp = []
        self.in_vote_weight = []
        self.in_vote_rep = []
        self.in_vote_rshares = []
        self.vp = []
        self.vp_timestamp = []
        self.rep = []
        self.rep_timestamp = []

    def search(self, search_str, start=None, stop=None, use_block_num=True):
        """ Returns ops in the given range"""
        ops = []
        if start is not None:
            start = addTzInfo(start)
        if stop is not None:
            stop = addTzInfo(stop)
        for op in self:
            if use_block_num and start is not None and isinstance(start, int):
                if op["block"] < start:
                    continue
            elif not use_block_num and start is not None and isinstance(
                    start, int):
                if op["index"] < start:
                    continue
            elif start is not None and isinstance(start,
                                                  (datetime, date, time)):
                if start > formatTimeString(op["timestamp"]):
                    continue
            if use_block_num and stop is not None and isinstance(stop, int):
                if op["block"] > stop:
                    continue
            elif not use_block_num and stop is not None and isinstance(
                    stop, int):
                if op["index"] > stop:
                    continue
            elif stop is not None and isinstance(stop, (datetime, date, time)):
                if stop < formatTimeString(op["timestamp"]):
                    continue
            op_string = json.dumps(list(op.values()))
            if re.search(search_str, op_string):
                ops.append(op)
        return ops

    def get_ops(self,
                start=None,
                stop=None,
                use_block_num=True,
                only_ops=[],
                exclude_ops=[]):
        """ Returns ops in the given range"""
        if start is not None:
            start = addTzInfo(start)
        if stop is not None:
            stop = addTzInfo(stop)
        for op in self:
            if use_block_num and start is not None and isinstance(start, int):
                if op["block"] < start:
                    continue
            elif not use_block_num and start is not None and isinstance(
                    start, int):
                if op["index"] < start:
                    continue
            elif start is not None and isinstance(start,
                                                  (datetime, date, time)):
                if start > formatTimeString(op["timestamp"]):
                    continue
            if use_block_num and stop is not None and isinstance(stop, int):
                if op["block"] > stop:
                    continue
            elif not use_block_num and stop is not None and isinstance(
                    stop, int):
                if op["index"] > stop:
                    continue
            elif stop is not None and isinstance(stop, (datetime, date, time)):
                if stop < formatTimeString(op["timestamp"]):
                    continue
            if exclude_ops and op["type"] in exclude_ops:
                continue
            if not only_ops or op["type"] in only_ops:
                yield op

    def get_data(self, timestamp=None, index=0):
        """ Returns snapshot for given timestamp"""
        if timestamp is None:
            timestamp = datetime.utcnow()
        timestamp = addTzInfo(timestamp)
        # Find rightmost value less than x
        i = bisect_left(self.timestamps, timestamp)
        if i:
            index = i - 1
        else:
            return {}
        ts = self.timestamps[index]
        own = self.own_vests[index]
        din = self.delegated_vests_in[index]
        dout = self.delegated_vests_out[index]
        dpay = self.own_dpay[index]
        bbd = self.own_bbd[index]
        sum_in = sum([din[key].amount for key in din])
        sum_out = sum([dout[key].amount for key in dout])
        bp_in = self.dpay.vests_to_sp(sum_in, timestamp=ts)
        bp_out = self.dpay.vests_to_sp(sum_out, timestamp=ts)
        bp_own = self.dpay.vests_to_sp(own, timestamp=ts)
        bp_eff = bp_own + bp_in - bp_out
        return {
            "timestamp": ts,
            "vests": own,
            "delegated_vests_in": din,
            "delegated_vests_out": dout,
            "bp_own": bp_own,
            "bp_eff": bp_eff,
            "dpay": dpay,
            "bbd": bbd,
            "index": index
        }

    def get_account_history(self, start=None, stop=None, use_block_num=True):
        """ Uses account history to fetch all related ops

            :param int/datetime start: start number/date of transactions to
                return (*optional*)
            :param int/datetime stop: stop number/date of transactions to
                return (*optional*)
            :param bool use_block_num: if true, start and stop are block numbers,
                otherwise virtual OP count numbers.

        """
        super(AccountSnapshot, self).__init__([
            h for h in self.account.history(
                start=start, stop=stop, use_block_num=use_block_num)
        ])

    def update_rewards(self, timestamp, curation_reward, author_vests,
                       author_dpay, author_bbd):
        self.reward_timestamps.append(timestamp)
        self.curation_rewards.append(curation_reward)
        self.author_rewards.append({
            "vests": author_vests,
            "dpay": author_dpay,
            "bbd": author_bbd
        })

    def update_out_vote(self, timestamp, weight):
        self.out_vote_timestamp.append(timestamp)
        self.out_vote_weight.append(weight)

    def update_in_vote(self, timestamp, weight, op):
        v = Vote(op)
        try:
            v.refresh()
            self.in_vote_timestamp.append(timestamp)
            self.in_vote_weight.append(weight)
            self.in_vote_rep.append(int(v["reputation"]))
            self.in_vote_rshares.append(int(v["rshares"]))
        except:
            print("Could not found: %s" % v)
            return

    def update(self,
               timestamp,
               own,
               delegated_in=None,
               delegated_out=None,
               dpay=0,
               bbd=0):
        """ Updates the internal state arrays

            :param datetime timestamp: datetime of the update
            :param Amount/float own: vests
            :param dict delegated_in: Incoming delegation
            :param dict delegated_out: Outgoing delegation
            :param Amount/float dpay: dpay
            :param Amount/float bbd: bbd

        """
        self.timestamps.append(timestamp - timedelta(seconds=1))
        self.own_vests.append(self.own_vests[-1])
        self.own_dpay.append(self.own_dpay[-1])
        self.own_bbd.append(self.own_bbd[-1])
        self.delegated_vests_in.append(self.delegated_vests_in[-1])
        self.delegated_vests_out.append(self.delegated_vests_out[-1])

        self.timestamps.append(timestamp)
        self.own_vests.append(self.own_vests[-1] + own)
        self.own_dpay.append(self.own_dpay[-1] + dpay)
        self.own_bbd.append(self.own_bbd[-1] + bbd)

        new_deleg = dict(self.delegated_vests_in[-1])
        if delegated_in is not None and delegated_in:
            if delegated_in['amount'] == 0:
                del new_deleg[delegated_in['account']]
            else:
                new_deleg[delegated_in['account']] = delegated_in['amount']
        self.delegated_vests_in.append(new_deleg)

        new_deleg = dict(self.delegated_vests_out[-1])
        if delegated_out is not None and delegated_out:
            if delegated_out['account'] is None:
                # return_vesting_delegation
                for delegatee in new_deleg:
                    if new_deleg[delegatee]['amount'] == delegated_out[
                            'amount']:
                        del new_deleg[delegatee]
                        break

            elif delegated_out['amount'] != 0:
                # new or updated non-zero delegation
                new_deleg[delegated_out['account']] = delegated_out['amount']

                # skip undelegations here, wait for 'return_vesting_delegation'
                # del new_deleg[delegated_out['account']]

        self.delegated_vests_out.append(new_deleg)

    def build(self,
              only_ops=[],
              exclude_ops=[],
              enable_rewards=False,
              enable_out_votes=False,
              enable_in_votes=False):
        """ Builds the account history based on all account operations

            :param array only_ops: Limit generator by these
                operations (*optional*)
            :param array exclude_ops: Exclude thse operations from
                generator (*optional*)

        """
        if len(self.timestamps) > 0:
            start_timestamp = self.timestamps[-1]
        else:
            start_timestamp = None
        for op in sorted(self, key=lambda k: k['timestamp']):
            ts = parse_time(op['timestamp'])
            if start_timestamp is not None and start_timestamp > ts:
                continue
            # print(op)
            if op['type'] in exclude_ops:
                continue
            if len(only_ops) > 0 and op['type'] not in only_ops:
                continue
            self.ops_statistics[op['type']] += 1
            self.parse_op(op,
                          only_ops=only_ops,
                          enable_rewards=enable_rewards,
                          enable_out_votes=enable_out_votes,
                          enable_in_votes=enable_in_votes)

    def parse_op(self,
                 op,
                 only_ops=[],
                 enable_rewards=False,
                 enable_out_votes=False,
                 enable_in_votes=False):
        """ Parse account history operation"""
        ts = parse_time(op['timestamp'])

        if op['type'] == "account_create":
            fee_dpay = Amount(op['fee'], dpay_instance=self.dpay).amount
            fee_vests = self.dpay.bp_to_vests(Amount(
                op['fee'], dpay_instance=self.dpay).amount,
                                              timestamp=ts)
            # print(fee_vests)
            if op['new_account_name'] == self.account["name"]:
                self.update(ts, fee_vests, 0, 0)
                return
            if op['creator'] == self.account["name"]:
                self.update(ts, 0, 0, 0, fee_dpay * (-1), 0)
                return

        elif op['type'] == "account_create_with_delegation":
            fee_dpay = Amount(op['fee'], dpay_instance=self.dpay).amount
            fee_vests = self.dpay.bp_to_vests(Amount(
                op['fee'], dpay_instance=self.dpay).amount,
                                              timestamp=ts)
            if op['new_account_name'] == self.account["name"]:
                if Amount(op['delegation'],
                          dpay_instance=self.dpay).amount > 0:
                    delegation = {
                        'account': op['creator'],
                        'amount': Amount(op['delegation'],
                                         dpay_instance=self.dpay)
                    }
                else:
                    delegation = None
                self.update(ts, fee_vests, delegation, 0)
                return

            if op['creator'] == self.account["name"]:
                delegation = {
                    'account': op['new_account_name'],
                    'amount': Amount(op['delegation'], dpay_instance=self.dpay)
                }
                self.update(ts, 0, 0, delegation, fee_dpay * (-1), 0)
                return

        elif op['type'] == "delegate_vesting_shares":
            vests = Amount(op['vesting_shares'], dpay_instance=self.dpay)
            # print(op)
            if op['delegator'] == self.account["name"]:
                delegation = {'account': op['delegatee'], 'amount': vests}
                self.update(ts, 0, 0, delegation)
                return
            if op['delegatee'] == self.account["name"]:
                delegation = {'account': op['delegator'], 'amount': vests}
                self.update(ts, 0, delegation, 0)
                return

        elif op['type'] == "transfer":
            amount = Amount(op['amount'], dpay_instance=self.dpay)
            # print(op)
            if op['from'] == self.account["name"]:
                if amount.symbol == "BEX":
                    self.update(ts, 0, 0, 0, amount * (-1), 0)
                elif amount.symbol == "BBD":
                    self.update(ts, 0, 0, 0, 0, amount * (-1))
            if op['to'] == self.account["name"]:
                if amount.symbol == "BEX":
                    self.update(ts, 0, 0, 0, amount, 0)
                elif amount.symbol == "BBD":
                    self.update(ts, 0, 0, 0, 0, amount)
            # print(op, vests)
            # self.update(ts, vests, 0, 0)
            return

        elif op['type'] == "fill_order":
            current_pays = Amount(op["current_pays"], dpay_instance=self.dpay)
            open_pays = Amount(op["open_pays"], dpay_instance=self.dpay)
            if op["current_owner"] == self.account["name"]:
                if current_pays.symbol == "BEX":
                    self.update(ts, 0, 0, 0, current_pays * (-1), open_pays)
                elif current_pays.symbol == "BBD":
                    self.update(ts, 0, 0, 0, open_pays, current_pays * (-1))
            if op["open_owner"] == self.account["name"]:
                if current_pays.symbol == "BEX":
                    self.update(ts, 0, 0, 0, current_pays, open_pays * (-1))
                elif current_pays.symbol == "BBD":
                    self.update(ts, 0, 0, 0, open_pays * (-1), current_pays)
            # print(op)
            return

        elif op['type'] == "transfer_to_vesting":
            dpay = Amount(op['amount'], dpay_instance=self.dpay)
            vests = self.dpay.bp_to_vests(dpay.amount, timestamp=ts)
            if op['from'] == self.account["name"]:
                self.update(ts, vests, 0, 0, dpay * (-1), 0)
            else:
                self.update(ts, vests, 0, 0, 0, 0)
            # print(op)
            # print(op, vests)
            return

        elif op['type'] == "fill_vesting_withdraw":
            # print(op)
            vests = Amount(op['withdrawn'], dpay_instance=self.dpay)
            self.update(ts, vests * (-1), 0, 0)
            return

        elif op['type'] == "return_vesting_delegation":
            delegation = {
                'account': None,
                'amount': Amount(op['vesting_shares'], dpay_instance=self.dpay)
            }
            self.update(ts, 0, 0, delegation)
            return

        elif op['type'] == "claim_reward_balance":
            vests = Amount(op['reward_vests'], dpay_instance=self.dpay)
            dpay = Amount(op['reward_dpay'], dpay_instance=self.dpay)
            bbd = Amount(op['reward_bbd'], dpay_instance=self.dpay)
            self.update(ts, vests, 0, 0, dpay, bbd)
            return

        elif op['type'] == "curation_reward":
            if "curation_reward" in only_ops or enable_rewards:
                vests = Amount(op['reward'], dpay_instance=self.dpay)
            if "curation_reward" in only_ops:
                self.update(ts, vests, 0, 0)
            if enable_rewards:
                self.update_rewards(ts, vests, 0, 0, 0)
            return

        elif op['type'] == "author_reward":
            if "author_reward" in only_ops or enable_rewards:
                # print(op)
                vests = Amount(op['vesting_payout'], dpay_instance=self.dpay)
                dpay = Amount(op['dpay_payout'], dpay_instance=self.dpay)
                bbd = Amount(op['bbd_payout'], dpay_instance=self.dpay)
            if "author_reward" in only_ops:
                self.update(ts, vests, 0, 0, dpay, bbd)
            if enable_rewards:
                self.update_rewards(ts, 0, vests, dpay, bbd)
            return

        elif op['type'] == "producer_reward":
            vests = Amount(op['vesting_shares'], dpay_instance=self.dpay)
            self.update(ts, vests, 0, 0)
            return

        elif op['type'] == "comment_benefactor_reward":
            if op['benefactor'] == self.account["name"]:
                vests = Amount(op['reward'], dpay_instance=self.dpay)
                self.update(ts, vests, 0, 0)
                return
            else:
                return

        elif op['type'] == "fill_convert_request":
            amount_in = Amount(op["amount_in"], dpay_instance=self.dpay)
            amount_out = Amount(op["amount_out"], dpay_instance=self.dpay)
            if op["owner"] == self.account["name"]:
                self.update(ts, 0, 0, 0, amount_out, amount_in * (-1))
            return

        elif op['type'] == "interest":
            interest = Amount(op["interest"], dpay_instance=self.dpay)
            self.update(ts, 0, 0, 0, 0, interest)
            return

        elif op['type'] == "vote":
            if "vote" in only_ops or enable_out_votes:
                weight = int(op['weight'])
                if op["voter"] == self.account["name"]:
                    self.update_out_vote(ts, weight)
            if "vote" in only_ops or enable_in_votes and op[
                    "author"] == self.account["name"]:
                weight = int(op['weight'])
                self.update_in_vote(ts, weight, op)
            return

        elif op['type'] in [
                'comment', 'feed_publish', 'shutdown_witness',
                'account_witness_vote', 'witness_update', 'custom_json',
                'limit_order_create', 'account_update',
                'account_witness_proxy', 'limit_order_cancel',
                'comment_options', 'delete_comment', 'interest',
                'recover_account', 'pow', 'fill_convert_request', 'convert',
                'request_account_recovery'
        ]:
            return

        # if "vests" in str(op).lower():
        #     print(op)
        # else:
        # print(op)

    def build_bp_arrays(self):
        """ Builds the own_sp and eff_sp array"""
        self.own_sp = []
        self.eff_sp = []
        for (ts, own, din, dout) in zip(self.timestamps, self.own_vests,
                                        self.delegated_vests_in,
                                        self.delegated_vests_out):
            sum_in = sum([din[key].amount for key in din])
            sum_out = sum([dout[key].amount for key in dout])
            bp_in = self.dpay.vests_to_sp(sum_in, timestamp=ts)
            bp_out = self.dpay.vests_to_sp(sum_out, timestamp=ts)
            bp_own = self.dpay.vests_to_sp(own, timestamp=ts)
            bp_eff = bp_own + bp_in - bp_out
            self.own_sp.append(bp_own)
            self.eff_sp.append(bp_eff)

    def build_rep_arrays(self):
        """ Build reputation arrays """
        self.rep_timestamp = [self.timestamps[1]]
        self.rep = [reputation_to_score(0)]
        current_reputation = 0
        for (ts, rshares, rep) in zip(self.in_vote_timestamp,
                                      self.in_vote_rshares, self.in_vote_rep):
            if rep > 0:
                if rshares > 0 or (rshares < 0 and rep > current_reputation):
                    current_reputation += rshares >> 6
            self.rep.append(reputation_to_score(current_reputation))
            self.rep_timestamp.append(ts)

    def build_vp_arrays(self):
        """ Build vote power arrays"""
        self.vp_timestamp = [self.timestamps[1]]
        self.vp = [DPAY_100_PERCENT]
        for (ts, weight) in zip(self.out_vote_timestamp, self.out_vote_weight):
            self.vp.append(self.vp[-1])

            if self.vp[-1] < DPAY_100_PERCENT:
                regenerated_vp = ((ts - self.vp_timestamp[-1]).total_seconds(
                )) * DPAY_100_PERCENT / DPAY_VOTE_REGENERATION_SECONDS
                self.vp[-1] += int(regenerated_vp)

            if self.vp[-1] > DPAY_100_PERCENT:
                self.vp[-1] = DPAY_100_PERCENT
            self.vp[-1] -= self.dpay._calc_resulting_vote(self.vp[-1], weight)
            if self.vp[-1] < 0:
                self.vp[-1] = 0

            self.vp_timestamp.append(ts)

    def build_curation_arrays(self, end_date=None, sum_days=7):
        """ Build curation arrays"""
        self.curation_per_1000_SP_timestamp = []
        self.curation_per_1000_SP = []
        if sum_days <= 0:
            raise ValueError("sum_days must be greater than 0")
        index = 0
        curation_sum = 0
        days = (self.reward_timestamps[-1] -
                self.reward_timestamps[0]).days // sum_days * sum_days
        if end_date is None:
            end_date = self.reward_timestamps[-1] - timedelta(days=days)
        for (ts, vests) in zip(self.reward_timestamps, self.curation_rewards):
            if vests == 0:
                continue
            sp = self.dpay.vests_to_sp(vests, timestamp=ts)
            data = self.get_data(timestamp=ts, index=index)
            index = data["index"]
            if "bp_eff" in data and data["bp_eff"] > 0:
                curation_1k_sp = sp / data["bp_eff"] * 1000 / sum_days * 7
            else:
                curation_1k_sp = 0
            if ts < end_date:
                curation_sum += curation_1k_sp
            else:
                self.curation_per_1000_SP_timestamp.append(end_date)
                self.curation_per_1000_SP.append(curation_sum)
                end_date = end_date + timedelta(days=sum_days)
                curation_sum = 0

    def __str__(self):
        return self.__repr__()

    def __repr__(self):
        return "<%s %s>" % (self.__class__.__name__, str(self.account["name"]))